Adding targets (Part 3/3) (#13769)

Adds target and/or target adjuster to cards whose abilities have the word "target", cards S-Z.
Add `spellCast` value to `CastSpellPaidBySourceTriggeredAbility`.
This commit is contained in:
ssk97 2025-06-20 18:58:13 -07:00 committed by GitHub
parent b24a20fec4
commit 5db4beac6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 209 additions and 499 deletions

View file

@ -1,6 +1,7 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BecomesTargetAnyTriggeredAbility;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.FlyingAbility;
@ -9,21 +10,21 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
/**
*
* @author spjspj
*/
public final class ScalelordReckoner extends CardImpl {
static FilterPermanent filterDragon = new FilterControlledPermanent(SubType.DRAGON, "a Dragon you control");
static FilterPermanent filterTarget = new FilterNonlandPermanent("nonland permanent that player controls");
public ScalelordReckoner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
@ -36,7 +37,10 @@ public final class ScalelordReckoner extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever a Dragon you control becomes the target of a spell or ability an opponent controls, destroy target nonland permanent that player controls.
this.addAbility(new ScalelordReckonerTriggeredAbility());
Ability ability = new BecomesTargetAnyTriggeredAbility(new DestroyTargetEffect(), filterDragon, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.PLAYER, false);
ability.addTarget(new TargetPermanent(filterTarget));
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private ScalelordReckoner(final ScalelordReckoner card) {
@ -48,39 +52,3 @@ public final class ScalelordReckoner extends CardImpl {
return new ScalelordReckoner(this);
}
}
class ScalelordReckonerTriggeredAbility extends BecomesTargetAnyTriggeredAbility {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Dragon you control");
static {
filter.add(SubType.DRAGON.getPredicate());
}
ScalelordReckonerTriggeredAbility() {
super(new DestroyTargetEffect().setText("destroy target nonland permanent that player controls"),
filter, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.NONE, false);
}
private ScalelordReckonerTriggeredAbility(final ScalelordReckonerTriggeredAbility ability) {
super(ability);
}
@Override
public ScalelordReckonerTriggeredAbility copy() {
return new ScalelordReckonerTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!super.checkTrigger(event, game)) {
return false;
}
FilterNonlandPermanent targetFilter = new FilterNonlandPermanent("nonland permanent that player controls");
targetFilter.add(new ControllerIdPredicate(event.getPlayerId()));
this.getTargets().clear();
this.addTarget(new TargetPermanent(targetFilter));
return true;
}
}

View file

@ -3,21 +3,21 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ToughnessPredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@ -26,6 +26,12 @@ import java.util.UUID;
*/
public final class SkymarkRoc extends CardImpl {
static FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls with toughness 2 or less");
static {
filter.add(new ToughnessPredicate(ComparisonType.OR_LESS, 2));
}
public SkymarkRoc(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}");
this.subtype.add(SubType.BIRD);
@ -37,7 +43,10 @@ public final class SkymarkRoc extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Skymark Roc attacks, you may return target creature defending player controls with toughness 2 or less to its owner's hand.
this.addAbility(new SkymarkRocAbility());
Ability ability = new AttacksTriggeredAbility(new ReturnToHandTargetEffect(), true, null, SetTargetPointer.PLAYER);
ability.addTarget(new TargetPermanent(filter));
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private SkymarkRoc(final SkymarkRoc card) {
@ -49,44 +58,3 @@ public final class SkymarkRoc extends CardImpl {
return new SkymarkRoc(this);
}
}
class SkymarkRocAbility extends TriggeredAbilityImpl {
public SkymarkRocAbility() {
super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), true);
}
private SkymarkRocAbility(final SkymarkRocAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ATTACKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getSourceId().equals(this.getSourceId())) {
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls with toughness 2 or less");
UUID defenderId = game.getCombat().getDefendingPlayerId(sourceId, game);
filter.add(new ControllerIdPredicate(defenderId));
filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3));
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} attacks, you may return target creature defending player controls with toughness 2 or less to its owner's hand.";
}
@Override
public SkymarkRocAbility copy() {
return new SkymarkRocAbility(this);
}
}

View file

