From 7a20b14016650714566202bf1b06ffcda102a45f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:58:21 -0400 Subject: [PATCH 1/3] [SPM] Implement SP//dr, Piloted by Peni --- .../card/dl/sources/ScryfallApiCard.java | 2 +- .../dl/sources/WizardCardsImageSource.java | 2 +- .../src/mage/cards/s/SPDrPilotedByPeni.java | 65 +++++++++++++++++++ Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 1 + .../base/impl/CardTestPlayerAPIImpl.java | 2 +- 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallApiCard.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallApiCard.java index b07e82734eb..ecf061f8152 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallApiCard.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallApiCard.java @@ -97,7 +97,7 @@ public class ScryfallApiCard { // broken adventure/omen card (scryfall changed it for some reason) // Scavenger Regent // Exude Toxin // https://scryfall.com/card/tdm/90/scavenger-regent-exude-toxin - if (this.name.contains("//")) { + if (this.name.contains(" // ")) { throw new IllegalArgumentException("Scryfall: unsupported data type, broken reversible_card must have same simple name" + this.set + " - " + this.collector_number + " - " + this.name); } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index 0f294434a0b..1af4b98bf7a 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -640,7 +640,7 @@ public enum WizardCardsImageSource implements CardImageSource { private String normalizeName(String name) { //Split card - if (name.contains("//")) { + if (name.contains(" // ")) { if (name.indexOf('(') > 0) { name = name.substring(0, name.indexOf('(') - 1); } diff --git a/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java b/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java new file mode 100644 index 00000000000..02c2254a032 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java @@ -0,0 +1,65 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SPDrPilotedByPeni extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a modified creature you control"); + + static { + filter.add(ModifiedPredicate.instance); + } + + public SPDrPilotedByPeni(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.HERO); + + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When SP//dr enters, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + + // Whenever a modified creature you control deals combat damage to a player, draw a card. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, + false, SetTargetPointer.NONE, true + )); + } + + private SPDrPilotedByPeni(final SPDrPilotedByPeni card) { + super(card); + } + + @Override + public SPDrPilotedByPeni copy() { + return new SPDrPilotedByPeni(this); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index d172015f4ba..8ad64cef5c3 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -41,6 +41,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("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("SP//dr, Piloted by Peni", 147, Rarity.UNCOMMON, mage.cards.s.SPDrPilotedByPeni.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)); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 436daf44d55..e8b225e759e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -1471,7 +1471,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement cardName = EmptyNames.replaceTestCommandByObjectName(cardName); int actual; - if (cardName.contains("//")) { // special logic for checked split cards, because in game logic of card name filtering is different from in test + if (cardName.contains(" // ")) { // special logic for checked split cards, because in game logic of card name filtering is different from in test actual = 0; for (Card card : currentGame.getPlayer(player.getId()).getHand().getCards(currentGame)) { if (CardUtil.haveSameNames(card.getName(), cardName, true)) { From 5edbb550bc0b76f453b66e9e8562563de523327a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 24 Jul 2025 10:59:56 -0400 Subject: [PATCH 2/3] add missing code --- Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java b/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java index 02c2254a032..e21dd19f2f8 100644 --- a/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java +++ b/Mage.Sets/src/mage/cards/s/SPDrPilotedByPeni.java @@ -17,6 +17,7 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -46,6 +47,8 @@ public final class SPDrPilotedByPeni extends CardImpl { // When SP//dr enters, put a +1/+1 counter on target creature. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); // Whenever a modified creature you control deals combat damage to a player, draw a card. this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( From 5ba5c6557a9d762911e32176d3975725f4d8d887 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 5 Sep 2025 18:16:01 -0400 Subject: [PATCH 3/3] update versions --- Mage.Sets/src/mage/sets/MarvelsSpiderMan.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 1153a9d5739..5c6ad9766d7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -184,7 +184,8 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Rocket-Powered Goblin Glider", 172, Rarity.RARE, mage.cards.r.RocketPoweredGoblinGlider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rocket-Powered Goblin Glider", 281, Rarity.RARE, mage.cards.r.RocketPoweredGoblinGlider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Romantic Rendezvous", 86, Rarity.COMMON, mage.cards.r.RomanticRendezvous.class)); - cards.add(new SetCardInfo("SP//dr, Piloted by Peni", 147, Rarity.UNCOMMON, mage.cards.s.SPDrPilotedByPeni.class)); + cards.add(new SetCardInfo("SP//dr, Piloted by Peni", 147, Rarity.UNCOMMON, mage.cards.s.SPDrPilotedByPeni.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("SP//dr, Piloted by Peni", 199, Rarity.UNCOMMON, mage.cards.s.SPDrPilotedByPeni.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sandman's Quicksand", 63, Rarity.UNCOMMON, mage.cards.s.SandmansQuicksand.class)); cards.add(new SetCardInfo("Sandman, Shifting Scoundrel", 112, Rarity.RARE, mage.cards.s.SandmanShiftingScoundrel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sandman, Shifting Scoundrel", 266, Rarity.RARE, mage.cards.s.SandmanShiftingScoundrel.class, NON_FULL_USE_VARIOUS));