implement [MH3] Strix Serenade ; refactor similar effects with Pongify effect

Slight refactor for Serenade, Swan Song and An Offer You Can't Refuse to
use the shared class (formely for Permanents only) for Pongify kind of effects.
This commit is contained in:
Susucre 2024-05-23 19:47:06 +02:00
parent 381104bd92
commit e3e34dae33
27 changed files with 230 additions and 139 deletions

View file

@ -1,6 +1,6 @@
package mage.cards.a;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -11,7 +11,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author Backfir3
*/
public final class Afterlife extends CardImpl {
@ -23,7 +22,7 @@ public final class Afterlife extends CardImpl {
// 1/1 white Spirit creature token with flying.
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new DestroyTargetEffect(true));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new SpiritWhiteToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new SpiritWhiteToken()));
}
private Afterlife(final Afterlife card) {

View file

@ -1,15 +1,12 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.token.TreasureToken;
import mage.game.stack.Spell;
import mage.target.TargetSpell;
import java.util.UUID;
@ -23,7 +20,10 @@ public final class AnOfferYouCantRefuse extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Counter target noncreature spell. Its controller creates two Treasure tokens.
this.getSpellAbility().addEffect(new AnOfferYouCantRefuseEffect());
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(
new TreasureToken(), 2, false, CreateTokenControllerTargetEffect.TargetKind.SPELL
));
this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE));
}
@ -35,32 +35,4 @@ public final class AnOfferYouCantRefuse extends CardImpl {
public AnOfferYouCantRefuse copy() {
return new AnOfferYouCantRefuse(this);
}
}
class AnOfferYouCantRefuseEffect extends OneShotEffect {
AnOfferYouCantRefuseEffect() {
super(Outcome.Benefit);
staticText = "counter target noncreature spell. Its controller creates two Treasure tokens";
}
private AnOfferYouCantRefuseEffect(final AnOfferYouCantRefuseEffect effect) {
super(effect);
}
@Override
public AnOfferYouCantRefuseEffect copy() {
return new AnOfferYouCantRefuseEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getSpell(getTargetPointer().getFirst(game, source));
if (spell == null) {
return false;
}
game.getStack().counter(spell.getId(), source, game);;
new TreasureToken().putOntoBattlefield(2, game, source, spell.getControllerId());
return true;
}
}
}

View file

@ -1,6 +1,6 @@
package mage.cards.a;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -20,7 +20,7 @@ public final class AngelicAscension extends CardImpl {
// Exile target creature or planeswalker. Its controller creates a 4/4 white Angel creature token with flying.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new AngelToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new AngelToken()));
this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker());
}

View file

@ -1,6 +1,6 @@
package mage.cards.b;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -21,7 +21,7 @@ public final class BeastWithin extends CardImpl {
// Destroy target permanent. Its controller creates a 3/3 green Beast creature token.
this.getSpellAbility().addTarget(new TargetPermanent());
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new BeastToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new BeastToken()));
}
private BeastWithin(final BeastWithin card) {

View file

@ -1,6 +1,6 @@
package mage.cards.b;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -22,7 +22,7 @@ public final class BovineIntervention extends CardImpl {
// Destroy target artifact or creature. Its controller creates a 2/2 white Ox creature token.
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE));
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new Ox22Token()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new Ox22Token()));
}
private BovineIntervention(final BovineIntervention card) {

View file

@ -1,6 +1,6 @@
package mage.cards.b;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -20,7 +20,7 @@ public final class BuyYourSilence extends CardImpl {
// Exile target nonland permanent. Its controller creates a Treasure token.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new TreasureToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new TreasureToken()));
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
}

View file

@ -4,7 +4,7 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.abilities.keyword.VigilanceAbility;
@ -41,7 +41,7 @@ public final class CavalierOfDawn extends CardImpl {
// When Cavalier of Dawn enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.
Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect());
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new GolemToken()));
ability.addEffect(new CreateTokenControllerTargetEffect(new GolemToken()));
ability.addTarget(new TargetNonlandPermanent(0, 1, false));
this.addAbility(ability);

