Scriptname _00E_ContainerController extends ReferenceAlias Hidden 
; This script sets up the sleight of hand loot of a chest upon activating it 

;=====================================================================================
;              							EVENTS                 					 
;=====================================================================================

event OnInit()
	RegisterForMenu("ContainerMenu")
	RegisterForMenu("LootMenu")
	PlayerREF.AddPerk(_00E_LockpickingReqPerk)
endevent

event OnPlayerLoadGame()
	lastContainer = None
	bLmHasGold = false
	bLmHasSlot = false
	RegisterForMenu("ContainerMenu")
	RegisterForMenu("LootMenu")
	if ! PlayerREF.HasPerk(_00E_LockpickingReqPerk)
		PlayerREF.AddPerk(_00E_LockpickingReqPerk)
	endif
endevent

event OnUpdate()
	ObjectReference currentContainer = lastContainer
	lastContainer = None
	
	if ! currentContainer
		return
	endif
	
	if UI.IsMenuOpen("LootMenu") && currentContainer == Game.GetCurrentCrosshairRef()
		if bLmHasGold
			IncrementGold(currentContainer)
		endif
		if bLmHasSlot
			OpenHiddenSlot(currentContainer, true)
		endif
	endif
endevent

event OnMenuOpen(String MenuName)
	
	if MenuName == "LootMenu"
		; Even when QuickLoot RE does not show up, it still sends open and close menu events
		; To determine if QuickLoot is open, we check it 0.1 seconds later
		
		lastContainer = None
		UnregisterForUpdate()
		ObjectReference lootMenuRef = Game.GetCurrentCrosshairRef()
		
		if ! lootMenuRef
			return
		endif
		
		if ! ( lootMenuRef.GetBaseObject() as Container ) || lootMenuRef.IsLocked() || lootMenuRef.IsActivationBlocked()
			return
		endif

		bLmHasGold = lootMenuRef.GetItemCount(Gold001) >= 5
		bLmHasSlot = false
		
		if bLmHasGold || _00E_ChestsWithHiddenSlots.HasForm(lootMenuRef.GetBaseObject())
			if ! bLmHasGold
				bLmHasSlot = true
			endif
			if ! IsProcessed(lootMenuRef)
				lastContainer = lootMenuRef
				; Clears previous request automatically
				RegisterForSingleUpdate(0.1)
			endif
		endif
		
		return
	endif
	
	if MenuName == "ContainerMenu"
		ObjectReference currentContainer = EnderalFunctions.GetCurrentContainer()

		if ! currentContainer || currentContainer as Actor
			return
		endif
	
		if currentContainer == containerToFill
			; Opened hidden container
			Utility.Wait(0.1)
			; Move unclaimed items to the original container
			containerToFill.RemoveAllItems(lastContainer, true, true)
			lastContainer = None
			containerToFill = None
			return
		endif

		bool bDoGold = currentContainer.GetItemCount(Gold001) >= 5
		bool bDoSlot = _00E_ChestsWithHiddenSlots.HasForm(currentContainer.GetBaseObject())

		if ! bDoGold && ! bDoSlot
			return
		endif
		
		if IsProcessed(currentContainer)
			return
		endif
		
		if bDoGold
			IncrementGold(currentContainer)
		endif
		
		if bDoSlot
			OpenHiddenSlot(currentContainer)
		endif

	endif
	
endevent

event OnMenuClose(String MenuName)
	if MenuName == "LootMenu"
		UnregisterForUpdate()
		lastContainer = None
		bLmHasGold = false
		bLmHasSlot = false
	endif
endevent


;=====================================================================================
;              							FUNCTIONS                 					 
;=====================================================================================

bool function IsProcessed(ObjectReference targetContainer)
	if targetContainer.GetItemCount(_00E_HiddenSlotChecked)
		return true
	endif

	targetContainer.AddItem(_00E_HiddenSlotChecked, 1, true)
	return false
endfunction

Function IncrementGold(ObjectReference targetContainer)

	int iGoldMultiplicator = _00E_GoldMult.GetValue() as int
	
	if iGoldMultiplicator <= 0
		iGoldMultiplicator = 5
	endif

	float fIncrementPercentage = ( PlayerREF.GetActorValue("Lockpicking") / iGoldMultiplicator ) / 100
	int iGoldBuffAmount = ( targetContainer.GetItemCount(Gold001) * fIncrementPercentage ) as Int
	
	if iGoldBuffAmount <= 0
		return
	endif
	
	targetContainer.AddItem(Gold001, iGoldBuffAmount)
	
	if iGoldBuffAmount > 1
		_00E_FS_LockpickingGoldBuffMSG.Show(iGoldBuffAmount as Int)
	EndIf
	
