diff --git a/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java b/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java
index 6d18e223b89..67471e9fd54 100644
--- a/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java
+++ b/Mage.Sets/src/mage/cards/g/GaleWaterdeepProdigy.java
@@ -37,7 +37,7 @@ public final class GaleWaterdeepProdigy extends CardImpl {
// If a spell cast from your graveyard this way would be put into your graveyard, exile it instead.
Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD,
new MayCastTargetCardEffect(true)
- .setText("you may cast up to one of the other type from your graveyard. If a spell cast from your graveyard this way would be put into your graveyard, exile it instead."),
+ .setText("you may cast up to one target card of the other type from your graveyard. If a spell cast from your graveyard this way would be put into your graveyard, exile it instead."),
StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY,
false, SetTargetPointer.SPELL, Zone.HAND
);
@@ -84,6 +84,6 @@ enum GaleWaterdeepProdigyAdjuster implements TargetAdjuster {
} else {
filter = SORCERY_FILTER;
}
- ability.addTarget(new TargetCardInYourGraveyard(filter));
+ ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter));
}
}
diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java
index 2f5fe12510c..ca98ec48195 100644
--- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java
+++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java
@@ -1,23 +1,21 @@
package mage.cards.h;
-import mage.ApprovingObject;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
-import mage.abilities.effects.OneShotEffect;
-import mage.cards.Card;
+import mage.abilities.effects.common.MayCastTargetCardEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.Outcome;
+import mage.constants.SetTargetPointer;
+import mage.constants.Zone;
import mage.filter.FilterCard;
-import mage.filter.common.FilterInstantOrSorcerySpell;
+import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.stack.Spell;
-import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
-import mage.watchers.common.CastFromHandWatcher;
+import mage.target.targetadjustment.TargetAdjuster;
+import mage.target.targetpointer.FirstTargetPointer;
import java.util.UUID;
@@ -26,13 +24,20 @@ import java.util.UUID;
* @author LevelX2
*/
public final class HarnessTheStorm extends CardImpl {
+ static FilterCard filter = new FilterCard("card with the same name as that spell from your graveyard");
public HarnessTheStorm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
// Whenever you cast an instant or sorcery spell from your hand, you may cast
// target card with the same name as that spell from your graveyard.
- this.addAbility(new HarnessTheStormTriggeredAbility(), new CastFromHandWatcher());
+ Ability ability = new SpellCastControllerTriggeredAbility(
+ Zone.BATTLEFIELD, new MayCastTargetCardEffect(false), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY,
+ false, SetTargetPointer.SPELL, Zone.HAND
+ );
+ ability.addTarget(new TargetCardInYourGraveyard(filter)); // Only used for text generation
+ ability.setTargetAdjuster(HarnessTheStormAdjuster.instance);
+ this.addAbility(ability);
}
private HarnessTheStorm(final HarnessTheStorm card) {
@@ -45,78 +50,20 @@ public final class HarnessTheStorm extends CardImpl {
}
}
-
-class HarnessTheStormTriggeredAbility extends SpellCastControllerTriggeredAbility {
-
- private static final FilterInstantOrSorcerySpell filterSpell = new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand");
-
- HarnessTheStormTriggeredAbility() {
- super(new HarnessTheStormEffect(), filterSpell, false);
- }
-
- private HarnessTheStormTriggeredAbility(final HarnessTheStormTriggeredAbility ability) {
- super(ability);
- }
-
+enum HarnessTheStormAdjuster implements TargetAdjuster {
+ instance;
@Override
- public boolean checkTrigger(GameEvent event, Game game) {
- if (super.checkTrigger(event, game)) {
- CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class);
- if (watcher != null && watcher.spellWasCastFromHand(event.getSourceId())) {
- Spell spell = game.getState().getStack().getSpell(event.getSourceId());
- if (spell != null) {
- FilterCard filterCard = new FilterCard("a card named " + spell.getName() + " in your graveyard");
- filterCard.add(new NamePredicate(spell.getName()));
- this.getTargets().clear();
- this.getTargets().add(new TargetCardInYourGraveyard(filterCard));
- return true;
- }
- }
+ public void adjustTargets(Ability ability, Game game) {
+ UUID spellId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability);
+ ability.getTargets().clear();
+ ability.getAllEffects().setTargetPointer(new FirstTargetPointer());
+
+ Spell spell = game.getSpellOrLKIStack(spellId);
+ if (spell == null){
+ return;
}
- return false;
- }
-
- @Override
- public HarnessTheStormTriggeredAbility copy() {
- return new HarnessTheStormTriggeredAbility(this);
- }
-
-}
-
-class HarnessTheStormEffect extends OneShotEffect {
-
- HarnessTheStormEffect() {
- super(Outcome.Benefit);
- this.staticText = "you may cast target card with the same name as that "
- + "spell from your graveyard. (You still pay its costs.)";
- }
-
- private HarnessTheStormEffect(final HarnessTheStormEffect effect) {
- super(effect);
- }
-
- @Override
- public HarnessTheStormEffect copy() {
- return new HarnessTheStormEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Player controller = game.getPlayer(source.getControllerId());
- if (controller == null) {
- return false;
- }
- Card card = controller.getGraveyard().get(getTargetPointer().getFirst(game, source), game);
- if (card == null) {
- return false;
- }
- if (controller.chooseUse(outcome, "Cast " + card.getIdName() + " from your graveyard?", source, game)) {
- game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
- controller.cast(controller.chooseAbilityForCast(card, game, false),
- game, false, new ApprovingObject(source, game));
- game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
- }
- return true;
-
+ FilterCard filter = new FilterCard("a card named " + spell.getName() + " in your graveyard");
+ filter.add(new NamePredicate(spell.getName()));
+ ability.addTarget(new TargetCardInYourGraveyard(filter));
}
}
diff --git a/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java b/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java
index 0d98b477525..c25814320f6 100644
--- a/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java
+++ b/Mage.Sets/src/mage/cards/i/ImpetuousDevils.java
@@ -1,26 +1,21 @@
package mage.cards.i;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
+import mage.abilities.TriggeredAbility;
+import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TrampleAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.CardType;
-import mage.constants.SubType;
-import mage.constants.Duration;
-import mage.constants.TargetController;
-import mage.constants.Zone;
-import mage.filter.common.FilterCreaturePermanent;
-import mage.filter.predicate.permanent.ControllerIdPredicate;
-import mage.game.Game;
-import mage.game.events.GameEvent;
+import mage.constants.*;
import mage.target.common.TargetCreaturePermanent;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
+
+import java.util.UUID;
/**
*
@@ -39,7 +34,12 @@ public final class ImpetuousDevils extends CardImpl {
// Haste
this.addAbility(HasteAbility.getInstance());
// When Impetuous Devils attacks, up to one target creature defending player controls blocks it this combat if able.
- this.addAbility(new ImpetuousDevilsAbility());
+ TriggeredAbility ability = new AttacksTriggeredAbility(new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat)
+ .setText("up to one target creature defending player controls blocks it this combat if able"), false, null, SetTargetPointer.PLAYER);
+ ability.setTriggerPhrase("When {this} attacks, ");
+ ability.addTarget(new TargetCreaturePermanent(0, 1));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
+ this.addAbility(ability);
// At the beginning of the end step, sacrifice Impetuous Devils.
this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.NEXT, new SacrificeSourceEffect(), false));
@@ -54,44 +54,3 @@ public final class ImpetuousDevils extends CardImpl {
return new ImpetuousDevils(this);
}
}
-
-class ImpetuousDevilsAbility extends TriggeredAbilityImpl {
-
- public ImpetuousDevilsAbility() {
- super(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat), false);
- }
-
- private ImpetuousDevilsAbility(final ImpetuousDevilsAbility 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");
- UUID defenderId = game.getCombat().getDefendingPlayerId(sourceId, game);
- filter.add(new ControllerIdPredicate(defenderId));
-
- this.getTargets().clear();
- TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false);
- this.addTarget(target);
- return true;
- }
- return false;
- }
-
- @Override
- public String getRule() {
- return "When {this} attacks, up to one target creature defending player controls blocks it this combat if able.";
- }
-
- @Override
- public ImpetuousDevilsAbility copy() {
- return new ImpetuousDevilsAbility(this);
- }
-}
diff --git a/Mage.Sets/src/mage/cards/k/KarmicJustice.java b/Mage.Sets/src/mage/cards/k/KarmicJustice.java
index 68bb6406d27..ef9e7be0aa1 100644
--- a/Mage.Sets/src/mage/cards/k/KarmicJustice.java
+++ b/Mage.Sets/src/mage/cards/k/KarmicJustice.java
@@ -1,7 +1,6 @@
package mage.cards.k;
-import java.util.UUID;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.DestroyTargetEffect;
@@ -15,6 +14,9 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.Target;
import mage.target.TargetPermanent;
+import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
+
+import java.util.UUID;
/**
*
@@ -25,7 +27,6 @@ public final class KarmicJustice extends CardImpl {
public KarmicJustice(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}");
-
// Whenever a spell or ability an opponent controls destroys a noncreature permanent you control, you may destroy target permanent that opponent controls.
this.addAbility(new KarmicJusticeTriggeredAbility());
}
@@ -45,8 +46,9 @@ class KarmicJusticeTriggeredAbility extends TriggeredAbilityImpl {
KarmicJusticeTriggeredAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect(), true);
this.setLeavesTheBattlefieldTrigger(true);
+ this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
-
+
private KarmicJusticeTriggeredAbility(final KarmicJusticeTriggeredAbility ability) {
super(ability);
}
diff --git a/Mage.Sets/src/mage/cards/m/MageRingResponder.java b/Mage.Sets/src/mage/cards/m/MageRingResponder.java
index 56ce5c14dca..069f0c4201f 100644
--- a/Mage.Sets/src/mage/cards/m/MageRingResponder.java
+++ b/Mage.Sets/src/mage/cards/m/MageRingResponder.java
@@ -1,9 +1,9 @@
package mage.cards.m;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.Ability;
+import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@@ -13,21 +13,21 @@ import mage.abilities.effects.common.UntapSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.SetTargetPointer;
import mage.constants.SubType;
-import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
-import mage.filter.predicate.permanent.ControllerIdPredicate;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.events.GameEvent.EventType;
import mage.target.common.TargetCreaturePermanent;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
+
+import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class MageRingResponder extends CardImpl {
-
+ private static final FilterCreaturePermanent filter
+ = new FilterCreaturePermanent("creature defending player controls");
public MageRingResponder(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}");
this.subtype.add(SubType.GOLEM);
@@ -41,7 +41,10 @@ public final class MageRingResponder extends CardImpl {
this.addAbility(new SimpleActivatedAbility(new UntapSourceEffect(), new ManaCostsImpl<>("{7}")));
// Whenever Mage-Ring Responder attacks, it deals 7 damage to target creature defending player controls.
- this.addAbility(new MageRingResponderAbility());
+ Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(7), false, null, SetTargetPointer.PLAYER);
+ ability.addTarget(new TargetCreaturePermanent(filter));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
+ this.addAbility(ability);
}
private MageRingResponder(final MageRingResponder card) {
@@ -53,44 +56,3 @@ public final class MageRingResponder extends CardImpl {
return new MageRingResponder(this);
}
}
-
-class MageRingResponderAbility extends TriggeredAbilityImpl {
-
- public MageRingResponderAbility() {
- super(Zone.BATTLEFIELD, new DamageTargetEffect(7));
- }
-
- private MageRingResponderAbility(final MageRingResponderAbility 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");
- UUID defenderId = game.getCombat().getDefenderId(sourceId);
- filter.add(new ControllerIdPredicate(defenderId));
-
- this.getTargets().clear();
- TargetCreaturePermanent target = new TargetCreaturePermanent(filter);
- this.addTarget(target);
- return true;
- }
- return false;
- }
-
- @Override
- public String getRule() {
- return "Whenever {this} attacks, it deals 7 damage to target creature defending player controls.";
- }
-
- @Override
- public MageRingResponderAbility copy() {
- return new MageRingResponderAbility(this);
- }
-}
diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java b/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java
index 2d293a138d2..b3a54890d0c 100644
--- a/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java
+++ b/Mage.Sets/src/mage/cards/m/MagusOfTheAbyss.java
@@ -1,29 +1,32 @@
package mage.cards.m;
-import java.util.UUID;
import mage.MageInt;
-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.SubType;
-import mage.constants.Zone;
-import mage.filter.common.FilterCreaturePermanent;
+import mage.constants.TargetController;
+import mage.filter.FilterPermanent;
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.common.TargetCreaturePermanent;
+import mage.target.TargetPermanent;
+import mage.target.targetadjustment.TargetAdjuster;
+import mage.target.targetpointer.FirstTargetPointer;
+
+import java.util.UUID;
/**
*
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public final class MagusOfTheAbyss extends CardImpl {
+ static FilterPermanent filter = new FilterPermanent("nonartifact creature that player controls of their choice");
public MagusOfTheAbyss(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
@@ -33,7 +36,11 @@ public final class MagusOfTheAbyss extends CardImpl {
this.toughness = new MageInt(3);
// 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 MagusOfTheAbyssTriggeredAbility());
+ 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(MagusOfTheAbyssTargetAdjuster.instance);
+ this.addAbility(ability);
}
private MagusOfTheAbyss(final MagusOfTheAbyss card) {
@@ -46,45 +53,24 @@ public final class MagusOfTheAbyss extends CardImpl {
}
}
-class MagusOfTheAbyssTriggeredAbility extends TriggeredAbilityImpl {
-
- MagusOfTheAbyssTriggeredAbility() {
- super(Zone.BATTLEFIELD, new DestroyTargetEffect(true), false);
+enum MagusOfTheAbyssTargetAdjuster implements TargetAdjuster {
+ instance;
+ private static final FilterPermanent filter
+ = new FilterPermanent("nonartifact creature that player controls of their choice");
+ static {
+ filter.add(Predicates.not(CardType.ARTIFACT.getPredicate()));
+ filter.add(CardType.CREATURE.getPredicate());
}
-
- private MagusOfTheAbyssTriggeredAbility(final MagusOfTheAbyssTriggeredAbility ability) {
- super(ability);
- }
-
@Override
- public MagusOfTheAbyssTriggeredAbility copy() {
- return new MagusOfTheAbyssTriggeredAbility(this);
- }
+ 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());
- @Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE;
+ FilterPermanent adjustedFilter = filter.copy();
+ adjustedFilter.add(new ControllerIdPredicate(opponentId));
+ Target newTarget = new TargetPermanent(adjustedFilter);
+ newTarget.setTargetController(opponentId);
+ ability.addTarget(newTarget);
}
-
- @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");
- filter.add(Predicates.not(CardType.ARTIFACT.getPredicate()));
- filter.add(new ControllerIdPredicate(player.getId()));
- Target target = new TargetCreaturePermanent(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.";
- }
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/m/ManaSkimmer.java b/Mage.Sets/src/mage/cards/m/ManaSkimmer.java
index 17e473baede..2cff22f5320 100644
--- a/Mage.Sets/src/mage/cards/m/ManaSkimmer.java
+++ b/Mage.Sets/src/mage/cards/m/ManaSkimmer.java
@@ -1,9 +1,9 @@
package mage.cards.m;
-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.DontUntapInControllersNextUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.FlyingAbility;
@@ -11,13 +11,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
-import mage.filter.common.FilterLandPermanent;
-import mage.filter.predicate.permanent.ControllerIdPredicate;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.target.TargetPermanent;
+import mage.target.common.TargetLandPermanent;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
+
+import java.util.UUID;
/**
*
@@ -34,7 +31,11 @@ public final class ManaSkimmer extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Mana Skimmer deals damage to a player, tap target land that player controls. That land doesn't untap during its controller's next untap step.
- this.addAbility(new ManaSkimmerTriggeredAbility());
+ Ability ability = new DealsDamageToAPlayerTriggeredAbility(new TapTargetEffect(), false, true);
+ ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That land"));
+ ability.addTarget(new TargetLandPermanent().withTargetName("target land that player controls"));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
+ this.addAbility(ability);
}
private ManaSkimmer(final ManaSkimmer card) {
@@ -46,44 +47,3 @@ public final class ManaSkimmer extends CardImpl {
return new ManaSkimmer(this);
}
}
-
-class ManaSkimmerTriggeredAbility extends TriggeredAbilityImpl {
-
- ManaSkimmerTriggeredAbility() {
- super(Zone.BATTLEFIELD, new TapTargetEffect(), false);
- addEffect(new DontUntapInControllersNextUntapStepTargetEffect());
- }
-
- private ManaSkimmerTriggeredAbility(final ManaSkimmerTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public ManaSkimmerTriggeredAbility copy() {
- return new ManaSkimmerTriggeredAbility(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 source = game.getPermanent(event.getSourceId());
- if (source != null && source.getId().equals(this.getSourceId())) {
- FilterLandPermanent filter = new FilterLandPermanent("land that player controls");
- filter.add(new ControllerIdPredicate(event.getPlayerId()));
- filter.setMessage("land 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, tap target land that player controls. That land doesn't untap during its controller's next untap step.";
- }
-}
diff --git a/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java b/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java
index 5e95ea8d9c5..ea41e0956cf 100644
--- a/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java
+++ b/Mage.Sets/src/mage/cards/m/MausoleumTurnkey.java
@@ -1,31 +1,31 @@
package mage.cards.m;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
-import mage.abilities.effects.OneShotEffect;
-import mage.cards.Card;
+import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.SubType;
import mage.constants.Outcome;
-import mage.constants.Zone;
+import mage.constants.SubType;
import mage.filter.common.FilterCreatureCard;
-import mage.filter.predicate.card.OwnerIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
-import mage.target.common.TargetCardInGraveyard;
+import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetOpponent;
+import mage.target.targetadjustment.TargetAdjuster;
+
+import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class MausoleumTurnkey extends CardImpl {
+ static FilterCreatureCard filter = new FilterCreatureCard("creature card of an opponent's choice");
public MausoleumTurnkey(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
@@ -36,8 +36,10 @@ public final class MausoleumTurnkey extends CardImpl {
this.toughness = new MageInt(2);
// When Mausoleum Turnkey enters the battlefield, return target creature card of an opponent's choice from your graveyard to your hand.
- this.addAbility(new EntersBattlefieldTriggeredAbility(new MausoleumTurnkeyEffect(), false));
-
+ Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect());
+ ability.addTarget(new TargetCardInYourGraveyard(filter));
+ ability.setTargetAdjuster(MausoleumTurnkeyAdjuster.instance);
+ this.addAbility(ability);
}
private MausoleumTurnkey(final MausoleumTurnkey card) {
@@ -50,50 +52,27 @@ public final class MausoleumTurnkey extends CardImpl {
}
}
-class MausoleumTurnkeyEffect extends OneShotEffect {
-
- MausoleumTurnkeyEffect() {
- super(Outcome.Benefit);
- this.staticText = "return target creature card of an opponent's choice from your graveyard to your hand";
- }
-
- private MausoleumTurnkeyEffect(final MausoleumTurnkeyEffect effect) {
- super(effect);
- }
+// Exact copy of KarplusanMinotaurAdjuster
+enum MausoleumTurnkeyAdjuster implements TargetAdjuster {
+ instance;
@Override
- public MausoleumTurnkeyEffect copy() {
- return new MausoleumTurnkeyEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
- UUID opponentId = null;
- if (game.getOpponents(controller.getId()).size() > 1) {
- Target target = new TargetOpponent(true);
- if (controller.chooseTarget(outcome, target, source, game)) {
- opponentId = target.getFirstTarget();
- }
- } else {
- opponentId = game.getOpponents(controller.getId()).iterator().next();
- }
- if (opponentId != null) {
- Player opponent = game.getPlayer(opponentId);
- if (opponent != null) {
- FilterCreatureCard filter = new FilterCreatureCard("creature card from " + controller.getLogName() + " graveyard");
- filter.add(new OwnerIdPredicate(controller.getId()));
- Target target = new TargetCardInGraveyard(filter);
- opponent.chooseTarget(outcome, target, source, game);
- Card card = game.getCard(target.getFirstTarget());
- if (card != null) {
- controller.moveCards(card, Zone.HAND, source, game);
- }
- }
- }
- return true;
+ public void adjustTargets(Ability ability, Game game) {
+ Player controller = game.getPlayer(ability.getControllerId());
+ if (controller == null) {
+ return;
+ }
+ UUID opponentId = null;
+ if (game.getOpponents(controller.getId()).size() > 1) {
+ Target target = new TargetOpponent(true);
+ if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) {
+ opponentId = target.getFirstTarget();
+ }
+ } else {
+ opponentId = game.getOpponents(controller.getId()).iterator().next();
+ }
+ if (opponentId != null) {
+ ability.getTargets().get(0).setTargetController(opponentId);
}
- return false;
}
}
diff --git a/Mage.Sets/src/mage/cards/n/Necrite.java b/Mage.Sets/src/mage/cards/n/Necrite.java
index bc0b994b982..56fc010bedf 100644
--- a/Mage.Sets/src/mage/cards/n/Necrite.java
+++ b/Mage.Sets/src/mage/cards/n/Necrite.java
@@ -1,31 +1,30 @@
package mage.cards.n;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
-import mage.filter.predicate.permanent.ControllerIdPredicate;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.target.Target;
import mage.target.TargetPermanent;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
+
+import java.util.UUID;
/**
*
* @author MarcoMarin
*/
public final class Necrite extends CardImpl {
+ static FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls");
public Necrite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
@@ -35,10 +34,10 @@ public final class Necrite extends CardImpl {
// Whenever Necrite attacks and isn't blocked, you may sacrifice it. If you do, destroy target creature defending player controls. It can't be regenerated.
DoIfCostPaid effect = new DoIfCostPaid(new DestroyTargetEffect(true), new SacrificeSourceCost(), "Sacrifice {this} to destroy target creature defending player controls?");
- effect.setText("you may sacrifice it. If you do, destroy target creature defending player controls. It can't be regenerated.");
- Ability ability = new NecriteTriggeredAbility(effect);
+ Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER);
+ ability.addTarget(new TargetPermanent(filter));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
-
}
private Necrite(final Necrite card) {
@@ -50,33 +49,3 @@ public final class Necrite extends CardImpl {
return new Necrite(this);
}
}
-
-class NecriteTriggeredAbility extends AttacksAndIsNotBlockedTriggeredAbility{
-
- public NecriteTriggeredAbility(Effect effect) {
- super(effect);
- }
-
- private NecriteTriggeredAbility(final NecriteTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public NecriteTriggeredAbility copy() {
- return new NecriteTriggeredAbility(this);
- }
-
- @Override
- public boolean checkTrigger(GameEvent event, Game game) {
- if (super.checkTrigger(event, game)){
- UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game);
- FilterPermanent filter = new FilterCreaturePermanent();
- filter.add(new ControllerIdPredicate(defendingPlayerId));
- Target target = new TargetPermanent(filter);
- this.getTargets().clear();
- this.addTarget(target);
- return true;
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/n/NestOfScarabs.java b/Mage.Sets/src/mage/cards/n/NestOfScarabs.java
index 66c39c6f280..d4545e85df7 100644
--- a/Mage.Sets/src/mage/cards/n/NestOfScarabs.java
+++ b/Mage.Sets/src/mage/cards/n/NestOfScarabs.java
@@ -20,8 +20,10 @@ public final class NestOfScarabs extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
// Whenever you put one or more -1/-1 counters on a creature, create that many 1/1 black Insect creature tokens.
- this.addAbility(new PutCounterOnCreatureTriggeredAbility(new CreateTokenEffect(new NestOfScarabsBlackInsectToken(), new EffectKeyValue("countersAdded"))
- .setText("create that many 1/1 black Insect creature tokens"), CounterType.M1M1.createInstance()));
+ this.addAbility(new PutCounterOnCreatureTriggeredAbility(
+ new CreateTokenEffect(new NestOfScarabsBlackInsectToken(),
+ new EffectKeyValue("countersAdded", "that many")),
+ CounterType.M1M1.createInstance()));
}
private NestOfScarabs(final NestOfScarabs card) {
diff --git a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java
index 403faf3ab60..9afa9db5bf5 100644
--- a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java
+++ b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java
@@ -1,22 +1,26 @@
package mage.cards.o;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
-import mage.abilities.effects.Effect;
+import mage.abilities.Ability;
+import mage.abilities.TriggeredAbility;
+import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.SuperType;
+import mage.constants.WatcherScope;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
-import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
-import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
-import mage.players.Player;
import mage.target.TargetPermanent;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
+import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.*;
@@ -25,6 +29,7 @@ import java.util.*;
* @author TheElk801
*/
public final class OKagachiVengefulKami extends CardImpl {
+ static FilterPermanent filter = new FilterNonlandPermanent("nonland permanent that player controls");
public OKagachiVengefulKami(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}{R}{G}");
@@ -42,7 +47,11 @@ public final class OKagachiVengefulKami extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Whenever O-Kagachi, Vengeful Kami deals combat damage to a player, if that player attacked you during their last turn, exile target nonland permanent that player controls
- this.addAbility(new OKagachiVengefulKamiTriggeredAbility());
+ TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ExileTargetEffect(), false, true);
+ ability.addTarget(new TargetPermanent(filter));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
+ ability.withInterveningIf(KagachiVengefulKamiCondition.instance);
+ this.addAbility(ability);
}
private OKagachiVengefulKami(final OKagachiVengefulKami card) {
@@ -55,66 +64,25 @@ public final class OKagachiVengefulKami extends CardImpl {
}
}
-class OKagachiVengefulKamiTriggeredAbility extends TriggeredAbilityImpl {
-
- OKagachiVengefulKamiTriggeredAbility() {
- super(Zone.BATTLEFIELD, new ExileTargetEffect(), false);
- this.addWatcher(new OKagachiVengefulKamiWatcher());
- }
-
- private OKagachiVengefulKamiTriggeredAbility(final OKagachiVengefulKamiTriggeredAbility ability) {
- super(ability);
- }
+enum KagachiVengefulKamiCondition implements Condition {
+ instance;
@Override
- public OKagachiVengefulKamiTriggeredAbility copy() {
- return new OKagachiVengefulKamiTriggeredAbility(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.getTargetId());
- if (player == null
- || !((DamagedPlayerEvent) event).isCombatDamage()
- || !event.getSourceId().equals(getSourceId())) {
- return false;
- }
- this.getEffects().setValue("damagedPlayer", event.getTargetId());
- FilterPermanent filter = new FilterNonlandPermanent("nonland permanent controlled by " + player.getName());
- filter.add(new ControllerIdPredicate(event.getTargetId()));
- this.getTargets().clear();
- this.addTarget(new TargetPermanent(filter));
- return true;
- }
-
- @Override
- public boolean checkInterveningIfClause(Game game) {
+ public boolean apply(Game game, Ability source) {
OKagachiVengefulKamiWatcher watcher = game.getState().getWatcher(OKagachiVengefulKamiWatcher.class);
if (watcher == null) {
return false;
}
- UUID playerId = null;
- for (Effect effect : this.getEffects()) {
- Object obj = effect.getValue("damagedPlayer");
- if (obj instanceof UUID) {
- playerId = (UUID) obj;
- break;
- }
- }
- return watcher.checkPlayer(getControllerId(), playerId);
+ return CardUtil.getEffectValueFromAbility(source, "damagedPlayer", UUID.class)
+ .filter(uuid -> watcher.checkPlayer(source.getControllerId(), uuid))
+ .isPresent();
}
@Override
- public String getRule() {
- return "Whenever {this} deals combat damage to a player, " +
- "if that player attacked you during their last turn, " +
- "exile target nonland permanent that player controls.";
+ public String toString() {
+ return "if that player attacked you during their last turn";
}
+
}
class OKagachiVengefulKamiWatcher extends Watcher {
diff --git a/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java b/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java
index 96a82a5c3e8..0455c5b46d8 100644
--- a/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java
+++ b/Mage.Sets/src/mage/cards/o/OrahSkyclaveHierophant.java
@@ -1,19 +1,25 @@
package mage.cards.o;
import mage.MageInt;
-import mage.MageObject;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.Ability;
+import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.keyword.LifelinkAbility;
+import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.SuperType;
import mage.filter.FilterCard;
-import mage.filter.predicate.mageobject.ManaValuePredicate;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledPermanent;
+import mage.filter.predicate.ObjectSourcePlayer;
+import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.events.ZoneChangeEvent;
+import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
+import mage.util.CardUtil;
import java.util.UUID;
@@ -21,6 +27,13 @@ import java.util.UUID;
* @author TheElk801
*/
public final class OrahSkyclaveHierophant extends CardImpl {
+ static FilterPermanent filterTrigger = new FilterControlledPermanent("Cleric you control");
+ static FilterCard filterTarget = new FilterCard("Cleric card with lesser mana value");
+ static {
+ filterTrigger.add(SubType.CLERIC.getPredicate());
+ filterTarget.add(SubType.CLERIC.getPredicate());
+ filterTarget.add(OrahSkyclaveHierophantPredicate.instance);
+ }
public OrahSkyclaveHierophant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}");
@@ -35,7 +48,9 @@ public final class OrahSkyclaveHierophant extends CardImpl {
this.addAbility(LifelinkAbility.getInstance());
// Whenever Orah, Skyclave Hierophant or another Cleric you control dies, return target Cleric card with lesser converted mana cost from your graveyard to the battlefield.
- this.addAbility(new OrahSkyclaveHierophantTriggeredAbility());
+ Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false, filterTrigger);
+ ability.addTarget(new TargetCardInYourGraveyard(filterTarget));
+ this.addAbility(ability);
}
private OrahSkyclaveHierophant(final OrahSkyclaveHierophant card) {
@@ -48,57 +63,15 @@ public final class OrahSkyclaveHierophant extends CardImpl {
}
}
-class OrahSkyclaveHierophantTriggeredAbility extends TriggeredAbilityImpl {
-
- OrahSkyclaveHierophantTriggeredAbility() {
- super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect());
- setLeavesTheBattlefieldTrigger(true);
- }
-
- private OrahSkyclaveHierophantTriggeredAbility(final OrahSkyclaveHierophantTriggeredAbility ability) {
- super(ability);
- }
+enum OrahSkyclaveHierophantPredicate implements ObjectSourcePlayerPredicate {
+ instance;
@Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.ZONE_CHANGE;
- }
-
- @Override
- public boolean checkTrigger(GameEvent event, Game game) {
- ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
- if (!zEvent.isDiesEvent()
- || !zEvent.getTarget().isControlledBy(getControllerId())
- || (!zEvent.getTarget().hasSubtype(SubType.CLERIC, game)
- && !zEvent.getTarget().getId().equals(getSourceId()))
- ) {
- return false;
- }
- FilterCard filterCard = new FilterCard(
- "Cleric card with mana value less than " + (zEvent.getTarget().getManaValue())
- );
- filterCard.add(SubType.CLERIC.getPredicate());
- filterCard.add(new ManaValuePredicate(
- ComparisonType.FEWER_THAN, zEvent.getTarget().getManaValue()
- ));
- this.getTargets().clear();
- this.addTarget(new TargetCardInYourGraveyard(filterCard));
- return true;
- }
-
- @Override
- public OrahSkyclaveHierophantTriggeredAbility copy() {
- return new OrahSkyclaveHierophantTriggeredAbility(this);
- }
-
- @Override
- public String getRule() {
- return "Whenever {this} or another Cleric you control dies, return target Cleric card " +
- "with lesser mana value from your graveyard to the battlefield.";
- }
-
- @Override
- public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
- return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
+ public boolean apply(ObjectSourcePlayer input, Game game) {
+ return CardUtil.getEffectValueFromAbility(
+ input.getSource(), "creatureDied", Permanent.class
+ )
+ .filter(permanent -> input.getObject().getManaValue() < permanent.getManaValue())
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java
index 2d33e36f563..2570380a90e 100644
--- a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java
+++ b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java
@@ -7,20 +7,14 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.DestroyTargetEffect;
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.game.Game;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
import mage.target.common.TargetLandPermanent;
-import mage.util.CardUtil;
+import mage.target.targetadjustment.XTargetsCountAdjuster;
-import java.util.List;
import java.util.UUID;
/**
@@ -38,9 +32,12 @@ public final class OrcishSettlers extends CardImpl {
this.toughness = new MageInt(1);
// {X}{X}{R}, {tap}, Sacrifice Orcish Settlers: Destroy X target lands.
- Ability ability = new SimpleActivatedAbility(new OrcishSettlersEffect(), new ManaCostsImpl<>("{X}{X}{R}"));
+ Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect().setText("Destroy X target lands"),
+ new ManaCostsImpl<>("{X}{X}{R}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
+ ability.addTarget(new TargetLandPermanent());
+ ability.setTargetAdjuster(new XTargetsCountAdjuster());
this.addAbility(ability);
}
@@ -53,43 +50,3 @@ public final class OrcishSettlers extends CardImpl {
return new OrcishSettlers(this);
}
}
-
-class OrcishSettlersEffect extends OneShotEffect {
-
- OrcishSettlersEffect() {
- super(Outcome.DestroyPermanent);
- this.staticText = "Destroy X target lands";
- }
-
- private OrcishSettlersEffect(final OrcishSettlersEffect effect) {
- super(effect);
- }
-
- @Override
- public OrcishSettlersEffect copy() {
- return new OrcishSettlersEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- int amount = CardUtil.getSourceCostsTag(game, source, "X", 0);
- if (amount == 0) {
- return false;
- }
- TargetLandPermanent target = new TargetLandPermanent(amount);
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null
- && target.canChoose(controller.getId(), source, game)
- && controller.choose(Outcome.DestroyPermanent, target, source, game)) {
- List targets = target.getTargets();
- targets.forEach((landId) -> {
- Permanent land = game.getPermanent(landId);
- if (land != null) {
- land.destroy(source, game, false);
- }
- });
- return true;
- }
- return false;
- }
-}
diff --git a/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java b/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java
index 0c48850b2c3..b2ade10d334 100644
--- a/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java
+++ b/Mage.Sets/src/mage/cards/p/PawpatchRecruit.java
@@ -22,6 +22,7 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.StackObject;
import mage.target.TargetPermanent;
+import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
import java.util.UUID;
@@ -65,6 +66,7 @@ class PawpatchRecruitTriggeredAbility extends TriggeredAbilityImpl {
public PawpatchRecruitTriggeredAbility() {
super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false);
+ this.setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
private PawpatchRecruitTriggeredAbility(final PawpatchRecruitTriggeredAbility ability) {
diff --git a/Mage.Sets/src/mage/cards/r/RampagingRaptor.java b/Mage.Sets/src/mage/cards/r/RampagingRaptor.java
index bf4ee11f65b..4f69d51409a 100644
--- a/Mage.Sets/src/mage/cards/r/RampagingRaptor.java
+++ b/Mage.Sets/src/mage/cards/r/RampagingRaptor.java
@@ -1,7 +1,8 @@
package mage.cards.r;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.Ability;
+import mage.abilities.common.DealsDamageToOpponentTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
@@ -14,16 +15,15 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
-import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.permanent.ProtectorIdPredicate;
import mage.game.Game;
-import mage.game.events.DamagedEvent;
-import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.TargetPermanent;
+import mage.target.targetadjustment.TargetAdjuster;
+import mage.target.targetpointer.FirstTargetPointer;
import java.util.UUID;
@@ -51,7 +51,10 @@ public final class RampagingRaptor extends CardImpl {
));
// Whenever Rampaging Raptor deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls or battle that player protects.
- this.addAbility(new RampagingRaptorTriggeredAbility());
+ Ability ability = new DealsDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH)
+ .withTargetDescription("target planeswalker that player controls or battle that player protects"), false, true, true);
+ ability.setTargetAdjuster(RampagingRaptorTargetAdjuster.instance);
+ this.addAbility(ability);
}
private RampagingRaptor(final RampagingRaptor card) {
@@ -64,33 +67,17 @@ public final class RampagingRaptor extends CardImpl {
}
}
-class RampagingRaptorTriggeredAbility extends TriggeredAbilityImpl {
-
- RampagingRaptorTriggeredAbility() {
- super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH), false);
- }
-
- private RampagingRaptorTriggeredAbility(final RampagingRaptorTriggeredAbility ability) {
- super(ability);
- }
+enum RampagingRaptorTargetAdjuster implements TargetAdjuster {
+ instance;
@Override
- public RampagingRaptorTriggeredAbility copy() {
- return new RampagingRaptorTriggeredAbility(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 opponent = game.getPlayer(event.getPlayerId());
- if (opponent == null
- || !event.getSourceId().equals(this.getSourceId())
- || !((DamagedEvent) event).isCombatDamage()) {
- return false;
+ public void adjustTargets(Ability ability, Game game) {
+ UUID opponentId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability);
+ Player opponent = game.getPlayer(opponentId);
+ ability.getTargets().clear();
+ ability.getAllEffects().setTargetPointer(new FirstTargetPointer());
+ if (opponent == null) {
+ return;
}
FilterPermanent filter = new FilterPermanent(
"planeswalker " + opponent.getLogName() + " controls " +
@@ -106,15 +93,6 @@ class RampagingRaptorTriggeredAbility extends TriggeredAbilityImpl {
new ProtectorIdPredicate(opponent.getId())
)
));
- this.getEffects().setValue("damage", event.getAmount());
- this.getTargets().clear();
- this.addTarget(new TargetPermanent(filter));
- return true;
- }
-
- @Override
- public String getRule() {
- return "Whenever {this} deals combat damage to an opponent, it deals that much damage " +
- "to target planeswalker that player controls or battle that player protects.";
+ ability.addTarget(new TargetPermanent(filter));
}
}
diff --git a/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java b/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java
index 36302890eb2..f9a6a8324b6 100644
--- a/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java
+++ b/Mage.Sets/src/mage/cards/r/RampagingWarMammoth.java
@@ -1,22 +1,21 @@
package mage.cards.r;
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.EffectKeyValue;
import mage.abilities.effects.common.DestroyTargetEffect;
-import mage.abilities.hint.StaticHint;
import mage.abilities.keyword.CyclingAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.stack.StackObject;
-import mage.target.common.TargetArtifactPermanent;
-import mage.util.CardUtil;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterArtifactPermanent;
+import mage.target.TargetPermanent;
+import mage.target.targetadjustment.TargetsCountAdjuster;
import java.util.UUID;
@@ -24,6 +23,7 @@ import java.util.UUID;
* @author Susucr
*/
public final class RampagingWarMammoth extends CardImpl {
+ static FilterPermanent filter = new FilterArtifactPermanent("up to X target artifacts");
public RampagingWarMammoth(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}");
@@ -39,7 +39,10 @@ public final class RampagingWarMammoth extends CardImpl {
this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{2}{R}")));
// When you cycle Rampaging War Mammoth, destroy up to X target artifacts.
- this.addAbility(new RampagingWarMammothTriggeredAbility());
+ Ability ability = new CycleTriggeredAbility(new DestroyTargetEffect());
+ ability.addTarget(new TargetPermanent(0,1, filter));
+ ability.setTargetAdjuster(new TargetsCountAdjuster(new EffectKeyValue("cycleXValue")));
+ this.addAbility(ability);
}
private RampagingWarMammoth(final RampagingWarMammoth card) {
@@ -51,56 +54,3 @@ public final class RampagingWarMammoth extends CardImpl {
return new RampagingWarMammoth(this);
}
}
-
-class RampagingWarMammothTriggeredAbility extends ZoneChangeTriggeredAbility {
-
- RampagingWarMammothTriggeredAbility() {
- super(Zone.ALL, null, "", false);
- }
-
- private RampagingWarMammothTriggeredAbility(RampagingWarMammothTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
- }
-
- @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;
- }
-
- CyclingAbility cyclingAbility = (CyclingAbility) object.getStackAbility();
- // If X is 0, or cycling from another ability that does not have {X} in cost,
- // this should trigger (but do nothing).
- int xValue = CardUtil.getSourceCostsTag(game, cyclingAbility, "X", 0);
-
- this.getEffects().clear();
- this.getTargets().clear();
-
- this.addEffect(new DestroyTargetEffect());
- // Target up to X artifacts
- this.addTarget(new TargetArtifactPermanent(0, xValue));
- this.getHints().clear();
- this.addHint(new StaticHint("X = " + xValue));
-
- return true;
- }
-
- @Override
- public RampagingWarMammothTriggeredAbility copy() {
- return new RampagingWarMammothTriggeredAbility(this);
- }
-
- @Override
- public String getRule() {
- return "When you cycle {this}, destroy up to X target artifacts.";
- }
-}
diff --git a/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java b/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java
index eeaacab7a2b..1e877367a4f 100644
--- a/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java
+++ b/Mage.Sets/src/mage/cards/r/RavenousGigantotherium.java
@@ -3,6 +3,8 @@ package mage.cards.r;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DamageMultiEffect;
import mage.abilities.keyword.DevourAbility;
@@ -12,10 +14,10 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanentAmount;
+import mage.util.CardUtil;
import java.util.Collection;
import java.util.List;
@@ -39,7 +41,11 @@ public final class RavenousGigantotherium extends CardImpl {
this.addAbility(new DevourAbility(3));
// When Ravenous Gigantotherium enters the battlefield, it deals X damage divided as you choose among up to X target creatures, where X is its power. Each of those creatures deals damage equal to its power to Ravenous Gigantotherium.
- this.addAbility(new RavenousGigantotheriumAbility());
+ Ability ability = new EntersBattlefieldTriggeredAbility(new DamageMultiEffect());
+ ability.addEffect(new RavenousGigantotheriumEffect());
+ ability.addTarget(new TargetCreaturePermanentAmount(RavenousGigantotheriumAmount.instance)
+ .withTargetName("up to X target creatures, where X is its power"));
+ this.addAbility(ability);
}
private RavenousGigantotherium(final RavenousGigantotherium card) {
@@ -52,47 +58,28 @@ public final class RavenousGigantotherium extends CardImpl {
}
}
-class RavenousGigantotheriumAbility extends EntersBattlefieldTriggeredAbility {
+enum RavenousGigantotheriumAmount implements DynamicValue {
+ instance;
- RavenousGigantotheriumAbility() {
- super(null, false);
- }
-
- private RavenousGigantotheriumAbility(final RavenousGigantotheriumAbility ability) {
- super(ability);
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ return CardUtil.getEffectValueFromAbility(sourceAbility, "permanentEnteredBattlefield", Permanent.class)
+ .map(permanent -> permanent.getPower().getValue()).orElse(0);
}
@Override
- public boolean checkTrigger(GameEvent event, Game game) {
- if (!super.checkTrigger(event, game)) {
- return false;
- }
- Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
- if (permanent == null) {
- return false;
- }
- int power = Math.max(permanent.getPower().getValue(), 0);
- this.getEffects().clear();
- this.addEffect(new DamageMultiEffect());
- this.addEffect(new RavenousGigantotheriumEffect());
- this.getTargets().clear();
- if (power < 1) {
- return true;
- }
- this.addTarget(new TargetCreaturePermanentAmount(power, 0, power));
- return true;
+ public DynamicValue copy() {
+ return instance;
}
@Override
- public String getRule() {
- return "When {this} enters, it deals X damage " +
- "divided as you choose among up to X target creatures, where X is its power. " +
- "Each of those creatures deals damage equal to its power to {this}.";
+ public String getMessage() {
+ return "its power";
}
@Override
- public RavenousGigantotheriumAbility copy() {
- return new RavenousGigantotheriumAbility(this);
+ public String toString() {
+ return "X";
}
}
@@ -100,6 +87,7 @@ class RavenousGigantotheriumEffect extends OneShotEffect {
RavenousGigantotheriumEffect() {
super(Outcome.Benefit);
+ this.setText("Each of those creatures deals damage equal to its power to {this}.");
}
private RavenousGigantotheriumEffect(final RavenousGigantotheriumEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/r/RelentlessDead.java b/Mage.Sets/src/mage/cards/r/RelentlessDead.java
index 3d5f3299013..cc3fe4406b5 100644
--- a/Mage.Sets/src/mage/cards/r/RelentlessDead.java
+++ b/Mage.Sets/src/mage/cards/r/RelentlessDead.java
@@ -3,22 +3,21 @@ package mage.cards.r;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DiesSourceTriggeredAbility;
+import mage.abilities.costs.common.DynamicValueGenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.dynamicvalue.common.TargetManaValue;
import mage.abilities.effects.common.DoIfCostPaid;
+import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.keyword.MenaceAbility;
-import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
import mage.filter.FilterCard;
+import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.AnotherPredicate;
-import mage.filter.predicate.mageobject.ManaValuePredicate;
-import mage.game.Game;
-import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
-import mage.util.ManaUtil;
import java.util.UUID;
@@ -26,6 +25,11 @@ import java.util.UUID;
* @author LevelX2
*/
public final class RelentlessDead extends CardImpl {
+ static FilterCard filter = new FilterCreatureCard("another target Zombie creature card with mana value X from your graveyard"); // This target defines X
+ static{
+ filter.add(SubType.ZOMBIE.getPredicate());
+ filter.add(AnotherPredicate.instance);
+ }
public RelentlessDead(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}");
@@ -40,7 +44,11 @@ public final class RelentlessDead extends CardImpl {
this.addAbility(new DiesSourceTriggeredAbility(new DoIfCostPaid(new ReturnToHandSourceEffect().setText("return it to its owner's hand"), new ManaCostsImpl<>("{B}"))));
// When Relentless Dead dies, you may pay {X}. If you do, return another target Zombie creature card with converted mana cost X from your graveyard to the battlefield.
- this.addAbility(new DiesSourceTriggeredAbility(new RelentlessDeadEffect()));
+ Ability ability = new DiesSourceTriggeredAbility(new DoIfCostPaid(
+ new ReturnFromGraveyardToBattlefieldTargetEffect(),
+ new DynamicValueGenericManaCost(TargetManaValue.instance, "{X}")));
+ ability.addTarget(new TargetCardInYourGraveyard(filter));
+ this.addAbility(ability);
}
private RelentlessDead(final RelentlessDead card) {
@@ -52,46 +60,3 @@ public final class RelentlessDead extends CardImpl {
return new RelentlessDead(this);
}
}
-
-class RelentlessDeadEffect extends OneShotEffect {
-
- RelentlessDeadEffect() {
- super(Outcome.PutCardInPlay);
- this.staticText = "you may pay {X}. If you do, return another target Zombie creature card with mana value X from your graveyard to the battlefield";
- }
-
- private RelentlessDeadEffect(final RelentlessDeadEffect effect) {
- super(effect);
- }
-
- @Override
- public RelentlessDeadEffect copy() {
- return new RelentlessDeadEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
- if (controller.chooseUse(Outcome.Benefit, "Do you want to pay {X} to return zombie?", source, game)) {
- int payCount = ManaUtil.playerPaysXGenericMana(true, "Relentless Dead", controller, source, game);
- // can be 0
- FilterCard filter = new FilterCard("Another target Zombie card with mana value {" + payCount + "}");
- filter.add(SubType.ZOMBIE.getPredicate());
- filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, payCount));
- filter.add(AnotherPredicate.instance);
- TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter);
- if (controller.chooseTarget(outcome, target, source, game)) {
- Card card = game.getCard(target.getFirstTarget());
- if (card != null) {
- controller.moveCards(card, Zone.BATTLEFIELD, source, game);
- }
- }
-
- }
- return true;
- }
- return false;
-
- }
-}
diff --git a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
index 97e6883c30a..5e853ee68c9 100644
--- a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
+++ b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
@@ -1,25 +1,20 @@
package mage.cards.s;
import mage.abilities.Ability;
+import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
-import mage.abilities.common.ZoneChangeTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.CyclingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
-import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.SharkToken;
import mage.game.stack.Spell;
-import mage.game.stack.StackObject;
-import mage.util.CardUtil;
import java.util.UUID;
@@ -42,7 +37,7 @@ public final class SharkTyphoon extends CardImpl {
this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{1}{U}")));
// When you cycle Shark Typhoon, create an X/X blue Shark creature token with flying.
- this.addAbility(new SharkTyphoonTriggeredAbility());
+ this.addAbility(new CycleTriggeredAbility(new SharkTyphoonCycleEffect()));
}
private SharkTyphoon(final SharkTyphoon card) {
@@ -82,42 +77,29 @@ class SharkTyphoonCastEffect extends OneShotEffect {
}
}
-class SharkTyphoonTriggeredAbility extends ZoneChangeTriggeredAbility {
+class SharkTyphoonCycleEffect extends OneShotEffect {
- SharkTyphoonTriggeredAbility() {
- super(Zone.ALL, null, "", false);
+ SharkTyphoonCycleEffect() {
+ super(Outcome.Benefit);
+ staticText = "create an X/X blue Shark creature token with flying";
}
- private SharkTyphoonTriggeredAbility(SharkTyphoonTriggeredAbility ability) {
- super(ability);
+ private SharkTyphoonCycleEffect(final SharkTyphoonCycleEffect effect) {
+ super(effect);
}
@Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
+ public SharkTyphoonCycleEffect copy() {
+ return new SharkTyphoonCycleEffect(this);
}
@Override
- public boolean checkTrigger(GameEvent event, Game game) {
- if (!event.getSourceId().equals(this.getSourceId())) {
- return false;
+ public boolean apply(Game game, Ability source) {
+ Object xValueObject = getValue("cycleXValue");
+ int xValue = 0;
+ if (xValueObject instanceof Integer) {
+ xValue = (int) xValueObject;
}
- StackObject object = game.getStack().getStackObject(event.getSourceId());
- if (object == null || !(object.getStackAbility() instanceof CyclingAbility)) {
- return false;
- }
- this.getEffects().clear();
- this.addEffect(new CreateTokenEffect(new SharkToken(CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0))));
- return true;
- }
-
- @Override
- public SharkTyphoonTriggeredAbility copy() {
- return new SharkTyphoonTriggeredAbility(this);
- }
-
- @Override
- public String getRule() {
- return "When you cycle this card, create an X/X blue Shark creature token with flying.";
+ return new SharkToken(xValue).putOntoBattlefield(1, game, source, source.getControllerId());
}
}
diff --git a/Mage.Sets/src/mage/cards/v/ValorsFlagship.java b/Mage.Sets/src/mage/cards/v/ValorsFlagship.java
index 4bc90315f4f..d72e3615232 100644
--- a/Mage.Sets/src/mage/cards/v/ValorsFlagship.java
+++ b/Mage.Sets/src/mage/cards/v/ValorsFlagship.java
@@ -1,8 +1,9 @@
package mage.cards.v;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
+import mage.abilities.dynamicvalue.common.EffectKeyValue;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.*;
import mage.cards.CardImpl;
@@ -10,12 +11,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.PilotSaddleCrewToken;
-import mage.game.stack.StackObject;
-import mage.util.CardUtil;
import java.util.UUID;
@@ -48,7 +44,8 @@ public final class ValorsFlagship extends CardImpl {
this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{X}{2}{W}")));
// When you cycle this card, create X 1/1 colorless Pilot creature tokens with "This token saddles Mounts and crews Vehicles as though its power were 2 greater."
- this.addAbility(new ValorsFlagshipTriggeredAbility());
+ this.addAbility(new CycleTriggeredAbility(
+ new CreateTokenEffect(new PilotSaddleCrewToken(), new EffectKeyValue("cycleXValue", "X"))));
}
private ValorsFlagship(final ValorsFlagship card) {
@@ -60,45 +57,3 @@ public final class ValorsFlagship extends CardImpl {
return new ValorsFlagship(this);
}
}
-
-class ValorsFlagshipTriggeredAbility extends TriggeredAbilityImpl {
-
- ValorsFlagshipTriggeredAbility() {
- super(Zone.ALL, null);
- }
-
- private ValorsFlagshipTriggeredAbility(final ValorsFlagshipTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public ValorsFlagshipTriggeredAbility copy() {
- return new ValorsFlagshipTriggeredAbility(this);
- }
-
- @Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
- }
-
- @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;
- }
- this.getEffects().clear();
- int amount = CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0);
- this.addEffect(new CreateTokenEffect(new PilotSaddleCrewToken(), amount));
- return true;
- }
-
- @Override
- public String getRule() {
- return "When you cycle this card, create X 1/1 colorless Pilot creature tokens with " +
- "\"This token saddles Mounts and crews Vehicles as though its power were 2 greater.\"";
- }
-}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java
index cbc4742c9a4..04696cceb3a 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CyclingTest.java
@@ -61,6 +61,24 @@ public class CyclingTest extends CardTestPlayerBase {
assertPowerToughness(playerB, "Pillarfield Ox", 0, 2);
}
+ /**
+ * Tests that X value is correctly read by the resulting triggered ability
+ */
+ @Test
+ public void cycleSharkTyphoon() {
+ addCard(Zone.HAND, playerA, "Shark Typhoon", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling");
+ setChoice(playerA, "X=6");
+
+ setStopAt(1, PhaseStep.BEGIN_COMBAT);
+ execute();
+ assertGraveyardCount(playerA, "Shark Typhoon", 1);
+ assertPowerToughness(playerA, "Shark Token", 6, 6);
+ assertTappedCount("Island", true, 8);
+ }
+
/**
* Cycle from graveyard or battlefield should not work.
*/
diff --git a/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java
index 0e08ea66c72..606b36db71c 100644
--- a/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/CycleTriggeredAbility.java
@@ -6,6 +6,7 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.StackObject;
+import mage.util.CardUtil;
/**
* @author Plopman
@@ -40,6 +41,7 @@ public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility {
return false;
}
this.getEffects().setValue("cycleCosts", object.getStackAbility().getCosts());
+ this.getEffects().setValue("cycleXValue", CardUtil.getSourceCostsTag(game, object.getStackAbility(), "X", 0));
return true;
}
diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java
index b3cbe5cb55d..23001575e37 100644
--- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java
+++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/EffectKeyValue.java
@@ -10,8 +10,8 @@ import mage.game.Game;
* @author stravant
*/
public class EffectKeyValue implements DynamicValue {
- private String key;
- private String description;
+ private final String key;
+ private final String description;
public EffectKeyValue(String key) {
this.key = key;
@@ -19,7 +19,7 @@ public class EffectKeyValue implements DynamicValue {
}
public EffectKeyValue(String key, String description) {
- this(key);
+ this.key = key;
this.description = description;
}
@@ -35,11 +35,11 @@ public class EffectKeyValue implements DynamicValue {
@Override
public String toString() {
- return "equal to";
+ return description;
}
@Override
public String getMessage() {
- return description;
+ return "";
}
-}
\ No newline at end of file
+}
diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java
index 1a15044b417..19dd98814b0 100644
--- a/Mage/src/main/java/mage/target/TargetImpl.java
+++ b/Mage/src/main/java/mage/target/TargetImpl.java
@@ -111,7 +111,7 @@ public abstract class TargetImpl implements Target {
if (min > 0 && max == Integer.MAX_VALUE) {
sb.append(CardUtil.numberToText(min));
sb.append(" or more ");
- } else if (!targetName.startsWith("X ") && (min != 1 || max != 1)) {
+ } else if (!targetName.startsWith("X ") && !targetName.startsWith("up to ") && (min != 1 || max != 1)) {
targetName = targetName.replace("another", "other"); //If non-singular, use "other" instead of "another"
if (getUseAnyNumber()) {