ScriptName footprintsConfigMenu Extends SKI_ConfigBase

Import Utility

Quest Property footprintsQuest Auto

footprintsPlayerScript Property footprintsPlayerRefAlias Auto

Keyword Property footprintsFootstepsEffect Auto

FormList Property footprintsSpellsFLST Auto
FormList Property footprintsCustomPlayerSpellsFLST Auto

; Gettable
GlobalVariable Property fp_FootprintsRefCount Auto
GlobalVariable Property fp_FootprintsFXCount Auto

; Settable
GlobalVariable Property fp_FootprintsNPCLimit Auto
GlobalVariable Property fp_FootprintsFXLimit Auto
GlobalVariable Property fp_IsFootprintsDisabled Auto
GlobalVariable Property fp_UseCustomFootprints Auto

Actor Property PlayerRef Auto


; History
;
; 1 - Initial Version

int Function GetVersion()
	return 1 ; Initial version
EndFunction

Spell Function GetSpellfromFLST( FormList flst )
	int iFLSTSize = flst.GetSize()
	While ( iFLSTSize )
		iFLSTSize -= 1
		Spell s = flst.GetAt( iFLSTSize ) as Spell
		If ( s && PlayerRef.HasSpell( s ) )
			return s
		EndIf
	EndWhile

	return None
EndFunction

Spell Function GetPlayerSpell()
	Spell s

	s = GetSpellFromFLST( footprintsCustomPlayerSpellsFLST )
	If ( s )
		return s
	EndIf

	s = GetSpellFromFlST( footprintsSpellsFLST )
	If ( s )
		return s
	EndIf

	return None
EndFunction

Function CloseMenu()
	Int kMenu = Input.GetMappedKey( "Tween Menu" )
	While ( IsInMenuMode() )
		Input.TapKey( kMenu )
		WaitMenuMode( 0.25 )
	EndWhile
EndFunction

;int INI_UND = -1
int INI_LOW = 0
int INI_MED = 1
int INI_HIGH = 2
int INI_ULTRA = 3

int Function INICheck()
	{ Sampling of INI preset values
		iMaxDecalsPerFrame == 0    		Low
		fLightLODStartFade < 1000 		Low
		fGrassStartFadeDistance < 3000	Low

		iMaxDecalsPerFrame < 30	   		Med
		fLightLODStartFade < 2500 		Med
		fGrassStartFadeDistance < 5000	Med

		iMaxDecalsPerFrame < 100   		High
		fLightLODStartFade < 3500 		High
		fGrassStartFadeDistance < 7000	High
	}

	int iMDPF = GetINIInt( "iMaxDecalsPerFrame:Display" )
	;float fLLODSF = GetINIFloat( "fLightLODStartFade:Display" )
	;float fGSFD = GetINIFloat( "fGrassStartFadeDistance:Display" )

	If ( iMDPF == 0 ;/&& fLLODSF < 1000 && fGSFD < 3000/; )
		return INI_LOW
	ElseIf ( iMDPF < 30 ;/&& fLLODSF < 2500 && fGSFD < 5000/; )
		return INI_MED
	ElseIf ( iMDPF < 100 ;/&& fLLODSF < 3500 && fGSFD < 7000/; )
		return INI_HIGH
	Else
		return INI_ULTRA
	EndIf

EndFunction

; Flags

int _useCustomFlags = 0x00
int _npcLimitFlags = 0x00
int _fxLimitFlags = 0x00
int HELP = 0x01

; Third-Party description text
int _page
String[] _modDesc
String[] _modAuthor
int _modOptIndex

; @overrides SKI_ConfigBase
Event OnConfigInit()
	Pages = new String[1]
	Pages[0] = "Settings"

	_modDesc = new String[32]
	_modAuthor = new String[32]
EndEvent

; @implements SKI_QuestBase
event OnGameReload()
	parent.OnGameReload()
endEvent

