1
Fork 0
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

#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);
}
}