Scriptname _00E_WeatherControlScriptSC extends ReferenceAlias

Int iScriptVersion = 0
Int Property LATEST_SCRIPT_VERSION = 1 AutoReadOnly

Event OnInit()
	iScriptVersion = LATEST_SCRIPT_VERSION
	iCurrentWeather = WEATHER_NONE
EndEvent

Event OnPlayerLoadGame()
	If iScriptVersion < LATEST_SCRIPT_VERSION
		iScriptVersion = LATEST_SCRIPT_VERSION

		; Release weather overrides from the previous version
		If AreSpecialWeathersEnabled()
			If LocationIsSuntemple(GetPlayerLocation())
				If IsSuntempleSpecialWeatherActive()
					Weather.ReleaseOverride()
				EndIf
			ElseIf LocationIsArk(GetPlayerLocation())
				If IsArkSpecialWeatherActive()
					Weather.ReleaseOverride()
				EndIf
			EndIf
		EndIf

		iCurrentWeather = WEATHER_NONE

		UpdateWeathers(True)
	EndIf
EndEvent

Event OnLocationChange(Location akOldLoc, Location akNewLoc)

	If AreSpecialWeathersEnabled() == False
		Return
	EndIf

	Bool bSuntempleSpecialWeather = IsSuntempleSpecialWeatherActive()
	Bool bArkSpecialWeather = IsArkSpecialWeatherActive()

	If bSuntempleSpecialWeather == False && bArkSpecialWeather == False
		iCurrentWeather = WEATHER_NONE
		Return
	EndIf

	Int iNewWeather = WEATHER_NONE
	Bool bDoGameTimeUpdates = False
	Bool bGradualTransition = False

	If bSuntempleSpecialWeather && LocationIsSuntemple(akNewLoc)
		bDoGameTimeUpdates = True

		If ((iCurrentArkWeather == WEATHER_OVERCAST) || (iCurrentArkWeather == WEATHER_RAIN)) && LocationIsArk(akOldLoc)
			iCurrentSuntempleWeather = iCurrentArkWeather ; Keep the weather from Ark if it suits
		ElseIf (iCurrentSuntempleWeather != WEATHER_OVERCAST) && (iCurrentSuntempleWeather != WEATHER_RAIN)
			iCurrentSuntempleWeather = RollSuntempleWeather()
		EndIf
		iNewWeather = iCurrentSuntempleWeather

		If GetActorReference().GetWorldSpace() == CapitalCityCastleWorld
			bGradualTransition = True
		EndIf

	ElseIf bArkSpecialWeather && LocationIsArk(akNewLoc)
		bDoGameTimeUpdates = True

		If (iCurrentSuntempleWeather != WEATHER_REROLL) && LocationIsSuntemple(akOldLoc)
			iCurrentArkWeather = iCurrentSuntempleWeather ; Keep the weather from Suntemple if it suits
		ElseIf iCurrentArkWeather == WEATHER_REROLL
			iCurrentArkWeather = RollArkWeather()
		EndIf
		iNewWeather = iCurrentArkWeather

		WorldSpace curWorld = GetActorReference().GetWorldSpace()
		If curWorld == Vyn || curWorld == CapitalCityCastleWorld
			bGradualTransition = True
		EndIf

	ElseIf bArkSpecialWeather && akNewLoc == ArkSiegeWeatherEdge
		; If we're leaving Ark's outskirts, keep the current Ark weather for a bit longer.
		; This prevents frequent weather switches if we're wondering at the edge of the siege weather zone and regularly crossing that edge.
		If (akOldLoc == CapitalCityLocation || akOldLoc == ArkSiegeWeather) && (iCurrentArkWeather == WEATHER_OVERCAST || iCurrentArkWeather == WEATHER_RAIN)
			iNewWeather = iCurrentArkWeather
			bGradualTransition = True
		EndIf

	EndIf

	SetNewWeather(iNewWeather, bGradualTransition)

	If bDoGameTimeUpdates
		; If the timer is not running or we just entered Ark, (re)start the timer
		If (bGameTimeUpdatesActive == False) || (LocationIsArk(akOldLoc) == False && LocationIsSuntemple(akOldLoc) == False)
			bGameTimeUpdatesActive = True
			RegisterForSingleUpdateGameTime(WEATHER_UPDATE_PERIOD)
		EndIf
	EndIf

EndEvent

Event OnUpdateGametime()
	UpdateWeathers(False)
EndEvent

