Jump to content

Convert a base form to a persistent reference temporarily?


HerrBaron

Recommended Posts

  • Replies 42
  • Created
  • Last Reply

Top Posters In This Topic

You only need one form list as storage; declare it in your mod. Put one blank item in it as a placeholder as suggested by rickerhk in the bethsoft thread.

 

David, any idea if the TempCloneForm NVSE function has ever actually been there? GECK with GeckPU doesn't seem to know about it...?

 

Thanks for the link; just checked it out. BTW, I'm gonna grab your quest mod as soon as I get back to playing instead of modding... :)

Link to comment
Share on other sites

I have actively avoided learning about NVSE so far. Looking forward to feedback (and an endorsement, if you like it) for Decisions With Regrets.

 

No doubt you've earned it; I suspect it's a very polished mod, and I respect the work that goes into those. Understand how you feel about NVSE, but there are some things you just can't accomplish without it. I resisted modding with it for a long time, myself, but as I got deeper into modding it, I found that there are a whole range of hoops you don't have to jump through with NVSE, and since most folks have it installed, I got over my qualms.

 

My only issue with it, seriously, is that the form list support is so buggy; lists are essential in data processing; they're a natural data structure for a broad range of ComSci issues. They even invented a language once to work with them; it was called LISP. It didn't do much else well, but it did lists superbly...! :)

Link to comment
Share on other sites

Here's some more info that might help in regards to clearing a list populated with Base forms. I've set up some test scripts and can manipulate base forms up until I try to remove a form - If I do the removal within a Label/Goto loop, one form will be removed, then the loop will abort. Any loop after that in the same script will also abort after one list function. I haven't checked if the list would be ok in subsequent frames for access, but a listcount is accurate. It does this in FOSE and NVSE.

 

If I re-arrange the script, removing the Label/Goto loop so that one form is removed per frame, I can clear the list.

 

This snippet aborts the loop after removing one Form:

 

Label 300
if (iIndex)
set iIndex to iIndex - 1
set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
set iRemoveResult to ListRemoveNthForm RHKTestBaseFormList iIndex
PrintToConsole "Remove Form Index %.0f Remove Result %.0f", iIndex, iRemoveResult
Goto 300
endif

 

 

Doing it this way clears the list:

 

scn RHKTestBaseFormsQuestScript2

ref rBaseObjREF
ref rReadFormREF
short iIndex
short iRemoveResult
short iFormCount
short iClearForm
short iMenuInit

;Populate a list, read it back, then clear it
;Call with ResetQuest, then iMenuInit == 1, StartQuest
;Questdelay .033


BEGIN GameMode

  if (iMenuInit == 1)

   set rBaseObjREF to BehemothFireHydrant
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to CG02WeapBBGun
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to BMWeapNailBoard
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to LakelurkSonic2HL
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to MisterGutsyPlasma1HP
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to NellisArtillery
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to Weap10mmSubmachineGun
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapFatman
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapNVBallisticFist
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapNVCaravanShotgun
   ListAddForm RHKTestBaseFormList rBaseObjREF    

     
   set iFormCount to ListGetCount RHKTestBaseFormList

   set iIndex to iFormCount
   
   PrintToConsole "Form Count after Adds %.0f ", iFormCount

   
   Label 100
   if (iIndex)
    set iIndex to iIndex - 1
    set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
    PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
    Goto 100
   endif
   
   set iMenuInit to 2
   set iClearForm to 1

  
  elseif (iMenuInit == 2)
  
   if (iClearForm)
    if (iFormCount)
     set iRemoveResult to ListRemoveNthForm RHKTestBaseFormList 0 ;Clear index zero, stuff moves up
     set iFormCount to iFormCount - 1
     PrintToConsole "Removed form %.0f", iFormCount
     if (iFormCount == 0)
      set iClearForm to 0
     endif
    endif
   else
    set iFormCount to ListGetCount RHKTestBaseFormList
    
    PrintToConsole "Form Count after del %.0f", iFormCount
    
    set iIndex to iFormCount

    Label 400
    if (iIndex)
     set iIndex to iIndex - 1
    set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
     PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
     Goto 400
    endif 


    StopQuest RHKFormTestMenu

    set iMenuInit to 0
   endif

  endif
 
END

 

 

 

 

Link to comment
Share on other sites

Here's some more info that might help in regards to clearing a list populated with Base forms. I've set up some test scripts and can manipulate base forms up until I try to remove a form - If I do the removal within a Label/Goto loop, one form will be removed, then the loop will abort. Any loop after that in the same script will also abort after one list function. I haven't checked if the list would be ok in subsequent frames for access, but a listcount is accurate. It does this in FOSE and NVSE.

 

If I re-arrange the script, removing the Label/Goto loop so that one form is removed per frame, I can clear the list.

 

