Jump to content

[LE] Function OnInit problem


Tasheni

Recommended Posts

I use this script Thanks to IsharaMeradin and ReDragon2013) for mounting my follower:

 

scriptName _ChiomaraPlayerMountMonitorScript extends ReferenceAlias

;-- Properties --------------------------------------
faction property CurrentFollowerFaction auto
actor property Dubha auto
visualeffect property Effect auto
actor property PlayerRef auto
actor property Chiomara auto

;-- Variables ---------------------------------------
actor Player

;-- Functions ---------------------------------------

function FollowerMount(actor myFollower, actor myHorse, String asEventName, Float afTime)

form EquippedItemLeft = PlayerRef.GetEquippedObject(0)
form EquippedItemRight = PlayerRef.GetEquippedObject(1)
if myFollower.IsInFaction(CurrentFollowerFaction) == 1 as Bool
if myFollower.GetActorValue("WaitingForPlayer") == 0 as Float
if EquippedItemLeft as Bool || EquippedItemRight as Bool
if asEventName == "tailHorseMount"
debug.SendAnimationEvent(Chiomara as objectreference, "IdleForceDefaultState")
myFollower.OnAnimationEvent(none, "tailHorseMount")
Effect.play(myFollower as objectreference, 0.300000, none)
myHorse.MoveTo(myFollower as objectreference, 50.0000 * math.sin(myFollower.GetAngleZ() + 90.0000), 50.0000 * math.cos(myFollower.GetAngleZ() + 90.0000), 0.000000, true)
utility.Wait(0.100000)
myFollower.SetAnimationVariableBool("bIsRiding", 1 as Bool)
myFollower.EvaluatePackage()
endIf
if asEventName == "tailHorseDismount"
Bool dismountInitiated = myFollower.Dismount()
myFollower.SetAnimationVariableBool("bIsRiding", 0 as Bool)
myFollower.EvaluatePackage()
endIf
else
return
endIf
endIf
endIf
endFunction

function OnInit()

utility.Wait(5.00000)
Player = game.GetPlayer()
self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseMount")
self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseDismount")
endFunction

function OnAnimationEvent(objectreference akSource, String asEventName)

if akSource == PlayerRef as objectreference
self.FollowerMount(Chiomara, Dubha, asEventName, 0.300000)
else
return
endIf
endFunction

 

That works fine - most of the time.

I discovered last week an issue with that script I never was aware of, because I never change my character (lol):

 

On a vanilla game without mods installed, the OnInit function stops working, if you open the console and type showracemenu, change the appearance of the player and close.

 

Then OnInit doesn't fire anymore. If you use Alternate Start, all works fine. I can't tell why that happens. I will use a workaround, but have not tested, yet: I create a new quest and put the follower alias with the script attached into it. Nothing else in it, so it can securely be stopped and started again, if necessary. But I would like to know, why that happens. Your suggestions are welcome.

Link to comment
Share on other sites

Aside from below, the way I have followers mount is I have them cast a spell which summons their mount and they ride it till I dismount

 

Rewrote yours real quick with notes of things that stood out to me, but TBH this script you use is way too busy for what its trying to do, and prone to having issues

 

The post formatted it weird maybe I shouldnt use the code but anyway it just made the spacing look off

Event OnInit()
     Utility.Wait(5.00000)
     RegisterForAnimationEvent(Game.GetPlayer(),"tailHorseMount")
     RegisterForAnimationEvent(Game.GetPlayer(),"tailHorseDismount")
EndEvent

; TBH you dont even need OnInit() at all. Your AIPack can listen for when player is mounted to do things. Preserved your approach though since it triggers below

