Scriptname _00E_ContainerController extends ReferenceAlias Hidden ; This script sets up the sleight of hand loot of a chest upon activating it int function _GetScriptVersion() Global return 1 endFunction ;===================================================================================== ; 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() || lootMenuRef.GetActorOwner() == Player 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 || currentContainer.GetActorOwner() == Player || currentContainer.GetParentCell() != PlayerREF.GetParentCell() 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 ActorBase Property Player 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