Scriptname zzCharacterMakingExtenderScript extends Quest
{Scaleform callback functon and holder of faceData}

Message Property zzExCharGenSaveMessage1 Auto
Message Property zzExCharGenSaveMessage2 Auto
Message Property zzExCharGenSaveMessage3 Auto
Message Property zzExCharGenSaveMessage4 Auto
Message Property zzExCharGenSaveMessage5 Auto

Message Property zzExCharGenLoadMessage0 Auto
Message Property zzExCharGenLoadMessage1 Auto
Message Property zzExCharGenLoadMessage2 Auto
Message Property zzExCharGenLoadMessage3 Auto
Message Property zzExCharGenLoadMessage4 Auto
Message Property zzExCharGenLoadMessage5 Auto

Message Property zzExCharGenRevertMessage Auto

Message Property zzExCharGenErrMsg1 Auto
Message Property zzExCharGenErrMsg2 Auto
Message Property zzExCharGenErrMsg3 Auto
Message Property zzExCharGenErrMsg4 Auto
Message Property zzExCharGenErrMsg5 Auto

Message Property zzExCharGenErrMsg10 Auto
Message Property zzExCharGenErrMsg11 Auto

Message Property zzExCharGenVertexConfirmMsg Auto

FormList Property zzExCharGenRaceList Auto
FormList Property zzExCharGenVampireList Auto

PlayerVampireQuestScript Property VampireQuest Auto
CompanionsHousekeepingScript Property CompanionsQuest Auto

string faceDataHolder = ""
string[] faceDataArray
bool locked = False
ColorForm hairColorForm = None
int hairSliderCount = 0
int pcScaleSliderCount = 0
int expressionSliderCount = 0

int lastExpressionAiMood = -1
int lastExpressionValue = 0

Light Property zzExCharGenLight  Auto
Light Property zzExCharGenLight2  Auto
ObjectReference lightObject = None
ObjectReference lightObject2 = None

Actor _player
ActorBase _playerBase

string validVersion

event OnInit()
	OnGameReload()
EndEvent

Function OnGameReload()
	;validVersion = "1.8.151.0"
	;validVersion = "1.9.29.0"
	validVersion = "1.9.32.0"

	if (GetState() != "Ready")
		GotoState("Ready")
	endif
	
	while (GetState() != "Ready")
		Utility.Wait(0.1)
		GotoState("Ready")
	endwhile
	GotoState("")
	;Debug.MessageBox("ExCharGen: init call")

	if (lightObject)
		lightObject.Delete()
		lightObject = None
	EndIf
	if (lightObject2)
		lightObject2.Delete()
		lightObject2 = None
	EndIf

	if (faceDataArray.length <= 0)
		faceDataArray = new String[10]
	endif

	if (Game.GetGameSettingInt("iNoseMorphCount") != 35 || Game.GetGameSettingInt("iEyeMorphCount") != 40 || Game.GetGameSettingInt("iLipMorphCount") != 33 )
		zzExCharGenErrMsg10.Show()
		;Debug.MessageBox("CharacterMakingExtender\n\n*ERROR*\nIlligal 'GameSetting' value. conflict other Mod?")
		Return
	EndIf

	if (Debug.GetVersionNumber() != validVersion)
		zzExCharGenErrMsg11.Show(); ** CME : unsupported TESV.exe version. turn off **
		Debug.Notification("TESV:" + Debug.GetVersionNumber() + " / Supported:" + validVersion)
		Debug.Trace("ERROR : CharacterMakingExtender unsupported TESV.exe version. turn off.", 2)
		Debug.Trace("ERROR : TESV:" + Debug.GetVersionNumber() + " / CME Supported:" + validVersion, 2)
		Return
	EndIf
		
	RegisterForModEvent("ExCharGen_GetSliderPos", "OnExCharGen_GetSliderPos")
	RegisterForModEvent("ExCharGen_SetSliderPos", "OnExCharGen_SetSliderPos")
	RegisterForModEvent("ExCharGen_InputSaveSlot", "OnExCharGen_InputSaveSlot")
	RegisterForModEvent("ExCharGen_InputLoadSlot", "OnExCharGen_InputLoadSlot")
	RegisterForModEvent("ExCharGen_MessageBox", "OnExCharGen_MessageBox")
	RegisterForModEvent("ExCharGen_SetHairColor", "OnExCharGen_SetHairColor")
	RegisterForModEvent("ExCharGen_ResetHairCount", "OnExCharGen_ResetHairCount")
	RegisterForModEvent("ExCharGen_SetPlayerScale", "OnExCharGen_SetPlayerScale")
	RegisterForModEvent("ExCharGen_ChangeRace", "OnExCharGen_ChangeRace")
	RegisterForModEvent("ExCharGen_SetLight", "OnExCharGen_SetLight")
	RegisterForModEvent("ExCharGen_ChangeExpression", "OnExCharGen_ChangeExpression")
	RegisterForModEvent("ExCharGen_PreExitMenu", "OnExCharGen_PreExitMenu")
	RegisterForModEvent("ExCharGen_VertexConfirm", "OnExCharGen_VertexConfirm")
	RegisterForModEvent("ExCharGen_StopMotion", "OnExCharGen_StopMotion")
	RegisterForModEvent("ExCharGen_ExportMesh", "OnExCharGen_ExportMesh")


	Utility.SetINIFloat("fPlayerBodyEditDistance:Interface", 350.0)
	if (!hairColorForm)
		hairColorForm = Game.GetFormFromFile(0x8ea9, "CharacterMakingExtender.esp") as ColorForm
	EndIf

	_player = Game.GetPlayer()
	_playerBase = _player.GetActorBase()
	
	UpdateModel()
