Jump to content

Fallout New Vegas GECK & Scripting Help 101


Recommended Posts

Posted

The UDF should *always* run synchronously, never allowing the calling script to continue until it returns (or crashes). It's not an async call like a spell.

 

Not sure what's going on with the script issue.. maybe a buggy NVSE version? What was the calling context when it was a UDF? You can't always GetContainer or things like that -- best to make the UDF take a parameter, and pass it in from the caller.

Posted

The UDF should *always* run synchronously, never allowing the calling script to continue until it returns (or crashes). It's not an async call like a spell.

 

Not sure what's going on with the script issue.. maybe a buggy NVSE version? What was the calling context when it was a UDF? You can't always GetContainer or things like that -- best to make the UDF take a parameter, and pass it in from the caller.

Oh sorry that was the converted version of the script, I previously had Begin Function (rActor) in the UDF version, that was the only thing I changed other than adding the female/male/creature check.
Posted

Also I just discovered now I got this working that when my SexoutOffspring renaming activates it seems to change the players name to that of the new offspring.

This script was given to me by someone else and works fine otherwise, but I really don't understand the JuJu being used to work out what I've done wrong.

 

 

Scn SexoutOffSpring0RenameTokenScript

ref rPlayer
ref rMsgA
ref rMsgB
ref rTarget
int bMenu
int sAdded
int iRemoving

Begin OnAdd
	Set rTarget to GetContainer
	Set rPlayer to PlayerREF
	Set rMsgA to SexoutOffSpringNameMsgA
	Set rMsgB to SexoutOffSpringNameMsgB
	SetNameEx "%n" rPlayer rMsgA
	SetNameEx "%n" rTarget rPlayer
	GetPlayerName
	Set sAdded to 1
End

Begin GameMode
	if (0 == sAdded)
		Return
	endif

	if (1 == bMenu) && iRemoving < 1
		SetNameEx "%n" rPlayer rMsgB
		rTarget.SetActorFullName SexoutOffSpringNameMsgB
		PlayerREF.SetActorFullName SexoutOffSpringNameMsgA
		rTarget.NX_SetEVFo "SOF:rOffSpringName" SexoutOffSpringNameMsgB
		RemoveMe
		Set iRemoving to 1
	endif
End

Begin MenuMode 1051
	Set bMenu to 1
End

 

Posted

Well this line seems suspect...

 

 

PlayerREF.SetActorFullName SexoutOffSpringNameMsgA

 

Yeah, I suspect it's needed for the magfic to work, I'm going to try adding:

 

PlayerREF.SetActorFullName rPlayer

 

before:

 

Set iRemoving to 1

 

and see if that sorts it.

Posted

Wait, the script is supposed to change the players name? I thought that's what you said it was doing, but didn't want it to. It's doing it in two spots. That one, and in the onadd with the SetNameEx. SetActorFullName takes a message (MEGF or whatever record type -- the one used for popup messages), SetNameEx takes a string.

Posted

Wait, the script is supposed to change the players name? I thought that's what you said it was doing, but didn't want it to. It's doing it in two spots. That one, and in the onadd with the SetNameEx. SetActorFullName takes a message (MEGF or whatever record type -- the one used for popup messages), SetNameEx takes a string.

Well from what I gather it temporarily uses the option to change the Player name to change an NPC with the tokens name which works ok, but seems to not set the player name back afterwards.
Posted

Oh blimey.. switch the order of these two lines, this may be the problem.

		RemoveMe
		Set iRemoving to 1
RemoveMe is a return. iRemoving isn't being set, so if the script runs again next frame (as it likely does, removeme isn't instant) then the names get swapped around a second time.. not good.
Posted

Oh blimey.. switch the order of these two lines, this may be the problem.

		RemoveMe
		Set iRemoving to 1
RemoveMe is a return. iRemoving isn't being set, so if the script runs again next frame (as it likely does, removeme isn't instant) then the names get swapped around a second time.. not good.

 

