Skip to content

Expanded yield system / auto-pass options#9643

Closed
MostCromulent wants to merge 79 commits intoCard-Forge:masterfrom
MostCromulent:YieldRework
Closed

Expanded yield system / auto-pass options#9643
MostCromulent wants to merge 79 commits intoCard-Forge:masterfrom
MostCromulent:YieldRework

Conversation

@MostCromulent
Copy link
Copy Markdown
Contributor

@MostCromulent MostCromulent commented Jan 30, 2026

Screenshot 2026-04-17 165223 Screenshot 2026-04-17 165214

Summary

Inspired by recent discussion on the Forge Discord, this PR adds an expanded yield system to reduce click fatigue in multiplayer games and speed up play. Changes are extensively documented in Documentation. Fully backwards compatible with current functionality: the feature is disabled by default and must be explicitly enabled in preferences.

Problem

In multiplayer Magic games (3+ players), the current priority system requires excessive clicking:

  • Dozens of priority passes every turn in a 4-player game.
  • Players must manually pass priority even when they have no possible actions.
  • This creates click fatigue and slows down gameplay significantly (particularly if players are inattentive and don't immediately respond to prompts).

Solution

Expanded yield options that give players more flexibility to control yield timing and conditions. The aim is to help players spend less time responding to unnecessary priority prompts and let them get to their desired phase of action quicker:

Particularly helpful for that one friend who won't pay attention to priority prompts in Commander.

  • Yield Options Panel: Dockable panel with extended yield buttons and visual feedback (blue=ready, red=active)
  • Six Yield Modes: Next Phase, Before Combat, End Step, End Turn, Your Next Turn, Stack Clears
  • Smart Suggestions: Prompts to auto-yield when player cannot respond (no mana, no actions, can't respond to stack). Configurable through checkbox options in game taskbar menu.
  • Configurable Interrupts: Automatically cancels yield when attacked, targeted, mass removal cast, etc. Interrupt conditions are highly configurable through checkbox options in game taskbar menu.
  • F-Key Hotkeys: F1-F6 for yield modes, ESC to cancel.

Key Design Decisions

  • GUI-layer only: No changes to game engine or network protocol (Edit: though see comments below about network implementation to avoid desync).
  • Feature-gated: Default OFF, requires explicit enable + restart
  • Backward compatible: Existing Ctrl+E behavior unchanged when feature disabled

Testing

Changes have been tested in local play (thanks to PotionSTAT for testing and feedback). As changes are purely on the GUI layer and do not involve network logic, there is no reason to think testing would not replicate in network use cases. (Edit: see comments about network play below).


Code authored by Claude Code (Opus 4.5) under human direction and review.

MostCromulent and others added 15 commits January 28, 2026 19:52
Adds feature-gated yield options to reduce clicking in multiplayer games:
- 3 yield modes: Until Stack Clears, Until End of Turn, Until Your Next Turn
- Right-click End Turn button for yield menu
- Keyboard shortcuts (Ctrl+Shift+S, Ctrl+Shift+N)
- Smart yield suggestions when player can't respond
- Configurable interrupt conditions via Game menu
- Master toggle in preferences (default OFF)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add checkbox in Gameplay section (after Auto-Yield)
- Hide yield keyboard shortcuts when feature disabled
- Update description to cover all features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix yield not auto-passing: mayAutoPass() now delegates to
  shouldAutoYieldForPlayer() for experimental yield modes
- Fix keybind/menu not passing priority: added selectButtonOk()
  call after setting yield mode
- Fix re-prompting when already yielding: added getYieldMode()
  method and isAlreadyYielding() check
- Integrate suggestions into prompt UI instead of modal dialogs:
  suggestions now appear in prompt area with Accept/Decline buttons
- Fix "no actions" prompt not firing: hasAvailableActions() now
  checks actual playability via getAllPossibleAbilities() instead
  of just checking if hand is non-empty

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix interrupt conditions to only trigger when player is specifically
  attacked (using getAttackersOf instead of getDefenders.contains)
- Separate UNTIL_END_OF_TURN and UNTIL_YOUR_NEXT_TURN end conditions:
  - UNTIL_END_OF_TURN now clears on UNTAP phase of any new turn
  - UNTIL_YOUR_NEXT_TURN clears when player's turn starts
- Remove yieldTurnOwner/yieldTurnNumber tracking (simplified approach)
- Fix menu checkboxes to stay open when toggled

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents the yield system rework including:
- Feature overview and yield modes
- Smart yield suggestions
- Interrupt conditions (with multiplayer scoping)
- Technical implementation details
- Testing guide and changelog

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- End Turn button now uses experimental yield system when enabled
- Exclude triggered abilities from "opponent spell" interrupt
  (targeted triggers handled by "targeting" interrupt instead)
- Move Auto-Yields into Yield Options submenu when experimental enabled
- Track turn number for UNTIL_END_OF_TURN to respect phase stops
- Fix yield re-enable after interrupt (track turn on first check)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clarifies that all code was written by Claude AI under human instruction.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New features:
- UNTIL_BEFORE_COMBAT: Yield until entering combat phase (F3)
- UNTIL_END_STEP: Yield until end step phase (F4)
- Updated hotkeys: F1-F5 for yield modes, ESC to cancel yield

Bug fixes:
- UNTIL_STACK_CLEARS now checks simultaneous stack entries
- UNTIL_END_OF_TURN no longer interrupted by combat on own turn

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add turn/phase tracking for UNTIL_END_STEP yield mode (same pattern as combat)
- Add tracking for UNTIL_YOUR_NEXT_TURN to handle clicks during own turn
- Rename "End Turn" button to "Next Turn" for clarity
- Update tooltips to accurately describe yield behavior
- Update documentation to reflect new tracking logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-suppress declined suggestions until next turn with hint text
- Fix PlayerView instance matching in yield methods (map key bug)
- Add yield button priority over smart suggestions
- Extend reveal interrupt to cover opponent choices
- Disable yield buttons during cleanup/discard phase
- Add isBeingAttacked helper for planeswalker/battle attacks
- Change YIELD_INTERRUPT_ON_REVEAL default to false
- Update documentation with all changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new interrupt condition that triggers when an opponent casts a
mass removal spell (board wipes, exile all, etc.) that could affect
the player's permanents. Detects DestroyAll, ChangeZoneAll (with
exile/graveyard destination), DamageAll, and SacrificeAll effects.

Only interrupts if the player has permanents matching the spell's
ValidCards filter - empty board means no interrupt.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New Features:
- UNTIL_NEXT_PHASE yield mode that clears on any phase transition
- Dynamic hotkey display in tooltips and prompts based on user preferences
- Button layout reordered: Next Phase, Combat, End Step / End Turn, Your Turn, Clear Stack

Hotkey defaults (F1-F6):
- F1: Next Phase (new)
- F2: Combat
- F3: End Step
- F4: End Turn
- F5: Your Turn
- F6: Clear Stack

Files changed:
- YieldMode.java: Added UNTIL_NEXT_PHASE enum
- YieldController.java: Phase tracking, dynamic cancel key display
- VYield.java: New button, dynamic tooltip updates
- CYield.java: Action listener and highlight logic
- KeyboardShortcuts.java: New shortcut action
- ForgePreferences.java: New preference, reordered F-keys
- en-US.properties: Localization with {0} placeholders for hotkeys

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Applied 10 amendments to improve documentation quality:

CRITICAL FIXES:
1. Add missing YieldController.java to file lists and architecture
   - YieldController is a core component that was completely missing
   - Updated "New Files" section from 3 to 4 files

2. Add comprehensive Architecture section
   - Component hierarchy diagram showing GUI layer organization
   - Detailed explanation of YieldController, AbstractGuiGame interaction
   - Network independence architecture with multi-player scenarios
   - Complete data flow diagrams for all yield operations
   - File organization with clear component responsibilities

MODERATE IMPROVEMENTS:
3. Expand State Management section with delegation pattern
   - Show AbstractGuiGame's lazy initialization of YieldController
   - Document YieldCallback interface implementation
   - Add complete state map documentation from YieldController
   - Include mode-specific end condition table

4. Correct Modified Files count and descriptions
   - Updated from 14 to 13 files (removed EDocID, FButton, ProtocolMethod)
   - Improved descriptions to match actual implementation
   - Clarified that network protocol has no yield-specific changes

MINOR ENHANCEMENTS:
5. Clarify Yield Options Panel button layout
   - Document 2-row layout structure
   - Add visual feedback section
   - Note cleanup/discard phase button disabling

6. Add PlayerView lookup technical detail
   - Document TrackableTypes.PlayerViewType.lookup() usage
   - Explain Map key consistency requirement

7. Expand Smart Yield Suggestions section
   - Add preference names for each suggestion type
   - Document auto-suppression behavior in detail
   - Clarify when suggestions appear vs. don't appear
   - Explain yield button priority over suggestions

8. Add Initial Implementation changelog entry
   - Document YieldController architecture rationale
   - Explain delegate and callback pattern choices
   - Note lazy initialization strategy

9. Fix typo: Make "disabled" bold for clarity in interrupt section

10. Add comprehensive Troubleshooting section
    - Yield activation issues
    - Unexpected yield clearing
    - Smart suggestion behavior
    - Network play expectations
    - Performance considerations

The documentation now accurately reflects the codebase implementation,
includes the requested Architecture section explaining component
interactions, and provides helpful troubleshooting guidance for users.

https://claude.ai/code/session_01SBGxSAqnqbpVuEsinNtrnZ
…-OorXS

Comprehensively update DOCUMENTATION.md for accuracy and completeness
DOCUMENTATION.md now contains all PR documentation, making the
separate .documentation/YieldRework-PR.md file redundant.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment thread DOCUMENTATION.md Outdated
Comment thread forge-gui/src/main/java/forge/gamemodes/match/input/InputPassPriority.java Outdated
MostCromulent and others added 3 commits January 31, 2026 06:53
The yield interrupt for "targeted by spell or ability" was not
triggering for Oona, Queen of the Fae's ability because the targeting
is in a sub-ability (DB$ Dig), not the main ability (AB$ ChooseColor).

Modified targetsPlayerOrPermanents() to recursively check sub-instances
via getSubInstance(), ensuring targeting in nested sub-abilities is
properly detected.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Per PR review feedback from tool4ever: hasAvailableActions was identical
to canRespondToStack. Removed the duplicate and reuse canRespondToStack
in shouldShowNoActionsPrompt.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactored YieldController to use network-safe GameView properties
instead of gameView.getGame() which returns an unsynchronized dummy
object for network clients.

- Use gameView.getPhase/getTurn/getPlayerTurn/getStack/getCombat
- Use CombatView and StackItemView instead of direct Game access
- Added StackItemView.getApiType() for mass removal detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@MostCromulent
Copy link
Copy Markdown
Contributor Author

MostCromulent commented Jan 30, 2026

Testing by PotionSTAT has revealed an issue with network play integration not realised before PR.

YieldController was using gameView.getGame() which returns an unsynchronized dummy object for network clients. Have refactored to use network-safe GameView properties and added StackItemView.getApiType() for mass removal detection. Will also check implications for smart prompts.

@MostCromulent
Copy link
Copy Markdown
Contributor Author

MostCromulent commented Jan 30, 2026

Re: Network Code Changes

While the yield system was designed to avoid network protocol changes, in testing discovered that smart suggestions in InputPassPriority had a network compatibility issue requiring new TrackableProperties. This is because the logic was checking the Game object on the server which doesn't exist on network clients.

The solution: Add two TrackableProperties (HasAvailableActions, WillLoseManaAtEndOfPhase) to PlayerView. These piggyback on existing GameView serialization—no protocol changes required. The host calculates these values and they're automatically included when GameView is sent to clients.

The yield system remains client-local; this ensures the data for yield suggestions is synchronized, while yield decisions stay independent per client.

The alternative to making these network changes would have been implementing a more basic heuristic for the yield prompts which would have been a worse and experience for the player.

Edit: Claude AI's explanation for why server needs to know client yield mode state

The server needs to track the client's yield mode to detect end conditions because the client doesn't have access to the same context as the server, which has the authoritative game state and can reliably detect when yield end conditions are met across all players.

When client activates a yield mode it uses notifyYieldModeChanged to notify the server. The server then monitors game state and checks yield end conditions in YieldController.java. When end condition is met the server calls clearYieldMode() which triggers syncYieldModeToClient() to notify the client.

Both server and client stay in sync about yield state. If only the client tracked it, multiplayer edge cases could cause the client to yield too long or not long enough.

MostCromulent and others added 4 commits January 31, 2026 10:18
- Add HasAvailableActions and WillLoseManaAtEndOfPhase TrackableProperties
- Refactor InputPassPriority to use PlayerView/GameView instead of transient Game
- Fix suggestions appearing immediately after yield ends (yieldJustEnded tracking)
- Fix wrong yield mode when clicking yield buttons (legacy set interference)
- Add PlayerView lookup to autoPassUntilEndOfTurn/autoPassCancel methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add setYieldModeSilent() to break infinite recursion when syncing
  yield state between server and client (stack overflow fix)
- Fix getPlayerView() in InputPassPriority to use network-synchronized
  PlayerView from GameView instead of local Player object
- Enhance hasAvailableActions() to actually check mana availability
  using heuristic (CostPartMana.canPay() always returns true)
- Smart suggestions now correctly trigger when player has cards but
  can't afford any spells

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ayout

- Add populate() calls to SLayoutIO.openLayout() and revertLayout() after
  loading completes, following the pattern used in FControl.setCurrentScreen()
- This fixes yield panel not reappearing after View > Refresh Layout or
  Layout > Open operations
- Incidentally fixes the same issue for other dynamic panels (dev mode, etc.)
- Add stale parent cell detection in VMatchUI to handle layout refresh
- In 2-player games, move Clear Stack button to middle position since
  Your Turn button is not shown (only relevant for 3+ player games)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create user-facing documentation for the experimental yield system:
- Yield modes and their end conditions
- Access methods (panel, right-click menu, keyboard shortcuts)
- Smart yield suggestions
- Configurable interrupt conditions
- Troubleshooting guide

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment thread forge-game/src/main/java/forge/game/player/Player.java Outdated

private PlayerView getPlayerView() {
return getController().getPlayer().getView();
// For network clients, we need to get the PlayerView from the GameView
Copy link
Copy Markdown
Contributor

@tool4ever tool4ever Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to investigate this, seems rather hacky

  • but if it's needed it should reuse lookupPlayerViewById

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll address the duplicate function issue now, and can come back to this if you find a better approach.

Move lookupPlayerViewById to IGuiGame interface and reuse in
InputPassPriority instead of duplicating the ID-based lookup logic.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment thread forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java Outdated
Comment thread forge-gui/src/main/java/forge/gamemodes/match/YieldController.java Outdated
MostCromulent and others added 3 commits April 26, 2026 07:54
YieldController's per-game state (legacy autoPassUntilEndOfTurn and
experimental yieldStates) persisted across games. Losing a game while
auto-passing carried the state into the next game, skipping all the
player's turns.

AbstractGuiGame.setGameView(null) — already the reset hook used by
HostedMatch.startGame between games — now also clears the YieldController.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the user has both APINA ("auto-pass with no actions") on and an
active yield mode like "Pass until end step", mayAutoPass short-circuits
on APINA before shouldAutoYieldForPlayer ever runs — but that function
is where the mode's stop-point self-clear logic lives. The mode
persisted indefinitely, auto-passing through the user's intended stop
point turn after turn.

Run shouldAutoYieldForPlayer first so stop conditions get a chance to
fire. The redundant autoPassUntilEndOfTurn check is dropped — it's
already handled inside shouldAutoYieldForPlayer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts:
#	forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java
@autumnmyst
Copy link
Copy Markdown
Contributor

  1. HasAvailableActions only updates when APINA is on, but the yield suggestions need that value updated even when not autopassing
  2. I'm noticing that when turning autopass OFF -> ON it passes once even if the player has actions, much like if the player pressed "Ok." Is this the desired behavior? It seems it could lead to frustration if they only meant to turn the toggle on for later.

Comment thread forge-gui/src/main/java/forge/player/PlayerControllerHuman.java Outdated
Comment thread forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
Drop the APINA clause from the gate: hasAvailableActions also
feeds InputPassPriority's smart-suggestion path (gated on
YIELD_DECLINE_SCOPE_*, defaults non-"never"), so with APINA off
the scan never ran and suggestions read stale data.

