Jump to content

Photo

How to make a script to activate an effect by holding a specific key

script onkeyup onkeydown hold key holding key effect skse

  • Please log in to reply
9 replies to this topic

#1
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

First of all, thanks for your concern on this help request of mine  :smile:

 

I'm not a native English speaker, so please be advised if my English is a bit messed up or not properly arranged.

I've been modding skyrim for several years, most of them involving patching and editing records in the plugins, but this is actually my first time trying to write a script. Yes, i'm totally new to scripting, and i just learned a bit about papyrus recently (i have no programming background whatsoever, so yeah papyrus is my first scripting language i learnt... just a bit, very very little).

 

I'm currently trying to make a script about using a "hold key" feature to activate an effect. The effect is higher and further jump effect (i'm involving fJumpHeightMin, fJumpMoveMult, and SpeedMult game settings) which will be triggered when some specific conditions are made. The conditions are:

1. The player must have a specific amount of Stamina in some variable ranges in order for the effect to work (i'm using getBaseAV("Stamina")).

2. The player must wear a specific footwear in order for the effect to work.

3. The player must hold a sneak key to activate the effect (may need to write how many seconds to hold the key, right? please do tell me). Consider that we need to hold the key for at least 1 second. When the player holds the sneak key for 1 second, the character will jump with the new fJumpHeightMin, fJumpMoveMult, and fJumpFallHeightMin game settings.

4. The effect activation will cost some Stamina (so the player will lose that amount of Stamina whenever he/she activate the effect). Lets say, the Stamina cost is 25.

5. A message will pop up on the up left corner of the screen if the player has no enough amount of Stamina to cast the effect.

 

The effect is part of a magic effect attached into the footwear (in condition 2). So this script will only activate when the player wears that footwear.

I understand that this script requires SKSE, and i'm having no clue on what exactly i should write to make it work as intended. I found OnKeyUp and OnKeyDown forms of SKSE but don't know exactly how to use it.

The amount of variable stamina ranges (condition 1) and the name of the footwear (condition 2) will be written in the following (my roughly unfinished written script):

Spoiler

So, where should i write codes for "holding the key" from SKSE in above script? And what to write? Some helps, examples, or corrections will be appreciated. Thanks in advance :smile:


Edited by qwertypol012, 03 January 2019 - 07:51 AM.


#2
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

I think i figured it out somehow after looking into Pounce n Dash mod by stonedsquirrel. I duplicated his script and tweaked it a bit into my liking, so thanks to him (he made his mod's scripts free to use as long as not for commercial use).  :smile:

 

Now, what needs to be done is how to check the player's race when they activate the effect. To explain it further, i decided to switch the condition number 1 (as stated in my first post) from "based on stamina amount" into "based on race", so the variables of higher jump will be based on player's race and not on stamina amount anymore. I found function Game.GetPlayer().GetRace() and it looks like the correct function to use, but i'm not sure if it works for activemagiceffect script since that's what my script extends to. So, would anyone mind to confirm about this?

 

Another thing i'm still wondering is that function Game.GetPlayer().GetRace() seems to require RaceText string to correctly check for race, and i don't know if we can put strings as properties for activemagiceffect script. Also, since the script is supposed to check for all vanilla race, how do we write all of vanilla race records into a single RaceText strings to be used by Game.GetPlayer().GetRace() function? Can we just put some numbers in front of "RaceText" to identify all vanilla races? Or do we have a better method to check them all which works under activemagiceffect script?

I know this may sound stupid or funny for some papyrus experts, hence i'm sorry still i'm still so green in this expertise  :sweat:. So, any enlightenments will be really appreciated  :laugh:

 

Here i also put the new script i wrote as an attachment. It's not completed yet in the part of vanilla race check, but other parts should have been done already. The script is too long to be copied here as a code, so i attached it instead. If there are some errors in the script, please give me correction. Thanks in advance  :smile:


Edited by qwertypol012, 02 January 2019 - 06:23 AM.


#3
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

Oh, i just remembered. There's another thing i'm also wodering. Currently i put string RaceText = "[Race <xxxRace (000xxxxx)>]" under Function because that's the part in which the script applies the higher jump effect to the player. So, will it work? Or does it have to be put under Events? If so, how to correctly check the race when the effect is activated then? Thanks in advance!

 

For some reason the attachment didn't work, so i'll just put the script here. Sorry if it's too long, but please do tell me if there's another way to post it here in a more simple way. Edit: just wrapped it in spoiler, good now

Spoiler

Edited by qwertypol012, 03 January 2019 - 04:52 AM.


#4
IsharaMeradin

IsharaMeradin

    The Pale Redguard

  • Members
  • PipPipPipPipPip
  • 8,983 posts

Use properties for the races.

 

Property declaration would be like this:

Race Property NordRace Auto
Race Property BretonRace Auto
; etc...

Usage within a function or event would be like this:

If Game.GetPlayer().GetRace() == NordRace
  ;do something for nords
ElseIf Game.GetPlayer().GetRace() == BretonRace
  ;do something for bretons
EndIf

TIP: You can eliminate multiple calls to the Game script for the player data by storing the player data within a variable.  You can do a property or local variable.  Examples

Actor Property PlayerRef Auto ;will auto fill with the player
Actor PlayerRef

Event OnEffectStart(Actor akTarget, Actor akCaster)
  PlayerRef = Game.GetPlayer()
EndEvent

In both scenarios, you can replace future uses of Game.GetPlayer() with PlayerRef.  This will speed up your script by eliminating the need to pause the script and wait while the thread jumps to the Game script to get the player info.

 

 



#5
ReDragon2013

ReDragon2013

    Old hand

  • Members
  • PipPipPip
  • 542 posts

1) If you use SKSE functions or events make sure your script handles that right.

2) Do not call the same method over and over for comparing. Store the result in a local variable and compare that instead.

