<aside> <img src="/icons/reorder_gray.svg" alt="/icons/reorder_gray.svg" width="40px" />
Navigation
</aside>
<aside> 📦 Chests spawn on the field, roll a tier and item drop, and can carry stackable effects (Frost, Tentacles, Chromatic) that alter how they spawn, open, or pay out.
</aside>
Chests & Loot covers two layers: the chest pool itself (tiers, spawn points, item drops) and an independent effect layer that can attach to any chest and change its spawn presentation, open behavior, or loot value.
ChestData holds one tier's spawn weight, base value, prefab and item-drop table; ChestDatabase rolls a tier weighted by BaseSpawnWeight plus any upgrade bonus, and looks up a tier's data.ChestData.RollItemDrop rolls an item id from the table and resolves its final sell value (rarity value upgrade, item multiplier, global value multiplier).ChestSpawnController.SpawnOnButtonClick, called from MainButtonBehavior.OnObjectClicked - see Core Clicker Loop), scaled by GameData.ChestsPerSpawn and the Chests effector multiplier (see Effectors). Owns one pool per tier and one pool per effect prefab.IInteractable; tapping it resolves a crit/one-shot damage roll and reduces CurrentHealth - Open() only fires once health reaches 0 (see Core Clicker Loop for the hit roll itself).ChestEffectBehavior is the base class concrete effects override.ChestSpawnController.BuildSnapshot and restored by RestoreFromSnapshot - see Save & restore below.FrostChestEffect / FrostBehavior / FrostSpawnController) - on open, launches a projectile to a nearby point that lands and drops a bonus item from the same chest's table.TentaclesChestEffect / TentaclesVisualBehavior / TentaclesSpawnController) - overrides spawn presentation with a flash-in, and on open blasts nearby unopened chests into auto-opening.ChromaticChestEffect) - marks the chest with a rainbow overlay for as long as it's attached, and multiplies the value of whatever item the chest drops.On OnChestOpened, FrostChestEffect picks a random offset point 20-30 units off the chest, finds the nearest valid spawn point to it via ChestSpawnAreaController.GetNearestSpawnPoint, and asks FrostSpawnController to launch a FrostBehavior projectile there, carrying this chest's ChestData (its item table). The projectile tweens to the target over a fixed duration; on arrival it spawns a new chest of the same tier at its landing point (via ChestSpawnController.SpawnChestAt), pre-tagged with its own Frost effect entry, then immediately calls SuppressChain on that new chest's Frost effect so opening the landed chest doesn't launch a further projectile - Frost hops exactly once per original chest, never chaining indefinitely.
The class's own doc comment describes an "explosion-flash-style appear instead of scale-in" on spawn, but the implementation doesn't currently override OverridesSpawnPresentation or PlaySpawnPresentation - so today a Tentacles chest spawns with the same appear animation as any other chest; only its OnChestOpened behavior (below) is live.
On open it runs a physics overlap check (Physics2D.OverlapCircleAll) in a fixed radius around the chest. Every other chest caught in that radius that isn't already opening/opened gets marked pending, gets its own Tentacles visual spawned at its position, and is opened after a short delay (giving the visual time to scale in first) - so one Tentacles chest can chain-open a cluster of nearby chests. The tentacle particle on the original chest scales down as its own closing beat.
Purely value/visual - no spawn or open-time behavior of its own. On Attach it turns on the chest's rainbow shader overlay (ChestBehavior.SetChromatic), which stays on for as long as the effect is attached, so a Chromatic-rolled chest reads as such before it's even opened. On OnItemSpawned it multiplies the dropped item's sell value - the item itself is unchanged (same id, same drop table), only its payout and pickup visual differ.
Every active, unopened chest on the field is captured into a SceneObjectsSave before the game saves: ChestSpawnController.BuildSnapshot records each chest's tier, position, current health, and attached effects' captured state (via each effect's CaptureState()) into a ChestSnapshot/ChestEffectState list. On load, ChestSpawnController.RestoreFromSnapshot respawns each chest silently (no appear animation, no OnChestSpawned event) at its saved position, re-attaches its effects and calls each one's RestoreState(data), then applies the saved health via ChestBehavior.OverrideHealth. This is what makes chests mid-fight survive an app restart instead of resetting on every load.