Jump to content

SexoutNG pseudo save/load support


prideslayer

Recommended Posts

Posted

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.

Posted

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.

Posted

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.

Posted

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.

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...