Tasheni Posted November 6, 2021 Share Posted November 6, 2021 I use this script Thanks to IsharaMeradin and ReDragon2013) for mounting my follower: scriptName _ChiomaraPlayerMountMonitorScript extends ReferenceAlias;-- Properties --------------------------------------faction property CurrentFollowerFaction autoactor property Dubha autovisualeffect property Effect autoactor property PlayerRef autoactor 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 endIfendFunctionfunction OnInit() utility.Wait(5.00000) Player = game.GetPlayer() self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseMount") self.RegisterForAnimationEvent(PlayerRef as objectreference, "tailHorseDismount")endFunctionfunction OnAnimationEvent(objectreference akSource, String asEventName) if akSource == PlayerRef as objectreference self.FollowerMount(Chiomara, Dubha, asEventName, 0.300000) else return endIfendFunction 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 More sharing options...
Sphered Posted November 6, 2021 Share Posted November 6, 2021 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 More sharing options...
Tasheni Posted November 6, 2021 Author Share Posted November 6, 2021 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 More sharing options...
IsharaMeradin Posted November 7, 2021 Share Posted November 7, 2021 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 More sharing options...
Tasheni Posted November 7, 2021 Author Share Posted November 7, 2021 (edited) 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 November 7, 2021 by Tasheni Link to comment Share on other sites More sharing options...
IsharaMeradin Posted November 7, 2021 Share Posted November 7, 2021 Is your quest flagged as start game enabled? If not, check it and see what happens. Link to comment Share on other sites More sharing options...
Tasheni Posted November 7, 2021 Author Share Posted November 7, 2021 (edited) 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 November 7, 2021 by Tasheni Link to comment Share on other sites More sharing options...
IsharaMeradin Posted November 7, 2021 Share Posted November 7, 2021 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 More sharing options...
Tasheni Posted November 7, 2021 Author Share Posted November 7, 2021 Yes, I think it's best to stick with that workaround. Thank you and have a nice evening. Link to comment Share on other sites More sharing options...
ReDragon2013 Posted November 13, 2021 Share Posted November 13, 2021 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 More sharing options...
Recommended Posts