@ -1,30 +1,28 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.ShadowAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterEnchantmentPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class SoltariVisionary extends CardImpl {
static FilterPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls");
public SoltariVisionary(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}");
this.subtype.add(SubType.SOLTARI);
@ -37,7 +35,10 @@ public final class SoltariVisionary extends CardImpl {
this.addAbility(ShadowAbility.getInstance());
// Whenever Soltari Visionary deals damage to a player, destroy target enchantment that player controls.
this.addAbility(new SoltariVisionaryTriggeredAbility());
Ability ability = new DealsDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private SoltariVisionary(final SoltariVisionary card) {
@ -49,43 +50,3 @@ public final class SoltariVisionary extends CardImpl {
return new SoltariVisionary(this);
}
}
class SoltariVisionaryTriggeredAbility extends TriggeredAbilityImpl {
SoltariVisionaryTriggeredAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false);
}
private SoltariVisionaryTriggeredAbility(final SoltariVisionaryTriggeredAbility ability) {
super(ability);
}
@Override
public SoltariVisionaryTriggeredAbility copy() {
return new SoltariVisionaryTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent soltari = game.getPermanent(event.getSourceId());
if (soltari != null && soltari.getId().equals(this.getSourceId())) {
FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("enchantment that player controls.");
filter.add(new ControllerIdPredicate(event.getPlayerId()));
filter.setMessage("enchantment controlled by " + game.getPlayer(event.getTargetId()).getLogName());
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} deals damage to a player, destroy target enchantment that player controls.";
}
}

View file

@ -1,36 +1,43 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetadjustment.TargetAdjuster;
import mage.target.targetpointer.FirstTargetPointer;
import java.util.UUID;
/**
*
* @author emerald000
*/
public final class TheAbyss extends CardImpl {
static FilterPermanent filter = new FilterPermanent("nonartifact creature that player controls of their choice");
public TheAbyss(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}");
this.supertype.add(SuperType.WORLD);
// At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated.
this.addAbility(new TheAbyssTriggeredAbility());
Ability ability = new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER,
new DestroyTargetEffect(true), false).withTargetPointerSet(true);
ability.addTarget(new TargetPermanent(filter)); // Only used for text generation
ability.setTargetAdjuster(TheAbyssTargetAdjuster.instance);
this.addAbility(ability);
}
private TheAbyss(final TheAbyss card) {
@ -43,45 +50,23 @@ public final class TheAbyss extends CardImpl {
}
}
class TheAbyssTriggeredAbility extends TriggeredAbilityImpl {
TheAbyssTriggeredAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect(true), false);
}
private TheAbyssTriggeredAbility(final TheAbyssTriggeredAbility ability) {
super(ability);
}
@Override
public TheAbyssTriggeredAbility copy() {
return new TheAbyssTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact creature you control");
enum TheAbyssTargetAdjuster implements TargetAdjuster {
instance;
private static final FilterPermanent filter
= new FilterCreaturePermanent("nonartifact creature that player controls of their choice");
static {
filter.add(Predicates.not(CardType.ARTIFACT.getPredicate()));
filter.add(new ControllerIdPredicate(player.getId()));
Target target = new TargetPermanent(filter);
target.setAbilityController(getControllerId());
target.setTargetController(player.getId());
this.getTargets().clear();
this.getTargets().add(target);
return true;
}
return false;
}
@Override
public String getRule() {
return "At the beginning of each player's upkeep, destroy target nonartifact creature that player controls of their choice. It can't be regenerated.";
public void adjustTargets(Ability ability, Game game) {
UUID playerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability);
ability.getTargets().clear();
ability.getAllEffects().setTargetPointer(new FirstTargetPointer());
FilterPermanent adjustedFilter = filter.copy();
adjustedFilter.add(new ControllerIdPredicate(playerId));
Target newTarget = new TargetPermanent(adjustedFilter);
newTarget.setTargetController(playerId);
ability.addTarget(newTarget);
}
}

View file

