diff --git a/SPID/include/Defs.h b/SPID/include/Defs.h index 7691604..29db1ac 100644 --- a/SPID/include/Defs.h +++ b/SPID/include/Defs.h @@ -54,6 +54,16 @@ struct Range return value >= min && value <= max; } + [[nodiscard]] bool IsExact() const + { + return min == max; + } + + [[nodiscard]] T GetRandom() const + { + return IsExact() ? min : RNG().generate(min, max); + } + // members T min{ std::numeric_limits::min() }; T max{ std::numeric_limits::max() }; @@ -83,7 +93,10 @@ struct Traits std::optional teammate{}; }; -using IdxOrCount = std::int32_t; +using Index = std::int32_t; +using Count = std::int32_t; +using RandomCount = Range; +using IndexOrCount = std::variant; using Chance = std::uint32_t; /// A standardized way of converting any object to string. diff --git a/SPID/include/Distribute.h b/SPID/include/Distribute.h index 787931b..9499025 100644 --- a/SPID/include/Distribute.h +++ b/SPID/include/Distribute.h @@ -80,14 +80,21 @@ namespace Distribute const NPCData& a_npcData, Forms::Distributables
& a_distributables, const PCLevelMult::Input& a_input, - std::function a_callback) + std::function a_callback) { auto& vec = a_distributables.GetForms(a_input.onlyPlayerLevelEntries); for (auto& formData : vec) { if (!a_npcData.HasMutuallyExclusiveForm(formData.form) && detail::passed_filters(a_npcData, a_input, formData)) { - a_callback(formData.form, formData.idxOrCount); - ++formData.npcCount; + if constexpr (std::is_same_v) { + if (a_callback(formData.form, formData.count.GetRandom())) { + ++formData.npcCount; + } + } else { + if (a_callback(formData.form, formData.packageIndex)) { + ++formData.npcCount; + } + } } } } @@ -134,7 +141,7 @@ namespace Distribute const NPCData& a_npcData, Forms::Distributables& a_distributables, const PCLevelMult::Input& a_input, - std::function&, bool)> a_callback) + std::function&, bool)> a_callback) { auto& vec = a_distributables.GetForms(a_input.onlyPlayerLevelEntries); @@ -142,15 +149,15 @@ namespace Distribute return; } - std::map collectedForms{}; - bool hasLeveledItems = false; + std::map collectedForms{}; + bool hasLeveledItems = false; for (auto& formData : vec) { if (!a_npcData.HasMutuallyExclusiveForm(formData.form) && detail::passed_filters(a_npcData, a_input, formData)) { if (formData.form->Is(RE::FormType::LeveledItem)) { hasLeveledItems = true; } - collectedForms.emplace(formData.form, formData.idxOrCount); + collectedForms.emplace(formData.form, formData.count.GetRandom()); ++formData.npcCount; } } diff --git a/SPID/include/FormData.h b/SPID/include/FormData.h index 093acb9..8c112aa 100644 --- a/SPID/include/FormData.h +++ b/SPID/include/FormData.h @@ -307,9 +307,10 @@ namespace Forms { std::uint32_t index{ 0 }; - Form* form{ nullptr }; - IdxOrCount idxOrCount{ 1 }; - FilterData filters{}; + Form* form{ nullptr }; + Index packageIndex{ 0 }; + RandomCount count{ 1, 1 }; + FilterData filters{}; std::string path{}; std::uint32_t npcCount{ 0 }; @@ -442,7 +443,7 @@ void Forms::Distributables::LookupForms(RE::TESDataHandler* a_dataHandler, forms.reserve(a_INIDataVec.size()); std::uint32_t index = 0; - for (auto& [formOrEditorID, strings, filterIDs, level, traits, idxOrCount, chance, path] : a_INIDataVec) { + for (auto& [formOrEditorID, strings, filterIDs, level, traits, packageIndex, itemsCount, chance, path] : a_INIDataVec) { try { if (auto form = detail::get_form(a_dataHandler, formOrEditorID, path); form) { FormFilters filterForms{}; @@ -456,7 +457,7 @@ void Forms::Distributables::LookupForms(RE::TESDataHandler* a_dataHandler, } if (validEntry) { - forms.emplace_back(index, form, idxOrCount, FilterData(strings, filterForms, level, traits, chance), path); + forms.emplace_back(index, form, packageIndex, itemsCount, FilterData(strings, filterForms, level, traits, chance), path); index++; } } diff --git a/SPID/include/LookupConfigs.h b/SPID/include/LookupConfigs.h index 063c2ed..a650760 100644 --- a/SPID/include/LookupConfigs.h +++ b/SPID/include/LookupConfigs.h @@ -46,7 +46,8 @@ namespace INI Filters rawFormFilters{}; LevelFilters levelFilters{}; Traits traits{}; - IdxOrCount idxOrCount{ 1 }; + Index index{ 0 }; + RandomCount count{ 1, 1 }; Chance chance{ 100 }; std::string path{}; }; diff --git a/SPID/src/Distribute.cpp b/SPID/src/Distribute.cpp index 2e40cee..9e1d400 100644 --- a/SPID/src/Distribute.cpp +++ b/SPID/src/Distribute.cpp @@ -89,8 +89,11 @@ namespace Distribute npc->GetSpellList()->AddShouts(a_shouts); }); - for_each_form(a_npcData, Forms::packages, a_input, [&](auto* a_packageOrList, [[maybe_unused]] IdxOrCount a_idx) { - auto packageIdx = a_idx; + for_each_form(a_npcData, Forms::packages, a_input, [&](auto* a_packageOrList, [[maybe_unused]] IndexOrCount a_idx) { + if (!std::holds_alternative(a_idx)) { + return false; + } + auto packageIdx = std::get(a_idx); if (a_packageOrList->Is(RE::FormType::Package)) { auto package = a_packageOrList->As(); @@ -172,7 +175,7 @@ namespace Distribute const auto npc = a_npcData.GetNPC(); const auto actor = a_npcData.GetActor(); - for_each_form(a_npcData, Forms::items, a_input, [&](std::map& a_objects, const bool a_hasLvlItem) { + 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) { detail::init_leveled_items(actor); diff --git a/SPID/src/DistributeManager.cpp b/SPID/src/DistributeManager.cpp index be7e6a3..1381c3b 100644 --- a/SPID/src/DistributeManager.cpp +++ b/SPID/src/DistributeManager.cpp @@ -222,8 +222,14 @@ namespace Distribute::Event const auto npcData = NPCData(actor, npc); const auto input = PCLevelMult::Input{ actor, npc, false }; - for_each_form(npcData, Forms::deathItems, input, [&](auto* a_deathItem, IdxOrCount a_count) { - detail::add_item(actor, a_deathItem, a_count); + for_each_form(npcData, Forms::deathItems, input, [&](auto* deathItem, IndexOrCount idxOrCount) { + if (!std::holds_alternative(idxOrCount)) { + return false; + } + + auto count = std::get(idxOrCount); + + detail::add_item(actor, deathItem, count.GetRandom()); return true; }); } diff --git a/SPID/src/LookupConfigs.cpp b/SPID/src/LookupConfigs.cpp index 07df2e0..71c14a2 100644 --- a/SPID/src/LookupConfigs.cpp +++ b/SPID/src/LookupConfigs.cpp @@ -246,15 +246,28 @@ namespace INI } //ITEMCOUNT/INDEX - if (a_key == "Package") { // reuse item count for package stack index - data.idxOrCount = 0; - } + if (kIdxOrCount < size) { - if (const auto& str = sections[kIdxOrCount]; distribution::is_valid_entry(str)) { - data.idxOrCount = string::to_num(str); + if (a_key == "Package") { // reuse item count for package stack index + if (const auto& str = sections[kIdxOrCount]; distribution::is_valid_entry(str)) { + data.index = string::to_num(str); + } + } else { + if (const auto& str = sections[kIdxOrCount]; distribution::is_valid_entry(str)) { + if (auto countPair = string::split(str, "/"); countPair.size() > 1) { + auto minCount = string::to_num(countPair[0]); + auto maxCount = string::to_num(countPair[1]); + + data.count = RandomCount(minCount, maxCount); + } else { + auto count = string::to_num(str); + + data.count = RandomCount(count, count); // create the exact match range. + } + } } } - + //CHANCE if (kChance < size) { if (const auto& str = sections[kChance]; distribution::is_valid_entry(str)) {