From c20a5110ca5c1b409c70424d9909c598da3ebb4e Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:45:06 +0200 Subject: [PATCH 01/66] fix [EOE] Illvoi Light Jammer's Mana Cost --- Mage.Sets/src/mage/cards/i/IllvoiLightJammer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/i/IllvoiLightJammer.java b/Mage.Sets/src/mage/cards/i/IllvoiLightJammer.java index 68810679a56..b2d6ce5c42c 100644 --- a/Mage.Sets/src/mage/cards/i/IllvoiLightJammer.java +++ b/Mage.Sets/src/mage/cards/i/IllvoiLightJammer.java @@ -21,7 +21,7 @@ import java.util.UUID; public final class IllvoiLightJammer extends CardImpl { public IllvoiLightJammer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); this.subtype.add(SubType.EQUIPMENT); From 33b8e6fcaaa570fed6a6ace4c0c11dbe5aee7035 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sun, 20 Jul 2025 11:49:45 -0400 Subject: [PATCH 02/66] rework verify skip for double-faced omen cards --- .../src/test/java/mage/verify/VerifyCardDataTest.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index e6f773d2bc9..504380ebb08 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1818,7 +1818,7 @@ public class VerifyCardDataTest { private void check(Card card, int cardIndex) { MtgJsonCard ref = MtgJsonService.cardFromSet(card.getExpansionSetCode(), card.getName(), card.getCardNumber()); if (ref != null) { - if (card instanceof SpellOptionCard && ref.layout.equals("reversible_card")) { + if ((card instanceof CardWithSpellOption || card instanceof SpellOptionCard) && ref.layout.equals("reversible_card")) { // TODO: Remove when MtgJson updated // workaround for reversible omen cards e.g. Bloomvine Regent // Claim Territory // Bloomvine Regent // both sides have main card info @@ -2337,11 +2337,7 @@ public class VerifyCardDataTest { String additionalName; if (card instanceof CardWithSpellOption) { // adventure/omen cards - if (card.getName().equals("Bloomvine Regent") || card.getName().equals("Marang River Regent") || card.getName().equals("Scavenger Regent")) { - additionalName = null; - } else { - additionalName = ((CardWithSpellOption) card).getSpellCard().getName(); - } + additionalName = ((CardWithSpellOption) card).getSpellCard().getName(); } else if (card.isTransformable() && !card.isNightCard()) { additionalName = card.getSecondCardFace().getName(); } else { From 9667d7573c97638798f9c97dfa376e611316a1d3 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 21 Jul 2025 11:04:04 -0400 Subject: [PATCH 03/66] small update to StationLevelAbility --- .../main/java/mage/abilities/keyword/StationLevelAbility.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java b/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java index 20791ca75f9..a021b34bd79 100644 --- a/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/StationLevelAbility.java @@ -127,7 +127,7 @@ class StationLevelCreatureEffect extends ContinuousEffectImpl { } switch (layer) { case TypeChangingEffects_4: - permanent.addCardType(game, CardType.ARTIFACT, CardType.CREATURE); + permanent.addCardType(game, CardType.CREATURE); return true; case PTChangingEffects_7: if (sublayer != SubLayer.SetPT_7b) { From a039800259534e4378c7b681c4b2dfe4255f24f7 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 21 Jul 2025 11:04:53 -0400 Subject: [PATCH 04/66] [EOE] update Diplomatic Immunity with day-one errata --- Mage.Sets/src/mage/cards/d/DiplomaticRelations.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java b/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java index d0fe0dfeb8e..54ce8343623 100644 --- a/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java +++ b/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java @@ -7,7 +7,7 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -20,11 +20,11 @@ public final class DiplomaticRelations extends CardImpl { public DiplomaticRelations(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); - // Target creature gets +1/+0 and gains vigilance until end of turn. It deals damage equal to its power to target creature an opponent controls. + // Target creature you control gets +1/+0 and gains vigilance until end of turn. It deals damage equal to its power to target creature an opponent controls. this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance()) .setText("and gains vigilance until end of turn")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("it")); this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); } From 33596d55b35dd4b9666c4ce05a53bd40b83c16ea Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 21 Jul 2025 15:38:22 -0400 Subject: [PATCH 05/66] [EOE] fix Pain for All targeting --- Mage.Sets/src/mage/cards/p/PainForAll.java | 23 ++++--------------- .../permanent/AnotherEnchantedPredicate.java | 11 +++++++-- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PainForAll.java b/Mage.Sets/src/mage/cards/p/PainForAll.java index b245e81c0a8..767fbf697a2 100644 --- a/Mage.Sets/src/mage/cards/p/PainForAll.java +++ b/Mage.Sets/src/mage/cards/p/PainForAll.java @@ -9,9 +9,9 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.permanent.AnotherEnchantedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -26,10 +26,10 @@ import java.util.UUID; */ public final class PainForAll extends CardImpl { - private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer("any other target"); + private static final FilterPermanentOrPlayer filter = new FilterAnyTarget("any other target"); static { - filter.getPermanentFilter().add(PainForAllPredicate.instance); + filter.getPermanentFilter().add(AnotherEnchantedPredicate.instance); } public PainForAll(UUID ownerId, CardSetInfo setInfo) { @@ -64,21 +64,6 @@ public final class PainForAll extends CardImpl { } } -enum PainForAllPredicate implements ObjectSourcePlayerPredicate { - instance; - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - return Optional - .ofNullable(input) - .map(ObjectSourcePlayer::getSource) - .map(source -> source.getSourcePermanentOrLKI(game)) - .map(Permanent::getAttachedTo) - .filter(permanentId -> !permanentId.equals(input.getObject().getId())) - .isPresent(); - } -} - class PainForAllFirstEffect extends OneShotEffect { PainForAllFirstEffect() { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java index 5de3a69c5d0..4311ae7e11b 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java @@ -5,6 +5,8 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Optional; + /** * Filters out the id of the enchanted object, if the source is an enchantment * @@ -15,8 +17,13 @@ public enum AnotherEnchantedPredicate implements ObjectSourcePlayerPredicate input, Game game) { - Permanent enchantment = input.getSource().getSourcePermanentIfItStillExists(game); - return enchantment != null && !input.getObject().getId().equals(enchantment.getAttachedTo()); + return !Optional + .ofNullable(input) + .map(ObjectSourcePlayer::getSource) + .map(source -> source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .filter(input.getObject().getId()::equals) + .isPresent(); } @Override From 1b6c5724a8dcd46f43c7ab4f729d750d47b1fe3b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 21 Jul 2025 17:07:55 -0400 Subject: [PATCH 06/66] [EOS] a few text fixes --- .../src/mage/cards/g/GemstoneCaverns.java | 2 +- .../src/mage/cards/w/WanderingFumarole.java | 48 +++++-------------- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java b/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java index c9fa5f9c270..14f678a3fd5 100644 --- a/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java +++ b/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java @@ -82,7 +82,7 @@ class GemstoneCavernsAbility extends StaticAbility implements OpeningHandAction @Override public String getRule() { - return "If {this} is in your opening hand and you're not the starting player, you may begin the game with {this} on the battlefield with a luck counter on it. If you do, exile a card from your hand."; + return "If this card is in your opening hand and you're not the starting player, you may begin the game with {this} on the battlefield with a luck counter on it. If you do, exile a card from your hand."; } @Override diff --git a/Mage.Sets/src/mage/cards/w/WanderingFumarole.java b/Mage.Sets/src/mage/cards/w/WanderingFumarole.java index 424a3705310..e3bec4359b2 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingFumarole.java +++ b/Mage.Sets/src/mage/cards/w/WanderingFumarole.java @@ -1,12 +1,8 @@ - package mage.cards.w; -import java.util.UUID; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.SwitchPowerToughnessSourceEffect; import mage.abilities.mana.BlueManaAbility; @@ -14,32 +10,35 @@ import mage.abilities.mana.RedManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.permanent.token.TokenImpl; +import mage.constants.SubType; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.UUID; /** - * * @author fireshoes */ public final class WanderingFumarole extends CardImpl { public WanderingFumarole(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Wandering Fumarole enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); - + // {T}: Add {U} or {R}. this.addAbility(new BlueManaAbility()); this.addAbility(new RedManaAbility()); - + // {2}{U}{R}: Until end of turn, Wandering Fumarole becomes a 1/4 blue and red Elemental creature with // "0: Switch this creature's power and toughness until end of turn." It's still a land. - Effect effect = new BecomesCreatureSourceEffect(new WanderingFumaroleToken(), CardType.LAND, Duration.EndOfTurn); - effect.setText("{this} becomes a 1/4 blue and red Elemental creature with \"0: Switch this creature's power and toughness until end of turn.\" It's still a land"); - this.addAbility(new SimpleActivatedAbility(effect, new ManaCostsImpl<>("{2}{U}{R}"))); + this.addAbility(new SimpleActivatedAbility(new BecomesCreatureSourceEffect(new CreatureToken( + 1, 4, "1/4 blue and red Elemental creature " + + "with \"{0}: Switch this creature's power and toughness until end of turn.\"", SubType.ELEMENTAL + ).withColor("UR").withAbility(new SimpleActivatedAbility( + new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{0}") + )), CardType.LAND, Duration.EndOfTurn).withDurationRuleAtStart(true), new ManaCostsImpl<>("{2}{U}{R}"))); } private WanderingFumarole(final WanderingFumarole card) { @@ -51,24 +50,3 @@ public final class WanderingFumarole extends CardImpl { return new WanderingFumarole(this); } } - -class WanderingFumaroleToken extends TokenImpl { - - public WanderingFumaroleToken() { - super("", "1/4 blue and red Elemental creature with \"0: Switch this creature's power and toughness until end of turn.\""); - cardType.add(CardType.CREATURE); - subtype.add(SubType.ELEMENTAL); - color.setRed(true); - color.setBlue(true); - power = new MageInt(1); - toughness = new MageInt(4); - addAbility(new SimpleActivatedAbility(new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{0}"))); - } - private WanderingFumaroleToken(final WanderingFumaroleToken token) { - super(token); - } - - public WanderingFumaroleToken copy() { - return new WanderingFumaroleToken(this); - } -} From 5b87fffc2e1fa9442b6edc172d688e4d01c17ffc Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 21 Jul 2025 17:26:24 -0400 Subject: [PATCH 07/66] [EOE] various text fixes --- Mage.Sets/src/mage/cards/a/AuxiliaryBoosters.java | 2 +- Mage.Sets/src/mage/cards/d/DiplomaticRelations.java | 3 ++- Mage.Sets/src/mage/cards/k/KavaronTurbodrone.java | 2 +- Mage.Sets/src/mage/cards/m/MechanShieldmate.java | 2 +- Mage.Sets/src/mage/cards/m/MentalModulation.java | 4 ++-- Mage.Sets/src/mage/cards/o/OrbitalPlunge.java | 2 +- Mage.Sets/src/mage/cards/p/PerigeeBeckoner.java | 2 +- Mage.Sets/src/mage/cards/p/PinnacleStarcage.java | 2 +- Mage.Sets/src/mage/cards/r/RigForWar.java | 9 ++++----- Mage.Sets/src/mage/cards/s/SelfcraftMechan.java | 2 +- .../src/test/java/mage/verify/VerifyCardDataTest.java | 1 - 11 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AuxiliaryBoosters.java b/Mage.Sets/src/mage/cards/a/AuxiliaryBoosters.java index 7143bb4d480..82337c6c81d 100644 --- a/Mage.Sets/src/mage/cards/a/AuxiliaryBoosters.java +++ b/Mage.Sets/src/mage/cards/a/AuxiliaryBoosters.java @@ -28,7 +28,7 @@ public final class AuxiliaryBoosters extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // When this Equipment enters, create a 2/2 colorless Robot artifact creature token and attach this Equipment to it. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenAttachSourceEffect(new RobotToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenAttachSourceEffect(new RobotToken(), " and"))); // Equipped creature gets +1/+2 and has flying. Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 2)); diff --git a/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java b/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java index 54ce8343623..0b5abb89aad 100644 --- a/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java +++ b/Mage.Sets/src/mage/cards/d/DiplomaticRelations.java @@ -21,7 +21,8 @@ public final class DiplomaticRelations extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // Target creature you control gets +1/+0 and gains vigilance until end of turn. It deals damage equal to its power to target creature an opponent controls. - this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0)); + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0) + .setText("target creature you control gets +1/+0")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance()) .setText("and gains vigilance until end of turn")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/k/KavaronTurbodrone.java b/Mage.Sets/src/mage/cards/k/KavaronTurbodrone.java index 8fdd27aca55..3582826bea7 100644 --- a/Mage.Sets/src/mage/cards/k/KavaronTurbodrone.java +++ b/Mage.Sets/src/mage/cards/k/KavaronTurbodrone.java @@ -32,7 +32,7 @@ public final class KavaronTurbodrone extends CardImpl { // {T}: Target creature you control gets +1/+1 and gains haste until end of turn. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility( new BoostTargetEffect(1, 1, Duration.EndOfTurn) - .setText("Target creature gets +1/+1"), + .setText("Target creature you control gets +1/+1"), new TapSourceCost() ); ability.addEffect(new GainAbilityTargetEffect( diff --git a/Mage.Sets/src/mage/cards/m/MechanShieldmate.java b/Mage.Sets/src/mage/cards/m/MechanShieldmate.java index 077b37d1bd8..7c26c5dae0a 100644 --- a/Mage.Sets/src/mage/cards/m/MechanShieldmate.java +++ b/Mage.Sets/src/mage/cards/m/MechanShieldmate.java @@ -37,7 +37,7 @@ public final class MechanShieldmate extends CardImpl { new ConditionalAsThoughEffect( new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), ArtifactEnteredUnderYourControlCondition.instance - ).setText("As long as an artifact entered the battlefield under your control this turn," + ).setText("As long as an artifact entered the battlefield under your control this turn, " + "this creature can attack as though it didn't have defender") ).addHint(new ConditionHint(ArtifactEnteredUnderYourControlCondition.instance)), new ArtifactEnteredControllerWatcher() diff --git a/Mage.Sets/src/mage/cards/m/MentalModulation.java b/Mage.Sets/src/mage/cards/m/MentalModulation.java index 7b5249369e5..4968a3c38ca 100644 --- a/Mage.Sets/src/mage/cards/m/MentalModulation.java +++ b/Mage.Sets/src/mage/cards/m/MentalModulation.java @@ -21,7 +21,7 @@ import java.util.UUID; public final class MentalModulation extends CardImpl { public MentalModulation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // This spell costs {1} less to cast during your turn. Ability ability = new SimpleStaticAbility( @@ -46,4 +46,4 @@ public final class MentalModulation extends CardImpl { public MentalModulation copy() { return new MentalModulation(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/o/OrbitalPlunge.java b/Mage.Sets/src/mage/cards/o/OrbitalPlunge.java index 94fa3a24ccd..e5238585a3d 100644 --- a/Mage.Sets/src/mage/cards/o/OrbitalPlunge.java +++ b/Mage.Sets/src/mage/cards/o/OrbitalPlunge.java @@ -43,7 +43,7 @@ class OrbitalPlungeEffect extends OneShotEffect { OrbitalPlungeEffect() { super(Outcome.Benefit); staticText = "{this} deals 6 damage to target creature. " + - "If excess damage was dealt to a permanent this way, create a Lander token."; + "If excess damage was dealt this way, create a Lander token."; } private OrbitalPlungeEffect(final OrbitalPlungeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/p/PerigeeBeckoner.java b/Mage.Sets/src/mage/cards/p/PerigeeBeckoner.java index 73f702f719c..dd53f59be3b 100644 --- a/Mage.Sets/src/mage/cards/p/PerigeeBeckoner.java +++ b/Mage.Sets/src/mage/cards/p/PerigeeBeckoner.java @@ -32,7 +32,7 @@ public final class PerigeeBeckoner extends CardImpl { // When this creature enters, until end of turn, another target creature you control gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control." Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0) - .setText("another target creature you control gets +2/+0")); + .setText("until end of turn, another target creature you control gets +2/+0")); ability.addEffect(new GainAbilityTargetEffect(new DiesSourceTriggeredAbility( new ReturnSourceFromGraveyardToBattlefieldEffect(true, true), false ), Duration.EndOfTurn, "and gains \"When this creature dies, " + diff --git a/Mage.Sets/src/mage/cards/p/PinnacleStarcage.java b/Mage.Sets/src/mage/cards/p/PinnacleStarcage.java index 32f9326474f..bacb40c78e9 100644 --- a/Mage.Sets/src/mage/cards/p/PinnacleStarcage.java +++ b/Mage.Sets/src/mage/cards/p/PinnacleStarcage.java @@ -104,7 +104,7 @@ class PinnacleStarcageTokenEffect extends OneShotEffect { PinnacleStarcageTokenEffect() { super(Outcome.Benefit); staticText = "put each card exiled with this artifact into its owner's graveyard, " + - "then create a 2/2 colorless Robot artifact token for each card put into a graveyard this way"; + "then create a 2/2 colorless Robot artifact creature token for each card put into a graveyard this way"; } private PinnacleStarcageTokenEffect(final PinnacleStarcageTokenEffect effect) { diff --git a/Mage.Sets/src/mage/cards/r/RigForWar.java b/Mage.Sets/src/mage/cards/r/RigForWar.java index 795b6fc653a..c5dc155fffa 100644 --- a/Mage.Sets/src/mage/cards/r/RigForWar.java +++ b/Mage.Sets/src/mage/cards/r/RigForWar.java @@ -7,7 +7,6 @@ import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -21,12 +20,12 @@ public final class RigForWar extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Target creature gets +3/+0 and gains first strike and reach until end of turn. - getSpellAbility().addEffect(new BoostTargetEffect(3, 0, Duration.EndOfTurn) + getSpellAbility().addEffect(new BoostTargetEffect(3, 0) .setText("target creature gets +3/+0")); - getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn) + getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()) .setText("and gains first strike")); - getSpellAbility().addEffect(new GainAbilityTargetEffect(ReachAbility.getInstance(), Duration.EndOfTurn) - .setText("and first reach until end of turn")); + getSpellAbility().addEffect(new GainAbilityTargetEffect(ReachAbility.getInstance()) + .setText("and reach until end of turn")); getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SelfcraftMechan.java b/Mage.Sets/src/mage/cards/s/SelfcraftMechan.java index 57841a66bcd..192a1266ae0 100644 --- a/Mage.Sets/src/mage/cards/s/SelfcraftMechan.java +++ b/Mage.Sets/src/mage/cards/s/SelfcraftMechan.java @@ -32,7 +32,7 @@ public final class SelfcraftMechan extends CardImpl { // When this creature enters, you may sacrifice an artifact. When you do, put a +1/+1 counter on target creature and draw a card. ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - ability.addEffect(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( ability, new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN), diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 504380ebb08..2bd11e04d93 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -161,7 +161,6 @@ public class VerifyCardDataTest { // color // skipListAddName(SKIP_LIST_COLOR, set, cardName); - skipListAddName(SKIP_LIST_COLOR, "FIN", "Summon: Alexander"); // cost // skipListAddName(SKIP_LIST_COST, set, cardName); From 6d6d3565a58cb6ac68e25cbabfcc236993261af4 Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Tue, 22 Jul 2025 02:13:06 +0200 Subject: [PATCH 08/66] fix Summon: Good King Mog XII, missing predicates on filter. fixes #13872 --- Mage.Sets/src/mage/cards/s/SummonGoodKingMogXII.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Mage.Sets/src/mage/cards/s/SummonGoodKingMogXII.java b/Mage.Sets/src/mage/cards/s/SummonGoodKingMogXII.java index 55312de092b..4cc53fb1eff 100644 --- a/Mage.Sets/src/mage/cards/s/SummonGoodKingMogXII.java +++ b/Mage.Sets/src/mage/cards/s/SummonGoodKingMogXII.java @@ -17,7 +17,9 @@ import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -121,6 +123,11 @@ class SummonGoodKingMogXIIEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterControlledPermanent("non-Saga token you control"); + static { + filter.add(Predicates.not(SubType.SAGA.getPredicate())); + filter.add(TokenPredicate.TRUE); + } + SummonGoodKingMogXIIEffect() { super(Outcome.Benefit); staticText = "create a token that's a copy of a non-Saga token you control"; From b2fac7abc84b461f9c4f730b4afeea731cf0013b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 22 Jul 2025 09:31:23 -0400 Subject: [PATCH 09/66] [DSK] Implement Monstrous Emergence --- .../src/mage/cards/m/MonstrousEmergence.java | 168 ++++++++++++++++++ .../src/mage/sets/DuskmournHouseOfHorror.java | 1 + 2 files changed, 169 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MonstrousEmergence.java diff --git a/Mage.Sets/src/mage/cards/m/MonstrousEmergence.java b/Mage.Sets/src/mage/cards/m/MonstrousEmergence.java new file mode 100644 index 00000000000..0b710acd841 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MonstrousEmergence.java @@ -0,0 +1,168 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MonstrousEmergence extends CardImpl { + + public MonstrousEmergence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // As an additional cost to cast this spell, choose a creature you control or reveal a creature card from your hand. + this.getSpellAbility().addCost(new MonstrousEmergenceCost()); + + // Monstrous Emergence deals damage equal to the power of the creature you chose or the card you revealed to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(MonstrousEmergenceValue.instance) + .setText("{this} deals damage equal to the power of the creature you chose or the card you revealed to target creature")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private MonstrousEmergence(final MonstrousEmergence card) { + super(card); + } + + @Override + public MonstrousEmergence copy() { + return new MonstrousEmergence(this); + } +} + +enum MonstrousEmergenceValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional + .ofNullable((Card) effect.getValue("monstrousEmergenceCost")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + } + + @Override + public MonstrousEmergenceValue copy() { + return this; + } + + @Override + public String getMessage() { + return "power of the creature you chose or the card you revealed"; + } + + @Override + public String toString() { + return "1"; + } +} + +class MonstrousEmergenceCost extends CostImpl { + + public MonstrousEmergenceCost() { + super(); + this.text = "choose a creature you control or reveal a creature card from your hand"; + } + + private MonstrousEmergenceCost(final MonstrousEmergenceCost cost) { + super(cost); + } + + @Override + public MonstrousEmergenceCost copy() { + return new MonstrousEmergenceCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return Optional + .ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .map(Player::getHand) + .filter(hand -> hand.count(StaticFilters.FILTER_CARD_CREATURE, game) > 0) + .isPresent() + || game + .getBattlefield() + .contains(StaticFilters.FILTER_CONTROLLED_CREATURE, controllerId, source, game, 1); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Player player = game.getPlayer(controllerId); + if (player == null) { + paid = false; + return paid; + } + boolean hasPermanent = game + .getBattlefield() + .contains(StaticFilters.FILTER_CONTROLLED_CREATURE, controllerId, source, game, 1); + boolean hasHand = player.getHand().count(StaticFilters.FILTER_CARD_CREATURE, game) > 0; + boolean usePermanent; + if (hasPermanent && hasHand) { + usePermanent = player.chooseUse( + Outcome.Neutral, "Choose a creature you control or reveal a creature card from your hand?", + null, "Choose controlled", "Reveal from hand", source, game + ); + } else if (hasPermanent) { + usePermanent = true; + } else if (hasHand) { + usePermanent = false; + } else { + paid = false; + return paid; + } + if (usePermanent) { + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.withNotTarget(true); + player.choose(Outcome.Neutral, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + paid = false; + return paid; + } + game.informPlayers(player.getLogName() + " chooses " + permanent.getLogName() + " on the battlefield"); + source.getEffects().setValue("monstrousEmergenceCost", permanent); + paid = true; + return true; + } + TargetCard target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); + player.choose(Outcome.Neutral, player.getHand(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + paid = false; + return paid; + } + player.revealCards(source, new CardsImpl(card), game); + game.informPlayers(player.getLogName() + " reveals " + card.getLogName() + " from their hand"); + source.getEffects().setValue("monstrousEmergenceCost", card); + paid = true; + return paid; + } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 481c8062516..019c578519d 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -216,6 +216,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Meathook Massacre II", 311, Rarity.MYTHIC, mage.cards.m.MeathookMassacreII.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Miasma Demon", 109, Rarity.UNCOMMON, mage.cards.m.MiasmaDemon.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); + cards.add(new SetCardInfo("Monstrous Emergence", 191, Rarity.COMMON, mage.cards.m.MonstrousEmergence.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("Mountain", 283, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); From 8aafba38b9675f60857d065a0a6f7a8a13ac05cb Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:08:29 +0100 Subject: [PATCH 10/66] Add hint to Ragost, Deft Gastronaut --- Mage.Sets/src/mage/cards/r/RagostDeftGastronaut.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/r/RagostDeftGastronaut.java b/Mage.Sets/src/mage/cards/r/RagostDeftGastronaut.java index 74997b24a41..bfd78c1a564 100644 --- a/Mage.Sets/src/mage/cards/r/RagostDeftGastronaut.java +++ b/Mage.Sets/src/mage/cards/r/RagostDeftGastronaut.java @@ -13,6 +13,7 @@ import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.effects.common.continuous.AddCardSubtypeAllEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.hint.ConditionHint; import mage.abilities.token.FoodAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; @@ -59,7 +60,7 @@ public final class RagostDeftGastronaut extends CardImpl { // At the beginning of each end step, if you gained life this turn, untap Ragost. this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.ANY, new UntapSourceEffect(), false, condition - )); + ).addHint(new ConditionHint(condition))); } private RagostDeftGastronaut(final RagostDeftGastronaut card) { From cdf23ac18a3af09c6e3f5436684488341e39df4c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 22 Jul 2025 16:32:41 -0400 Subject: [PATCH 11/66] rework warp implementation (#13874) --- Mage.Sets/src/mage/cards/f/FullBore.java | 8 +-- .../mage/abilities/keyword/WarpAbility.java | 69 +++++++++++++++---- Mage/src/main/java/mage/game/stack/Spell.java | 2 - 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/Mage.Sets/src/mage/cards/f/FullBore.java b/Mage.Sets/src/mage/cards/f/FullBore.java index 77b88483b32..d29a26cfc1d 100644 --- a/Mage.Sets/src/mage/cards/f/FullBore.java +++ b/Mage.Sets/src/mage/cards/f/FullBore.java @@ -1,6 +1,5 @@ package mage.cards.f; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -17,7 +16,6 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import java.util.Collections; import java.util.UUID; /** @@ -63,11 +61,7 @@ class FullBoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null - || !game - .getPermanentCostsTags() - .getOrDefault(new MageObjectReference(permanent, game, -1), Collections.emptyMap()) - .containsKey(WarpAbility.WARP_ACTIVATION_VALUE_KEY)) { + if (permanent == null || !WarpAbility.checkIfPermanentWarped(permanent, game)) { return false; } game.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()) diff --git a/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java index f3de58b05e7..10b18f10d98 100644 --- a/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/WarpAbility.java @@ -1,6 +1,7 @@ package mage.abilities.keyword; import mage.MageIdentifier; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -10,14 +11,33 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.*; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import mage.watchers.Watcher; +import java.util.Collections; import java.util.Set; import java.util.UUID; /** + * 702.185. Warp + *

+ * 702.185a Warp represents two static abilities that function while the card with warp is on the stack, + * one of which may create a delayed triggered ability. “Warp [cost]” means + * “You may cast this card from your hand by paying [cost] rather than its mana cost” and + * “If this spell’s warp cost was paid, exile the permanent this spell becomes at the beginning of the next end step. + * Its owner may cast this card after the current turn has ended for as long as it remains exiled.” + * Casting a spell for its warp cost follows the rules for paying alternative costs in rules 601.2b and 601.2f–h. + *

+ * 702.185b Some effects refer to “warped” cards in exile. A warped card in exile is one + * that was exiled by the delayed triggered ability created by a warp ability. + *

+ * 702.185c Some effects refer to whether “a spell was warped this turn.” + * This means that a spell was cast for its warp cost this turn. + * * @author TheElk801 */ public class WarpAbility extends SpellAbility { @@ -41,6 +61,7 @@ public class WarpAbility extends SpellAbility { this.addCost(new ManaCostsImpl<>(manaString)); this.setAdditionalCostsRuleVisible(false); this.allowGraveyard = allowGraveyard; + this.addWatcher(new WarpAbilityWatcher()); } private WarpAbility(final WarpAbility ability) { @@ -48,15 +69,6 @@ public class WarpAbility extends SpellAbility { this.allowGraveyard = ability.allowGraveyard; } - // The ability sets up a delayed trigger which can't be set up using the cost tag system - public static void addDelayedTrigger(SpellAbility spellAbility, Game game) { - if (spellAbility instanceof WarpAbility) { - game.addDelayedTriggeredAbility( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new WarpExileEffect()), spellAbility - ); - } - } - @Override public ActivationStatus canActivate(UUID playerId, Game game) { switch (game.getState().getZone(getSourceId())) { @@ -104,6 +116,13 @@ public class WarpAbility extends SpellAbility { public static String makeWarpString(UUID playerId) { return playerId + "- Warped"; } + + public static boolean checkIfPermanentWarped(Permanent permanent, Game game) { + return permanent != null + && game.getPermanentCostsTags() + .getOrDefault(new MageObjectReference(permanent, game, -1), Collections.emptyMap()) + .containsKey(WarpAbility.WARP_ACTIVATION_VALUE_KEY); + } } class WarpExileEffect extends OneShotEffect { @@ -122,8 +141,9 @@ class WarpExileEffect extends OneShotEffect { } } - WarpExileEffect() { + WarpExileEffect(Permanent permanent, Game game) { super(Outcome.Benefit); + this.setTargetPointer(new FixedTarget(permanent, game)); staticText = "exile this creature if it was cast for its warp cost"; } @@ -138,9 +158,12 @@ class WarpExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null || permanent.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter() + 1) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getOwnerId()); + if (player == null) { return false; } player.moveCardsToExile( @@ -155,3 +178,23 @@ class WarpExileEffect extends OneShotEffect { return true; } } + +class WarpAbilityWatcher extends Watcher { + + WarpAbilityWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + if (WarpAbility.checkIfPermanentWarped(permanent, game)) { + game.addDelayedTriggeredAbility( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new WarpExileEffect(permanent, game)), permanent.getSpellAbility() + ); + } + } +} diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 70e66ba58ce..7cc905df6b6 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -8,7 +8,6 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.PrototypeAbility; import mage.abilities.keyword.TransformAbility; -import mage.abilities.keyword.WarpAbility; import mage.cards.*; import mage.constants.*; import mage.counters.Counter; @@ -422,7 +421,6 @@ public class Spell extends StackObjectImpl implements Card { } else { MageObjectReference mor = new MageObjectReference(getSpellAbility()); game.storePermanentCostsTags(mor, getSpellAbility()); - WarpAbility.addDelayedTrigger(getSpellAbility(), game); return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } } From 76e1b60c3238c72a32365cb536a27f414aa910a9 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 23 Jul 2025 10:55:32 -0400 Subject: [PATCH 12/66] add otherwise effect to LookLibraryAndPickControllerEffect --- .../src/mage/cards/a/AdventureAwaits.java | 40 ++--------- .../src/mage/cards/b/BlossomPrancer.java | 58 ++++------------ .../src/mage/cards/c/ContagiousVorrac.java | 56 ++-------------- .../src/mage/cards/p/PulsarSquadronAce.java | 66 +++---------------- Mage.Sets/src/mage/cards/r/RosecotKnight.java | 57 ++++------------ .../LookLibraryAndPickControllerEffect.java | 25 +++++++ 6 files changed, 71 insertions(+), 231 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AdventureAwaits.java b/Mage.Sets/src/mage/cards/a/AdventureAwaits.java index 5c5d027b531..94725b74ece 100644 --- a/Mage.Sets/src/mage/cards/a/AdventureAwaits.java +++ b/Mage.Sets/src/mage/cards/a/AdventureAwaits.java @@ -1,16 +1,12 @@ package mage.cards.a; -import mage.abilities.Ability; -import mage.abilities.Mode; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.cards.Cards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.PutCards; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -24,7 +20,9 @@ public final class AdventureAwaits extends CardImpl { // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. If you don't put a card into your hand this way, draw a card. - this.getSpellAbility().addEffect(new AdventureAwaitsEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).withOtherwiseEffect(new DrawCardSourceControllerEffect(1))); } private AdventureAwaits(final AdventureAwaits card) { @@ -36,33 +34,3 @@ public final class AdventureAwaits extends CardImpl { return new AdventureAwaits(this); } } - -class AdventureAwaitsEffect extends LookLibraryAndPickControllerEffect { - - AdventureAwaitsEffect() { - super(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM); - } - - private AdventureAwaitsEffect(final AdventureAwaitsEffect effect) { - super(effect); - } - - @Override - public AdventureAwaitsEffect copy() { - return new AdventureAwaitsEffect(this); - } - - @Override - public boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { - super.actionWithPickedCards(game, source, player, pickedCards, otherCards); - if (pickedCards.isEmpty()) { - player.drawCards(1, source, game); - } - return true; - } - - @Override - public String getText(Mode mode) { - return super.getText(mode).concat(". If you didn't put a card into your hand this way, draw a card"); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlossomPrancer.java b/Mage.Sets/src/mage/cards/b/BlossomPrancer.java index 37bc85c8de6..5013690e4ac 100644 --- a/Mage.Sets/src/mage/cards/b/BlossomPrancer.java +++ b/Mage.Sets/src/mage/cards/b/BlossomPrancer.java @@ -1,12 +1,10 @@ package mage.cards.b; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.ReachAbility; -import mage.cards.Cards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,8 +12,6 @@ import mage.constants.PutCards; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -24,6 +20,15 @@ import java.util.UUID; */ public final class BlossomPrancer extends CardImpl { + private static final FilterCard filter = new FilterCard("creature or enchantment card"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + } + public BlossomPrancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); @@ -38,7 +43,9 @@ public final class BlossomPrancer extends CardImpl { // You may reveal a creature or enchantment card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. // If you didn't put a card into your hand this way, you gain 4 life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new BlossomPrancerEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).withOtherwiseEffect(new GainLifeEffect(4)))); } private BlossomPrancer(final BlossomPrancer card) { @@ -50,42 +57,3 @@ public final class BlossomPrancer extends CardImpl { return new BlossomPrancer(this); } } - -class BlossomPrancerEffect extends LookLibraryAndPickControllerEffect { - - private static final FilterCard filter = new FilterCard("creature or enchantment card"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - - BlossomPrancerEffect() { - super(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM); - } - - private BlossomPrancerEffect(final BlossomPrancerEffect effect) { - super(effect); - } - - @Override - public BlossomPrancerEffect copy() { - return new BlossomPrancerEffect(this); - } - - @Override - public boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { - super.actionWithPickedCards(game, source, player, pickedCards, otherCards); - if (pickedCards.isEmpty()) { - player.gainLife(4, game, source); - } - return true; - } - - @Override - public String getText(Mode mode) { - return super.getText(mode).concat(". If you didn't put a card into your hand this way, you gain 4 life"); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ContagiousVorrac.java b/Mage.Sets/src/mage/cards/c/ContagiousVorrac.java index 26afb610699..899e828bb5d 100644 --- a/Mage.Sets/src/mage/cards/c/ContagiousVorrac.java +++ b/Mage.Sets/src/mage/cards/c/ContagiousVorrac.java @@ -1,20 +1,15 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.counter.ProliferateEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.PutCards; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -33,7 +28,9 @@ public final class ContagiousVorrac extends CardImpl { this.toughness = new MageInt(3); // When Contagious Vorrac enters the battlefield, look at the top four cards of your library. You may reveal a land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. If you didn't put a card into your hand this way, proliferate. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ContagiousVorracEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).withOtherwiseEffect(new ProliferateEffect()))); } private ContagiousVorrac(final ContagiousVorrac card) { @@ -45,42 +42,3 @@ public final class ContagiousVorrac extends CardImpl { return new ContagiousVorrac(this); } } - -class ContagiousVorracEffect extends OneShotEffect { - - ContagiousVorracEffect() { - super(Outcome.Benefit); - staticText = "look at the top four cards of your library. You may reveal a land card from among them " + - "and put it into your hand. Put the rest on the bottom of your library in a random order. " + - "If you didn't put a card into your hand this way, proliferate. " + - "(Choose any number of permanents and/or players, then give each another counter of each kind already there.)"; - } - - private ContagiousVorracEffect(final ContagiousVorracEffect effect) { - super(effect); - } - - @Override - public ContagiousVorracEffect copy() { - return new ContagiousVorracEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 4)); - TargetCard target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_LAND); - player.choose(Outcome.DrawCard, cards, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - player.revealCards(source, new CardsImpl(card), game); - player.moveCards(card, Zone.HAND, source, game); - } - cards.retainZone(Zone.LIBRARY, game); - player.putCardsOnBottomOfLibrary(cards, game, source, false); - return card != null || new ProliferateEffect().apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PulsarSquadronAce.java b/Mage.Sets/src/mage/cards/p/PulsarSquadronAce.java index 6c282803f31..8ef4d238bb9 100644 --- a/Mage.Sets/src/mage/cards/p/PulsarSquadronAce.java +++ b/Mage.Sets/src/mage/cards/p/PulsarSquadronAce.java @@ -1,23 +1,18 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.PutCards; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterBySubtypeCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; -import java.util.Optional; import java.util.UUID; /** @@ -25,6 +20,8 @@ import java.util.UUID; */ public final class PulsarSquadronAce extends CardImpl { + private static final FilterCard filter = new FilterBySubtypeCard(SubType.SPACECRAFT); + public PulsarSquadronAce(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -34,7 +31,9 @@ public final class PulsarSquadronAce extends CardImpl { this.toughness = new MageInt(2); // When this creature enters, look at the top five cards of your library. You may reveal a Spacecraft card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. If you didn't put a card into your hand this way, put a +1/+1 counter on this creature. - this.addAbility(new EntersBattlefieldTriggeredAbility(new PulsarSquadronAceEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).withOtherwiseEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())))); } private PulsarSquadronAce(final PulsarSquadronAce card) { @@ -46,48 +45,3 @@ public final class PulsarSquadronAce extends CardImpl { return new PulsarSquadronAce(this); } } - -class PulsarSquadronAceEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterBySubtypeCard(SubType.SPACECRAFT); - - PulsarSquadronAceEffect() { - super(Outcome.Benefit); - staticText = "look at the top five cards of your library. You may reveal a Spacecraft card from among them " + - "and put it into your hand. Put the rest on the bottom of your library in a random order. " + - "If you didn't put a card into your hand this way, put a +1/+1 counter on {this}"; - } - - private PulsarSquadronAceEffect(final PulsarSquadronAceEffect effect) { - super(effect); - } - - @Override - public PulsarSquadronAceEffect copy() { - return new PulsarSquadronAceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5)); - TargetCard target = new TargetCardInLibrary(0, 1, filter); - player.choose(outcome, cards, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - player.putCardsOnBottomOfLibrary(cards, game, source, false); - Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) - .filter(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)) - .isPresent(); - return true; - } - player.revealCards(source, new CardsImpl(card), game); - player.moveCards(card, Zone.HAND, source, game); - cards.retainZone(Zone.LIBRARY, game); - player.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RosecotKnight.java b/Mage.Sets/src/mage/cards/r/RosecotKnight.java index 1e6608f34c2..7f0bc70da7d 100644 --- a/Mage.Sets/src/mage/cards/r/RosecotKnight.java +++ b/Mage.Sets/src/mage/cards/r/RosecotKnight.java @@ -1,24 +1,18 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -27,6 +21,15 @@ import java.util.UUID; */ public final class RosecotKnight extends CardImpl { + private static final FilterCard filter = new FilterCard("artifact or enchantment card"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + } + public RosecotKnight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); @@ -39,7 +42,9 @@ public final class RosecotKnight extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // When Rosecot Knight enters the battlefield, look at the top six cards of your library. You may reveal an artifact or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. If you didn't put a card into your hand this way, put a +1/+1 counter on Rosecot Knight. - this.addAbility(new EntersBattlefieldTriggeredAbility(new RosecotKnightEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 6, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).withOtherwiseEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())))); } private RosecotKnight(final RosecotKnight card) { @@ -51,41 +56,3 @@ public final class RosecotKnight extends CardImpl { return new RosecotKnight(this); } } - -class RosecotKnightEffect extends LookLibraryAndPickControllerEffect { - - private static final FilterCard filter = new FilterCard("artifact or enchantment card"); - - static { - filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - } - - RosecotKnightEffect() { - super(6, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM); - } - - private RosecotKnightEffect(final RosecotKnightEffect effect) { - super(effect); - } - - @Override - public RosecotKnightEffect copy() { - return new RosecotKnightEffect(this); - } - - @Override - protected boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { - super.actionWithPickedCards(game, source, player, pickedCards, otherCards); - game.processAction(); - pickedCards.retainZone(Zone.HAND, game); - if (pickedCards.isEmpty()) { - new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); - } - return true; - } - - @Override - public String getText(Mode mode) { - return super.getText(mode).concat(". If you didn't put a card into your hand this way, put a +1/+1 counter on {this}"); - } -} diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index 332ff288d9c..742fe427431 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -4,6 +4,9 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.PutCards; @@ -26,6 +29,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff protected boolean revealPickedCards; protected boolean optional; protected boolean upTo; + protected Effect otherwiseEffect = null; public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, PutCards putPickedCards, PutCards putLookedCards) { @@ -87,6 +91,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff this.revealPickedCards = effect.revealPickedCards; this.optional = effect.optional; this.upTo = effect.upTo; + this.otherwiseEffect = effect.otherwiseEffect != null ? effect.otherwiseEffect.copy() : null; } @Override @@ -94,6 +99,11 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff return new LookLibraryAndPickControllerEffect(this); } + public LookLibraryAndPickControllerEffect withOtherwiseEffect(Effect otherwiseEffect) { + this.otherwiseEffect = otherwiseEffect; + return this; + } + @Override protected boolean actionWithLookedCards(Game game, Ability source, Player player, Cards cards) { int number = Math.min(numberToPick, cards.count(filter, source.getControllerId(), source, game)); @@ -120,6 +130,15 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff protected boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { boolean result = putPickedCards.moveCards(player, pickedCards, source, game); result |= putLookedCards.moveCards(player, otherCards, source, game); + if (!pickedCards.isEmpty() || otherwiseEffect == null) { + return result; + } + game.processAction(); + if (otherwiseEffect instanceof OneShotEffect) { + otherwiseEffect.apply(game, source); + } else if (otherwiseEffect instanceof ContinuousEffect) { + game.addEffect((ContinuousEffect) otherwiseEffect, source); + } return result; } @@ -196,6 +215,12 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff sb.append("back "); } sb.append(putLookedCards.getMessage(false, plural)); + if (otherwiseEffect != null) { + sb.append(". If you didn't put a card "); + sb.append(putPickedCards.getMessage(false, false)); + sb.append(" this way, "); + sb.append(otherwiseEffect.getText(mode)); + } // get text frame from super class and inject action text return setText(mode, sb.toString()); From 3a92da6f675de61c3f4556287f8a429dd7d41a82 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 23 Jul 2025 14:42:06 -0400 Subject: [PATCH 13/66] update duel commander ban list --- .../src/mage/deck/DuelCommander.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java index e2255b9cef6..697de25bcef 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java @@ -10,6 +10,7 @@ public class DuelCommander extends Commander { banned.add("Ancestral Recall"); banned.add("Ancient Tomb"); banned.add("Back to Basics"); + banned.add("Balance"); banned.add("Bazaar of Baghdad"); banned.add("Black Lotus"); banned.add("Capture of Jingzhou"); @@ -32,9 +33,9 @@ public class DuelCommander extends Commander { banned.add("Gifts Ungiven"); banned.add("Grim Monolith"); banned.add("Hermit Druid"); - banned.add("Hogaak, Arisen Necropolis"); banned.add("Humility"); banned.add("Imperial Seal"); + banned.add("Invert Polarity"); banned.add("Jeweled Lotus"); banned.add("Karakas"); banned.add("Library of Alexandria"); @@ -63,6 +64,7 @@ public class DuelCommander extends Commander { banned.add("Protean Hulk"); banned.add("Ragavan, Nimble Pilferer"); banned.add("Rain of Filth"); + banned.add("Reanimate"); banned.add("Scapeshift"); banned.add("Sensei's Divining Top"); banned.add("Serra's Sanctum"); @@ -78,13 +80,14 @@ public class DuelCommander extends Commander { banned.add("Time Warp"); banned.add("Tinker"); banned.add("Tolarian Academy"); + banned.add("Trazyn The Infinite"); banned.add("Treasure Cruise"); banned.add("Uro, Titan of Nature's Wrath"); banned.add("Vampiric Tutor"); banned.add("Wasteland"); + banned.add("White Plume Adventurer"); bannedCommander.add("Ajani, Nacatl Pariah"); - bannedCommander.add("Akiri, Line-Slinger"); bannedCommander.add("Arahbo, Roar of the World"); bannedCommander.add("Asmoranomardicadaistinaculdacar"); bannedCommander.add("Baral, Chief of Compliance"); @@ -96,14 +99,16 @@ public class DuelCommander extends Commander { bannedCommander.add("Emry, Lurker of the Loch"); bannedCommander.add("Eris, Roar of the Storm"); bannedCommander.add("Esior, Wardwing Familiar"); + bannedCommander.add("Ezio Auditore da Firenze"); bannedCommander.add("Geist of Saint Traft"); bannedCommander.add("Inalla, Archmage Ritualist"); + bannedCommander.add("Hogaak, Arisen Necropolis"); bannedCommander.add("Krark, the Thumbless"); bannedCommander.add("Minsc & Boo, Timeless Heroes"); bannedCommander.add("Nadu, Winged Wisdom"); bannedCommander.add("Najeela, the Blade-Blossom"); - bannedCommander.add("Oloro, Ageless Ascetic"); bannedCommander.add("Old Stickfingers"); + bannedCommander.add("Oloro, Ageless Ascetic"); bannedCommander.add("Omnath, Locus of Creation"); bannedCommander.add("Prime Speaker Vannifar"); bannedCommander.add("Raffine, Scheming Seer"); @@ -115,6 +120,5 @@ public class DuelCommander extends Commander { bannedCommander.add("Vial Smasher the Fierce"); bannedCommander.add("Winota, Joiner of Forces"); bannedCommander.add("Yuriko, the Tiger's Shadow"); - bannedCommander.add("Zurgo Bellstriker"); } } From a0c58c829ad032f6b51dced0f0d850255219699b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 23 Jul 2025 16:33:20 -0400 Subject: [PATCH 14/66] [SPM] add set --- .../dl/sources/ScryfallImageSupportCards.java | 1 + Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 22 +++++++++++++++++++ Utils/known-sets.txt | 1 + Utils/mtg-cards-data.txt | 1 + Utils/mtg-sets-data.txt | 1 + 5 files changed, 26 insertions(+) create mode 100644 Mage.Sets/src/mage/sets/MarvelsSpiderMan.java diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index b132bfb77e2..29b20a0d26b 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -591,6 +591,7 @@ public class ScryfallImageSupportCards { add("EOE"); // Edge of Eternities add("EOC"); // Edge of Eternities Commander add("EOS"); // Edge of Eternities: Stellar Sights + add("SPM"); // Marvel's Spider-Man add("SPE"); // Marvel's Spider-Man Eternal add("TLA"); // Avatar: The Last Airbender diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java new file mode 100644 index 00000000000..1b84edfe82a --- /dev/null +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -0,0 +1,22 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class MarvelsSpiderMan extends ExpansionSet { + + private static final MarvelsSpiderMan instance = new MarvelsSpiderMan(); + + public static MarvelsSpiderMan getInstance() { + return instance; + } + + private MarvelsSpiderMan() { + super("Marvel's Spider-Man", "SPM", ExpansionSet.buildDate(2025, 9, 26), SetType.EXPANSION); + this.blockName = "Marvel's Spider-Man"; // for sorting in GUI + this.hasBasicLands = false; // temporary + } +} diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 41e5637f9c5..a3483768fea 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -176,6 +176,7 @@ Magic Origins|MagicOrigins| Magic Player Rewards|MagicPlayerRewards| Magic: The Gathering-Commander|Commander| Magic: The Gathering-Conspiracy|Conspiracy| +Marvel's Spider-Man|MarvelsSpiderMan| Marvel's Spider-Man Eternal|MarvelsSpiderManEternal| Masterpiece Series|MasterpieceSeries| Masterpiece Series Amonkhet|MasterpieceSeriesAmonkhet| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index a8509dc657a..84b7923fac1 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -59700,3 +59700,4 @@ Viridescent Bog|Edge of Eternities Commander|190|R||Land|||{1}, {T}: Add {B}{G}. Wastes|Edge of Eternities Commander|191|C||Basic Land|||{T}: Add {C}.| Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spelsl you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| +Origin of Spider-Man|Marvel's Spider-Man|9|R|{1}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create a 2/1 green Spider creature token with reach.$II -- Put a +1/+1 counter on target creature you control. It becomes a legendary Spider Hero in addition to its other types.$III -- Target creature you control gains double strike until end of turn.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 2a0c35d220e..49164ecb554 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -176,6 +176,7 @@ Masters 25|A25| Magic: The Gathering-Commander|CMD| Magic: The Gathering-Conspiracy|CNS| Media Inserts|MBP| +Marvel's Spider-Man|SPM| Marvel's Spider-Man Eternal|SPE| March of the Machine|MOM| March of the Machine Commander|MOC| From cfb062a47d9be030680329b35e30af3ca61d1069 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 23 Jul 2025 16:40:48 -0400 Subject: [PATCH 15/66] [SPM] Implement Origin of Spider-Man --- .../src/mage/cards/o/OriginOfSpiderMan.java | 93 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 3 + .../game/permanent/token/Spider21Token.java | 31 +++++++ 3 files changed, 127 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/OriginOfSpiderMan.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/Spider21Token.java diff --git a/Mage.Sets/src/mage/cards/o/OriginOfSpiderMan.java b/Mage.Sets/src/mage/cards/o/OriginOfSpiderMan.java new file mode 100644 index 00000000000..b9a4f4785d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OriginOfSpiderMan.java @@ -0,0 +1,93 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Spider21Token; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OriginOfSpiderMan extends CardImpl { + + public OriginOfSpiderMan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Create a 2/1 green Spider creature token with reach. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new Spider21Token())); + + // II -- Put a +1/+1 counter on target creature you control. It becomes a legendary Spider Hero in addition to its other types. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, + new Effects( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new OriginOfSpiderManEffect() + ), new TargetControlledCreaturePermanent() + ); + + // III -- Target creature you control gains double strike until end of turn. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()), + new TargetControlledCreaturePermanent() + ); + this.addAbility(sagaAbility); + } + + private OriginOfSpiderMan(final OriginOfSpiderMan card) { + super(card); + } + + @Override + public OriginOfSpiderMan copy() { + return new OriginOfSpiderMan(this); + } +} + +class OriginOfSpiderManEffect extends ContinuousEffectImpl { + + OriginOfSpiderManEffect() { + super(Duration.Custom, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + staticText = "It becomes a legendary Spider Hero in addition to its other types"; + } + + private OriginOfSpiderManEffect(final OriginOfSpiderManEffect effect) { + super(effect); + } + + @Override + public OriginOfSpiderManEffect copy() { + return new OriginOfSpiderManEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return false; + } + permanent.addSuperType(game, SuperType.LEGENDARY); + permanent.addSubType(game, SubType.SPIDER); + permanent.addSubType(game, SubType.HERO); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 1b84edfe82a..437c9f640e8 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -1,6 +1,7 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.constants.Rarity; import mage.constants.SetType; /** @@ -18,5 +19,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { super("Marvel's Spider-Man", "SPM", ExpansionSet.buildDate(2025, 9, 26), SetType.EXPANSION); this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = false; // temporary + + cards.add(new SetCardInfo("Origin of Spider-Man", 9, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class)); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/Spider21Token.java b/Mage/src/main/java/mage/game/permanent/token/Spider21Token.java new file mode 100644 index 00000000000..f8a41c6de60 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Spider21Token.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.ReachAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class Spider21Token extends TokenImpl { + + public Spider21Token() { + super("Spider Token", "2/1 green Spider creature token with reach"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add(SubType.SPIDER); + power = new MageInt(2); + toughness = new MageInt(1); + + this.addAbility(ReachAbility.getInstance()); + } + + private Spider21Token(final Spider21Token token) { + super(token); + } + + public Spider21Token copy() { + return new Spider21Token(this); + } +} From df3aef978cb93535af6371ec6e1c589df5ed3de0 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:44:53 -0400 Subject: [PATCH 16/66] [SPM] update spoiler and reprints --- Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 8 ++- Utils/mtg-cards-data.txt | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 437c9f640e8..b9f394d9ffc 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -18,8 +18,14 @@ public final class MarvelsSpiderMan extends ExpansionSet { private MarvelsSpiderMan() { super("Marvel's Spider-Man", "SPM", ExpansionSet.buildDate(2025, 9, 26), SetType.EXPANSION); this.blockName = "Marvel's Spider-Man"; // for sorting in GUI - this.hasBasicLands = false; // temporary + this.hasBasicLands = true; + cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + 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)); + cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 84b7923fac1..56e4c65d676 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -59700,4 +59700,62 @@ Viridescent Bog|Edge of Eternities Commander|190|R||Land|||{1}, {T}: Add {B}{G}. Wastes|Edge of Eternities Commander|191|C||Basic Land|||{T}: Add {C}.| Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spelsl you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| +Aunt May|Marvel's Spider-Man|3|U|{W}|Legendary Creature - Human Citizen|0|2|Whenever another creature you control enters, you gain 1 life. If it's a Spider, put a +1/+1 counter on it.| +Daily Bugle Reporters|Marvel's Spider-Man|6|C|{3}{W}|Creature - Human Citizen|2|3|When this creature enters, choose one --$* Puff Piece -- Put a +1/+1 counter on each of up to two target creatures.$* Investigative Journalism -- Return target creature card with mana value 2 or less from your graveyard to your hand.| Origin of Spider-Man|Marvel's Spider-Man|9|R|{1}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create a 2/1 green Spider creature token with reach.$II -- Put a +1/+1 counter on target creature you control. It becomes a legendary Spider Hero in addition to its other types.$III -- Target creature you control gains double strike until end of turn.| +Peter Parker|Marvel's Spider-Man|10|M|{1}{W}|Legendary Creature - Human Scientist Hero|0|1|When Peter Parker enters, create a 2/1 green Spider creature token with reach.${1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery.| +Amazing Spider-Man|Marvel's Spider-Man|10|M|{1}{G}{W}{U}|Legendary Creature - Spider Human Hero|4|4|Vigilance, reach$Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}.| +Selfless Police Captain|Marvel's Spider-Man|12|C|{1}{W}|Creature - Human Detective|1|1|This creature enters with a +1/+1 counter on it.$When this creature leaves the battlefield, put its +1/+1 counters on target creature you control.| +Spectacular Tactics|Marvel's Spider-Man|15|C|{1}{W}|Instant|||Choose one --$* Put a +1/+1 counter on target creature you control. It gains hexproof until end of turn.$* Destroy target creature with power 4 or greater.| +Spider-Man, Web-Slinger|Marvel's Spider-Man|16|C|{2}{W}|Legendary Creature - Spider Human Hero|3|3|Web-slinging {W}| +Starling, Aerial Ally|Marvel's Spider-Man|18|C|{4}{W}|Legendary Creature - Human Hero|3|4|Flying$When Starling enters, another target creature you control gains flying until end of turn.| +Thwip!|Marvel's Spider-Man|20|C|{W}|Instant|||Target creature gets +2/+2 and gains flying until end of turn. If it's a Spider, you gain 2 life.| +Web Up|Marvel's Spider-Man|21|C|{2}{W}|Enchantment|||When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield.| +Wild Pack Squad|Marvel's Spider-Man|23|C|{2}{W}|Creature - Human Mercenary|2|3|At the beginning of combat on your turn, up to one target creature gains first strike and vigilance until end of turn.| +Beetle, Legacy Criminal|Marvel's Spider-Man|26|C|{3}{U}|Legendary Creature - Human Rogue Villain|3|3|Flying${1}{U}, Exile this card from your graveyard: Put a +1/+1 counter on target creature. It gains flying until end of turn. Activate only as a sorcery.| +Doc Ock, Sinister Scientist|Marvel's Spider-Man|29|C|{4}{U}|Legendary Creature - Human Scientist Villain|4|5|As long as there are eight or more cards in your graveyard, Doc Ock has base power and toughness 8/8.$As long as you control another Villain, Doc Ock has hexproof.| +Doc Ock's Henchmen|Marvel's Spider-Man|30|C|{2}{U}|Creature - Human Villain|2|1|Flash$Whenever this creature attacks, it connives.| +Flying Octobot|Marvel's Spider-Man|31|U|{1}{U}|Artifact Creature - Robot Villain|1|1|Flying$Whenever another Villain you control enters, put a +1/+1 counter on this creature. This ability triggers only once each turn.| +Oscorp Research Team|Marvel's Spider-Man|40|C|{3}{U}|Creature - Human Scientist|1|5|{6}{U}: Draw two cards.| +Spider-Byte, Web Warden|Marvel's Spider-Man|44|U|{2}{U}|Legendary Creature - Spider Avatar Hero|2|2|When Spider-Byte enters, return up to one target nonland permanent to its owner's hand.| +Unstable Experiment|Marvel's Spider-Man|47|C|{1}{U}|Instant|||Target player draws a card, then up to one target creature you control connives.| +Whoosh!|Marvel's Spider-Man|48|C|{1}{U}|Instant|||Kicker {1}{U}$Return target nonland permanent to its owner's hand. If this spell was kicked, draw a card.| +Merciless Enforcers|Marvel's Spider-Man|58|C|{1}{B}|Creature - Human Mercenary Villain|2|1|Lifelink${3}{B}: This creature deals 1 damage to each opponent.| +Risky Research|Marvel's Spider-Man|62|C|{2}{B}|Sorcery|||Surveil 2, then draw two cards. You lose 2 life.| +Scorpion, Seething Striker|Marvel's Spider-Man|64|U|{3}{B}|Legendary Creature - Scorpion Human Villain|3|3|Deathtouch$At the beginning of your end step, if a creature died this turn, target creature you control connives.| +Scorpion's Sting|Marvel's Spider-Man|65|C|{1}{B}|Instant|||Target creature gets -3/-3 until end of turn.| +Spider-Man Noir|Marvel's Spider-Man|67|U|{4}{B}|Legendary Creature - Spider Human Hero|4|4|Menace$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.| +Tombstone, Career Criminal|Marvel's Spider-Man|70|U|{2}{B}|Legendary Creature - Human Villain|2|2|When Tombstone enters, return target Villain card from your graveyard to your hand.$Villain spells you cast cost {1} less to cast.| +Venom, Evil Unleashed|Marvel's Spider-Man|71|C|{4}{B}|Legendary Creature - Symbiote Villain|4|5|Deathtouch${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.| +Venom's Hunger|Marvel's Spider-Man|73|C|{4}{B}|Sorcery|||This spell costs {2} less to cast if you control a Villain.$Destroy target creature. You gain 2 life.| +Angry Rabble|Marvel's Spider-Man|75|C|{1}{R}|Creature - Human Citizen|2|2|Trample$Whenever you cast a spell with mana value 4 or greater, this creature deals 1 damage to each opponent.${5}{R}: Put two +1/+1 counters on this creature. Activate only as a sorcery.| +Electro's Bolt|Marvel's Spider-Man|77|C|{2}{R}|Sorcery|||Electro's Bolt deals 4 damage to target creature.$Mayhem {1}{R}| +Masked Meower|Marvel's Spider-Man|82|C|{R}|Creature - Spider Cat Hero|1|1|Haste$Discard a card, Sacrifice this creature: Draw a card.| +Romantic Rendezvous|Marvel's Spider-Man|86|C|{1}{R}|Sorcery|||Discard a card, then draw two cards.| +Shock|Marvel's Spider-Man|88|C|{R}|Instant|||Shock deals 2 damage to any target.| +Shocker, Unshakable|Marvel's Spider-Man|89|U|{4}{R}{R}|Legendary Creature - Human Rogue Villain|5|5|During your turn, Shocker has first strike.$Vibro-Shock Gauntlets -- When Shocker enters, he deals 2 damage to target creature and 2 damage to that creature's controller.| +Spider-Gwen, Free Spirit|Marvel's Spider-Man|90|C|{2}{R}|Legendary Creature - Spider Human Hero|2|3|Reach$Whenever Spider-Gwen becomes tapped, you may discard a card. If you do, draw a card.| +Spider-Islanders|Marvel's Spider-Man|91|C|{3}{R}|Creature - Spider Horror Citizen|4|3|Mayhem {1}{R}| +Stegron the Dinosaur Man|Marvel's Spider-Man|95|C|{4}{R}|Legendary Creature - Dinosaur Villain|5|4|Menace$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.| +Taxi Driver|Marvel's Spider-Man|97|C|{1}{R}|Creature - Human Pilot|3|1|{1}, {T}: Target creature gains haste until end of turn.| +Grow Extra Arms|Marvel's Spider-Man|101|C|{1}{G}|Instant|||This spell costs {1} less to cast if it targets a Spider.$Target creature gets +4/+4 until end of turn.| +Guy in the Chair|Marvel's Spider-Man|102|C|{2}{G}|Creature - Human Advisor|2|3|{T}: Add one mana of any color.$Web Support -- {2}{G}, {T}: Put a +1/+1 counter on target Spider. Activate only as a sorcery.| +Kapow!|Marvel's Spider-Man|103|C|{2}{G}|Sorcery|||Put a +1/+1 counter on target creature you control. It fights target creature an opponent controls.| +Kraven's Cats|Marvel's Spider-Man|104|C|{1}{G}|Creature - Cat Villain|2|2|{2}{G}: This creature gets +2/+2 until end of turn. Activate only once each turn.| +Lurking Lizards|Marvel's Spider-Man|107|C|{1}{G}|Creature - Lizard Villain|1|3|Trample$Whenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on this creature.| +Scout the City|Marvel's Spider-Man|113|C|{1}{G}|Sorcery|||Choose one --$* Look Around -- Mill three cards. You may put a permanent card from among them into your hand. You gain 3 life.$* Bring Down -- Destroy target creature with flying.| +Spider-Ham, Peter Porker|Marvel's Spider-Man|114|R|{1}{G}|Legendary Creature - Spider Boar Hero|2|2|When Spider-Ham enters, create a Food token.$Animal May-Ham -- Other Spiders, Boars, Bats, Bears, Birds, Cats, Dogs, Frogs, Jackals, Lizards, Mice, Otters, Rabbits, Raccoons, Rats, Squirrels, Turtles, and Wolves you control get +1/+1.| +Spider-Man, Brooklyn Visionary|Marvel's Spider-Man|115|C|{4}{G}|Legendary Creature - Spider Human Hero|4|3|Web-slinging {2}{G}$When Spider-Man enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| +Spider-Rex, Daring Dino|Marvel's Spider-Man|116|C|{4}{G}{G}|Legendary Creature - Spider Dinosaur Hero|6|6|Reach, trample$Ward {2}| +SP//dr, Piloted by Peni|Marvel's Spider-Man|147|U|{3}{W}{U}|Legendary Artifact Creature - Spider Hero|4|4|Vigilance$When SP//dr enters, put a +1/+1 counter on target creature.$Whenever a modified creature you control deals combat damage to a player, draw a card.| +Spider-Man 2099|Marvel's Spider-Man|150|R|{U}{R}|Legendary Creature - Spider Human Hero|2|3|From the Future -- You can't cast Spider-Man 2099 during your first, second, or third turns of the game.$Double strike, vigilance$At the beginning of your end step, if you've played a land or cast a spell this turn from anywhere other than your hand, Spider-Man 2099 deals damage equal to his power to any target.| +Eerie Gravestone|Marvel's Spider-Man|163|C|{2}|Artifact|||When this artifact enters, draw a card.${1}{B}, Sacrifice this artifact: Mill four cards. You may put a creature card from among them into your hand.| +Mechanical Mobster|Marvel's Spider-Man|168|C|{3}|Artifact Creature - Human Robot Villain|2|1|When this creature enters, exile up to one target card from a graveyard. Target creature you control connives.| +Spider-Bot|Marvel's Spider-Man|173|C|{2}|Artifact Creature - Spider Robot Scout|2|1|Reach$When this creature enters, you may search your library for a basic land card, reveal it, then shuffle and put that card on top.| +Plains|Marvel's Spider-Man|194|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Marvel's Spider-Man|195|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Marvel's Spider-Man|196|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Marvel's Spider-Man|197|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Marvel's Spider-Man|198|C||Basic Land - Forest|||({T}: Add {G}.)| +Peter Parker|Marvel's Spider-Man|232|M|{1}{W}|Legendary Creature - Human Scientist Hero|0|1|When Peter Parker enters, create a 2/1 green Spider creature token with reach.${1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery.| +Amazing Spider-Man|Marvel's Spider-Man|232|M|{1}{G}{W}{U}|Legendary Creature - Spider Human Hero|4|4|Vigilance, reach$Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}.| From fd8313bb0aa940f6a229133c61a174a7252dc57d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:45:09 -0400 Subject: [PATCH 17/66] [SPE] update spoiler --- Utils/mtg-cards-data.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 56e4c65d676..473eac70a0e 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -59102,6 +59102,26 @@ Vault of the Archangel|Tarkir: Dragonstorm Commander|410|R||Land|||{T}: Add {C}. Windbrisk Heights|Tarkir: Dragonstorm Commander|411|R||Land|||Hideaway 4$This land enters tapped.${T}: Add {W}.${W}, {T}: You may play the exiled card without paying its mana cost if you attacked with three or more creatures this turn.| Woodland Cemetery|Tarkir: Dragonstorm Commander|412|R||Land|||This land enters tapped unless you control a Swamp or a Forest.${T}: Add {B} or {G}.| Yavimaya Coast|Tarkir: Dragonstorm Commander|413|R||Land|||{T}: Add {C}.${T}: Add {G} or {U}. This land deals 1 damage to you.| +Amateur Hero|Marvel's Spider-Man Eternal|1|C|{2}{W}|Creature - Human Hero|3|3|When this creature enters, you gain 2 life.| +Amazing Alliance|Marvel's Spider-Man Eternal|2|R|{1}{W}{W}|Enchantment|||Creatures you control get +1/+1.$Whenever you attack with one or more legendary creatures, you gain that much life.| +MJ, Rising Star|Marvel's Spider-Man Eternal|3|U|{2}{W}|Legendary Creature - Human Performer|2|3|Vigilance$Whenever you gain life, put a +1/+1 counter on MJ.| +Spider-Man, Peter Parker|Marvel's Spider-Man Eternal|4|M|{3}{W}{W}|Legendary Creature - Spider Human Hero|4|4|Flying$Whenever you gain life, put a +1/+1 counter on target creature you control. It gains indestructible until end of turn.| +Alchemax Slayer-Bots|Marvel's Spider-Man Eternal|5|C|{2}{U}|Artifact Creature - Robot Villain|2|2|When this creature enters, tap target creature an opponent controls and put a stun counter on it.| +Future Flight|Marvel's Spider-Man Eternal|6|R|{2}{U}{U}|Enchantment - Aura|||Enchant creature$When this Aura enters, draw two cards.$Enchanted creature gets +2/+0 and has flying.| +Lyla, Holographic Assistant|Marvel's Spider-Man Eternal|7|U|{3}{U}|Legenday Artifact Creature - Illusion Advisor|2|2|Whenever you draw a card, put a +1/+1 counter on target creature.| +Spider-Man 2099, Miguel O'Hara|Marvel's Spider-Man Eternal|8|M|{4}{U}|Legendary Creature - Spider Human Hero|4|4|When Spider-Man 2099 enters, return up to one target creature to its owner's hand.$Whenever one or more creatures you control deal combat damage to a player, draw a card.| +Grendel, Spawn of Knull|Marvel's Spider-Man Eternal|9|U|{3}{B}|Legendary Creature - Symbiote Dragon Villain|3|3|Flying$Deathtouch| +Lethal Protection|Marvel's Spider-Man Eternal|10|R|{3}{B}|Sorcery|||Destroy target creature. Return up to one target creature card from your graveyard to your hand.| +Symbiote Spawn|Marvel's Spider-Man Eternal|11|C|{2}{B}|Creature - Symbiote Villain|3|2|When this creature dies, each opponent loses 2 life and you gain 2 life.| +Venom, Eddie Brock|Marvel's Spider-Man Eternal|12|M|{4}{B}{B}|Legendary Creature - Symbiote Villain|6|4|Menace$Whenever another creature dies, put a +1/+1 counter on Venom. If that creature was a Villain, draw a card.| +Double Trouble|Marvel's Spider-Man Eternal|13|R|{4}{R}|Instant|||Double the power of each creature you control until end of turn.| +Ghost-Spider, Gwen Stacy|Marvel's Spider-Man Eternal|14|M|{3}{R}{R}|Legendary Creature - Spider Human Hero|4|4|Menace$Whenever Ghost-Spider attacks, she deals X damage to defending player, where X is the number of attacking creatures.| +The Mary Janes|Marvel's Spider-Man Eternal|15|U|{3}{R}|Legendary Creature - Human Bard Performer|3|3|This spell costs {1} less to cast for each creature that attacked this turn.$Menace| +Rampaging Classmate|Marvel's Spider-Man Eternal|16|C|{2}{R}|Creature - Lizard Berserker|3|2|Whenever this creature attacks, it gets +1/+0 until end of turn for each other attacking creature.| +Prowler, Misguided Mentor|Marvel's Spider-Man Eternal|17|U|{2}{G}|Legendary Creature - Human Rogue Villain|3|3|Prowler can't be blocked by creatures with power 2 or less.$Whenever Prowler deals combat damage to a player, put a +1/+1 counter on another target creature you control.| +Spider-Man, Miles Morales|Marvel's Spider-Man Eternal|18|M|{4}{G}{G}|Legendary Creature - Spider Human Hero|5|5|Vigilance, trample$Whenever Spider-Man enters or attacks, put a +1/+1 counter on each other creature you control. Those creatures gain trample until end of turn.| +Twisted Spider-Clone|Marvel's Spider-Man Eternal|19|C|{3}{G}|Creature - Spider Human|4|4|When this creature enters, put a +1/+1 counter on each creature you control with a +1/+1 counter on it.| +Venom Blast|Marvel's Spider-Man Eternal|20|R|{2}{G}{G}|Sorcery|||Put two +1/+1 counters on target creature you control. It deals damage equal to its power to up to one other target creature.| Grasping Tentacles|Marvel's Spider-Man Eternal|21|R|{1}{U}{B}|Sorcery|||Target opponent mills eight cards. You may put an artifact card from that player's graveyard onto the battlefield under your control.| Venom, Deadly Devourer|Marvel's Spider-Man Eternal|22|R|{2}{B}{G}|Legendary Creature - Symbiote Villain|4|4|Vigilance, menace${3}: Exile target creature card from a graveyard. When you do, put X +1/+1 counters on target Symbiote, where X is the exiled card's toughness.| Green Goblin, Nemesis|Marvel's Spider-Man Eternal|23|R|{2}{B}{R}|Legendary Creature - Goblin Human Villain|3|3|Flying$Whenever you discard a nonland card, put a +1/+1 counter on target Goblin you control.$Whenever you discard a land card, create a tapped Treasure token.| From 3793717dbef4e56fdd09aabe4a94a8a7a75a5102 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:47:46 -0400 Subject: [PATCH 18/66] [SPE] Implement Amateur Hero --- Mage.Sets/src/mage/cards/a/AmateurHero.java | 38 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 39 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AmateurHero.java diff --git a/Mage.Sets/src/mage/cards/a/AmateurHero.java b/Mage.Sets/src/mage/cards/a/AmateurHero.java new file mode 100644 index 00000000000..1855b38d92c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AmateurHero.java @@ -0,0 +1,38 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AmateurHero extends CardImpl { + + public AmateurHero(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, you gain 2 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2))); + } + + private AmateurHero(final AmateurHero card) { + super(card); + } + + @Override + public AmateurHero copy() { + return new AmateurHero(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index c715cc22e54..9492f18e4ba 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -20,6 +20,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = false; // temporary + 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("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 c7b9a8289a3c820449a2ed39ae93678c117e0841 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:48:28 -0400 Subject: [PATCH 19/66] [SPE] Implement MJ, Rising Star --- Mage.Sets/src/mage/cards/m/MJRisingStar.java | 45 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MJRisingStar.java diff --git a/Mage.Sets/src/mage/cards/m/MJRisingStar.java b/Mage.Sets/src/mage/cards/m/MJRisingStar.java new file mode 100644 index 00000000000..5f8505ccd56 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MJRisingStar.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MJRisingStar extends CardImpl { + + public MJRisingStar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PERFORMER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever you gain life, put a +1/+1 counter on MJ. + this.addAbility(new GainLifeControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + } + + private MJRisingStar(final MJRisingStar card) { + super(card); + } + + @Override + public MJRisingStar copy() { + return new MJRisingStar(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 9492f18e4ba..e69c3411671 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -24,6 +24,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("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("MJ, Rising Star", 3, Rarity.UNCOMMON, mage.cards.m.MJRisingStar.class)); cards.add(new SetCardInfo("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); From b7e8f245733566b53d42252a723fce36ca48375c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:49:47 -0400 Subject: [PATCH 20/66] [SPE] Implement Spider-Man, Peter Parker --- .../mage/cards/s/SpiderManPeterParker.java | 53 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderManPeterParker.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderManPeterParker.java b/Mage.Sets/src/mage/cards/s/SpiderManPeterParker.java new file mode 100644 index 00000000000..e5bc54a8ab6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderManPeterParker.java @@ -0,0 +1,53 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderManPeterParker extends CardImpl { + + public SpiderManPeterParker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + 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); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you gain life, put a +1/+1 counter on target creature you control. It gains indestructible until end of turn. + Ability ability = new GainLifeControllerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()).setText("It gains indestructible until end of turn")); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private SpiderManPeterParker(final SpiderManPeterParker card) { + super(card); + } + + @Override + public SpiderManPeterParker copy() { + return new SpiderManPeterParker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index e69c3411671..93bb3a8e732 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -27,6 +27,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("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); + cards.add(new SetCardInfo("Spider-Man, Peter Parker", 4, Rarity.MYTHIC, mage.cards.s.SpiderManPeterParker.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); } } From 7bbe0f6471253a84b3d8251cfdbe33ffe4f0dbae Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:51:05 -0400 Subject: [PATCH 21/66] [SPE] Implement Alchemax Slayer-Bots --- .../src/mage/cards/a/AlchemaxSlayerBots.java | 45 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AlchemaxSlayerBots.java diff --git a/Mage.Sets/src/mage/cards/a/AlchemaxSlayerBots.java b/Mage.Sets/src/mage/cards/a/AlchemaxSlayerBots.java new file mode 100644 index 00000000000..fda458ef877 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AlchemaxSlayerBots.java @@ -0,0 +1,45 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.TapTargetEffect; +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.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AlchemaxSlayerBots extends CardImpl { + + public AlchemaxSlayerBots(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, tap target creature an opponent controls and put a stun counter on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private AlchemaxSlayerBots(final AlchemaxSlayerBots card) { + super(card); + } + + @Override + public AlchemaxSlayerBots copy() { + return new AlchemaxSlayerBots(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 93bb3a8e732..7bde16704dd 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -20,6 +20,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = false; // temporary + 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("Grasping Tentacles", 21, Rarity.RARE, mage.cards.g.GraspingTentacles.class)); From 3898272d58e72e9bde71d7897618fbce3262dbcf Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:52:12 -0400 Subject: [PATCH 22/66] [SPE] Implement Future Flight --- Mage.Sets/src/mage/cards/f/FutureFlight.java | 58 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 59 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FutureFlight.java diff --git a/Mage.Sets/src/mage/cards/f/FutureFlight.java b/Mage.Sets/src/mage/cards/f/FutureFlight.java new file mode 100644 index 00000000000..36013f52665 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FutureFlight.java @@ -0,0 +1,58 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.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 FutureFlight extends CardImpl { + + public FutureFlight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // When this Aura enters, draw two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2))); + + // Enchanted creature gets +2/+0 and has flying. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.addAbility(ability); + } + + private FutureFlight(final FutureFlight card) { + super(card); + } + + @Override + public FutureFlight copy() { + return new FutureFlight(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 7bde16704dd..b77c6c1c797 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("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)); cards.add(new SetCardInfo("MJ, Rising Star", 3, Rarity.UNCOMMON, mage.cards.m.MJRisingStar.class)); From 105fd2c26e0bfdf8e5fc5a32ab1748e83e3afa32 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:54:09 -0400 Subject: [PATCH 23/66] [SPE] Implement Lyla, Holographic Assistant --- .../cards/l/LylaHolographicAssistant.java | 45 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LylaHolographicAssistant.java diff --git a/Mage.Sets/src/mage/cards/l/LylaHolographicAssistant.java b/Mage.Sets/src/mage/cards/l/LylaHolographicAssistant.java new file mode 100644 index 00000000000..c9532f8b678 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LylaHolographicAssistant.java @@ -0,0 +1,45 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawCardControllerTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LylaHolographicAssistant extends CardImpl { + + public LylaHolographicAssistant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ILLUSION); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you draw a card, put a +1/+1 counter on target creature. + Ability ability = new DrawCardControllerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private LylaHolographicAssistant(final LylaHolographicAssistant card) { + super(card); + } + + @Override + public LylaHolographicAssistant copy() { + return new LylaHolographicAssistant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index b77c6c1c797..cbd1ed26732 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("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)); + 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("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); From 4fc5b04470608e95adf6cac7510271fa733a164c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:54:44 -0400 Subject: [PATCH 24/66] [SPE] Implement Grendel, Spawn of Knull --- .../src/mage/cards/g/GrendelSpawnOfKnull.java | 44 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GrendelSpawnOfKnull.java diff --git a/Mage.Sets/src/mage/cards/g/GrendelSpawnOfKnull.java b/Mage.Sets/src/mage/cards/g/GrendelSpawnOfKnull.java new file mode 100644 index 00000000000..d66da8e094b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrendelSpawnOfKnull.java @@ -0,0 +1,44 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrendelSpawnOfKnull extends CardImpl { + + public GrendelSpawnOfKnull(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SYMBIOTE); + this.subtype.add(SubType.DRAGON); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private GrendelSpawnOfKnull(final GrendelSpawnOfKnull card) { + super(card); + } + + @Override + public GrendelSpawnOfKnull copy() { + return new GrendelSpawnOfKnull(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index cbd1ed26732..a8679a3c5be 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("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)); + cards.add(new SetCardInfo("Grendel, Spawn of Knull", 9, Rarity.UNCOMMON, mage.cards.g.GrendelSpawnOfKnull.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("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); From 929e0ccb5cd5a4a52e1a0da77fd7a3cedbcf4098 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:55:43 -0400 Subject: [PATCH 25/66] [SPE] Implement Symbiote Spawn --- Mage.Sets/src/mage/cards/s/SymbioteSpawn.java | 42 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SymbioteSpawn.java diff --git a/Mage.Sets/src/mage/cards/s/SymbioteSpawn.java b/Mage.Sets/src/mage/cards/s/SymbioteSpawn.java new file mode 100644 index 00000000000..cffdd192649 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SymbioteSpawn.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SymbioteSpawn extends CardImpl { + + public SymbioteSpawn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SYMBIOTE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When this creature dies, each opponent loses 2 life and you gain 2 life. + Ability ability = new DiesSourceTriggeredAbility(new LoseLifeOpponentsEffect(2)); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + this.addAbility(ability); + } + + private SymbioteSpawn(final SymbioteSpawn card) { + super(card); + } + + @Override + public SymbioteSpawn copy() { + return new SymbioteSpawn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index a8679a3c5be..2ebd2f3f5d1 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -32,6 +32,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("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.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("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); } } From 9c2ff630eaa3a564122d57e12cc530afb104cedb Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:57:29 -0400 Subject: [PATCH 26/66] [SPE] Implement Prowler, Misguided Mentor --- .../mage/cards/p/ProwlerMisguidedMentor.java | 51 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 52 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/ProwlerMisguidedMentor.java diff --git a/Mage.Sets/src/mage/cards/p/ProwlerMisguidedMentor.java b/Mage.Sets/src/mage/cards/p/ProwlerMisguidedMentor.java new file mode 100644 index 00000000000..eceb8f2efb3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProwlerMisguidedMentor.java @@ -0,0 +1,51 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DauntAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProwlerMisguidedMentor extends CardImpl { + + public ProwlerMisguidedMentor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Prowler can't be blocked by creatures with power 2 or less. + this.addAbility(new DauntAbility()); + + // Whenever Prowler deals combat damage to a player, put a +1/+1 counter on another target creature you control. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private ProwlerMisguidedMentor(final ProwlerMisguidedMentor card) { + super(card); + } + + @Override + public ProwlerMisguidedMentor copy() { + return new ProwlerMisguidedMentor(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 2ebd2f3f5d1..d1cd2c64bc1 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -29,6 +29,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { cards.add(new SetCardInfo("Grendel, Spawn of Knull", 9, Rarity.UNCOMMON, mage.cards.g.GrendelSpawnOfKnull.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)); cards.add(new SetCardInfo("Pumpkin Bombs", 26, Rarity.RARE, mage.cards.p.PumpkinBombs.class)); cards.add(new SetCardInfo("Sensational Spider-Man", 25, Rarity.RARE, mage.cards.s.SensationalSpiderMan.class)); cards.add(new SetCardInfo("Spider-Man, Peter Parker", 4, Rarity.MYTHIC, mage.cards.s.SpiderManPeterParker.class)); From ba28fd87577e4c22193911c656a28ef09bdb6fea Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 08:59:54 -0400 Subject: [PATCH 27/66] [SPE] Implement Spider-Man, Miles Morales --- .../mage/cards/s/SpiderManMilesMorales.java | 61 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 62 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderManMilesMorales.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderManMilesMorales.java b/Mage.Sets/src/mage/cards/s/SpiderManMilesMorales.java new file mode 100644 index 00000000000..cb95c800e7b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderManMilesMorales.java @@ -0,0 +1,61 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderManMilesMorales extends CardImpl { + + public SpiderManMilesMorales(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Spider-Man enters or attacks, put a +1/+1 counter on each other creature you control. Those creatures gain trample until end of turn. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE + )); + ability.addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE + ).setText("Those creatures gain trample until end of turn")); + this.addAbility(ability); + } + + private SpiderManMilesMorales(final SpiderManMilesMorales card) { + super(card); + } + + @Override + public SpiderManMilesMorales copy() { + return new SpiderManMilesMorales(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index d1cd2c64bc1..6ba1de200d6 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -32,6 +32,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { 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("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)); cards.add(new SetCardInfo("Symbiote Spawn", 11, Rarity.COMMON, mage.cards.s.SymbioteSpawn.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); From 68e710c5c1cb893647bc900f3d26abd2140168b2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:00:59 -0400 Subject: [PATCH 28/66] [SPE] Implement Twisted Spider-Clone --- .../src/mage/cards/t/TwistedSpiderClone.java | 42 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TwistedSpiderClone.java diff --git a/Mage.Sets/src/mage/cards/t/TwistedSpiderClone.java b/Mage.Sets/src/mage/cards/t/TwistedSpiderClone.java new file mode 100644 index 00000000000..379200c2b43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TwistedSpiderClone.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TwistedSpiderClone extends CardImpl { + + public TwistedSpiderClone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When this creature enters, put a +1/+1 counter on each creature you control with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1 + ))); + } + + private TwistedSpiderClone(final TwistedSpiderClone card) { + super(card); + } + + @Override + public TwistedSpiderClone copy() { + return new TwistedSpiderClone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index 6ba1de200d6..f8cfd7f134e 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("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("Twisted Spider-Clone", 19, Rarity.COMMON, mage.cards.t.TwistedSpiderClone.class)); cards.add(new SetCardInfo("Venom, Deadly Devourer", 22, Rarity.RARE, mage.cards.v.VenomDeadlyDevourer.class)); } } From 3b9300b1ff1410a00997d3357175bd6af4068ee2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:03:25 -0400 Subject: [PATCH 29/66] [SPE] Implement Venom Blast --- Mage.Sets/src/mage/cards/v/VenomBlast.java | 41 +++++++++++++++++++ .../mage/sets/MarvelsSpiderManEternal.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VenomBlast.java diff --git a/Mage.Sets/src/mage/cards/v/VenomBlast.java b/Mage.Sets/src/mage/cards/v/VenomBlast.java new file mode 100644 index 00000000000..f9105491fb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomBlast.java @@ -0,0 +1,41 @@ +package mage.cards.v; + +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenomBlast extends CardImpl { + + public VenomBlast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); + + // Put two +1/+1 counters on target creature you control. It deals damage equal to its power to up to one other target creature. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))); + this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect() + .setText("It deals damage equal to its power to up to one other target creature")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2 + ).setTargetTag(2)); + } + + private VenomBlast(final VenomBlast card) { + super(card); + } + + @Override + public VenomBlast copy() { + return new VenomBlast(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java index f8cfd7f134e..0457ffe02fd 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderManEternal.java @@ -36,6 +36,7 @@ public final class MarvelsSpiderManEternal extends ExpansionSet { 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("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)); } } From 5133c2e68d232d7c7b7d92da121ab72720636497 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:30:30 -0400 Subject: [PATCH 30/66] [SPM] Implement Aunt May --- Mage.Sets/src/mage/cards/a/AuntMay.java | 77 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 78 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AuntMay.java diff --git a/Mage.Sets/src/mage/cards/a/AuntMay.java b/Mage.Sets/src/mage/cards/a/AuntMay.java new file mode 100644 index 00000000000..0756a23e7c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AuntMay.java @@ -0,0 +1,77 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AuntMay extends CardImpl { + + public AuntMay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Whenever another creature you control enters, you gain 1 life. If it's a Spider, put a +1/+1 counter on it. + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new GainLifeEffect(1), + StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL, + false, SetTargetPointer.PERMANENT + ); + ability.addEffect(new AuntMayEffect()); + this.addAbility(ability); + } + + private AuntMay(final AuntMay card) { + super(card); + } + + @Override + public AuntMay copy() { + return new AuntMay(this); + } +} + +class AuntMayEffect extends OneShotEffect { + + AuntMayEffect() { + super(Outcome.Benefit); + staticText = "If it's a Spider, put a +1/+1 counter on it"; + } + + private AuntMayEffect(final AuntMayEffect effect) { + super(effect); + } + + @Override + public AuntMayEffect copy() { + return new AuntMayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(getTargetPointer().getFirst(game, source)) + .map(game::getPermanent) + .filter(permanent -> permanent.hasSubtype(SubType.SPIDER, game)) + .filter(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index b9f394d9ffc..b47ad293e51 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -20,6 +20,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = true; + cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); From 1251c6046fff9a7b875803b46223cc347a7e5ed6 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:32:42 -0400 Subject: [PATCH 31/66] [SPM] Implement Daily Bugle Reporters --- .../src/mage/cards/d/DailyBugleReporters.java | 63 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 64 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DailyBugleReporters.java diff --git a/Mage.Sets/src/mage/cards/d/DailyBugleReporters.java b/Mage.Sets/src/mage/cards/d/DailyBugleReporters.java new file mode 100644 index 00000000000..3a594835ae0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DailyBugleReporters.java @@ -0,0 +1,63 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DailyBugleReporters extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 2 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } + + public DailyBugleReporters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When this creature enters, choose one -- + // * Puff Piece -- Put a +1/+1 counter on each of up to two target creatures. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent(0, 2)); + ability.withFirstModeFlavorWord("Puff Piece"); + + // * Investigative Journalism -- Return target creature card with mana value 2 or less from your graveyard to your hand. + ability.addMode(new Mode(new ReturnFromGraveyardToHandTargetEffect()) + .addTarget(new TargetCardInYourGraveyard(filter)) + .withFlavorWord("Investigative Journalism")); + this.addAbility(ability); + } + + private DailyBugleReporters(final DailyBugleReporters card) { + super(card); + } + + @Override + public DailyBugleReporters copy() { + return new DailyBugleReporters(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index b47ad293e51..83913cfd930 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -21,6 +21,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { this.hasBasicLands = true; cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); + cards.add(new SetCardInfo("Daily Bugle Reporters", 6, Rarity.COMMON, mage.cards.d.DailyBugleReporters.class)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); From 1a0f3b68fc3f07aef31fe6434678cf1527ee35b8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:38:06 -0400 Subject: [PATCH 32/66] [SPM] Implement Selfless Police Captain --- .../mage/cards/s/SelflessPoliceCaptain.java | 51 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../PutSourceCountersOnTargetEffect.java | 16 +++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/s/SelflessPoliceCaptain.java diff --git a/Mage.Sets/src/mage/cards/s/SelflessPoliceCaptain.java b/Mage.Sets/src/mage/cards/s/SelflessPoliceCaptain.java new file mode 100644 index 00000000000..2d900ebf522 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SelflessPoliceCaptain.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.PutSourceCountersOnTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SelflessPoliceCaptain extends CardImpl { + + public SelflessPoliceCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DETECTIVE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // This creature enters with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + "with a +1/+1 counter on it" + )); + + // When this creature leaves the battlefield, put its +1/+1 counters on target creature you control. + Ability ability = new DiesSourceTriggeredAbility(new PutSourceCountersOnTargetEffect(CounterType.P1P1)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private SelflessPoliceCaptain(final SelflessPoliceCaptain card) { + super(card); + } + + @Override + public SelflessPoliceCaptain copy() { + return new SelflessPoliceCaptain(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 83913cfd930..bbe7fd364da 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -27,6 +27,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { 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)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java index 60e0232529c..491f066dc69 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -12,12 +13,20 @@ import mage.game.permanent.Permanent; */ public class PutSourceCountersOnTargetEffect extends OneShotEffect { + private final CounterType counterType; + public PutSourceCountersOnTargetEffect() { + this((CounterType) null); + } + + public PutSourceCountersOnTargetEffect(CounterType counterType) { super(Outcome.Benefit); + this.counterType = counterType; } private PutSourceCountersOnTargetEffect(final PutSourceCountersOnTargetEffect effect) { super(effect); + this.counterType = effect.counterType; } @Override @@ -32,6 +41,10 @@ public class PutSourceCountersOnTargetEffect extends OneShotEffect { if (sourcePermanent == null || permanent == null) { return false; } + if (counterType != null) { + int count = sourcePermanent.getCounters(game).getCount(counterType); + return count > 0 && permanent.addCounters(counterType.createInstance(count), source, game); + } sourcePermanent .getCounters(game) .values() @@ -45,6 +58,7 @@ public class PutSourceCountersOnTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "put its counters on " + getTargetPointer().describeTargets(mode.getTargets(), "that creature"); + return "put its" + (counterType != null ? " " + counterType : "") + " counters on " + + getTargetPointer().describeTargets(mode.getTargets(), "that creature"); } } From b49956b9c4d6e96186ecfbdac6bede20a5105728 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:42:34 -0400 Subject: [PATCH 33/66] [SPM] Implement Spectacular Tactics --- .../src/mage/cards/s/SpectacularTactics.java | 53 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpectacularTactics.java diff --git a/Mage.Sets/src/mage/cards/s/SpectacularTactics.java b/Mage.Sets/src/mage/cards/s/SpectacularTactics.java new file mode 100644 index 00000000000..1470cccea94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpectacularTactics.java @@ -0,0 +1,53 @@ +package mage.cards.s; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpectacularTactics extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public SpectacularTactics(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Choose one -- + // * Put a +1/+1 counter on target creature you control. It gains hexproof until end of turn. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance()).setText("It gains hexproof until end of turn")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + + // * Destroy target creature with power 4 or greater. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetPermanent(filter))); + } + + private SpectacularTactics(final SpectacularTactics card) { + super(card); + } + + @Override + public SpectacularTactics copy() { + return new SpectacularTactics(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index bbe7fd364da..3a439737782 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("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); } } From 999f542bb5c85c09bacd23690bed3f30a0c6fef8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:43:31 -0400 Subject: [PATCH 34/66] [SPM] Implement Starling, Aerial Ally --- .../src/mage/cards/s/StarlingAerialAlly.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/StarlingAerialAlly.java diff --git a/Mage.Sets/src/mage/cards/s/StarlingAerialAlly.java b/Mage.Sets/src/mage/cards/s/StarlingAerialAlly.java new file mode 100644 index 00000000000..1f73ec7a85b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StarlingAerialAlly.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StarlingAerialAlly extends CardImpl { + + public StarlingAerialAlly(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Starling enters, another target creature you control gains flying until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private StarlingAerialAlly(final StarlingAerialAlly card) { + super(card); + } + + @Override + public StarlingAerialAlly copy() { + return new StarlingAerialAlly(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 3a439737782..d168cda0bc7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -30,6 +30,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); + cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); } } From 10c9b5dc99f39baa1d4b5b76076f95cbd13674df Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:44:18 -0400 Subject: [PATCH 35/66] [SPM] Implement Web Up --- Mage.Sets/src/mage/cards/w/WebUp.java | 36 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 37 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WebUp.java diff --git a/Mage.Sets/src/mage/cards/w/WebUp.java b/Mage.Sets/src/mage/cards/w/WebUp.java new file mode 100644 index 00000000000..e0280436d9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WebUp.java @@ -0,0 +1,36 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +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 WebUp extends CardImpl { + + public WebUp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileUntilSourceLeavesEffect()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_NON_LAND)); + this.addAbility(ability); + } + + private WebUp(final WebUp card) { + super(card); + } + + @Override + public WebUp copy() { + return new WebUp(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index d168cda0bc7..ef9823a11bc 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -32,5 +32,6 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); } } From 909f25d8b533db5ce3950c2c36f51fd20697333a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:45:07 -0400 Subject: [PATCH 36/66] [SPM] Implement Doc Ock's Henchmen --- .../src/mage/cards/d/DocOcksHenchmen.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DocOcksHenchmen.java diff --git a/Mage.Sets/src/mage/cards/d/DocOcksHenchmen.java b/Mage.Sets/src/mage/cards/d/DocOcksHenchmen.java new file mode 100644 index 00000000000..c66103c317f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DocOcksHenchmen.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DocOcksHenchmen extends CardImpl { + + public DocOcksHenchmen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Whenever this creature attacks, it connives. + this.addAbility(new AttacksTriggeredAbility(new ConniveSourceEffect())); + } + + private DocOcksHenchmen(final DocOcksHenchmen card) { + super(card); + } + + @Override + public DocOcksHenchmen copy() { + return new DocOcksHenchmen(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index ef9823a11bc..af8007fc5a8 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -22,6 +22,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.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("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); From da9b01f6986647b2b67e0bb76b4ab576b75cc477 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:46:21 -0400 Subject: [PATCH 37/66] [SPM] Implement Flying Octobot --- Mage.Sets/src/mage/cards/f/FlyingOctobot.java | 54 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FlyingOctobot.java diff --git a/Mage.Sets/src/mage/cards/f/FlyingOctobot.java b/Mage.Sets/src/mage/cards/f/FlyingOctobot.java new file mode 100644 index 00000000000..a362fe29cf5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlyingOctobot.java @@ -0,0 +1,54 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FlyingOctobot extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VILLAIN, "another Villain you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public FlyingOctobot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever another Villain you control enters, put a +1/+1 counter on this creature. This ability triggers only once each turn. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + ).setTriggersLimitEachTurn(1)); + } + + private FlyingOctobot(final FlyingOctobot card) { + super(card); + } + + @Override + public FlyingOctobot copy() { + return new FlyingOctobot(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index af8007fc5a8..1c7abc93106 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -23,6 +23,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.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("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("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); From 82386813b250aeeb23b75a61a720bfa93e8b7fe0 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:47:13 -0400 Subject: [PATCH 38/66] [SPM] Implement Oscorp Research Team --- .../src/mage/cards/o/OscorpResearchTeam.java | 39 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 40 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/OscorpResearchTeam.java diff --git a/Mage.Sets/src/mage/cards/o/OscorpResearchTeam.java b/Mage.Sets/src/mage/cards/o/OscorpResearchTeam.java new file mode 100644 index 00000000000..4d55a1b3570 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OscorpResearchTeam.java @@ -0,0 +1,39 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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 OscorpResearchTeam extends CardImpl { + + public OscorpResearchTeam(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // {6}{U}: Draw two cards. + this.addAbility(new SimpleActivatedAbility(new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{6}{U}"))); + } + + private OscorpResearchTeam(final OscorpResearchTeam card) { + super(card); + } + + @Override + public OscorpResearchTeam copy() { + return new OscorpResearchTeam(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 1c7abc93106..e02d0da904f 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -28,6 +28,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); 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)); + cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); From ab1d5ff6991edf22e044b3d41eaa2faea8d6f8fd Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:48:14 -0400 Subject: [PATCH 39/66] [SPM] Implement Spider-Byte, Web Warden --- .../src/mage/cards/s/SpiderByteWebWarden.java | 45 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderByteWebWarden.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderByteWebWarden.java b/Mage.Sets/src/mage/cards/s/SpiderByteWebWarden.java new file mode 100644 index 00000000000..b3e66f10cbf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderByteWebWarden.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderByteWebWarden extends CardImpl { + + public SpiderByteWebWarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.AVATAR); + this.subtype.add(SubType.HERO); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Spider-Byte enters, return up to one target nonland permanent to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetNonlandPermanent(0, 1)); + this.addAbility(ability); + } + + private SpiderByteWebWarden(final SpiderByteWebWarden card) { + super(card); + } + + @Override + public SpiderByteWebWarden copy() { + return new SpiderByteWebWarden(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index e02d0da904f..fffec23ddc5 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -33,6 +33,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); + cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); From 218aa5079cf06947589b82e275ae1907a62e81ef Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:49:52 -0400 Subject: [PATCH 40/66] [SPM] Implement Whoosh! --- Mage.Sets/src/mage/cards/b/BlinkOfAnEye.java | 14 +++--- Mage.Sets/src/mage/cards/i/IntoTheRoil.java | 13 +++--- Mage.Sets/src/mage/cards/w/Whoosh.java | 43 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 4 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/w/Whoosh.java diff --git a/Mage.Sets/src/mage/cards/b/BlinkOfAnEye.java b/Mage.Sets/src/mage/cards/b/BlinkOfAnEye.java index 0441ef725cf..aa0c3013881 100644 --- a/Mage.Sets/src/mage/cards/b/BlinkOfAnEye.java +++ b/Mage.Sets/src/mage/cards/b/BlinkOfAnEye.java @@ -1,8 +1,5 @@ - package mage.cards.b; -import java.util.UUID; - import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,8 +10,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author JRHerlehy */ public final class BlinkOfAnEye extends CardImpl { @@ -26,10 +24,12 @@ public final class BlinkOfAnEye extends CardImpl { this.addAbility(new KickerAbility("{1}{U}")); // Return target nonland permanent to its owner's hand. If this spell was kicked, draw a card. - this.getSpellAbility().addTarget(new TargetNonlandPermanent()); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), KickedCondition.ONCE, - "If this spell was kicked, draw a card")); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), + KickedCondition.ONCE, "if this spell was kicked, draw a card" + )); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } private BlinkOfAnEye(final BlinkOfAnEye card) { diff --git a/Mage.Sets/src/mage/cards/i/IntoTheRoil.java b/Mage.Sets/src/mage/cards/i/IntoTheRoil.java index 95337fc4f88..7322729f24a 100644 --- a/Mage.Sets/src/mage/cards/i/IntoTheRoil.java +++ b/Mage.Sets/src/mage/cards/i/IntoTheRoil.java @@ -1,8 +1,5 @@ - - package mage.cards.i; -import java.util.UUID; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,15 +10,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author Viserion */ public final class IntoTheRoil extends CardImpl { public IntoTheRoil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Kicker {1}{U} (You may pay an additional {1}{U} as you cast this spell.) this.addAbility(new KickerAbility("{1}{U}")); @@ -30,8 +27,8 @@ public final class IntoTheRoil extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), - KickedCondition.ONCE, - "if this spell was kicked, draw a card")); + KickedCondition.ONCE, "if this spell was kicked, draw a card" + )); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } diff --git a/Mage.Sets/src/mage/cards/w/Whoosh.java b/Mage.Sets/src/mage/cards/w/Whoosh.java new file mode 100644 index 00000000000..43fb9db1054 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Whoosh.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.KickerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Whoosh extends CardImpl { + + public Whoosh(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Kicker {1}{U} + this.addAbility(new KickerAbility("{1}{U}")); + + // Return target nonland permanent to its owner's hand. If this spell was kicked, draw a card. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), + KickedCondition.ONCE, "if this spell was kicked, draw a card" + )); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private Whoosh(final Whoosh card) { + super(card); + } + + @Override + public Whoosh copy() { + return new Whoosh(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index fffec23ddc5..cee7af12605 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -37,5 +37,6 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); 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)); } } From 486f2319fbf56a331dcf01cada888ee3ef09afff Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:50:40 -0400 Subject: [PATCH 41/66] [SPM] Implement Merciless Enforcers --- .../src/mage/cards/m/MercilessEnforcers.java | 47 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MercilessEnforcers.java diff --git a/Mage.Sets/src/mage/cards/m/MercilessEnforcers.java b/Mage.Sets/src/mage/cards/m/MercilessEnforcers.java new file mode 100644 index 00000000000..b4523cfdedd --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MercilessEnforcers.java @@ -0,0 +1,47 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MercilessEnforcers extends CardImpl { + + public MercilessEnforcers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // {3}{B}: This creature deals 1 damage to each opponent. + this.addAbility(new SimpleActivatedAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), new ManaCostsImpl<>("{3}{B}") + )); + } + + private MercilessEnforcers(final MercilessEnforcers card) { + super(card); + } + + @Override + public MercilessEnforcers copy() { + return new MercilessEnforcers(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index cee7af12605..0117e9b73a5 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -26,6 +26,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { 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("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + 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)); cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); From b475b379f2147b9e4358feaf799a7839b7a168ed Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:51:34 -0400 Subject: [PATCH 42/66] [SPM] Implement Risky Research --- Mage.Sets/src/mage/cards/r/RiskyResearch.java | 34 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 35 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RiskyResearch.java diff --git a/Mage.Sets/src/mage/cards/r/RiskyResearch.java b/Mage.Sets/src/mage/cards/r/RiskyResearch.java new file mode 100644 index 00000000000..8a2b8dc7007 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiskyResearch.java @@ -0,0 +1,34 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiskyResearch extends CardImpl { + + public RiskyResearch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Surveil 2, then draw two cards. You lose 2 life. + this.getSpellAbility().addEffect(new SurveilEffect(2, false)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then")); + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); + } + + private RiskyResearch(final RiskyResearch card) { + super(card); + } + + @Override + public RiskyResearch copy() { + return new RiskyResearch(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 0117e9b73a5..012c404fb60 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("Origin of Spider-Man", 9, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class)); cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); From 288901be1d5306643be4a5b843bf4c83028a43fe Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:54:55 -0400 Subject: [PATCH 43/66] [SPM] Implement Scorpion, Seething Striker --- .../mage/cards/s/ScorpionSeethingStriker.java | 76 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../effects/keyword/ConniveSourceEffect.java | 6 +- 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java diff --git a/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java new file mode 100644 index 00000000000..ae85ab0fa00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScorpionSeethingStriker.java @@ -0,0 +1,76 @@ +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.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; + +/** + * @author TheElk801 + */ +public final class ScorpionSeethingStriker extends CardImpl { + + public ScorpionSeethingStriker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SCORPION); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Deathtouch + 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.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ScorpionSeethingStriker(final ScorpionSeethingStriker card) { + super(card); + } + + @Override + public ScorpionSeethingStriker copy() { + 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/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 012c404fb60..89d12456a5a 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -32,6 +32,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); + cards.add(new SetCardInfo("Scorpion, Seething Striker", 64, Rarity.UNCOMMON, mage.cards.s.ScorpionSeethingStriker.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java index f7641bf46ba..d435e102853 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java @@ -85,13 +85,9 @@ public class ConniveSourceEffect extends OneShotEffect { * @return */ public static boolean connive(Permanent permanent, int amount, Ability source, Game game) { - if (amount < 1) { + if (permanent == null || amount < 1) { return false; } - if (permanent == null) { - return false; - } - boolean permanentStillOnBattlefield = game.getState().getZone(permanent.getId()) == Zone.BATTLEFIELD; Player player = game.getPlayer(permanent.getControllerId()); if (player == null) { From 3047559cd13e5d4dd28843c1c7c52766b3bdfb3d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:55:42 -0400 Subject: [PATCH 44/66] [SPM] Implement Scorpion's Sting --- .../src/mage/cards/s/ScorpionsSting.java | 32 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 33 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/ScorpionsSting.java diff --git a/Mage.Sets/src/mage/cards/s/ScorpionsSting.java b/Mage.Sets/src/mage/cards/s/ScorpionsSting.java new file mode 100644 index 00000000000..ddc30679ba4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScorpionsSting.java @@ -0,0 +1,32 @@ +package mage.cards.s; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScorpionsSting extends CardImpl { + + public ScorpionsSting(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Target creature gets -3/-3 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-3, -3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private ScorpionsSting(final ScorpionsSting card) { + super(card); + } + + @Override + public ScorpionsSting copy() { + return new ScorpionsSting(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 89d12456a5a..68add678715 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -32,6 +32,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); + cards.add(new SetCardInfo("Scorpion's Sting", 65, Rarity.COMMON, mage.cards.s.ScorpionsSting.class)); cards.add(new SetCardInfo("Scorpion, Seething Striker", 64, Rarity.UNCOMMON, mage.cards.s.ScorpionSeethingStriker.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); From 91e5a4b994ca06a3b194afcc8e31c7df9671936c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:59:01 -0400 Subject: [PATCH 45/66] [SPM] Implement Tombstone, Career Criminal --- .../mage/cards/t/TombstoneCareerCriminal.java | 54 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../filter/common/FilterBySubtypeCard.java | 10 ++-- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/t/TombstoneCareerCriminal.java diff --git a/Mage.Sets/src/mage/cards/t/TombstoneCareerCriminal.java b/Mage.Sets/src/mage/cards/t/TombstoneCareerCriminal.java new file mode 100644 index 00000000000..b38f4a67822 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TombstoneCareerCriminal.java @@ -0,0 +1,54 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.common.FilterBySubtypeCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TombstoneCareerCriminal extends CardImpl { + + private static final FilterCard filter = new FilterBySubtypeCard(SubType.VILLAIN); + private static final FilterCard filter2 = new FilterBySubtypeCard(SubType.VILLAIN, "Villain spells"); + + public TombstoneCareerCriminal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Tombstone enters, return target Villain card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + + // Villain spells you cast cost {1} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter2, 1))); + } + + private TombstoneCareerCriminal(final TombstoneCareerCriminal card) { + super(card); + } + + @Override + public TombstoneCareerCriminal copy() { + return new TombstoneCareerCriminal(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 68add678715..ac68c04faad 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -40,6 +40,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("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.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)); } diff --git a/Mage/src/main/java/mage/filter/common/FilterBySubtypeCard.java b/Mage/src/main/java/mage/filter/common/FilterBySubtypeCard.java index d99d2ab47bf..b5bb2f023e4 100644 --- a/Mage/src/main/java/mage/filter/common/FilterBySubtypeCard.java +++ b/Mage/src/main/java/mage/filter/common/FilterBySubtypeCard.java @@ -1,18 +1,22 @@ - - package mage.filter.common; import mage.constants.SubType; import mage.filter.FilterCard; /** + * TODO: Collapse this into FilterCard + * * @author LevelX2 */ public class FilterBySubtypeCard extends FilterCard { public FilterBySubtypeCard(SubType subtype) { - super(subtype + " card"); + this(subtype, subtype + " card"); + } + + public FilterBySubtypeCard(SubType subtype, String name) { + super(name); this.add(subtype.getPredicate()); } From 804ac33f8740d511d002947ca88b7fed98379146 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 09:59:52 -0400 Subject: [PATCH 46/66] [SPM] Implement Masked Meower --- Mage.Sets/src/mage/cards/m/MaskedMeower.java | 48 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 49 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MaskedMeower.java diff --git a/Mage.Sets/src/mage/cards/m/MaskedMeower.java b/Mage.Sets/src/mage/cards/m/MaskedMeower.java new file mode 100644 index 00000000000..e12df95be94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaskedMeower.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.HasteAbility; +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 MaskedMeower extends CardImpl { + + public MaskedMeower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.HERO); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Discard a card, Sacrifice this creature: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new DiscardCardCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private MaskedMeower(final MaskedMeower card) { + super(card); + } + + @Override + public MaskedMeower copy() { + return new MaskedMeower(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index ac68c04faad..dafa167dcb8 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -26,6 +26,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { 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("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.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 13093b47645a86ba8c7e39f230b3f77442fb2a7d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:01:02 -0400 Subject: [PATCH 47/66] [SPM] Implement Spider-Gwen, Free Spirit --- .../mage/cards/s/SpiderGwenFreeSpirit.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderGwenFreeSpirit.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderGwenFreeSpirit.java b/Mage.Sets/src/mage/cards/s/SpiderGwenFreeSpirit.java new file mode 100644 index 00000000000..d665ed2cde4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderGwenFreeSpirit.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderGwenFreeSpirit extends CardImpl { + + public SpiderGwenFreeSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{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(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever Spider-Gwen becomes tapped, you may discard a card. If you do, draw a card. + this.addAbility(new BecomesTappedSourceTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()) + )); + } + + private SpiderGwenFreeSpirit(final SpiderGwenFreeSpirit card) { + super(card); + } + + @Override + public SpiderGwenFreeSpirit copy() { + return new SpiderGwenFreeSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index dafa167dcb8..78e710cd64e 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -39,6 +39,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); 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("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.class)); From c52ce9a8d63925e70a96154af43998c9ee841730 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:02:09 -0400 Subject: [PATCH 48/66] [SPM] Implement Taxi Driver --- Mage.Sets/src/mage/cards/t/TaxiDriver.java | 46 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TaxiDriver.java diff --git a/Mage.Sets/src/mage/cards/t/TaxiDriver.java b/Mage.Sets/src/mage/cards/t/TaxiDriver.java new file mode 100644 index 00000000000..8ec5ee44834 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaxiDriver.java @@ -0,0 +1,46 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaxiDriver extends CardImpl { + + public TaxiDriver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PILOT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // {1}, {T}: Target creature gains haste until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance()), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private TaxiDriver(final TaxiDriver card) { + super(card); + } + + @Override + public TaxiDriver copy() { + return new TaxiDriver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 78e710cd64e..ce9ffb159b0 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -42,6 +42,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spider-Gwen, Free Spirit", 90, Rarity.COMMON, mage.cards.s.SpiderGwenFreeSpirit.class)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.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("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.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)); From 8e693146c84530a662b6efc43dfd96e3a8dc0692 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:03:49 -0400 Subject: [PATCH 49/66] [SPM] Implement Guy in the Chair --- Mage.Sets/src/mage/cards/g/GuyInTheChair.java | 53 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GuyInTheChair.java diff --git a/Mage.Sets/src/mage/cards/g/GuyInTheChair.java b/Mage.Sets/src/mage/cards/g/GuyInTheChair.java new file mode 100644 index 00000000000..7cf834eeeef --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuyInTheChair.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuyInTheChair extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.SPIDER, "Spider"); + + public GuyInTheChair(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + + // Web Support -- {2}{G}, {T}: Put a +1/+1 counter on target Spider. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{2}{G}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability.withFlavorWord("Web Support")); + } + + private GuyInTheChair(final GuyInTheChair card) { + super(card); + } + + @Override + public GuyInTheChair copy() { + return new GuyInTheChair(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index ce9ffb159b0..e3aad265081 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("Doc Ock's Henchmen", 30, Rarity.COMMON, mage.cards.d.DocOcksHenchmen.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("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("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.class)); cards.add(new SetCardInfo("Merciless Enforcers", 58, Rarity.COMMON, mage.cards.m.MercilessEnforcers.class)); From 07ca274ba2ceda56591e94d733438015953fb7ba Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:04:58 -0400 Subject: [PATCH 50/66] [SPM] Implement Kapow! --- Mage.Sets/src/mage/cards/k/Kapow.java | 37 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 38 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/Kapow.java diff --git a/Mage.Sets/src/mage/cards/k/Kapow.java b/Mage.Sets/src/mage/cards/k/Kapow.java new file mode 100644 index 00000000000..7b6763ae964 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/Kapow.java @@ -0,0 +1,37 @@ +package mage.cards.k; + +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Kapow extends CardImpl { + + public Kapow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Put a +1/+1 counter on target creature you control. It fights target creature an opponent controls. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new FightTargetsEffect().setText("It fights target creature an opponent controls")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + } + + private Kapow(final Kapow card) { + super(card); + } + + @Override + public Kapow copy() { + return new Kapow(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index e3aad265081..0aa0283a09d 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -27,6 +27,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); 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)); cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.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)); From 877587fcdd1659b6bf7364d9164064db12dbb544 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:05:48 -0400 Subject: [PATCH 51/66] [SPM] Implement Kraven's Cats --- Mage.Sets/src/mage/cards/k/KravensCats.java | 42 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KravensCats.java diff --git a/Mage.Sets/src/mage/cards/k/KravensCats.java b/Mage.Sets/src/mage/cards/k/KravensCats.java new file mode 100644 index 00000000000..be829a58d23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KravensCats.java @@ -0,0 +1,42 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KravensCats extends CardImpl { + + public KravensCats(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}{G}: This creature gets +2/+2 until end of turn. Activate only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{G}") + )); + } + + private KravensCats(final KravensCats card) { + super(card); + } + + @Override + public KravensCats copy() { + return new KravensCats(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 0aa0283a09d..593c32277b9 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -28,6 +28,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { 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)); + cards.add(new SetCardInfo("Kraven's Cats", 104, Rarity.COMMON, mage.cards.k.KravensCats.class)); cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.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)); From 3371a824c5020a0b31c091baa4add143099d9a30 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:07:12 -0400 Subject: [PATCH 52/66] [SPM] Implement Lurking Lizards --- .../src/mage/cards/l/LurkingLizards.java | 54 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LurkingLizards.java diff --git a/Mage.Sets/src/mage/cards/l/LurkingLizards.java b/Mage.Sets/src/mage/cards/l/LurkingLizards.java new file mode 100644 index 00000000000..d519cae84ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LurkingLizards.java @@ -0,0 +1,54 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ManaValuePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LurkingLizards extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell with mana value 4 or greater"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); + } + + public LurkingLizards(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on this creature. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, false + )); + } + + private LurkingLizards(final LurkingLizards card) { + super(card); + } + + @Override + public LurkingLizards copy() { + return new LurkingLizards(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 593c32277b9..99c7aaba44b 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("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)); 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("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)); From d508d52dcbf7386a67234eed973b538654d28b36 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:09:00 -0400 Subject: [PATCH 53/66] [SPM] Implement Scout the City --- Mage.Sets/src/mage/cards/s/ScoutTheCity.java | 43 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 44 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/ScoutTheCity.java diff --git a/Mage.Sets/src/mage/cards/s/ScoutTheCity.java b/Mage.Sets/src/mage/cards/s/ScoutTheCity.java new file mode 100644 index 00000000000..609dc961bbd --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScoutTheCity.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.MillThenPutInHandEffect; +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 ScoutTheCity extends CardImpl { + + public ScoutTheCity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // Choose one -- + // * Look Around -- Mill three cards. You may put a permanent card from among them into your hand. You gain 3 life. + this.getSpellAbility().addEffect(new MillThenPutInHandEffect(3, StaticFilters.FILTER_CARD_PERMANENT)); + this.getSpellAbility().addEffect(new GainLifeEffect(3)); + this.getSpellAbility().withFirstModeFlavorWord("Look Around"); + + // * Bring Down -- Destroy target creature with flying. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()) + .addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_FLYING)) + .withFlavorWord("Bring Down")); + } + + private ScoutTheCity(final ScoutTheCity card) { + super(card); + } + + @Override + public ScoutTheCity copy() { + return new ScoutTheCity(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 99c7aaba44b..4c7aab68d07 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -39,6 +39,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); cards.add(new SetCardInfo("Scorpion's Sting", 65, Rarity.COMMON, mage.cards.s.ScorpionsSting.class)); cards.add(new SetCardInfo("Scorpion, Seething Striker", 64, Rarity.UNCOMMON, mage.cards.s.ScorpionSeethingStriker.class)); + cards.add(new SetCardInfo("Scout the City", 113, Rarity.COMMON, mage.cards.s.ScoutTheCity.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); From 4eb4ba949c8deb69fbc54b6f4361fc889efa4a13 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:12:43 -0400 Subject: [PATCH 54/66] [SPM] Implement Spider-Ham, Peter Porker --- .../mage/cards/s/SpiderHamPeterPorker.java | 81 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 82 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderHamPeterPorker.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderHamPeterPorker.java b/Mage.Sets/src/mage/cards/s/SpiderHamPeterPorker.java new file mode 100644 index 00000000000..5089e260d1f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderHamPeterPorker.java @@ -0,0 +1,81 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderHamPeterPorker extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent( + "Spiders, Boars, Bats, Bears, Birds, Cats, Dogs, Frogs, Jackals, Lizards, " + + "Mice, Otters, Rabbits, Raccoons, Rats, Squirrels, Turtles, and Wolves" + ); + + static { + filter.add(Predicates.or( + SubType.SPIDER.getPredicate(), + SubType.BOAR.getPredicate(), + SubType.BAT.getPredicate(), + SubType.BEAR.getPredicate(), + SubType.BIRD.getPredicate(), + SubType.CAT.getPredicate(), + SubType.DOG.getPredicate(), + SubType.FROG.getPredicate(), + SubType.JACKAL.getPredicate(), + SubType.LIZARD.getPredicate(), + SubType.MOUSE.getPredicate(), + SubType.OTTER.getPredicate(), + SubType.RABBIT.getPredicate(), + SubType.RACCOON.getPredicate(), + SubType.RAT.getPredicate(), + SubType.SQUIRREL.getPredicate(), + SubType.TURTLE.getPredicate(), + SubType.WOLF.getPredicate() + )); + } + + public SpiderHamPeterPorker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.BOAR); + this.subtype.add(SubType.HERO); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Spider-Ham enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // Animal May-Ham -- Other Spiders, Boars, Bats, Bears, Birds, Cats, Dogs, Frogs, Jackals, Lizards, Mice, Otters, Rabbits, Raccoons, Rats, Squirrels, Turtles, and Wolves you control get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + )).withFlavorWord("Animal May-Ham")); + } + + private SpiderHamPeterPorker(final SpiderHamPeterPorker card) { + super(card); + } + + @Override + public SpiderHamPeterPorker copy() { + return new SpiderHamPeterPorker(this); + } +} +// it CAN get weirder! diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 4c7aab68d07..5e72a6638d5 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -45,6 +45,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); 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("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.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)); From 6ae6b2593ae4c50f01f1776c1ba69b985350dfd4 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:13:12 -0400 Subject: [PATCH 55/66] [SPM] Implement Spider-Rex, Daring Dino --- .../src/mage/cards/s/SpiderRexDaringDino.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderRexDaringDino.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderRexDaringDino.java b/Mage.Sets/src/mage/cards/s/SpiderRexDaringDino.java new file mode 100644 index 00000000000..4c2c2a5d034 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderRexDaringDino.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderRexDaringDino extends CardImpl { + + public SpiderRexDaringDino(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.DINOSAUR); + this.subtype.add(SubType.HERO); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + } + + private SpiderRexDaringDino(final SpiderRexDaringDino card) { + super(card); + } + + @Override + public SpiderRexDaringDino copy() { + return new SpiderRexDaringDino(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 5e72a6638d5..8ab4acc12ca 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -46,6 +46,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-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("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)); From 189f187ee9da8d11bd0a68319143a6dcf3b622b5 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:19:05 -0400 Subject: [PATCH 56/66] [SPM] Implement Eerie Gravestone --- .../src/mage/cards/e/EerieGravestone.java | 44 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EerieGravestone.java diff --git a/Mage.Sets/src/mage/cards/e/EerieGravestone.java b/Mage.Sets/src/mage/cards/e/EerieGravestone.java new file mode 100644 index 00000000000..e30d9e2b4bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EerieGravestone.java @@ -0,0 +1,44 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.MillThenPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EerieGravestone extends CardImpl { + + public EerieGravestone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // When this artifact enters, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // {1}{B}, Sacrifice this artifact: Mill four cards. You may put a creature card from among them into your hand. + Ability ability = new SimpleActivatedAbility( + new MillThenPutInHandEffect(4, StaticFilters.FILTER_CARD_CREATURE), new ManaCostsImpl<>("{1}{B}") + ); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private EerieGravestone(final EerieGravestone card) { + super(card); + } + + @Override + public EerieGravestone copy() { + return new EerieGravestone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 8ab4acc12ca..25a6f1314f0 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -23,6 +23,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.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("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("Guy in the Chair", 102, Rarity.COMMON, mage.cards.g.GuyInTheChair.class)); From 891247d3b931ba29f5706a765c44a91c4ed50b90 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:20:04 -0400 Subject: [PATCH 57/66] [SPM] Implement Spider-Bot --- Mage.Sets/src/mage/cards/s/SpiderBot.java | 47 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderBot.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderBot.java b/Mage.Sets/src/mage/cards/s/SpiderBot.java new file mode 100644 index 00000000000..fb9a2fb8a86 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderBot.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderBot extends CardImpl { + + public SpiderBot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.ROBOT); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When this creature enters, you may search your library for a basic land card, reveal it, then shuffle and put that card on top. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ), true)); + } + + private SpiderBot(final SpiderBot card) { + super(card); + } + + @Override + public SpiderBot copy() { + return new SpiderBot(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 25a6f1314f0..4388cb041d1 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -44,6 +44,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); + cards.add(new SetCardInfo("Spider-Bot", 173, Rarity.COMMON, mage.cards.s.SpiderBot.class)); 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)); From 53584410f670d1a285f4ba549c2c324e2905bc2a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:22:59 -0400 Subject: [PATCH 58/66] [SPM] Implement Thwip! --- Mage.Sets/src/mage/cards/t/Thwip.java | 79 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 80 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/Thwip.java diff --git a/Mage.Sets/src/mage/cards/t/Thwip.java b/Mage.Sets/src/mage/cards/t/Thwip.java new file mode 100644 index 00000000000..1fd4404e6ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Thwip.java @@ -0,0 +1,79 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Thwip extends CardImpl { + + public Thwip(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Target creature gets +2/+2 and gains flying until end of turn. If it's a Spider, you gain 2 life. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 2, Duration.EndOfTurn + ).setText("Target creature gets +2/+2")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); + this.getSpellAbility().addEffect(new ThwipEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Thwip(final Thwip card) { + super(card); + } + + @Override + public Thwip copy() { + return new Thwip(this); + } +} + +class ThwipEffect extends OneShotEffect { + + ThwipEffect() { + super(Outcome.Benefit); + staticText = "If it's a Spider, you gain 2 life"; + } + + private ThwipEffect(final ThwipEffect effect) { + super(effect); + } + + @Override + public ThwipEffect copy() { + return new ThwipEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null + && permanent.hasSubtype(SubType.SPIDER, game) + && Optional + .ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .filter(player -> player.gainLife(2, game, source) > 0) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 4388cb041d1..0b0e244158a 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -52,6 +52,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.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)); cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.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)); From 56aa97cc0fcbcef5923d61358397f4be000d50ab Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:26:12 -0400 Subject: [PATCH 59/66] [SPM] Implement Romantic Rendezvous --- .../src/mage/cards/r/RomanticRendezvous.java | 32 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 33 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RomanticRendezvous.java diff --git a/Mage.Sets/src/mage/cards/r/RomanticRendezvous.java b/Mage.Sets/src/mage/cards/r/RomanticRendezvous.java new file mode 100644 index 00000000000..57feb99476d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RomanticRendezvous.java @@ -0,0 +1,32 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RomanticRendezvous extends CardImpl { + + public RomanticRendezvous(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Discard a card, then draw two cards. + this.getSpellAbility().addEffect(new DiscardControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then")); + } + + private RomanticRendezvous(final RomanticRendezvous card) { + super(card); + } + + @Override + public RomanticRendezvous copy() { + return new RomanticRendezvous(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 0b0e244158a..4c87f97992f 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -38,6 +38,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); + cards.add(new SetCardInfo("Romantic Rendezvous", 86, Rarity.COMMON, mage.cards.r.RomanticRendezvous.class)); cards.add(new SetCardInfo("Scorpion's Sting", 65, Rarity.COMMON, mage.cards.s.ScorpionsSting.class)); cards.add(new SetCardInfo("Scorpion, Seething Striker", 64, Rarity.UNCOMMON, mage.cards.s.ScorpionSeethingStriker.class)); cards.add(new SetCardInfo("Scout the City", 113, Rarity.COMMON, mage.cards.s.ScoutTheCity.class)); From a0207f3d676f86b68c71fb3fbd103522e2736129 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:27:43 -0400 Subject: [PATCH 60/66] [SPM] Implement Venom's Hunger --- Mage.Sets/src/mage/cards/v/VenomsHunger.java | 50 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 51 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VenomsHunger.java diff --git a/Mage.Sets/src/mage/cards/v/VenomsHunger.java b/Mage.Sets/src/mage/cards/v/VenomsHunger.java new file mode 100644 index 00000000000..dd4c84eeb3a --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomsHunger.java @@ -0,0 +1,50 @@ +package mage.cards.v; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +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.common.FilterControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenomsHunger extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.VILLAIN, "you control a Villain") + ); + + public VenomsHunger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // This spell costs {2} less to cast if you control a Villain. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Destroy target creature. You gain 2 life. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private VenomsHunger(final VenomsHunger card) { + super(card); + } + + @Override + public VenomsHunger copy() { + return new VenomsHunger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 4c87f97992f..48f7be2237b 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("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("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.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)); } From 75b553fe72e3d2b7594404e7760ca2723e4a1f4b Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:30:21 -0400 Subject: [PATCH 61/66] [SPM] Implement Beetle, Legacy Criminal --- .../mage/cards/b/BeetleLegacyCriminal.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java diff --git a/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java b/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java new file mode 100644 index 00000000000..fdb86fd1b9f --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BeetleLegacyCriminal.java @@ -0,0 +1,59 @@ +package mage.cards.b; + +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.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BeetleLegacyCriminal extends CardImpl { + + public BeetleLegacyCriminal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}{U}, Exile this card from your graveyard: Put a +1/+1 counter on target creature. It gains flying until end of turn. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.GRAVEYARD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{1}{U}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + ability.addTarget(new TargetCreaturePermanent()); + ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()) + .setText("Put a +1/+1 counter on target creature")); + this.addAbility(ability); + } + + private BeetleLegacyCriminal(final BeetleLegacyCriminal card) { + super(card); + } + + @Override + public BeetleLegacyCriminal copy() { + return new BeetleLegacyCriminal(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 48f7be2237b..70360520c47 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -21,6 +21,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { this.hasBasicLands = true; cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); + 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("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class)); From a5e97960104fb6ac9f084f4b4c255ed51ab6e13f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:38:12 -0400 Subject: [PATCH 62/66] [SPM] Implement Angry Rabble --- Mage.Sets/src/mage/cards/a/AngryRabble.java | 56 +++++++++++++++++++ .../src/mage/cards/a/AscendantPackleader.java | 15 ++--- .../src/mage/cards/d/DisdainfulStroke.java | 19 ++----- .../src/mage/cards/e/EtheriumSpinner.java | 13 +---- .../src/mage/cards/l/LurkingLizards.java | 13 +---- Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../SpellCastControllerTriggeredAbility.java | 3 +- .../main/java/mage/filter/StaticFilters.java | 7 +++ 8 files changed, 83 insertions(+), 44 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AngryRabble.java diff --git a/Mage.Sets/src/mage/cards/a/AngryRabble.java b/Mage.Sets/src/mage/cards/a/AngryRabble.java new file mode 100644 index 00000000000..2bf05366df9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngryRabble.java @@ -0,0 +1,56 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngryRabble extends CardImpl { + + public AngryRabble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever you cast a spell with mana value 4 or greater, this creature deals 1 damage to each opponent. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), + StaticFilters.FILTER_SPELL_MV_4_OR_GREATER, false + )); + + // {5}{R}: Put two +1/+1 counters on this creature. Activate only as a sorcery. + this.addAbility(new ActivateAsSorceryActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ManaCostsImpl<>("{5}{R}") + )); + } + + private AngryRabble(final AngryRabble card) { + super(card); + } + + @Override + public AngryRabble copy() { + return new AngryRabble(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AscendantPackleader.java b/Mage.Sets/src/mage/cards/a/AscendantPackleader.java index 21d87ecc1c0..f4c58b1ad3f 100644 --- a/Mage.Sets/src/mage/cards/a/AscendantPackleader.java +++ b/Mage.Sets/src/mage/cards/a/AscendantPackleader.java @@ -1,33 +1,31 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.ComparisonType; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.FilterSpell; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.ManaValuePredicate; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class AscendantPackleader extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("a permanent with mana value 4 or greater"); - private static final FilterSpell filter2 = new FilterSpell("a spell with mana value 4 or greater"); static { filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); - filter2.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); } public AscendantPackleader(UUID ownerId, CardSetInfo setInfo) { @@ -48,8 +46,7 @@ public final class AscendantPackleader extends CardImpl { // Whenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on Ascendant Packleader. this.addAbility(new SpellCastControllerTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - filter2, - false + StaticFilters.FILTER_SPELL_MV_4_OR_GREATER, false )); } diff --git a/Mage.Sets/src/mage/cards/d/DisdainfulStroke.java b/Mage.Sets/src/mage/cards/d/DisdainfulStroke.java index c89c82ed6c5..d5b3f9d34b2 100644 --- a/Mage.Sets/src/mage/cards/d/DisdainfulStroke.java +++ b/Mage.Sets/src/mage/cards/d/DisdainfulStroke.java @@ -1,34 +1,25 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.StaticFilters; import mage.target.TargetSpell; +import java.util.UUID; + /** - * * @author emerald000 */ public final class DisdainfulStroke extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("spell with mana value 4 or greater"); - static { - filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); - } public DisdainfulStroke(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Counter target spell with converted mana cost 4 or greater. this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetSpell(filter)); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_MV_4_OR_GREATER)); } private DisdainfulStroke(final DisdainfulStroke card) { diff --git a/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java b/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java index ab7e8e32652..76047553b65 100644 --- a/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java +++ b/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java @@ -6,10 +6,8 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.StaticFilters; import mage.game.permanent.token.ThopterColorlessToken; import java.util.UUID; @@ -19,12 +17,6 @@ import java.util.UUID; */ public final class EtheriumSpinner extends CardImpl { - private static final FilterSpell filter = new FilterSpell("a spell with mana value 4 or greater"); - - static { - filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); - } - public EtheriumSpinner(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}"); @@ -35,7 +27,8 @@ public final class EtheriumSpinner extends CardImpl { // Whenever you cast a spell with mana value 4 or greater, create a 1/1 colorless Thopter artifact creature token with flying. this.addAbility(new SpellCastControllerTriggeredAbility( - new CreateTokenEffect(new ThopterColorlessToken()), filter, false + new CreateTokenEffect(new ThopterColorlessToken()), + StaticFilters.FILTER_SPELL_MV_4_OR_GREATER, false )); } diff --git a/Mage.Sets/src/mage/cards/l/LurkingLizards.java b/Mage.Sets/src/mage/cards/l/LurkingLizards.java index d519cae84ef..e38cdfde6f8 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingLizards.java +++ b/Mage.Sets/src/mage/cards/l/LurkingLizards.java @@ -7,11 +7,9 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.StaticFilters; import java.util.UUID; @@ -20,12 +18,6 @@ import java.util.UUID; */ public final class LurkingLizards extends CardImpl { - private static final FilterSpell filter = new FilterSpell("a spell with mana value 4 or greater"); - - static { - filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); - } - public LurkingLizards(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -39,7 +31,8 @@ public final class LurkingLizards extends CardImpl { // Whenever you cast a spell with mana value 4 or greater, put a +1/+1 counter on this creature. this.addAbility(new SpellCastControllerTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, false + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_SPELL_MV_4_OR_GREATER, false )); } diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 70360520c47..7bf740b4f64 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -20,6 +20,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { this.blockName = "Marvel's Spider-Man"; // for sorting in GUI this.hasBasicLands = true; + cards.add(new SetCardInfo("Angry Rabble", 75, Rarity.COMMON, mage.cards.a.AngryRabble.class)); cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); 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)); diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java index db019d5d7b4..d3008b2085a 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java @@ -10,6 +10,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * @author North, Susucr @@ -103,7 +104,7 @@ public class SpellCastControllerTriggeredAbility extends TriggeredAbilityImpl { } private void makeTriggerPhrase() { - String text = getWhen() + "you cast " + filter.getMessage(); + String text = getWhen() + "you cast " + CardUtil.addArticle(filter.getMessage()); switch (fromZone) { case ALL: diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 0a5b6fdf79a..05e18a8be30 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -1093,6 +1093,13 @@ public final class StaticFilters { FILTER_SPELL_KICKED_A.setLockedFilter(true); } + public static final FilterSpell FILTER_SPELL_MV_4_OR_GREATER = new FilterSpell("spell with mana value 4 or greater"); + + static { + FILTER_SPELL_MV_4_OR_GREATER.add(new ManaValuePredicate(ComparisonType.OR_GREATER, 4)); + FILTER_SPELL_MV_4_OR_GREATER.setLockedFilter(true); + } + public static final FilterSpell FILTER_SPELL_NO_MANA_SPENT = new FilterSpell("a spell, if no mana was spent to cast it"); static { From a4d90bae0fc78036733475d51b8daa9f839db489 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:47:46 -0400 Subject: [PATCH 63/66] [SPM] Implement Spider-Man, Web Slinger --- .../src/mage/cards/s/SpiderManWebSlinger.java | 40 +++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../abilities/keyword/WebSlingingAbility.java | 72 +++++++++++++++++++ Utils/keywords.txt | 1 + 4 files changed, 114 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderManWebSlinger.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderManWebSlinger.java b/Mage.Sets/src/mage/cards/s/SpiderManWebSlinger.java new file mode 100644 index 00000000000..d4af2a9f821 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderManWebSlinger.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.WebSlingingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderManWebSlinger extends CardImpl { + + public SpiderManWebSlinger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Web-slinging {W} + this.addAbility(new WebSlingingAbility(this, "{W}")); + } + + private SpiderManWebSlinger(final SpiderManWebSlinger card) { + super(card); + } + + @Override + public SpiderManWebSlinger copy() { + return new SpiderManWebSlinger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 7bf740b4f64..e75a51b1f82 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -51,6 +51,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, 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("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java b/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java new file mode 100644 index 00000000000..4faa0001a6e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/WebSlingingAbility.java @@ -0,0 +1,72 @@ +package mage.abilities.keyword; + +import mage.MageIdentifier; +import mage.abilities.SpellAbility; +import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; + +import java.util.Set; + +/** + * @author LevelX2 + */ +public class WebSlingingAbility extends SpellAbility { + + public static final String WEB_SLINGING_ACTIVATION_VALUE_KEY = "webSlingingActivation"; + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("tapped creature you control"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + public WebSlingingAbility(Card card, String manaString) { + super(card.getSpellAbility()); + this.newId(); + this.setCardName(card.getName() + " with Web-slinging"); + zone = Zone.HAND; + spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + + this.clearManaCosts(); + this.clearManaCostsToPay(); + this.addCost(new ManaCostsImpl<>(manaString)); + this.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))); + + this.setRuleAtTheTop(true); + } + + protected WebSlingingAbility(final WebSlingingAbility ability) { + super(ability); + } + + @Override + public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { + if (!super.activate(game, allowedIdentifiers, noMana)) { + return false; + } + this.setCostsTag(WEB_SLINGING_ACTIVATION_VALUE_KEY, null); + return true; + } + + @Override + public WebSlingingAbility copy() { + return new WebSlingingAbility(this); + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("Web-slinging "); + sb.append(getManaCosts().getText()); + sb.append(" (You may cast this spell for "); + sb.append(getManaCosts().getText()); + sb.append(" if you also return a tapped creature you control to its owner's hand.)"); + return sb.toString(); + } +} diff --git a/Utils/keywords.txt b/Utils/keywords.txt index 5dd4945cf5d..f23982f5082 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -149,4 +149,5 @@ Vanishing|number| Vigilance|instance| Ward|cost| Warp|card, manaString| +Web-slinging|card, manaString| Wither|instance| From 856e5353cbfee06232e4c2f14614f29f32aa1fb8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:49:33 -0400 Subject: [PATCH 64/66] [SPM] Implement Shocker, Unshakable --- .../src/mage/cards/s/ShockerUnshakable.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/ShockerUnshakable.java diff --git a/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java b/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java new file mode 100644 index 00000000000..661ecfe7032 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShockerUnshakable extends CardImpl { + + public ShockerUnshakable(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // During your turn, Shocker has first strike. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield), + MyTurnCondition.instance, "During your turn, {this} has first strike." + ))); + + // Vibro-Shock Gauntlets -- When Shocker enters, he deals 2 damage to target creature and 2 damage to that creature's controller. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "he")); + ability.addEffect(new DamageTargetControllerEffect(2).setText("and 2 damage to that creature's controller")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability.withFlavorWord("Vibro-Shock Gauntlets")); + } + + private ShockerUnshakable(final ShockerUnshakable card) { + super(card); + } + + @Override + public ShockerUnshakable copy() { + return new ShockerUnshakable(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index e75a51b1f82..07a6722940a 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -46,6 +46,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Scout the City", 113, Rarity.COMMON, mage.cards.s.ScoutTheCity.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Shocker, Unshakable", 89, Rarity.UNCOMMON, mage.cards.s.ShockerUnshakable.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); cards.add(new SetCardInfo("Spider-Bot", 173, Rarity.COMMON, mage.cards.s.SpiderBot.class)); cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class)); From 175efbf4036c0f9f025e1c1d0cd3238b9a4194ce Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:50:41 -0400 Subject: [PATCH 65/66] [SPM] Implement Spider-Man, Brooklyn Visionary --- .../cards/s/SpiderManBrooklynVisionary.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SpiderManBrooklynVisionary.java diff --git a/Mage.Sets/src/mage/cards/s/SpiderManBrooklynVisionary.java b/Mage.Sets/src/mage/cards/s/SpiderManBrooklynVisionary.java new file mode 100644 index 00000000000..69b9656b79f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiderManBrooklynVisionary.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.keyword.WebSlingingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiderManBrooklynVisionary extends CardImpl { + + public SpiderManBrooklynVisionary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + 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(3); + + // Web-slinging {2}{G} + this.addAbility(new WebSlingingAbility(this, "{2}{G}")); + + // When Spider-Man enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ))); + } + + private SpiderManBrooklynVisionary(final SpiderManBrooklynVisionary card) { + super(card); + } + + @Override + public SpiderManBrooklynVisionary copy() { + return new SpiderManBrooklynVisionary(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 07a6722940a..1d021809fcc 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -52,6 +52,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, 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)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); From ecdd531003ee0d6bf2e35be5e07f96f0dd501c92 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:52:35 -0400 Subject: [PATCH 66/66] [SPM] Implement Wild Pack Squad --- Mage.Sets/src/mage/cards/w/WildPackSquad.java | 47 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WildPackSquad.java diff --git a/Mage.Sets/src/mage/cards/w/WildPackSquad.java b/Mage.Sets/src/mage/cards/w/WildPackSquad.java new file mode 100644 index 00000000000..80775c0dc5f --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildPackSquad.java @@ -0,0 +1,47 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildPackSquad extends CardImpl { + + public WildPackSquad(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, up to one target creature gains first strike and vigilance until end of turn. + Ability ability = new BeginningOfCombatTriggeredAbility(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()) + .setText("up to one target creature gains first strike")); + ability.addEffect(new GainAbilityTargetEffect(VigilanceAbility.getInstance()) + .setText("and vigilance until end of turn")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + } + + private WildPackSquad(final WildPackSquad card) { + super(card); + } + + @Override + public WildPackSquad copy() { + return new WildPackSquad(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 1d021809fcc..d172015f4ba 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -63,5 +63,6 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.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)); } }