Skip to content

Commit

Permalink
Prevent outfits from stacking and other fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
powerof3 committed Mar 4, 2024
1 parent 3a5a880 commit 42dba26
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 56 deletions.
1 change: 0 additions & 1 deletion SPID/include/Distribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ namespace Distribute
}
}

void equip_worn_outfit(RE::Actor* actor, const RE::BGSOutfit* a_outfit);
void add_item(RE::Actor* a_actor, RE::TESBoundObject* a_item, std::uint32_t a_itemCount);
void init_leveled_items(RE::Actor* a_actor);
bool can_equip_outfit(const RE::TESNPC* a_npc, RE::BGSOutfit* a_outfit);
Expand Down
2 changes: 2 additions & 0 deletions SPID/include/DistributeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Distribute
namespace detail
{
bool should_process_NPC(RE::TESNPC* a_npc, RE::BGSKeyword* a_keyword = processed);

void equip_worn_outfit(RE::Actor* actor, const RE::BGSOutfit* a_outfit);
void force_equip_outfit(RE::Actor* a_actor, const RE::TESNPC* a_npc);
}

Expand Down
4 changes: 2 additions & 2 deletions SPID/include/FormData.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,15 @@ namespace Forms
void ForEachDistributable(Func&& a_func, Args&&... args)
{
a_func(keywords, std::forward<Args>(args)...);
a_func(factions, std::forward<Args>(args)...);
a_func(perks, std::forward<Args>(args)...);
a_func(spells, std::forward<Args>(args)...);
a_func(levSpells, std::forward<Args>(args)...);
a_func(perks, std::forward<Args>(args)...);
a_func(shouts, std::forward<Args>(args)...);
a_func(items, std::forward<Args>(args)...);
a_func(deathItems, std::forward<Args>(args)...);
a_func(outfits, std::forward<Args>(args)...);
a_func(sleepOutfits, std::forward<Args>(args)...);
a_func(factions, std::forward<Args>(args)...);
a_func(packages, std::forward<Args>(args)...);
a_func(skins, std::forward<Args>(args)...);
}
Expand Down
61 changes: 23 additions & 38 deletions SPID/src/Distribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,6 @@ namespace Distribute
{
namespace detail
{
void equip_worn_outfit(RE::Actor* actor, const RE::BGSOutfit* a_outfit)
{
if (!actor || !a_outfit) {
return;
}

if (const auto invChanges = actor->GetInventoryChanges()) {
if (const auto entryLists = invChanges->entryList) {
const auto formID = a_outfit->GetFormID();

for (const auto& entryList : *entryLists) {
if (entryList && entryList->object && entryList->extraLists) {
for (const auto& xList : *entryList->extraLists) {
const auto outfitItem = xList ? xList->GetByType<RE::ExtraOutfitItem>() : nullptr;
if (outfitItem && outfitItem->id == formID) {
RE::ActorEquipManager::GetSingleton()->EquipObject(actor, entryList->object, xList, 1, nullptr, true);
}
}
}
}
}
}
}

void add_item(RE::Actor* a_actor, RE::TESBoundObject* a_item, std::uint32_t a_itemCount)
{
using func_t = void (*)(RE::Actor*, RE::TESBoundObject*, std::uint32_t, bool, std::uint32_t, RE::BSScript::Internal::VirtualMachine*);
Expand Down Expand Up @@ -73,6 +49,10 @@ namespace Distribute
}
});

for_each_form<RE::BGSPerk>(a_npcData, Forms::perks, a_input, [&](const std::vector<RE::BGSPerk*>& a_perks) {
npc->AddPerks(a_perks, 1);
});

for_each_form<RE::SpellItem>(a_npcData, Forms::spells, a_input, [&](const std::vector<RE::SpellItem*>& a_spells) {
npc->GetSpellList()->AddSpells(a_spells);
});
Expand All @@ -81,10 +61,6 @@ namespace Distribute
npc->GetSpellList()->AddLevSpells(a_levSpells);
});

for_each_form<RE::BGSPerk>(a_npcData, Forms::perks, a_input, [&](const std::vector<RE::BGSPerk*>& a_perks) {
npc->AddPerks(a_perks, 1);
});

for_each_form<RE::TESShout>(a_npcData, Forms::shouts, a_input, [&](const std::vector<RE::TESShout*>& a_shouts) {
npc->GetSpellList()->AddShouts(a_shouts);
});
Expand Down Expand Up @@ -172,21 +148,30 @@ namespace Distribute
const auto npc = a_npcData.GetNPC();
const auto actor = a_npcData.GetActor();

if (!actor->IsDead()) {
actor->ResetInventory(false);
}