Aghh yeah that's a screwup of my making, I've done that one before, I only just added the RemoveMe today as it wasn't there, so unfortunately it's not the issue.
Posted

Old renaming scripts with MessageBoxEx/SetActorFullName etc. are a lil confusing.

New NVSE functions allow you to do it a lil more readable with strings and Get/SetName

I copy paste a scrap of code I used:

...
    elseif iStage == 20    ;

        Let iStage := 21
        Let sMyName := $(Player.GetName)

        Let sOldAlias := $(rMarkerREF.GetMapMarkerName)
        Player.SetName $sOldAlias
        Return

    elseif iStage == 21

        Let iStage := 22
        GetPlayerName
        Return

    elseif iStage == 22

        Let iStage := 0

        Let sNewAlias := $(Player.GetName)

        rMarkerREF.SetMapMarkerName $sNewAlias
        Let aXMMainQuest.arObjects[2][iIndex] := $sNewAlias
        Player.SetName $sMyName

        sv_destruct sMyName
        sv_destruct sOldAlias
        sv_destruct sNewAlias
...

Stage 20 gives player the name of the reference, so that when you call GetPlayerName you won't see your name but the old reference name.

Stage 21 calls GetPlayerName

Stage 22 gives the ref the new player name, changes the player name with the original one.

Posted

Aside: If called on a form, ToString ($) actually returns it's name if it has one, so using GetName (and GetMapMarkerName?) is redundant. Also, if you do use GetName, since it returns a string already, you don't need to use ToString ($) to store it in a string_var:

        Let sMyName := $(Player.GetName)

        Let sOldAlias := $(rMarkerREF.GetMapMarkerName)
        Player.SetName $sOldAlias

Could be written more cleanly:

        Let sMyName := $Player ; # player name as string

        Let sOldAlias := rMarkerREF.GetMapMarkerName ; # map marker name as string
        Player.SetName $sOldAlias ; # But, SetName doesn't recognize string_VAR, so you do need $
Posted

I always had a bit of blur on $, when it was working and when it was not. My best deal, in the end, was abounding of it. Actually your simple example just explained me when I need it... thanx :)

Posted

Old renaming scripts with MessageBoxEx/SetActorFullName etc. are a lil confusing.

New NVSE functions allow you to do it a lil more readable with strings and Get/SetName

I copy paste a scrap of code I used:

Hmm I tried this but I can't get it to compile, I seem to be missing the SetMarkerName function.

 

 

 

Scn SexoutOffSpring0RenameTokenScriptNEW

int iStage
ref rCreatureOriginalName
ref sOldAlias
ref $sOldAlias
ref sNewAlias
ref $sNewAlias
ref sMyName
ref $sMyName
ref rMarkerREF

Begin GameMode

	if iStage == 0 ; *** Copy the Plyers name to somewhere safe and stick the offsprings name in the player pigeon hole
		Set iStage to 1
		Set rCreatureOriginalName to GetContainer
;		Set sMyName to $(Player.GetName)

;		Set sOldAlias to rMarkerREF.GetMapMarkerName
		Player.SetName $sOldAlias
		Return

	elseif iStage == 1 ; *** Activate the popup change name thingy on screen

		Set iStage to 2
		GetPlayerName
		Return

	elseif iStage == 2 ; *** copy the new name to the offspring and copy the original player name back to the player
		Set iStage to 3
;		Set sNewAlias to $(Player.GetName)

;		rMarkerREF.SetMapMarkerName $sNewAlias

;		Set aXMMainQuest.arObjects[2][iIndex] to $sNewAlias
		Player.SetName $sMyName

;		sv_truct sMyName
;		sv_destruct sOldAlias
;		sv_destruct sNewAlias

	elseif iStage == 3 ; *** delete me from inventory
		Set iStage to 4
		RemoveMe

	endif

End

 

 

I checked I'm using NVSE 4_6 beta 2

 

ahh just found beta 7 will try that

 

