From 705ce2320d3a28fe961755d585a4d5be5f0233b2 Mon Sep 17 00:00:00 2001 From: ssk97 Date: Wed, 26 Feb 2025 00:14:48 -0800 Subject: [PATCH] [DFT] Canyon Vaulter, Cloudspire Skycycle, Dune Drifter (#13382) * Support Mounts and Your Main restriction in CrewsVehicleSourceTriggeredAbility * Genericize Reckless Velocitaur * Implement [DFT] Canyon Vaulter, Cloudspire Skycycle, and Dune Drifter --- Mage.Sets/src/mage/cards/c/CanyonVaulter.java | 43 +++++++++++++ .../src/mage/cards/c/CloudspireSkycycle.java | 60 +++++++++++++++++++ Mage.Sets/src/mage/cards/d/DuneDrifter.java | 57 ++++++++++++++++++ .../src/mage/cards/r/RecklessVelocitaur.java | 58 ++++-------------- Mage.Sets/src/mage/sets/Aetherdrift.java | 3 + .../CrewsVehicleSourceTriggeredAbility.java | 19 +++++- 6 files changed, 192 insertions(+), 48 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/c/CanyonVaulter.java create mode 100644 Mage.Sets/src/mage/cards/c/CloudspireSkycycle.java create mode 100644 Mage.Sets/src/mage/cards/d/DuneDrifter.java diff --git a/Mage.Sets/src/mage/cards/c/CanyonVaulter.java b/Mage.Sets/src/mage/cards/c/CanyonVaulter.java new file mode 100644 index 00000000000..7141b745670 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CanyonVaulter.java @@ -0,0 +1,43 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CrewsVehicleSourceTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class CanyonVaulter extends CardImpl { + + public CanyonVaulter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.KOR); + this.subtype.add(SubType.PILOT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Whenever this creature saddles a Mount or crews a Vehicle during your main phase, that Mount or Vehicle gains flying until end of turn. + Effect effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + effect.setText("that Mount or Vehicle gains flying until end of turn"); + this.addAbility(new CrewsVehicleSourceTriggeredAbility(effect, true, true)); + } + + private CanyonVaulter(final CanyonVaulter card) { + super(card); + } + + @Override + public CanyonVaulter copy() { + return new CanyonVaulter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CloudspireSkycycle.java b/Mage.Sets/src/mage/cards/c/CloudspireSkycycle.java new file mode 100644 index 00000000000..fe62143da4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CloudspireSkycycle.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.DistributeCountersEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; +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.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.common.TargetPermanentAmount; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class CloudspireSkycycle extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("other target Vehicles and/or creatures you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.or(SubType.VEHICLE.getPredicate(), CardType.CREATURE.getPredicate())); + } + + public CloudspireSkycycle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}{W}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this Vehicle enters, distribute two +1/+1 counters among one or two other target Vehicles and/or creatures you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect()); + ability.addTarget(new TargetPermanentAmount(2, 1, filter)); + this.addAbility(ability); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + + } + + private CloudspireSkycycle(final CloudspireSkycycle card) { + super(card); + } + + @Override + public CloudspireSkycycle copy() { + return new CloudspireSkycycle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DuneDrifter.java b/Mage.Sets/src/mage/cards/d/DuneDrifter.java new file mode 100644 index 00000000000..8a3f5a6307b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuneDrifter.java @@ -0,0 +1,57 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.XManaValueTargetAdjuster; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class DuneDrifter extends CardImpl { + + private static final FilterCard filter = new FilterCard("artifact or creature card with mana value X or less from your graveyard"); + + static { + filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate())); + } + + public DuneDrifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{X}{W}{B}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this Vehicle enters, return target artifact or creature card with mana value X or less from your graveyard to the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.setTargetAdjuster(new XManaValueTargetAdjuster(ComparisonType.OR_LESS)); + this.addAbility(ability); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + + } + + private DuneDrifter(final DuneDrifter card) { + super(card); + } + + @Override + public DuneDrifter copy() { + return new DuneDrifter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RecklessVelocitaur.java b/Mage.Sets/src/mage/cards/r/RecklessVelocitaur.java index 66781d9082d..a6fd111e961 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessVelocitaur.java +++ b/Mage.Sets/src/mage/cards/r/RecklessVelocitaur.java @@ -1,18 +1,17 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CrewsVehicleSourceTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; 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.target.targetpointer.FixedTarget; import java.util.UUID; @@ -30,7 +29,14 @@ public final class RecklessVelocitaur extends CardImpl { this.toughness = new MageInt(3); // Whenever this creature saddles a Mount or crews a Vehicle during your main phase, that Mount or Vehicle gets +2/+0 and gains trample until end of turn. - this.addAbility(new RecklessVelocitaurTriggeredAbility()); + + Effect boostEffect = new BoostTargetEffect(1, 1, Duration.EndOfTurn) + .setText("that Mount or Vehicle gets +2/+0"); + Effect abilityGainEffect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn) + .setText("and gains trample until end of turn"); + Ability ability = new CrewsVehicleSourceTriggeredAbility(boostEffect, true, true); + ability.addEffect(abilityGainEffect); + this.addAbility(ability); } private RecklessVelocitaur(final RecklessVelocitaur card) { @@ -42,43 +48,3 @@ public final class RecklessVelocitaur extends CardImpl { return new RecklessVelocitaur(this); } } - -class RecklessVelocitaurTriggeredAbility extends TriggeredAbilityImpl { - - RecklessVelocitaurTriggeredAbility() { - super(Zone.BATTLEFIELD, new BoostTargetEffect(2, 0).setText("that Mount or Vehicle gets +2/+0")); - this.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and gains trample until end of turn")); - this.setTriggerPhrase("Whenever {this} saddles a Mount or crews a Vehicle during your main phase, "); - } - - private RecklessVelocitaurTriggeredAbility(final RecklessVelocitaurTriggeredAbility ability) { - super(ability); - } - - @Override - public RecklessVelocitaurTriggeredAbility copy() { - return new RecklessVelocitaurTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - switch (event.getType()) { - case SADDLED_MOUNT: - case CREWED_VEHICLE: - return true; - default: - return false; - } - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!this.isControlledBy(game.getActivePlayerId()) - || !game.isMainPhase() - || !event.getTargetId().equals(this.getSourceId())) { - return false; - } - this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId())); - return true; - } -} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 90384a4214c..7e036201459 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -62,6 +62,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Burnout Bashtronaut", 115, Rarity.RARE, mage.cards.b.BurnoutBashtronaut.class)); cards.add(new SetCardInfo("Caelorna, Coral Tyrant", 40, Rarity.UNCOMMON, mage.cards.c.CaelornaCoralTyrant.class)); cards.add(new SetCardInfo("Camera Launcher", 232, Rarity.COMMON, mage.cards.c.CameraLauncher.class)); + cards.add(new SetCardInfo("Canyon Vaulter", 8, Rarity.UNCOMMON, mage.cards.c.CanyonVaulter.class)); cards.add(new SetCardInfo("Caradora, Heart of Alacria", 195, Rarity.RARE, mage.cards.c.CaradoraHeartOfAlacria.class)); cards.add(new SetCardInfo("Carrion Cruiser", 78, Rarity.UNCOMMON, mage.cards.c.CarrionCruiser.class)); cards.add(new SetCardInfo("Chandra, Spark Hunter", 116, Rarity.MYTHIC, mage.cards.c.ChandraSparkHunter.class)); @@ -69,6 +70,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Clamorous Ironclad", 117, Rarity.COMMON, mage.cards.c.ClamorousIronclad.class)); cards.add(new SetCardInfo("Cloudspire Captain", 9, Rarity.UNCOMMON, mage.cards.c.CloudspireCaptain.class)); cards.add(new SetCardInfo("Cloudspire Coordinator", 196, Rarity.UNCOMMON, mage.cards.c.CloudspireCoordinator.class)); + cards.add(new SetCardInfo("Cloudspire Skycycle", 197, Rarity.UNCOMMON, mage.cards.c.CloudspireSkycycle.class)); cards.add(new SetCardInfo("Coalstoke Gearhulk", 198, Rarity.MYTHIC, mage.cards.c.CoalstokeGearhulk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Coalstoke Gearhulk", 349, Rarity.MYTHIC, mage.cards.c.CoalstokeGearhulk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Coalstoke Gearhulk", 477, Rarity.MYTHIC, mage.cards.c.CoalstokeGearhulk.class, NON_FULL_USE_VARIOUS)); @@ -95,6 +97,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Draconautics Engineer", 121, Rarity.RARE, mage.cards.d.DraconauticsEngineer.class)); cards.add(new SetCardInfo("Dracosaur Auxiliary", 122, Rarity.UNCOMMON, mage.cards.d.DracosaurAuxiliary.class)); cards.add(new SetCardInfo("Dredger's Insight", 159, Rarity.UNCOMMON, mage.cards.d.DredgersInsight.class)); + cards.add(new SetCardInfo("Dune Drifter", 200, Rarity.UNCOMMON, mage.cards.d.DuneDrifter.class)); cards.add(new SetCardInfo("Dynamite Diver", 123, Rarity.COMMON, mage.cards.d.DynamiteDiver.class)); cards.add(new SetCardInfo("Earthrumbler", 160, Rarity.UNCOMMON, mage.cards.e.Earthrumbler.class)); cards.add(new SetCardInfo("Embalmed Ascendant", 201, Rarity.UNCOMMON, mage.cards.e.EmbalmedAscendant.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java index 3f684fa2ff3..cac0128b939 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java @@ -10,14 +10,26 @@ import mage.target.targetpointer.FixedTarget; public class CrewsVehicleSourceTriggeredAbility extends TriggeredAbilityImpl { + private final boolean mountsAlso; + private final boolean yourMainPhaseOnly; + public CrewsVehicleSourceTriggeredAbility(Effect effect) { + this(effect, false, false); + } + + public CrewsVehicleSourceTriggeredAbility(Effect effect, boolean mountsAlso, boolean yourMainPhaseOnly) { super(Zone.BATTLEFIELD, effect, false); this.addIcon(CardIconImpl.ABILITY_CREW); - setTriggerPhrase("Whenever {this} crews a Vehicle, "); + this.mountsAlso = mountsAlso; + this.yourMainPhaseOnly = yourMainPhaseOnly; + setTriggerPhrase("Whenever {this}" + (mountsAlso ? " saddles a Mount or" : "") + + " crews a Vehicle" + (yourMainPhaseOnly ? " during your main phase" : "") + ", "); } protected CrewsVehicleSourceTriggeredAbility(final CrewsVehicleSourceTriggeredAbility ability) { super(ability); + this.mountsAlso = ability.mountsAlso; + this.yourMainPhaseOnly = ability.yourMainPhaseOnly; } @Override @@ -27,11 +39,14 @@ public class CrewsVehicleSourceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CREWED_VEHICLE; + return event.getType() == GameEvent.EventType.CREWED_VEHICLE || (mountsAlso && event.getType() == GameEvent.EventType.SADDLED_MOUNT); } @Override public boolean checkTrigger(GameEvent event, Game game) { + if (yourMainPhaseOnly && !(game.isMainPhase() && this.isControlledBy(game.getActivePlayerId()))) { + return false; + } if (event.getTargetId().equals(getSourceId())) { for (Effect effect : getEffects()) { // set the vehicle id as target