#pragma once 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) { if (!a_containerList || !a_form) { return 0; } std::uint32_t iResult = 0; a_containerList->ForEachForm([&](RE::TESForm& a_container) { const auto refrItem = a_container.As(); if (refrItem) { const auto inv = refrItem->GetInventory([&](RE::TESBoundObject& a_object) -> bool { return a_form->formID == a_object.formID; }); const auto it = inv.find(a_form); iResult += it != inv.end() ? it->second.first : 0; } return true; }); return iResult; } inline std::uint32_t GetItemCountInActors(RE::StaticFunctionTag*, std::vector a_refArray, // accepts ObjectReference[] and Actor[] RE::TESBoundObject* a_form) { if (a_refArray.size() <= 0 || !a_form) { return 0; } std::uint32_t iResult = 0; for (RE::Actor* actorItem : a_refArray) { if (actorItem) { const auto inv = actorItem->GetInventory([&](RE::TESBoundObject& a_object) -> bool { return a_form->formID == a_object.formID; }); const auto it = inv.find(a_form); iResult += it != inv.end() ? it->second.first : 0; } } return iResult; } // From po3's Papyrus Extender inline std::vector GetPlayerFollowers(RE::StaticFunctionTag*) { std::vector result; if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) { for (auto& actorHandle : processLists->highActorHandles) { if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate()) { result.push_back(actor.get()); } } } return result; } 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); logger::info("Registered GetItemCountInActors"sv); BIND(GetPlayerFollowers); logger::info("Registered GetPlayerFollowers"sv); } }