ludic/packages/ludic.zones/state.ludic
Orkuncakilkaya 8b85282502 ludic.zones: a disc per player from their fog, merged into clusters; the simulating packages ask whether a place is simulated
zones_set / zones_clear / zones_merge, zones_contains / zones_nearest and the clusters' bounding circles,
over fixed arrays of ZONES_MAX (16). WildlifeWorld.active freezes an animal outside (no state change, no
dice), NpcWorld.active a walker (and no birth outside), VehicleWorld.active a moored boat, and
ThingsWorld.restocks keeps a morning's restock inside; every default is "everywhere", so an unbound game
is unchanged. Tests: the merge (near players one cluster, far two, a player leaving splits a chain),
contains, nearest, the radius; wildlife, npc, vehicles and things pass as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:53:23 +03:00

40 lines
1.7 KiB
Text

# state.ludic - the discs by player slot and the clusters the last merge made
export const ZONES_MAX: int = 16 # player slots a world can hold (at least PLY_MAX)
export const ZONES_NO_FOG: float = 900.0 # the radius of a player who sees to the horizon
export const ZONES_PAST_FOG: float = 40.0 # simulated this far past what a player can see
export const ZONES_LEAST: float = 150.0 # and never less than this
export state ZonesState {
zn_on: words = words(ZONES_MAX)
zn_x: []float = floats(ZONES_MAX)
zn_z: []float = floats(ZONES_MAX)
zn_r: []float = floats(ZONES_MAX)
zn_cl: words = words(ZONES_MAX) # each disc's cluster, after zones_merge
zn_up: words = words(ZONES_MAX) # the merge's union-find
zn_ncl: int = 0
zn_cx: []float = floats(ZONES_MAX) # each cluster's bounding circle
zn_cz: []float = floats(ZONES_MAX)
zn_cr: []float = floats(ZONES_MAX)
zn_cn: words = words(ZONES_MAX) # how many discs it holds
}
# a player's radius from how far they see: fog_dist <= 0 is no fog
export function zones_radius(fog_dist: float) -> float {
if fog_dist <= 0.0 { return ZONES_NO_FOG }
return Math.max(fog_dist + ZONES_PAST_FOG, ZONES_LEAST)
}
export function zones_set(zones_st: mut ZonesState, pid: int, x: float, z: float, r: float) -> void {
if pid < 0 or pid >= ZONES_MAX { return }
zones_st.zn_on[pid] = 1
zones_st.zn_x[pid] = x
zones_st.zn_z[pid] = z
zones_st.zn_r[pid] = r
}
export function zones_clear(zones_st: mut ZonesState, pid: int) -> void { if pid >= 0 and pid < ZONES_MAX { zones_st.zn_on[pid] = 0 } }
export function zones_reset(zones_st: mut ZonesState) -> void {
for i in 0 .. ZONES_MAX { zones_st.zn_on[i] = 0 }
zones_st.zn_ncl = 0
}