Jump to content

Fallout New Vegas GECK & Scripting Help 101


Recommended Posts

Posted

OK, I've got a question about resurrection and respawning. Here's the setup:

 

The player is captured and can:

  • Kill the captor via dialog
  • Make captor unconscious via dialog

I need the captor reset so it can be used again. (Repeating quest here.)

 

If unconscious this is simple. Move captor back to holding cell, make conscious, disable. It can be reused for when the player is captured again.

 

Now, the question is, what is the best practice if the captor is killed? Would calling RessurectActor on it, moving it to the holding cell, then disabling be the way to go? Would forcing it to respawn be better?

 

And perhaps another question: am I making this too complicated or is there a better way to go about this? :angel:

Posted

I've done a little investigation with UDFs, perhaps someone will find this interesting.

 

So, you should never do 'sv_destruct' on a function argument, or on a local UDF string_var if you set it to another string_var (that makes a pointer to it, not a copy of it, unlike 'let').

 

(From gribbleshnibbit documentation):

 

 

 


A note about local variables within functions: when the function terminates, all local variables are reset to zero. Local array variables are automatically cleaned up so there is no need to use ar_Null to reset them. String variables used to hold function arguments are also automatically destroyed. Local string variables, however, are not automatically cleaned up because they may refer to strings in use by other scripts. It is the scripter's responsibility to use sv_Destruct to destroy any local variables when appropriate. The following example code illustrates this idea:

	scn SomeFunction
	string_var arg
	string_var local0
	string_var local1
	string_var local2    
	Begin Function { arg }
	    let local0 := "some string"
	    set local1 to someQuest.someStringVar
	    let local2 := someQuest.someStringVar
	    sv_Destruct local0 local2
	End
	

In the above script, the string variable arg will be automatically cleaned up by OBSE when the function terminates. local1 will not be, and should not be destroyed explicitly because doing so would invalidate the someStringVar variable in an external script. local0, however, must be explicitly destroyed as it is not referenced by any other script. local2 must also be destroyed as let, unlike set, creates a copy of the string with a new string ID.

 

 

 

Does that mean that function arguments are not 'real' variables, they are pointers to real variables? I tested this with:

 

 

 

scn myUDF

string_var arg1
int arg2

Begin Function { arg1, arg2 }
   printc "myudf: %z  and %g", arg1, arg2
    sv_destruct arg1
    set arg2 to 99 ; * identical result with let or set
   printc "myudf: %z  and %g", arg1, arg2
End
scn mytestquestscript

string_var mystring
int myint

ref rRef
int itype

Begin GameMode

    let mystring := "my important string"
    let myint := 5
    printc "First: %z %g ", mystring, myint
    call myudf mystring, myint
    printc "Post UDF: %z %g ", mystring, myint


   let rRef := myudf
   let itype := GetType rRef
   PrintC "the type of a udf is %g" itype
End

 

 

 

Which gave my the scof output:

 

 

SetConsoleOutputFilename >> 'udf2.txt'

First: my important string 5   ( the two vars in my quest )

myudf: my important string  and 5 ( the two vars as arguments in the function )

myudf: NULL  and 99 ( the two var as arguments, after I sv_destruct and reset )

Post UDF: my important string 5 ( the two vars in my quest post UDF are still unchanged )

the type of a udf is 17
 

 

 

----

 

Conclusion: Apparently not. A shame, I would love to be able to pass a pointer to a quest var like this.

 

Whilst needless, doing "sv_destruct" on an argument is not dangerous.

 

Presumably then, the only reason NVSE does not automatically destroy local string_vars is just in case you did 'set .. to ..' with them, which does create a pointer (I checked myself).
 

Posted

Anybody know where I can find an explanation of what SetUIFloat, SetUIString and what UI functions in general do? I checked the NVSE command list but it doesn't really say what they do. I'd assume SetUIFloat has to do with x,y positions and SetUIString has to do with placing messages on the HUD. Regardless, I can't figure out how it is that they work, I mean, say I use those functions, what is it that is supposed to happen on the HUD/game?

Posted

There's no documentation on huds and it's better if you know some xml to work with them. You can set variables or (behaviours?features?) using these functions, you see them starting with underscore usually. You must cross-check the hud file to understand what they are doing, it is inside Data\menus\prefabs\name of the mod

Guest tomm434
Posted

OK, I've got a question about resurrection and respawning. Here's the setup:

 

The player is captured and can:

  • Kill the captor via dialog
  • Make captor unconscious via dialog

I need the captor reset so it can be used again. (Repeating quest here.)

 

