Jump to content

Fallout New Vegas GECK & Scripting Help 101


Recommended Posts

Posted

Since a lot of the bits are apparently unknown, I checked all the GetActorBaseFlagsHigh/Low flags on two base NPCs copies, one flagged. The Agro radius flag doesn't seem to be in them.

Posted

Sorry, it looks like it has been overlooked. Looks easy to add though.

 

It makes me feel guilty... but yeah if it was possible it would be wondrous :)

I also checked all the Actor Values in NVSE documentation but the aggro radius seems really unexistent, except maybe when it comes of package functions

Posted

As seen ix FNVEdit, aggro radius flags are a different set of flags, that are part of AI Data. Logically it should be part of TESAIForm in NVSE.

 

Posted

As seen ix FNVEdit, aggro radius flags are a different set of flags, that are part of AI Data. Logically it should be part of TESAIForm in NVSE.

 

Here is where I looked for it, with no luck :(

Posted

A short discussion with AJ got me thinking, and I've written a short almost-tutorial for all of you that shows my approach to staged spell effect scripts. There's no explanation beyond the comments I put in the script, so if the reasons for anything aren't clear, just let me know and I will explain further.

 

This is the basic boilerplate I use just about everywhere when I need a script with stages. It works fine as an effect, object, or quest script. The main goal (for the the only goal) for stages is to split up the script so it runs over the course of several frames. Sometimes you do this because the script is too complicated to finish in one frame without hurting the framerate, other times you do it because you need to wait for a period of time (as little as one frame) for something your script does to take effect.

 

So here it is.

scn MyStagedSpellScript

int iStage
int iLastStage
float gsp
float fDelay

Begin GameMode
  ; # Put this in a variable, you only want to call it once
  ; # inside a script, so if you want to use it in two places,
  ; # you need it in a var.
  let gsp := getSecondsPassed
  
  ; # Delay here if need be
  let fDelay := fDelay - gsp
  if fDelay > 0
    Return
  endif

  ; # Put your stages in descending order, so you can write them without
  ; # any 'elseif' statements, since there is a limit to how many of those
  ; # you can have.
  ;
  ; # In ascending order, without elseifs, if stage 10 sets the stage to 20
  ; # then stage 20 will run in the same frame as stage 10.  The entire
  ; # point of a staged script is to cause the stages to run in different
  ; # frames.

  if (10000 == iStage)
    ; # Do NOTHING here, waiting on dispel
  endif

  if (2000 == iStage)
    let iStage := 10000
    ; # If this is a spell effect script, dispel the spell here, e.g.
    ; # Dispel MyStagedSpell
  endif
  
  ; # Backstop stage.
  if (1000 == iStage)
    let iStage := 2000
    printC "An error occured in stage %g, backstop caught." iLastStage
  endif
  
  if (20 == iStage)
    ; # Save the current stage for backstop debugging or other uses.
    let iLastStage := iStage

    ; # backstop
    let iStage := 1000
    
    ; # Always backstop your stages this way.  This prevents a crashed
    ; # stage from repeating, which it will do if you only set the
    ; # value for the next stage at the end of the current one.

    ; # Do your stage 20 stuff.
    
    ; # maybe it needs a delay of 5 seconds instead of one frame.
    let fDelay := 5

    ; # Move to next stage
    let iStage := 2000
  endif
  
  ; # If your stages are a simple 0, 1, 2, 3, 4 you have two problems
  ; # with adding a new stage between 2 and 3 for example.  You will
  ; # have to either renumber all of the stages (4 -> 5, 3 -> 4, etc)
  ; # or you will have to jump around in a fashion that makes the
  ; # script hard to understand, for example by adding stage 5 and then
  ; # changing the "run order" from 0,1,2,3,4 to 0,1,2,5,3,4.
  ; #
  ; # So leave gaps like this (10 or 100 is usually good) between your
  ; # initial stage values.  This way later you can add stages between
  ; # others easily.
  
  if (10 == iStage)
    ; # Save the current stage for backstop debugging or other uses.
    let iLastStage := iStage

    ; # backstop
    let iStage := 1000

    ; # Do your stage 10 stuff

    ; # Move to next stage
    let iStage := 20
  endif
  
  if (0 == iStage)
    ; # Save the current stage for backstop debugging or other uses.
    let iLastStage := iStage

    ; # backstop
    let iStage := 1000
    
    ; # Do your init stuff

    ; # Move to next stage
    let iStage := 10
  endif
End
EDIT: Wasn't thinking, you need to set iLastStage in every stage, not once at the top. Duh. Updating now.

 

EDIT2: Update complete. Also added hashmarks to comments to make them stand out on forum code highlighter.

Guest luthienanarion
Posted

A curiosity about declaring variables inside dialogue result scripts, since some time ago this came out.

I just found a vanilla example of it.

...

As you can see it declares a float.

I've been declaring local variables in dialogue results and quest stages for years now. I never knew the possibility was in question.

  • 2 weeks later...
Posted
            if IsImageSpaceActive aaPFadeToBlackISFX
                PrintC "IMOD Active"
            else
                MessageBoxEx "Done and Done"
            endif

"Done and done" will appear after the IMOD seconds will be passed, so I guess an IMOD dispels on its own.

Maybe this seems obvious for some, but I just tested this thing and I'm posting it because I remember some post on the past saying the contrary, that any IMOD needed to be RIMOD. I always did it but at this point I don't think so.

Guest luthienanarion
Posted

 

Sorry, it looks like it has been overlooked. Looks easy to add though.

 

It makes me feel guilty... but yeah if it was possible it would be wondrous :)

I also checked all the Actor Values in NVSE documentation but the aggro radius seems really unexistent, except maybe when it comes of package functions

 

 

My NVSE plugin has actor.LNGetAggroRadius and actor.LNSetAggroRadius if you need them for something before NVSE adds them.

Posted

Thank you very much Luthien, I really missed that one.

 

I take the occasion to ask you about another of your functions.
I solved all the other issues and only remains the SetMapMarkerName, I can't make it work

 

rMarkerREF.SetMapMarkerName "something"

rMarkerREF.SetMapMarkerName something

rMarkerREF.SetMapMarkerName sMyStringVar

rMarkerREF.SetMapMarkerName $sMyStringVar

 

They all compile, but noone gives a result in game, GetMapMarkerName returns empty everytime. The marker passes from having a name (the one I decided prior) to be empty, on the map it appears as çZ or something like that.

 

The issue is surely in the syntax, the variables are all fine.

Guest luthienanarion
Posted

Thank you very much Luthien, I really missed that one.

 

I take the occasion to ask you about another of your functions.

I solved all the other issues and only remains the SetMapMarkerName, I can't make it work

 

rMarkerREF.SetMapMarkerName "something"

rMarkerREF.SetMapMarkerName something

rMarkerREF.SetMapMarkerName sMyStringVar

rMarkerREF.SetMapMarkerName $sMyStringVar

 

They all compile, but noone gives a result in game, GetMapMarkerName returns empty everytime. The marker passes from having a name (the one I decided prior) to be empty, on the map it appears as çZ or something like that.

 

The issue is surely in the syntax, the variables are all fine.

 

I'll double-check my code and do some more testing. I'm thinking I should also add a function that returns whether a reference is a map marker or not.

Posted

I'm pretty sure that rMarkerREF is a good reference, I pick that value from an array I built manually (I listed every value). Also, GetMapMarkerName returns the previous value, when I call it before SetMapMarkerName, so... yeah, I really think I'm using an uncorrect syntax when I call the function. I always need to make many attempts when I pass strings to functions, because I noticed how they work in different ways, but this time I really failed every combination and I'm confused

Guest luthienanarion
Posted

The error was on my end, actually. I changed the method I used to set the value of the map marker name, and it's working now in testing.

It seems that I already had an IsMapMarker function defined but forgot to register it, so that'll be in v9 anyway.

Posted

Thank you so much. I have the script already done, in case you'll want an extra test from me

Guest luthienanarion
Posted

Thank you so much. I have the script already done, in case you'll want an extra test from me

 

I sent a PM with a link to an early build you can test with.

Posted

No, got a python CLI handy? (never leave home without one).

 

>>> bin(18432) # convert int to binary string
'0b100100000000000'

 

So, thats bits 11 + 14, which according to the docs means all the glasses you checked use slots:

11:    eyeglasses14:    mask

If you were to open one of the glasses up in the GECK and select a new slot as well, say "Upper Body" (bit 2) then you get:

 

>>> 0b100100000000100 # bit 2 now set. What's that as an int?

18436

 

If you were instead to unselect the mask slot, maybe to make glasses that can worn over the top of one.

 

>>> 0b000100000000000 # bit 14 is no set anymore, just 11

2048

 

Some mods may only use this slot, others may use any number of others for complex outfits. To check if an item has the glasses slot, you can do (there may be a better way):

int ItemBitMask
 
set ItemBitMask to GetEquipmentSlotsMask SomeItem
 
if ItemBitMask == (SetBit ItemBitMask, 11)
    ; the item is using the 'eyeglasses' bit
endif
Posted

windows 'calc' will do binary/hex/etc for you too, in 'programmer' mode.

 

This looks dodgy though.

if ItemBitMask == (SetBit ItemBitMask, 11)
    ; the item is using the 'eyeglasses' bit
endif
Won't that match glasses that don't have bit14 set?

 

if ItemBitMask & (1 << 11)
; do stuff
Is a bit more canonical.

 

Edit: fixed, thx odessa.

Posted

My code should evaluate true if the slots mask is equal to itself with bit11 ("eyeglasses" slot) set to 1. I am assuming the value of bit14 ("Mask" slot) is not important.

 

But, your code looks like a better/more normal way of checking for a bit :). Bit manipulation isn't something I've ever done much of.

Guest tomm434
Posted

Odessa, prideslayer, thanks!

 

I ended up using Odessa's version because I couldn't get "manipulation" to work - GECK says "wrong syntax"

if ItemBitMask == (SetBit ItemBitMask, 11) picks up glasses and helmets which uses glasses slot as well.

 

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