Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/ObjectProperties.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "ObjectProperties.h"

RandValueParams::RandValueParams(CHANCE_TYPE a_type, const RE::TESObjectREFR* a_ref) :
rng(a_type, a_ref)
RandValueParams::RandValueParams(Chance a_chance, const RE::TESObjectREFR* a_ref) :
rng(a_chance, a_ref)
{}

FloatRange::FloatRange(const std::string& a_str)
Expand Down Expand Up @@ -139,15 +139,15 @@ bool ObjectProperties::IsValid() const
return location || rotation || refScale || recordFlagsSet != 0 || recordFlagsUnset != 0;
}

void ObjectProperties::SetChanceType(CHANCE_TYPE a_type)
void ObjectProperties::SetChance(Chance a_chance)
{
chanceType = a_type;
chance = a_chance;
}

void ObjectProperties::SetTransform(RE::TESObjectREFR* a_refr) const
{
if (location || rotation || refScale) {
RandValueParams params(chanceType, a_refr);
RandValueParams params(chance, a_refr);
if (location) {
location->SetTransform(a_refr->data.location, params);
}
Expand Down
6 changes: 3 additions & 3 deletions src/ObjectProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

struct RandValueParams
{
RandValueParams(CHANCE_TYPE a_type, const RE::TESObjectREFR* a_ref);
RandValueParams(Chance a_chance, const RE::TESObjectREFR* a_ref);

BOS_RNG rng{};
bool clamp{ false };
Expand Down Expand Up @@ -72,15 +72,15 @@ class ObjectProperties

bool IsValid() const;

void SetChanceType(CHANCE_TYPE a_type);
void SetChance(Chance a_chance);
void SetTransform(RE::TESObjectREFR* a_refr) const;
void SetRecordFlags(RE::TESObjectREFR* a_refr) const;

private:
void assign_record_flags(const std::string& a_str, bool a_unsetFlag);

// members
CHANCE_TYPE chanceType{ CHANCE_TYPE::kRefHash };
Chance chance{};

std::optional<Point3Range> location{ std::nullopt };
std::optional<Point3Range> rotation{ std::nullopt };
Expand Down
3 changes: 3 additions & 0 deletions src/PCH.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ template <class K, class D>
using Map = ankerl::unordered_dense::map<K, D>;
template <class T>
using Set = ankerl::unordered_dense::set<T>;
template <class T>
using OrderedSet = std::set<T>;

using FormIDSet = Set<RE::FormID>;
using FormIDOrSet = std::variant<RE::FormID, FormIDSet>;
using FormIDOrderedSet = OrderedSet<RE::FormID>;

template <class T>
using FormIDMap = Map<RE::FormID, T>;
Expand Down
19 changes: 15 additions & 4 deletions src/RNG.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "RNG.h"

BOS_RNG::BOS_RNG(CHANCE_TYPE a_type, const RE::TESObjectREFR* a_ref) :
type(a_type)
BOS_RNG::BOS_RNG(Chance a_chance, const RE::TESObjectREFR* a_ref) :
type(a_chance.chanceType)
{
switch (type) {
case CHANCE_TYPE::kRefHash:
Expand All @@ -27,11 +27,19 @@ BOS_RNG::BOS_RNG(CHANCE_TYPE a_type, const RE::TESObjectREFR* a_ref) :
}
}
break;
case CHANCE_TYPE::kRandom:
seed = a_chance.seed;
break;
default:
break;
}
}

BOS_RNG::BOS_RNG(Chance a_chance) :
type(a_chance.chanceType),
seed(a_chance.seed)
{}

Chance::Chance(const std::string& a_str)
{
if (distribution::is_valid_entry(a_str)) {
Expand All @@ -43,8 +51,11 @@ Chance::Chance(const std::string& a_str)
} else {
chanceType = CHANCE_TYPE::kRefHash;
}

if (srell::cmatch match; srell::regex_search(a_str.c_str(), match, regex::generic)) {
chanceValue = string::to_num<float>(match[1].str());
const auto chanceOptions = string::split(match[1].str(), ",");
chanceValue = string::to_num<float>(chanceOptions[0]);
seed = chanceOptions.size() > 1 ? string::to_num<std::uint64_t>(chanceOptions[1]) : 0;
}
}
}
Expand All @@ -53,7 +64,7 @@ Chance::Chance(const std::string& a_str)
bool Chance::PassedChance(const RE::TESObjectREFR* a_ref) const
{
if (chanceValue < 100.0f) {
BOS_RNG rng(chanceType, a_ref);
BOS_RNG rng(*this, a_ref);
if (const auto rngValue = rng.generate<float>(0.0f, 100.0f); rngValue > chanceValue) {
return false;
}
Expand Down
51 changes: 26 additions & 25 deletions src/RNG.h
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
#pragma once

struct BOS_RNG
enum class CHANCE_TYPE
{
kRandom,
kRefHash,
kLocationHash
};

struct Chance
{
public:
enum class CHANCE_TYPE
{
kRandom,
kRefHash,
kLocationHash
};
Chance() = default;
explicit Chance(const std::string& a_str);

bool PassedChance(const RE::TESObjectREFR* a_ref) const;

// members
CHANCE_TYPE chanceType{ CHANCE_TYPE::kRefHash };
float chanceValue{ 100.0f };
std::uint64_t seed{ 0 };

};

struct BOS_RNG
{
public:
BOS_RNG() = default;
BOS_RNG(CHANCE_TYPE a_type, const RE::TESObjectREFR* a_ref);
BOS_RNG(Chance a_chance, const RE::TESObjectREFR* a_ref);
BOS_RNG(Chance a_chance);

template <class T>
T generate(T a_min, T a_max) const
{
if (type == CHANCE_TYPE::kRandom) {
if (type == CHANCE_TYPE::kRandom && seed == 0) {
return SeedRNG().generate<T>(a_min, a_max);
}
return SeedRNG(seed).generate<T>(a_min, a_max);
}

// members
CHANCE_TYPE type;
std::uint64_t seed;
};

using CHANCE_TYPE = BOS_RNG::CHANCE_TYPE;

struct Chance
{
public:
Chance() = default;
explicit Chance(const std::string& a_str);

bool PassedChance(const RE::TESObjectREFR* a_ref) const;

// members
CHANCE_TYPE chanceType{ CHANCE_TYPE::kRefHash };
float chanceValue{ 100.0f };
std::uint64_t seed { 0 };
};
31 changes: 29 additions & 2 deletions src/SwapData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace FormSwap
record(a_input.record),
path(a_input.path)
{
properties.SetChanceType(chance.chanceType);
properties.SetChance(chance);
}

bool ObjectData::HasValidProperties(const RE::TESObjectREFR* a_ref) const
Expand Down Expand Up @@ -49,7 +49,7 @@ namespace FormSwap
auto& set = std::get<FormIDSet>(formIDSet);

const auto setEnd = std::distance(set.begin(), set.end()) - 1;
const auto randIt = BOS_RNG(chance.chanceType, a_ref).generate<std::int64_t>(0, setEnd);
const auto randIt = BOS_RNG(chance, a_ref).generate<std::int64_t>(0, setEnd);

return RE::TESForm::LookupByID<RE::TESBoundObject>(*std::next(set.begin(), randIt));
}
Expand Down Expand Up @@ -92,6 +92,33 @@ namespace FormSwap
} else {
logger::error("\t\t\t\tfail : [{}] (SWAP formID not found)", a_str);
}
} else if (const auto baseFormIDs = util::GetFormIDOrderedSet(formPair[0]); !baseFormIDs.empty()) {
if (auto swapFormIDs = util::GetFormIDOrderedSet(formPair[1]); !swapFormIDs.empty()) {
if (baseFormIDs.size() > swapFormIDs.size()) {
logger::error("\t\t\t\tfail : [{}] (SWAP formID set must be equal or larger than BASE formID set)", a_str);
return;
}
auto properties = formPair.size() > 2 ? formPair[2] : std::string{};
auto chance = formPair.size() > 3 ? formPair[3] : std::string{};

auto a_chance = Chance(chance);
auto a_rng = BOS_RNG(a_chance);

// randomly assign each baseFormID to a unique swapFormID
for (auto itBaseFormID : baseFormIDs) {
const auto setEnd = std::distance(swapFormIDs.begin(), swapFormIDs.end()) - 1;
const auto randIt = a_rng.generate<std::int64_t>(0, setEnd);
auto swapFormID = swapFormIDs.extract(*std::next(swapFormIDs.begin(), randIt));
if (swapFormID) {
const Input input(properties, std::string{}, a_str, a_path);
SwapFormData swapFormData(swapFormID.value(), input);

a_func(itBaseFormID, swapFormData);
}
}
} else {
logger::error("\t\t\t\tfail : [{}] (SWAP formID set not found)", a_str);
}
} else {
logger::error("\t\t\t\tfail : [{}] (BASE formID not found)", a_str);
}
Expand Down
17 changes: 17 additions & 0 deletions src/Util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,21 @@ namespace util
return GetFormID(a_str);
}
}

FormIDOrderedSet GetFormIDOrderedSet(const std::string& a_str)
{
FormIDOrderedSet set;
if (a_str.contains(",")) {
const auto IDStrs = string::split(a_str, ",");
for (auto& IDStr : IDStrs) {
if (auto formID = GetFormID(IDStr); formID != 0) {
set.emplace(formID);
} else {
logger::error("\t\t\tfailed to process {} (formID not found)", IDStr);
}
}
return set;
}
return set;
}
}
1 change: 1 addition & 0 deletions src/Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ namespace util

RE::FormID GetFormID(const std::string& a_str);
FormIDOrSet GetSwapFormID(const std::string& a_str);
FormIDOrderedSet GetFormIDOrderedSet(const std::string& a_str);
}