Event OnAnimationEvent(Objectreference akSource,String asEventName)
	 Bool Review = akSource == Game.GetPlayer() && (asEventName == "tailHorseMount" || asEventName == "tailHorseDismount") && Chiomara as Bool && Dubha as Bool && Chiomara.IsInFaction(CurrentFollowerFaction) && !Chiomara.GetActorValue("WaitingForPlayer")
	 If Review; Above is busy but it consolidated your checks to save other steps if not needed
		 Float afTime = 0.3; You werent using this so if you meant to you need to implement it where applicable
		 Form EquippedItemLeft = (akSource as Actor).GetEquippedObject(0)
		 Form EquippedItemRight = (akSource as Actor).GetEquippedObject(1)
		 Bool Proceed = EquippedItemLeft as Bool || EquippedItemRight as Bool; Why are we doing armed checks? Combat? There are more optimals ways
		 If Proceed && asEventName == "tailHorseMount"
			 Debug.SendAnimationEvent(Chiomara,"Jumpland"); Jumpland is more reliable than IdleForceDefaultState
			 Chiomara.OnAnimationEvent(none,"tailHorseMount"); This wont do anything unless Chiomara has this script function attached somewhere
			 Effect.Play(Chiomara,0.3); I assume this is where you were wanting afTime but you can just keep it as 0.3
			 Dubha.MoveTo(Chiomara,50.0 * Math.Sin(Chiomara.GetAngleZ() + 90.0),50.0 * Math.Cos(Chiomara.GetAngleZ() + 90.0),0.0)
			 Utility.Wait(0.1)
                         ;I have to assume your AIPack is telling your follower to mount at this point otherwise you need to activate the horse
			 ;Chiomara.SetAnimationVariableBool("bIsRiding",True); Is this necessary though?
			 ;Chiomara.EvaluatePackage(); Ditto. Their package stack should be using IsMounted etc checks
		 ElseIf asEventName == "tailHorseDismount" && Proceed
			 Chiomara.Dismount(); No need to declare this as a bool it just waits till they dismount to continue below
			 ;Chiomara.SetAnimationVariableBool("bIsRiding",False); Same as above the package will review
			 ;Chiomara.EvaluatePackage()
                 EndIf
         EndIf
EndEvent
Link to comment
Share on other sites

Hello Sphered, thank you for your response. I'm not a scripter, so I need a bit time to figure out how your script works.

My followers don't need a spell to summon their horse. Horses are teleported to followers automatically if player mounts. bIsRiding is necessary as there is no papyrus function to mount npcs, only for dismount.

 

Your AIPack can listen for when player is mounted to do things.

This is true but needs way too much time. I mount six followers at once and the script I use does it mostly fast and reliable.

 

Why are we doing armed checks? Combat? There are more optimals ways

 

If player unequips weapons and spells my followers start sandboxing. And that also triggers banter scenes between them. They should not be mounted with the player then.

 

My script was made with the help of the community, the topic is here: https://forums.nexusmods.com/index.php?/topic/6211071-follower-mount-and-dismount-script-need-help/?hl=tasheni&do=findComment&comment=55813681

 

The way I did it, OnInit is necessary. But why does it stop working after open racemenu via console? If that happens to other scripts as well, this would be a real problem.

 

My workaround works so far, just tested it. Player can talk to my followers and tell them to mount faster. This stops the monitor quest and restarts it. The script runs fine again then. Player needs to do this everytime he opens racemenu.

Link to comment
Share on other sites

You are waiting a full 5 seconds inside the OnInit event. Opening the console and the race menu will both pause the timer causing the 5 seconds to take place later than you would expect. I recommend registering for a single update in the OnInit event and pushing the rest of that code into the OnUpdate event instead. The update event will still be pushed back due to menu usage but you may have better results. Plus it is good practice to minimize what is done inside the OnInit event. Especially since certain scenarios can trigger the event twice for some quests.

 

For example:

Event OnInit()
  RegisterForSingleUpdate(5.0)
endEvent

Event OnUpdate()
  RegisterForAnimationEvent(PlayerRef, "tailHorseMount")
  RegisterForAnimationEvent(PlayerRef, "tailHorseDismount")
EndEvent
Link to comment
Share on other sites

Hi Ishara, thank you for guiding me. I did now how you said. Here is the modified and tweaked script:


scriptName _RubyPlayerMountMonitorScript extends ReferenceAlias

;-- Properties --------------------------------------
actor property Ruby auto
visualeffect property Effect auto
faction property CurrentFollowerFaction auto
actor property PlayerRef auto
actor property Assan auto

;-- Variables ---------------------------------------
actor Player

;-- Functions ---------------------------------------

; Skipped compiler generated GotoState

; Skipped compiler generated GetState

function FollowerMount(actor myFollower, actor myHorse, String asEventName, Float afTime)

    form EquippedItemLeft = PlayerRef.GetEquippedObject(0)
    form EquippedItemRight = PlayerRef.GetEquippedObject(1)
    if myFollower.IsInFaction(CurrentFollowerFaction) == 1 as Bool
        if myFollower.GetActorValue("WaitingForPlayer") == 0 as Float
            if EquippedItemLeft as Bool || EquippedItemRight as Bool
                if asEventName == "tailHorseMount"
                    debug.SendAnimationEvent(Ruby as objectreference, "IdleForceDefaultState")
                    myFollower.OnAnimationEvent(none, "tailHorseMount")
                    Effect.play(myHorse as objectreference, 0.300000, none)
                    myHorse.MoveTo(myFollower as objectreference, 55.0000 * math.sin(myFollower.GetAngleZ() + 90.0000), 55.0000 * math.cos(myFollower.GetAngleZ() + 90.0000), 0.000000, true)
                    ;utility.Wait(0.100000)
                    myFollower.SetAnimationVariableBool("bIsRiding", 1 as Bool)
                    myFollower.EvaluatePackage()
                endIf
                if asEventName == "tailHorseDismount"
                    Bool dismountInitiated = myFollower.Dismount()
                    myFollower.SetAnimationVariableBool("bIsRiding", 0 as Bool)
                    myFollower.EvaluatePackage()
                endIf
            else
                return
            endIf
        endIf
    endIf