; @implements SKI_ConfigBase
Event OnPageReset( String a_page )
	{Called when a new page is selected, including the initial empty page}

	If ( a_page == "" )
		_page = 0
		SetCursorFillMode( TOP_TO_BOTTOM )

		bool canRemove = (fp_IsFootprintsDisabled.GetValue() && PlayerRef.IsInInterior())
		;canRemove = canRemove && footprintsQuest.IsStopped()
		canRemove = canRemove && !(fp_FootprintsRefCount.GetValue() as Bool)

		AddTextOption( "Footprints Enabled", !fp_IsFootprintsDisabled.GetValue() ) ; 0

		If ( fp_IsFootprintsDisabled.GetValue() )
			AddTextOptionST( "STATUS_SAFE_TO_REMOVE", "Footprints Safe to Remove", canRemove ) ; 2
		Else
			AddEmptyOption() ; 2
		EndIf

		AddHeaderOption( "NPC Status" ) ; 4

		String npcCount = (fp_FootprintsRefCount.GetValue() as Int) + "/" + (fp_FootprintsNPCLimit.GetValue() as Int)
		String fxCount = (fp_FootprintsFXCount.GetValue() as Int) + "/" + (fp_FootprintsFXLimit.GetValue() as Int)

		AddTextOptionST( "STATUS_TOTAL_NPCS", "Total NPCs with Footprints", npcCount ) ; 6
		AddTextOptionST( "STATUS_TOTAL_FX", "Footprints with Particle FX",  fxCount ) ; 8

		AddHeaderOption( "Player Status" ) ; 10

		Spell s = GetPlayerSpell()
		String sName = "None"
		String mgName = "None"
		If ( s )
			sName = (s as Form).GetName()

			MagicEffect mg = s.GetNthEffectMagicEffect( 0 )
			If ( mg )
				mgName = (mg as Form).GetName()
			EndIf
		EndIf

		AddTextOption( "Player Race", (PlayerRef.GetRace() as Form).GetName() ) ; 12
		AddTextOption( "Player Spell", sName ) ; 14
		AddTextOption( "Player Effect", mgName ) ; 16
		AddTextOptionST( "STATUS_REAPPLY_PLAYER_EFFECT", "Reapply Player Effect", "" ) ; 18

		AddHeaderOption( "INI Status" ) ; 20

		Bool bDecals = GetINIBool( "bDecals:Decals" )

		int iniPreset = INICheck()

		String iniDesc
		If ( iniPreset == INI_LOW || !bDecals )
			iniDesc = "WARNING: Decals appear to be turned off."
		ElseIf ( iniPreset == INI_ULTRA )
			iniDesc = "Using 'Ultra' decal settings."
		ElseIf ( iniPreset == INI_HIGH )
			iniDesc = "Using 'High' decal settings."
		ElseIf ( iniPreset == INI_MED )
			iniDesc = "Using 'Medium' decal settings."
		EndIf

		AddTextOption( iniDesc, "" ) ; 22

		SetCursorPosition( 5 )
		AddHeaderOption( "Third Party Plugins" ) ; 5

		Int tModCount = Game.GetModCount()
		Int fpIndex = Game.GetModByName( "Footprints.esp" )
		Int fpModCount = 0

		_modOptIndex = 7

		Int mIndex = fpIndex + 1
		While ( mIndex < tModCount )
			String modNameStr = Game.GetModName( mIndex )

			Int modDeps = Game.GetModDependencyCount( mIndex )
			If ( modDeps > 0 )
				Int iDep = 0
				While ( iDep < modDeps )
					If ( fpIndex == Game.GetNthModDependency( mIndex, iDep ) )
						AddTextOption( modNameStr, "" )
						_modDesc[fpModCount] = Game.GetModDescription( mIndex )
						_modAuthor[fpModCount] = Game.GetModAuthor( mIndex )
						iDep = modDeps ; break
						fpModCount += 1
					EndIf
					iDep += 1
				EndWhile
			EndIf

			mIndex += 1
		EndWhile

		If ( fpModCount > 0 && !fp_UseCustomFootprints.GetValue() )
			AddEmptyOption() ; 7 + fpModCount * 2
			AddTextOption( "WARNING: Third party hook disabled.", "", HELP ) ; 9 + fpModCount * 2
		EndIf

	ElseIf ( a_page == "Settings" )
		_page = 1
		SetCursorFillMode( TOP_TO_BOTTOM )

		Bool fpEnabled = !(fp_IsFootprintsDisabled.GetValue() as Bool)
		Bool fpUseCustom = fp_UseCustomFootprints.GetValue() as Bool

		AddToggleOptionST( "SETTING_ENABLE_FOOTPRINTS", "Enable Footprints", fpEnabled ) ; 0
		AddToggleOptionST( "SETTING_USE_CUSTOM_PRINTS", "Use Custom Footprints", fpUseCustom, _useCustomFlags ) ; 2

		AddHeaderOption( "NPC Settings" ) ; 4

		Int fpNPCLimit = fp_FootprintsNPCLimit.GetValue() as Int
		Int fpFXLimit = fp_FootprintsFXLimit.GetValue() as Int

		AddSliderOptionST( "SETTING_NPC_LIMIT", "NPC Limit", fpNPCLimit, "{0}", _npcLimitFlags ) ; 6

		SetCursorPosition( 7 )
		If ( fp_FootprintsNPCLimit.GetValue() < 25 )
			AddTextOption( "WARNING: You may notice some NPCs missing", "", HELP ) ; 7
			AddTextOption( "prints at low values.", "", HELP ) ; 9
		Else
			AddTextOptionST( "SETTING_NPC_LIMIT_DESC", "Recommended Minimum for uGridsToLoad 5: 25**", "" ) ; 7
		EndIf

		SetCursorPosition( 8 )
		AddSliderOptionST( "SETTING_FX_LIMIT", "FX Limit", fpFXLimit, "{0}", _fxLimitFlags ) ; 8

		AddHeaderOption( "INI Settings" ) ; 10
		Bool bDecals = GetINIBool( "bDecals:Decals" )

		Float fDecalLifetime = GetINIFloat( "fDecalLifetime:Display" )
		Int iMaxDecalsPerFrame = GetINIInt( "iMaxDecalsPerFrame:Display" )

		AddTextOption( "[Decals]", "", HELP ) ; 12
		AddToggleOptionST( "SETTING_INI_DECALS", "bDecals", bDecals ) ; 14
		; SKSE does not support Get/Set for "u" INI settings yet
		AddTextOptionST( "SETTING_INI_MAX_DECALS", "uMaxDecals", "" ) ; 16

		AddTextOption( "[Display]", "", HELP ) ; 18
		AddSliderOptionST( "SETTING_INI_DECAL_LIFETIME", "fDecalLifetime", fDecalLifetime ) ; 20
		AddSliderOptionST( "SETTING_INI_DECAL_MAXPERFRAME", "iMaxDecalsPerFrame", iMaxDecalsPerFrame ) ; 22

		If ( !bDecals )
			SetCursorPosition( 15 )
			AddTextOption( "WARNING: Decals are turned off!", "", HELP )
		EndIf

		SetCursorPosition( 17 )
		AddTextOption( "SKSE does not support Get/Set for this setting.", "", HELP )

		If ( iMaxDecalsPerFrame == 0 )
			SetCursorPosition( 23 )
			AddTextOption( "WARNING: Decals are turned off!", "", HELP )
		EndIf

	EndIf