View file

@ -4,7 +4,7 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.UnearthAbility;
@ -21,7 +21,6 @@ import mage.target.common.TargetNonlandPermanent;
import java.util.UUID;
/**
*
* @author weirddan455
*/
public final class CityscapeLeveler extends CardImpl {
@ -38,7 +37,7 @@ public final class CityscapeLeveler extends CardImpl {
// When you cast this spell and whenever Cityscape Leveler attacks, destroy up to one target nonland permanent. Its controller creates a tapped Powerstone token.
Ability ability = new CityscapeLevelerAbility();
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new PowerstoneToken(), 1, true));
ability.addEffect(new CreateTokenControllerTargetEffect(new PowerstoneToken(), 1, true));
ability.addTarget(new TargetNonlandPermanent(0, 1));
this.addAbility(ability);

View file

@ -5,7 +5,7 @@ import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.constants.SubType;
import mage.constants.SuperType;
@ -43,7 +43,7 @@ public final class CommanderSofiaDaguerre extends CardImpl {
// Crash Landing -- When Commander Sofia Daguerre enters the battlefield,
// destroy up to one target legendary permanent. That permanent's controller creates a Junk token.
Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect());
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new JunkToken())
ability.addEffect(new CreateTokenControllerTargetEffect(new JunkToken())
.setText("that permanent's controller creates a Junk token"));
ability.addTarget(new TargetPermanent(0, 1, filter));
this.addAbility(ability.withFlavorWord("Crash Landing"));

View file

@ -1,7 +1,7 @@
package mage.cards.c;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.ChangelingAbility;
import mage.cards.CardImpl;
@ -14,7 +14,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class CribSwap extends CardImpl {
@ -27,7 +26,7 @@ public final class CribSwap extends CardImpl {
this.addAbility(new ChangelingAbility());
// Exile target creature. Its controller creates a 1/1 colorless Shapeshifter creature token with changeling.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new CribSwapShapeshifterWhiteToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new CribSwapShapeshifterWhiteToken()));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}

View file

@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -38,7 +38,7 @@ public final class GallowsAtWillowHill extends CardImpl {
// {3}, {tap}, Tap three untapped Humans you control: Destroy target creature. Its controller creates a 1/1 white Spirit creature token with flying.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new GenericManaCost(3));
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new SpiritWhiteToken()));
ability.addEffect(new CreateTokenControllerTargetEffect(new SpiritWhiteToken()));
ability.addCost(new TapSourceCost());
ability.addCost(new TapTargetCost(new TargetControlledPermanent(3, 3, humanFilter, false)));
ability.addTarget(new TargetCreaturePermanent());

View file

@ -1,6 +1,6 @@
package mage.cards.g;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -20,7 +20,7 @@ public final class GenerousGift extends CardImpl {
// Destroy target permanent. Its controller creates a 3/3 green Elephant creature token.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new ElephantToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new ElephantToken()));
this.getSpellAbility().addTarget(new TargetPermanent());
}

View file

@ -1,6 +1,6 @@
package mage.cards.g;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -32,7 +32,7 @@ public final class GetLost extends CardImpl {
// Destroy target creature, enchantment, or planeswalker. Its controller creates two Map tokens.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new MapToken(), 2, false));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new MapToken(), 2, false));
this.getSpellAbility().addTarget(new TargetPermanent(filter));
}

View file

@ -1,7 +1,7 @@
package mage.cards.p;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -12,7 +12,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author dustinconrad
*/
public final class Pongify extends CardImpl {
@ -22,7 +21,7 @@ public final class Pongify extends CardImpl {
// Destroy target creature. It can't be regenerated. That creature's controller creates a 3/3 green Ape creature token.
this.getSpellAbility().addEffect(new DestroyTargetEffect(true));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new ApeToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new ApeToken()));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}

View file

