[SNC] Implement High-Rise Sawjack. (#8847)

* [SNC] Implement High-Rise Sawjack. Add BlocksCreatureWithFlyingTriggeredAbility.

* [SNC] Implement more generic BlocksCreatureTriggeredAbility

Co-authored-by: Evan Kranzler <theelk801@gmail.com>
This commit is contained in:
Hidde van Bavel 2022-04-23 22:43:26 +02:00 committed by GitHub
parent aa2215fefb
commit 53e5e2cd74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 177 additions and 242 deletions

View file

@ -1,7 +1,10 @@
package mage.cards.c;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FirstStrikeAbility;
@ -12,6 +15,9 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@ -23,6 +29,12 @@ import java.util.UUID;
*/
public final class CrimsonRoc extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying");
static {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
}
public CrimsonRoc(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
@ -34,7 +46,13 @@ public final class CrimsonRoc extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Crimson Roc blocks a creature without flying, Crimson Roc gets +1/+0 and gains first strike until end of turn.
this.addAbility(new CrimsonRocTriggeredAbility());
Ability ability = new BlocksCreatureTriggeredAbility(new BoostSourceEffect(
1, 0, Duration.EndOfTurn
).setText("{this} gets +1/+0"), filter, false);
ability.addEffect(new GainAbilitySourceEffect(
FirstStrikeAbility.getInstance(), Duration.EndOfTurn
).setText("and gains first strike until end of turn"));
this.addAbility(ability);
}
private CrimsonRoc(final CrimsonRoc card) {
@ -45,43 +63,4 @@ public final class CrimsonRoc extends CardImpl {
public CrimsonRoc copy() {
return new CrimsonRoc(this);
}
}
class CrimsonRocTriggeredAbility extends TriggeredAbilityImpl {
CrimsonRocTriggeredAbility() {
super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), false);
this.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn));
}
private CrimsonRocTriggeredAbility(final CrimsonRocTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!event.getSourceId().equals(this.getSourceId())) {
return false;
}
Permanent permanent = game.getPermanent(event.getTargetId());
return permanent != null
&& permanent.isCreature(game)
&& !permanent.hasAbility(FlyingAbility.getInstance(), game);
}
@Override
public String getRule() {
return "Whenever {this} blocks a creature without flying, " +
"{this} gets +1/+0 and gains first strike until end of turn.";
}
@Override
public CrimsonRocTriggeredAbility copy() {
return new CrimsonRocTriggeredAbility(this);
}
}
}

View file

@ -3,8 +3,7 @@ package mage.cards.e;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
@ -13,10 +12,9 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
/**
*
@ -24,6 +22,12 @@ import mage.game.events.GameEvent.EventType;
*/
public final class EzurisArchers extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public EzurisArchers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}");
this.subtype.add(SubType.ELF);
@ -32,9 +36,11 @@ public final class EzurisArchers extends CardImpl {
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever Ezuri's Archers blocks a creature with flying, Ezuri's Archers gets +3/+0 until end of turn.
this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), false));
this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), filter, false));
}
private EzurisArchers(final EzurisArchers card) {
@ -46,34 +52,3 @@ public final class EzurisArchers extends CardImpl {
return new EzurisArchers(this);
}
}
class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl {
public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
}
public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getSourceId().equals(this.getSourceId()) && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId());
}
@Override
public String getTriggerPhrase() {
return "Whenever {this} blocks a creature with flying, " ;
}
@Override
public BlocksCreatureWithFlyingTriggeredAbility copy() {
return new BlocksCreatureWithFlyingTriggeredAbility(this);
}
}

View file

@ -3,7 +3,7 @@ package mage.cards.f;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
@ -16,13 +16,8 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
@ -48,7 +43,7 @@ public final class FrostwebSpider extends CardImpl {
// Whenever Frostweb Spider blocks a creature with flying, put a +1/+1 counter on Frostweb Spider at end of combat.
Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())), true);
effect.setText("put a +1/+1 counter on {this} at end of combat");
this.addAbility(new FrostwebSpiderTriggeredAbility(effect, filter, false));
this.addAbility(new BlocksCreatureTriggeredAbility(effect, filter,false));
}
private FrostwebSpider(final FrostwebSpider card) {
@ -59,45 +54,4 @@ public final class FrostwebSpider extends CardImpl {
public FrostwebSpider copy() {
return new FrostwebSpider(this);
}
}
class FrostwebSpiderTriggeredAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
public FrostwebSpiderTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
}
public FrostwebSpiderTriggeredAbility(final FrostwebSpiderTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getSourceId().equals(this.getSourceId())) {
Permanent blocked = game.getPermanent(event.getTargetId());
if (blocked != null && filter.match(blocked, game)) {
return true;
}
}
return false;
}
@Override
public String getTriggerPhrase() {
return "Whenever {this} blocks a " + filter.getMessage() + ", " ;
}
@Override
public FrostwebSpiderTriggeredAbility copy() {
return new FrostwebSpiderTriggeredAbility(this);
}
}
}

View file

@ -0,0 +1,52 @@
package mage.cards.h;
import mage.MageInt;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import java.util.UUID;
/**
* @author Hiddevb
*/
public final class HighRiseSawjack extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public HighRiseSawjack(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}");
this.subtype.add(SubType.ELF);
this.subtype.add(SubType.CITIZEN);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever High-Rise Sawjack blocks a creature with flying, High-Rise Sawjack gets +2/+0 until end of turn.
this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false));
}
private HighRiseSawjack(final HighRiseSawjack card) {
super(card);
}
@Override
public HighRiseSawjack copy() {
return new HighRiseSawjack(this);
}
}

View file

