diff options
| author | historia <[not public]> | 2026-09-17 22:00:33 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-17 22:00:33 -0400 |
| commit | 32a3c59cebf2a16277e54d715a67adfdbe00b456 (patch) | |
| tree | 9bc87011513ef92f0613d9339fc55689f130915d /internal/game/casino.go | |
| parent | fea2cc6839ec3ee17940a2dea69622dc6f4deabf (diff) | |
| download | thehouseoficarus-32a3c59cebf2a16277e54d715a67adfdbe00b456.tar.gz | |
fix: exact casino settlement/refund coverage, journal damage handling, craft output ordering, aggregate ingredient planning
Diffstat (limited to 'internal/game/casino.go')
| -rw-r--r-- | internal/game/casino.go | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/internal/game/casino.go b/internal/game/casino.go index 79d324a..133eb34 100644 --- a/internal/game/casino.go +++ b/internal/game/casino.go @@ -70,21 +70,32 @@ func (w casinoWallet) Wager(amount int) (casino.Wager, error) { // The record stays open as an outstanding stake until the round // resolves; recovery refunds open stakes after a crash. w.g.Economy.registerStake(rec) - return casino.Wager{Total: amount, Chips: chips, Credits: credits}, nil + return casino.Wager{Total: amount, Chips: chips, Credits: credits, ID: rec.ID}, nil } // PayCredits applies a payout durably. The journal record is written first; // if the save fails, the record stays open and startup recovery re-pays it // (the player is owed the settlement). func (w casinoWallet) PayCredits(amount int) error { - return w.payCreditsFlagged(amount, false) + return w.payCreditsFlagged(amount, false, nil) +} + +// PayStakeCover applies a settlement that INCLUDES the return of the listed +// stake wager IDs (a table hand pays its stake back inside the payout). The +// record is journaled with that linkage, so a shutdown refund never returns +// those stakes a second time; recovery re-applies the owed payout instead. +func (w casinoWallet) PayStakeCover(amount int, stakeIDs []string) error { + return w.payCreditsFlagged(amount, false, stakeIDs) } // payCreditsFlagged journals and applies a credit payout; a settlement // payout (refund=false) proves the round resolved during recovery, while a // refund payout (refund=true) marks a stake RETURNED at shutdown/eviction // (its chip part returns in chips, not through this credit payout). -func (w casinoWallet) payCreditsFlagged(amount int, refund bool) error { +// stakeIDs, when non-empty, records WHICH open stakes this settlement +// returns (table hands); empty means the payout resolves the round without +// a linked stake return (slots winnings). +func (w casinoWallet) payCreditsFlagged(amount int, refund bool, stakeIDs []string) error { if amount <= 0 { return nil } @@ -96,7 +107,7 @@ func (w casinoWallet) payCreditsFlagged(amount int, refund bool) error { // With the cap blocking, the balance is unchanged and the open record // keeps the owed amount durable; startup recovery re-applies it once // the balance has room below the cap. - rec, err := w.g.Economy.startKind("payout", refund, w.p, 0, amount, + rec, err := w.g.Economy.startKind("payout", refund, stakeIDs, w.p, 0, amount, creditsBefore, creditsAfter, chipsBefore, chipsBefore) if err != nil { // The journal is unavailable (persistent append failure). Last @@ -168,6 +179,15 @@ func (w casinoWallet) payCreditsFlagged(amount int, refund bool) error { // honors the resolution instead of refunding an already-resolved round. func (w casinoWallet) ResolveStakes() { unresolved := w.g.Economy.ResolveStakes(economyKey(w.p)) + w.recordResolutionEvidence(unresolved) +} + +// recordResolutionEvidence persists file-side resolution evidence for stake +// records whose settled markers could not be journaled. The character file +// then proves the round resolved even though the journal could not record +// its marker, so recovery still honors the resolution instead of refunding +// an already-resolved round. +func (w casinoWallet) recordResolutionEvidence(unresolved []*economyRecord) { if len(unresolved) == 0 { return } @@ -186,6 +206,18 @@ func (w casinoWallet) ResolveStakes() { } } +// ResolveStake settles ONE outstanding stake by wallet handle: the hand it +// belongs to was paid (its return is inside the settlement) or lost, so it +// must never be refunded. Unresolvable markers fall back to the same file- +// side evidence the bulk ResolveStakes uses. +func (w casinoWallet) ResolveStake(stakeID string) { + if stakeID == "" { + return + } + unresolved := w.g.Economy.ResolveStakeByID(economyKey(w.p), stakeID) + w.recordResolutionEvidence(unresolved) +} + // recordStakeEvidence adds every currently open stake of the player to the // file-side resolution evidence list and returns how many IDs were newly // recorded. Used when the economy journal is unavailable: the open wager @@ -207,8 +239,25 @@ func (w casinoWallet) recordStakeEvidence() int { // come back as chips, credits through the durable payout path. The stakes // are resolved only once the return is durable; on failure the chip return // is rolled back out of memory and the open records drive recovery instead. +// +// Stakes already accounted for by an open settlement payout are NOT +// refunded: a journaled table settlement includes its hand's stake return +// and recovery re-applies that owed payout, so refunding the stake here +// would pay the round twice (the returned credits then arrive on top of +// the stake). The stakes are resolved; their money arrives with the +// re-applied settlement. func (w casinoWallet) RefundOutstanding() (chips, credits int, err error) { for _, rec := range w.g.Economy.openStakes(economyKey(w.p)) { + if resolvedStakeRecorded(w.p, rec.ID) { + // Already resolved through file-side evidence: recovery + // settles it, never refunds it. + continue + } + if w.g.Economy.stakeCovered(rec) { + // The covering settlement is journaled and owed: resolving + // the stake defers its return to the payout re-application. + continue + } chips += rec.Chips credits += rec.Credit } @@ -227,7 +276,7 @@ func (w casinoWallet) RefundOutstanding() (chips, credits int, err error) { } } if credits > 0 { - if err := w.payCreditsFlagged(credits, true); err != nil { + if err := w.payCreditsFlagged(credits, true, nil); err != nil { if chips > 0 { // Roll the chip return back out of memory: the durable // refund will re-apply both amounts from the open records. |
