implement [ACR] Senu, Keen-Eyed Protector ; small refactor on AttacksAndIsNotBlockedTriggeredAbility's setTargetPointer

This commit is contained in:
Susucre 2024-07-06 18:20:08 +02:00
parent c41052066d
commit 9bc1289341
21 changed files with 426 additions and 140 deletions

View file

@ -1,7 +1,6 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.Effect;
@ -9,16 +8,18 @@ import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class AbyssalNightstalker extends CardImpl {
public AbyssalNightstalker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.NIGHTSTALKER);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
@ -26,7 +27,7 @@ public final class AbyssalNightstalker extends CardImpl {
// Whenever Abyssal Nightstalker attacks and isn't blocked, defending player discards a card.
Effect effect = new DiscardTargetEffect(1);
effect.setText("defending player discards a card");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER));
}
private AbyssalNightstalker(final AbyssalNightstalker card) {

View file

@ -1,7 +1,6 @@
package mage.cards.b;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
@ -14,20 +13,21 @@ import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class BoneDancer extends CardImpl {
public BoneDancer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.ZOMBIE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Whenever Bone Dancer attacks and isn't blocked, you may put the top creature card of defending player's graveyard onto the battlefield under your control. If you do, Bone Dancer assigns no combat damage this turn.
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new BoneDancerEffect(), true, true);
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new BoneDancerEffect(), true, SetTargetPointer.PLAYER);
ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true));
this.addAbility(ability);
}

View file

