Scriptname _00E_BardAudienceScript extends Actor Faction Property BardAudienceStateFaction Auto _00E_BardDialogueFunctions Property BardDialogue Auto Package Property CrossedArmsListenPackage Auto Bool Property NoApplaud Auto Bool Property NoHeadtrackingBard Auto Int Property STATE_NONE = -1 AutoReadOnly Int Property STATE_APPLAUD = 0 AutoReadOnly Int Property STATE_LISTEN = 1 AutoReadOnly Bool bBardIsPlaying = False ;===================================================================================== ; EVENTS ;===================================================================================== Event OnLoad() If IsDead() == False GoToState("Spectating") RegisterForModEvent("BardSongStarted", "OnBardSongStarted") RegisterForModEvent("BardSongApplaud", "OnBardSongApplaud") RegisterForModEvent("BardSongEnded", "OnBardSongEnded") EndIf EndEvent State Spectating Event OnUnload() Terminate() EndEvent Event OnDying(Actor akKiller) Terminate() EndEvent Event OnDeath(Actor akKiller) Terminate() EndEvent EndState Event OnBardSongStarted(string a_eventName, string a_strArg, float a_numArg, Form a_sender) If Is3DLoaded() == False Terminate() Return EndIf bBardIsPlaying = True If TryLockStateUpdate() WaitRandom(1.0, 2.0) SetAudienceState(STATE_LISTEN) UnlockStateUpdate() EndIf EndEvent Event OnBardSongApplaud(string a_eventName, string a_strArg, float a_numArg, Form a_sender) If Is3DLoaded() == False Terminate() Return EndIf bBardIsPlaying = False If TryLockStateUpdate() If NoApplaud == False If CrossedArmsListenPackage != None && GetCurrentPackage() == CrossedArmsListenPackage SetAudienceState(STATE_LISTEN + 1) Debug.SendAnimationEvent(self, "IdleOffsetStop") ; This is the way to exit OffsetArmsCrossedStart idle Utility.Wait(1.0) Else WaitRandom(0.01, 0.25) EndIf SetAudienceState(STATE_APPLAUD) WaitRandom(7.0, 7.5) Else ; No applauding WaitRandom(5.0, 5.5) EndIf If Is3DLoaded() && bBardIsPlaying SetAudienceState(STATE_LISTEN) Else SetAudienceState(STATE_NONE) EndIf UnlockStateUpdate() EndIf EndEvent Event OnBardSongEnded(string a_eventName, string a_strArg, float a_numArg, Form a_sender) If Is3DLoaded() == False Terminate() Return EndIf bBardIsPlaying = False If TryLockStateUpdate() WaitRandom(1.0, 2.0) SetAudienceState(STATE_NONE) UnlockStateUpdate() EndIf EndEvent ;===================================================================================== ; FUNCTIONS ;===================================================================================== Function Terminate() GoToState("") bBardIsPlaying = False UnregisterForAllModEvents() RemoveFromFaction(BardAudienceStateFaction) EndFunction Function WaitRandom(Float fMinWaitSecs, Float fMaxWaitSecs) Utility.Wait(Utility.RandomFloat(fMinWaitSecs, fMaxWaitSecs)) EndFunction Function SetAudienceState(Int iNewState) If iNewState >= 0 If iNewState == STATE_LISTEN iNewState = Utility.RandomInt(1, 100) EndIf SetFactionRank(BardAudienceStateFaction, iNewState) EvaluatePackage() ; Look at If NoHeadtrackingBard == False ObjectReference lookTarget = BardDialogue.GetSingingBardActor() If lookTarget SetLookAt(lookTarget) Else ClearLookAt() EndIf EndIf Else RemoveFromFaction(BardAudienceStateFaction) EvaluatePackage() If NoHeadtrackingBard == False ClearLookAt() EndIf ; The NPC might not switch from their _00E_AnimTest_SC package if they are in combat, so they need an additional kick here _00E_AnimTest_SC myAnimTest = ((Self as Actor) as _00E_AnimTest_SC) If myAnimTest myAnimTest.CombatResetAnimations() EndIf EndIf EndFunction Bool bStateUpdateLocked = False Bool Function TryLockStateUpdate() If bStateUpdateLocked Return False EndIf bStateUpdateLocked = True Return True EndFunction Function UnlockStateUpdate() bStateUpdateLocked = False EndFunction