EndFunction

function UpdateModel()
	if (Game.GetGameSettingInt("iNoseMorphCount") != 35 || Game.GetGameSettingInt("iEyeMorphCount") != 40 || Game.GetGameSettingInt("iLipMorphCount") != 33 )
		Return
	EndIf
	if (Debug.GetVersionNumber() != validVersion)
		Return
	EndIf

	if (locked)
		Return
	EndIf
	locked = True

	; split faceMorph slider data and join.
	; length of string-variable can be more than 100kB when game is running,
	; but failed to load more than about 4kB.
	String faceDataStr = faceDataHolder + faceDataArray[0] + faceDataArray[1] + faceDataArray[2] + faceDataArray[3] + faceDataArray[4]
	faceDataStr += faceDataArray[5] + faceDataArray[6] + faceDataArray[7] + faceDataArray[8] + faceDataArray[9]

	if (StringUtil.GetLength(faceDataStr) > 0)
		int len = StringUtil.GetLength(faceDataStr)
		int pos = len - 32
		int index
		int lastID = 0
		while (pos < len && pos > 0)
			index = StringUtil.Find(faceDataStr, ",", pos)
			if (index >= 0)
				lastID = StringUtil.Substring(faceDataStr, pos, index-pos) as Int
				pos = index + 1
			Else
				pos = len
			EndIf
		EndWhile
		if (_player.IsOnMount())
			_player.Dismount()
			int i = 0
			while(_player.IsOnMount() && i < 120)
				i = i + 1
				Utility.Wait(0.01)
			EndWhile

			if (_playerBase.GetFacePreset(0) != 33 && lastID != 99998)
				int selectedButton = zzExCharGenRevertMessage.show()
				if (selectedButton == 0)
					_playerBase.SetFacePreset(33, 0)
					Game.ShowLimitedRaceMenu()
				elseif (selectedButton == 1)
					faceDataStr = ""
					faceDataHolder = ""
					faceDataArray[0] = ""
					faceDataArray[1] = ""
					faceDataArray[2] = ""
					faceDataArray[3] = ""
					faceDataArray[4] = ""
					faceDataArray[5] = ""
					faceDataArray[6] = ""
					faceDataArray[7] = ""
					faceDataArray[8] = ""
					faceDataArray[9] = ""
				EndIf
			Else
				string raceName = _player.GetRace().GetName()
				Game.PlayBink(raceName + "," + faceDataStr)