@ -1,6 +1,6 @@
package mage.cards.r;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.ForetellAbility;
import mage.cards.CardImpl;
@ -22,7 +22,7 @@ public final class Ravenform extends CardImpl {
// Exile target artifact or creature. Its controller creates a 1/1 blue Bird creature token with flying.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new BlueBirdToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new BlueBirdToken()));
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE));
// Foretell {U}

View file

@ -1,6 +1,6 @@
package mage.cards.r;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -23,7 +23,7 @@ public final class ReduceToMemory extends CardImpl {
// Exile target nonland permanent. Its controller creates a 3/2 red and white spirit creature token.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new Spirit32Token()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new Spirit32Token()));
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
}

View file

@ -1,6 +1,6 @@
package mage.cards.r;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -21,7 +21,7 @@ public final class Resculpt extends CardImpl {
// Exile target artifact or creature. Its controller creates a 4/4 blue and red Elemental creature token.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new Elemental44Token()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new Elemental44Token()));
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE));
}

View file

@ -5,7 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.common.MutatesSourceTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.CreateTokenTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.MutateAbility;
@ -52,7 +52,7 @@ public final class SawtuskDemolisher extends CardImpl {
// Whenever this creature mutates, destroy target noncreature permanent. Its controller creates a 3/3 green Beast creature token.
Ability ability = new MutatesSourceTriggeredAbility(new DestroyTargetEffect());
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new BeastToken()));
ability.addEffect(new CreateTokenControllerTargetEffect(new BeastToken()));
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
}

View file

@ -1,6 +1,6 @@
package mage.cards.s;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -20,7 +20,7 @@ public final class SecureTheScene extends CardImpl {
// Exile target nonland permanent. Its controller creates a 1/1 white Soldier creature token.
this.getSpellAbility().addEffect(new ExileTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new SoldierToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new SoldierToken()));
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
}

View file

@ -0,0 +1,49 @@
package mage.cards.s;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.game.permanent.token.SwanSongBirdToken;
import mage.target.TargetSpell;
import java.util.UUID;
/**
* @author Susucr
*/
public final class StrixSerenade extends CardImpl {
private static final FilterSpell filter = new FilterSpell("artifact, creature, or planeswalker spell");
static {
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate(),
CardType.PLANESWALKER.getPredicate()
));
}
public StrixSerenade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Counter target artifact, creature, or planeswalker spell. Its controller creates a 2/2 blue Bird creature token with flying.
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(
new SwanSongBirdToken(), CreateTokenControllerTargetEffect.TargetKind.SPELL
));
this.getSpellAbility().addTarget(new TargetSpell(filter));
}
private StrixSerenade(final StrixSerenade card) {
super(card);
}
@Override
public StrixSerenade copy() {
return new StrixSerenade(this);
}
}

View file

@ -1,6 +1,6 @@
package mage.cards.s;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -21,7 +21,7 @@ public final class StrokeOfMidnight extends CardImpl {
// Destroy target nonland permanent. Its controller creates a 1/1 white Human creature token.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetPermanentEffect(new HumanToken()));
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new HumanToken()));
this.getSpellAbility().addTarget(new TargetNonlandPermanent());
}

View file

