Skip to content

Commit

Permalink
Merge branch 'master' into feature/exclusive-groups
Browse files Browse the repository at this point in the history
  • Loading branch information
adya committed Mar 12, 2024
2 parents 5bd77ed + e017e6a commit 35c2d0a
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 123 deletions.
7 changes: 2 additions & 5 deletions SPID/include/Distribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,7 @@ 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);
}

// old method (distributing one by one)
Expand Down Expand Up @@ -265,7 +262,7 @@ namespace Distribute
}

void Distribute(NPCData& a_npcData, const PCLevelMult::Input& a_input);
void DistributeItemOutfits(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_noItemOutfits = false);
void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries, bool a_noItems = false);
}
7 changes: 5 additions & 2 deletions SPID/include/DistributeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ namespace Distribute
{
inline RE::BGSKeyword* processed{ nullptr };
inline RE::BGSKeyword* processedOnLoad{ nullptr };
inline RE::BGSKeyword* processedOutfit{ nullptr };

namespace detail
{
bool should_process_NPC(RE::TESNPC* a_npc, RE::BGSKeyword* a_keyword = processed);
void force_equip_outfit(RE::Actor* a_actor, const RE::TESNPC* a_npc);

std::set<RE::BIPED_MODEL::BipedObjectSlot> get_equipped_item_slots(RE::Actor* a_actor);
void force_equip_outfit(RE::Actor* a_actor, const RE::TESNPC* a_npc, const std::set<RE::BGSBipedObjectForm::BipedObjectSlot>& a_slots);

void distribute_on_load(RE::Actor* a_actor, RE::TESNPC* a_npc);
}

namespace Actor
Expand Down
4 changes: 2 additions & 2 deletions SPID/include/FormData.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,15 +368,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
98 changes: 41 additions & 57 deletions SPID/src/Distribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,12 @@ 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*);
REL::Relocation<func_t> func{ RELOCATION_ID(55945, 56489) };
return func(a_actor, a_item, a_itemCount, true, 0, RE::BSScript::Internal::VirtualMachine::GetSingleton());
}

void init_leveled_items(RE::Actor* a_actor)
{
if (const auto invChanges = a_actor->GetInventoryChanges(true)) {
invChanges->InitLeveledItems();
}
}

bool can_equip_outfit(const RE::TESNPC* a_npc, RE::BGSOutfit* a_outfit)
{
if (a_npc->HasKeyword(processedOutfit) || a_npc->defaultOutfit == a_outfit) {
return false;
}

return true;
}
}

void Distribute(NPCData& a_npcData, const PCLevelMult::Input& a_input)
Expand All @@ -73,6 +33,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 +45,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 @@ -154,6 +114,14 @@ namespace Distribute
return false;
});

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

for_each_form<RE::BGSOutfit>(a_npcData, Forms::sleepOutfits, a_input, [&](auto* a_outfit) {
if (npc->sleepOutfit != a_outfit) {
npc->sleepOutfit = a_outfit;
Expand All @@ -163,7 +131,7 @@ namespace Distribute
});
}

void DistributeItemOutfits(NPCData& a_npcData, const PCLevelMult::Input& a_input)
void DistributeItems(NPCData& a_npcData, const PCLevelMult::Input& a_input)
{
if (a_input.onlyPlayerLevelEntries && PCLevelMult::Manager::GetSingleton()->HasHitLevelCap(a_input)) {
return;
Expand All @@ -172,34 +140,50 @@ namespace Distribute
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);
});

bool recalcInventory = 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);
recalcInventory = true;
if (const auto invChanges = actor->GetInventoryChanges(true)) {
invChanges->InitLeveledItems();
}
} else {
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;
});

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;
if (recalcInventory) {
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);
}
}
return false;
});
}
}

void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries, bool a_noItemOutfits)
void Distribute(NPCData& a_npcData, bool a_onlyLeveledEntries, bool a_noItems)
{
const auto input = PCLevelMult::Input{ a_npcData.GetActor(), a_npcData.GetNPC(), a_onlyLeveledEntries };

Distribute(a_npcData, input);
if (!a_noItemOutfits) {
DistributeItemOutfits(a_npcData, input);
if (!a_noItems) {
DistributeItems(a_npcData, input);
}
}
}
Loading

0 comments on commit 35c2d0a

Please sign in to comment.