Scriptname _00E_PlayerFunctions extends actor  

;=====================================================================================
; Equip/unequip torches
;=====================================================================================

Int Function GetHandSlotEx(int iHand)
	; By default, iHand = 0 for left hand, 1 for right hand
	; In SKSE's "Equip Ex" functions though: iHand = 2 for left hand, 1 for right hand
	Return 2 - iHand
EndFunction

Bool Function UnequipTorches(Form[] equippedTorches)
	Bool unequipping = False
	Int iHand = 0
	While iHand < equippedTorches.Length
		If GetEquippedItemType(iHand) == 11 ; A torch is in the hand?
			Form torch = GetEquippedObject(iHand)
			If torch
				UnequipItemEx(torch, GetHandSlotEx(iHand))
				equippedTorches[iHand] = torch
				unequipping = True
			EndIf
		EndIf

		iHand += 1
	EndWhile

	Return unequipping
EndFunction

Function ReequipTorches(Form[] equippedTorches)
	Int iHand = 0
	While iHand < equippedTorches.Length
		Form torch = equippedTorches[iHand]
		If torch
			If GetItemCount(torch) > 0
				EquipItemEx(torch, GetHandSlotEx(iHand), False, True)
			EndIf
			; "Forget" about the form to not keep it persistent if equippedTorches is a script's property or variable
			equippedTorches[iHand] = None 
		EndIf
		iHand += 1
	EndWhile
EndFunction


;=====================================================================================
; Combat music control
;=====================================================================================

MusicType[] ActiveCombatMusics
MusicType[] StoppingCombatMusics
Int StoppingCombatMusicCounter = 0

Int Property COMBAT_MUSIC_LOCK_NONE     = 0 AutoReadOnly
Int Property COMBAT_MUSIC_LOCK_START    = 1 AutoReadOnly
Int Property COMBAT_MUSIC_LOCK_STOP     = 2 AutoReadOnly
Int Property COMBAT_MUSIC_LOCK_FAILSAFE = 3 AutoReadOnly

Int CombatMusicLockLevel = 0 ; = COMBAT_MUSIC_LOCK_NONE

Function InitCombatMusic()
	If ActiveCombatMusics.Length == 0
		ActiveCombatMusics = _NewMusicArray()
	EndIf

	If StoppingCombatMusics.Length == 0
		StoppingCombatMusics = _NewMusicArray()
	EndIf

	If StoppingCombatMusicCounter > 0 || ActiveCombatMusics[0]
		GoToState("CombatMusicTracking")
	EndIf
EndFunction

Bool Function StartCombatMusic(MusicType newMusic)
	; Debug.Trace(self + ", StartCombatMusic, newMusic = " + newMusic)

	Bool result = False

	While CombatMusicLockLevel > COMBAT_MUSIC_LOCK_NONE
		Utility.Wait(0.03) ; wait for two frames
	EndWhile
	CombatMusicLockLevel = COMBAT_MUSIC_LOCK_START

	Int Index = _AddUniqueMusicToArray(ActiveCombatMusics, newMusic)
	If Index >= 0
		ActiveCombatMusics[Index].Add()
		result = (Index == 0) ; Is this the first combat music in this fight?
	EndIf

	StoppingCombatMusicCounter = 0

	GoToState("CombatMusicTracking")

	CombatMusicLockLevel = COMBAT_MUSIC_LOCK_NONE

	Return result
EndFunction

Function StopCombatMusic()
	; Debug.Trace(self + ", StopCombatMusic")

	While CombatMusicLockLevel > COMBAT_MUSIC_LOCK_NONE
		If CombatMusicLockLevel == COMBAT_MUSIC_LOCK_START || CombatMusicLockLevel == COMBAT_MUSIC_LOCK_STOP
			Return
		EndIf
		Utility.Wait(0.03)
	EndWhile
	CombatMusicLockLevel = COMBAT_MUSIC_LOCK_STOP

	Int Index = 0
	While Index < ActiveCombatMusics.Length && ActiveCombatMusics[Index]
		ActiveCombatMusics[Index].Remove()
		_AddUniqueMusicToArray(StoppingCombatMusics, ActiveCombatMusics[Index])
		Index += 1
	EndWhile

	ActiveCombatMusics = _NewMusicArray()

	StoppingCombatMusicCounter = 8

	GoToState("CombatMusicTracking")

	CombatMusicLockLevel = COMBAT_MUSIC_LOCK_NONE
EndFunction


State CombatMusicTracking

	Event OnUpdate()

		; _00E_EPUpdateFunctions that is also attached to the player, does the job of registering for updates.
		; That's why there is no RegisterForUpdate anywhere in this script.

		; Debug.Trace("_00E_PlayerFunctions, OnUpdate")

		If IsInCombat() || CombatMusicLockLevel > COMBAT_MUSIC_LOCK_NONE
			Return
		EndIf

		If StoppingCombatMusicCounter > 0

			CombatMusicLockLevel = COMBAT_MUSIC_LOCK_FAILSAFE

			; Debug.Trace(self + ", OnUpdate: failsaving")

			Int Index = 0
			While Index < StoppingCombatMusics.Length && StoppingCombatMusics[Index]
				StoppingCombatMusics[Index].Add()
				StoppingCombatMusics[Index].Remove()
				Index += 1
			EndWhile

			StoppingCombatMusicCounter -= 1
			If StoppingCombatMusicCounter <= 0
				StoppingCombatMusics = _NewMusicArray()
			EndIf 

			CombatMusicLockLevel = COMBAT_MUSIC_LOCK_NONE

		ElseIf ActiveCombatMusics[0] ; Failsafe in case StopCombatMusic is not called for whatever reason

			StopCombatMusic()

		Else

			GoToState("")

		EndIf

	EndEvent

EndState

MusicType[] Function _NewMusicArray()
	Return New MusicType[10]
EndFunction

Int Function _AddUniqueMusicToArray(MusicType[] musics, MusicType newMusic)
	Int n = musics.Length
	Int Index = 0

	; Loop through array until we reach the end or newMusic or an empty entry
	While Index < n && musics[Index] != newMusic && musics[Index] != None
		Index += 1
	EndWhile

	If Index < n && musics[Index] == None
		musics[Index] = newMusic
		Return Index
	Else
		Return -1
	EndIf
EndFunction