;zzCharacterMakingExtenderFunc.SetMergedMorphs(raceName + "," + faceDataStr)
				Actor _lastHorse = Game.GetPlayersLastRiddenHorse()
				i = 0
				while(!_player.IsOnMount() && !_lastHorse.IsDead() && i < 120)
					_lastHorse.Activate(_player)
					Utility.Wait(0.01)
					i = i + 1
				EndWhile
			EndIf
		Else

			if (_playerBase.GetFacePreset(0) != 33 && lastID != 99998)
				int selectedButton = zzExCharGenRevertMessage.show()
				if (selectedButton == 0)
					_playerBase.SetFacePreset(33, 0)
					Game.ShowLimitedRaceMenu()
				elseif (selectedButton == 1)
					faceDataStr = ""
					faceDataHolder = ""
					faceDataArray[0] = ""
					faceDataArray[1] = ""
					faceDataArray[2] = ""
					faceDataArray[3] = ""
					faceDataArray[4] = ""
					faceDataArray[5] = ""
					faceDataArray[6] = ""
					faceDataArray[7] = ""
					faceDataArray[8] = ""
					faceDataArray[9] = ""
				EndIf
			Else
				;if (Game.IsCamSwitchControlsEnabled())
				;	Game.ForceThirdPerson()
				;EndIf
				string raceName = Game.GetPlayer().GetRace().GetName()
				Game.PlayBink(raceName + "," + faceDataStr)
;zzCharacterMakingExtenderFunc.SetMergedMorphs(raceName + "," + faceDataStr)
			EndIf
		endif


		len = StringUtil.GetLength(faceDataStr)
		index = 0
		pos = 0
		int uid
		int value = -1
		int tmp
		while (index < len)
			pos = StringUtil.Find(faceDataStr, ",", index)
			if (pos >= 0)
				uid = StringUtil.Substring(faceDataStr, index, pos-index) as Int
				index = pos + 1
				pos = StringUtil.Find(faceDataStr, ",", index)
				tmp = StringUtil.Substring(faceDataStr, index, pos-index) as Int
				if (pos < 0)
					index = len
				Else
					index = pos + 1
				EndIf
				if (uid == -46)
					value = Math.LogicalAnd(tmp, 0xffffff)
					index = len
				EndIf
			Else
				index = len
			EndIf
		EndWhile
	
		if (value >= 0)
			hairColorForm.SetColor(value)
			_playerBase.SetHairColor(hairColorForm)
			Game.UpdateHairColor()
		EndIf
		
	endif

	if (lastExpressionAiMood < 0 || lastExpressionValue <= 0)
		_Player.ClearExpressionOverride()
	else
		_Player.SetExpressionOverride(lastExpressionAiMood, lastExpressionValue)
	endif


	locked = False
	
EndFunction


Event OnExCharGen_GetSliderPos(string eventName, string strArg, float numArg, Form sender)
	string result = ""
	if (StringUtil.GetLength(faceDataHolder) > 0)
		result = faceDataHolder + faceDataArray[0] + faceDataArray[1] + faceDataArray[2] + faceDataArray[3] + faceDataArray[4]
		result += faceDataArray[5] + faceDataArray[6] + faceDataArray[7] + faceDataArray[8] + faceDataArray[9]
	endif
	
	UI.InvokeString("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenGetListCallback", result)
endEvent

Event OnExCharGen_SetSliderPos(string eventName, string strArg, float numArg, Form sender)
	if (Debug.GetVersionNumber() != validVersion)
		Return
	EndIf
	if (StringUtil.GetLength(strArg) <= 0)
		faceDataHolder = ""
		faceDataArray[0] = ""
		faceDataArray[1] = ""
		faceDataArray[2] = ""
		faceDataArray[3] = ""
		faceDataArray[4] = ""
		faceDataArray[5] = ""
		faceDataArray[6] = ""
		faceDataArray[7] = ""
		faceDataArray[8] = ""
		faceDataArray[9] = ""
	Else
		faceDataHolder = StringUtil.Substring(strArg, 0, 4000)
		faceDataArray[0] = StringUtil.Substring(strArg, 4000, 4000)
		faceDataArray[1] = StringUtil.Substring(strArg, 8000, 4000)
		faceDataArray[2] = StringUtil.Substring(strArg, 12000, 4000)
		faceDataArray[3] = StringUtil.Substring(strArg, 16000, 4000)
		faceDataArray[4] = StringUtil.Substring(strArg, 20000, 4000)
		faceDataArray[5] = StringUtil.Substring(strArg, 24000, 4000)
		faceDataArray[6] = StringUtil.Substring(strArg, 28000, 4000)
		faceDataArray[7] = StringUtil.Substring(strArg, 32000, 4000)
		faceDataArray[8] = StringUtil.Substring(strArg, 36000, 4000)
		faceDataArray[9] = StringUtil.Substring(strArg, 40000, 4000)
	endif
endEvent