Nope GECK still won't accept it, doesn't like the := or the sv stuff or the $() stuff

 

Am I missing NVSE 5 or something?

Posted

Oh, sorry SetMarkerName is not intended to be used, that was for my purpose. I wanted to show only the Set/GetNames but I guess I took the most confusing example of code... shame on me.

Posted

Oh, sorry SetMarkerName is not intended to be used, that was for my purpose. I wanted to show only the Set/GetNames but I guess I took the most confusing example of code... shame on me.

No probs, I gutted all that out, I'm getting there, I got to this now but it's not working because I think I need that $() NVSE commands to work somehow when I can get my NVSE sorted out.

 

 

 

Scn SexoutOffSpring0RenameTokenScriptNEW

int iStage
ref rOriginalPlayerName
ref rOriginalOffSpringName
ref rNewOffSpringName

Begin GameMode

	if iStage == 0 ; *** Copy the Plyers name to somewhere safe and stick the offsprings name in the player pigeon hole
		Set iStage to 1
		Set rOriginalOffSpringName to GetContainer
		Set rOriginalPlayerName to Player.GetName

		Player.SetName rOriginalOffSpringName
		Return

	elseif iStage == 1 ; *** Activate the popup change name thingy on screen

		Set iStage to 2
		GetPlayerName
		Return

	elseif iStage == 2 ; *** copy the new name to the offspring and copy the original player name back to the player
		Set iStage to 3
		Set rNewOffSpringName to Player.GetName
		Player.SetName rOriginalPlayerName

	elseif iStage == 3 ; *** delete me from inventory
		Set iStage to 4
		RemoveMe

	endif

End

 

Posted

Names are strings, not forms, so you need a string_var to store them not a ref. You need to use let with string_var.

string_var player_name
ref rContainer
int iStage
 
if iStage == 0
    let rContainer := GetContainer
    if rContainer
        let player_name := $PlayerREF ; # == PlayerREF.GetName 
        PlayerREF.SetName $rContainer ; # SetName requires ToString ($) to accept string_var
        let iStage := 1
    endif
...
    sv_Destruct player_name
Posted

Names are strings, not forms, so you need a string_var to store them not a ref. You need to use let with string_var.

 

 

 

 

 

string_var player_name
ref rContainer
int iStage
 
if iStage == 0
    let rContainer := GetContainer
    if rContainer
        let player_name := $PlayerREF ; # == PlayerREF.GetName 
        PlayerREF.SetName $rContainer ; # SetName requires ToString ($) to accept string_var
        let iStage := 1
    endif
...
    sv_Destruct player_name

 

Thanks Odessa, PS and AJ that helped heaps, I now have:

 

 

 

Scn SexoutOffSpring0RenameTokenScriptNEW

int iStage
ref rOriginalPlayerREF
ref rOriginalOffSpringREF

string_var sNewOffSpringName
string_var sPlayerName

Begin GameMode
 
	if iStage == 0
		let rOriginalOffSpringREF := GetContainer
		if rOriginalOffSpringREF
			let sPlayerName := $PlayerREF ; # == PlayerREF.GetName 
			PlayerREF.SetName $rOriginalOffSpringREF ; # SetName requires ToString ($) to accept string_var
			let iStage := 1
		endif

	elseif iStage == 1 ; *** Activate the popup change name thingy on screen
		let iStage := 2
		GetPlayerName
		Return

	elseif iStage == 2 ; *** copy the new name to the offspring and copy the original player name back to the player
		let iStage := 3
		let sNewOffSpringName := PlayerREF.GetName
		rOriginalOffSpringREF.SetName $sNewOffSpringName
		PlayerREF.SetName $sPlayerName

		sv_Destruct sPlayerName
		sv_Destruct sNewOffSpringName

	elseif iStage == 3 ; *** delete me from inventory
		let iStage := 4
		RemoveMe

	endif

End

 

It's a pretty simple script, I just needed to learn new language to do it :)