endFunction

function OnAnimationEvent(objectreference akSource, String asEventName)

    if akSource == PlayerRef as objectreference
        self.FollowerMount(Ruby, Assan, asEventName, 0.300000)
    else
        return
    endIf
endFunction

function OnInit()
    Debug.Messagebox("Script running")
    RegisterForSingleUpdate(0.3)

endFunction

function OnUpdate()
    Player = game.GetPlayer()
    self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseMount")
    self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseDismount")
endFunction

I hope I did it right. Script compiles fine, but the result is the same. No OnInit event when playing vanilla Skyrim and open racemenu during the intro scene. Then I talked to Ruby to mount faster, quest stopped and started new and all runs right.

Discovered right now that this happens, too with Alternate Start. Well, I guess I have to stick with my workaround.

Edited by Tasheni
Link to comment
Share on other sites

No, it's not anymore. It was when I discovered this bug the first time. I have now a frame quest that is start game enabled and handles the storylines. All necessary quests are started through a quest stage from this quest.

 

But to ensure this, I tried that with setting the quest start game enabled and removed the script lines that would start the quest. Same result. Discovered now: If player changes the race, then OnInit stops working. If I use racemenu to change only eyecolor or hair, script works fine.

 

That explains, why the script never worked with vanilla start, but with Alternative Start. Racemenu was opened before my mod triggered in LAL. In Helgen Intro it is opened when Hadvar asks: Who are you? But my playermounting quest starts before this event.

Edited by Tasheni
Link to comment
Share on other sites

That is weird to say the least. I wonder if it isn't the OnInit failing but rather the animation registrations. While the reference ID for the player doesn't change, the appearance and all that jazz does change with a race change. I suspect that the animation registrations are getting lost and need to be reapplied.

 

Probably best to stick with the solution you came up with since you never know when the player might decide to change race. Shoot, I wonder how it would have behaved with werewolf and vampire, those are technically race changes too. Might explain some of the bug reports I've seen...

Link to comment
Share on other sites

For understanding: We assume the ReferenceAlias script(s) are running on playerAlias. Each alias and script as well has an own quest, which is started and stopped by a frame quest you mentioned, depends on stage.

 

I think it does not make sense to use different script names for the same purpose. Something inside the scripts can be tweaked to have only one script with properties different filled.

 

_MountPlayerAliasScript

 

Scriptname _MountPlayerAliasScript extends ReferenceAlias
; https://forums.nexusmods.com/index.php?/topic/10690973-function-oninit-problem/

;scriptName _ChiomaraPlayerMountMonitorScript extends ReferenceAlias
;scriptName _RubyPlayerMountMonitorScript extends ReferenceAlias

;-- Properties --------------------------------------

  Faction      PROPERTY CurrentFollowerFaction auto
  VisualEffect PROPERTY Effect                 auto

  Actor PROPERTY theNPC auto
      ; 1 Chiomara,
      ; 2 Ruby
 
  Actor PROPERTY theHorse auto
      ; 1 Dubha,
      ; 2 Assan

  Float fEffectTime = 0.3


;-- EVENTs -- 4

EVENT OnInit()
    RegisterForSingleUpdate(2.0)
ENDEVENT

EVENT OnPlayerLoadGame()
    RegisterForSingleUpdate(2.1)
ENDEVENT

EVENT OnUpdate()
    Utility.Wait(3.0)

; playerAlias script only:
; self.GetReference()      == Game.GetPlayer() as ObjectReference
; self.GetActorReference() == Game.GetPlayer()

    objectReference player = self.GetReference()
    IF ( player )
        Debug.Trace("tailHorse animations will be register for " +self)   ; see "papyrus.0.log"

        RegisterForAnimationEvent(player, "tailHorseMount")           ; register for mount animation (start horse riding)
        RegisterForAnimationEvent(player, "tailHorseDismount")        ; register for dismount        (stop horse riding)
    ENDIF
