From 8af801416c15e0368a2a6a5001726cd73b4f6baa Mon Sep 17 00:00:00 2001 From: tiera3 <87589219+tiera3@users.noreply.github.com> Date: Sun, 19 Jan 2025 13:53:43 +1000 Subject: [PATCH 01/28] fix [LCI] collation - remove non-full art basics (#13237) --- Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index 43694b2b05b..b69a7f099d0 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -531,7 +531,7 @@ class TheLostCavernsOfIxalanCollator implements BoosterCollator { private final CardRun uncommonB = new CardRun(true, "254", "33", "48", "23", "58", "286", "96", "251", "25", "111", "51", "5", "125", "8", "124", "186", "22", "102", "261", "87", "272", "107", "59", "120", "278", "19", "103", "42", "93", "21", "247", "33", "48", "111", "10", "50", "96", "23", "54", "286", "58", "17", "254", "213", "124", "8", "252", "59", "102", "25", "247", "51", "5", "125", "251", "107", "42", "93", "19", "103", "186", "22", "87", "278", "21", "261", "120", "272", "254", "17", "54", "252", "50", "10", "213", "48", "33", "58", "286", "96", "23", "51", "251", "124", "8", "125", "5", "102", "25", "59", "120", "247", "107", "186", "22", "272", "87", "261", "103", "278", "19", "93", "21", "111", "42", "252", "17", "54", "213", "10", "50"); private final CardRun uncommonC = new CardRun(true, "245", "141", "301", "180", "230", "150", "220", "147", "194", "227", "148", "178", "139", "184", "260", "322", "263", "150", "187", "303", "198", "232", "183", "139", "270", "97", "173", "16", "187", "263", "198", "141", "298", "162", "232", "91", "173", "230", "143", "180", "170", "184", "242", "226", "147", "215", "320", "224", "187", "260", "236", "263", "143", "184", "242", "270", "245", "183", "147", "216", "236", "133", "224", "215", "310", "152", "302", "143", "331", "97", "178", "306", "323", "304", "198", "162", "329", "133", "312", "148", "215", "91", "170", "260", "179", "226", "194", "165", "16", "216", "97", "227", "152", "270", "150", "179", "139", "91", "170", "194", "165", "16", "141", "180", "152", "179", "220", "178", "173", "325", "148"); private final CardRun rare = new CardRun(false, "219", "219", "1", "1", "88", "44", "44", "221", "221", "223", "223", "176", "176", "92", "134", "47", "47", "135", "135", "137", "137", "94", "94", "269", "249", "98", "98", "181", "181", "228", "228", "52", "52", "145", "145", "271", "271", "12", "12", "14", "14", "185", "229", "188", "188", "153", "153", "189", "191", "191", "156", "156", "193", "193", "196", "196", "231", "231", "61", "61", "20", "20", "157", "157", "63", "63", "256", "256", "234", "234", "158", "204", "67", "26", "237", "237", "161", "161", "113", "113", "208", "208", "115", "115", "238", "32", "280", "280", "281", "281", "282", "282", "283", "283", "284", "284", "258", "258", "239", "34", "34", "211", "211", "121", "121", "240", "241", "241", "122", "122", "123", "123", "80", "80", "285", "285", "126", "126", "264", "264", "127", "127", "222", "225", "225", "55", "56", "56", "257", "235", "212", "39", "39", "265", "265", "266", "266", "81", "81", "267", "267", "171", "171", "41", "41", "243", "244", "244", "43", "43"); - private final CardRun land = new CardRun(false, "268", "268", "268", "268", "268", "273", "273", "273", "273", "273", "274", "274", "274", "274", "274", "275", "275", "275", "275", "275", "276", "276", "276", "276", "276", "277", "277", "277", "277", "277", "279", "279", "279", "279", "279", "287", "287", "287", "288", "288", "288", "289", "289", "289", "290", "290", "290", "291", "291", "291", "393", "393", "393", "394", "394", "394", "395", "395", "395", "396", "396", "396", "397", "397", "397", "398", "398", "398", "399", "399", "399", "400", "400", "400", "401", "401", "401", "402", "402", "402"); + private final CardRun land = new CardRun(false, "268", "268", "268", "268", "268", "273", "273", "273", "273", "273", "274", "274", "274", "274", "274", "275", "275", "275", "275", "275", "276", "276", "276", "276", "276", "277", "277", "277", "277", "277", "279", "279", "279", "279", "279", "287", "287", "287", "288", "288", "288", "289", "289", "289", "290", "290", "290", "291", "291", "291"); private final BoosterStructure AABBBCCCC = new BoosterStructure( commonA, commonA, -- 2.47.2 From 9ffdf48b6fe9267debf77a5d003b345301b4886a Mon Sep 17 00:00:00 2001 From: tiera3 <87589219+tiera3@users.noreply.github.com> Date: Sun, 19 Jan 2025 13:54:06 +1000 Subject: [PATCH 02/28] correct collector number of [LEG] Firestorm Phoenix (#13228) --- Mage.Sets/src/mage/sets/Legends.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index e3a1b69ff3a..0af66ba756b 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -107,7 +107,7 @@ public final class Legends extends ExpansionSet { 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("Firestorm Phoenix", 145, Rarity.RARE, mage.cards.f.FirestormPhoenix.class)); + cards.add(new SetCardInfo("Firestorm Phoenix", 147, Rarity.RARE, mage.cards.f.FirestormPhoenix.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)); -- 2.47.2 From 5358fdd933fee5eba59040c2fcc45aa4acffadcf Mon Sep 17 00:00:00 2001 From: tiera3 <87589219+tiera3@users.noreply.github.com> Date: Sun, 19 Jan 2025 13:54:35 +1000 Subject: [PATCH 03/28] update collector numbers to match scryfall for [MB2] playtest cards (#13230) --- Mage.Sets/src/mage/sets/MysteryBooster2.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Mage.Sets/src/mage/sets/MysteryBooster2.java b/Mage.Sets/src/mage/sets/MysteryBooster2.java index 62a03702c84..c7c1c2b0fdc 100644 --- a/Mage.Sets/src/mage/sets/MysteryBooster2.java +++ b/Mage.Sets/src/mage/sets/MysteryBooster2.java @@ -107,7 +107,7 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Gitaxian Probe", 28, Rarity.COMMON, mage.cards.g.GitaxianProbe.class)); cards.add(new SetCardInfo("Giver of Runes", 147, Rarity.RARE, mage.cards.g.GiverOfRunes.class)); cards.add(new SetCardInfo("Gix, Yawgmoth Praetor", 245, Rarity.MYTHIC, mage.cards.g.GixYawgmothPraetor.class)); - cards.add(new SetCardInfo("Gobland", 374, Rarity.RARE, mage.cards.g.Gobland.class)); + cards.add(new SetCardInfo("Gobland", 563, Rarity.RARE, mage.cards.g.Gobland.class)); cards.add(new SetCardInfo("Goblin Charbelcher", 221, Rarity.RARE, mage.cards.g.GoblinCharbelcher.class)); cards.add(new SetCardInfo("Goblin Gang Leader", 144, Rarity.UNCOMMON, mage.cards.g.GoblinGangLeader.class)); cards.add(new SetCardInfo("Goblin Guide", 58, Rarity.RARE, mage.cards.g.GoblinGuide.class)); @@ -119,7 +119,7 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Greater Good", 207, Rarity.RARE, mage.cards.g.GreaterGood.class)); cards.add(new SetCardInfo("Grinding Station", 223, Rarity.UNCOMMON, mage.cards.g.GrindingStation.class)); cards.add(new SetCardInfo("Gush", 164, Rarity.COMMON, mage.cards.g.Gush.class)); - cards.add(new SetCardInfo("Hish of the Snake Cult", 356, Rarity.RARE, mage.cards.h.HishOfTheSnakeCult.class)); + cards.add(new SetCardInfo("Hish of the Snake Cult", 595, Rarity.RARE, mage.cards.h.HishOfTheSnakeCult.class)); cards.add(new SetCardInfo("Hogaak, Arisen Necropolis", 136, Rarity.RARE, mage.cards.h.HogaakArisenNecropolis.class)); cards.add(new SetCardInfo("Hollow One", 95, Rarity.RARE, mage.cards.h.HollowOne.class)); cards.add(new SetCardInfo("Hoodwink", 123, Rarity.COMMON, mage.cards.h.Hoodwink.class)); @@ -128,7 +128,7 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Hunting Cheetah", 134, Rarity.COMMON, mage.cards.h.HuntingCheetah.class)); cards.add(new SetCardInfo("Hydroblast", 165, Rarity.COMMON, mage.cards.h.Hydroblast.class)); cards.add(new SetCardInfo("Ice-Fang Coatl", 83, Rarity.RARE, mage.cards.i.IceFangCoatl.class)); - cards.add(new SetCardInfo("Indicate", 265, Rarity.RARE, mage.cards.i.Indicate.class)); + cards.add(new SetCardInfo("Indicate", 501, Rarity.RARE, mage.cards.i.Indicate.class)); cards.add(new SetCardInfo("Iona, Shield of Emeria", 12, Rarity.MYTHIC, mage.cards.i.IonaShieldOfEmeria.class)); cards.add(new SetCardInfo("Isochron Scepter", 96, Rarity.UNCOMMON, mage.cards.i.IsochronScepter.class)); cards.add(new SetCardInfo("Jace Beleren", 29, Rarity.MYTHIC, mage.cards.j.JaceBeleren.class)); @@ -163,7 +163,7 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Mirri's Guile", 209, Rarity.RARE, mage.cards.m.MirrisGuile.class)); cards.add(new SetCardInfo("Mirri, Weatherlight Duelist", 252, Rarity.MYTHIC, mage.cards.m.MirriWeatherlightDuelist.class)); cards.add(new SetCardInfo("Mishra's Bauble", 97, Rarity.UNCOMMON, mage.cards.m.MishrasBauble.class)); - cards.add(new SetCardInfo("Mox Poison", 369, Rarity.RARE, mage.cards.m.MoxPoison.class)); + cards.add(new SetCardInfo("Mox Poison", 608, Rarity.RARE, mage.cards.m.MoxPoison.class)); cards.add(new SetCardInfo("Multani, Yavimaya's Avatar", 248, Rarity.MYTHIC, mage.cards.m.MultaniYavimayasAvatar.class)); cards.add(new SetCardInfo("Mutilate", 45, Rarity.RARE, mage.cards.m.Mutilate.class)); cards.add(new SetCardInfo("Mystic Sanctuary", 110, Rarity.COMMON, mage.cards.m.MysticSanctuary.class)); @@ -236,7 +236,7 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Static Orb", 234, Rarity.RARE, mage.cards.s.StaticOrb.class)); cards.add(new SetCardInfo("Stifle", 173, Rarity.RARE, mage.cards.s.Stifle.class)); cards.add(new SetCardInfo("Stitcher's Supplier", 48, Rarity.UNCOMMON, mage.cards.s.StitchersSupplier.class)); - cards.add(new SetCardInfo("Stone Drake", 363, Rarity.RARE, mage.cards.s.StoneDrake.class)); + cards.add(new SetCardInfo("Stone Drake", 602, Rarity.RARE, mage.cards.s.StoneDrake.class)); cards.add(new SetCardInfo("Stony Silence", 21, Rarity.RARE, mage.cards.s.StonySilence.class)); cards.add(new SetCardInfo("Street Wraith", 49, Rarity.COMMON, mage.cards.s.StreetWraith.class)); cards.add(new SetCardInfo("Summoner's Pact", 74, Rarity.RARE, mage.cards.s.SummonersPact.class)); @@ -281,12 +281,12 @@ public class MysteryBooster2 extends ExpansionSet { cards.add(new SetCardInfo("Wasteland", 115, Rarity.UNCOMMON, mage.cards.w.Wasteland.class)); cards.add(new SetCardInfo("Whiteout", 77, Rarity.COMMON, mage.cards.w.Whiteout.class)); cards.add(new SetCardInfo("Winds of Change", 201, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Wisedrafter's Will", 303, Rarity.RARE, mage.cards.w.WisedraftersWill.class)); + cards.add(new SetCardInfo("Wisedrafter's Will", 539, Rarity.RARE, mage.cards.w.WisedraftersWill.class)); cards.add(new SetCardInfo("Wish", 64, Rarity.RARE, mage.cards.w.Wish.class)); cards.add(new SetCardInfo("Wishclaw Talisman", 51, Rarity.RARE, mage.cards.w.WishclawTalisman.class)); cards.add(new SetCardInfo("Worst Fears", 52, Rarity.MYTHIC, mage.cards.w.WorstFears.class)); - cards.add(new SetCardInfo("Wowzer, the Aspirational", 365, Rarity.RARE, mage.cards.w.WowzerTheAspirational.class)); - cards.add(new SetCardInfo("Wrath of Leknif", 366, Rarity.RARE, mage.cards.w.WrathOfLeknif.class)); + cards.add(new SetCardInfo("Wowzer, the Aspirational", 604, Rarity.RARE, mage.cards.w.WowzerTheAspirational.class)); + cards.add(new SetCardInfo("Wrath of Leknif", 605, Rarity.RARE, mage.cards.w.WrathOfLeknif.class)); cards.add(new SetCardInfo("Xantcha, Sleeper Agent", 253, Rarity.RARE, mage.cards.x.XantchaSleeperAgent.class)); cards.add(new SetCardInfo("Yorion, Sky Nomad", 94, Rarity.RARE, mage.cards.y.YorionSkyNomad.class)); cards.add(new SetCardInfo("Zombie Master", 188, Rarity.RARE, mage.cards.z.ZombieMaster.class)); -- 2.47.2 From a698385066305c563ab0785cc9e4c5be3122eb32 Mon Sep 17 00:00:00 2001 From: tiera3 <87589219+tiera3@users.noreply.github.com> Date: Sun, 19 Jan 2025 13:55:13 +1000 Subject: [PATCH 04/28] Update image download links for [SLD] back faces (#13231) --- .../dl/sources/ScryfallImageSupportCards.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index 81c95a5b3d0..f582edecba3 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -613,28 +613,39 @@ public class ScryfallImageSupportCards { // SLD // fake double faced cards put("SLD/Adrix and Nev, Twincasters/1544b", "https://api.scryfall.com/cards/sld/1544/en?format=image&face=back"); + put("SLD/Ajani Goldmane/745b", "https://api.scryfall.com/cards/sld/745/en?format=image&face=back"); put("SLD/Ajani Goldmane/1453b", "https://api.scryfall.com/cards/sld/1453/en?format=image&face=back"); put("SLD/Anointed Procession/1511b", "https://api.scryfall.com/cards/sld/1453/en?format=image&face=back"); + put("SLD/Birds of Paradise/1675b", "https://api.scryfall.com/cards/sld/1675/en?format=image&face=back"); put("SLD/Blightsteel Colossus/1079b", "https://api.scryfall.com/cards/sld/1079/en?format=image&face=back"); + put("SLD/Chandra Nalaar/748b", "https://api.scryfall.com/cards/sld/748/en?format=image&face=back"); put("SLD/Chandra Nalaar/1456b", "https://api.scryfall.com/cards/sld/1456/en?format=image&face=back"); put("SLD/Darksteel Colossus/1081b", "https://api.scryfall.com/cards/sld/1081/en?format=image&face=back"); put("SLD/Death Baron/1458b", "https://api.scryfall.com/cards/sld/1458/en?format=image&face=back"); put("SLD/Doubling Cube/1080b", "https://api.scryfall.com/cards/sld/1080/en?format=image&face=back"); put("SLD/Etali, Primal Storm/1123b", "https://api.scryfall.com/cards/sld/1123/en?format=image&face=back"); + put("SLD/Garruk Wildspeaker/749b", "https://api.scryfall.com/cards/sld/749/en?format=image&face=back"); put("SLD/Garruk Wildspeaker/1457b", "https://api.scryfall.com/cards/sld/1457/en?format=image&face=back"); put("SLD/Ghalta, Primal Hunger/1124b", "https://api.scryfall.com/cards/sld/1124/en?format=image&face=back"); put("SLD/Grimgrin, Corpse-Born/1461b", "https://api.scryfall.com/cards/sld/1461/en?format=image&face=back"); + put("SLD/Jace Beleren/746b", "https://api.scryfall.com/cards/sld/746/en?format=image&face=back"); put("SLD/Jace Beleren/1454b", "https://api.scryfall.com/cards/sld/1454/en?format=image&face=back"); put("SLD/Jetmir, Nexus of Revels/1509b", "https://api.scryfall.com/cards/sld/1509/en?format=image&face=back"); + put("SLD/Jetmir, Nexus of Revels/1555b", "https://api.scryfall.com/cards/sld/1555/en?format=image&face=back"); put("SLD/Jinnie Fay, Jetmir's Second/1510b", "https://api.scryfall.com/cards/sld/1510/en?format=image&face=back"); + put("SLD/Jinnie Fay, Jetmir's Second/1556b", "https://api.scryfall.com/cards/sld/1556/en?format=image&face=back"); + put("SLD/Kardur, Doomscourge/1807b", "https://api.scryfall.com/cards/sld/1807/en?format=image&face=back"); put("SLD/Krark's Thumb/383b", "https://api.scryfall.com/cards/sld/383/en?format=image&face=back"); put("SLD/Krark, the Thumbless/1543b", "https://api.scryfall.com/cards/sld/1543/en?format=image&face=back"); + put("SLD/Liliana Vess/747b", "https://api.scryfall.com/cards/sld/747/en?format=image&face=back"); put("SLD/Liliana Vess/1455b", "https://api.scryfall.com/cards/sld/1455/en?format=image&face=back"); + put("SLD/Norin the Wary/827b", "https://api.scryfall.com/cards/sld/827/en?format=image&face=back"); put("SLD/Noxious Ghoul/1459b", "https://api.scryfall.com/cards/sld/1459/en?format=image&face=back"); put("SLD/Okaun, Eye of Chaos/380b", "https://api.scryfall.com/cards/sld/380/en?format=image&face=back"); - put("SLD/Okaun, Eye of Chaos/380b*", "https://api.scryfall.com/cards/sld/380★/en?format=image&face=back"); + put("SLD/Okaun, Eye of Chaos/380*b", "https://api.scryfall.com/cards/sld/380★/en?format=image&face=back"); put("SLD/Propaganda/381b", "https://api.scryfall.com/cards/sld/381/en?format=image&face=back"); put("SLD/Rin and Seri, Inseparable/1508b", "https://api.scryfall.com/cards/sld/1508/en?format=image&face=back"); + put("SLD/Rin and Seri, Inseparable/1554b", "https://api.scryfall.com/cards/sld/1554/en?format=image&face=back"); put("SLD/Sakashima of a Thousand Faces/1541b", "https://api.scryfall.com/cards/sld/1541/en?format=image&face=back"); put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back"); put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back"); @@ -643,9 +654,10 @@ public class ScryfallImageSupportCards { put("SLD/Unholy Grotto/1462b", "https://api.scryfall.com/cards/sld/1462/en?format=image&face=back"); put("SLD/Yargle, Glutton of Urborg/1542b", "https://api.scryfall.com/cards/sld/1542/en?format=image&face=back"); put("SLD/Zndrsplt, Eye of Wisdom/379b", "https://api.scryfall.com/cards/sld/379/en?format=image&face=back"); - put("SLD/Zndrsplt, Eye of Wisdom/379b*", "https://api.scryfall.com/cards/sld/379★/en?format=image&face=back"); + put("SLD/Zndrsplt, Eye of Wisdom/379*b", "https://api.scryfall.com/cards/sld/379★/en?format=image&face=back"); put("SLD/Zombie Master/1460b", "https://api.scryfall.com/cards/sld/1460/en?format=image&face=back"); // normal cards + put("SLD/Counterspell/99999SCTLR", "https://api.scryfall.com/cards/sld/SCTLR/"); // see issue 11157 put("SLD/Viscera Seer/99999VS", "https://api.scryfall.com/cards/sld/VS/"); // see issue 11157 // CALC - custom alchemy version of cards. -- 2.47.2 From 02599fbaa45138c27e0fcee50c21212bfbdab924 Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:08:00 +0000 Subject: [PATCH 05/28] Simplify Rendmaw implementation --- Mage.Sets/src/mage/cards/r/RendmawCreakingNest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/r/RendmawCreakingNest.java b/Mage.Sets/src/mage/cards/r/RendmawCreakingNest.java index fcf91f09500..a7a3b54fefa 100644 --- a/Mage.Sets/src/mage/cards/r/RendmawCreakingNest.java +++ b/Mage.Sets/src/mage/cards/r/RendmawCreakingNest.java @@ -117,10 +117,7 @@ class RendmawCreakingNestEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - if (!game.getPlayer(playerId).isInGame()) { - continue; - } + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game, true)) { Token token = new Black22BirdToken(); token.putOntoBattlefield(1, game, source, playerId, true, false); token.getLastAddedTokenIds().forEach(id -> game.addEffect( -- 2.47.2 From 0bcf5f9e0343fbbcfe0e343be812369eb30df315 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Sun, 19 Jan 2025 21:09:57 +0000 Subject: [PATCH 06/28] [DSK] Implement Unable to Scream (#13234) * Introduced LoseAllAbilitiesAttachedEffect * Added unit tests for Unable to Scream --- .../src/mage/cards/u/UnableToScream.java | 95 +++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../cards/single/dsk/UnableToScreamTest.java | 154 ++++++++++++++++++ .../LoseAllAbilitiesAttachedEffect.java | 51 ++++++ 4 files changed, 301 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/u/UnableToScream.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/dsk/UnableToScreamTest.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAttachedEffect.java diff --git a/Mage.Sets/src/mage/cards/u/UnableToScream.java b/Mage.Sets/src/mage/cards/u/UnableToScream.java new file mode 100644 index 00000000000..215f870b1bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnableToScream.java @@ -0,0 +1,95 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; +import mage.abilities.effects.common.continuous.AddCardTypeAttachedEffect; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesAttachedEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +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 java.util.UUID; + +/** + * @author markort147 + */ +public final class UnableToScream extends CardImpl { + + public UnableToScream(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.Detriment)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature loses all abilities and is a Toy artifact creature with base power and toughness 0/2 in addition to its other types. + Ability ability = new SimpleStaticAbility(new LoseAllAbilitiesAttachedEffect(AttachmentType.AURA)); + ability.addEffect(new AddCardSubtypeAttachedEffect(SubType.TOY, AttachmentType.AURA).setText(" and is a Toy")); + ability.addEffect(new AddCardTypeAttachedEffect(CardType.ARTIFACT, AttachmentType.AURA).setText(" artifact creature")); + ability.addEffect(new SetBasePowerToughnessEnchantedEffect(0, 2).setText(" with base power and toughness 0/2 in addition to its other types.")); + this.addAbility(ability); + + // As long as enchanted creature is face down, it can't be turned face up. + this.addAbility(new SimpleStaticAbility(new UnableToScreamPreventingEffect())); + } + + private UnableToScream(final UnableToScream card) { + super(card); + } + + @Override + public UnableToScream copy() { + return new UnableToScream(this); + } +} + +class UnableToScreamPreventingEffect extends ContinuousRuleModifyingEffectImpl { + + UnableToScreamPreventingEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + setText("As long as enchanted creature is face down, it can't be turned face up."); + } + + private UnableToScreamPreventingEffect(final UnableToScreamPreventingEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType().equals(GameEvent.EventType.TURN_FACE_UP); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent aura = game.getPermanent(source.getSourceId()); + if (aura == null) { + return false; + } + + Permanent creature = game.getPermanent(aura.getAttachedTo()); + if (creature == null) { + return false; + } + + return creature.isFaceDown(game) && event.getTargetId().equals(creature.getId()); + } + + @Override + public UnableToScreamPreventingEffect copy() { + return new UnableToScreamPreventingEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 4ddb9287005..77b70772490 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -241,6 +241,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Twist Reality", 77, Rarity.COMMON, mage.cards.t.TwistReality.class)); cards.add(new SetCardInfo("Twitching Doll", 201, Rarity.RARE, mage.cards.t.TwitchingDoll.class)); cards.add(new SetCardInfo("Tyvar, the Pummeler", 202, Rarity.MYTHIC, mage.cards.t.TyvarThePummeler.class)); + cards.add(new SetCardInfo("Unable to Scream", 78, Rarity.COMMON, mage.cards.u.UnableToScream.class)); cards.add(new SetCardInfo("Under the Skin", 203, Rarity.UNCOMMON, mage.cards.u.UnderTheSkin.class)); cards.add(new SetCardInfo("Unidentified Hovership", 37, Rarity.RARE, mage.cards.u.UnidentifiedHovership.class)); cards.add(new SetCardInfo("Unnerving Grasp", 80, Rarity.UNCOMMON, mage.cards.u.UnnervingGrasp.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dsk/UnableToScreamTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dsk/UnableToScreamTest.java new file mode 100644 index 00000000000..7d7e95ec257 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dsk/UnableToScreamTest.java @@ -0,0 +1,154 @@ +package org.mage.test.cards.single.dsk; + +import mage.abilities.Ability; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.Card; +import mage.constants.*; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.stream.Collectors; + +/** + * @author markort147 + */ +public class UnableToScreamTest extends CardTestPlayerBase { + + /* + * Unable to Scream {U} + * Enchantment - Aura + * Enchant creature + * Enchanted creature loses all abilities and is a Toy artifact creature with base power and toughness 0/2 in addition to its other types. + * As long as enchanted creature is face down, it can't be turned face up. + */ + public static final String UNABLE_TO_SCREAM = "Unable to Scream"; + + /* + * Appetite for the Unnatural {2}{G} + * Instant + * Destroy target artifact or enchantment. You gain 2 life. + */ + public static final String APPETITE_FOR_THE_UNNATURAL = "Appetite for the Unnatural"; + + + // Cast a spell that would turn the creature face up, but Unable to Scream negates the effect. + // After removing Unable to Scream, cast the spell again and the effect applies correctly. + @Test + public void preventFromTurningFaceUpTest() { + /* + * Akroma, Angel of Fury {5}{R}{R}{R} + * Creature - Legendary Angel + * 6/6 + * Akroma, Angel of Fury can't be countered. + * Flying + * Trample + * Protection from white and from blue. + * {R}: Akroma, Angel of Fury gets +1/+0 until end of turn. + * Morph {3}{R}{R}{R} + */ + final String akromaAngelOfFury = "Akroma, Angel of Fury"; + + /* + * Break Open {1}{R} + * Instant + * Turn target face-down creature an opponent controls face up. + */ + final String breakOpen = "Break Open"; + + setStrictChooseMode(true); + + addCard(Zone.HAND, playerB, akromaAngelOfFury); + addCard(Zone.HAND, playerB, APPETITE_FOR_THE_UNNATURAL); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 3); + + addCard(Zone.HAND, playerA, UNABLE_TO_SCREAM); + addCard(Zone.HAND, playerA, breakOpen, 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + // prepare the face down creature + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, akromaAngelOfFury + " using Morph"); + // attach Unable to Scream to it + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, UNABLE_TO_SCREAM, EmptyNames.FACE_DOWN_CREATURE.getTestCommand(), true); + // cast a spell that would turn the creature face up + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, breakOpen, EmptyNames.FACE_DOWN_CREATURE.getTestCommand()); + + // the creature is still face down + checkPermanentCount("Face down creature is on the battlefield", 3, PhaseStep.BEGIN_COMBAT, playerB, EmptyNames.FACE_DOWN_CREATURE.getTestCommand(), 1); + checkPermanentCount("Akroma is not on the battlefield", 3, PhaseStep.BEGIN_COMBAT, playerB, akromaAngelOfFury, 0); + + // destroy Unable to Scream + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, APPETITE_FOR_THE_UNNATURAL, UNABLE_TO_SCREAM); + // cast a spell that would turn the creature face up + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, breakOpen, EmptyNames.FACE_DOWN_CREATURE.getTestCommand()); + + // now the creature is turned face up + checkPermanentCount("Face down creature is not on the battlefield", 5, PhaseStep.BEGIN_COMBAT, playerB, EmptyNames.FACE_DOWN_CREATURE.getTestCommand(), 0); + checkPermanentCount("Akroma is on the battlefield", 5, PhaseStep.BEGIN_COMBAT, playerB, akromaAngelOfFury, 1); + + setStopAt(5, PhaseStep.BEGIN_COMBAT); + execute(); + } + + // Unable to Scream changes type, subtype and base stats of a creature. + // After removing Unable to Scream, the creature restores its type, subtype, and base stats. + @Test + public void becomesEffectTest() { + /* + * Llanowar Elves {G} + * Creature - Elf Druid + * 1/1 + * {T}: Add {G}. + */ + final String llanowarElves = "Llanowar Elves"; + + setStrictChooseMode(true); + + addCard(Zone.HAND, playerB, APPETITE_FOR_THE_UNNATURAL); + addCard(Zone.BATTLEFIELD, playerB, llanowarElves); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 3); + + addCard(Zone.HAND, playerA, UNABLE_TO_SCREAM); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + + // attach Unable to Scream to the creature + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, UNABLE_TO_SCREAM, llanowarElves); + + // the creature is an artifact creature, toy elf druid with base stats 0/2 + runCode("The creature is an artifact creature, toy elf druid with base stats 0/2", 1, PhaseStep.BEGIN_COMBAT, playerB, + (info, player, game) -> { + Card elves = game.getBattlefield().getAllActivePermanents().stream().filter(p -> p.getName().equals(llanowarElves)).findAny().orElse(null); + Assert.assertNotNull("The creature must be on the battlefield", elves); + Assert.assertEquals("The creature must have base power 0", 0, elves.getPower().getValue()); + Assert.assertEquals("The creature must have base toughness 2", 2, elves.getToughness().getValue()); + Assert.assertTrue("The creature must have lost its abilities", elves.getAbilities(game).isEmpty()); + Assert.assertEquals("The creature must be an artifact creature", new HashSet<>(Arrays.asList(CardType.ARTIFACT, CardType.CREATURE)), new HashSet<>(elves.getCardType(game))); + Assert.assertEquals("The creature must be a Toy Elf Druid", new HashSet<>(Arrays.asList(SubType.TOY, SubType.ELF, SubType.DRUID)), new HashSet<>(elves.getSubtype(game))); + } + ); + + // destroy Unable to Scream + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, APPETITE_FOR_THE_UNNATURAL, UNABLE_TO_SCREAM); + + // the creature is a creature, elf druid with base stats 1/1 + runCode("The creature is creature, toy elf druid with base stats 1/1", 2, PhaseStep.BEGIN_COMBAT, playerB, + (info, player, game) -> { + Card elves = game.getBattlefield().getAllActivePermanents().stream().filter(p -> p.getName().equals(llanowarElves)).findAny().orElse(null); + Assert.assertNotNull("The creature must be on the battlefield", elves); + Assert.assertEquals("The creature must have base power 1", 1, elves.getPower().getValue()); + Assert.assertEquals("The creature must have base toughness 1", 1, elves.getToughness().getValue()); + Assert.assertTrue("The creature must have restored its abilities", elves.getAbilities(game).stream().map(Ability::getClass).collect(Collectors.toList()).contains(GreenManaAbility.class)); + Assert.assertEquals("The creature must be just a creature", Collections.singleton(CardType.CREATURE), new HashSet<>(elves.getCardType(game))); + Assert.assertEquals("The creature must be an Elf Druid", new HashSet<>(Arrays.asList(SubType.ELF, SubType.DRUID)), new HashSet<>(elves.getSubtype(game))); + } + ); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAttachedEffect.java new file mode 100644 index 00000000000..ea9ef01f106 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAttachedEffect.java @@ -0,0 +1,51 @@ + + +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author markort147 + */ +public class LoseAllAbilitiesAttachedEffect extends ContinuousEffectImpl { + + protected AttachmentType attachmentType; + + public LoseAllAbilitiesAttachedEffect(AttachmentType attachmentType) { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility); + this.attachmentType = attachmentType; + setText(); + } + + protected LoseAllAbilitiesAttachedEffect(final LoseAllAbilitiesAttachedEffect effect) { + super(effect); + this.attachmentType = effect.attachmentType; + } + + @Override + public LoseAllAbilitiesAttachedEffect copy() { + return new LoseAllAbilitiesAttachedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + Permanent creature = game.getPermanent(equipment.getAttachedTo()); + if (creature != null) { + creature.removeAllAbilities(source.getSourceId(), game); + return true; + } + } + return false; + } + + private void setText() { + staticText = attachmentType.verb() + " creature loses all abilities"; + } + +} -- 2.47.2 From 3e21e3fb52231ca97bf26ce97eb15fe8c12d0cfe Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Mon, 20 Jan 2025 01:41:28 +0000 Subject: [PATCH 07/28] Add DSC token images --- .../sources/ScryfallImageSupportTokens.java | 26 ++++++++++++++++++- .../src/mage/cards/g/GristTheHungerTide.java | 1 - Mage/src/main/resources/tokens-database.txt | 24 +++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index 7679f7b895a..b0851db1cd7 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -2493,7 +2493,31 @@ public class ScryfallImageSupportTokens { // DSK put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image"); - + + // DSC + put("DSC/Angel", "https://api.scryfall.com/cards/tdsc/2/en?format=image"); + put("DSC/Beast", "https://api.scryfall.com/cards/tdsc/8/en?format=image"); + put("DSC/Bird", "https://api.scryfall.com/cards/tdsc/5/en?format=image"); + put("DSC/Demon", "https://api.scryfall.com/cards/tdsc/6/en?format=image"); + put("DSC/Devil", "https://api.scryfall.com/cards/tdsc/7/en?format=image"); + put("DSC/Elemental", "https://api.scryfall.com/cards/tdsc/9/en?format=image"); + put("DSC/Fractal", "https://api.scryfall.com/cards/tdsc/20/en?format=image"); + put("DSC/Human Soldier", "https://api.scryfall.com/cards/tdsc/3/en?format=image"); + put("DSC/Inkling", "https://api.scryfall.com/cards/tdsc/21/en?format=image"); + put("DSC/Insect/1", "https://api.scryfall.com/cards/tdsc/22/en?format=image"); + put("DSC/Insect/2", "https://api.scryfall.com/cards/tdsc/10/en?format=image"); + put("DSC/Insect/3", "https://api.scryfall.com/cards/tdsc/11/en?format=image"); + put("DSC/Insect/4", "https://api.scryfall.com/cards/tdsc/12/en?format=image"); + put("DSC/Ooze/1", "https://api.scryfall.com/cards/tdsc/14/en?format=image"); + put("DSC/Ooze/2", "https://api.scryfall.com/cards/tdsc/13/en?format=image"); + put("DSC/Phyrexian Beast", "https://api.scryfall.com/cards/tdsc/15/en?format=image"); + put("DSC/Shapeshifter", "https://api.scryfall.com/cards/tdsc/1/en?format=image"); + put("DSC/Shark", "https://api.scryfall.com/cards/tdsc/4/en?format=image"); + put("DSC/Spider", "https://api.scryfall.com/cards/tdsc/16/en?format=image"); + put("DSC/Treefolk", "https://api.scryfall.com/cards/tdsc/17/en?format=image"); + put("DSC/Wurm/1", "https://api.scryfall.com/cards/tdsc/18/en?format=image"); + put("DSC/Wurm/2", "https://api.scryfall.com/cards/tdsc/19/en?format=image"); + // FDN put("FDN/Beast/1", "https://api.scryfall.com/cards/tfdn/32/en?format=image"); put("FDN/Beast/2", "https://api.scryfall.com/cards/tfdn/33/en?format=image"); diff --git a/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java b/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java index 832b686ff96..bae6785d8e7 100644 --- a/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java +++ b/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java @@ -24,7 +24,6 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.IzoniInsectToken; import mage.game.permanent.token.Token; import mage.players.Player; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreatureOrPlaneswalker; import java.util.Arrays; diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index d4f567f4b12..ee55d3a7383 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -2366,6 +2366,30 @@ |Generate|TOK:BLC|Wolf|1||GarrukCursedHuntsmanToken| |Generate|TOK:BLC|Wolf|2||WolfToken| +# DSC +|Generate|TOK:DSC|Angel|||AngelToken| +|Generate|TOK:DSC|Beast|||BeastToken| +|Generate|TOK:DSC|Bird|||Black22BirdToken| +|Generate|TOK:DSC|Demon|||DemonToken| +|Generate|TOK:DSC|Devil|||DevilToken| +|Generate|TOK:DSC|Elemental|||TitaniaProtectorOfArgothElementalToken| +|Generate|TOK:DSC|Fractal|||FractalToken| +|Generate|TOK:DSC|Human Soldier|||HumanSoldierToken| +|Generate|TOK:DSC|Inkling|||InklingToken| +|Generate|TOK:DSC|Insect|1||IzoniInsectToken| +|Generate|TOK:DSC|Insect|2||InsectToken| +|Generate|TOK:DSC|Insect|3||InsectToken| +|Generate|TOK:DSC|Insect|4||InsectDeathToken| +|Generate|TOK:DSC|Ooze|1||OozeToken| +|Generate|TOK:DSC|Ooze|2||BiogenicOozeToken| +|Generate|TOK:DSC|Phyrexian Beast|||PhyrexianBeastToken| +|Generate|TOK:DSC|Shapeshifter|||ShapeshifterDeathtouchToken| +|Generate|TOK:DSC|Shark|||SharkToken| +|Generate|TOK:DSC|Spider|||SpiderToken| +|Generate|TOK:DSC|Treefolk|||WrennAndSevenTreefolkToken| +|Generate|TOK:DSC|Wurm|1||Wurm55Token| +|Generate|TOK:DSC|Wurm|2||WurmWithTrampleToken| + # FDN |Generate|TOK:FDN|Beast|1||BeastToken| |Generate|TOK:FDN|Beast|2||BeastToken2| -- 2.47.2 From 5fcc037caed48871889da794ac0a3634bfd2dd2f Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:04:28 -0500 Subject: [PATCH 08/28] [ACR] Implement Kassandra, Eagle Bearer --- .../mage/cards/k/KassandraEagleBearer.java | 161 ++++++++++++++++++ Mage.Sets/src/mage/sets/AssassinsCreed.java | 1 + 2 files changed, 162 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java diff --git a/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java b/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java new file mode 100644 index 00000000000..c1769f27084 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java @@ -0,0 +1,161 @@ +package mage.cards.k; + +import java.util.Objects; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.*; +import mage.constants.*; +import mage.abilities.keyword.HasteAbility; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author Grath + */ +public final class KassandraEagleBearer extends CardImpl { + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(KassandraEagleBearerPredicate.instance); + } + + public KassandraEagleBearer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When Kassandra enters the battlefield, search your graveyard, hand, and library for a card named The Spear of Leonidas, put it onto the battlefield, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new KassandraEagleBearerEffect(), false)); + + // Whenever a creature you control with a legendary Equipment attached to it deals combat damage to a player, draw a card. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(new DrawCardSourceControllerEffect(1), + filter, false, SetTargetPointer.NONE, true).setTriggerPhrase( + "Whenever a creature you control with a legendary Equipment attached to it deals combat damage to a player, ")); + } + + private KassandraEagleBearer(final KassandraEagleBearer card) { + super(card); + } + + @Override + public KassandraEagleBearer copy() { + return new KassandraEagleBearer(this); + } +} + +class KassandraEagleBearerEffect extends OneShotEffect { + private static final String spearName = "The Spear of Leonidas"; + + KassandraEagleBearerEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "search your graveyard, hand and/or library for a card named The Spear of Leonidas," + + " put it onto the battlefield, then shuffle."; + } + + private KassandraEagleBearerEffect(final KassandraEagleBearerEffect effect) { + super(effect); + } + + @Override + public KassandraEagleBearerEffect copy() { + return new KassandraEagleBearerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Card spearCard = null; + FilterCard filter = new FilterCard("card named The Spear of Leonidas"); + filter.add(new NamePredicate(spearName)); + TargetCardInLibrary libraryTarget = new TargetCardInLibrary(filter); + if (controller.searchLibrary(libraryTarget, source, game)) { + for (UUID id : libraryTarget.getTargets()) { + spearCard = game.getCard(id); + } + } + + // Hand is a hidden zone - you may fail to find a Spear of Leonidas that's in your hand. + // 701.19b. If a player is searching a hidden zone for cards with a stated quality, such as a card with a + // certain card type or color, that player isn't required to find some or all of those cards even if they're + // present in that zone. + // This is true even if your hand is revealed: + // 400.2. ... Hidden zones are zones in which not all players can be expected to see the cards' faces. + // Library and hand are hidden zones, even if all the cards in one such zone happen to be revealed. + if (spearCard == null) { + FilterCard filter2 = new FilterCard("card from your hand named The Spear of Leonidas"); + filter2.add(new NamePredicate(spearName)); + TargetCard target = new TargetCard(0, 1, Zone.HAND, filter2); + target.withNotTarget(true); + Cards cards = new CardsImpl(); + cards.addAllCards(controller.getHand().getCards(filter, source.getControllerId(), source, game)); + if (!cards.isEmpty()) { + controller.choose(outcome, cards, target, source, game); + for (UUID id : target.getTargets()) { + spearCard = game.getCard(id); + } + } + } + + // You cannot fail to find a spear if there is one in your graveyard, because the graveyard is not hidden. + if (spearCard == null) { + TargetCard target = new TargetCard(1, 1, Zone.GRAVEYARD, filter); + target.withNotTarget(true); + Cards cards = new CardsImpl(); + cards.addAllCards(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game)); + if (!cards.isEmpty()) { + controller.choose(outcome, cards, target, source, game); + for (UUID id : target.getTargets()) { + spearCard = game.getCard(id); + } + } + } + + if (spearCard != null) { + controller.moveCards(spearCard, Zone.BATTLEFIELD, source, game); + } + controller.shuffleLibrary(source, game); + return true; + } +} + +enum KassandraEagleBearerPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + return input.getAttachments() + .stream() + .map(game::getPermanentOrLKIBattlefield) + .filter(Objects::nonNull) + .anyMatch(attachment -> attachment.hasSubtype(SubType.EQUIPMENT, game) && attachment.isLegendary()); + } + + @Override + public String toString() { + return "creature you control with a legendary Equipment attached to it"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/AssassinsCreed.java b/Mage.Sets/src/mage/sets/AssassinsCreed.java index 09f13e42ce4..4800ca335fe 100644 --- a/Mage.Sets/src/mage/sets/AssassinsCreed.java +++ b/Mage.Sets/src/mage/sets/AssassinsCreed.java @@ -84,6 +84,7 @@ public final class AssassinsCreed extends ExpansionSet { cards.add(new SetCardInfo("Hunter's Bow", 41, Rarity.UNCOMMON, mage.cards.h.HuntersBow.class)); cards.add(new SetCardInfo("Island", 103, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Jackdaw", 58, Rarity.RARE, mage.cards.j.Jackdaw.class)); + cards.add(new SetCardInfo("Kassandra, Eagle Bearer", 59, Rarity.MYTHIC, mage.cards.k.KassandraEagleBearer.class)); cards.add(new SetCardInfo("Keen-Eyed Raven", 279, Rarity.UNCOMMON, mage.cards.k.KeenEyedRaven.class)); cards.add(new SetCardInfo("Labyrinth Adversary", 290, Rarity.UNCOMMON, mage.cards.l.LabyrinthAdversary.class)); cards.add(new SetCardInfo("Leonardo da Vinci", 20, Rarity.MYTHIC, mage.cards.l.LeonardoDaVinci.class)); -- 2.47.2 From 9ba12d13d2e84e754faf1ac40da23c61fa705226 Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:52:48 -0500 Subject: [PATCH 09/28] Update Kassandra, Eagle Bearer to reduce player choose dialogues from three to two. --- .../mage/cards/k/KassandraEagleBearer.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java b/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java index c1769f27084..fb19218dd2d 100644 --- a/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java +++ b/Mage.Sets/src/mage/cards/k/KassandraEagleBearer.java @@ -1,6 +1,7 @@ package mage.cards.k; import java.util.Objects; +import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; @@ -98,36 +99,30 @@ class KassandraEagleBearerEffect extends OneShotEffect { } } - // Hand is a hidden zone - you may fail to find a Spear of Leonidas that's in your hand. - // 701.19b. If a player is searching a hidden zone for cards with a stated quality, such as a card with a - // certain card type or color, that player isn't required to find some or all of those cards even if they're - // present in that zone. - // This is true even if your hand is revealed: - // 400.2. ... Hidden zones are zones in which not all players can be expected to see the cards' faces. - // Library and hand are hidden zones, even if all the cards in one such zone happen to be revealed. if (spearCard == null) { FilterCard filter2 = new FilterCard("card from your hand named The Spear of Leonidas"); filter2.add(new NamePredicate(spearName)); - TargetCard target = new TargetCard(0, 1, Zone.HAND, filter2); - target.withNotTarget(true); - Cards cards = new CardsImpl(); - cards.addAllCards(controller.getHand().getCards(filter, source.getControllerId(), source, game)); - if (!cards.isEmpty()) { - controller.choose(outcome, cards, target, source, game); - for (UUID id : target.getTargets()) { - spearCard = game.getCard(id); - } + Cards spears = new CardsImpl(); + spears.addAllCards(controller.getHand().getCards(filter, source.getControllerId(), source, game)); + Set spearsInGraveyard = controller.getGraveyard().getCards(filter, source.getControllerId(), source, game); + TargetCard target; + if (spearsInGraveyard.isEmpty()) { + // Hand is a hidden zone - you may fail to find a Spear of Leonidas that's in your hand. + // 701.19b. If a player is searching a hidden zone for cards with a stated quality, such as a card with a + // certain card type or color, that player isn't required to find some or all of those cards even if they're + // present in that zone. + // This is true even if your hand is revealed: + // 400.2. ... Hidden zones are zones in which not all players can be expected to see the cards' faces. + // Library and hand are hidden zones, even if all the cards in one such zone happen to be revealed. + target = new TargetCard(0, 1, Zone.HAND, filter); + } else { + spears.addAllCards(spearsInGraveyard); + // You cannot fail to find a spear if there is one in your graveyard, because the graveyard is not hidden. + target = new TargetCard(1, 1, Zone.HAND, filter); } - } - - // You cannot fail to find a spear if there is one in your graveyard, because the graveyard is not hidden. - if (spearCard == null) { - TargetCard target = new TargetCard(1, 1, Zone.GRAVEYARD, filter); target.withNotTarget(true); - Cards cards = new CardsImpl(); - cards.addAllCards(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game)); - if (!cards.isEmpty()) { - controller.choose(outcome, cards, target, source, game); + if (!spears.isEmpty()) { + controller.choose(outcome, spears, target, source, game); for (UUID id : target.getTargets()) { spearCard = game.getCard(id); } -- 2.47.2 From 29bab5f6140cc5e7132e976f501be0ad76054d42 Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:26:29 -0500 Subject: [PATCH 10/28] Fix Tribute to the World Tree to still draw a card if the creature has died before the ability resolves. --- Mage.Sets/src/mage/cards/t/TributeToTheWorldTree.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/t/TributeToTheWorldTree.java b/Mage.Sets/src/mage/cards/t/TributeToTheWorldTree.java index 42ffe0a780e..202812dd81e 100644 --- a/Mage.Sets/src/mage/cards/t/TributeToTheWorldTree.java +++ b/Mage.Sets/src/mage/cards/t/TributeToTheWorldTree.java @@ -63,7 +63,7 @@ class TributeToTheWorldTreeEffect extends OneShotEffect { } // We need to ask the game for the actualized object for the entering permanent. - Permanent permanent = game.getPermanent(permanentEntering.getId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(permanentEntering.getId()); if (permanent == null) { return false; } -- 2.47.2 From 3f79ffa21ae8978a4eaa2854aa7d6e4d2bce9acf Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 22 Jan 2025 19:06:05 +0400 Subject: [PATCH 11/28] refactor: improved cards hints support for combined triggers like OrTriggeredAbility --- .../UntilYourNextTurnDelayedTriggeredAbility.java | 9 +++++++++ .../ConditionalInterveningIfTriggeredAbility.java | 9 +++++++++ .../abilities/decorator/ConditionalTriggeredAbility.java | 9 +++++++++ .../java/mage/abilities/meta/OrTriggeredAbility.java | 8 ++++++++ 4 files changed, 35 insertions(+) diff --git a/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java index 33f9a066f40..86c873bdf00 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java @@ -8,6 +8,7 @@ import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.abilities.hint.Hint; import mage.constants.Duration; import mage.constants.EffectType; import mage.game.Game; @@ -15,6 +16,7 @@ import mage.game.events.GameEvent; import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.ArrayList; import java.util.List; /** @@ -86,6 +88,13 @@ public class UntilYourNextTurnDelayedTriggeredAbility extends DelayedTriggeredAb ability.addWatcher(watcher); } + @Override + public List getHints() { + List res = new ArrayList<>(super.getHints()); + res.addAll(ability.getHints()); + return res; + } + @Override public Effects getEffects(Game game, EffectType effectType) { return ability.getEffects(game, effectType); diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java index ab4e86f5d4d..6a5245ccc44 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java @@ -7,6 +7,7 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.Condition; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.abilities.hint.Hint; import mage.constants.EffectType; import mage.constants.Zone; import mage.game.Game; @@ -14,6 +15,7 @@ import mage.game.events.GameEvent; import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.ArrayList; import java.util.List; /** @@ -111,6 +113,13 @@ public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityIm ability.addWatcher(watcher); } + @Override + public List getHints() { + List res = new ArrayList<>(super.getHints()); + res.addAll(ability.getHints()); + return res; + } + @Override public Effects getEffects(Game game, EffectType effectType) { return ability.getEffects(game, effectType); diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java index 4a2b89ce8f5..0eda93cf9e1 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java @@ -8,12 +8,14 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.Condition; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.abilities.hint.Hint; import mage.constants.EffectType; import mage.game.Game; import mage.game.events.GameEvent; import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.ArrayList; import java.util.List; /** @@ -106,6 +108,13 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { ability.addWatcher(watcher); } + @Override + public List getHints() { + List res = new ArrayList<>(super.getHints()); + res.addAll(ability.getHints()); + return res; + } + @Override public Effects getEffects(Game game, EffectType effectType) { return ability.getEffects(game, effectType); diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java index 2342564f662..b3d2851fb42 100644 --- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java @@ -5,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.abilities.hint.Hint; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -126,6 +127,13 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { } } + @Override + public List getHints() { + List res = new ArrayList<>(super.getHints()); + this.triggeredAbilities.forEach(a -> res.addAll(a.getHints())); + return res; + } + @Override public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { boolean res = false; -- 2.47.2 From e6ae7e9114e567cae2b7af2a2e4123fab7ab4fc6 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 22 Jan 2025 19:35:43 +0400 Subject: [PATCH 12/28] refactor: fixed wrong copy code of some fields --- Mage/src/main/java/mage/abilities/AbilityImpl.java | 6 +++--- Mage/src/main/java/mage/players/PlayerImpl.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index e965fadc827..114e88343f5 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -116,7 +116,7 @@ public abstract class AbilityImpl implements Ability { this.manaCosts = ability.manaCosts.copy(); this.manaCostsToPay = ability.manaCostsToPay.copy(); this.costs = ability.costs.copy(); - this.watchers = CardUtil.deepCopyObject(ability.getWatchers()); + this.watchers = CardUtil.deepCopyObject(ability.watchers); this.subAbilities = CardUtil.deepCopyObject(ability.subAbilities); this.modes = ability.getModes().copy(); @@ -131,8 +131,8 @@ public abstract class AbilityImpl implements Ability { this.canFizzle = ability.canFizzle; this.targetAdjuster = ability.targetAdjuster; this.costAdjuster = ability.costAdjuster; - this.hints = CardUtil.deepCopyObject(ability.getHints()); - this.icons = CardUtil.deepCopyObject(ability.getIcons()); + this.hints = CardUtil.deepCopyObject(ability.hints); + this.icons = CardUtil.deepCopyObject(ability.icons); this.customOutcome = ability.customOutcome; this.identifier = ability.identifier; this.activated = ability.activated; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index fc1a1ad0f51..4afac403234 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -366,7 +366,7 @@ public abstract class PlayerImpl implements Player, Serializable { this.canPlotFromTopOfLibrary = player.canPlotFromTopOfLibrary(); this.drawsFromBottom = player.isDrawsFromBottom(); this.drawsOnOpponentsTurn = player.isDrawsOnOpponentsTurn(); - this.alternativeSourceCosts = CardUtil.deepCopyObject(player.getAlternativeSourceCosts()); + this.alternativeSourceCosts = CardUtil.deepCopyObject(((PlayerImpl) player).alternativeSourceCosts); this.topCardRevealed = player.isTopCardRevealed(); -- 2.47.2 From 383e0a44b41427694bcb571504c76a1b2318b426 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:07:27 -0500 Subject: [PATCH 13/28] [DFT] update spoiler and reprints --- Mage.Sets/src/mage/sets/Aetherdrift.java | 16 +++++ Utils/mtg-cards-data.txt | 76 ++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 96f17a52775..341bc28532d 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -21,8 +21,24 @@ public final class Aetherdrift extends ExpansionSet { this.hasBasicLands = false; // temporary this.hasBoosters = false; // temporary + cards.add(new SetCardInfo("Bloodfell Caves", 251, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); + cards.add(new SetCardInfo("Bloodghast", 77, Rarity.RARE, mage.cards.b.Bloodghast.class)); + cards.add(new SetCardInfo("Blossoming Sands", 252, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); cards.add(new SetCardInfo("Brightglass Gearhulk", 191, Rarity.MYTHIC, mage.cards.b.BrightglassGearhulk.class)); cards.add(new SetCardInfo("Daretti, Rocketeer Engineer", 120, Rarity.RARE, mage.cards.d.DarettiRocketeerEngineer.class)); + cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Earthrumbler", 160, Rarity.UNCOMMON, mage.cards.e.Earthrumbler.class)); + cards.add(new SetCardInfo("Forest", 289, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 280, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jungle Hollow", 256, Rarity.COMMON, mage.cards.j.JungleHollow.class)); + cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rugged Highlands", 262, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); + cards.add(new SetCardInfo("Scoured Barrens", 263, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); + cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swiftwater Cliffs", 265, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); + cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); + cards.add(new SetCardInfo("Tranquil Cove", 267, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index a0c47159601..d9cc3128301 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -55969,9 +55969,85 @@ Marshland Hordemaster|Alchemy: Bloomburrow|27|R|{1}{B}{R}|Creature - Lizard Warl Recruit Instructor|Alchemy: Bloomburrow|28|M|{R}{W}|Creature - Mouse Warrior|1|1|Whenever one or more Mice you control attack, draft a card from Recruit Instructor's spellbook.$Valiant -- Whenever Recruit Instructor becomes the target of a spell or ability you control for the first time each turn, create a 1/1 white Mouse creature token.| Resourceful Collector|Alchemy: Bloomburrow|29|R|{1}{R}{G}|Creature Raccoon Druid|3|3|Haste$At the beginning of your end step, a random non-Food permanent card in your graveyard perpetually becomes a Food artifact in addition to its other types and gains "{2}, Exile this artifact: You gain 3 life." You may play that card for as long as it's in your graveyard.| Thought Rattle|Alchemy: Bloomburrow|30|R|{U}{B}|Sorcery|||Target opponent reveals each nonland card in their hand. You choose one of those cards. Exile that card.$Threshold -- If seven or more cards are in your graveyard, seek a Rat card. It perpetually gains "This spell costs to cast."| +Air Response Unit|Aetherdrift|1|U|{2}{W}|Artifact - Vehicle|3|3|Flying, vigilance$Crew 1| +Basri, Tomorrow's Champion|Aetherdrift|3|R|{W}|Legendary Creature - Human Knight|2|1|{W}, {T}, Exert Basri: Create a 1/1 white Cat creature token with lifelink.$Cycling {2}{W}$When you cycle this card, Cats you control gain hexproof and indestructible until end of turn.| +Bulwark Ox|Aetherdrift|7|R|{1}{W}|Creature - Ox Mount|2|2|Whenever this creature attacks while saddled, put a +1/+1 counter on target creature.$Sacrifice this creature: Creatures you control with counters on them gain hexproof and indestructible until end of turn.$Saddle 1| +Lightshield Parry|Aetherdrift|19|C|{W}|Instant|||Target creature gets +2/+2 until end of turn.$Cycling {2}| +Valor's Flagship|Aetherdrift|35|M|{4}{W}{W}{W}|Legendary Artifact - Vehicle|7|7|Flying, first strike, lifelink$Crew 3$Cycling {X}{2}{W}$When you cycle this card, create X 1/1 colorless Pilot creature tokens with "This token saddles Mounts and crews Vehicles as though its power were 2 greater."| +Hulldrifter|Aetherdrift|47|C|{3}{U}{U}|Artifact - Vehicle|3|2|Flying$When this Vehicle enters, draw two cards.$Crew 3| +Midnight Mangler|Aetherdrift|50|C|{1}{U}|Artifact - Vehicle|3|3|During turns other than yours, this Vehicle is an artifact creature.$Crew 2| +Repurposing Bay|Aetherdrift|56|R|{2}{U}|Artifact|||{2}, {T}, Sacrifice another artifact: Search your library for an artifact card with mana value equal to 1 plus the sacrificed artifact's mana value, put that card onto the battlefield, then shuffle. Activate only as a sorcery.| +Vnwxt, Verbose Host|Aetherdrift|73|R|{1}{U}|Legendary Creature - Homunculus|0|4|Start your engines!$You have no maximum hand size.$Max speed -- If you would draw a card, draw two cards instead.| +Bloodghast|Aetherdrift|77|R|{B}{B}|Creature - Vampire Spirit|2|1|Bloodghast can't block.$Bloodghast has haste as long as an opponent has 10 or less life.$Landfall -- Whenever a land you control enters, you may return Bloodghast from your graveyard to the battlefield.| +Cryptcaller Chariot|Aetherdrift|80|R|{3}{B}|Artifact - Vehicle|5|5|Menace$Whenever you discard one or more cards, create that many tapped 2/2 black Zombie creature tokens.$Crew 2| +The Last Ride|Aetherdrift|94|M|{B}|Legendary Artifact - Vehicle|13|13|The Last Ride gets -X/-X, where X is your life total.${2}{B}, Pay 2 life: Draw a card.$Crew 2| +Quag Feast|Aetherdrift|100|R|{1}{B}|Sorcery|||Choose target creature, planeswalker, or Vehicle. Mill two cards, then destroy the chosen permanent if its mana value is less than or equal to the number of cards in your graveyard.| +Streaking Oilgorger|Aetherdrift|107|C|{4}{B}|Creature - Vampire|3|3|Flying, haste$Start your engines!$Max speed -- This creature has lifelink.| +Boommobile|Aetherdrift|113|R|{2}{R}{R}|Artifact - Vehicle|5|5|When this Vehicle enters, add four mana of any one color. Spend this mana only to activate abilities.$Exhaust -- {X}{2}{R}: This Vehicle deals X damage to any target. Put a +1/+1 counter on this Vehicle.$Crew 2| +Chandra, Spark Hunter|Aetherdrift|116|M|{3}{R}|Legendary Planeswalker - Chandra|4|At the beginning of combat on your turn, choose up to one target Vehicle you control. Until end of turn, it becomes an artifact creature and gains haste.$+2: You may sacrifice an artifact or discard a card. If you do, draw a card.$+0: Create a 3/2 colorless Vehicle artifact token with crew 1.$-7: You get an emblem with "Whenever an artifact you control enters, this emblem deals 3 damage to any target."| Daretti, Rocketeer Engineer|Aetherdrift|120|R|{4}{R}|Legendary Creature - Goblin Artificer|*|5|Daretti's power is equal to the greatest mana value among artifacts you control.$Whenever Daretti enters or attacks, choose target artifact card in your graveyard. You may sacrifice an artifact. If you do, return the chosen card to the battlefield.| +Draconautics Engineer|Aetherdrift|121|R|{1}{R}|Creature - Goblin Artificer|2|2|Exhaust -- {R}: Other creatures you control gain haste until end of turn. Put a +1/+1 counter on this creature.$Exhaust -- {3}{R}: Create a 4/4 red Dinosaur Dragon creature token with flying.| +Hazoret, Godseeker|Aetherdrift|133|M|{1}{R}|Legendary Creature - God|5|3|Indestructible, haste$Start your engines!${1}, {T}: Target creature with power 2 or less can't be blocked this turn.$Hazoret can't attack or block unless you have max speed.| +Prowcatcher Specialist|Aetherdrift|142|C|{1}{R}|Creature - Goblin Warrior|2|1|Haste$Exhaust -- {3}{R}: Put two +1/+1 counters on this creature.| +Agonasaur Rex|Aetherdrift|151|R|{3}{G}{G}|Creature - Dinosaur|8|8|Trample$Cycling {2}{G}$When you cycle this card, put two +1/+1 counters on up to one target creature or Vehicle. It gains trample and indestructible until end of turn.| Earthrumbler|Aetherdrift|160|U|{4}{G}|Artifact - Vehicle|7|6|Vigilance, trample$Exile an artifact or creature card from your graveyard: This Vehicle becomes an artifact creature until end of turn.$Crew 3| +Elvish Refueler|Aetherdrift|161|U|{2}{G}|Creature - Elf Druid|2|3|During your turn, as long as you haven't activated an exhaust ability this turn, you may activate exhaust abilities as though they haven't been activated.$Exhaust -- {1}{G}: Put a +1/+1 counter on this creature.| +Thunderous Velocipede|Aetherdrift|183|M|{1}{G}{G}|Artifact - Vehicle|5|5|Trample$Each other Vehicle and creature you control enters with an additional +1/+1 counter on it if its mana value is 4 or less. Otherwise, it enters with three additional +1/+1 counters on it.$Crew 3| +Venomsac Lagac|Aetherdrift|185|C|{1}{G}|Creature - Lizard Mount|2|1|Deathtouch$Whenever this creature attacks while saddled, it gets +0/+3 until end of turn.$Saddle 2| +Aatchik, Emerald Radian|Aetherdrift|187|R|{3}{B}{B}{G}|Legendary Creature - Insect Druid|3|3|When Aatchik enters, create a 1/1 green Insect creature token for each artifact and/or creature card in your graveyard.$Whenever another Insect you control dies, put a +1/+1 counter on Aatchik. Each opponent loses 1 life.| +Apocalypse Runner|Aetherdrift|188|U|{2}{B}{R}|Artifact - Vehicle|6|5|{T}: Target creature you control with power 2 or less gains lifelink until end of turn and can't be blocked this turn.$Crew 3| +Boosted Sloop|Aetherdrift|190|U|{1}{U}{R}|Artifact - Vehicle|3|3|Menace$Whenever you attack, draw a card, then discard a card.$Crew 1| Brightglass Gearhulk|Aetherdrift|191|M|{G}{G}{W}{W}|Artifact Creature - Construct|4|4|First strike, trample$When this creature enters, you may search your library for up to two artifact, creature, and/or enchantment cards with mana value 1 or less, reveal them, put them into your hand, then shuffle.| +Captain Howler, Sea Scourge|Aetherdrift|194|R|{2}{U}{R}|Legendary Creature - Shark Pirate|5|4|Ward--{2}, Pay 2 life.$Whenever you discard one or more cards, target creature gets +2/+0 until end of turn for each card discarded this way. Whenever that creature deals combat damage to a player this turn, you draw a card.| +Caradora, Heart of Alacria|Aetherdrift|195|R|{2}{G}{W}|Legendary Creature - Human Knight|4|2|When Caradora enters, you may search your library for a Mount or Vehicle card, reveal it, put it into your hand, then shuffle.$If one or more +1/+1 counters would be put on a creature or Vehicle you control, that many plus one +1/+1 counters are put on it instead.| +Cloudspire Skycycle|Aetherdrift|197|U|{2}{R}{W}|Artifact - Vehicle|2|3|Flying$When this Vehicle enters, distribute two +1/+1 counters among one or two other target Vehicles and/or creatures you control.$Crew 1| +Far Fortune, End Boss|Aetherdrift|203|R|{2}{B}{R}|Legendary Creature - Human Mercenary|4|5|Start your engines!$Whenever you attack, Far Fortune deals 1 damage to each opponent.$Max speed -- If a source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus 1 instead.| +Guidelight Pathmaker|Aetherdrift|206|U|{4}{W}{U}|Artifact - Vehicle|6|5|Vigilance$When this Vehicle enters, you may search your library for an artifact card and reveal it. Put it onto the battlefield if its mana value is 2 or less. Otherwise, put it into your hand. Then shuffle.$Crew 2| +Kolodin, Triumph Caster|Aetherdrift|210|R|{R}{W}|Legendary Creature - Human Pilot|2|3|Mounts and Vehicles you control have haste.$Whenever a Mount you control enters, it becomes saddled until end of turn.$Whenever a Vehicle you control enters, it becomes an artifact creature until end of turn.| +Lagorin, Soul of Alacria|Aetherdrift|211|U|{G}{W}|Legendary Creature - Beast Mount|1|1|Flying$Whenever Lagorin attacks while saddled, put a +1/+1 counter on each of up to two target Mounts and/or Vehicles.$Saddle 1| +Loot, the Pathfinder|Aetherdrift|212|M|{2}{G}{U}{R}|Legendary Creature - Beast Noble|2|4|Double strike, vigilance, haste$Exhaust -- {G}, {T}: Add three mana of any one color.$Exhaust -- {U}, {T}: Draw three cards.$Exhaust -- {R}, {T}: Loot deals 3 damage to any target.| +Mendicant Core, Guidelight|Aetherdrift|213|R|{W}{U}|Legendary Artifact Creature - Robot|*|3|Mendicant Core's power is equal to the number of artifacts you control.$Start your engines!$Max speed -- Whenever you cast an artifact spell, you may pay {1}. If you do, copy it.| +Oildeep Gearhulk|Aetherdrift|215|M|{U}{U}{B}{B}|Artifact Creature - Construct|4|4|Lifelink, ward {1}$When this creature enters, look at target player's hand. You may choose a card from it. If you do, that player discards that card, then draws a card.| +Pyrewood Gearhulk|Aetherdrift|216|M|{2}{R}{R}{G}{G}|Artifact Creature - Construct|7|7|Vigilance, menace$When this creature enters, other creatures you control get +2/+2 and gain vigilance and menace until end of turn. Damage can't be prevented this turn.| +Rangers' Aetherhive|Aetherdrift|217|U|{1}{G}{U}|Artifact - Vehicle|3|5|Vigilance$Whenever you activate an exhaust ability, create a 1/1 colorless Thopter artifact creature token with flying.$Crew 1| +Redshift, Rocketeer Chief|Aetherdrift|218|R|{R}{G}|Legendary Creature - Goblin Pilot|2|3|Vigilance${T}: Add X mana of any one color, where X is Redshift's power. Spend this mana only to activate abilities.$Exhaust -- {10}{R}{G}: Put any number of permanent cards from your hand onto the battlefield.| +Rocketeer Boostbuggy|Aetherdrift|220|U|{R}{G}|Artifact - Vehicle|3|2|Whenever this Vehicle attacks, create a Treasure token.$Exhaust -- {3}: This Vehicle becomes an artifact creature. Put a +1/+1 counter on it.$Crew 1| +Sab-Sunen, Luxa Embodied|Aetherdrift|221|M|{3}{G}{U}|Legendary Creature - God|6|6|Reach, trample, indestructible$Sab-Sunen can't attack or block unless it has an even number of counters on it.$At the beginning of your first main phase, put a +1/+1 counter on Sab-Sunen. Then if it has an odd number of counters on it, draw two cards.| +Sita Varma, Masked Racer|Aetherdrift|223|R|{G}{U}|Legendary Creature - Human Rogue|2|3|Exhaust -- {X}{G}{G}{U}: Put X +1/+1 counters on Sita Varma. Then you may have the base power and toughness of each other creature you control become equal to Sita Varma's power until end of turn.| +Winter, Cursed Rider|Aetherdrift|228|R|{U}{B}|Legendary Creature - Human Warlock|3|2|Ward--Pay 2 life.$Artifacts you control have "Ward--Pay 2 life."$Exhaust -- {2}{U}{B}, {T}, Exile X artifact cards from your graveyard: Each other nonartifact creature gets -X/-X until end of turn.| +Zahur, Glory's Past|Aetherdrift|229|R|{W}{B}|Legendary Creature - Zombie Cat Warrior|3|2|Start your engines!$Sacrifice another creature: Surveil 1. Activate only once each turn.$Max speed -- Whenever a nontoken creature you control dies, create a tapped 2/2 black Zombie creature token.| +The Aetherspark|Aetherdrift|231|M|{4}|Legendary Artifact Planeswalker - Equipment|4|As long as The Aetherspark is attached to a creature, The Aetherspark can't be attacked and has "Whenever equipped creature deals combat damage during your turn, put that many loyalty counters on The Aetherspark."$+1: Attach The Aetherspark to up to one target creature you control. Put a +1/+1 counter on that creature.$-5: Draw two cards.$-10: Add ten mana of any one color.| +Lifecraft Engine|Aetherdrift|234|R|{3}|Artifact - Vehicle|4|4|As this Vehicle enters, choose a creature type.$Vehicle creatures you control are the chosen creature type in addition to their other types.$Each creature you control of the chosen type other than this Vehicle gets +1/+1.$Crew 3| +Starting Column|Aetherdrift|244|C|{3}|Artifact|||Start your engines!${T}: Add one mana of any color.$Max speed -- {T}, Sacrifice this artifact: Draw two cards, then discard a card.| +Amonkhet Raceway|Aetherdrift|248|U||Land|||Start your engines!${T}: Add {C}.$Max speed -- {T}: Target creature gains haste until end of turn.| +Avishkar Raceway|Aetherdrift|249|C||Land|||Start your engines!${T}: Add {C}.$Max speed -- {3}, {T}, Discard a card: Draw a card.| +Bleachbone Verge|Aetherdrift|250|R||Land|||{T}: Add {B}.${T}: Add {W}. Activate only if you control a Plains or a Swamp.| +Bloodfell Caves|Aetherdrift|251|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {B} or {R}.| +Blossoming Sands|Aetherdrift|252|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {G} or {W}.| +Country Roads|Aetherdrift|253|U||Land|||This land enters tapped unless you control a Mount or Vehicle.${T}: Add {W}.${1}{W}, {T}, Sacrifice this land: Create a 1/1 colorless Pilot creature token with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." Activate only as a sorcery.| +Dismal Backwater|Aetherdrift|254|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {U} or {B}.| +Foul Roads|Aetherdrift|255|U||Land|||This land enters tapped unless you control a Mount or Vehicle.${T}: Add {B}.${1}{B}, {T}, Sacrifice this land: Create a 1/1 colorless Pilot creature token with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." Activate only as a sorcery.| +Jungle Hollow|Aetherdrift|256|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {B} or {G}.| +Muraganda Raceway|Aetherdrift|257|R||Land|||Start your engines!${T}: Add {C}.$Max speed -- {T}: Add {C}{C}.| +Night Market|Aetherdrift|258|C||Land|||This land enters tapped. As it enters, choose a color.${T}: Add one mana of the chosen color.$Cycling {3}| +Reef Roads|Aetherdrift|259|U||Land|||This land enters tapped unless you control a Mount or Vehicle.${T}: Add {U}.${1}{U}, {T}, Sacrifice this land: Create a 1/1 colorless Pilot creature token with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." Activate only as a sorcery.| +Riverpyre Verge|Aetherdrift|260|R||Land|||{T}: Add {R}.${T}: Add {U}. Activate only if you control an Island or a Mountain.| +Rocky Roads|Aetherdrift|261|U||Land|||This land enters tapped unless you control a Mount or Vehicle.${T}: Add {R}.${1}{R}, {T}, Sacrifice this land: Create a 1/1 colorless Pilot creature token with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." Activate only as a sorcery.| +Rugged Highlands|Aetherdrift|262|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {R} or {G}.| +Scoured Barrens|Aetherdrift|263|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {W} or {B}.| +Sunbillow Verge|Aetherdrift|264|R||Land|||{T}: Add {W}.${T}: Add {R}. Activate only if you control a Mountain or a Plains.| +Swiftwater Cliffs|Aetherdrift|265|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {U} or {R}.| +Thornwood Falls|Aetherdrift|266|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {G} or {U}.| +Tranquil Cove|Aetherdrift|267|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {W} or {U}.| +Wastewood Verge|Aetherdrift|268|R||Land|||{T}: Add {G}.${T}: Add {B}. Activate only if you control a Swamp or a Forest.| +Wild Roads|Aetherdrift|269|U||Land|||This land enters tapped unless you control a Mount or Vehicle.${T}: Add {G}.${1}{G}, {T}, Sacrifice this land: Create a 1/1 colorless Pilot creature token with "This token saddles Mounts and crews Vehicles as though its power were 2 greater." Activate only as a sorcery.| +Willowrush Verge|Aetherdrift|270|R||Land|||{T}: Add {U}.${T}: Add {G}. Activate only if you control a Forest or an Island.| +Wind-Scarred Crag|Aetherdrift|271|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {R} or {W}.| +Plains|Aetherdrift|272|C||Basic Land - Plains|||({T}: Add {W}.)| +Swamp|Aetherdrift|274|C||Basic Land - Swamp|||({T}: Add {B}.)| +Island|Aetherdrift|280|C||Basic Land - Island|||({T}: Add {U}.)| +Mountain|Aetherdrift|286|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Aetherdrift|289|C||Basic Land - Forest|||({T}: Add {G}.)| Dawnwing Marshal|Foundations Jumpstart|1|U|{1}{W}|Creature - Cat Soldier|2|2|Flying${4}{W}: Creatures you control get +1/+1 until end of turn.| Eidolon of Astral Winds|Foundations Jumpstart|2|R|{2}{W}|Enchantment Creature - Spirit|2|4|Vigilance$Constellation -- Whenever Eidolon of Astral Winds or another enchantment you control enters, choose target creature you control. Until end of turn, that creature has base power and toughness 4/4 and gains flying.| Faithful Pikemaster|Foundations Jumpstart|3|C|{3}{W}|Creature - Rhino Monk Soldier|3|4|When Faithful Pikemaster enters, scry 2.$As long as it's your turn, Faithful Pikemaster has first strike.| -- 2.47.2 From 6cac369573b5c4d2bf14807d11e5ba84fe9d8ba9 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:09:08 -0500 Subject: [PATCH 14/28] [DFT] Implement Air Response Unit --- .../src/mage/cards/a/AirResponseUnit.java | 44 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AirResponseUnit.java diff --git a/Mage.Sets/src/mage/cards/a/AirResponseUnit.java b/Mage.Sets/src/mage/cards/a/AirResponseUnit.java new file mode 100644 index 00000000000..bbf6752e521 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirResponseUnit.java @@ -0,0 +1,44 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.keyword.CrewAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AirResponseUnit extends CardImpl { + + public AirResponseUnit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private AirResponseUnit(final AirResponseUnit card) { + super(card); + } + + @Override + public AirResponseUnit copy() { + return new AirResponseUnit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 341bc28532d..5966ef803d6 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -21,6 +21,7 @@ public final class Aetherdrift extends ExpansionSet { this.hasBasicLands = false; // temporary this.hasBoosters = false; // temporary + cards.add(new SetCardInfo("Air Response Unit", 1, Rarity.UNCOMMON, mage.cards.a.AirResponseUnit.class)); cards.add(new SetCardInfo("Bloodfell Caves", 251, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); cards.add(new SetCardInfo("Bloodghast", 77, Rarity.RARE, mage.cards.b.Bloodghast.class)); cards.add(new SetCardInfo("Blossoming Sands", 252, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); -- 2.47.2 From 1a33b564402391d702a5a5fd30da013024424ef2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:10:23 -0500 Subject: [PATCH 15/28] [DFT] Implement Boosted Sloop --- Mage.Sets/src/mage/cards/b/BoostedSloop.java | 47 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BoostedSloop.java diff --git a/Mage.Sets/src/mage/cards/b/BoostedSloop.java b/Mage.Sets/src/mage/cards/b/BoostedSloop.java new file mode 100644 index 00000000000..10a7c280b27 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoostedSloop.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoostedSloop extends CardImpl { + + public BoostedSloop(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}{R}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever you attack, draw a card, then discard a card. + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new DrawDiscardControllerEffect(1, 1), 1 + )); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private BoostedSloop(final BoostedSloop card) { + super(card); + } + + @Override + public BoostedSloop copy() { + return new BoostedSloop(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 5966ef803d6..5e70d4008de 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -25,6 +25,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Bloodfell Caves", 251, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); cards.add(new SetCardInfo("Bloodghast", 77, Rarity.RARE, mage.cards.b.Bloodghast.class)); cards.add(new SetCardInfo("Blossoming Sands", 252, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); + cards.add(new SetCardInfo("Boosted Sloop", 190, Rarity.UNCOMMON, mage.cards.b.BoostedSloop.class)); cards.add(new SetCardInfo("Brightglass Gearhulk", 191, Rarity.MYTHIC, mage.cards.b.BrightglassGearhulk.class)); cards.add(new SetCardInfo("Daretti, Rocketeer Engineer", 120, Rarity.RARE, mage.cards.d.DarettiRocketeerEngineer.class)); cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); -- 2.47.2 From 4ec5ed64baf4e6c93b6cd1d95220ad23a87332d8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:15:20 -0500 Subject: [PATCH 16/28] [DFT] Implement Hulldrifter --- Mage.Sets/src/mage/cards/h/Hulldrifter.java | 45 +++++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/Hulldrifter.java diff --git a/Mage.Sets/src/mage/cards/h/Hulldrifter.java b/Mage.Sets/src/mage/cards/h/Hulldrifter.java new file mode 100644 index 00000000000..e3c0e2ef566 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Hulldrifter.java @@ -0,0 +1,45 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Hulldrifter extends CardImpl { + + public Hulldrifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{U}{U}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this Vehicle enters, draw two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2))); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + } + + private Hulldrifter(final Hulldrifter card) { + super(card); + } + + @Override + public Hulldrifter copy() { + return new Hulldrifter(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 5e70d4008de..c9d48584cca 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -31,6 +31,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Earthrumbler", 160, Rarity.UNCOMMON, mage.cards.e.Earthrumbler.class)); cards.add(new SetCardInfo("Forest", 289, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hulldrifter", 47, Rarity.COMMON, mage.cards.h.Hulldrifter.class)); cards.add(new SetCardInfo("Island", 280, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jungle Hollow", 256, Rarity.COMMON, mage.cards.j.JungleHollow.class)); cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); -- 2.47.2 From 9b865433626a46a31916e2d7fc17956bdce49639 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:16:29 -0500 Subject: [PATCH 17/28] [DFT] Implement Lightshield Parry --- .../src/mage/cards/l/LightshieldParry.java | 37 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 38 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LightshieldParry.java diff --git a/Mage.Sets/src/mage/cards/l/LightshieldParry.java b/Mage.Sets/src/mage/cards/l/LightshieldParry.java new file mode 100644 index 00000000000..63cb8aba62b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightshieldParry.java @@ -0,0 +1,37 @@ +package mage.cards.l; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.CyclingAbility; +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 LightshieldParry extends CardImpl { + + public LightshieldParry(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)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); + } + + private LightshieldParry(final LightshieldParry card) { + super(card); + } + + @Override + public LightshieldParry copy() { + return new LightshieldParry(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index c9d48584cca..476b4b7fd59 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -34,6 +34,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Hulldrifter", 47, Rarity.COMMON, mage.cards.h.Hulldrifter.class)); cards.add(new SetCardInfo("Island", 280, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jungle Hollow", 256, Rarity.COMMON, mage.cards.j.JungleHollow.class)); + cards.add(new SetCardInfo("Lightshield Parry", 19, Rarity.COMMON, mage.cards.l.LightshieldParry.class)); cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rugged Highlands", 262, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); -- 2.47.2 From 55e262fe3e98b6100d469c882a104f181b0dcb31 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:19:05 -0500 Subject: [PATCH 18/28] [DFT] Implement Lagorin, Soul of Alacria --- .../mage/cards/l/LagorinSoulOfAlacria.java | 64 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 65 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LagorinSoulOfAlacria.java diff --git a/Mage.Sets/src/mage/cards/l/LagorinSoulOfAlacria.java b/Mage.Sets/src/mage/cards/l/LagorinSoulOfAlacria.java new file mode 100644 index 00000000000..4ba1c5ee11f --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LagorinSoulOfAlacria.java @@ -0,0 +1,64 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWhileSaddledTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.SaddleAbility; +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.predicate.Predicates; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LagorinSoulOfAlacria extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("Mounts and/or Vehicles"); + + static { + filter.add(Predicates.or( + SubType.MOUNT.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public LagorinSoulOfAlacria(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAST); + this.subtype.add(SubType.MOUNT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Lagorin attacks while saddled, put a +1/+1 counter on each of up to two target Mounts and/or Vehicles. + Ability ability = new AttacksWhileSaddledTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetPermanent(0, 2, filter)); + this.addAbility(ability); + + // Saddle 1 + this.addAbility(new SaddleAbility(1)); + } + + private LagorinSoulOfAlacria(final LagorinSoulOfAlacria card) { + super(card); + } + + @Override + public LagorinSoulOfAlacria copy() { + return new LagorinSoulOfAlacria(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 476b4b7fd59..716e6984da6 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -34,6 +34,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Hulldrifter", 47, Rarity.COMMON, mage.cards.h.Hulldrifter.class)); cards.add(new SetCardInfo("Island", 280, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jungle Hollow", 256, Rarity.COMMON, mage.cards.j.JungleHollow.class)); + cards.add(new SetCardInfo("Lagorin, Soul of Alacria", 211, Rarity.UNCOMMON, mage.cards.l.LagorinSoulOfAlacria.class)); cards.add(new SetCardInfo("Lightshield Parry", 19, Rarity.COMMON, mage.cards.l.LightshieldParry.class)); cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); -- 2.47.2 From 2ffc36b20c33cdc6562e2461e2147b854b57290f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:23:26 -0500 Subject: [PATCH 19/28] [DFT] Implement Bleachbone Verge --- .../src/mage/cards/b/BleachboneVerge.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BleachboneVerge.java diff --git a/Mage.Sets/src/mage/cards/b/BleachboneVerge.java b/Mage.Sets/src/mage/cards/b/BleachboneVerge.java new file mode 100644 index 00000000000..c6f4d32016e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BleachboneVerge.java @@ -0,0 +1,59 @@ +package mage.cards.b; + +import mage.Mana; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.mana.ActivateIfConditionManaAbility; +import mage.abilities.mana.BlackManaAbility; +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.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BleachboneVerge extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("you control a Plains or a Swamp"); + + static { + filter.add(Predicates.or( + SubType.PLAINS.getPredicate(), + SubType.SWAMP.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a Plains or a Swamp"); + + public BleachboneVerge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {B}. + this.addAbility(new BlackManaAbility()); + + // {T}: Add {W}. Activate only if you control a Plains or a Swamp. + this.addAbility(new ActivateIfConditionManaAbility( + Zone.BATTLEFIELD, new BasicManaEffect(Mana.WhiteMana(1)), new TapSourceCost(), condition + ).addHint(hint)); + } + + private BleachboneVerge(final BleachboneVerge card) { + super(card); + } + + @Override + public BleachboneVerge copy() { + return new BleachboneVerge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 716e6984da6..65543da1cd0 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -22,6 +22,7 @@ public final class Aetherdrift extends ExpansionSet { this.hasBoosters = false; // temporary cards.add(new SetCardInfo("Air Response Unit", 1, Rarity.UNCOMMON, mage.cards.a.AirResponseUnit.class)); + cards.add(new SetCardInfo("Bleachbone Verge", 250, Rarity.RARE, mage.cards.b.BleachboneVerge.class)); cards.add(new SetCardInfo("Bloodfell Caves", 251, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); cards.add(new SetCardInfo("Bloodghast", 77, Rarity.RARE, mage.cards.b.Bloodghast.class)); cards.add(new SetCardInfo("Blossoming Sands", 252, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); -- 2.47.2 From 78dfb820d5c88e54d1a3b3e2a28dd9efd69162d7 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:29:34 -0500 Subject: [PATCH 20/28] [DFT] Implement Riverpyre Verge --- .../src/mage/cards/r/RiverpyreVerge.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RiverpyreVerge.java diff --git a/Mage.Sets/src/mage/cards/r/RiverpyreVerge.java b/Mage.Sets/src/mage/cards/r/RiverpyreVerge.java new file mode 100644 index 00000000000..500aaa12711 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiverpyreVerge.java @@ -0,0 +1,59 @@ +package mage.cards.r; + +import mage.Mana; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.mana.ActivateIfConditionManaAbility; +import mage.abilities.mana.RedManaAbility; +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.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiverpyreVerge extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("you control an Island or a Mountain"); + + static { + filter.add(Predicates.or( + SubType.ISLAND.getPredicate(), + SubType.MOUNTAIN.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control an Island or a Mountain"); + + public RiverpyreVerge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {R}. + this.addAbility(new RedManaAbility()); + + // {T}: Add {U}. Activate only if you control an Island or a Mountain. + this.addAbility(new ActivateIfConditionManaAbility( + Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlueMana(1)), new TapSourceCost(), condition + ).addHint(hint)); + } + + private RiverpyreVerge(final RiverpyreVerge card) { + super(card); + } + + @Override + public RiverpyreVerge copy() { + return new RiverpyreVerge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 65543da1cd0..cfcd3eec9fb 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -39,6 +39,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Lightshield Parry", 19, Rarity.COMMON, mage.cards.l.LightshieldParry.class)); cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riverpyre Verge", 260, Rarity.RARE, mage.cards.r.RiverpyreVerge.class)); cards.add(new SetCardInfo("Rugged Highlands", 262, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Scoured Barrens", 263, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); -- 2.47.2 From 015149e2492bc0d827485a4b066d9d1477a970a5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:31:50 -0500 Subject: [PATCH 21/28] [DFT] Implement Wastewood Verge --- .../src/mage/cards/w/WastewoodVerge.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WastewoodVerge.java diff --git a/Mage.Sets/src/mage/cards/w/WastewoodVerge.java b/Mage.Sets/src/mage/cards/w/WastewoodVerge.java new file mode 100644 index 00000000000..3be1f8e5c38 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WastewoodVerge.java @@ -0,0 +1,59 @@ +package mage.cards.w; + +import mage.Mana; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.mana.ActivateIfConditionManaAbility; +import mage.abilities.mana.GreenManaAbility; +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.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WastewoodVerge extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("you control a Swamp or a Forest"); + + static { + filter.add(Predicates.or( + SubType.SWAMP.getPredicate(), + SubType.FOREST.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a Swamp or a Forest"); + + public WastewoodVerge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // {T}: Add {B}. Activate only if you control a Swamp or a Forest. + this.addAbility(new ActivateIfConditionManaAbility( + Zone.BATTLEFIELD, new BasicManaEffect(Mana.BlackMana(1)), new TapSourceCost(), condition + ).addHint(hint)); + } + + private WastewoodVerge(final WastewoodVerge card) { + super(card); + } + + @Override + public WastewoodVerge copy() { + return new WastewoodVerge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index cfcd3eec9fb..2725ac30759 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -46,6 +46,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Swiftwater Cliffs", 265, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Tranquil Cove", 267, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Wastewood Verge", 268, Rarity.RARE, mage.cards.w.WastewoodVerge.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); } } -- 2.47.2 From a585c7f8a9cb3d1c30fc78f13af6ab08f55f0989 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:33:27 -0500 Subject: [PATCH 22/28] [DFT] Implement Sunbillow Verge --- .../src/mage/cards/s/SunbillowVerge.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SunbillowVerge.java diff --git a/Mage.Sets/src/mage/cards/s/SunbillowVerge.java b/Mage.Sets/src/mage/cards/s/SunbillowVerge.java new file mode 100644 index 00000000000..cc1a6877985 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunbillowVerge.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +import mage.Mana; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.mana.ActivateIfConditionManaAbility; +import mage.abilities.mana.WhiteManaAbility; +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.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SunbillowVerge extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("you control a Mountain or a Plains"); + + static { + filter.add(Predicates.or( + SubType.MOUNTAIN.getPredicate(), + SubType.PLAINS.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a Mountain or a Plains"); + + public SunbillowVerge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {W}. + this.addAbility(new WhiteManaAbility()); + + // {T}: Add {R}. Activate only if you control a Mountain or a Plains. + this.addAbility(new ActivateIfConditionManaAbility( + Zone.BATTLEFIELD, new BasicManaEffect(Mana.RedMana(1)), new TapSourceCost(), condition + ).addHint(hint)); + } + + private SunbillowVerge(final SunbillowVerge card) { + super(card); + } + + @Override + public SunbillowVerge copy() { + return new SunbillowVerge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 2725ac30759..1b4cb6bf999 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -42,6 +42,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Riverpyre Verge", 260, Rarity.RARE, mage.cards.r.RiverpyreVerge.class)); cards.add(new SetCardInfo("Rugged Highlands", 262, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Scoured Barrens", 263, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); + cards.add(new SetCardInfo("Sunbillow Verge", 264, Rarity.RARE, mage.cards.s.SunbillowVerge.class)); cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 265, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); -- 2.47.2 From 644efb3ee8f501daf9aef2bc0b7a28f2ab598715 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:34:49 -0500 Subject: [PATCH 23/28] [DFT] Implement Willowrush Verge --- .../src/mage/cards/w/WillowrushVerge.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WillowrushVerge.java diff --git a/Mage.Sets/src/mage/cards/w/WillowrushVerge.java b/Mage.Sets/src/mage/cards/w/WillowrushVerge.java new file mode 100644 index 00000000000..d08e9cd261c --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WillowrushVerge.java @@ -0,0 +1,59 @@ +package mage.cards.w; + +import mage.Mana; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.mana.ActivateIfConditionManaAbility; +import mage.abilities.mana.BlueManaAbility; +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.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WillowrushVerge extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("you control a Forest or an Island"); + + static { + filter.add(Predicates.or( + SubType.FOREST.getPredicate(), + SubType.ISLAND.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a Forest or an Island"); + + public WillowrushVerge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // {T}: Add {G}. Activate only if you control a Forest or an Island. + this.addAbility(new ActivateIfConditionManaAbility( + Zone.BATTLEFIELD, new BasicManaEffect(Mana.GreenMana(1)), new TapSourceCost(), condition + ).addHint(hint)); + } + + private WillowrushVerge(final WillowrushVerge card) { + super(card); + } + + @Override + public WillowrushVerge copy() { + return new WillowrushVerge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 1b4cb6bf999..5026cf3be97 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -48,6 +48,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Tranquil Cove", 267, Rarity.COMMON, mage.cards.t.TranquilCove.class)); cards.add(new SetCardInfo("Wastewood Verge", 268, Rarity.RARE, mage.cards.w.WastewoodVerge.class)); + cards.add(new SetCardInfo("Willowrush Verge", 270, Rarity.RARE, mage.cards.w.WillowrushVerge.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); } } -- 2.47.2 From 396613c18077abad290f9e09067dc098ec3bd249 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:36:08 -0500 Subject: [PATCH 24/28] [DFT] Implement Venomsac Lagac --- Mage.Sets/src/mage/cards/v/VenomsacLagac.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VenomsacLagac.java diff --git a/Mage.Sets/src/mage/cards/v/VenomsacLagac.java b/Mage.Sets/src/mage/cards/v/VenomsacLagac.java new file mode 100644 index 00000000000..86acabbd1e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomsacLagac.java @@ -0,0 +1,49 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.AttacksWhileSaddledTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.SaddleAbility; +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 VenomsacLagac extends CardImpl { + + public VenomsacLagac(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.MOUNT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever this creature attacks while saddled, it gets +0/+3 until end of turn. + this.addAbility(new AttacksWhileSaddledTriggeredAbility( + new BoostSourceEffect(0, 3, Duration.EndOfTurn, "it") + )); + + // Saddle 2 + this.addAbility(new SaddleAbility(2)); + } + + private VenomsacLagac(final VenomsacLagac card) { + super(card); + } + + @Override + public VenomsacLagac copy() { + return new VenomsacLagac(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 5026cf3be97..c3fe68a81bb 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -47,6 +47,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Swiftwater Cliffs", 265, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Tranquil Cove", 267, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Venomsac Lagac", 185, Rarity.COMMON, mage.cards.v.VenomsacLagac.class)); cards.add(new SetCardInfo("Wastewood Verge", 268, Rarity.RARE, mage.cards.w.WastewoodVerge.class)); cards.add(new SetCardInfo("Willowrush Verge", 270, Rarity.RARE, mage.cards.w.WillowrushVerge.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); -- 2.47.2 From ca4efa6494a12b277b38bce8057daf255df129f4 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:38:10 -0500 Subject: [PATCH 25/28] [DFT] Implement The Last Ride --- Mage.Sets/src/mage/cards/t/TheLastRide.java | 59 +++++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TheLastRide.java diff --git a/Mage.Sets/src/mage/cards/t/TheLastRide.java b/Mage.Sets/src/mage/cards/t/TheLastRide.java new file mode 100644 index 00000000000..c705d96a989 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLastRide.java @@ -0,0 +1,59 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.CrewAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLastRide extends CardImpl { + + private static final DynamicValue xValue = new SignInversionDynamicValue(ControllerLifeCount.instance, false); + + public TheLastRide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(13); + this.toughness = new MageInt(13); + + // The Last Ride gets -X/-X, where X is your life total. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield))); + + // {2}{B}, Pay 2 life: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{B}")); + ability.addCost(new PayLifeCost(2)); + this.addAbility(ability); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private TheLastRide(final TheLastRide card) { + super(card); + } + + @Override + public TheLastRide copy() { + return new TheLastRide(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index c3fe68a81bb..9b488a83260 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -45,6 +45,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Sunbillow Verge", 264, Rarity.RARE, mage.cards.s.SunbillowVerge.class)); cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 265, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); + cards.add(new SetCardInfo("The Last Ride", 94, Rarity.MYTHIC, mage.cards.t.TheLastRide.class)); cards.add(new SetCardInfo("Thornwood Falls", 266, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Tranquil Cove", 267, Rarity.COMMON, mage.cards.t.TranquilCove.class)); cards.add(new SetCardInfo("Venomsac Lagac", 185, Rarity.COMMON, mage.cards.v.VenomsacLagac.class)); -- 2.47.2 From 9276e1be83824e7f9901aaf302881513ca338cbb Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:52:21 -0500 Subject: [PATCH 26/28] [DRC] add set --- .../dl/sources/ScryfallImageSupportCards.java | 1 + .../src/mage/sets/AetherdriftCommander.java | 21 +++++++++++++++++++ Utils/known-sets.txt | 1 + Utils/mtg-cards-data.txt | 4 ++++ Utils/mtg-sets-data.txt | 1 + 5 files changed, 28 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/AetherdriftCommander.java diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index f582edecba3..7ea38fbc962 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -567,6 +567,7 @@ public class ScryfallImageSupportCards { add("J25"); // Foundations Jumpstart add("INR"); // Innistrad Remastered add("DFT"); // Aetherdrift + add("DRC"); // Aetherdrift Commander // Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks add("CALC"); // Custom Alchemized versions of existing cards diff --git a/Mage.Sets/src/mage/sets/AetherdriftCommander.java b/Mage.Sets/src/mage/sets/AetherdriftCommander.java new file mode 100644 index 00000000000..586cef234b8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/AetherdriftCommander.java @@ -0,0 +1,21 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class AetherdriftCommander extends ExpansionSet { + + private static final AetherdriftCommander instance = new AetherdriftCommander(); + + public static AetherdriftCommander getInstance() { + return instance; + } + + private AetherdriftCommander() { + super("Aetherdrift Commander", "DRC", ExpansionSet.buildDate(2025, 1, 21), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; + } +} diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 873a2878507..c390b14fc9d 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -3,6 +3,7 @@ Alchemy: Innistrad|AlchemyInnistrad| Adventures in the Forgotten Realms|AdventuresInTheForgottenRealms| Forgotten Realms Commander|ForgottenRealmsCommander| Aetherdrift|Aetherdrift| +Aetherdrift Commander|AetherdriftCommander| Aether Revolt|AetherRevolt| Alara Reborn|AlaraReborn| Alliances|Alliances| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index d9cc3128301..9cfebfe3ad7 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -56816,3 +56816,7 @@ Thriving Heath|Foundations Jumpstart|777|C||Land|||Thriving Heath enters tapped. Thriving Isle|Foundations Jumpstart|778|C||Land|||Thriving Isle enters tapped. As it enters, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.| Thriving Moor|Foundations Jumpstart|779|C||Land|||Thriving Moor enters tapped. As it enters, choose a color other than black.${T}: Add {B} or one mana of the chosen color.| Vault of Whispers|Foundations Jumpstart|780|C||Artifact Land|||{T}: Add {B}.| +Hashaton, Scarab's Fist|Aetherdrift Commander|1|M|{W}{B}|Legendary Creature - Zombie Wizard|1|3|Whenever you discard a creature card, you may pay {2}{U}. If you do, create a tapped token that's a copy of that card, except it's a 4/4 black Zombie.| +Pia Nalaar, Chief Mechanic|Aetherdrift Commander|2|M|{G}{U}{R}|Legendary Creature - Human Artificer|2|4|Whenever one or more artifact creatures you control deal combat damage to a player, you get {E}{E}.$At the beginning of your end step, you may pay one or more {E}. If you do, create an X/X colorless Vehicle artifact token named Nalaar Aetherjet with flying and crew 2, where X is the amount of {E} spent this way.| +Saheeli, Radiant Creator|Aetherdrift Commander|3|M|{1}{G}{U}{R}|Legendary Creature - Human Artificer|4|4|Whenever you cast an Artificer or artifact spell, you get {E}.$At the beginning of combat on your turn, you may pay {E}{E}{E}. When you do, create a token that's a copy of target permanent you control, except it's a 5/5 artifact creature in addition to its other types and has haste. Sacrifice it at the beginning of the next end step.| +Temmet, Naktamun's Will|Aetherdrift Commander|4|M|{2}{W}{U}{B}|Legendary Creature - Zombie Wizard|4|4|Vigilance, menace$Whenever you attack, draw a card, then discard a card.$Whenever you draw a card, Zombies you control get +1/+1 until end of turn.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 748c9cebdd0..fb62f4256b6 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -13,6 +13,7 @@ Alchemy: Innistrad|Y22| Adventures in the Forgotten Realms|AFR| Forgotten Realms Commander|AFC| Aetherdrift|DFT| +Aetherdrift Commander|DRC| Aether Revolt|AER| Amonkhet|AKH| Shards of Alara|ALA| -- 2.47.2 From 812f0555e361471b7f44337f9fc38e6fa504f9d0 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:55:39 -0500 Subject: [PATCH 27/28] [DRC] Implement Temmet, Naktamun's Will --- .../src/mage/cards/t/TemmetNaktamunsWill.java | 61 +++++++++++++++++++ .../src/mage/sets/AetherdriftCommander.java | 3 + 2 files changed, 64 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TemmetNaktamunsWill.java diff --git a/Mage.Sets/src/mage/cards/t/TemmetNaktamunsWill.java b/Mage.Sets/src/mage/cards/t/TemmetNaktamunsWill.java new file mode 100644 index 00000000000..f3f7448dbcd --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TemmetNaktamunsWill.java @@ -0,0 +1,61 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.DrawCardControllerTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.MenaceAbility; +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.filter.common.FilterCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TemmetNaktamunsWill extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombies"); + + public TemmetNaktamunsWill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever you attack, draw a card, then discard a card. + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new DrawDiscardControllerEffect(1, 1), 1 + )); + + // Whenever you draw a card, Zombies you control get +1/+1 until end of turn. + this.addAbility(new DrawCardControllerTriggeredAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter), false + )); + } + + private TemmetNaktamunsWill(final TemmetNaktamunsWill card) { + super(card); + } + + @Override + public TemmetNaktamunsWill copy() { + return new TemmetNaktamunsWill(this); + } +} diff --git a/Mage.Sets/src/mage/sets/AetherdriftCommander.java b/Mage.Sets/src/mage/sets/AetherdriftCommander.java index 586cef234b8..de0e49a6bb8 100644 --- a/Mage.Sets/src/mage/sets/AetherdriftCommander.java +++ b/Mage.Sets/src/mage/sets/AetherdriftCommander.java @@ -1,6 +1,7 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.constants.Rarity; import mage.constants.SetType; /** @@ -17,5 +18,7 @@ public final class AetherdriftCommander extends ExpansionSet { private AetherdriftCommander() { super("Aetherdrift Commander", "DRC", ExpansionSet.buildDate(2025, 1, 21), SetType.SUPPLEMENTAL); this.hasBasicLands = false; + + cards.add(new SetCardInfo("Temmet, Naktamun's Will", 4, Rarity.MYTHIC, mage.cards.t.TemmetNaktamunsWill.class)); } } -- 2.47.2 From c4512a2a52fdac53cb3b82976bb36eb44cb4eb9f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 22 Jan 2025 11:56:25 -0500 Subject: [PATCH 28/28] fix verify failure --- Mage.Sets/src/mage/sets/Aetherdrift.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 9b488a83260..c69e66050a2 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -18,7 +18,7 @@ public final class Aetherdrift extends ExpansionSet { private Aetherdrift() { super("Aetherdrift", "DFT", ExpansionSet.buildDate(2025, 2, 14), SetType.EXPANSION); this.blockName = "Aetherdrift"; // for sorting in GUI - this.hasBasicLands = false; // temporary + this.hasBasicLands = true; this.hasBoosters = false; // temporary cards.add(new SetCardInfo("Air Response Unit", 1, Rarity.UNCOMMON, mage.cards.a.AirResponseUnit.class)); -- 2.47.2