Jump to content

Fallout New Vegas GECK & Scripting Help 101


Recommended Posts

Posted

I'm in favor of a stringmap call convention (I already use one of my own). Since dialog scripts return 0 for GetCallingScript, you could workaround the issue with:

 

if eval 0 == args["ActorX"] && 0 == GetCallingScript

    let ActorX := GetSelf

endif

 

Or, perhaps use: 1009 == MenuMode

Posted

I'm in favor of a stringmap call convention (I already use one of my own).

I do this quite often at my dayjob. It's easier to extend interfaces that way than to run around changing the params and updating all the calling code. That said, do you know if it would work as I outlined above? Can I use that sort of evaluation (ar_map + getself) in the call to the UDF?

 

Since dialog scripts return 0 for GetCallingScript, you could workaround the issue with:

 

if eval 0 == args["ActorX"] && 0 == GetCallingScript

    let ActorX := GetSelf

endif

 

Or, perhaps use: 1009 == MenuMode

I'm not sure what you're getting at here. What's actorX have to do with this?

 

To be honest the GetCallingScript thing is a minor annoyance, not a real problem. It would only become a real problem if somebody split their fnSexoutActPrep/Set/Run calls across different script fragments. This would then potentially conflict with another mod (or even the same mod) doing the same thing, with a different logical act.

 

The purpose of the GetCallingScript is so that scriptA can call fnSexoutActPrep in one frame.. maybe call the Set's a few frames later.. and call Run even a few acts after that, and scriptB can do the same thing, simultaneously. The GetCallingScript is used as a key into an array to facilitate that, so multiple mods can do this without overwriting eachothers vars.

 

The "real" solution was for fnSexoutActPrep to return a key value that's passed in all subsequent Prep/Run calls, but at the time I thought that would be "too much work" to save/use for modders. In light of this discussion, it would also make the UDF method unusable in script fragments because there's no local var available to hold the result of Prep.

Posted

 

That should not be a permanent condition. I would say it happens once in every 20 or so GECK scripting session. It might also come from a specific error, but I don't have enough statistics to form an hypothesis.

 

Can't say 1 every 20, but I can tell you one of my common mistakes, which just CTDed when I wrote my previous post:

If MyVar := something

I use := on If as for Let

 

 

Jaam not sure if this helps you, but I'm noticing how it likes CTD when I make something wrong in the IFs, it could be that := but also checking a variable not declared. Of course it could simply be because it's the kinds of mistakes I do often

 

Posted

It might be related to if. Some error display already had to be deactivated because they used too many parameters, maybe if too.

 

Posted

CTDs from powerup? I thought I was the one writing crazy code around here.. but I haven't managed to crash the GECK in a long time. Not since I had that fucko error in the sexout esm that crashed it every time you tried to quit.

Posted

well pride it didn't start a long time ago. I would say a month maybe two. At start I thought it was because of some ESP, but then I noticed it was even on new ESPs. I did installed new dlls under NVSE, maybe this makes the difference. But also I do make a lot of mistakes when I write code, maybe I just make too many

Posted

None of your mistakes should crash the geck. It's like errors in c++ code crashing the compiler, just should not be possible.

 

OTOH this is the GECK we're talking about, it makes the impossible possible, right? ;)

Posted

Error reporting is a program. And any program can crash. And yes you could crash a compiler with bad syntax. I would be extremely surprised if it has never happened already.

 

Posted

jaam,

The only thing I know of that even comes close is the array iteration operator, but it's probably not something NX can do.

 

AJ,

In cases like that, you're better served by just making the UDF take an array (stringmap) as an argument. Then you can do something like this:

  call mySexoutUDF ar_Map("actorA"::getself, "actorB"::playerRef, ...)
Which MIGHT work, depending on how the UDF call likes (or doesn't) the ar_map evaluation rather than a straight var in that context. If it works, it's "hooray", and I'll put such a 'helper' UDF in sexout itself fairly soon. The UDF itself would just take the one stringmap parameter and then iterate through it making the sexout calls

 

scn mySexoutUDF

array_var arParams

array_var arItem
string_var sType

Begin Function{arParams}
  call fnSexoutActPrep

  foreach item <- arParams
    let sType := TypeOf item["value"]

    if eval "Form" == sType
      call fnSexoutActSetRef item["key"] item["value"]
    elseif eval "Number" == sType
      call fnSexoutActSetFloat item["key"] item["value"]
    endif
  loop

  call fnSexoutActRun
End
This function is basically what fnSexoutActRun itself does. All the fnSexoutActSet* functions just store things in a stringmap like this, then ActRun goes through it in exactly the same way, setting the NX vars and then doing the CIOS.

 

 

Closest I can get is this:

call npTestScriptFunc2Script ar_Map("actorA"::0, "actorB"::playerRef)

but you should be able to decode 0 as getSelf in the called UDF:

scn npTestScriptFunc2Script

array_var aTiti
ref self

begin Function { aTiti }
	set self to GetSelf
	PrintC	"Hello %n [%i]" self self
end

Posted

I "can't do that" since we have no distinction between null and 0.

 

There are animations where actorA being null and B being set is 'normal'. Or A & C without B, or B&C without A, ad nauseum.

 

I'll have to use a MAX_INT value instead. I'll define one as a global in sexout (0xffffffff) if there isn't one that's easy to use already.

 

--------

 

I've *never* crashed a "white box" compiler (e.g. a MS, Borland, etc. product) with bad syntax, and I've been coding since.. hell turbo pascal 5.5 whenever that was. Just saying. ;) Freeware compilers are another matter.

