From 88277c36c02f72fcaa7d4c8eded8a480db29a30b Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 17 Dec 2024 13:24:55 +0100 Subject: [PATCH 1/4] Full Control unleashed --- .../java/forge/ai/PlayerControllerAi.java | 5 ++ .../src/main/java/forge/util/Localizer.java | 2 - .../src/main/java/forge/game/card/Card.java | 3 - .../forge/game/cost/CostPartWithList.java | 2 + .../java/forge/game/cost/CostPayment.java | 16 ++--- .../forge/game/player/PlayerController.java | 28 ++++++-- .../game/spellability/AbilityActivated.java | 4 +- .../java/forge/game/spellability/Spell.java | 4 +- .../home/settings/CSubmenuPreferences.java | 1 - .../home/settings/VSubmenuPreferences.java | 9 --- .../java/forge/screens/match/CMatchUI.java | 36 ++++++++++ .../util/PlayerControllerForTests.java | 6 ++ .../forge/screens/match/MatchController.java | 37 +++++++++++ .../forge/screens/settings/SettingsPage.java | 4 -- forge-gui/res/languages/de-DE.properties | 11 +++- forge-gui/res/languages/en-US.properties | 11 +++- forge-gui/res/languages/es-ES.properties | 11 +++- forge-gui/res/languages/fr-FR.properties | 11 +++- forge-gui/res/languages/it-IT.properties | 11 +++- forge-gui/res/languages/ja-JP.properties | 11 +++- forge-gui/res/languages/pt-BR.properties | 11 +++- forge-gui/res/languages/zh-CN.properties | 11 +++- .../match/input/InputPassPriority.java | 4 +- .../gamemodes/match/input/InputPayMana.java | 3 +- .../gamemodes/net/server/NetGuiGame.java | 7 ++ .../java/forge/gui/interfaces/IGuiGame.java | 4 ++ .../properties/ForgePreferences.java | 1 - .../forge/player/PlayerControllerHuman.java | 66 ++++++++----------- 28 files changed, 239 insertions(+), 91 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 8fc3e496a92..80c8e17a57c 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -1672,4 +1672,9 @@ public CardCollection chooseCardsForEffectMultiple(Map v return choices; } + + @Override + public List orderCosts(List costs) { + return null; + } } diff --git a/forge-core/src/main/java/forge/util/Localizer.java b/forge-core/src/main/java/forge/util/Localizer.java index 588c292fddf..fb8d6624c41 100644 --- a/forge-core/src/main/java/forge/util/Localizer.java +++ b/forge-core/src/main/java/forge/util/Localizer.java @@ -140,7 +140,6 @@ public String getMessage(boolean forcedEnglish, final String key, final Object.. } public void setLanguage(final String languageRegionID, final String languagesDirectory) { - String[] splitLocale = languageRegionID.split("-"); Locale oldLocale = locale; @@ -174,7 +173,6 @@ public void setLanguage(final String languageRegionID, final String languagesDir notifyObservers(); } - } public List getLanguages() { 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 aa310614e6b..fa73243ad80 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -4829,7 +4829,6 @@ public final boolean tap(boolean attacker, boolean tapAnimation, SpellAbility ca return false; } - // Run triggers final Map runParams = AbilityKey.mapFromCard(this); runParams.put(AbilityKey.Attacker, attacker); runParams.put(AbilityKey.Cause, cause); @@ -4845,12 +4844,10 @@ public final boolean tap(boolean attacker, boolean tapAnimation, SpellAbility ca public final boolean untap(boolean untapAnimation) { if (!tapped) { return false; } - // Run Replacement effects if (getGame().getReplacementHandler().run(ReplacementType.Untap, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) { return false; } - // Run triggers getGame().getTriggerHandler().runTrigger(TriggerType.Untaps, AbilityKey.mapFromCard(this), false); runUntapCommands(); diff --git a/forge-game/src/main/java/forge/game/cost/CostPartWithList.java b/forge-game/src/main/java/forge/game/cost/CostPartWithList.java index 0f52ed6e839..aaf316ea322 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartWithList.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartWithList.java @@ -118,6 +118,8 @@ public final boolean executePayment(Player payer, SpellAbility ability, Card tar // always returns true, made this to inline with return protected boolean executePayment(Player payer, SpellAbility ability, CardCollectionView targetCards, final boolean effect) { + // need to refresh statics (e.g. sacrificing Omnath, Locus of Mana to Momentous Fall could end up with less toughness) + payer.getGame().getAction().checkStaticAbilities(); table.setLastStateBattlefield(payer.getGame().copyLastStateBattlefield()); table.setLastStateGraveyard(payer.getGame().copyLastStateGraveyard()); diff --git a/forge-game/src/main/java/forge/game/cost/CostPayment.java b/forge-game/src/main/java/forge/game/cost/CostPayment.java index 997487800f0..de9ab5b712c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPayment.java +++ b/forge-game/src/main/java/forge/game/cost/CostPayment.java @@ -28,6 +28,7 @@ import forge.game.card.CardZoneTable; import forge.game.mana.*; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.spellability.SpellAbility; import org.apache.commons.lang3.tuple.Pair; @@ -109,13 +110,7 @@ public static boolean canPayAdditionalCosts(Cost cost, final SpellAbility abilit * @return a boolean. */ public final boolean isFullyPaid() { - for (final CostPart part : adjustedCost.getCostParts()) { - if (!this.paidCostParts.contains(part)) { - return false; - } - } - - return true; + return paidCostParts.containsAll(adjustedCost.getCostParts()); } /** @@ -136,7 +131,12 @@ public final void refundPayment() { public boolean payCost(final CostDecisionMakerBase decisionMaker) { adjustedCost = CostAdjustment.adjust(cost, ability); - final List costParts = adjustedCost.getCostPartsWithZeroMana(); + List costParts = adjustedCost.getCostPartsWithZeroMana(); + + if (adjustedCost.getCostParts().size() > 1 && decisionMaker.getPlayer().getController().isFullControl(FullControlFlag.ChooseCostOrder)) { + // if mana part is shown here it wouldn't include reductions, but that's just a minor inconvenience + costParts = decisionMaker.getPlayer().getController().orderCosts(costParts); + } final Game game = decisionMaker.getPlayer().getGame(); 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 8479fed70a1..4f77bb7197a 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -35,8 +35,10 @@ import java.util.Arrays; import java.util.Collection; +import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; /** @@ -51,7 +53,7 @@ public enum ManaPaymentPurpose { DeclareBlocker, Echo, Multikicker, - CumulativeUpkeep, + CumulativeUpkeep } public enum BinaryChoiceType { @@ -61,9 +63,21 @@ public enum BinaryChoiceType { OddsOrEvens, UntapOrLeaveTapped, LeftOrRight, - AddOrRemove, + AddOrRemove } + public enum FullControlFlag { + ChooseCostOrder, + ChooseCostReductionOrderAndVariableAmount, + //ChooseManaPoolShard, // select shard with special properties + NoPaymentFromManaAbility, + NoFreeCombatCostHandling, + AllowPaymentStartWithMissingResources, + //AdditionalLayerTimestampOrder // tokens etc. + } + + private Set fullControls = EnumSet.noneOf(FullControlFlag.class); + protected final GameView gameView; protected final Player player; @@ -290,10 +304,12 @@ public final boolean payManaCost(CostPartMana costPartMana, SpellAbility sa, Str public abstract List chooseCardsForZoneChange(ZoneType destination, List origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider); - public boolean isFullControl() { - return false; + public Set getFullControl() { + return fullControls; + } + public boolean isFullControl(FullControlFlag f) { + return fullControls.contains(f); } - public void setFullControl(boolean full) {} public abstract void autoPassCancel(); @@ -324,4 +340,6 @@ public AnteResult getAnteResult() { public abstract CardCollection chooseCardsForEffectMultiple(Map validMap, SpellAbility sa, String title, boolean isOptional); + public abstract List orderCosts(List costs); + } diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java b/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java index 1eb494eb31c..ce10ab07de9 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java @@ -22,6 +22,7 @@ import forge.game.cost.Cost; import forge.game.cost.CostPayment; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.staticability.StaticAbilityCantBeCast; /** @@ -95,7 +96,8 @@ public boolean canPlay() { return false; } - return CostPayment.canPayAdditionalCosts(this.getPayCosts(), this, false); + return player.getController().isFullControl(FullControlFlag.AllowPaymentStartWithMissingResources) + || CostPayment.canPayAdditionalCosts(this.getPayCosts(), this, false); } /** {@inheritDoc} */ diff --git a/forge-game/src/main/java/forge/game/spellability/Spell.java b/forge-game/src/main/java/forge/game/spellability/Spell.java index 81ed51fb199..0fc57b7997d 100644 --- a/forge-game/src/main/java/forge/game/spellability/Spell.java +++ b/forge-game/src/main/java/forge/game/spellability/Spell.java @@ -30,6 +30,7 @@ import forge.game.cost.Cost; import forge.game.cost.CostPayment; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.replacement.ReplacementType; import forge.game.staticability.StaticAbilityCantBeCast; import forge.game.zone.ZoneType; @@ -101,7 +102,8 @@ public boolean canPlay() { return false; } - if (!CostPayment.canPayAdditionalCosts(this.getPayCosts(), this, false)) { + if (!activator.getController().isFullControl(FullControlFlag.AllowPaymentStartWithMissingResources) && + !CostPayment.canPayAdditionalCosts(this.getPayCosts(), this, false)) { return false; } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java index eb574fbe1aa..7199b52dc8f 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java @@ -139,7 +139,6 @@ public void initialize() { lstControls.add(Pair.of(view.getCbCompactMainMenu(), FPref.UI_COMPACT_MAIN_MENU)); lstControls.add(Pair.of(view.getCbUseSentry(), FPref.USE_SENTRY)); lstControls.add(Pair.of(view.getCbCheckSnapshot(), FPref.CHECK_SNAPSHOT_AT_STARTUP)); - lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS)); lstControls.add(Pair.of(view.getCbPauseWhileMinimized(), FPref.UI_PAUSE_WHILE_MINIMIZED)); lstControls.add(Pair.of(view.getCbWorkshopSyntax(), FPref.DEV_WORKSHOP_SYNTAX)); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java index c00f04fba40..fd4912bd138 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java @@ -98,7 +98,6 @@ public enum VSubmenuPreferences implements IVSubmenu { private final JCheckBox cbCompactMainMenu = new OptionsCheckBox(localizer.getMessage("cbCompactMainMenu")); private final JCheckBox cbDetailedPaymentDesc = new OptionsCheckBox(localizer.getMessage("cbDetailedPaymentDesc")); private final JCheckBox cbGrayText = new OptionsCheckBox(localizer.getMessage("cbGrayText")); - private final JCheckBox cbPromptFreeBlocks = new OptionsCheckBox(localizer.getMessage("cbPromptFreeBlocks")); private final JCheckBox cbPauseWhileMinimized = new OptionsCheckBox(localizer.getMessage("cbPauseWhileMinimized")); private final JCheckBox cbCompactPrompt = new OptionsCheckBox(localizer.getMessage("cbCompactPrompt")); private final JCheckBox cbEscapeEndsTurn = new OptionsCheckBox(localizer.getMessage("cbEscapeEndsTurn")); @@ -255,9 +254,6 @@ public enum VSubmenuPreferences implements IVSubmenu { pnlPrefs.add(cbCloneImgSource, titleConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlCloneImgSource")), descriptionConstraints); - pnlPrefs.add(cbPromptFreeBlocks, titleConstraints); - pnlPrefs.add(new NoteLabel(localizer.getMessage("nlPromptFreeBlocks")), descriptionConstraints); - pnlPrefs.add(cbPauseWhileMinimized, titleConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlPauseWhileMinimized")), descriptionConstraints); @@ -884,11 +880,6 @@ public JCheckBox getCbCloneImgSource() { return cbCloneImgSource; } - /** @return {@link javax.swing.JCheckBox} */ - public JCheckBox getCbPromptFreeBlocks() { - return cbPromptFreeBlocks; - } - public JCheckBox getCbPauseWhileMinimized() { return cbPauseWhileMinimized; } diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index d086a053132..40cdb688e02 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -28,9 +28,11 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -68,6 +70,7 @@ import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; @@ -1519,4 +1522,37 @@ private void createLandPopupPanel(Card land) { FOptionPane.showOptionDialog(null, title, null, mainPanel, options); } } + + @Override + public void showFullControl(PlayerView pv, Set controlFlags) { + final String lblFullControl = Localizer.getInstance().getMessage("lblFullControl"); + final JPopupMenu menu = new JPopupMenu(lblFullControl); + GuiUtils.addMenuItem(menu, lblFullControl, null, () -> { + FOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblFullControlDetails"), lblFullControl); + }); + + addFullControlEntry(menu, "lblChooseCostOrder", FullControlFlag.ChooseCostOrder, controlFlags); + addFullControlEntry(menu, "lblChooseCostReductionOrder", FullControlFlag.ChooseCostReductionOrderAndVariableAmount, controlFlags); + addFullControlEntry(menu, "lblNoPaymentFromManaAbility", FullControlFlag.NoPaymentFromManaAbility, controlFlags); + addFullControlEntry(menu, "lblNoFreeCombatCostHandling", FullControlFlag.NoFreeCombatCostHandling, controlFlags); + addFullControlEntry(menu, "lblAllowPaymentStartWithMissingResources", FullControlFlag.AllowPaymentStartWithMissingResources, controlFlags); + + Component parent = view.getControl().getFieldViewFor(pv).getAvatarArea(); + menu.show(parent, parent.getX(), parent.getY()); + } + + private void addFullControlEntry(JPopupMenu menu, String label, FullControlFlag flag, Set controlFlags) { + JCheckBoxMenuItem item = new JCheckBoxMenuItem(Localizer.getInstance().getMessage(label)); + if (controlFlags.contains(flag)) { + item.setSelected(true); + } + item.addActionListener(arg0 -> { + if (controlFlags.contains(flag)) { + controlFlags.remove(flag); + } else { + controlFlags.add(flag); + } + }); + menu.add(item); + } } 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 8363dd06378..d0dfd52faf9 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 @@ -786,4 +786,10 @@ public List chooseSpellAbilitiesForEffect(List spell // TODO Auto-generated method stub return null; } + + @Override + public List orderCosts(List costs) { + // TODO Auto-generated method stub + return null; + } } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 771429ae002..240c81035a1 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import forge.adventure.scene.DuelScene; @@ -11,6 +12,7 @@ import forge.ai.GameState; import forge.deck.Deck; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.item.IPaperCard; import forge.util.collect.FCollection; import org.apache.commons.lang3.StringUtils; @@ -48,6 +50,9 @@ import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.localinstance.skin.FSkinProp; +import forge.menu.FCheckBoxMenuItem; +import forge.menu.FMenuItem; +import forge.menu.FPopupMenu; import forge.model.FModel; import forge.player.PlayerZoneUpdate; import forge.player.PlayerZoneUpdates; @@ -63,6 +68,7 @@ import forge.toolbox.FOptionPane; import forge.trackable.TrackableCollection; import forge.util.ITriggerEvent; +import forge.util.Localizer; import forge.util.MessageUtil; import forge.util.WaitCallback; import forge.util.collect.FCollectionView; @@ -737,4 +743,35 @@ public static HostedMatch hostMatch() { public static HostedMatch getHostedMatch() { return hostedMatch; } + + @Override + public void showFullControl(PlayerView selected, Set controlFlags) { + FPopupMenu menu = new FPopupMenu() { + @Override + protected void buildMenu() { + addItem(new FMenuItem(Forge.getLocalizer().getMessage("lblFullControl"), + e -> { + FOptionPane.showMessageDialog(Localizer.getInstance().getMessage("lblFullControlDetails"), "Full Control details"); + })); + addItem(getFullControlMenuEntry("lblChooseCostOrder", FullControlFlag.ChooseCostOrder, controlFlags)); + addItem(getFullControlMenuEntry("lblChooseCostReductionOrder", FullControlFlag.ChooseCostReductionOrderAndVariableAmount, controlFlags)); + addItem(getFullControlMenuEntry("lblNoPaymentFromManaAbility", FullControlFlag.NoPaymentFromManaAbility, controlFlags)); + addItem(getFullControlMenuEntry("lblNoFreeCombatCostHandling", FullControlFlag.NoFreeCombatCostHandling, controlFlags)); + addItem(getFullControlMenuEntry("lblAllowPaymentStartWithMissingResources", FullControlFlag.AllowPaymentStartWithMissingResources, controlFlags)); + } + }; + + menu.show(getView(), getView().getPlayerPanel(selected).localToScreenX(0), getView().getPlayerPanel(selected).localToScreenY(0)); + } + + private FCheckBoxMenuItem getFullControlMenuEntry(String label, FullControlFlag flag, Set controlFlags) { + return new FCheckBoxMenuItem(Forge.getLocalizer().getMessage(label), controlFlags.contains(flag), + e -> { + if (controlFlags.contains(flag)) { + controlFlags.remove(flag); + } else { + controlFlags.add(flag); + } + }); + } } diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java index ca1252e12c4..5faa2e86104 100644 --- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java @@ -256,10 +256,6 @@ public void valueChanged(String newValue) { Forge.getLocalizer().getMessage("cbCloneImgSource"), Forge.getLocalizer().getMessage("nlCloneImgSource")), 1); - lstSettings.addItem(new BooleanSetting(FPref.MATCHPREF_PROMPT_FREE_BLOCKS, - Forge.getLocalizer().getMessage("cbPromptFreeBlocks"), - Forge.getLocalizer().getMessage("nlPromptFreeBlocks")), - 1); lstSettings.addItem(new BooleanSetting(FPref.UI_DETAILED_SPELLDESC_IN_PROMPT, Forge.getLocalizer().getMessage("cbDetailedPaymentDesc"), Forge.getLocalizer().getMessage("nlDetailedPaymentDesc")), diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 5f860b802d3..a859337ca49 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -94,7 +94,6 @@ cbTimedTargOverlay=Aktiviere Zielpfeiloptimierung cbCompactMainMenu=Nutze kompakteres Seitenmenü cbDetailedPaymentDesc=Spruchbeschreibung in Bestätigungsfenster cbGrayText=Ausgrauen von unzutreffenden Blöcken im Kartentext -cbPromptFreeBlocks=Freies Block-Management cbPauseWhileMinimized=Pausiere wenn minimiert cbCompactPrompt=Kompaktes Bestätigungsfenster cbEscapeEndsTurn=Nutze Escape für Zugende @@ -162,7 +161,6 @@ nlpAiSideboardingMode=Wählen Sie die Art der KI-Sideboards: Aus (die KI tritt n nlPerformanceMode=Schalten zusätzlich Prüfungen auf statische Fähigkeiten ab, um das Spiel zu beschleunigen. Warnung: Kann Probleme mit 'Aufblitzen' bei Karten von KI-Gegner verursachen! nlFilteredHands=Erzeugt zwei Starthände, und behält die, welche am nächsten an der durchschnittlichen Länderanzahl im Deck ist. (Erfordert Neustart) nlCloneImgSource=Zeige das originale Kartenbild des Klones statt der geklonten Karte. -nlPromptFreeBlocks=Wenn ein neuer Block nichts kosten würde, dann wird er automatisch bezahlt. nlPauseWhileMinimized=Wenn aktiviert, pausiert Forge im minimierten Zustand (betrifft hauptsächlich KI gegen KI). nlEscapeEndsTurn=Wenn aktiviert, funktioniert ESCape als Alternative um den Zug zu beenden. nlDetailedPaymentDesc=Wenn aktiviert, werden detaillierte Spruch-/Fähigkeitsbeschreibungen beim Auswählen von Zielen bzw. Bezahlen von Kosten angezeigt. @@ -1271,6 +1269,15 @@ lblMorph=Morph #CardFactoryUtil.java lblCraft=anzahl der herzustellenden Karten #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}, du hast den Münzwurf gewonnen. lblYouLostTheLastGame={0}, du hast das letzte Spiel verloren. lblWouldYouLiketoPlayorDraw=Willst du lieber zuerst spielen oder ziehen? diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 508d76d4922..d6791d58cd9 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -95,7 +95,6 @@ cbTimedTargOverlay=Enable Targeting Overlay Optimization cbCompactMainMenu=Use Compact Main Sidebar Menu cbDetailedPaymentDesc=Spell Description in Payment Prompt cbGrayText=Gray out unmet conditions in card text -cbPromptFreeBlocks=Free Block Handling cbPauseWhileMinimized=Pause While Minimized cbCompactPrompt=Compact Prompt cbEscapeEndsTurn=Use Escape Key to End Turn @@ -164,7 +163,6 @@ nlExperimentalRestore=EXPERIMENTAL - Stores a snapshot to be used for undoing sp nlPerformanceMode=Disables additional static abilities checks to speed up the game engine. (Warning: breaks some ''as if had flash'' scenarios when casting cards owned by opponents). nlFilteredHands=Generates two starting hands and keeps the one with the closest to average land count for the deck. (REQUIRES RESTART) nlCloneImgSource=When enabled clones will use their original art instead of the cloned card''s art. -nlPromptFreeBlocks=When enabled, if you would have to pay 0 to block, pay automatically without prompt. nlPauseWhileMinimized=When enabled, Forge pauses when minimized (primarily for AI vs AI). nlEscapeEndsTurn=When enabled, Escape key functions as an alternative shortcut to end the current turn. nlDetailedPaymentDesc=When enabled, detailed spell/ability descriptions are shown when choosing targets and paying costs. @@ -1287,6 +1285,15 @@ lblMorph=Morph #CardFactoryUtil.java lblCraft=how many cards to craft #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}, you have won the coin toss. lblYouLostTheLastGame={0}, you lost the last game. lblWouldYouLiketoPlayorDraw=Would you like to play or draw? diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 9d6b31e9c06..7c4025c5977 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -95,7 +95,6 @@ cbTimedTargOverlay=Habilitar optimización de superposición de capas cbCompactMainMenu=Usar el menú de la barra lateral principal compacta cbDetailedPaymentDesc=Descripción del hechizo en el aviso del pago cbGrayText=Gray out unmet conditions in card text -cbPromptFreeBlocks=Manejar bloqueos en el combate sí no requieren coste cbPauseWhileMinimized=Pausa mientras minimizado cbCompactPrompt=Ventana de aviso compacta cbEscapeEndsTurn=Use la tecla Escape para Fin del Turno @@ -164,7 +163,6 @@ nlExperimentalRestore=EXPERIMENTAL - Almacena una instantánea que se utilizará nlPerformanceMode=Desactiva las comprobaciones de habilidades estáticas adicionales para acelerar el motor del juego. (Advertencia: rompe algunos escenarios ''como si tuviera flash'' cuando se lanzan cartas de propiedad de los oponentes). nlFilteredHands=Genera dos manos iniciales y mantiene la que tiene el recuento de tierras más cercano al promedio del mazo (Requiere reinicio) nlCloneImgSource=Cuando se habilita, los clones usarán su arte original en lugar del arte de la carta clonada. -nlPromptFreeBlocks=Cuando está habilitado, si tuvieses que pagar 0 para bloquear, paga automáticamente sin aviso. nlPauseWhileMinimized=Cuando está habilitado, Forge hace una pausa cuando está minimizado (principalmente para IA contra IA). nlEscapeEndsTurn=Cuando está habilitada, la tecla Escape funciona como un atajo alternativo para finalizar el turno actual. nlDetailedPaymentDesc=Cuando está habilitado, se muestran descripciones detalladas de hechizos / habilidades al elegir objetivos y pagar costos. @@ -1281,6 +1279,15 @@ lblMorph=Mutar #CardFactoryUtil.java lblCraft=cuántas cartas crear #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}, has ganado el lanzamiento de la moneda. lblYouLostTheLastGame={0}, perdiste la última partida. lblWouldYouLiketoPlayorDraw=¿Quieres jugar primero o ceder? diff --git a/forge-gui/res/languages/fr-FR.properties b/forge-gui/res/languages/fr-FR.properties index 641a311bdc4..77198ed29f2 100644 --- a/forge-gui/res/languages/fr-FR.properties +++ b/forge-gui/res/languages/fr-FR.properties @@ -94,7 +94,6 @@ cbTimedTargOverlay=Activer l'optimisation de la superposition de ciblage cbCompactMainMenu=Utiliser le menu principal compact de la barre latérale cbDetailedPaymentDesc=Épeler la description dans l'invite de paiement cbGrayText=Gris les conditions non remplies dans le texte de la carte -cbPromptFreeBlocks=Gestion libre des blocs cbPauseWhileMinimized=Pause pendant la minimisation cbCompactPrompt=Invite compacte cbEscapeEndsTurn=Utilisez la touche d'échappement pour terminer le tour @@ -162,7 +161,6 @@ nlpAiSideboardingMode=Choisissez la manière dont les buffets de l'IA sont désa nlPerformanceMode=Désactive les vérifications supplémentaires des capacités statiques pour accélérer le moteur de jeu. (Attention : casse certains scénarios 'comme si c'était flash' lors du lancement de cartes appartenant à des adversaires). nlFilteredHands=Génère deux mains de départ et conserve celle dont le nombre de terrains est le plus proche de la moyenne pour le deck. (NÉCESSITE UN REDÉMARRAGE) nlCloneImgSource=Lorsqu'il est activé, les clones utiliseront leur art original au lieu de l'art de la carte clonée. -nlPromptFreeBlocks=Lorsqu'il est activé, si vous deviez payer 0 pour bloquer, payez automatiquement sans invite. nlPauseWhileMinimized=Lorsqu'il est activé, Forge s'arrête lorsqu'il est réduit (principalement pour l'IA par rapport à l'IA). nlEscapeEndsTurn=Lorsqu'elle est activée, la touche Échap fonctionne comme un raccourci alternatif pour terminer le tour en cours. nlDetailedPaymentDesc=Lorsqu'il est activé, les descriptions détaillées des sorts/capacités sont affichées lors du choix des cibles et du paiement des coûts. @@ -1275,6 +1273,15 @@ lblMorph=Morph #CardFactoryUtil.java lblCraft=combien de cartes créer #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}, vous avez gagné le tirage au sort. lblYouLostTheLastGame={0}, vous avez perdu la dernière partie. lblWouldYouLiketoPlayorDraw=Voulez-vous jouer ou piocher ? diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index ee600e78198..773b4498f5c 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -93,7 +93,6 @@ cbTimedTargOverlay=Abilita l'ottimizzazione delle sovraimperssioni per scegliere cbCompactMainMenu=Usa la barra principale del menu compatta cbDetailedPaymentDesc=Descrizione della magia nella richiesta di pagamento cbGrayText=Gray out unmet conditions in card text -cbPromptFreeBlocks=Gestione libera dei blocchi cbPauseWhileMinimized=Pausa se ridotto a icona cbCompactPrompt=Riquadro messaggi compatto cbEscapeEndsTurn=Utilizzare il tasto Esc per terminare il turno @@ -161,7 +160,6 @@ nlpAiSideboardingMode=Scegli il modo in cui i sideboard dell'IA: Off (l'IA non u nlPerformanceMode=Disabilita delle verifiche aggiuntive delle abilità statiche per velocizzare il motore di gioco. (Attenzione: non fa funzionare correttamente il giocare carte di proprietà di un avversario in contesti "come se avesse lampo"). nlFilteredHands=Genera due mani iniziali e mantiene quella con il numero di terre più vicino alla media del mazzo. (RIAVVIO NECESSARIO) nlCloneImgSource=Se abilitato, i cloni useranno la loro arte originale invece di quella della carta clonata. -nlPromptFreeBlocks=Se abilitato, quando è richiesto un pagamento di 0 per bloccare, paga automaticamente senza chiedere conferma. nlPauseWhileMinimized=Se abilitato, mette in pausa Forge quando è ridotto a icona (principalmente per IA vs IA). nlEscapeEndsTurn=Se abilitato, il tasto Esc funziona come scorciatoia alternativa per terminare il turno in corso. nlDetailedPaymentDesc=Se abilitato, vengono visualizzate descrizioni dettagliate di magie/abilità quando si scelgono bersagli e si pagano i costi. @@ -1272,6 +1270,15 @@ lblMorph=Metamorfosi #CardFactoryUtil.java lblCraft=quante carte creare #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss= %s, hai vinto il lancio della moneta. lblYouLostTheLastGame= %s, hai perso l'ultima partita. lblWouldYouLiketoPlayorDraw=Preferisci iniziare o pescare? diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index 37ccbb15d75..6fae88b8aef 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -94,7 +94,6 @@ cbTimedTargOverlay=ターゲティングオーバーレイ最適化を有効に cbCompactMainMenu=コンパクトメインサイドバーメニューを使用 cbDetailedPaymentDesc=支払いプロンプトでもスペル説明を表示する cbGrayText=Gray out unmet conditions in card text -cbPromptFreeBlocks=ブロック自動処理 cbPauseWhileMinimized=最小化中の一時停止 cbCompactPrompt=コンパクトプロンプト cbEscapeEndsTurn=エスケープキーを使用してターンを終了する @@ -162,7 +161,6 @@ nlpAiSideboardingMode=AI のサイドボード方法を選択します: オフ ( nlPerformanceMode=常在型能力の追加チェックを無効にして、ゲームエンジンを高速化します。 (警告:対戦相手が所有するカードをキャストするときに、「あたかもフラッシュがあるかのように」の能力が無効になるかもしれません。) nlFilteredHands=2つのハンドを生成し、デッキの平均土地数に最も近いハンドをキープします。 nlCloneImgSource=有効にすると、クローンはクローン先のカードのアートの代わりに元のアートを使用します。 -nlPromptFreeBlocks=有効にすると、ブロックするために0を支払う必要がある場合、プロンプトなしで自動的に支払います。 nlPauseWhileMinimized=有効にすると、Forge は最小化すると一時停止します(主に AI 対 AI)。 nlEscapeEndsTurn=有効にすると、エスケープキーは現在のターンを終了するための代替ショートカットとして機能します。 nlDetailedPaymentDesc=有効にすると、ターゲットを選択してコストを支払うときに、呪文/能力の詳細な説明が表示されます。 @@ -1274,6 +1272,15 @@ lblMorph=変異 #CardFactoryUtil.java lblCraft=カードを何枚作成するか #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}、あなたはコイントスに勝ちました。 lblYouLostTheLastGame={0}、あなたは先のゲームに負けた。 lblWouldYouLiketoPlayorDraw=先攻にしますか、それとも後攻? diff --git a/forge-gui/res/languages/pt-BR.properties b/forge-gui/res/languages/pt-BR.properties index 160fdbc913c..3fdd1a19e04 100644 --- a/forge-gui/res/languages/pt-BR.properties +++ b/forge-gui/res/languages/pt-BR.properties @@ -95,7 +95,6 @@ cbTimedTargOverlay=Habilitar Otimização da Sobreposição de Alvo cbCompactMainMenu=Usar o Menu Lateral Principal Compacto cbDetailedPaymentDesc=Descrição da Mágica na Solicitação do Custo cbGrayText=Desabilitar condições incompatíveis no texto da carta -cbPromptFreeBlocks=Bloqueio Gratuito Automático cbPauseWhileMinimized=Pausar Quando Minimizado cbCompactPrompt=Solicitação Compacta cbEscapeEndsTurn=Usar a tecla Esc para Fim do Turno @@ -163,7 +162,6 @@ nlpAiSideboardingMode=Escolha a forma como os sideboards de IA: Off (a IA não f nlPerformanceMode=Desabilita verificações adicionais de habilidades estáticas para acelerar o jogo. (Aviso\: quebra alguns cenários 'como se tivesse lampejo' ao conjurar cartas pertencentes a adversários). nlFilteredHands=Gera duas mãos iniciais e mantém a mão mais próxima da média da contagem de terreno do deck. (REQUER REINÍCIO) nlCloneImgSource=Quando ativado os clones usarão sua arte original em vez da arte da carta clonada. -nlPromptFreeBlocks=Quando ativado, se você tiver que pagar 0 para bloquear, pague automaticamente sem solicitação. nlPauseWhileMinimized=Quando ativado, o Forge pausa quando minimizado (principalmente para IA vs IA). nlEscapeEndsTurn=Quando ativado, a tecla Escape funciona como um atalho alternativo para o final do turno atual. nlDetailedPaymentDesc=Quando ativado, as descrições detalhadas da magia/habilidade são mostradas na escolha dos alvos e no pagamento dos custos. @@ -1302,6 +1300,15 @@ lblMorph=Metamorfose #CardFactoryUtil.java lblCraft=quantas cartas criar #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0}, você ganhou na moeda. lblYouLostTheLastGame={0}, você perdeu o último jogo. lblWouldYouLiketoPlayorDraw=Você quer iniciar ou comprar? diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index ca769793316..74f70b12562 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -95,7 +95,6 @@ cbTimedTargOverlay=启用定位叠加优化 cbCompactMainMenu=使用紧凑的主侧边栏菜单 cbDetailedPaymentDesc=在付费提示中详细描述咒语 cbGrayText=将牌张文本中未满足条件的部分显示为灰色 -cbPromptFreeBlocks=不阻塞处理 cbPauseWhileMinimized=暂停时最小化 cbCompactPrompt=紧凑型提示 cbEscapeEndsTurn=使用空格结束回合 @@ -164,7 +163,6 @@ nlExperimentalRestore=实验性-储存用于回退咒语或异能的快照 nlPerformanceMode=禁止其他静态能力检查以加速游戏引擎(警告:对手手牌有闪现单卡能使用时可能会跳过)。 nlFilteredHands=生成两个起手并发给你最接近套牌地比例的起手(需要重启) nlCloneImgSource=启用克隆的时候将使用原画而不是克隆牌的画 -nlPromptFreeBlocks=启用后如果你需要支付0来阻挡,则不会提示自动支付0。 nlPauseWhileMinimized=启用后,Forge将在暂停时最小化(主要用于AI VS AI)。 nlEscapeEndsTurn=启用后,空格键可以用于结束当前回合的替代按键。 nlDetailedPaymentDesc=启用后,选择目标和支付费用的时候会显示详细的咒语/异能说明。 @@ -1278,6 +1276,15 @@ lblMorph=变身 #CardFactoryUtil.java lblCraft=需要制作多少张卡片 #PlayerControllerHuman.java +lblFullControl=Full Control +lblFullControlDetails=This feature lets you skip different helpers that streamline gameplay by avoiding somewhat annoying GUI interactions and instead use AI logic to make reasonable decisions for beginners.\nUseful for certain corner cases or if you want to challenge yourself with the Comprehensive Rules:\ne.g. the opposite cost order is needed if activating an animated "Halo Fountain" that's also tapped. +lblChooseCostOrder=Choose cost order +lblChooseCostReductionOrder=Choose cost reduction order & amount +lblNoPaymentFromManaAbility=Don\'t attempt paying when generating mana +lblNoFreeCombatCostHandling=Don\'t accept attack/block costs of \{0\} +lblAllowPaymentStartWithMissingResources=Allow payment start when cost seems unaffordable +lblOrderCosts=Order costs +lblPayFirst=Pay first lblYouHaveWonTheCoinToss={0},你赢得了这次掷硬币。 lblYouLostTheLastGame={0},最后一场比赛你输了。 lblWouldYouLiketoPlayorDraw=你想先手还是后手? diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java index 93eb1395e37..9ba01c81c5c 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java @@ -124,8 +124,8 @@ private void passPriority(final Runnable runnable) { @Override protected final void onPlayerSelected(Player selected, final ITriggerEvent triggerEvent) { PlayerController pc = selected.getController(); - if (pc.isGuiPlayer()) { - pc.setFullControl(!pc.isFullControl()); + if (!pc.isAI()) { + getController().getGui().showFullControl(selected.getView(), pc.getFullControl()); } } diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java index 6e9a9d9c62e..b7e6bb21952 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java @@ -11,6 +11,7 @@ import forge.game.card.Card; import forge.game.mana.ManaCostBeingPaid; import forge.game.player.Player; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.player.actions.PayManaFromPoolAction; import forge.game.spellability.AbilityManaPart; @@ -344,7 +345,7 @@ else if (colorMatches.size() < abilitiesMap.size()) { } } - if (restrictionsMet && !player.getController().isFullControl()) { + if (restrictionsMet && !player.getController().isFullControl(FullControlFlag.NoPaymentFromManaAbility)) { player.getManaPool().payManaFromAbility(saPaidFor, manaCost, chosen); } if (!restrictionsMet || chosen.getPayCosts().hasManaCost()) { diff --git a/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java index 04f0e1fa70b..9674c4023fd 100644 --- a/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java @@ -9,6 +9,7 @@ import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbilityView; import forge.game.zone.ZoneType; @@ -25,6 +26,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; public class NetGuiGame extends AbstractGuiGame { @@ -319,4 +321,9 @@ protected void updateCurrentPlayer(final PlayerView player) { // TODO Auto-generated method stub } + @Override + public void showFullControl(PlayerView view, Set controlFlags) { + // TODO Auto-generated method stub + } + } diff --git a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java index 601bbb9b9cf..b4899a77a7f 100644 --- a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java @@ -12,6 +12,7 @@ import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbilityView; import forge.game.zone.ZoneType; @@ -27,6 +28,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; public interface IGuiGame { @@ -273,4 +275,6 @@ public interface IGuiGame { void clearAutoYields(); void setCurrentPlayer(PlayerView player); + + void showFullControl(PlayerView view, Set controlFlags); } diff --git a/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java index cd7c92340d5..425460c4a08 100644 --- a/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java @@ -188,7 +188,6 @@ public enum FPref { CHECK_SNAPSHOT_AT_STARTUP("true"), MATCH_HOT_SEAT_MODE("false"), //this only applies to mobile game - MATCHPREF_PROMPT_FREE_BLOCKS("false"), NEW_GAME_SCREEN("Constructed"), LOAD_GAME_SCREEN("BoosterDraft"), diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 5efe16894b0..4cb6571a290 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -94,8 +94,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont private boolean mayLookAtAllCards = false; private boolean disableAutoYields = false; - private boolean fullControl = false; - private IGuiGame gui; protected final InputQueue inputQueue; @@ -199,15 +197,6 @@ public void endTempShowCards() { tempShownCards.clear(); } - @Override - public boolean isFullControl() { - return fullControl; - } - @Override - public void setFullControl(boolean full) { - fullControl = full; - } - /** * Uses GUI to learn which spell the player (human in our case) would like * to play @@ -399,7 +388,7 @@ public Integer announceRequirements(final SpellAbility ability, final String ann } if (cost != null) { Integer costX = cost.getMaxForNonManaX(ability, player, false); - if (costX != null) { + if (costX != null && !player.getController().isFullControl(FullControlFlag.AllowPaymentStartWithMissingResources)) { max = Math.min(max, costX); } if (cost.hasManaCost() && !abXMin) { @@ -836,31 +825,25 @@ public boolean confirmTrigger(final WrappedAbility wrapper) { @Override public Player chooseStartingPlayer(final boolean isFirstGame) { + String prompt = null; + if (isFirstGame) { + prompt = localizer.getMessage("lblYouHaveWonTheCoinToss", player.getName()); + } else { + prompt = localizer.getMessage("lblYouLostTheLastGame", player.getName()); + } + if (getGame().getPlayers().size() == 2) { - String prompt = null; - if (isFirstGame) { - prompt = localizer.getMessage("lblYouHaveWonTheCoinToss", player.getName()); - } else { - prompt = localizer.getMessage("lblYouLostTheLastGame", player.getName()); - } prompt += "\n\n" + localizer.getMessage("lblWouldYouLiketoPlayorDraw"); final InputConfirm inp = new InputConfirm(this, prompt, localizer.getMessage("lblPlay"), localizer.getMessage("lblDraw")); inp.showAndWait(); return inp.getResult() ? this.player : this.player.getOpponents().get(0); - } else { - String prompt = null; - if (isFirstGame) { - prompt = localizer.getMessage("lblYouHaveWonTheCoinToss", player.getName()); - } else { - prompt = localizer.getMessage("lblYouLostTheLastGame", player.getName()); - } - prompt += "\n\n" + localizer.getMessage("lblWhoWouldYouLiketoStartthisGame"); - final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList<>(this, 1, 1, - new FCollection<>(getGame().getPlayersInTurnOrder())); - input.setMessage(prompt); - input.showAndWait(); - return input.getFirstSelected(); } + + prompt += "\n\n" + localizer.getMessage("lblWhoWouldYouLiketoStartthisGame"); + final InputSelectEntitiesFromList input = new InputSelectEntitiesFromList<>(this, 1, 1, getGame().getPlayersInTurnOrder()); + input.setMessage(prompt); + input.showAndWait(); + return input.getFirstSelected(); } @Override @@ -897,6 +880,16 @@ public List enlistAttackers(List attackers) { return chosenCards; } + @Override + public List orderCosts(List costs) { + if (costs.size() < 2) { + return costs; + } + List chosen = getGui().order(localizer.getMessage("lblOrderCosts"), localizer.getMessage("lblPayFirst"), + 0, 0, costs, null, null, false); + return chosen; + } + @Override public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) { GameEntityViewMap gameCacheBlockers = GameEntityView.getMap(oldBlockers); @@ -1562,10 +1555,9 @@ public CardCollectionView chooseCardsToRevealFromHand(int min, int max, final Ca } @Override - public boolean payManaOptional(final Card c, final Cost cost, final SpellAbility sa, final String prompt, - final ManaPaymentPurpose purpose) { - if (sa == null && cost.isOnlyManaCost() && cost.getTotalMana().isZero() - && !FModel.getPreferences().getPrefBoolean(FPref.MATCHPREF_PROMPT_FREE_BLOCKS)) { + public boolean payManaOptional(final Card c, final Cost cost, final SpellAbility sa, final String prompt, final ManaPaymentPurpose purpose) { + if (cost.isOnlyManaCost() && cost.getTotalMana().isZero() && isFullControl(FullControlFlag.NoFreeCombatCostHandling) + && (purpose == ManaPaymentPurpose.DeclareAttacker || purpose == ManaPaymentPurpose.DeclareBlocker)) { return true; } return HumanPlay.payCostDuringAbilityResolve(this, player, c, cost, sa, prompt); @@ -1899,7 +1891,7 @@ public ReplacementEffect chooseSingleReplacementEffect(final List possibleStatics) { final StaticAbility first = possibleStatics.get(0); - if (possibleStatics.size() == 1 || !fullControl) { + if (possibleStatics.size() == 1 || !isFullControl(FullControlFlag.ChooseCostOrder)) { return first; } final List sts = possibleStatics.stream().map(StaticAbility::toString).collect(Collectors.toList()); @@ -3283,7 +3275,7 @@ public int chooseNumberForKeywordCost(SpellAbility sa, Cost cost, KeywordInterfa @Override public int chooseNumberForCostReduction(final SpellAbility sa, final int min, final int max) { - if (fullControl) { + if (isFullControl(FullControlFlag.ChooseCostReductionOrderAndVariableAmount)) { return chooseNumber(sa, localizer.getMessage("lblChooseAmountCostReduction"), min, max); } return max; From eb8c52226b8becd2b0ce481cf21239ffda2e9051 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 17 Dec 2024 14:49:55 +0100 Subject: [PATCH 2/4] Fix APNAP order --- .../main/java/forge/game/ability/effects/TokenEffect.java | 5 ++--- .../java/forge/game/ability/effects/TokenEffectBase.java | 2 +- forge-gui/res/cardsfolder/g/giant_inheritance.txt | 2 +- forge-gui/res/cardsfolder/q/questing_cosplayer.txt | 2 +- forge-gui/res/cardsfolder/t/the_rani.txt | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index d0664275e3e..ff25adb4bf9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -41,8 +41,7 @@ protected String getStackDescription(SpellAbility sa) { final Card host = sa.getHostCard(); String desc = sa.getParam("SpellDescription"); List words = Arrays.asList(desc.split(" ")); - final List creators = AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", - "You"), sa); + final List creators = getDefinedPlayersOrTargeted(sa, "TokenOwner"); if (!words.get(0).equalsIgnoreCase("Create") && desc.contains(" create")) { String[] parts = desc.split(" create", 2); desc = parts[0] + " " + Lang.joinHomogenous(creators) + " create" + parts[1]; @@ -123,7 +122,7 @@ public void resolve(SpellAbility sa) { useZoneTable = true; } - makeTokenTable(AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa), + makeTokenTable(getDefinedPlayersOrTargeted(sa, "TokenOwner"), sa.getParam("TokenScript").split(","), AbilityUtils.calculateAmount(host, sa.getParamOrDefault("TokenAmount", "1"), sa), false, triggerList, combatChanged, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java index 521e81a49b8..9a642c8653e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java @@ -79,7 +79,7 @@ protected TokenCreateTable makeTokenTable(TokenCreateTable tokenTable, final boo // support PlayerCollection for affected Set toRemove = Sets.newHashSet(); - for (Player p : Sets.newHashSet(tokenTable.rowKeySet())) { + for (Player p : Lists.newArrayList(tokenTable.rowKeySet())) { final Map repParams = AbilityKey.mapFromAffected(p); repParams.put(AbilityKey.Token, tokenTable); repParams.put(AbilityKey.Cause, sa); diff --git a/forge-gui/res/cardsfolder/g/giant_inheritance.txt b/forge-gui/res/cardsfolder/g/giant_inheritance.txt index 68e4b90dfcc..246f26718f8 100644 --- a/forge-gui/res/cardsfolder/g/giant_inheritance.txt +++ b/forge-gui/res/cardsfolder/g/giant_inheritance.txt @@ -5,7 +5,7 @@ K:Enchant creature A:SP$ Attach | Cost$ 4 G | ValidTgts$ Creature | AILogic$ Pump S:Mode$ Continuous | Affected$ Card.EnchantedBy | AddPower$ 5 | AddToughness$ 5 | AddTrigger$ AttackTrigger | Description$ Enchanted creature gets +5/+5 and has "Whenever this creature attacks, create a Monster Role token attached to up to one target attacking creature." (Enchanted creature gets +1/+1 and has trample.) SVar:AttackTrigger:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever this creature attacks, create a Monster Role token attached to up to one target attacking creature." (Enchanted creature gets +1/+1 and has trample. -SVar:TrigToken:DB$ Token | TokenScript$ role_monster | AttachedTo$ Targeted | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target attacking creature | ValidTgts$ Creature.attacking +SVar:TrigToken:DB$ Token | TokenScript$ role_monster | AttachedTo$ Targeted | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target attacking creature | ValidTgts$ Creature.attacking | TokenOwner$ You T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME is put into a graveyard from the battlefield, return CARDNAME to its owner's hand. SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Defined$ TriggeredNewCardLKICopy SVar:SacMe:2 diff --git a/forge-gui/res/cardsfolder/q/questing_cosplayer.txt b/forge-gui/res/cardsfolder/q/questing_cosplayer.txt index fd2ecbe0138..2585baf9568 100644 --- a/forge-gui/res/cardsfolder/q/questing_cosplayer.txt +++ b/forge-gui/res/cardsfolder/q/questing_cosplayer.txt @@ -3,7 +3,7 @@ ManaCost:1 G Types:Creature Human Bard PT:1/1 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a Questing Role token and attach it to target creature. (If you control another Role on it, put that one into the graveyard. Enchanted creature has all the abilities of Questing Beast.) -SVar:TrigToken:DB$ Token | TokenScript$ role_questing | AttachedTo$ Targeted | ValidTgts$ Creature +SVar:TrigToken:DB$ Token | TokenScript$ role_questing | AttachedTo$ Targeted | ValidTgts$ Creature | TokenOwner$ You DeckHas:Type$Aura|Role & Ability$Token DeckHints:Type$Aura Oracle:When Questing Cosplayer enters the battlefield, create a Questing Role token and attach it to target creature. (If you control another Role on it, put that one into the graveyard. Enchanted creature has all the abilities of Questing Beast.) diff --git a/forge-gui/res/cardsfolder/t/the_rani.txt b/forge-gui/res/cardsfolder/t/the_rani.txt index 5ff59f3f078..d7cbe882a1c 100644 --- a/forge-gui/res/cardsfolder/t/the_rani.txt +++ b/forge-gui/res/cardsfolder/t/the_rani.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Time Lord Scientist PT:3/4 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME enters or attacks, create a red Aura enchantment token named Mark of the Rani attached to another target creature. That token has enchant creature and "Enchanted creature gets +2/+2 and is goaded." T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters or attacks, create a red Aura enchantment token named Mark of the Rani attached to another target creature. That token has enchant creature and "Enchanted creature gets +2/+2 and is goaded." -SVar:TrigToken:DB$ Token | TokenScript$ mark_of_the_rani | AttachedTo$ Targeted | ValidTgts$ Creature.Other | TgtPrompt$ Select another target creature +SVar:TrigToken:DB$ Token | TokenScript$ mark_of_the_rani | TokenOwner$ You | AttachedTo$ Targeted | ValidTgts$ Creature.Other | TgtPrompt$ Select another target creature T:Mode$ DamageDone | ValidSource$ Creature.IsGoaded | ValidTarget$ Opponent | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigInvestigate | TriggerDescription$ Whenever a goaded creature deals combat damage to one of your opponents, investigate. SVar:TrigInvestigate:DB$ Investigate SVar:HasAttackEffect:TRUE From 4410521511392b4dd6dd38e51446bbeda18ff4c3 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 17 Dec 2024 16:12:04 +0100 Subject: [PATCH 3/4] Clean up --- forge-ai/src/main/java/forge/ai/PlayerControllerAi.java | 2 +- forge-game/src/main/java/forge/game/cost/CostPayment.java | 3 +-- .../src/main/java/forge/player/PlayerControllerHuman.java | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 80c8e17a57c..a7f7c54d23f 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -1675,6 +1675,6 @@ public CardCollection chooseCardsForEffectMultiple(Map v @Override public List orderCosts(List costs) { - return null; + return costs; } } diff --git a/forge-game/src/main/java/forge/game/cost/CostPayment.java b/forge-game/src/main/java/forge/game/cost/CostPayment.java index de9ab5b712c..d6a47c75ca9 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPayment.java +++ b/forge-game/src/main/java/forge/game/cost/CostPayment.java @@ -28,7 +28,6 @@ import forge.game.card.CardZoneTable; import forge.game.mana.*; import forge.game.player.Player; -import forge.game.player.PlayerController.FullControlFlag; import forge.game.spellability.SpellAbility; import org.apache.commons.lang3.tuple.Pair; @@ -133,7 +132,7 @@ public boolean payCost(final CostDecisionMakerBase decisionMaker) { adjustedCost = CostAdjustment.adjust(cost, ability); List costParts = adjustedCost.getCostPartsWithZeroMana(); - if (adjustedCost.getCostParts().size() > 1 && decisionMaker.getPlayer().getController().isFullControl(FullControlFlag.ChooseCostOrder)) { + if (adjustedCost.getCostParts().size() > 1) { // if mana part is shown here it wouldn't include reductions, but that's just a minor inconvenience costParts = decisionMaker.getPlayer().getController().orderCosts(costParts); } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 4cb6571a290..a78b84d323f 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -31,6 +31,7 @@ import forge.game.mana.ManaConversionMatrix; import forge.game.mana.ManaCostBeingPaid; import forge.game.player.*; +import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.actions.SelectCardAction; import forge.game.player.actions.SelectPlayerAction; import forge.game.replacement.ReplacementEffect; @@ -882,7 +883,7 @@ public List enlistAttackers(List attackers) { @Override public List orderCosts(List costs) { - if (costs.size() < 2) { + if (!isFullControl(FullControlFlag.ChooseCostOrder) || costs.size() < 2) { return costs; } List chosen = getGui().order(localizer.getMessage("lblOrderCosts"), localizer.getMessage("lblPayFirst"), From 1a75c064902365832ac62626554c603d481840e8 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Wed, 18 Dec 2024 20:35:59 +0100 Subject: [PATCH 4/4] Refactor menu opening --- .../src/main/java/forge/screens/match/CMatchUI.java | 11 +++++++---- .../java/forge/screens/match/controllers/CField.java | 8 +++++++- .../util/PlayerControllerForTests.java | 3 +-- .../src/forge/screens/match/MatchController.java | 9 ++++++--- .../src/forge/screens/match/views/VAvatar.java | 8 ++++++++ .../gamemodes/match/input/InputPassPriority.java | 9 --------- .../java/forge/gamemodes/net/server/NetGuiGame.java | 7 ------- .../src/main/java/forge/gui/interfaces/IGuiGame.java | 4 ---- .../src/main/java/forge/player/HumanCostDecision.java | 3 --- 9 files changed, 29 insertions(+), 33 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 40cdb688e02..05459f6074b 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -19,6 +19,7 @@ import java.awt.*; import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; @@ -1523,8 +1524,11 @@ private void createLandPopupPanel(Card land) { } } - @Override - public void showFullControl(PlayerView pv, Set controlFlags) { + public void showFullControl(PlayerView pv, MouseEvent e) { + if (pv.isAI()) { + return; + } + Set controlFlags = getGameView().getGame().getPlayer(pv).getController().getFullControl(); final String lblFullControl = Localizer.getInstance().getMessage("lblFullControl"); final JPopupMenu menu = new JPopupMenu(lblFullControl); GuiUtils.addMenuItem(menu, lblFullControl, null, () -> { @@ -1537,8 +1541,7 @@ public void showFullControl(PlayerView pv, Set controlFlags) { addFullControlEntry(menu, "lblNoFreeCombatCostHandling", FullControlFlag.NoFreeCombatCostHandling, controlFlags); addFullControlEntry(menu, "lblAllowPaymentStartWithMissingResources", FullControlFlag.AllowPaymentStartWithMissingResources, controlFlags); - Component parent = view.getControl().getFieldViewFor(pv).getAvatarArea(); - menu.show(parent, parent.getX(), parent.getY()); + menu.show(view.getControl().getFieldViewFor(pv).getAvatarArea(), e.getX(), e.getY()); } private void addFullControlEntry(JPopupMenu menu, String label, FullControlFlag flag, Set controlFlags) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CField.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CField.java index 2bb49c8c518..554c14e2680 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CField.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CField.java @@ -22,6 +22,8 @@ import java.awt.event.MouseListener; import java.util.function.Function; +import javax.swing.SwingUtilities; + import forge.game.player.PlayerView; import forge.game.zone.ZoneType; import forge.gamemodes.match.input.Input; @@ -46,7 +48,11 @@ public class CField implements ICDoc { private final MouseListener madAvatar = new MouseAdapter() { @Override public void mousePressed(final MouseEvent e) { - matchUI.getGameController().selectPlayer(player, new MouseTriggerEvent(e)); + if (SwingUtilities.isRightMouseButton(e)) { + matchUI.showFullControl(player, e); + } else { + matchUI.getGameController().selectPlayer(player, new MouseTriggerEvent(e)); + } } }; 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 d0dfd52faf9..44686e6f731 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 @@ -789,7 +789,6 @@ public List chooseSpellAbilitiesForEffect(List spell @Override public List orderCosts(List costs) { - // TODO Auto-generated method stub - return null; + return costs; } } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 240c81035a1..98c255ffa60 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -744,8 +744,11 @@ public static HostedMatch getHostedMatch() { return hostedMatch; } - @Override - public void showFullControl(PlayerView selected, Set controlFlags) { + public void showFullControl(PlayerView selected, float x, float y) { + if (selected.isAI()) { + return; + } + Set controlFlags = getGameView().getGame().getPlayer(selected).getController().getFullControl(); FPopupMenu menu = new FPopupMenu() { @Override protected void buildMenu() { @@ -761,7 +764,7 @@ protected void buildMenu() { } }; - menu.show(getView(), getView().getPlayerPanel(selected).localToScreenX(0), getView().getPlayerPanel(selected).localToScreenY(0)); + menu.show(getView(), getView().getPlayerPanel(selected).localToScreenX(x), getView().getPlayerPanel(selected).localToScreenY(y)); } private FCheckBoxMenuItem getFullControlMenuEntry(String label, FullControlFlag flag, Set controlFlags) { diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java index ae087cf7180..424f0ccfddd 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java @@ -97,6 +97,7 @@ protected void onEnd(boolean endingAll) { player.setAvatarLifeDifference(0); } } + @Override public boolean tap(float x, float y, int count) { //must invoke in game thread in case a dialog needs to be shown @@ -104,6 +105,13 @@ public boolean tap(float x, float y, int count) { return true; } + @Override + public boolean longPress(float x, float y) { + //must invoke in game thread in case a dialog needs to be shown + ThreadUtil.invokeInGameThread(() -> MatchController.instance.showFullControl(player, x, y)); + return true; + } + public Vector2 getTargetingArrowOrigin() { Vector2 origin = new Vector2(this.screenPos.x, this.screenPos.y); origin.x += getWidth()-getWidth()/8f; diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java index 9ba01c81c5c..1de6e932620 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java @@ -20,7 +20,6 @@ import forge.game.Game; import forge.game.card.Card; import forge.game.player.Player; -import forge.game.player.PlayerController; import forge.game.player.actions.PassPriorityAction; import forge.game.spellability.SpellAbility; import forge.localinstance.properties.ForgePreferences.FPref; @@ -121,14 +120,6 @@ private void passPriority(final Runnable runnable) { public List getChosenSa() { return chosenSa; } - @Override - protected final void onPlayerSelected(Player selected, final ITriggerEvent triggerEvent) { - PlayerController pc = selected.getController(); - if (!pc.isAI()) { - getController().getGui().showFullControl(selected.getView(), pc.getFullControl()); - } - } - @Override protected boolean onCardSelected(final Card card, final List otherCardsToSelect, final ITriggerEvent triggerEvent) { //remove unplayable unless triggerEvent specified, in which case unplayable may be shown as disabled options diff --git a/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java index 9674c4023fd..04f0e1fa70b 100644 --- a/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/gamemodes/net/server/NetGuiGame.java @@ -9,7 +9,6 @@ import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; -import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbilityView; import forge.game.zone.ZoneType; @@ -26,7 +25,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Function; public class NetGuiGame extends AbstractGuiGame { @@ -321,9 +319,4 @@ protected void updateCurrentPlayer(final PlayerView player) { // TODO Auto-generated method stub } - @Override - public void showFullControl(PlayerView view, Set controlFlags) { - // TODO Auto-generated method stub - } - } diff --git a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java index b4899a77a7f..601bbb9b9cf 100644 --- a/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/gui/interfaces/IGuiGame.java @@ -12,7 +12,6 @@ import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; -import forge.game.player.PlayerController.FullControlFlag; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbilityView; import forge.game.zone.ZoneType; @@ -28,7 +27,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Function; public interface IGuiGame { @@ -275,6 +273,4 @@ public interface IGuiGame { void clearAutoYields(); void setCurrentPlayer(PlayerView player); - - void showFullControl(PlayerView view, Set controlFlags); } diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 91d3112402b..71834f72e7d 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -1316,9 +1316,6 @@ public PaymentDecision visit(final CostUntapType cost) { CardCollection typeList = CardLists.getValidCards(player.getGame().getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, source, ability); typeList = CardLists.filter(typeList, CardPredicates.TAPPED, c -> c.getCounters(CounterEnumType.STUN) == 0 || c.canRemoveCounters(CounterType.get(CounterEnumType.STUN))); - if (!cost.canUntapSource) { - typeList.remove(source); - } int c = cost.getAbilityAmount(ability); final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, c, c, typeList, ability); inp.setCancelAllowed(true);