@ -1,34 +1,31 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class CoralFighters extends CardImpl {
public CoralFighters(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.subtype.add(SubType.MERFOLK);
this.subtype.add(SubType.SOLDIER);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Whenever Coral Fighters attacks and isn't blocked, look at the top card of defending player's library. You may put that card on the bottom of that player's library.
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new CoralFightersEffect(), false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new CoralFightersEffect(), false, SetTargetPointer.PLAYER));
}
private CoralFighters(final CoralFighters card) {
@ -61,15 +58,14 @@ class CoralFightersEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player defendingPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if(controller != null && defendingPlayer != null) {
if (controller != null && defendingPlayer != null) {
Card card = defendingPlayer.getLibrary().getFromTop(game);
if(card != null) {
if (card != null) {
Cards cards = new CardsImpl(card);
controller.lookAtCards("Coral Fighters", cards, game);
if (controller.chooseUse(outcome, "Put that card on the bottom of its owner's library?", source, game)) {
controller.moveCardToLibraryWithInfo(card, source, game, Zone.LIBRARY, false, false);
}
else {
} else {
game.informPlayers(controller.getLogName() + " puts the card back on top of the library.");
}
return true;

View file

@ -1,7 +1,6 @@
package mage.cards.c;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.Effect;
@ -9,16 +8,18 @@ import mage.abilities.effects.common.counter.AddPoisonCounterTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class CryptCobra extends CardImpl {
public CryptCobra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.SNAKE);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
@ -26,7 +27,7 @@ public final class CryptCobra extends CardImpl {
// Whenever Crypt Cobra attacks and isn't blocked, defending player gets a poison counter.
Effect effect = new AddPoisonCounterTargetEffect(1);
effect.setText("defending player gets a poison counter");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER));
}
private CryptCobra(final CryptCobra card) {

View file

@ -1,7 +1,6 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -12,16 +11,18 @@ import mage.abilities.keyword.ShadowAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class DauthiMindripper extends CardImpl {
public DauthiMindripper(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.DAUTHI);
this.subtype.add(SubType.MINION);
this.power = new MageInt(2);
@ -32,7 +33,10 @@ public final class DauthiMindripper extends CardImpl {
// Whenever Dauthi Mindripper attacks and isn't blocked, you may sacrifice it. If you do, defending player discards three cards.
Effect effect = new DiscardTargetEffect(3);
effect.setText("defending player discards three cards");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid(effect, new SacrificeSourceCost()), false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(
new DoIfCostPaid(effect, new SacrificeSourceCost()),
false, SetTargetPointer.PLAYER
));
}
private DauthiMindripper(final DauthiMindripper card) {

View file

@ -1,7 +1,6 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.dynamicvalue.common.CardsInTargetPlayersGraveyardCount;
@ -11,16 +10,18 @@ import mage.abilities.keyword.FearAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class Guiltfeeder extends CardImpl {
public Guiltfeeder(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.HORROR);
this.power = new MageInt(0);
this.toughness = new MageInt(4);
@ -30,7 +31,7 @@ public final class Guiltfeeder extends CardImpl {
// Whenever Guiltfeeder attacks and isn't blocked, defending player loses 1 life for each card in their graveyard.
Effect effect = new LoseLifeTargetEffect(new CardsInTargetPlayersGraveyardCount());
effect.setText("defending player loses 1 life for each card in their graveyard");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER));
}
private Guiltfeeder(final Guiltfeeder card) {

View file

@ -1,7 +1,6 @@
package mage.cards.k;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
@ -11,17 +10,19 @@ 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.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class KeeperOfTresserhorn extends CardImpl {
public KeeperOfTresserhorn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}");
this.subtype.add(SubType.AVATAR);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
@ -29,7 +30,7 @@ public final class KeeperOfTresserhorn extends CardImpl {
// Whenever Keeper of Tresserhorn attacks and isn't blocked, it assigns no combat damage this turn and defending player loses 2 life.
Effect effect = new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn);
effect.setText("it assigns no combat damage this turn");
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true);
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER);
effect = new LoseLifeTargetEffect(2);
effect.setText("and defending player loses 2 life");
ability.addEffect(effect);

View file

@ -1,7 +1,6 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
@ -17,23 +16,20 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.TrampleAbility;
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.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class LimDulsPaladin extends CardImpl {
public LimDulsPaladin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.KNIGHT);
this.power = new MageInt(0);
@ -48,7 +44,7 @@ public final class LimDulsPaladin extends CardImpl {
// Whenever Lim-Dul's Paladin attacks and isn't blocked, it assigns no combat damage to defending player this turn and that player loses 4 life.
Effect effect = new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn);
effect.setText("it assigns no combat damage this turn");
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true);
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER);
effect = new LoseLifeTargetEffect(4);
effect.setText("and defending player loses 4 life");
ability.addEffect(effect);
@ -84,11 +80,11 @@ class LimDulsPaladinEffect extends SacrificeSourceUnlessPaysEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if(permanent != null) {
if (permanent != null) {
super.apply(game, source);
// Not in play anymore -> was sacrificed, draw a card
if(game.getPermanent(source.getSourceId()) == null) {
return new DrawCardSourceControllerEffect(1).apply(game, source);
if (game.getPermanent(source.getSourceId()) == null) {
return new DrawCardSourceControllerEffect(1).apply(game, source);
}
return true;
}

View file

@ -1,7 +1,6 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -11,16 +10,18 @@ import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class MindstabThrull extends CardImpl {
public MindstabThrull(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.THRULL);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
@ -28,7 +29,9 @@ public final class MindstabThrull extends CardImpl {
// Whenever Mindstab Thrull attacks and isn't blocked, you may sacrifice it. If you do, defending player discards three cards.
Effect effect = new DiscardTargetEffect(3);
effect.setText("defending player discards three cards");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid(effect, new SacrificeSourceCost()), false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(
new DoIfCostPaid(effect, new SacrificeSourceCost()), false, SetTargetPointer.PLAYER
));
}
private MindstabThrull(final MindstabThrull card) {

View file

@ -25,13 +25,13 @@ public final class PygmyHippo extends CardImpl {
public PygmyHippo(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}");
this.subtype.add(SubType.HIPPO);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Whenever Pygmy Hippo attacks and isn't blocked, you may have defending player activate a mana ability of each land they control and lose all unspent mana. If you do, Pygmy Hippo assigns no combat damage this turn and at the beginning of your next main phase this turn, you add an amount of {C} equal to the amount of mana that player lost this way.
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new PygmyHippoEffect(), true, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new PygmyHippoEffect(), true, SetTargetPointer.PLAYER));
}
private PygmyHippo(final PygmyHippo card) {
@ -77,11 +77,11 @@ class PygmyHippoEffect extends OneShotEffect {
game.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true), source);
if (amountToAdd > 0) {
DelayedTriggeredAbility delayed = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(
new AddManaToManaPoolSourceControllerEffect(new Mana(ManaType.COLORLESS, amountToAdd)),
false, TargetController.YOU,
AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN);
game.addDelayedTriggeredAbility(delayed, source);
DelayedTriggeredAbility delayed = new AtTheBeginOfMainPhaseDelayedTriggeredAbility(
new AddManaToManaPoolSourceControllerEffect(new Mana(ManaType.COLORLESS, amountToAdd)),
false, TargetController.YOU,
AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN);
game.addDelayedTriggeredAbility(delayed, source);
}
return true;
}

View file

@ -0,0 +1,117 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedAllTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.SourceInExileCondition;
import mage.abilities.costs.common.ExileSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.keyword.ScryEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
* @author Susucr
*/
public final class SenuKeenEyedProtector extends CardImpl {
private static final FilterPermanent filter =
new FilterControlledCreaturePermanent("a legendary creature you control");
static {
filter.add(SuperType.LEGENDARY.getPredicate());
}
public SenuKeenEyedProtector(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.BIRD);
this.subtype.add(SubType.SCOUT);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// {T}, Exile Senu, Keen-Eyed Protector: You gain 2 life and scry 2.
Ability ability = new SimpleActivatedAbility(
new GainLifeEffect(2),
new TapSourceCost()
);
ability.addCost(new ExileSourceCost());
ability.addEffect(new ScryEffect(2).concatBy("and"));
this.addAbility(ability);
// When a legendary creature you control attacks and isn't blocked, if Senu is exiled, put it onto the battlefield attacking.
this.addAbility(
new ConditionalInterveningIfTriggeredAbility(
new AttacksAndIsNotBlockedAllTriggeredAbility(
Zone.EXILED, new SenuKeenEyedProtectorEffect(), filter
), SourceInExileCondition.instance,
"When a legendary creature you control attacks and isn't blocked, "
+ "if {this} is exiled, put it onto the battlefield attacking"
)
);
}
private SenuKeenEyedProtector(final SenuKeenEyedProtector card) {
super(card);
}
@Override
public SenuKeenEyedProtector copy() {
return new SenuKeenEyedProtector(this);
}
}
class SenuKeenEyedProtectorEffect extends OneShotEffect {
SenuKeenEyedProtectorEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "put it onto the battlefield attacking";
}
private SenuKeenEyedProtectorEffect(final SenuKeenEyedProtectorEffect effect) {
super(effect);
}
@Override
public SenuKeenEyedProtectorEffect copy() {
return new SenuKeenEyedProtectorEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = source.getSourceCardIfItStillExists(game);
if (player == null || card == null) {
return false;
}
player.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent creature = game.getPermanent(card.getId());
if (creature != null) {
game.getCombat().addAttackingCreature(creature.getId(), game);
}
return true;
}
}

