From 886dd1f0b2ae05549dbe6e1e0027a56f5943d56f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 15 Nov 2025 10:24:28 -0500 Subject: [PATCH] [TLA] Implement Lost Days --- Mage.Sets/src/mage/cards/d/DeemInferior.java | 45 +------------------ Mage.Sets/src/mage/cards/l/LostDays.java | 39 ++++++++++++++++ .../src/mage/cards/t/TemporalCleansing.java | 45 +------------------ .../src/mage/sets/AvatarTheLastAirbender.java | 1 + .../PutOnTopOrBottomLibraryTargetEffect.java | 33 ++++++++++++-- 5 files changed, 74 insertions(+), 89 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/l/LostDays.java diff --git a/Mage.Sets/src/mage/cards/d/DeemInferior.java b/Mage.Sets/src/mage/cards/d/DeemInferior.java index 2745bc88338..dc4a84da763 100644 --- a/Mage.Sets/src/mage/cards/d/DeemInferior.java +++ b/Mage.Sets/src/mage/cards/d/DeemInferior.java @@ -3,16 +3,12 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -33,7 +29,7 @@ public final class DeemInferior extends CardImpl { this.addAbility(ability.addHint(CardsDrawnThisTurnDynamicValue.getHint())); // The owner of target nonland permanent puts it into their library second from the top or on the bottom. - this.getSpellAbility().addEffect(new DeemInferiorEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } @@ -46,40 +42,3 @@ public final class DeemInferior extends CardImpl { return new DeemInferior(this); } } - -// Same as Temporal Cleansing. -class DeemInferiorEffect extends OneShotEffect { - - DeemInferiorEffect() { - super(Outcome.Benefit); - staticText = "the owner of target nonland permanent puts it into their library second from the top or on the bottom"; - } - - private DeemInferiorEffect(final DeemInferiorEffect effect) { - super(effect); - } - - @Override - public DeemInferiorEffect copy() { - return new DeemInferiorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - Player player = game.getPlayer(permanent.getOwnerId()); - if (player == null) { - return false; - } - if (player.chooseUse( - outcome, "Put " + permanent.getIdName() + " second from the top or on the bottom?", - null, "Second from top", "Bottom", source, game - )) { - return player.putCardOnTopXOfLibrary(permanent, game, source, 2, true); - } - return player.putCardsOnBottomOfLibrary(permanent, game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LostDays.java b/Mage.Sets/src/mage/cards/l/LostDays.java new file mode 100644 index 00000000000..92d8967e83d --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LostDays.java @@ -0,0 +1,39 @@ +package mage.cards.l; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LostDays extends CardImpl { + + public LostDays(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}"); + + this.subtype.add(SubType.LESSON); + + // The owner of target creature or enchantment puts it into their library second from the top or on the bottom. You create a Clue token. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("You")); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); + } + + private LostDays(final LostDays card) { + super(card); + } + + @Override + public LostDays copy() { + return new LostDays(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TemporalCleansing.java b/Mage.Sets/src/mage/cards/t/TemporalCleansing.java index 250e304cc9b..32002794171 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalCleansing.java +++ b/Mage.Sets/src/mage/cards/t/TemporalCleansing.java @@ -1,15 +1,10 @@ package mage.cards.t; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.keyword.ConvokeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -26,7 +21,7 @@ public final class TemporalCleansing extends CardImpl { this.addAbility(new ConvokeAbility()); // The owner of target nonland permanent puts it into their library second from the top or on the bottom. - this.getSpellAbility().addEffect(new TemporalCleansingEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } @@ -39,39 +34,3 @@ public final class TemporalCleansing extends CardImpl { return new TemporalCleansing(this); } } - -class TemporalCleansingEffect extends OneShotEffect { - - TemporalCleansingEffect() { - super(Outcome.Benefit); - staticText = "the owner of target nonland permanent puts it into their library second from the top or on the bottom"; - } - - private TemporalCleansingEffect(final TemporalCleansingEffect effect) { - super(effect); - } - - @Override - public TemporalCleansingEffect copy() { - return new TemporalCleansingEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - Player player = game.getPlayer(permanent.getOwnerId()); - if (player == null) { - return false; - } - if (player.chooseUse( - outcome, "Put " + permanent.getIdName() + " second from the top or on the bottom?", - null, "Second from top", "Bottom", source, game - )) { - return player.putCardOnTopXOfLibrary(permanent, game, source, 2, true); - } - return player.putCardsOnBottomOfLibrary(permanent, game, source); - } -} diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java index bbeb3385f06..c8b4db17dfe 100644 --- a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java @@ -230,6 +230,7 @@ public final class AvatarTheLastAirbender extends ExpansionSet { cards.add(new SetCardInfo("Lightning Strike", 146, Rarity.COMMON, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Lo and Li, Twin Tutors", 108, Rarity.UNCOMMON, mage.cards.l.LoAndLiTwinTutors.class)); cards.add(new SetCardInfo("Long Feng, Grand Secretariat", 233, Rarity.UNCOMMON, mage.cards.l.LongFengGrandSecretariat.class)); + cards.add(new SetCardInfo("Lost Days", 62, Rarity.COMMON, mage.cards.l.LostDays.class)); cards.add(new SetCardInfo("Mai, Jaded Edge", 147, Rarity.UNCOMMON, mage.cards.m.MaiJadedEdge.class)); cards.add(new SetCardInfo("Mai, Scornful Striker", 109, Rarity.RARE, mage.cards.m.MaiScornfulStriker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mai, Scornful Striker", 374, Rarity.RARE, mage.cards.m.MaiScornfulStriker.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java index 4a99ba55bd2..45dfa70ed00 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java @@ -6,21 +6,29 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; /** * @author TheElk801 */ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { + private final int position; private final boolean textOwnerOf; public PutOnTopOrBottomLibraryTargetEffect(boolean textOwnerOf) { + this(1, textOwnerOf); + } + + public PutOnTopOrBottomLibraryTargetEffect(int position, boolean textOwnerOf) { super(Outcome.ReturnToHand); + this.position = position; this.textOwnerOf = textOwnerOf; } private PutOnTopOrBottomLibraryTargetEffect(final PutOnTopOrBottomLibraryTargetEffect effect) { super(effect); + this.position = effect.position; this.textOwnerOf = effect.textOwnerOf; } @@ -35,10 +43,14 @@ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { if (player == null) { return false; } + String message = position > 1 ? "into your library " + CardUtil.numberToOrdinalText(position) + " from the top or on the" : "on the top or"; boolean onTop = player.chooseUse( - Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", + Outcome.Detriment, "Put the targeted object " + message + " bottom of your library?", null, "Top", "Bottom", source, game ); + if (onTop && position > 1) { + return new PutIntoLibraryNFromTopTargetEffect(position).apply(game, source); + } return new PutOnLibraryTargetEffect(onTop).apply(game, source); } @@ -47,8 +59,23 @@ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } + StringBuilder sb = new StringBuilder(); String targetText = getTargetPointer().describeTargets(mode.getTargets(), "that permanent"); - return (textOwnerOf ? "the owner of " + targetText : targetText + "'s owner") + - " puts it on their choice of the top or bottom of their library"; + if (textOwnerOf) { + sb.append("the owner of "); + sb.append(targetText); + } else { + sb.append(targetText); + sb.append("'s owner"); + } + sb.append(" puts it"); + if (position > 1) { + sb.append("into their library "); + sb.append(CardUtil.numberToOrdinalText(position)); + sb.append(" from the top or on the bottom"); + } else { + sb.append("on their choice of the top or bottom of their library"); + } + return sb.toString(); } }