scriptname _00E_PlayerhousingMaster extends Quest Conditional

Actor Property player Auto
ReferenceAlias Property currentHousingObjectInTranslation Auto
ReferenceAlias Property currentHousingObjectInManipulation Auto
Message Property _00E_Playerhousing_CannotPlaceObjectsHere Auto
Message Property _00E_Playerhousing_ContainerContentMove Auto
Message Property _00E_Playerhousing_StartTutorial Auto
Message Property _00E_Playerhousing_ExpansionBoardTutorial Auto
Message Property _00E_Playerhousing_TranslationMode Auto
Message Property _00E_Playerhousing_TranslationModeTutorial Auto
Message Property _00E_Playerhousing_TranslationModeTutorial_Gamepad Auto
Message Property _00E_Playerhousing_ManipulationMode Auto
Message Property _00E_Playerhousing_ManipulationModeTutorial Auto
Message Property _00E_Playerhousing_ManipulationModeTutorial_Gamepad Auto
Sound Property UIMenuActive Auto
GlobalVariable Property _00E_Meditate_Allowed Auto
GlobalVariable Property _00E_Phasmalist_TankMode Auto
GlobalVariable Property _00E_DisableCraftingTutorials Auto

_00E_Playerhousing_Furniture currentHousingObject

Bool Property bIsInPlacementMode = False Auto Conditional
Bool Property bDisableNormalActivation = False Auto Conditional
Bool bGamepadMode = False
Bool bDroppedFromInventory = False
Int iPickupKey

Float fStoredOffsetAngleZ
Float fStoredOffsetPositionZ

String Property CONTROL_ACTIVATE = "Activate" AutoReadOnly
String Property CONTROL_SHEATH = "Ready Weapon" AutoReadOnly


;=====================================================================================
;              						GLOBAL FUNCTIONS
;=====================================================================================

_00E_PlayerhousingMaster Function GetMaster() Global
	Return Game.GetFormFromFile(0x00043270, "Skyrim.esm") as _00E_PlayerhousingMaster
EndFunction

Bool Function ReferenceCanBeActivated(ObjectReference ref) Global
	If (ref as _00E_Playerhousing_Furniture)
		_00E_PlayerhousingMaster master = GetMaster()
		If master
			Return master.IsNormalActivationEnabled()
		EndIf
	EndIf

	Return True
EndFunction


;=====================================================================================
;              						TUTORIALS
;=====================================================================================

Bool bStartTutorialShown = False

Bool bHideTranslationTutorial = False
Bool bHideTranslationTutorial_Gamepad = False
Bool bHideManipulationTutorial = False
Bool bHideManipulationTutorial_Gamepad = False

Function ShowStartBuildModeTutorial()
	If _00E_DisableCraftingTutorials.GetValueInt() == 0 && bStartTutorialShown == False
		bStartTutorialShown = True
		_00E_Playerhousing_StartTutorial.Show()
	EndIf
EndFunction

Function ShowExpansionBoardTutorial()
	; Called from _00E_Game_Playerhouse_BoardSC
	If _00E_Playerhousing_ExpansionBoardTutorial.Show() == 1
		bHideTranslationTutorial = False
		bHideTranslationTutorial_Gamepad = False
		bHideManipulationTutorial = False
		bHideManipulationTutorial_Gamepad = False
	EndIf
EndFunction

Bool Function _ShowPlacementModeTutorial(Message msgTutorial, Bool bHideFlag)
	If bHideFlag == False
		Return (msgTutorial.Show() == 1)
	Else
		Return bHideFlag
	EndIf
EndFunction

Function ShowTranslationModeTutorial()
	If bGamepadMode
		bHideTranslationTutorial_Gamepad = _ShowPlacementModeTutorial(_00E_Playerhousing_TranslationModeTutorial_Gamepad, bHideTranslationTutorial_Gamepad)
	Else
		bHideTranslationTutorial = _ShowPlacementModeTutorial(_00E_Playerhousing_TranslationModeTutorial, bHideTranslationTutorial)
	EndIf
EndFunction

Function ShowManipulationModeTutorial()
	If bGamepadMode
		bHideManipulationTutorial_Gamepad = _ShowPlacementModeTutorial(_00E_Playerhousing_ManipulationModeTutorial_Gamepad, bHideManipulationTutorial_Gamepad)
	Else
		bHideManipulationTutorial = _ShowPlacementModeTutorial(_00E_Playerhousing_ManipulationModeTutorial, bHideManipulationTutorial)
	EndIf
EndFunction


