fix: beacon follows the owner's newest bag; older bags never clear it

Dying again mid corpse-run drops a second bag (old + new coexist in the world,
each on its own 5-minute timer) and re-points the owner's beacon at the new
one. Previously the OLDER bag's later despawn/looting fired the unscoped
beacon-clear and wiped the beam pointing at the newer bag. LootBags now tracks
each owner's latest bag and only its destruction clears the beacon.

docs/loot-bags.md: documented the multi-bag + beacon-follows-newest behavior.

Live-verified: two coexisting bags, beacon on the newest; looting the OLD bag
left the beacon untouched; looting the NEW bag cleared it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Samuel Lison
2026-07-06 15:38:26 +10:00
co-authored by Claude Opus 4.8
parent f6a26ddd30
commit 44c0f8e25c
3 changed files with 28 additions and 4 deletions
+7
View File
@@ -5,6 +5,13 @@ All notable changes to SurvivorCore are recorded here. The format follows
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). At release time, `## Unreleased`
is promoted to the new version and `main` is tagged `vX.Y.Z`.
## Unreleased
### Fixed
- **Beacon scoped to the newest bag** — dying again mid corpse-run re-points the owner's beacon at
the new bag (old and new bags coexist, each on its own 5-minute timer); previously the OLDER
bag's later despawn/looting would wipe the beacon that pointed at the newer bag.
## 0.7.3 — 2026-07-06
### Fixed
+6 -1
View File
@@ -15,7 +15,12 @@ survival stakes system: get back to your bag before it's gone — or before some
deaths stay reachable), holding the contents as `IntValue` children (item id → count). A
floating **countdown** shows everyone how long it has left; the **owner** also gets a tall
golden **beacon** (client-side, only they see it) and a "You died" toast.
4. After `LifetimeSeconds` the bag despawns with whatever is still inside.
4. After `LifetimeSeconds` (default **5 minutes**) the bag despawns with whatever is still inside.
**Dying again mid corpse-run:** every death drops its own bag — old and new **coexist in the
world**, each on its own 5-minute timer, each lootable. Your **beacon always points at your newest
bag** (a new death re-points it); it clears only when *that* bag is looted empty or expires — an
older bag despawning never touches it.
## Looting
+15 -3
View File
@@ -36,6 +36,12 @@ local LootBags = {}
local started = false
local looting: { [Player]: boolean } = {} -- re-entry guard per collector
-- Each owner's NEWEST bag — the one their beacon points at. Older bags coexist in the world on
-- their own timers; only the latest bag's fate may clear the owner's beacon (dying again mid
-- corpse-run re-points the beacon at the new bag, and the old bag's later despawn must not
-- touch it).
local latestBag: { [Player]: Instance } = {}
-- ── Bag construction ─────────────────────────────────────────────────────────
local function bagTemplate(): PVInstance?
@@ -292,12 +298,17 @@ local function dropBag(player: Player, position: Vector3)
-- is truly gone (the nil-fire below) or the lifetime lapses.
local host2 = bagHost(bag)
local beaconPos = if host2 then host2.Position else position
latestBag[player] = bag
if cfg.OwnerBeacon ~= false then
Remotes.event("LootBagDropped"):FireClient(player, beaconPos, lifetime)
bag.Destroying:Connect(function()
-- Truly gone server-side (emptied or expired) → clear the owner's beacon early.
if player.Parent then
Remotes.event("LootBagDropped"):FireClient(player, nil)
-- Clear the owner's beacon ONLY if this is still their newest bag (an older bag
-- despawning/emptying must not wipe the beacon that points at a newer one).
if latestBag[player] == bag then
latestBag[player] = nil
if player.Parent then
Remotes.event("LootBagDropped"):FireClient(player, nil)
end
end
end)
end
@@ -357,6 +368,7 @@ function LootBags.start(_options: { [string]: any }?)
Players.PlayerAdded:Connect(watchPlayer)
Players.PlayerRemoving:Connect(function(player)
looting[player] = nil
latestBag[player] = nil
end)
end