You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
7.7 KiB
270 lines
7.7 KiB
#pragma once
|
|
|
|
namespace Papyrus::ObjectReference
|
|
{
|
|
namespace inv_util
|
|
{
|
|
inline bool can_be_taken(const std::unique_ptr<RE::InventoryEntryData>& 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<RE::BGSListForm>();
|
|
|
|
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<RE::BGSListForm>();
|
|
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<RE::BGSKeyword>();
|
|
if (exkeyword && a_form->As<RE::BGSKeywordForm>()->HasKeyword(exkeyword)) {
|
|
isExcluded = true;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
|
|
return isExcluded;
|
|
}
|
|
}
|
|
|
|
const RE::BGSKeyword* keyword = a_excludeForm->As<RE::BGSKeyword>();
|
|
|
|
if (keyword) {
|
|
if (a_form->As<RE::BGSKeywordForm>()->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<RE::Actor>() && atargetRef->As<RE::Actor>()->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<RE::FormType>(a_formType);
|
|
|
|
const auto keyword = a_keywordOrList ? a_keywordOrList->As<RE::BGSKeyword>() : nullptr;
|
|
const auto keywordList = a_keywordOrList ? a_keywordOrList->As<RE::BGSListForm>() : 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<RE::BGSKeywordForm>()->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<RE::BGSListForm>()->ForEachForm([&](RE::TESForm& a_exform) {
|
|
const auto refrItem = a_exform.As<RE::TESObjectREFR>();
|
|
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<RE::TESObjectREFR>();
|
|
|
|
if (!containerRef) {
|
|
a_vm->TraceStack("containerRef in AddItemsOfTypeAndKeywordToList is not a reference", a_stackID);
|
|
return 0;
|
|
}
|
|
|
|
const auto formType = static_cast<RE::FormType>(a_formType);
|
|
const bool bNoType = formType == RE::FormType::None;
|
|
|
|
const auto keyword = a_keywordOrList ? a_keywordOrList->As<RE::BGSKeyword>() : nullptr;
|
|
const auto keywordList = a_keywordOrList ? a_keywordOrList->As<RE::BGSListForm>() : nullptr;
|
|
|
|
auto inv = containerRef->GetInventory([&](RE::TESBoundObject& a_exform) {
|
|
return (bNoType || a_exform.formType == formType)
|
|
&& (
|
|
(!keyword && !keywordList)
|
|
|| (keyword && a_exform.As<RE::BGSKeywordForm>()->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<RE::TESObjectREFR>();
|
|
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<RE::Actor*> 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<RE::Actor*> GetPlayerFollowers(RE::StaticFunctionTag*)
|
|
{
|
|
std::vector<RE::Actor*> 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);
|
|
}
|
|
}
|
|
|