prideslayer Posted August 12, 2012 Posted August 12, 2012 Most of you know I have save/load/new game support in a private build of NVSE, and I'm waiting on the silverlock team to get back to me with my patch request to add it to the official release. I plan to give them another week to at least respond before releasing my own build of NVSE (which NVSE Extender v10 will require). Without this support in NVSE, using NX for persistent data is basically impossible. NX_Set* variable persistence is almost exactly the opposite of what we need in order for it to really be useful -- When you first start FONV all NX vars are empty. If you load a game where something had set them, they are still empty. If a mod sets them (as sexout does), and then a game is loaded, they are still set even if they are irrelevant to the game that was just loaded. While waiting on a response (or my deadline) to get this support into NVSE, I've come up with a reasonable work around that I'm going to put into sexout as a trial run. This thread describes how the system works (it's simple, trust me), and how other modders can use it in their own mods. I advise those of you using NX vars to read this, but not to actually implement this until I'm at least sure it works in sexout itself. It should, but you never know. If you're very enterprising, create a test mod that implements this and report any issues you find. Short Version A scripted item is added to the actors inventory when sex starts. Saving: The script continually does an NX_Get* of all the vars it knows about. Loading: The script continuously checks GetGameLoaded and GetGameRestarted, similar to a quest init script. Whenever this block is entered, all defined NX variables on the actor are re-set from the values stored locally in the script. Cleanup: NX vars are cleared via NX_Clr* functions and the token removes itself. In the sexout version of this token, used for saving/loading sexout state, this occurs if the InUse flag gets unset on the actor. Long Version: The item script is a standard (for me) staged GameMode script. OnAdd and OnDrop are not used because they're unreliable in some cases. As usual, I order the stages from highest to lowest, and set the init stage early. I also delay at least 1 second between runs while in stage 1 (the main stage). At present the stages are: 0 : Initial setup. Sets stage to 100, then if the container is a valid actor, sets the stage to 1. 1 : Normal running stage. This stage first checks to see if the actors InUse flag is set. If not, stage is set to 100. If the inuse flag is set, then an if/else load detection block is entered. If the game was loaded, then all NX vars are set to the stored values, if not, all NX vars are saved and delay is reset. 100 : Shutting down. This stage is reached if the container is not a valid actor, or the container is a valid actor but the inuse flag is not set. The next stage is set to 200, and then actor validity is double-checked. If the actor is valid, the stage is set to 101. 101 : Stage set to 200, NX Sexout vars are cleared. 200 : Stage is set to -1 (a nonsense value), and RemoveMe is called. Overall the code skeleton looks like this: Begin GameMode set gsp to GetSecondsPassed if ((fDelay - gsp) > 0) set fDelay to fDelay - gsp Return endif if (200 == bInit) ; Done, remove self set bInit to -1 ; nonsense value RemoveMe elseif (101 == bInit) ; Clear all sexout stuff set bInit to 200 self.NX_ClrEVFl "Sexout:Start" self.NX_ClrEVFo "Sexout:Start" elseif (100 == bInit) ; Prepping to remove self set bInit to 200 ; failsafe if (0 != self) if (isReference self) if (self.isActor) ; safe to clear set bInit to 101 endif endif endif elseif (1 == bInit) set iAV to self.GetAV Variable04 if (0 == (LogicalAnd iAV SexoutNG.FlagInUse)) ; No longer in use, clean up set bInit to 100 else if (GetGameLoaded || GetGameRestarted) ; We have been loaded, restore values to NX. set self to GetContainer self.NX_SetEVFl "Sexout:...." endif ; Set delay for next run set fDelay to 1 ; Save NX vars to local copy set var to self.NX_GetEVFl "Sexout:...." endif elseif (0 == bInit) set bInit to 100 ; failsafe set self to GetContainer set fDelay to 0 if (0 != self) if (isReference self) if (self.isActor) ; safe to use set bInit to 1 endif endif endif endif End ; GameMode I am pretty sure that this idea is going to work as intended. If it does, then other mods can do something similar with tokens of their own. Those mods may not even have to 'removeme' except on actor death, and each mod that wants to save data in this way will only need one token.
prideslayer Posted August 12, 2012 Author Posted August 12, 2012 Note there will be a slight change to this script, as I will check for the presence of an NX var in addition to the game loaded/restarted check for that block, otherwise that block is going to fire when the token is first added. I'm modifying the base effect script to set that value up in NX so it will be there when the token is added, but not if the game is loaded.
prideslayer Posted August 12, 2012 Author Posted August 12, 2012 Seems to be working fine after adding an initial delay to the script. For whatever reason, first frame of gamemode or so after the item is added, getcontainer is 0. Added an onadd block that just sets self, then this block to the top of the script after the gsp and delay check.. set elapsed to elapsed + gsp if ((0 == self) && (0.5 > elapsed)) set self to GetContainer Return endif Gives it half a second to respond correctly before hitting the ref checks in stage 0 and aborting.
prideslayer Posted August 12, 2012 Author Posted August 12, 2012 Full script from the current beta (69b6) here: scn SexoutNGSaverTokenSCRIPT ref self int bInit int iAV int bSaver float gsp float fdelay float elapsed int bLoaded int bDoTFC ref refSpellTarget ref male ref female ref raper int anim int sextype ref CBDialogM ref CBDialogF ref CBSpellM ref CBSpellF ref CBItemM ref CBItemF ref CBPackM ref CBPackF float duration ref actorA ref actorB ref actorC ref actorX int animA int animB int animC int isAnal int isOral int isVaginal float fHOffsetA float fHOffsetB float fHOffsetC float fVOffsetA float fVOffsetB float fVOffsetC int bDontUndressA int bDontUndressB int bDontUndressC int bDontRedressA int bDontRedressB int bDontRedressC ref bodyA ref bodyB ref bodyC ref CBDialogA ref CBDialogB ref CBDialogC ref CBDialogX ref CBSpellA ref CBSpellB ref CBSpellC ref CBSpellX ref CBItemA ref CBItemB ref CBItemC ref CBItemX ref CBPackA ref CBPackB ref CBPackC ref CBPackX ref refSurface float fSurfaceX float fSurfaceY float fSurfaceZ float fSurfaceAngle int noAnim int nUseZAZ int bActorAmale int bActorABCr int bActorBmale int bActorCmale int bCanOral int bCanVaginal int bCanAnal float fX float fY float fZ int spunTargets Begin OnAdd set self to GetContainer End ; OnAdd Begin GameMode set gsp to GetSecondsPassed if (GetGameLoaded || GetGameRestarted) set bLoaded to 1 set bDoTFC to 1 endif set elapsed to elapsed + gsp ; If we're loaded and have not tfcd yet, delay if ((1 == bLoaded) && (1 == bDoTFC)) set bDoTFC to 2 set fDelay to 2.5 Return endif ; General delay if ((fDelay - gsp) > 0) set fDelay to fDelay - gsp Return endif ; Do TFC if we need to if ((self == playerREF) && (2 == bDoTFC)) set bDoTFC to 0 con_tfc endif if ((0 == self) && (0.5 > elapsed)) set self to GetContainer Return endif if (200 == bInit) ; Done, remove self set bInit to -1 ; nonsense value RemoveMe elseif (101 == bInit) ; Clear all sexout stuff set bInit to 200 self.NX_ClrEVFl "Sexout:Start" self.NX_ClrEVFo "Sexout:Start" elseif (100 == bInit) ; Prepping to remove self set bInit to 200 ; failsafe if (self) if (isReference self) if (self.isActor) ; safe to clear set bInit to 101 endif endif endif elseif (1 == bInit) set iAV to self.GetAV Variable04 if (0 == (LogicalAnd iAV SexoutNG.FlagInUse)) ; No longer in use, clean up set bInit to 100 else if (bLoaded) ; We have been loaded, restore values to NX. set bLoaded to 0 set bSaver to self.NX_GetEVFl "Sexout:Saver" if (0 == bSaver) self.NX_SetEVFl "Sexout:Saver" 1 self.NX_SetEVFo "Sexout:Start::spellTarget" refSpellTarget self.NX_SetEVFo "Sexout:Start::raper" raper self.NX_SetEVFl "Sexout:Start::duration" duration self.NX_SetEVFl "Sexout:Start::isAnal" isAnal self.NX_SetEVFl "Sexout:Start::isVaginal" isVaginal self.NX_SetEVFl "Sexout:Start::isOral" isOral self.NX_SetEVFo "Sexout:Start::actorA" actorA self.NX_SetEVFo "Sexout:Start::actorB" actorB self.NX_SetEVFo "Sexout:Start::actorC" actorC self.NX_SetEVFo "Sexout:Start::actorX" actorX self.NX_SetEVFl "Sexout:Start::animA" animA self.NX_SetEVFl "Sexout:Start::animB" animB self.NX_SetEVFl "Sexout:Start::animC" animC self.NX_SetEVFl "Sexout:Start::fHOffsetA" fHOffsetA self.NX_SetEVFl "Sexout:Start::fHOffsetB" fHOffsetB self.NX_SetEVFl "Sexout:Start::fHOffsetC" fHOffsetC self.NX_SetEVFl "Sexout:Start::fVOffsetA" fVOffsetA self.NX_SetEVFl "Sexout:Start::fVOffsetB" fVOffsetB self.NX_SetEVFl "Sexout:Start::fVOffsetC" fVOffsetC self.NX_SetEVFl "Sexout:Start::bDontUndressA" bDontUndressA self.NX_SetEVFl "Sexout:Start::bDontUndressB" bDontUndressB self.NX_SetEVFl "Sexout:Start::bDontUndressC" bDontUndressC self.NX_SetEVFl "Sexout:Start::bDontRedressA" bDontRedressA self.NX_SetEVFl "Sexout:Start::bDontRedressB" bDontRedressB self.NX_SetEVFl "Sexout:Start::bDontREdressC" bDontREdressC self.NX_SetEVFo "Sexout:Start::bodyA" bodyA self.NX_SetEVFo "Sexout:Start::bodyB" bodyB self.NX_SetEVFo "Sexout:Start::bodyC" bodyC self.NX_SetEVFo "Sexout:Start::CBDialogA" CBDialogA self.NX_SetEVFo "Sexout:Start::CBDialogB" CBDialogB self.NX_SetEVFo "Sexout:Start::CBDialogC" CBDialogC self.NX_SetEVFo "Sexout:Start::CBDialogX" CBDialogX self.NX_SetEVFo "Sexout:Start::CBSpellA" CBSpellA self.NX_SetEVFo "Sexout:Start::CBSpellB" CBSpellB self.NX_SetEVFo "Sexout:Start::CBSpellC" CBSpellC self.NX_SetEVFo "Sexout:Start::CBSpellX" CBSpellX self.NX_SetEVFo "Sexout:Start::CBItemA" CBItemA self.NX_SetEVFo "Sexout:Start::CBItemB" CBItemB self.NX_SetEVFo "Sexout:Start::CBItemC" CBItemC self.NX_SetEVFo "Sexout:Start::CBItemX" CBItemX self.NX_SetEVFo "Sexout:Start::CBPackA" CBPackA self.NX_SetEVFo "Sexout:Start::CBPackB" CBPackB self.NX_SetEVFo "Sexout:Start::CBPackC" CBPackC self.NX_SetEVFo "Sexout:Start::CBPackX" CBPackX self.NX_SetEVFo "Sexout:Start::refSurface" refSurface self.NX_SetEVFl "Sexout:Start::fSurfaceX" fSurfaceX self.NX_SetEVFl "Sexout:Start::fSurfaceY" fSurfaceY self.NX_SetEVFl "Sexout:Start::fSurfaceZ" fSurfaceZ self.NX_SetEVFl "Sexout:Start::fSurfaceAngle" fSurfaceAngle self.NX_SetEVFl "Sexout:Start::noAnim" noAnim self.NX_SetEVFl "Sexout:Start::nUseZAZ" nUseZAZ self.NX_SetEVFl "Sexout:Start::bActorAmale" bActorAmale self.NX_SetEVFl "Sexout:Start::bActorAblockCrotch" bActorABCr self.NX_SetEVFl "Sexout:Start::bActorBmale" bActorBmale self.NX_SetEVFl "Sexout:Start::bActorCmale" bActorCmale self.NX_SetEVFl "Sexout:Start::bCanOral" bCanOral self.NX_SetEVFl "Sexout:Start::bCanVaginal" bCanVaginal self.NX_SetEVFl "Sexout:Start::bCanAnal" bCanAnal self.NX_SetEVFl "Sexout:Start::focusX" fX self.NX_SetEVFl "Sexout:Start::focusY" fY self.NX_SetEVFl "Sexout:Start::focusZ" fZ self.NX_SetEVFl "Sexout:Core:Sextype:Vaginal" isVaginal self.NX_SetEVFl "Sexout:Core:Sextype:Anal" isAnal self.NX_SetEVFl "Sexout:Core:Sextype:Oral" isOral self.NX_SetEVFl "Sexout:Core:Actors:Count" spunTargets self.NX_SetEVFo "Sexout:Core:Partners:A" actorA self.NX_SetEVFo "Sexout:Core:Partners:B" actorB self.NX_SetEVFo "Sexout:Core:Partners:C" actorC endif endif ; Set delay for next run set fDelay to 0.5 ; Save NX vars to local copy set refSpellTarget to self.NX_GetEVFo "Sexout:Start::spellTarget" set raper to self.NX_GetEVFo "Sexout:Start::raper" set duration to self.NX_GetEVFl "Sexout:Start::duration" set isAnal to self.NX_GetEVFl "Sexout:Start::isAnal" set isVaginal to self.NX_GetEVFl "Sexout:Start::isVaginal" set isOral to self.NX_GetEVFl "Sexout:Start::isOral" set actorA to self.NX_GetEVFo "Sexout:Start::actorA" set actorB to self.NX_GetEVFo "Sexout:Start::actorB" set actorC to self.NX_GetEVFo "Sexout:Start::actorC" set actorX to self.NX_GetEVFo "Sexout:Start::actorX" set animA to self.NX_GetEVFl "Sexout:Start::animA" set animB to self.NX_GetEVFl "Sexout:Start::animB" set animC to self.NX_GetEVFl "Sexout:Start::animC" set fHOffsetA to self.NX_GetEVFl "Sexout:Start::fHOffsetA" set fHOffsetB to self.NX_GetEVFl "Sexout:Start::fHOffsetB" set fHOffsetC to self.NX_GetEVFl "Sexout:Start::fHOffsetC" set fVOffsetA to self.NX_GetEVFl "Sexout:Start::fVOffsetA" set fVOffsetB to self.NX_GetEVFl "Sexout:Start::fVOffsetB" set fVOffsetC to self.NX_GetEVFl "Sexout:Start::fVOffsetC" set bDontUndressA to self.NX_GetEVFl "Sexout:Start::bDontUndressA" set bDontUndressB to self.NX_GetEVFl "Sexout:Start::bDontUndressB" set bDontUndressC to self.NX_GetEVFl "Sexout:Start::bDontUndressC" set bDontRedressA to self.NX_GetEVFl "Sexout:Start::bDontRedressA" set bDontRedressB to self.NX_GetEVFl "Sexout:Start::bDontRedressB" set bDontREdressC to self.NX_GetEVFl "Sexout:Start::bDontREdressC" set bodyA to self.NX_GetEVFo "Sexout:Start::bodyA" set bodyB to self.NX_GetEVFo "Sexout:Start::bodyB" set bodyC to self.NX_GetEVFo "Sexout:Start::bodyC" set CBDialogA to self.NX_GetEVFo "Sexout:Start::CBDialogA" set CBDialogB to self.NX_GetEVFo "Sexout:Start::CBDialogB" set CBDialogC to self.NX_GetEVFo "Sexout:Start::CBDialogC" set CBDialogX to self.NX_GetEVFo "Sexout:Start::CBDialogX" set CBSpellA to self.NX_GetEVFo "Sexout:Start::CBSpellA" set CBSpellB to self.NX_GetEVFo "Sexout:Start::CBSpellB" set CBSpellC to self.NX_GetEVFo "Sexout:Start::CBSpellC" set CBSpellX to self.NX_GetEVFo "Sexout:Start::CBSpellX" set CBItemA to self.NX_GetEVFo "Sexout:Start::CBItemA" set CBItemB to self.NX_GetEVFo "Sexout:Start::CBItemB" set CBItemC to self.NX_GetEVFo "Sexout:Start::CBItemC" set CBItemX to self.NX_GetEVFo "Sexout:Start::CBItemX" set CBPackA to self.NX_GetEVFo "Sexout:Start::CBPackA" set CBPackB to self.NX_GetEVFo "Sexout:Start::CBPackB" set CBPackC to self.NX_GetEVFo "Sexout:Start::CBPackC" set CBPackX to self.NX_GetEVFo "Sexout:Start::CBPackX" set refSurface to self.NX_GetEVFo "Sexout:Start::refSurface" set fSurfaceX to self.NX_GetEVFl "Sexout:Start::fSurfaceX" set fSurfaceY to self.NX_GetEVFl "Sexout:Start::fSurfaceY" set fSurfaceZ to self.NX_GetEVFl "Sexout:Start::fSurfaceZ" set fSurfaceAngle to self.NX_GetEVFl "Sexout:Start::fSurfaceAngle" set noAnim to self.NX_GetEVFl "Sexout:Start::noAnim" set nUseZAZ to self.NX_GetEVFl "Sexout:Start::nUseZAZ" set bActorAmale to self.NX_GetEVFl "Sexout:Start::bActorAmale" set bActorABCr to self.NX_GetEVFl "Sexout:Start::bActorAblockCrotch" set bActorBmale to self.NX_GetEVFl "Sexout:Start::bActorBmale" set bActorCmale to self.NX_GetEVFl "Sexout:Start::bActorCmale" set bCanOral to self.NX_GetEVFl "Sexout:Start::bCanOral" set bCanVaginal to self.NX_GetEVFl "Sexout:Start::bCanVaginal" set bCanAnal to self.NX_GetEVFl "Sexout:Start::bCanAnal" set fX to self.NX_GetEVFl "Sexout:Start::focusX" set fY to self.NX_GetEVFl "Sexout:Start::focusY" set fZ to self.NX_GetEVFl "Sexout:Start::focusZ" set spunTargets to self.NX_GetEVFl "Sexout:Core:Actors:Count" endif elseif (0 == bInit) set bInit to 100 ; failsafe set self to GetContainer set fDelay to 0 if (self) if (isReference self) if (self.isActor) ; safe to use set bInit to 1 endif endif endif endif End ; GameMode Tested and seemed to work ok. It will bring you back into TFC if the player is having sex in the save, just takes it a moment.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.