-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
AssignDamageReq (GRE type 30) is never sent. Combat damage is auto-distributed by the engine. The player can't choose how to split damage across multiple blockers — trample, deathtouch+trample, and asymmetric block scenarios all resolve without player input.
This is a functional gap, not cosmetic — it changes game outcomes.
Pointers
- Proto:
AssignDamageReq,AssignDamageResp,AssignDamageConfirmation,DamageAssigner,DamageAssignmentinmessages.proto - Arena-notes:
docs/combat-flow.md— full wire sequence including Phase 3 (assign damage), sub-message field tables, ResultCode enum - Arena-notes:
docs/request-dispatch-table.md— AssignDamageRequest client class shape - Recordings: protocol examples exist (scan with
just tape proto decode-recordingforAssignDamageReqgreType) - Existing combat code:
MatchSessionalready handles DeclareAttackers/Blockers with two-phase pattern. AssignDamage is single-phase (Req → Resp → Confirmation) - Bridge: check how Forge currently resolves combat damage in
WebPlayerController— that's where the engine blocks waiting for assignment
Wire sequence (from arena-notes combat-flow.md)
SERVER → CLIENT: AssignDamageReq (repeated DamageAssigner)
CLIENT → SERVER: AssignDamageResp (same DamageAssigner with assignedDamage filled)
SERVER → CLIENT: AssignDamageConfirmation (ResultCode)
Single-phase — no iterative update loop like attackers/blockers.
Key proto shape
DamageAssigner: one per attacking creature that needs assignment. Contains totalDamage (power), canIgnoreBlockers (trample flag), and repeated DamageAssignment slots with minDamage/maxDamage bounds per recipient. Client fills assignedDamage on each slot and sends back.
Constraints
- Auto-distribution should remain the default — only send AssignDamageReq when damage assignment is genuinely ambiguous (multiple blockers, trample)
- Must work for both seats:
MatchSessionhandles human player,FamiliarSessionshould auto-resolve (assign min to each, remainder to last/player) - Follows the existing combat handler pattern — wire it in
MatchHandlerdispatch alongside DeclareAttackers/Blockers
Open questions (for scoping agent to resolve)
- Auto-assign setting: Arena has an "auto-assign combat damage" checkbox. Is this purely client-side (client auto-fills AssignDamageResp) or does the server skip AssignDamageReq when the setting is active? Check
SettingsMessagefields and recording patterns for correlation. - OrderReq for blocker ordering: When an attacker is blocked by multiple creatures, the real server sends
OrderReq(GRE type 17) beforeAssignDamageReqto let the player order damage recipients. Is this needed for correctness or does Forge handle ordering internally? - Forge bridge surface: How does
WebPlayerControllercurrently intercept the damage assignment decision? Is there an existing prompt/override point, or does it need a newCompletableFuturebridge?
Scope
In: AssignDamageReq/Resp/Confirmation GRE handshake. Building and sending the request when assignment is ambiguous. Handling the response and submitting to engine.
Out: Damage prevention/redirection, replacement effects on damage, first-strike-specific edge cases (those are separate systems). OrderReq for blocker ordering can be a follow-up.
References
docs/systems-map.md— Tier 2 gapdocs/catalog.yaml— combat damage section