It compiles fine so I'll give it a go :)

Posted

I had a eureka moment a bit earlier to solve a puzzle that's been digging at me for quite a while but I've never really spent the time to investigate. Tested and it works fine. The puzzle is "How can you have a quest var, or something similar, that other mods can check to see if your mod is ready to proceed -- WITHOUT any potential race conditions."

 

An example of one that doesn't work is in the current version of sexout, called "SexoutNG.bSexoutReady". This is a quest var I initially created in the hopes that other mods would check it before making sexout calls or accessing other sexout quest vars. The main quest sets it to 0 on gameloaded/restarted and then back to 1 after everything is ready.

 

It doesn't work reliably because in a savegame, it's 1, and if a mod checks it when the game is loaded in a script that runs before sexout has a chance to set it back to 0, they erroneously think sexout is ready.

 

This however is simple, and works reliably:

let rIsReady := TempCloneForm 00SexoutActor
TempCloneForms are not saved in savegames, and automatically reset to 0 whenever a game is loaded or a new game is started.

 

So beta2 of the next sexout (v93) will have a new method to determine if sexout is ready. Instead of checking that quest var, there will be a UDF (in case I must change this AGAIN) called "fnSexoutGetReady". If it returns 1, sexout is ready. If not, it's not.

 

For now this will be accomplished by it checking the status of that ref var.

 

Simple, and it works! Use something similar in your own mods and put this nightmare to rest once and for all.

Posted

Practical example, this is what I'm actually doing in sexout now (unreleased 93b2).

 

In the quest script restarted/loaded block:

; this is no longer used
; set bSexoutReady to 1
let rIsReady := TempCloneForm 00SexoutActor
And the UDF y'all will be calling

scn fnSexoutGetReady

int bReady

Begin GameMode
  let bReady := 0
  if SexoutNG.rIsReady
    let bReady := 1
  endif

  SetFunctionValue bReady
End
That's all there is to it.
Posted

I've been thinking that maybe we need to use the potential of custom events a bit more when it comes to timing-sensitive stuff. I've been using some of it in Spunk, to notify other mods that spunk's init cycle is done, it's start & end hooks have finished, and orgasms have happened. The obvious advantage is that a mod that wishes to start something depending on such events doesn't need to periodically check anything, just register a UDF for the event and wait for it to be triggered. You'd just broadcast a "SexoutReady" event and that'd be it. People start whatever they need to in that UDF.

 