@ -1,23 +1,19 @@
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.token.SwanSongBirdToken;
import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
import mage.target.TargetSpell;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class SwanSong extends CardImpl {
@ -25,16 +21,21 @@ public final class SwanSong extends CardImpl {
private static final FilterSpell filter = new FilterSpell("enchantment, instant, or sorcery spell");
static {
filter.add(Predicates.or(CardType.ENCHANTMENT.getPredicate(),
filter.add(Predicates.or(
CardType.ENCHANTMENT.getPredicate(),
CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate()));
CardType.SORCERY.getPredicate()
));
}
public SwanSong(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
// Counter target enchantment, instant or sorcery spell. Its controller creates a 2/2 blue Bird creature token with flying.
this.getSpellAbility().addEffect(new SwanSongEffect());
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(
new SwanSongBirdToken(), CreateTokenControllerTargetEffect.TargetKind.SPELL
));
this.getSpellAbility().addTarget(new TargetSpell(filter));
}
@ -46,37 +47,4 @@ public final class SwanSong extends CardImpl {
public SwanSong copy() {
return new SwanSong(this);
}
}
class SwanSongEffect extends OneShotEffect {
SwanSongEffect() {
super(Outcome.Benefit);
this.staticText = "Counter target enchantment, instant, or sorcery spell. Its controller creates a 2/2 blue Bird creature token with flying";
}
private SwanSongEffect(final SwanSongEffect effect) {
super(effect);
}
@Override
public SwanSongEffect copy() {
return new SwanSongEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
boolean countered = false;
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
Spell spell = game.getStack().getSpell(targetId);
if (game.getStack().counter(targetId, source, game)) {
countered = true;
}
if (spell != null) {
Token token = new SwanSongBirdToken();
token.putOntoBattlefield(1, game, source, spell.getControllerId());
}
}
return countered;
}
}
}

View file

@ -6,7 +6,7 @@ import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
@ -20,7 +20,6 @@ import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class TransmogrifyingWand extends CardImpl {
@ -40,7 +39,7 @@ public final class TransmogrifyingWand extends CardImpl {
new DestroyTargetEffect(),
new GenericManaCost(1)
);
ability.addEffect(new CreateTokenControllerTargetPermanentEffect(new OxToken()));
ability.addEffect(new CreateTokenControllerTargetEffect(new OxToken()));
ability.addCost(new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()));
ability.addTarget(new TargetCreaturePermanent());

View file

@ -6,7 +6,7 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetPermanentEffect;
import mage.abilities.effects.common.CreateTokenControllerTargetEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.ExileThenReturnTargetEffect;
import mage.constants.Outcome;
@ -89,7 +89,7 @@ class UnyieldingGatekeeperEffect extends OneShotEffect {
false, false, PutCards.BATTLEFIELD_TAPPED).apply(game, source);
} else {
new ExileTargetEffect().apply(game, source);
new CreateTokenControllerTargetPermanentEffect(new DetectiveToken()).apply(game, source);
new CreateTokenControllerTargetEffect(new DetectiveToken()).apply(game, source);
}
return true;
}

View file

@ -102,6 +102,7 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Sorin, Ravenous Neonate", 245, Rarity.MYTHIC, mage.cards.s.SorinRavenousNeonate.class));
cards.add(new SetCardInfo("Spawn-Gang Commander", 140, Rarity.UNCOMMON, mage.cards.s.SpawnGangCommander.class));
cards.add(new SetCardInfo("Strength of the Harvest", 258, Rarity.UNCOMMON, mage.cards.s.StrengthOfTheHarvest.class));
cards.add(new SetCardInfo("Strix Serenade", 71, Rarity.RARE, mage.cards.s.StrixSerenade.class));
cards.add(new SetCardInfo("Stump Stomp", 259, Rarity.UNCOMMON, mage.cards.s.StumpStomp.class));
cards.add(new SetCardInfo("Suppression Ray", 260, Rarity.UNCOMMON, mage.cards.s.SuppressionRay.class));
cards.add(new SetCardInfo("Swamp", 306, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));

View file

