aboutsummaryrefslogtreecommitdiff
path: root/internal/game/sys_safespot.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/sys_safespot.go')
-rw-r--r--internal/game/sys_safespot.go23
1 files changed, 23 insertions, 0 deletions
diff --git a/internal/game/sys_safespot.go b/internal/game/sys_safespot.go
index 539f69d..ce99610 100644
--- a/internal/game/sys_safespot.go
+++ b/internal/game/sys_safespot.go
@@ -104,6 +104,18 @@ func (g *Game) activateSafespot(sess *net.Session, p *player.Player, ss *Safespo
return
}
+ // Two players can start hiding in the same tick and both pass the cap check
+ // at hide time (the occupant is only appended here, when the countdown
+ // completes). Re-check the cap now so a max_occupants cover never ends with
+ // more occupants than it allows.
+ if cfg.MaxOccupants > 0 && len(st.SafespotOccupants) >= cfg.MaxOccupants {
+ g.safespot.Delete(p.Name)
+ sess.WriteLine("")
+ sess.WriteLine(fmt.Sprintf("%s already hiding there!",
+ joinSafespotOccupants(st.SafespotOccupants)))
+ return
+ }
+
st.SafespotOccupants = append(st.SafespotOccupants, p.Name)
var msg string
@@ -143,11 +155,22 @@ func (g *Game) safespotMaintenance(sess *net.Session, p *player.Player, ss *Safe
return
}
+ // Decay accumulation and the decay roll are per-object, not per-occupant:
+ // SafespotTick calls this once per occupant, so N players on one cover
+ // would otherwise advance the counter N times and roll decay N times per
+ // tick. The first occupant does the object-level work; the per-player
+ // UnsafeChance slip below stays per occupant.
+ isFirstOccupant := st.SafespotOccupants[0] == p.Name
+
if cfg.UnsafeChance > 0 && rand.Float64() < cfg.UnsafeChance {
g.forceLeaveSafespot(sess, p, ss, "You slip and are no longer covered!")
return
}
+ if !isFirstOccupant {
+ return
+ }
+
levelIdx := st.SafespotLevel - 1
degraded := false