Add a !shouldAutoYieldForPlayer gate so the scan is skipped when
an active yield mode is going to make mayAutoPass() short-circuit
on its result. Interrupts still trigger the scan because
shouldAutoYieldForPlayer clears the mode and returns false in
that case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@MostCromulent
Copy link
Copy Markdown
Contributor Author

MostCromulent commented Apr 26, 2026

2. I'm noticing that when turning autopass OFF -> ON it passes once even if the player has actions, much like if the player pressed "Ok." Is this the desired behavior? It seems it could lead to frustration if they only meant to turn the toggle on for later.

This is intentional, but I'm open-minded on whether it's best UI design.

Basic idea is that if user is activating auto-pass on their priority it indicates they want to yield. This is same reason activating always-yes or always-no on a stack trigger doesn't just silently toggle the preference, it also applies it and passes priority at the same time.

The alternative has its downsides too. If you activate auto-pass after already receiving priority it can't recalculate APINA (or at least when I looked into this it would have resulted in some very messy code which wasn't worth it) - so you have situation where you activate auto-pass, you may have no actions available, but it just sits there leaving you with priority. That's probably even more confusing.

@mermerico
Copy link
Copy Markdown

I love this PR but I found the settings a bit confusing. Here was my effort to reorganize. Let me know what you think and I can upload a patchset.

