I'm starting to need OBSE's OnGameLoaded functions.
This is the closest I've come to emulating this. Is there a better way?
Attached is the main Quest Script and the Player Script for my Eat, Drink and Sleep mod.
However, I also use this code in 4 other mods.
Scriptname kuEASQSMain extends Quest Function debugTrace (String debugMessage, Int debugLevel = 1, Bool notify = False) If debugMode && debugMode >= debugLevel If notify Debug.Notification ("!kuEASQSMain." + debugMessage) EndIf Debug.Trace ("!kuEASQSMain." + debugMessage) EndIfEndFunction;these are version-control variables and properties.;best that these are not changed or removed.;mod-specific variables are listed below - closer to the initialisation functions for ease of editing.Bool Property started AutoFloat versionFloat lastVersionFloat lastOnUpdateTimeUpdateBool Property resetNow AutoInt Property debugMode AutoInt Property testCase AutoBool stoppedThenStartedFloat updateIntervalBool Property uninstallNow AutoInt menuModeBool initedMQ00QuestScript Property questMQ00 Auto;set this property to point to MQ00Event OnInit () ;because OnInit () executes twice the first time around: http://www.creationkit.com/OnInit.html, ;a variable is set to prevent it doing anything the 2nd time even if what it does is to register an update. If !inited inited = True Int oldDebugMode = debugMode ;show debugs in the log during initialisations. the current debugMode is saved. ;and the debugMode set high, so that debugs are logged. debugMode = 10 debugTrace ("OnInit") RegisterForSingleUpdate (1) ;restore the previous debugMode. debugMode = oldDebugMode EndIfEndEventEvent OnMenuMode (Int id = 1) If menuMode != id menuMode = id debugTrace ("OnMenuMode " + menuMode) EndIfEndEventEvent OnUpdate () ;set version and update interval ;in MQ00 Stage 5, it is suggested that some things shouldn't start at Start Game Enabled. ;so I simply, check for this and not do anycode unless MQ00 is at stage 5 and over. version = 0.53 updateInterval = 1 If questMQ00.GetStage () >= 5 Float timeNow = Utility.GetCurrentRealTime () If !menuMode && Math.abs (timeNow - lastOnUpdateTimeUpdate) > 60 ;if current number of seconds is > 1 minute from the last recorded second in the game, it's ;likely that the game was reloaded. initGameLoaded () ElseIf version != lastVersion || resetNow ;there is a new version. or the player manually reset the mod by typing in the console: ;SETPQV RESETNOW TRUE initGameLoaded () ElseIf uninstallNow debugTrace ("OnUpdate uninstall") uninstallNow = False uninstall () debugTrace ("uninstalled", 0, True) Stop () Else ;tick () is the main update function. ;add your code in that function instead of here, to keep this starting block free of ;mod-specific code. tick () ;register only for a single update. ;if RegisterForUpdate () is used, and the mod is deactivated, the Event manager will keep ;send OnUpdate () Event to the deactivated mod. problems will occur. ;with RegisterForSingleUpdate (), if the mod is deactivated, the Event manager will fail ;only once. RegisterForSingleUpdate (updateInterval) EndIf ;save the current number of seconds since game-start. lastOnUpdateTimeUpdate = timeNow menuMode = 0 Else RegisterForSingleUpdate (updateInterval) EndIfEndEventFunction initGameLoaded () Int oldDebugMode = debugMode ;show debugs in the log during initialisations. debugMode = 10 Bool newReset If version != lastVersion || !started || resetNow If lastVersion && !stoppedThenStarted ;if the mod was previously installed (i.e. lastVersion is set), then reset the mod ;calling Stop () and Start (). ;because aliases are only ever filled at OnInit () Event, this is needed in case the ;updates adds or removes new aliases. debugTrace ("initGameLoaded reset from v" + lastVersion + " to v" + version) ;do uninstall procedure uninstall (True) inited = False UnregisterForUpdate () Stop () Utility.Wait (1) ;Start () will reinitiate the OnInit () Event. Start () stoppedThenStarted = True newReset = True Else ;this is a new mod activation or a player initiated reset. debugTrace ("initGameLoaded init v" + version) stoppedThenStarted = False lastVersion = version resetNow = False initNewVersion () started = True EndIf EndIf If !newReset ;if the game wasn't reset above (i.e. Stop () and Start () wasn't called), then this ;must be a normal game load. debugTrace ("initGameLoaded loaded v" + version) initNewGameLoad () ;RegisterForSingleUpdate () needed here because RegisterForSingleUpdate (1) EndIf debugMode = oldDebugModeEndFunctionFunction initNewVersion () If !started ;initialise user customisable properties here. ;checking started variable ensures that any updates to the mod will not change user customisations. userEndureMaxHours = 12 userEndureMaxLevel = 25 EndIf ;do other initialisations here autoEatQuest.initNewVersion () eatQuest.initNewVersion () sleepQuest.initNewVersion ()EndFunctionFunction initNewGameLoad () ;initialise any game-load specific stuff here. autoEatQuest.initNewGameLoad () eatQuest.initNewGameLoad () sleepQuest.initNewGameLoad ()EndFunctionFunction uninstall (Bool resetting = False) debugTrace ("uninstall") eatQuest.uninstall () sleepQuest.uninstall () aliasesQuest.UnregisterForUpdate () aliasesQuest.Stop () If !resetting uninstallMessage.Show () EndIfEndFunction;listed here are the mod-specific variables.;it's closer to the initialisation functions for ease of code editing.kuEASAutoEatQS Property autoEatQuest AutokuEASQSEat Property eatQuest AutokuEASQSSleep Property sleepQuest AutoMessage Property uninstallMessage AutoFloat Property userEndureMaxHours AutoFloat Property userEndureMaxLevel AutoFloat Property userEndureEffectsFactor AutoQuest Property aliasesQuest AutoFunction tick () ;this is the main interval code. autoEatQuest.tick () eatQuest.tick () sleepQuest.tick () If testCase doTestCase (testCase) testCase = 0 EndIfEndFunctionFunction doTestCase (Int testCaseToDo) ;if i need to do any "unit tests", i do it with this: ;SETPQV questname testCase testnumber Int oldDebugMode = debugMode debugMode = 10 debugTrace ("doTest " + testCaseToDo) If testCaseToDo == 1 autoEatQuest.populateFoodRefs () EndIf Debug.Notification ("!kuEASAutoEatQS.doTestCase " + testCaseToDo + " done.") debugMode = oldDebugModeEndFunction In another Script attached to a Player Alias:
Scriptname kuEASPlayerS extends ReferenceAlias{kuertee eat and sleep player script}kuEASQSEat Property eatQuest AutoEvent OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) ;;eating from inventory - a sample code specific to the mod ;eatQuest.debugTrace ("kuEASPlayerS.OnItemRemoved " + akBaseItem + ", " + aiItemCount) ;FormList foodList = eatQuest.foodList ;FormList drinkList = eatQuest.drinkList ;If foodList.HasForm (akBaseItem) || drinkList.HasForm (akBaseItem) ; If !akItemReference && !akDestContainer ; eatQuest.eatFood (akBaseItem, aiItemCount) ; EndIf ;EndIf checkMenuMode ()EndEventFunction checkMenuMode (Int menuModeId = 1) ;sets menumode to 1 in the main quest if player inventory changes. ;this prevents initGameLoaded () from executing if the player stays in MenuMode for more than 60 seconds. kuEASQSMain mainQuest = GetOwningQuest () as kuEASQSMain If Utility.IsInMenuMode () mainQuest.OnMenuMode (menuModeId) EndIfEndFunctionEvent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) checkMenuMode ()EndEventEvent OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) checkMenuMode ()EndEventEvent OnObjectEquipped(Form akBaseObject, ObjectReference akReference) checkMenuMode ()EndEventEvent OnObjectUnequipped(Form akBaseObject, ObjectReference akReference) checkMenuMode ()EndEventIs there a better way? Have I missed something in the CK?
This new version is 99% accurate in determining these events:
- first mod activation calls initNewVersion ()
- every game load calls initNewGameLoad()
- user-triggered uninstallation via SETPQV calls uninstall ()
- when a new version is activated over the old version, it calls uninstall (), initNewVersion (), initNewGameLoad () while keeping user customisations intact
How I use this Script:
- I copy everything to a new Quest Script.
- I declare mod-specific variables.
- I change the code in initNewVersion (), initNewGameLoad (), uninstall (), tick () and doTestCase ().
- When I need a debug traced, I use debugTrace () instead of Debug.Trace () or Debug.Notification ().
Also, as suggested above, my mods can have user customisations via SETPQV.
In the example above, they can set the endure time of effects of being hungry, thirsty and exhausted.
I've found work-arounds for the problems previously listed.
So I've hidden them in a spoiler tag.
I can't rely on OnInit () because it only fires when the mod is first activated. So any initialisations attached to that during development will get initialised once only. And during development, variables change - a lot. So if once changes and I add it to OnInit (), my next play-test will not initialise that variable properly - because OnInit () was already triggered in a previous game.
Problems:
1. Because OnUpdate only runs in game time (i.e. not in MenuMode), initGameLoaded () will fire if the player stays in MenuMode for more than 60 seconds.
2. If the player stays on the Main Menu before loading a game for more than 10 seconds, initGameRestarted () will not execute.
3. Also, initGameRestarted () will not execute except for the first game loaded.
Luckily, I've not needed initGameRestarted () yet.
And initGameLoaded () firing if I stay in MenuMode for more than 60 seconds is simply an inconvenience.
(i.e. my variables do not initialise because "started" variable is set.)
