aboutsummaryrefslogtreecommitdiff
path: root/internal/casino/core.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/casino/core.go')
-rw-r--r--internal/casino/core.go34
1 files changed, 34 insertions, 0 deletions
diff --git a/internal/casino/core.go b/internal/casino/core.go
index 85a5e28..a0ac1c8 100644
--- a/internal/casino/core.go
+++ b/internal/casino/core.go
@@ -127,6 +127,40 @@ func (c *tableCore[P]) refundAllLocked() []Event {
return events
}
+// settleStakeOutcome applies one wager's outcome through the wallet and
+// reports whether the settlement could NOT be made durable. It carries the
+// money-critical ordering shared by every table game (documented in
+// building_guide/concurrency.md): compute the payout, pay it via
+// PayStakeCover BEFORE announcing the win, and only then resolve the stakes
+// the settlement returned. On a persistence failure the stakes are left open
+// so recovery re-applies the owed payout and a shutdown refund never returns
+// them a second time; the caller must not announce a paid win and must not
+// run the player-wide ResolveStakes.
+//
+// payoutErr is a payout-computation error (for example an overflowed
+// multiplier): it is treated exactly like a persistence failure so a
+// clamped or absurd amount is never paid. A nil wallet (test scaffolding)
+// resolves the stakes in memory only.
+func settleStakeOutcome(w Wallet, payout int, stakeIDs []string, payoutErr error) (failed bool) {
+ if payoutErr != nil {
+ return true
+ }
+ if w == nil {
+ return false
+ }
+ if payout > 0 {
+ if err := w.PayStakeCover(payout, stakeIDs); err != nil {
+ return true
+ }
+ }
+ for _, id := range stakeIDs {
+ if id != "" {
+ w.ResolveStake(id)
+ }
+ }
+ return false
+}
+
// gameTitle renders a configured game name as a message heading.
func gameTitle(game GameName) string {
name := string(game)