Merge pull request #4277 from Northmoc/WHO-trap

WHO: the_toymakers_trap.txt + support
This commit is contained in:
Paul Hammerton
2023-12-04 14:33:10 +00:00
committed by GitHub
14 changed files with 92 additions and 5 deletions

View File

@@ -1877,6 +1877,8 @@ public class AiController {
} else { } else {
return options.get(0); return options.get(0);
} }
case ChooseNumber:
return Aggregates.random(options);
default: default:
return options.get(0); return options.get(0);
} }

View File

@@ -53,7 +53,7 @@ public final class AbilityFactory {
public static final List<String> additionalAbilityKeys = Lists.newArrayList( public static final List<String> additionalAbilityKeys = Lists.newArrayList(
"WinSubAbility", "OtherwiseSubAbility", // Clash "WinSubAbility", "OtherwiseSubAbility", // Clash
"BidSubAbility", // BidLifeEffect "BidSubAbility", // BidLifeEffect
"ChooseNumberSubAbility", "Lowest", "Highest", "NotLowest", // ChooseNumber "ChooseNumberSubAbility", "Lowest", "Highest", "NotLowest", "GuessCorrect", "GuessWrong", // ChooseNumber
"HeadsSubAbility", "TailsSubAbility", "LoseSubAbility", // FlipCoin "HeadsSubAbility", "TailsSubAbility", "LoseSubAbility", // FlipCoin
"TrueSubAbility", "FalseSubAbility", // Branch "TrueSubAbility", "FalseSubAbility", // Branch
"ChosenPile", "UnchosenPile", // MultiplePiles & TwoPiles "ChosenPile", "UnchosenPile", // MultiplePiles & TwoPiles

View File

@@ -1,5 +1,6 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -15,6 +16,9 @@ import forge.game.spellability.SpellAbility;
import forge.util.Lang; import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.tuple.Pair;
public class ChooseNumberEffect extends SpellAbilityEffect { public class ChooseNumberEffect extends SpellAbilityEffect {
@@ -47,11 +51,17 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
final Map<Player, Integer> chooseMap = Maps.newHashMap(); final Map<Player, Integer> chooseMap = Maps.newHashMap();
// defined guesser must try to guess the chosen - currently only on "The Toymaker's Trap"
boolean guessedCorrect = false;
Pair<Player, Integer> guessPair = null;
// may need future work to ensure chooser and guesser get same choices even in absence of RemoveChoices param
List<Integer> choices = new ArrayList<>();
for (final Player p : getTargetPlayers(sa)) { for (final Player p : getTargetPlayers(sa)) {
if (!p.isInGame()) { if (!p.isInGame()) {
continue; continue;
} }
int chosen; Integer chosen;
if (random) { if (random) {
chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min; chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min;
//TODO more useful notify for RepeatEach -> ChooseNumber with random //TODO more useful notify for RepeatEach -> ChooseNumber with random
@@ -61,6 +71,16 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
if (anyNumber) { if (anyNumber) {
Integer value = p.getController().announceRequirements(sa, title); Integer value = p.getController().announceRequirements(sa, title);
chosen = value == null ? 0 : value; chosen = value == null ? 0 : value;
} else if (sa.hasParam("RemoveChoices")) {
// currently we always remove remembered numbers, so the value is not really used yet
for (int i = min; i <= max; i++) {
choices.add(i);
}
for (Object o : card.getRemembered()) {
if (o instanceof Integer) choices.remove((Integer) o);
}
if (choices.isEmpty()) continue;
chosen = p.getController().chooseNumber(sa, title, choices, null);
} else { } else {
chosen = p.getController().chooseNumber(sa, title, min, max); chosen = p.getController().chooseNumber(sa, title, min, max);
} }
@@ -72,15 +92,35 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
card.setChosenNumber(chosen); card.setChosenNumber(chosen);
} }
if (sa.hasParam("Notify")) { if (sa.hasParam("Notify")) {
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p); p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().
getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
}
if (sa.hasParam("Guesser") && chosen != null) { // if nothing was chosen, there is nothing to guess
final FCollectionView<Player> gChoices =
AbilityUtils.getDefinedPlayers(card, sa.getParam("Guesser"), sa);
final Player guesser = choices.isEmpty() ? null : p.getController().
chooseSingleEntityForEffect(gChoices, sa, Localizer.getInstance().getMessage("lblChoosePlayer"),
false, null);
if (guesser != null) {
guessPair = Pair.of(guesser, guesser.getController().chooseNumber(sa,
Localizer.getInstance().getMessage("lblChooseNumber"), choices, null));
// if more complicated effects require this in the future it may be worth a unique message
if (chooseMap.containsValue(guessPair.getValue())) guessedCorrect = true;
} }
} }
if (secretlyChoose) { }
if (secretlyChoose && !chooseMap.isEmpty()) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
List<Player> highestNum = Lists.newArrayList(); List<Player> highestNum = Lists.newArrayList();
List<Player> lowestNum = Lists.newArrayList(); List<Player> lowestNum = Lists.newArrayList();
int highest = 0; int highest = 0;
int lowest = Integer.MAX_VALUE; int lowest = Integer.MAX_VALUE;
if (guessPair != null) {
sb.append(Localizer.getInstance().getMessage("lblPlayerGuessedNum", guessPair.getKey().getName(),
String.valueOf(guessPair.getValue())));
sb.append("\r\n");
}
for (Entry<Player, Integer> ev : chooseMap.entrySet()) { for (Entry<Player, Integer> ev : chooseMap.entrySet()) {
int num = ev.getValue(); int num = ev.getValue();
Player player = ev.getKey(); Player player = ev.getKey();
@@ -153,7 +193,24 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
card.addRemembered(highestNum); card.addRemembered(highestNum);
} }
} }
if (sa.hasParam("GuessCorrect") && guessedCorrect) { // correct guess doesn't use any chosen num yet
SpellAbility sub = sa.getAdditionalAbility("GuessCorrect");
AbilityUtils.resolve(sub);
}
if (sa.hasParam("GuessWrong") && guessPair != null && !guessedCorrect) {
SpellAbility sub = sa.getAdditionalAbility("GuessWrong");
// wrong currently uses the guess, not the chosen
card.setChosenNumber(guessPair.getValue());
card.addRemembered(guessPair.getKey());
AbilityUtils.resolve(sub);
card.clearChosenNumber();
card.removeRemembered(guessPair.getKey());
} }
} }
if (sa.hasParam("RememberChosen")) card.addRemembered(chooseMap.values());
}
} }