View file

@ -1,20 +1,14 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.AttacksAndIsNotBlockedAllTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.keyword.ProwlAbility;
import mage.cards.CardImpl;
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.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import java.util.UUID;
@ -23,6 +17,8 @@ import java.util.UUID;
*/
public final class StinkdrinkerBandit extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.ROGUE, "a Rogue you control");
public StinkdrinkerBandit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.GOBLIN);
@ -35,7 +31,11 @@ public final class StinkdrinkerBandit extends CardImpl {
this.addAbility(new ProwlAbility("{1}{B}"));
// Whenever a Rogue you control attacks and isn't blocked, it gets +2/+1 until end of turn.
this.addAbility(new StinkdrinkerBanditTriggeredAbility());
this.addAbility(new AttacksAndIsNotBlockedAllTriggeredAbility(
Zone.BATTLEFIELD,
new BoostTargetEffect(2, 1, Duration.EndOfTurn),
filter, false, SetTargetPointer.PERMANENT
));
}
private StinkdrinkerBandit(final StinkdrinkerBandit card) {
@ -46,42 +46,4 @@ public final class StinkdrinkerBandit extends CardImpl {
public StinkdrinkerBandit copy() {
return new StinkdrinkerBandit(this);
}
}
class StinkdrinkerBanditTriggeredAbility extends TriggeredAbilityImpl {
StinkdrinkerBanditTriggeredAbility() {
super(Zone.BATTLEFIELD, new BoostTargetEffect(2, 1, Duration.EndOfTurn));
}
private StinkdrinkerBanditTriggeredAbility(final StinkdrinkerBanditTriggeredAbility ability) {
super(ability);
}
@Override
public StinkdrinkerBanditTriggeredAbility copy() {
return new StinkdrinkerBanditTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.UNBLOCKED_ATTACKER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null
&& isControlledBy(permanent.getControllerId())
&& permanent.hasSubtype(SubType.ROGUE, game)) {
getEffects().setTargetPointer(new FixedTarget(permanent, game));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a Rogue you control attacks and isn't blocked, it gets +2/+1 until end of turn.";
}
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
@ -9,21 +8,16 @@ import mage.abilities.condition.common.SourceRemainsInZoneCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.Zone;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author L_J
*/
public final class StromgaldSpy extends CardImpl {
@ -39,10 +33,10 @@ public final class StromgaldSpy extends CardImpl {
// for as long as Stromgald Spy remains on the battlefield. If you do, Stromgald Spy assigns no combat damage this turn.
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(
new ConditionalContinuousEffect(
new StromgaldSpyEffect(),
new SourceRemainsInZoneCondition(Zone.BATTLEFIELD),
"you may have defending player play with their hand revealed for as long as {this} remains on the battlefield"),
true, true);
new StromgaldSpyEffect(),
new SourceRemainsInZoneCondition(Zone.BATTLEFIELD),
"you may have defending player play with their hand revealed for as long as {this} remains on the battlefield"),
true, SetTargetPointer.PLAYER);
ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true));
this.addAbility(ability);
}

