From a1d528f261b155eade331ce872ee0c15b7852e85 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:10:09 -0400 Subject: [PATCH 01/18] [SPM] Implement Doc Ock, Sinister Scientist --- .../mage/cards/d/DocOckSinisterScientist.java | 69 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 70 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DocOckSinisterScientist.java diff --git a/Mage.Sets/src/mage/cards/d/DocOckSinisterScientist.java b/Mage.Sets/src/mage/cards/d/DocOckSinisterScientist.java new file mode 100644 index 00000000000..675412e19cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DocOckSinisterScientist.java @@ -0,0 +1,69 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DocOckSinisterScientist extends CardImpl { + + private static final Condition condition = new CardsInControllerGraveyardCondition(8); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VILLAIN); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition2 = new PermanentsOnTheBattlefieldCondition(filter); + + public DocOckSinisterScientist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // As long as there are eight or more cards in your graveyard, Doc Ock has base power and toughness 8/8. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new SetBasePowerToughnessSourceEffect(8, 8, Duration.WhileOnBattlefield), condition, + "as long as there are eight or more cards in your graveyard, {this} has base power and toughness 8/8" + ))); + + // As long as you control another Villain, Doc Ock has hexproof. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(HexproofAbility.getInstance()), condition2, + "as long as you control another Villain, {this} has hexproof" + ))); + } + + private DocOckSinisterScientist(final DocOckSinisterScientist card) { + super(card); + } + + @Override + public DocOckSinisterScientist copy() { + return new DocOckSinisterScientist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index d172015f4ba..e5e8bc8134b 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -25,6 +25,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Beetle, Legacy Criminal", 26, Rarity.COMMON, mage.cards.b.BeetleLegacyCriminal.class)); cards.add(new SetCardInfo("Daily Bugle Reporters", 6, Rarity.COMMON, mage.cards.d.DailyBugleReporters.class)); cards.add(new SetCardInfo("Doc Ock's Henchmen", 30, Rarity.COMMON, mage.cards.d.DocOcksHenchmen.class)); + cards.add(new SetCardInfo("Doc Ock, Sinister Scientist", 29, Rarity.COMMON, mage.cards.d.DocOckSinisterScientist.class)); cards.add(new SetCardInfo("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class)); cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); From a76d82884b2055af1def04ad6ea955830ecde9a1 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:11:31 -0400 Subject: [PATCH 02/18] [SPM] Implement Grow Extra Arms --- Mage.Sets/src/mage/cards/g/GrowExtraArms.java | 47 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GrowExtraArms.java diff --git a/Mage.Sets/src/mage/cards/g/GrowExtraArms.java b/Mage.Sets/src/mage/cards/g/GrowExtraArms.java new file mode 100644 index 00000000000..0afce620725 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrowExtraArms.java @@ -0,0 +1,47 @@ +package mage.cards.g; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrowExtraArms extends CardImpl { + + private static final Condition condition + = new SourceTargetsPermanentCondition(new FilterPermanent(SubType.SPIDER, "a Spider")); + + public GrowExtraArms(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // This spell costs {1} less to cast if it targets a Spider. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(1, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Target creature gets +4/+4 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private GrowExtraArms(final GrowExtraArms card) { + super(card); + } + + @Override + public GrowExtraArms copy() { + return new GrowExtraArms(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index e5e8bc8134b..2dd6060755a 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -29,6 +29,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class)); cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Grow Extra Arms", 101, Rarity.COMMON, mage.cards.g.GrowExtraArms.class)); cards.add(new SetCardInfo("Guy in the Chair", 102, Rarity.COMMON, mage.cards.g.GuyInTheChair.class)); cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kapow!", 103, Rarity.COMMON, mage.cards.k.Kapow.class)); From 167a44399a5cf8c6131d2f5a99aea6966506b349 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:15:39 -0400 Subject: [PATCH 03/18] [SPM] Implement Venom, Evil Unleashed --- .../mage/cards/b/BeetleLegacyCriminal.java | 2 +- .../src/mage/cards/v/VenomEvilUnleashed.java | 58 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/v/VenomEvilUnleashed.java diff --git a/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java b/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java index fdb86fd1b9f..233f3b7981e 100644 --- a/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java +++ b/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java @@ -44,7 +44,7 @@ public final class BeetleLegacyCriminal extends CardImpl { ability.addCost(new ExileSourceFromGraveCost()); ability.addTarget(new TargetCreaturePermanent()); ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()) - .setText("Put a +1/+1 counter on target creature")); + .setText("It gains flying until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VenomEvilUnleashed.java b/Mage.Sets/src/mage/cards/v/VenomEvilUnleashed.java new file mode 100644 index 00000000000..b58c7a5c575 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomEvilUnleashed.java @@ -0,0 +1,58 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenomEvilUnleashed extends CardImpl { + + public VenomEvilUnleashed(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SYMBIOTE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // {2}{B}, Exile this card from your graveyard: Put two +1/+1 counters on target creature. It gains deathtouch until end of turn. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.GRAVEYARD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{2}{B}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + ability.addTarget(new TargetCreaturePermanent()); + ability.addEffect(new GainAbilityTargetEffect(DeathtouchAbility.getInstance()) + .setText("It gains deathtouch until end of turn")); + this.addAbility(ability); + } + + private VenomEvilUnleashed(final VenomEvilUnleashed card) { + super(card); + } + + @Override + public VenomEvilUnleashed copy() { + return new VenomEvilUnleashed(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 2dd6060755a..2f412dd33f1 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -63,6 +63,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class)); cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.class)); cards.add(new SetCardInfo("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.class)); + cards.add(new SetCardInfo("Venom, Evil Unleashed", 71, Rarity.COMMON, mage.cards.v.VenomEvilUnleashed.class)); cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); cards.add(new SetCardInfo("Whoosh!", 48, Rarity.COMMON, mage.cards.w.Whoosh.class)); cards.add(new SetCardInfo("Wild Pack Squad", 23, Rarity.COMMON, mage.cards.w.WildPackSquad.class)); From c28a6780806fbc1082f1ed41a2c2edeed7009533 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:30:26 -0400 Subject: [PATCH 04/18] [SPM] Implement Unstable Experiment --- Mage.Sets/src/mage/cards/c/ChangeOfPlans.java | 8 ++-- .../src/mage/cards/k/KamizObscuraOculus.java | 31 ++----------- .../src/mage/cards/o/ObscuraConfluence.java | 29 +----------- .../mage/cards/s/ScorpionSeethingStriker.java | 31 +------------ .../src/mage/cards/u/UnstableExperiment.java | 37 ++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../effects/keyword/ConniveTargetEffect.java | 44 +++++++++++++++++++ 7 files changed, 93 insertions(+), 88 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/u/UnstableExperiment.java create mode 100644 Mage/src/main/java/mage/abilities/effects/keyword/ConniveTargetEffect.java diff --git a/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java index 0d0b27b6f5b..e4b236b1c97 100644 --- a/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java +++ b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java @@ -2,7 +2,7 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -30,6 +30,7 @@ public final class ChangeOfPlans extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{1}{U}"); // Each of X target creatures you control connive. You may have any number of them phase out. + this.getSpellAbility().addEffect(new ConniveTargetEffect().setText("each of X target creatures you control connive")); this.getSpellAbility().addEffect(new ChangeOfPlansEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); @@ -49,7 +50,7 @@ class ChangeOfPlansEffect extends OneShotEffect { ChangeOfPlansEffect() { super(Outcome.Benefit); - staticText = "each of X target creatures you control connive. You may have any number of them phase out"; + staticText = "You may have any number of them phase out"; } private ChangeOfPlansEffect(final ChangeOfPlansEffect effect) { @@ -73,9 +74,6 @@ class ChangeOfPlansEffect extends OneShotEffect { if (permanents.isEmpty()) { return false; } - for (Permanent permanent : permanents) { - ConniveSourceEffect.connive(permanent, 1, source, game); - } Player player = game.getPlayer(source.getControllerId()); if (player == null) { return true; diff --git a/Mage.Sets/src/mage/cards/k/KamizObscuraOculus.java b/Mage.Sets/src/mage/cards/k/KamizObscuraOculus.java index 592a648f543..b08245c145f 100644 --- a/Mage.Sets/src/mage/cards/k/KamizObscuraOculus.java +++ b/Mage.Sets/src/mage/cards/k/KamizObscuraOculus.java @@ -6,7 +6,7 @@ import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -39,7 +39,7 @@ public final class KamizObscuraOculus extends CardImpl { // Whenever you attack, target attacking creature can't be blocked this turn. It connives. Then choose another attacking creature with lesser power. That creature gains double strike until end of turn. Ability ability = new AttacksWithCreaturesTriggeredAbility(new CantBeBlockedTargetEffect(), 1); - ability.addEffect(new KamizConniveEffect()); + ability.addEffect(new ConniveTargetEffect().setText("it connives")); ability.addEffect(new KamizDoubleStrikeEffect().concatBy("Then")); ability.addTarget(new TargetAttackingCreature()); this.addAbility(ability); @@ -55,29 +55,6 @@ public final class KamizObscuraOculus extends CardImpl { } } -class KamizConniveEffect extends OneShotEffect { - - KamizConniveEffect() { - super(Outcome.Benefit); - staticText = "it connives"; - } - - private KamizConniveEffect(final KamizConniveEffect effect) { - super(effect); - } - - @Override - public KamizConniveEffect copy() { - return new KamizConniveEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - return ConniveSourceEffect.connive(permanent, 1, source, game); - } -} - class KamizDoubleStrikeEffect extends OneShotEffect { KamizDoubleStrikeEffect() { @@ -109,8 +86,8 @@ class KamizDoubleStrikeEffect extends OneShotEffect { if (target.choose(outcome, source.getControllerId(), source.getSourceId(), source, game)) { game.addEffect( new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()) - .setTargetPointer(new FixedTarget(target.getFirstTarget(), game)) - , source); + .setTargetPointer(new FixedTarget(target.getFirstTarget(), game)), source + ); } return true; } diff --git a/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java b/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java index 663747f9a98..4d053ef18a8 100644 --- a/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java +++ b/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java @@ -5,7 +5,7 @@ import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,7 +14,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; import mage.target.TargetPlayer; @@ -44,7 +43,7 @@ public final class ObscuraConfluence extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // • Target creature connives. - this.getSpellAbility().addMode(new Mode(new ObscuraConfluenceConniveEffect()).addTarget(new TargetCreaturePermanent())); + this.getSpellAbility().addMode(new Mode(new ConniveTargetEffect()).addTarget(new TargetCreaturePermanent())); // • Target player returns a creature card from their graveyard to their hand. this.getSpellAbility().addMode(new Mode(new ObscuraConfluenceReturnEffect()).addTarget(new TargetPlayer())); @@ -60,30 +59,6 @@ public final class ObscuraConfluence extends CardImpl { } } -class ObscuraConfluenceConniveEffect extends OneShotEffect { - - ObscuraConfluenceConniveEffect() { - super(Outcome.Benefit); - staticText = "target creature connives. (Draw a card, then discard a card. " + - "If you discarded a nonland card, put a +1/+1 counter on that creature.)"; - } - - private ObscuraConfluenceConniveEffect(final ObscuraConfluenceConniveEffect effect) { - super(effect); - } - - @Override - public ObscuraConfluenceConniveEffect copy() { - return new ObscuraConfluenceConniveEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - return ConniveSourceEffect.connive(permanent, 1, source, game); - } -} - class ObscuraConfluenceReturnEffect extends OneShotEffect { ObscuraConfluenceReturnEffect() { diff --git a/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java index ae85ab0fa00..61699b8f551 100644 --- a/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java +++ b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java @@ -2,17 +2,14 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; -import mage.game.Game; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -36,7 +33,7 @@ public final class ScorpionSeethingStriker extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // At the beginning of your end step, if a creature died this turn, target creature you control connives. - Ability ability = new BeginningOfEndStepTriggeredAbility(new ScorpionSeethingStrikerEffect()); + Ability ability = new BeginningOfEndStepTriggeredAbility(new ConniveTargetEffect()); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } @@ -50,27 +47,3 @@ public final class ScorpionSeethingStriker extends CardImpl { return new ScorpionSeethingStriker(this); } } - -class ScorpionSeethingStrikerEffect extends OneShotEffect { - - ScorpionSeethingStrikerEffect() { - super(Outcome.Benefit); - staticText = "target creature you control connives"; - } - - private ScorpionSeethingStrikerEffect(final ScorpionSeethingStrikerEffect effect) { - super(effect); - } - - @Override - public ScorpionSeethingStrikerEffect copy() { - return new ScorpionSeethingStrikerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return ConniveSourceEffect.connive( - game.getPermanent(getTargetPointer().getFirst(game, source)), 1, source, game - ); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnstableExperiment.java b/Mage.Sets/src/mage/cards/u/UnstableExperiment.java new file mode 100644 index 00000000000..45e47307181 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnstableExperiment.java @@ -0,0 +1,37 @@ +package mage.cards.u; + +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnstableExperiment extends CardImpl { + + public UnstableExperiment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Target player draws a card, then up to one target creature you control connives. + this.getSpellAbility().addEffect(new DrawCardTargetEffect(1)); + this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addEffect(new ConniveTargetEffect().setTargetPointer(new SecondTargetPointer()).concatBy(", then")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1)); + } + + private UnstableExperiment(final UnstableExperiment card) { + super(card); + } + + @Override + public UnstableExperiment copy() { + return new UnstableExperiment(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 2f412dd33f1..72bf67a3015 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -62,6 +62,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Taxi Driver", 97, Rarity.COMMON, mage.cards.t.TaxiDriver.class)); cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class)); cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.class)); + cards.add(new SetCardInfo("Unstable Experiment", 47, Rarity.COMMON, mage.cards.u.UnstableExperiment.class)); cards.add(new SetCardInfo("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.class)); cards.add(new SetCardInfo("Venom, Evil Unleashed", 71, Rarity.COMMON, mage.cards.v.VenomEvilUnleashed.class)); cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ConniveTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveTargetEffect.java new file mode 100644 index 00000000000..cf2edfe58c1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveTargetEffect.java @@ -0,0 +1,44 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class ConniveTargetEffect extends OneShotEffect { + + public ConniveTargetEffect() { + super(Outcome.Benefit); + } + + private ConniveTargetEffect(final ConniveTargetEffect effect) { + super(effect); + } + + @Override + public ConniveTargetEffect copy() { + return new ConniveTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + ConniveSourceEffect.connive(game.getPermanent(targetId), 1, source, game); + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return this.getTargetPointer().describeTargets(mode.getTargets(), "it") + " connives"; + } +} From bd3519005f99a9d3f336faa3f13fcd48c7e2aaee Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:31:06 -0400 Subject: [PATCH 05/18] [SPM] add missing condition to Scorpion, Seething Striker --- Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java index 61699b8f551..ca42cd43563 100644 --- a/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java +++ b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java @@ -2,7 +2,9 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.condition.common.MorbidCondition; import mage.abilities.effects.keyword.ConniveTargetEffect; +import mage.abilities.hint.common.MorbidHint; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; @@ -33,9 +35,9 @@ public final class ScorpionSeethingStriker extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // At the beginning of your end step, if a creature died this turn, target creature you control connives. - Ability ability = new BeginningOfEndStepTriggeredAbility(new ConniveTargetEffect()); + Ability ability = new BeginningOfEndStepTriggeredAbility(new ConniveTargetEffect()).withInterveningIf(MorbidCondition.instance); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.addHint(MorbidHint.instance)); } private ScorpionSeethingStriker(final ScorpionSeethingStriker card) { From 24304c2880df3d483beb5567ea87e9123804c33a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:32:26 -0400 Subject: [PATCH 06/18] [SPM] Implement Mechanical Mobster --- .../src/mage/cards/m/MechanicalMobster.java | 48 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 49 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MechanicalMobster.java diff --git a/Mage.Sets/src/mage/cards/m/MechanicalMobster.java b/Mage.Sets/src/mage/cards/m/MechanicalMobster.java new file mode 100644 index 00000000000..df0f73c0ef2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MechanicalMobster.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.keyword.ConniveTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MechanicalMobster extends CardImpl { + + public MechanicalMobster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When this creature enters, exile up to one target card from a graveyard. Target creature you control connives. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); + ability.addTarget(new TargetCardInGraveyard(0, 1)); + ability.addEffect(new ConniveTargetEffect().setTargetPointer(new SecondTargetPointer())); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private MechanicalMobster(final MechanicalMobster card) { + super(card); + } + + @Override + public MechanicalMobster copy() { + return new MechanicalMobster(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 72bf67a3015..bc057052da7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -36,6 +36,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Kraven's Cats", 104, Rarity.COMMON, mage.cards.k.KravensCats.class)); cards.add(new SetCardInfo("Lurking Lizards", 107, Rarity.COMMON, mage.cards.l.LurkingLizards.class)); cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.class)); + cards.add(new SetCardInfo("Mechanical Mobster", 168, Rarity.COMMON, mage.cards.m.MechanicalMobster.class)); cards.add(new SetCardInfo("Merciless Enforcers", 58, Rarity.COMMON, mage.cards.m.MercilessEnforcers.class)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Origin of Spider-Man", 9, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class)); From 8587bcc0688d3e33dadb302095947e0df8bc18c2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:36:38 -0400 Subject: [PATCH 07/18] [SPM] Implement Spider-Man Noir --- Mage.Sets/src/mage/cards/s/SpiderManNoir.java | 83 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 84 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderManNoir.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderManNoir.java b/Mage.Sets/src/mage/cards/s/SpiderManNoir.java new file mode 100644 index 00000000000..abe72d486c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderManNoir.java @@ -0,0 +1,83 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderManNoir extends CardImpl { + + public SpiderManNoir(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever a creature you control attacks alone, put a +1/+1 counter on it. Then surveil X, where X is the number of counters on it. + Ability ability = new AttacksAloneControlledTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it") + ); + ability.addEffect(new SpiderManNoirEffect()); + this.addAbility(ability); + } + + private SpiderManNoir(final SpiderManNoir card) { + super(card); + } + + @Override + public SpiderManNoir copy() { + return new SpiderManNoir(this); + } +} + +class SpiderManNoirEffect extends OneShotEffect { + + SpiderManNoirEffect() { + super(Outcome.Benefit); + staticText = "Then surveil X, where X is the number of counters on it"; + } + + private SpiderManNoirEffect(final SpiderManNoirEffect effect) { + super(effect); + } + + @Override + public SpiderManNoirEffect copy() { + return new SpiderManNoirEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + return player != null + && permanent != null + && player.surveil(permanent.getCounters(game).getTotalCount(), source, game); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index bc057052da7..947c5ac70db 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -55,6 +55,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class)); cards.add(new SetCardInfo("Spider-Gwen, Free Spirit", 90, Rarity.COMMON, mage.cards.s.SpiderGwenFreeSpirit.class)); cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 114, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class)); + cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class)); cards.add(new SetCardInfo("Spider-Man, Brooklyn Visionary", 115, Rarity.COMMON, mage.cards.s.SpiderManBrooklynVisionary.class)); cards.add(new SetCardInfo("Spider-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class)); cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.class)); From f5902e8ee0f385cca3dd43d1bc465566c33d3f0e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:39:34 -0400 Subject: [PATCH 08/18] [SPM] Implement Stegron the Dinosaur Man --- .../mage/cards/s/StegronTheDinosaurMan.java | 57 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/StegronTheDinosaurMan.java diff --git a/Mage.Sets/src/mage/cards/s/StegronTheDinosaurMan.java b/Mage.Sets/src/mage/cards/s/StegronTheDinosaurMan.java new file mode 100644 index 00000000000..1e0ada677dc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StegronTheDinosaurMan.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StegronTheDinosaurMan extends CardImpl { + + public StegronTheDinosaurMan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.DINOSAUR); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility()); + + // Dinosaur Formula -- {1}{R}, Discard this card: Until end of turn, target creature you control gets +3/+1 and becomes a Dinosaur in addition to its other types. + Ability ability = new SimpleActivatedAbility( + Zone.HAND, + new BoostTargetEffect(3, 1) + .setText("until end of turn, target creature you control gets +3/+1"), + new ManaCostsImpl<>("{1}{R}") + ); + ability.addCost(new DiscardSourceCost()); + ability.addEffect(new AddCardSubTypeTargetEffect(SubType.DINOSAUR, Duration.EndOfTurn) + .setText("and becomes a Dinosaur in addition to its other types")); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability.withFlavorWord("Dinosaur Formula")); + } + + private StegronTheDinosaurMan(final StegronTheDinosaurMan card) { + super(card); + } + + @Override + public StegronTheDinosaurMan copy() { + return new StegronTheDinosaurMan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 947c5ac70db..622ff106419 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -60,6 +60,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spider-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class)); cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.class)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); + cards.add(new SetCardInfo("Stegron the Dinosaur Man", 95, Rarity.COMMON, mage.cards.s.StegronTheDinosaurMan.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Taxi Driver", 97, Rarity.COMMON, mage.cards.t.TaxiDriver.class)); cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class)); From 3682805a808021c086266cb132e098959250c6fe Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:50:12 -0400 Subject: [PATCH 09/18] [SPM] Implement Spider-Islanders --- .../src/mage/cards/s/SpiderIslanders.java | 38 ++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 7 ++ .../mage/abilities/keyword/MayhemAbility.java | 73 +++++++++++++++++++ .../abilities/keyword/WebSlingingAbility.java | 2 +- Utils/keywords.txt | 1 + 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderIslanders.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/MayhemAbility.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderIslanders.java b/Mage.Sets/src/mage/cards/s/SpiderIslanders.java new file mode 100644 index 00000000000..f741921c1c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderIslanders.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.MayhemAbility; +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 SpiderIslanders extends CardImpl { + + public SpiderIslanders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HORROR); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Mayhem {1}{R} + this.addAbility(new MayhemAbility(this, "{1}{R}")); + } + + private SpiderIslanders(final SpiderIslanders card) { + super(card); + } + + @Override + public SpiderIslanders copy() { + return new SpiderIslanders(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 622ff106419..559abecd14d 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -4,11 +4,15 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.Arrays; +import java.util.List; + /** * @author TheElk801 */ public final class MarvelsSpiderMan extends ExpansionSet { + private static final List unfinished = Arrays.asList("Electro's Bolt", "Spider-Islanders"); private static final MarvelsSpiderMan instance = new MarvelsSpiderMan(); public static MarvelsSpiderMan getInstance() { @@ -55,6 +59,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class)); cards.add(new SetCardInfo("Spider-Gwen, Free Spirit", 90, Rarity.COMMON, mage.cards.s.SpiderGwenFreeSpirit.class)); cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 114, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class)); + cards.add(new SetCardInfo("Spider-Islanders", 91, Rarity.COMMON, mage.cards.s.SpiderIslanders.class)); cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class)); cards.add(new SetCardInfo("Spider-Man, Brooklyn Visionary", 115, Rarity.COMMON, mage.cards.s.SpiderManBrooklynVisionary.class)); cards.add(new SetCardInfo("Spider-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class)); @@ -71,5 +76,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); cards.add(new SetCardInfo("Whoosh!", 48, Rarity.COMMON, mage.cards.w.Whoosh.class)); cards.add(new SetCardInfo("Wild Pack Squad", 23, Rarity.COMMON, mage.cards.w.WildPackSquad.class)); + + cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MayhemAbility.java b/Mage/src/main/java/mage/abilities/keyword/MayhemAbility.java new file mode 100644 index 00000000000..4b0478a40ba --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/MayhemAbility.java @@ -0,0 +1,73 @@ +package mage.abilities.keyword; + +import mage.ApprovingObject; +import mage.MageIdentifier; +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.watchers.common.CastSpellLastTurnWatcher; + +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class MayhemAbility extends SpellAbility { + + public static final String MAYHEM_ACTIVATION_VALUE_KEY = "mayhemActivation"; + + private final String rule; + + public MayhemAbility(Card card, String manaString) { + super(card.getSpellAbility()); + this.newId(); + this.setCardName(card.getName() + " with Mayhem"); + zone = Zone.GRAVEYARD; + spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + + this.clearManaCosts(); + this.clearManaCostsToPay(); + this.addCost(new ManaCostsImpl<>(manaString)); + + this.setRuleAtTheTop(true); + this.rule = "Surge " + manaString + + " (You may cast this card from your graveyard for "+manaString+ + " if you discarded it this turn. Timing rules still apply.)"; + } + + protected MayhemAbility(final MayhemAbility ability) { + super(ability); + this.rule = ability.rule; + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + // TODO: Implement this + return super.canActivate(playerId,game); + } + + @Override + public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { + if (!super.activate(game, allowedIdentifiers, noMana)) { + return false; + } + this.setCostsTag(MAYHEM_ACTIVATION_VALUE_KEY, null); + return true; + } + + @Override + public MayhemAbility copy() { + return new MayhemAbility(this); + } + + @Override + public String getRule() { + return rule; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java b/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java index 4faa0001a6e..be683fb32fb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java @@ -16,7 +16,7 @@ import mage.target.common.TargetControlledPermanent; import java.util.Set; /** - * @author LevelX2 + * @author TheElk801 */ public class WebSlingingAbility extends SpellAbility { diff --git a/Utils/keywords.txt b/Utils/keywords.txt index f23982f5082..fa446453d07 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -84,6 +84,7 @@ Lifelink|instance| Living metal|new| Living weapon|new| Madness|cost| +Mayhem|card, manaString| Melee|new| Menace|new| Mentor|new| From bb37e796653b2192bd448779fce4dcfcce38ee04 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:50:59 -0400 Subject: [PATCH 10/18] [SPM] Implement Electro's Bolt --- Mage.Sets/src/mage/cards/e/ElectrosBolt.java | 36 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 37 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/ElectrosBolt.java diff --git a/Mage.Sets/src/mage/cards/e/ElectrosBolt.java b/Mage.Sets/src/mage/cards/e/ElectrosBolt.java new file mode 100644 index 00000000000..0db11cffee2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElectrosBolt.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.MayhemAbility; +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 ElectrosBolt extends CardImpl { + + public ElectrosBolt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Electro's Bolt deals 4 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Mayhem {1}{R} + this.addAbility(new MayhemAbility(this, "{1}{R}")); + } + + private ElectrosBolt(final ElectrosBolt card) { + super(card); + } + + @Override + public ElectrosBolt copy() { + return new ElectrosBolt(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 559abecd14d..359e2562dc7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -31,6 +31,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Doc Ock's Henchmen", 30, Rarity.COMMON, mage.cards.d.DocOcksHenchmen.class)); cards.add(new SetCardInfo("Doc Ock, Sinister Scientist", 29, Rarity.COMMON, mage.cards.d.DocOckSinisterScientist.class)); cards.add(new SetCardInfo("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class)); + cards.add(new SetCardInfo("Electro's Bolt", 77, Rarity.COMMON, mage.cards.e.ElectrosBolt.class)); cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grow Extra Arms", 101, Rarity.COMMON, mage.cards.g.GrowExtraArms.class)); From 447a5e33dd8c54db3a865050eee1eae972af4b72 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:54:54 -0400 Subject: [PATCH 11/18] [SPE] Implement Double Trouble --- Mage.Sets/src/mage/cards/d/DoubleTrouble.java | 68 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 69 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DoubleTrouble.java diff --git a/Mage.Sets/src/mage/cards/d/DoubleTrouble.java b/Mage.Sets/src/mage/cards/d/DoubleTrouble.java new file mode 100644 index 00000000000..3dd0b2a5ba1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoubleTrouble.java @@ -0,0 +1,68 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DoubleTrouble extends CardImpl { + + public DoubleTrouble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + // Double the power of each creature you control until end of turn. + this.getSpellAbility().addEffect(new DoubleTroubleEffect()); + } + + private DoubleTrouble(final DoubleTrouble card) { + super(card); + } + + @Override + public DoubleTrouble copy() { + return new DoubleTrouble(this); + } +} + +class DoubleTroubleEffect extends OneShotEffect { + + DoubleTroubleEffect() { + super(Outcome.Benefit); + staticText = "double the power of each creature you control until end of turn"; + } + + private DoubleTroubleEffect(final DoubleTroubleEffect effect) { + super(effect); + } + + @Override + public DoubleTroubleEffect copy() { + return new DoubleTroubleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game + )) { + int power = permanent.getPower().getValue(); + if (power != 0) { + game.addEffect(new BoostTargetEffect(power, 0) + .setTargetPointer(new FixedTarget(permanent, game)), source); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 0457ffe02fd..7f6eb0f4e87 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -23,6 +23,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Alchemax Slayer-Bots", 5, Rarity.COMMON, mage.cards.a.AlchemaxSlayerBots.class)); cards.add(new SetCardInfo("Amateur Hero", 1, Rarity.COMMON, mage.cards.a.AmateurHero.class)); cards.add(new SetCardInfo("Doc Ock, Evil Inventor", 24, Rarity.RARE, mage.cards.d.DocOckEvilInventor.class)); + cards.add(new SetCardInfo("Double Trouble", 13, Rarity.RARE, mage.cards.d.DoubleTrouble.class)); cards.add(new SetCardInfo("Future Flight", 6, Rarity.RARE, mage.cards.f.FutureFlight.class)); cards.add(new SetCardInfo("Grasping Tentacles", 21, Rarity.RARE, mage.cards.g.GraspingTentacles.class)); cards.add(new SetCardInfo("Green Goblin, Nemesis", 23, Rarity.RARE, mage.cards.g.GreenGoblinNemesis.class)); From 8a3d12502112aeb2bde257a79220d672f39ef6bc Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 13:58:52 -0400 Subject: [PATCH 12/18] [SPE] Implement Amazing Alliance --- .../src/mage/cards/a/AmazingAlliance.java | 46 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AmazingAlliance.java diff --git a/Mage.Sets/src/mage/cards/a/AmazingAlliance.java b/Mage.Sets/src/mage/cards/a/AmazingAlliance.java new file mode 100644 index 00000000000..9cbaa9e1a94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AmazingAlliance.java @@ -0,0 +1,46 @@ +package mage.cards.a; + +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.EffectKeyValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AmazingAlliance extends CardImpl { + + private static final DynamicValue xValue = new EffectKeyValue( + AttacksWithCreaturesTriggeredAbility.VALUEKEY_NUMBER_ATTACKERS, "that much" + ); + + public AmazingAlliance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); + + // Creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); + + // Whenever you attack with one or more legendary creatures, you gain that much life. + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new GainLifeEffect(xValue), 1, StaticFilters.FILTER_CREATURES_LEGENDARY + )); + } + + private AmazingAlliance(final AmazingAlliance card) { + super(card); + } + + @Override + public AmazingAlliance copy() { + return new AmazingAlliance(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 7f6eb0f4e87..2fdbf60bc8c 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -22,6 +22,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Alchemax Slayer-Bots", 5, Rarity.COMMON, mage.cards.a.AlchemaxSlayerBots.class)); cards.add(new SetCardInfo("Amateur Hero", 1, Rarity.COMMON, mage.cards.a.AmateurHero.class)); + cards.add(new SetCardInfo("Amazing Alliance", 2, Rarity.RARE, mage.cards.a.AmazingAlliance.class)); cards.add(new SetCardInfo("Doc Ock, Evil Inventor", 24, Rarity.RARE, mage.cards.d.DocOckEvilInventor.class)); cards.add(new SetCardInfo("Double Trouble", 13, Rarity.RARE, mage.cards.d.DoubleTrouble.class)); cards.add(new SetCardInfo("Future Flight", 6, Rarity.RARE, mage.cards.f.FutureFlight.class)); From 525e3aa7b16cd90df160fc9ee32d67bcf05a4f6a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:02:30 -0400 Subject: [PATCH 13/18] [SPE] Implement Ghost-Spider, Gwen Stacy --- .../mage/cards/g/GhostSpiderGwenStacy.java | 58 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 59 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GhostSpiderGwenStacy.java diff --git a/Mage.Sets/src/mage/cards/g/GhostSpiderGwenStacy.java b/Mage.Sets/src/mage/cards/g/GhostSpiderGwenStacy.java new file mode 100644 index 00000000000..a22de7d4aaf --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhostSpiderGwenStacy.java @@ -0,0 +1,58 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GhostSpiderGwenStacy extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_ATTACKING_CREATURE); + private static final Hint hint = new ValueHint("Attacking creatures", xValue); + + public GhostSpiderGwenStacy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever Ghost-Spider attacks, she deals X damage to defending player, where X is the number of attacking creatures. + this.addAbility(new AttacksTriggeredAbility( + new DamageTargetEffect(xValue) + .setText("she deals X damage to defending player, where X is the number of attacking creatures"), + false, null, SetTargetPointer.PLAYER + ).addHint(hint)); + } + + private GhostSpiderGwenStacy(final GhostSpiderGwenStacy card) { + super(card); + } + + @Override + public GhostSpiderGwenStacy copy() { + return new GhostSpiderGwenStacy(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 2fdbf60bc8c..d25dc3f649d 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -26,6 +26,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Doc Ock, Evil Inventor", 24, Rarity.RARE, mage.cards.d.DocOckEvilInventor.class)); cards.add(new SetCardInfo("Double Trouble", 13, Rarity.RARE, mage.cards.d.DoubleTrouble.class)); cards.add(new SetCardInfo("Future Flight", 6, Rarity.RARE, mage.cards.f.FutureFlight.class)); + cards.add(new SetCardInfo("Ghost-Spider, Gwen Stacy", 14, Rarity.MYTHIC, mage.cards.g.GhostSpiderGwenStacy.class)); cards.add(new SetCardInfo("Grasping Tentacles", 21, Rarity.RARE, mage.cards.g.GraspingTentacles.class)); cards.add(new SetCardInfo("Green Goblin, Nemesis", 23, Rarity.RARE, mage.cards.g.GreenGoblinNemesis.class)); cards.add(new SetCardInfo("Grendel, Spawn of Knull", 9, Rarity.UNCOMMON, mage.cards.g.GrendelSpawnOfKnull.class)); From d50db8bca9b9869501ab74f23381c6cfb75e7125 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:04:41 -0400 Subject: [PATCH 14/18] [SPE] Implement Lethal Protection --- .../src/mage/cards/l/LethalProtection.java | 40 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 41 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LethalProtection.java diff --git a/Mage.Sets/src/mage/cards/l/LethalProtection.java b/Mage.Sets/src/mage/cards/l/LethalProtection.java new file mode 100644 index 00000000000..5e121d32484 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LethalProtection.java @@ -0,0 +1,40 @@ +package mage.cards.l; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LethalProtection extends CardImpl { + + public LethalProtection(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Destroy target creature. Return up to one target creature card from your graveyard to your hand. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect().setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard( + 0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD + )); + } + + private LethalProtection(final LethalProtection card) { + super(card); + } + + @Override + public LethalProtection copy() { + return new LethalProtection(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index d25dc3f649d..fb65b10f564 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -30,6 +30,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Grasping Tentacles", 21, Rarity.RARE, mage.cards.g.GraspingTentacles.class)); cards.add(new SetCardInfo("Green Goblin, Nemesis", 23, Rarity.RARE, mage.cards.g.GreenGoblinNemesis.class)); cards.add(new SetCardInfo("Grendel, Spawn of Knull", 9, Rarity.UNCOMMON, mage.cards.g.GrendelSpawnOfKnull.class)); + cards.add(new SetCardInfo("Lethal Protection", 10, Rarity.RARE, mage.cards.l.LethalProtection.class)); cards.add(new SetCardInfo("Lyla, Holographic Assistant", 7, Rarity.UNCOMMON, mage.cards.l.LylaHolographicAssistant.class)); cards.add(new SetCardInfo("MJ, Rising Star", 3, Rarity.UNCOMMON, mage.cards.m.MJRisingStar.class)); cards.add(new SetCardInfo("Prowler, Misguided Mentor", 17, Rarity.UNCOMMON, mage.cards.p.ProwlerMisguidedMentor.class)); From f3ed594715a5c70a72a22e268e6a33e8cd72b7de Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:06:23 -0400 Subject: [PATCH 15/18] [SPE] Implement Rampaging Classmate --- .../src/mage/cards/r/RampagingClassmate.java | 47 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RampagingClassmate.java diff --git a/Mage.Sets/src/mage/cards/r/RampagingClassmate.java b/Mage.Sets/src/mage/cards/r/RampagingClassmate.java new file mode 100644 index 00000000000..4f6e97b8695 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampagingClassmate.java @@ -0,0 +1,47 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RampagingClassmate extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_ATTACKING_CREATURE, 1); + + public RampagingClassmate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever this creature attacks, it gets +1/+0 until end of turn for each other attacking creature. + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + xValue, StaticValue.get(0), Duration.EndOfTurn, "it" + ))); + } + + private RampagingClassmate(final RampagingClassmate card) { + super(card); + } + + @Override + public RampagingClassmate copy() { + return new RampagingClassmate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index fb65b10f564..b98ea6de79c 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -35,6 +35,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("MJ, Rising Star", 3, Rarity.UNCOMMON, mage.cards.m.MJRisingStar.class)); cards.add(new SetCardInfo("Prowler, Misguided Mentor", 17, Rarity.UNCOMMON, mage.cards.p.ProwlerMisguidedMentor.class)); cards.add(new SetCardInfo("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); + cards.add(new SetCardInfo("Rampaging Classmate", 16, Rarity.COMMON, mage.cards.r.RampagingClassmate.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); cards.add(new SetCardInfo("Spider-Man, Miles Morales", 18, Rarity.MYTHIC, mage.cards.s.SpiderManMilesMorales.class)); cards.add(new SetCardInfo("Spider-Man, Peter Parker", 4, Rarity.MYTHIC, mage.cards.s.SpiderManPeterParker.class)); From 3b1a5bc8ceb6c581a5544f0b279adbc356cec745 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:07:58 -0400 Subject: [PATCH 16/18] [SPE] Implement Spider-Man 2099, Miguel O'Hara --- .../cards/s/SpiderMan2099MiguelOHara.java | 50 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 51 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderMan2099MiguelOHara.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderMan2099MiguelOHara.java b/Mage.Sets/src/mage/cards/s/SpiderMan2099MiguelOHara.java new file mode 100644 index 00000000000..82c23d78c46 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderMan2099MiguelOHara.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderMan2099MiguelOHara extends CardImpl { + + public SpiderMan2099MiguelOHara(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Spider-Man 2099 enters, return up to one target creature to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // Whenever one or more creatures you control deal combat damage to a player, draw a card. + this.addAbility(new OneOrMoreCombatDamagePlayerTriggeredAbility(new DrawCardSourceControllerEffect(1))); + } + + private SpiderMan2099MiguelOHara(final SpiderMan2099MiguelOHara card) { + super(card); + } + + @Override + public SpiderMan2099MiguelOHara copy() { + return new SpiderMan2099MiguelOHara(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index b98ea6de79c..14d7f98dc1d 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -37,6 +37,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); cards.add(new SetCardInfo("Rampaging Classmate", 16, Rarity.COMMON, mage.cards.r.RampagingClassmate.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); + cards.add(new SetCardInfo("Spider-Man 2099, Miguel O'Hara", 8, Rarity.MYTHIC, mage.cards.s.SpiderMan2099MiguelOHara.class)); cards.add(new SetCardInfo("Spider-Man, Miles Morales", 18, Rarity.MYTHIC, mage.cards.s.SpiderManMilesMorales.class)); cards.add(new SetCardInfo("Spider-Man, Peter Parker", 4, Rarity.MYTHIC, mage.cards.s.SpiderManPeterParker.class)); cards.add(new SetCardInfo("Symbiote Spawn", 11, Rarity.COMMON, mage.cards.s.SymbioteSpawn.class)); From 8cd3256c650c31072574a5d2ff0ab6758ef8724c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:12:16 -0400 Subject: [PATCH 17/18] [SPE] Implement Venom, Eddie Brock --- .../src/mage/cards/v/VenomEddieBrock.java | 82 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 83 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VenomEddieBrock.java diff --git a/Mage.Sets/src/mage/cards/v/VenomEddieBrock.java b/Mage.Sets/src/mage/cards/v/VenomEddieBrock.java new file mode 100644 index 00000000000..b21e1406228 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomEddieBrock.java @@ -0,0 +1,82 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +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.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenomEddieBrock extends CardImpl { + + public VenomEddieBrock(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SYMBIOTE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(6); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever another creature dies, put a +1/+1 counter on Venom. If that creature was a Villain, draw a card. + Ability ability = new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true + ); + ability.addEffect(new VenomEddieBrockEffect()); + this.addAbility(ability); + } + + private VenomEddieBrock(final VenomEddieBrock card) { + super(card); + } + + @Override + public VenomEddieBrock copy() { + return new VenomEddieBrock(this); + } +} + +class VenomEddieBrockEffect extends OneShotEffect { + + VenomEddieBrockEffect() { + super(Outcome.Benefit); + staticText = "If that creature was a Villain, draw a card"; + } + + private VenomEddieBrockEffect(final VenomEddieBrockEffect effect) { + super(effect); + } + + @Override + public VenomEddieBrockEffect copy() { + return new VenomEddieBrockEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue("creatureDied"); + return player != null + && permanent != null + && permanent.hasSubtype(SubType.VILLAIN, game) + && player.drawCards(1, source, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 14d7f98dc1d..40c23ea29be 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -44,5 +44,6 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Twisted Spider-Clone", 19, Rarity.COMMON, mage.cards.t.TwistedSpiderClone.class)); cards.add(new SetCardInfo("Venom Blast", 20, Rarity.RARE, mage.cards.v.VenomBlast.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); + cards.add(new SetCardInfo("Venom, Eddie Brock", 12, Rarity.MYTHIC, mage.cards.v.VenomEddieBrock.class)); } } From 788041c5b50f71531d19127c1df7785822cb2c2a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 14:15:31 -0400 Subject: [PATCH 18/18] [SPE] Implement The Mary Janes --- Mage.Sets/src/mage/cards/t/TheMaryJanes.java | 52 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TheMaryJanes.java diff --git a/Mage.Sets/src/mage/cards/t/TheMaryJanes.java b/Mage.Sets/src/mage/cards/t/TheMaryJanes.java new file mode 100644 index 00000000000..63210e9109d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheMaryJanes.java @@ -0,0 +1,52 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CreaturesThatAttackedThisTurnCount; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheMaryJanes extends CardImpl { + + public TheMaryJanes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.subtype.add(SubType.PERFORMER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // This spell costs {1} less to cast for each creature that attacked this turn. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionForEachSourceEffect( + 1, CreaturesThatAttackedThisTurnCount.instance + ) + ).addHint(CreaturesThatAttackedThisTurnCount.getHint())); + + // Menace + this.addAbility(new MenaceAbility()); + } + + private TheMaryJanes(final TheMaryJanes card) { + super(card); + } + + @Override + public TheMaryJanes copy() { + return new TheMaryJanes(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 40c23ea29be..532b1723ad7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -41,6 +41,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Spider-Man, Miles Morales", 18, Rarity.MYTHIC, mage.cards.s.SpiderManMilesMorales.class)); cards.add(new SetCardInfo("Spider-Man, Peter Parker", 4, Rarity.MYTHIC, mage.cards.s.SpiderManPeterParker.class)); cards.add(new SetCardInfo("Symbiote Spawn", 11, Rarity.COMMON, mage.cards.s.SymbioteSpawn.class)); + cards.add(new SetCardInfo("The Mary Janes", 15, Rarity.UNCOMMON, mage.cards.t.TheMaryJanes.class)); cards.add(new SetCardInfo("Twisted Spider-Clone", 19, Rarity.COMMON, mage.cards.t.TwistedSpiderClone.class)); cards.add(new SetCardInfo("Venom Blast", 20, Rarity.RARE, mage.cards.v.VenomBlast.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class));