;=====================================================================================
;              						SERVICE FUNCTIONS
;=====================================================================================

Bool Function CanEnterPlacementMode()
	Return (_00E_Meditate_Allowed.GetValue() != 0.0 && _00E_Phasmalist_TankMode.GetValue() == 0.0)
EndFunction

Float fPlacementModeCarryWeightMod = 0.0

Function EnterPlacementMode()
	If bIsInPlacementMode == False
		bIsInPlacementMode = True
		_00E_Meditate_Allowed.SetValueInt(0)
		Game.SetInChargen(true, true, false) ; Forbid saving the game while placing stuff

		; Make the player over encumbered to prevent them from the default running and in general to slow them down
		fPlacementModeCarryWeightMod = Player.GetActorValue("CarryWeight") * 2.0
		If fPlacementModeCarryWeightMod < 1000.0
			fPlacementModeCarryWeightMod = 1000.0
		EndIf
		Player.ModActorValue("CarryWeight", -fPlacementModeCarryWeightMod)

		bGamepadMode = Game.UsingGamepad()
		If bGamepadMode == False
			iPickupKey = Input.GetMappedKey(CONTROL_SHEATH, 0)
		Else
			iPickupKey = 277
		EndIf
	EndIf
EndFunction

Function ExitPlacementMode()
	If bIsInPlacementMode
		bIsInPlacementMode = False
		If fPlacementModeCarryWeightMod != 0.0
			Player.ModActorValue("CarryWeight", fPlacementModeCarryWeightMod)
			fPlacementModeCarryWeightMod = 0.0
		EndIf
		Game.SetInChargen(false, true, false) ; Re-allow saving
		_00E_Meditate_Allowed.SetValueInt(1)
	EndIf

	currentHousingObject = None ; Prevent persistence
EndFunction

Function PickUpHousingObject()
	 ; Clear currentHousingObject ASAP because of possible race conditions
	_00E_Playerhousing_Furniture furnitureRef = (currentHousingObject as _00E_Playerhousing_Furniture)
	currentHousingObject = None

	Form furnBaseObject = furnitureRef.GetBaseObject()
	If (furnBaseObject as ActorBase) || (furnBaseObject as Container)
		If furnitureRef.GetNumItems() > 0
			furnitureRef.RemoveAllItems(Player)
			_00E_Playerhousing_ContainerContentMove.Show()
		Else
			; Whatever...
			furnitureRef.RemoveAllItems(Player)
		EndIf
	EndIf
	Player.AddItem(furnitureRef.GetInventoryItem(), 1, False)
	furnitureRef.Disable()
	_00E_Phasmalist_Workbench worbenchRef = (furnitureRef as ObjectReference) as _00E_Phasmalist_Workbench
	If worbenchRef
		worbenchRef.OnPickUp()
	EndIf
	furnitureRef.Delete()
EndFunction

Function FinishPlacingHousingObject()
	; Clear currentHousingObject ASAP because of possible race conditions
	_00E_Playerhousing_Furniture furnitureRef = (currentHousingObject as _00E_Playerhousing_Furniture)
	currentHousingObject = None

	Utility.Wait(0.05) ; Wait for the shaders to stop for sure
	furnitureRef.finishPlacement()
	PlaySwitchSound()
EndFunction

Function PlaySwitchSound()
	UIMenuActive.Play(player)
EndFunction

Function RegisterNewHousingObjectOffsets(Float fNewOffsetAngleZ, Float fNewOffsetPositionZ)
	fStoredOffsetAngleZ    = fNewOffsetAngleZ
	fStoredOffsetPositionZ = fNewOffsetPositionZ
EndFunction


;=====================================================================================
;              						CONTROLS
;=====================================================================================

Bool bLockActions = False
Bool bActiveActivate = False

Function LockActions()
	bLockActions = True
	InterruptActivate()
EndFunction

Function UnlockActions()
	bLockActions = False
	InterruptActivate()
EndFunction

Function InterruptActivate()
	If bActiveActivate
		bActiveActivate = False
		UnregisterForUpdate()
	EndIf
EndFunction

Function EnableBuildmodeControls()
	RegisterForControl(CONTROL_ACTIVATE)
	If bIsInPlacementMode && iPickupKey > 0
		RegisterForKey(iPickupKey)
	EndIf

	UnlockActions()
EndFunction

Function DisableBuildmodeControls()
	LockActions()

	UnregisterForAllControls()
	UnregisterForAllKeys()
	UnregisterForUpdate()
EndFunction

