Jump to content

[LE] How do I limit a script event to trigger once a second?


Recommended Posts

So I have a simple script that cast a spell whenever I get hit, which is attached to a permanent magic effect with conditions. Problem is, when I get hit by flame or frost it triggers like 100 times a second and crash my PC, before my conditions kick in to make it stop. How do I limit the event to trigger only once per second?

 

Scriptname MagicCastOnHit extends ActiveMagicEffect
{This script cast a spell on hit.}

;======================================================================================;
; PROPERTIES /
;=============/

SPELL PROPERTY armorSpell AUTO

;======================================================================================;
; VARIABLES /
;=============/

Actor TargetActor

;======================================================================================;
; EVENTS /
;=============/
Event OnEffectStart(Actor Target, Actor Caster)
TargetActor = Target
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

armorSpell.cast(TargetActor, TargetActor)

EndEvent

Edited by 123hamster
Link to comment
Share on other sites

One way to do it is to have the script go into a cooldown state as soon as the OnHit event is called, and then have the OnHit event do nothing while in cooldown state

 

example:

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

	GoToState("Cooldown")
	
	armorSpell.cast(TargetActor, TargetActor)

	RegisterForSingleUpdate(1)

EndEvent

State Cooldown
	Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
	EndEvent
EndState

Event OnUpdate()
	GoToState("")
EndEvent
Edited by rkkn
Link to comment
Share on other sites

  • 1 month later...

Thanks again for the code, this wind up being very useful as a replacement for the original MagicPlayEffectShaderOnHitScript. I didn't realize the original script was this problematic.

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

	GoToState("Cooldown")
	
	MagicEffectShader.play(TargetActor,ShaderDuration)

	RegisterForSingleUpdate(1)

EndEvent

State Cooldown
	Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
	EndEvent
EndState

Event OnUpdate()
	GoToState("")
EndEvent

 

Link to comment
Share on other sites

vanilla script as follow:

 

Scriptname MagicPlayEffectShaderOnHitScript extends ActiveMagicEffect  
{This script plays an effect shader on hit.}

;======================================================================================;
;  PROPERTIES  /
;=============/

EffectShader property MagicEffectShader auto
{The Effect Shader we want.}
float property ShaderDuration = 0.00 auto
{Duration of Effect Shader.}

;======================================================================================;
;  VARIABLES   /
;=============/

Actor TargetActor


;======================================================================================;
;   EVENTS     /
;=============/
Event OnEffectStart(Actor Target, Actor Caster)
    TargetActor = Target
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

        MagicEffectShader.play(TargetActor,ShaderDuration)
    
endevent

 

 

 

MagicPlayEffectShaderOnHitScript

 

Scriptname MagicPlayEffectShaderOnHitScript extends ActiveMagicEffect  
{v1.5 ReDragon 2021}  ; script plays an effect shader on hit
; https://forums.nexusmods.com/index.php?/topic/10580203-how-do-i-limit-a-script-event-to-trigger-once-a-second/

  EffectShader PROPERTY MagicEffectShader auto      ; The Effect Shader we want.

  Float PROPERTY ShaderDuration auto                ; [default=0.0], duration of EffectShader

  ObjectReference Target    ; as replacement for vanilla variable "TargetActor"


; -- EVENTs -- 

EVENT OnEffectStart(Actor akTarget, Actor akCaster)
    Target = akTarget as ObjectReference
    gotoState("Waiting")            ; ### STATE ###
ENDEVENT


EVENT OnEffectFinish(Actor akTarget, Actor akCaster)
    gotoState("")                   ; ### STATE ###
    Target = None
ENDEVENT


;===============================
State Waiting
;============
    EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4)
        gotoState("CoolDown")       ; ### STATE ###
        IF ( Target )
            MagicEffectShader.Play(Target, ShaderDuration)
            RegisterForSingleUpdate(1.0)
        ENDIF
    ENDEVENT
;=======
endState


;===============================
State CoolDown  ; like rkkn version
;=============
    EVENT OnUpdate()
        IF ( Target )
            gotoState("Waiting")    ; ### STATE ###
        ENDIF
    ENDEVENT
;=======
endState

 

 

Edited by ReDragon2013
Link to comment
Share on other sites

Thanks for your interest.

 

So just a n00b question, would

Float PROPERTY ShaderDuration auto  

Work without modify every magical effect that uses this script? Do we have to go into each mage armor (and whatever else that uses it), and set property to 0.0?

 

Modify the original script and keep the property line as-is rather than changing it to the way ReDragon had it. You will then be able to have the default value of 0.0 for any records that do not have an overriding value assigned in the Creation Kit's property interface.