EndFunction

function OpenHiddenSlot(ObjectReference currentContainer, bool bLootMenu = false)

	if ! SetUpHiddenSlot(currentContainer)
		return
	endif
	
	UILockpickingCylinderTurnM.Play(PlayerREF)
	messageToShow.Show()

	if bLootMenu
		containerToFill.RemoveAllItems(currentContainer, true, true)
	else
		; Open hidden container after the original one closes
		Utility.Wait(0.1)
		
		If IsOwned(currentContainer)
			containerToFill.SetFactionOwner(SleightOfHandOwnerFaction)
		Else
			containerToFill.SetFactionOwner(none)
		Endif
		
		lastContainer = currentContainer
		containerToFill.Activate(PlayerREF, True)
	endif
	
	If containerToFill == _00E_FS_SleightOfHand_HiddenSlot_BigSlotREF
		_00E_EPHandler.GiveEP(_00E_BigHiddenSlotExpReward.GetValue() as int)
		If _00E_HiddenSlotAchievementUnlocked.GetValueInt() == 0
			UIEnchantingLearnEffectM.Play(PlayerREF)
			_00E_HiddenSlotAchievementUnlocked.SetValueInt(1)
			Steam.UnlockAchievement("END_HIDDEN_SLOT_01")
		EndIf
	EndIf
	
endfunction

bool function SetUpHiddenSlot(ObjectReference aContainer)

	if ! DoesContainerHaveHiddenSlot()
		return false
	EndIf
	
	messageToShow = GetSlotMessage()
	int iHiddenSlotTier = GetHiddenSlotTier()
	
	int iFormlistIndexOffset = 8*(iHiddenSlotTier - 1)
	int iFormlistIndex
	
	if messageToShow == _00E_FS_SleightOfHand_HiddenSlot_sSmallSlotFound
	
		containerToFill = _00E_FS_SleightOfHand_HiddenSlot_SmallSlotREF
		iFormlistIndex = Utility.RandomInt(0, 2) + iFormlistIndexOffset
		
	Elseif messageToShow == _00E_FS_SleightOfHand_HiddenSlot_sMediumSlotFound
	
		containerToFill = _00E_FS_SleightOfHand_HiddenSlot_MediumSlotREF
		iFormlistIndex = Utility.RandomInt(3, 5) + iFormlistIndexOffset
	
	Elseif messageToShow == _00E_FS_SleightOfHand_HiddenSlot_sBigSlotFound
	
		containerToFill = _00E_FS_SleightOfHand_HiddenSlot_BigSlotREF
		iFormlistIndex = Utility.RandomInt(6, 7) + iFormlistIndexOffset
	
	EndIf
	
	Formlist hiddenSlotFormlist = _00E_FS_HiddenSlotRewardFormlists.GetAt(iFormlistIndex) as Formlist
	AddItemsToContainer(hiddenSlotFormlist, iFormlistIndexOffset, iHiddenSlotTier)
	
	return true
	
EndFunction

Function AddItemsToContainer(Formlist itemsToAdd, int iFormlistIndexOffset, int iHiddenSlotTier)
	
	containerToFill.RemoveAllItems()

	if containerToFill == _00E_FS_SleightOfHand_HiddenSlot_BigSlotREF
	
		if ! itemsToAdd.HasForm(_00E_FS_SleightOfHand_HiddenSlotUsedMarker)
			itemsToAdd.AddForm(_00E_FS_SleightOfHand_HiddenSlotUsedMarker)
		Else
			int iFormlistIndex = Utility.RandomInt(3, 5) + iFormlistIndexOffset
			itemsToAdd = _00E_FS_HiddenSlotRewardFormlists.GetAt(iFormlistIndex) as Formlist
			messageToShow = _00E_FS_SleightOfHand_HiddenSlot_sMediumSlotFound
		EndIf
		
	EndIf

	int iIndex = itemsToAdd.GetSize() - 1

	while iIndex >= 0
	
		Form formToAdd = itemsToAdd.GetAt(iIndex)
	
		if formToAdd == Gold001
			containerToFill.AddItem(itemsToAdd.GetAt(iIndex), iHiddenSlotTier*5)
		Else	
			containerToFill.AddItem(itemsToAdd.GetAt(iIndex), 1)
		EndIf
		
		iIndex -= 1
		
	endwhile
	
EndFunction

bool Function DoesContainerHaveHiddenSlot()

	float fHiddenSlotChance = Utility.RandomInt(0, 100)
	
	int iPlayerPickpocketSkill = PlayerREF.GetActorValue("Pickpocket") as Int
	
	; raised the divider from 2 to 2.5, maybe we should raise it even further
	; otherwise too much loot might be given away
	float fPlayerChance = iPlayerPickpocketSkill/2.5
	
	If fPlayerChance < 15
		fPlayerChance = 15
	EndIf
	
	return (fHiddenSlotChance <= fPlayerChance)