3) Use functions to split your code, it's better to read and easier to maintain

 

BerserkerJumpEffectScript

Spoiler

BerserkerDashEffectScript

Spoiler

Edited by ReDragon2013, 03 January 2019 - 02:01 AM.


#6
ReDragon2013

ReDragon2013

    Old hand

  • Members
  • PipPipPip
  • 542 posts

to make your script code invisible on this forum, use the spoiler tags in brakets (without spaces) like html code style

[ spoiler ]

 Scriptname xyz_Script extends Quest

[ /spoiler ]

 

Spoiler

Edited by ReDragon2013, 03 January 2019 - 02:08 AM.


#7
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

Finally! Thank you very much for the replies!!! This is amazing!  :D

Use properties for the races.

 

Property declaration would be like this:

Race Property NordRace Auto
Race Property BretonRace Auto
; etc...

Usage within a function or event would be like this:

If Game.GetPlayer().GetRace() == NordRace
  ;do something for nords
ElseIf Game.GetPlayer().GetRace() == BretonRace
  ;do something for bretons
EndIf

TIP: You can eliminate multiple calls to the Game script for the player data by storing the player data within a variable.  You can do a property or local variable.  Examples

Actor Property PlayerRef Auto ;will auto fill with the player
Actor PlayerRef

Event OnEffectStart(Actor akTarget, Actor akCaster)
  PlayerRef = Game.GetPlayer()
EndEvent

In both scenarios, you can replace future uses of Game.GetPlayer() with PlayerRef.  This will speed up your script by eliminating the need to pause the script and wait while the thread jumps to the Game script to get the player info.

 

 

