jadelight_spelunker.txt and ExploreEffect improvements

This commit is contained in:
Northmoc
2023-11-04 14:30:27 -04:00
parent 4d91c98cad
commit e06d4bcb87
18 changed files with 115 additions and 85 deletions

View File

@@ -242,7 +242,7 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> params) {
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> params, Card cardToShow) {
return getAi().confirmAction(sa, mode, message, params);
}

View File

@@ -1,13 +1,9 @@
package forge.game.ability.effects;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import forge.game.Game;
import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
@@ -20,9 +16,13 @@ import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.Localizer;
import java.util.List;
import java.util.Map;
public class ExploreEffect extends SpellAbilityEffect {
/* (non-Javadoc)
@@ -47,7 +47,9 @@ public class ExploreEffect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
final Game game = sa.getHostCard().getGame();
final Card host = sa.getHostCard();
final Game game = host.getGame();
int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
GameEntityCounterTable table = new GameEntityCounterTable();
final CardZoneTable triggerList = new CardZoneTable();
@@ -55,8 +57,9 @@ public class ExploreEffect extends SpellAbilityEffect {
moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield());
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
for (final Card c : getTargetCards(sa)) {
if (game.getReplacementHandler().run(ReplacementType.Explore, AbilityKey.mapFromAffected(c)) != ReplacementResult.NotReplaced) {
for (int i = 0; i < amount; i++) {
if (game.getReplacementHandler().run(ReplacementType.Explore, AbilityKey.mapFromAffected(c))
!= ReplacementResult.NotReplaced) {
continue;
}
@@ -66,20 +69,18 @@ public class ExploreEffect extends SpellAbilityEffect {
CardCollection top = pl.getTopXCardsFromLibrary(1);
if (!top.isEmpty()) {
Card movedCard = null;
game.getAction().reveal(top, pl, false, Localizer.getInstance().getMessage("lblRevealedForExplore") + " - ");
game.getAction().reveal(top, pl, false,
Localizer.getInstance().getMessage("lblRevealedForExplore") + " - ");
final Card r = top.getFirst();
final Zone originZone = game.getZoneOf(r);
if (r.isLand()) {
movedCard = game.getAction().moveTo(ZoneType.Hand, r, sa, moveParams);
revealedLand = true;
} else {
// TODO find better way to choose optional send away
final Card choosen = pl.getController().chooseSingleCardForZoneChange(
ZoneType.Graveyard, Lists.newArrayList(ZoneType.Library), sa, top, null,
Localizer.getInstance().getMessage("lblPutThisCardToYourGraveyard"), true, pl);
if (choosen != null) {
movedCard = game.getAction().moveTo(ZoneType.Graveyard, choosen, sa, moveParams);
}
if (pl.getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblPutThisCardToYourGraveyard",
CardTranslation.getTranslatedName(r.getName())), null, r))
movedCard = game.getAction().moveTo(ZoneType.Graveyard, r, sa, moveParams);
}
if (originZone != null && movedCard != null) {
@@ -87,8 +88,7 @@ public class ExploreEffect extends SpellAbilityEffect {
}
}
if (!revealedLand) {
// need to get newest game state to check
// if it is still on the battlefield
// need to get newest game state to check if it is still on the battlefield
// and the timestamp didnt change
Card gamec = game.getCardState(c);
if (gamec.isInPlay() && gamec.equalsWithTimestamp(c)) {
@@ -101,6 +101,7 @@ public class ExploreEffect extends SpellAbilityEffect {
if (!top.isEmpty()) runParams.put(AbilityKey.Explored, top.getFirst());
game.getTriggerHandler().runTrigger(TriggerType.Explores, runParams, false);
}
}
table.replaceCounterEffect(game, sa, true);
triggerList.triggerChangesZoneAll(game, sa);
}

View File

@@ -131,7 +131,10 @@ public abstract class PlayerController {
public abstract <T extends GameEntity> List<T> chooseEntitiesForEffect(FCollectionView<T> optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer, Map<String, Object> params);
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> params);
public final boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> params) {
return confirmAction(sa, mode, message, params, null);
}
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> params, Card cardToShow);
public abstract boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife, String string, int bid, Player winner);
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, GameEntity affected, String question);
public abstract boolean confirmStaticApplication(Card hostCard, PlayerActionConfirmMode mode, String message, String logic);

View File

@@ -187,7 +187,7 @@ public class PlayerControllerForTests extends PlayerController {
}
@Override
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> newParam) {
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message, Map<String, Object> newParam, Card cardToShow) {
return true;
}

View File

@@ -3,7 +3,6 @@ ManaCost:1 G G
Types:Creature Merfolk Scout Ranger
PT:2/1
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExplore | TriggerDescription$ When CARDNAME enters the battlefield, 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.)
SVar:TrigExplore:DB$ Explore | SubAbility$ DBExplore
SVar:DBExplore:DB$ Explore
SVar:TrigExplore:DB$ Explore | Num$ 2
DeckHas:Ability$Counters
Oracle:When Jadelight Ranger enters the battlefield, 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.)

View File

@@ -0,0 +1,9 @@
Name:Jadelight Spelunker
ManaCost:X G
Types:Creature Merfolk Scout
PT:1/1
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExplore | TriggerDescription$ When CARDNAME enters the battlefield, 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.)
SVar:TrigExplore:DB$ Explore | Num$ X
SVar:X:Count$xPaid
DeckHas:Ability$Counters
Oracle:When Jadelight Spelunker enters the battlefield, 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.)

View File

@@ -4,8 +4,7 @@ Types:Creature Merfolk Scout
PT:2/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a Map token. (It's an artifact with "{1}, {T}, Sacrifice this artifact: Target creature you control explores. Activate only as a sorcery.")
SVar:TrigToken:DB$ Token | TokenScript$ c_a_map_sac_explore
R:Event$ Explore | ValidExplorer$ Creature.YouCtrl | ReplaceWith$ Explore1 | Description$ If a creature you control would explore, instead it explores, then it explores again.
SVar:Explore1:DB$ Explore | Defined$ ReplacedCard | SubAbility$ Explore2
SVar:Explore2:DB$ Explore | Defined$ ReplacedCard
R:Event$ Explore | ActiveZones$ Battlefield | ValidExplorer$ Creature.YouCtrl | ReplaceWith$ Explore1 | Description$ If a creature you control would explore, instead it explores, then it explores again.
SVar:Explore1:DB$ Explore | Defined$ ReplacedCard | Num$ 2
DeckHas:Ability$Token|Sacrifice & Type$Map|Artifact
Oracle:When Topography Tracker enters the battlefield, create a Map token. (It's an artifact with "{1}, {T}, Sacrifice this artifact: Target creature you control explores. Activate only as a sorcery.")\nIf a creature you control would explore, instead it explores, then it explores again.

View File

@@ -1,7 +1,7 @@
Name:Twists and Turns
ManaCost:G
Types:Enchantment
R:Event$ Explore | ValidExplorer$ Creature.YouCtrl | ReplaceWith$ DBScry | Description$ If a creature you control would explore, instead you scry 1, then that creature explores.
R:Event$ Explore | ActiveZones$ Battlefield | ValidExplorer$ Creature.YouCtrl | ReplaceWith$ DBScry | Description$ If a creature you control would explore, instead you scry 1, then that creature explores.
SVar:DBScry:DB$ Scry | SubAbility$ DBExplore
SVar:DBExplore:DB$ Explore | Defined$ ReplacedCard
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExplore | TriggerDescription$ When CARDNAME enters the battlefield, target creature you control explores.

View File

@@ -1995,7 +1995,7 @@ lblChooseACreatureYouControlToEncode=Wähle eine Kreatur unter deiner Kontrolle
lblDoYouWantEndTurn=Möchtest du den Zug beenden?
#ExploreEffect.java
lblRevealedForExplore=Zeige offen vor zum Erkunden
lblPutThisCardToYourGraveyard=Lege diese Karte auf deinen Friedhof?
lblPutThisCardToYourGraveyard=[Erkunden] Lege {0} auf deinen Friedhof?
#FightEffect.java
lblWouldYouLikeFight=Möchtest du, daß {0} gegen {1} kämpft?
#FlipCoinEffect.java

View File

@@ -2000,7 +2000,7 @@ lblChooseACreatureYouControlToEncode=Choose a creature you control to encode
lblDoYouWantEndTurn=Do you want to end the turn?
#ExploreEffect.java
lblRevealedForExplore=Revealed for Explore
lblPutThisCardToYourGraveyard=Put this card in your graveyard?
lblPutThisCardToYourGraveyard=[Explore] Put {0} in your graveyard?
#FightEffect.java
lblWouldYouLikeFight=Do you want {0} to fight {1}?
#FlipCoinEffect.java

View File

@@ -1996,7 +1996,7 @@ lblChooseACreatureYouControlToEncode=Elige una criatura que controlas para codif
lblDoYouWantEndTurn=¿Quieres terminar el turno?
#ExploreEffect.java
lblRevealedForExplore=Mostrado para explorar
lblPutThisCardToYourGraveyard=¿Poner esta carta en tu cementerio?
lblPutThisCardToYourGraveyard=[Explorar] ¿Poner {0} en tu cementerio?
#FightEffect.java
lblWouldYouLikeFight=¿Quieres que {0} luche contra {1}?
#FlipCoinEffect.java

View File

@@ -2000,7 +2000,7 @@ lblChooseACreatureYouControlToEncode=Choisissez une créature que vous contrôle
lblDoYouWantEndTurn=Voulez-vous terminer le tour ?
#ExploreEffect.java
lblRevealedForExplore=Révélé pour l''exploration
lblPutThisCardToYourGraveyard=Mettre cette carte dans votre cimetiere ?
lblPutThisCardToYourGraveyard=[Explorer] Mettre {0} dans votre cimetiere ?
#FightEffect.java
lblWouldYouLikeFight=Voulez-vous que {0} combatte {1} ?
#FlipCoinEffect.java

View File

@@ -1996,7 +1996,7 @@ lblChooseACreatureYouControlToEncode=Scegli una creatura che controlli per codif
lblDoYouWantEndTurn=Vuoi concludere il turno?
#ExploreEffect.java
lblRevealedForExplore=Rivelata dall''abilità Esplora
lblPutThisCardToYourGraveyard=Metti la carta nel cimitero?
lblPutThisCardToYourGraveyard=[Esplora] Metti {0} nel cimitero?
#FightEffect.java
lblWouldYouLikeFight=Vuoi che {0} lotti con {1}?
#FlipCoinEffect.java

View File

@@ -1995,7 +1995,7 @@ lblChooseACreatureYouControlToEncode=暗号化するクリーチャーをを選
lblDoYouWantEndTurn=ターンを終了しますか?
#ExploreEffect.java
lblRevealedForExplore=探検で公開した
lblPutThisCardToYourGraveyard=このカードを墓地に置きますか?
lblPutThisCardToYourGraveyard={0} を墓地に入れますか?[探る]
#FightEffect.java
lblWouldYouLikeFight={0}と {1}は格闘してもいいですか?
#FlipCoinEffect.java

View File

@@ -2057,7 +2057,7 @@ lblChooseACreatureYouControlToEncode=Escolha uma criatura que você controla par
lblDoYouWantEndTurn=Você quer terminar o turno?
#ExploreEffect.java
lblRevealedForExplore=Revelado por Explore
lblPutThisCardToYourGraveyard=Pôr esta carta no seu cemitério?
lblPutThisCardToYourGraveyard=[Explore] Pôr {0} no seu cemitério?
#FightEffect.java
lblWouldYouLikeFight=Deseja que {0} lute com {1}?
#FlipCoinEffect.java

View File

@@ -2000,7 +2000,7 @@ lblChooseACreatureYouControlToEncode=选择你控制的生物进场赋码
lblDoYouWantEndTurn=你想要结束回合吗?
#ExploreEffect.java
lblRevealedForExplore=勘察所展示
lblPutThisCardToYourGraveyard=这张牌放到你的坟墓场?
lblPutThisCardToYourGraveyard={0}放在你的墓地里?[探讨]
#FightEffect.java
lblWouldYouLikeFight=你想要让{0}与{1}进行互斗吗?
#FlipCoinEffect.java

View File

@@ -50,6 +50,7 @@ public class InputConfirm extends InputSyncronizedBase {
private boolean result;
private SpellAbility sa;
private CardView card;
private final boolean showDiffCard;
// simple interface to hide ugliness deciding how to confirm
protected static ImmutableList<String> defaultOptions = ImmutableList.of(Localizer.getInstance().getMessage("lblYes"), Localizer.getInstance().getMessage("lblNo"));
@@ -97,6 +98,23 @@ public class InputConfirm extends InputSyncronizedBase {
return inp.getResult();
}
}
public static boolean confirm(final PlayerControllerHuman controller, final CardView card, final SpellAbility sa, final String message) {
return InputConfirm.confirm(controller, card, sa, message, true, defaultOptions);
}
public static boolean confirm(final PlayerControllerHuman controller, final CardView card, final SpellAbility sa, final String message, final boolean defaultIsYes, final List<String> options) {
if (GuiBase.getInterface().isLibgdxPort()) {
return controller.getGui().confirm(card, message, defaultIsYes, options);
} else {
InputConfirm inp;
if (options.size() == 2) {
inp = new InputConfirm(controller, message, options.get(0), options.get(1), defaultIsYes, card, sa);
} else {
inp = new InputConfirm(controller, message, defaultOptions.get(0), defaultOptions.get(1), defaultIsYes, card, sa);
}
inp.showAndWait();
return inp.getResult();
}
}
public InputConfirm(final PlayerControllerHuman controller, String message0) {
this(controller, message0, Localizer.getInstance().getMessage("lblYes"), Localizer.getInstance().getMessage("lblNo"), true);
@@ -115,6 +133,7 @@ public class InputConfirm extends InputSyncronizedBase {
result = defaultYes0;
this.sa = null;
this.card = null;
showDiffCard = false;
}
public InputConfirm(final PlayerControllerHuman controller, String message0, SpellAbility sa0) {
@@ -134,6 +153,7 @@ public class InputConfirm extends InputSyncronizedBase {
result = defaultYes0;
this.sa = sa0;
this.card = sa != null ? sa.getView().getHostCard() : null;
showDiffCard = false;
}
public InputConfirm(final PlayerControllerHuman controller, String message0, CardView card0) {
@@ -153,6 +173,20 @@ public class InputConfirm extends InputSyncronizedBase {
result = defaultYes0;
this.sa = null;
this.card = card0;
showDiffCard = false;
}
public InputConfirm(final PlayerControllerHuman controller, String message0, String yesButtonText0,
String noButtonText0, boolean defaultYes0, CardView card0, SpellAbility sa0) {
super(controller);
message = message0;
yesButtonText = yesButtonText0;
noButtonText = noButtonText0;
defaultYes = defaultYes0;
result = defaultYes0;
this.sa = sa0;
this.card = card0;
showDiffCard = true;
}
/** {@inheritDoc} */
@@ -161,7 +195,7 @@ public class InputConfirm extends InputSyncronizedBase {
getController().getGui().updateButtons(getOwner(), yesButtonText, noButtonText, true, true, defaultYes);
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT) && card != null) {
final StringBuilder sb = new StringBuilder();
sb.append(card.toString());
sb.append(showDiffCard ? sa.getHostCard().toString() : card.toString());
if (sa != null && sa.toString().length() > 1) { // some spell abilities have no useful string value
sb.append(" - ").append(sa.toString());
}

View File

@@ -771,27 +771,12 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
* SpellAbility, java.lang.String, java.lang.String)
*/
@Override
public boolean confirmAction(final SpellAbility sa, final PlayerActionConfirmMode mode, final String message, Map<String, Object> params) {
if (sa != null && sa.getHostCard() != null && sa.hasParam("ShowCardInPrompt")) {
// The card wants another thing displayed in the prompt on mouse over rather than itself
Card show = null;
Object o = null;
switch (sa.getParam("ShowCardInPrompt")) {
case "RememberedFirst":
o = sa.getHostCard().getFirstRemembered();
if (o instanceof Card) {
show = (Card) o;
}
break;
case "RememberedLast":
o = Iterables.getLast(sa.getHostCard().getRemembered(), null);
if (o instanceof Card) {
show = (Card) o;
}
break;
}
tempShowCard(show);
boolean result = InputConfirm.confirm(this, ((Card) sa.getHostCard().getFirstRemembered()).getView(), message);
public boolean confirmAction(final SpellAbility sa, final PlayerActionConfirmMode mode, final String message,
Map<String, Object> params, Card cardToShow) {
// Another card should be displayed in the prompt on mouse over rather than the SA source
if (cardToShow != null) {
tempShowCard(cardToShow);
boolean result = InputConfirm.confirm(this, cardToShow.getView(), sa, message);
endTempShowCards();
return result;
}