Function UpdateWeathers(Bool bForceUpdate)
	bGameTimeUpdatesActive = False

	If AreSpecialWeathersEnabled() == False
		Return
	EndIf

	If bForceUpdate || (RollChance() > 50) ; Time to reroll weather?
		If IsSuntempleSpecialWeatherActive() && LocationIsSuntemple(GetPlayerLocation())
			bGameTimeUpdatesActive = True
			iCurrentSuntempleWeather = RollSuntempleWeather()
			SetNewWeather(iCurrentSuntempleWeather, True)
		EndIf
		If IsArkSpecialWeatherActive() && LocationIsArk(GetPlayerLocation())
			bGameTimeUpdatesActive = True
			iCurrentArkWeather = RollArkWeather()
			SetNewWeather(iCurrentArkWeather, True)
		EndIf

		If bGameTimeUpdatesActive == False ; Not in Ark and not in Suntemple
			iCurrentSuntempleWeather = WEATHER_REROLL
			iCurrentArkWeather = WEATHER_REROLL
		EndIf
	Else
		bGameTimeUpdatesActive = True
	EndIf

	If bGameTimeUpdatesActive
		RegisterForSingleUpdateGameTime(WEATHER_UPDATE_PERIOD)
	EndIf
EndFunction

Bool Function AreSpecialWeathersEnabled()
	If MQ17.GetStage() >= 5
		Return False
	EndIf

	Int mq12bStage = MQ12b.GetStage()
	If mq12bStage >= 5 && mq12bStage < 135
		Return False
	EndIf

	Return True
EndFunction

Bool Function IsSuntempleSpecialWeatherActive()
	Return MQ09.IsCompleted()
EndFunction

Bool Function IsArkSpecialWeatherActive()
	Return MQ12b.IsCompleted()
EndFunction

Bool Function LocationIsSuntemple(Location lc)
	If lc
		Return _00E_SuntempleLocations.HasForm(lc)
	EndIf

	Return False
EndFunction

Bool Function LocationIsArk(Location lc)
	If lc
		If (lc == CapitalCityLocation) || (lc == ArkSiegeWeather) || lc.isChild(CapitalCityLocation)
			Return True
		EndIf
	EndIf

	Return False
EndFunction

Int Function RollChance()
	Return Utility.RandomInt(0, 100)
EndFunction

Int Function RollSuntempleWeather()
	If RollChance() >= 50
		Return WEATHER_OVERCAST
	Else
		Return WEATHER_RAIN
	EndIf
EndFunction

Int Function RollArkWeather()
	Int iChance = RollChance()
	If iCurrentArkWeather == WEATHER_RAIN
		If iChance >= 50
			Return WEATHER_OVERCAST
		Else
			Return WEATHER_RAIN
		EndIf
	Else
		If iChance > 80
			Return WEATHER_NONE
		ElseIf iChance < 40
			Return WEATHER_RAIN
		Else
			Return WEATHER_OVERCAST
		EndIf
	EndIf
EndFunction

Function SetNewWeather(Int iNewWeather, Bool bGradualTransition)
	If iNewWeather == iCurrentWeather
		Return
	EndIf

	iCurrentWeather = iNewWeather

	If iCurrentWeather == WEATHER_NONE
		If _00E_MQ11c_SilberhainDeadWeather.GetValueInt() == 0
			Weather.ReleaseOverride()
		EndIf
	ElseIf iCurrentWeather == WEATHER_OVERCAST
		If bGradualTransition
			_00E_EnderalOvercast.SetActive(True)
		Else
			_00E_EnderalOvercast.ForceActive(True)
		EndIf
	ElseIf iCurrentWeather == WEATHER_RAIN
		If bGradualTransition
			SkyrimOvercastRain.SetActive(True)
		Else
			SkyrimOvercastRain.ForceActive(True)
		EndIf
	Else
		Debug.Trace(self + ", SetNewWeather: unsupported iNewWeather " + iNewWeather)
	EndIf
EndFunction

Location Function GetPlayerLocation()
	Return GetActorReference().GetCurrentLocation()
EndFunction


;Properties and Variables

Float Property WEATHER_UPDATE_PERIOD = 3.0 AutoReadOnly ; In hours

Int Property WEATHER_REROLL   = 0 AutoReadOnly
Int Property WEATHER_OVERCAST = 1 AutoReadOnly
Int Property WEATHER_RAIN     = 2 AutoReadOnly
Int Property WEATHER_NONE     = 3 AutoReadOnly

Int iCurrentWeather = 0
Int iCurrentSuntempleWeather = 0
Int iCurrentArkWeather = 0
Bool bGameTimeUpdatesActive = False

Location Property CapitalCityLocation Auto
Location Property ArkSiegeWeather Auto
Location Property ArkSiegeWeatherEdge Auto
FormList Property _00E_SuntempleLocations Auto

Weather Property _00E_EnderalOvercast Auto
Weather Property SkyrimOvercastRain Auto

GlobalVariable Property _00E_MQ11c_SilberhainDeadWeather Auto

Quest Property MQ09 Auto
Quest Property MQ12b Auto
Quest Property MQ17 Auto

WorldSpace Property Vyn Auto
WorldSpace Property CapitalCityCastleWorld Auto