Counter reset on re-attach created duplicate critters

This commit is contained in:
Eddoursul 2026-08-30 02:22:15 +02:00
parent 874b5faf2e
commit b5ccf39c9e
2 changed files with 44 additions and 16 deletions

Binary file not shown.

View File

@ -57,6 +57,10 @@ Bool property bReducedRespawn = true auto
int property iCurrentCritterCount = 0 auto hidden ; not used, set to -1 to break vanilla spawner while loops int property iCurrentCritterCount = 0 auto hidden ; not used, set to -1 to break vanilla spawner while loops
bool bLooping = false ; reintroduced to catch baked runaway loops bool bLooping = false ; reintroduced to catch baked runaway loops
float extraWaitTime = 0.0 ; extra time in seconds before trying again float extraWaitTime = 0.0 ; extra time in seconds before trying again
float fDetachGameTime = 0.0 ; game time (days) of the last cell detach
; critter.psc delays the kill of a detached critter by 0.31831 game hours and cancels it if the cell attaches again earlier,
; so the live count is carried over on such a quick re-attach
float fOldCrittersDeadAfter = 0.02
float property fCheckPlayerDistanceTime = 2.0 auto hidden float property fCheckPlayerDistanceTime = 2.0 auto hidden
@ -108,7 +112,12 @@ EVENT OnCellAttach()
VanillaLoopBreak() VanillaLoopBreak()
; the spawner will attach to a cell, this can be the cell we just teleported to (door) or one that loaded in the distance ; the spawner will attach to a cell, this can be the cell we just teleported to (door) or one that loaded in the distance
; shouldSpawn() will check if the spawner should start spawning critters, wait a bit or do nothing ; shouldSpawn() will check if the spawner should start spawning critters, wait a bit or do nothing
iSpawnedCritterCount = 0 ; critters of the previous attach survive a short detach, keep counting them
int liveCritters = iSpawnedCritterCount - iDeadCritterCount
if liveCritters < 0 || liveCritters > iMaxCritterCount || Utility.GetCurrentGameTime() - fDetachGameTime > fOldCrittersDeadAfter
liveCritters = 0
endif
iSpawnedCritterCount = liveCritters
iDeadCritterCount = 0 iDeadCritterCount = 0
isSpawning = false isSpawning = false
@ -146,6 +155,7 @@ endEVENT
EVENT onCellDetach() EVENT onCellDetach()
shouldTryAgain = false shouldTryAgain = false
UnregisterForUpdate() UnregisterForUpdate()
fDetachGameTime = Utility.GetCurrentGameTime()
endEVENT endEVENT
Function SpawnABatchOfCritters() Function SpawnABatchOfCritters()
@ -171,15 +181,20 @@ Function SpawnABatchOfCritters()
spawnAttempts = 1 spawnAttempts = 1
endif endif
bool spawnFailed = spawnAttempts > 0
while (spawnAttempts>0) while (spawnAttempts>0)
if (SpawnCritterAtRef(self)) if (SpawnCritterAtRef(self))
iSpawnedCritterCount += 1 iSpawnedCritterCount += 1
spawnFailed = false
endif endif
spawnAttempts -=1 spawnAttempts -=1
endWhile endWhile
isSpawning = false isSpawning = false
if (iMaxCritterCount - iSpawnedCritterCount + iDeadCritterCount>0) if spawnFailed
;no critter could be placed, CritterTypes is broken: do not retry until the next cell attach or critter death
shouldTryAgain = false
elseif (iMaxCritterCount - iSpawnedCritterCount + iDeadCritterCount>0)
;we couldn't spawn enough critters, or the player is currently killing them : try a bit later ;we couldn't spawn enough critters, or the player is currently killing them : try a bit later
QueueAdditionalSpawns() QueueAdditionalSpawns()
endIf endIf
@ -216,22 +231,35 @@ bool Function SpawnCritterAtRef(ObjectReference arSpawnRef)
if VanillaLoopBreak() if VanillaLoopBreak()
return false return false
endif endif
; Pick a random critter type int typeCount = 0
Activator critterType = CritterTypes.GetAt(RandomInt(0, CritterTypes.GetSize() - 1)) as Activator if CritterTypes
typeCount = CritterTypes.GetSize()
if critterType endif
Critter critty = arSpawnRef.PlaceAtMe(critterType, 1, false, true) as Critter if typeCount == 0
if critty Debug.Trace("CritterSpawn :" + self + " has an empty CritterTypes list")
critty.SetInitialSpawnerProperties(fLeashLength, fLeashHeight, fLeashDepth, fMaxPlayerDistance + fLeashLength, self)
return true
endif
else
Debug.Trace("CritterSpawn :" + arSpawnRef + " attempted to spawn a bad critter type, check the contents of " + CritterTypes );
return false return false
endif endif
return false ; Pick a random critter type
Activator critterType = CritterTypes.GetAt(RandomInt(0, typeCount - 1)) as Activator
if !critterType
Debug.Trace("CritterSpawn :" + arSpawnRef + " attempted to spawn a bad critter type, check the contents of " + CritterTypes)
return false
endif
ObjectReference critterRef = arSpawnRef.PlaceAtMe(critterType, 1, false, true)
Critter critty = critterRef as Critter
if !critty
; the activator has no Critter script, remove the orphan reference
Debug.Trace("CritterSpawn :" + critterType + " has no Critter script, check the contents of " + CritterTypes)
if critterRef
critterRef.Delete()
endif
return false
endif
critty.SetInitialSpawnerProperties(fLeashLength, fLeashHeight, fLeashDepth, fMaxPlayerDistance + fLeashLength, self)
return true
endFunction endFunction