for_each_form<RE::BGSOutfit>(a_npcData, Forms::outfits, a_input, [&](auto* a_outfit) {
if (detail::can_equip_outfit(npc, a_outfit)) {
actor->RemoveOutfitItems(npc->defaultOutfit);
npc->defaultOutfit = a_outfit;
npc->AddKeyword(processedOutfit);
return true;
}
return false;
});

for_each_form<RE::TESBoundObject>(a_npcData, Forms::items, a_input, [&](std::map<RE::TESBoundObject*, IdxOrCount>& a_objects, const bool a_hasLvlItem) {
if (npc->AddObjectsToContainer(a_objects, npc)) {
if (a_hasLvlItem) {
detail::init_leveled_items(actor);
}
return true;
}
return false;
});

for_each_form<RE::BGSOutfit>(a_npcData, Forms::outfits, a_input, [&](auto* a_outfit) {
if (detail::can_equip_outfit(npc, a_outfit)) {
actor->RemoveOutfitItems(npc->defaultOutfit);
npc->defaultOutfit = a_outfit;
npc->AddKeyword(processedOutfit);
for (auto& [item, count] : a_objects) {
if (item->Is(RE::FormType::Weapon, RE::FormType::Armor)) {
RE::ActorEquipManager::GetSingleton()->EquipObject(actor, item);
}
}
return true;
}
return false;
Expand Down
58 changes: 43 additions & 15 deletions SPID/src/DistributeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Distribute
{
bool detail::should_process_NPC(RE::TESNPC* a_npc, RE::BGSKeyword* a_keyword)
{
if (a_npc->IsDeleted() || a_npc->HasKeyword(a_keyword)) {
if (a_npc->IsPlayer() || a_npc->IsDeleted() || a_npc->HasKeyword(a_keyword)) {
return false;
}

Expand All @@ -15,13 +15,42 @@ namespace Distribute
return true;
}

void detail::equip_worn_outfit(RE::Actor* actor, const RE::BGSOutfit* a_outfit)
{
if (!actor || !a_outfit) {
return;
}

if (const auto invChanges = actor->GetInventoryChanges()) {
if (const auto entryLists = invChanges->entryList) {
const auto formID = a_outfit->GetFormID();

for (const auto& entryList : *entryLists) {
if (entryList && entryList->object && entryList->extraLists) {
for (const auto& xList : *entryList->extraLists) {
const auto outfitItem = xList ? xList->GetByType<RE::ExtraOutfitItem>() : nullptr;
if (outfitItem && outfitItem->id == formID) {
RE::ActorEquipManager::GetSingleton()->EquipObject(actor, entryList->object, xList, 1, nullptr, true);
}
}
}
}
}
}
}

void detail::force_equip_outfit(RE::Actor* a_actor, const RE::TESNPC* a_npc)
{
if (!a_npc->defaultOutfit) {
return;
}

if (!a_actor->HasOutfitItems(a_npc->defaultOutfit) && !a_actor->IsDead()) {
if (const auto invChanges = a_actor->GetInventoryChanges()) {
invChanges->InitOutfitItems(a_npc->defaultOutfit, a_npc->GetLevel());
}
}

equip_worn_outfit(a_actor, a_npc->defaultOutfit);
}

Expand Down Expand Up @@ -62,9 +91,7 @@ namespace Distribute
const auto root = func(a_this, a_arg1);

if (const auto npc = a_this->GetActorBase()) {
if (npc->HasKeyword(processedOutfit)) {
detail::force_equip_outfit(a_this, npc);
}
detail::force_equip_outfit(a_this, npc);
}

return root;
Expand All @@ -89,9 +116,8 @@ namespace Distribute
auto npcData = NPCData(a_this, npc);
Distribute(npcData, false);
}
if (npc->HasKeyword(processedOutfit)) {
detail::force_equip_outfit(a_this, npc);
}

detail::force_equip_outfit(a_this, npc);
}
}
static inline REL::Relocation<decltype(thunk)> func;
Expand Down Expand Up @@ -146,15 +172,17 @@ namespace Distribute

if (const auto processLists = RE::ProcessLists::GetSingleton()) {
timer.start();
processLists->ForAllActors([&](RE::Actor* a_actor) {
if (const auto npc = a_actor->GetActorBase(); npc && detail::should_process_NPC(npc)) {
auto npcData = NPCData(a_actor, npc);
Distribute(npcData, false, true);
++actorCount;

for (auto& actorHandle : processLists->lowActorHandles) {
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);
++actorCount;
}
}
return RE::BSContainer::ForEachResult::kContinue;
});
timer.end();
}
timer.end();
}

LogResults(actorCount);
Expand Down

0 comments on commit 42dba26

Please sign in to comment.