Event OnExCharGen_InputSaveSlot(string eventName, string strArg, float numArg, Form sender)
	UI.InvokeBool("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenCallbackCheck", False)

	int result = -1
	int mode = 0
	while (result < 0)
		int selectedButton
		if (mode == 0)
			selectedButton = zzExCharGenSaveMessage1.show()
		elseif (mode == 1)
			selectedButton = zzExCharGenSaveMessage2.show()
		elseif (mode == 2)
			selectedButton = zzExCharGenSaveMessage3.show()
		elseif (mode == 3)
			selectedButton = zzExCharGenSaveMessage4.show()
		else
			selectedButton = zzExCharGenSaveMessage5.show()
		endif
		if (selectedButton == 8)
			mode = (mode + 1) % 5
		elseif (selectedButton == 9)
			result = 0
		else
			result = selectedButton + mode*8 + 1
		endif
	endwhile
	
	UI.InvokeNumber("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenInputSaveSlotCallBack", result)
endEvent

Event OnExCharGen_InputLoadSlot(string eventName, string strArg, float numArg, Form sender)
	UI.InvokeBool("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenCallbackCheck", False)

	int result = -100
	int mode = 0
	while (result <= -100)
		int selectedButton
		if (mode == 0)
			selectedButton = zzExCharGenLoadMessage0.show()
		elseif (mode == 1)
			selectedButton = zzExCharGenLoadMessage1.show()
		elseif (mode == 2)
			selectedButton = zzExCharGenLoadMessage2.show()
		elseif (mode == 3)
			selectedButton = zzExCharGenLoadMessage3.show()
		elseif (mode == 4)
			selectedButton = zzExCharGenLoadMessage4.show()
		else
			selectedButton = zzExCharGenLoadMessage5.show()
		endif
		
		if ((mode == 0 && selectedButton == 4) || (mode != 0 && selectedButton == 8))
			mode = (mode + 1) % 6
		elseif ((mode == 0 && selectedButton == 5) || (mode != 0 && selectedButton == 9))
			result = -99
		elseif (mode == 0 && selectedButton == 3)
			result = 0
		elseif (mode == 0)
			result = -1 - selectedButton
		else
			result = selectedButton + (mode - 1)*8 + 1
		endif
	endwhile
	UI.InvokeNumber("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenInputLoadSlotCallBack", result)
endEvent

Event OnExCharGen_MessageBox(string eventName, string strArg, float numArg, Form sender)
	if (numArg == 0)
		Debug.MessageBox("CharacterMakingExtender\n\n" + strArg)
	ElseIf (numArg == 1)
		zzExCharGenErrMsg1.Show()
	ElseIf (numArg == 2)
		zzExCharGenErrMsg2.Show()
	ElseIf (numArg == 3)
		zzExCharGenErrMsg3.Show()
	ElseIf (numArg == 4)
		zzExCharGenErrMsg4.Show()
	ElseIf (numArg == 5)
		zzExCharGenErrMsg5.Show()
	EndIf
endEvent

Event OnExCharGen_SetHairColor(string eventName, string strArg, float numArg, Form sender)
	int newCount = numArg as Int
	int value = strArg as Int
	if (hairSliderCount > newCount)
		Return
	EndIf
	hairSliderCount = newCount

	hairColorForm.SetColor(value)
	_playerBase.SetHairColor(hairColorForm)
	Game.UpdateHairColor()

EndEvent

Event OnExCharGen_SetPlayerScale(string eventName, string strArg, float numArg, Form sender)
	int newCount = numArg as Int
	float value = strArg as float
	if (pcScaleSliderCount > newCount)
		Return
	EndIf
	pcScaleSliderCount = newCount

	_Player.SetScale(value +1)
	
EndEvent

Event OnExCharGen_ChangeExpression(string eventName, string strArg, float numArg, Form sender)
	int newCount = numArg as Int
	int tmp = strArg as Int
	int value = tmp % 1000
	int aiMood = (tmp / 1000) - 920
	if (expressionSliderCount > newCount)
		Return
	EndIf
	expressionSliderCount = newCount
	
	lastExpressionAiMood = aiMood
	lastExpressionValue = value

	if (aiMood < 0 || value <= 0)
		_Player.ClearExpressionOverride()
	else
		_Player.SetExpressionOverride(aiMood, value)
	endif
EndEvent

Event OnExCharGen_ResetHairCount(string eventName, string strArg, float numArg, Form sender)
	hairSliderCount = 0
	pcScaleSliderCount = 0
	expressionSliderCount = 0