@ -1,35 +1,43 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastAllTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.CantGainLifeAllEffect;
import mage.constants.*;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPlayer;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
import mage.filter.predicate.other.PlayerIdPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPlayer;
import mage.target.targetpointer.FixedTarget;
import mage.target.targetadjustment.TargetAdjuster;
import mage.target.targetpointer.FirstTargetPointer;
import mage.watchers.common.SpellsCastWatcher;
import java.util.UUID;
/**
*
* @author Grath
*/
public final class TheLordOfPain extends CardImpl {
private static final FilterSpell filter = new FilterSpell("their first spell each turn");
static {
filter.add(TheLordOfPainPredicate.instance);
}
public TheLordOfPain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}");
@ -48,7 +56,12 @@ public final class TheLordOfPain extends CardImpl {
));
// Whenever a player casts their first spell each turn, choose another target player. The Lord of Pain deals damage equal to that spell's mana value to the chosen player.
this.addAbility(new TheLordOfPainTriggeredAbility());
Ability ability = new SpellCastAllTriggeredAbility(
new DamageTargetEffect(TheLordOfPainValue.instance)
.setText("choose another target player. {this} deals damage equal to that spell's mana value to the chosen player")
, filter, false, SetTargetPointer.PLAYER);
ability.setTargetAdjuster(TheLordOfPainTargetAdjuster.instance);
this.addAbility(ability);
}
private TheLordOfPain(final TheLordOfPain card) {
@ -72,70 +85,40 @@ enum TheLordOfPainPredicate implements Predicate<StackObject> {
}
}
class TheLordOfPainTriggeredAbility extends SpellCastAllTriggeredAbility {
private static final FilterSpell filter = new FilterSpell("their first spell each turn");
enum TheLordOfPainTargetAdjuster implements TargetAdjuster {
instance;
static {
filter.add(TheLordOfPainPredicate.instance);
@Override
public void adjustTargets(Ability ability, Game game) {
UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability);
ability.getTargets().clear();
ability.getAllEffects().setTargetPointer(new FirstTargetPointer());
FilterPlayer filter = new FilterPlayer("another target player");
filter.add(Predicates.not(new PlayerIdPredicate(opponentId)));
Target newTarget = new TargetPlayer(filter);
ability.addTarget(newTarget);
}
}
public TheLordOfPainTriggeredAbility() {
super(new TheLordOfPainEffect(), filter, false, SetTargetPointer.PLAYER);
}
enum TheLordOfPainValue implements DynamicValue {
instance;
protected TheLordOfPainTriggeredAbility(final TheLordOfPainTriggeredAbility ability) {
super(ability);
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Object spell = effect.getValue("spellCast");
if (spell instanceof Spell) {
return ((Spell) spell).getManaValue();
}
return 0;
}
@Override
public TheLordOfPainTriggeredAbility copy() {
return new TheLordOfPainTriggeredAbility(this);
public TheLordOfPainValue copy() {
return instance;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (super.checkTrigger(event, game)) {
Player controller = game.getPlayer(getControllerId());
Spell spell = (Spell)getEffects().get(0).getValue("spellCast");
if (controller != null) {
FilterPlayer filter2 = new FilterPlayer("another target player");
filter2.add(Predicates.not(new MageObjectReferencePredicate(spell.getControllerId(), game)));
TargetPlayer target = new TargetPlayer(1, 1, false, filter2);
controller.choose(Outcome.Damage, target, this, game);
getEffects().setTargetPointer(new FixedTarget(target.getFirstTarget()));
return true;
public String getMessage() {
return "that spell's mana value";
}
}
return false;
}
}
class TheLordOfPainEffect extends OneShotEffect {
TheLordOfPainEffect() {
super(Outcome.Benefit);
staticText = "choose another target player. {this} deals damage equal to that spell's mana value to the chosen player";
}
private TheLordOfPainEffect(final TheLordOfPainEffect effect) {
super(effect);
}
@Override
public TheLordOfPainEffect copy() {
return new TheLordOfPainEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Spell spell = (Spell)this.getValue("spellCast");
if (spell != null) {
int cost = spell.getManaValue();
Player target = game.getPlayer(getTargetPointer().getFirst(game, source));
if (target != null) {
target.damage(cost, source.getSourceId(), source, game);
return true;
}
}
return false; }
}

View file

@ -1,38 +1,39 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CopyEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.PermanentPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public class TheMyriadPools extends CardImpl {
private static final FilterSpell filter = new FilterSpell("a permanent spell");
static {
filter.add(PermanentPredicate.instance);
}
public TheMyriadPools(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, null);
this.supertype.add(SuperType.LEGENDARY);
@ -41,11 +42,12 @@ public class TheMyriadPools extends CardImpl {
this.nightCard = true;
// {T}: Add {U}.
Ability ability = new BlueManaAbility();
// Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn.
this.addAbility(ability, new TheMyriadPoolsWatcher(ability.getOriginalId().toString()));
this.addAbility(new TheMyriadPoolsTriggeredAbility());
this.addAbility(new BlueManaAbility());
// Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn.
Ability ability = new CastSpellPaidBySourceTriggeredAbility(new TheMyriadPoolsCopyEffect(), filter, false);
ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_TARGET_PERMANENT));
this.addAbility(ability);
}
private TheMyriadPools(final TheMyriadPools card) {
@ -58,90 +60,11 @@ public class TheMyriadPools extends CardImpl {
}
}
class TheMyriadPoolsWatcher extends Watcher {
private UUID permanentId = UUID.randomUUID();
private final String originalId;
public TheMyriadPoolsWatcher(String originalId) {
super(WatcherScope.CARD);
this.originalId = originalId;
}
public boolean manaUsedToCastPermanentPart(UUID id) {
return permanentId.equals(id);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.MANA_PAID) {
if (event.getData() != null
&& event.getData().equals(originalId)) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null
&& spell.isPermanent(game)) {
Card card = spell.getCard();
permanentId = card.getId();
}
}
}
}
@Override
public void reset() {
super.reset();
}
}
class TheMyriadPoolsTriggeredAbility extends TriggeredAbilityImpl {
public TheMyriadPoolsTriggeredAbility() {
super(Zone.BATTLEFIELD, new TheMyriadPoolsCopyEffect());
}
private TheMyriadPoolsTriggeredAbility(final TheMyriadPoolsTriggeredAbility ability) {
super(ability);
}
@Override
public TheMyriadPoolsTriggeredAbility copy() {
return new TheMyriadPoolsTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.SPELL_CAST;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
TheMyriadPoolsWatcher watcher = game.getState().getWatcher(TheMyriadPoolsWatcher.class, this.getSourceId());
if (watcher != null
&& watcher.manaUsedToCastPermanentPart(event.getSourceId())) {
Spell spell = game.getSpell(event.getSourceId());
if (spell != null
&& spell.isControlledBy(getControllerId())) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
}
return true;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever you cast a permanent spell using mana produced by {this}, up to one other target permanent you control becomes a copy of that spell until end of turn.";
}
}
class TheMyriadPoolsCopyEffect extends OneShotEffect {
TheMyriadPoolsCopyEffect() {
super(Outcome.Neutral);
this.staticText = "copy of card on stack";
this.staticText = "up to one other target permanent you control becomes a copy of that spell until end of turn";
}
private TheMyriadPoolsCopyEffect(final TheMyriadPoolsCopyEffect effect) {
@ -155,28 +78,18 @@ class TheMyriadPoolsCopyEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent targetPermanentToCopyTo = null;
Permanent targetPermanentToCopyTo = game.getPermanent(getTargetPointer().getFirst(game, source));
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
Object spell = getValue("spellCast");
if (controller == null || targetPermanentToCopyTo == null || !(spell instanceof Spell)) {
return false;
}
TargetPermanent target = new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_PERMANENT, false);
if (controller.choose(Outcome.Neutral, target, source, game)) {
targetPermanentToCopyTo = game.getPermanent(target.getFirstTarget());
}
Card copyFromCardOnStack = game.getCard(getTargetPointer().getFirst(game, source));
Permanent newBluePrint = null;
if (targetPermanentToCopyTo != null) {
if (copyFromCardOnStack != null) {
newBluePrint = new PermanentCard(copyFromCardOnStack, source.getControllerId(), game);
Permanent newBluePrint = new PermanentCard(((Spell)spell).getCard(), source.getControllerId(), game);
newBluePrint.assignNewId();
CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, targetPermanentToCopyTo.getId());
Ability newAbility = source.copy();
copyEffect.init(newAbility, game);
game.addEffect(copyEffect, newAbility);
}
return true;
}
return false;
}
}