If unconscious this is simple. Move captor back to holding cell, make conscious, disable. It can be reused for when the player is captured again.

 

Now, the question is, what is the best practice if the captor is killed? Would calling RessurectActor on it, moving it to the holding cell, then disabling be the way to go? Would forcing it to respawn be better?

 

And perhaps another question: am I making this too complicated or is there a better way to go about this? :angel:

 

Do you do use fade to black  on scene when captor is killed?

;Somewhere in the quest you have a reference.

ref CaptorDeadRef


------------------------------------------------------------------
Effect script (yeah, a spell)

Scriptname CaptorScene

int scene
int stage
float timer
ref CaptorDeadRef

float ftimer

begin ScriptEffectUpdate
let timer +=GetSecondsPassed


if eval ((ftimer += ScriptEffectElapsedSeconds) < 0.3)
   return
else
   let fTimer := 0
endif


if stage ==0
   if timer >=0
        DisablePlayerControls 1 1 1 1 1 1 1
        Captor.setrestrained 1
        imod FadeToBlack9sISFX
        set timer to 0
        set stage to 1
   endif
endif

if stage ==1


     if timer >=6
       CaptorRef.disable
       set YourQuest.CaptorDeadRef to Captor.placeatme aaMS15CaptoryDeadBody 1
       set CaptorDeadRef to YourQuest.CaptorDeadRef
       CaptorDeadRef.killactor CG01DadREF 3 ; Instead of CG01Dad ref you insert any reference
       imod FadeInFromBlack4sISFX
       set timer to 0
       set stage to 2
     endif
endif

if stage ==2
     if timer >=4
      set scene to 1
      set stage to 3
     endif
endif


if scene ==1

    EnablePlayerControls
    set scene to 2
    dispel CaptorScene
endif


end

So after some time you need to clean up created dead body, you can do it from any script you want, just type

ref MyRef
set Myref to myquest.CaptorDeadBody
MyRef.disable
Myref.markfordelete

And the captor who was in dialogue will always be A-L-I-V-E! I know that means lying to player but it's easier for you.

Posted

Yeah I know about XMLs, and that's all done, the old mod has it. I just need to know what it is that those functions in particular do, I'll check MCM, checked oHUD, but I didn't see much with it, I'll see if I can find out what's going on with it through the hardcore needs part, guessing that will use the string function. 

Posted

they mainly set variables which are contained inside the xml, there's not much more, it's the xml that says how the hud behaves, you must look at that

Posted

An example pasted from a hud of mine:

 

XML:

...

<systemcolor>
<copy> &hudmain; </copy>
<onlyif>
    <copy src="io()" trait="_HealthLow" />
    <eq> 0 </eq>
</onlyif>

Script:

... (If the health is not low)
SETUIFloat "HUDMainMenu\_HealthLow" 0
...

The hud color is inherited if that var HealthLow is 0. Inside the script I check the PC health value and I decide it's not low, so I set that value to 0 with SETUIFloat

Posted

 

Do you do use fade to black  on scene when captor is killed?

 

Ah! Now there's an idea! Much simpler I think. Thanks for the suggestion! :angel:

 

I think that about wraps up my problem then. Once I get that working I think I can add a few more encounters to this project before release. :lol:

Guest tomm434
Posted

Nessa, is this for TTW? New quest mod?

Posted

Nessa, is this for TTW? New quest mod?

 

Yes, actually. It's a TTW extension for Odessa's glorious Another Kick in the Head. :angel:  It's actually fully functional, I'm just adding more "Bad End" mini quests and dream sequences at the moment. Oddly that's taking more time than the rest of the mod took setting up. Odessa did a beyond splendid job making it simple to add to! :lol:

Posted

Ok peeps, I present you with this:

  let arTmp := rSrc.NX_GetEVFoAr "Sexout:Start::"
  foreach element <- arTmp
    ar_dump element
    let nxKey := element["key"]
    sv_Replace "Sexout:Start::|Sexout:Started::" nxKey
    let foVal := element["value"]
    DebugPrint "fnSCSv fo: %z %n (%i)" nxKey foVal foVal
    rTgt.NX_SetEVFo $nxKey foVal

    sv_destruct nxKey
  loop
Which outputs this to the debug log:

** Dumping Array #6 **

Refs: 1 Owner 0C: Sexout.esm

[ key ] : sexout:start::actora

[ value ] : 1104096.000000

fnSCSv fo: Sexout:Started::actora <no name> (00000000)

The question I pose... what gives?

 

I use the same code (except for the sv_replace) in a different UDF and it works fine. This one is having some kind of problem with foVal -- that or I did some stupid "is it plugged in" move and can't see it.

 

