From 9666676766bf21364f4fc4d0d1d336e72f2a91b4 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 6 Oct 2026 12:57:23 -0400 Subject: refactor: split casino.go, dedup helpers, remove audit docs --- internal/combat/state.go | 7 +++++++ internal/combat/state_test.go | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'internal/combat') diff --git a/internal/combat/state.go b/internal/combat/state.go index e1ee8e7..17a9c09 100644 --- a/internal/combat/state.go +++ b/internal/combat/state.go @@ -36,6 +36,13 @@ func (t *Tracker) Enter(playerName, mobID string) { if prev, ok := t.combatants[playerName]; ok { delete(t.mobTargets, prev.MobID) } + // If another player already holds this mob, replacing the mobTargets + // entry would leave their combatants entry pointing at a mob this new + // player now owns. Clear it so their later Leave cannot delete this + // player's claim and unlock a mob that is still being fought. + if prevOwner, ok := t.mobTargets[mobID]; ok && prevOwner != playerName { + delete(t.combatants, prevOwner) + } t.combatants[playerName] = &State{ PlayerName: playerName, MobID: mobID, diff --git a/internal/combat/state_test.go b/internal/combat/state_test.go index 8005ba3..d21bc0d 100644 --- a/internal/combat/state_test.go +++ b/internal/combat/state_test.go @@ -19,3 +19,23 @@ func TestTrackerEnterReleasesPreviousMob(t *testing.T) { t.Fatal("mobB still marked in combat after leave") } } + +// Regression: two players claiming the same mob must not leave a dangling +// combatants entry for the displaced player; otherwise that player's later +// Leave deletes the new owner's mobTargets claim and unlocks a live fight. +func TestTrackerEnterDisplacesOtherPlayer(t *testing.T) { + tr := NewTracker() + tr.Enter("alice", "mobA") + tr.Enter("bob", "mobA") + if !tr.IsMobInCombat("mobA") { + t.Fatal("mobA should still be in combat after the second claim") + } + if tr.MobTarget("mobA") != "bob" { + t.Fatalf("mobTarget = %q, want bob", tr.MobTarget("mobA")) + } + // Alice was displaced; her leave must not unlock Bob's fight. + tr.Leave("alice") + if !tr.IsMobInCombat("mobA") || tr.MobTarget("mobA") != "bob" { + t.Fatal("alice's leave unlocked the mob bob is still fighting") + } +} -- cgit v1.2.3