View file

@ -1,6 +1,5 @@
package mage.cards.t;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
@ -13,11 +12,9 @@ import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetOpponent;
import java.util.Set;
import java.util.UUID;
/**
@ -31,6 +28,7 @@ public final class ThranTome extends CardImpl {
// Reveal the top three cards of your library. Target opponent chooses one of those cards. Put that card into your graveyard, then draw two cards.
Ability ability = new SimpleActivatedAbility(new ThranTomeEffect(), new ManaCostsImpl<>("{5}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
@ -62,35 +60,18 @@ class ThranTomeEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
// validate source and controller exist
// validate opponent and controller exist
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (sourceObject == null || controller == null) {
if (opponent == null || controller == null) {
return false;
}
// target an opponent, if able
Player opponent;
Set<UUID> opponents = game.getOpponents(controller.getId());
opponents.removeIf(opp -> !game.getPlayer(opp).canBeTargetedBy(sourceObject, source.getControllerId(), source, game));
if (opponents.isEmpty()) {
return false;
} else {
if (opponents.size() == 1) {
opponent = game.getPlayer(opponents.iterator().next());
} else {
Target target = new TargetOpponent();
controller.chooseTarget(Outcome.Detriment, target, source, game);
opponent = game.getPlayer(target.getFirstTarget());
}
}
// reveal the cards and choose one. put it in the graveyard
Card cardToGraveyard;
Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3));
controller.revealCards(sourceObject.getIdName(), cards, game);
controller.revealCards(source, cards, game);
if (cards.size() == 1) {
cardToGraveyard = cards.getRandom(game);

View file

@ -35,6 +35,7 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetPermanentOrPlayer;
import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
import java.util.UUID;
@ -98,6 +99,7 @@ class ToralfGodOfFuryTriggeredAbility extends TriggeredAbilityImpl implements Ba
ToralfGodOfFuryTriggeredAbility() {
super(Zone.BATTLEFIELD, null);
this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
private ToralfGodOfFuryTriggeredAbility(final ToralfGodOfFuryTriggeredAbility ability) {

View file

@ -1,7 +1,10 @@
package mage.cards.v;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.dynamicvalue.common.EffectKeyValue;
import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.VigilanceAbility;
@ -10,15 +13,10 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetadjustment.ManaValueTargetAdjuster;
import java.util.UUID;
@ -26,6 +24,7 @@ import java.util.UUID;
* @author TheElk801
*/
public final class VenerableWarsinger extends CardImpl {
FilterCard filter = new FilterCreatureCard("creature card with mana value X or less from your graveyard");
public VenerableWarsinger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}");
@ -42,7 +41,11 @@ public final class VenerableWarsinger extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Whenever Venerable Warsinger deals combat damage to a player, you may return target creature card with mana value X or less from your graveyard to the battlefield, where X is the amount of damage that Venerable Warsinger dealt to that player.
this.addAbility(new VenerableWarsingerTriggeredAbility());
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true);
ability.addTarget(new TargetCardInYourGraveyard(filter));
ability.setTargetAdjuster(new ManaValueTargetAdjuster(new EffectKeyValue("damage"), ComparisonType.OR_LESS));
ability.addEffect(new InfoEffect("where X is the amount of damage {this} dealt to that player").concatBy(","));
this.addAbility(ability);
}
private VenerableWarsinger(final VenerableWarsinger card) {
@ -54,48 +57,3 @@ public final class VenerableWarsinger extends CardImpl {
return new VenerableWarsinger(this);
}
}
class VenerableWarsingerTriggeredAbility extends TriggeredAbilityImpl {
VenerableWarsingerTriggeredAbility() {
super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), true);
}
private VenerableWarsingerTriggeredAbility(final VenerableWarsingerTriggeredAbility ability) {
super(ability);
}
@Override
public VenerableWarsingerTriggeredAbility copy() {
return new VenerableWarsingerTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Player player = game.getPlayer(event.getPlayerId());
if (player == null
|| !event.getSourceId().equals(getSourceId())
|| !((DamagedEvent) event).isCombatDamage()) {
return false;
}
FilterCard filter = new FilterCreatureCard(
"creature card with mana value " + event.getAmount() + " less from your graveyard"
);
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, event.getAmount() + 1));
this.getTargets().clear();
this.addTarget(new TargetCardInYourGraveyard(filter));
return true;
}
@Override
public String getRule() {
return "Whenever {this} deals combat damage to a player, you may return target creature card " +
"with mana value X or less from your graveyard to the battlefield, " +
"where X is the amount of damage {this} dealt to that player.";
}
}

