diff --git a/SPID/include/DistributePCLevelMult.h b/SPID/include/DistributePCLevelMult.h index 74f9087..d8f7eea 100644 --- a/SPID/include/DistributePCLevelMult.h +++ b/SPID/include/DistributePCLevelMult.h @@ -1,9 +1,6 @@ #pragma once -namespace Distribute +namespace Distribute::PlayerLeveledActor { - namespace PlayerLeveledActor - { - void Install(); - } + void Install(); } diff --git a/SPID/include/LookupFilters.h b/SPID/include/LookupFilters.h index 9f5e1f4..59bd298 100644 --- a/SPID/include/LookupFilters.h +++ b/SPID/include/LookupFilters.h @@ -15,5 +15,5 @@ namespace Filter bool forms(RE::TESNPC& a_actorbase, const FormFilters& a_formFilters); - SECONDARY_RESULT secondary(const RE::TESNPC& a_actorbase, const LevelFilters& a_levelFilters, const Traits& a_traits, float chance, bool a_noPlayerLevelDistribution); + SECONDARY_RESULT secondary(const RE::TESNPC& a_actorbase, const LevelFilters& a_levelFilters, const Traits& a_traits, float a_chance, bool a_noPlayerLevelDistribution); } diff --git a/SPID/include/LookupForms.h b/SPID/include/LookupForms.h index 031c812..e17e229 100644 --- a/SPID/include/LookupForms.h +++ b/SPID/include/LookupForms.h @@ -45,7 +45,7 @@ namespace Lookup a_formID.emplace(mergedFormID); } const std::string mergedModString{ mergedModName }; - if (!(a_modName.value_or("").empty()) && !mergedModString.empty() && a_modName.value_or("") != mergedModString) { + if (!a_modName.value_or("").empty() && !mergedModString.empty() && a_modName.value_or("") != mergedModString) { if (conversion_log.empty()) { conversion_log = std::format("{}->{}", a_modName.value_or(""), mergedModString); } else { diff --git a/SPID/include/PCLevelMultManager.h b/SPID/include/PCLevelMultManager.h index b24fbcf..94a9e19 100644 --- a/SPID/include/PCLevelMultManager.h +++ b/SPID/include/PCLevelMultManager.h @@ -66,20 +66,20 @@ namespace PCLevelMult kHit }; - struct Entries - { - std::map> rejectedEntries{}; // Distributed formID, FormData vector index - std::set> distributedEntries{}; // Distributed formID, distributed count/idx - }; - struct Data { - LEVEL_CAP_STATE levelCapState{}; + struct Entries + { + std::unordered_map> rejectedEntries{}; // Distributed formID, FormData vector index + std::set> distributedEntries{}; // Distributed formID, distributed count/idx + }; + + LEVEL_CAP_STATE levelCapState{}; std::map entries{}; // Actor Level, Entries }; - std::map> // NPC formID, Data + std::unordered_map> // NPC formID, Data cache{}; std::uint64_t currentPlayerID{ 0 }; diff --git a/SPID/src/Cache.cpp b/SPID/src/Cache.cpp index ecae1f5..7b513a1 100644 --- a/SPID/src/Cache.cpp +++ b/SPID/src/Cache.cpp @@ -8,7 +8,7 @@ namespace Cache if (function) { return function(a_formID); } - return std::string(); + return {}; } bool FormType::GetWhitelisted(const RE::FormType a_type) diff --git a/SPID/src/DistributePCLevelMult.cpp b/SPID/src/DistributePCLevelMult.cpp index a12da84..18720aa 100644 --- a/SPID/src/DistributePCLevelMult.cpp +++ b/SPID/src/DistributePCLevelMult.cpp @@ -2,145 +2,142 @@ #include "Distribute.h" #include "PCLevelMultManager.h" -namespace Distribute +namespace Distribute::PlayerLeveledActor { - namespace PlayerLeveledActor - { - struct HandleUpdatePlayerLevel - { - static void thunk(RE::Actor* a_actor) - { - if (const auto npc = a_actor->GetActorBase(); npc && npc->HasPCLevelMult()) { - const auto input = npc->IsDynamicForm() ? PCLevelMult::Input{ a_actor, npc, true, false } : // use character formID for permanent storage - PCLevelMult::Input{ npc, true, false }; - Distribute(npc, input); - } + struct HandleUpdatePlayerLevel + { + static void thunk(RE::Actor* a_actor) + { + if (const auto npc = a_actor->GetActorBase(); npc && npc->HasPCLevelMult()) { + const auto input = npc->IsDynamicForm() ? PCLevelMult::Input{ a_actor, npc, true, false } : // use character formID for permanent storage + PCLevelMult::Input{ npc, true, false }; + Distribute(npc, input); + } - func(a_actor); - } - static inline REL::Relocation func; - }; + func(a_actor); + } + static inline REL::Relocation func; + }; - struct LoadGame - { - static void thunk(RE::Character* a_this, std::uintptr_t a_buf) - { - if (const auto actorbase = a_this->GetActorBase(); actorbase && actorbase->HasPCLevelMult()) { - const auto input = actorbase->IsDynamicForm() ? PCLevelMult::Input{ a_this, actorbase, true, false } : // use character formID for permanent storage - PCLevelMult::Input{ actorbase, true, false }; + struct LoadGame + { + static void thunk(RE::Character* a_this, std::uintptr_t a_buf) + { + if (const auto actorbase = a_this->GetActorBase(); actorbase && actorbase->HasPCLevelMult()) { + const auto input = actorbase->IsDynamicForm() ? PCLevelMult::Input{ a_this, actorbase, true, false } : // use character formID for permanent storage + PCLevelMult::Input{ actorbase, true, false }; - if (const auto pcLevelMultManager = PCLevelMult::Manager::GetSingleton(); !pcLevelMultManager->FindDistributedEntry(input)) { - //start distribution for first time - Distribute(actorbase, input); - } else { - //handle redistribution and removal - pcLevelMultManager->ForEachDistributedEntry(input, [&](RE::TESForm& a_form, [[maybe_unused]] IdxOrCount a_count, bool a_isBelowLevel) { - switch (a_form.GetFormType()) { - case RE::FormType::Keyword: - { - auto keyword = a_form.As(); - if (a_isBelowLevel) { - actorbase->RemoveKeyword(keyword); - } else { - actorbase->AddKeyword(keyword); - } - } - break; - case RE::FormType::Faction: - { - auto faction = a_form.As(); - auto it = std::ranges::find_if(actorbase->factions, [&](const auto& factionRank) { - return factionRank.faction == faction; - }); - if (it != actorbase->factions.end()) { - if (a_isBelowLevel) { - (*it).rank = -1; - } else { - (*it).rank = 1; - } - } - } - break; - case RE::FormType::Perk: - { - auto perk = a_form.As(); - if (a_isBelowLevel) { - actorbase->RemovePerk(perk); - } else { - actorbase->AddPerk(perk, 1); - } - } - break; - case RE::FormType::Spell: - { - auto spell = a_form.As(); - if (auto actorEffects = actorbase->GetSpellList()) { - if (a_isBelowLevel) { - actorEffects->RemoveSpell(spell); - } else if (!actorEffects->GetIndex(spell)) { - actorEffects->AddSpell(spell); - } - } - } - break; - case RE::FormType::LeveledSpell: - { - auto spell = a_form.As(); - if (auto actorEffects = actorbase->GetSpellList()) { - if (a_isBelowLevel) { - actorEffects->RemoveLevSpell(spell); - } else { - actorEffects->AddLevSpell(spell); - } - } - } - break; - case RE::FormType::Shout: - { - auto shout = a_form.As(); - if (auto actorEffects = actorbase->GetSpellList()) { - if (a_isBelowLevel) { - actorEffects->RemoveShout(shout); - } else { - actorEffects->AddShout(shout); - } - } - } - break; - default: - { - if (a_form.IsInventoryObject()) { - auto boundObject = static_cast(&a_form); - if (a_isBelowLevel) { - actorbase->RemoveObjectFromContainer(boundObject, a_count); - } else if (actorbase->CountObjectsInContainer(boundObject) < a_count) { - actorbase->AddObjectToContainer(boundObject, a_count, a_this); - } - } - } - break; - } - }); - } - } + if (const auto pcLevelMultManager = PCLevelMult::Manager::GetSingleton(); !pcLevelMultManager->FindDistributedEntry(input)) { + //start distribution for first time + Distribute(actorbase, input); + } else { + //handle redistribution and removal + pcLevelMultManager->ForEachDistributedEntry(input, [&](RE::TESForm& a_form, [[maybe_unused]] IdxOrCount a_count, bool a_isBelowLevel) { + switch (a_form.GetFormType()) { + case RE::FormType::Keyword: + { + auto keyword = a_form.As(); + if (a_isBelowLevel) { + actorbase->RemoveKeyword(keyword); + } else { + actorbase->AddKeyword(keyword); + } + } + break; + case RE::FormType::Faction: + { + auto faction = a_form.As(); + auto it = std::ranges::find_if(actorbase->factions, [&](const auto& factionRank) { + return factionRank.faction == faction; + }); + if (it != actorbase->factions.end()) { + if (a_isBelowLevel) { + (*it).rank = -1; + } else { + (*it).rank = 1; + } + } + } + break; + case RE::FormType::Perk: + { + auto perk = a_form.As(); + if (a_isBelowLevel) { + actorbase->RemovePerk(perk); + } else { + actorbase->AddPerk(perk, 1); + } + } + break; + case RE::FormType::Spell: + { + auto spell = a_form.As(); + if (auto actorEffects = actorbase->GetSpellList()) { + if (a_isBelowLevel) { + actorEffects->RemoveSpell(spell); + } else if (!actorEffects->GetIndex(spell)) { + actorEffects->AddSpell(spell); + } + } + } + break; + case RE::FormType::LeveledSpell: + { + auto spell = a_form.As(); + if (auto actorEffects = actorbase->GetSpellList()) { + if (a_isBelowLevel) { + actorEffects->RemoveLevSpell(spell); + } else { + actorEffects->AddLevSpell(spell); + } + } + } + break; + case RE::FormType::Shout: + { + auto shout = a_form.As(); + if (auto actorEffects = actorbase->GetSpellList()) { + if (a_isBelowLevel) { + actorEffects->RemoveShout(shout); + } else { + actorEffects->AddShout(shout); + } + } + } + break; + default: + { + if (a_form.IsInventoryObject()) { + auto boundObject = static_cast(&a_form); + if (a_isBelowLevel) { + actorbase->RemoveObjectFromContainer(boundObject, a_count); + } else if (actorbase->CountObjectsInContainer(boundObject) < a_count) { + actorbase->AddObjectToContainer(boundObject, a_count, a_this); + } + } + } + break; + } + }); + } + } - func(a_this, a_buf); - } - static inline REL::Relocation func; + func(a_this, a_buf); + } + static inline REL::Relocation func; - static inline size_t index{ 0 }; - static inline size_t size{ 0xF }; - }; + static inline size_t index{ 0 }; + static inline size_t size{ 0xF }; + }; - void Install() - { - // ProcessLists::HandleUpdate - // inlined into SetLevel in AE - REL::Relocation target{ RELOCATION_ID(40575, 41567), OFFSET(0x86, 0x137) }; - stl::write_thunk_call(target.address()); + void Install() + { + // ProcessLists::HandleUpdate + // inlined into SetLevel in AE + REL::Relocation target{ RELOCATION_ID(40575, 41567), OFFSET(0x86, 0x137) }; + stl::write_thunk_call(target.address()); - stl::write_vfunc(); - logger::info(" Hooked npc load save"); - } - } + stl::write_vfunc(); + logger::info(" Hooked npc load save"); + } } diff --git a/SPID/src/KeywordDependencies.cpp b/SPID/src/KeywordDependencies.cpp index f06f0e5..79108a9 100644 --- a/SPID/src/KeywordDependencies.cpp +++ b/SPID/src/KeywordDependencies.cpp @@ -158,9 +158,9 @@ void Dependencies::ResolveKeywords() addDependencies(strings_NOT, findKeyword); addDependencies(strings_MATCH, findKeyword); addDependencies(strings_ANY, [&](const std::string& name) -> RE::BGSKeyword* { - for (const auto& iter : allKeywords) { - if (string::icontains(iter.first, name)) { - return iter.second; + for (const auto& [keywordName, keyword] : allKeywords) { + if (string::icontains(keywordName, name)) { + return keyword; } } return nullptr; diff --git a/SPID/src/PCLevelMultManager.cpp b/SPID/src/PCLevelMultManager.cpp index 1ec52dd..1828037 100644 --- a/SPID/src/PCLevelMultManager.cpp +++ b/SPID/src/PCLevelMultManager.cpp @@ -170,7 +170,8 @@ namespace PCLevelMult } } - void Manager::DeleteNPC(RE::FormID a_characterID) + // For spawned actors with FF reference IDs + void Manager::DeleteNPC(RE::FormID a_characterID) { auto& currentCache = cache[GetSingleton()->GetCurrentPlayerID()]; if (const auto it = currentCache.find(a_characterID); it != currentCache.end()) {