@ -0,0 +1,74 @@
package org.mage.test.cards.single.mh3;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class StrixSerenadeTest extends CardTestPlayerBase {
/**
* {@link mage.cards.s.StrixSerenade Strix Serenade} {U}
* Instant
* Counter target artifact, creature, or planeswalker spell. Its controller creates a 2/2 blue Bird creature token with flying.
*/
private static final String serenade = "Strix Serenade";
@Test
public void test_Simple() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.HAND, playerA, serenade);
addCard(Zone.HAND, playerB, "Mox Ruby");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Mox Ruby");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, serenade, "Mox Ruby", "Mox Ruby");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, "Mox Ruby", 1);
assertPermanentCount(playerB, "Bird Token", 1);
}
@Test
public void test_Simple_OwnSpellTargetted() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.HAND, playerA, serenade);
addCard(Zone.HAND, playerA, "Mox Ruby");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Ruby");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, serenade, "Mox Ruby", "Mox Ruby");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Mox Ruby", 1);
assertPermanentCount(playerA, "Bird Token", 1);
}
@Test
public void test_CantBeCountered_CreateToken() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.HAND, playerA, serenade);
addCard(Zone.HAND, playerB, "Chandra, Awakened Inferno"); // Can't be countered
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Chandra, Awakened Inferno");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, serenade, "Chandra, Awakened Inferno", "Chandra, Awakened Inferno");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Chandra, Awakened Inferno", 1);
assertPermanentCount(playerB, "Bird Token", 1);
}
}

View file

@ -5,8 +5,8 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.Token;
import mage.players.Player;
import mage.util.CardUtil;
@ -14,46 +14,78 @@ import mage.util.CardUtil;
/**
* @author Susucr
* <p>
* Have the Controller of target permanent (or LKI controller) create Tokens.
* Have the Controller of target object (permanent, or spell) create Tokens.
*/
public class CreateTokenControllerTargetPermanentEffect extends OneShotEffect {
public class CreateTokenControllerTargetEffect extends OneShotEffect {
private final Token token;
private final DynamicValue amount;
private final boolean tapped;
public CreateTokenControllerTargetPermanentEffect(Token token) {
/**
* What the target is supposed to be, to retrieve its controller from
*/
public enum TargetKind {
PERMANENT,
SPELL
}
private final TargetKind targetKind;
public CreateTokenControllerTargetEffect(Token token) {
this(token, 1, false);
}
public CreateTokenControllerTargetPermanentEffect(Token token, int amount, boolean tapped) {
public CreateTokenControllerTargetEffect(Token token, TargetKind targetKind) {
this(token, 1, false, targetKind);
}
public CreateTokenControllerTargetEffect(Token token, int amount, boolean tapped) {
this(token, StaticValue.get(amount), tapped);
}
public CreateTokenControllerTargetPermanentEffect(Token token, DynamicValue amount, boolean tapped) {
public CreateTokenControllerTargetEffect(Token token, int amount, boolean tapped, TargetKind targetKind) {
this(token, StaticValue.get(amount), tapped, targetKind);
}
public CreateTokenControllerTargetEffect(Token token, DynamicValue amount, boolean tapped) {
this(token, amount, tapped, TargetKind.PERMANENT);
}
public CreateTokenControllerTargetEffect(Token token, DynamicValue amount, boolean tapped, TargetKind targetKind) {
super(Outcome.Neutral);
this.token = token;
this.amount = amount.copy();
this.tapped = tapped;
this.staticText = makeText();
this.targetKind = targetKind;
}
protected CreateTokenControllerTargetPermanentEffect(final CreateTokenControllerTargetPermanentEffect effect) {
protected CreateTokenControllerTargetEffect(final CreateTokenControllerTargetEffect effect) {
super(effect);
this.token = effect.token.copy();
this.amount = effect.amount.copy();
this.tapped = effect.tapped;
this.targetKind = effect.targetKind;
}
@Override
public CreateTokenControllerTargetPermanentEffect copy() {
return new CreateTokenControllerTargetPermanentEffect(this);
public CreateTokenControllerTargetEffect copy() {
return new CreateTokenControllerTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
if (permanent != null) {
Player controllerOfTarget = game.getPlayer(permanent.getControllerId());
Controllable controllable = null;
switch (targetKind) {
case PERMANENT:
controllable = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
break;
case SPELL:
controllable = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source));
break;
}
if (controllable != null) {
Player controllerOfTarget = game.getPlayer(controllable.getControllerId());
if (controllerOfTarget != null) {
int value = amount.calculate(game, source, this);
return token.putOntoBattlefield(value, game, source, controllerOfTarget.getId(), tapped, false);