image image image image

@autumnmyst
Copy link
Copy Markdown
Contributor

@mermerico my concern here is that “intelligent” and “advanced” aren’t mutually exclusive. Often times you will sit with autopass on but then might draw an instant you don’t intend to play immediately, and will then use the yield options to pass forward to a certain point (while having interrupts to stop that yielding), all the while keeping autopass on. For legacy behavior everything is behind a flag in preferences and, if using this system, I wonder how necessary having a legacy setting is since you would just flip the flag (end turn + auto yields still work like how they do in current forge regardless)

Replace the YieldMode enum and the dedicated phase-mode buttons (Combat,
End Step, End Turn, Your Turn, Before Your Turn, Next Phase) with a
single (player, phase) yield marker. Right-click any phase indicator on
desktop, or long-press on mobile, to set a fast-forward marker that
auto-passes priority until the marked phase is reached and then clears.
Markers are per-(player, phase), so an opponent's End Step is distinct
from your own End Step.

The Yield panel collapses to Auto-Pass + Settings; F3-F9 shortcuts and
their preferences are removed. Mobile gains feature parity via two new
pref-gated entries in the in-match Game menu (Yield Options dialog,
Auto-Pass: ON/OFF). The mobile Yield Options dialog is scrollable with a
settings-menu-style layout (gradient section bars, generous row padding).
Stack-yield is reachable only via the existing "Can't respond to stack"
smart suggestion - no manual button on either platform.