View File

@@ -1830,6 +1830,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
view.updateChosenNumber(this); view.updateChosenNumber(this);
} }
public final void clearChosenNumber() {
chosenNumber = null;
view.clearChosenNumber();
}
public final Card getExiledWith() { public final Card getExiledWith() {
return exiledWith; return exiledWith;
} }

View File

@@ -387,6 +387,9 @@ public class CardView extends GameEntityView {
void updateChosenNumber(Card c) { void updateChosenNumber(Card c) {
set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString()); set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString());
} }
void clearChosenNumber() {
set(TrackableProperty.ChosenNumber, "");
}
public List<String> getStoredRolls() { public List<String> getStoredRolls() {
return get(TrackableProperty.StoredRolls); return get(TrackableProperty.StoredRolls);

View File

@@ -0,0 +1,12 @@
Name:The Toymaker's Trap
ManaCost:2 B
Types:Enchantment
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChooseNumber | TriggerDescription$ At the beginning of your upkeep, secretly choose a number between 1 and 5 that hasn't been chosen. If you do, an opponent guesses which number you chose, then you reveal the number you chose. If they guessed wrong, they lose life equal to the number they guessed and you draw a card. If they guessed right, sacrifice The Toymaker's Trap.
SVar:TrigChooseNumber:DB$ ChooseNumber | SecretlyChoose$ True | Min$ 1 | Max$ 5 | RemoveChoices$ Remembered | Guesser$ Opponent | GuessWrong$ DBLoseLife | GuessCorrect$ DBSac | RememberChosen$ True | SubAbility$ DBCleanup
SVar:DBLoseLife:DB$ LoseLife | Defined$ RememberedPlayer | LifeAmount$ Count$ChosenNumber | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw
SVar:DBSac:DB$ Sacrifice
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Sacrifice
Oracle:At the beginning of your upkeep, secretly choose a number between 1 and 5 that hasn't been chosen. If you do, an opponent guesses which number you chose, then you reveal the number you chose. If they guessed wrong, they lose life equal to the number they guessed and you draw a card. If they guessed right, sacrifice The Toymaker's Trap.

View File

@@ -1907,6 +1907,7 @@ lblChooseOne=Wähle eines
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Wähle eine Zahl lblChooseNumber=Wähle eine Zahl
lblPlayerChoseNum={0} wähle {1} lblPlayerChoseNum={0} wähle {1}
lblPlayerGuessedNum={0} hat {1} erraten
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Wähle einen Spieler lblChoosePlayer=Wähle einen Spieler
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1912,6 +1912,7 @@ lblChooseOne=Choose one
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Choose a number lblChooseNumber=Choose a number
lblPlayerChoseNum={0} chose {1} lblPlayerChoseNum={0} chose {1}
lblPlayerGuessedNum={0} guessed {1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Choose a player lblChoosePlayer=Choose a player
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1908,6 +1908,7 @@ lblChooseOne=Elige uno
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Elige un número lblChooseNumber=Elige un número
lblPlayerChoseNum={0} eligió {1} lblPlayerChoseNum={0} eligió {1}
lblPlayerGuessedNum={0} adivinó {1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Elige un jugador lblChoosePlayer=Elige un jugador
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1878,7 +1878,7 @@ lblLookingCardIn=Regarder les cartes dans
lblDoYouWantPlayCard=Voulez-vous jouer à {0} ? lblDoYouWantPlayCard=Voulez-vous jouer à {0} ?
lblDoYouWantPlayCardTransformed=Voulez-vous jouer à {0} transformée? lblDoYouWantPlayCardTransformed=Voulez-vous jouer à {0} transformée?
lblSelectCardFromPlayerZone=Sélectionnez une carte de {0} {1} lblSelectCardFromPlayerZone=Sélectionnez une carte de {0} {1}
lblSelectUpToNumCardFromPlayerZone=S\u00e9lectionnez jusqu''\u00e0 {0} cartes de {1} {2} lblSelectUpToNumCardFromPlayerZone=Sélectionnez jusqu''à {0} cartes de {1} {2}
lblSelectCardsFromPlayerZone=Sélectionner les cartes de {0} {1} lblSelectCardsFromPlayerZone=Sélectionner les cartes de {0} {1}
lblCancelSearchUpToSelectNumCards=Annuler la recherche ? Jusqu''à {0} carte(s) supplémentaire(s) peuvent être sélectionnées. lblCancelSearchUpToSelectNumCards=Annuler la recherche ? Jusqu''à {0} carte(s) supplémentaire(s) peuvent être sélectionnées.
#ChangeZoneAllEffect.java #ChangeZoneAllEffect.java
@@ -1911,6 +1911,7 @@ lblChooseOne=Choisissez-en un
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Choisissez un nombre lblChooseNumber=Choisissez un nombre
lblPlayerChoseNum={0} a choisi {1} lblPlayerChoseNum={0} a choisi {1}
lblPlayerGuessedNum={0} deviné {1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Choisir un joueur lblChoosePlayer=Choisir un joueur
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1908,6 +1908,7 @@ lblChooseOne=Scegli uno
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Scegli un numero lblChooseNumber=Scegli un numero
lblPlayerChoseNum={0} ha scelto {1} lblPlayerChoseNum={0} ha scelto {1}
lblPlayerGuessedNum={0} ha indovinato {1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Scegli un giocatore lblChoosePlayer=Scegli un giocatore
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1907,6 +1907,7 @@ lblChooseOne=以下から 1つを選ぶ
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=数字を 1つ選ぶ lblChooseNumber=数字を 1つ選ぶ
lblPlayerChoseNum={0}が {1}を選んだ lblPlayerChoseNum={0}が {1}を選んだ
lblPlayerGuessedNum={0}は {1}を推測しました
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=プレイヤーを選ぶ lblChoosePlayer=プレイヤーを選ぶ
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1969,6 +1969,7 @@ lblChooseOne=Escolha um
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=Escolha um número lblChooseNumber=Escolha um número
lblPlayerChoseNum={0} escolheu {1} lblPlayerChoseNum={0} escolheu {1}
lblPlayerGuessedNum={0} adivinhou {1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=Escolha um jogador lblChoosePlayer=Escolha um jogador
#ChooseSourceEffect.java #ChooseSourceEffect.java

View File

@@ -1912,6 +1912,7 @@ lblChooseOne=选择一个
#ChooseNumberEffect.java #ChooseNumberEffect.java
lblChooseNumber=选择一个数 lblChooseNumber=选择一个数
lblPlayerChoseNum={0}已选择{1} lblPlayerChoseNum={0}已选择{1}
lblPlayerGuessedNum={0}猜了{1}
#ChoosePlayerEffect.java #ChoosePlayerEffect.java
lblChoosePlayer=选择一个牌手 lblChoosePlayer=选择一个牌手
#ChooseSourceEffect.java #ChooseSourceEffect.java