From a55ae8bea4607cf98f9c7b8469971a988c1bd782 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 13 Nov 2024 11:54:26 -0500 Subject: [PATCH] [J25] Implement Frontline Heroism --- .../src/mage/cards/f/FrontlineHeroism.java | 146 ++++++++++++++++++ .../src/mage/sets/FoundationsJumpstart.java | 1 + 2 files changed, 147 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FrontlineHeroism.java diff --git a/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java b/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java new file mode 100644 index 00000000000..ae262c06221 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FrontlineHeroism.java @@ -0,0 +1,146 @@ +package mage.cards.f; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.filter.predicate.other.HasOnlySingleTargetPermanentPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.AkroanSoldierToken; +import mage.game.permanent.token.Token; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.RandomUtil; +import mage.util.functions.StackObjectCopyApplier; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class FrontlineHeroism extends CardImpl { + + private static final FilterSpell filter + = new FilterSpell("a spell that targets only a single creature you control"); + + static { + filter.add(new HasOnlySingleTargetPermanentPredicate(StaticFilters.FILTER_CONTROLLED_CREATURE)); + } + + public FrontlineHeroism(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // When Frontline Heroism enters, create a 1/1 red Soldier creature token with haste. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new AkroanSoldierToken()))); + + // Whenever you cast a spell that targets only a single creature you control, create a 1/1 red Soldier creature token with haste, then copy that spell. The copy targets that token. + this.addAbility(new SpellCastControllerTriggeredAbility(new FrontlineHeroismEffect(), filter, false)); + } + + private FrontlineHeroism(final FrontlineHeroism card) { + super(card); + } + + @Override + public FrontlineHeroism copy() { + return new FrontlineHeroism(this); + } +} + +class FrontlineHeroismEffect extends OneShotEffect { + + private static final class FrontlineHeroismApplier implements StackObjectCopyApplier { + + private final Iterator predicate; + + FrontlineHeroismApplier(Permanent permanent, Game game) { + this.predicate = Arrays.asList(new MageObjectReferencePredicate(permanent, game)).iterator(); + } + + @Override + public void modifySpell(StackObject stackObject, Game game) { + } + + @Override + public MageObjectReferencePredicate getNextNewTargetType() { + if (predicate.hasNext()) { + return predicate.next(); + } + return null; + } + } + + FrontlineHeroismEffect() { + super(Outcome.Benefit); + staticText = "create a 1/1 red Soldier creature token with haste, " + + "then copy that spell. The copy targets that token"; + } + + private FrontlineHeroismEffect(final FrontlineHeroismEffect effect) { + super(effect); + } + + @Override + public FrontlineHeroismEffect copy() { + return new FrontlineHeroismEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; + } + Token token = new AkroanSoldierToken(); + token.putOntoBattlefield(1, game, source); + Set permanents = token + .getLastAddedTokenIds() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Permanent permanent; + switch (permanents.size()) { + case 0: + return false; + case 1: + permanent = RandomUtil.randomFromCollection(permanents); + break; + default: + FilterPermanent filter = new FilterPermanent("token to target with the copied spell"); + filter.add(Predicates.or( + permanents + .stream() + .map(MageItem::getId) + .map(PermanentIdPredicate::new) + .collect(Collectors.toSet()) + )); + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + permanent = game.getPermanent(target.getFirstTarget()); + } + spell.createCopyOnStack( + game, source, source.getControllerId(), false, + 1, new FrontlineHeroismApplier(permanent, game) + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/FoundationsJumpstart.java b/Mage.Sets/src/mage/sets/FoundationsJumpstart.java index a8dfdbb07bf..a1f49a93eda 100644 --- a/Mage.Sets/src/mage/sets/FoundationsJumpstart.java +++ b/Mage.Sets/src/mage/sets/FoundationsJumpstart.java @@ -279,6 +279,7 @@ public final class FoundationsJumpstart extends ExpansionSet { cards.add(new SetCardInfo("Forgotten Cave", 766, Rarity.UNCOMMON, mage.cards.f.ForgottenCave.class)); cards.add(new SetCardInfo("Foul Play", 442, Rarity.UNCOMMON, mage.cards.f.FoulPlay.class)); cards.add(new SetCardInfo("Fretwork Colony", 443, Rarity.UNCOMMON, mage.cards.f.FretworkColony.class)); + cards.add(new SetCardInfo("Frontline Heroism", 15, Rarity.RARE, mage.cards.f.FrontlineHeroism.class)); cards.add(new SetCardInfo("Frost Trickster", 313, Rarity.COMMON, mage.cards.f.FrostTrickster.class)); cards.add(new SetCardInfo("Fumulus, the Infestation", 42, Rarity.RARE, mage.cards.f.FumulusTheInfestation.class)); cards.add(new SetCardInfo("Fungal Plots", 658, Rarity.UNCOMMON, mage.cards.f.FungalPlots.class));