View file

@ -1,7 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.Effect;
@ -10,16 +9,18 @@ import mage.abilities.keyword.FearAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class SuqAtaAssassin extends CardImpl {
public SuqAtaAssassin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ASSASSIN);
this.power = new MageInt(1);
@ -30,7 +31,7 @@ public final class SuqAtaAssassin extends CardImpl {
// Whenever Suq'Ata Assassin attacks and isn't blocked, defending player gets a poison counter.
Effect effect = new AddPoisonCounterTargetEffect(1);
effect.setText("defending player gets a poison counter");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER));
}
private SuqAtaAssassin(final SuqAtaAssassin card) {

View file

@ -1,7 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.effects.Effect;
@ -10,16 +9,18 @@ import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class SwampMosquito extends CardImpl {
public SwampMosquito(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
this.subtype.add(SubType.INSECT);
this.power = new MageInt(0);
this.toughness = new MageInt(1);
@ -29,7 +30,7 @@ public final class SwampMosquito extends CardImpl {
// Whenever Swamp Mosquito attacks and isn't blocked, defending player gets a poison counter.
Effect effect = new AddPoisonCounterTargetEffect(1);
effect.setText("defending player gets a poison counter");
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, true));
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(effect, false, SetTargetPointer.PLAYER));
}
private SwampMosquito(final SwampMosquito card) {

View file

@ -7,6 +7,7 @@ import mage.abilities.keyword.AfflictAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
@ -34,7 +35,7 @@ public final class WildfireEternal extends CardImpl {
// Whenever Wildfire Eternal attacks and isn't blocked, you may cast an instant or sorcery card from your hand without paying its mana cost.
this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(
new CastFromHandForFreeEffect(filter), false, true
new CastFromHandForFreeEffect(filter), false, SetTargetPointer.PLAYER
));
}

View file

@ -92,6 +92,7 @@ public final class AssassinsCreed extends ExpansionSet {
cards.add(new SetCardInfo("Restart Sequence", 30, Rarity.UNCOMMON, mage.cards.r.RestartSequence.class));
cards.add(new SetCardInfo("Rooftop Bypass", 298, Rarity.RARE, mage.cards.r.RooftopBypass.class));
cards.add(new SetCardInfo("Royal Assassin", 93, Rarity.RARE, mage.cards.r.RoyalAssassin.class));
cards.add(new SetCardInfo("Senu, Keen-Eyed Protector", 8, Rarity.RARE, mage.cards.s.SenuKeenEyedProtector.class));
cards.add(new SetCardInfo("Settlement Blacksmith", 280, Rarity.UNCOMMON, mage.cards.s.SettlementBlacksmith.class));
cards.add(new SetCardInfo("Shao Jun", 63, Rarity.UNCOMMON, mage.cards.s.ShaoJun.class));
cards.add(new SetCardInfo("Sigurd, Jarl of Ravensthorpe", 66, Rarity.RARE, mage.cards.s.SigurdJarlOfRavensthorpe.class));

View file

@ -0,0 +1,103 @@
package org.mage.test.cards.single.acr;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class SenuKeenEyedProtectorTest extends CardTestPlayerBase {
/**
* {@link mage.cards.s.SenuKeenEyedProtector Senu, Keen-Eyed Protector} {1}{W}
* Legendary Creature Bird Scout
* Flying, vigilance
* {T}, Exile Senu, Keen-Eyed Protector: You gain 2 life and scry 2.
* When a legendary creature you control attacks and isnt blocked, if Senu is exiled, put it onto the battlefield attacking.
* 2/1
*/
private static final String senu = "Senu, Keen-Eyed Protector";
@Test
public void test_Trigger() {
setStrictChooseMode(true);
addCard(Zone.EXILED, playerA, senu);
addCard(Zone.BATTLEFIELD, playerA, "Isamaru, Hound of Konda");
attack(1, playerA, "Isamaru, Hound of Konda");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 2 - 2);
assertPermanentCount(playerA, senu, 1);
}
@Test
public void test_NoTrigger_FromGraveyard() {
setStrictChooseMode(true);
addCard(Zone.GRAVEYARD, playerA, senu);
addCard(Zone.BATTLEFIELD, playerA, "Isamaru, Hound of Konda");
attack(1, playerA, "Isamaru, Hound of Konda");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 2);
assertPermanentCount(playerA, senu, 0);
}
@Test
public void test_NoTrigger_FromHand() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, senu);
addCard(Zone.BATTLEFIELD, playerA, "Isamaru, Hound of Konda");
attack(1, playerA, "Isamaru, Hound of Konda");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 2);
assertPermanentCount(playerA, senu, 0);
}
@Test
public void test_NoTrigger_NonLegendaryAttack() {
setStrictChooseMode(true);
addCard(Zone.EXILED, playerA, senu);
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
attack(1, playerA, "Elite Vanguard");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 2);
assertPermanentCount(playerA, senu, 0);
}
@Test
public void test_NoTrigger_OpponentAttack() {
setStrictChooseMode(true);
addCard(Zone.EXILED, playerB, senu);
addCard(Zone.BATTLEFIELD, playerA, "Isamaru, Hound of Konda");
attack(1, playerA, "Isamaru, Hound of Konda");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertLife(playerB, 20 - 2);
assertPermanentCount(playerA, senu, 0);
assertPermanentCount(playerB, senu, 0);
}
}

