From b88cd910c34e0190d5f08d42f9bebaf223837e98 Mon Sep 17 00:00:00 2001 From: Matthew Wilson Date: Thu, 15 Feb 2024 05:17:11 +0200 Subject: [PATCH] [MKM] Implement Melek, Reforged Researcher (#11788) --- .../mage/cards/m/MelekReforgedResearcher.java | 125 ++++++++++++++++++ .../src/mage/sets/MurdersAtKarlovManor.java | 1 + 2 files changed, 126 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MelekReforgedResearcher.java diff --git a/Mage.Sets/src/mage/cards/m/MelekReforgedResearcher.java b/Mage.Sets/src/mage/cards/m/MelekReforgedResearcher.java new file mode 100644 index 00000000000..eddf9e6909b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MelekReforgedResearcher.java @@ -0,0 +1,125 @@ +package mage.cards.m; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +/** + * + * @author DominionSpy + */ +public final class MelekReforgedResearcher extends CardImpl { + + private static final FilterCard filter = new FilterInstantOrSorceryCard("the first instant or sorcery spell"); + + static { + filter.add(new MelekReforgedResearcherPredicate()); + } + + public MelekReforgedResearcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.WEIRD); + this.subtype.add(SubType.DETECTIVE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Melek, Reforged Researcher's power and toughness are each equal to twice the number of instant and sorcery cards in your graveyard. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetBasePowerToughnessSourceEffect( + new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY, 2)) + .setText("{this}'s power and toughness are each equal to twice the number of instant and sorcery cards in your graveyard"))); + + // The first instant or sorcery spell you cast each turn costs {3} less to cast. + Effect effect = new SpellsCostReductionControllerEffect(filter, 3); + effect.setText("The first instant or sorcery spell you cast each turn costs {3} less to cast"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), + new MelekReforgedResearcherWatcher()); + } + + private MelekReforgedResearcher(final MelekReforgedResearcher card) { + super(card); + } + + @Override + public MelekReforgedResearcher copy() { + return new MelekReforgedResearcher(this); + } +} + +class MelekReforgedResearcherPredicate implements ObjectSourcePlayerPredicate { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + if (input.getObject() instanceof Card && + ((Card) input.getObject()).isInstantOrSorcery(game)) { + MelekReforgedResearcherWatcher watcher = game.getState().getWatcher(MelekReforgedResearcherWatcher.class); + return watcher != null && + watcher.getInstantOrSorcerySpellsCastThisTurn(input.getPlayerId()) == 0; + } + return false; + } + + @Override + public String toString() { + return "The first instant or sorcery spell you cast each turn"; + } +} + +class MelekReforgedResearcherWatcher extends Watcher { + + private final Map playerInstantOrSorcerySpells = new HashMap<>(); + + MelekReforgedResearcherWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch (GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null || !spell.isInstantOrSorcery(game)) { + return; + } + playerInstantOrSorcerySpells.put(event.getPlayerId(), + getInstantOrSorcerySpellsCastThisTurn(event.getPlayerId()) + 1); + } + + @Override + public void reset() { + playerInstantOrSorcerySpells.clear(); + super.reset(); + } + + public int getInstantOrSorcerySpellsCastThisTurn(UUID playerId) { + return playerInstantOrSorcerySpells.getOrDefault(playerId, 0); + } +} diff --git a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java index b436ef85457..0660feec3ac 100644 --- a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java +++ b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java @@ -158,6 +158,7 @@ public final class MurdersAtKarlovManor extends ExpansionSet { cards.add(new SetCardInfo("Marketwatch Phantom", 24, Rarity.COMMON, mage.cards.m.MarketwatchPhantom.class)); cards.add(new SetCardInfo("Massacre Girl, Known Killer", 94, Rarity.MYTHIC, mage.cards.m.MassacreGirlKnownKiller.class)); cards.add(new SetCardInfo("Meddling Youths", 219, Rarity.UNCOMMON, mage.cards.m.MeddlingYouths.class)); + cards.add(new SetCardInfo("Melek, Reforged Researcher", 430, Rarity.MYTHIC, mage.cards.m.MelekReforgedResearcher.class)); cards.add(new SetCardInfo("Meticulous Archive", 264, Rarity.RARE, mage.cards.m.MeticulousArchive.class)); cards.add(new SetCardInfo("Mistway Spy", 65, Rarity.UNCOMMON, mage.cards.m.MistwaySpy.class)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));