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.
 
 
 

208 lines
5.2 KiB

#pragma once
#include <SimpleIni.h>
using namespace SKSE;
using namespace SKSE::log;
inline void ListRemoveItem(RE::BGSListForm* a_List, RE::TESForm* a_form)
{
using func_t = decltype(&ListRemoveItem);
REL::Relocation<func_t> func{ REL::RelocationID(20471, 20914) };
return func(a_List, a_form);
}
inline void ListRevert(RE::BGSListForm* a_form)
{
using func_t = decltype(&ListRevert);
REL::Relocation<func_t> func{ REL::RelocationID(20469, 20912) };
return func(a_form);
}
inline std::uint32_t GetItemCount(RE::TESObjectREFR* a_container, RE::TESForm* a_form)
{
std::int32_t iResult = 0;
auto invChanges = a_container->GetInventoryChanges();
if (invChanges && invChanges->entryList) {
for (auto& entry : *invChanges->entryList) {
if (entry && entry->object == a_form) {
if (entry->IsLeveled()) {
return entry->countDelta > 0 ? entry->countDelta : 0;
} else {
iResult = entry->countDelta;
break;
}
}
}
}
auto container = a_container->GetContainer();
if (container) {
container->ForEachContainerObject([&](RE::ContainerObject& a_entry) {
if (a_entry.obj == a_form) {
iResult += a_entry.count;
return false;
}
return true;
});
}
return iResult > 0 ? iResult : 0;
}
inline std::int32_t GetItemCount(RE::TESObjectREFR* a_container, RE::FormID a_formID)
{
std::int32_t iResult = 0;
auto invChanges = a_container->GetInventoryChanges();
if (invChanges && invChanges->entryList) {
for (auto& entry : *invChanges->entryList) {
if (entry && entry->object && entry->object->formID == a_formID) {
if (entry->IsLeveled()) {
return entry->countDelta > 0 ? entry->countDelta : 0;
} else {
iResult = entry->countDelta;
break;
}
}
}
}
auto container = a_container->GetContainer();
if (container) {
container->ForEachContainerObject([&](RE::ContainerObject& a_entry) {
if (a_entry.obj && a_entry.obj->formID == a_formID) {
iResult += a_entry.count;
return false;
}
return true;
});
}
return iResult > 0 ? iResult : 0;
}
inline bool RefListHasItem(RE::TESForm* a_refOrList, RE::FormID a_formID)
{
if (!a_refOrList || !a_formID) {
log::warn("Invalid arguments in RefListHasItem");
return false;
}
const auto refr = a_refOrList->As<RE::TESObjectREFR>();
if (refr) {
return GetItemCount(refr, a_formID) > 0;
}
const auto list = a_refOrList->As<RE::BGSListForm>();
if (list) {
bool bResult = false;
list->ForEachForm([&](RE::TESForm& a_form) {
if (&a_form && RefListHasItem(&a_form, a_formID)) {
bResult = true;
return false;
}
return true;
});
return bResult;
}
return false;
}
inline bool FollowersHaveItem(RE::TESForm* a_form)
{
if (const auto processLists = RE::ProcessLists::GetSingleton(); processLists) {
for (auto& actorHandle : processLists->highActorHandles) {
if (auto actor = actorHandle.get(); actor && actor->IsPlayerTeammate()) {
if (GetItemCount(actor->As<RE::TESObjectREFR>(), a_form) > 0) {
return true;
}
}
}
}
return false;
}
inline bool IsInSameCell(RE::TESObjectREFR* ref)
{
return ref && (ref->GetParentCell() == RE::PlayerCharacter::GetSingleton()->GetParentCell());
}
inline void LoadINI(std::map<std::string, bool>* settings, const char* iniPath)
{
for (auto it = settings->begin(); it != settings->end(); it++) {
log::info("[DEFAULT] {} = {}", it->first, it->second);
}
if (!std::filesystem::exists(iniPath)) {
log::warn("{} does not exist, using default values.", iniPath);
return;
}
try {
CSimpleIniA ini;
ini.SetUnicode(false);
ini.SetMultiKey(false);
ini.LoadFile(iniPath);
std::list<CSimpleIniA::Entry> keysList;
ini.GetAllKeys("", keysList);
bool bUpdateINI = false;
for (auto it = settings->begin(); it != settings->end(); it++) {
bool bExists = false;
for (const auto& k : keysList) {
if (it->first == k.pItem) {
settings->insert_or_assign(k.pItem, ini.GetBoolValue("", k.pItem, settings->at(k.pItem)));
log::info("[INI] {} = {}", k.pItem, settings->at(k.pItem));
bExists = true;
break;
}
}
if (!bExists) {
ini.SetBoolValue("", it->first.c_str(), it->second);
bUpdateINI = true;
}
}
if (bUpdateINI) {
log::info("New settings detected, adding to ArtifactTracker.ini");
ini.SaveFile(iniPath);
}
} catch (const std::exception& e) {
log::error(e.what());
}
}
inline void RunBenchmark(std::function<void()> benchmark, std::string desc)
{
const auto start = std::chrono::high_resolution_clock::now();
benchmark();
const auto end = std::chrono::high_resolution_clock::now();
const auto elapsed = std::chrono::duration<double>(end - start);
log::info("{}: Elapsed time: {} seconds", desc, elapsed.count());
}
inline std::vector<RE::Actor*> GetPlayerFollowers()
{
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;
}