EndEvent

State SETTING_NPC_LIMIT
	Event OnSliderOpenST()
		SetSliderDialogStartValue( fp_FootprintsNPCLimit.GetValue() )
		SetSliderDialogDefaultValue( 50 )
		SetSliderDialogRange( 0, 100 )
		SetSliderDialogInterval( 1 )
	EndEvent

	Event OnSliderAcceptST( float a_value )

		SetSliderOptionValueST( a_value )
		fp_FootprintsNPCLimit.SetValue( a_value as Int )

		If ( a_value == 0 )
			_fxLimitFlags = OPTION_FLAG_DISABLED
		Else
			_fxLimitFlags = OPTION_FLAG_NONE
		EndIf

		SetOptionFlagsST( _fxLimitFlags, False, "SETTING_FX_LIMIT" )

		If ( a_value < fp_FootprintsFXLimit.GetValue() )
			SetSliderOptionValueST( a_value, "{0}", False, "SETTING_FX_LIMIT" )
			fp_FootprintsFXLimit.SetValue( a_value as Int )
		EndIf

		ForcePageReset()
	EndEvent

	Event OnDefaultST()
		SetSliderOptionValueST( 50 )
		fp_FootprintsNPCLimit.SetValue( 50 )
	EndEvent

	Event OnHighlightST()
		SetInfoText( "The total number of NPCs in an area which can have the Footprints effect.\n\nA few NPC races are exempt from this limit such as horses. This is so that the player horse is guaranteed to have footprints." )
	EndEvent