Thanks for the reply! Never thought that we can simply use properties for races (that's actually possible, right)  :sweat:

Also, thanks for the tip for optimizing the script. Never know how to optimize codes in script, simply because i learnt it self-taught with no structured materials :tongue:

Once again, thanks for the optimizing tip. This should be very useful for me if i want to make more scripts in the future  :smile:

 

to make your script code invisible on this forum, use the spoiler tags in brakets (without spaces) like html code style

[ spoiler ]

 Scriptname xyz_Script extends Quest

[ /spoiler ]

 

Spoiler

Thanks for the tip. I've actually tried to use spoiler tags, but it didn't work because i wrote it wrong. Now it works.  :smile:


Edited by qwertypol012, 03 January 2019 - 07:30 AM.


#8
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

1) If you use SKSE functions or events make sure your script handles that right.

2) Do not call the same method over and over for comparing. Store the result in a local variable and compare that instead.

3) Use functions to split your code, it's better to read and easier to maintain

 

BerserkerJumpEffectScript

Spoiler

BerserkerDashEffectScript

Spoiler

This took me awhile to learn and fathom the scripts. Thank you very much for the scripts! I'm very grateful with that  :D

Now, there are several things i want to ask regarding your edited scripts.

 

1. About this part of BerserkerDashEffectScript:

;IF (i == 0)        ; blank
    zzDashAbilityI   = zzDashAbilityBlankI
    zzDashAbilityII  = zzDashAbilityBlankII
    zzDashAbilityIII = zzDashAbilityBlankIII
    zzDashAbilityIV  = zzDashAbilityBlankIV
    zzDashAbilityV   = zzDashAbilityBlankV
;ENDIF
Why did you comment it out? Is it how it's supposed to be?
 
2. About part of this function (in BerserkerDashEffectScript):
;---------------------
    player.DamageActorValue("Stamina", fs)
    player.DamageActorValue("Magicka", fm)
    player.AddSpell(zzDashAbilityI, False)
    myF_Perks(player, Jump1, Length1, Speed1)
ENDFUNCTION
If i understand it correctly, the function damages the player's stamina and/or magicka if they're lower than the required amount (fm and fs), right?
If so, then what i actually want is that the function only damages the player's stam &/or mag if they're higher than fm &/or fs as a result of succesfully casted the effect (if you successfully cast the effect, your stam &/or mag will be damaged). If you fail, then your stam &/or mag won't be damaged.
Am i correct in this part (which means that part of the script need to be edited)?
 
Edit: I think i am. I think it needs to be wrapped in another IF ENDIF with condition if player's sta & mag are higher than fs & fm. (i just did)
 
3. About this part of the script (still in BerserkerDashEffectScript):
;-------------------------------------------------------------
FUNCTION myF_Perks(Actor player, Float fJ, Float fL, Float fS)  ; internal helper
;-------------------------------------------------------------
    int i = player.GetRace().GetFormID()
    
    IF     (i == 0x00013740)    ; ArgonianRace
    ELSEIF (i == 0x00013745)    ; KhajiitRace
    ELSEIF (i == 0x00013748)    ; RedguardRace
    ELSEIF (i == 0x00013749)    ; WoodElfRace
    ELSE
        Game.SetGameSettingFloat("fJumpHeightMin", JumpHeight + fJ)
        Game.SetGameSettingFloat("fJumpMoveMult", JumpLength + fL)
        player.ForceActorValue("speedmult", SpeedMult + fS)
        player.AddPerk(zzDummyPerk)
        player.RemovePerk(zzDummyPerk)
    ENDIF


;;;    Utility.Wait(0.1)
    player.AddPerk(zzFallProtection)
ENDFUNCTION

I still couldn't fully grasp it yet. If i understand it correctly, this function checks if the player race is one of the mentioned races, and if it's true then it adds jump heigh, jump length, and speed mult with the amount stored in FJ, FL, and FS, right?

So first, where do the fJ, fL, and fS call to? I couldn't find those floats anywhere else. It's the same with myF_Perks(player, Jumpx, Lengthx, Speedx (x = 1 to 5)) in which i couldn't see where Jumpx, Lengthx, and Speedx get their values from.
Also, has this function also check for vampire version of each respective race? Or do i need to add more ESLEIF for each vampire races?
 