This snippet aborts the loop after removing one Form:

 

Label 300
if (iIndex)
set iIndex to iIndex - 1
set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
set iRemoveResult to ListRemoveNthForm RHKTestBaseFormList iIndex
PrintToConsole "Remove Form Index %.0f Remove Result %.0f", iIndex, iRemoveResult
Goto 300
endif

 

 

Doing it this way clears the list:

 

scn RHKTestBaseFormsQuestScript2

ref rBaseObjREF
ref rReadFormREF
short iIndex
short iRemoveResult
short iFormCount
short iClearForm
short iMenuInit

;Populate a list, read it back, then clear it
;Call with ResetQuest, then iMenuInit == 1, StartQuest
;Questdelay .033


BEGIN GameMode

  if (iMenuInit == 1)

   set rBaseObjREF to BehemothFireHydrant
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to CG02WeapBBGun
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to BMWeapNailBoard
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to LakelurkSonic2HL
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to MisterGutsyPlasma1HP
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to NellisArtillery
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to Weap10mmSubmachineGun
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapFatman
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapNVBallisticFist
   ListAddForm RHKTestBaseFormList rBaseObjREF
   set rBaseObjREF to WeapNVCaravanShotgun
   ListAddForm RHKTestBaseFormList rBaseObjREF    

     
   set iFormCount to ListGetCount RHKTestBaseFormList

   set iIndex to iFormCount
   
   PrintToConsole "Form Count after Adds %.0f ", iFormCount

   
   Label 100
   if (iIndex)
    set iIndex to iIndex - 1
    set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
    PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
    Goto 100
   endif
   
   set iMenuInit to 2
   set iClearForm to 1

  
  elseif (iMenuInit == 2)
  
   if (iClearForm)
    if (iFormCount)
     set iRemoveResult to ListRemoveNthForm RHKTestBaseFormList 0 ;Clear index zero, stuff moves up
     set iFormCount to iFormCount - 1
     PrintToConsole "Removed form %.0f", iFormCount
     if (iFormCount == 0)
      set iClearForm to 0
     endif
    endif
   else
    set iFormCount to ListGetCount RHKTestBaseFormList
    
    PrintToConsole "Form Count after del %.0f", iFormCount
    
    set iIndex to iFormCount

    Label 400
    if (iIndex)
     set iIndex to iIndex - 1
    set rReadFormREF to ListGetNthForm RHKTestBaseFormList iIndex
     PrintToConsole "Item %n at Index %0.f", rReadFormREF, iIndex
     Goto 400
    endif 


    StopQuest RHKFormTestMenu

    set iMenuInit to 0
   endif

  endif
 
END

 

 

Hey Ricker! :)

 

Thanks for going to the trouble on this. Very revealing, in that you're doing this in a quest rather than in a block handler that's responding to an event. I note that when my script crashes (it CTD's; it doesn't just abort processing), it's always at a particular place in NVSE_1_1.dll. We know that this game engine multithreads, and I'm wondering if maybe we're hitting a threading race condition or infinite loop or a combination of the two.

 

In the next couple of days, I'm going to build a debug version of nvse_1_1.dll, and do some stepping through in the debugger with it. If I find anything, I'll post it here in this thread, and send what I find to the NVSE guys. Maybe it'll save them some time and effort.

 

BTW, you write very nice, clean code! :)

Link to comment
Share on other sites

Thanks for going to the trouble on this. Very revealing, in that you're doing this in a quest rather than in a block handler that's responding to an event.

 

Hmm - I've never run a Label/Goto Loop inside an event handler block. I don't recall clearly but I may have read that that should not be done. I just use that type of block to set things up for a gamemode or menumode block to follow.

 

I tried a similar test script on an armor token added to the player, with the same results. But generally, I use quest scripts sort of like subroutines, starting and stopping when needed. I like them because I can adjust the quest delay so they don't necessarily have to run every frame, depending on the application.

 

I note that when my script crashes (it CTD's; it doesn't just abort processing), it's always at a particular place in NVSE_1_1.dll. We know that this game engine multithreads, and I'm wondering if maybe we're hitting a threading race condition or infinite loop or a combination of the two.

 

My understanding is that all scripts are run in the same thread, sequentially. So you won't have a case where you have two scripts trying to change the same variable somewhere else at the same time, for example.

 

In the next couple of days, I'm going to build a debug version of nvse_1_1.dll, and do some stepping through in the debugger with it. If I find anything, I'll post it here in this thread, and send what I find to the NVSE guys. Maybe it'll save them some time and effort.

 

BTW, you write very nice, clean code!

 

Thanks. I think the NVSE guys could use some help because from what i've gathered, they are really busy with real-life concerns. Like work ;) That would be really cool if you could do that and they were receptive to it.

 

 

 

Link to comment
Share on other sites

