diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index b9e0a3afb10..eb258ee1a5f 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -588,6 +588,12 @@ public class PlayerControllerAi extends PlayerController { return Aggregates.random(rolls); } + @Override + public Integer chooseRollToIgnore(List rolls) { + //TODO create AI logic for this + return Aggregates.random(rolls); + } + @Override public boolean mulliganKeepHand(Player firstPlayer, int cardsToReturn) { return !ComputerUtil.wantMulligan(player, cardsToReturn); diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index 0db9ccaa4bc..96f598e30a1 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -73,6 +73,7 @@ public enum AbilityKey { Fizzle("Fizzle"), FoundSearchingLibrary("FoundSearchingLibrary"), Ignore("Ignore"), + IgnoreChosen("IgnoreChosen"), IsCombat("IsCombat"), // TODO confirm that this and IsCombatDamage can be merged IsCombatDamage("IsCombatDamage"), IsDamage("IsDamage"), diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index ed79ced4e5b..4c312e9e919 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2625,6 +2625,25 @@ public class AbilityUtils { return doXMath(game.getStack().getMaxDistinctSources(), expr, c, ctb); } + if (sq[0].equals("MaxSameStoredRolls")) { + int max = 0; + List rolls = c.getStoredRolls(); + if (rolls != null) { + int lastNum = 0; + for (Integer roll : rolls) { + if (roll.equals(lastNum)) { + continue; // no need to count instances of the same roll multiple times + } + int tally = Collections.frequency(rolls, roll); + if (tally > max) { + max = tally; + } + lastNum = roll; + } + } + return doXMath(max, expr, c, ctb); + } + //Count$Random.. if (sq[0].equals("Random")) { int min = calculateAmount(c, sq[1], ctb); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java index 2eca5cf041d..26802697ab7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java @@ -3,6 +3,7 @@ package forge.game.ability.effects; import java.util.List; import java.util.Map; +import com.google.common.collect.Maps; import forge.game.GameObject; import forge.game.PlanarDice; import forge.game.ability.AbilityKey; @@ -13,7 +14,6 @@ import forge.game.player.Player; import forge.game.replacement.ReplacementResult; import forge.game.spellability.SpellAbility; - public class ReplaceEffect extends SpellAbilityEffect { @Override @@ -44,6 +44,12 @@ public class ReplaceEffect extends SpellAbilityEffect { } } else if ("PlanarDice".equals(type)) { params.put(varName, PlanarDice.smartValueOf(varValue)); + } else if ("Map".equals(type)) { + Map m = Maps.newHashMap(); + for (Player key : AbilityUtils.getDefinedPlayers(card, sa.getParam("VarKey"), sa)) { + m.put(key, AbilityUtils.calculateAmount(card, varValue, sa)); + } + params.put(varName, m); } else { params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa)); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java index 428c1f1e620..a12c6629308 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java @@ -1,22 +1,22 @@ package forge.game.ability.effects; -import java.util.*; - -import forge.game.event.GameEventRollDie; -import org.apache.commons.lang3.StringUtils; - import com.google.common.collect.Lists; - +import com.google.common.collect.Maps; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.event.GameEventRollDie; import forge.game.player.Player; import forge.game.player.PlayerCollection; +import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; import forge.util.Localizer; import forge.util.MyRandom; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; public class RollDiceEffect extends SpellAbilityEffect { @@ -37,11 +37,6 @@ public class RollDiceEffect extends SpellAbilityEffect { return sb.toString(); } - private static int getRollAdvange(final Player player) { - String str = "If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll."; - return player.getKeywords().getAmount(str); - } - /* (non-Javadoc) * @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) */ @@ -68,11 +63,27 @@ public class RollDiceEffect extends SpellAbilityEffect { return rollDiceForPlayer(sa, player, amount, sides, 0, 0, null); } private static int rollDiceForPlayer(SpellAbility sa, Player player, int amount, int sides, int ignore, int modifier, List rollsResult) { + Map ignoreChosenMap = Maps.newHashMap(); + + final Map repParams = AbilityKey.mapFromAffected(player); + repParams.put(AbilityKey.Number, amount); + repParams.put(AbilityKey.Ignore, ignore); + repParams.put(AbilityKey.IgnoreChosen, ignoreChosenMap); + + switch (player.getGame().getReplacementHandler().run(ReplacementType.RollDice, repParams)) { + case NotReplaced: + break; + case Updated: { + amount = (int) repParams.get(AbilityKey.Number); + ignore = (int) repParams.get(AbilityKey.Ignore); + ignoreChosenMap = (Map) repParams.get(AbilityKey.IgnoreChosen); + break; + } + } + if (amount == 0) { return 0; } - int advantage = getRollAdvange(player); - amount += advantage; int total = 0; List naturalRolls = (rollsResult == null ? new ArrayList<>() : rollsResult); @@ -85,21 +96,38 @@ public class RollDiceEffect extends SpellAbilityEffect { total += roll; } - if (amount > 0) { - String message = Localizer.getInstance().getMessage("lblPlayerRolledResult", player, StringUtils.join(naturalRolls, ", ")); - player.getGame().getAction().notifyOfValue(sa, player, message, null); - } - naturalRolls.sort(null); + List ignored = new ArrayList<>(); // Ignore lowest rolls - advantage += ignore; - if (advantage > 0) { - for (int i = advantage - 1; i >= 0; --i) { + if (ignore > 0) { + for (int i = ignore - 1; i >= 0; --i) { total -= naturalRolls.get(i); + ignored.add(naturalRolls.get(i)); naturalRolls.remove(i); } } + // Player chooses to ignore rolls + for (Player chooser : ignoreChosenMap.keySet()) { + for (int ig = 0; ig < ignoreChosenMap.get(chooser); ig++) { + Integer ign = chooser.getController().chooseRollToIgnore(naturalRolls); + total -= ign; + ignored.add(ign); + naturalRolls.remove(ign); + } + } + + //Notify of results + if (amount > 0) { + StringBuilder sb = new StringBuilder(); + sb.append(Localizer.getInstance().getMessage("lblPlayerRolledResult", player, + StringUtils.join(naturalRolls, ", "))); + if (!ignored.isEmpty()) { + sb.append("\r\n").append(Localizer.getInstance().getMessage("lblIgnoredRolls", + StringUtils.join(ignored, ", "))); + } + player.getGame().getAction().notifyOfValue(sa, player, sb.toString(), null); + } List rolls = Lists.newArrayList(); int oddResults = 0; @@ -177,6 +205,9 @@ public class RollDiceEffect extends SpellAbilityEffect { List rolls = new ArrayList<>(); int total = rollDiceForPlayer(sa, player, amount, sides, ignore, modifier, rolls); + if (sa.hasParam("StoreResults")) { + host.addStoredRolls(rolls); + } if (sa.hasParam("ResultSVar")) { sa.setSVar(sa.getParam("ResultSVar"), Integer.toString(total)); } @@ -235,8 +266,12 @@ public class RollDiceEffect extends SpellAbilityEffect { List results = new ArrayList<>(playersToRoll.size()); for (Player player : playersToRoll) { - int result = rollDice(sa, player, amount, sides); - results.add(result); + if (sa.hasParam("RerollResults")) { + rerollDice(sa, host, player, sides); + } else { + int result = rollDice(sa, player, amount, sides); + results.add(result); + } } if (rememberHighest) { int highest = 0; @@ -252,4 +287,22 @@ public class RollDiceEffect extends SpellAbilityEffect { } } } + + private void rerollDice(SpellAbility sa, Card host, Player roller, int sides) { + List toReroll = Lists.newArrayList(); + + for (Integer storedResult : host.getStoredRolls()) { + if (roller.getController().confirmAction(sa, null, + Localizer.getInstance().getMessage("lblRerollResult", storedResult), null)) { + toReroll.add(storedResult); + } + } + + Map replaceMap = Maps.newHashMap(); + for (Integer old : toReroll) { + int newRoll = rollDice(sa, roller, 1, sides); + replaceMap.put(old, newRoll); + } + host.replaceStoredRoll(replaceMap); + } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 11b2c9d145f..00eb5dbedec 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -189,6 +189,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private final Set rememberedObjects = Sets.newLinkedHashSet(); private Map flipResult; + private List storedRolls; private final Map assignedDamageMap = Maps.newTreeMap(); @@ -1279,6 +1280,33 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } } + public final List getStoredRolls() { + return storedRolls; + } + public final List getStoredRollsForView() { + List forView = new ArrayList<>(); + for (Integer i : storedRolls) { + forView.add(String.valueOf(i)); + } + return forView; + } + public final void addStoredRolls(final List results) { + if (storedRolls == null) { + storedRolls = Lists.newArrayList(); + } + storedRolls.addAll(results); + storedRolls.sort(null); + view.updateStoredRolls(this); + } + public final void replaceStoredRoll(final Map replaceMap) { + for (Integer oldValue : replaceMap.keySet()) { + storedRolls.remove(oldValue); + storedRolls.add(replaceMap.get(oldValue)); + } + storedRolls.sort(null); + view.updateStoredRolls(this); + } + public final String getFlipResult(final Player flipper) { if (flipResult == null) { return null; diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index ee45f9f7504..9aa8fb65c57 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -388,6 +388,13 @@ public class CardView extends GameEntityView { set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString()); } + public List getStoredRolls() { + return get(TrackableProperty.StoredRolls); + } + void updateStoredRolls(Card c) { + set(TrackableProperty.StoredRolls, c.getStoredRollsForView()); + } + public List getChosenColors() { return get(TrackableProperty.ChosenColors); } diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index 6652b75d24d..cb04526f753 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -188,6 +188,7 @@ public abstract class PlayerController { } public abstract PlanarDice choosePDRollToIgnore(List rolls); + public abstract Integer chooseRollToIgnore(List rolls); public abstract Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer); diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceRollDice.java b/forge-game/src/main/java/forge/game/replacement/ReplaceRollDice.java new file mode 100644 index 00000000000..4897ca15fb8 --- /dev/null +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceRollDice.java @@ -0,0 +1,41 @@ +package forge.game.replacement; + +import forge.game.ability.AbilityKey; +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; + +import java.util.Map; + +public class ReplaceRollDice extends ReplacementEffect { + + /** + * Instantiates a new replace roll planar dice. + * + * @param params the params + * @param host the host + */ + public ReplaceRollDice(final Map params, final Card host, final boolean intrinsic) { + super(params, host, intrinsic); + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) + */ + @Override + public boolean canReplace(Map runParams) { + if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) { + return false; + } + return true; + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Number, runParams.get(AbilityKey.Number)); + sa.setReplacingObject(AbilityKey.Ignore, runParams.get(AbilityKey.Ignore)); + sa.setReplacingObject(AbilityKey.IgnoreChosen, runParams.get(AbilityKey.IgnoreChosen)); + } +} diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java index 21107cd0410..41106760423 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java @@ -39,6 +39,7 @@ public enum ReplacementType { ProduceMana(ReplaceProduceMana.class), Proliferate(ReplaceProliferate.class), RemoveCounter(ReplaceRemoveCounter.class), + RollDice(ReplaceRollDice.class), RollPlanarDice(ReplaceRollPlanarDice.class), Scry(ReplaceScry.class), SetInMotion(ReplaceSetInMotion.class), diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index ef7ff1a198d..8502a64c8e5 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -66,6 +66,7 @@ public enum TrackableProperty { ChosenColors(TrackableTypes.StringListType), ChosenCards(TrackableTypes.CardViewCollectionType), ChosenNumber(TrackableTypes.StringType), + StoredRolls(TrackableTypes.StringListType), ChosenPlayer(TrackableTypes.PlayerViewType), ProtectingPlayer(TrackableTypes.PlayerViewType), ChosenDirection(TrackableTypes.EnumType(Direction.class)), diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 0d73b0ba31a..7d59c7f79b8 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -495,6 +495,11 @@ public class PlayerControllerForTests extends PlayerController { return Aggregates.random(rolls); } + @Override + public Integer chooseRollToIgnore(List rolls) { + return Aggregates.random(rolls); + } + @Override public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer) { return chooseItem(options); diff --git a/forge-gui/res/cardsfolder/b/bamboozling_beeble.txt b/forge-gui/res/cardsfolder/b/bamboozling_beeble.txt new file mode 100644 index 00000000000..3901b6d6993 --- /dev/null +++ b/forge-gui/res/cardsfolder/b/bamboozling_beeble.txt @@ -0,0 +1,12 @@ +Name:Bamboozling Beeble +ManaCost:U +Types:Creature Beeble +PT:1/1 +K:Protection from Robots +A:AB$ Effect | Cost$ 1 T | ValidTgts$ Player | ReplacementEffects$ RigRoll | RememberObjects$ Targeted | ExileOnMoved$ Battlefield | SpellDescription$ The next time target player would roll one or more dice this turn, instead they roll that many dice plus one and you choose one of those rolls to ignore. +SVar:RigRoll:Event$ RollDice | ValidPlayer$ Player.IsRemembered | ReplaceWith$ PlusRoll | Description$ The next time target player would roll one or more dice this turn, instead they roll that many dice plus one and you choose one of those rolls to ignore. +SVar:PlusRoll:DB$ ReplaceEffect | VarName$ Number | VarValue$ ReplaceCount$Number/Plus.1 | SubAbility$ IgnoreRoll +SVar:IgnoreRoll:DB$ ReplaceEffect | VarName$ IgnoreChosen | VarType$ Map | VarKey$ You | VarValue$ 1 | SubAbility$ DBExileEffect +SVar:DBExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile +AI:RemoveDeck:All +Oracle:Protection from Robots\n{1}, {T}: The next time target player would roll one or more dice this turn, instead they roll that many dice plus one and you choose one of those rolls to ignore. diff --git a/forge-gui/res/cardsfolder/b/barbarian_class.txt b/forge-gui/res/cardsfolder/b/barbarian_class.txt index e31c394d41b..01a088c8a61 100644 --- a/forge-gui/res/cardsfolder/b/barbarian_class.txt +++ b/forge-gui/res/cardsfolder/b/barbarian_class.txt @@ -1,7 +1,9 @@ Name:Barbarian Class ManaCost:R Types:Enchantment Class -S:Mode$ Continuous | Affected$ You | AddKeyword$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. | Description$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +R:Event$ RollDice | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ PlusRoll | Description$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +SVar:PlusRoll:DB$ ReplaceEffect | VarName$ Number | VarValue$ ReplaceCount$Number/Plus.1 | SubAbility$ IgnoreLowest +SVar:IgnoreLowest:DB$ ReplaceEffect | VarName$ Ignore | VarValue$ ReplaceCount$Ignore/Plus.1 K:Class:2:1 R:AddTrigger$ TriggerRoll SVar:TriggerRoll:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ TrigPump | Secondary$ True | TriggerDescription$ Whenever you roll one or more dice, target creature you control gets +2/+0 and gains menace until end of turn. SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | NumAtt$ 2 | KW$ Menace diff --git a/forge-gui/res/cardsfolder/c/centaur_of_attention.txt b/forge-gui/res/cardsfolder/c/centaur_of_attention.txt new file mode 100644 index 00000000000..d3b024fecd1 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/centaur_of_attention.txt @@ -0,0 +1,11 @@ +Name:Centaur of Attention +ManaCost:3 G G +Types:Creature Centaur Performer +PT:3/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRollDice | TriggerDescription$ When CARDNAME enters the battlefield, roll five six-sided dice and store those results on it. +SVar:TrigRollDice:DB$ RollDice | Amount$ 5 | StoreResults$ True +T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigReroll | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of combat on your turn, you may reroll any number of CARDNAME's stored results. +SVar:TrigReroll:DB$ RollDice | RerollResults$ True +S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | AddToughness$ X | Description$ Centaur of Attention gets +X/+X, where X is the greatest number of stored results on it of the same value. +SVar:X:Count$MaxSameStoredRolls +Oracle:When Centaur of Attention enters the battlefield, roll five six-sided dice and store those results on it.\nAt the beginning of combat on your turn, you may reroll any number of Centaur of Attention's stored results.\nCentaur of Attention gets +X/+X, where X is the greatest number of stored results on it of the same value. diff --git a/forge-gui/res/cardsfolder/p/pixie_guide.txt b/forge-gui/res/cardsfolder/p/pixie_guide.txt index ff3345eb4a4..3e47190f97e 100644 --- a/forge-gui/res/cardsfolder/p/pixie_guide.txt +++ b/forge-gui/res/cardsfolder/p/pixie_guide.txt @@ -3,5 +3,7 @@ ManaCost:1 U Types:Creature Faerie PT:1/3 K:Flying -S:Mode$ Continuous | Affected$ You | AddKeyword$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. | Description$ Grant an Advantage — If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +R:Event$ RollDice | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ PlusRoll | Description$ Grant an Advantage — If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +SVar:PlusRoll:DB$ ReplaceEffect | VarName$ Number | VarValue$ ReplaceCount$Number/Plus.1 | SubAbility$ IgnoreLowest +SVar:IgnoreLowest:DB$ ReplaceEffect | VarName$ Ignore | VarValue$ ReplaceCount$Ignore/Plus.1 Oracle:Flying\nGrant an Advantage — If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. diff --git a/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt b/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt index 09d82a0d8ec..61925ad4b8b 100644 --- a/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt +++ b/forge-gui/res/cardsfolder/w/wyll_blade_of_frontiers.txt @@ -2,7 +2,9 @@ Name:Wyll, Blade of Frontiers ManaCost:1 R Types:Legendary Creature Human Warlock PT:1/1 -S:Mode$ Continuous | Affected$ You | AddKeyword$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. | Description$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +R:Event$ RollDice | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ PlusRoll | Description$ If you would roll one or more dice, instead roll that many dice plus one and ignore the lowest roll. +SVar:PlusRoll:DB$ ReplaceEffect | VarName$ Number | VarValue$ ReplaceCount$Number/Plus.1 | SubAbility$ IgnoreLowest +SVar:IgnoreLowest:DB$ ReplaceEffect | VarName$ Ignore | VarValue$ ReplaceCount$Ignore/Plus.1 T:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ TrigPut | TriggerDescription$ Whenever you roll one or more dice, put a +1/+1 counter on CARDNAME. SVar:TrigPut:DB$ PutCounter | CounterType$ P1P1 K:Choose a Background diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index cd77379e798..10ffc3e333c 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -2054,6 +2054,8 @@ lblDoYouWantRepeatProcessAgain=Möchtest du den Vorgang wiederholen? lblDoYouWantRevealYourHand=Möchtest du deine Handkarten offen vorzeigen? #RollDiceEffect.java lblPlayerRolledResult={0} würfelt {1} +lblIgnoredRolls=Ignorierte Würfelwürfe: {0} +lblRerollResult={0} neu auswürfeln? #RollPlanarDiceEffect.java lblPlanarDiceResult=Ergebnis Weltenwürfel: {0} #SacrificeEffect.java diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index ffa8f4e1200..94b2d20ed6f 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -2059,6 +2059,8 @@ lblDoYouWantRepeatProcessAgain=Do you want to repeat this process again? lblDoYouWantRevealYourHand=Do you want to reveal your hand? #RollDiceEffect.java lblPlayerRolledResult={0} rolled {1} +lblIgnoredRolls=Ignored rolls: {0} +lblRerollResult=Reroll {0}? #RollPlanarDiceEffect.java lblPlanarDiceResult=Planar dice result: {0} #SacrificeEffect.java diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 53a52fd103f..c8ca80f9a10 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -2055,8 +2055,10 @@ lblDoYouWantRepeatProcessAgain=¿Quiere repetir este proceso de nuevo? lblDoYouWantRevealYourHand=¿Quieres descubrir tu mano? #RollDiceEffect.java lblPlayerRolledResult={0} lanzó {1} +lblIgnoredRolls=Dados ignorados: {0} +lblRerollResult=¿Volver a tirar {0}? #RollPlanarDiceEffect.java -lblPlanarDiceResult=Planar dice result: {0} +lblPlanarDiceResult=Resultado de los dados planares: {0} #SacrificeEffect.java lblDoYouWantPayEcho=¿Quieres pagar Eco lblPayEcho=Pagar Eco diff --git a/forge-gui/res/languages/fr-FR.properties b/forge-gui/res/languages/fr-FR.properties index cfed0b20c91..e187f531698 100644 --- a/forge-gui/res/languages/fr-FR.properties +++ b/forge-gui/res/languages/fr-FR.properties @@ -2059,6 +2059,8 @@ lblDoYouWantRepeatProcessAgain=Voulez-vous répéter ce processus à nouveau ? lblDoYouWantRevealYourHand=Voulez-vous révéler votre main ? #RollDiceEffect.java lblPlayerRolledResult={0} a lancé {1} +lblIgnoredRolls=Rouleaux ignorés: {0} +lblRerollResult=Relancez {0} ? #RollPlanarDiceEffect.java lblPlanarDiceResult=Planar dice result: {0} #SacrificeEffect.java diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index 34127d963ec..3aa5c4ee96b 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -2055,6 +2055,8 @@ lblDoYouWantRepeatProcessAgain=Vuoi ripetere nuovamente questo procedimento? lblDoYouWantRevealYourHand=Vuoi rivelare la tua mano? #RollDiceEffect.java lblPlayerRolledResult={0} ha ottenuto {1} col dado +lblIgnoredRolls=Tiri ignorati: {0} +lblRerollResult=Rilanciare {0}? #RollPlanarDiceEffect.java lblPlanarDiceResult=Planar dice result: {0} #SacrificeEffect.java diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index 8ed396820c4..2747a09d639 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -2054,8 +2054,10 @@ lblDoYouWantRepeatProcessAgain=この手順をもう一度しますか? lblDoYouWantRevealYourHand=手札を公開しますか? #RollDiceEffect.java lblPlayerRolledResult={0}が {1}をロールしました +lblIgnoredRolls=無視されたサイコロロール: {0} +lblRerollResult={0}リロール? #RollPlanarDiceEffect.java -lblPlanarDiceResult=Planar dice result: {0} +lblPlanarDiceResult=平面サイコロの結果:{0} #SacrificeEffect.java lblDoYouWantPayEcho=エコーコストを支払いますか: lblPayEcho=エコーコストを支払います diff --git a/forge-gui/res/languages/pt-BR.properties b/forge-gui/res/languages/pt-BR.properties index 3237ff24dbf..0e4fea5cf06 100644 --- a/forge-gui/res/languages/pt-BR.properties +++ b/forge-gui/res/languages/pt-BR.properties @@ -2116,6 +2116,8 @@ lblDoYouWantRepeatProcessAgain=Quer repetir este processo novamente? lblDoYouWantRevealYourHand=Você quer revelar sua mão? #RollDiceEffect.java lblPlayerRolledResult={0} tirou {1} +lblIgnoredRolls=Rolos ignorados: {0} +lblRerollResult=Rolar {0}? #RollPlanarDiceEffect.java lblPlanarDiceResult=Planar dice result: {0} #SacrificeEffect.java diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 00b05dfe7b7..e6b62d2134c 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -2059,6 +2059,8 @@ lblDoYouWantRepeatProcessAgain=你是否想再次重复这个过程? lblDoYouWantRevealYourHand=你想展示你的手牌吗? #RollDiceEffect.java lblPlayerRolledResult={0}掷骰结果为{1} +lblIgnoredRolls=忽略的卷: {0} +lblRerollResult=重滚{0}? #RollPlanarDiceEffect.java lblPlanarDiceResult=时空骰子点数: {0} #SacrificeEffect.java diff --git a/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java index d59afb7868c..9d83549487b 100644 --- a/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/gui/card/CardDetailUtil.java @@ -484,6 +484,15 @@ public class CardDetailUtil { area.append("(chosen number: ").append(card.getChosenNumber()).append(")"); } + // stored dice results + if (card.getStoredRolls() != null) { + if (area.length() != 0) { + area.append("\n"); + } + area.append("(stored dice results: ").append(StringUtils.join(card.getStoredRolls(), ", ")); + area.append(")"); + } + // chosen player if (card.getChosenPlayer() != null) { if (area.length() != 0) { diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index d83ca8a5e36..d8666cab24d 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -1413,6 +1413,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return getGui().one(Localizer.getInstance().getMessage("lblChooseRollIgnore"), rolls); } + @Override + public Integer chooseRollToIgnore(List rolls) { + return getGui().one(Localizer.getInstance().getMessage("lblChooseRollIgnore"), rolls); + } + @Override public Object vote(final SpellAbility sa, final String prompt, final List options, final ListMultimap votes, Player forPlayer) {