From 20eba0fbd7346c82e2045b0e7f6bce09922161a1 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 13 Jan 2019 21:41:19 +0100 Subject: [PATCH] GameAction: add PlayerController:confirmMulliganScry --- .../src/main/java/forge/ai/AiController.java | 3 +- .../java/forge/ai/PlayerControllerAi.java | 6 + .../src/main/java/forge/game/GameAction.java | 108 ++++++++++-------- .../game/ability/effects/ScryEffect.java | 19 ++- .../game/player/PlayerActionConfirmMode.java | 2 +- .../forge/game/player/PlayerController.java | 2 + .../util/PlayerControllerForTests.java | 6 + .../forge/player/PlayerControllerHuman.java | 5 + 8 files changed, 87 insertions(+), 64 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 5e6e5797859..c4fc6be078f 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -1209,8 +1209,7 @@ public class AiController { } public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) { - ApiType api = (sa == null ) ? null : sa.getApi(); - if ( api == null && mode == PlayerActionConfirmMode.Scry ) return true; // special hack for mulligan + ApiType api = sa.getApi(); // Abilities without api may also use this routine, However they should provide a unique mode value ?? How could this work? if (api == null) { diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index bc002769539..c7b845e9051 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -1164,4 +1164,10 @@ public class PlayerControllerAi extends PlayerController { return chosenOptCosts; } + + @Override + public boolean confirmMulliganScry(Player p) { + // Always true? + return true; + } } diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 9fcc3baf709..d58cefa2d2c 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -1714,15 +1714,18 @@ public class GameAction { } while (!allKept); //Vancouver Mulligan as a scry with the decisions inside - ArrayList scryers = new ArrayList(); + List scryers = Lists.newArrayList(); for(Player p : whoCanMulligan) { if (p.getStartingHandSize() > p.getZone(ZoneType.Hand).size()) { scryers.add(p); } } - if ( scryers.size() > 0 ) { - scry(scryers,1,true,null); - } + + for(Player p : scryers) { + if (p.getController().confirmMulliganScry(p)) { + scry(ImmutableList.of(p), 1, null); + } + } } private void runPreOpeningHandActions(final Player first) { @@ -1830,51 +1833,56 @@ public class GameAction { // 701.17c If multiple players scry at once, each of those players looks at the top cards of their library // at the same time. Those players decide in APNAP order (see rule 101.4) where to put those // cards, then those cards move at the same time. - public void scry(Listplayers,int numScry, boolean isOptional, SpellAbility cause) { - if ( numScry == 0 ) { return; } - // reveal the top N library cards to the player (only) - if ( players.size() > 1 ) { // no real need to separate out the look if there is only one player scrying - for ( final Player p : players ) { - final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry)); - p.getGame().getAction().revealTo(topN,p); - } - } - // make the decisions - ArrayList> decisions = - new ArrayList>(); - for ( final Player p : players ) { - if (isOptional && !p.getController().confirmAction(cause, PlayerActionConfirmMode.Scry, "Do you want to scry?")) { - decisions.add(new ImmutablePair(new CardCollection(),new CardCollection())); - } else { - final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry)); - ImmutablePair decision = p.getController().arrangeForScry(topN); - decisions.add(decision); - int numToTop = decision.getLeft()==null ? 0 : decision.getLeft().size(); - int numToBottom = decision.getRight()==null ? 0 : decision.getRight().size(); - p.getGame().fireEvent(new GameEventScry(p, numToTop, numToBottom)); // publicize the decision - } - } - // do the moves after all the decisions (maybe not necesssary, but let's do it the official way) - for ( int i = 0; i runParams = Maps.newHashMap(); - runParams.put("Player", p); - p.getGame().getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false); - } - } + public void scry(List players, int numScry, SpellAbility cause) { + if (numScry == 0) { + return; + } + // reveal the top N library cards to the player (only) + // no real need to separate out the look if + // there is only one player scrying + if (players.size() > 1) { + for (final Player p : players) { + final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry)); + revealTo(topN, p); + } + } + // make the decisions + List> decisions = Lists.newArrayList(); + for (final Player p : players) { + final CardCollection topN = new CardCollection(p.getCardsIn(ZoneType.Library, numScry)); + ImmutablePair decision = p.getController().arrangeForScry(topN); + decisions.add(decision); + int numToTop = decision.getLeft() == null ? 0 : decision.getLeft().size(); + int numToBottom = decision.getRight() == null ? 0 : decision.getRight().size(); + // publicize the decision + game.fireEvent(new GameEventScry(p, numToTop, numToBottom)); + } + // do the moves after all the decisions (maybe not necesssary, but let's + // do it the official way) + for (int i = 0; i < players.size(); i++) { + // no good iterate simultaneously in Java + final Player p = players.get(i); + final CardCollection toTop = decisions.get(i).getLeft(); + final CardCollection toBottom = decisions.get(i).getRight(); + if (toTop != null) { + Collections.reverse(toTop); // reverse to get the correct order + for (Card c : toTop) { + moveToLibrary(c, cause, null); + } + } + if (toBottom != null) { + for (Card c : toBottom) { + moveToBottomOfLibrary(c, cause, null); + } + } + + if (cause != null) { + // set up triggers (but not actually do them until later) + final Map runParams = Maps.newHashMap(); + runParams.put("Player", p); + game.getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false); + } + } + } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java index 2f7785d77ec..290a490e7ad 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ScryEffect.java @@ -4,18 +4,17 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import java.util.List; -import java.util.ArrayList; + +import com.google.common.collect.Lists; + public class ScryEffect extends SpellAbilityEffect { @Override protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - final List tgtPlayers = getTargetPlayers(sa); - - for (final Player p : tgtPlayers) { + for (final Player p : getTargetPlayers(sa)) { sb.append(p.toString()).append(" "); } @@ -37,18 +36,16 @@ public class ScryEffect extends SpellAbilityEffect { boolean isOptional = sa.hasParam("Optional"); - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final List tgtPlayers = getTargetPlayers(sa); - final ArrayList players = new ArrayList(); // players really affected + final List players = Lists.newArrayList(); // players really affected // Optional here for spells that have optional multi-player scrying - for (final Player p : tgtPlayers) { - if ( ((tgt == null) || p.canBeTargetedBy(sa)) && + for (final Player p : getTargetPlayers(sa)) { + if ( (!sa.usesTargeting() || p.canBeTargetedBy(sa)) && (!isOptional || p.getController().confirmAction(sa, null, "Do you want to scry?")) ) { players.add(p); } } - sa.getActivatingPlayer().getGame().getAction().scry(players,num,false,sa); + sa.getActivatingPlayer().getGame().getAction().scry(players, num, sa); } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java b/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java index 4886ff984fa..2b265c32be8 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java +++ b/forge-game/src/main/java/forge/game/player/PlayerActionConfirmMode.java @@ -15,6 +15,6 @@ public enum PlayerActionConfirmMode { OptionalChoose, Tribute, // Ripple; - Scry; + ; } 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 3e09e7c3f1c..33295250a62 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -260,4 +260,6 @@ public abstract class PlayerController { } public abstract List chooseOptionalCosts(SpellAbility choosen, List optionalCostValues); + + public abstract boolean confirmMulliganScry(final Player p); } 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 4a2c07f63c6..8393f236a1c 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 @@ -678,4 +678,10 @@ public class PlayerControllerForTests extends PlayerController { return null; } + @Override + public boolean confirmMulliganScry(Player p) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 06ae6d2e691..28ace52e11a 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2889,4 +2889,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont optionalCost, choosen.getHostCard().getView()); } + @Override + public boolean confirmMulliganScry(Player p) { + return InputConfirm.confirm(this, (SpellAbility)null, "Do you want to scry?"); + } + }