EndEvent

Event OnExCharGen_PreExitMenu(string eventName, string strArg, float numArg, Form sender)
	if (lightObject)
		lightObject.Delete()
		lightObject = None
	EndIf
	if (lightObject2)
		lightObject2.Delete()
		lightObject2 = None
	EndIf
	_Player.ClearExpressionOverride()
	debug.sendanimationevent(_player, "idlestop")
	locked = False
EndEvent

Event OnExCharGen_ChangeRace(string eventName, string strArg, float numArg, Form sender)
	Race playerRace = _player.GetRace()
	if (zzExCharGenRaceList.HasForm(playerRace))
		int i = 0
		int num = zzExCharGenRaceList.GetSize()
		while (i < num)
			Race originalRace = zzExCharGenRaceList.GetAt(i) as Race
			Race vampireRace = zzExCharGenVampireList.GetAt(i) as Race
			if (playerRace == originalRace)
				_player.SetRace(vampireRace)
				
				CompanionsQuest.PlayerOriginalRace = originalRace
				VampireQuest.CureRace = originalRace
				
				; exit loop
				i = num
			EndIf
			i = i + 1
		EndWhile
	EndIf
EndEvent


Event OnExCharGen_SetLight(string eventName, string strArg, float numArg, Form sender)
	if (numArg != 99)
		if (!lightObject)
			lightObject = _player.placeAtMe(zzExCharGenLight)
		EndIf
		if (!lightObject2)
			lightObject2 = _player.placeAtMe(zzExCharGenLight2)
		EndIf
	EndIf

	if (numArg == 0)
		lightObject.DisableNoWait()
		lightObject2.DisableNoWait()
	ElseIf (numArg == 1)
		lightObject.EnableNoWait()
		lightObject2.DisableNoWait()
		lightObject.MoveTo(_player, Math.Sin(_player.GetAngleZ()) * 180, Math.Cos(_player.GetAngleZ())*180, _player.GetHeight())
	ElseIf (numArg == 2)
		lightObject.DisableNoWait()
		lightObject2.EnableNoWait()
		lightObject2.MoveTo(_player, Math.Sin(_player.GetAngleZ()) * 180, Math.Cos(_player.GetAngleZ())*180, _player.GetHeight())
	ElseIf (numArg == 3)
		lightObject.EnableNoWait()
		lightObject2.DisableNoWait()
		lightObject.MoveTo(_player, Math.Sin(_player.GetAngleZ()) * 100, Math.Cos(_player.GetAngleZ())*100, _player.GetHeight())
	ElseIf (numArg == 4)
		lightObject.DisableNoWait()
		lightObject2.EnableNoWait()
		lightObject2.MoveTo(_player, Math.Sin(_player.GetAngleZ()) * 100, Math.Cos(_player.GetAngleZ())*100, _player.GetHeight())
	EndIf

EndEvent


Event OnExCharGen_VertexConfirm(string eventName, string strArg, float numArg, Form sender)
	int selectedButton
	selectedButton = zzExCharGenVertexConfirmMsg.show()
	UI.InvokeBool("RaceSex Menu", "_root.RaceSexMenuBaseInstance.RaceSexPanelsInstance.ExCharGenVertexConfirmCallback", (selectedButton == 0))
EndEvent

Event OnExCharGen_StopMotion(string eventName, string strArg, float numArg, Form sender)
	if (numArg == 0)
		debug.sendanimationevent(_player, "idlestop")
	else
		debug.sendanimationevent(_player, "idlestaticposeastart")
	EndIf
EndEvent

Event OnExCharGen_ExportMesh(string eventName, string strArg, float numArg, Form sender)
	if (CharGen.GetScriptVersion() < 2)
		Debug.MessageBox("Export failed. no Scripts/CharGen.pex or old version found.")
		return
	endif
	if (SKSE.GetPluginVersion("CharGen") < 0)
		Debug.MessageBox("Export failed. no SKSE/Plugins/chargen.dll found.")
		return
	endif
		
	if (numArg == 0)
		String playerName = _playerBase.GetName()
		CharGen.ExportHead(playerName)
		Debug.MessageBox("Export Done!")
	else
		Debug.MessageBox("Cannot export nif in Color/Vertex menu. Please change any other menu.")
	endif
	
EndEvent