Edit: I think i just grasped it. Float fJ, float fL, and float FS will call to Jumpx, Lengthx, and Speedx as part of function myF_Perks, right?
I also seemed to get temporal memory loss for not knowing where Jumpx, Lengthx, and Speedx get their values from (big duh on that, lol)  :sweat:  :tongue:
And i think i also need to add vampire races ones if i want them to be checked in the function. (just did)
 
4. Do i need to put objectReference playerRef as a property for the script? Also, anything else i need to add to the properties?
As a reference, this is my currently existing properties for BerserkerDashEffectScript:
Spoiler
The only ones i can think of is float f and int i, but i'm not sure if they need to be added as properties (i just added them anyway, just to be safe).
 
5. What does RETURN function exactly for? Can i also use it in any other functions? I have another script about casting a custom spell and i'm interested in using this to work as some kind of failsafe if the spell fail to cast
 
 
That's it for now. I'll ask again if i get more questions. Thank you very much  :smile:

Edited by qwertypol012, 03 January 2019 - 07:23 PM.


#9
ReDragon2013

ReDragon2013

    Old hand

  • Members
  • PipPipPip
  • 542 posts

Sorry for my late return, but I am not so good to make explanation. But if you want to understand papyrus language, you have to code scripts (again and again).
qwertypol012 asked:

1) Why did you comment it out? Is it how it's supposed to be?

;IF (i == 0)        ; blank
    zzDashAbilityI   = zzDashAbilityBlankI
    zzDashAbilityII  = zzDashAbilityBlankII
    zzDashAbilityIII = zzDashAbilityBlankIII
    zzDashAbilityIV  = zzDashAbilityBlankIV
    zzDashAbilityV   = zzDashAbilityBlankV
;ENDIF

Whenever you use multiple if/elseif conditions make sure to have an escape door.
One condition should be the default branch.

2) About part of this function (in BerserkerDashEffectScript):

    player.DamageActorValue("Stamina", fs)
    player.DamageActorValue("Magicka", fm)

I only try to optimize the script, I cannot really know what you want to aim here.
As I understand you found a proper solution.

The whole function is like that:

;-------------------
FUNCTION AddStage1()
;-------------------
    actor player = Game.GetPlayer()
    float fs = DashCostStam.GetValue()

IF (player.GetActorValue("stamina") < fs)            ; stamina = Game.GetPlayer().GetAv("stamina")
    myF_Fail(1)
    RETURN    ; - STOP -
ENDIF
;---------------------
    float fm = DashCostMag.Getvalue()

IF (player.GetActorValue("magicka") < fm)            ; magicka = Game.GetPlayer().GetAv("magicka")
    myyF_Fail(2)
    RETURN    ; - STOP -
ENDIF
;---------------------
    player.DamageActorValue("Stamina", fs)
    player.DamageActorValue("Magicka", fm)
    player.AddSpell(zzDashAbilityI, False)
    myF_Perks(player, Jump1, Length1, Speed1)
ENDFUNCTION

You wrote: "what i actually want is that the function only damages the player's stam &/or mag if they're higher than fm &/or fs"
As you can see stamina and magicka are checked before DamageActorValue() may run. That is what you wanted.

3) About this part of script:

;-------------------------------------------------------------
FUNCTION myF_Perks(Actor player, Float fJ, Float fL, Float fS)  ; internal helper
;-------------------------------------------------------------
    int i = player.GetRace().GetFormID()
    
    IF     (i == 0x00013740)    ; ArgonianRace
    ELSEIF (i == 0x00013745)    ; KhajiitRace
    ELSEIF (i == 0x00013748)    ; RedguardRace
    ELSEIF (i == 0x00013749)    ; WoodElfRace
    ELSE
        Game.SetGameSettingFloat("fJumpHeightMin", JumpHeight + fJ)
        Game.SetGameSettingFloat("fJumpMoveMult", JumpLength + fL)
        player.ForceActorValue("speedmult", SpeedMult + fS)
        player.AddPerk(zzDummyPerk)
        player.RemovePerk(zzDummyPerk)
    ENDIF
