From b03b3517eaed99689cb520955ba4f46ea7023d30 Mon Sep 17 00:00:00 2001 From: Chris H Date: Sun, 30 Jun 2024 12:30:05 -0400 Subject: [PATCH] Backup Plan with hot swappable Input --- .../java/forge/ai/PlayerControllerAi.java | 17 +++ .../src/main/java/forge/game/GameAction.java | 6 +- .../game/extrahands/BackupPlanService.java | 78 +++++++++++ .../main/java/forge/game/player/Player.java | 37 +++++- .../forge/game/player/PlayerController.java | 36 ++---- .../main/java/forge/game/zone/ZoneType.java | 9 +- .../home/sanctioned/CSubmenuDraft.java | 1 + .../util/PlayerControllerForTests.java | 13 +- forge-gui/res/cardsfolder/b/backup_plan.txt | 4 + forge-gui/res/editions/Conspiracy.txt | 2 +- .../match/input/InputChooseStartingHand.java | 75 +++++++++++ .../forge/player/PlayerControllerHuman.java | 121 +++++------------- 12 files changed, 279 insertions(+), 120 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/extrahands/BackupPlanService.java create mode 100644 forge-gui/res/cardsfolder/b/backup_plan.txt create mode 100644 forge-gui/src/main/java/forge/gamemodes/match/input/InputChooseStartingHand.java diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index d96e26b7b9a..31b282b6705 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -36,6 +36,7 @@ import forge.game.replacement.ReplacementEffect; import forge.game.spellability.*; import forge.game.staticability.StaticAbility; import forge.game.trigger.WrappedAbility; +import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; import forge.item.PaperCard; import forge.util.Aggregates; @@ -853,6 +854,22 @@ public class PlayerControllerAi extends PlayerController { return brains.chooseSaToActivateFromOpeningHand(usableFromOpeningHand); } + @Override + public PlayerZone chooseStartingHand(List zones) { + // Rate all the hands using the AI's hand evaluation function + int bestScore = Integer.MIN_VALUE; + PlayerZone bestZone = null; + for (PlayerZone zone : zones) { + int score = ComputerUtil.scoreHand(zone.getCards(), this.player, 0); + if (score > bestScore) { + bestScore = score; + bestZone = zone; + } + } + + return bestZone; + } + @Override public int chooseNumber(SpellAbility sa, String title, int min, int max) { return brains.chooseNumber(sa, title, min, max); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index c64406e6a29..dcb3839a4be 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -31,6 +31,7 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; import forge.game.event.*; +import forge.game.extrahands.BackupPlanService; import forge.game.keyword.Keyword; import forge.game.keyword.KeywordInterface; import forge.game.mulligan.MulliganService; @@ -2074,7 +2075,10 @@ public class GameAction { p1.drawCards(p1.getStartingHandSize()); } - // If pl has Backup Plan as a Conspiracy draw that many extra hands + BackupPlanService backupPlans = new BackupPlanService(p1); + if (backupPlans.initializeExtraHands()) { + backupPlans.chooseHand(); + } } // Choose starting hand for each player with multiple hands diff --git a/forge-game/src/main/java/forge/game/extrahands/BackupPlanService.java b/forge-game/src/main/java/forge/game/extrahands/BackupPlanService.java new file mode 100644 index 00000000000..a61fd39d90f --- /dev/null +++ b/forge-game/src/main/java/forge/game/extrahands/BackupPlanService.java @@ -0,0 +1,78 @@ +package forge.game.extrahands; + +import com.google.common.collect.Lists; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.zone.PlayerZone; +import forge.game.zone.ZoneType; + +import java.util.List; + +public class BackupPlanService { + private final Player player; + private boolean multipleHands = false; + List hands = Lists.newArrayList(); + private PlayerZone hand; + + public BackupPlanService(Player p1) { + this.player = p1; + } + + public boolean initializeExtraHands() { + hand = player.getZone(ZoneType.Hand); + hands.add(hand); + + // If pl has Backup Plan as a Conspiracy draw that many extra hands + if (player.getExtraZones() == null) { + return multipleHands; + } + for(PlayerZone extraHand : player.getExtraZones()) { + if (extraHand.getZoneType() == ZoneType.ExtraHand) { + player.drawCards(7, extraHand); + multipleHands = true; + hands.add(extraHand); + // If we figure out how to render the zone in the UI, do it here + } + } + + player.updateZoneForView(hand); + return multipleHands; + } + + public void chooseHand() { + if (!multipleHands) { + return; + } + + PlayerZone library = player.getZone(ZoneType.Library); + // Choose one of the starting hands and recycle the rest + PlayerZone startingHand = player.getController().chooseStartingHand(hands); + if (startingHand == hand) { + for(PlayerZone extraHand : player.getExtraZones()) { + if (extraHand.getZoneType() == ZoneType.ExtraHand) { + for (Card c : Lists.newArrayList(extraHand.getCards().iterator())) { + player.getGame().getAction().moveTo(library, c, null); + } + } + } + } else { + for (Card c : Lists.newArrayList(hand.getCards().iterator())) { + player.getGame().getAction().moveTo(library, c, null); + } + + for(PlayerZone extraHand : player.getExtraZones()) { + boolean starting = startingHand.equals(extraHand); + for (Card c : Lists.newArrayList(extraHand.getCards().iterator())) { + if (starting) { + player.getGame().getAction().moveTo(hand, c, null); + } else { + player.getGame().getAction().moveTo(library, c, null); + } + } + } + } + + player.resetExtraZones(ZoneType.ExtraHand); + player.updateZoneForView(player.getZone(ZoneType.Hand)); + } +} 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 192c85223b1..64df7561b58 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -156,6 +156,8 @@ public class Player extends GameEntity implements Comparable { private List completedDungeons = new ArrayList<>(); private final Map zones = Maps.newEnumMap(ZoneType.class); + private List extraZones = null; + private final Map adjustLandPlays = Maps.newHashMap(); private final Set adjustLandPlaysInfinite = Sets.newHashSet(); private Map maingameCardsMap = Maps.newHashMap(); @@ -1198,9 +1200,18 @@ public class Player extends GameEntity implements Comparable { } public final CardCollectionView drawCards(final int n) { - return drawCards(n, null, AbilityKey.newMap()); + return drawCards(n, null, AbilityKey.newMap(), this.getZone(ZoneType.Hand)); } + + public final CardCollectionView drawCards(final int n, PlayerZone zone) { + return drawCards(n, null, AbilityKey.newMap(), zone); + } + public final CardCollectionView drawCards(final int n, SpellAbility cause, Map params) { + return drawCards(n, cause, params, this.getZone(ZoneType.Hand)); + } + + public final CardCollectionView drawCards(final int n, SpellAbility cause, Map params, PlayerZone zone) { final CardCollection drawn = new CardCollection(); if (n <= 0) { return drawn; @@ -1225,7 +1236,7 @@ public class Player extends GameEntity implements Comparable { if (gameStarted && !canDraw()) { return drawn; } - drawn.addAll(doDraw(toReveal, cause, params)); + drawn.addAll(doDraw(toReveal, cause, params, zone)); } // reveal multiple drawn cards when playing with the top of the library revealed @@ -1240,7 +1251,7 @@ public class Player extends GameEntity implements Comparable { /** * @return a CardCollectionView of cards actually drawn */ - private CardCollectionView doDraw(Map revealed, SpellAbility sa, Map params) { + private CardCollectionView doDraw(Map revealed, SpellAbility sa, Map params, PlayerZone hand) { final CardCollection drawn = new CardCollection(); final PlayerZone library = getZone(ZoneType.Library); @@ -1275,7 +1286,7 @@ public class Player extends GameEntity implements Comparable { } } - c = game.getAction().moveToHand(c, cause, params); + c = game.getAction().moveTo(hand, c, cause, params); drawn.add(c); // CR 121.6c additional actions can't be performed when draw gets replaced @@ -1341,6 +1352,15 @@ public class Player extends GameEntity implements Comparable { } } + public final List getExtraZones() { + return extraZones; + } + + public void resetExtraZones(ZoneType type) { + extraZones.removeIf(z -> z.getZoneType().equals(type)); + } + + public final CardCollectionView getCardsIn(final ZoneType zoneType) { return getCardsIn(zoneType, true); } @@ -2964,6 +2984,15 @@ public class Player extends GameEntity implements Comparable { continue; } } + + if (Objects.equals(conspire.getName(), "Backup Plan")) { + PlayerZone hand = new PlayerZone(ZoneType.ExtraHand, this); + if (this.extraZones == null) { + this.extraZones = new ArrayList<>(); + } + this.extraZones.add(hand); + } + com.add(conspire); } 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 426fd7b314e..4be2feb911b 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -1,20 +1,9 @@ package forge.game.player; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import com.google.common.collect.Lists; -import forge.game.*; -import forge.game.mana.ManaCostBeingPaid; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - import com.google.common.base.Predicate; import com.google.common.collect.ListMultimap; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; - import forge.LobbyPlayer; import forge.card.ColorSet; import forge.card.ICardFace; @@ -22,12 +11,9 @@ import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; import forge.deck.Deck; import forge.deck.DeckSection; +import forge.game.*; import forge.game.GameOutcome.AnteResult; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CardView; -import forge.game.card.CounterType; +import forge.game.card.*; import forge.game.combat.Combat; import forge.game.cost.Cost; import forge.game.cost.CostPart; @@ -35,18 +21,23 @@ import forge.game.cost.CostPartMana; import forge.game.keyword.KeywordInterface; import forge.game.mana.Mana; import forge.game.mana.ManaConversionMatrix; +import forge.game.mana.ManaCostBeingPaid; import forge.game.replacement.ReplacementEffect; -import forge.game.spellability.AbilitySub; -import forge.game.spellability.OptionalCostValue; -import forge.game.spellability.SpellAbility; -import forge.game.spellability.SpellAbilityStackInstance; -import forge.game.spellability.TargetChoices; +import forge.game.spellability.*; import forge.game.staticability.StaticAbility; import forge.game.trigger.WrappedAbility; +import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; import forge.item.PaperCard; import forge.util.ITriggerEvent; import forge.util.collect.FCollectionView; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * A prototype for player controller class @@ -192,6 +183,7 @@ public abstract class PlayerController { public abstract CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave); public abstract CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid); public abstract List chooseSaToActivateFromOpeningHand(List usableFromOpeningHand); + public abstract PlayerZone chooseStartingHand(List zones); public abstract Mana chooseManaFromPool(List manaChoices); public abstract String chooseSomeType(String kindOfType, SpellAbility sa, Collection validTypes, List invalidTypes, boolean isOptional); diff --git a/forge-game/src/main/java/forge/game/zone/ZoneType.java b/forge-game/src/main/java/forge/game/zone/ZoneType.java index f8a434dd17c..678c0b403b0 100644 --- a/forge-game/src/main/java/forge/game/zone/ZoneType.java +++ b/forge-game/src/main/java/forge/game/zone/ZoneType.java @@ -1,13 +1,12 @@ package forge.game.zone; +import com.google.common.base.Function; +import forge.util.Localizer; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import com.google.common.base.Function; - -import forge.util.Localizer; - /** * The Enum Zone. */ @@ -26,6 +25,8 @@ public enum ZoneType { SchemeDeck(true, "lblSchemeDeckZone"), PlanarDeck(true, "lblPlanarDeckZone"), Subgame(true, "lblSubgameZone"), + // ExtraHand is used for Backup Plan for temporary extra hands + ExtraHand(true, "lblHandZone"), None(true, "lblNoneZone"); public static final List STATIC_ABILITIES_SOURCE_ZONES = Arrays.asList(Battlefield, Graveyard, Exile, Command, Stack/*, Hand*/); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java index f062aa726c7..d8c8292e0da 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java @@ -205,6 +205,7 @@ public enum CSubmenuDraft implements ICDoc { final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer()); starter.add(human); human.setId(0); + human.assignConspiracies(); for(Map.Entry aiDeck : aiMap.entrySet()) { RegisteredPlayer aiPlayer = new RegisteredPlayer(aiDeck.getValue()).setPlayer(GamePlayerUtil.createAiPlayer()); aiPlayer.setId(aiDeck.getKey()); 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 26db194dc9d..5a35f7cead2 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 @@ -3,6 +3,7 @@ package forge.gamesimulationtests.util; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import forge.LobbyPlayer; import forge.ai.ComputerUtil; @@ -37,6 +38,7 @@ import forge.game.replacement.ReplacementEffect; import forge.game.spellability.*; import forge.game.staticability.StaticAbility; import forge.game.trigger.WrappedAbility; +import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; import forge.gamesimulationtests.util.card.CardSpecification; import forge.gamesimulationtests.util.card.CardSpecificationHandler; @@ -51,9 +53,11 @@ import forge.util.MyRandom; import forge.util.collect.FCollectionView; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; -import com.google.common.collect.Lists; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Default harmless implementation for tests. @@ -310,6 +314,11 @@ public class PlayerControllerForTests extends PlayerController { return usableFromOpeningHand; } + @Override + public PlayerZone chooseStartingHand(List zones) { + return zones.get(0); + } + @Override public Mana chooseManaFromPool(List manaChoices) { return chooseItem(manaChoices); diff --git a/forge-gui/res/cardsfolder/b/backup_plan.txt b/forge-gui/res/cardsfolder/b/backup_plan.txt new file mode 100644 index 00000000000..7e05458433c --- /dev/null +++ b/forge-gui/res/cardsfolder/b/backup_plan.txt @@ -0,0 +1,4 @@ +Name:Backup Plan +Types:Conspiracy +Text:Draw an additional hand of seven cards as the game begins. Before taking mulligans, shuffle all but one of your hands into your library. +Oracle: (Start the game with this conspiracy face up in the command zone.)\nDraw an additional hand of seven cards as the game begins. Before taking mulligans, shuffle all but one of your hands into your library. diff --git a/forge-gui/res/editions/Conspiracy.txt b/forge-gui/res/editions/Conspiracy.txt index 871cd12021c..28e32cec3a6 100644 --- a/forge-gui/res/editions/Conspiracy.txt +++ b/forge-gui/res/editions/Conspiracy.txt @@ -224,7 +224,7 @@ ScryfallCode=CNS 1 Advantageous Proclamation|CNS 1 Aether Searcher|CNS 1 Agent of Acquisitions|CNS -#1 Backup Plan|CNS +1 Backup Plan|CNS 1 Brago's Favor|CNS 1 Canal Dredger|CNS 1 Cogwork Grinder|CNS diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputChooseStartingHand.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputChooseStartingHand.java new file mode 100644 index 00000000000..6897dc7e562 --- /dev/null +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputChooseStartingHand.java @@ -0,0 +1,75 @@ +package forge.gamemodes.match.input; + +import com.google.common.collect.Lists; +import forge.game.Game; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.zone.PlayerZone; +import forge.game.zone.ZoneType; +import forge.player.PlayerControllerHuman; + +import java.util.Deque; +import java.util.List; + +public class InputChooseStartingHand extends InputSyncronizedBase { + // An input for choosing multiple different starting hands for Backup Plan + // Ideally all would render at once, but for now we're just going to show the primary, and loop through each hand + // When you like one, click OK and the rest will be cleared + private final Deque hands; + PlayerZone primaryHand = null; + Game game; + + + public InputChooseStartingHand(final PlayerControllerHuman controller, final Player humanPlayer) { + super(controller); + + game = humanPlayer.getGame(); + primaryHand = humanPlayer.getZone(ZoneType.Hand); + hands = Lists.newLinkedList(); + for(PlayerZone extraHand : humanPlayer.getExtraZones()) { + if (extraHand.getZoneType() == ZoneType.ExtraHand) { + hands.add(extraHand); + } + } + } + + public PlayerZone getSelectedHand() { + // We're going to be manipulating what the primary hand is during this process so always return it + return primaryHand; + } + + @Override + protected void showMessage() { + if (hands.isEmpty()) { + stop(); + } + + getController().getGui().updateButtons(getOwner(), "View Next", "Accept Hand", true, true, true); + showMessage("Select the currently viewed hand to start the game with. The other " + hands.size() + " hand(s) will be shuffled into your library."); + } + + @Override + protected final void onCancel() { + stop(); + } + + @Override + protected final void onOk() { + // Rotate hands. Take everything in current hand, add it to the next hand + // Then take everything in the next hand and add it to the current hand + PlayerZone nextExtraHand = hands.poll(); + assert nextExtraHand != null; + List currentList = Lists.newArrayList(primaryHand.getCards().iterator()); + List extraList = Lists.newArrayList(nextExtraHand.getCards().iterator()); + + primaryHand.setCards(extraList); + nextExtraHand.setCards(currentList); + hands.add(nextExtraHand); + } + + + @Override + public String getActivateAction(Card card) { + return null; + } +} diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index db2648eab7b..53274393f2c 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -1,87 +1,24 @@ package forge.player; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.TreeSet; - - -import forge.game.player.actions.SelectCardAction; -import forge.game.player.actions.SelectPlayerAction; -import forge.game.trigger.TriggerType; - -import forge.game.mana.ManaCostBeingPaid; -import forge.gamemodes.match.input.*; -import forge.trackable.TrackableCollection; -import forge.util.ImageUtil; -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.Range; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -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 com.google.common.collect.Multimap; - +import com.google.common.collect.*; import forge.LobbyPlayer; import forge.StaticData; import forge.ai.GameState; import forge.ai.PlayerControllerAi; -import forge.card.CardDb; -import forge.card.CardSplitType; -import forge.card.CardStateName; -import forge.card.ColorSet; -import forge.card.ICardFace; -import forge.card.MagicColor; +import forge.card.*; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckRecognizer; import forge.deck.DeckSection; -import forge.game.Game; -import forge.game.GameEntity; -import forge.game.GameEntityView; -import forge.game.GameEntityViewMap; -import forge.game.GameLogEntryType; -import forge.game.GameObject; -import forge.game.GameType; -import forge.game.PlanarDice; +import forge.game.*; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CardFaceView; -import forge.game.card.CardLists; -import forge.game.card.CardPlayOption; -import forge.game.card.CardPredicates; -import forge.game.card.CardUtil; -import forge.game.card.CardView; -import forge.game.card.CounterEnumType; -import forge.game.card.CounterType; +import forge.game.card.*; import forge.game.card.token.TokenInfo; import forge.game.combat.Combat; import forge.game.combat.CombatUtil; @@ -93,28 +30,23 @@ import forge.game.keyword.Keyword; import forge.game.keyword.KeywordInterface; import forge.game.mana.Mana; import forge.game.mana.ManaConversionMatrix; -import forge.game.player.DelayedReveal; -import forge.game.player.Player; -import forge.game.player.PlayerActionConfirmMode; -import forge.game.player.PlayerController; -import forge.game.player.PlayerView; +import forge.game.mana.ManaCostBeingPaid; +import forge.game.player.*; +import forge.game.player.actions.SelectCardAction; +import forge.game.player.actions.SelectPlayerAction; import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementLayer; -import forge.game.spellability.AbilityManaPart; -import forge.game.spellability.AbilitySub; -import forge.game.spellability.OptionalCostValue; -import forge.game.spellability.SpellAbility; -import forge.game.spellability.SpellAbilityStackInstance; -import forge.game.spellability.SpellAbilityView; -import forge.game.spellability.TargetChoices; +import forge.game.spellability.*; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; +import forge.game.trigger.TriggerType; import forge.game.trigger.WrappedAbility; import forge.game.zone.MagicStack; import forge.game.zone.PlayerZone; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.gamemodes.match.NextGameDecision; +import forge.gamemodes.match.input.*; import forge.gui.FThreads; import forge.gui.GuiBase; import forge.gui.control.FControlGamePlayback; @@ -130,16 +62,21 @@ import forge.localinstance.achievements.AchievementCollection; import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgePreferences.FPref; import forge.model.FModel; -import forge.util.CardTranslation; -import forge.util.DeckAIUtils; -import forge.util.ITriggerEvent; -import forge.util.Lang; -import forge.util.Localizer; -import forge.util.MessageUtil; -import forge.util.TextUtil; +import forge.trackable.TrackableCollection; +import forge.util.*; import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; import io.sentry.Sentry; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.Range; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; /** * A prototype for player controller class @@ -1653,6 +1590,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return result; } + @Override + public PlayerZone chooseStartingHand(List zones) { + // Create new zone objects in the UI temporarily. + // Spawn a new input dialog, it works by selecting a card in the zone you want and clicking OK + // The card will then extract the PlayerZone via the card that is chosen and return it to this function + // Which will then return the PlayerZone to the caller + player.updateZoneForView(player.getZone(ZoneType.Hand)); + final InputChooseStartingHand inp = new InputChooseStartingHand(this, player); + inp.showAndWait(); + return inp.getSelectedHand(); + } + @Override public boolean chooseBinary(final SpellAbility sa, final String question, final BinaryChoiceType kindOfChoice, final Boolean defaultVal) {