EndFunction

int Function GetHiddenSlotTier()

	int iPlayerLevel = PlayerLevel.GetValueInt()

	if iPlayerLevel >= iTierCap_1 && iPlayerLevel < iTierCap_2
		Return 1
	Elseif iPlayerLevel >= iTierCap_2 && iPlayerLevel < iTierCap_3
		Return 2
	Elseif iPlayerLevel >= iTierCap_3 && iPlayerLevel < iTierCap_4
		Return 3
	Elseif iPlayerLevel >= iTierCap_4 && iPlayerLevel < iTierCap_5
		Return 4
	Else
		Return 5
	EndIf
	
EndFunction

Message Function GetSlotMessage()

	; This calculates whether the hidden slot will be filled with a small, a regular, or a rare reward

	int iSlotSize = Utility.RandomInt(1, 100)
	
	if iSlotSize <= iBigSlotChance && PlayerREF.GetActorValue("Pickpocket") >= 75
		return _00E_FS_SleightOfHand_HiddenSlot_sBigSlotFound

	Elseif (iSlotSize > iBigSlotChance) && (iSlotSize <= (iMediumSlotChance + iBigSlotChance)) && PlayerREF.GetActorValue("Pickpocket") >= 50
		return _00E_FS_SleightOfHand_HiddenSlot_sMediumSlotFound
	
	Else
		return _00E_FS_SleightOfHand_HiddenSlot_sSmallSlotFound
	
	EndIf
	
EndFunction

bool Function IsOwned(ObjectReference aContainer)

	If aContainer.GetActorOwner()
		return true
	EndIf
	
	Cell ContainerParentCell = aContainer.GetParentCell()
	
	return ContainerParentCell.GetActorOwner() || ContainerParentCell.GetFactionOwner()
	
EndFunction

;=====================================================================================
;              							PROPERTIES                 					 
;=====================================================================================

; These integers determine at which levels player can access the different tiers
int iTierCap_1 = 0
int iTierCap_2 = 15
int iTierCap_3 = 25
int iTierCap_4 = 35
int iTierCap_5 = 45

; These integers determine the likelihood of the different slot sizes
int iSmallSlotChance = 50
int iMediumSlotChance = 35
int iBigSlotChance = 15

; This formlist will be filled with the formlist containing the items that will actually be added into the container
Message messageToShow 
ObjectReference lastContainer
ObjectReference containerToFill

bool bLmHasGold
bool bLmHasSlot

Actor Property PlayerRef  Auto  

GlobalVariable Property PlayerLevel  Auto  
GlobalVariable Property _00E_HiddenSlotAchievementUnlocked  Auto  
GlobalVariable Property _00E_BigHiddenSlotExpReward Auto

; Use this to control how much the lockpicking skill increments the gold found in chest. When changing, remember to change in _00E_LootContainer.psc as well!
; Current calculation: Gold in chest*((Lockpicking/iGoldMultiplicator)/100)
GlobalVariable Property _00E_GoldMult  Auto  

; These REFs simply provide the containers that will be filled when finding a secret slot
ObjectReference Property _00E_FS_SleightOfHand_HiddenSlot_SmallSlotREF  Auto  
ObjectReference Property _00E_FS_SleightOfHand_HiddenSlot_MediumSlotREF  Auto  
ObjectReference Property _00E_FS_SleightOfHand_HiddenSlot_BigSlotREF  Auto  

MiscObject Property Gold001  Auto  
MiscObject Property _00E_FS_SleightOfHand_HiddenSlotUsedMarker  Auto  
MiscObject Property _00E_HiddenSlotChecked  Auto 

Sound Property UILockpickingCylinderTurnM  Auto  
Sound Property UIEnchantingLearnEffectM  Auto  

Message Property _00E_FS_SleightOfHand_HiddenSlot_sSmallSlotFound  Auto  
Message Property _00E_FS_SleightOfHand_HiddenSlot_sMediumSlotFound  Auto  
Message Property _00E_FS_SleightOfHand_HiddenSlot_sBigSlotFound  Auto  

; This contains all formlists with items for the rewards.For every tier, there are nine different treasures to be found, three in small and medium category, two in big.
FormList Property _00E_FS_HiddenSlotRewardFormlists  Auto  
FormList Property _00E_ChestsWithHiddenSlots Auto

Faction Property SleightOfHandOwnerFaction  Auto  

Message Property _00E_FS_LockpickingGoldBuffMSG  Auto  

Perk Property _00E_LockpickingReqPerk  Auto