Thanks for going to the trouble on this. Very revealing, in that you're doing this in a quest rather than in a block handler that's responding to an event.

 

Hmm - I've never run a Label/Goto Loop inside an event handler block. I don't recall clearly but I may have read that that should not be done. I just use that type of block to set things up for a gamemode or menumode block to follow.

 

I tried a similar test script on an armor token added to the player, with the same results. But generally, I use quest scripts sort of like subroutines, starting and stopping when needed. I like them because I can adjust the quest delay so they don't necessarily have to run every frame, depending on the application.

 

I note that when my script crashes (it CTD's; it doesn't just abort processing), it's always at a particular place in NVSE_1_1.dll. We know that this game engine multithreads, and I'm wondering if maybe we're hitting a threading race condition or infinite loop or a combination of the two.

 

My understanding is that all scripts are run in the same thread, sequentially. So you won't have a case where you have two scripts trying to change the same variable somewhere else at the same time, for example.

 

In the next couple of days, I'm going to build a debug version of nvse_1_1.dll, and do some stepping through in the debugger with it. If I find anything, I'll post it here in this thread, and send what I find to the NVSE guys. Maybe it'll save them some time and effort.

 

BTW, you write very nice, clean code!

 

Thanks. I think the NVSE guys could use some help because from what i've gathered, they are really busy with real-life concerns. Like work ;) That would be really cool if you could do that and they were receptive to it.

 

 

Ah, guess I wasn't clear; the gamemode block is where I'm doing the clear loop, not in an OnActivate or whatever. That said, I've assumed that gamemode is an event handler of sorts, just called on the basis of being there for each frame.

 

It's GREAT to know that scripts are run on the same thread sequentially; that eliminates a big worry and a great big can of worms debugging-wise...

 

Very good points about quest scripts; I'll build a version of the script I'm having problems with to run as a quest script modelled on your example above; this may be all it takes.

 

Roger on the receptive thing; real life must always trump pro bono stuff. That said, they do include the source code with each download. The NVSE guys are tops in my book; IMHO, they've contributed more to these games with their script extenders than anyone else, by enabling a whole class of high-quality mods that wouldn't have been possible without them.

 

Thanks again, Ricker! Good to have you around! :)

Link to comment
Share on other sites

Ok, I'll bite: have a look; maybe you can see something I'm not. This still always crashes the second time it's run! I'd rip my hair out, if I had any...! (Boy, the code tag here really, really sucks!)

 

ScriptName WSTNHKExceptionListMgrScript

; -

; state machine states

; -

short bInitList;

short bMoveItems;

short bClearList;

 

short HotKeyIndex;

 

int iListIndex;

int HotKeyItemCount;

int ItemType;

int nItems;

 

ref rHKBaseObject;

 

Begin GameMode

 

if ( bInitList )

 

;--------

; This part works every time...

;--------

 

; Get a list of weapons assigned to hotkeys; these

; will not be removed.

set HotKeyItemCount to 0;

set HotKeyIndex to 0;

 

label 100

set HotKeyIndex to HotKeyIndex + 1;

 

if ( HotKeyIndex <= 8 )

 

set rHKBaseObject to Player.GetHotKeyItem HotKeyIndex;

 

if ( rHKBaseObject )

 

set ItemType to GetObjectType rHKBaseObject;

 

if ( ItemType == 40 )

 

printc "Adding %n", rHKBaseObject;

 

AddFormToFormList WSTNHKItemList, rHKBaseObject;

set rHKBaseObject to 0;

set HotKeyItemCount to HotKeyItemCount + 1;

endif

endif

 

goto 100;

 

endif ; ( HotKeyIndex <= 8 )

 

set bInitList to 0;

set bMoveItems to 1;

 

elseif ( bMoveItems )

 

set nItems to Player.GetNumItems;

 

if ( nItems )

;-----

; I THINK this works every time, but can't be sure, since game CTD's. No way to check the console

;-----

 

if ( HotKeyItemCount )

printc "HKItemCount = %x", HotKeyItemCount;

Player.RemoveAllTypedItems StgWeaponsREF, 0, 1, 40, WSTNHKItemList;

else

; No hotkeyed weapons, just take 'em.

Player.RemoveAllTypedItems StgWeaponsREF, 0, 1, 40;

endif ; ( HotKeyItemCount )

 

endif ;( nItems )

 

set bMoveItems to 0;

set bClearList to 1;

 

elseif ( bClearList )

 

set HotKeyItemCount to ListGetCount WSTNHKItemList;

 

if ( HotKeyItemCount )

set rHKBaseObject to ListRemoveNthForm WSTNHKItemList, 0;

printc "removed %0.f", rHKBaseObject;

else

StopQuest WSTNHKExceptionListMgrQuest

endif ; ( HotKeyItemCount )

 

endif ; ( bClearList )

 

End

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...