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 {
return options.get(0);
}
case ChooseNumber:
return Aggregates.random(options);
default:
return options.get(0);
}

View File

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

View File

@@ -1,5 +1,6 @@
package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -15,6 +16,9 @@ import forge.game.spellability.SpellAbility;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.tuple.Pair;
public class ChooseNumberEffect extends SpellAbilityEffect {
@@ -47,11 +51,17 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
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)) {
if (!p.isInGame()) {
continue;
}
int chosen;
Integer chosen;
if (random) {
chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min;
//TODO more useful notify for RepeatEach -> ChooseNumber with random
@@ -61,6 +71,16 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
if (anyNumber) {
Integer value = p.getController().announceRequirements(sa, title);
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 {
chosen = p.getController().chooseNumber(sa, title, min, max);
}
@@ -72,15 +92,35 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
card.setChosenNumber(chosen);
}
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();
List<Player> highestNum = Lists.newArrayList();
List<Player> lowestNum = Lists.newArrayList();
int highest = 0;
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()) {
int num = ev.getValue();
Player player = ev.getKey();
@@ -153,7 +193,24 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
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);
}
public final void clearChosenNumber() {
chosenNumber = null;
view.clearChosenNumber();
}
public final Card getExiledWith() {
return exiledWith;
}

View File

@@ -387,6 +387,9 @@ public class CardView extends GameEntityView {
void updateChosenNumber(Card c) {
set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString());
}
void clearChosenNumber() {
set(TrackableProperty.ChosenNumber, "");
}
public List<String> getStoredRolls() {
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
lblChooseNumber=Wähle eine Zahl
lblPlayerChoseNum={0} wähle {1}
lblPlayerGuessedNum={0} hat {1} erraten
#ChoosePlayerEffect.java
lblChoosePlayer=Wähle einen Spieler
#ChooseSourceEffect.java

View File

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

View File

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

View File

@@ -1878,7 +1878,7 @@ lblLookingCardIn=Regarder les cartes dans
lblDoYouWantPlayCard=Voulez-vous jouer à {0} ?
lblDoYouWantPlayCardTransformed=Voulez-vous jouer à {0} transformée?
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}
lblCancelSearchUpToSelectNumCards=Annuler la recherche ? Jusqu''à {0} carte(s) supplémentaire(s) peuvent être sélectionnées.
#ChangeZoneAllEffect.java
@@ -1911,6 +1911,7 @@ lblChooseOne=Choisissez-en un
#ChooseNumberEffect.java
lblChooseNumber=Choisissez un nombre
lblPlayerChoseNum={0} a choisi {1}
lblPlayerGuessedNum={0} deviné {1}
#ChoosePlayerEffect.java
lblChoosePlayer=Choisir un joueur
#ChooseSourceEffect.java

View File

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

View File

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

View File

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

View File

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