1

Added the exclusion keyword ETR_NotArtifact, improved artifact filtering

This commit is contained in:
Eddoursul 2022-07-05 17:52:30 +02:00
parent 0c22f0b8bd
commit 81b174e028
11 changed files with 78 additions and 91 deletions

Binary file not shown.

View File

@ -3,3 +3,6 @@ Keyword = ETR_ExtraArtifact|Misc Item|0x1F6D4,0x200B6,0x200BA,0x20949,0x59654,0x
; Treasure Maps
Keyword = ETR_ExtraArtifact|Book|0xEF07A,0xF33CD,0xF33CE,0xF33CF,0xF33D0,0xF33D1,0xF33D2,0xF33D3,0xF33D4,0xF33D5,0xF33E0
; Soul Gem Fragments
Keyword = ETR_NotArtifact|Misc Item|0x67181,0x67182,0x67183,0x67184,0x67185

Binary file not shown.

Binary file not shown.

View File

@ -60,7 +60,7 @@ DisableFormat: 'false'
FixNamespaceComments: 'false'
IncludeBlocks: Preserve
IndentCaseBlocks: 'true'
IndentCaseLabels: 'false'
IndentCaseLabels: 'true'
IndentExternBlock: Indent
IndentGotoLabels: 'false'
IndentPPDirectives: AfterHash

View File