(I know the following is probably make folks nervous about changing the interface yet again, but technically sexout itself could register a UDF for a "SexoutStart" event that modders would broadcast, specifying the parameters with the optional stringmap. You'd have everything in there that you'd need and wouldn't even need to make sexout a master.)

Posted

I'll gladly do that, if it'll work. Seems like I could support both no problem (the notification and the polling), but think about this:

 

How is your own mod going to know sexout has actually sent the notification -- or that you just think it has, because you recorded that it was sent in a quest var or something that got loaded in a save?

 

That var that you set to 0 in your gameloaded/restarted block and then don't set to 1 until you get the event will still itself be 1 if the user saves after the event. Even if you set it to 0 again, that's not proof against your own scripts in spells and such in the save running before you've set it back to 0 on a game load.

 

Calling the UDF in sexout everywhere you need it will ensure it's actually ready. You can even check it in the gamemode or scripteffectupdate blocks of your spells and quests that may also be present in the save game, so they 'pause' when a game is loaded until sexout is ready.

Posted

I'll gladly do that, if it'll work. Seems like I could support both no problem (the notification and the polling), but think about this:

 

How is your own mod going to know sexout has actually sent the notification -- or that you just think it has, because you recorded that it was sent in a quest var or something that got loaded in a save?

 

That var that you set to 0 in your gameloaded/restarted block and then don't set to 1 until you get the event will still itself be 1 if the user saves after the event. Even if you set it to 0 again, that's not proof against your own scripts in spells and such in the save running before you've set it back to 0 on a game load.

 

Calling the UDF in sexout everywhere you need it will ensure it's actually ready. You can even check it in the gamemode or scripteffectupdate blocks of your spells and quests that may also be present in the save game, so they 'pause' when a game is loaded until sexout is ready.

Well, that's just a matter of modders implementing it right and what type of mod they're making. A functionality mod that checks any act that goes on, like spunk or wear & tear, would be obvious choices to listen in on that, while mods that set off acts would probably need that UDF instead to check at the moment before the act starts. I'm just putting it out there that custom events are pretty powerful stuff, especially considering the optional stringmap. Atm, every time an orgasm happens in spunk, I broadcast a shitload of intel about it, in addition to the mere fact that it happened. If another mod picks it up, all the better, if not, nothing lost.

 

I don't feel I strictly need to check the ready var for spunk, for instance, because my own init cycle lasts long enough for NG to do whatever it needs to. However, for prettiness' sake, I could hold off my own init cycle until such an event tells me NG is ready. They could also be a prettier solution to registering start and end hook scripts. Instead of adding spells to a formlist that you loop through & then cast, maybe just tell us "SexoutActStart" or "SexoutActEnd" and we'll be notified if we register a UDF for it and take it from there, if you provided some intel in the stringmap like the spelltarget etc, or who knows, pretty much every variable that was set could be sent along.

Not saying only do it that way from on or do it rightaway. Just saying it's there to be used. :)

Posted

I'm just putting it out there that custom events are pretty powerful stuff, especially considering the optional stringmap. Atm, every time an orgasm happens in spunk, I broadcast a shitload of intel about it, in addition to the mere fact that it happened. If another mod picks it up, all the better, if not, nothing lost.

I've never used them or even looked at them, but I'm more than willing to implement a ready broadcast, as well as the global start/stop callbacks this way in addition to the existing registration system.

 

I don't feel I strictly need to check the ready var for spunk, for instance, because my own init cycle lasts long enough for NG to do whatever it needs to.

That's the idea everyone has worked under I think, but it doesn't always work. This came to me after my existing ready and init/upgrade in the current beta failed to have some quest array vars ready before Odessas ESP tried to use them via UDFs.

 

I managed that by putting the ar_constructs and checks for ar_null inside the UDF as well as the main quest script, so if the UDF was called before sexouts update was finished, the arrays wouldn't be null.

 

However, for prettiness' sake, I could hold off my own init cycle until such an event tells me NG is ready. They could also be a prettier solution to registering start and end hook scripts. Instead of adding spells to a formlist that you loop through & then cast, maybe just tell us "SexoutActStart" or "SexoutActEnd" and we'll be notified if we register a UDF for it and take it from there, if you provided some intel in the stringmap like the spelltarget etc, or who knows, pretty much every variable that was set could be sent along.

Not saying only do it that way from on or do it rightaway. Just saying it's there to be used. :)

Yep I like the idea of using them for the global hooks. That system is a massive hack right now. Don't go peeking into how it works, it's embarrassing but the best I could do at the time. It predates NX and all this fancy NVSE stuff. ;)

 

Also I know Hal has a bunch of timers in SCR that wait for things to be ready that take an indeterminate amount of time. He could use the events and/or the ready UDF as well.

Posted

Yep I like the idea of using them for the global hooks. That system is a massive hack right now. Don't go peeking into how it works, it's embarrassing but the best I could do at the time. It predates NX and all this fancy NVSE stuff. ;)

Well understood. It's just screaming for it now that you've moved toward having people start things with a UDF with a stringmap parameter too. I'd like nothing better than to have a UDF ready to be notified like

 

array_var args

ref tgt

 

begin Function {args}

 

let myquest.args := ar_copy args ; everything I need in one place

let tgt:= args["SpellTarget"]

tgt.CIOS myStartHookSpell ; looking up whatever it needs in myquest.args & erasing when done

 

End

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...