forked from External/mage
[SPM] Implement Spider-Punk
This commit is contained in:
parent
642362e99d
commit
8e0a222f9b
3 changed files with 251 additions and 0 deletions
157
Mage.Sets/src/mage/cards/s/SpiderPunk.java
Normal file
157
Mage.Sets/src/mage/cards/s/SpiderPunk.java
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
|
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||||
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
|
import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||||
|
import mage.abilities.keyword.HasteAbility;
|
||||||
|
import mage.abilities.keyword.RiotAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.EntersTheBattlefieldEvent;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentToken;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.game.stack.StackAbility;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Jmlundeen
|
||||||
|
*/
|
||||||
|
public final class SpiderPunk extends CardImpl {
|
||||||
|
|
||||||
|
static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SPIDER, "Spiders you control");
|
||||||
|
|
||||||
|
public SpiderPunk(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{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(1);
|
||||||
|
|
||||||
|
// Riot
|
||||||
|
this.addAbility(new RiotAbility());
|
||||||
|
|
||||||
|
// Other Spiders you control have riot.
|
||||||
|
Ability ability = new SimpleStaticAbility(new SpiderPunkRiotETBEffect());
|
||||||
|
ability.addEffect(new GainAbilityControlledEffect(new RiotAbility(), Duration.WhileOnBattlefield, filter, true)
|
||||||
|
.setText(""));
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// Spells and abilities can't be countered.
|
||||||
|
this.addAbility(new SimpleStaticAbility(new SpiderPunkCantCounterEffect()));
|
||||||
|
|
||||||
|
// Damage can't be prevented.
|
||||||
|
this.addAbility(new SimpleStaticAbility(new DamageCantBePreventedEffect(Duration.WhileOnBattlefield)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpiderPunk(final SpiderPunk card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpiderPunk copy() {
|
||||||
|
return new SpiderPunk(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpiderPunkCantCounterEffect extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
SpiderPunkCantCounterEffect() {
|
||||||
|
super(Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||||
|
staticText = "Spells and abilities can't be countered";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SpiderPunkCantCounterEffect(final SpiderPunkCantCounterEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpiderPunkCantCounterEffect copy() {
|
||||||
|
return new SpiderPunkCantCounterEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.COUNTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
Object object = game.getObject(event.getTargetId());
|
||||||
|
return object instanceof Spell || object instanceof StackAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Remove after fixing continuous effects working on entering permanents
|
||||||
|
class SpiderPunkRiotETBEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
|
SpiderPunkRiotETBEffect() {
|
||||||
|
super(Duration.WhileOnBattlefield, Outcome.BoostCreature);
|
||||||
|
staticText = "Other Spiders you control have riot";
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpiderPunkRiotETBEffect(SpiderPunkRiotETBEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||||
|
return creature != null
|
||||||
|
&& creature.getId() != source.getSourceId()
|
||||||
|
&& creature.isControlledBy(source.getControllerId())
|
||||||
|
&& creature.isCreature(game)
|
||||||
|
&& !(creature instanceof PermanentToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
|
Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||||
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
|
if (creature == null || player == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (player.chooseUse(
|
||||||
|
outcome, "Have " + creature.getLogName() + " enter the battlefield with a +1/+1 counter on it or with haste?",
|
||||||
|
null, "+1/+1 counter", "Haste", source, game
|
||||||
|
)) {
|
||||||
|
game.informPlayers(player.getLogName() + " choose to put a +1/+1 counter on " + creature.getName());
|
||||||
|
creature.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game, event.getAppliedEffects());
|
||||||
|
} else {
|
||||||
|
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom);
|
||||||
|
effect.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game) + 1));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpiderPunkRiotETBEffect copy() {
|
||||||
|
return new SpiderPunkRiotETBEffect(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -109,6 +109,9 @@ public final class MarvelsSpiderMan extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Spider-Man, Brooklyn Visionary", 115, Rarity.COMMON, mage.cards.s.SpiderManBrooklynVisionary.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-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class));
|
||||||
|
cards.add(new SetCardInfo("Spider-Punk", 207, Rarity.RARE, mage.cards.s.SpiderPunk.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Spider-Punk", 210, Rarity.RARE, mage.cards.s.SpiderPunk.class, NON_FULL_USE_VARIOUS));
|
||||||
|
cards.add(new SetCardInfo("Spider-Punk", 92, Rarity.RARE, mage.cards.s.SpiderPunk.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.class));
|
cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.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("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class));
|
cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package org.mage.test.cards.single.spm;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
|
import mage.abilities.keyword.RiotAbility;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.target.TargetPlayer;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Jmlundeen
|
||||||
|
*/
|
||||||
|
public class SpiderPunkTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Spider-Punk
|
||||||
|
{1}{R}
|
||||||
|
Legendary Creature - Spider Human Hero
|
||||||
|
Riot
|
||||||
|
Other Spiders you control have riot.
|
||||||
|
Spells and abilities can't be countered.
|
||||||
|
Damage can't be prevented.
|
||||||
|
2/1
|
||||||
|
*/
|
||||||
|
private static final String spiderPunk = "Spider-Punk";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Counterspell
|
||||||
|
{U}{U}
|
||||||
|
Instant
|
||||||
|
Counter target spell.
|
||||||
|
*/
|
||||||
|
private static final String counterspell = "Counterspell";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Disallow
|
||||||
|
{1}{U}{U}
|
||||||
|
Instant
|
||||||
|
Counter target spell, activated ability, or triggered ability.
|
||||||
|
*/
|
||||||
|
private static final String disallow = "Disallow";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Giant Spider
|
||||||
|
{3}{G}
|
||||||
|
Creature - Spider
|
||||||
|
Reach <i>(This creature can block creatures with flying.)</i>
|
||||||
|
2/4
|
||||||
|
*/
|
||||||
|
private static final String giantSpider = "Giant Spider";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSpiderPunk() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost());
|
||||||
|
ability.addTarget(new TargetPlayer(1));
|
||||||
|
addCustomCardWithAbility("{T} deal damage", playerA, ability);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, spiderPunk);
|
||||||
|
setChoice(playerA, "No"); // Haste - Spider-Punk
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Island", 5);
|
||||||
|
addCard(Zone.HAND, playerA, giantSpider);
|
||||||
|
addCard(Zone.HAND, playerB, counterspell);
|
||||||
|
addCard(Zone.HAND, playerB, disallow);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, giantSpider);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, counterspell, giantSpider);
|
||||||
|
|
||||||
|
setChoice(playerA, "No"); // Haste
|
||||||
|
|
||||||
|
attack(1, playerA, giantSpider);
|
||||||
|
attack(1, playerA, spiderPunk);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: {this} deals 2 damage", playerB);
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, disallow);
|
||||||
|
addTarget(playerB, "stack ability");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertLife(playerB, 20 - 2 - 2 - 2);
|
||||||
|
assertAbilityCount(playerA, giantSpider, RiotAbility.class, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue