Jump to content

How to use event handlers for hotkey scripting?


FiftyTifty

Recommended Posts

I'm trying to make a script that, when the insert key is pressed, will freeze all the player owned items nearby, so they cannot be moved around. I got the base idea down:

 

Make array of all item types (weapon, clothing, aid, misc, ammo, books, ingredients)

 

Iterate through each array

 

Call SetRigidBodyMass 100 on each ref in each array

 

But, unfortunately, the documentation on how to actually use events to handle hotkeys is lacking: https://geckwiki.com/index.php/SetOnKeyDownEventHandler

 

Judging by that wee article, I need to have two scripts. One that does all the actual work, and a quest script that starts the event handler for the hotkey. But that's not working:

 

The current script to be called:

 

SetOnKeyDownEventHandler AAAFyTyHotkeyFreezeItemsScript 1 210

scn AAAFyTyHotkeyFreezeItemsScript
int    iKeyID

array_var array_MiscRefsInCell
array_var array_BookRefsInCell
array_var array_ClothingRefsInCell
array_var array_IngredientRefsInCell
array_var array_WeaponRefsInCell
array_var array_AmmoRefsInCell
array_var array_AlchemyRefsInCell
array_var array_Refs

begin function {iKeyID}
    
    let array_BookRefsInCell := GetRefs 25 1
    let array_ClothingRefsInCell := GetRefs 27 1
    let array_IngredientRefsInCell := GetRefs 29 1
    let array_MiscRefsInCell := GetRefs 31 1
    let array_WeaponRefsInCell := GetRefs 40 1
    let array_AmmoRefsInCell := GetRefs 41 1
    let array_AlchemyRefsInCell := GetRefs 47 1
    
end function

 

 

The script attached to the quest:

 

 

scn AAAFyTyHotkeyFreezeItemsHotkeyEventScript

SetOnKeyDownEventHandler AAAFyTyHotkeyFreezeItemsScript 1 210

 

 

The error: "All script commands must be inside a begin/end block."

 

So where do I go from here?

Link to comment
Share on other sites

I figured out how the event handler should look:

 

 

scn AAAFyTyHotkeyFreezeItemsHotkeyEventScript
short bDone

begin GameMode
    
    if bDone == 0
        SetOnKeyDownEventHandler AAAFyTyHotkeyFreezeItemsScript 1 210
        set bDone to 1
        StopQuest AAAFyTyHotkeyFreezeItemsQuest
    endif

end

 

So that's well and good, it compiles fine, though I don't know if stopping the quest will also disable the event handler.

 

The next hurdle, is figuring out how to get each ref from the arrays.

Link to comment
Share on other sites

Doesn't seem to do anything. Damn.

 

So I have three scripts in total. The first, is the quest script:

scn AAAFyTyHotkeyFreezeItemsHotkeyEventScript
short bDone

begin GameMode
    
    if bDone == 0
        SetOnKeyDownEventHandler AAAFyTyHotkeyFreezeItemsScript 1 210
        set bDone to 1
        ;StopQuest AAAFyTyHotkeyFreezeItemsQuest
    endif

end

Here is the script being referenced by the event handler:

scn AAAFyTyHotkeyFreezeItemsScript
int    iKeyID

array_var array_MiscRefsInCell
array_var array_BookRefsInCell
array_var array_ClothingRefsInCell
array_var array_IngredientRefsInCell
array_var array_WeaponRefsInCell
array_var array_AmmoRefsInCell
array_var array_AlchemyRefsInCell
array_var array_Refs

ref refItem

begin function {iKeyID}
    
    let array_BookRefsInCell := GetRefs 25 1
    let array_ClothingRefsInCell := GetRefs 27 1
    let array_IngredientRefsInCell := GetRefs 29 1
    let array_MiscRefsInCell := GetRefs 31 1
    let array_WeaponRefsInCell := GetRefs 40 1
    let array_AmmoRefsInCell := GetRefs 41 1
    let array_AlchemyRefsInCell := GetRefs 47 1
    
    foreach array_Refs <- array_BookRefsInCell
        let refItem := array_BookRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_ClothingRefsInCell
        let refItem := array_ClothingRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_IngredientRefsInCell
        let refItem := array_IngredientRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_MiscRefsInCell
        let refItem := array_MiscRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_WeaponRefsInCell
        let refItem := array_WeaponRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_AmmoRefsInCell
        let refItem := array_AmmoRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_AlchemyRefsInCell
        let refItem := array_AlchemyRefsInCell["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
end function

And here's the wee script function that is repeatedly called:

scn AAAFyTyFreezeIfPlayerOwner
ref refItem

Begin function {refItem}
    if refItem.GetOwner == Player
            refItem.SetRigidBodyMass 100
        endif
    return
End

So it should work; it all compiles fine. The only way I could see the cause of this not working, is that I need to get the actual player actor reference, whereas the Player variable may only reference the player base record?

 

Edit: Changing the player check to if RefItem.IsOwner doesn't remedy the issue. So it's something else that is causing the script to not run on any of the references, if there are any in the arrays.

 

2nd Edit: I was improperly cycling through the arrays, so now I know that they have references in them. Here is the updated script:

 

 

scn AAAFyTyHotkeyFreezeItemsScript
int    iKeyID

array_var array_MiscRefsInCell
array_var array_BookRefsInCell
array_var array_ClothingRefsInCell
array_var array_IngredientRefsInCell
array_var array_WeaponRefsInCell
array_var array_AmmoRefsInCell
array_var array_AlchemyRefsInCell
array_var array_Refs

ref refItem

begin function {iKeyID}
    
    let array_BookRefsInCell := GetRefs 25, 1
    let array_ClothingRefsInCell := GetRefs 26, 1
    let array_IngredientRefsInCell := GetRefs 29, 1
    let array_MiscRefsInCell := GetRefs 31, 1
    let array_WeaponRefsInCell := GetRefs 40, 1
    let array_AmmoRefsInCell := GetRefs 41, 1
    let array_AlchemyRefsInCell := GetRefs 47, 1
    
    Ar_Dump array_BookRefsInCell
    Ar_Dump array_ClothingRefsInCell
    Ar_Dump array_IngredientRefsInCell
    Ar_Dump array_MiscRefsInCell
    Ar_Dump array_WeaponRefsInCell
    Ar_Dump array_AmmoRefsInCell
    Ar_Dump array_AlchemyRefsInCell
    
    foreach array_Refs <- array_BookRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_ClothingRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_IngredientRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_MiscRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_WeaponRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_AmmoRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
    foreach array_Refs <- array_AlchemyRefsInCell
        let refItem := array_Refs["value"]
        call AAAFyTyFreezeIfPlayerOwner refItem
    loop
    
end function

 

So the arrays are being filled properly. That's good. But the references are not being affected by the rigid body mass function, which is bad.

Edited by FiftyTifty
Link to comment
Share on other sites

Attached a Print "Called SetRigidBodyMass" to my UDF, and it does not get called. So I'm getting closer; for some reason, my if check isn't evaluating to true when it should be.

 

Edit: Right, managed to get it to be called with some clever thinking.

 

Every item dropped by the player has a formID beginning with FF. If I just check for the items with an ID more than FF000000, we're golden.

scn AAAFyTyFreezeIfPlayerOwner
ref refItem
string_var strFormID
int iRefFormID
int iFFToInt

Begin function {refItem}
    
    let iFFToInt := 4278190080
    let strFormID := GetFormIDString refItem
    let iRefFormID := ToNumber strFormID, 1

    if iRefFormID > iFFToInt
            refItem.SetRigidBodyMass 100
            Print "Called SetRigidBodyMass"
        endif
    return
End

But now there's a new issue. Despite calling SetRigidBodyMass on the items, it doesn't have any effect for some reason.

 

Edit2: I added another Print function to check the FormID of refItem , just to make sure the items are being passed along to the script. They print as expected, so that's not the issue.

Edited by FiftyTifty
Link to comment
Share on other sites

Following this with interest. Unfortunately don't have any experience to assist. Just don't want you to think you are talking to yourself in an empty room.

 

Have you seen CIPCIS article "Detecting Keypresses"? An "EventHandler" is triggered in response to some action. You started out looking for a "hotkey" and what I don't see is any code to detect that in "scn AAAFyTyHotkeyFreezeItemsHotkeyEventScript" or elsewhere.

 

-Dubious-

Link to comment
Share on other sites

Following this with interest. Unfortunately don't have any experience to assist. Just don't want you to think you are talking to yourself in an empty room.

 

Have you seen CIPCIS article "Detecting Keypresses"? An "EventHandler" is triggered in response to some action. You started out looking for a "hotkey" and what I don't see is any code to detect that in "scn AAAFyTyHotkeyFreezeItemsHotkeyEventScript" or elsewhere.

 

-Dubious-

 

I actually managed to get the hotkey working. And CIPCIS' method is not ideal, as it uses GameMode for the bulk of the scripting. The point of having event handlers, is to only process code when we need to, rather than every frame or every few seconds.

 

To get it to work, you make two scripts. One is the script you attach to the quest that has a very barebones GameMode block, which then readies the event handler. You then point it to the second script you made, which is the one that does all the work. If you look at the script I have attached to the quest, it calls the following line:

 

SetOnKeyDownEventHandler AAAFyTyHotkeyFreezeItemsScript 1 210

 

AAAFyTyHotkeyFreezeItemsScript is the name of the script I made that does the bulk of the processing. The 1 means we want to enable the event handler, and 210 is the key code for the insert key.

Link to comment
Share on other sites

Honestly I would just use a "Begin OnActivate" to do your freezing / unfreezing. Placed on an activator in the cell (switch / button ?)

 

And I'm assuming all the items would have been grabbed , then moved , then released ... prior to wanting to freeze them ?

 

So you could have another activator , that starts a gamemode block ... that will start assigning items upon release , to then be frozen by the OnActivate script ??? IDK ... just my thoughts for something more simple since arrays are a mystery to me. More simple as in clunky I guess :confused:

Link to comment
Share on other sites

Honestly I would just use a "Begin OnActivate" to do your freezing / unfreezing. Placed on an activator in the cell (switch / button ?)

 

And I'm assuming all the items would have been grabbed , then moved , then released ... prior to wanting to freeze them ?

 

So you could have another activator , that starts a gamemode block ... that will start assigning items upon release , to then be frozen by the OnActivate script ??? IDK ... just my thoughts for something more simple since arrays are a mystery to me. More simple as in clunky I guess :confused:

 

I'd rather not have to use an object in lieu of the hotkey. Good news is that the hotkey works, it's just I can't get a function to run on the objects inside the arrays, which I'd have to do in the same way even if I did use an activator. Got to be able to get the items somehow.

 

Also, I've made a whole bunch of hoarding dens, and I'd really rather not have to grab and re-place everything again.

Link to comment
Share on other sites

The "OnActivate" is superior to the "OnFunction" because the interface does not have to second guess accidental key press. Or style of pressing the key ... Literally the distance between top and bottom key press.

 

Takes exponential AI guess work ... vs "Begin OnActivate" Plus you can give the player a perk that will give secondary "E" key choices upon mouse over per item. Which executes a second choice "Begin OnActivate"

Link to comment
Share on other sites

  • Recently Browsing   0 members

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