diff --git a/Artifact Tracker.esp b/Artifact Tracker.esp index ead6179..f4198e0 100644 Binary files a/Artifact Tracker.esp and b/Artifact Tracker.esp differ diff --git a/SKSE/Plugins/ArtifactTrackerFunctions.dll b/SKSE/Plugins/ArtifactTrackerFunctions.dll index 3a49b5a..21d91f3 100644 Binary files a/SKSE/Plugins/ArtifactTrackerFunctions.dll and b/SKSE/Plugins/ArtifactTrackerFunctions.dll differ diff --git a/Scripts/ETR_Functions.pex b/Scripts/ETR_Functions.pex index 0a56104..1355e3b 100644 Binary files a/Scripts/ETR_Functions.pex and b/Scripts/ETR_Functions.pex differ diff --git a/Scripts/ETR_TrackFoundItems.pex b/Scripts/ETR_TrackFoundItems.pex index e17fe19..746e8eb 100644 Binary files a/Scripts/ETR_TrackFoundItems.pex and b/Scripts/ETR_TrackFoundItems.pex differ diff --git a/Scripts/ETR_TrackNewItems.pex b/Scripts/ETR_TrackNewItems.pex index 86ed3f6..c935fd9 100644 Binary files a/Scripts/ETR_TrackNewItems.pex and b/Scripts/ETR_TrackNewItems.pex differ diff --git a/Scripts/ETR_TrackStoredItems.pex b/Scripts/ETR_TrackStoredItems.pex index a4f1096..b4e2f15 100644 Binary files a/Scripts/ETR_TrackStoredItems.pex and b/Scripts/ETR_TrackStoredItems.pex differ diff --git a/Source/DLL/src/Functions/ArtifactTracker.h b/Source/DLL/src/Functions/ArtifactTracker.h index d30461c..bffbe45 100644 --- a/Source/DLL/src/Functions/ArtifactTracker.h +++ b/Source/DLL/src/Functions/ArtifactTracker.h @@ -2,6 +2,54 @@ namespace Papyrus::ArtifactTracker { + inline bool is_excluded(RE::TESForm* a_form, RE::TESForm* a_excludeForm = NULL) + { + if (!a_excludeForm) { + return false; + } + + const RE::BGSListForm* list = a_excludeForm->As(); + + if (list) { + if (list->HasForm(a_form)) { + return true; + } else { + bool isExcluded = false; + + list->ForEachForm([&](RE::TESForm& a_exform) { + const auto exlist = a_exform.As(); + if (exlist) { + if (exlist->forms.size() > 0) { + if (exlist->forms[0]->Is(RE::FormType::Keyword) ? a_form->HasKeywordInList(exlist, false) : exlist->HasForm(a_form)) { + isExcluded = true; + return false; + } + } + } else { + const auto exkeyword = a_exform.As(); + if (exkeyword && a_form->As()->HasKeyword(exkeyword)) { + isExcluded = true; + return false; + } + } + return true; + }); + + return isExcluded; + } + } + + const RE::BGSKeyword* keyword = a_excludeForm->As(); + + if (keyword) { + if (a_form->As()->HasKeyword(keyword)) { + return true; + } + } + + return false; + } + inline bool is_artifact(RE::TESForm* a_form, RE::TESForm* a_excludeForm = NULL) { const auto formType = a_form->GetFormType(); @@ -10,13 +58,93 @@ namespace Papyrus::ArtifactTracker return false; } - if (Papyrus::ObjectReference::inv_util::is_excluded(a_form, a_excludeForm)) { + if (!a_form->GetPlayable() || is_excluded(a_form, a_excludeForm)) { return false; } return true; } + inline std::int32_t AddAllFormsToList(RE::StaticFunctionTag*, + RE::BGSListForm* a_targetList, + short a_formType, + RE::TESForm* a_excludeForm = NULL) + { + const auto dataHandler = RE::TESDataHandler::GetSingleton(); + + if (!dataHandler) { + return a_targetList->forms.size(); + } + + const auto formType = static_cast(a_formType); + + for (const auto& form : dataHandler->GetFormArray(formType)) { + if (!form || !form->GetPlayable()) { + continue; + } + if (a_excludeForm && is_excluded(form, a_excludeForm)) { + continue; + } + a_targetList->AddForm(form); + } + + return a_targetList->forms.size(); + } + + inline std::int32_t AddArtifactsToList(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, + RE::TESForm* a_refOrList, + RE::BGSListForm* a_targetList, + RE::TESForm* a_excludeForm = NULL, + bool excludeOnlyMisc = false) + { + if (!a_refOrList) { + a_vm->TraceStack("a_refOrList in AddItemsOfTypeAndKeywordToList is None", a_stackID); + return 0; + } + if (!a_targetList) { + a_vm->TraceStack("a_targetList in AddItemsOfTypeAndKeywordToList is None", a_stackID); + return 0; + } + + if (a_refOrList->Is(RE::FormType::FormList)) { + a_refOrList->As()->ForEachForm([&](RE::TESForm& a_exform) { + const auto refrItem = a_exform.As(); + if (refrItem) { + AddArtifactsToList(a_vm, a_stackID, {}, refrItem, a_targetList, a_excludeForm, excludeOnlyMisc); + } + return true; + }); + return a_targetList->forms.size(); + } + + const auto containerRef = a_refOrList->As(); + + if (!containerRef) { + a_vm->TraceStack("containerRef in AddItemsOfTypeAndKeywordToList is not a reference", a_stackID); + return 0; + } + + auto inv = containerRef->GetInventory([&](RE::TESBoundObject& a_exform) { + return a_exform.GetPlayable() + && ( + a_exform.formType == RE::FormType::Armor + || (a_exform.formType == RE::FormType::Weapon && a_exform.formID != 0x000001F4) + || a_exform.formType == RE::FormType::Misc + || a_exform.formType == RE::FormType::Book + ) + && (excludeOnlyMisc ? (a_exform.formType != RE::FormType::Misc || !is_excluded(&a_exform, a_excludeForm)) : !is_excluded(&a_exform, a_excludeForm)); + }); + + for (const auto& [item, data] : inv) { + const auto& [count, entry] = data; + if (count > 0) { + a_targetList->AddForm(item); + } + } + + return a_targetList->forms.size(); + } + inline RE::TESObjectREFR* GetCellStorage(RE::StaticFunctionTag*, RE::TESObjectREFR* a_ref, RE::BGSListForm* a_refList, @@ -119,12 +247,11 @@ namespace Papyrus::ArtifactTracker continue; } - const auto contInv = a_ref->GetInventory(); + const auto contInv = a_ref->GetInventory([&](RE::TESBoundObject& a_object) -> bool { + return !cellItems.contains(a_object.formID); + }); for (const auto& [item, data] : contInv) { - if (cellItems.contains(item->formID)) { - continue; - } const auto& [count, entry] = data; if (count > 0) { cellItems[item->formID] = true; @@ -146,12 +273,12 @@ namespace Papyrus::ArtifactTracker if (cellItems.contains(baseObj->formID)) { continue; } + + cellItems[baseObj->formID] = true; if (!is_artifact(baseObj, a_excludeForm)) { continue; } - - cellItems[baseObj->formID] = true; if (inv.find(baseObj) == inv.end()) { a_cellStorage->AddObjectToContainer(baseObj, nullptr, 1, nullptr); @@ -170,6 +297,10 @@ namespace Papyrus::ArtifactTracker inline void Bind(VM& a_vm) { + BIND(AddAllFormsToList); + logger::info("Registered AddAllFormsToList"sv); + BIND(AddArtifactsToList); + logger::info("Registered AddArtifactsToList"sv); BIND(GetCellStorage); logger::info("Registered GetCellStorage"sv); BIND(HasRefInCell); diff --git a/Source/DLL/src/Functions/ObjectReference.h b/Source/DLL/src/Functions/ObjectReference.h index 5958db9..ac7c919 100644 --- a/Source/DLL/src/Functions/ObjectReference.h +++ b/Source/DLL/src/Functions/ObjectReference.h @@ -2,194 +2,6 @@ namespace Papyrus::ObjectReference { - namespace inv_util - { - inline bool can_be_taken(const std::unique_ptr& a_entry, bool a_noEquipped, bool a_noFavourited, bool a_noQuestItem) - { - if (a_noEquipped && a_entry->IsWorn()) { - return false; - } - if (a_noFavourited && a_entry->IsFavorited()) { - return false; - } - if (a_noQuestItem && a_entry->IsQuestObject()) { - return false; - } - if (a_entry->object->formID == 0x000001F4) { // Unarmed - return false; - } - return true; - } - - inline bool is_excluded(RE::TESForm* a_form, RE::TESForm* a_excludeForm = NULL) - { - if (!a_excludeForm) { - return false; - } - - const RE::BGSListForm* list = a_excludeForm->As(); - - if (list) { - if (list->HasForm(a_form)) { - return true; - } else { - bool isExcluded = false; - - list->ForEachForm([&](RE::TESForm& a_exform) { - const auto exlist = a_exform.As(); - if (exlist) { - if (exlist->forms.size() > 0) { - if (exlist->forms[0]->Is(RE::FormType::Keyword) ? a_form->HasKeywordInList(exlist, false) : exlist->HasForm(a_form)) { - isExcluded = true; - return false; - } - } - } else { - const auto exkeyword = a_exform.As(); - if (exkeyword && a_form->As()->HasKeyword(exkeyword)) { - isExcluded = true; - return false; - } - } - return true; - }); - - return isExcluded; - } - } - - const RE::BGSKeyword* keyword = a_excludeForm->As(); - - if (keyword) { - if (a_form->As()->HasKeyword(keyword)) { - return true; - } - } - - return false; - } - - inline RE::ITEM_REMOVE_REASON get_remove_reason(RE::TESObjectREFR* atargetRef) - { - RE::ITEM_REMOVE_REASON iReason = RE::ITEM_REMOVE_REASON::kStoreInContainer; - - if (atargetRef->As() && atargetRef->As()->IsPlayerTeammate()) { - iReason = RE::ITEM_REMOVE_REASON::kStoreInTeammate; - } - - return iReason; - } - } - - inline std::int32_t AddAllFormsToList(RE::StaticFunctionTag*, - RE::BGSListForm* a_targetList, - std::int32_t a_formType, - RE::TESForm* a_keywordOrList = NULL, - RE::TESForm* a_excludeForm = NULL, - bool a_onlyPlayable = true) - { - const auto formType = static_cast(a_formType); - - const auto keyword = a_keywordOrList ? a_keywordOrList->As() : nullptr; - const auto keywordList = a_keywordOrList ? a_keywordOrList->As() : nullptr; - - const auto dataHandler = RE::TESDataHandler::GetSingleton(); - - if (!dataHandler) { - return a_targetList->forms.size(); - } - - for (const auto& form : dataHandler->GetFormArray(formType)) { - if (!form) { - continue; - } - if (a_onlyPlayable && !form->GetPlayable()) { - continue; - } - if ((keyword && !form->As()->HasKeyword(keyword)) || (keywordList && !form->HasKeywordInList(keywordList, false))) { - continue; - } - if (a_excludeForm && inv_util::is_excluded(form, a_excludeForm)) { - continue; - } - a_targetList->AddForm(form); - } - - return a_targetList->forms.size(); - } - - inline std::int32_t AddItemsOfTypeAndKeywordToList(VM* a_vm, StackID a_stackID, RE::StaticFunctionTag*, - RE::TESForm* a_refOrList, - RE::BGSListForm* a_targetList, - std::uint32_t a_formType = 0, - RE::TESForm* a_keywordOrList = NULL, - RE::TESForm* a_excludeForm = NULL, - bool a_noEquipped = TRUE, - bool a_noFavourited = TRUE, - bool a_noQuestItem = TRUE) - { - if (!a_refOrList) { - a_vm->TraceStack("a_refOrList in AddItemsOfTypeAndKeywordToList is None", a_stackID); - return 0; - } - if (!a_targetList) { - a_vm->TraceStack("a_targetList in AddItemsOfTypeAndKeywordToList is None", a_stackID); - return 0; - } - - if (a_refOrList->Is(RE::FormType::FormList)) { - a_refOrList->As()->ForEachForm([&](RE::TESForm& a_exform) { - const auto refrItem = a_exform.As(); - if (refrItem) { - AddItemsOfTypeAndKeywordToList(a_vm, a_stackID, {}, refrItem, a_targetList, a_formType, a_keywordOrList, a_excludeForm, a_noEquipped, a_noFavourited, a_noQuestItem); - } - return true; - }); - return a_targetList->forms.size(); - } - - const auto containerRef = a_refOrList->As(); - - if (!containerRef) { - a_vm->TraceStack("containerRef in AddItemsOfTypeAndKeywordToList is not a reference", a_stackID); - return 0; - } - - const auto formType = static_cast(a_formType); - const bool bNoType = formType == RE::FormType::None; - - const auto keyword = a_keywordOrList ? a_keywordOrList->As() : nullptr; - const auto keywordList = a_keywordOrList ? a_keywordOrList->As() : nullptr; - - auto inv = containerRef->GetInventory([&](RE::TESBoundObject& a_exform) { - return (bNoType || a_exform.formType == formType) - && ( - (!keyword && !keywordList) - || (keyword && a_exform.As()->HasKeyword(keyword)) - || (keywordList && a_exform.HasKeywordInList(keywordList, false))) - && (!a_excludeForm || !inv_util::is_excluded(&a_exform, a_excludeForm)) - && a_exform.GetPlayable() && a_exform.formID != 0x000001F4; - }); - - if (containerRef->IsPlayerRef()) { - for (const auto& [item, data] : inv) { - const auto& [count, entry] = data; - if (count > 0 && inv_util::can_be_taken(entry, a_noEquipped, a_noFavourited, a_noQuestItem)) { - a_targetList->AddForm(item); - } - } - } else { - for (const auto& [item, data] : inv) { - const auto& [count, entry] = data; - if (count > 0) { - a_targetList->AddForm(item); - } - } - } - - return a_targetList->forms.size(); - } - inline std::uint32_t GetItemCountInList(RE::StaticFunctionTag*, RE::BGSListForm* a_containerList, RE::TESBoundObject* a_form) @@ -256,10 +68,6 @@ namespace Papyrus::ObjectReference inline void Bind(VM& a_vm) { - BIND(AddAllFormsToList); - logger::info("Registered AddAllFormsToList"sv); - BIND(AddItemsOfTypeAndKeywordToList); - logger::info("Registered AddItemsOfTypeAndKeywordToList"sv); BIND(GetItemCountInList); logger::info("Registered GetItemCountInList"sv); BIND(GetItemCountInActors); diff --git a/Source/DLL/src/Papyrus.h b/Source/DLL/src/Papyrus.h index 3a4e060..cf5ad93 100644 --- a/Source/DLL/src/Papyrus.h +++ b/Source/DLL/src/Papyrus.h @@ -9,7 +9,7 @@ namespace Papyrus { using StackID = RE::VMStackID; using Severity = RE::BSScript::ErrorLogger::Severity; - inline constexpr auto script = "EddsArtifactTracker"sv; + inline constexpr auto script = "ETR_Functions"sv; bool Bind(VM* a_vm); } diff --git a/Source/Scripts/ETR_Functions.psc b/Source/Scripts/ETR_Functions.psc index 3e4faa3..729b195 100644 --- a/Source/Scripts/ETR_Functions.psc +++ b/Source/Scripts/ETR_Functions.psc @@ -1,12 +1,8 @@ Scriptname ETR_Functions Hidden -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; ObjectReference functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +int function AddAllFormsToList(FormList targetList, int formType, Form excludeForm = None) native global -int function AddAllFormsToList(FormList targetList, int formType, Form keywordOrList = None, Form excludeForm = None, bool onlyPlayable = true) native global - -int function AddItemsOfTypeAndKeywordToList(Form refOrList, FormList targetList, int formType = 0, Form keywordOrList = None, Form excludeForm = None, bool noEquipped = true, bool noFavourited = true, bool noQuestItem = true) native global +int function AddArtifactsToList(Form refOrList, FormList targetList, Form excludeForm = None, bool excludeOnlyMisc = false) native global int function GetItemCountInList(FormList refList, Form baseForm) native global @@ -14,10 +10,6 @@ int function GetItemCountInActors(Actor[] refArray, Form baseForm) native global Actor[] function GetPlayerFollowers() native global -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Artifact Tracker -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ObjectReference function GetCellStorage(ObjectReference ref, FormList refList, Form refToCreate, bool autoCreate = true) native global bool function HasRefInCell(Form item, Cell currentCell = None, bool checkContainers = true, FormList excludeList = None) native global diff --git a/Source/Scripts/ETR_TrackFoundItems.psc b/Source/Scripts/ETR_TrackFoundItems.psc index 273f2f3..01972f2 100644 --- a/Source/Scripts/ETR_TrackFoundItems.psc +++ b/Source/Scripts/ETR_TrackFoundItems.psc @@ -7,17 +7,20 @@ FormList Property ETR_ItemsFound Auto FormList Property ETR_ItemsStored Auto FormList Property ETR_PersistentStorageList Auto FormList Property ETR_ExcludeFromNew Auto -FormList Property ETR_ExcludeFromCellItems Auto +FormList Property ETR_ExcludeMisc Auto Container Property ETR_CellStorageContainer Auto Keyword Property LocTypePlayerHouse Auto -bool bAtHome = false +bool bBusy = false int iFollowerIndex = 0 -bool bUpdateFollowers = false -bool bSyncStorage = false -bool bUpdateLists = false +bool bAtHome = false +bool bRescanHome = false +bool bRescanPersistent = false +ObjectReference lastDestContainer = None +bool lastDestIsPersistent = false +int iUpdateCount event OnInit() @@ -27,12 +30,16 @@ endevent Event OnPlayerLoadGame() AddInventoryEventFilter(ETR_ItemsFound) + Location currentLocation = PlayerRef.GetCurrentLocation() + bAtHome = currentLocation && currentLocation.HasKeyword(LocTypePlayerHouse) + lastDestContainer = None EndEvent Event OnLocationChange(Location akOldLoc, Location akNewLoc) bAtHome = akNewLoc && akNewLoc.HasKeyword(LocTypePlayerHouse) + lastDestContainer = None int iCurrentFollowers = 0; Actor[] aFollowers = ETR_Functions.GetPlayerFollowers() @@ -43,95 +50,72 @@ Event OnLocationChange(Location akOldLoc, Location akNewLoc) endwhile if iCurrentFollowers != iFollowerIndex - ; If the list of followers has changed, rebuild ETR_ItemsFound and ETR_ItemsNew iFollowerIndex = iCurrentFollowers - bUpdateFollowers = true + bRescanHome = false + bRescanPersistent = false RegisterForSingleUpdate(3.0) ; wait until followers load into the location endif endEvent +Event OnMenuClose(String MenuName) + UnregisterForUpdate() + OnUpdate() +EndEvent + + Event OnUpdate() - Actor[] aFollowers - int i + if UI.IsMenuOpen("ContainerMenu") + RegisterForMenu("ContainerMenu") + return + endif - if bUpdateLists + while bBusy + Debug.Notification("Found OnUpdate is busy") + Utility.wait(0.5) + endwhile + + bBusy = true + + iUpdateCount += 1 + Debug.Notification("Running Found OnUpdate " + iUpdateCount) - if Utility.IsInMenuMode() - RegisterForSingleUpdate(1.0) + if bRescanHome + if lastDestContainer && lastDestContainer as Actor && (lastDestContainer as Actor).IsPlayerTeammate() + lastDestContainer = None return endif - - bUpdateLists = false - bUpdateFollowers = false - - if bSyncStorage - bSyncStorage = false - ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) - ETR_Functions.SyncCellStorage(cellStorage, ETR_ExcludeFromCellItems) + bRescanHome = false + ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) + ETR_Functions.SyncCellStorage(cellStorage, ETR_ExcludeMisc) + if ! bRescanPersistent + ETR_Functions.AddArtifactsToList(cellStorage, ETR_ItemsStored) endif + endif - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 26, None, ETR_ExcludeFromCellItems) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 41, None, ETR_ExcludeFromCellItems) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 27, None, ETR_ExcludeFromCellItems) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 32, None, ETR_ExcludeFromCellItems) - - ETR_ItemsFound.Revert() - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) - - aFollowers = ETR_Functions.GetPlayerFollowers() - i = aFollowers.length - while i > 0 - i -= 1 - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) + if bRescanPersistent + bRescanPersistent = false + Form[] aContainers = ETR_PersistentStorageList.ToArray() + int n = aContainers.length + while n > 0 + n -= 1 + ETR_Functions.AddArtifactsToList(aContainers[n], ETR_ItemsStored, ETR_ExcludeMisc, true) endwhile - - ETR_ItemsNew.Revert() - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 26, None, ETR_ExcludeFromNew) ; armor - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 41, None, ETR_ExcludeFromNew) ; weapons - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 27, None, ETR_ExcludeFromNew) ; books - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 32, None, ETR_ExcludeFromNew) ; misc items - - return - endif - if bUpdateFollowers - bUpdateFollowers = false - - Debug.Notification("Team changed, updating lists") - - ETR_ItemsFound.Revert() - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) - - aFollowers = ETR_Functions.GetPlayerFollowers() - i = aFollowers.length - while i > 0 - i -= 1 - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) - endwhile + ETR_ItemsFound.Revert() + ETR_Functions.AddArtifactsToList(PlayerRef, ETR_ItemsFound, ETR_ExcludeFromNew) - ETR_ItemsNew.Revert() - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 26, None, ETR_ExcludeFromNew) ; armor - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 41, None, ETR_ExcludeFromNew) ; weapons - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 27, None, ETR_ExcludeFromNew) ; books - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 32, None, ETR_ExcludeFromNew) ; misc items + Actor[] aFollowers = ETR_Functions.GetPlayerFollowers() + int i = aFollowers.length + while i > 0 + i -= 1 + ETR_Functions.AddArtifactsToList(aFollowers[i], ETR_ItemsFound, ETR_ExcludeFromNew) + endwhile - endif + bBusy = false EndEvent @@ -139,9 +123,23 @@ EndEvent event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) if akDestContainer - bSyncStorage = bAtHome - bUpdateLists = true - RegisterForSingleUpdate(1.0) + if lastDestContainer != akDestContainer + lastDestContainer = akDestContainer + lastDestIsPersistent = ETR_PersistentStorageList.HasForm(akDestContainer) + endif + ; Moving items without latent functions should help with avoiding stack dumps + if lastDestIsPersistent + bRescanHome = false + bRescanPersistent = true + RegisterForSingleUpdate(0.5) + elseif bAtHome + bRescanHome = true + bRescanPersistent = false + RegisterForSingleUpdate(0.5) + elseif PlayerRef.GetItemCount(akBaseItem) == 0 && ETR_Functions.GetItemCountInActors(ETR_Functions.GetPlayerFollowers(), akBaseItem) == 0 + ETR_ItemsFound.RemoveAddedForm(akBaseItem) + ETR_ItemsNew.AddForm(akBaseItem) + endif elseif bAtHome && akItemReference ETR_ItemsFound.RemoveAddedForm(akBaseItem) ETR_ItemsStored.AddForm(akBaseItem) diff --git a/Source/Scripts/ETR_TrackNewItems.psc b/Source/Scripts/ETR_TrackNewItems.psc index 3e4a6a8..a9f7ae5 100644 --- a/Source/Scripts/ETR_TrackNewItems.psc +++ b/Source/Scripts/ETR_TrackNewItems.psc @@ -7,6 +7,8 @@ FormList Property ETR_ItemsFound Auto FormList Property ETR_ItemsStored Auto FormList Property ETR_ExcludeFromNew Auto FormList Property ETR_PersistentStorageList Auto +FormList Property ETR_ExcludeMisc Auto +FormList Property ETR_FoundAndStored Auto event OnInit() @@ -36,37 +38,32 @@ event OnPlayerLoadGame() ahzmorehudie.RegisterIconFormList("dbmDisp", ETR_ItemsStored) endif + If SKSE.GetPluginVersion("QuickLootRE") >= 292 + QuickLootRE.RegisterNewItemsList(ETR_ItemsNew) + QuickLootRE.RegisterDisplayedItemsList(ETR_ItemsStored) + QuickLootRE.RegisterFoundItemsList(ETR_ItemsFound) + endif + ; Rebuild all lists to avoid discrepancies, stale data, and broken records ETR_ItemsStored.Revert() - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 26, None, ETR_ExcludeFromNew) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 41, None, ETR_ExcludeFromNew) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 27, None, ETR_ExcludeFromNew) - ETR_Functions.AddItemsOfTypeAndKeywordToList(ETR_PersistentStorageList, ETR_ItemsStored, 32, None, ETR_ExcludeFromNew) + ETR_Functions.AddArtifactsToList(ETR_PersistentStorageList, ETR_ItemsStored, ETR_ExcludeMisc, true) ETR_ItemsFound.Revert() - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(PlayerRef, ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) + ETR_Functions.AddArtifactsToList(PlayerRef, ETR_ItemsFound, ETR_ExcludeFromNew) Actor[] aFollowers = ETR_Functions.GetPlayerFollowers() int i = aFollowers.length while i > 0 i -= 1 - if ! aFollowers[i].IsDead() && ! aFollowers[i].IsDisabled() - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 26, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 41, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 27, None, ETR_ExcludeFromNew, false, false, false) - ETR_Functions.AddItemsOfTypeAndKeywordToList(aFollowers[i], ETR_ItemsFound, 32, None, ETR_ExcludeFromNew, false, false, false) - endif + ETR_Functions.AddArtifactsToList(aFollowers[i], ETR_ItemsFound, ETR_ExcludeFromNew) endwhile ETR_ItemsNew.Revert() - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 26, None, ETR_ExcludeFromNew) ; armor - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 41, None, ETR_ExcludeFromNew) ; weapons - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 27, None, ETR_ExcludeFromNew) ; books - ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 32, None, ETR_ExcludeFromNew) ; misc items + ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 26, ETR_FoundAndStored) + ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 27, ETR_FoundAndStored) + ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 32, ETR_ExcludeFromNew) + ETR_Functions.AddAllFormsToList(ETR_ItemsNew, 41, ETR_FoundAndStored) endevent diff --git a/Source/Scripts/ETR_TrackStoredItems.psc b/Source/Scripts/ETR_TrackStoredItems.psc index cc0f79c..c090bb5 100644 --- a/Source/Scripts/ETR_TrackStoredItems.psc +++ b/Source/Scripts/ETR_TrackStoredItems.psc @@ -6,12 +6,22 @@ FormList Property ETR_ItemsNew Auto FormList Property ETR_ItemsFound Auto FormList Property ETR_ItemsStored Auto FormList Property ETR_PersistentStorageList Auto +FormList Property ETR_ExcludeFromNew Auto +FormList Property ETR_ExcludeMisc Auto Container Property ETR_CellStorageContainer Auto Keyword Property LocTypePlayerHouse Auto +bool bBusy = false bool bAtHome = false +bool bRescanHome = false +bool bRescanPersistent = false +ObjectReference lastDestContainer = None +bool lastDestIsPersistent = false +ObjectReference lastSourceContainer = None +bool lastSourceIsPersistent = false +int iUpdateCount event OnInit() @@ -21,69 +31,134 @@ endevent Event OnPlayerLoadGame() AddInventoryEventFilter(ETR_ItemsStored) + Location currentLocation = PlayerRef.GetCurrentLocation() + bAtHome = currentLocation && currentLocation.HasKeyword(LocTypePlayerHouse) + if bAtHome + GotoState("AtHome") + else + GotoState("") + endif EndEvent Event OnLocationChange(Location akOldLoc, Location akNewLoc) bAtHome = akNewLoc && akNewLoc.HasKeyword(LocTypePlayerHouse) + if bAtHome + GotoState("AtHome") + else + GotoState("") + endif endEvent -; The item is already registered as stored, and we just stored more -event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) +Event OnMenuClose(String MenuName) + UnregisterForUpdate() + OnUpdate() +EndEvent + + +Event OnUpdate() - if ! bAtHome + if UI.IsMenuOpen("ContainerMenu") + RegisterForMenu("ContainerMenu") return endif - if akDestContainer + while bBusy + Debug.Notification("Stored OnUpdate is busy") + Utility.wait(0.5) + endwhile - if !(akDestContainer as Actor) - if ETR_PersistentStorageList.HasForm(akDestContainer) - return - endif - elseif (akDestContainer as Actor).IsPlayerTeammate() + bBusy = true + + iUpdateCount += 1 + Debug.Notification("Running Stored OnUpdate " + iUpdateCount) + + if bRescanHome + if lastSourceContainer && lastSourceContainer as Actor && (lastSourceContainer as Actor).IsPlayerTeammate() + lastSourceContainer = None return endif - + ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) + ETR_Functions.SyncCellStorage(cellStorage, ETR_ExcludeMisc) endif - if ((akDestContainer && akDestContainer.GetParentCell() == PlayerRef.GetParentCell()) || (! akDestContainer && ETR_Functions.HasRefInCell(akBaseItem, None, true, ETR_PersistentStorageList))) + if bRescanPersistent - ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) + ETR_ItemsStored.Revert() + Form[] aContainers = ETR_PersistentStorageList.ToArray() + int n = aContainers.length + while n > 0 + n -= 1 + ETR_Functions.AddArtifactsToList(aContainers[n], ETR_ItemsStored, ETR_ExcludeMisc, true) + endwhile - if cellStorage.GetItemCount(akBaseItem) == 0 - cellStorage.AddItem(akBaseItem, 1, true) - endif + ETR_ItemsFound.Revert() + ETR_Functions.AddArtifactsToList(PlayerRef, ETR_ItemsFound, ETR_ExcludeFromNew) + + Actor[] aFollowers = ETR_Functions.GetPlayerFollowers() + int i = aFollowers.length + while i > 0 + i -= 1 + ETR_Functions.AddArtifactsToList(aFollowers[i], ETR_ItemsFound, ETR_ExcludeFromNew) + endwhile endif -endevent + bBusy = false + +EndEvent -; We took a stored item, and we want to find out if it's the last stored item of its kind +; We acquired a stored item, and we want to find out if we just have taken the last stored item of its kind event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) - if akSourceContainer && !(akSourceContainer as Actor) && ETR_PersistentStorageList.HasForm(akSourceContainer) - if ETR_Functions.GetItemCountInList(ETR_PersistentStorageList, akBaseItem) == 0 - ETR_ItemsStored.RemoveAddedForm(akBaseItem) - ETR_ItemsFound.AddForm(akBaseItem) + if akSourceContainer + if lastSourceContainer != akSourceContainer + lastSourceContainer = akSourceContainer + lastSourceIsPersistent = ETR_PersistentStorageList.HasForm(akSourceContainer) + endif + if bAtHome || lastSourceIsPersistent + bRescanHome = bAtHome + bRescanPersistent = true + RegisterForSingleUpdate(0.5) endif - elseif bAtHome ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) - int iCount = cellStorage.GetItemCount(akBaseItem) - - if iCount > 0 && ! ETR_Functions.HasRefInCell(akBaseItem, None, true, ETR_PersistentStorageList) - cellStorage.RemoveItem(akBaseItem, iCount, true) - + if cellStorage.GetItemCount(akBaseItem) + ETR_Functions.SyncCellStorage(cellStorage, ETR_ExcludeMisc) if ETR_Functions.GetItemCountInList(ETR_PersistentStorageList, akBaseItem) == 0 ETR_ItemsStored.RemoveAddedForm(akBaseItem) ETR_ItemsFound.AddForm(akBaseItem) endif - endif - endif endevent + + +state AtHome + + ; The item is already registered as stored, and we just stored more + event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) + + if akDestContainer + if lastDestContainer != akDestContainer + lastDestContainer = akDestContainer + lastDestIsPersistent = ETR_PersistentStorageList.HasForm(akDestContainer) + endif + if ! lastDestIsPersistent + bRescanHome = true + bRescanPersistent = false + RegisterForSingleUpdate(0.5) + endif + elseif akItemReference + ObjectReference cellStorage = ETR_Functions.GetCellStorage(PlayerRef, ETR_PersistentStorageList, ETR_CellStorageContainer) + if cellStorage.GetItemCount(akBaseItem) == 0 + cellStorage.AddItem(akBaseItem, 1, true) + endif + endif + + endevent + +endstate