;;;    Utility.Wait(0.1)
    player.AddPerk(zzFallProtection)
ENDFUNCTION

What is the different between (global) script variable and (local script) function variable?
For example "JumpHeight" is a script variable (which you didn't provide us), it does not need to give us as function parameter,
but it can be. I use very short names for function variables to make different to global script variable names.

You wrote also: "So first, where do the fJ, fL, and fS call to? I couldn't find those floats anywhere else."

Every function has its own name room to identify variables. In the head you can put parameter names as you like the type
should be known to the compiler (int, float, actor, objectReference, etc.).
They are stored on the function stack like any other declared internal function variable.

You asked: "Also, has this function also check for vampire version of each respective race?
Or do i need to add more ESLEIF for each vampire races?"

Depends on what should be the result, you have to put vampire IDs too.

; string RaceText11 = "[Race <ArgonianRaceVampire (0008883A)>]"

    ELSEIF (i == 0x00013749)    ; WoodElfRace
    ELSEIF (i == 0x0008883A)    ; ArgonianRaceVampire
    ELSE

4) Do I need to put objectReference playerRef as a property for the script?
Try to minimize using of objectReference and actor as predefined property or script variable.

You asked: "The only ones i can think of is float f and int i, but i'm not sure if they need to be added as properties
(i just added them anyway, just to be safe)."

NO. NO. Both are local function variables and not needed to be declared out of the function.

5) What does RETURN function exactly for? Can i also use it in any other functions?
The papyrus term "RETURN" is like "ENDFUNCTION" or "ENDEVENT" depends of the body you call it.
Keep in mind that functions can be like this:

EVENT OnCellLoad()
    RETURN    ; - STOP - no parameter by default, because event body
ENDEVENT

FUNCTION XYZ()
    RETURN    ; - STOP - no function return parameter needed
ENDFUNCTION

Int FUNCTION intXYZ()
    RETURN 0    ; function returns with type integer (as digit)
ENDFUNCTION

Int FUNCTION intXYZ_2()
    int i = 0
    RETURN i    ; function returns with type integer (as value stored in local script variable)
ENDFUNCTION

Float FUNCTION floatXYZ()
    RETURN 0.0    ; function returns with type float (as digit)
ENDFUNCTION

Float FUNCTION floatXYZ_2(Float f)
    f = 0.0
    RETURN f    ; function returns with type float (as value stored in local script variable)
ENDFUNCTION

Edited by ReDragon2013, 24 January 2019 - 11:28 PM.


#10
qwertypol012

qwertypol012

    Resident poster

  • Members
  • PipPipPipPipPip
  • 2,743 posts

 

4) Do I need to put objectReference playerRef as a property for the script?

Try to minimize using of objectReference and actor as predefined property or script variable.

You asked: "The only ones i can think of is float f and int i, but i'm not sure if they need to be added as properties
(i just added them anyway, just to be safe)."

NO. NO. Both are local function variables and not needed to be declared out of the function.
 

Thanks for your reply! Yes, actually i've been learning almost everyday since the day i asked about this script, and now i understand that they're local function variables and should not be put as script properties  :laugh: 

Yes, code more scripts is a good way to learn more, but i also learnt by cracking up mods' scripts which i'm interested in. In the end, i only want to code something which i'm really interested in, so i'm not sure if i'll be able to master papyrus scripting faster. That said, i mostly always do anything to get something i really want, and if that's a script then i'll learn anything in order to finish that script. Just 2 cents though, not a big real. And thanks for coming back to give your reply.  :smile:







Also tagged with one or more of these keywords: script, onkeyup, onkeydown, hold key, holding key, effect, skse

Page loaded in: 1.076 seconds