View file

@ -1,9 +1,10 @@
package mage.cards.w;
import mage.MageInt;
import mage.abilities.common.ZoneChangeTriggeredAbility;
import mage.abilities.Ability;
import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.dynamicvalue.common.EffectKeyValue;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.CyclingAbility;
import mage.abilities.keyword.ReachAbility;
@ -12,14 +13,10 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.StackObject;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ManaValueTargetAdjuster;
import java.util.UUID;
@ -27,6 +24,7 @@ import java.util.UUID;
* @author TheElk801
*/
public final class WebstrikeElite extends CardImpl {
FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with mana value X");
public WebstrikeElite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}");
@ -43,7 +41,10 @@ public final class WebstrikeElite extends CardImpl {
this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{G}{G}")));
// When you cycle this card, destroy up to one target artifact or enchantment with mana value X.
this.addAbility(new WebstrikeEliteTriggeredAbility());
Ability ability = new CycleTriggeredAbility(new DestroyTargetEffect());
ability.addTarget(new TargetPermanent(0, 1, filter));
ability.setTargetAdjuster(new ManaValueTargetAdjuster(new EffectKeyValue("cycleXValue"), ComparisonType.EQUAL_TO));
this.addAbility(ability);
}
private WebstrikeElite(final WebstrikeElite card) {
@ -55,47 +56,3 @@ public final class WebstrikeElite extends CardImpl {
return new WebstrikeElite(this);
}
}
class WebstrikeEliteTriggeredAbility extends ZoneChangeTriggeredAbility {
WebstrikeEliteTriggeredAbility() {
super(Zone.ALL, new DestroyTargetEffect(), "", false);
}
private WebstrikeEliteTriggeredAbility(final WebstrikeEliteTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
}
@Override
public WebstrikeEliteTriggeredAbility copy() {
return new WebstrikeEliteTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!event.getSourceId().equals(this.getSourceId())) {
return false;
}
StackObject object = game.getStack().getStackObject(event.getSourceId());
if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) {
return false;
}
FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with mana value X");
filter.add(new ManaValuePredicate(
ComparisonType.EQUAL_TO, GetXValue.instance.calculate(game, object.getStackAbility(), null)
));
this.getTargets().clear();
this.addTarget(new TargetPermanent(0, 1, filter));
return true;
}
@Override
public String getRule() {
return "When you cycle this card, destroy up to one target artifact or enchantment with mana value X.";
}
}

