aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/modifier/ModifierValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/modifier/ModifierValue.cpp')
-rw-r--r--src/openvic-simulation/modifier/ModifierValue.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/openvic-simulation/modifier/ModifierValue.cpp b/src/openvic-simulation/modifier/ModifierValue.cpp
new file mode 100644
index 0000000..e3e7b0b
--- /dev/null
+++ b/src/openvic-simulation/modifier/ModifierValue.cpp
@@ -0,0 +1,149 @@
+#include "ModifierValue.hpp"
+
+#include "openvic-simulation/utility/TslHelper.hpp"
+
+using namespace OpenVic;
+
+ModifierValue::ModifierValue() = default;
+ModifierValue::ModifierValue(effect_map_t&& new_values) : values { std::move(new_values) } {}
+ModifierValue::ModifierValue(ModifierValue const&) = default;
+ModifierValue::ModifierValue(ModifierValue&&) = default;
+
+ModifierValue& ModifierValue::operator=(ModifierValue const&) = default;
+ModifierValue& ModifierValue::operator=(ModifierValue&&) = default;
+
+void ModifierValue::trim() {
+ erase_if(values, [](effect_map_t::value_type const& value) -> bool {
+ return value.second == fixed_point_t::_0();
+ });
+}
+
+size_t ModifierValue::get_effect_count() const {
+ return values.size();
+}
+
+void ModifierValue::clear() {
+ values.clear();
+}
+
+bool ModifierValue::empty() const {
+ return values.empty();
+}
+
+fixed_point_t ModifierValue::get_effect(ModifierEffect const& effect, bool* effect_found) const {
+ const effect_map_t::const_iterator it = values.find(&effect);
+ if (it != values.end()) {
+ if (effect_found != nullptr) {
+ *effect_found = true;
+ }
+ return it->second;
+ }
+
+ if (effect_found != nullptr) {
+ *effect_found = false;
+ }
+ return fixed_point_t::_0();
+}
+
+fixed_point_t ModifierValue::get_effect_nullcheck(ModifierEffect const* effect, bool* effect_found) const {
+ if (effect != nullptr) {
+ return get_effect(*effect, effect_found);
+ }
+
+ if (effect_found != nullptr) {
+ *effect_found = false;
+ }
+ return fixed_point_t::_0();
+}
+
+bool ModifierValue::has_effect(ModifierEffect const& effect) const {
+ return values.contains(&effect);
+}
+
+void ModifierValue::set_effect(ModifierEffect const& effect, fixed_point_t value) {
+ values[&effect] = value;
+}
+
+ModifierValue& ModifierValue::operator+=(ModifierValue const& right) {
+ for (effect_map_t::value_type const& value : right.values) {
+ values[value.first] += value.second;
+ }
+ return *this;
+}
+
+ModifierValue ModifierValue::operator+(ModifierValue const& right) const {
+ ModifierValue copy = *this;
+ return copy += right;
+}
+
+ModifierValue ModifierValue::operator-() const {
+ ModifierValue copy = *this;
+ for (auto value : mutable_iterator(copy.values)) {
+ value.second = -value.second;
+ }
+ return copy;
+}
+
+ModifierValue& ModifierValue::operator-=(ModifierValue const& right) {
+ for (effect_map_t::value_type const& value : right.values) {
+ values[value.first] -= value.second;
+ }
+ return *this;
+}
+
+ModifierValue ModifierValue::operator-(ModifierValue const& right) const {
+ ModifierValue copy = *this;
+ return copy -= right;
+}
+
+ModifierValue& ModifierValue::operator*=(fixed_point_t const& right) {
+ for (auto value : mutable_iterator(values)) {
+ value.second *= right;
+ }
+ return *this;
+}
+
+ModifierValue ModifierValue::operator*(fixed_point_t const& right) const {
+ ModifierValue copy = *this;
+ return copy *= right;
+}
+
+void ModifierValue::apply_exclude_targets(ModifierEffect::target_t excluded_targets) {
+ using enum ModifierEffect::target_t;
+
+ // We could test if excluded_targets is NO_TARGETS (and so we do nothing) or ALL_TARGETS (and so we clear everything),
+ // but so long as this is always called with an explicit/hardcoded value then we'll never have either of those cases.
+ erase_if(
+ values,
+ [excluded_targets](effect_map_t::value_type const& value) -> bool {
+ return !ModifierEffect::excludes_targets(value.first->get_targets(), excluded_targets);
+ }
+ );
+}
+
+void ModifierValue::multiply_add_exclude_targets(
+ ModifierValue const& other, fixed_point_t multiplier, ModifierEffect::target_t excluded_targets
+) {
+ using enum ModifierEffect::target_t;
+
+ if (multiplier == fixed_point_t::_1() && excluded_targets == NO_TARGETS) {
+ *this += other;
+ } else if (multiplier != fixed_point_t::_0()) {
+ // We could test that excluded_targets != ALL_TARGETS, but in practice it's always
+ // called with an explcit/hardcoded value and so won't ever exclude everything.
+ for (effect_map_t::value_type const& value : other.values) {
+ if (ModifierEffect::excludes_targets(value.first->get_targets(), excluded_targets)) {
+ values[value.first] += value.second * multiplier;
+ }
+ }
+ }
+}
+
+namespace OpenVic { // so the compiler shuts up
+ std::ostream& operator<<(std::ostream& stream, ModifierValue const& value) {
+ for (ModifierValue::effect_map_t::value_type const& effect : value.values) {
+ stream << effect.first << ": " << effect.second << "\n";
+ }
+ return stream;
+ }
+}