EndState

State SETTING_NPC_LIMIT_DESC
	Event OnHighlightST()
		SetInfoText( "** As you run around the 5x5 loaded area you will accumulate NPCs with the effect until they unload again. This means that on default uGrids you can see as many as 25 active Footprints effects at once." )
	EndEvent
EndState

State SETTING_FX_LIMIT
	Event OnSliderOpenST()
		SetSliderDialogStartValue( fp_FootprintsFXLimit.GetValue() )
		SetSliderDialogDefaultValue( 20 )
		SetSliderDialogRange( 0, fp_FootprintsNPCLimit.GetValue() )
		SetSliderDialogInterval( 1 )
	EndEvent

	Event OnSliderAcceptST( float a_value )
		SetSliderOptionValueST( a_value )
		fp_FootprintsFXLimit.SetValue( a_value as Int )
	EndEvent

	Event OnDefaultST()
		SetSliderOptionValueST( 20 )
		fp_FootprintsFXLimit.SetValue( 20 )
	EndEvent

	Event OnHighlightST()
		SetInfoText( "The total number of NPCs which are allowed to have Particle FX.\nIf NPC Limit = 50 and FX Limit = 20, then only 20/50 NPCs can have active particle FX. The NPC must have FX on their Impact Effect to count toward the limit.\n\nThe player will always have particle FX, as will a few select races which are exempt from the limits such as horses." )
	EndEvent
EndState

State SETTING_INI_DECALS
	Event OnSelectST()
		Bool decals = GetINIBool( "bDecals:Decals" )

		SetToggleOptionValueST( !decals )
		SetINIBool( "bDecals:Decals", !decals )

		ForcePageReset()
	EndEvent

	Event OnDefaultST()
		SetToggleOptionValueST( True )
		SetINIBool( "bDecals:Decals", True )
		ForcePageReset()
	EndEvent

	Event OnHighlightST()
		SetInfoText("")
	EndEvent
EndState

State SETTING_INI_MAX_DECALS
	Event OnHighlightST()
		SetInfoText( "You must set this manually in SkyrimPrefs.ini. Ultra=1000, High=250, Medium=100, Low=0 (Off)" )
	EndEvent
EndState

State SETTING_INI_DECAL_LIFETIME
	Event OnSliderOpenST()
		SetSliderDialogStartValue( GetINIFloat( "fDecalLifetime:Display" ) )
		SetSliderDialogDefaultValue( 30 )
		SetSliderDialogRange( 0, 90 )
		SetSliderDialogInterval( 1 )
	EndEvent

	Event OnSliderAcceptST( float a_value )
		SetSliderOptionValueST( a_value )
		SetINIFloat( "fDecalLifetime:Display", a_value )
	EndEvent

	Event OnDefaultST()
		SetSliderOptionValueST( 30 )
		SetINIFloat( "fDecalLifetime:Display", 30 )
	EndEvent

	Event OnHighlightST()
		SetInfoText( "The number of seconds it takes a decal to fade away after reaching the max decal limit (uMaxDecals)." )
	EndEvent
EndState

