diff --git a/SPID/include/Distribute.h b/SPID/include/Distribute.h index ad26751..a9b0751 100644 --- a/SPID/include/Distribute.h +++ b/SPID/include/Distribute.h @@ -262,7 +262,5 @@ namespace Distribute } void Distribute(NPCData& a_npcData, const PCLevelMult::Input& a_input); - void DistributeItems(NPCData& a_npcData, const PCLevelMult::Input& a_input); - - void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries, bool a_noItems = false); + void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries); } diff --git a/SPID/include/DistributeManager.h b/SPID/include/DistributeManager.h index 595e1f0..83cd48f 100644 --- a/SPID/include/DistributeManager.h +++ b/SPID/include/DistributeManager.h @@ -3,7 +3,7 @@ namespace Distribute { inline RE::BGSKeyword* processed{ nullptr }; - inline RE::BGSKeyword* processedOnLoad{ nullptr }; + inline RE::BGSKeyword* processedOutfit{ nullptr }; namespace detail { diff --git a/SPID/src/Distribute.cpp b/SPID/src/Distribute.cpp index c0ce8fc..9a217b6 100644 --- a/SPID/src/Distribute.cpp +++ b/SPID/src/Distribute.cpp @@ -106,16 +106,9 @@ namespace Distribute return false; }); - for_each_form(a_npcData, Forms::skins, a_input, [&](auto* a_skin) { - if (npc->skin != a_skin) { - npc->skin = a_skin; - return true; - } - return false; - }); - for_each_form(a_npcData, Forms::outfits, a_input, [&](auto* a_outfit) { - if (npc->defaultOutfit != a_outfit) { + if (npc->defaultOutfit != a_outfit && !npc->HasKeyword(processedOutfit)) { + npc->AddKeyword(processedOutfit); npc->defaultOutfit = a_outfit; return true; } @@ -129,63 +122,23 @@ namespace Distribute } return false; }); - } - - void DistributeItems(NPCData& a_npcData, const PCLevelMult::Input& a_input) - { - if (a_input.onlyPlayerLevelEntries && PCLevelMult::Manager::GetSingleton()->HasHitLevelCap(a_input)) { - return; - } - - const auto npc = a_npcData.GetNPC(); - const auto actor = a_npcData.GetActor(); - auto inv_before = actor->GetInventory([](auto& item) { - return item.Is(RE::FormType::Weapon, RE::FormType::Armor); + for_each_form(a_npcData, Forms::items, a_input, [&](std::map& a_objects, const bool a_hasLvlItem) { + return npc->AddObjectsToContainer(a_objects, npc); }); - bool recalcInventory = false; - bool startsDead = actor->IsDead() || (actor->formFlags & RE::Actor::RecordFlags::kStartsDead) != 0; - - for_each_form(a_npcData, Forms::items, a_input, [&](std::map& a_objects, const bool a_hasLvlItem) { - if (npc->AddObjectsToContainer(a_objects, npc)) { - if (a_hasLvlItem) { - recalcInventory = true; - if (const auto invChanges = actor->GetInventoryChanges(true)) { - invChanges->InitLeveledItems(); - } - } else if (!startsDead) { - for (auto& [item, count] : a_objects) { - if (item->Is(RE::FormType::Weapon, RE::FormType::Armor)) { - RE::ActorEquipManager::GetSingleton()->EquipObject(actor, item); - } - } - } + for_each_form(a_npcData, Forms::skins, a_input, [&](auto* a_skin) { + if (npc->skin != a_skin) { + npc->skin = a_skin; return true; } return false; }); - - if (recalcInventory && !startsDead) { - auto inv_after = actor->GetInventory([](auto& item) { - return item.Is(RE::FormType::Weapon, RE::FormType::Armor); - }); - for (auto& [item, data] : inv_after) { - auto& [count, extra] = data; - if (!inv_before.contains(item) && count > 0 && !extra->IsWorn()) { - RE::ActorEquipManager::GetSingleton()->EquipObject(actor, item); - } - } - } } - void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries, bool a_noItems) + void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries) { const auto input = PCLevelMult::Input{ a_npcData.GetActor(), a_npcData.GetNPC(), a_onlyLeveledEntries }; - Distribute(a_npcData, input); - if (!a_noItems) { - DistributeItems(a_npcData, input); - } } } diff --git a/SPID/src/DistributeManager.cpp b/SPID/src/DistributeManager.cpp index ce4d670..d6eb3d0 100644 --- a/SPID/src/DistributeManager.cpp +++ b/SPID/src/DistributeManager.cpp @@ -46,7 +46,8 @@ namespace Distribute invChanges->InitOutfitItems(a_npc->defaultOutfit, a_npc->GetLevel()); } - std::vector armorToRemove; + std::vector armorToRemove; + std::vector armorToEquip; if (const auto invChanges = a_actor->GetInventoryChanges()) { if (const auto entryLists = invChanges->entryList) { @@ -65,7 +66,7 @@ namespace Distribute continue; } } - RE::ActorEquipManager::GetSingleton()->EquipObject(a_actor, entryList->object, xList, 1, nullptr, true, true, false); + armorToEquip.push_back(entryList->object); } } } @@ -73,30 +74,29 @@ namespace Distribute } } - if (!armorToRemove.empty()) { - SKSE::GetTaskInterface()->AddTask([a_actor, armorToRemove]() { - for (auto& armor : armorToRemove) { - if (armor) { - a_actor->RemoveItem(armor, 1, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr); - } + SKSE::GetTaskInterface()->AddTask([a_actor, armorToRemove, armorToEquip]() { + for (auto& armor : armorToRemove) { + if (armor) { + a_actor->RemoveItem(armor, 1, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr); } - }); - } + } + for (auto& armor : armorToEquip) { + RE::ActorEquipManager::GetSingleton()->EquipObject(a_actor, armor, nullptr, 1, nullptr, true, true, false, false); + } + }); } void detail::distribute_on_load(RE::Actor* a_actor, RE::TESNPC* a_npc) { - const auto process = should_process_NPC(a_npc); - const auto processOnLoad = detail::should_process_NPC(a_npc, processedOnLoad); - if (process || processOnLoad) { + auto slots = detail::get_equipped_item_slots(a_actor); + a_actor->RemoveOutfitItems(nullptr); + + if (should_process_NPC(a_npc)) { auto npcData = NPCData(a_actor, a_npc); - if (process) { - Distribute(npcData, false, true); - } - if (processOnLoad) { - DistributeItems(npcData, { a_actor, a_npc, false }); - } + Distribute(npcData, false); } + + detail::force_equip_outfit(a_actor, a_npc, slots); } namespace Actor @@ -107,12 +107,7 @@ namespace Distribute static bool thunk(RE::Character* a_this) { if (const auto npc = a_this->GetActorBase()) { - auto slots = detail::get_equipped_item_slots(a_this); - a_this->RemoveOutfitItems(nullptr); - detail::distribute_on_load(a_this, npc); - - detail::force_equip_outfit(a_this, npc, slots); } return func(a_this); @@ -131,15 +126,10 @@ namespace Distribute func(a_this, a_buf); if (const auto npc = a_this->GetActorBase()) { - auto slots = detail::get_equipped_item_slots(a_this); - a_this->RemoveOutfitItems(nullptr); - // some leveled npcs are completely reset upon loading if (a_this->Is3DLoaded()) { detail::distribute_on_load(a_this, npc); } - - detail::force_equip_outfit(a_this, npc, slots); } } static inline REL::Relocation func; @@ -164,8 +154,8 @@ namespace Distribute if (processed = factory->Create(); processed) { processed->formEditorID = "SPID_Processed"; } - if (processedOnLoad = factory->Create(); processedOnLoad) { - processedOnLoad->formEditorID = "SPID_ProcessedOnLoad"; + if (processedOutfit = factory->Create(); processedOutfit) { + processedOutfit->formEditorID = "SPID_ProcessedOutfit"; } } @@ -195,7 +185,7 @@ namespace Distribute if (const auto& actor = actorHandle.get()) { if (const auto npc = actor->GetActorBase(); npc && detail::should_process_NPC(npc)) { auto npcData = NPCData(actor.get(), npc); - Distribute(npcData, false, true); + Distribute(npcData, false); ++actorCount; } } @@ -215,7 +205,7 @@ namespace Distribute logger::info("{:*^50}", "RESULTS"); ForEachDistributable([&](Distributables
& a_distributable) { - if (a_distributable && a_distributable.GetType() != RECORD::kItem && a_distributable.GetType() != RECORD::kOutfit && a_distributable.GetType() != RECORD::kDeathItem) { + if (a_distributable && a_distributable.GetType() != RECORD::kDeathItem) { logger::info("{}", RECORD::add[a_distributable.GetType()]); auto& forms = a_distributable.GetForms();