Event OnControlDown(String control)
	If control == CONTROL_ACTIVATE
		If bActiveActivate
			bActiveActivate = False
			bDisableNormalActivation = True
			UnregisterForUpdate()
		ElseIf bLockActions == False
			bActiveActivate = True
			bDisableNormalActivation = False
			RegisterForSingleUpdate(1.1)
		EndIf
	EndIf
EndEvent

Event OnControlUp(String control, Float holdTime)
	If control == CONTROL_ACTIVATE 
		If bActiveActivate
			bActiveActivate = False
			UnregisterForUpdate()
			If bLockActions == False
				activateShortPressed()
			EndIf
		EndIf
	EndIf
EndEvent

Event OnUpdate()
	If bActiveActivate
		bActiveActivate = False
		bDisableNormalActivation = True
		If bLockActions == False
			activateLongPressed()
		EndIf
	EndIf
EndEvent

Event OnKeyDown(Int iKeyCode)
	If iKeyCode == iPickupKey 
		If bLockActions == False
			pickUpPressed()
		EndIf
	EndIf
EndEvent


;=====================================================================================
;              							DEFAULT STATE
;=====================================================================================

Event OnBeginState()
	ExitPlacementMode()
EndEvent

Function playerItemDropped(_00E_Playerhousing_FurnitureItem akItemReference)
	; Called from _00E_Playerhousing_FurnitureItem on a placeable dropped from the inventory
	Player.AddItem(akItemReference, 1, False)
	_00E_Playerhousing_CannotPlaceObjectsHere.Show()
EndFunction

Function activateShortPressed()
	; Process short activate press
EndFunction

Function activateLongPressed()
	; Process long activate press
EndFunction

Function pickUpPressed()
	; Process pick up key press
EndFunction

Function enableBuildmode()
	; Enter the build mode when the player enters their house
	ShowStartBuildModeTutorial()
	GoToState("Buildmode")
EndFunction

Function disableBuildmode()
	; Exit a build mode when the player leaves their house
EndFunction

Bool Function IsNormalActivationEnabled()
	; The player can activate a placeable furniture normally
	Return True
EndFunction


;=====================================================================================
;              							STATE Buildmode
;=====================================================================================

STATE Buildmode
	; The player can enter the manipulation or translation mode by choosing a housing object or dropping a housing item
	
	Event OnBeginState()
		ExitPlacementMode()
		bDisableNormalActivation = True
		EnableBuildmodeControls()
	EndEvent
	
	Event OnEndState()
		DisableBuildmodeControls()
	EndEvent

	Function playerItemDropped(_00E_Playerhousing_FurnitureItem akItemReference)
		If CanEnterPlacementMode() == False || bLockActions ; Locked by something else
			Player.AddItem(akItemReference, 1, False)
			Return
		EndIf
		LockActions()

		currentHousingObject = akItemReference.placeFurnitureAtMe()
		If currentHousingObject == None
			; Some error happened
			Player.AddItem(akItemReference, 1, False)
			UnlockActions()
			Return
		EndIf

		DisableBuildmodeControls()
		akItemReference.Disable()
		currentHousingObject.InventoryItem = akItemReference.GetBaseObject()
		akItemReference.Delete()
		bDroppedFromInventory = True
		GoToState("Translation")
	EndFunction
	
	Function activateLongPressed()
		LockActions()

		_00E_Playerhousing_Furniture targetRef = Game.GetCurrentCrosshairRef() as _00E_Playerhousing_Furniture
		If targetRef && targetRef.IsFurnitureInUse() == False && Utility.IsInMenuMode() == False && CanEnterPlacementMode()
			currentHousingObject = targetRef
			GoToState("Translation")
		Else
			UnlockActions()
		EndIf
	EndFunction
	
	Function activateShortPressed()
		ObjectReference targetRef = Game.GetCurrentCrosshairRef()
		If (targetRef as _00E_Playerhousing_Furniture) && (bLockActions == False)
			If (targetRef as _00E_Playerhousing_FurnitureItem)
				; Activate() would mean "Take" for this misc. object, so do nothing
			ElseIf (targetRef as _00E_Playerhousing_MannequinControl) || (targetRef as _00E_BedScript) || (targetRef as _00E_Phasmalist_Workbench) || (targetRef as _00E_PlaceableGrammophonPlay)
				; 2.1 TODO: Add crafting workbenches
				; These objects do activation themselves in OnActivate event
			Else
				targetRef.Activate(player, true)
			EndIf
		EndIf
	EndFunction

	Function enableBuildmode()
		; Do nothing
	EndFunction
	
	Function disableBuildmode()
		GoToState("")
	EndFunction

	Bool Function IsNormalActivationEnabled()
		Return ((bDisableNormalActivation == False) && (bLockActions == False))
	EndFunction

