From a472ff9f1866141aac29994d03a7e8b71e65e1ed Mon Sep 17 00:00:00 2001 From: jmlundeen Date: Tue, 4 Mar 2025 17:44:40 -0600 Subject: [PATCH 1/4] [DFT] Add Guidelight Matrix artifact add static method from SaddleAbility to saddle a permanent add common saddle effect refactor Alacrian Armory with new saddle effect --- .../src/mage/cards/a/AlacrianArmory.java | 18 +---- .../src/mage/cards/g/GuidelightMatrix.java | 66 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 1 + .../common/SaddleTargetMountEffect.java | 44 +++++++++++++ .../mage/abilities/keyword/SaddleAbility.java | 17 +++++ 5 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/g/GuidelightMatrix.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AlacrianArmory.java b/Mage.Sets/src/mage/cards/a/AlacrianArmory.java index 7f0f5f5286c..efece7d0c13 100644 --- a/Mage.Sets/src/mage/cards/a/AlacrianArmory.java +++ b/Mage.Sets/src/mage/cards/a/AlacrianArmory.java @@ -3,15 +3,12 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.CrewSaddleIncreasedPowerAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.EndTurnEffect; import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.SaddleAbility; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; @@ -25,12 +22,9 @@ import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.SaddledSourceThisTurnPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.targetpointer.FixedTarget; /** * @@ -100,18 +94,10 @@ class AlacrianArmoryAnimateEffect extends OneShotEffect { return false; } if (target.hasSubtype(SubType.MOUNT, game)) { - target.getAbilities().stream().filter( - ability -> ability instanceof SaddleAbility) - .findFirst() - .ifPresent(ability -> game.fireEvent(GameEvent.getEvent( - GameEvent.EventType.MOUNT_SADDLED, - ability.getSourceId(), - ability, source.getControllerId())) - ); + SaddleAbility.applySaddle(target, game); } if (target.hasSubtype(SubType.VEHICLE, game)) { - game.addEffect(new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.CREATURE, CardType.ARTIFACT) - .setTargetPointer(new FixedTarget(target, game)), source); + game.addEffect(new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.CREATURE, CardType.ARTIFACT), source); } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java new file mode 100644 index 00000000000..93b938c91c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java @@ -0,0 +1,66 @@ +package mage.cards.g; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CompositeCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.SaddleTargetMountEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author Jmlundeen + */ +public final class GuidelightMatrix extends CardImpl { + + private static final FilterControlledPermanent mountFilter = new FilterControlledPermanent("Mount you control"); + private static final FilterControlledPermanent vehicleFilter = new FilterControlledPermanent("Vehicle you control"); + + static { + mountFilter.add(SubType.MOUNT.getPredicate()); + vehicleFilter.add(SubType.VEHICLE.getPredicate()); + } + + public GuidelightMatrix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + + // When this artifact enters, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + // {2}, {T}: Target Mount you control becomes saddled until end of turn. Activate only as a sorcery. + Ability saddledAbility = new ActivateAsSorceryActivatedAbility(new SaddleTargetMountEffect(), + new CompositeCost(new ManaCostsImpl<>("{2}"), new TapSourceCost(), "{2}, {T}") + ); + saddledAbility.addTarget(new TargetPermanent(mountFilter)); + this.addAbility(saddledAbility); + // {2}, {T}: Target Vehicle you control becomes an artifact creature until end of turn. + Ability animateVehicleAbility = new SimpleActivatedAbility( + new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE) + .setText("Target Vehicle you control becomes an artifact creature until end of turn."), + new CompositeCost(new ManaCostsImpl<>("{2}"), new TapSourceCost(), "{2}, {T}")); + animateVehicleAbility.addTarget(new TargetPermanent(vehicleFilter)); + this.addAbility(animateVehicleAbility); + } + + private GuidelightMatrix(final GuidelightMatrix card) { + super(card); + } + + @Override + public GuidelightMatrix copy() { + return new GuidelightMatrix(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index fa0196632dd..85b43477ebf 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -134,6 +134,7 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Grim Bauble", 88, Rarity.COMMON, mage.cards.g.GrimBauble.class)); cards.add(new SetCardInfo("Grim Javelineer", 89, Rarity.COMMON, mage.cards.g.GrimJavelineer.class)); cards.add(new SetCardInfo("Guardian Sunmare", 15, Rarity.RARE, mage.cards.g.GuardianSunmare.class)); + cards.add(new SetCardInfo("Guidelight Matrix", 233, Rarity.COMMON, mage.cards.g.GuidelightMatrix.class)); cards.add(new SetCardInfo("Guidelight Pathmaker", 206, Rarity.UNCOMMON, mage.cards.g.GuidelightPathmaker.class)); cards.add(new SetCardInfo("Guidelight Synergist", 16, Rarity.UNCOMMON, mage.cards.g.GuidelightSynergist.class)); cards.add(new SetCardInfo("Haunt the Network", 207, Rarity.UNCOMMON, mage.cards.h.HauntTheNetwork.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java new file mode 100644 index 00000000000..66de8d61eef --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java @@ -0,0 +1,44 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SaddleAbility; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Jmlundeen + */ +public class SaddleTargetMountEffect extends OneShotEffect { + + public SaddleTargetMountEffect() { + super(Outcome.Benefit); + staticText = "Target Mount you control becomes saddled until end of turn"; + } + + public SaddleTargetMountEffect(String rule) { + super(Outcome.Benefit); + staticText = rule; + } + + protected SaddleTargetMountEffect(final SaddleTargetMountEffect effect) { + super(effect); + } + + @Override + public SaddleTargetMountEffect copy() { + return new SaddleTargetMountEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetMount = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetMount == null || !targetMount.hasSubtype(SubType.MOUNT, game)) { + return false; + } + return SaddleAbility.applySaddle(targetMount, game); + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java index 6967270ddc3..a9b2d74730f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SaddleAbility.java @@ -48,6 +48,23 @@ public class SaddleAbility extends SimpleActivatedAbility { this.value = ability.value; } + public static boolean applySaddle(Permanent permanent, Game game) { + if (permanent == null) { + return false; + } + SaddleAbility saddleAbility = permanent.getAbilities().stream() + .filter(a -> a instanceof SaddleAbility) + .map(a -> (SaddleAbility) a) + .findFirst() + .orElse(null); + if (saddleAbility != null) { + SaddleEventEffect effect = new SaddleEventEffect(); + effect.apply(game, saddleAbility); + return true; + } + return false; + } + @Override public SaddleAbility copy() { return new SaddleAbility(this); From b9c1bd09a8b97f579c84e750798f8b077b76ad73 Mon Sep 17 00:00:00 2001 From: jmlundeen Date: Mon, 3 Mar 2025 21:54:30 -0600 Subject: [PATCH 2/4] [DFT] Add Kolodin, Triumph Caster --- .../mage/cards/k/KolodinTriumphCaster.java | 68 +++++++++++++++++++ Mage.Sets/src/mage/sets/Aetherdrift.java | 3 + 2 files changed, 71 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KolodinTriumphCaster.java diff --git a/Mage.Sets/src/mage/cards/k/KolodinTriumphCaster.java b/Mage.Sets/src/mage/cards/k/KolodinTriumphCaster.java new file mode 100644 index 00000000000..dd4b4110415 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KolodinTriumphCaster.java @@ -0,0 +1,68 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.SaddleTargetMountEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; + +/** + * + * @author Jmlundeen + */ +public final class KolodinTriumphCaster extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Mounts and Vehicles you control"); + private static final FilterControlledPermanent mountFilter = new FilterControlledPermanent("Mount"); + private static final FilterControlledPermanent vehicleFilter = new FilterControlledPermanent("Vehicle"); + static { + filter.add(Predicates.or( + SubType.MOUNT.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + mountFilter.add(SubType.MOUNT.getPredicate()); + vehicleFilter.add(SubType.VEHICLE.getPredicate()); + } + + public KolodinTriumphCaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PILOT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Mounts and Vehicles you control have haste. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new GainAbilityControlledEffect(HasteAbility.getInstance(), + Duration.WhileOnBattlefield, filter))); + // Whenever a Mount you control enters, it becomes saddled until end of turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new SaddleTargetMountEffect("it becomes saddled until end of turn"), + mountFilter)); + // Whenever a Vehicle you control enters, it becomes an artifact creature until end of turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new AddCardTypeTargetEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE) + .setText("it becomes an artifact creature until end of turn"), vehicleFilter) + ); + } + + private KolodinTriumphCaster(final KolodinTriumphCaster card) { + super(card); + } + + @Override + public KolodinTriumphCaster copy() { + return new KolodinTriumphCaster(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index 85b43477ebf..e5458abe890 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -153,6 +153,9 @@ public final class Aetherdrift extends ExpansionSet { cards.add(new SetCardInfo("Kalakscion, Hunger Tyrant", 93, Rarity.UNCOMMON, mage.cards.k.KalakscionHungerTyrant.class)); cards.add(new SetCardInfo("Keen Buccaneer", 48, Rarity.COMMON, mage.cards.k.KeenBuccaneer.class)); cards.add(new SetCardInfo("Kickoff Celebrations", 135, Rarity.COMMON, mage.cards.k.KickoffCelebrations.class)); + cards.add(new SetCardInfo("Kolodin, Triumph Caster", 210, Rarity.RARE, mage.cards.k.KolodinTriumphCaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kolodin, Triumph Caster", 364, Rarity.RARE, mage.cards.k.KolodinTriumphCaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kolodin, Triumph Caster", 483, Rarity.RARE, mage.cards.k.KolodinTriumphCaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lagorin, Soul of Alacria", 211, Rarity.UNCOMMON, mage.cards.l.LagorinSoulOfAlacria.class)); cards.add(new SetCardInfo("Leonin Surveyor", 18, Rarity.COMMON, mage.cards.l.LeoninSurveyor.class)); cards.add(new SetCardInfo("Lifecraft Engine", 234, Rarity.RARE, mage.cards.l.LifecraftEngine.class)); From 9a0cfaa5e7bf58f1cc5df538ed3f6c3ed7cd635c Mon Sep 17 00:00:00 2001 From: jmlundeen Date: Sat, 15 Mar 2025 12:11:46 -0500 Subject: [PATCH 3/4] Update SaddleTargetMountEffect and GuidelightMatrix changed SaddleTargetMountEffect apply to pass first target changed GuidelightMatrix to not use composite cost --- Mage.Sets/src/mage/cards/g/GuidelightMatrix.java | 5 ++--- .../abilities/effects/common/SaddleTargetMountEffect.java | 6 +----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java index 93b938c91c3..42fd69c618a 100644 --- a/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java +++ b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java @@ -41,9 +41,8 @@ public final class GuidelightMatrix extends CardImpl { // When this artifact enters, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // {2}, {T}: Target Mount you control becomes saddled until end of turn. Activate only as a sorcery. - Ability saddledAbility = new ActivateAsSorceryActivatedAbility(new SaddleTargetMountEffect(), - new CompositeCost(new ManaCostsImpl<>("{2}"), new TapSourceCost(), "{2}, {T}") - ); + Ability saddledAbility = new ActivateAsSorceryActivatedAbility(new SaddleTargetMountEffect(), new ManaCostsImpl<>("{2}")); + saddledAbility.addCost(new TapSourceCost()); saddledAbility.addTarget(new TargetPermanent(mountFilter)); this.addAbility(saddledAbility); // {2}, {T}: Target Vehicle you control becomes an artifact creature until end of turn. diff --git a/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java index 66de8d61eef..e32f6036408 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SaddleTargetMountEffect.java @@ -34,11 +34,7 @@ public class SaddleTargetMountEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent targetMount = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetMount == null || !targetMount.hasSubtype(SubType.MOUNT, game)) { - return false; - } - return SaddleAbility.applySaddle(targetMount, game); + return SaddleAbility.applySaddle(game.getPermanent(getTargetPointer().getFirst(game, source)), game); } } From 4a0a8559f9621814d4571b34f608ec3bc66ddafe Mon Sep 17 00:00:00 2001 From: jmlundeen Date: Sun, 16 Mar 2025 15:08:27 -0500 Subject: [PATCH 4/4] Remove Composite Cost --- Mage.Sets/src/mage/cards/g/GuidelightMatrix.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java index 42fd69c618a..542728b3e39 100644 --- a/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java +++ b/Mage.Sets/src/mage/cards/g/GuidelightMatrix.java @@ -49,7 +49,8 @@ public final class GuidelightMatrix extends CardImpl { Ability animateVehicleAbility = new SimpleActivatedAbility( new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE) .setText("Target Vehicle you control becomes an artifact creature until end of turn."), - new CompositeCost(new ManaCostsImpl<>("{2}"), new TapSourceCost(), "{2}, {T}")); + new ManaCostsImpl<>("{2}")); + animateVehicleAbility.addCost(new TapSourceCost()); animateVehicleAbility.addTarget(new TargetPermanent(vehicleFilter)); this.addAbility(animateVehicleAbility); }