View file

@ -0,0 +1,75 @@
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
/**
* @author Susucr
*/
public class AttacksAndIsNotBlockedAllTriggeredAbility extends TriggeredAbilityImpl {
private final FilterPermanent filter;
private final SetTargetPointer setTargetPointer;
public AttacksAndIsNotBlockedAllTriggeredAbility(Effect effect, FilterPermanent filter) {
this(Zone.BATTLEFIELD, effect, filter);
}
public AttacksAndIsNotBlockedAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter) {
this(zone, effect, filter, false, SetTargetPointer.NONE);
}
public AttacksAndIsNotBlockedAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer) {
super(zone, effect, optional);
this.filter = filter;
this.setTargetPointer = setTargetPointer;
setTriggerPhrase("Whenever " + filter.getMessage() + " attacks and isn't blocked, ");
}
private AttacksAndIsNotBlockedAllTriggeredAbility(final AttacksAndIsNotBlockedAllTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
this.setTargetPointer = ability.setTargetPointer;
}
@Override
public AttacksAndIsNotBlockedAllTriggeredAbility copy() {
return new AttacksAndIsNotBlockedAllTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.UNBLOCKED_ATTACKER;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
return false;
}
switch (setTargetPointer) {
case NONE:
break;
case PLAYER:
this.getEffects().setTargetPointer(new FixedTarget(
game.getCombat().getDefendingPlayerId(event.getTargetId(), game), game
));
break;
case PERMANENT:
getEffects().setTargetPointer(new FixedTarget(permanent, game));
break;
default:
throw new IllegalArgumentException("Wrong code usage: not supported setTargetPointer");
}
return true;
}
}

View file

@ -2,6 +2,7 @@ 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.GameEvent;
@ -10,17 +11,17 @@ import mage.target.targetpointer.FixedTarget;
public class AttacksAndIsNotBlockedTriggeredAbility extends TriggeredAbilityImpl {
private final boolean setTargetPointer;
private final SetTargetPointer setTargetPointer;
public AttacksAndIsNotBlockedTriggeredAbility(Effect effect) {
this(effect, false, false);
this(effect, false);
}
public AttacksAndIsNotBlockedTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, false);
this(effect, optional, SetTargetPointer.NONE);
}
public AttacksAndIsNotBlockedTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) {
public AttacksAndIsNotBlockedTriggeredAbility(Effect effect, boolean optional, SetTargetPointer setTargetPointer) {
super(Zone.BATTLEFIELD, effect, optional);
this.setTargetPointer = setTargetPointer;
setTriggerPhrase("Whenever {this} attacks and isn't blocked, ");
@ -47,10 +48,16 @@ public class AttacksAndIsNotBlockedTriggeredAbility extends TriggeredAbilityImpl
if (!event.getTargetId().equals(getSourceId())) {
return false;
}
if (setTargetPointer) {
this.getEffects().setTargetPointer(new FixedTarget(
game.getCombat().getDefendingPlayerId(getSourceId(), game), game
));
switch (setTargetPointer) {
case NONE:
break;
case PLAYER:
this.getEffects().setTargetPointer(new FixedTarget(
game.getCombat().getDefendingPlayerId(getSourceId(), game), game
));
break;
default:
throw new IllegalArgumentException("Wrong code usage: not supported setTargetPointer");
}
return true;
}

View file

@ -0,0 +1,21 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.Zone;
import mage.game.Game;
/**
* If {this} is exiled
*
* @author Susucr
*/
public enum SourceInExileCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return game.getState().getZone(source.getSourceId()) == Zone.EXILED;
}
}