From 1a205ff193e282aba27c966591c706319481af8d Mon Sep 17 00:00:00 2001
From: Susucre <34709007+Susucre@users.noreply.github.com>
Date: Thu, 26 Oct 2023 12:22:18 +0200
Subject: [PATCH] [LCI] Implement Jadelight Spelunker
---
.../src/mage/cards/d/DeadeyeTracker.java | 7 +--
.../src/mage/cards/j/JadelightRanger.java | 11 ++--
.../src/mage/cards/j/JadelightSpelunker.java | 44 +++++++++++++++
.../src/mage/sets/TheLostCavernsOfIxalan.java | 1 +
.../effects/keyword/ExploreSourceEffect.java | 56 ++++++++++++-------
.../effects/keyword/ExploreTargetEffect.java | 4 +-
6 files changed, 94 insertions(+), 29 deletions(-)
create mode 100644 Mage.Sets/src/mage/cards/j/JadelightSpelunker.java
diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeTracker.java b/Mage.Sets/src/mage/cards/d/DeadeyeTracker.java
index c9175b6764b..613413f41ae 100644
--- a/Mage.Sets/src/mage/cards/d/DeadeyeTracker.java
+++ b/Mage.Sets/src/mage/cards/d/DeadeyeTracker.java
@@ -1,7 +1,6 @@
package mage.cards.d;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@@ -18,8 +17,9 @@ import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.target.common.TargetCardInOpponentsGraveyard;
+import java.util.UUID;
+
/**
- *
* @author TheElk801
*/
public final class DeadeyeTracker extends CardImpl {
@@ -35,8 +35,7 @@ public final class DeadeyeTracker extends CardImpl {
// {1}{B}, {T}: Exile two target cards from an opponent's graveyard. Deadeye Tracker explores.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new TapSourceCost());
ability.addCost(new ManaCostsImpl<>("{1}{B}"));
- Effect effect = new ExploreSourceEffect();
- effect.setText("{this} explores");
+ Effect effect = new ExploreSourceEffect(true, "{this}");
ability.addEffect(effect);
ability.addTarget(new TargetCardInOpponentsGraveyard(2, 2, new FilterCard("cards from an opponent's graveyard"), true));
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/j/JadelightRanger.java b/Mage.Sets/src/mage/cards/j/JadelightRanger.java
index 2caf4dfcdb9..fd0164d1f3e 100644
--- a/Mage.Sets/src/mage/cards/j/JadelightRanger.java
+++ b/Mage.Sets/src/mage/cards/j/JadelightRanger.java
@@ -1,7 +1,6 @@
package mage.cards.j;
import mage.MageInt;
-import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.keyword.ExploreSourceEffect;
import mage.cards.CardImpl;
@@ -26,9 +25,13 @@ public final class JadelightRanger extends CardImpl {
this.toughness = new MageInt(1);
// When Jadelight Ranger enters the battlefield, it explores, then it explores again.
- Ability ability = new EntersBattlefieldTriggeredAbility(new ExploreSourceEffect(false, "it"), false);
- ability.addEffect(new ExploreSourceEffect().setText(", then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process.)"));
- this.addAbility(ability);
+ this.addAbility(new EntersBattlefieldTriggeredAbility(
+ new ExploreSourceEffect(2, false, "it")
+ .setText("it explores, then it explores again. (Reveal the top card of your library. "
+ + "Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, "
+ + "then put the card back or put it into your graveyard. Then repeat this process.)"),
+ false
+ ));
}
private JadelightRanger(final JadelightRanger card) {
diff --git a/Mage.Sets/src/mage/cards/j/JadelightSpelunker.java b/Mage.Sets/src/mage/cards/j/JadelightSpelunker.java
new file mode 100644
index 00000000000..68b1044c4cf
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/j/JadelightSpelunker.java
@@ -0,0 +1,44 @@
+package mage.cards.j;
+
+import mage.MageInt;
+import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.dynamicvalue.common.ManacostVariableValue;
+import mage.abilities.effects.keyword.ExploreSourceEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SubType;
+
+import java.util.UUID;
+
+/**
+ * @author Susucr
+ */
+public final class JadelightSpelunker extends CardImpl {
+
+ public JadelightSpelunker(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{G}");
+
+ this.subtype.add(SubType.MERFOLK);
+ this.subtype.add(SubType.SCOUT);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(1);
+
+ // When Jadelight Spelunker enters the battlefield, it explores X times.
+ this.addAbility(new EntersBattlefieldTriggeredAbility(
+ new ExploreSourceEffect(ManacostVariableValue.ETB, false, "{it}")
+ .setText("it explores X times. (To have it explore, reveal the top card of your library. "
+ + "Put that card into your hand if it’s a land. Otherwise, put a +1/+1 counter on that creature, "
+ + "then put the card back or put it into your graveyard.)")
+ ));
+ }
+
+ private JadelightSpelunker(final JadelightSpelunker card) {
+ super(card);
+ }
+
+ @Override
+ public JadelightSpelunker copy() {
+ return new JadelightSpelunker(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java
index 27af935a58e..3995d3373a6 100644
--- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java
+++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java
@@ -41,6 +41,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
cards.add(new SetCardInfo("Huatli, Poet of Unity", 189, Rarity.MYTHIC, mage.cards.h.HuatliPoetOfUnity.class));
cards.add(new SetCardInfo("Island", 395, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 188, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class));
+ cards.add(new SetCardInfo("Jadelight Spelunker", 196, Rarity.RARE, mage.cards.j.JadelightSpelunker.class));
cards.add(new SetCardInfo("Kellan, Daring Traveler", 231, Rarity.RARE, mage.cards.k.KellanDaringTraveler.class));
cards.add(new SetCardInfo("Miner's Guidewing", 24, Rarity.COMMON, mage.cards.m.MinersGuidewing.class));
cards.add(new SetCardInfo("Mountain", 399, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java
index 4077d6f15a1..29fcbb73595 100644
--- a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java
@@ -1,6 +1,8 @@
package mage.abilities.effects.keyword;
import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardsImpl;
@@ -19,6 +21,8 @@ import java.util.UUID;
*/
public class ExploreSourceEffect extends OneShotEffect {
+ private final DynamicValue amount;
+
private static final String REMINDER_TEXT = ". (Reveal the top card of your library. "
+ "Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on "
+ "this creature, then put the card back or put it into your graveyard.)";
@@ -28,13 +32,24 @@ public class ExploreSourceEffect extends OneShotEffect {
}
public ExploreSourceEffect(boolean showAbilityHint, String explorerText) {
+ this(1, showAbilityHint, explorerText);
+ }
+
+ public ExploreSourceEffect(int amount, boolean showAbilityHint, String explorerText) {
+ this(StaticValue.get(amount), showAbilityHint, explorerText);
+ }
+
+ public ExploreSourceEffect(DynamicValue amount, boolean showAbilityHint, String explorerText) {
super(Outcome.Benefit);
+
+ this.amount = amount;
// triggered ability text gen will replace {this} with "it" where applicable
- staticText = "{this} explores" + (showAbilityHint ? REMINDER_TEXT : "");
+ staticText = explorerText + " explores" + (showAbilityHint ? REMINDER_TEXT : "");
}
protected ExploreSourceEffect(final ExploreSourceEffect effect) {
super(effect);
+ this.amount = effect.amount;
}
@Override
@@ -44,33 +59,36 @@ public class ExploreSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- return explorePermanent(game, source.getSourceId(), source);
+ return explorePermanent(game, source.getSourceId(), source, this.amount.calculate(game, source, this));
}
- public static boolean explorePermanent(Game game, UUID permanentId, Ability source) {
+ public static boolean explorePermanent(Game game, UUID permanentId, Ability source, int amount) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId);
- if (controller == null || permanent == null) {
+ if (controller == null || permanent == null || amount <= 0) {
return false;
}
- game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EXPLORED, permanentId, source, permanent.getControllerId()));
- Card card = controller.getLibrary().getFromTop(game);
- if (card != null) {
- controller.revealCards("Explored card", new CardsImpl(card), game);
- if (card.isLand(game)) {
- controller.moveCards(card, Zone.HAND, source, game);
- } else {
- addCounter(game, permanent, source);
- if (controller.chooseUse(Outcome.Neutral, "Put " + card.getLogName() + " in your graveyard?", source, game)) {
- controller.moveCards(card, Zone.GRAVEYARD, source, game);
+
+ for (int i = 0; i < amount; ++i) {
+ game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EXPLORED, permanentId, source, permanent.getControllerId()));
+ Card card = controller.getLibrary().getFromTop(game);
+ if (card != null) {
+ controller.revealCards("Explored card", new CardsImpl(card), game);
+ if (card.isLand(game)) {
+ controller.moveCards(card, Zone.HAND, source, game);
} else {
- game.informPlayers(controller.getLogName() + " leaves " + card.getLogName() + " on top of their library.");
+ addCounter(game, permanent, source);
+ if (controller.chooseUse(Outcome.Neutral, "Put " + card.getLogName() + " in your graveyard?", source, game)) {
+ controller.moveCards(card, Zone.GRAVEYARD, source, game);
+ } else {
+ game.informPlayers(controller.getLogName() + " leaves " + card.getLogName() + " on top of their library.");
+ }
}
+ } else {
+ // If no card is revealed, most likely because that player's library is empty,
+ // the exploring creature receives a +1/+1 counter.
+ addCounter(game, permanent, source);
}
- } else {
- // If no card is revealed, most likely because that player's library is empty,
- // the exploring creature receives a +1/+1 counter.
- addCounter(game, permanent, source);
}
return true;
}
diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java
index 6138a6e2c8d..d8baf9087af 100644
--- a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java
@@ -38,7 +38,7 @@ public class ExploreTargetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- return ExploreSourceEffect.explorePermanent(game, getTargetPointer().getFirst(game, source), source);
+ return ExploreSourceEffect.explorePermanent(game, getTargetPointer().getFirst(game, source), source, 1);
}
@Override
@@ -47,7 +47,7 @@ public class ExploreTargetEffect extends OneShotEffect {
return staticText;
}
return getTargetPointer().describeTargets(mode.getTargets(), "it")
- + " explores" + (withReminderText ? REMINDER_TEXT : "") ;
+ + " explores" + (withReminderText ? REMINDER_TEXT : "");
}
}