State SETTING_INI_DECAL_MAXPERFRAME
	Event OnSliderOpenST()
		SetSliderDialogStartValue( GetINIInt( "iMaxDecalsPerFrame:Display" ) as Float )
		SetSliderDialogDefaultValue( 50 )
		SetSliderDialogRange( 0, 100 )
		SetSliderDialogInterval( 1 )
	EndEvent

	Event OnSliderAcceptST( float a_value )
		SetSliderOptionValueST( a_value )
		SetINIInt( "iMaxDecalsPerFrame:Display", a_value as Int )
		ForcePageReset()
	EndEvent

	Event OnDefaultST()
		SetSliderOptionValueST( 50 )
		SetINIInt( "iMaxDecalsPerFrame:Display", 50 )
		ForcePageReset()
	EndEvent

	Event OnHighlightST()
		SetInfoText( "The max number of decals that can be shown per frame." )
	EndEvent
EndState

Function ToggleFootprintsFlags()
	If ( fp_IsFootprintsDisabled.GetValue() )
		_useCustomFlags = OPTION_FLAG_DISABLED
		_npcLimitFlags = OPTION_FLAG_DISABLED
		_fxLimitFlags = OPTION_FLAG_DISABLED
	Else
		_useCustomFlags = OPTION_FLAG_NONE
		_npcLimitFlags = OPTION_FLAG_NONE
		_fxLimitFlags = OPTION_FLAG_NONE
	EndIf

	SetOptionFlagsST( _useCustomFlags, False, "SETTING_USE_CUSTOM_PRINTS" )
	SetOptionFlagsST( _npcLimitFlags, False, "SETTING_NPC_LIMIT" )
	SetOptionFlagsST( _fxLimitFlags, False, "SETTING_FX_LIMIT" )
EndFunction

State SETTING_ENABLE_FOOTPRINTS
	Event OnSelectST()
		Bool fpEnabled = !(fp_IsFootprintsDisabled.GetValue() as Bool)

		SetToggleOptionValueST( !fpEnabled )
		fp_IsFootprintsDisabled.SetValue( fpEnabled as Int )
		ToggleFootprintsFlags()
	EndEvent

	Event OnDefaultST()
		SetToggleOptionValueST( True )
		fp_IsFootprintsDisabled.SetValue( 0 )
		ToggleFootprintsFlags()
	EndEvent

	Event OnHighlightST()
		SetInfoText("")
	EndEvent
EndState

State SETTING_USE_CUSTOM_PRINTS
	Event OnSelectST()
		Bool fpUseCustom = fp_UseCustomFootprints.GetValue()

		SetToggleOptionValueST( !fpUseCustom )
		fp_UseCustomFootprints.SetValue( (!fpUseCustom) as Int )
	EndEvent

	Event OnDefaultST()
		SetToggleOptionValueST( False )
		fp_UseCustomFootprints.SetValue( 0 )
	EndEvent

	Event OnHighlightST()
		SetInfoText( "Enable hook to load third party Footprint effects." )
	EndEvent
EndState

State STATUS_REAPPLY_PLAYER_EFFECT
	Event OnSelectST()
		CloseMenu()
		footprintsPlayerRefAlias.ResetPlayer()
	EndEvent

	Event OnHighlightST()
		SetInfoText( "" )
	EndEvent
EndState

State STATUS_SAFE_TO_REMOVE
	Event OnHighlightST()
		SetInfoText( "You must disable the footprints and then wait inside." )
	EndEvent
EndState

State STATUS_TOTAL_NPCS
	Event OnHighlightST()
		SetInfoText( "The total number of NPCs in the area with a Footprint effect." )
	EndEvent
EndState

State STATUS_TOTAL_FX
	Event OnHighlightST()
		SetInfoText( "The number of Footprints (out of the total) in the area using Particle FX." )
	EndEvent
EndState

Event OnOptionHighlight( int a_option )
	{Used to display the third party plugin description and author as info text}
	Int modIndex = (a_option - _modOptIndex) / 2

	If ( (_page == 0) && (a_option % 2 > 0) && (modIndex >= 0) )
		String desc = _modDesc[modIndex]
		String auth = _modAuthor[modIndex]
		If ( desc != "" )
			SetInfoText( desc + "\nby " + auth )
		EndIf
	EndIf
EndEvent