Posted

A bad if was not enough anyway :) , The trick is what you pass needs to be a valid ref, or you need a placeHolder key name for "Use GetSelf as ActorA"

Posted

Well I made that damnable menu, and surprisingly it works for the most part. The issue I've got with it right now, is that it doesn't show the messages as fast as I would like, for starters bringing up the main message takes a while, I have to hold down the key for a while, I don't know if that's how IsKeyPressed is supposed to work, I thought it was just pressing the key and that'd be it. 

 

In any case, this is what I came up with: 

 

 

 

scn 0AR15ModKitScript 

int iButtonA
int iButtonB
int iButtonC
int iButtonD 
int iSetHotKey 
int iMenuHotKey 
int iContainsModKit
int iMenuMessage
int iIndex  
int iTenWeapons 
int iFifteenWeapons 
int iTwentyWeapons 

Begin GameMode 

	Let iContainsModKit :=  playerREF.GetItemCount 0AR15ModKit 
	Let iTenWeapons := playerREF.GetItemCount 0WeapAR1510in
	Let iFifteenWeapons := playerREF.GetItemCount 0WeapAR1515in 
	Let iTwentyWeapons  := playerREF.GetItemCount 0WeapAR1520in

	
	If(iTenWeapons >= 1) 
		Let iIndex := 0
	ElseIf (iFifteenWeapons >= 1) 
		Let iIndex := 1
	ElseIf (iTwentyWeapons >= 1) 
		Let iIndex := 2
	EndIf 
	
	If (iSetHotKey == 0) 
		Let iMenuHotKey := 37
		Let iSetHotKey := 1
	EndIf 
	
	If (iContainsModKit > 0 && IsKeyPressed iMenuHotKey)
		ShowMessage 0AR15ModKitMenu
	EndIf
;-------------------------------------------------------------------
	;Main menu, options include hot key configuration and weapon selection(10 in, 15 in and 20 in barrels)
	If (iMenuMessage == 0)
		Let iButtonA := GetButtonPressed 
		If (iButtonA == -1) 
			Return 
		ElseIf (iButtonA == 0)
			Return 
		ElseIf (iButtonA == 1) 
			ShowMessage 0AR1510inModSelection 
			Let iMenuMessage := 1
		ElseIf (iButtonA == 2) 
			ShowMessage 0AR1515inModSelection 
			Let iMenuMessage := 2
		ElseIf (iButtonA == 3) 
			ShowMessage 0AR1520inModSelection 
			Let iMenuMessage := 3
		ElseIf (iButtonA == 4)
			Return
		EndIf
	EndIf 
;--------------------------------------------------------------------
	;10in barrel menu, includes several mods for the 10in barrel version 
	If (iMenuMessage == 1) 
		Let iButtonB := GetButtonPressed
		If (iButtonA == -1) 
			return
		ElseIf (iButtonB == 0) 
			Let iIndex := 1
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 1) 
			Let iIndex := 2
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 2) 
			Let iIndex += 10
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 3) 
			Let iIndex += 1000
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 4) 
			Let iIndex += 100
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 5)
			Let iIndex -= 10
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 6) 
			Let iIndex -= 1000
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 7) 
			Let iIndex -= 100
			Call 0AR15ModSelectionFunction 1, iIndex
			Return 
		ElseIf (iButtonB == 8) 
			ShowMessage 0AR15ModKitMenu
			Let iMenuMessage := 0
		ElseIf (iButtonB == 9) 
			Return
		EndIf 
	EndIf
;-------------------------------------------------------------------------------
	;15in barrel variant menu, mods for 15in version 
	If (iMenuMessage == 2)
		Let iButtonC := GetButtonPressed 
		If (iButtonA == -1) 
			return
		ElseIf (iButtonC == 0) 
			Let iIndex := 0
			Call 0AR15ModSelectionFunction 2, iIndex
			Return 
		ElseIf (iButtonC == 1) 
			Let iIndex := 2
			Call 0AR15ModSelectionFunction 2, iIndex
			Return 
		ElseIf (iButtonC == 2) 
			Let iIndex += 100
			Call 0AR15ModSelectionFunction 2, iIndex
			Return 
		ElseIf (iButtonC == 3) 
			Let iIndex -= 100
			Call 0AR15ModSelectionFunction 2, iIndex
			Return
		ElseIf (iButtonC == 4)
			ShowMessage 0AR15ModKitMenu 
			Let iMenuMessage := 0
			Return 
		ElseIf (iButtonC == 5) 
			Return
		EndIf
	EndIf 
