Compare commits
No commits in common. "278c4cfefdcba4b78b165965e8a1d25685dd7f4d" and "dcc1b25aec4bd7a084c9814e04521aa1d62a834e" have entirely different histories.
278c4cfefd
...
dcc1b25aec
@ -649,7 +649,6 @@ CommonLibSSE-NG by Ryan McKenzie, powerofthree, Charmed Baryon, and others
|
|||||||
Better Dialogue Controls by ecirbaf
|
Better Dialogue Controls by ecirbaf
|
||||||
Unofficial Enderal Port (fs.dll) by Hishutup and FelesNoctis
|
Unofficial Enderal Port (fs.dll) by Hishutup and FelesNoctis
|
||||||
Shorter Grass by Fhaarkas
|
Shorter Grass by Fhaarkas
|
||||||
CritterSpawn Congestion Fix by Excinerus
|
|
||||||
Ghost Item Bug Fix for SkyUI by EdmanSA
|
Ghost Item Bug Fix for SkyUI by EdmanSA
|
||||||
Drunk Sinking Head Idle Fix by KnightRangersGuild
|
Drunk Sinking Head Idle Fix by KnightRangersGuild
|
||||||
Book Covers Skyrim by DanielCoffey
|
Book Covers Skyrim by DanielCoffey
|
||||||
|
@ -1 +1 @@
|
|||||||
version = 2.0.13
|
version = 2.0.12.5
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -151,3 +151,15 @@ Function TriggerAnimationSyncUpdate()
|
|||||||
RegisterForSingleUpdate(3.0)
|
RegisterForSingleUpdate(3.0)
|
||||||
EndIf
|
EndIf
|
||||||
EndFunction
|
EndFunction
|
||||||
|
|
||||||
|
Function UpdateFillPackages(Package akFillPackage) ; Version 2.0.8 Update
|
||||||
|
Int i = 0
|
||||||
|
While i < akCustomAnimPackageArray.Length
|
||||||
|
akCustomAnimPackageArray[i] = akFillPackage
|
||||||
|
i += 1
|
||||||
|
EndWhile
|
||||||
|
|
||||||
|
If Is3DLoaded()
|
||||||
|
ResetAnimations()
|
||||||
|
EndIf
|
||||||
|
EndFunction
|
||||||
|
@ -543,6 +543,17 @@ Function ClearPlayerAlias()
|
|||||||
|
|
||||||
EndFunction
|
EndFunction
|
||||||
|
|
||||||
|
Function UpdateAarosCarryTraySpell() ; Version 2.0.8 Update
|
||||||
|
If _00E_FS_NQ07_AarosREF.HasSpell(_00E_AbCarryDrinkTray_Old)
|
||||||
|
_00E_FS_NQ07_AarosREF.RemoveSpell(_00E_AbCarryDrinkTray_Old)
|
||||||
|
Wait(1.0)
|
||||||
|
Int iCurStage = GetCurrentStageID()
|
||||||
|
If iCurStage >= 35 && iCurStage < 50
|
||||||
|
AarosAddSpell()
|
||||||
|
EndIf
|
||||||
|
EndIf
|
||||||
|
EndFunction
|
||||||
|
|
||||||
Function AskCreatePotion()
|
Function AskCreatePotion()
|
||||||
|
|
||||||
If GetCurrentStageID() == 115
|
If GetCurrentStageID() == 115
|
||||||
|
@ -195,6 +195,10 @@ Function RegisterNewHousingObjectOffsets(Float fNewOffsetAngleZ, Float fNewOffse
|
|||||||
fStoredOffsetPositionZ = fNewOffsetPositionZ
|
fStoredOffsetPositionZ = fNewOffsetPositionZ
|
||||||
EndFunction
|
EndFunction
|
||||||
|
|
||||||
|
Function Update_209()
|
||||||
|
bStartTutorialShown = ((Self as Quest) as _00E_PlayerhousingTutorial).StartTutorialIsShown()
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
|
||||||
;=====================================================================================
|
;=====================================================================================
|
||||||
; CONTROLS
|
; CONTROLS
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Scriptname _00E_PlayerSetUpScript extends ObjectReference
|
Scriptname _00E_PlayerSetUpScript extends ObjectReference
|
||||||
{Initializes all the necessary Quests, maintains the player, contains various OnPlayerLoadGame() failsafes. This script is important for proper updating, do not overwrite it.}
|
{Initializes all the necessary Quests, maintains the player, contains various OnPlayerLoadGame() failsafes. This script is important for proper updating, do not overwrite it.}
|
||||||
|
|
||||||
Float Property CURRENT_PATCH_VERSION = 2.13 AutoReadOnly
|
Float Property CURRENT_PATCH_VERSION = 2.124 AutoReadOnly
|
||||||
|
|
||||||
|
|
||||||
;=====================================================================================
|
;=====================================================================================
|
||||||
@ -34,6 +34,8 @@ Event OnInit()
|
|||||||
|
|
||||||
EnableDisableKillmove()
|
EnableDisableKillmove()
|
||||||
|
|
||||||
|
; Added in 1.5.8.0
|
||||||
|
|
||||||
; starts all quests that are in the formlist
|
; starts all quests that are in the formlist
|
||||||
Int iIndex = QuestsToStart.GetSize()
|
Int iIndex = QuestsToStart.GetSize()
|
||||||
While iIndex > 0
|
While iIndex > 0
|
||||||
@ -57,7 +59,7 @@ Event OnPlayerLoadGame()
|
|||||||
_00E_Func_CheckEnderalDLL.Run()
|
_00E_Func_CheckEnderalDLL.Run()
|
||||||
|
|
||||||
Maintenance()
|
Maintenance()
|
||||||
If GetState() != "RealPlayer"
|
If GetState() != "RealPlayer" ; Post-1.2.5.0 version update
|
||||||
GoToState("RealPlayer")
|
GoToState("RealPlayer")
|
||||||
EndIf
|
EndIf
|
||||||
EndIf
|
EndIf
|
||||||
@ -72,6 +74,114 @@ State RealPlayer
|
|||||||
EndState
|
EndState
|
||||||
|
|
||||||
|
|
||||||
|
;=====================================================================================
|
||||||
|
; 2.0.6
|
||||||
|
;=====================================================================================
|
||||||
|
|
||||||
|
Function UpdateMQ12b_206()
|
||||||
|
_00E_MQ12b_Functions MQ12bFunctions = Game.GetForm(0x2EBAD) as _00E_MQ12b_Functions
|
||||||
|
Quest MQ15 = Game.GetFormFromFile(0x0002EBB0, "Skyrim.esm") as Quest
|
||||||
|
If MQ12bFunctions.GetCurrentStageID() >= 135 && MQ15.GetCurrentStageID() < 5
|
||||||
|
MQ12bFunctions.OldReenableDisabledNPC()
|
||||||
|
EndIf
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
|
||||||
|
;=====================================================================================
|
||||||
|
; 2.0.8
|
||||||
|
;=====================================================================================
|
||||||
|
|
||||||
|
Function Update_208()
|
||||||
|
; Obsolete abilities cleanup
|
||||||
|
_00E_FS_NQ07_Functions FS_NQ07_Quest = Game.GetFormFromFile(0x0001CA09, "Enderal - Forgotten Stories.esm") as _00E_FS_NQ07_Functions
|
||||||
|
Int iFS_NQ07Stage = FS_NQ07_Quest.GetCurrentStageID()
|
||||||
|
If iFS_NQ07Stage >= 5 && iFS_NQ07Stage < 410
|
||||||
|
FS_NQ07_Quest.UpdateAarosCarryTraySpell()
|
||||||
|
Else
|
||||||
|
RemoveObsoleteSpell(0x0009A893, "Skyrim.esm", 0x000F649A, "Skyrim.esm")
|
||||||
|
EndIf
|
||||||
|
|
||||||
|
RemoveObsoleteSpell(0x0010D339, "Skyrim.esm", 0x000F649A, "Skyrim.esm")
|
||||||
|
RemoveObsoleteSpell(0x0006FFAF, "Skyrim.esm", 0x000F6498, "Skyrim.esm")
|
||||||
|
RemoveObsoleteSpell(0x000F64A0, "Skyrim.esm", 0x000F6498, "Skyrim.esm")
|
||||||
|
|
||||||
|
; Refill _00E_AnimTest_SC package arrays where needed
|
||||||
|
FillAnimTestPackages(0x00137889, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x0013788A, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x0013789F, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x001378A2, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x001378AA, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x001378AB, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x00147E12, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x00147E14, "Skyrim.esm", 0x00070657, "Skyrim.esm")
|
||||||
|
|
||||||
|
FillAnimTestPackages(0x0010D336, "Skyrim.esm", 0x00070645, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x0010D33B, "Skyrim.esm", 0x00070645, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x00147DEA, "Skyrim.esm", 0x00070645, "Skyrim.esm")
|
||||||
|
FillAnimTestPackages(0x00147E37, "Skyrim.esm", 0x00070645, "Skyrim.esm")
|
||||||
|
|
||||||
|
; "Gypsy minstrels" update
|
||||||
|
Keyword performSpotKwd = Game.GetFormFromFile(0x000FB905, "Skyrim.esm") as Keyword
|
||||||
|
(Game.GetFormFromFile(0x00044EBC, "Skyrim.esm") as _00E_BardPlayInstrumentScript).LinkedPlayMarkerKeyword = performSpotKwd
|
||||||
|
|
||||||
|
(Game.GetFormFromFile(0x00046D79, "Skyrim.esm") as _00E_GypsyMinstrelsControlScript).UpdateWaypoint()
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
Function RemoveObsoleteSpell(Int idNPC, String esmNPC, Int idSpell, String esmSpell)
|
||||||
|
Spell obsoleteSpell = Game.GetFormFromFile(idSpell, esmSpell) as Spell
|
||||||
|
(Game.GetFormFromFile(idNPC, esmNPC) as Actor).RemoveSpell(obsoleteSpell)
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
Function FillAnimTestPackages(Int idNPC, String esmNPC, Int idPackage, String esmPackage)
|
||||||
|
Package newPackage = Game.GetFormFromFile(idPackage, esmPackage) as Package
|
||||||
|
(Game.GetFormFromFile(idNPC, esmNPC) as _00E_AnimTest_SC).UpdateFillPackages(newPackage)
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
|
||||||
|
;=====================================================================================
|
||||||
|
; 2.0.10
|
||||||
|
;=====================================================================================
|
||||||
|
|
||||||
|
Function Update_210()
|
||||||
|
Spell abSoulcaller = Game.GetFormFromFile(0x002F0EA, "Enderal - Forgotten Stories.esm") as Spell
|
||||||
|
If PlayerREF.HasSpell(abSoulcaller)
|
||||||
|
PlayerREF.RemoveSpell(abSoulcaller)
|
||||||
|
Utility.Wait(1)
|
||||||
|
PlayerREF.AddSpell(abSoulcaller, False)
|
||||||
|
EndIf
|
||||||
|
|
||||||
|
Perk perkBloodlust = Game.GetFormFromFile(0x00069D38, "Skyrim.esm") as Perk
|
||||||
|
_ResetPerk(perkBloodlust)
|
||||||
|
|
||||||
|
_00E_PlayerhousingMaster.GetMaster().Update_209()
|
||||||
|
|
||||||
|
; Previous versions may have silence tracks stuck
|
||||||
|
Levelsystem.RemoveSilence()
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
|
||||||
|
;=====================================================================================
|
||||||
|
; 2.0.12
|
||||||
|
;=====================================================================================
|
||||||
|
|
||||||
|
Function Update_212()
|
||||||
|
PlayerREF.AddPerk(Game.GetFormFromFile(0x14CF8, "Enderal - Forgotten Stories.esm") as Perk) ; _00E_SE_WerewolfBlockFurniturePerk
|
||||||
|
PlayerREF.AddPerk(Game.GetFormFromFile(0x14CFA, "Enderal - Forgotten Stories.esm") as Perk) ; _00E_SE_DismantlePerk
|
||||||
|
PlayerREF.AddPerk(Game.GetFormFromFile(0x14CF9, "Enderal - Forgotten Stories.esm") as Perk) ; _00E_SE_2_0_12_UpgradePerk
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
Function Update_212_hotfix1()
|
||||||
|
Quest rNQ05 = Game.GetFormFromFile(0x1C82F, "Enderal - Forgotten Stories.esm") as Quest
|
||||||
|
if rNQ05.GetCurrentStageID() >= 30 && rNQ05.GetCurrentStageID() < 40
|
||||||
|
PlayerREF.AddPerk(Game.GetFormFromFile(0x14CF6, "Enderal - Forgotten Stories.esm") as Perk) ; _00E_FS_NQ05_CraftPotionPerk
|
||||||
|
endif
|
||||||
|
Quest rNQ07 = Game.GetFormFromFile(0x1CA09, "Enderal - Forgotten Stories.esm") as Quest
|
||||||
|
if rNQ07.GetCurrentStageID() == 115
|
||||||
|
PlayerREF.AddPerk(Game.GetFormFromFile(0x14CF7, "Enderal - Forgotten Stories.esm") as Perk) ; _00E_FS_NQ07_CraftPotionPerk
|
||||||
|
endif
|
||||||
|
EndFunction
|
||||||
|
|
||||||
|
|
||||||
;=====================================================================================
|
;=====================================================================================
|
||||||
; ALL UPDATES
|
; ALL UPDATES
|
||||||
;=====================================================================================
|
;=====================================================================================
|
||||||
@ -149,14 +259,28 @@ endfunction
|
|||||||
|
|
||||||
Function Maintenance()
|
Function Maintenance()
|
||||||
|
|
||||||
if fPatchVersion <= 2.13
|
if fPatchVersion <= 1.62
|
||||||
Debug.MessageBox("A savegame was loaded which was made before the release of Enderal SE. In this save, several new features won't be available and there is a chance that you'll encounter grave bugs. Please, start a new game.")
|
Debug.MessageBox("A savegame was loaded which was made before the release of Enderal SE. In this save, several new features won't be available and there is a chance that you'll encounter grave bugs. Please, start a new game.")
|
||||||
;Game.QuitToMainMenu()
|
Game.QuitToMainMenu()
|
||||||
;return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if fPatchVersion < CURRENT_PATCH_VERSION
|
if fPatchVersion < CURRENT_PATCH_VERSION
|
||||||
;
|
If fPatchVersion < 2.06
|
||||||
|
UpdateMQ12b_206()
|
||||||
|
EndIf
|
||||||
|
If fPatchVersion < 2.08
|
||||||
|
Update_208()
|
||||||
|
EndIf
|
||||||
|
If fPatchVersion < 2.10
|
||||||
|
Update_210()
|
||||||
|
EndIf
|
||||||
|
If fPatchVersion < 2.12
|
||||||
|
Update_212()
|
||||||
|
EndIf
|
||||||
|
If fPatchVersion < 2.121
|
||||||
|
Update_212_hotfix1()
|
||||||
|
EndIf
|
||||||
fPatchVersion = CURRENT_PATCH_VERSION
|
fPatchVersion = CURRENT_PATCH_VERSION
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
scriptName CritterSpawn extends ObjectReference
|
scriptName CritterSpawn extends ObjectReference
|
||||||
|
{MODIFIED BY STEVE40 and USKP}
|
||||||
|
|
||||||
import Critter
|
import Critter
|
||||||
import Utility
|
import Utility
|
||||||
@ -41,292 +42,189 @@ float property fLeashOverride auto
|
|||||||
bool property bSpawnInPrecipitation auto
|
bool property bSpawnInPrecipitation auto
|
||||||
{Should this critter spawn in rain/snow? DEFAULT: FALSE}
|
{Should this critter spawn in rain/snow? DEFAULT: FALSE}
|
||||||
|
|
||||||
|
|
||||||
Bool property bAllowRespawn = true auto
|
|
||||||
Bool property bReducedRespawn = true auto
|
|
||||||
;----------------------------------------------
|
;----------------------------------------------
|
||||||
; Constants (shouldn't need to modify these)
|
; Constants (shouldn't need to modify these)
|
||||||
;----------------------------------------------
|
;----------------------------------------------
|
||||||
|
float fCheckPlayerDistanceTime = 2.0
|
||||||
|
|
||||||
;----------------------------------------------
|
;----------------------------------------------
|
||||||
; Variables to keep track of spawned critters
|
; Variables to keep track of spawned critters
|
||||||
;----------------------------------------------
|
;----------------------------------------------
|
||||||
|
int property iCurrentCritterCount = 0 auto hidden
|
||||||
|
bool bLooping
|
||||||
|
bool bPrintDebug = FALSE ; should usually be set to false.
|
||||||
|
int recursions
|
||||||
|
|
||||||
|
; Do initial stuff when my 3D has loaded up.
|
||||||
|
EVENT OnCellAttach() ; USKP 1.3.3 - Changed from OnLoad() to be more reliable, especially in interior cells.
|
||||||
int property iCurrentCritterCount = 0 auto hidden ; not used, set to -1 to break vanilla spawner while loops
|
; The Spawner will register for update and periodically check whether the player is close or not
|
||||||
bool bLooping = false ; reintroduced to catch baked runaway loops
|
; - JOEL REFACTOR - Going to use onLoad() & onUnload() instead of states?
|
||||||
float extraWaitTime = 0.0 ; extra time in seconds before trying again
|
; GotoState("WaitingForPlayer")
|
||||||
|
; - JOEL REFACTOR - also no longer need to update
|
||||||
|
; RegisterForSingleUpdate(fCheckPlayerDistanceTime)
|
||||||
float property fCheckPlayerDistanceTime = 2.0 auto hidden
|
|
||||||
int property iSpawnedCritterCount = 0 auto hidden
|
if bPrintDebug == TRUE
|
||||||
int property iDeadCritterCount = 0 auto hidden
|
; debug.trace("spawner " + self + " loaded.")
|
||||||
int property iRespawnDelay = 6 auto hidden
|
recursions = 0
|
||||||
|
|
||||||
|
|
||||||
bool property isSpawning = false auto hidden
|
|
||||||
bool property shouldTryAgain = false auto hidden
|
|
||||||
actor property PlayerRef auto
|
|
||||||
|
|
||||||
|
|
||||||
bool bPrintDebug = FALSE
|
|
||||||
Cell _ParentCell
|
|
||||||
|
|
||||||
Cell property ParentCell
|
|
||||||
Cell function get()
|
|
||||||
if !_ParentCell
|
|
||||||
_ParentCell = self.GetParentCell()
|
|
||||||
endif
|
|
||||||
return _ParentCell
|
|
||||||
endFunction
|
|
||||||
endproperty
|
|
||||||
|
|
||||||
|
|
||||||
bool Function VanillaLoopBreak()
|
|
||||||
|
|
||||||
if (bLooping || iCurrentCritterCount>0)
|
|
||||||
; breaking OnCellAttach runaway loop in baked vanilla functions
|
|
||||||
bLooping = false
|
|
||||||
; breaking SpawnInitialCritterBatch runaway loop in baked vanilla and uskp functions
|
|
||||||
iCurrentCritterCount = 0
|
|
||||||
|
|
||||||
Debug.Trace("CritterSpawn : Runaway Spawner warning :" + self);
|
|
||||||
return true
|
|
||||||
endif
|
endif
|
||||||
return false
|
|
||||||
EndFunction
|
; set our control bool to start the loop
|
||||||
Function SpawnInitialCritterBatch()
|
bLooping = TRUE
|
||||||
VanillaLoopBreak()
|
|
||||||
endFunction
|
while bLooping
|
||||||
|
if bPrintDebug
|
||||||
|
recursions += 1
|
||||||
|
; debug.trace("spawner " + self + " while loop #" + recursions)
|
||||||
|
endif
|
||||||
|
|
||||||
EVENT OnCellAttach()
|
|
||||||
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
|
|
||||||
; shouldSpawn() will check if the spawner should start spawning critters, wait a bit or do nothing
|
|
||||||
iSpawnedCritterCount = 0
|
|
||||||
iDeadCritterCount = 0
|
|
||||||
isSpawning = false
|
|
||||||
|
|
||||||
shouldTryAgain = true
|
|
||||||
|
|
||||||
if shouldSpawn()
|
if !shouldSpawn()
|
||||||
SpawnABatchOfCritters()
|
; wait a bit, then see if the player is close again.
|
||||||
elseif shouldTryAgain
|
; Removing this to eliminate some TPLOG spam
|
||||||
;randomize the update time so we're less likely to have synchronized spawners asking for updates
|
; ; debug.TraceConditional("player not yet near spawner " + self, bPrintDebug)
|
||||||
RegisterForSingleUpdate(fCheckPlayerDistanceTime * Randomfloat(1.0,1.5))
|
utility.wait(fCheckPlayerDistanceTime)
|
||||||
|
else
|
||||||
endif
|
; ; debug.TraceConditional("spawner " + self + " ready to spawn!!!", bPrintDebug)
|
||||||
|
; player must be nearby - spawn our initial critters
|
||||||
|
; don't follow up as we no longer wish to re-generate new critters until the player leaves entirely
|
||||||
|
spawnInitialCritterBatch()
|
||||||
|
bLooping = FALSE
|
||||||
|
endif
|
||||||
|
endWhile
|
||||||
|
|
||||||
endEVENT
|
endEVENT
|
||||||
|
|
||||||
event OnUpdate()
|
EVENT onUnload()
|
||||||
|
; when our 3D unloads, stop looping until loaded again.
|
||||||
VanillaLoopBreak()
|
bLooping = FALSE
|
||||||
if (iSpawnedCritterCount < iMaxCritterCount*10)
|
; ; debug.TraceConditional("spawner " + self + " unloading due to onUnload() EVENT.", bPrintDebug)
|
||||||
if shouldSpawn()
|
|
||||||
SpawnABatchOfCritters()
|
|
||||||
elseif shouldTryAgain
|
|
||||||
RegisterForSingleUpdate(fCheckPlayerDistanceTime + extraWaitTime )
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endEvent
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EVENT onUnload()
|
|
||||||
shouldTryAgain = false
|
|
||||||
UnregisterForUpdate()
|
|
||||||
endEVENT
|
endEVENT
|
||||||
|
|
||||||
EVENT onCellDetach()
|
EVENT onCellDetach()
|
||||||
shouldTryAgain = false
|
bLooping = FALSE
|
||||||
UnregisterForUpdate()
|
; ; debug.TraceConditional("spawner " + self + " unloading due to onCellDetach() EVENT.", bPrintDebug)
|
||||||
endEVENT
|
endEVENT
|
||||||
|
|
||||||
Function SpawnABatchOfCritters()
|
Function SpawnInitialCritterBatch()
|
||||||
VanillaLoopBreak()
|
; How many do we need to spawn?
|
||||||
; Important note here, even if the instance locking this thread gets dumped midway leaving the thread locked
|
int icrittersToSpawn = iMaxCritterCount - iCurrentCritterCount
|
||||||
; this wouldn't leave threads wait()ing in the stacks, they'll just keep reregistering every iSpawnedCritterCount
|
|
||||||
; and just won't spawn anything, the whole thing will be fixed when the spawner is unloaded and loaded again
|
|
||||||
|
|
||||||
if (! isSpawning && iSpawnedCritterCount < iMaxCritterCount*10)
|
; Create that many critters
|
||||||
isSpawning = true
|
int i = 0;
|
||||||
|
while (i < icrittersToSpawn)
|
||||||
|
; Create one critter at a time
|
||||||
;if not using the Fixed critter script there's no way to prevent over-reported critter deaths, but we'll cap spawns anyway to the max value
|
SpawnCritter()
|
||||||
if (iDeadCritterCount > iSpawnedCritterCount)
|
|
||||||
iDeadCritterCount = iSpawnedCritterCount
|
|
||||||
endIf
|
|
||||||
|
|
||||||
|
|
||||||
int spawnAttempts = iMaxCritterCount - iSpawnedCritterCount + iDeadCritterCount
|
|
||||||
|
|
||||||
;limiting amount of respawns by distance
|
|
||||||
if (iDeadCritterCount>0 && bReducedRespawn)
|
|
||||||
spawnAttempts = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
while (spawnAttempts)
|
|
||||||
if (SpawnCritterAtRef(self))
|
|
||||||
iSpawnedCritterCount += 1
|
|
||||||
endif
|
|
||||||
spawnAttempts -=1
|
|
||||||
endWhile
|
|
||||||
|
|
||||||
isSpawning = false
|
|
||||||
if (iMaxCritterCount - iSpawnedCritterCount + iDeadCritterCount)
|
|
||||||
;we couldn't spawn enough critters, or the player is currently killing them : try a bit later
|
|
||||||
QueueAdditionalSpawns()
|
|
||||||
endIf
|
|
||||||
endIf
|
|
||||||
endFunction
|
|
||||||
|
|
||||||
|
; Wait a bit before the next spawn
|
||||||
function QueueAdditionalSpawns()
|
;Wait(fFastSpawnInterval)
|
||||||
VanillaLoopBreak()
|
|
||||||
if (!isSpawning && iSpawnedCritterCount < iMaxCritterCount*10)
|
; Next
|
||||||
UnregisterForUpdate()
|
i = i + 1
|
||||||
RegisterForSingleUpdate(1+ (1+iSpawnedCritterCount) * iRespawnDelay )
|
endWhile
|
||||||
endif
|
|
||||||
endFunction
|
endFunction
|
||||||
|
|
||||||
; Called by critters when they die
|
; Called by critters when they die
|
||||||
Event OnCritterDied()
|
Event OnCritterDied()
|
||||||
VanillaLoopBreak()
|
; Decrement current critter count, next time OnUpdate
|
||||||
if iDeadCritterCount < iSpawnedCritterCount
|
; gets called, we'll spawn a new one
|
||||||
iDeadCritterCount += 1
|
if iCurrentCritterCount > 0
|
||||||
else
|
iCurrentCritterCount -= 1; faster [USKP 2.0.1]
|
||||||
;iDeadCritterCount is overflowing for some reason
|
elseif iCurrentCritterCount < 0
|
||||||
;increase the spawned Critter count instead so the queue keeps getting postponed until the script shuts down
|
; iCurrentCritterCount must be in the negatives. Something is up, but for now increment towards zero
|
||||||
iSpawnedCritterCount = iDeadCritterCount
|
iCurrentCritterCount = 0; earler saves with failed deletions [USKP 2.0.1]
|
||||||
Debug.Trace("CritterSpawn : iDeadCritterCount overflowing " + iDeadCritterCount);
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
; a critter died, if we're not currently spawning, try to refresh the queue or push back the delay
|
|
||||||
QueueAdditionalSpawns()
|
|
||||||
endEvent
|
endEvent
|
||||||
|
|
||||||
bool Function SpawnCritterAtRef(ObjectReference arSpawnRef)
|
; Spawns one Critter
|
||||||
|
bool Function SpawnCritter()
|
||||||
if VanillaLoopBreak()
|
if (iCurrentCritterCount < iMaxCritterCount) && (iCurrentCritterCount >= 0)
|
||||||
return false
|
; Go ahead with the actual spawn
|
||||||
|
return SpawnCritterAtRef(self)
|
||||||
|
;/// [USKP 2.0.1] moved into SpawnCritterAtRef
|
||||||
|
; Increment count
|
||||||
|
iCurrentCritterCount = iCurrentCritterCount + 1
|
||||||
|
return true
|
||||||
|
///;
|
||||||
|
elseif iCurrentCritterCount < 0
|
||||||
|
; debug.trace("("+self+") has invalid iCurrentCritterCount of "+iCurrentCritterCount+", abort!")
|
||||||
|
; turn off loop
|
||||||
|
bLooping = FALSE
|
||||||
|
else
|
||||||
|
; debug.trace("("+self+") SpawnCritter() failed because iCurrentCritterCount is "+iCurrentCritterCount)
|
||||||
|
; ;debug.trace("("+self+") iMaxCritterCount: "+iMaxCritterCount)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
return False ; [USKP 1.3.1] to help eliminate log spam and potential long term save bloating.
|
||||||
|
endFunction
|
||||||
|
|
||||||
|
; Spawns one Critter at a specific location
|
||||||
|
; returns true on success [USKP 2.0.1]
|
||||||
|
;
|
||||||
|
bool Function SpawnCritterAtRef(ObjectReference arSpawnRef)
|
||||||
; Pick a random critter type
|
; Pick a random critter type
|
||||||
Activator critterType = CritterTypes.GetAt(RandomInt(0, CritterTypes.GetSize() - 1)) as Activator
|
Activator critterType = CritterTypes.GetAt(RandomInt(0, CritterTypes.GetSize() - 1)) as Activator
|
||||||
|
|
||||||
if critterType
|
if critterType == none
|
||||||
Critter critty = arSpawnRef.PlaceAtMe(critterType, 1, false, true) as Critter
|
; STEVE40+USKP extra check
|
||||||
if critty
|
|
||||||
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
|
||||||
|
|
||||||
|
; Create the critter and cast it to the critter base class
|
||||||
|
ObjectReference critterRef = arSpawnRef.PlaceAtMe(critterType, 1, false, true)
|
||||||
|
Critter thecritter = critterRef as Critter
|
||||||
|
|
||||||
return false
|
if thecritter == none
|
||||||
|
; STEVE40+USKP extra check
|
||||||
endFunction
|
|
||||||
|
|
||||||
|
|
||||||
float Function GetPlayerDistance() ; Caches player reference too
|
|
||||||
|
|
||||||
if VanillaLoopBreak()
|
|
||||||
return fMaxPlayerDistance + 1
|
|
||||||
endif
|
|
||||||
if !PlayerRef
|
|
||||||
PlayerRef = Game.GetPlayer()
|
|
||||||
endif
|
|
||||||
return PlayerRef.GetDistance(self)
|
|
||||||
endFunction
|
|
||||||
|
|
||||||
bool Function ShouldSpawn()
|
|
||||||
if VanillaLoopBreak()
|
|
||||||
return false
|
return false
|
||||||
endif
|
endif
|
||||||
if (iSpawnedCritterCount >= iMaxCritterCount*10)
|
|
||||||
shouldTryAgain = false
|
|
||||||
return false
|
|
||||||
endif
|
|
||||||
|
|
||||||
if (!bAllowRespawn && (iSpawnedCritterCount >= iMaxCritterCount))
|
|
||||||
shouldTryAgain = false
|
|
||||||
return false
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ParentCell != none
|
|
||||||
float distance = GetPlayerDistance()
|
|
||||||
if !self.is3dLoaded() || ( distance > fMaxPlayerDistance)
|
|
||||||
extraWaitTime = 2.0
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
if (bReducedRespawn && iDeadCritterCount > 0 && distance <= fMaxPlayerDistance*0.75 )
|
|
||||||
if (Randomfloat(1 )>0.99 && !PlayerRef.HasLos(self))
|
|
||||||
extraWaitTime = 0.0
|
|
||||||
else
|
|
||||||
extraWaitTime = 2.0
|
|
||||||
return false
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
extraWaitTime = 0.0
|
|
||||||
endif
|
|
||||||
endIf
|
|
||||||
return IsActiveTime() && CustomCheck()
|
|
||||||
else
|
|
||||||
shouldTryAgain = false
|
|
||||||
return false
|
|
||||||
endif
|
|
||||||
endFunction
|
|
||||||
|
|
||||||
function SetExtraWaitTime(float t)
|
; Set initial variables on the critter
|
||||||
extraWaitTime = t
|
; ; Debug.TraceConditional("Spawner " + self + " is creating Critter " + thecritter, bPrintDebug);
|
||||||
endFunction
|
thecritter.SetInitialSpawnerProperties(fLeashLength, fLeashHeight, fLeashDepth, fMaxPlayerDistance + fLeashLength, self)
|
||||||
function ClearExtraWaitTime()
|
|
||||||
extraWaitTime = 0
|
|
||||||
endFunction
|
|
||||||
|
|
||||||
|
; Increment count [USKP 2.0.1]
|
||||||
;Custom method to override in custom scripts
|
iCurrentCritterCount += 1
|
||||||
bool Function CustomCheck()
|
|
||||||
return true
|
return true
|
||||||
endFunction
|
endFunction
|
||||||
|
|
||||||
bool Function IsActiveTime()
|
; Utility method that returns the player's distance
|
||||||
if VanillaLoopBreak()
|
float Function GetPlayerDistance()
|
||||||
|
return Game.GetPlayer().GetDistance(self)
|
||||||
|
endFunction
|
||||||
|
|
||||||
|
; Utility method that tells the spawner whether it should spawn critters
|
||||||
|
bool Function ShouldSpawn()
|
||||||
|
;DREW - Added an extra safety measure for if the object is stuck in the spawn check loop while the 3d is not loaded
|
||||||
|
; NOTE - is3dLoaded dumps an error when the 3d is not loaded, but the function still returns false which should
|
||||||
|
; set bLooping to false and jump out of the bLooping While, at which point no additional errors will be thrown
|
||||||
|
; GetParentCell check first helps avoid error log in exteriors? [USKP 2.0.1]
|
||||||
|
if self.GetParentCell() && self.is3dLoaded()
|
||||||
|
if !(GetPlayerDistance() <= fMaxPlayerDistance)
|
||||||
|
return false
|
||||||
|
endIf
|
||||||
|
; Otherwise, base value on time of day (no handling of wrap around though...)
|
||||||
|
return IsActiveTime()
|
||||||
|
else ;if the 3d is not loaded jump out of the looped state. Just an extra safety measure.
|
||||||
|
; ;debug.Trace(self + ": should be setting bLooping to False")
|
||||||
|
bLooping = FALSE
|
||||||
return false
|
return false
|
||||||
endif
|
endif
|
||||||
bool binTimeRange = (fEndSpawnTime != fStartSpawnTime) ;dont bother reading or checking for Gamehour if not timeframe is set
|
endFunction
|
||||||
|
|
||||||
if (binTimeRange)
|
bool Function IsActiveTime()
|
||||||
if GameHour
|
bool binTimeRange = false
|
||||||
float GameHourf = GameHour.GetValue()
|
|
||||||
if (fEndSpawnTime >= fStartSpawnTime)
|
; BUGFIX BY STEVE40 - I found one case in Hearthfire where Bethesda didn't set the GameHour property on the script, causing it to spam the logs
|
||||||
binTimeRange = (GameHourf >= fStartSpawnTime) && (GameHourf < fEndSpawnTime)
|
if GameHour == none
|
||||||
else
|
bLooping = False ; kill the script
|
||||||
binTimeRange = (GameHourf >= fStartSpawnTime) || (GameHourf < fEndSpawnTime)
|
return false
|
||||||
endIf
|
endIf
|
||||||
else
|
|
||||||
shouldTryAgain = false ;spawner not set up properly, stop it
|
if (fEndSpawnTime >= fStartSpawnTime)
|
||||||
Debug.Trace("CritterSpawn :" + self + " spawner not set up properly, has a timerane while missing the GameHourf property");
|
binTimeRange = (GameHour.GetValue() >= fStartSpawnTime) && (GameHour.GetValue() < fEndSpawnTime)
|
||||||
|
else
|
||||||
return false
|
binTimeRange = (GameHour.GetValue() >= fStartSpawnTime) || (GameHour.GetValue() < fEndSpawnTime)
|
||||||
endif
|
endIf
|
||||||
endif
|
return binTimeRange && ((Weather.GetCurrentWeather() == none) || \
|
||||||
|
(Weather.GetCurrentWeather().GetClassification() < 2) || \
|
||||||
if (binTimeRange)
|
(bSpawnInPrecipitation == TRUE))
|
||||||
if (bSpawnInPrecipitation) ;dont check for weather condition if not needed
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
Weather W = Weather.GetCurrentWeather()
|
|
||||||
return !W || (W.GetClassification() < 2)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return false
|
|
||||||
endFunction
|
endFunction
|
||||||
|
Loading…
Reference in New Issue
Block a user