From 9098eff1ba83f1105b7510005a092b547d0bdaf5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 14:15:20 -0400 Subject: [PATCH 01/43] fix verify failure --- Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java index b45ddacc30d..9dc674a51c3 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java @@ -32,7 +32,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Goryo's Vengeance", 372, Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class)); cards.add(new SetCardInfo("Growth Spiral", 88, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); cards.add(new SetCardInfo("Living Death", 373, Rarity.MYTHIC, mage.cards.l.LivingDeath.class)); - cards.add(new SetCardInfo("Sol Ring", 94, Rarity.COMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Sol Ring", 94, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("They Came from the Pipes", 14, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class)); } } From 397bc8733a0eccb2ae293d221e92df98c7594c4d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 15:14:18 -0400 Subject: [PATCH 02/43] [DSK] update spoiler --- Utils/mtg-cards-data.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 3c495327b3e..4a7c862222f 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -54066,12 +54066,14 @@ Unstoppable Slasher|Duskmourn: House of Horror|119|R|{2}{B}|Creature - Zombie As Valgavoth, Terror Eater|Duskmourn: House of Horror|120|M|{6}{B}{B}{B}|Legendary Creature - Elder Demon|9|9|Flying, lifelink$Ward--Sacrifice three nonland permanents.$If a card you didn't control would be put into an opponent's graveyard from anywhere, exile it instead.$During your turn, you may play cards exiled with Valgavoth. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.| Valgavoth's Faithful|Duskmourn: House of Horror|121|U|{B}|Creature - Human Cleric|1|1|{3}{B}, Sacrifice Valgavoth's Faithful: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery.| Vile Mutilator|Duskmourn: House of Horror|122|U|{5}{B}{B}|Creature - Demon|6|5|As an additional cost to cast this spell, sacrifice a creature or enchantment.$Flying, trample$When Vile Mutilator enters, each opponent sacrifices a nontoken enchantment, then sacrifices a nontoken creature.| +Withering Torment|Duskmourn: House of Horror|124|U|{2}{B}|Instant|||Destroy target creature or enchantment. You lose 2 life.| Betrayer's Bargain|Duskmourn: House of Horror|126|U|{1}{R}|Instant|||As an additioinal cost to cast this spell, sacrifice a creature or enchantment or pay {2}.$Betrayer's Bargain deals 5 damage to target creature. If that creature would die this turn, exile it instead.| Chainsaw|Duskmourn: House of Horror|128|R|{1}{R}|Artifact - Equipment|||When Chainsaw enters, it deals 3 damage to up to one target creature.$Whenever one or more creatures die, put a rev counter on Chainsaw.$Equipped creature gets +X/+0, where X is the number of rev counters on Chainsaw.$Equip {3}| Charred Foyer // Warped Space|Duskmourn: House of Horror|129|M|{3}{R}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$At the beginning of your upkeep, exile the top card of your library. You may play that card this turn.$Warped Space${4}{R}{R}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.| Clockwork Percussionist|Duskmourn: House of Horror|130|C|{R}|Artifact Creature - Monkey Toy|1|1|Haste$When Clockwork Percussionist dies, exile the top card of your library. You may play it until the end of your next turn.| Cursed Recording|Duskmourn: House of Horror|131|R|{2}{R}{R}|Artifact|||Whenever you cast an instant or sorcery spell, put a time counter on Cursed Recording. Then if there are seven or more time counters on it, remove those counters and it deals 20 damage to you.${T}: When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.| Diversion Specialist|Duskmourn: House of Horror|132|U|{3}{R}|Creature - Human Warrior|4|3|Menace${1}, Sacrifice another creature or enchantment: Exile the top card of your library. You may play it this turn.| +Enduring Courage|Duskmourn: House of Horror|133|R|{2}{R}{R}|Enchantment Creature - Dog Glimmer|3|3|Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn.$When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| Fear of Being Hunted|Duskmourn: House of Horror|134|U|{1}{R}{R}|Enchantment Creature - Nightmare|4|2|Haste$Fear of Being Hunted must be blocked if able.| Fear of Burning Alive|Duskmourn: House of Horror|135|U|{4}{R}{R}|Enchantment Creature - Nightmare|4|4|When Fear of Burning Alive enters, it deals 4 damage to each opponent.$Delirium -- Whenever a source you control deals noncombat damage to an opponent, if there are four or more card types among cards in your graveyard, Fear of Burning Alive deals that amount of damage to target creature that player controls.| Fear of Missing Out|Duskmourn: House of Horror|136|R|{1}{R}|Enchantment Creature - Nightmare|2|3|When Fear of Missing Out enters, discard a card, then draw a card.$Delirium -- Whenever Fear of Missing Out attacks for the first time each turn, if there are four or more card types among cards in your graveyard, untap target creature. After this phase, there is an additional combat phase.| @@ -54103,10 +54105,10 @@ Balustrade Wurm|Duskmourn: House of Horror|168|R|{3}{G}{G}|Creature - Wurm|5|5|T Bashful Beastie|Duskmourn: House of Horror|169|C|{4}{G}|Creature - Beast|5|4|When Bashful Beastie dies, manifest dread.| Break Down the Door|Duskmourn: House of Horror|170|U|{2}{G}|Instant|||Choose one --$* Exile target artifact.$* Exile target enchantment.$* Manifest dread.| Cautious Survivor|Duskmourn: House of Horror|172|C|{3}{G}|Creature - Elf Survivor|4|4|Survival -- At the beginning of your second main phase, if Cautious Survivor is tapped, you gain 2 life.| -Coordinated Clobbering|Duskmourn: House of Horror|173|C|{G}|Sorcery|||Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.| -Cryptid Inspector|Duskmourn: House of Horror|174|C|{2}{G}|Creature Elf Warrior|2|3|Vigilance$Whenever a face-down permanent you control enters and whenever Cryptid Inspector or another permanent you control is turned face up, put a +1/+1 counter on Cryptid Inspector.| +Coordinated Clobbering|Duskmourn: House of Horror|173|U|{G}|Sorcery|||Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.| +Cryptid Inspector|Duskmourn: House of Horror|174|C|{2}{G}|Creature - Elf Warrior|2|3|Vigilance$Whenever a face-down permanent you control enters and whenever Cryptid Inspector or another permanent you control is turned face up, put a +1/+1 counter on Cryptid Inspector.| Defiant Survivor|Duskmourn: House of Horror|175|U|{2}{G}|Creature - Human Survivor|3|2|Survival -- At the beginning of your second main phase, if Defiant Survivor is tapped, manifest dread.| -Flesh Burrower|Duskmourn: House of Horror|178|C|{1}{G}|Creature Insect|2|2|Deathtouch$Whenever Flesh Burrower attacks, another target creature you control gains deathtouch until end of turn.| +Flesh Burrower|Duskmourn: House of Horror|178|C|{1}{G}|Creature - Insect|2|2|Deathtouch$Whenever Flesh Burrower attacks, another target creature you control gains deathtouch until end of turn.| Grasping Longneck|Duskmourn: House of Horror|180|C|{2}{G}|Enchantment Creature - Horror|4|2|Reach$When Grasping Longneck dies, you gain 2 life.| Greenhouse // Rickety Gazebo|Duskmourn: House of Horror|181|U|{2}{G}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lands you control have "{T}: Add one mana of any color."$Rickety Gazebo${3}{G}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, mill four cards, then return up to two permanent cards from among them to your hand.| Hauntwoods Shrieker|Duskmourn: House of Horror|182|M|{1}{G}{G}|Creature - Beast Mutant|3|3|Whenever Hauntwoods Shrieker attacks, manifest dread.${1}{G}: Reveal target face-down permanent. If it's a creature card, you may turn it face up.| @@ -54118,6 +54120,7 @@ Omnivorous Flytrap|Duskmourn: House of Horror|192|R|{2}{G}|Creature - Plant|2|4| Overgrown Zealot|Duskmourn: House of Horror|193|U|{1}{G}|Creature - Elf Druid|0|4|{T}: Add one mana of any color.${T}: Add two mana of any one color. Spend this mana only to turn permanents face up.| Overlord of the Hauntwoods|Duskmourn: House of Horror|194|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever Overlord of the Hauntwoods enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.| Patchwork Beastie|Duskmourn: House of Horror|195|U|{G}|Artifact Creature - Beast|3|3|Delirium -- Patchwork Beastie can't attack or block unless there are four or more card types among cards in your graveyard.$At the beginning of your upkeep, you may mill a card.| +Rootwise Survivor|Duskmourn: House of Horror|196|U|{3}{G}{G}|Creature - Human Survivor|3|4|Haste$Survival -- At the beginning of your second main phase, if Rootwise Survivor is tapped, put three +1/+1 counters on up to one target land you control. That land becomes a 0/0 Elemental creature in addition to its other types. It gains haste until your next turn.| Say Its Name|Duskmourn: House of Horror|197|C|{1}{G}|Sorcery|||Mill three cards. Then you may return a creature or land card from your graveyard to your hand.$Exile this card and two other cards named Say Its Name from your graveyard: Search your graveyard, hand, and/or library for a card named Altanak, the Thrice-Called and put it onto the battlefield. If you search your library this way, shuffle. Activate only as a sorcery.| Slavering Branchsnapper|Duskmourn: House of Horror|198|C|{4}{G}{G}|Creature - Lizard|7|6|Trample$Forestcycling {2}| Spineseeker Centipede|Duskmourn: House of Horror|199|C|{2}{G}|Creature - Insect|2|1|When Spineseeker Centipede enters, search your library for a basic land card, reveal it, put it into your hand, then shuffle.$Delirium -- Spineseeker Centipede gets +1/+2 and has vigilance as long as there are four or more card types among cards in your graveyard.| @@ -54133,13 +54136,14 @@ Baseball Bat|Duskmourn: House of Horror|209|U|{G}{W}|Artifact - Equipment|||When Disturbing Mirth|Duskmourn: House of Horror|212|U|{B}{R}|Enchantment|||When Disturbing Mirth enters, you may sacrifice another enchantment or creature. If you do, draw two cards.$When you sacrifice Disturbing Mirth, manifest dread.| Drag to the Roots|Duskmourn: House of Horror|213|U|{2}{B}{G}|Instant|||Delirium -- This spell costs {2} less to cast as long as there are four or more card types among cards in your graveyard.$Destroy target nonland permanent.| Fear of Infinity|Duskmourn: House of Horror|214|U|{1}{U}{B}|Enchantment Creature - Nightmare|2|2|Flying, lifelink$Fear of Infinity can't block.$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, you may return Fear of Infinity from your graveyard to your hand.| +Gremlin Tamer|Duskmourn: House of Horror|215|U|{W}{U}|Creature - Human Scout|2|2|Eerie - Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 1/1 red Gremlin creature token.| Growing Dread|Duskmourn: House of Horror|216|U|{G}{U}|Enchantment|||Flash$When Growing Dread enters, manifest dread.$Whenever you turn a permanent face up, put a +1/+1 counter on it.| Inquisitive Glimmer|Duskmourn: House of Horror|217|U|{W}{U}|Enchantment Creature - Fox Glimmer|2|3|Enchantment spells you cast cost {1} less to cast.$Unlock costs you pay cost {1} less.| Intruding Soulrager|Duskmourn: House of Horror|218|U|{U}{R}|Creature - Spirit|2|2|Vigilance${T}, Sacrifice a Room: Intruding Soulrager deals 2 damage to each opponent. Draw a card.| The Jolly Balloon Man|Duskmourn: House of Horror|219|R|{1}{R}{W}|Legendary Creature - Human Clown|1|4|Haste${1}, {T}: Create a token that's a copy of another target creature you control, except it's a 1/1 red Balloon creature in addition to its other colors and types and it has flying and haste. Sacrifice it at the beginning of the next end step. Activate only as a sorcery.| Kaito, Bane of Nightmares|Duskmourn: House of Horror|220|M|{2}{U}{B}|Legendary Planeswalker - Kaito|4|Ninjutsu {1}{U}{B}$During your turn, as long as Kaito has one or more loyalty counters on him, he's a 3/4 Ninja creature and has hexproof.$+1: You get an emblem with "Ninjas you control get +1/+1."$0: Surveil 2. Then draw a card for each opponent who lost life this turn.$-2: Tap target creature. Put two stun counters on it.| Midnight Mayhem|Duskmourn: House of Horror|222|U|{2}{R}{W}|Sorcery|||Create three 1/1 red Gremlin creature tokens. Gremlins you control gain menace, lifelink, and haste until end of turn.| -Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Creature Rat Ninja Wizard|2|2|Menace$Whenever Nashi, Searcher in the Dark deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi.| +Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Creature - Rat Ninja Wizard|2|2|Menace$Whenever Nashi, Searcher in the Dark deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi.| Niko, Light of Hope|Duskmourn: House of Horror|224|M|{2}{W}{U}|Legendary Creature - Human Wizard|3|4|When Niko, Light of Hope enters, create two Shard tokens.${2}, {T}: Exile target nonlegendary creature you control. Shards you control become copies of it until the beginning of the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step.| Oblivious Bookworm|Duskmourn: House of Horror|225|U|{G}{U}|Creature - Human Wizard|2|3|At the beginning of your end step, you may draw a card. If you do, discard a card unless a permanent entered the battlefield face down under your control this turn or you turned a permanent face up this turn.| Peer Past the Veil|Duskmourn: House of Horror|226|R|{2}{R}{G}|Instant|||Discard your hand. Then draw X cards, where X is the number of card types among cards in your graveyard.| From dd471949c5f4fccde5a8750063114240c945d10b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 16:59:52 -0400 Subject: [PATCH 03/43] [DSK] Implement Withering Torment --- Mage.Sets/src/mage/cards/a/AngelicEdict.java | 18 +++------- Mage.Sets/src/mage/cards/b/BlessedLight.java | 16 +++------ Mage.Sets/src/mage/cards/b/BloodAspirant.java | 13 +------ .../src/mage/cards/e/ErtaiTheCorrupted.java | 20 ++++------- .../mage/cards/e/EtherswornAdjudicator.java | 21 +++-------- Mage.Sets/src/mage/cards/f/FinalFlare.java | 16 ++------- Mage.Sets/src/mage/cards/f/FinalPayment.java | 22 ++++-------- .../src/mage/cards/f/FinalVengeance.java | 14 ++------ Mage.Sets/src/mage/cards/f/FlickerOfFate.java | 14 ++------ .../mage/cards/k/KayaIntangibleSlayer.java | 20 +++-------- Mage.Sets/src/mage/cards/m/MireInMisery.java | 14 ++------ Mage.Sets/src/mage/cards/m/Mortify.java | 20 +++-------- .../src/mage/cards/o/OneWithTheStars.java | 13 ++----- .../src/mage/cards/s/ShatterTheOath.java | 14 ++------ Mage.Sets/src/mage/cards/u/UrnOfGodfire.java | 14 ++------ .../src/mage/cards/w/WitheringTorment.java | 35 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../main/java/mage/filter/StaticFilters.java | 10 ++++++ 18 files changed, 97 insertions(+), 198 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/w/WitheringTorment.java diff --git a/Mage.Sets/src/mage/cards/a/AngelicEdict.java b/Mage.Sets/src/mage/cards/a/AngelicEdict.java index a4c3f9386e0..ee1cb0d48ec 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicEdict.java +++ b/Mage.Sets/src/mage/cards/a/AngelicEdict.java @@ -1,33 +1,25 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AngelicEdict extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - } - public AngelicEdict(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); // Exile target creature or enchantment. getSpellAbility().addEffect(new ExileTargetEffect()); - getSpellAbility().addTarget(new TargetPermanent(filter)); + getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); } private AngelicEdict(final AngelicEdict card) { diff --git a/Mage.Sets/src/mage/cards/b/BlessedLight.java b/Mage.Sets/src/mage/cards/b/BlessedLight.java index 2164cdc9c3a..00f6507b215 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedLight.java +++ b/Mage.Sets/src/mage/cards/b/BlessedLight.java @@ -1,33 +1,25 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BlessedLight extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - } - public BlessedLight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); // Exile target creature or enchantment. getSpellAbility().addEffect(new ExileTargetEffect()); - getSpellAbility().addTarget(new TargetPermanent(filter)); + getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); } private BlessedLight(final BlessedLight card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodAspirant.java b/Mage.Sets/src/mage/cards/b/BloodAspirant.java index 9aa5fce17a4..577479a1717 100644 --- a/Mage.Sets/src/mage/cards/b/BloodAspirant.java +++ b/Mage.Sets/src/mage/cards/b/BloodAspirant.java @@ -17,8 +17,6 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -28,15 +26,6 @@ import java.util.UUID; */ public final class BloodAspirant extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public BloodAspirant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -56,7 +45,7 @@ public final class BloodAspirant extends CardImpl { new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}") ); ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(filter)); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); ability.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn) .setText("That creature can't block this turn.")); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java b/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java index 0ce93a09d58..ee217634f90 100644 --- a/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java +++ b/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java @@ -1,7 +1,6 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,25 +14,18 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetSpell; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ErtaiTheCorrupted extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or enchantment"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - } public ErtaiTheCorrupted(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); @@ -44,10 +36,10 @@ public final class ErtaiTheCorrupted extends CardImpl { // {U}, {tap}, Sacrifice a creature or enchantment: Counter target spell. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl<>("{U}")); ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(filter)); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); ability.addTarget(new TargetSpell()); this.addAbility(ability); -} + } private ErtaiTheCorrupted(final ErtaiTheCorrupted card) { super(card); diff --git a/Mage.Sets/src/mage/cards/e/EtherswornAdjudicator.java b/Mage.Sets/src/mage/cards/e/EtherswornAdjudicator.java index 2d4825f6191..95f29ba6e90 100644 --- a/Mage.Sets/src/mage/cards/e/EtherswornAdjudicator.java +++ b/Mage.Sets/src/mage/cards/e/EtherswornAdjudicator.java @@ -1,8 +1,5 @@ - - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,26 +13,19 @@ 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 mage.filter.StaticFilters; import mage.target.Target; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class EtherswornAdjudicator extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate())); - } public EtherswornAdjudicator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.VEDALKEN); this.subtype.add(SubType.KNIGHT); @@ -47,7 +37,7 @@ public final class EtherswornAdjudicator extends CardImpl { // {1}{W}{B}, {T}: Destroy target creature or enchantment. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{W}{B}")); ability.addCost(new TapSourceCost()); - Target target = new TargetPermanent(filter); + Target target = new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT); ability.addTarget(target); this.addAbility(ability); // {2}{U}: Untap Ethersworn Adjudicator. @@ -62,5 +52,4 @@ public final class EtherswornAdjudicator extends CardImpl { public EtherswornAdjudicator copy() { return new EtherswornAdjudicator(this); } - } diff --git a/Mage.Sets/src/mage/cards/f/FinalFlare.java b/Mage.Sets/src/mage/cards/f/FinalFlare.java index 7471da692d3..a2926703fe6 100644 --- a/Mage.Sets/src/mage/cards/f/FinalFlare.java +++ b/Mage.Sets/src/mage/cards/f/FinalFlare.java @@ -5,9 +5,7 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.target.common.TargetControlledPermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -17,21 +15,11 @@ import java.util.UUID; */ public final class FinalFlare extends CardImpl { - private static final FilterControlledPermanent filter - = new FilterControlledPermanent("a creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public FinalFlare(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // As an additional cost to cast this spell, sacrifice a creature or enchantment. - this.getSpellAbility().addCost(new SacrificeTargetCost(filter)); + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); // Final Flare deals 5 damage to target creature. this.getSpellAbility().addEffect(new DamageTargetEffect(5)); diff --git a/Mage.Sets/src/mage/cards/f/FinalPayment.java b/Mage.Sets/src/mage/cards/f/FinalPayment.java index f046e19db01..79f2b0c8573 100644 --- a/Mage.Sets/src/mage/cards/f/FinalPayment.java +++ b/Mage.Sets/src/mage/cards/f/FinalPayment.java @@ -1,8 +1,5 @@ package mage.cards.f; -import java.util.UUID; - -import mage.abilities.costs.Cost; import mage.abilities.costs.OrCost; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.SacrificeTargetCost; @@ -10,30 +7,23 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.target.common.TargetControlledPermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author FateRevoked */ public final class FinalPayment extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or enchantment"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - } public FinalPayment(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{B}"); // As an additional cost to cast this spell, pay 5 life or sacrifice a creature or enchantment. - final Cost lifeCost = new PayLifeCost(5); - final Cost sacrificeCost = new SacrificeTargetCost(filter); - - this.getSpellAbility().addCost(new OrCost("pay 5 life or sacrifice a creature or enchantment", lifeCost, sacrificeCost + this.getSpellAbility().addCost(new OrCost( + "pay 5 life or sacrifice a creature or enchantment", new PayLifeCost(5), + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT) )); // Destroy target creature diff --git a/Mage.Sets/src/mage/cards/f/FinalVengeance.java b/Mage.Sets/src/mage/cards/f/FinalVengeance.java index ee2b34dfae8..49514af9d46 100644 --- a/Mage.Sets/src/mage/cards/f/FinalVengeance.java +++ b/Mage.Sets/src/mage/cards/f/FinalVengeance.java @@ -5,8 +5,7 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -16,20 +15,11 @@ import java.util.UUID; */ public final class FinalVengeance extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public FinalVengeance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // As an additional cost to cast this spell, sacrifice a creature or enchantment. - this.getSpellAbility().addCost(new SacrificeTargetCost(filter)); + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); // Exile target creature. this.getSpellAbility().addEffect(new ExileTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/f/FlickerOfFate.java b/Mage.Sets/src/mage/cards/f/FlickerOfFate.java index 21356da3cdf..3b6a9092b7c 100644 --- a/Mage.Sets/src/mage/cards/f/FlickerOfFate.java +++ b/Mage.Sets/src/mage/cards/f/FlickerOfFate.java @@ -4,8 +4,7 @@ import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import java.util.UUID; @@ -15,21 +14,12 @@ import java.util.UUID; */ public final class FlickerOfFate extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public FlickerOfFate(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Exile target creature or enchantment, then return it to the battlefield under its owner's control. this.getSpellAbility().addEffect(new ExileThenReturnTargetEffect(false, false)); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); } private FlickerOfFate(final FlickerOfFate card) { diff --git a/Mage.Sets/src/mage/cards/k/KayaIntangibleSlayer.java b/Mage.Sets/src/mage/cards/k/KayaIntangibleSlayer.java index 53038628504..93e4cf7ef76 100644 --- a/Mage.Sets/src/mage/cards/k/KayaIntangibleSlayer.java +++ b/Mage.Sets/src/mage/cards/k/KayaIntangibleSlayer.java @@ -1,7 +1,5 @@ package mage.cards.k; -import java.util.UUID; - import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -10,31 +8,23 @@ import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.constants.*; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.UUID; + /** * @author TheElk801 */ public final class KayaIntangibleSlayer extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public KayaIntangibleSlayer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{W}{B}{B}"); @@ -57,7 +47,7 @@ public final class KayaIntangibleSlayer extends CardImpl { // -3: Exile target creature or enchantment. If it wasn't an Aura, create a token that's a copy of it, except it's a 1/1 white Spirit creature with flying in addition to its other types. ability = new LoyaltyAbility(new KayaIntangibleSlayerExileEffect(), -3); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MireInMisery.java b/Mage.Sets/src/mage/cards/m/MireInMisery.java index 78d79df94c3..68b2e234b6a 100644 --- a/Mage.Sets/src/mage/cards/m/MireInMisery.java +++ b/Mage.Sets/src/mage/cards/m/MireInMisery.java @@ -4,8 +4,7 @@ import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import java.util.UUID; @@ -14,20 +13,11 @@ import java.util.UUID; */ public final class MireInMisery extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("a creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public MireInMisery(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Each opponent sacrifices a creature or enchantment. - this.getSpellAbility().addEffect(new SacrificeOpponentsEffect(filter)); + this.getSpellAbility().addEffect(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); } private MireInMisery(final MireInMisery card) { diff --git a/Mage.Sets/src/mage/cards/m/Mortify.java b/Mage.Sets/src/mage/cards/m/Mortify.java index f3c29f5e4cd..83d5105be3d 100644 --- a/Mage.Sets/src/mage/cards/m/Mortify.java +++ b/Mage.Sets/src/mage/cards/m/Mortify.java @@ -1,34 +1,24 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import java.util.UUID; + /** * @author Loki */ public final class Mortify extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate())); - } - public Mortify(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{B}"); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); } private Mortify(final Mortify card) { diff --git a/Mage.Sets/src/mage/cards/o/OneWithTheStars.java b/Mage.Sets/src/mage/cards/o/OneWithTheStars.java index 1b641db4363..183575959f8 100644 --- a/Mage.Sets/src/mage/cards/o/OneWithTheStars.java +++ b/Mage.Sets/src/mage/cards/o/OneWithTheStars.java @@ -8,8 +8,7 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -21,14 +20,6 @@ import java.util.UUID; */ public final class OneWithTheStars extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } public OneWithTheStars(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); @@ -36,7 +27,7 @@ public final class OneWithTheStars extends CardImpl { this.subtype.add(SubType.AURA); // Enchant creature or enchantment - TargetPermanent auraTarget = new TargetPermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget); diff --git a/Mage.Sets/src/mage/cards/s/ShatterTheOath.java b/Mage.Sets/src/mage/cards/s/ShatterTheOath.java index dae3efef7a2..5cf803fad39 100644 --- a/Mage.Sets/src/mage/cards/s/ShatterTheOath.java +++ b/Mage.Sets/src/mage/cards/s/ShatterTheOath.java @@ -6,8 +6,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.RoleType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FirstTargetPointer; @@ -20,21 +19,12 @@ import java.util.UUID; */ public final class ShatterTheOath extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public ShatterTheOath(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // Destroy target creature or enchantment. Create a Wicked Role token attached to up to one target creature you control. this.getSpellAbility().addEffect(new DestroyTargetEffect().setTargetPointer(new FirstTargetPointer())); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); this.getSpellAbility().addEffect(new CreateRoleAttachedTargetEffect(RoleType.WICKED).setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1)); } diff --git a/Mage.Sets/src/mage/cards/u/UrnOfGodfire.java b/Mage.Sets/src/mage/cards/u/UrnOfGodfire.java index 129510c43bf..b756d87fa7b 100644 --- a/Mage.Sets/src/mage/cards/u/UrnOfGodfire.java +++ b/Mage.Sets/src/mage/cards/u/UrnOfGodfire.java @@ -10,8 +10,7 @@ import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import java.util.UUID; @@ -21,15 +20,6 @@ import java.util.UUID; */ public final class UrnOfGodfire extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or enchantment"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public UrnOfGodfire(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); @@ -40,7 +30,7 @@ public final class UrnOfGodfire extends CardImpl { Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(6)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WitheringTorment.java b/Mage.Sets/src/mage/cards/w/WitheringTorment.java new file mode 100644 index 00000000000..2d5ee441206 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WitheringTorment.java @@ -0,0 +1,35 @@ +package mage.cards.w; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WitheringTorment extends CardImpl { + + public WitheringTorment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Destroy target creature or enchantment. You lose 2 life. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); + } + + private WitheringTorment(final WitheringTorment card) { + super(card); + } + + @Override + public WitheringTorment copy() { + return new WitheringTorment(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 3211d12fe1f..86f2fd27d9b 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -163,6 +163,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Victor, Valgavoth's Seneschal", 238, Rarity.RARE, mage.cards.v.VictorValgavothsSeneschal.class)); cards.add(new SetCardInfo("Wary Watchdog", 206, Rarity.COMMON, mage.cards.w.WaryWatchdog.class)); cards.add(new SetCardInfo("Winter, Misanthropic Guide", 240, Rarity.RARE, mage.cards.w.WinterMisanthropicGuide.class)); + cards.add(new SetCardInfo("Withering Torment", 124, Rarity.UNCOMMON, mage.cards.w.WitheringTorment.class)); cards.add(new SetCardInfo("Zimone, All-Questioning", 241, Rarity.RARE, mage.cards.z.ZimoneAllQuestioning.class)); cards.removeIf(setCardInfo -> setCardInfo.getName().startsWith("Overlord")); diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index afd6a3958b7..adcaf221b1e 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -346,6 +346,16 @@ public final class StaticFilters { FILTER_PERMANENT_ARTIFACT_OR_CREATURE.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT = new FilterPermanent("creature or enchantment"); + + static { + FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT = new FilterPermanent("artifact, creature, or enchantment"); static { From a29706f4282f1c826399fd460b67af2d552e13d2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:04:37 -0400 Subject: [PATCH 04/43] [DSK] Implement Diversion Specialist --- .../src/mage/cards/d/DiversionSpecialist.java | 49 +++++++++++++++++++ .../src/mage/cards/p/PopularEgotist.java | 16 +----- .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../main/java/mage/filter/StaticFilters.java | 11 +++++ 4 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/DiversionSpecialist.java diff --git a/Mage.Sets/src/mage/cards/d/DiversionSpecialist.java b/Mage.Sets/src/mage/cards/d/DiversionSpecialist.java new file mode 100644 index 00000000000..0a40c60a35a --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiversionSpecialist.java @@ -0,0 +1,49 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DiversionSpecialist extends CardImpl { + + public DiversionSpecialist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // {1}, Sacrifice another creature or enchantment: Exile the top card of your library. You may play it this turn. + Ability ability = new SimpleActivatedAbility(new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), new GenericManaCost(1)); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT)); + this.addAbility(ability); + } + + private DiversionSpecialist(final DiversionSpecialist card) { + super(card); + } + + @Override + public DiversionSpecialist copy() { + return new DiversionSpecialist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PopularEgotist.java b/Mage.Sets/src/mage/cards/p/PopularEgotist.java index b631a3b7a12..39e06eb8f49 100644 --- a/Mage.Sets/src/mage/cards/p/PopularEgotist.java +++ b/Mage.Sets/src/mage/cards/p/PopularEgotist.java @@ -17,9 +17,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -29,17 +26,6 @@ import java.util.UUID; */ public final class PopularEgotist extends CardImpl { - private static final FilterControlledPermanent filter - = new FilterControlledPermanent("another creature or enchantment"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - public PopularEgotist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); @@ -52,7 +38,7 @@ public final class PopularEgotist extends CardImpl { Ability ability = new SimpleActivatedAbility(new GainAbilitySourceEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn ), new ManaCostsImpl<>("{1}{B}")); - ability.addCost(new SacrificeTargetCost(filter)); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT)); ability.addEffect(new TapSourceEffect().setText("tap it")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 86f2fd27d9b..1541ce3c4cf 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -47,6 +47,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Defiant Survivor", 175, Rarity.UNCOMMON, mage.cards.d.DefiantSurvivor.class)); cards.add(new SetCardInfo("Demonic Counsel", 92, Rarity.RARE, mage.cards.d.DemonicCounsel.class)); cards.add(new SetCardInfo("Disturbing Mirth", 212, Rarity.UNCOMMON, mage.cards.d.DisturbingMirth.class)); + cards.add(new SetCardInfo("Diversion Specialist", 132, Rarity.UNCOMMON, mage.cards.d.DiversionSpecialist.class)); cards.add(new SetCardInfo("Doomsday Excruciator", 94, Rarity.RARE, mage.cards.d.DoomsdayExcruciator.class)); cards.add(new SetCardInfo("Drag to the Roots", 213, Rarity.UNCOMMON, mage.cards.d.DragToTheRoots.class)); cards.add(new SetCardInfo("Emerge from the Cocoon", 5, Rarity.COMMON, mage.cards.e.EmergeFromTheCocoon.class)); diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index adcaf221b1e..17e1f1bea73 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -356,6 +356,17 @@ public final class StaticFilters { FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT.setLockedFilter(true); } + + public static final FilterPermanent FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT = new FilterPermanent("another creature or enchantment"); + + static { + FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT = new FilterPermanent("artifact, creature, or enchantment"); static { From 95384a72f36e1d65831122a614c6e183eae569bb Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:09:26 -0400 Subject: [PATCH 05/43] [DSK] Implement Enduring Courage --- .../src/mage/cards/e/EnduringCourage.java | 52 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EnduringCourage.java diff --git a/Mage.Sets/src/mage/cards/e/EnduringCourage.java b/Mage.Sets/src/mage/cards/e/EnduringCourage.java new file mode 100644 index 00000000000..be65c188e04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnduringCourage.java @@ -0,0 +1,52 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EnduringGlimmerTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnduringCourage extends CardImpl { + + public EnduringCourage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.DOG); + this.subtype.add(SubType.GLIMMER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn. + Ability ability = new EntersBattlefieldAllTriggeredAbility( + new BoostTargetEffect(2, 0).setText("it gets +2/+0"), + StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL + ); + ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setText("and gains haste until end of turn")); + this.addAbility(ability); + + // When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment. + this.addAbility(new EnduringGlimmerTriggeredAbility()); + } + + private EnduringCourage(final EnduringCourage card) { + super(card); + } + + @Override + public EnduringCourage copy() { + return new EnduringCourage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 1541ce3c4cf..8499ca62683 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -51,6 +51,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Doomsday Excruciator", 94, Rarity.RARE, mage.cards.d.DoomsdayExcruciator.class)); cards.add(new SetCardInfo("Drag to the Roots", 213, Rarity.UNCOMMON, mage.cards.d.DragToTheRoots.class)); cards.add(new SetCardInfo("Emerge from the Cocoon", 5, Rarity.COMMON, mage.cards.e.EmergeFromTheCocoon.class)); + cards.add(new SetCardInfo("Enduring Courage", 133, Rarity.RARE, mage.cards.e.EnduringCourage.class)); cards.add(new SetCardInfo("Enduring Curiosity", 51, Rarity.RARE, mage.cards.e.EnduringCuriosity.class)); cards.add(new SetCardInfo("Enduring Innocence", 6, Rarity.RARE, mage.cards.e.EnduringInnocence.class)); cards.add(new SetCardInfo("Enduring Tenacity", 95, Rarity.RARE, mage.cards.e.EnduringTenacity.class)); From 1b358f47c943bb1fa40d8c50e7d93751b80e0b82 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:10:19 -0400 Subject: [PATCH 06/43] [DSK] Implement Gremlin Tamer --- Mage.Sets/src/mage/cards/g/GremlinTamer.java | 39 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 40 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GremlinTamer.java diff --git a/Mage.Sets/src/mage/cards/g/GremlinTamer.java b/Mage.Sets/src/mage/cards/g/GremlinTamer.java new file mode 100644 index 00000000000..897764dd61e --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GremlinTamer.java @@ -0,0 +1,39 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.abilityword.EerieAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.Gremlin11Token; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GremlinTamer extends CardImpl { + + public GremlinTamer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Eerie - Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 1/1 red Gremlin creature token. + this.addAbility(new EerieAbility(new CreateTokenEffect(new Gremlin11Token()))); + } + + private GremlinTamer(final GremlinTamer card) { + super(card); + } + + @Override + public GremlinTamer copy() { + return new GremlinTamer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 8499ca62683..2a566624b03 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -80,6 +80,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Glimmerlight", 249, Rarity.COMMON, mage.cards.g.Glimmerlight.class)); cards.add(new SetCardInfo("Gloomlake Verge", 260, Rarity.RARE, mage.cards.g.GloomlakeVerge.class)); cards.add(new SetCardInfo("Grasping Longneck", 180, Rarity.COMMON, mage.cards.g.GraspingLongneck.class)); + cards.add(new SetCardInfo("Gremlin Tamer", 215, Rarity.UNCOMMON, mage.cards.g.GremlinTamer.class)); cards.add(new SetCardInfo("Growing Dread", 216, Rarity.UNCOMMON, mage.cards.g.GrowingDread.class)); cards.add(new SetCardInfo("Hand That Feeds", 139, Rarity.COMMON, mage.cards.h.HandThatFeeds.class)); cards.add(new SetCardInfo("Hardened Escort", 16, Rarity.COMMON, mage.cards.h.HardenedEscort.class)); From 627d532e4b0a6b6e3101ca63a9501c45d3c60213 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:15:49 -0400 Subject: [PATCH 07/43] [DSK] Implement Midnight Mayhem --- .../src/mage/cards/m/MidnightMayhem.java | 49 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MidnightMayhem.java diff --git a/Mage.Sets/src/mage/cards/m/MidnightMayhem.java b/Mage.Sets/src/mage/cards/m/MidnightMayhem.java new file mode 100644 index 00000000000..53522fc47be --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MidnightMayhem.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.game.permanent.token.Gremlin11Token; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MidnightMayhem extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.GREMLIN, ""); + + public MidnightMayhem(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{W}"); + + // Create three 1/1 red Gremlin creature tokens. Gremlins you control gain menace, lifelink, and haste until end of turn. + this.getSpellAbility().addEffect(new CreateTokenEffect(new Gremlin11Token(), 3)); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + new MenaceAbility(true), Duration.EndOfTurn, filter + ).setText("Gremlins you control gain menace")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, filter + ).setText(", lifelink")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, filter + ).setText(", and haste until end of turn")); + } + + private MidnightMayhem(final MidnightMayhem card) { + super(card); + } + + @Override + public MidnightMayhem copy() { + return new MidnightMayhem(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 2a566624b03..f707ae80bff 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -98,6 +98,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Leyline of Resonance", 143, Rarity.RARE, mage.cards.l.LeylineOfResonance.class)); cards.add(new SetCardInfo("Leyline of the Void", 106, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Glimmer", 19, Rarity.UNCOMMON, mage.cards.l.LionheartGlimmer.class)); + cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); cards.add(new SetCardInfo("Most Valuable Slayer", 144, Rarity.COMMON, mage.cards.m.MostValuableSlayer.class)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Murder", 110, Rarity.COMMON, mage.cards.m.Murder.class)); From 83d3673d9a031a26b512660a639d50f9a1cf69c0 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:20:20 -0400 Subject: [PATCH 08/43] [DSK] Implement Betrayer's Bargain --- .../src/mage/cards/b/BetrayersBargain.java | 44 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BetrayersBargain.java diff --git a/Mage.Sets/src/mage/cards/b/BetrayersBargain.java b/Mage.Sets/src/mage/cards/b/BetrayersBargain.java new file mode 100644 index 00000000000..8dc11cb79e0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BetrayersBargain.java @@ -0,0 +1,44 @@ +package mage.cards.b; + +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BetrayersBargain extends CardImpl { + + public BetrayersBargain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // As an additional cost to cast this spell, sacrifice a creature or enchantment or pay {2}. + this.getSpellAbility().addCost(new OrCost( + "sacrifice a creature or enchantment or pay {2}", + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT), new GenericManaCost(2) + )); + + // Betrayer's Bargain deals 5 damage to target creature. If that creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private BetrayersBargain(final BetrayersBargain card) { + super(card); + } + + @Override + public BetrayersBargain copy() { + return new BetrayersBargain(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index f707ae80bff..15228402963 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -30,6 +30,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Baseball Bat", 209, Rarity.UNCOMMON, mage.cards.b.BaseballBat.class)); cards.add(new SetCardInfo("Bashful Beastie", 169, Rarity.COMMON, mage.cards.b.BashfulBeastie.class)); cards.add(new SetCardInfo("Bear Trap", 243, Rarity.COMMON, mage.cards.b.BearTrap.class)); + cards.add(new SetCardInfo("Betrayer's Bargain", 126, Rarity.UNCOMMON, mage.cards.b.BetrayersBargain.class)); cards.add(new SetCardInfo("Blazemire Verge", 256, Rarity.RARE, mage.cards.b.BlazemireVerge.class)); cards.add(new SetCardInfo("Bleeding Woods", 257, Rarity.COMMON, mage.cards.b.BleedingWoods.class)); cards.add(new SetCardInfo("Break Down the Door", 170, Rarity.UNCOMMON, mage.cards.b.BreakDownTheDoor.class)); From 0ffb3e2349df87da998c1f246e3ee14247b87815 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 17:26:25 -0400 Subject: [PATCH 09/43] [DSK] Implement Arabella, Abandoned Doll --- .../mage/cards/a/ArabellaAbandonedDoll.java | 57 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArabellaAbandonedDoll.java diff --git a/Mage.Sets/src/mage/cards/a/ArabellaAbandonedDoll.java b/Mage.Sets/src/mage/cards/a/ArabellaAbandonedDoll.java new file mode 100644 index 00000000000..56ed1e66ca7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArabellaAbandonedDoll.java @@ -0,0 +1,57 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArabellaAbandonedDoll extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterControlledCreaturePermanent("creatures you control with power 2 or less"), null + ); + private static final Hint hint = new ValueHint("Creatures you control with power 2 or less", xValue); + + public ArabellaAbandonedDoll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TOY); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever Arabella, Abandoned Doll attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less. + Ability ability = new AttacksTriggeredAbility( + new DamagePlayersEffect(xValue, TargetController.OPPONENT) + .setText("it deals X damage to each opponent") + ); + ability.addEffect(new GainLifeEffect(xValue)); + this.addAbility(ability.addHint(hint)); + } + + private ArabellaAbandonedDoll(final ArabellaAbandonedDoll card) { + super(card); + } + + @Override + public ArabellaAbandonedDoll copy() { + return new ArabellaAbandonedDoll(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 15228402963..5091a0890e4 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -25,6 +25,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Altanak, the Thrice-Called", 166, Rarity.UNCOMMON, mage.cards.a.AltanakTheThriceCalled.class)); cards.add(new SetCardInfo("Anthropede", 167, Rarity.COMMON, mage.cards.a.Anthropede.class)); cards.add(new SetCardInfo("Appendage Amalgam", 83, Rarity.COMMON, mage.cards.a.AppendageAmalgam.class)); + cards.add(new SetCardInfo("Arabella, Abandoned Doll", 208, Rarity.UNCOMMON, mage.cards.a.ArabellaAbandonedDoll.class)); cards.add(new SetCardInfo("Attack-in-the-Box", 242, Rarity.UNCOMMON, mage.cards.a.AttackInTheBox.class)); cards.add(new SetCardInfo("Balustrade Wurm", 168, Rarity.RARE, mage.cards.b.BalustradeWurm.class)); cards.add(new SetCardInfo("Baseball Bat", 209, Rarity.UNCOMMON, mage.cards.b.BaseballBat.class)); From dde6c758ba009ddaf6035d948c7d9cd5db0d6644 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:01:31 -0400 Subject: [PATCH 10/43] [DSK] Implement Fanatic of the Harrowing --- .../mage/cards/f/FanaticOfTheHarrowing.java | 78 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 79 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FanaticOfTheHarrowing.java diff --git a/Mage.Sets/src/mage/cards/f/FanaticOfTheHarrowing.java b/Mage.Sets/src/mage/cards/f/FanaticOfTheHarrowing.java new file mode 100644 index 00000000000..dd337f0a4e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FanaticOfTheHarrowing.java @@ -0,0 +1,78 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FanaticOfTheHarrowing extends CardImpl { + + public FanaticOfTheHarrowing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Fanatic of the Harrowing enters, each player discards a card. If you discarded a card this way, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new FanaticOfTheHarrowingEffect())); + } + + private FanaticOfTheHarrowing(final FanaticOfTheHarrowing card) { + super(card); + } + + @Override + public FanaticOfTheHarrowing copy() { + return new FanaticOfTheHarrowing(this); + } +} + +class FanaticOfTheHarrowingEffect extends OneShotEffect { + + FanaticOfTheHarrowingEffect() { + super(Outcome.Benefit); + staticText = "each player discards a card. If you discarded a card this way, draw a card"; + } + + private FanaticOfTheHarrowingEffect(final FanaticOfTheHarrowingEffect effect) { + super(effect); + } + + @Override + public FanaticOfTheHarrowingEffect copy() { + return new FanaticOfTheHarrowingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean flag = false; + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + continue; + } + if (!player.discard(1, false, false, source, game).isEmpty() + && player.equals(source.getControllerId())) { + flag = true; + } + } + if (flag) { + game.getPlayer(source.getControllerId()).drawCards(1, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 5091a0890e4..b0a89a1c637 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -59,6 +59,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Enduring Tenacity", 95, Rarity.RARE, mage.cards.e.EnduringTenacity.class)); cards.add(new SetCardInfo("Etched Cornfield", 258, Rarity.COMMON, mage.cards.e.EtchedCornfield.class)); cards.add(new SetCardInfo("Ethereal Armor", 7, Rarity.UNCOMMON, mage.cards.e.EtherealArmor.class)); + cards.add(new SetCardInfo("Fanatic of the Harrowing", 96, Rarity.COMMON, mage.cards.f.FanaticOfTheHarrowing.class)); cards.add(new SetCardInfo("Fear of Being Hunted", 134, Rarity.UNCOMMON, mage.cards.f.FearOfBeingHunted.class)); cards.add(new SetCardInfo("Fear of Failed Tests", 55, Rarity.UNCOMMON, mage.cards.f.FearOfFailedTests.class)); cards.add(new SetCardInfo("Fear of Falling", 56, Rarity.UNCOMMON, mage.cards.f.FearOfFalling.class)); From 8d1ad34ecfe3d2566b9888f8ba88640f37ba0400 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:16:59 -0400 Subject: [PATCH 11/43] [DSK] Implement Oblivious Bookworm --- .../src/mage/cards/o/ObliviousBookworm.java | 116 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 117 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/ObliviousBookworm.java diff --git a/Mage.Sets/src/mage/cards/o/ObliviousBookworm.java b/Mage.Sets/src/mage/cards/o/ObliviousBookworm.java new file mode 100644 index 00000000000..e93846523b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObliviousBookworm.java @@ -0,0 +1,116 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObliviousBookworm extends CardImpl { + + public ObliviousBookworm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // At the beginning of your end step, you may draw a card. If you do, discard a card unless a permanent entered the battlefield face down under your control this turn or you turned a permanent face up this turn. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new DrawCardSourceControllerEffect(1), TargetController.YOU, true + ); + ability.addEffect(new ConditionalOneShotEffect( + new DiscardControllerEffect(1), ObliviousBookwormCondition.instance, "If you do, discard " + + "a card unless a permanent entered the battlefield face down under your control " + + "this turn or you turned a permanent face up this turn" + )); + this.addAbility(ability.addHint(ObliviousBookwormCondition.getHint()), new ObliviousBookwormWatcher()); + } + + private ObliviousBookworm(final ObliviousBookworm card) { + super(card); + } + + @Override + public ObliviousBookworm copy() { + return new ObliviousBookworm(this); + } +} + +enum ObliviousBookwormCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint( + new InvertCondition(instance), "You had a face-down " + + "permanent enter or turned a permanent face-up this turn" + ); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return !ObliviousBookwormWatcher.checkPlayer(game, source); + } +} + +class ObliviousBookwormWatcher extends Watcher { + + private final Set set = new HashSet<>(); + + ObliviousBookwormWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case ENTERS_THE_BATTLEFIELD: + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent != null && permanent.isFaceDown(game)) { + set.add(permanent.getControllerId()); + } + return; + case TURNED_FACE_UP: + set.add(event.getPlayerId()); + } + } + + @Override + public void reset() { + set.clear(); + super.reset(); + } + + static boolean checkPlayer(Game game, Ability source) { + return game + .getState() + .getWatcher(ObliviousBookwormWatcher.class) + .set + .contains(source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index b0a89a1c637..49a71313a6b 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -107,6 +107,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Murder", 110, Rarity.COMMON, mage.cards.m.Murder.class)); cards.add(new SetCardInfo("Murky Sewer", 263, Rarity.COMMON, mage.cards.m.MurkySewer.class)); cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class)); + cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class)); cards.add(new SetCardInfo("Overlord of the Boilerbilges", 146, Rarity.MYTHIC, mage.cards.o.OverlordOfTheBoilerbilges.class)); cards.add(new SetCardInfo("Overlord of the Floodpits", 68, Rarity.MYTHIC, mage.cards.o.OverlordOfTheFloodpits.class)); cards.add(new SetCardInfo("Overlord of the Hauntwoods", 194, Rarity.MYTHIC, mage.cards.o.OverlordOfTheHauntwoods.class)); From e5b447f3382c0c37ae574d2f2f39466fd1450b47 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:23:20 -0400 Subject: [PATCH 12/43] [DSK] Implement Rootwise Survivor --- .../src/mage/cards/r/RootwiseSurvivor.java | 57 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RootwiseSurvivor.java diff --git a/Mage.Sets/src/mage/cards/r/RootwiseSurvivor.java b/Mage.Sets/src/mage/cards/r/RootwiseSurvivor.java new file mode 100644 index 00000000000..c5838daaa80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RootwiseSurvivor.java @@ -0,0 +1,57 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.abilityword.SurvivalAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RootwiseSurvivor extends CardImpl { + + public RootwiseSurvivor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SURVIVOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Survival -- At the beginning of your second main phase, if Rootwise Survivor is tapped, put three +1/+1 counters on up to one target land you control. That land becomes a 0/0 Elemental creature in addition to its other types. It gains haste until your next turn. + Ability ability = new SurvivalAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(3))); + ability.addEffect(new BecomesCreatureTargetEffect(new CreatureToken( + 0, 0, "0/0 Elemental creature" + ).withSubType(SubType.ELEMENTAL), false, false, Duration.EndOfTurn)); + ability.addTarget(new TargetLandPermanent(0, 1)); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("it gains haste until your next turn")); + this.addAbility(ability); + } + + private RootwiseSurvivor(final RootwiseSurvivor card) { + super(card); + } + + @Override + public RootwiseSurvivor copy() { + return new RootwiseSurvivor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 49a71313a6b..9e5cf62aafc 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -128,6 +128,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Razortrap Gorge", 267, Rarity.COMMON, mage.cards.r.RazortrapGorge.class)); cards.add(new SetCardInfo("Resurrected Cultist", 115, Rarity.COMMON, mage.cards.r.ResurrectedCultist.class)); cards.add(new SetCardInfo("Rite of the Moth", 229, Rarity.UNCOMMON, mage.cards.r.RiteOfTheMoth.class)); + cards.add(new SetCardInfo("Rootwise Survivor", 196, Rarity.UNCOMMON, mage.cards.r.RootwiseSurvivor.class)); cards.add(new SetCardInfo("Savior of the Small", 27, Rarity.UNCOMMON, mage.cards.s.SaviorOfTheSmall.class)); cards.add(new SetCardInfo("Scrabbling Skullcrab", 71, Rarity.UNCOMMON, mage.cards.s.ScrabblingSkullcrab.class)); cards.add(new SetCardInfo("Screaming Nemesis", 157, Rarity.MYTHIC, mage.cards.s.ScreamingNemesis.class)); From d2505ad33ab52f54c5f5bbb5d917b117855994b3 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:27:01 -0400 Subject: [PATCH 13/43] [DSK] Implement Wildfire Wickerfolk --- .../src/mage/cards/w/WildfireWickerfolk.java | 57 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WildfireWickerfolk.java diff --git a/Mage.Sets/src/mage/cards/w/WildfireWickerfolk.java b/Mage.Sets/src/mage/cards/w/WildfireWickerfolk.java new file mode 100644 index 00000000000..f473e11cf01 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildfireWickerfolk.java @@ -0,0 +1,57 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildfireWickerfolk extends CardImpl { + + public WildfireWickerfolk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.SCARECROW); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Delirium -- Wildfire Wickerfolk gets +1/+1 and has trample as long as there are four or more card types among cards in your graveyard. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + DeliriumCondition.instance, "{this} gets +1/+1" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), DeliriumCondition.instance, + "and has trample as long as there are four or more card types among cards in your graveyard" + )); + this.addAbility(ability.setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardHint.YOU)); + } + + private WildfireWickerfolk(final WildfireWickerfolk card) { + super(card); + } + + @Override + public WildfireWickerfolk copy() { + return new WildfireWickerfolk(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 9e5cf62aafc..824620a6fe6 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -171,6 +171,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Vicious Clown", 163, Rarity.COMMON, mage.cards.v.ViciousClown.class)); cards.add(new SetCardInfo("Victor, Valgavoth's Seneschal", 238, Rarity.RARE, mage.cards.v.VictorValgavothsSeneschal.class)); cards.add(new SetCardInfo("Wary Watchdog", 206, Rarity.COMMON, mage.cards.w.WaryWatchdog.class)); + cards.add(new SetCardInfo("Wildfire Wickerfolk", 239, Rarity.UNCOMMON, mage.cards.w.WildfireWickerfolk.class)); cards.add(new SetCardInfo("Winter, Misanthropic Guide", 240, Rarity.RARE, mage.cards.w.WinterMisanthropicGuide.class)); cards.add(new SetCardInfo("Withering Torment", 124, Rarity.UNCOMMON, mage.cards.w.WitheringTorment.class)); cards.add(new SetCardInfo("Zimone, All-Questioning", 241, Rarity.RARE, mage.cards.z.ZimoneAllQuestioning.class)); From 5f580ab69278d5983688a821110fc3b028ba84e5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:34:56 -0400 Subject: [PATCH 14/43] [DSK] Implement Wickerfolk Thresher --- .../src/mage/cards/w/WickerfolkThresher.java | 84 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 85 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WickerfolkThresher.java diff --git a/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java b/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java new file mode 100644 index 00000000000..9d405b5897f --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WickerfolkThresher.java @@ -0,0 +1,84 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WickerfolkThresher extends CardImpl { + + public WickerfolkThresher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.SCARECROW); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Delirium -- Whenever Wickerfolk Thresher attacks, if there are four or more card types among cards in your graveyard, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility(new WickerfolkThresherEffect()), + DeliriumCondition.instance, "Whenever {this} attacks, if there are four or more card types " + + "among cards in your graveyard, look at the top card of your library. If it's a land card, you may " + + "put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand." + ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardHint.YOU)); + } + + private WickerfolkThresher(final WickerfolkThresher card) { + super(card); + } + + @Override + public WickerfolkThresher copy() { + return new WickerfolkThresher(this); + } +} + +class WickerfolkThresherEffect extends OneShotEffect { + + WickerfolkThresherEffect() { + super(Outcome.Benefit); + } + + private WickerfolkThresherEffect(final WickerfolkThresherEffect effect) { + super(effect); + } + + @Override + public WickerfolkThresherEffect copy() { + return new WickerfolkThresherEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.lookAtCards("Top card of library", card, game); + if (card.isLand(game) && player.chooseUse(Outcome.PutLandInPlay, "Put it onto the battlefield?", source, game)) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + if (!Zone.BATTLEFIELD.match(game.getState().getZone(card.getId()))) { + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 824620a6fe6..6b99bd3b82e 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -171,6 +171,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Vicious Clown", 163, Rarity.COMMON, mage.cards.v.ViciousClown.class)); cards.add(new SetCardInfo("Victor, Valgavoth's Seneschal", 238, Rarity.RARE, mage.cards.v.VictorValgavothsSeneschal.class)); cards.add(new SetCardInfo("Wary Watchdog", 206, Rarity.COMMON, mage.cards.w.WaryWatchdog.class)); + cards.add(new SetCardInfo("Wickerfolk Thresher", 207, Rarity.UNCOMMON, mage.cards.w.WickerfolkThresher.class)); cards.add(new SetCardInfo("Wildfire Wickerfolk", 239, Rarity.UNCOMMON, mage.cards.w.WildfireWickerfolk.class)); cards.add(new SetCardInfo("Winter, Misanthropic Guide", 240, Rarity.RARE, mage.cards.w.WinterMisanthropicGuide.class)); cards.add(new SetCardInfo("Withering Torment", 124, Rarity.UNCOMMON, mage.cards.w.WitheringTorment.class)); From 04fb295dde552ba81599523f90128ca78266ea31 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 19:49:40 -0400 Subject: [PATCH 15/43] [DSK] Implement Hedge Shredder --- Mage.Sets/src/mage/cards/h/HedgeShredder.java | 102 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 103 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/HedgeShredder.java diff --git a/Mage.Sets/src/mage/cards/h/HedgeShredder.java b/Mage.Sets/src/mage/cards/h/HedgeShredder.java new file mode 100644 index 00000000000..19dfb28b325 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HedgeShredder.java @@ -0,0 +1,102 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeBatchEvent; +import mage.game.events.ZoneChangeEvent; +import mage.target.targetpointer.FixedTargets; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class HedgeShredder extends CardImpl { + + public HedgeShredder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}{G}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Whenever Hedge Shredder attacks, you may mill two cards. + this.addAbility(new AttacksTriggeredAbility(new MillCardsControllerEffect(2), true)); + + // Whenever one or more land cards are put into your graveyard from your library, put them onto the battlefield tapped. + this.addAbility(new HedgeShredderTriggeredAbility()); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private HedgeShredder(final HedgeShredder card) { + super(card); + } + + @Override + public HedgeShredder copy() { + return new HedgeShredder(this); + } +} + +class HedgeShredderTriggeredAbility extends TriggeredAbilityImpl { + + HedgeShredderTriggeredAbility() { + super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect()); + } + + private HedgeShredderTriggeredAbility(final HedgeShredderTriggeredAbility ability) { + super(ability); + } + + @Override + public HedgeShredderTriggeredAbility copy() { + return new HedgeShredderTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Set set = ((ZoneChangeBatchEvent) event).getEvents() + .stream() + .filter(e -> isControlledBy(e.getPlayerId())) + .filter(e -> e.getFromZone().match(Zone.LIBRARY)) + .filter(e -> e.getToZone().match(Zone.GRAVEYARD)) + .map(ZoneChangeEvent::getTargetId) + .map(game::getCard) + .filter(Objects::nonNull) + .filter(card -> card.isLand(game)) + .collect(Collectors.toSet()); + if (set.isEmpty()) { + return false; + } + this.getEffects().setTargetPointer(new FixedTargets(set, game)); + return true; + } + + @Override + public String getRule() { + return "Whenever one or more land cards are put into your graveyard " + + "from your library, put them onto the battlefield tapped."; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 6b99bd3b82e..aff0da92a12 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -87,6 +87,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Growing Dread", 216, Rarity.UNCOMMON, mage.cards.g.GrowingDread.class)); cards.add(new SetCardInfo("Hand That Feeds", 139, Rarity.COMMON, mage.cards.h.HandThatFeeds.class)); cards.add(new SetCardInfo("Hardened Escort", 16, Rarity.COMMON, mage.cards.h.HardenedEscort.class)); + cards.add(new SetCardInfo("Hedge Shredder", 183, Rarity.RARE, mage.cards.h.HedgeShredder.class)); cards.add(new SetCardInfo("House Cartographer", 185, Rarity.UNCOMMON, mage.cards.h.HouseCartographer.class)); cards.add(new SetCardInfo("Hushwood Verge", 261, Rarity.RARE, mage.cards.h.HushwoodVerge.class)); cards.add(new SetCardInfo("Impossible Inferno", 140, Rarity.COMMON, mage.cards.i.ImpossibleInferno.class)); From 1ab4c1858da5d0d243f25397f047a7fb3da4fafc Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 09:47:01 -0400 Subject: [PATCH 16/43] [DSK] Implement Nashi, Searchr in the Dark --- .../mage/cards/n/NashiSearcherInTheDark.java | 101 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 102 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NashiSearcherInTheDark.java diff --git a/Mage.Sets/src/mage/cards/n/NashiSearcherInTheDark.java b/Mage.Sets/src/mage/cards/n/NashiSearcherInTheDark.java new file mode 100644 index 00000000000..f3efe3694ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NashiSearcherInTheDark.java @@ -0,0 +1,101 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NashiSearcherInTheDark extends CardImpl { + + public NashiSearcherInTheDark(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.RAT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever Nashi, Searcher in the Dark deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new NashiSearcherInTheDarkEffect())); + } + + private NashiSearcherInTheDark(final NashiSearcherInTheDark card) { + super(card); + } + + @Override + public NashiSearcherInTheDark copy() { + return new NashiSearcherInTheDark(this); + } +} + +class NashiSearcherInTheDarkEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("legendary and/or enchantment cards"); + + static { + filter.add(Predicates.or( + SuperType.LEGENDARY.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + } + + NashiSearcherInTheDarkEffect() { + super(Outcome.Benefit); + staticText = "you mill that many cards. You may put any number of legendary and/or enchantment cards from " + + "among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on {this}"; + } + + private NashiSearcherInTheDarkEffect(final NashiSearcherInTheDarkEffect effect) { + super(effect); + } + + @Override + public NashiSearcherInTheDarkEffect copy() { + return new NashiSearcherInTheDarkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + int amount = (Integer) getValue("damage"); + if (player == null || amount < 1) { + return false; + } + Cards cards = player.millCards(amount, source, game); + TargetCard target = new TargetCard(0, Integer.MAX_VALUE, Zone.ALL, filter); + target.withNotTarget(true); + player.choose(Outcome.ReturnToHand, cards, target, source, game); + Cards toHand = new CardsImpl(target.getTargets()); + player.moveCards(toHand, Zone.HAND, source, game); + toHand.retainZone(Zone.HAND, game); + if (toHand.isEmpty()) { + Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) + .ifPresent(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index aff0da92a12..22a60db734d 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -107,6 +107,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Murder", 110, Rarity.COMMON, mage.cards.m.Murder.class)); cards.add(new SetCardInfo("Murky Sewer", 263, Rarity.COMMON, mage.cards.m.MurkySewer.class)); + cards.add(new SetCardInfo("Nashi, Searcher in the Dark", 223, Rarity.RARE, mage.cards.n.NashiSearcherInTheDark.class)); cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class)); cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class)); cards.add(new SetCardInfo("Overlord of the Boilerbilges", 146, Rarity.MYTHIC, mage.cards.o.OverlordOfTheBoilerbilges.class)); From 32a8601166815727416c99d28ebd4744d264576a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 09:59:25 -0400 Subject: [PATCH 17/43] [DSK] Implement Marina Vendrell's Grimoire --- .../mage/cards/m/MarinaVendrellsGrimoire.java | 107 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 108 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java diff --git a/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java b/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java new file mode 100644 index 00000000000..02d66919f0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarinaVendrellsGrimoire.java @@ -0,0 +1,107 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.dynamicvalue.common.SavedGainedLifeValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseGameSourceControllerEffect; +import mage.abilities.effects.common.continuous.DontLoseByZeroOrLessLifeEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarinaVendrellsGrimoire extends CardImpl { + + public MarinaVendrellsGrimoire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + + // When Marina Vendrell's Grimoire enters, if you cast it, draw five cards. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(5)), + CastFromEverywhereSourceCondition.instance, "When {this} enters, if you cast it, draw five cards." + )); + + // You have no maximum hand size and don't lose the game for having 0 or less life. + Ability ability = new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET + )); + ability.addEffect(new DontLoseByZeroOrLessLifeEffect(Duration.WhileOnBattlefield) + .setText("and don't lose the game for having 0 or less life")); + this.addAbility(ability); + + // Whenever you gain life, draw that many cards. + this.addAbility(new GainLifeControllerTriggeredAbility( + new DrawCardSourceControllerEffect(SavedGainedLifeValue.MANY) + )); + + // Whenever you lose life, discard that many cards. Then if you have no cards in hand, you lose the game. + this.addAbility(new MarinaVendrellsGrimoireTriggeredAbility()); + } + + private MarinaVendrellsGrimoire(final MarinaVendrellsGrimoire card) { + super(card); + } + + @Override + public MarinaVendrellsGrimoire copy() { + return new MarinaVendrellsGrimoire(this); + } +} + +class MarinaVendrellsGrimoireTriggeredAbility extends TriggeredAbilityImpl { + + MarinaVendrellsGrimoireTriggeredAbility() { + super(Zone.BATTLEFIELD, new DiscardControllerEffect(SavedDamageValue.MANY)); + this.addEffect(new ConditionalOneShotEffect( + new LoseGameSourceControllerEffect(), HellbentCondition.instance, + "Then if you have no cards in hand, you lose the game" + )); + this.setTriggerPhrase("Whenever you lose life, "); + } + + private MarinaVendrellsGrimoireTriggeredAbility(final MarinaVendrellsGrimoireTriggeredAbility ability) { + super(ability); + } + + @Override + public MarinaVendrellsGrimoireTriggeredAbility copy() { + return new MarinaVendrellsGrimoireTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_LIFE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + this.getEffects().setValue("damage", event.getAmount()); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 22a60db734d..e63ce4a79ad 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -102,6 +102,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Leyline of Resonance", 143, Rarity.RARE, mage.cards.l.LeylineOfResonance.class)); cards.add(new SetCardInfo("Leyline of the Void", 106, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Glimmer", 19, Rarity.UNCOMMON, mage.cards.l.LionheartGlimmer.class)); + cards.add(new SetCardInfo("Marina Vendrell's Grimoire", 64, Rarity.RARE, mage.cards.m.MarinaVendrellsGrimoire.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); cards.add(new SetCardInfo("Most Valuable Slayer", 144, Rarity.COMMON, mage.cards.m.MostValuableSlayer.class)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); From 2ed9a964ee430da66c876b815c238afbf2b69654 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 10:05:07 -0400 Subject: [PATCH 18/43] [DSK] Implement Orphans of the Wheat --- .../src/mage/cards/o/OrphansOfTheWheat.java | 94 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 95 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/OrphansOfTheWheat.java diff --git a/Mage.Sets/src/mage/cards/o/OrphansOfTheWheat.java b/Mage.Sets/src/mage/cards/o/OrphansOfTheWheat.java new file mode 100644 index 00000000000..126c7ed8bee --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrphansOfTheWheat.java @@ -0,0 +1,94 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class OrphansOfTheWheat extends CardImpl { + + public OrphansOfTheWheat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Orphans of the Wheat attacks, tap any number of untapped creatures you control. Orphans of the Wheat gets +1/+1 until end of turn for each creature tapped this way. + this.addAbility(new AttacksTriggeredAbility(new OrphansOfTheWheatEffect())); + } + + private OrphansOfTheWheat(final OrphansOfTheWheat card) { + super(card); + } + + @Override + public OrphansOfTheWheat copy() { + return new OrphansOfTheWheat(this); + } +} + +class OrphansOfTheWheatEffect extends OneShotEffect { + + OrphansOfTheWheatEffect() { + super(Outcome.Benefit); + staticText = "tap any number of untapped creatures you control. " + + "{this} gets +1/+1 until end of turn for each creature tapped this way"; + } + + private OrphansOfTheWheatEffect(final OrphansOfTheWheatEffect effect) { + super(effect); + } + + @Override + public OrphansOfTheWheatEffect copy() { + return new OrphansOfTheWheatEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetPermanent( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, true + ); + player.choose(Outcome.Tap, target, source, game); + List permanents = target + .getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + for (Permanent permanent : permanents) { + permanent.tap(source, game); + } + if (permanents.isEmpty()) { + return false; + } + int amount = permanents.size(); + game.addEffect(new BoostSourceEffect(amount, amount, Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index e63ce4a79ad..3275ea20cbd 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -111,6 +111,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Nashi, Searcher in the Dark", 223, Rarity.RARE, mage.cards.n.NashiSearcherInTheDark.class)); cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class)); cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class)); + cards.add(new SetCardInfo("Orphans of the Wheat", 22, Rarity.UNCOMMON, mage.cards.o.OrphansOfTheWheat.class)); cards.add(new SetCardInfo("Overlord of the Boilerbilges", 146, Rarity.MYTHIC, mage.cards.o.OverlordOfTheBoilerbilges.class)); cards.add(new SetCardInfo("Overlord of the Floodpits", 68, Rarity.MYTHIC, mage.cards.o.OverlordOfTheFloodpits.class)); cards.add(new SetCardInfo("Overlord of the Hauntwoods", 194, Rarity.MYTHIC, mage.cards.o.OverlordOfTheHauntwoods.class)); From a03da762eb3faaa32dffa3097d186775aec32cb5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 10:16:03 -0400 Subject: [PATCH 19/43] [DSK] Implement Sawblade Skinripper --- .../src/mage/cards/s/SawbladeSkinripper.java | 114 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 115 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SawbladeSkinripper.java diff --git a/Mage.Sets/src/mage/cards/s/SawbladeSkinripper.java b/Mage.Sets/src/mage/cards/s/SawbladeSkinripper.java new file mode 100644 index 00000000000..442ff4cb294 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SawbladeSkinripper.java @@ -0,0 +1,114 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetAnyTarget; +import mage.watchers.common.PermanentsSacrificedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SawbladeSkinripper extends CardImpl { + + public SawbladeSkinripper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // {2}, Sacrifice another creature or enchantment: Put a +1/+1 counter on Sawblade Skinripper. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(2) + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ANOTHER_CREATURE_OR_ENCHANTMENT)); + this.addAbility(ability); + + // At the beginning of your end step, if you sacrificed one or more permanents this turn, Sawblade Skinripper deals that much damage to any target. + ability = new BeginningOfEndStepTriggeredAbility( + new DamageTargetEffect(SawbladeSkinripperValue.instance), TargetController.YOU, + SawbladeSkinripperCondition.instance, false + ); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability, new PermanentsSacrificedWatcher()); + } + + private SawbladeSkinripper(final SawbladeSkinripper card) { + super(card); + } + + @Override + public SawbladeSkinripper copy() { + return new SawbladeSkinripper(this); + } +} + +enum SawbladeSkinripperCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return !game + .getState() + .getWatcher(PermanentsSacrificedWatcher.class) + .getThisTurnSacrificedPermanents(source.getControllerId()) + .isEmpty(); + } + + @Override + public String toString() { + return "you sacrificed one or more permanents this turn"; + } +} + +enum SawbladeSkinripperValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getState() + .getWatcher(PermanentsSacrificedWatcher.class) + .getThisTurnSacrificedPermanents(sourceAbility.getControllerId()) + .size(); + } + + @Override + public SawbladeSkinripperValue copy() { + return this; + } + + @Override + public String getMessage() { + return "that much"; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 3275ea20cbd..7e0aaa0869c 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -134,6 +134,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Rite of the Moth", 229, Rarity.UNCOMMON, mage.cards.r.RiteOfTheMoth.class)); cards.add(new SetCardInfo("Rootwise Survivor", 196, Rarity.UNCOMMON, mage.cards.r.RootwiseSurvivor.class)); cards.add(new SetCardInfo("Savior of the Small", 27, Rarity.UNCOMMON, mage.cards.s.SaviorOfTheSmall.class)); + cards.add(new SetCardInfo("Sawblade Skinripper", 231, Rarity.UNCOMMON, mage.cards.s.SawbladeSkinripper.class)); cards.add(new SetCardInfo("Scrabbling Skullcrab", 71, Rarity.UNCOMMON, mage.cards.s.ScrabblingSkullcrab.class)); cards.add(new SetCardInfo("Screaming Nemesis", 157, Rarity.MYTHIC, mage.cards.s.ScreamingNemesis.class)); cards.add(new SetCardInfo("Shardmage's Rescue", 29, Rarity.UNCOMMON, mage.cards.s.ShardmagesRescue.class)); From b332a10360c9e414564d26d122c0f2b9e0342217 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 10:22:54 -0400 Subject: [PATCH 20/43] [DSK] Implement Vile Mutilator --- Mage.Sets/src/mage/cards/v/VileMutilator.java | 65 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 66 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VileMutilator.java diff --git a/Mage.Sets/src/mage/cards/v/VileMutilator.java b/Mage.Sets/src/mage/cards/v/VileMutilator.java new file mode 100644 index 00000000000..a1cb99a7ef0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VileMutilator.java @@ -0,0 +1,65 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VileMutilator extends CardImpl { + + private static final FilterPermanent filter = new FilterEnchantmentPermanent("nontoken enchantment"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("nontoken creature"); + + static { + filter.add(TokenPredicate.FALSE); + filter2.add(TokenPredicate.FALSE); + } + + public VileMutilator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // As an additional cost to cast this spell, sacrifice a creature or enchantment. + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Vile Mutilator enters, each opponent sacrifices a nontoken enchantment, then sacrifices a nontoken creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(filter)); + ability.addEffect(new SacrificeOpponentsEffect(filter2).setText(", then sacrifices a nontoken creature")); + this.addAbility(ability); + } + + private VileMutilator(final VileMutilator card) { + super(card); + } + + @Override + public VileMutilator copy() { + return new VileMutilator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 7e0aaa0869c..6936ee5b401 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -175,6 +175,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Veteran Survivor", 40, Rarity.UNCOMMON, mage.cards.v.VeteranSurvivor.class)); cards.add(new SetCardInfo("Vicious Clown", 163, Rarity.COMMON, mage.cards.v.ViciousClown.class)); cards.add(new SetCardInfo("Victor, Valgavoth's Seneschal", 238, Rarity.RARE, mage.cards.v.VictorValgavothsSeneschal.class)); + cards.add(new SetCardInfo("Vile Mutilator", 122, Rarity.UNCOMMON, mage.cards.v.VileMutilator.class)); cards.add(new SetCardInfo("Wary Watchdog", 206, Rarity.COMMON, mage.cards.w.WaryWatchdog.class)); cards.add(new SetCardInfo("Wickerfolk Thresher", 207, Rarity.UNCOMMON, mage.cards.w.WickerfolkThresher.class)); cards.add(new SetCardInfo("Wildfire Wickerfolk", 239, Rarity.UNCOMMON, mage.cards.w.WildfireWickerfolk.class)); From 0b4313846ec1ec75b081dca5fbf1e2150b913de4 Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:08:40 -0400 Subject: [PATCH 21/43] [ACR] Implement Roshan, Hidden Magister. --- .../mage/cards/r/RoshanHiddenMagister.java | 77 +++++++++++++++++++ Mage.Sets/src/mage/sets/AssassinsCreed.java | 1 + .../AddCreatureSubTypeAllMultiZoneEffect.java | 24 +++++- 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/r/RoshanHiddenMagister.java diff --git a/Mage.Sets/src/mage/cards/r/RoshanHiddenMagister.java b/Mage.Sets/src/mage/cards/r/RoshanHiddenMagister.java new file mode 100644 index 00000000000..47760e576b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoshanHiddenMagister.java @@ -0,0 +1,77 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.TurnedFaceUpAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.AddCreatureSubTypeAllMultiZoneEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreatureSpell; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterOwnedCreatureCard; +import mage.filter.predicate.card.FaceDownPredicate; + +/** + * + * @author Grath + */ +public final class RoshanHiddenMagister extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Face-down creatures"); + public static final FilterControlledCreatureSpell filterSpells = new FilterControlledCreatureSpell("creature spells you control"); + public static final FilterOwnedCreatureCard filterCards = new FilterOwnedCreatureCard("creature cards you own"); + + static { + filter.add(FaceDownPredicate.instance); + } + + public RoshanHiddenMagister(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Other creatures you control are Assassins in addition to their other types. The same is true for creature spells you control and creature cards you own that aren't on the battlefield. + this.addAbility(new SimpleStaticAbility(new AddCreatureSubTypeAllMultiZoneEffect( + StaticFilters.FILTER_CONTROLLED_CREATURES, + filterSpells, + filterCards, + SubType.ASSASSIN + ))); + + // Face-down creatures you control have menace. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,new GainAbilityControlledEffect( + new MenaceAbility(false), + Duration.WhileOnBattlefield, + filter + ))); + + // Whenever a permanent you control is turned face up, you draw a card and you lose 1 life. + Ability ability = new TurnedFaceUpAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + StaticFilters.FILTER_CONTROLLED_A_PERMANENT + ); + ability.addEffect(new LoseLifeSourceControllerEffect(1)); + this.addAbility(ability); + } + + private RoshanHiddenMagister(final RoshanHiddenMagister card) { + super(card); + } + + @Override + public RoshanHiddenMagister copy() { + return new RoshanHiddenMagister(this); + } +} diff --git a/Mage.Sets/src/mage/sets/AssassinsCreed.java b/Mage.Sets/src/mage/sets/AssassinsCreed.java index 2bae1f33ef7..49117b4c31d 100644 --- a/Mage.Sets/src/mage/sets/AssassinsCreed.java +++ b/Mage.Sets/src/mage/sets/AssassinsCreed.java @@ -107,6 +107,7 @@ public final class AssassinsCreed extends ExpansionSet { cards.add(new SetCardInfo("Rest in Peace", 83, Rarity.RARE, mage.cards.r.RestInPeace.class)); cards.add(new SetCardInfo("Restart Sequence", 30, Rarity.UNCOMMON, mage.cards.r.RestartSequence.class)); cards.add(new SetCardInfo("Rooftop Bypass", 298, Rarity.RARE, mage.cards.r.RooftopBypass.class)); + cards.add(new SetCardInfo("Roshan, Hidden Magister", 32, Rarity.UNCOMMON, mage.cards.r.RoshanHiddenMagister.class)); cards.add(new SetCardInfo("Royal Assassin", 93, Rarity.RARE, mage.cards.r.RoyalAssassin.class)); cards.add(new SetCardInfo("Senu, Keen-Eyed Protector", 8, Rarity.RARE, mage.cards.s.SenuKeenEyedProtector.class)); cards.add(new SetCardInfo("Settlement Blacksmith", 280, Rarity.UNCOMMON, mage.cards.s.SettlementBlacksmith.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java index 7cc0aabe1cf..8367e9ceab7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java @@ -24,19 +24,35 @@ public class AddCreatureSubTypeAllMultiZoneEffect extends ContinuousEffectImpl { private final FilterControlledCreaturePermanent filterPermanent; private final FilterControlledCreatureSpell filterSpell; private final FilterOwnedCreatureCard filterCard; + private final SubType chosenType; public AddCreatureSubTypeAllMultiZoneEffect( FilterControlledCreaturePermanent filterPermanent, FilterControlledCreatureSpell filterSpell, FilterOwnedCreatureCard filterCard + ) { + this(filterPermanent, filterSpell, filterCard, null); + } + + public AddCreatureSubTypeAllMultiZoneEffect( + FilterControlledCreaturePermanent filterPermanent, + FilterControlledCreatureSpell filterSpell, + FilterOwnedCreatureCard filterCard, + SubType chosenType ) { super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); this.filterPermanent = filterPermanent; this.filterSpell = filterSpell; this.filterCard = filterCard; + this.chosenType = chosenType; - staticText = filterPermanent.getMessage() + " are the chosen type in addition to their other types. " + String typeMessage = "the chosen type"; + if (chosenType != null) { + typeMessage = chosenType.getPluralName(); + } + + staticText = filterPermanent.getMessage() + " are " + typeMessage + " in addition to their other types. " + "The same is true for " + filterSpell.getMessage() + " and " + filterCard.getMessage() + " that aren't on the battlefield"; } @@ -46,6 +62,7 @@ public class AddCreatureSubTypeAllMultiZoneEffect extends ContinuousEffectImpl { this.filterPermanent = effect.filterPermanent; this.filterSpell = effect.filterSpell; this.filterCard = effect.filterCard; + this.chosenType = effect.chosenType; } @Override @@ -57,7 +74,10 @@ public class AddCreatureSubTypeAllMultiZoneEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { UUID controllerId = source.getControllerId(); Player controller = game.getPlayer(controllerId); - SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + SubType subType = this.chosenType; + if (subType == null) { + subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + } if (controller == null || subType == null) { return false; } From e9a58c194f49b1cda74de801aafb1ee6aeb9ce18 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 11:10:51 -0400 Subject: [PATCH 22/43] [DSK] Implement Grievous Wound --- Mage.Sets/src/mage/cards/g/GrievousWound.java | 88 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../continuous/CantGainLifeAllEffect.java | 77 ++++++++-------- 3 files changed, 130 insertions(+), 36 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/g/GrievousWound.java diff --git a/Mage.Sets/src/mage/cards/g/GrievousWound.java b/Mage.Sets/src/mage/cards/g/GrievousWound.java new file mode 100644 index 00000000000..ec35432ee57 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrievousWound.java @@ -0,0 +1,88 @@ +package mage.cards.g; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.LoseHalfLifeTargetEffect; +import mage.abilities.effects.common.continuous.CantGainLifeAllEffect; +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.TargetPlayer; +import mage.target.targetpointer.FixedTarget; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrievousWound extends CardImpl { + + public GrievousWound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); + + this.subtype.add(SubType.AURA); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted player can't gain life. + this.addAbility(new SimpleStaticAbility( + new CantGainLifeAllEffect(Duration.WhileOnBattlefield, TargetController.ENCHANTED) + )); + + // Whenever enchanted player is dealt damage, they lose half their life, rounded up. + this.addAbility(new GrievousWoundTriggeredAbility()); + } + + private GrievousWound(final GrievousWound card) { + super(card); + } + + @Override + public GrievousWound copy() { + return new GrievousWound(this); + } +} + +class GrievousWoundTriggeredAbility extends TriggeredAbilityImpl { + + GrievousWoundTriggeredAbility() { + super(Zone.BATTLEFIELD, new LoseHalfLifeTargetEffect().setText("they lose half their life, rounded up")); + this.setTriggerPhrase("Whenever enchanted player is dealt damage, "); + } + + private GrievousWoundTriggeredAbility(final GrievousWoundTriggeredAbility ability) { + super(ability); + } + + @Override + public GrievousWoundTriggeredAbility copy() { + return new GrievousWoundTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_BATCH_FOR_ONE_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!Optional + .ofNullable(getSourcePermanentIfItStillExists(game)) + .map(Permanent::getAttachedTo) + .equals(event.getTargetId())) { + return false; + } + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 6936ee5b401..4062f1173a7 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -84,6 +84,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Gloomlake Verge", 260, Rarity.RARE, mage.cards.g.GloomlakeVerge.class)); cards.add(new SetCardInfo("Grasping Longneck", 180, Rarity.COMMON, mage.cards.g.GraspingLongneck.class)); cards.add(new SetCardInfo("Gremlin Tamer", 215, Rarity.UNCOMMON, mage.cards.g.GremlinTamer.class)); + cards.add(new SetCardInfo("Grievous Wound", 102, Rarity.RARE, mage.cards.g.GrievousWound.class)); cards.add(new SetCardInfo("Growing Dread", 216, Rarity.UNCOMMON, mage.cards.g.GrowingDread.class)); cards.add(new SetCardInfo("Hand That Feeds", 139, Rarity.COMMON, mage.cards.h.HandThatFeeds.class)); cards.add(new SetCardInfo("Hardened Escort", 16, Rarity.COMMON, mage.cards.h.HardenedEscort.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CantGainLifeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CantGainLifeAllEffect.java index 5a07edb97f8..0d363ea0da2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CantGainLifeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CantGainLifeAllEffect.java @@ -1,18 +1,15 @@ - package mage.abilities.effects.common.continuous; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.TargetController; +import mage.constants.*; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.Optional; +import java.util.UUID; + /** * @author LevelX2 */ @@ -48,41 +45,47 @@ public class CantGainLifeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - switch (targetController) { - case YOU: - controller.setCanGainLife(false); - break; - case NOT_YOU: - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null && !player.equals(controller)) { - player.setCanGainLife(false); - } + if (controller == null) { + return false; + } + switch (targetController) { + case YOU: + controller.setCanGainLife(false); + break; + case NOT_YOU: + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && !player.equals(controller)) { + player.setCanGainLife(false); } - break; - case OPPONENT: - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (controller.hasOpponent(playerId, game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.setCanGainLife(false); - } - } - } - break; - case ANY: - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + } + break; + case OPPONENT: + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (controller.hasOpponent(playerId, game)) { Player player = game.getPlayer(playerId); if (player != null) { player.setCanGainLife(false); } } - break; - } - return true; + } + break; + case ANY: + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.setCanGainLife(false); + } + } + break; + case ENCHANTED: + Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .map(Permanent::getAttachedTo) + .map(game::getPlayer) + .ifPresent(player -> player.setCanGainLife(false)); } - return false; + return true; } private String setText() { @@ -100,6 +103,8 @@ public class CantGainLifeAllEffect extends ContinuousEffectImpl { case ANY: sb.append("Players"); break; + case ENCHANTED: + sb.append("enchanted player"); } sb.append(" can't gain life"); if (!this.duration.toString().isEmpty()) { From 36ba9fc6879dff4376ad0977f020da88edf7b44a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:15:10 -0400 Subject: [PATCH 23/43] [DSK] update spoiler --- Utils/mtg-cards-data.txt | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 4a7c862222f..b655a337b8a 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -53993,8 +53993,10 @@ Friendly Ghost|Duskmourn: House of Horror|12|C|{3}{W}|Creature - Spirit|2|4|Flyi Glimmer Seeker|Duskmourn: House of Horror|14|U|{2}{W}|Creature - Human Survivor|3|3|Survival -- At the beginning of your second main phase, if Glimmer Seeker is tapped, draw a card if you control a Glimmer creature. If you don't control a Glimmer creature, create a 1/1 white Glimmer enchantment creature token.| Grand Entryway // Elegant Rotunda|Duskmourn: House of Horror|15|C|{1}{W}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, create a 1/1 white Glimmer enchantment creature token.$Elegant Rotunda${2}{W}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.| Hardened Escort|Duskmourn: House of Horror|16|C|{2}{W}|Creature - Human Soldier|2|4|Whenever Hardened Escort attacks, another target creature you control gets +1/+0 and gains indestructible until end of turn.| +Jump Scare|Duskmourn: House of Horror|17|C|{W}|Instant|||Until end of turn, target creature gets +2/+2, gains flying, and becomes a Horror enchantment creature in addition to its other types.| Leyline of Hope|Duskmourn: House of Horror|18|R|{2}{W}{W}|Enchantment|||If Leyline of Hope is in your opening hand, you may begin the game with it on the battlefield.$If you would gain life, you gain that much life plus 1 instead.$As long as you have at least 7 life more than your starting life total, creatures you control get +2/+2.| Lionheart Glimmer|Duskmourn: House of Horror|19|U|{3}{W}{W}|Enchantment Creature - Cat Glimmer|2|5|Ward {2}$Whenever you attack, creatures you control get +1/+1 until end of turn.| +Optimistic Scavenger|Duskmourn: House of Horror|21|U|{W}|Creature - Human Scout|1|1|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, put a +1/+1 counter on target creature.| Orphans of the Wheat|Duskmourn: House of Horror|22|U|{1}{W}|Creature - Human|2|1|Whenever Orphans of the Wheat attacks, tap any number of untapped creatures you control. Orphans of the Wheat gets +1/+1 until end of turn for each creature tapped this way.| Overlord of the Mistmoors|Duskmourn: House of Horror|23|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever Overlord of the Mistmoors enters or attacks, create two 2/1 white Insect creature tokens with flying.| Patched Plaything|Duskmourn: House of Horror|24|U|{2}{W}|Artifact Creature - Toy|4|3|Double strike$Patched Plaything enters with two -1/-1 counters on it if you cast it from your hand.| @@ -54010,13 +54012,16 @@ Unsettling Twins|Duskmourn: House of Horror|38|C|{3}{W}|Creature - Human|2|2|Whe Unwanted Remake|Duskmourn: House of Horror|39|U|{W}|Instant|||Destroy target creature. Its controller manifests dread.| Veteran Survivor|Duskmourn: House of Horror|40|U|{W}|Creature - Human Survivor|2|1|Survival -- At the beginning of your second main phase, if Veteran Survivor is tapped, exile up to one target card from a graveyard.$As long as there are three or more cards exiled with Veteran Survivor, it gets +3/+3 and has hexproof.| The Wandering Rescuer|Duskmourn: House of Horror|41|M|{3}{W}{W}|Legendary Creature - Human Samurai Noble|3|4|Flash$Convoke$Double strike$Other tapped creatures you control have hexproof.| +Abhorrent Oculus|Duskmourn: House of Horror|42|M|{2}{U}|Creature - Eye|5|5|As an additional cost to cast this spell, exile six cards from your graveyard.$Flying$At the beginning of each opponent's upkeep, manifest dread.| Bottomless Pool // Locker Room|Duskmourn: House of Horror|43|U|{U}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, return up to one target creature to its owner's hand.$Locker Room${4}{U}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever one or more creatures you control deal combat damage to a player, draw a card.| Central Elevator // Promising Stairs|Duskmourn: House of Horror|44|R|{3}{U}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, search your library for a Room card that doesn't have the same name as a Room you control, reveal it, put it into your hand, then shuffle.$Promising Stairs${2}{U}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$At the beginning of your upkeep, surveil 1. You win the game if there are eight or more different names among unlocked doors of Rooms you control.| Clammy Prowler|Duskmourn: House of Horror|45|C|{3}{U}|Enchantment Creature - Horror|2|5|Whenever Clammy Prowler attacks, another target attacking creature can't be blocked this turn.| Creeping Peeper|Duskmourn: House of Horror|46|C|{1}{U}|Creature - Eye|2|1|{T}: Add {U}. Spend this mana only to cast an enchantment spell, unlock a door, or turn a permanent face up.| Cursed Windbreaker|Duskmourn: House of Horror|47|U|{2}{U}|Artifact - Equipment|||When Cursed Windbreaker enters, manifest dread, then attach Cursed Windbreaker to that creature.$Equipped creature has flying.$Equip {3}| Daggermaw Megalodon|Duskmourn: House of Horror|48|C|{4}{U}{U}|Creature - Shark|5|7|Vigilance$Islandcycling {2}| +Duskmourn's Domination|Duskmourn: House of Horror|50|U|{4}{U}{U}|Enchantment - Aura|||Enchant creature$You control enchanted creature.$Enchanted creature gets -3/-0 and loses all abilities.| Enduring Curiosity|Duskmourn: House of Horror|51|R|{2}{U}{U}|Enchantment Creature - Cat Glimmer|4|3|Flash$Whenever a creature you control deals combat damage to a player, draw a card.$When Enduring Curiosity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| +Enter the Enigma|Duskmourn: House of Horror|52|C|{U}|Sorcery|||Target creature can't be blocked this turn.$Draw a card.| Fear of Failed Tests|Duskmourn: House of Horror|55|U|{4}{U}|Enchantment Creature - Nightmare|2|7|Whenever Fear of Failed Tests deals combat damage to a player, draw that many cards.| Fear of Falling|Duskmourn: House of Horror|56|U|{3}{U}{U}|Enchantment Creature - Nightmare|4|4|Flying$Whenever Fear of Falling attacks, target creature defending player controls gets -2/-0 and loses flying until your next turn.| Fear of Impostors|Duskmourn: House of Horror|57|U|{1}{U}{U}|Enchantment Creature - Nightmare|3|2|Flash$When Fear of Impostors enters, counter target spell. Its controller manifests dread.| @@ -54028,6 +54033,7 @@ Marina Vendrell's Grimoire|Duskmourn: House of Horror|64|R|{5}{U}|Legendary Arti The Mindskinner|Duskmourn: House of Horror|66|R|{U}{U}{U}|Legendary Enchantment Creature - Nightmare|10|1|The Mindskinner can't be blocked.$If a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards.| Mirror Room // Fractured Realm|Duskmourn: House of Horror|67|M|{2}{U}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$Fractured Realm${5}{U}{U}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$If a triggered ability of a permanent you control triggers, that ability triggers an additional time.| Overlord of the Floodpits|Duskmourn: House of Horror|68|M|{3}{U}{U}|Enchantment Creature - Avatar Horror|5|3|Impending 4--{1}{U}{U}$Flying$Whenever Overlord of the Floodpits enters or attacks, draw two cards, then discard a card.| +Paranormal Analyst|Duskmourn: House of Horror|69|U|{1}{U}|Creature - Human Detective|1|3|Whenever you manifest dread, put a card you put into your graveyard this way into your hand.| Piranha Fly|Duskmourn: House of Horror|70|C|{1}{U}|Creature - Fish Insect|2|1|Flying$Piranha Fly enters tapped.| Scrabbling Skullcrab|Duskmourn: House of Horror|71|U|{U}|Creature - Crab Skeleton|0|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, target player mills two cards.| Silent Hallcreeper|Duskmourn: House of Horror|72|R|{1}{U}|Enchantment Creature - Horror|1|1|Silent Hallcreeper can't be blocked.$Whenever Silent Hallcreeper deals combat damage to a player, choose one that hasn't been chosen --$* Put two +1/+1 counters on Silent Hallcreeper.$* Draw a card.$* Silent Hallcreeper becomes a copy of another target creature you control.| @@ -54040,6 +54046,7 @@ Unable to Scream|Duskmourn: House of Horror|78|C|{U}|Enchantment - Aura|||Enchan Unwilling Vessel|Duskmourn: House of Horror|81|U|{2}{U}|Creature - Human Wizard|3|2|Vigilance$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, put a possession counter on Unwilling Vessel.$When Unwilling Vessel dies, create an X/X blue Spirit creature token with flying, where X is the number of counters on Unwilling Vessel.| Vanish from Sight|Duskmourn: House of Horror|82|C|{3}{U}|Instant|||Target nonland permanent's owner puts it on the top or bottom of their library. Surveil 1.| Appendage Amalgam|Duskmourn: House of Horror|83|C|{2}{B}|Enchantment Creature - Horror|3|2|Flash$Whenever Appendage Amalgam attacks, surveil 1.| +Balemurk Leech|Duskmourn: House of Horror|84|C|{1}{B}|Creature Leech|2|2|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, each opponent loses 1 life.| Come Back Wrong|Duskmourn: House of Horror|86|R|{2}{B}|Sorcery|||Destroy target creature. If a creature card is put into a graveyard this way, return it to the battlefield under your control. Sacrifice it at the beginning of your next end step.| Commune with Evil|Duskmourn: House of Horror|87|U|{2}{B}|Sorcery|||Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. You gain 3 life.| Cynical Loner|Duskmourn: House of Horror|89|U|{1}{B}|Creature - Human Survivor|3|1|Cynical Loner can't be blocked by Glimmers.$Survival -- At the beginning of your second main phase, if Cynical Loner is tapped, you may search your library for a card, put it into your graveyard, then shuffle.| @@ -54055,12 +54062,17 @@ Funeral Room // Awakening Hall|Duskmourn: House of Horror|100|M|{2}{B}|Enchantme Give In to Violence|Duskmourn: House of Horror|101|C|{1}{B}|Instant|||Target creature gets +2/+2 and gains lifelink until end of turn.| Grievous Wound|Duskmourn: House of Horror|102|R|{3}{B}{B}|Enchantment - Aura|||Enchant player$Enchanted player can't gain life.$Whenever enchanted player is dealt damage, they lose half their life, rounded up.| Innocuous Rat|Duskmourn: House of Horror|103|C|{1}{B}|Creature - Rat|1|1|When Innocuous Rat dies, manifest dread.| +Let's Play a Game|Duskmourn: House of Horror|105|U|{3}{B}|Sorcery|||Delirium -- Choose one. If there are four or more card types among cards in your graveyard, choose one or more instead.$* Creatures your opponents control get -1/-1 until end of turn.$* Each opponent discards two cards.$* Each opponent loses 3 life and you gain 3 life.| Leyline of the Void|Duskmourn: House of Horror|106|R|{2}{B}{B}|Enchantment|||If Leyline of the Void is in your opening hand, you may begin the game with it on the battlefield.$If a card would be put into an opponent's graveyard from anywhere, exile it instead.| +Live or Die|Duskmourn: House of Horror|107|U|{3}{B}{B}|Instant|||Choose one --$* Return target creature card from your graveyard to the battlefield.$* Destroy target creature.| Meathook Massacre II|Duskmourn: House of Horror|108|M|{X}{X}{B}{B}{B}{B}|Legendary Enchantment|||When Meathook Massacre II enters, each player sacrifices X creatures.$Whenever a creature you control dies, you may pay 3 life. If you do, return that card under your control with a finality counter on it.$Whenever a creature an opponent controls dies, they may pay 3 life. If they don't, return that card under your control with a finality counter on it.| Murder|Duskmourn: House of Horror|110|C|{1}{B}{B}|Instant|||Destroy target creature.| Nowhere to Run|Duskmourn: House of Horror|111|U|{1}{B}|Enchantment|||Flash$When Nowhere to Run enters, target creature an opponent controls gets -3/-3 until end of turn.$Creatures your opponents control can be the targets of spells and abilities as though they didn't have hexproof. Ward abilities of those creatures don't trigger.| +Osseous Sticktwister|Duskmourn: House of Horror|112|U|{1}{B}|Artifact Creature - Scarecrow|2|2|Lifelink$Delirium -- At the beginning of your end step, if there are four or more card types among cards in your graveyard, each opponent may sacrifice a nonland permanent or discard a card. Then Osseous Sticktwister deals damage equal to its power to each opponent who didn't sacrifice a permanent or discard a card this way.| Popular Egotist|Duskmourn: House of Horror|114|U|{2}{B}|Creature - Human Rogue|3|2|{1}{B}, Sacrifice another creature or enchantment: Popular Egotist gains indestructible until end of turn. Tap it.$Whenever you sacrifice a permanent, target opponent loses 1 life and you gain 1 life.| Resurrected Cultist|Duskmourn: House of Horror|115|C|{2}{B}|Creature - Human Cleric|4|1|Delirium -- {2}{B}{B}: Return Resurrected Cultist from your graveyard to the battlefield with a finality counter on it. Activate only if there are four or more card types among cards in your graveyard and only as a sorcery.| +Spectral Snatcher|Duskmourn: House of Horror|116|C|{4}{B}{B}|Creature - Spirit|6|5|Ward--Discard a card.$Swampcycling {2}| +Sporogenic Infection|Duskmourn: House of Horror|117|U|{1}{B}|Enchantment - Aura|||Enchant creature$When Sporogenic Infection enters, target player sacrifices a creature other than enchanted creature.$When enchanted creature is dealt damage, destroy it.| Unholy Annex // Ritual Chamber|Duskmourn: House of Horror|118|R|{2}{B}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life.$Ritual Chamber${3}{B}{B}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, create a 6/6 black Demon creature token with flying.| Unstoppable Slasher|Duskmourn: House of Horror|119|R|{2}{B}|Creature - Zombie Assassin|2|3|Deathtouch$Whenever Unstoppable Slasher deals combat damage to a player, they lose half their life, rounded up.$When Unstoppable Slasher dies, if it had no counters on it, return it to the battlefield tapped under its owner's control with two stun counters on it.| Valgavoth, Terror Eater|Duskmourn: House of Horror|120|M|{6}{B}{B}{B}|Legendary Creature - Elder Demon|9|9|Flying, lifelink$Ward--Sacrifice three nonland permanents.$If a card you didn't control would be put into an opponent's graveyard from anywhere, exile it instead.$During your turn, you may play cards exiled with Valgavoth. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.| @@ -54090,6 +54102,7 @@ Overlord of the Boilerbilges|Duskmourn: House of Horror|146|M|{4}{R}{R}|Enchantm Piggy Bank|Duskmourn: House of Horror|148|U|{1}{R}|Artifact Creature - Boar Toy|3|2|When Piggy Bank dies, create a Treasure token.| Pyroclasm|Duskmourn: House of Horror|149|U|{1}{R}|Sorcery|||Pyroclasm deals 2 damage to each creature.| Ragged Playmate|Duskmourn: House of Horror|150|C|{1}{R}|Artifact Creature - Toy|2|2|{1}, {T}: Target creature with power 2 or less can't be blocked this turn.| +Rampaging Soulrager|Duskmourn: House of Horror|151|C|{2}{R}|Creature - Spirit|1|4|Rampaging Soulrager gets +3/+0 as long as there are two or more unlocked doors among Rooms you control.| Razorkin Hordecaller|Duskmourn: House of Horror|152|U|{4}{R}|Creature - Human Clown Berserker|4|4|Haste$Whenever you attack, create a 1/1 red Gremlin creature token.| Razorkin Needlehead|Duskmourn: House of Horror|153|R|{R}{R}|Creature - Human Assassin|2|2|Razorkin Needlehead has first strike during your turn.$Whenever an opponent draws a card, Razorkin Needlehead deals 1 damage to them.| The Rollercrusher Ride|Duskmourn: House of Horror|155|M|{X}{2}{R}|Legendary Enchantment|||Delirium -- If a source you control would deal noncombat damage to a permanent or player while there are four or more card types among cards in your graveyard, it deals double that damage instead.$When The Rollercrusher Ride enters, it deals X damage to each of up to X target creatures.| @@ -54104,18 +54117,23 @@ Anthropede|Duskmourn: House of Horror|167|C|{3}{G}|Creature - Insect|3|4|Reach$W Balustrade Wurm|Duskmourn: House of Horror|168|R|{3}{G}{G}|Creature - Wurm|5|5|This spell can't be countered.$Trample, haste$Delirium -- {2}{G}{G}: Return Balustrade Wurm from your graveyard to the battlefield with a finality counter on it. Activate only if there are four or more card types among cards in your graveyard and only as a sorcery.| Bashful Beastie|Duskmourn: House of Horror|169|C|{4}{G}|Creature - Beast|5|4|When Bashful Beastie dies, manifest dread.| Break Down the Door|Duskmourn: House of Horror|170|U|{2}{G}|Instant|||Choose one --$* Exile target artifact.$* Exile target enchantment.$* Manifest dread.| +Cathartic Parting|Duskmourn: House of Horror|171|C|{1}{G}|Sorcery|||The owner of target artifact or enchantment an opponent controls shuffles it into their library. You may shuffle up to four target cards from your graveyard into your library.| Cautious Survivor|Duskmourn: House of Horror|172|C|{3}{G}|Creature - Elf Survivor|4|4|Survival -- At the beginning of your second main phase, if Cautious Survivor is tapped, you gain 2 life.| Coordinated Clobbering|Duskmourn: House of Horror|173|U|{G}|Sorcery|||Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.| Cryptid Inspector|Duskmourn: House of Horror|174|C|{2}{G}|Creature - Elf Warrior|2|3|Vigilance$Whenever a face-down permanent you control enters and whenever Cryptid Inspector or another permanent you control is turned face up, put a +1/+1 counter on Cryptid Inspector.| Defiant Survivor|Duskmourn: House of Horror|175|U|{2}{G}|Creature - Human Survivor|3|2|Survival -- At the beginning of your second main phase, if Defiant Survivor is tapped, manifest dread.| +Enduring Vitality|Duskmourn: House of Horror|176|R|{1}{G}{G}|Enchantment Creature - Elk Glimmer|3|3|Vigilance$Creatures you control have "{T}: Add one mana of any color."$When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| Flesh Burrower|Duskmourn: House of Horror|178|C|{1}{G}|Creature - Insect|2|2|Deathtouch$Whenever Flesh Burrower attacks, another target creature you control gains deathtouch until end of turn.| +Frantic Strength|Duskmourn: House of Horror|179|C|{2}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +2/+2 and has trample.| Grasping Longneck|Duskmourn: House of Horror|180|C|{2}{G}|Enchantment Creature - Horror|4|2|Reach$When Grasping Longneck dies, you gain 2 life.| Greenhouse // Rickety Gazebo|Duskmourn: House of Horror|181|U|{2}{G}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lands you control have "{T}: Add one mana of any color."$Rickety Gazebo${3}{G}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, mill four cards, then return up to two permanent cards from among them to your hand.| Hauntwoods Shrieker|Duskmourn: House of Horror|182|M|{1}{G}{G}|Creature - Beast Mutant|3|3|Whenever Hauntwoods Shrieker attacks, manifest dread.${1}{G}: Reveal target face-down permanent. If it's a creature card, you may turn it face up.| Hedge Shredder|Duskmourn: House of Horror|183|R|{2}{G}{G}|Artifact - Vehicle|5|5|Whenever Hedge Shredder attacks, you may mill two cards.$Whenever one or more land cards are put into your graveyard from your library, put them onto the battlefield tapped.$Crew 1| House Cartographer|Duskmourn: House of Horror|185|U|{1}{G}|Creature - Human Scout Survivor|2|2|Survival -- At the beginning of your second main phase, if House Cartographer is tapped, reveal cards from the top of your library until you reveal a land card. Put that card into your hand and the rest on the bottom of your library in a random order.| Insidious Fungus|Duskmourn: House of Horror|186|U|{G}|Creature - Fungus|1|2|{2}, Sacrifice Insidious Fungus: Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Draw a card. Then you may put a land card from your hand onto the battlefield tapped.| +Kona, Rescue Beastie|Duskmourn: House of Horror|187|R|{3}{G}|Legendary Creature - Beast Survivor|4|3|Survival - At the beginning of your second main phase, if Kona, Rescue Beastie is tapped, you may put a permanent card from your hand onto the battlefield| Leyline of Mutation|Duskmourn: House of Horror|188|R|{2}{G}{G}|Enchantment|||If Leyline of Mutation is in your opening hand, you may begin the game with it on the battlefield.$You may pay {W}{U}{B}{R}{G} rather than pay the mana cost for spells that you cast.| +Manifest Dread|Duskmourn: House of Horror|189|C|{1}{G}|Sorcery|||Manifest dread.| Omnivorous Flytrap|Duskmourn: House of Horror|192|R|{2}{G}|Creature - Plant|2|4|Delirium -- Whenever Omnivorous Flytrap enters or attacks, if there are four or more card types among cards in your graveyard, distribute two +1/+1 counters among one or two target creatures. Then if there are six or more card types among cards in your graveyard, double the number of +1/+1 counters on those creatures.| Overgrown Zealot|Duskmourn: House of Horror|193|U|{1}{G}|Creature - Elf Druid|0|4|{T}: Add one mana of any color.${T}: Add two mana of any one color. Spend this mana only to turn permanents face up.| Overlord of the Hauntwoods|Duskmourn: House of Horror|194|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever Overlord of the Hauntwoods enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.| @@ -54133,10 +54151,11 @@ Wary Watchdog|Duskmourn: House of Horror|206|C|{1}{G}|Creature - Dog|3|1|When Wa Wickerfolk Thresher|Duskmourn: House of Horror|207|U|{3}{G}|Artifact Creature - Scarecrow|5|4|Delirium -- Whenever Wickerfolk Thresher attacks, if there are four or more card types among cards in your graveyard, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand.| Arabella, Abandoned Doll|Duskmourn: House of Horror|208|U|{R}{W}|Legendary Artifact Creature - Toy|1|3|Whenever Arabella, Abandoned Doll attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.| Baseball Bat|Duskmourn: House of Horror|209|U|{G}{W}|Artifact - Equipment|||When Baseball Bat enters, attach it to target creature you control.$Equipped creature gets +1/+1.$Whenever equipped creature attacks, tap up to one target creature.$Equip {3}| +Broodspinner|Duskmourn: House of Horror|211|U|{B}{G}|Creature - Spider|2|3|Reach$When Broodspinner enters, surveil 2.${4}{B}{G}, {T}, Sacrifice Broodspinner: Create a number of 1/1 black and green Insect creature tokens with flying equal to the number of card types among cards in your graveyard.| Disturbing Mirth|Duskmourn: House of Horror|212|U|{B}{R}|Enchantment|||When Disturbing Mirth enters, you may sacrifice another enchantment or creature. If you do, draw two cards.$When you sacrifice Disturbing Mirth, manifest dread.| Drag to the Roots|Duskmourn: House of Horror|213|U|{2}{B}{G}|Instant|||Delirium -- This spell costs {2} less to cast as long as there are four or more card types among cards in your graveyard.$Destroy target nonland permanent.| Fear of Infinity|Duskmourn: House of Horror|214|U|{1}{U}{B}|Enchantment Creature - Nightmare|2|2|Flying, lifelink$Fear of Infinity can't block.$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, you may return Fear of Infinity from your graveyard to your hand.| -Gremlin Tamer|Duskmourn: House of Horror|215|U|{W}{U}|Creature - Human Scout|2|2|Eerie - Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 1/1 red Gremlin creature token.| +Gremlin Tamer|Duskmourn: House of Horror|215|U|{W}{U}|Creature - Human Scout|2|2|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 1/1 red Gremlin creature token.| Growing Dread|Duskmourn: House of Horror|216|U|{G}{U}|Enchantment|||Flash$When Growing Dread enters, manifest dread.$Whenever you turn a permanent face up, put a +1/+1 counter on it.| Inquisitive Glimmer|Duskmourn: House of Horror|217|U|{W}{U}|Enchantment Creature - Fox Glimmer|2|3|Enchantment spells you cast cost {1} less to cast.$Unlock costs you pay cost {1} less.| Intruding Soulrager|Duskmourn: House of Horror|218|U|{U}{R}|Creature - Spirit|2|2|Vigilance${T}, Sacrifice a Room: Intruding Soulrager deals 2 damage to each opponent. Draw a card.| @@ -54147,6 +54166,7 @@ Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Cr Niko, Light of Hope|Duskmourn: House of Horror|224|M|{2}{W}{U}|Legendary Creature - Human Wizard|3|4|When Niko, Light of Hope enters, create two Shard tokens.${2}, {T}: Exile target nonlegendary creature you control. Shards you control become copies of it until the beginning of the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step.| Oblivious Bookworm|Duskmourn: House of Horror|225|U|{G}{U}|Creature - Human Wizard|2|3|At the beginning of your end step, you may draw a card. If you do, discard a card unless a permanent entered the battlefield face down under your control this turn or you turned a permanent face up this turn.| Peer Past the Veil|Duskmourn: House of Horror|226|R|{2}{R}{G}|Instant|||Discard your hand. Then draw X cards, where X is the number of card types among cards in your graveyard.| +Restricted Office // Lecture Hall|Duskmourn: House of Horror|227|R|{2}{W}{W}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this room, destroy all creatures with power 3 or greater.$Lecture Hall${5}{U}{U}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Other permanents you control have hexproof.| Rite of the Moth|Duskmourn: House of Horror|229|U|{1}{W}{B}{B}|Sorcery|||Return target creature card from your graveyard to the battlefield with a finality counter on it.$Flashback {3}{W}{W}{B}| Sawblade Skinripper|Duskmourn: House of Horror|231|U|{1}{B}{R}|Creature - Human Assassin|3|2|Menace${2}, Sacrifice another creature or enchantment: Put a +1/+1 counter on Sawblade Skinripper.$At the beginning of your end step, if you sacrificed one or more permanents this turn, Sawblade Skinripper deals that much damage to any target.| Shrewd Storyteller|Duskmourn: House of Horror|232|U|{1}{G}{W}|Creature - Human Survivor|3|3|Survival -- At the beginning of your second main phase, if Shrewd Storyteller is tapped, put a +1/+1 counter on target creature.| @@ -54160,11 +54180,14 @@ Winter, Misanthropic Guide|Duskmourn: House of Horror|240|R|{1}{B}{R}{G}|Legenda Zimone, All-Questioning|Duskmourn: House of Horror|241|R|{1}{G}{U}|Legendary Creature - Human Wizard|1|1|At the beginning of your end step, if a land entered the battlefield under your control this turn and you control a prime number of lands, create Primo, the Indivisible, a legendary 0/0 green and blue Fractal creature token, then put that many +1/+1 counters on it.| Attack-in-the-Box|Duskmourn: House of Horror|242|U|{3}|Artifact Creature - Toy|2|4|Whenever Attack-in-the-Box attacks, you may have it get +4/+0 until end of turn. If you do, sacrifice it at the beginning of the next end step.| Bear Trap|Duskmourn: House of Horror|243|C|{1}|Artifact|||Flash${3}, {T}, Sacrifice Bear Trap: It deals 3 damage to target creature.| +Conductive Machete|Duskmourn: House of Horror|244|U|{4}|Artifact - Equipment|||When Conductive Machete enters, manifest dread, then attach Conductive Machete to that creature.$Equipped creature gets +2/+1.$Equip {4}| Found Footage|Duskmourn: House of Horror|246|C|{1}|Artifact - Clue|||You may look at face-down creatures your opponents control any time.${2}, Sacrifice Found Footage: Surveil 2, then draw a card.| Friendly Teddy|Duskmourn: House of Horror|247|C|{2}|Artifact Creature - Bear Toy|2|2|When Friendly Teddy dies, each player draws a card.| Ghost Vacuum|Duskmourn: House of Horror|248|R|{1}|Artifact|||{T}: Exile target card from a graveyard.${6}, {T}, Sacrifice Ghost Vacuum: Put each creature card exiled with Ghost Vacuum onto the battlefield under your control with a flying counter on it. Each of them is a 1/1 Spirit in addition to its other types. Activate only as a sorcery.| Glimmerlight|Duskmourn: House of Horror|249|C|{2}|Artifact - Equipment|||When Glimmerlight enters, create a 1/1 white Glimmer enchantment creature token.$Equipped creature gets +1/+1.$Equip {1}| Haunted Screen|Duskmourn: House of Horror|250|U|{3}|Artifact|||{T}: Add {W} or {B}.${T}, Pay 1 life: Add {G}, {U}, or {R}.${7}: Put seven +1/+1 counters on Haunted Screen. It becomes a 0/0 Spirit creature in addition to its other types. Activate only once.| +Malevolent Chandelier|Duskmourn: House of Horror|252|C|{6}|Artifact Creature - Construct|4|4|Flying${2}: Put target card from a graveyard on the bottom of its owner's library. Activate only as a sorcery.| +Marvin, Murderous Mimic|Duskmourn: House of Horror|253|R|{2}|Legendary Artifact Creature - Toy|2|2|Marvin, Murderous Mimic has all activated abilities of creatures you control that don't have the same name as this creature.| Saw|Duskmourn: House of Horror|254|U|{2}|Artifact - Equipment|||Equipped creature gets +2/+0.$Whenever equipped creature attacks, you may sacrifice a permanent other than that creature or Saw. If you do, draw a card.$Equip {2}| Abandoned Campground|Duskmourn: House of Horror|255|C||Land|||Abandoned Campground enters tapped unless a player has 13 or less life.${T}: Add {W} or {U}.| Blazemire Verge|Duskmourn: House of Horror|256|R||Land|||{T}: Add {B}.${T}: Add {R}. Activate only if you control a Swamp or a Mountain.| From 393f07387874411222f20f3fed1275c94cecb425 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:16:15 -0400 Subject: [PATCH 24/43] [DSK] Implement Optimistic Scavenger --- .../src/mage/cards/o/OptimisticScavenger.java | 43 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 44 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/OptimisticScavenger.java diff --git a/Mage.Sets/src/mage/cards/o/OptimisticScavenger.java b/Mage.Sets/src/mage/cards/o/OptimisticScavenger.java new file mode 100644 index 00000000000..7135c80a4e2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OptimisticScavenger.java @@ -0,0 +1,43 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.abilityword.EerieAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OptimisticScavenger extends CardImpl { + + public OptimisticScavenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, put a +1/+1 counter on target creature. + Ability ability = new EerieAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private OptimisticScavenger(final OptimisticScavenger card) { + super(card); + } + + @Override + public OptimisticScavenger copy() { + return new OptimisticScavenger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 4062f1173a7..600dacf5de3 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -112,6 +112,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Nashi, Searcher in the Dark", 223, Rarity.RARE, mage.cards.n.NashiSearcherInTheDark.class)); cards.add(new SetCardInfo("Neglected Manor", 264, Rarity.COMMON, mage.cards.n.NeglectedManor.class)); cards.add(new SetCardInfo("Oblivious Bookworm", 225, Rarity.UNCOMMON, mage.cards.o.ObliviousBookworm.class)); + cards.add(new SetCardInfo("Optimistic Scavenger", 21, Rarity.UNCOMMON, mage.cards.o.OptimisticScavenger.class)); cards.add(new SetCardInfo("Orphans of the Wheat", 22, Rarity.UNCOMMON, mage.cards.o.OrphansOfTheWheat.class)); cards.add(new SetCardInfo("Overlord of the Boilerbilges", 146, Rarity.MYTHIC, mage.cards.o.OverlordOfTheBoilerbilges.class)); cards.add(new SetCardInfo("Overlord of the Floodpits", 68, Rarity.MYTHIC, mage.cards.o.OverlordOfTheFloodpits.class)); From 579298fc30d71e69801249eb90a125319af81ced Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:18:34 -0400 Subject: [PATCH 25/43] [DSK] Implement Broodspinner --- Mage.Sets/src/mage/cards/b/Broodspinner.java | 58 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 59 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/Broodspinner.java diff --git a/Mage.Sets/src/mage/cards/b/Broodspinner.java b/Mage.Sets/src/mage/cards/b/Broodspinner.java new file mode 100644 index 00000000000..638644dbff2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Broodspinner.java @@ -0,0 +1,58 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.IzoniInsectToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Broodspinner extends CardImpl { + + public Broodspinner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); + + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Broodspinner enters, surveil 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(2))); + + // {4}{B}{G}, {T}, Sacrifice Broodspinner: Create a number of 1/1 black and green Insect creature tokens with flying equal to the number of card types among cards in your graveyard. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect( + new IzoniInsectToken(), CardTypesInGraveyardCount.YOU + ), new ManaCostsImpl<>("{4}{B}{G}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability.addHint(CardTypesInGraveyardHint.YOU)); + } + + private Broodspinner(final Broodspinner card) { + super(card); + } + + @Override + public Broodspinner copy() { + return new Broodspinner(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 600dacf5de3..5d2ca9998de 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -35,6 +35,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Blazemire Verge", 256, Rarity.RARE, mage.cards.b.BlazemireVerge.class)); cards.add(new SetCardInfo("Bleeding Woods", 257, Rarity.COMMON, mage.cards.b.BleedingWoods.class)); cards.add(new SetCardInfo("Break Down the Door", 170, Rarity.UNCOMMON, mage.cards.b.BreakDownTheDoor.class)); + cards.add(new SetCardInfo("Broodspinner", 211, Rarity.UNCOMMON, mage.cards.b.Broodspinner.class)); cards.add(new SetCardInfo("Cautious Survivor", 172, Rarity.COMMON, mage.cards.c.CautiousSurvivor.class)); cards.add(new SetCardInfo("Chainsaw", 128, Rarity.RARE, mage.cards.c.Chainsaw.class)); cards.add(new SetCardInfo("Clammy Prowler", 45, Rarity.COMMON, mage.cards.c.ClammyProwler.class)); From deafaf318833a4d48bab4814a488e696c9761f68 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:19:53 -0400 Subject: [PATCH 26/43] [DSK] Implement Enduring Vitality --- .../src/mage/cards/e/EnduringVitality.java | 52 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EnduringVitality.java diff --git a/Mage.Sets/src/mage/cards/e/EnduringVitality.java b/Mage.Sets/src/mage/cards/e/EnduringVitality.java new file mode 100644 index 00000000000..8dbeefb7681 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnduringVitality.java @@ -0,0 +1,52 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EnduringGlimmerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnduringVitality extends CardImpl { + + public EnduringVitality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}{G}"); + + this.subtype.add(SubType.ELK); + this.subtype.add(SubType.GLIMMER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Creatures you control have "{T}: Add one mana of any color." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new AnyColorManaAbility(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); + + // When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment. + this.addAbility(new EnduringGlimmerTriggeredAbility()); + } + + private EnduringVitality(final EnduringVitality card) { + super(card); + } + + @Override + public EnduringVitality copy() { + return new EnduringVitality(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 5d2ca9998de..ce49f42ebf2 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -58,6 +58,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Enduring Curiosity", 51, Rarity.RARE, mage.cards.e.EnduringCuriosity.class)); cards.add(new SetCardInfo("Enduring Innocence", 6, Rarity.RARE, mage.cards.e.EnduringInnocence.class)); cards.add(new SetCardInfo("Enduring Tenacity", 95, Rarity.RARE, mage.cards.e.EnduringTenacity.class)); + cards.add(new SetCardInfo("Enduring Vitality", 176, Rarity.RARE, mage.cards.e.EnduringVitality.class)); cards.add(new SetCardInfo("Etched Cornfield", 258, Rarity.COMMON, mage.cards.e.EtchedCornfield.class)); cards.add(new SetCardInfo("Ethereal Armor", 7, Rarity.UNCOMMON, mage.cards.e.EtherealArmor.class)); cards.add(new SetCardInfo("Fanatic of the Harrowing", 96, Rarity.COMMON, mage.cards.f.FanaticOfTheHarrowing.class)); From e59e2a0e18b4cced092f7a1e8114080cc803ec30 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:20:46 -0400 Subject: [PATCH 27/43] [DSK] Implement Kona, Rescue Beastie --- .../src/mage/cards/k/KonaRescueBeastie.java | 41 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KonaRescueBeastie.java diff --git a/Mage.Sets/src/mage/cards/k/KonaRescueBeastie.java b/Mage.Sets/src/mage/cards/k/KonaRescueBeastie.java new file mode 100644 index 00000000000..a8973914eea --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KonaRescueBeastie.java @@ -0,0 +1,41 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.abilityword.SurvivalAbility; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KonaRescueBeastie extends CardImpl { + + public KonaRescueBeastie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAST); + this.subtype.add(SubType.SURVIVOR); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Survival - At the beginning of your second main phase, if Kona, Rescue Beastie is tapped, you may put a permanent card from your hand onto the battlefield + this.addAbility(new SurvivalAbility(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE_A))); + } + + private KonaRescueBeastie(final KonaRescueBeastie card) { + super(card); + } + + @Override + public KonaRescueBeastie copy() { + return new KonaRescueBeastie(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index ce49f42ebf2..d72551f8751 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -99,6 +99,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Insidious Fungus", 186, Rarity.UNCOMMON, mage.cards.i.InsidiousFungus.class)); cards.add(new SetCardInfo("Intruding Soulrager", 218, Rarity.UNCOMMON, mage.cards.i.IntrudingSoulrager.class)); cards.add(new SetCardInfo("Island", 273, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Kona, Rescue Beastie", 187, Rarity.RARE, mage.cards.k.KonaRescueBeastie.class)); cards.add(new SetCardInfo("Lakeside Shack", 262, Rarity.COMMON, mage.cards.l.LakesideShack.class)); cards.add(new SetCardInfo("Leyline of Hope", 18, Rarity.RARE, mage.cards.l.LeylineOfHope.class)); cards.add(new SetCardInfo("Leyline of Mutation", 188, Rarity.RARE, mage.cards.l.LeylineOfMutation.class)); From 29f4ef7dcd890fbfb59cc63c120a85f68a5107f6 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:21:57 -0400 Subject: [PATCH 28/43] [DSK] Implement Live or Die --- Mage.Sets/src/mage/cards/l/LiveOrDie.java | 40 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 41 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LiveOrDie.java diff --git a/Mage.Sets/src/mage/cards/l/LiveOrDie.java b/Mage.Sets/src/mage/cards/l/LiveOrDie.java new file mode 100644 index 00000000000..a9dc3cb40ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LiveOrDie.java @@ -0,0 +1,40 @@ +package mage.cards.l; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LiveOrDie extends CardImpl { + + public LiveOrDie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}{B}"); + + // Choose one -- + // * Return target creature card from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // * Destroy target creature. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetCreaturePermanent())); + } + + private LiveOrDie(final LiveOrDie card) { + super(card); + } + + @Override + public LiveOrDie copy() { + return new LiveOrDie(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index d72551f8751..c8892b9745c 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -106,6 +106,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Leyline of Resonance", 143, Rarity.RARE, mage.cards.l.LeylineOfResonance.class)); cards.add(new SetCardInfo("Leyline of the Void", 106, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Glimmer", 19, Rarity.UNCOMMON, mage.cards.l.LionheartGlimmer.class)); + cards.add(new SetCardInfo("Live or Die", 107, Rarity.UNCOMMON, mage.cards.l.LiveOrDie.class)); cards.add(new SetCardInfo("Marina Vendrell's Grimoire", 64, Rarity.RARE, mage.cards.m.MarinaVendrellsGrimoire.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); cards.add(new SetCardInfo("Most Valuable Slayer", 144, Rarity.COMMON, mage.cards.m.MostValuableSlayer.class)); From 37c1d149624f1c5c5368290672f86ae46364c0e8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:22:36 -0400 Subject: [PATCH 29/43] [DSK] Implement Manifest Dread --- Mage.Sets/src/mage/cards/m/ManifestDread.java | 30 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 31 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/ManifestDread.java diff --git a/Mage.Sets/src/mage/cards/m/ManifestDread.java b/Mage.Sets/src/mage/cards/m/ManifestDread.java new file mode 100644 index 00000000000..4a8a06a07b2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/ManifestDread.java @@ -0,0 +1,30 @@ +package mage.cards.m; + +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ManifestDread extends CardImpl { + + public ManifestDread(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // Manifest dread. + this.getSpellAbility().addEffect(new ManifestDreadEffect()); + } + + private ManifestDread(final ManifestDread card) { + super(card); + } + + @Override + public ManifestDread copy() { + return new ManifestDread(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index c8892b9745c..343f285abe8 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -107,6 +107,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Leyline of the Void", 106, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Glimmer", 19, Rarity.UNCOMMON, mage.cards.l.LionheartGlimmer.class)); cards.add(new SetCardInfo("Live or Die", 107, Rarity.UNCOMMON, mage.cards.l.LiveOrDie.class)); + cards.add(new SetCardInfo("Manifest Dread", 189, Rarity.COMMON, mage.cards.m.ManifestDread.class)); cards.add(new SetCardInfo("Marina Vendrell's Grimoire", 64, Rarity.RARE, mage.cards.m.MarinaVendrellsGrimoire.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); cards.add(new SetCardInfo("Most Valuable Slayer", 144, Rarity.COMMON, mage.cards.m.MostValuableSlayer.class)); From 2f5ecbe571b860fcfdbafa675aa23c7bf9cce673 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:23:23 -0400 Subject: [PATCH 30/43] [DSK] Implement Spectral Snatcher --- .../src/mage/cards/s/SpectralSnatcher.java | 42 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpectralSnatcher.java diff --git a/Mage.Sets/src/mage/cards/s/SpectralSnatcher.java b/Mage.Sets/src/mage/cards/s/SpectralSnatcher.java new file mode 100644 index 00000000000..206c668a9df --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpectralSnatcher.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.SwampcyclingAbility; +import mage.abilities.keyword.WardAbility; +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 SpectralSnatcher extends CardImpl { + + public SpectralSnatcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Ward--Discard a card. + this.addAbility(new WardAbility(new DiscardCardCost())); + + // Swampcycling {2} + this.addAbility(new SwampcyclingAbility(new ManaCostsImpl<>("{2}"))); + } + + private SpectralSnatcher(final SpectralSnatcher card) { + super(card); + } + + @Override + public SpectralSnatcher copy() { + return new SpectralSnatcher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 343f285abe8..125a22e62d4 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -150,6 +150,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Silent Hallcreeper", 72, Rarity.RARE, mage.cards.s.SilentHallcreeper.class)); cards.add(new SetCardInfo("Skullsnap Nuisance", 234, Rarity.UNCOMMON, mage.cards.s.SkullsnapNuisance.class)); cards.add(new SetCardInfo("Slavering Branchsnapper", 198, Rarity.COMMON, mage.cards.s.SlaveringBranchsnapper.class)); + cards.add(new SetCardInfo("Spectral Snatcher", 116, Rarity.COMMON, mage.cards.s.SpectralSnatcher.class)); cards.add(new SetCardInfo("Spineseeker Centipede", 199, Rarity.COMMON, mage.cards.s.SpineseekerCentipede.class)); cards.add(new SetCardInfo("Split Up", 32, Rarity.RARE, mage.cards.s.SplitUp.class)); cards.add(new SetCardInfo("Splitskin Doll", 33, Rarity.UNCOMMON, mage.cards.s.SplitskinDoll.class)); From 1fba56ee13fd948ce9b1fd6547f738bf9283e1ae Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:25:02 -0400 Subject: [PATCH 31/43] [DSK] Implement Frantic Strength --- .../src/mage/cards/f/FranticStrength.java | 57 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FranticStrength.java diff --git a/Mage.Sets/src/mage/cards/f/FranticStrength.java b/Mage.Sets/src/mage/cards/f/FranticStrength.java new file mode 100644 index 00000000000..bedbe3977c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FranticStrength.java @@ -0,0 +1,57 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FranticStrength extends CardImpl { + + public FranticStrength(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature gets +2/+2 and has trample. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); + this.addAbility(ability); + } + + private FranticStrength(final FranticStrength card) { + super(card); + } + + @Override + public FranticStrength copy() { + return new FranticStrength(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 125a22e62d4..aede1b8bc82 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -78,6 +78,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Floodfarm Verge", 259, Rarity.RARE, mage.cards.f.FloodfarmVerge.class)); cards.add(new SetCardInfo("Floodpits Drowner", 59, Rarity.UNCOMMON, mage.cards.f.FloodpitsDrowner.class)); cards.add(new SetCardInfo("Forest", 276, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Frantic Strength", 179, Rarity.COMMON, mage.cards.f.FranticStrength.class)); cards.add(new SetCardInfo("Friendly Ghost", 12, Rarity.COMMON, mage.cards.f.FriendlyGhost.class)); cards.add(new SetCardInfo("Friendly Teddy", 247, Rarity.COMMON, mage.cards.f.FriendlyTeddy.class)); cards.add(new SetCardInfo("Give In to Violence", 101, Rarity.COMMON, mage.cards.g.GiveInToViolence.class)); From b95d7d202dd3d5497b0072fffccf7cc259d19b74 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:26:47 -0400 Subject: [PATCH 32/43] [DSK] Implement Abhorrent Oculus --- .../src/mage/cards/a/AbhorrentOculus.java | 52 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AbhorrentOculus.java diff --git a/Mage.Sets/src/mage/cards/a/AbhorrentOculus.java b/Mage.Sets/src/mage/cards/a/AbhorrentOculus.java new file mode 100644 index 00000000000..e318c452ab8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AbhorrentOculus.java @@ -0,0 +1,52 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AbhorrentOculus extends CardImpl { + + public AbhorrentOculus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.EYE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // As an additional cost to cast this spell, exile six cards from your graveyard. + this.getSpellAbility().addCost(new ExileFromGraveCost( + new TargetCardInYourGraveyard(StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD) + )); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of each opponent's upkeep, manifest dread. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ManifestDreadEffect(), TargetController.OPPONENT, false + )); + } + + private AbhorrentOculus(final AbhorrentOculus card) { + super(card); + } + + @Override + public AbhorrentOculus copy() { + return new AbhorrentOculus(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index aede1b8bc82..30cfc793f78 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -22,6 +22,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { this.hasBoosters = false; // temporary cards.add(new SetCardInfo("Abandoned Campground", 255, Rarity.COMMON, mage.cards.a.AbandonedCampground.class)); + cards.add(new SetCardInfo("Abhorrent Oculus", 42, Rarity.MYTHIC, mage.cards.a.AbhorrentOculus.class)); cards.add(new SetCardInfo("Altanak, the Thrice-Called", 166, Rarity.UNCOMMON, mage.cards.a.AltanakTheThriceCalled.class)); cards.add(new SetCardInfo("Anthropede", 167, Rarity.COMMON, mage.cards.a.Anthropede.class)); cards.add(new SetCardInfo("Appendage Amalgam", 83, Rarity.COMMON, mage.cards.a.AppendageAmalgam.class)); From dfa44c39aa1ea1444477b17aca21a01f30e1dcd5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:30:12 -0400 Subject: [PATCH 33/43] [DSK] Implement Enter the Enigma --- .../src/mage/cards/e/EnterTheEnigma.java | 36 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 37 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EnterTheEnigma.java diff --git a/Mage.Sets/src/mage/cards/e/EnterTheEnigma.java b/Mage.Sets/src/mage/cards/e/EnterTheEnigma.java new file mode 100644 index 00000000000..6183648aae6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnterTheEnigma.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +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 EnterTheEnigma extends CardImpl { + + public EnterTheEnigma(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + // Target creature can't be blocked this turn. + this.getSpellAbility().addEffect(new CantBeBlockedTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private EnterTheEnigma(final EnterTheEnigma card) { + super(card); + } + + @Override + public EnterTheEnigma copy() { + return new EnterTheEnigma(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 30cfc793f78..700beaa49fd 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -60,6 +60,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Enduring Innocence", 6, Rarity.RARE, mage.cards.e.EnduringInnocence.class)); cards.add(new SetCardInfo("Enduring Tenacity", 95, Rarity.RARE, mage.cards.e.EnduringTenacity.class)); cards.add(new SetCardInfo("Enduring Vitality", 176, Rarity.RARE, mage.cards.e.EnduringVitality.class)); + cards.add(new SetCardInfo("Enter the Enigma", 52, Rarity.COMMON, mage.cards.e.EnterTheEnigma.class)); cards.add(new SetCardInfo("Etched Cornfield", 258, Rarity.COMMON, mage.cards.e.EtchedCornfield.class)); cards.add(new SetCardInfo("Ethereal Armor", 7, Rarity.UNCOMMON, mage.cards.e.EtherealArmor.class)); cards.add(new SetCardInfo("Fanatic of the Harrowing", 96, Rarity.COMMON, mage.cards.f.FanaticOfTheHarrowing.class)); From 91b0f9a443ac48b196865ffb47b1f6f68354f83e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:31:00 -0400 Subject: [PATCH 34/43] [DSK] Implement Balemurk Leech --- Mage.Sets/src/mage/cards/b/BalemurkLeech.java | 37 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 38 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BalemurkLeech.java diff --git a/Mage.Sets/src/mage/cards/b/BalemurkLeech.java b/Mage.Sets/src/mage/cards/b/BalemurkLeech.java new file mode 100644 index 00000000000..2e7f7edf422 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BalemurkLeech.java @@ -0,0 +1,37 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.abilityword.EerieAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BalemurkLeech extends CardImpl { + + public BalemurkLeech(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.LEECH); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, each opponent loses 1 life. + this.addAbility(new EerieAbility(new LoseLifeOpponentsEffect(1))); + } + + private BalemurkLeech(final BalemurkLeech card) { + super(card); + } + + @Override + public BalemurkLeech copy() { + return new BalemurkLeech(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 700beaa49fd..6df574d7705 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -28,6 +28,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Appendage Amalgam", 83, Rarity.COMMON, mage.cards.a.AppendageAmalgam.class)); cards.add(new SetCardInfo("Arabella, Abandoned Doll", 208, Rarity.UNCOMMON, mage.cards.a.ArabellaAbandonedDoll.class)); cards.add(new SetCardInfo("Attack-in-the-Box", 242, Rarity.UNCOMMON, mage.cards.a.AttackInTheBox.class)); + cards.add(new SetCardInfo("Balemurk Leech", 84, Rarity.COMMON, mage.cards.b.BalemurkLeech.class)); cards.add(new SetCardInfo("Balustrade Wurm", 168, Rarity.RARE, mage.cards.b.BalustradeWurm.class)); cards.add(new SetCardInfo("Baseball Bat", 209, Rarity.UNCOMMON, mage.cards.b.BaseballBat.class)); cards.add(new SetCardInfo("Bashful Beastie", 169, Rarity.COMMON, mage.cards.b.BashfulBeastie.class)); From f1460eae510350fdc77fbf95f56334c6edd6acdb Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:34:26 -0400 Subject: [PATCH 35/43] [DSK] Implement Malevolent Chandelier --- .../mage/cards/m/MalevolentChandelier.java | 48 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 49 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MalevolentChandelier.java diff --git a/Mage.Sets/src/mage/cards/m/MalevolentChandelier.java b/Mage.Sets/src/mage/cards/m/MalevolentChandelier.java new file mode 100644 index 00000000000..015ccb84a66 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MalevolentChandelier.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MalevolentChandelier extends CardImpl { + + public MalevolentChandelier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}: Put target card from a graveyard on the bottom of its owner's library. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new PutOnLibraryTargetEffect(false), new GenericManaCost(2) + ); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + } + + private MalevolentChandelier(final MalevolentChandelier card) { + super(card); + } + + @Override + public MalevolentChandelier copy() { + return new MalevolentChandelier(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 6df574d7705..12fc3c1194e 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -111,6 +111,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Leyline of the Void", 106, Rarity.RARE, mage.cards.l.LeylineOfTheVoid.class)); cards.add(new SetCardInfo("Lionheart Glimmer", 19, Rarity.UNCOMMON, mage.cards.l.LionheartGlimmer.class)); cards.add(new SetCardInfo("Live or Die", 107, Rarity.UNCOMMON, mage.cards.l.LiveOrDie.class)); + cards.add(new SetCardInfo("Malevolent Chandelier", 252, Rarity.COMMON, mage.cards.m.MalevolentChandelier.class)); cards.add(new SetCardInfo("Manifest Dread", 189, Rarity.COMMON, mage.cards.m.ManifestDread.class)); cards.add(new SetCardInfo("Marina Vendrell's Grimoire", 64, Rarity.RARE, mage.cards.m.MarinaVendrellsGrimoire.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); From 6775c3088eaa7650c777c1705dfe1cb6ab89a936 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 18:38:59 -0400 Subject: [PATCH 36/43] [DSK] Implement Conductive Machete --- .../src/mage/cards/c/ConductiveMachete.java | 43 +++++++++++++++++++ .../src/mage/cards/c/CursedWindbreaker.java | 40 +---------------- .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../common/ManifestDreadThenAttachEffect.java | 42 ++++++++++++++++++ 4 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/c/ConductiveMachete.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/ManifestDreadThenAttachEffect.java diff --git a/Mage.Sets/src/mage/cards/c/ConductiveMachete.java b/Mage.Sets/src/mage/cards/c/ConductiveMachete.java new file mode 100644 index 00000000000..afc99303f5a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConductiveMachete.java @@ -0,0 +1,43 @@ +package mage.cards.c; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ManifestDreadThenAttachEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +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 ConductiveMachete extends CardImpl { + + public ConductiveMachete(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Conductive Machete enters, manifest dread, then attach Conductive Machete to that creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ManifestDreadThenAttachEffect())); + + // Equipped creature gets +2/+1. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); + + // Equip {4} + this.addAbility(new EquipAbility(4)); + } + + private ConductiveMachete(final ConductiveMachete card) { + super(card); + } + + @Override + public ConductiveMachete copy() { + return new ConductiveMachete(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CursedWindbreaker.java b/Mage.Sets/src/mage/cards/c/CursedWindbreaker.java index 93d95a645f5..0adbba0c400 100644 --- a/Mage.Sets/src/mage/cards/c/CursedWindbreaker.java +++ b/Mage.Sets/src/mage/cards/c/CursedWindbreaker.java @@ -1,22 +1,16 @@ package mage.cards.c; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ManifestDreadThenAttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.effects.keyword.ManifestDreadEffect; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import java.util.UUID; @@ -31,7 +25,7 @@ public final class CursedWindbreaker extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // When Cursed Windbreaker enters, manifest dread, then attach Cursed Windbreaker to that creature. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CursedWindbreakerEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new ManifestDreadThenAttachEffect())); // Equipped creature has flying. this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( @@ -51,33 +45,3 @@ public final class CursedWindbreaker extends CardImpl { return new CursedWindbreaker(this); } } - -class CursedWindbreakerEffect extends OneShotEffect { - - CursedWindbreakerEffect() { - super(Outcome.Benefit); - staticText = "manifest dread, then attach {this} to that creature"; - } - - private CursedWindbreakerEffect(final CursedWindbreakerEffect effect) { - super(effect); - } - - @Override - public CursedWindbreakerEffect copy() { - return new CursedWindbreakerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Permanent creature = ManifestDreadEffect.doManifestDread(player, source, game); - Permanent equipment = source.getSourcePermanentIfItStillExists(game); - return creature != null - && equipment != null - && creature.addAttachment(equipment.getId(), source, game); - } -} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 12fc3c1194e..525a4bbdee1 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -43,6 +43,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Clammy Prowler", 45, Rarity.COMMON, mage.cards.c.ClammyProwler.class)); cards.add(new SetCardInfo("Clockwork Percussionist", 130, Rarity.COMMON, mage.cards.c.ClockworkPercussionist.class)); cards.add(new SetCardInfo("Commune with Evil", 87, Rarity.UNCOMMON, mage.cards.c.CommuneWithEvil.class)); + cards.add(new SetCardInfo("Conductive Machete", 244, Rarity.UNCOMMON, mage.cards.c.ConductiveMachete.class)); cards.add(new SetCardInfo("Cult Healer", 2, Rarity.COMMON, mage.cards.c.CultHealer.class)); cards.add(new SetCardInfo("Cursed Recording", 131, Rarity.RARE, mage.cards.c.CursedRecording.class)); cards.add(new SetCardInfo("Cursed Windbreaker", 47, Rarity.UNCOMMON, mage.cards.c.CursedWindbreaker.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ManifestDreadThenAttachEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ManifestDreadThenAttachEffect.java new file mode 100644 index 00000000000..d2999ecfc1e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ManifestDreadThenAttachEffect.java @@ -0,0 +1,42 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class ManifestDreadThenAttachEffect extends OneShotEffect { + + public ManifestDreadThenAttachEffect() { + super(Outcome.Benefit); + staticText = "manifest dread, then attach {this} to that creature"; + } + + private ManifestDreadThenAttachEffect(final ManifestDreadThenAttachEffect effect) { + super(effect); + } + + @Override + public ManifestDreadThenAttachEffect copy() { + return new ManifestDreadThenAttachEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Permanent creature = ManifestDreadEffect.doManifestDread(player, source, game); + Permanent equipment = source.getSourcePermanentIfItStillExists(game); + return creature != null + && equipment != null + && creature.addAttachment(equipment.getId(), source, game); + } +} From 0235d350505c184f704407bb5a9373adb0daf489 Mon Sep 17 00:00:00 2001 From: alma555 Date: Tue, 10 Sep 2024 18:42:34 -0400 Subject: [PATCH 37/43] UnderTheSkin implemented (#12838) * UnderTheSkin in * Applied the fixes suggested by theelk801 * more theelk801 fixes --------- Co-authored-by: Alma --- Mage.Sets/src/mage/cards/u/UnderTheSkin.java | 80 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 81 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/u/UnderTheSkin.java diff --git a/Mage.Sets/src/mage/cards/u/UnderTheSkin.java b/Mage.Sets/src/mage/cards/u/UnderTheSkin.java new file mode 100644 index 00000000000..06df505cb46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnderTheSkin.java @@ -0,0 +1,80 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author alma555 + */ +public final class UnderTheSkin extends CardImpl { + + public UnderTheSkin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Manifest Dread + this.getSpellAbility().addEffect(new ManifestDreadEffect()); + + // You may return a permanent card from your graveyard to your hand. + this.getSpellAbility().addEffect(new UnderTheSkinEffect()); + } + private UnderTheSkin(final UnderTheSkin card) { + super(card); + } + + @Override + public UnderTheSkin copy() { + return new UnderTheSkin(this); + } +} + +class UnderTheSkinEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterPermanentCard("permanent card from your graveyard"); + + UnderTheSkinEffect() { + super(Outcome.Benefit); + this.concatBy("
"); + staticText = "You may return a permanent card from your graveyard to your hand."; + } + + private UnderTheSkinEffect(final UnderTheSkinEffect effect) { + super(effect); + } + + @Override + public UnderTheSkinEffect copy() { + return new UnderTheSkinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true); + + player.choose(Outcome.ReturnToHand, target, source, game); + + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + return player.moveCards(card, Zone.HAND, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 525a4bbdee1..2eaf1a69658 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -177,6 +177,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("Under the Skin", 203, Rarity.UNCOMMON, mage.cards.u.UnderTheSkin.class)); cards.add(new SetCardInfo("Unsettling Twins", 38, Rarity.COMMON, mage.cards.u.UnsettlingTwins.class)); cards.add(new SetCardInfo("Untimely Malfunction", 161, Rarity.UNCOMMON, mage.cards.u.UntimelyMalfunction.class)); cards.add(new SetCardInfo("Unwanted Remake", 39, Rarity.UNCOMMON, mage.cards.u.UnwantedRemake.class)); From 81023eb3b4b0341ef0e8ba15e41dd7eec9530cd2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 21:41:13 -0400 Subject: [PATCH 38/43] [DSK] Implement Exorcise --- Mage.Sets/src/mage/cards/e/Exorcise.java | 50 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + Utils/mtg-cards-data.txt | 1 + 3 files changed, 52 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/Exorcise.java diff --git a/Mage.Sets/src/mage/cards/e/Exorcise.java b/Mage.Sets/src/mage/cards/e/Exorcise.java new file mode 100644 index 00000000000..d01648cd8eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Exorcise.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Exorcise extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("artifact, enchantment, or creature with power 4 or greater"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.ENCHANTMENT.getPredicate(), + Predicates.and( + CardType.CREATURE.getPredicate(), + new PowerPredicate(ComparisonType.MORE_THAN, 3) + ) + )); + } + + public Exorcise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); + + // Exile target artifact, enchantment, or creature with power 4 or greater. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private Exorcise(final Exorcise card) { + super(card); + } + + @Override + public Exorcise copy() { + return new Exorcise(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 2eaf1a69658..660aebf76ce 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -65,6 +65,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Enter the Enigma", 52, Rarity.COMMON, mage.cards.e.EnterTheEnigma.class)); cards.add(new SetCardInfo("Etched Cornfield", 258, Rarity.COMMON, mage.cards.e.EtchedCornfield.class)); cards.add(new SetCardInfo("Ethereal Armor", 7, Rarity.UNCOMMON, mage.cards.e.EtherealArmor.class)); + cards.add(new SetCardInfo("Exorcise", 8, Rarity.UNCOMMON, mage.cards.e.Exorcise.class)); cards.add(new SetCardInfo("Fanatic of the Harrowing", 96, Rarity.COMMON, mage.cards.f.FanaticOfTheHarrowing.class)); cards.add(new SetCardInfo("Fear of Being Hunted", 134, Rarity.UNCOMMON, mage.cards.f.FearOfBeingHunted.class)); cards.add(new SetCardInfo("Fear of Failed Tests", 55, Rarity.UNCOMMON, mage.cards.f.FearOfFailedTests.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index b655a337b8a..1852673f7aa 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -53986,6 +53986,7 @@ Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|4|M|{1}{W}|Ench Emerge from the Cocoon|Duskmourn: House of Horror|5|C|{4}{W}|Sorcery|||Return target creature card from your graveyard to the battlefield. You gain 3 life.| Enduring Innocence|Duskmourn: House of Horror|6|R|{1}{W}{W}|Enchantment Creature - Sheep Glimmer|2|1|Lifelink$Whenever one or more other creatures you control with power 2 or less enter, draw a card. This ability triggers only once each turn.$When Enduring Innocence dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| Ethereal Armor|Duskmourn: House of Horror|7|U|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each enchantment you control and has first strike.| +Exorcise|Duskmourn: House of Horror|8|U|{1}{W}|Sorcery|||Exile target artifact, enchantment, or creature with power 4 or greater.| Fear of Abduction|Duskmourn: House of Horror|9|U|{4}{W}{W}|Enchantment Creature - Nightmare|5|5|As an additional cost to cast this spell, exile a creature you control.$Flying$When Fear of Abduction enters, exile target creature an opponent controls.$When Fear of Abduction leaves the battlefield, put each card exiled with it into its owner's hand.| Fear of Immobility|Duskmourn: House of Horror|10|C|{4}{W}|Enchantment Creature - Nightmare|4|4|When Fear of Immobility enters, tap up to one target creature. If an opponent controls that creature, put a stun counter on it.| Fear of Surveillance|Duskmourn: House of Horror|11|C|{1}{W}|Enchantment Creature - Nightmare|2|2|Vigilance$Whenever Fear of Surveillance attacks, surveil 1.| From 9c7d2160d20361ac91f17883c934fb3487626931 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 10 Sep 2024 21:48:02 -0400 Subject: [PATCH 39/43] [DSK] Implement Duskmourn's Domination --- .../mage/cards/d/DuskmournsDomination.java | 80 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 81 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DuskmournsDomination.java diff --git a/Mage.Sets/src/mage/cards/d/DuskmournsDomination.java b/Mage.Sets/src/mage/cards/d/DuskmournsDomination.java new file mode 100644 index 00000000000..0527f725ddd --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskmournsDomination.java @@ -0,0 +1,80 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.ControlEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DuskmournsDomination extends CardImpl { + + public DuskmournsDomination(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // You control enchanted creature. + this.addAbility(new SimpleStaticAbility(new ControlEnchantedEffect())); + + // Enchanted creature gets -3/-0 and loses all abilities. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(-3, 0)); + ability.addEffect(new DuskmournsDominationEffect()); + this.addAbility(ability); + } + + private DuskmournsDomination(final DuskmournsDomination card) { + super(card); + } + + @Override + public DuskmournsDomination copy() { + return new DuskmournsDomination(this); + } +} + +class DuskmournsDominationEffect extends ContinuousEffectImpl { + + DuskmournsDominationEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.LoseAbility); + staticText = "and loses all abilities"; + } + + private DuskmournsDominationEffect(final DuskmournsDominationEffect effect) { + super(effect); + } + + @Override + public DuskmournsDominationEffect copy() { + return new DuskmournsDominationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.removeAllAbilities(source.getSourceId(), game)); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 660aebf76ce..f57e852d43f 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -56,6 +56,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Diversion Specialist", 132, Rarity.UNCOMMON, mage.cards.d.DiversionSpecialist.class)); cards.add(new SetCardInfo("Doomsday Excruciator", 94, Rarity.RARE, mage.cards.d.DoomsdayExcruciator.class)); cards.add(new SetCardInfo("Drag to the Roots", 213, Rarity.UNCOMMON, mage.cards.d.DragToTheRoots.class)); + cards.add(new SetCardInfo("Duskmourn's Domination", 50, Rarity.UNCOMMON, mage.cards.d.DuskmournsDomination.class)); cards.add(new SetCardInfo("Emerge from the Cocoon", 5, Rarity.COMMON, mage.cards.e.EmergeFromTheCocoon.class)); cards.add(new SetCardInfo("Enduring Courage", 133, Rarity.RARE, mage.cards.e.EnduringCourage.class)); cards.add(new SetCardInfo("Enduring Curiosity", 51, Rarity.RARE, mage.cards.e.EnduringCuriosity.class)); From be394fa8117635a0ae92b87155b1f785686070b7 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 11 Sep 2024 08:47:37 -0400 Subject: [PATCH 40/43] [DSC] update spoiler and reprints --- .../sets/DuskmournHouseOfHorrorCommander.java | 9 +++++++++ Utils/mtg-cards-data.txt | 20 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java index 9dc674a51c3..539cb8e8c6e 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java @@ -19,6 +19,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { super("Duskmourn: House of Horror Commander", "DSC", ExpansionSet.buildDate(2024, 9, 27), SetType.SUPPLEMENTAL); this.hasBasicLands = false; + cards.add(new SetCardInfo("Aminatou's Augury", 71, Rarity.RARE, mage.cards.a.AminatousAugury.class)); cards.add(new SetCardInfo("Arcane Signet", 92, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Archon of Cruelty", 371, Rarity.MYTHIC, mage.cards.a.ArchonOfCruelty.class)); cards.add(new SetCardInfo("Ash Barrens", 260, Rarity.COMMON, mage.cards.a.AshBarrens.class)); @@ -28,11 +29,19 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Command Tower", 96, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Crypt Ghast", 368, Rarity.MYTHIC, mage.cards.c.CryptGhast.class)); cards.add(new SetCardInfo("Damn", 369, Rarity.MYTHIC, mage.cards.d.Damn.class)); + cards.add(new SetCardInfo("Diabolic Vision", 87, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); cards.add(new SetCardInfo("Exhume", 370, Rarity.MYTHIC, mage.cards.e.Exhume.class)); cards.add(new SetCardInfo("Goryo's Vengeance", 372, Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class)); cards.add(new SetCardInfo("Growth Spiral", 88, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); cards.add(new SetCardInfo("Living Death", 373, Rarity.MYTHIC, mage.cards.l.LivingDeath.class)); + cards.add(new SetCardInfo("Mesa Enchantress", 68, Rarity.RARE, mage.cards.m.MesaEnchantress.class)); + cards.add(new SetCardInfo("Moon-Blessed Cleric", 69, Rarity.UNCOMMON, mage.cards.m.MoonBlessedCleric.class)); + cards.add(new SetCardInfo("Ponder", 73, Rarity.COMMON, mage.cards.p.Ponder.class)); + cards.add(new SetCardInfo("Portent", 74, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Sol Ring", 94, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Telling Time", 75, Rarity.UNCOMMON, mage.cards.t.TellingTime.class)); + cards.add(new SetCardInfo("Terminus", 70, Rarity.RARE, mage.cards.t.Terminus.class)); cards.add(new SetCardInfo("They Came from the Pipes", 14, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class)); + cards.add(new SetCardInfo("Utter End", 91, Rarity.RARE, mage.cards.u.UtterEnd.class)); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 1852673f7aa..b58a60d3ac4 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -54570,23 +54570,41 @@ Tornellan Protector|Sega Dreamcast Cards|9|R|{2}{W}|Creature - Cleric|1|2|{T}: U Velukan Dragon|Sega Dreamcast Cards|10|R|{5}{R}{R}|Creature - Dragon|5|5|Flying$Whenever Velukan Dragon attacks or blocks, roll a six-sided die. Velukan Dragon gets +X/+0 until end of turn, where X is the result minus 1.| Aminatou, Veil Piercer|Duskmourn: House of Horror Commander|1|M|{1}{W}{U}{B}|Legendary Creature - Human Wizard|2|4|At the beginning of your upkeep, surveil 2.$Each enchantment card in your hand has miracle. Its miracle cost is equal to its mana cost reduced by {4}.| Kianne, Corrupted Memory|Duskmourn: House of Horror Commander|2|M|{2}{G}{U}|Legendary Creature - Illusion|2|2|As long as Kianne's power is even, you may cast noncreature spells as though they had flash.$As long as Kianne's power is odd, you may cast creature spells as though they had flash.$Whenever you draw a card, put a +1/+1 counter on Kianne.| +The Master of Keys|Duskmourn: House of Horror Commander|4|M|{X}{W}{U}{B}|Legendary Enchantment Creature - Horror|3|3|Flying$When The Master of Keys enters, put X +1/+1 counters on it and mill twice X cards.$Each enchantment card in your graveyard has escape. The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard.| Valgavoth, Harrower of Souls|Duskmourn: House of Horror Commander|6|M|{2}{B}{R}|Legendary Creature - Elder Demon|4|4|Flying$Ward--Pay 2 life.$Whenever an opponent loses life for the first time during each of their turns, put a +1/+1 counter on Valgavoth, Harrower of Souls and draw a card.| Winter, Cynical Opportunist|Duskmourn: House of Horror Commander|7|M|{2}{B}{G}|Legendary Creature - Human Warlock|2|5|Deathtouch$Whenever Winter attacks, mill three cards.$Delirium -- At the beginning of your end step, you may exile any number of cards from your graveyard with four or more card types among them. If you do, put a permanent card from among them onto the battlefield with a finality counter on it.| Zimone, Mystery Unraveler|Duskmourn: House of Horror Commander|8|M|{2}{G}{U}|Legendary Creature - Human Wizard|3|3|Landfall -- Whenever a land you control enters, manifest dread if this is the first time this ability has resolved this turn. Otherwise, you may turn a permanent you control face up.| +Redress Fate|Duskmourn: House of Horror Commander|9|R|{6}{W}{W}|Sorcery|||Return all artifact and enchantment cards from your graveyard to the battlefield.$Miracle {3}{W}| +Secret Arcade // Dusty Parlor|Duskmourn: House of Horror Commander|10|R|{4}{W}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Nonland permanents you control and permanent spells you control are enchantments in addition to their other types.$Dusty Parlor${2}{W}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever you cast an enchantment spell, put a number of +1/+1 counters equal to that spell's mana value on up to one target creature.| +Soaring Lightbringer|Duskmourn: House of Horror Commander|11|R|{4}{W}|Enchantment Creature - Bird Glimmer|4|5|Flying$Other enchantment creatures you control have flying.$Whenever you attack a player, create a 1/1 white Glimmer enchantment creature token that's tapped and attacking that player.| +Fear of Sleep Paralysis|Duskmourn: House of Horror Commander|12|R|{5}{U}|Enchantment Creature - Nightmare|6|6|Flying$Eerie -- Whenever Fear of Sleep Paralysis or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.$Stun counters can't be removed from permanents your opponents control.| Glitch Interpreter|Duskmourn: House of Horror Commander|13|R|{2}{U}|Creature - Human Wizard|2|3|When Glitch Interpreter enters, if you control no face-down permanents, return Glitch Interpreter to its owner's hand and manifest dread.$Whenever one or more colorless creatures you control deal combat damage to a player, draw a card.| They Came from the Pipes|Duskmourn: House of Horror Commander|14|R|{4}{U}|Enchantment|||When They Came from the Pipes enters, manifest dread twice.$Whenever a face-down creature you control enters, draw a card.| Zimone's Hypothesis|Duskmourn: House of Horror Commander|15|R|{3}{U}{U}|Instant|||You may put a +1/+1 counter on a creature. Then choose odd or even. Return each creature with power of the chosen quality to its owner's hand.| +Ancient Cellarspawn|Duskmourn: House of Horror Commander|16|R|{1}{B}{B}|Enchantment Creature - Horror|3|3|Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.$Whenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.| +Cramped Vents // Access Maze|Duskmourn: House of Horror Commander|17|R|{3}{B}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, this Room deals 6 damage to target creature an opponent controls. You gain life equal to the excess damage dealt this way.$Access Maze${5}{B}{B}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Once during each of your turns, you may cast a spell from your hand by paying life equal to its mana value rather than paying its mana cost.| +Metamorphosis Fanatic|Duskmourn: House of Horror Commander|21|R|{4}{B}{B}|Creature - Human Cleric|4|4|Lifelink$When Metamorphosis Fanatic enters, return up to one target creature card from your graveyard to the battlefield with a lifelink counter on it.$Miracle {1}{B}| Curator Beastie|Duskmourn: House of Horror Commander|30|R|{4}{G}{G}|Creature - Beast|6|6|Reach$Colorless creatures you control enter with two additional +1/+1 counters on them.$Whenever Curator Beastie enters or attacks, manifest dread.| Disorienting Choice|Duskmourn: House of Horror Commander|32|R|{3}{G}|Sorcery|||For each opponent, choose up to one target artifact or enchantment that player controls. For each permanent chosen this way, its controller may exile it. Then if one or more of the chosen permanents are still on the battlefield, you search your library for up to that many land cards, put them onto the battlefield tapped, then shuffle.| Experimental Lab // Staff Room|Duskmourn: House of Horror Commander|33|R|{3}{G}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, manifest dread, then put two +1/+1 counters and a trample counter on that creature.$Staff Room${2}{G}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever a creature you control deals combat damage to a player, turn that creature face up or put a +1/+1 counter on it.| Shriekwood Devourer|Duskmourn: House of Horror Commander|35|R|{5}{G}{G}|Creature - Treefolk|7|5|Trample$Whenever you attack with one or more creatures, untap up to X lands, where X is the greatest power among those creatures.| +Phenomenon Investigators|Duskmourn: House of Horror Commander|38|R|{2}{U}{B}|Creature - Human Detective|3|4|As Phenomenon Investigators enters, choose Believe or Doubt.$* Believe -- Whenever a nontoken creature you control dies, create a 2/2 black Horror enchantment creature token.$* Doubt -- At the beginning of your end step, you may return a nonland permanent you own to your hand. If you do, draw a card.| Giggling Skitterspike|Duskmourn: House of Horror Commander|39|R|{4}|Artifact Creature - Toy|1|1|Indestructible$Whenever Giggling Skitterspike attacks, blocks, or becomes the target of a spell, it deals damage equal to its power to each opponent.${5}: Monstrosity 5.| +Mesa Enchantress|Duskmourn: House of Horror Commander|68|R|{1}{W}{W}|Creature - Human Druid|0|2|Whenever you cast an enchantment spell, you may draw a card.| +Moon-Blessed Cleric|Duskmourn: House of Horror Commander|69|U|{2}{W}|Creature - Human Elf Cleric|3|2|Divine Intervention -- When Moon-Blessed Cleric enters, you may search your library for an enchantment card, reveal it, then shuffle and put that card on top.| +Terminus|Duskmourn: House of Horror Commander|70|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| +Aminatou's Augury|Duskmourn: House of Horror Commander|71|R|{6}{U}{U}|Sorcery|||Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. Until end of turn, for each nonland card type, you may cast a spell of that type from among the exiled cards without paying its mana cost.| Cackling Counterpart|Duskmourn: House of Horror Commander|72|R|{1}{U}{U}|Instant|||Create a token that's a copy of target creature you control.$Flashback {5}{U}{U}| +Ponder|Duskmourn: House of Horror Commander|73|C|{U}|Sorcery|||Look at the top three cards of your library, then put them back in any order. You may shuffle.$Draw a card.| +Portent|Duskmourn: House of Horror Commander|74|C|{U}|Sorcery|||Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle.$Draw a card at the beginning of the next turn's upkeep.| +Telling Time|Duskmourn: House of Horror Commander|75|U|{1}{U}|Instant|||Look at the top three cards of your library. Put one of those cards into your hand, one on top of your library, and one on the bottom of your library.| Beast Within|Duskmourn: House of Horror Commander|80|U|{2}{G}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Beast creature token.| Citanul Hierophants|Duskmourn: House of Horror Commander|81|R|{3}{G}|Creature - Human Druid|3|2|Creatures you control have "{T}: Add {G}."| +Diabolic Vision|Duskmourn: House of Horror Commander|87|U|{U}{B}|Sorcery|||Look at the top five cards of your library. Put one of them into your hand and the rest on top of your library in any order.| Growth Spiral|Duskmourn: House of Horror Commander|88|C|{G}{U}|Instant|||Draw a card. You may put a land card from your hand onto the battlefield.| +Utter End|Duskmourn: House of Horror Commander|91|R|{2}{W}{B}|Instant|||Exile target nonland permanent.| Arcane Signet|Duskmourn: House of Horror Commander|92|C|{2}|Artifact|||{T}: Add one mana of any color in your commander's color identity.| -Sol Ring|Duskmourn: House of Horror Commander|94|C|{1}|Artifact|||{T}: Add {C}{C}.| +Sol Ring|Duskmourn: House of Horror Commander|94|U|{1}|Artifact|||{T}: Add {C}{C}.| Command Tower|Duskmourn: House of Horror Commander|96|C||Land|||{T}: Add one mana of any color in your commander's color identity.| Ash Barrens|Duskmourn: House of Horror Commander|260|C||Land|||{T}: Add {C}.$Basic landcycling {1}| Crypt Ghast|Duskmourn: House of Horror Commander|368|M|{3}{B}|Creature - Spirit|2|2|Extort$Whenever you tap a Swamp for mana, add an additional {B}.| From 96a75d1a0e5b3905a6aa05071a20f6e7ac2682d6 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 11 Sep 2024 08:50:51 -0400 Subject: [PATCH 41/43] [DSC] Implement Metamorphosis Fanatic --- .../mage/cards/m/MetamorphosisFanatic.java | 52 +++++++++++++++++++ .../sets/DuskmournHouseOfHorrorCommander.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MetamorphosisFanatic.java diff --git a/Mage.Sets/src/mage/cards/m/MetamorphosisFanatic.java b/Mage.Sets/src/mage/cards/m/MetamorphosisFanatic.java new file mode 100644 index 00000000000..e7029e2aa75 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MetamorphosisFanatic.java @@ -0,0 +1,52 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldWithCounterTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MiracleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MetamorphosisFanatic extends CardImpl { + + public MetamorphosisFanatic(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Metamorphosis Fanatic enters, return up to one target creature card from your graveyard to the battlefield with a lifelink counter on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.LIFELINK.createInstance())); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // Miracle {1}{B} + this.addAbility(new MiracleAbility("{1}{B}")); + } + + private MetamorphosisFanatic(final MetamorphosisFanatic card) { + super(card); + } + + @Override + public MetamorphosisFanatic copy() { + return new MetamorphosisFanatic(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java index 539cb8e8c6e..20a3640d974 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java @@ -35,6 +35,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Growth Spiral", 88, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); cards.add(new SetCardInfo("Living Death", 373, Rarity.MYTHIC, mage.cards.l.LivingDeath.class)); cards.add(new SetCardInfo("Mesa Enchantress", 68, Rarity.RARE, mage.cards.m.MesaEnchantress.class)); + cards.add(new SetCardInfo("Metamorphosis Fanatic", 21, Rarity.RARE, mage.cards.m.MetamorphosisFanatic.class)); cards.add(new SetCardInfo("Moon-Blessed Cleric", 69, Rarity.UNCOMMON, mage.cards.m.MoonBlessedCleric.class)); cards.add(new SetCardInfo("Ponder", 73, Rarity.COMMON, mage.cards.p.Ponder.class)); cards.add(new SetCardInfo("Portent", 74, Rarity.COMMON, mage.cards.p.Portent.class)); From dc849bea4a0ed211a4cc84ed0c5aeb99428265da Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 11 Sep 2024 09:27:02 -0400 Subject: [PATCH 42/43] [DSK] Implement Paranormal Analyst --- .../src/mage/cards/p/ParanormalAnalyst.java | 119 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + .../effects/keyword/ManifestDreadEffect.java | 3 + .../main/java/mage/game/events/GameEvent.java | 1 + .../game/events/ManifestedDreadEvent.java | 31 +++++ 5 files changed, 155 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/ParanormalAnalyst.java create mode 100644 Mage/src/main/java/mage/game/events/ManifestedDreadEvent.java diff --git a/Mage.Sets/src/mage/cards/p/ParanormalAnalyst.java b/Mage.Sets/src/mage/cards/p/ParanormalAnalyst.java new file mode 100644 index 00000000000..45cee0cf316 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParanormalAnalyst.java @@ -0,0 +1,119 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ManifestedDreadEvent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ParanormalAnalyst extends CardImpl { + + public ParanormalAnalyst(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DETECTIVE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you manifest dread, put a card you put into your graveyard this way into your hand. + this.addAbility(new ParanormalAnalystTriggeredAbility()); + } + + private ParanormalAnalyst(final ParanormalAnalyst card) { + super(card); + } + + @Override + public ParanormalAnalyst copy() { + return new ParanormalAnalyst(this); + } +} + +class ParanormalAnalystTriggeredAbility extends TriggeredAbilityImpl { + + ParanormalAnalystTriggeredAbility() { + super(Zone.BATTLEFIELD, new ParanormalAnalystEffect()); + setTriggerPhrase("Whenever you manifest dread, "); + } + + private ParanormalAnalystTriggeredAbility(final ParanormalAnalystTriggeredAbility ability) { + super(ability); + } + + @Override + public ParanormalAnalystTriggeredAbility copy() { + return new ParanormalAnalystTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.MANIFESTED_DREAD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + this.getEffects().setTargetPointer(new FixedTargets(((ManifestedDreadEvent) event).getGraveyardCards())); + return true; + } +} + +class ParanormalAnalystEffect extends OneShotEffect { + + ParanormalAnalystEffect() { + super(Outcome.Benefit); + staticText = "put a card you put into your graveyard this way into your hand"; + } + + private ParanormalAnalystEffect(final ParanormalAnalystEffect effect) { + super(effect); + } + + @Override + public ParanormalAnalystEffect copy() { + return new ParanormalAnalystEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + cards.retainZone(Zone.GRAVEYARD, game); + Card card; + switch (cards.size()) { + case 0: + return false; + case 1: + card = cards.getRandom(game); + break; + default: + TargetCard target = new TargetCardInYourGraveyard(); + target.withNotTarget(true); + player.choose(outcome, cards, target, source, game); + card = game.getCard(target.getFirstTarget()); + } + return player.moveCards(card, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index f57e852d43f..47a283c45e6 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -131,6 +131,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Overlord of the Floodpits", 68, Rarity.MYTHIC, mage.cards.o.OverlordOfTheFloodpits.class)); cards.add(new SetCardInfo("Overlord of the Hauntwoods", 194, Rarity.MYTHIC, mage.cards.o.OverlordOfTheHauntwoods.class)); cards.add(new SetCardInfo("Overlord of the Mistmoors", 23, Rarity.MYTHIC, mage.cards.o.OverlordOfTheMistmoors.class)); + cards.add(new SetCardInfo("Paranormal Analyst", 69, Rarity.UNCOMMON, mage.cards.p.ParanormalAnalyst.class)); cards.add(new SetCardInfo("Patched Plaything", 24, Rarity.UNCOMMON, mage.cards.p.PatchedPlaything.class)); cards.add(new SetCardInfo("Patchwork Beastie", 195, Rarity.UNCOMMON, mage.cards.p.PatchworkBeastie.class)); cards.add(new SetCardInfo("Peculiar Lighthouse", 265, Rarity.COMMON, mage.cards.p.PeculiarLighthouse.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java index 1d95b80d8c7..08b39d74c6d 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java @@ -8,6 +8,7 @@ import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.ManifestedDreadEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; @@ -65,6 +66,8 @@ public class ManifestDreadEffect extends OneShotEffect { } cards.retainZone(Zone.LIBRARY, game); player.moveCards(cards, Zone.GRAVEYARD, source, game); + cards.retainZone(Zone.GRAVEYARD, game); + game.fireEvent(new ManifestedDreadEvent(permanent, source, player.getId(), cards, game)); return permanent; } } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 73d61926f72..413b2261cc5 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -478,6 +478,7 @@ public class GameEvent implements Serializable { PHASE_IN, PHASED_IN, TURN_FACE_UP, TURNED_FACE_UP, TURN_FACE_DOWN, TURNED_FACE_DOWN, + MANIFESTED_DREAD, /* OPTION_USED targetId originalId of the ability that triggered the event sourceId sourceId of the ability that triggered the event diff --git a/Mage/src/main/java/mage/game/events/ManifestedDreadEvent.java b/Mage/src/main/java/mage/game/events/ManifestedDreadEvent.java new file mode 100644 index 00000000000..846a2a7ec64 --- /dev/null +++ b/Mage/src/main/java/mage/game/events/ManifestedDreadEvent.java @@ -0,0 +1,31 @@ +package mage.game.events; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.cards.Cards; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class ManifestedDreadEvent extends GameEvent { + + private final List graveyardCards = new ArrayList<>(); + + public ManifestedDreadEvent(Permanent permanent, Ability source, UUID playerId, Cards cards, Game game) { + super(EventType.MANIFESTED_DREAD, permanent == null ? null : permanent.getId(), source, playerId); + cards.getCards(game) + .stream() + .map(card -> new MageObjectReference(card, game)) + .forEach(graveyardCards::add); + } + + public List getGraveyardCards() { + return graveyardCards; + } +} From b97bb9b5df893c2c0d6449cec4597e413d57390c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 11 Sep 2024 14:07:50 -0400 Subject: [PATCH 43/43] [DSK] Implement Let's Play a Game --- Mage.Sets/src/mage/cards/l/LetsPlayAGame.java | 61 +++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 62 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LetsPlayAGame.java diff --git a/Mage.Sets/src/mage/cards/l/LetsPlayAGame.java b/Mage.Sets/src/mage/cards/l/LetsPlayAGame.java new file mode 100644 index 00000000000..85b4f2a6db1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LetsPlayAGame.java @@ -0,0 +1,61 @@ +package mage.cards.l; + +import mage.abilities.Mode; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LetsPlayAGame extends CardImpl { + + public LetsPlayAGame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Delirium -- Choose one. If there are four or more card types among cards in your graveyard, choose one or more instead. + this.getSpellAbility().getModes().setChooseText( + "choose one. If there are four or more card types among cards in your graveyard, choose one or more instead." + ); + this.getSpellAbility().getModes().setMoreCondition(DeliriumCondition.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DELIRIUM); + this.getSpellAbility().addHint(CardTypesInGraveyardHint.YOU); + + // * Creatures your opponents control get -1/-1 until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false + )); + + // * Each opponent discards two cards. + this.getSpellAbility().addMode(new Mode(new DiscardEachPlayerEffect( + StaticValue.get(2), false, TargetController.OPPONENT + ))); + + // * Each opponent loses 3 life and you gain 3 life. + this.getSpellAbility().addMode(new Mode(new LoseLifeOpponentsEffect(3)) + .addEffect(new GainLifeEffect(3).concatBy("and"))); + } + + private LetsPlayAGame(final LetsPlayAGame card) { + super(card); + } + + @Override + public LetsPlayAGame copy() { + return new LetsPlayAGame(this); + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 47a283c45e6..d70f4da0cac 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -108,6 +108,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Island", 273, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Kona, Rescue Beastie", 187, Rarity.RARE, mage.cards.k.KonaRescueBeastie.class)); cards.add(new SetCardInfo("Lakeside Shack", 262, Rarity.COMMON, mage.cards.l.LakesideShack.class)); + cards.add(new SetCardInfo("Let's Play a Game", 105, Rarity.UNCOMMON, mage.cards.l.LetsPlayAGame.class)); cards.add(new SetCardInfo("Leyline of Hope", 18, Rarity.RARE, mage.cards.l.LeylineOfHope.class)); cards.add(new SetCardInfo("Leyline of Mutation", 188, Rarity.RARE, mage.cards.l.LeylineOfMutation.class)); cards.add(new SetCardInfo("Leyline of Resonance", 143, Rarity.RARE, mage.cards.l.LeylineOfResonance.class));