;-------------------------------------------------------------------------------
	If (iMenuMessage == 3)
		Let iButtonD := GetButtonPressed
		ElseIf (iButtonA == -1) 
			return
		If (iButtonD == 0) 
			Let iIndex := 0
			Call 0AR15ModSelectionFunction 3, iIndex
			Return
		ElseIf (iButtonD == 1) 
			Let iIndex := 1
			Call 0AR15ModSelectionFunction 3, iIndex
			Return
		ElseIf (iButtonD == 2) 
			Let iIndex += 10
			Call 0AR15ModSelectionFunction 3, iIndex
			Return 
		ElseIf (iButtonD == 2) 
			Let iIndex += 100
			Call 0AR15ModSelectionFunction 3, iIndex
			Return
		ElseIf (iButtonD == 3) 
			Let iIndex -= 10
			Call 0AR15ModSelectionFunction 3, iIndex
			Return
		ElseIf (iButtonD == 4) 
			Let iIndex -= 100
			Call 0AR15ModSelectionFunction 3, iIndex
			Return 
		ElseIf (iButtonD == 5) 
			ShowMessage 0AR15ModKitMenu 
			Let iMenuMessage := 0
			Return 
		ElseIf (iButtonD == 6) 
			Return 
		EndIf 
	EndIf 
End 

 

 

 

Also wondering if I should just put the function call at the end of every menu, as in right before the EndIf of each If (iMenuMessage == x), instead of placing it in every block. 

Posted

Well I made that damnable menu, and surprisingly it works for the most part. The issue I've got with it right now, is that it doesn't show the messages as fast as I would like, for starters bringing up the main message takes a while, I have to hold down the key for a while, I don't know if that's how IsKeyPressed is supposed to work, I thought it was just pressing the key and that'd be it.

 

 

Depends on the script frequency, I guess.

 

Also wondering if I should just put the function call at the end of every menu, as in right before the EndIf of each If (iMenuMessage == x), instead of placing it in every block.

Doesn't hurt, especially because the parameter to the call is the same as iMenuMessage.

You can probably also just put one GetButtonPressed & "return if < 0" up top.

Posted

So... does anyone know what causes topics to magically disappear from a quest's topics tab?

They're all still there if I check the dialog tree, just not in the topics tab's left column where I actually need to see and select them. Tried with and without NVSE and PU. Redownloaded the geck. No difference.

 

post-18170-0-85155000-1419114131_thumb.jpg

post-18170-0-62243600-1419114142_thumb.jpg

 

 

Posted

something like the issue Halstrom had with Windows 8? wrong window placement or something like this?

just to be make an attempt, I would rename / move the GECK ini inside documents, so that it will re-create it. Of course I don't know about dialogues, but I do know it contains some infos about some windows and their placement

Posted

Oh, FFS, I'm such a doofus. The columns weren't aligned properly, all I needed to do was drag them right again.

That's 3 hours of searching forums, switching out NVSE/PU/MO, investigating my geck inis and what not!  Genius at work here! :idea:

Posted

 

Depends on the script frequency, I guess.

 

 

Not sure I like that, the script is always running, I thought about that, and it might not be such a good idea. I guess if there's no other way I'd keep it like this, but I don't like its response time, it is simply too slow, especially when compared to menus from other mods. That said, I don't know if the amount of options and they size of the menu matters. I would guess it does, especially with the if statements. 

Posted

Question: I have a mod with some scripts (let's call it "Blah") and some reference ID variables, e.g. one called "ref" which I can access with Blah.ref (obviously). Now I thought I could check whether this reference is invalid (normally it should point to an actor) with something like

if(Blah.ref == 0)
which has worked fine so far, but after playing for several hours I have now a situation where this line returns FALSE, i.e. Blah.ref is NOT zero, but the script silently crashes anyway when I try to do anything with Blah.ref (e.g. set newRef to Blah.ref). So this reference seems invalid in some way. However, this line
PrintC "%n - %i" Blah.ref Blah.ref
prints "<no name> - 00000000" which I thought means that no reference is stored in this variable, and so when evaluating the variable against 0 it should return TRUE, but apparently that isn't the case. So what's going on here? Is this a variable that points to an object that isn't loaded in memory because it exists in a faraway cell and isn't persistent? If so, how can I check whether doing anything with the reference will crash my script? I found the IsReference function, but I can't use it with the Blah.ref syntax since it needs an "explicit reference" (which I presume means a static reference).

 

I have no idea how to proceed from here, please help...

Posted

What is the correct syntax for this? I tried

if(IsReference Blah.ref == 0)
and at that line when compiling I get the message "Syntax Error. Reference not allowed in this context." and "Missing parameter reference. Compiled Script not saved!"

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