Route opponent-hand reveal and discard through FloatingZone on desktop#10660
Route opponent-hand reveal and discard through FloatingZone on desktop#10660MostCromulent wants to merge 5 commits into
Conversation
…on desktop For RevealYouChoose / LookYouChoose discards (Inquisition, Thoughtseize, etc.) on desktop, present the opponent's hand visually in the FloatingZone instead of a names-list dialog: - Reveal step: replace getGui().reveal() (names list) with tempShowZones plus a minimal OK dialog. The actual cards are visible in the FloatingZone; the dialog just blocks until the user acknowledges. - Pick step: route through InputSelectCardsFromList so the user clicks legal targets directly in the FloatingZone. tempShow the full hand for Reveal/Look modes without RevealNumber so non-selectable revealed cards remain visible; for RevealNumber spells (Blackmail, Cabal Interrogator, etc.) the path is unchanged so unrevealed cards stay hidden. Both halves gate on UI_SELECT_FROM_CARD_DISPLAYS && !isLibgdxPort() -- the same condition useSelectCardsInput already uses. Mobile and the preference-off path keep the existing dialog flow. Also fix CMatchUI.hideZones to mirror tempShowZones' Hand handling -- the show side opens the FloatingZone for an opponent's Hand, but the hide side only checked FLOATING_ZONE_TYPES (which omits Hand), so the FloatingZone never closed programmatically after the prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Let me know if you want the |
|
I think in general this seems better:
the only minor downside remaining is no longer being able to use the keyboard to progress:
what if we (temporarily) assign the number keys to the first 9 selectables? might have to draw small labels on them for clearity or something - maybe based on Ctrl press 🤔 (there's actually one place in |
yeah I'll try that out - might also look at how seamlessly we could integrate a search filter at the top as well, since we also lose that compared being able to start typing in the previous list view |
Adds a name-search field at the top of FloatingZone and Ctrl+1-9 hotkeys for the first nine selectable cards during an active selection prompt. Numbered badges render on those cards and a small hint footer surfaces the shortcut. Also fixes CMatchUI.updateCards so opponent-hand FloatingZones refresh on highlight changes — previously only the local VHand was covered. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| if (!fz.isVisible()) continue; | ||
| final CardPanel target = fz.findPanelByHotkeyDigit(digit); | ||
| if (target == null) continue; | ||
| fz.getMatchUI().getGameController().selectCard(target.getCard(), null, |
There was a problem hiding this comment.
I wonder if we could use 0 to just select the first X minimum needed to proceed
but might be too tricky to obtain here...?
There was a problem hiding this comment.
Looks like this shouldn't be too hard but would require small protocol change.
Currently InputSelectCardsFromList doesn't broadcast the min/max amount to network clients, it just waits to receive the choice. Would need to add that to the protocol. This is what happens with list dialogs already so there's precedent for it.
Changes involved:
1. IGuiGame.java — new interface method
void setSelectionRange(int min, int max);
Placed next to setSelectables(...).
2. AbstractGuiGame.java — base impl (all concrete GUIs inherit it: CMatchUI, MatchController mobile, RemoteClientGuiGame,
HeadlessNetworkGuiGame)
private int selectionMin = 0, selectionMax = 0;
public void setSelectionRange(int min, int max) { selectionMin = min; selectionMax = max; }
public int getSelectionMin() { return selectionMin; }
// inside clearSelectables():
selectionMin = 0; selectionMax = 0;
3. ProtocolMethod.java — register for the wire
setSelectionRange (Mode.SERVER, Void.TYPE, Integer.TYPE, Integer.TYPE),
4. InputSelectEntitiesFromList.java — publish min/max when a selection starts
getController().getGui().setSelectables(vCards);
getController().getGui().setSelectionRange(min, max); // new
5. FloatingZone.java — new Ctrl+0 branch in dispatchHotkey
if (digit == 0) {
final int need = fz.getMatchUI().getSelectionMin();
if (need < 1) return false;
int picked = 0;
for (final CardPanel panel : fz.getCardPanels()) {
if (picked >= need) break;
if (!fz.getMatchUI().isSelectable(panel.getCard())) continue;
fz.getMatchUI().getGameController().selectCard(panel.getCard(), null,
new MouseTriggerEvent(MouseEvent.BUTTON1, 0, 0));
picked++;
}
return true;
}
(Logic folded into the existing digit block — we'd just relax the digit < 1 lower bound.)
hmn I'm undecided if users might prefer having the preference actually GUI-exposed now that this PR increases its usage 🤔 |
| // Reveal/Look modes (no RevealNumber) publicly disclose the full hand — keep non-selectable revealed cards visible | ||
| final String discardMode = sa.getParam("Mode"); | ||
| final boolean fullHandRevealedToChooser = discardMode != null | ||
| && !sa.hasParam("RevealNumber") | ||
| && (discardMode.startsWith("Reveal") || discardMode.startsWith("Look")); |
There was a problem hiding this comment.
Could the reveal-full-hand flag be a parameter computed at the call site? A while ago I was trying to cut back on the number of places where the PlayerController has to dissect a SpellAbility in order to decide how to behave. Looks like only DiscardEffect would need it - BalanceEffect and ConniveEffect both only use the player's own hand.
When the local player is picking cards from a revealed opponent zone (e.g. Mind Warp, Coercion), the FloatingZone now renders the current prompt at the top of the window so the player doesn't have to glance back to the main prompt panel while deciding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PlayerController.chooseCardsToDiscardFrom now takes the collection of cards the chooser is allowed to see, rather than letting the controller inspect the SpellAbility to decide visibility — addressing reviewer feedback to stop dissecting SpellAbilities inside the controller. DiscardEffect (the only caller that reveals extra cards) computes the visible set at the call site; a 5-arg convenience overload keeps BalanceEffect/ConniveEffect untouched. Incidentally fixes a case where, with RevealNumber set and a DiscardValid filter, revealed-but-invalid cards would vanish from the chooser's UI even though the reveal had publicly disclosed them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>



USING MIND WARP, X=2
BEFORE:


Reveal step
Select step
AFTER:


Reveal step
Select step
Summary
Per #10646 (comment):
RevealYouChoose/LookYouChoosediscards (Inquisition, Mind Warp, etc.) currently surface as a names-list reveal dialog followed by a separate selection grid, when the opponent's hand could be the selection UI directly.This routes both steps through the existing FloatingZone: reveal opens the hand face-up with a minimal OK acknowledgement; the pick uses
InputSelectCardsFromListso legal targets are clicked in that same FloatingZone.Implementation
PlayerControllerHuman.reveal()— desktop opponent-hand reveals swapgetGui().reveal()(names list) fortempShowZones+getGui().message()(visual hand + minimal OK).PlayerControllerHuman.chooseCardsToDiscardFrom()— opponent-discard pick routes throughInputSelectCardsFromList; tempShows the full hand forReveal*/Look*modes withoutRevealNumberso revealed non-selectable cards stay visible.RevealNumberspells (Blackmail, Cabal Interrogator) keep the conservative tempShow-of-valid path so unrevealed cards stay face-down.CMatchUI.hideZones()— fix a pre-existing asymmetry:tempShowZonesspecial-casesZoneType.Hand, buthideZonesonly checkedFLOATING_ZONE_TYPES(which omits Hand). The FloatingZone opens for an opponent's hand but never closed programmatically.Safety
Both PCH changes gate on
UI_SELECT_FROM_CARD_DISPLAYS && !getGui().isLibgdxPort()— the same conditionuseSelectCardsInputalready uses. Mobile and preference-off paths are unchanged.isLibgdxPort()is the per-GUI network-safe check from #10615. No engine, protocol, orTrackablePropertychanges.RevealNumberpartial-reveal spells (e.g. Blackmail revealing 3 of 5) are rendered safely:FloatingZone.getCards()returns all hand cards, but each is drawn according to the existingmayViewcheck — onlymayLookTemp-flagged cards (the revealed subset) show their faces, the rest render as card backs. Non-revealed cards' identities stay hidden; only hand size is conveyed, which is already public info.Potential code cleanup (not in this PR)
FPref.UI_SELECT_FROM_CARD_DISPLAYSwas added in 2019 (commit09fc3ae60c2) alongside the originalarrangeForScryGUI introduction, which brought in-zone selection as a new UX. The preference has defaulted totruewith no user-facing UI toggle ever since — effectively the active desktop UI path for 7+ years.The preference gates whether
InputSelectextends beyond the local player's own hand and battlefield to other zones (opponent-hand FloatingZone, libraries, graveyards, etc.) — i.e. click a card in its zone display versus fall back to a names-list dialog. All three desktop call sites inPlayerControllerHumanpair it with!getGui().isLibgdxPort().A separate cleanup PR could drop the
FPrefentry, simplify the three dual-gate sites to single!isLibgdxPort()checks, and collapse the now-dead fallback branches inuseSelectCardsInput(the zone-set ternary) andarrangeForScry(the manual-order path).🤖 Generated with Claude Code