From 33d83dc0c5d3b3776a5a5cea0c0e7ad0bd4989f5 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Thu, 19 Mar 2020 06:22:44 +0000 Subject: [PATCH] Vote: replace hidden keywords with timestamped properties --- .../src/main/java/forge/ai/ComputerUtil.java | 2 +- .../java/forge/ai/PlayerControllerAi.java | 4 +- .../main/java/forge/ai/ability/VoteAi.java | 6 + forge-game/src/main/java/forge/game/Game.java | 13 +++ .../main/java/forge/game/StaticEffect.java | 31 +++--- .../game/ability/effects/VoteEffect.java | 103 ++++++++++-------- .../src/main/java/forge/game/card/Card.java | 4 +- .../main/java/forge/game/player/Player.java | 86 +++++++++++++++ .../forge/game/player/PlayerController.java | 2 +- .../java/forge/game/player/PlayerView.java | 34 ++++++ .../game/staticability/StaticAbility.java | 12 +- .../StaticAbilityContinuous.java | 14 +++ .../forge/trackable/TrackableProperty.java | 3 + .../util/PlayerControllerForTests.java | 2 +- forge-gui/res/cardsfolder/b/ballot_broker.txt | 4 +- .../cardsfolder/b/bragos_representative.txt | 2 +- forge-gui/res/cardsfolder/e/expropriate.txt | 9 ++ .../res/cardsfolder/i/illusion_of_choice.txt | 4 +- forge-gui/res/languages/en-US.properties | 3 + .../forge/player/PlayerControllerHuman.java | 2 +- 20 files changed, 258 insertions(+), 82 deletions(-) create mode 100644 forge-gui/res/cardsfolder/e/expropriate.txt diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index c9eb6634f57..bec6e19c4d6 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -2323,7 +2323,7 @@ public class ComputerUtil { return chosen; } - public static Object vote(Player ai, List options, SpellAbility sa, Multimap votes) { + public static Object vote(Player ai, List options, SpellAbility sa, Multimap votes, Player forPlayer) { final Card source = sa.getHostCard(); final Player controller = source.getController(); final Game game = controller.getGame(); diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 04a9f303832..56d592d5b8e 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -513,8 +513,8 @@ public class PlayerControllerAi extends PlayerController { } @Override - public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes) { - return ComputerUtil.vote(player, options, sa, votes); + public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer) { + return ComputerUtil.vote(player, options, sa, votes, forPlayer); } @Override diff --git a/forge-ai/src/main/java/forge/ai/ability/VoteAi.java b/forge-ai/src/main/java/forge/ai/ability/VoteAi.java index 58aab03ecbb..33d23dd3b22 100644 --- a/forge-ai/src/main/java/forge/ai/ability/VoteAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/VoteAi.java @@ -46,6 +46,12 @@ public class VoteAi extends SpellAbilityAi { @Override public int chooseNumber(Player player, SpellAbility sa, int min, int max, Map params) { + if (params.containsKey("Voter")) { + Player p = (Player)params.get("Voter"); + if (p.isOpponentOf(player)) { + return min; + } + } if (sa.getActivatingPlayer().isOpponentOf(player)) { return min; } diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 849e2de4a0d..2a49bae9d59 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -914,4 +914,17 @@ public class Game { } return false; } + + public Player getControlVote() { + Player result = null; + long maxValue = 0; + for (Player p : getPlayers()) { + Long v = p.getHighestControlVote(); + if (v != null && v > maxValue) { + maxValue = v; + result = p; + } + } + return result; + } } diff --git a/forge-game/src/main/java/forge/game/StaticEffect.java b/forge-game/src/main/java/forge/game/StaticEffect.java index dc9d51094a0..d6ce1813d7e 100644 --- a/forge-game/src/main/java/forge/game/StaticEffect.java +++ b/forge-game/src/main/java/forge/game/StaticEffect.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -37,7 +37,7 @@ import com.google.common.collect.Maps; *

* StaticEffect class. *

- * + * * @author Forge * @version $Id$ */ @@ -72,7 +72,7 @@ public class StaticEffect { /** * setTimestamp TODO Write javadoc for this method. - * + * * @param t * a long */ @@ -82,7 +82,7 @@ public class StaticEffect { /** * getTimestamp. TODO Write javadoc for this method. - * + * * @return a long */ public final long getTimestamp() { @@ -93,7 +93,7 @@ public class StaticEffect { *

* Getter for the field source. *

- * + * * @return a {@link forge.game.card.Card} object. */ public final Card getSource() { @@ -104,7 +104,7 @@ public class StaticEffect { *

* Getter for the field affectedCards. *

- * + * * @return a {@link forge.CardList} object. */ public final CardCollectionView getAffectedCards() { @@ -115,7 +115,7 @@ public class StaticEffect { *

* Setter for the field affectedCards. *

- * + * * @param list * a {@link forge.CardList} object. */ @@ -125,7 +125,7 @@ public class StaticEffect { /** * Gets the affected players. - * + * * @return the affected players */ public final List getAffectedPlayers() { @@ -134,7 +134,7 @@ public class StaticEffect { /** * Sets the affected players. - * + * * @param list * the new affected players */ @@ -144,7 +144,7 @@ public class StaticEffect { /** * setParams. TODO Write javadoc for this method. - * + * * @param params * a HashMap */ @@ -154,7 +154,7 @@ public class StaticEffect { /** * Gets the params. - * + * * @return the params */ public final Map getParams() { @@ -171,13 +171,12 @@ public class StaticEffect { /** * Undo everything that was changed by this effect. - * + * * @return a {@link CardCollectionView} of all affected cards. */ final CardCollectionView remove() { final CardCollectionView affectedCards = getAffectedCards(); final List affectedPlayers = getAffectedPlayers(); - //final Map params = getParams(); String changeColorWordsTo = null; @@ -245,6 +244,10 @@ public class StaticEffect { p.removeMaxLandPlays(getTimestamp()); p.removeMaxLandPlaysInfinite(getTimestamp()); + + p.removeControlVote(getTimestamp()); + p.removeAdditionalVote(getTimestamp()); + p.removeAdditionalOptionalVote(getTimestamp()); } // modify the affected card diff --git a/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java b/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java index 769e758388c..cc572a9c5fd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/VoteEffect.java @@ -1,6 +1,7 @@ package forge.game.ability.effects; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -9,9 +10,9 @@ import forge.game.ability.AbilityKey; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import forge.game.Game; import forge.game.ability.AbilityFactory; @@ -19,10 +20,7 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardLists; -import forge.game.card.CardPredicates; import forge.game.player.Player; -import forge.game.player.PlayerCollection; -import forge.game.player.PlayerPredicates; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; @@ -67,33 +65,29 @@ public class VoteEffect extends SpellAbilityEffect { return; } - // starting with the activator - int pSize = tgtPlayers.size(); Player activator = sa.getActivatingPlayer(); - while (tgtPlayers.contains(activator) && !activator.equals(Iterables.getFirst(tgtPlayers, null))) { - tgtPlayers.add(pSize - 1, tgtPlayers.remove(0)); + + // starting with the activator + int aidx = tgtPlayers.indexOf(activator); + if (aidx != -1) { + Collections.rotate(tgtPlayers, -aidx); } + ListMultimap votes = ArrayListMultimap.create(); - Player voter = null; - - PlayerCollection voters = game.getPlayers().filter(PlayerPredicates.hasKeyword("You choose how each player votes this turn.")); - - if (voters.size() > 1) { - List illusions = CardLists.filter(voters.getCardsIn(ZoneType.Command), CardPredicates.nameEquals("Illusion of Choice Effect")); - voter = Collections.max(illusions, CardPredicates.compareByTimestamp()).getController(); - } else if (voters.size() == 1) { - voter = voters.get(0); - } + Player voter = game.getControlVote(); for (final Player p : tgtPlayers) { - int voteAmount = p.getKeywords().getAmount("You get an additional vote.") + 1; - int optionalVotes = p.getKeywords().getAmount("You may vote an additional time."); - voteAmount += p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyAdditionalVotesDoYouWant"), 0, optionalVotes); + int voteAmount = p.getAdditionalVotesAmount() + 1; + int optionalVotes = p.getAdditionalOptionalVotesAmount(); Player realVoter = voter == null ? p : voter; + Map params = Maps.newHashMap(); + params.put("Voter", realVoter); + voteAmount += p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyAdditionalVotesDoYouWant"), 0, optionalVotes, params); + for (int i = 0; i < voteAmount; i++) { - Object result = realVoter.getController().vote(sa, host + Localizer.getInstance().getMessage("lblVote") + ":", voteType, votes); + Object result = realVoter.getController().vote(sa, host + Localizer.getInstance().getMessage("lblVote") + ":", voteType, votes, p); votes.put(result, p); host.getGame().getAction().nofityOfValue(sa, p, result + "\r\n" + Localizer.getInstance().getMessage("lblCurrentVote") + ":" + votes, p); @@ -104,34 +98,49 @@ public class VoteEffect extends SpellAbilityEffect { runParams.put(AbilityKey.AllVotes, votes); game.getTriggerHandler().runTrigger(TriggerType.Vote, runParams, false); - List subAbs = Lists.newArrayList(); - final List mostVotes = getMostVotes(votes); - if (sa.hasParam("Tied") && mostVotes.size() > 1) { - subAbs.add(sa.getParam("Tied")); - } else if (sa.hasParam("VoteSubAbility")) { - for (final Object o : mostVotes) { - host.addRemembered(o); - } - subAbs.add(sa.getParam("VoteSubAbility")); - } else { - for (Object type : mostVotes) { - subAbs.add(sa.getParam("Vote" + type.toString())); - } - } - if (sa.hasParam("StoreVoteNum")) { - for (final Object type : voteType) { - host.setSVar("VoteNum" + type, "Number$" + votes.get(type).size()); - } - } else { - for (final String subAb : subAbs) { - final SpellAbility action = AbilityFactory.getAbility(host.getSVar(subAb), host); + if (sa.hasParam("EachVote")) { + for (Map.Entry> e : votes.asMap().entrySet()) { + final SpellAbility action = AbilityFactory.getAbility(host, sa.getParam("Vote" + e.getKey().toString())); + action.setActivatingPlayer(sa.getActivatingPlayer()); ((AbilitySub) action).setParent(sa); - AbilityUtils.resolve(action); + + for (Player p : e.getValue()) { + host.addRemembered(p); + AbilityUtils.resolve(action); + host.removeRemembered(p); + } + } + } else { + List subAbs = Lists.newArrayList(); + final List mostVotes = getMostVotes(votes); + if (sa.hasParam("Tied") && mostVotes.size() > 1) { + subAbs.add(sa.getParam("Tied")); + } else if (sa.hasParam("VoteSubAbility")) { + for (final Object o : mostVotes) { + host.addRemembered(o); + } + subAbs.add(sa.getParam("VoteSubAbility")); + } else { + for (Object type : mostVotes) { + subAbs.add(sa.getParam("Vote" + type.toString())); + } + } + if (sa.hasParam("StoreVoteNum")) { + for (final Object type : voteType) { + host.setSVar("VoteNum" + type, "Number$" + votes.get(type).size()); + } + } else { + for (final String subAb : subAbs) { + final SpellAbility action = AbilityFactory.getAbility(host, subAb); + action.setActivatingPlayer(sa.getActivatingPlayer()); + ((AbilitySub) action).setParent(sa); + AbilityUtils.resolve(action); + } + } + if (sa.hasParam("VoteSubAbility")) { + host.clearRemembered(); } - } - if (sa.hasParam("VoteSubAbility")) { - host.clearRemembered(); } } 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 1d278409976..f2ab81b38b9 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -3938,7 +3938,9 @@ public class Card extends GameEntity implements Comparable { keywordsGrantedByTextChanges.add(newKw); } } - addChangedCardKeywordsInternal(addKeywords, removeKeywords, false, false, timestamp, true); + if (!addKeywords.isEmpty() || !removeKeywords.isEmpty()) { + addChangedCardKeywordsInternal(addKeywords, removeKeywords, false, false, timestamp, true); + } } private void updateKeywordsOnRemoveChangedText(final KeywordsChange k) { diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 93e53b59b3d..f21c28a6d60 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -162,6 +162,10 @@ public class Player extends GameEntity implements Comparable { private Card blessingEffect = null; private Card keywordEffect = null; + private Map additionalVotes = Maps.newHashMap(); + private Map additionalOptionalVotes = Maps.newHashMap(); + private SortedSet controlVotes = Sets.newTreeSet(); + private final AchievementTracker achievementTracker = new AchievementTracker(); private final PlayerView view; @@ -3067,4 +3071,86 @@ public class Player extends GameEntity implements Comparable { this.updateZoneForView(com); return keywordEffect; } + + public void addAdditionalVote(long timestamp, int value) { + additionalVotes.put(timestamp, value); + getView().updateAdditionalVote(this); + getGame().fireEvent(new GameEventPlayerStatsChanged(this, false)); + } + + public void removeAdditionalVote(long timestamp) { + if (additionalVotes.remove(timestamp) != null) { + getView().updateAdditionalVote(this); + getGame().fireEvent(new GameEventPlayerStatsChanged(this, false)); + } + } + + public int getAdditionalVotesAmount() { + int value = 0; + for (Integer i : additionalVotes.values()) { + value += i; + } + return value; + } + + public void addAdditionalOptionalVote(long timestamp, int value) { + additionalOptionalVotes.put(timestamp, value); + getView().updateOptionalAdditionalVote(this); + getGame().fireEvent(new GameEventPlayerStatsChanged(this, false)); + } + public void removeAdditionalOptionalVote(long timestamp) { + if (additionalOptionalVotes.remove(timestamp) != null) { + getView().updateOptionalAdditionalVote(this); + getGame().fireEvent(new GameEventPlayerStatsChanged(this, false)); + } + } + + public int getAdditionalOptionalVotesAmount() { + int value = 0; + for (Integer i : additionalOptionalVotes.values()) { + value += i; + } + return value; + } + + public boolean addControlVote(long timestamp) { + if (controlVotes.add(timestamp)) { + updateControlVote(); + return true; + } + return false; + } + public boolean removeControlVote(long timestamp) { + if (controlVotes.remove(timestamp)) { + updateControlVote(); + return true; + } + return false; + } + + void updateControlVote() { + // need to update all players because it can't know + Player control = getGame().getControlVote(); + for (Player pl : getGame().getPlayers()) { + pl.getView().updateControlVote(pl.equals(control)); + getGame().fireEvent(new GameEventPlayerStatsChanged(pl, false)); + } + } + + public Set getControlVote() { + return controlVotes; + } + + public void setControlVote(Set value) { + controlVotes.clear(); + controlVotes.addAll(value); + updateControlVote(); + } + + public Long getHighestControlVote() { + if (controlVotes.isEmpty()) { + return null; + } + return controlVotes.last(); + } } 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 62d57539212..ec79ece50b7 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -166,7 +166,7 @@ public abstract class PlayerController { return chooseSomeType(kindOfType, sa, validTypes, invalidTypes, false); } - public abstract Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes); + public abstract Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer); public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question); public abstract CardCollectionView getCardsToMulligan(Player firstPlayer); diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 6aa49b215b0..2da3dac4bf6 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -271,6 +271,27 @@ public class PlayerView extends GameEntityView { set(TrackableProperty.NumDrawnThisTurn, p.getNumDrawnThisTurn()); } + public int getAdditionalVote() { + return get(TrackableProperty.AdditionalVote); + } + public void updateAdditionalVote(Player p) { + set(TrackableProperty.AdditionalVote, p.getAdditionalVotesAmount()); + } + + public int getOptionalAdditionalVote() { + return get(TrackableProperty.OptionalAdditionalVote); + } + public void updateOptionalAdditionalVote(Player p) { + set(TrackableProperty.OptionalAdditionalVote, p.getAdditionalOptionalVotesAmount()); + } + + public boolean getControlVote() { + return get(TrackableProperty.ControlVotes); + } + public void updateControlVote(boolean val) { + set(TrackableProperty.ControlVotes, val); + } + public ImmutableMultiset getKeywords() { return get(TrackableProperty.Keywords); } @@ -497,6 +518,19 @@ public class PlayerView extends GameEntityView { details.add(Localizer.getInstance().getMessage("lblCardDrawnThisTurnHas", String.valueOf(getNumDrawnThisTurn()))); details.add(Localizer.getInstance().getMessage("lblDamagepreventionHas", String.valueOf(getPreventNextDamage()))); + int v = getAdditionalVote(); + if (v > 0) { + details.add(Localizer.getInstance().getMessage("lblAdditionalVotes", String.valueOf(v))); + } + v = getOptionalAdditionalVote(); + if (v > 0) { + details.add(Localizer.getInstance().getMessage("lblOptionalAdditionalVotes", String.valueOf(v))); + } + + if (getControlVote()) { + details.add(Localizer.getInstance().getMessage("lblControlsVote")); + } + if (getIsExtraTurn()) { details.add(Localizer.getInstance().getMessage("lblIsExtraTurn")); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index f8442310ec0..421edc80b60 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -181,15 +181,9 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone layers.add(StaticAbilityLayer.MODIFYPT); } - if (hasParam("AddHiddenKeyword")) { - layers.add(StaticAbilityLayer.RULES); - } - - if (hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")) { - layers.add(StaticAbilityLayer.RULES); - } - - if (hasParam("AdjustLandPlays")) { + if (hasParam("AddHiddenKeyword") + || hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount") + || hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")) { layers.add(StaticAbilityLayer.RULES); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index f0b0813bfc3..f6d8a9b6984 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -513,6 +513,20 @@ public final class StaticAbilityContinuous { } } + if (params.containsKey("ControlVote")) { + p.addControlVote(se.getTimestamp()); + } + if (params.containsKey("AdditionalVote")) { + String mhs = params.get("AdditionalVote"); + int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb); + p.addAdditionalVote(se.getTimestamp(), add); + } + if (params.containsKey("AdditionalOptionalVote")) { + String mhs = params.get("AdditionalOptionalVote"); + int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb); + p.addAdditionalOptionalVote(se.getTimestamp(), add); + } + if (params.containsKey("RaiseMaxHandSize")) { String rmhs = params.get("RaiseMaxHandSize"); int rmax = AbilityUtils.calculateAmount(hostCard, rmhs, stAb); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 2660337d82f..039085ee9d0 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -134,6 +134,9 @@ public enum TrackableProperty { HasUnlimitedLandPlay(TrackableTypes.BooleanType), NumLandThisTurn(TrackableTypes.IntegerType), NumDrawnThisTurn(TrackableTypes.IntegerType), + AdditionalVote(TrackableTypes.IntegerType), + OptionalAdditionalVote(TrackableTypes.IntegerType), + ControlVotes(TrackableTypes.BooleanType), Keywords(TrackableTypes.KeywordCollectionViewType, FreezeMode.IgnoresFreeze), Commander(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze), CommanderCast(TrackableTypes.IntegerMapType), 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 c9ee0f75d17..921b860fc40 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 @@ -486,7 +486,7 @@ public class PlayerControllerForTests extends PlayerController { } @Override - public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes) { + public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer) { return chooseItem(options); } diff --git a/forge-gui/res/cardsfolder/b/ballot_broker.txt b/forge-gui/res/cardsfolder/b/ballot_broker.txt index 23086c0407f..ea6110e74ce 100644 --- a/forge-gui/res/cardsfolder/b/ballot_broker.txt +++ b/forge-gui/res/cardsfolder/b/ballot_broker.txt @@ -2,5 +2,5 @@ Name:Ballot Broker ManaCost:2 W Types:Creature Human Advisor PT:2/3 -S:Mode$ Continuous | Affected$ You | AddKeyword$ You may vote an additional time. | Description$ While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.) -Oracle:While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.) \ No newline at end of file +S:Mode$ Continuous | Affected$ You | AdditionalOptionalVote$ 1 | Description$ While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.) +Oracle:While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.) diff --git a/forge-gui/res/cardsfolder/b/bragos_representative.txt b/forge-gui/res/cardsfolder/b/bragos_representative.txt index 40fedfb2763..12ff6add8d1 100644 --- a/forge-gui/res/cardsfolder/b/bragos_representative.txt +++ b/forge-gui/res/cardsfolder/b/bragos_representative.txt @@ -2,6 +2,6 @@ Name:Brago's Representative ManaCost:2 W Types:Creature Human Advisor PT:1/4 -S:Mode$ Continuous | Affected$ You | AddKeyword$ You get an additional vote. | Description$ While voting, you get an additional vote. (The votes can be for different choices or for the same choice.) +S:Mode$ Continuous | Affected$ You | AdditionalVote$ 1 | Description$ While voting, you get an additional vote. (The votes can be for different choices or for the same choice.) SVar:Picture:http://www.wizards.com/global/images/magic/general/bragos_representative.jpg Oracle:While voting, you get an additional vote. (The votes can be for different choices or for the same choice.) diff --git a/forge-gui/res/cardsfolder/e/expropriate.txt b/forge-gui/res/cardsfolder/e/expropriate.txt new file mode 100644 index 00000000000..3ced790ee5e --- /dev/null +++ b/forge-gui/res/cardsfolder/e/expropriate.txt @@ -0,0 +1,9 @@ +Name:Expropriate +ManaCost:7 U U +Types:Sorcery +A:SP$ Vote | Cost$ 7 U U | Defined$ Player | VoteType$ Time,Money | VoteTime$ DBTime | VoteMoney$ DBMoney | EachVote$ True | SubAbility$ DBChange | SpellDescription$ Council’s dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it. Exile Expropriate. +SVar:DBTime:DB$ AddTurn | Defined$ You | NumTurns$ 1 +SVar:DBMoney:DB$ ChooseCard | Defined$ You | Choices$ Permanent.RememberedPlayerOwn | SubAbility$ DBControl +SVar:DBControl:DB$ GainControl | Defined$ ChosenCard | NewController$ You +SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ None +Oracle:Council’s dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it. Exile Expropriate. diff --git a/forge-gui/res/cardsfolder/i/illusion_of_choice.txt b/forge-gui/res/cardsfolder/i/illusion_of_choice.txt index 851503cf9a0..805ccb7b2eb 100644 --- a/forge-gui/res/cardsfolder/i/illusion_of_choice.txt +++ b/forge-gui/res/cardsfolder/i/illusion_of_choice.txt @@ -3,6 +3,6 @@ ManaCost:U Types:Instant A:SP$ Effect | Cost$ U | Name$ Illusion of Choice Effect | StaticAbilities$ STVoter | SubAbility$ DBDraw | SpellDescription$ You choose how each player votes this turn. Draw a card. SVar:DBDraw:DB$ Draw | NumCards$ 1 -SVar:STVoter:Mode$ Continuous | EffectZone$ Command | Affected$ You | AddKeyword$ You choose how each player votes this turn. | Description$ You choose how each player votes this turn. +SVar:STVoter:Mode$ Continuous | EffectZone$ Command | Affected$ You | ControlVote$ True | Description$ You choose how each player votes this turn. AI:RemoveDeck:All -Oracle:You choose how each player votes this turn. Draw a card. \ No newline at end of file +Oracle:You choose how each player votes this turn. Draw a card. diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 7b149832456..3041bb1895d 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -2010,6 +2010,9 @@ lblDamagepreventionHas=Damage prevention: {0} lblIsExtraTurn=Extra Turn: Yes lblExtraTurnCountHas=Extra Turn Count: {0} lblAntedHas=Ante''d: {0} +lblAdditionalVotes=You get {0} additional votes. +lblOptionalAdditionalVotes=You may vote {0} additional times. +lblControlsVote=You choose how each player votes. #VStack.java lblAlwaysYes=Always Yes lblAlwaysNo=Always No diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index a2a08af75ec..30a90edd8fe 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -1181,7 +1181,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont @Override public Object vote(final SpellAbility sa, final String prompt, final List options, - final ListMultimap votes) { + final ListMultimap votes, Player forPlayer) { return getGui().one(prompt, options); }