Network protocol replaces setYieldMode/syncYieldMode with
setYieldMarker/clearYieldMarker/setStackYield/syncYieldMarkerCleared.
NetGameController delegates yield reads to the local YieldController so
client-side reads see server-driven auto-clears.

Speed Settings: a new section in the Yield Settings dialog adds two
checkboxes that skip the cosmetic phase / stack-resolve delays inserted
by the auto-pass scheduler. Cherry-picked from upstream commit 42a6edb
by Autumn Wind (autumnmyst).

Wiki doc rewritten for the new UX.

Co-Authored-By: Autumn Wind <209156905+autumnmyst@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
autumnmyst added a commit to autumnmyst/forge that referenced this pull request Apr 27, 2026
Squash of PR Card-Forge#9643 (YieldRework) at 9a1b18c.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@autumnmyst
Copy link
Copy Markdown
Contributor

The right-click yields are really cool. Just a couple suggestions:

  1. Have some way to yield just the stack (the suggestions are good, but won't appear if you can respond). Maybe right-clicking the current phase with a non-empty stack could just yield that stack and nothing else, but right clicking current phase with empty stack yields everything until that phase comes around again (like it does currently)?
    [A really advanced version of this could let you right click a spell/ability on the stack, and yield to specifically that spell/ability, but you would need to deal with those objects getting deleted/manipulated which could get messy, so unless it's trivial probably save for later PR.]

  2. Have a checkbox at the bottom of yield interrupts for "Autopass respects interrupts" (unchecked by default). From playing a few games, I'm noticing it's exceedingly rare that I want to actually hold prio when I have no actions (honestly I haven't found a single reason to do so against the computer, since there's no point in bluffing counterspells etc.). I'm finding that interrupts are mainly used for stopping the fast-forward, since I might have an instant I want to cast only in case of an interrupt. However, if I don't have anything, autopass respecting interrupts means it stops me on all my interrupts even if I couldn't do anything about it. I'm suggesting leaving this unchecked by default since (from my experience) the only reason to hold when you have nothing is: 1. if things are playing out too quickly to follow (in which case you could also just turn off autopass / turn on resolve delay) 2. To bluff a counterspell in multiplayer. Both of these I'd consider extenuating enough circumstances to warrant opening the menu and checking the box.

MostCromulent and others added 2 commits April 28, 2026 06:54
Adds a one-shot "Yield to entire stack" entry to the stack item menu on
both desktop and mobile. Activates the existing stack-yield mode and
passes priority immediately, so the stack resolves without further
prompts until empty.

Available for both abilities and spells: the menu's ability-only items
(auto-yield, always yes/no) stay gated as before; the new entry sits
below them. On mobile the entry uses the standard yield warning icon,
matching the Auto-Yields and Auto-Pass entries in VGameMenu.

Gated on YIELD_EXPERIMENTAL_OPTIONS — when off, behavior is unchanged:
abilities show the prior menu, spells fall through to direct CardZoom
(mobile) / no-op (desktop).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds YIELD_AUTO_PASS_RESPECTS_INTERRUPTS (default false). When unchecked,
the no-actions auto-pass no longer halts on interrupt conditions
(attackers, targeting, mass removal, etc.) — the player has nothing to
respond with, so stopping is just a "press OK to continue" with no
decision attached.

Interrupts still apply to active yield modes (auto-yield, phase markers,
stack yield) — those clear on interrupt regardless of this pref, since
there the player presumably wants to be informed.

UI: new checkbox at the bottom of the Yield Interrupts section in both
VYieldSettings (desktop) and VYieldOptions (mobile). Synced per-player
via the existing setYieldInterruptPref protocol.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RafaelHGOliveira added a commit to RafaelHGOliveira/forge that referenced this pull request Apr 27, 2026
@MostCromulent
Copy link
Copy Markdown
Contributor Author

MostCromulent commented Apr 27, 2026

The right-click yields are really cool. Just a couple suggestions:

@autumnmyst both implemented. 👍

Conflicts resolved:
- IGameController, ProtocolMethod: keep yield interface/protocol entries
  alongside upstream's new setUiShouldSkipPhase
- PlayerControllerHuman: switch to upstream's cached isUiSetToSkipPhase
  while preserving the YIELD_SKIP_PHASE_DELAY guard
- PhaseLabel (desktop), VPhaseIndicator (mobile): keep both yieldMarked
  state and upstream's onToggled callback fields/methods

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@autumnmyst
Copy link
Copy Markdown
Contributor

I found and fixed a small bug as well as moving interrupts to being event-driven. I figured since I'd already implemented a fix I would just make a PR into your branch: MostCromulent#18

Comment thread forge-gui/src/main/java/forge/gamemodes/net/ProtocolMethod.java Outdated
return;
}
} else {
// Yield mode (EOT, next turn, etc.) — intentionally skip attackers
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the legality check was removed
this seems wrong

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about the old auto pass cancel:
do we feel it's now more desired to keep passing even if we had to declare attackers...?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think you're right: once the interrupt fires we want to cancel the yield. If the user has APINA enabled then it can take care of things from there.

declareAttackers: the 10/04 APINA/yield-mode split dropped validateAttackers(combat)
from the yield-mode branch. Without it, must-attack effects (Goad, "attacks each combat
if able") spin PhaseHandler.declareAttackersTurnBasedAction's retry loop — it re-validates
after declareAttackers returns and loops on failure. Restored. APINA branch unchanged.

ProtocolMethod: replaced fully-qualified ForgePreferences.FPref reference with a normal import.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread forge-gui/src/main/java/forge/gamemodes/net/ProtocolMethod.java
@MostCromulent
Copy link
Copy Markdown
Contributor Author

MostCromulent commented May 4, 2026

Closing this PR - replaced by #10606.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Netplay QOL Quality of Life

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto Yield does not work in multiplayer

7 participants