ENDSTATE


;=====================================================================================
;              							STATE Translation
;=====================================================================================

STATE Translation
	; The selected housing object is moved with the player
	
	Event OnBeginState()
		Bool bEnteringPlacement = (bIsInPlacementMode == False)

		Game.DisablePlayerControls(abMovement = false, abFighting = true, abCamSwitch = false, abLooking = false, abSneaking = false, abMenu = true, abActivate = true)
		EnterPlacementMode()

		If bEnteringPlacement && bDroppedFromInventory == False
			ObjectReference housingObjRef = currentHousingObject as ObjectReference
			If (housingObjRef as _00E_PlaceableGrammophonPlay)
				(housingObjRef as _00E_PlaceableGrammophonPlay).StopMusic()
			EndIf
		EndIf

		If bDroppedFromInventory == False
			PlaySwitchSound()
		Else
			bDroppedFromInventory = False
		EndIf

		_00E_Playerhousing_TranslationMode.Show()

		(currentHousingObjectInTranslation as _00E_PlayerhousingCurrentOTranslation).Setup(currentHousingObject, bEnteringPlacement, fStoredOffsetAngleZ, fStoredOffsetPositionZ)

		ShowTranslationModeTutorial()
 
		EnableBuildmodeControls()
	EndEvent
	
	Event OnEndState()
		Game.EnablePlayerControls(abMovement = true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abActivate = true)
	EndEvent
	
	Function activateShortPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInTranslation as _00E_PlayerhousingCurrentOTranslation).Shutdown()
		GoToState("Manipulation")
	EndFunction
	
	Function activateLongPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInTranslation as _00E_PlayerhousingCurrentOTranslation).Shutdown()
		FinishPlacingHousingObject()
		GoToState("Buildmode")
	EndFunction

	Function pickUpPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInTranslation as _00E_PlayerhousingCurrentOTranslation).Shutdown()
		PickUpHousingObject()
		GoToState("Buildmode")
	EndFunction
	
	Function enableBuildmode()
		; Do nothing
	EndFunction
	
	Function disableBuildmode()
		DisableBuildmodeControls()
		(currentHousingObjectInTranslation as _00E_PlayerhousingCurrentOTranslation).Shutdown()
		If currentHousingObject
			PickUpHousingObject()
		EndIf
		GoToState("")
	EndFunction
	
	Bool Function IsNormalActivationEnabled()
		Return False
	EndFunction

ENDSTATE


;=====================================================================================
;              							STATE Manipulation
;=====================================================================================

STATE Manipulation
	; The player can change orientation or altitude of the selected housing object by using the keys

	Event OnBeginState()
		Game.DisablePlayerControls(abMovement = false, abFighting = true, abCamSwitch = false, abLooking = false, abSneaking = false, abMenu = true, abActivate = true)
		Game.SetPlayerAIDriven(True)
		
		PlaySwitchSound()

		_00E_Playerhousing_ManipulationMode.Show()
		
		(currentHousingObjectInManipulation as _00E_PlayerhousingCurrentOManipulate).Setup(currentHousingObject)

		ShowManipulationModeTutorial()

		EnableBuildmodeControls()
	EndEvent

	Event OnEndState()
		Game.SetPlayerAIDriven(False)
		Game.EnablePlayerControls(abMovement = true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abActivate = true)
	EndEvent
	
	Function activateShortPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInManipulation as _00E_PlayerhousingCurrentOManipulate).Shutdown(True)
		GoToState("Translation")
	EndFunction
	
	Function activateLongPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInManipulation as _00E_PlayerhousingCurrentOManipulate).Shutdown(False)
		FinishPlacingHousingObject()
		GoToState("Buildmode")
	EndFunction

	Function pickUpPressed()
		DisableBuildmodeControls()
		(currentHousingObjectInManipulation as _00E_PlayerhousingCurrentOManipulate).Shutdown(False)
		PickUpHousingObject()
		GoToState("Buildmode")
	EndFunction
	
	Function enableBuildmode()
		; Do nothing
	EndFunction
	
	Function disableBuildmode()
		DisableBuildmodeControls()
		(currentHousingObjectInManipulation as _00E_PlayerhousingCurrentOManipulate).Shutdown(False)
		If currentHousingObject
			PickUpHousingObject()
		EndIf
		GoToState("")
	EndFunction
	
	Bool Function IsNormalActivationEnabled()
		Return False
	EndFunction

ENDSTATE