View file

@ -56,23 +56,29 @@ public class BarracksOfTheThousandTest extends CardTestPlayerBase {
}
@Test
public void trigger_onlyonce_doublemana() {
public void trigger_onceTwice_doublemana() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Heartbeat of Spring");
addCard(Zone.BATTLEFIELD, playerA, "Mana Reflection");
addCard(Zone.HAND, playerA, "Armored Warhorse");
addCard(Zone.HAND, playerA, "Savannah Lions", 2);
initToTransform();
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Armored Warhorse");
checkPermanentCount("One Gnome Soldier Token", 1, PhaseStep.BEGIN_COMBAT, playerA, "Gnome Soldier Token", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Savannah Lions");
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Savannah Lions");
setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Gnome Soldier Token", 1);
assertPermanentCount(playerA, "Gnome Soldier Token", 3);
assertPermanentCount(playerA, "Armored Warhorse", 1);
assertPermanentCount(playerA, "Savannah Lions", 2);
}
@Test
public void noTrigger_NotPaidWithBarrack() {
setStrictChooseMode(true);

View file

@ -0,0 +1,27 @@
package org.mage.test.cards.single.lci;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class TheMyriadPoolsTest extends CardTestPlayerBase {
@Test
public void castCopiesCorrectly() {
addCard(Zone.BATTLEFIELD, playerA, "The Myriad Pools");
addCard(Zone.BATTLEFIELD, playerA, "Memnite");
addCard(Zone.HAND, playerA, "Flying Men");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flying Men");
addTarget(playerA, "Memnite");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
setStrictChooseMode(true);
execute();
assertPermanentCount(playerA, "The Myriad Pools", 1);
assertPermanentCount(playerA, "Memnite", 0);
assertPermanentCount(playerA, "Flying Men", 2);
}
}

View file

@ -71,6 +71,7 @@ public class CastSpellPaidBySourceTriggeredAbility extends TriggeredAbilityImpl
if (setTargetPointer) {
this.getAllEffects().setTargetPointer(new FixedTarget(spell.getId(), game));
}
this.getEffects().setValue("spellCast", spell);
return true;
}