Identical code in the same UDF for copying floats rather than forms works fine.

Posted

Ah, yeah, it gives you the decimal of the formid. For some reason, this is what happens with an ar_dump on GetEvfloAr, because iirc nx stores forms decimally. But if you pass element["value"] to a ref var, you should be able to still get a form from that.

For readouts, you can output to a hex formID string with let sv_hex := NumToHex iNum 8

Posted

It's actually 0 as presented. foVal is a form and you can see in the debugprint, it's coming up all 0's.

 

let foVal := element["value"]
DebugPrint "fnSCSv fo: %z %n (%i)" nxKey foVal foVal

(output)

fnSCSv fo: Sexout:Started::actora <no name> (00000000)
When I get the EVFo out later, it's 0 as well. This is basically identical to what I do in fnSexoutActRun, which works perfectly well. I'm missing something stupid and basic this go around; it's my first time using the NX_Get....Ar's and sv_replace.
Posted

I could be wrong about reconverting them back to forms, and NX_GETEVFOAr may need fixing. I've only ever needed the NX_Ar functions for readouts through ar_dump etc, so when I got numbers there I probably converted to hex, got a readout from that & moved on.

Posted

I kinda figured it was an NX issue. I'll fire it off to jaam to take a look at since he wrote those functions. In the script I've switched to just doing an NX_GetEV.. with the key and that seems to be working fine, just finishing up testing.

Posted

I didn't, but the print isn't actually the issue.

 

This code:

  let arTmp := rSrc.NX_GetEVFoAr "Sexout:Start::"
  foreach element <- arTmp
    let nxKey := element["key"]
    let foVal := element["value"]
    sv_Replace "Sexout:Start::|Sexout:Started::" nxKey
    rTgt.NX_SetEVFo $nxKey foVal

    sv_destruct nxKey
  loop
Is just doing the NX_GetEVFoAr in order to copy all the elements to a new namespace.

 

When it runs (there is a similar one right before it for floats), the NX destination vars all come up null/0 and sexout of course aborts when it sees that. The floats work fine.

 

I changed it to this and it works fine:

  let arTmp := rSrc.NX_GetEVFoAr "Sexout:Start::"
  foreach element <- arTmp
    let nxKey := element["key"]
    let rVal  := rSrc.NX_GetEVFo $nxKey
    sv_Replace "Sexout:Start::|Sexout:Started::" nxKey
    rTgt.NX_SetEVFo $nxKey rVal

    sv_destruct nxKey
  loop
The only difference there is I'm not using the element value and am instead doing a normal NX_GetEVFo with the element key.
Posted

Don't bite but.. foVal was defined as a ref ?

 

I'll try to debug that, after the other three things I piled up today. :)

 

Posted

Yeah, it was. Here's the full original UDF.

 

scn fnSexoutCopyStartvars
; Copies Sexout:Start NX vars from rSrc to rTgt and renames them
; into the Sexout:Started namespace.

; args
ref rSrc
ref rTgt

; internal
array_var  element
array_var  arTmp
string_var nxKey

float fVal
ref   rVal

Begin Function{rSrc rTgt}

  let arTmp := rSrc.NX_GetEVFoAr "Sexout:Start::"
  foreach element <- arTmp
    let nxKey := element["key"]
    let rVal  := element["value"]
    sv_Replace "Sexout:Start::|Sexout:Started::" nxKey
    DebugPrint "fnSCSv fo: %z %n (%i)" nxKey rVal rVal
    rTgt.NX_SetEVFo $nxKey rVal

    sv_destruct nxKey
  loop

  let arTmp := rSrc.NX_GetEVFlAr "Sexout:Start::"
  foreach element <- arTmp
    let nxKey := element["key"]
    let fVal  := element["value"]
    sv_Replace "Sexout:Start::|Sexout:Started::" nxKey
    DebugPrint "fnSCSv fl: %z %f" nxKey fVal
    rTgt.NX_SetEVFl $nxKey fVal

    sv_destruct nxKey
  loop


End
That is the checked in version right now in svn, except for the change to NX_GetEV.. from element["value"]

 

I never checked in the nonworking version, before the variable rename.

Posted

Question for the more mathematically inclined:

 

I literally only just found out that if you let an int to a float, you'll get the floor of the float. What I want instead is the float rounded up or down according to regular rounding methods (eg the ceil if the float is  >= .5 , the floor if < .5). How do I go about doing that in as few lines as possible?

Posted

Regular rounding (bank rounding) is a bit more complex than that (you round x.5 towards the even number -- so 1.5 rounds to 2, as does 2.5), but that should get you by. ;)

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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