diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index e41a8bbd5d5..2b6602d1be8 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -1810,7 +1810,19 @@ public class ComputerUtil { return chosen; } - + + public static String vote(Player ai, List options, String logic) { + if (logic == null) { + return Aggregates.random(options); + } else { + switch (logic) { + case "GraceOrCondemnation": + return ai.getCreaturesInPlay().size() > ai.getOpponent().getCreaturesInPlay().size() ? "Grace" : "Condemnation"; + default: return Iterables.getFirst(options, null); + } + } + } + public static List getSafeTargets(final Player ai, SpellAbility sa, List validCards) { List safeCards = new ArrayList(validCards); safeCards = CardLists.filter(safeCards, new Predicate() { @@ -1935,4 +1947,5 @@ public class ComputerUtil { return bestBoardPosition; } + } diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index c505742590c..bfd0cb479d3 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -367,6 +367,12 @@ public class PlayerControllerAi extends PlayerController { return chosen; } + @Override + public String vote(SpellAbility sa, String prompt, List options) { + String result = ComputerUtil.vote(player, options, sa.getParam("AILogic")); + return result; + } + /* (non-Javadoc) * @see forge.game.player.PlayerController#confirmReplacementEffect(forge.card.replacement.ReplacementEffect, forge.card.spellability.SpellAbility, java.lang.String) */ 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 07fae3ba9c5..89838f69082 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,16 +1,20 @@ package forge.game.ability.effects; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; -import forge.game.player.PlayerController; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; + +import java.util.Arrays; import java.util.List; + import org.apache.commons.lang3.StringUtils; public class VoteEffect extends SpellAbilityEffect { @@ -29,7 +33,7 @@ public class VoteEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final List tgtPlayers = getTargetPlayers(sa); - final String voteType = sa.getParam("VoteType"); + final List voteType = Arrays.asList(sa.getParam("VoteType").split(",")); final Card host = sa.getHostCard(); // starting with the activator int pSize = tgtPlayers.size(); @@ -37,29 +41,49 @@ public class VoteEffect extends SpellAbilityEffect { while (tgtPlayers.contains(activator) && !activator.equals(Iterables.getFirst(tgtPlayers, null))) { tgtPlayers.add(pSize - 1, tgtPlayers.remove(0)); } - int choice1 = 0; - int choice2 = 0; + ArrayListMultimap votes = ArrayListMultimap.create(); for (final Player p : tgtPlayers) { - final boolean result = p.getController().chooseBinary(sa, sa.getHostCard() + "Vote:", PlayerController.BinaryChoiceType.valueOf(voteType)); - if (result) { - choice1++; - } else { - choice2++; + int voteAmount = p.getAmountOfKeyword("You get an additional vote.") + 1; + for (int i = 0; i < voteAmount; i++) { + final String result = p.getController().vote(sa, sa.getHostCard() + "Vote:", voteType); + votes.put(result, p); + host.getGame().getAction().nofityOfValue(sa, p, result + "\r\nCurrent Votes:" + votes, p); } - host.getGame().getAction().nofityOfValue(sa, p, voteType.split("Or")[result ? 0 : 1], null); } - String subAb; - if (choice1 > choice2) { - subAb = sa.getParam("FirstChoice"); - } else if (choice1 < choice2) { - subAb = sa.getParam("SecondChoice"); + + + List subAbs = Lists.newArrayList(); + final List mostVotes = getMostVotes(votes); + if (sa.hasParam("Tied") && mostVotes.size() > 1) { + subAbs.add(sa.getParam("Tied")); } else { - subAb = sa.getParam("Tied"); + for (String type : mostVotes) { + subAbs.add(sa.getParam("Vote" + type)); + } } - final SpellAbility action = AbilityFactory.getAbility(host.getSVar(subAb), host); - action.setActivatingPlayer(sa.getActivatingPlayer()); - ((AbilitySub) action).setParent(sa); - AbilityUtils.resolve(action); + + for (final String subAb : subAbs) { + final SpellAbility action = AbilityFactory.getAbility(host.getSVar(subAb), host); + action.setActivatingPlayer(sa.getActivatingPlayer()); + ((AbilitySub) action).setParent(sa); + AbilityUtils.resolve(action); + } + } + + private List getMostVotes(ArrayListMultimap votes) { + List most = Lists.newArrayList(); + int amount = 0; + for (String voteType : votes.keySet()) { + int voteAmount = votes.get(voteType).size(); + if (voteAmount == amount) { + most.add(voteType); + } else if (voteAmount > amount) { + amount = voteAmount; + most.clear(); + most.add(voteType); + } + } + return most; } } 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 965a056c2d2..3920c765447 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -2790,6 +2790,16 @@ public class Player extends GameEntity implements Comparable { return 1 << tokenDoublers; // pow(a,0) = 1; pow(a,1) = a } + public final int getAmountOfKeyword(final String k) { + int count = 0; + for (String kw : this.getKeywords()) { + if (kw.equals(k)) { + count++; + } + } + return count; + } + public void onCleanupPhase() { for (Card c : getCardsIn(ZoneType.Hand)) { c.setDrawnThisTurn(false); 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 4365b2bba89..730cf77d637 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -64,8 +64,6 @@ public abstract class PlayerController { OddsOrEvens, UntapOrLeaveTapped, UntapTimeVault, - GraceOrCondemnation, - DeathOrTorture, } protected final Game game; @@ -178,6 +176,7 @@ public abstract class PlayerController { return chooseSomeType(kindOfType, sa, validTypes, invalidTypes, false); } public abstract String chooseSomeType(String kindOfType, SpellAbility sa, List validTypes, List invalidTypes, boolean isOptional); + public abstract String vote(SpellAbility sa, String prompt, List options); public abstract Pair chooseAndRemoveOrPutCounter(Card cardWithCounter); public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question); public abstract List getCardsToMulligan(boolean isCommander, Player firstPlayer); 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 811d38d4993..cffd596dad3 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 @@ -446,6 +446,11 @@ public class PlayerControllerForTests extends PlayerController { return chooseItem(validTypes); } + @Override + public String vote(SpellAbility sa, String prompt, List options) { + return chooseItem(options); + } + @Override public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate cpp, String name) { throw new IllegalStateException("Erring on the side of caution here..."); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 2a55c657207..2562a75f05e 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -571,6 +571,11 @@ public class PlayerControllerHuman extends PlayerController { return SGuiChoose.one("Choose a " + kindOfType.toLowerCase() + " type", validTypes); } + @Override + public String vote(SpellAbility sa, String prompt, List options) { + return SGuiChoose.one(prompt, options); + } + /* (non-Javadoc) * @see forge.game.player.PlayerController#confirmReplacementEffect(forge.card.replacement.ReplacementEffect, forge.card.spellability.SpellAbility, java.lang.String) */ @@ -793,6 +798,9 @@ public class PlayerControllerHuman extends PlayerController { case Protection: String choser = StringUtils.capitalize(mayBeYou(target)); return String.format("%s %s protection from %s", choser, Lang.joinVerb(choser, "choose"), value); + case Vote: + String chooser = StringUtils.capitalize(mayBeYou(target)); + return String.format("%s %s %s", chooser, Lang.joinVerb(chooser, "vote"), value); default: return String.format("%s effect's value for %s is %s", sa.getHostCard().getName(), mayBeYou(target), value); }