ENDEVENT


EVENT OnAnimationEvent(Objectreference akSource, String asEventName)
    IF (akSource == self.GetReference())        
        myF_Anim(akSource, asEventName)
    ENDIF
ENDEVENT


;-- FUNCTIONs -- 4

;-------------------------
FUNCTION myF_FixAI(Bool b)
;-------------------------
; "I have to assume your AIPack is telling your follower to mount at this point otherwise you need to activate the horse" (*Sphered)

IF ( theNPC )
    theNPC.SetAnimationVariableBool("bIsRiding", b)     ; "Is this necessary though?" (*)
    theNPC.EvaluatePackage()                            ; "Their package stack should be using IsMounted etc checks" (*)
ENDIF
ENDFUNCTION


;--------------------------------------
Bool FUNCTION myF_Nothing(Actor player)
;--------------------------------------
;IF player.GetEquippedObject(0)        ; SKSE required! -- item in players leftHand
IF player.GetEquippedItemType(0)
    Return False
ENDIF
;---------
;IF player.GetEquippedObject(1)        ; SKSE required! -- item in players rightHand
IF player.GetEquippedItemType(1)
    Return False
ENDIF
;---------
    Return TRUE            ; 0: Nothing (Hand to hand)
ENDFUNCTION


;--------------------------------------------------------------
FUNCTION myF_Anim(ObjectReference akSource, String asEventName)
;--------------------------------------------------------------
IF theNPC.IsInFaction(CurrentFollowerFaction)
ELSE
    RETURN    ; - STOP - /1    npc (mod added) is not a real follower at time
ENDIF
;---------------------
IF (theNPC.GetActorValue("WaitingForPlayer") == 0)
ELSE
    RETURN    ; - STOP - /2    npc (mod added) is waiting for the player
ENDIF
;---------------------
IF myF_Nothing(akSource as Actor)
    RETURN    ; - STOP - /3    player does not have anything equipped by hand
ENDIF
;---------------------
IF (asEventName == "tailHorseDismount")
    int i = 10
    WHILE (i)
        Utility.Wait(0.1)
        IF theNPC.Dismount()            ; "No need to declare this as a bool it just waits till they dismount to continue below" (*)  ???
            myF_FixAI(False)
            RETURN    ; - STOP - /4a    theNPC is dismounted as well
        ENDIF
;        ----------------------
        i = i - 1        ; decrease counter to have an escape option for this loop
    ENDWHILE
    RETURN    ; - STOP - /4b    player is dismounted
ENDIF
;---------------------
;IF (asEventName == "tailHorseMount")
;;;    Debug.SendAnimationEvent(theNPC as ObjectReference, "IdleForceDefaultState")    ; play special idle here
    Debug.SendAnimationEvent(theNPC as ObjectReference, "Jumpland")                    ; "is more reliable than IdleForceDefaultState" (*)

    ; 'This wont do anything unless theNPC (aka Chiomara) has a script with this event attached somewhere' (*Sphered)
    theNPC.OnAnimationEvent(None, "tailHorseMount")                                    ; ???

; https://www.creationkit.com/index.php?title=Play_-_VisualEffect
    Effect.Play(theNPC as ObjectReference, fEffectTime)

    MoveHorseToNPC()
    Utility.Wait(0.1)
    myF_FixAI(TRUE)
;ENDIF
ENDFUNCTION


; Chiomora
;    myHorse.MoveTo(myFollower as objectreference, 50.0000 * math.sin(myFollower.GetAngleZ() + 90.0000), 50.0000 * math.cos(myFollower.GetAngleZ() + 90.0000), 0.000000, true)
;    utility.Wait(0.100000)

; Ruby
;    myHorse.MoveTo(myFollower as objectreference, 55.0000 * math.sin(myFollower.GetAngleZ() + 90.0000), 55.0000 * math.cos(myFollower.GetAngleZ() + 90.0000), 0.000000, true)
;    ;utility.Wait(0.100000)

;------------------------
FUNCTION MoveHorseToNPC()  ; helper, outsourced code for better overview
;------------------------
    float aZ = theNPC.GetAngleZ() + 90.0        ; get the angleZ and add 90 degree
    float fx = Math.SIN(aZ) * 52.5
    float fy = Math.COS(aZ) * 52.5

IF (theNPC) && (theHorse)
    theHorse.MoveTo(theNPC as ObjectReference, fx, fy, 0.0, TRUE)
ENDIF
ENDFUNCTION

 

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

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