enderalse/scripts/source/_00e_bardplayinstrumentscript.psc

135 lines
3.4 KiB
Plaintext

Scriptname _00E_BardPlayInstrumentScript extends Actor
Sound Property MusicPiece Auto
Package Property PlayPackage Auto
{ The package must have <subject> HasLoaded3D == 1 condition and optionally <subject> GetDisabled == 0 condition (if the reference can be disabled) }
Keyword Property LinkedPlayMarkerKeyword Auto
Spell Property BardPlayTrackerSP Auto
Bool Property DontRestartTrack Auto
Int Property PLAYSTATE_STOPPED = 0 AutoReadOnly
Int Property PLAYSTATE_PLAYING = 1 AutoReadOnly
Int Property PLAYSTATE_STOPPING_FADE = 2 AutoReadOnly
Int PlayState
Int MusicInstance
Float MusicVolume
Int WarmupCounter
Float LastWarmupDistance
Event OnPackageStart(Package akNewPackage)
; Debug.Trace("_00E_BardPlayInstrumentScript, OnPackageStart, " + akNewPackage)
If akNewPackage == PlayPackage
AddSpell(BardPlayTrackerSP, False)
Else
RemoveSpell(BardPlayTrackerSP)
StopMusic()
EndIf
EndEvent
Event OnBardsLoadGame(string eventName, string strArg, float numArg, Form sender)
; Debug.Trace("_00E_BardPlayInstrumentScript, OnBardsLoadGame...")
If PlayState == PLAYSTATE_PLAYING
StopMusicInstance()
RegisterForSingleUpdate(0.25)
Else ; PlayState == PLAYSTATE_STOPPING_FADE
StopMusic()
EndIf
EndEvent
Int Function TickWarmupCounter()
ObjectReference PlayMarker = GetLinkedRef(LinkedPlayMarkerKeyword)
If PlayMarker
Float d = GetDistance(PlayMarker)
; Is the NPC close to the play marker and kept the same distance from it since the previous tick (doesn't move)?
If d < 128.0 && (WarmupCounter == 0 || Math.abs(d - LastWarmupDistance) < 1.0)
LastWarmupDistance = d
Return WarmupCounter + 1
EndIf
EndIf
Return 0
EndFunction
Event OnUpdate()
If PlayState == PLAYSTATE_STOPPED
Return
EndIf
If MusicInstance != 0 ; Fading
MusicVolume -= 0.025
If MusicVolume >= 0.1
Sound.SetInstanceVolume(MusicInstance, MusicVolume)
RegisterForSingleUpdate(0.2)
ElseIf PlayState == PLAYSTATE_PLAYING
StopMusicInstance()
RegisterForSingleUpdate(0.1)
Else ; PlayState == PLAYSTATE_STOPPING_FADE
StopMusic()
EndIf
Else
If PlayState == PLAYSTATE_PLAYING
; Wait for the NPC to get close to its linked play marker and stay stationary (more or less) for some time
WarmupCounter = TickWarmupCounter()
If WarmupCounter > 4
MusicInstance = MusicPiece.Play(self)
MusicVolume = 1.0
If DontRestartTrack == False
RegisterForSingleUpdate(2 * 60 + 40) ; 2:40 - roughly the length of the longest "classical" track in Sound\FX\Enderal\Bards
EndIf
Else
RegisterForSingleUpdate(0.25)
EndIf
Else ; PlayState == PLAYSTATE_STOPPING_FADE
StopMusic()
EndIf
EndIf
EndEvent
Function StopMusicInstance()
If MusicInstance != 0
Int _tempInst = MusicInstance
MusicInstance = 0
Sound.StopInstance(_tempInst)
EndIf
EndFunction
Function StartMusic()
If PlayState != PLAYSTATE_PLAYING
PlayState = PLAYSTATE_PLAYING
RegisterForModEvent("BardsLoadGame", "OnBardsLoadGame")
StopMusicInstance()
RegisterForSingleUpdate(0.01)
EndIf
EndFunction
Function StopMusic()
If PlayState != PLAYSTATE_STOPPED
PlayState = PLAYSTATE_STOPPED
UnregisterForUpdate()
StopMusicInstance()
UnregisterForModEvent("BardsLoadGame")
EndIf
WarmupCounter = 0
EndFunction
Function FadeAndStopMusic()
If PlayState != PLAYSTATE_STOPPED
If MusicInstance != 0
PlayState = PLAYSTATE_STOPPING_FADE
RegisterForSingleUpdate(0.1)
While PlayState == PLAYSTATE_STOPPING_FADE
Utility.Wait(0.5)
EndWhile
Else
StopMusic()
EndIf
EndIf
EndFunction