@ -18,15 +18,18 @@ namespace ArtifactTracker
std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
RE::TESObjectREFR* g_cellStorage;
void Init()
bool Init()
{
g_bLoaded = false;
if (g_bLoaded) {
return true;
}
const auto dataHandler = RE::TESDataHandler::GetSingleton();
if (!dataHandler) {
SKSE::log::error("Failed to call RE::TESDataHandler::GetSingleton()");
return;
SKSE::log::error("Unable to call RE::TESDataHandler::GetSingleton()");
RE::DebugMessageBox("Unable to initialize Artifact Tracker.");
return false;
}
g_cellContainer = dataHandler->LookupForm(0x800, "Artifact Tracker.esp")->As<RE::TESBoundObject>(); // ETR_CellStorageContainer
@ -40,47 +43,74 @@ namespace ArtifactTracker
const auto recipeKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xF5CB0, "Skyrim.esm"); // VendorItemRecipe
const auto excludeKeywords = dataHandler->LookupForm<RE::BGSListForm>(0x801, "Artifact Tracker.esp"); // ETR_ExcludeMiscKeywords
const auto dummyKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xF3E6C, "Skyrim.esm"); // Dummy
const auto extraArtifactKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xDE3FD3, "Update.esm"); // ETR_ExtraArtifact
const auto notArtifactKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xDE3FD4, "Update.esm"); // ETR_NotArtifact
if (!g_cellContainer || !g_listNew || !g_listStored || !g_listFound || !g_persistentStorage || !g_homeKeyword || !recipeKeyword || !excludeKeywords) {
SKSE::log::warn("Failed to load data from Artifact Tracker.esp");
RE::DebugMessageBox("Failed to load data from Artifact Tracker.esp, the mod is disabled.");
return;
if (!g_cellContainer || !g_listNew || !g_listStored || !g_listFound || !g_persistentStorage || !g_homeKeyword || !recipeKeyword || !excludeKeywords || !dummyKeyword || !extraArtifactKeyword || !notArtifactKeyword) {
SKSE::log::warn("Unable to load data from Artifact Tracker.esp");
RE::DebugMessageBox("Unable to load data from Artifact Tracker.esp, the mod is disabled.");
return false;
}
// Preloading item lists
g_artifactFormTypes.insert(RE::FormType::Weapon);
for (const auto& form : dataHandler->GetFormArray(RE::FormType::Weapon)) {
if (form->GetPlayable()) {
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectWEAP>()) {
if (form->GetPlayable() && !form->IsBound() && !form->weaponData.flags.all(RE::TESObjectWEAP::Data::Flag::kCantDrop) && !form->IsDeleted() && !form->HasKeyword(dummyKeyword) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
g_artifactMap.erase(0x1F4); // Unarmed
g_artifactFormTypes.insert(RE::FormType::Armor);
for (const auto& form : dataHandler->GetFormArray(RE::FormType::Armor)) {
if (form->GetPlayable()) {
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectARMO>()) {
if (form->GetPlayable() && !form->IsDeleted() && !form->HasKeyword(dummyKeyword) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
g_artifactMap.erase(0xD64); // SkinNaked
g_artifactMap.erase(0x69CE3); // SkinNakedBeast
g_artifactMap.erase(0xCDD86); // SkinNakedWerewolfBeast
g_artifactFormTypes.insert(RE::FormType::Book);
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectBOOK>()) {
if (form && !form->TeachesSpell() && (form->HasKeyword(recipeKeyword) || BookCheck::IsBook(form))) {
if (!form->TeachesSpell() && !form->IsDeleted() && (form->HasKeyword(recipeKeyword) || form->HasKeyword(extraArtifactKeyword) || BookCheck::IsBook(form)) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
g_artifactFormTypes.insert(RE::FormType::Misc);
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectMISC>()) {
if (form->GetPlayable() && !form->HasKeywordInList(excludeKeywords, false)) {
if (form->GetPlayable() && !form->IsDeleted() && (form->HasKeyword(extraArtifactKeyword) || !form->HasKeywordInList(excludeKeywords, false)) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
g_artifactMap.erase(0xA); // Lockpick
g_artifactMap.erase(0xF); // Gold
// Fishing CC
for (const auto& form : dataHandler->GetFormArray<RE::AlchemyItem>()) {
if (!form->IsDeleted() && form->HasKeyword(extraArtifactKeyword) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::AlchemyItem);
}
}
for (const auto& form : dataHandler->GetFormArray<RE::IngredientItem>()) {
if (!form->IsDeleted() && form->HasKeyword(extraArtifactKeyword) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::Ingredient);
}
}
for (const auto& form : dataHandler->GetFormArray<RE::TESSoulGem>()) {
if (!form->IsDeleted() && form->HasKeyword(extraArtifactKeyword) && !form->HasKeyword(notArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::SoulGem);
}
}
// Fishing CC (remove, when KID adds formlist support)
const auto plaqueFish = dataHandler->LookupForm<RE::BGSListForm>(0xF4B, "ccBGSSSE001-Fish.esm"); // ccBGSSSE001_FishPlaqueGiftFilterList
if (plaqueFish) {
plaqueFish->ForEachForm([&](RE::TESForm& a_form) {
@ -93,58 +123,15 @@ namespace ArtifactTracker
EventListener::Install();
g_bLoaded = true;
return true;
}
void OnKeywordDistribution()
{
const auto dataHandler = RE::TESDataHandler::GetSingleton();
const auto extraArtifactKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xDE3FD3, "Update.esm"); // ETR_ExtraArtifact
if (!dataHandler || !extraArtifactKeyword) {
SKSE::log::error("Unable to load ETR_ExtraArtifact in OnKeywordDistribution");
return;
}
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectBOOK>()) {
if (form->HasKeyword(extraArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectMISC>()) {
if (form->GetPlayable() && form->HasKeyword(extraArtifactKeyword)) {
g_artifactMap[form->formID] = form;
}
}
for (const auto& form : dataHandler->GetFormArray<RE::AlchemyItem>()) {
if (form->HasKeyword(extraArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::AlchemyItem);
}
}
for (const auto& form : dataHandler->GetFormArray<RE::IngredientItem>()) {
if (form->HasKeyword(extraArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::Ingredient);
}
}
for (const auto& form : dataHandler->GetFormArray<RE::TESSoulGem>()) {
if (form->HasKeyword(extraArtifactKeyword)) {
g_artifactMap[form->formID] = form;
g_artifactFormTypes.insert(RE::FormType::SoulGem);
}
}
}
bool IsArtifact(RE::TESForm* a_form)
bool IsArtifact(const RE::TESForm* a_form)
{
return a_form && g_artifactFormTypes.contains(a_form->GetFormType()) && g_artifactMap.contains(a_form->formID);
}
RE::TESForm* GetArtifactByID(RE::FormID a_formID)
RE::TESForm* GetArtifactByID(const RE::FormID a_formID)
{
if (!a_formID) {
return nullptr;
@ -169,7 +156,7 @@ namespace ArtifactTracker
});
}
void SetContainerMode(bool bOpening)
void SetContainerMode(const bool bOpening)
{
if (bOpening) {
@ -229,7 +216,7 @@ namespace ArtifactTracker
return baseObj->formType == RE::FormType::Container || (baseObj->formType == RE::FormType::NPC && !a_ref->IsDisabled() && baseObj->As<RE::TESNPC>()->GetRace()->formID == 0x0010760A);
}
void OnCellEnter(RE::FormID a_formID)
void OnCellEnter(const RE::FormID a_formID)
{
RE::TESObjectCELL* cell = RE::TESForm::LookupByID<RE::TESObjectCELL>(a_formID);
RE::BGSLocation* location = cell ? cell->GetLocation() : nullptr;
@ -260,7 +247,7 @@ namespace ArtifactTracker
}
}
void OnCellEnter(RE::BGSLocation* location, RE::TESObjectCELL* cell)
void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell)
{
if (!location || !cell->IsInteriorCell() || cell != RE::PlayerCharacter::GetSingleton()->GetParentCell() || !location->HasKeyword(g_homeKeyword)) {
ToggleHomeMode(nullptr);
@ -303,7 +290,7 @@ namespace ArtifactTracker
}
}
void SyncCellStorage(RE::FormID a_ignoreRef)
void SyncCellStorage(const RE::TESObjectREFR* a_ignoreRef)
{
if (!IsHome()) {
#ifdef _DEBUG
@ -322,7 +309,7 @@ namespace ArtifactTracker
const auto inv = g_cellStorage->GetInventory();
for (const auto& a_ref : cell->references) {
if (a_ignoreRef == a_ref->formID) {
if (a_ignoreRef && a_ignoreRef->formID == a_ref->formID) {
continue;
}
@ -428,7 +415,7 @@ namespace ArtifactTracker
if (!g_bHomeContainer) {
const auto container = RE::TESForm::LookupByID<RE::TESObjectREFR>(a_event->oldContainer);
if (container && !GetItemCount(container, form)) {
SyncCellStorage(container->formID);
SyncCellStorage(container);
}
}
@ -575,7 +562,7 @@ namespace ArtifactTracker
if (g_cellStorage && IsInSameCell(container)) { // deleted from container at home
if (!GetItemCount(container, form)) {
SyncCellStorage(container->formID);
SyncCellStorage(container);
}
}

View File

@ -15,25 +15,23 @@ namespace ArtifactTracker
extern std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
extern RE::TESObjectREFR* g_cellStorage;
void Init();
bool Init();
void OnKeywordDistribution();
bool IsArtifact(const RE::TESForm* a_item);
bool IsArtifact(RE::TESForm* a_item);
RE::TESForm* GetArtifactByID(RE::FormID a_formID);
RE::TESForm* GetArtifactByID(const RE::FormID a_formID);
bool IsHome();
void OnGameLoad();
void SetContainerMode(bool bOpening);
void SetContainerMode(const bool bOpening);
void OnCellEnter(RE::FormID a_formID);
void OnCellEnter(const RE::FormID a_formID);
void OnCellEnter(RE::BGSLocation* location, RE::TESObjectCELL* cell);
void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell);
void SyncCellStorage(RE::FormID a_ignoreRef = NULL);
void SyncCellStorage(const RE::TESObjectREFR* a_ignoreRef = nullptr);
void OnContainerChanged(const RE::TESContainerChangedEvent* a_event, RE::TESForm* form);

View File

@ -20,7 +20,7 @@ auto EventListener::ProcessEvent(
{
if (a_event->eventName == "KID_KeywordDistributionDone") {
SKSE::GetModCallbackEventSource()->RemoveEventSink(EventListener::GetSingleton());
ArtifactTracker::OnKeywordDistribution();
ArtifactTracker::Init();
}
return RE::BSEventNotifyControl::kContinue;

View File

@ -29,14 +29,13 @@ namespace {
void InitializeMessaging()
{
GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) {
if (message->type == MessagingInterface::kPostPostLoad) {
if (message->type == MessagingInterface::kPostLoad) {
SKSE::GetModCallbackEventSource()->AddEventSink(EventListener::GetSingleton());
} else if (message->type == MessagingInterface::kDataLoaded) {
ArtifactTracker::Init();
} else if (message->type == MessagingInterface::kPostLoadGame) {
} else if (message->type == MessagingInterface::kNewGame || message->type == MessagingInterface::kPreLoadGame) {
SKSE::GetModCallbackEventSource()->RemoveEventSink(EventListener::GetSingleton());
ArtifactTracker::OnGameLoad();
ArtifactTracker::Init(); // if KID is not installed
} else if (message->type == MessagingInterface::kPostLoadGame) {
ArtifactTracker::OnGameLoad(); // refresh g_persistentMap from savegame
}
});
}

View File

@ -5,9 +5,9 @@
namespace Papyrus::PapyrusFunctions
{
constexpr bool IsLoaded(RE::StaticFunctionTag*)
inline bool Load(RE::StaticFunctionTag*)
{
return ArtifactTracker::g_bLoaded;
return ArtifactTracker::Init();
}
inline RE::TESObjectREFR* GetCellStorage(RE::StaticFunctionTag*)
@ -75,8 +75,8 @@ namespace Papyrus::PapyrusFunctions
inline void Bind(VM& a_vm)
{
BIND(IsLoaded);
logger::info("Registered IsLoaded"sv);
BIND(Load);
logger::info("Registered Load"sv);
BIND(GetArtifactCount);
logger::info("Registered GetArtifactCount"sv);
BIND(RescanStoredArtifacts);

View File

@ -22,7 +22,7 @@ endevent
Event OnPlayerLoadGame()
if ! IsLoaded()
if ! Load()
ETR_ItemsNew.Revert()
ETR_ItemsFound.Revert()
ETR_ItemsStored.Revert()
@ -166,7 +166,7 @@ endstate
; NATIVE FUNCTIONS
bool function IsLoaded() native global
bool function Load() native global
int function GetArtifactCount() native global