Adding targets (Part 1/3) (#13680)

Adds target and/or target adjuster to cards whose abilities have the word "target", cards A-G.
Creates SourceDealsNoncombatDamageToOpponentTriggeredAbility and DefineByTriggerTargetAdjuster
This commit is contained in:
ssk97 2025-06-17 22:35:49 -07:00 committed by GitHub
parent 6d3bd7a19f
commit 9ce5dd212a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 355 additions and 729 deletions

View file

@ -5,7 +5,9 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -13,9 +15,9 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInOpponentsGraveyard;
@ -37,7 +39,10 @@ public final class AgadeemOccultist extends CardImpl {
this.toughness = new MageInt(2);
// {tap}: Put target creature card from an opponent's graveyard onto the battlefield under your control if its converted mana cost is less than or equal to the number of Allies you control.
this.addAbility(new SimpleActivatedAbility(new AgadeemOccultistEffect(), new TapSourceCost()));
Ability ability = new SimpleActivatedAbility(new AgadeemOccultistEffect(), new TapSourceCost());
ability.addTarget(new TargetCardInOpponentsGraveyard(new FilterCreatureCard("target creature card from an opponent's graveyard")));
ability.addHint(new ValueHint("Allies you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ALLY))));
this.addAbility(ability);
}
@ -50,7 +55,6 @@ public final class AgadeemOccultist extends CardImpl {
return new AgadeemOccultist(this);
}
}
class AgadeemOccultistEffect extends OneShotEffect {
AgadeemOccultistEffect() {
@ -70,28 +74,14 @@ class AgadeemOccultistEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
int allycount = 0;
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
if (permanent.hasSubtype(SubType.ALLY, game)) {
allycount++;
}
}
FilterCard filter = new FilterCard("creature card in an opponent's graveyard");
filter.add(CardType.CREATURE.getPredicate());
TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(1, 1, filter);
if (controller != null) {
if (target.canChoose(source.getControllerId(), source, game)
&& controller.choose(Outcome.GainControl, target, source, game)) {
if (!target.getTargets().isEmpty()) {
Card card = game.getCard(target.getFirstTarget());
Card card = game.getCard(source.getFirstTarget());
if (card != null) {
int allycount = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ALLY)).calculate(game, source, this);
if (card.getManaValue() <= allycount) {
return controller.moveCards(card, Zone.BATTLEFIELD, source, game);
}
}
}
}
return true;
}
return false;

View file

@ -1,21 +1,20 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
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.target.common.TargetCreaturePermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
/**
*
@ -32,7 +31,11 @@ public final class AvalancheTusker extends CardImpl {
this.toughness = new MageInt(4);
// Whenever Avalanche Tusker attacks, target creature defending player controls blocks it this turn if able.
this.addAbility(new AvalancheTuskerAbility());
Ability ability = new AttacksTriggeredAbility(new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat)
.setText("target creature defending player controls blocks it this combat if able"), false, null, SetTargetPointer.PLAYER);
ability.addTarget(new TargetCreaturePermanent());
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private AvalancheTusker(final AvalancheTusker card) {
@ -44,44 +47,3 @@ public final class AvalancheTusker extends CardImpl {
return new AvalancheTusker(this);
}
}
class AvalancheTuskerAbility extends TriggeredAbilityImpl {
public AvalancheTuskerAbility() {
super(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(Duration.EndOfCombat), false);
}
private AvalancheTuskerAbility(final AvalancheTuskerAbility 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(filter);
this.addTarget(target);
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} attacks, target creature defending player controls blocks it this combat if able.";
}
@Override
public AvalancheTuskerAbility copy() {
return new AvalancheTuskerAbility(this);
}
}

View file

@ -1,31 +1,34 @@
package mage.cards.b;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.FlyingAbility;
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.FilterNonlandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.GenericTargetAdjuster;
import mage.target.targetpointer.FirstTargetPointer;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class BladegriffPrototype extends CardImpl {
static FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent of that player's choice that one of your opponents controls");
static{
filter.add(BladegriffSourceOpponentControlsPredicate.instance);
}
public BladegriffPrototype(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}");
@ -38,7 +41,10 @@ public final class BladegriffPrototype extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Bladegriff Prototype deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls.
this.addAbility(new BladegriffPrototypeAbility());
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
ability.setTargetAdjuster(new ThatPlayersChoiceTargetAdjuster());
this.addAbility(ability);
}
private BladegriffPrototype(final BladegriffPrototype card) {
@ -50,55 +56,26 @@ public final class BladegriffPrototype extends CardImpl {
return new BladegriffPrototype(this);
}
}
class BladegriffPrototypeAbility extends TriggeredAbilityImpl {
BladegriffPrototypeAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false);
}
private BladegriffPrototypeAbility(final BladegriffPrototypeAbility ability) {
super(ability);
}
enum BladegriffSourceOpponentControlsPredicate implements ObjectSourcePlayerPredicate<Controllable> {
instance;
@Override
public BladegriffPrototypeAbility copy() {
return new BladegriffPrototypeAbility(this);
public boolean apply(ObjectSourcePlayer<Controllable> input, Game game) {
Controllable object = input.getObject();
UUID playerId = input.getSource().getControllerId();
return !object.isControlledBy(playerId)
&& game.getPlayer(playerId).hasOpponent(object.getControllerId(), game);
}
}
class ThatPlayersChoiceTargetAdjuster extends GenericTargetAdjuster {
@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(getControllerId());
if (player == null
|| !event.getSourceId().equals(this.sourceId)
|| !((DamagedEvent) event).isCombatDamage()) {
return false;
}
FilterPermanent filter = new FilterNonlandPermanent(
"nonland permanent controlled by an opponent of " + player.getName()
);
filter.add(Predicates.or(
game.getOpponents(getControllerId())
.stream()
.map(ControllerIdPredicate::new)
.collect(Collectors.toSet())
));
TargetPermanent target = new TargetPermanent(filter);
target.setTargetController(event.getPlayerId());
this.getTargets().clear();
this.addTarget(target);
return true;
}
@Override
public String getRule() {
return "Whenever {this} deals combat damage to a player, " +
"destroy target nonland permanent of that player's choice " +
"that one of your opponents controls.";
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());
Target newTarget = blueprintTarget.copy();
newTarget.setTargetController(opponentId);
ability.addTarget(newTarget);
}
}

View file

@ -3,21 +3,21 @@ package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import mage.util.CardUtil;
import mage.watchers.Watcher;
@ -46,7 +46,10 @@ public final class ChandrasIncinerator extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Whenever a source you control deals noncombat damage to an opponent, Chandra's Incinerator deals that much damage to target creature or planeswalker that player controls.
this.addAbility(new ChandrasIncineratorTriggeredAbility());
Ability ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH), SetTargetPointer.PLAYER);
ability.addTarget(new TargetPermanent(new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker that player controls")));
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private ChandrasIncinerator(final ChandrasIncinerator card) {
@ -123,47 +126,3 @@ class ChandrasIncineratorWatcher extends Watcher {
return damageMap.getOrDefault(playerId, 0);
}
}
class ChandrasIncineratorTriggeredAbility extends TriggeredAbilityImpl {
ChandrasIncineratorTriggeredAbility() {
super(Zone.BATTLEFIELD, null);
}
private ChandrasIncineratorTriggeredAbility(final ChandrasIncineratorTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
DamagedPlayerEvent dEvent = (DamagedPlayerEvent) event;
if (dEvent.isCombatDamage()
|| !game.getOpponents(event.getTargetId()).contains(getControllerId())
|| !game.getControllerId(event.getSourceId()).equals(getControllerId())) {
return false;
}
this.getEffects().clear();
this.addEffect(new DamageTargetEffect(event.getAmount()));
FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker");
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
@Override
public ChandrasIncineratorTriggeredAbility copy() {
return new ChandrasIncineratorTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever a source you control deals noncombat damage to an opponent, " +
"{this} deals that much damage to target creature or planeswalker that player controls.";
}
}

View file

@ -1,7 +1,8 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.DoubleStrikeAbility;
@ -10,13 +11,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import java.util.Objects;
import java.util.UUID;
/**
@ -33,7 +28,9 @@ public final class ChandrasPyreling extends CardImpl {
this.toughness = new MageInt(3);
// Whenever a source you control deals noncombat damage to an opponent, Chandra's Pyreling gets +1/+0 and gains double strike until end of turn.
this.addAbility(new ChandrasPyrelingAbility());
Ability ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn).setText(" this creature gets +1/+0"));
ability.addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn).setText("gains double strike until end of turn").concatBy("and"));
this.addAbility(ability);
}
private ChandrasPyreling(final ChandrasPyreling card) {
@ -45,38 +42,3 @@ public final class ChandrasPyreling extends CardImpl {
return new ChandrasPyreling(this);
}
}
class ChandrasPyrelingAbility extends TriggeredAbilityImpl {
ChandrasPyrelingAbility() {
super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn));
addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn));
}
private ChandrasPyrelingAbility(final ChandrasPyrelingAbility ability) {
super(ability);
}
@Override
public ChandrasPyrelingAbility copy() {
return new ChandrasPyrelingAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
return !damageEvent.isCombatDamage()
&& game.getOpponents(controllerId).contains(event.getTargetId())
&& Objects.equals(controllerId, game.getControllerId(event.getSourceId()));
}
@Override
public String getRule() {
return "Whenever a source you control deals noncombat damage to an opponent, {this} gets +1/+0 and gains double strike until end of turn.";
}
}

View file

@ -2,13 +2,17 @@ package mage.cards.c;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.abilities.keyword.ReachAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
@ -16,10 +20,10 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
import mage.filter.predicate.mageobject.ToughnessPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetadjustment.GenericTargetAdjuster;
import java.util.UUID;
@ -44,7 +48,10 @@ public final class ColfenorTheLastYew extends CardImpl {
this.addAbility(ReachAbility.getInstance());
// Whenever Colfenor, the Last Yew or another creature you control dies, return up to one other target creature card with lesser toughness from your graveyard to your hand.
this.addAbility(new ColfenorTheLastYewTriggeredAbility());
Ability ability = new DiesThisOrAnotherTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false, StaticFilters.FILTER_CONTROLLED_CREATURE);
ability.addTarget(new TargetCardInYourGraveyard(0, 1, new FilterCreatureCard("other target creature card with lesser toughness")));
ability.setTargetAdjuster(new ColfenorTheLastYewTargetAdjuster());
this.addAbility(ability);
}
private ColfenorTheLastYew(final ColfenorTheLastYew card) {
@ -56,43 +63,15 @@ public final class ColfenorTheLastYew extends CardImpl {
return new ColfenorTheLastYew(this);
}
}
class ColfenorTheLastYewTriggeredAbility extends DiesThisOrAnotherTriggeredAbility {
ColfenorTheLastYewTriggeredAbility() {
super(new ReturnFromGraveyardToHandTargetEffect(), false, StaticFilters.FILTER_CONTROLLED_CREATURE);
}
private ColfenorTheLastYewTriggeredAbility(final ColfenorTheLastYewTriggeredAbility ability) {
super(ability);
}
class ColfenorTheLastYewTargetAdjuster extends GenericTargetAdjuster {
@Override
public DiesThisOrAnotherTriggeredAbility copy() {
return new ColfenorTheLastYewTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!super.checkTrigger(event, game)) {
return false;
}
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Permanent permanent = zEvent.getTarget();
if (permanent == null) {
return false;
}
public void adjustTargets(Ability ability, Game game) {
Permanent permanent = (Permanent)ability.getEffects().get(0).getValue("creatureDied");
ability.getTargets().clear();
Target newTarget = blueprintTarget.copy();
FilterCard filterCard = new FilterCreatureCard("creature card with toughness less than " + permanent.getToughness().getValue());
filterCard.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, permanent.getToughness().getValue()));
filterCard.add(Predicates.not(new MageObjectReferencePredicate(new MageObjectReference(permanent, game))));
this.getTargets().clear();
this.addTarget(new TargetCardInYourGraveyard(0, 1, filterCard));
return true;
}
@Override
public String getRule() {
return "Whenever {this} or another creature you control dies, return up to one other target creature card " +
"with lesser toughness from your graveyard to your hand.";
ability.addTarget(newTarget);
}
}

View file

@ -1,20 +1,19 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
*
@ -26,7 +25,10 @@ public final class DeathsPresence extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{G}");
// Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died.
this.addAbility(new DeathsPresenceTriggeredAbility());
this.addAbility(new DiesCreatureTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance(), DeathsPresenceDiedPermanentPowerCount.instance)
.setText("put X +1/+1 counters on target creature you control, where X is the power of the creature that died"),
false, StaticFilters.FILTER_CONTROLLED_CREATURE));
}
private DeathsPresence(final DeathsPresence card) {
@ -39,50 +41,31 @@ public final class DeathsPresence extends CardImpl {
}
}
class DeathsPresenceTriggeredAbility extends TriggeredAbilityImpl {
enum DeathsPresenceDiedPermanentPowerCount implements DynamicValue {
instance;
public DeathsPresenceTriggeredAbility() {
super(Zone.BATTLEFIELD, null);
setLeavesTheBattlefieldTrigger(true);
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
Permanent targetPermanent = (Permanent) effect.getValue("creatureDied");
if (targetPermanent != null) {
return targetPermanent.getPower().getValue();
}
private DeathsPresenceTriggeredAbility(final DeathsPresenceTriggeredAbility ability) {
super(ability);
return 0;
}
@Override
public DeathsPresenceTriggeredAbility copy() {
return new DeathsPresenceTriggeredAbility(this);
public DeathsPresenceDiedPermanentPowerCount copy() {
return DeathsPresenceDiedPermanentPowerCount.instance;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
public String toString() {
return "X";
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zoneChangeEvent = (ZoneChangeEvent) event;
if (zoneChangeEvent.isDiesEvent()) {
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (permanent != null && permanent.isControlledBy(this.getControllerId()) && permanent.isCreature(game)) {
this.getTargets().clear();
this.addTarget(new TargetControlledCreaturePermanent());
this.getEffects().clear();
this.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(permanent.getPower().getValue())));
return true;
}
}
return false;
}
@Override
public String getRule() {
return "Whenever a creature you control dies, put X +1/+1 counters on target creature you control, where X is the power of the creature that died.";
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
public String getMessage() {
return "its power";
}
}

View file

@ -10,13 +10,11 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterLandPermanent;
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.common.TargetLandPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
@ -53,6 +51,8 @@ class DeusOfCalamityTriggeredAbility extends TriggeredAbilityImpl {
public DeusOfCalamityTriggeredAbility() {
super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false);
addTarget(new TargetLandPermanent());
setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
}
private DeusOfCalamityTriggeredAbility(final DeusOfCalamityTriggeredAbility ability) {
@ -74,11 +74,7 @@ class DeusOfCalamityTriggeredAbility extends TriggeredAbilityImpl {
if (event.getSourceId().equals(this.getSourceId())
&& event.getAmount() > 5
&& game.getOpponents(this.getControllerId()).contains(event.getTargetId())) {
FilterPermanent filter = new FilterLandPermanent("land of the damaged player");
filter.add(new ControllerIdPredicate(event.getTargetId()));
Target target = new TargetPermanent(filter);
this.getTargets().clear();
this.addTarget(target);
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
return false;

View file

@ -1,19 +1,16 @@
package mage.cards.d;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.constants.SubType;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.counters.CounterType;
import mage.filter.FilterOpponent;
@ -21,16 +18,23 @@ import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.watchers.Watcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class DiseasedVermin extends CardImpl {
static final FilterOpponent filter = new FilterOpponent("player previously dealt damage by {this}");
static {
filter.add(new DiseasedVerminPredicate());
}
public DiseasedVermin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
@ -46,12 +50,11 @@ public final class DiseasedVermin extends CardImpl {
false));
// At the beginning of your upkeep, Diseased Vermin deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it.
Ability ability = new BeginningOfUpkeepTriggeredAbility(
new DiseasedVerminEffect()
);
Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(new CountersSourceCount(CounterType.INFECTION))
.setText("{this} deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it"));
ability.addTarget(new TargetPlayer(filter));
ability.addWatcher(new DiseasedVerminWatcher());
this.addAbility(ability);
}
private DiseasedVermin(final DiseasedVermin card) {
@ -64,51 +67,6 @@ public final class DiseasedVermin extends CardImpl {
}
}
class DiseasedVerminEffect extends OneShotEffect {
static final FilterOpponent filter = new FilterOpponent("player previously dealt damage by {this}");
static {
filter.add(new DiseasedVerminPredicate());
}
public DiseasedVerminEffect() {
super(Outcome.Benefit);
this.staticText = "{this} deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it";
}
private DiseasedVerminEffect(final DiseasedVerminEffect effect) {
super(effect);
}
@Override
public DiseasedVerminEffect copy() {
return new DiseasedVerminEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null
&& controller != null) {
TargetPlayer targetOpponent = new TargetPlayer(1, 1, false, filter);
if (targetOpponent.canChoose(controller.getId(), source, game)
&& controller.choose(Outcome.Damage, targetOpponent, source, game)) {
Player opponent = game.getPlayer(targetOpponent.getFirstTarget());
if (opponent != null
&& sourcePermanent.getCounters(game).getCount(CounterType.INFECTION) > 0) {
opponent.damage(
sourcePermanent.getCounters(game).getCount(CounterType.INFECTION),
source.getSourceId(), source, game, false, true);
return true;
}
}
}
return false;
}
}
class DiseasedVerminPredicate implements ObjectSourcePlayerPredicate<Player> {
@Override

View file

@ -1,8 +1,9 @@
package mage.cards.f;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility;
import mage.abilities.condition.common.DeliriumCondition;
import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
@ -11,13 +12,9 @@ import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.DamagedEvent;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@ -39,7 +36,13 @@ public final class FearOfBurningAlive extends CardImpl {
));
// Delirium -- Whenever a source you control deals noncombat damage to an opponent, if there are four or more card types among cards in your graveyard, Fear of Burning Alive deals that amount of damage to target creature that player controls.
this.addAbility(new FearOfBurningAliveTriggeredAbility());
TriggeredAbility ability = new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.AMOUNT), SetTargetPointer.PLAYER);
ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that player controls")));
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
ability.withInterveningIf(DeliriumCondition.instance);
ability.setAbilityWord(AbilityWord.DELIRIUM);
ability.addHint(CardTypesInGraveyardCount.YOU.getHint());
this.addAbility(ability);
}
private FearOfBurningAlive(final FearOfBurningAlive card) {
@ -51,49 +54,3 @@ public final class FearOfBurningAlive extends CardImpl {
return new FearOfBurningAlive(this);
}
}
class FearOfBurningAliveTriggeredAbility extends TriggeredAbilityImpl {
FearOfBurningAliveTriggeredAbility() {
super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MANY)
.setText("{this} deals that amount of damage to target creature that player controls"));
this.setTriggerPhrase("Whenever a source you control deals noncombat damage to an opponent, " +
"if there are four or more card types among cards in your graveyard, ");
this.setAbilityWord(AbilityWord.DELIRIUM);
this.addHint(CardTypesInGraveyardCount.YOU.getHint());
}
private FearOfBurningAliveTriggeredAbility(final FearOfBurningAliveTriggeredAbility ability) {
super(ability);
}
@Override
public FearOfBurningAliveTriggeredAbility copy() {
return new FearOfBurningAliveTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((DamagedEvent) event).isCombatDamage()
|| !isControlledBy(game.getControllerId(event.getSourceId()))
|| !game.getOpponents(getControllerId()).contains(event.getTargetId())) {
return false;
}
this.getEffects().setValue("damage", event.getAmount());
FilterPermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
@Override
public boolean checkInterveningIfClause(Game game) {
return DeliriumCondition.instance.apply(game, this);
}
}

View file

@ -15,10 +15,8 @@ import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.filter.common.FilterCreaturePermanent;
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;
@ -52,7 +50,10 @@ public final class FelineSovereign extends CardImpl {
this.addAbility(ability);
// Whenever one or more Cats you control deal combat damage to a player, destroy up to one target artifact or enchantment that player controls.
this.addAbility(new FelineSovereignTriggeredAbility());
Ability ability2 = new OneOrMoreCombatDamagePlayerTriggeredAbility(new DestroyTargetEffect(), SetTargetPointer.PLAYER, filterCat, false);
ability2.addTarget(new TargetPermanent(0, 1, new FilterArtifactOrEnchantmentPermanent("artifact or enchantment that player controls")));
ability2.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability2);
}
private FelineSovereign(final FelineSovereign card) {
@ -64,34 +65,3 @@ public final class FelineSovereign extends CardImpl {
return new FelineSovereign(this);
}
}
class FelineSovereignTriggeredAbility extends OneOrMoreCombatDamagePlayerTriggeredAbility {
private static final FilterCreaturePermanent catFilter = new FilterCreaturePermanent(SubType.CAT, "Cats");
FelineSovereignTriggeredAbility() {
super(new DestroyTargetEffect().setText("destroy up to one target artifact or enchantment that player controls"), catFilter);
}
private FelineSovereignTriggeredAbility(final FelineSovereignTriggeredAbility ability) {
super(ability);
}
@Override
public FelineSovereignTriggeredAbility copy() {
return new FelineSovereignTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!super.checkTrigger(event, game)) {
return false;
}
this.getTargets().clear();
FilterArtifactOrEnchantmentPermanent filter = new FilterArtifactOrEnchantmentPermanent();
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.addTarget(new TargetPermanent(0, 1, filter, false));
return true;
}
}

View file

@ -2,7 +2,7 @@ package mage.cards.f;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.combat.GoadTargetEffect;
@ -14,14 +14,13 @@ import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.DefenderAttackedEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@ -31,9 +30,11 @@ import java.util.UUID;
public final class FirkraagCunningInstigator extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent();
private static final FilterPermanent filterDragons = new FilterControlledCreaturePermanent("Dragons you control");
static {
filter.add(FirkraagCunningInstigatorPredicate.instance);
filterDragons.add(SubType.DRAGON.getPredicate());
}
public FirkraagCunningInstigator(UUID ownerId, CardSetInfo setInfo) {
@ -51,7 +52,10 @@ public final class FirkraagCunningInstigator extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// Whenever one or more Dragons you control attack an opponent, goad target creature that player controls.
this.addAbility(new FirkraagCunningInstigatorTriggeredAbility());
Ability abilityGoad = new AttacksWithCreaturesTriggeredAbility(Zone.BATTLEFIELD, new GoadTargetEffect(), 1, filterDragons, true);
abilityGoad.addTarget(new TargetPermanent(new FilterCreaturePermanent("target creature that player controls")));
abilityGoad.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(abilityGoad);
// Whenever a creature deals combat damage to one of your opponents, if that creature had to attack this combat, you put a +1/+1 counter on Firkraag, Cunning Instigator and you draw a card.
Ability ability = new DealsDamageToAPlayerAllTriggeredAbility(
@ -88,48 +92,3 @@ enum FirkraagCunningInstigatorPredicate implements Predicate<Permanent> {
.anyMatch(input.getId()::equals);
}
}
class FirkraagCunningInstigatorTriggeredAbility extends TriggeredAbilityImpl {
FirkraagCunningInstigatorTriggeredAbility() {
super(Zone.BATTLEFIELD, new GoadTargetEffect());
}
private FirkraagCunningInstigatorTriggeredAbility(final FirkraagCunningInstigatorTriggeredAbility ability) {
super(ability);
}
@Override
public FirkraagCunningInstigatorTriggeredAbility copy() {
return new FirkraagCunningInstigatorTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (this.isControlledBy(event.getPlayerId())
&& game.getOpponents(this.getControllerId()).contains(event.getTargetId())
&& ((DefenderAttackedEvent) event)
.getAttackers(game)
.stream()
.anyMatch(permanent -> permanent.hasSubtype(SubType.DRAGON, game))) {
this.getTargets().clear();
FilterPermanent filter = new FilterCreaturePermanent(
"creature controlled by " + game.getPlayer(event.getTargetId()).getName()
);
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.addTarget(new TargetPermanent(filter));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever one or more Dragons you control attack an opponent, goad target creature that player controls.";
}
}

View file

@ -1,20 +1,17 @@
package mage.cards.f;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.HasteAbility;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterCard;
@ -24,6 +21,11 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
@ -64,6 +66,7 @@ class FroghemothTriggeredAbility extends DealsCombatDamageToAPlayerTriggeredAbil
public FroghemothTriggeredAbility() {
super(new FroghemothEffect(), false);
setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
private FroghemothTriggeredAbility(final FroghemothTriggeredAbility ability) {

View file

@ -15,6 +15,7 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
import mage.watchers.common.CastFromHandWatcher;
import java.util.UUID;
@ -71,6 +72,7 @@ class GaleWaterdeepProdigyTriggeredAbility extends SpellCastControllerTriggeredA
false
);
addWatcher(new CastFromHandWatcher());
setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
private GaleWaterdeepProdigyTriggeredAbility(final GaleWaterdeepProdigyTriggeredAbility ability) {

View file

@ -1,29 +1,23 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterArtifactPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.combat.CombatGroup;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.target.common.TargetArtifactPermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
/**
*
@ -40,14 +34,13 @@ public final class GoblinVandal extends CardImpl {
this.toughness = new MageInt(1);
// Whenever Goblin Vandal attacks and isn't blocked, you may pay {R}. If you do, destroy target artifact defending player controls and Goblin Vandal assigns no combat damage this turn.
Effect effect = new DestroyTargetEffect();
effect.setText("destroy target artifact defending player controls");
DoIfCostPaid effect2 = new DoIfCostPaid(effect, new ManaCostsImpl<>("{R}"), "Pay {R} to destroy artifact of defending player?");
effect = new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn);
effect.setText("and {this} assigns no combat damage this turn");
effect2.addEffect(effect);
this.addAbility(new GoblinVandalTriggeredAbility(effect2));
DoIfCostPaid effect = new DoIfCostPaid(new DestroyTargetEffect().setText("destroy target artifact defending player controls"),
new ManaCostsImpl<>("{R}"), "Pay {R} to destroy artifact of defending player?");
effect.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn).setText("and {this} assigns no combat damage this turn"));
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER);
ability.addTarget(new TargetArtifactPermanent());
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
private GoblinVandal(final GoblinVandal card) {
@ -59,47 +52,3 @@ public final class GoblinVandal extends CardImpl {
return new GoblinVandal(this);
}
}
class GoblinVandalTriggeredAbility extends TriggeredAbilityImpl {
public GoblinVandalTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect, false );
}
private GoblinVandalTriggeredAbility(final GoblinVandalTriggeredAbility ability) {
super(ability);
}
@Override
public GoblinVandalTriggeredAbility copy() {
return new GoblinVandalTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent sourcePermanent = game.getPermanent(getSourceId());
if (sourcePermanent.isAttacking()) {
for (CombatGroup combatGroup: game.getCombat().getGroups()) {
if (combatGroup.getBlockers().isEmpty() && combatGroup.getAttackers().contains(getSourceId())) {
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game);
FilterPermanent filter = new FilterArtifactPermanent();
filter.add(new ControllerIdPredicate(defendingPlayerId));
Target target = new TargetPermanent(filter);
this.addTarget(target);
return true;
}
}
}
return false;
}
@Override
public String getRule() {
return "Whenever {this} attacks and isn't blocked, you may pay {R}. If you do, destroy target artifact defending player controls and {this} assigns no combat damage this turn.";
}
}

View file

@ -1,7 +1,8 @@
package mage.cards.g;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.Ability;
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
@ -18,11 +19,8 @@ import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.events.DefenderAttackedEvent;
import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@ -58,7 +56,12 @@ public final class GornogTheRedReaper extends CardImpl {
this.addAbility(new SimpleStaticAbility(new CowardsCantBlockWarriorsEffect()));
// Whenever one or more Warriors you control attack a player, target creature that player controls becomes a Coward.
this.addAbility(new GornogTheRedReaperTriggeredAbility());
Ability ability = new AttacksWithCreaturesTriggeredAbility(Zone.BATTLEFIELD,
new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.COWARD),
1, filter, true);
ability.addTarget(new TargetCreaturePermanent());
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
// Attacking Warriors you control get +X/+0, where X is the number of Cowards your opponents control.
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
@ -75,42 +78,3 @@ public final class GornogTheRedReaper extends CardImpl {
return new GornogTheRedReaper(this);
}
}
class GornogTheRedReaperTriggeredAbility extends TriggeredAbilityImpl {
GornogTheRedReaperTriggeredAbility() {
super(Zone.BATTLEFIELD, new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.COWARD)
.setText("target creature that player controls becomes a Coward"));
this.setTriggerPhrase("Whenever one or more Warriors you control attack a player, ");
}
private GornogTheRedReaperTriggeredAbility(final GornogTheRedReaperTriggeredAbility ability) {
super(ability);
}
@Override
public GornogTheRedReaperTriggeredAbility copy() {
return new GornogTheRedReaperTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (game.getPlayer(event.getTargetId()) == null
|| ((DefenderAttackedEvent) event)
.getAttackers(game)
.stream()
.noneMatch(p -> p.hasSubtype(SubType.WARRIOR, game) && p.isControlledBy(getControllerId()))) {
return false;
}
FilterPermanent filter = new FilterCreaturePermanent("creature controlled by defending player");
filter.add(new ControllerIdPredicate(event.getTargetId()));
this.getTargets().clear();
this.addTarget(new TargetPermanent(filter));
return true;
}
}

View file

@ -20,6 +20,7 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetadjustment.DefineByTriggerTargetAdjuster;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
@ -69,6 +70,7 @@ class GrenzoHavocRaiserTriggeredAbility extends TriggeredAbilityImpl {
public GrenzoHavocRaiserTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect, false);
setTriggerPhrase("Whenever a creature you control deals combat damage to a player, ");
setTargetAdjuster(DefineByTriggerTargetAdjuster.instance);
}
private GrenzoHavocRaiserTriggeredAbility(final GrenzoHavocRaiserTriggeredAbility ability) {

View file

@ -1,16 +1,19 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
@ -32,8 +35,11 @@ public final class GuardiansOfKoilos extends CardImpl {
this.toughness = new MageInt(4);
// When Guardians of Koilos enters the battlefield, you may return another target historic permanent you control to its owner's hand.
this.addAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandChosenControlledPermanentEffect(filter)
.setText("you may return another target historic permanent you control to its owner's hand. <i>(Artifacts, legendaries, and Sagas are historic.)</i>"), true));
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()
.setText("you may return another target historic permanent you control to its owner's hand. <i>(Artifacts, legendaries, and Sagas are historic.)</i>"),
true);
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
}
private GuardiansOfKoilos(final GuardiansOfKoilos card) {

View file

@ -1,21 +1,21 @@
package mage.cards.n;
import java.util.Objects;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
import mage.constants.*;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import java.util.UUID;
/**
*
@ -40,7 +40,7 @@ public final class NivMizzetVisionary extends CardImpl {
this.addAbility(new SimpleStaticAbility(effect));
// Whenever a source you control deals noncombat damage to an opponent, you draw that many cards.
this.addAbility(new NivMizzetVisionaryAbility());
this.addAbility(new SourceDealsNoncombatDamageToOpponentTriggeredAbility(new DrawCardSourceControllerEffect(SavedDamageValue.MANY, true)));
}
private NivMizzetVisionary(final NivMizzetVisionary card) {
@ -52,41 +52,3 @@ public final class NivMizzetVisionary extends CardImpl {
return new NivMizzetVisionary(this);
}
}
class NivMizzetVisionaryAbility extends TriggeredAbilityImpl {
NivMizzetVisionaryAbility() {
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(SavedDamageValue.MANY));
}
private NivMizzetVisionaryAbility(final NivMizzetVisionaryAbility ability) {
super(ability);
}
@Override
public NivMizzetVisionaryAbility copy() {
return new NivMizzetVisionaryAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
if (damageEvent.isCombatDamage()
|| !game.getOpponents(controllerId).contains(event.getTargetId())
|| !Objects.equals(controllerId, game.getControllerId(event.getSourceId()))) {
return false;
}
getAllEffects().setValue("damage", event.getAmount());
return true;
}
@Override
public String getRule() {
return "Whenever a source you control deals noncombat damage to an opponent, you draw that many cards.";
}
}

View file

@ -1,16 +1,14 @@
package mage.cards.v;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SourceDealsNoncombatDamageToOpponentTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect;
import mage.cards.AdventureCard;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.constants.SetTargetPointer;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
@ -24,7 +22,10 @@ public final class VirtueOfCourage extends AdventureCard {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new CardType[]{CardType.INSTANT}, "{3}{R}{R}", "Embereth Blaze", "{1}{R}");
// Whenever a source you control deals noncombat damage to an opponent, you may exile that many cards from the top of your library. You may play those cards this turn.
this.addAbility(new VirtueOfCourageTriggeredAbility());
this.addAbility(new SourceDealsNoncombatDamageToOpponentTriggeredAbility(
new ExileTopXMayPlayUntilEffect(SavedDamageValue.MANY, false, Duration.EndOfTurn)
.setText("you may exile that many cards from the top of your library. You may play those cards this turn.")
, true, SetTargetPointer.NONE));
// Embereth Blaze
// Embereth Blaze deals 2 damage to any target.
@ -43,44 +44,3 @@ public final class VirtueOfCourage extends AdventureCard {
return new VirtueOfCourage(this);
}
}
class VirtueOfCourageTriggeredAbility extends TriggeredAbilityImpl {
VirtueOfCourageTriggeredAbility() {
super(Zone.BATTLEFIELD, null, true);
}
private VirtueOfCourageTriggeredAbility(final VirtueOfCourageTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
DamagedPlayerEvent dEvent = (DamagedPlayerEvent) event;
if (dEvent.isCombatDamage()
|| !game.getOpponents(getControllerId()).contains(event.getTargetId())
|| !game.getControllerId(event.getSourceId()).equals(getControllerId())) {
return false;
}
this.getEffects().clear();
this.addEffect(new ExileTopXMayPlayUntilEffect(event.getAmount(), Duration.EndOfTurn));
return true;
}
@Override
public VirtueOfCourageTriggeredAbility copy() {
return new VirtueOfCourageTriggeredAbility(this);
}
@Override
public String getRule() {
return "whenever a source you control deals noncombat damage to an opponent, "
+ "you may exile that many cards from the top of your library. "
+ "You may play those cards this turn.";
}
}

View file

@ -0,0 +1,41 @@
package org.mage.test.cards.single.otc;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class BladegriffPrototypeTest extends CardTestPlayerBase {
private static final String griff = "Bladegriff Prototype";
@Test
public void test_CanTargetOwn() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Squire");
addCard(Zone.BATTLEFIELD, playerA, griff);
attack(1, playerA, griff);
addTarget(playerB, "Squire");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertGraveyardCount(playerB, "Squire", 1);
}
@Test(expected=AssertionError.class)
public void test_CantTargetYours() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, "Squire");
addCard(Zone.BATTLEFIELD, playerA, griff);
attack(1, playerA, griff);
addTarget(playerB, griff);
setStopAt(1, PhaseStep.END_COMBAT);
execute();
}
}

View file

@ -85,7 +85,7 @@ public class VerifyCardDataTest {
private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class);
private static String FULL_ABILITIES_CHECK_SET_CODES = "BLC"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all
private static String FULL_ABILITIES_CHECK_SET_CODES = "*"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all
private static boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages
private static final boolean CHECK_COPYABLE_FIELDS = true; // disable for better verify test performance

View file

@ -0,0 +1,66 @@
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
/**
* @author notgreat
*/
public class SourceDealsNoncombatDamageToOpponentTriggeredAbility extends TriggeredAbilityImpl {
SetTargetPointer setTargetPointer;
public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect) {
this(effect, SetTargetPointer.NONE);
}
public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer) {
this(effect, false, setTargetPointer);
}
public SourceDealsNoncombatDamageToOpponentTriggeredAbility(Effect effect, boolean optional, SetTargetPointer setTargetPointer) {
super(Zone.BATTLEFIELD, effect, optional);
this.setTargetPointer = setTargetPointer;
setTriggerPhrase("Whenever a source you control deals noncombat damage to an opponent, ");
}
protected SourceDealsNoncombatDamageToOpponentTriggeredAbility(final SourceDealsNoncombatDamageToOpponentTriggeredAbility ability) {
super(ability);
setTargetPointer = ability.setTargetPointer;
}
@Override
public SourceDealsNoncombatDamageToOpponentTriggeredAbility copy() {
return new SourceDealsNoncombatDamageToOpponentTriggeredAbility(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.getTargetId());
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
if (opponent == null || !game.isOpponent(opponent, getControllerId())
|| !isControlledBy(game.getControllerId(event.getSourceId()))
|| damageEvent.isCombatDamage()) {
return false;
}
int damageAmount = event.getAmount();
if (damageAmount < 1) {
return false;
}
this.getEffects().setValue("damage", damageAmount);
if (setTargetPointer == SetTargetPointer.PLAYER) {
getEffects().setTargetPointer(new FixedTarget(event.getSourceId()));
}
return true;
}
}

View file

@ -10,7 +10,8 @@ import mage.game.Game;
*/
public enum SavedDamageValue implements DynamicValue {
MANY("many"),
MUCH("much");
MUCH("much"),
AMOUNT("amount of");
private final String message;

View file

@ -0,0 +1,18 @@
package mage.target.targetadjustment;
import mage.abilities.Ability;
import mage.game.Game;
/**
* Use this to indicate that the targets are dynamically added via the Ability directly
* While still satisfying the Verify target check
*
* @author notgreat
*/
public enum DefineByTriggerTargetAdjuster implements TargetAdjuster{
instance;
@Override
public void adjustTargets(Ability ability, Game game){
//Do nothing
}
}