float property ShaderDuration = 0.00 auto
Link to comment
Share on other sites

123hamster asked:

 

1. "Work without modify every magical effect that uses this script?"

YES

 

2. "Do we have to go into each mage armor (and whatever else that uses it), and set property to 0.0?"

not really, see answer of IsharaMeradin

 

Just in addition to IsharaMeradins posting to make the things hopefully more clearly.

PapyrusSampleScript

 

Scriptname PapyrusSampleScript extends Quest    ; ObjectReference, ReferenceAlias, ActiveMAgicEffect etc.
; https://forums.nexusmods.com/index.php?/topic/10580203-how-do-i-limit-a-script-event-to-trigger-once-a-second/

; Properties and script variables starts with a default value, if this value is not overriding
;   - by script itself as new default
;   - by using the Creation Kits property interface to change the default script value.

; ----------------
; property samples
; ----------------
  Float PROPERTY fTimer       auto           ; [default=0.0], the property starts with None which is the same as 0.0
                                             ; exception: if another value has been set by CK, the CreationKit value is taken !!!
 ;Float PROPERTY fTimer = 0.0 auto

  Int   PROPERTY iCounter     auto           ; [default=0]
 ;Int   PROPERTY iCounter = 0 auto
 
  Bool  PROPERTY bRun         auto           ; [default=False]
 ;Bool  PROPERTY bRun = False auto

; ------------------------------------
  Float PROPERTY fTimer1   = 1.0  auto       ; [default=1.0], during papyrus script initialization the value of property "fTimer1" will be set to 1.0
                                             ; exception: if another value has been set by CK, the CreationKit value is taken !!!
  Int   PROPERTY iCounter1 = 1    auto
  Bool  PROPERTY bRun1     = TRUE auto


; ----------------
; variable samples
; ----------------
  Float fTimer2                              ; [default=0.0]
 ;Float fTimer2 = 0.0

  Int   iCounter2                            ; [default=0]
 ;Int   iCounter2 = 0
 
  Bool  bRun2                                ; [default=False]
 ;Bool  bRun2 = False

;-----------------------
  Float fTimer3   = 2.0                      ; [default=2.0], during papyrus script initialization the value of variable "fTimer3" will be set to 2.0
  Int   iCounter3 = 2
  Bool  bRun3     = TRUE                     ; [default=TRUE], during .. value of variable "bRun3" will be set to TRUE

 

 

 

Script initialization runs before event OnInit() is ready to start any code inside!

And if event OnInit() has been finished any other event or function inside the script can be triggered or called. Thats the reason why anyone should avoid this:

 

DO NOT DO THAT!

 

EVENT OnInit()
   ; any code here
  Utility.Wait(1.0)         ; or any other waittime here
  ; any code here
ENDEVENT

 


What is the different between (A)

  Float PROPERTY fTimer       auto            ; [default=0.0], the property starts with this value
  Int   PROPERTY iCounter     auto            ; [default=0]
  Bool  PROPERTY bRun         auto            ; [default=False]

and these with property pre-selection by script (B)

  Float PROPERTY fTimer = 0.0 auto            ; [default=0.0]
  Int   PROPERTY iCounter = 0 auto            ; [default=0]
  Bool  PROPERTY bRun = False auto            ; [default=False]

 

 

(A) .variableTable
      .variable ::fTimer_var float
        .userFlags 0
        .initialValue None                    ; None is here the same as 0.0      - FLOAT
      .endVariable
      .variable ::iCounter_var int
        .userFlags 0
        .initialValue None                    ; None is here the same as 0        - INT
      .endVariable
      .variable ::bRun_var bool
        .userFlags 0
        .initialValue None                    ; None is here the same as False    - BOOL
      .endVariable
.endVariableTable
(B) .variableTable
      .variable ::fTimer_var float
        .userFlags 0
        .initialValue 0.0
      .endVariable
      .variable ::iCounter_var int
        .userFlags 0
        .initialValue 0
      .endVariable
      .variable ::bRun_var bool
        .userFlags 0
        .initialValue False
      .endVariable
.endVariableTable

 

 

Edited by ReDragon2013
Link to comment
Share on other sites

alright cool, so I can just copy and compile as is with no esp changes? Thanks.

 

Never would have thought that int/float/bool would make a difference when the code will run either way (but slower).

 

Hopefully Mage Armor stop crashing my game when hit by multiple flame spells.

Edited by 123hamster
Link to comment
Share on other sites

  • Recently Browsing   0 members

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