[SPM] implement Spider-Verse

This commit is contained in:
jmlundeen 2025-09-05 12:40:38 -05:00
parent 32282a42b7
commit 2f15477214
3 changed files with 196 additions and 0 deletions

View file

@ -0,0 +1,113 @@
package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ruleModifying.LegendRuleDoesntApplyEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.CastFromZonePredicate;
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.util.functions.StackObjectCopyApplier;
import java.util.UUID;
/**
*
* @author Jmlundeen
*/
public final class SpiderVerse extends CardImpl {
private static final FilterControlledCreaturePermanent creatureFilter = new FilterControlledCreaturePermanent("Spiders you control");
private static final FilterSpell spellFilter = new FilterSpell("a spell from anywhere other than your hand");
static {
creatureFilter.add(SubType.SPIDER.getPredicate());
spellFilter.add(Predicates.not(new CastFromZonePredicate(Zone.HAND)));
}
public SpiderVerse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}");
// The "legend rule" doesn't apply to Spiders you control.
this.addAbility(new SimpleStaticAbility(new LegendRuleDoesntApplyEffect(creatureFilter)));
// Whenever you cast a spell from anywhere other than your hand, you may copy it. If you do, you may choose new targets for the copy. If the copy is a permanent spell, it gains haste. Do this only once each turn.
this.addAbility(new SpellCastControllerTriggeredAbility(
new SpiderVerseEffect(),
true
).setDoOnlyOnceEachTurn(true)
);
}
private SpiderVerse(final SpiderVerse card) {
super(card);
}
@Override
public SpiderVerse copy() {
return new SpiderVerse(this);
}
}
class SpiderVerseEffect extends OneShotEffect {
SpiderVerseEffect() {
super(Outcome.Benefit);
staticText = "copy it. If you do, you may choose new targets for the copy. " +
"If the copy is a permanent spell, it gains haste";
}
protected SpiderVerseEffect(final SpiderVerseEffect effect) {
super(effect);
}
@Override
public SpiderVerseEffect copy() {
return new SpiderVerseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = (Spell) getValue("spellCast");
if (spell == null) {
return false;
}
spell.createCopyOnStack(
game, source, source.getControllerId(), true,
1, SpiderVerseCopyApplier.instance);
return true;
}
}
enum SpiderVerseCopyApplier implements StackObjectCopyApplier {
instance;
@Override
public void modifySpell(StackObject stackObject, Game game) {
if (!stackObject.isPermanent(game)) {
return;
}
Spell spell = (Spell) stackObject;
spell.addAbilityForCopy(HasteAbility.getInstance());
}
@Override
public MageObjectReferencePredicate getNextNewTargetType() {
return null;
}
}

View file

@ -244,6 +244,8 @@ public final class MarvelsSpiderMan extends ExpansionSet {
cards.add(new SetCardInfo("Spider-Slayer, Hatred Honed", 175, Rarity.UNCOMMON, mage.cards.s.SpiderSlayerHatredHoned.class)); cards.add(new SetCardInfo("Spider-Slayer, Hatred Honed", 175, Rarity.UNCOMMON, mage.cards.s.SpiderSlayerHatredHoned.class));
cards.add(new SetCardInfo("Spider-Suit", 176, Rarity.UNCOMMON, mage.cards.s.SpiderSuit.class)); cards.add(new SetCardInfo("Spider-Suit", 176, Rarity.UNCOMMON, mage.cards.s.SpiderSuit.class));
cards.add(new SetCardInfo("Spider-UK", 17, Rarity.UNCOMMON, mage.cards.s.SpiderUK.class)); cards.add(new SetCardInfo("Spider-UK", 17, Rarity.UNCOMMON, mage.cards.s.SpiderUK.class));
cards.add(new SetCardInfo("Spider-Verse", 263, Rarity.MYTHIC, mage.cards.s.SpiderVerse.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Verse", 93, Rarity.MYTHIC, mage.cards.s.SpiderVerse.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 152, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 152, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 230, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 230, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spiders-Man, Heroic Horde", 117, Rarity.UNCOMMON, mage.cards.s.SpidersManHeroicHorde.class)); cards.add(new SetCardInfo("Spiders-Man, Heroic Horde", 117, Rarity.UNCOMMON, mage.cards.s.SpidersManHeroicHorde.class));

View file

@ -0,0 +1,81 @@
package org.mage.test.cards.single.spm;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommander4Players;
/**
*
* @author Jmlundeen
*/
public class SpiderVerseTest extends CardTestCommander4Players {
/*
Spider-Verse
{3}{R}{R}
Enchantment
The "legend rule" doesn't apply to Spiders you control.
Whenever you cast a spell from anywhere other than your hand, you may copy it. If you do, you may choose new targets for the copy. If the copy is a permanent spell, it gains haste. Do this only once each turn.
*/
private static final String spiderVerse = "Spider-Verse";
/*
Lightning Bolt
{R}
Instant
Lightning Bolt deals 3 damage to any target.
*/
private static final String lightningBolt = "Lightning Bolt";
/*
Bear Cub
{1}{G}
Creature - Bear
2/2
*/
private static final String bearCub = "Bear Cub";
/*
Ashiok, Nightmare Muse
{3}{U}{B}
Legendary Planeswalker - Ashiok
+1: Create a 2/3 blue and black Nightmare creature token with "Whenever this creature attacks or blocks, each opponent exiles the top two cards of their library."
-3: Return target nonland permanent to its owner's hand, then that player exiles a card from their hand.
-7: You may cast up to three face-up cards your opponents own from exile without paying their mana costs.
*/
private static final String ashiokNightmareMuse = "Ashiok, Nightmare Muse";
@Test
public void testSpiderVerse() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, spiderVerse);
addCard(Zone.BATTLEFIELD, playerA, ashiokNightmareMuse);
addCard(Zone.EXILED, playerB, lightningBolt);
addCard(Zone.EXILED, playerB, bearCub);
addCounters(1, PhaseStep.PRECOMBAT_MAIN, playerA, ashiokNightmareMuse, CounterType.LOYALTY, 9);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-7");
setChoice(playerA, lightningBolt);
setChoice(playerA, true);
addTarget(playerA, playerD);
setChoice(playerA, false, 2);
setChoice(playerA, true, 2); // use spider-verse / new target
addTarget(playerA, playerB);
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "-7");
setChoice(playerA, true, 2); // ashiok + spider-verse
attack(5, playerA, bearCub, playerC); // copy has haste
setStopAt(5, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 20 - 3);
assertLife(playerD, 20 - 3);
assertLife(playerC, 20 - 2);
}
}