@ -3,8 +3,7 @@ package mage.cards.n;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
@ -13,10 +12,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
/**
*
@ -24,6 +21,12 @@ import mage.game.events.GameEvent.EventType;
*/
public final class NetcasterSpider extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public NetcasterSpider(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}");
this.subtype.add(SubType.SPIDER);
@ -33,8 +36,9 @@ public final class NetcasterSpider extends CardImpl {
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever Netcaster Spider blocks a creature with flying, Netcaster Spider gets +2/+0 until end of turn.
this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), false));
this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false));
}
private NetcasterSpider(final NetcasterSpider card) {
@ -45,36 +49,4 @@ public final class NetcasterSpider extends CardImpl {
public NetcasterSpider copy() {
return new NetcasterSpider(this);
}
}
class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl {
public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
}
public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getSourceId().equals(this.getSourceId())
&& game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId());
}
@Override
public String getTriggerPhrase() {
return "Whenever {this} blocks a creature with flying, " ;
}
@Override
public BlocksCreatureWithFlyingTriggeredAbility copy() {
return new BlocksCreatureWithFlyingTriggeredAbility(this);
}
}

View file

@ -1,7 +1,7 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
@ -10,9 +10,8 @@ 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.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
import java.util.UUID;
@ -21,6 +20,12 @@ import java.util.UUID;
*/
public final class Snarespinner extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public Snarespinner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
@ -32,7 +37,7 @@ public final class Snarespinner extends CardImpl {
this.addAbility(ReachAbility.getInstance());
// Whenever Snarespinner blocks a creature with flying, Snarespinner gets +2/+0 until end of turn.
this.addAbility(new SnarespinnerTriggeredAbility());
this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false));
}
private Snarespinner(final Snarespinner card) {
@ -43,36 +48,4 @@ public final class Snarespinner extends CardImpl {
public Snarespinner copy() {
return new Snarespinner(this);
}
}
class SnarespinnerTriggeredAbility extends TriggeredAbilityImpl {
SnarespinnerTriggeredAbility() {
super(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), false);
}
private SnarespinnerTriggeredAbility(final SnarespinnerTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getSourceId().equals(this.getSourceId())
&& game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId());
}
@Override
public String getRule() {
return "Whenever {this} blocks a creature with flying, {this} gets +2/+0 until end of turn.";
}
@Override
public SnarespinnerTriggeredAbility copy() {
return new SnarespinnerTriggeredAbility(this);
}
}

View file

@ -3,8 +3,7 @@ package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
@ -13,10 +12,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AbilityPredicate;
/**
*
@ -24,6 +21,12 @@ import mage.game.events.GameEvent.EventType;
*/
public final class WoollySpider extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public WoollySpider(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}");
this.subtype.add(SubType.SPIDER);
@ -33,8 +36,9 @@ public final class WoollySpider extends CardImpl {
// Reach
this.addAbility(ReachAbility.getInstance());
// Whenever Woolly Spider blocks a creature with flying, Woolly Spider gets +0/+2 until end of turn.
this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), false));
this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), filter, false));
}
private WoollySpider(final WoollySpider card) {
@ -45,35 +49,4 @@ public final class WoollySpider extends CardImpl {
public WoollySpider copy() {
return new WoollySpider(this);
}
}
class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl {
public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
}
public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getSourceId().equals(this.getSourceId()) && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId());
}
@Override
public String getTriggerPhrase() {
return "Whenever {this} blocks a creature with flying, " ;
}
@Override
public BlocksCreatureWithFlyingTriggeredAbility copy() {
return new BlocksCreatureWithFlyingTriggeredAbility(this);
}
}

View file

@ -130,6 +130,7 @@ public final class StreetsOfNewCapenna extends ExpansionSet {
cards.add(new SetCardInfo("Graveyard Shift", 81, Rarity.UNCOMMON, mage.cards.g.GraveyardShift.class));
cards.add(new SetCardInfo("Grisly Sigil", 82, Rarity.UNCOMMON, mage.cards.g.GrislySigil.class));
cards.add(new SetCardInfo("Halo Fountain", 15, Rarity.MYTHIC, mage.cards.h.HaloFountain.class));
cards.add(new SetCardInfo("High-Rise Sawjack", 150, Rarity.COMMON, mage.cards.h.HighRiseSawjack.class));
cards.add(new SetCardInfo("Halo Scarab", 239, Rarity.COMMON, mage.cards.h.HaloScarab.class));
cards.add(new SetCardInfo("Hoard Hauler", 109, Rarity.RARE, mage.cards.h.HoardHauler.class));
cards.add(new SetCardInfo("Hold for Ransom", 16, Rarity.COMMON, mage.cards.h.HoldForRansom.class));

View file

@ -0,0 +1,56 @@
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.keyword.FlyingAbility;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
* @author Hiddevb
*/
public class BlocksCreatureTriggeredAbility extends TriggeredAbilityImpl {
private final FilterCreaturePermanent filter;
public BlocksCreatureTriggeredAbility(Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = StaticFilters.FILTER_PERMANENT_CREATURE;
}
public BlocksCreatureTriggeredAbility(Effect effect, FilterCreaturePermanent filter, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
}
public BlocksCreatureTriggeredAbility(final BlocksCreatureTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getSourceId().equals(this.getSourceId())
&& !filter.match(game.getPermanent(event.getSourceId()), game);
}
@Override
public String getTriggerPhrase() {
return "Whenever {this} blocks "
+ (filter.getMessage().startsWith("an ") ? "" : "a ")
+ filter.getMessage() + ", " ;
}
@Override
public BlocksCreatureTriggeredAbility copy() {
return new BlocksCreatureTriggeredAbility(this);
}
}