aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/economy
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation/economy')
-rw-r--r--src/openvic-simulation/economy/BuildingType.cpp31
-rw-r--r--src/openvic-simulation/economy/BuildingType.hpp4
-rw-r--r--src/openvic-simulation/economy/EconomyManager.hpp5
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.cpp130
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.hpp17
-rw-r--r--src/openvic-simulation/economy/GoodInstance.cpp2
-rw-r--r--src/openvic-simulation/economy/GoodInstance.hpp2
-rw-r--r--src/openvic-simulation/economy/ResourceGatheringOperation.cpp21
-rw-r--r--src/openvic-simulation/economy/ResourceGatheringOperation.hpp28
-rw-r--r--src/openvic-simulation/economy/production/ArtisanalProducer.cpp (renamed from src/openvic-simulation/economy/ArtisanalProducer.cpp)0
-rw-r--r--src/openvic-simulation/economy/production/ArtisanalProducer.hpp (renamed from src/openvic-simulation/economy/ArtisanalProducer.hpp)10
-rw-r--r--src/openvic-simulation/economy/production/Employee.cpp8
-rw-r--r--src/openvic-simulation/economy/production/Employee.hpp13
-rw-r--r--src/openvic-simulation/economy/production/FactoryProducer.cpp (renamed from src/openvic-simulation/economy/FactoryProducer.cpp)0
-rw-r--r--src/openvic-simulation/economy/production/FactoryProducer.hpp (renamed from src/openvic-simulation/economy/FactoryProducer.hpp)29
-rw-r--r--src/openvic-simulation/economy/production/ProductionType.cpp (renamed from src/openvic-simulation/economy/ProductionType.cpp)79
-rw-r--r--src/openvic-simulation/economy/production/ProductionType.hpp (renamed from src/openvic-simulation/economy/ProductionType.hpp)43
-rw-r--r--src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp351
-rw-r--r--src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp64
19 files changed, 655 insertions, 182 deletions
diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp
index f0fc8a8..2801cfa 100644
--- a/src/openvic-simulation/economy/BuildingType.cpp
+++ b/src/openvic-simulation/economy/BuildingType.cpp
@@ -1,11 +1,13 @@
#include "BuildingType.hpp"
+#include "openvic-simulation/modifier/ModifierManager.hpp"
+
using namespace OpenVic;
using namespace OpenVic::NodeTools;
BuildingType::BuildingType(
std::string_view identifier, building_type_args_t& building_type_args
-) : Modifier { identifier, std::move(building_type_args.modifier) },
+) : Modifier { identifier, std::move(building_type_args.modifier), modifier_type_t::BUILDING },
type { building_type_args.type },
on_completion { building_type_args.on_completion },
completion_size { building_type_args.completion_size },
@@ -61,7 +63,8 @@ bool BuildingTypeManager::load_buildings_file(
) -> bool {
BuildingType::building_type_args_t building_type_args {};
- bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(building_type_args.modifier),
+ bool ret = NodeTools::expect_dictionary_keys_and_default(
+ modifier_manager.expect_base_province_modifier(building_type_args.modifier),
"type", ONE_EXACTLY, expect_identifier(assign_variable_callback(building_type_args.type)),
"on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(building_type_args.on_completion)),
"completion_size", ZERO_OR_ONE,
@@ -112,14 +115,27 @@ bool BuildingTypeManager::load_buildings_file(
)(root);
lock_building_types();
- for (BuildingType const& building_type : building_types.get_items()) {
+ IndexedMap<BuildingType, ModifierEffectCache::building_type_effects_t>& building_type_effects =
+ modifier_manager.modifier_effect_cache.building_type_effects;
+
+ building_type_effects.set_keys(&get_building_types());
+
+ for (BuildingType const& building_type : get_building_types()) {
+ using enum ModifierEffect::format_t;
+ using enum ModifierEffect::target_t;
+
+ ModifierEffectCache::building_type_effects_t& this_building_type_effects = building_type_effects[building_type];
+
static constexpr std::string_view max_prefix = "max_";
static constexpr std::string_view min_prefix = "min_build_";
- ret &= modifier_manager.add_modifier_effect(
- StringUtils::append_string_views(max_prefix, building_type.get_identifier()), true, ModifierEffect::format_t::INT
+ ret &= modifier_manager.register_technology_modifier_effect(
+ this_building_type_effects.max_level, StringUtils::append_string_views(max_prefix, building_type.get_identifier()),
+ true, INT, StringUtils::append_string_views("$", building_type.get_identifier(), "$ $TECH_MAX_LEVEL$")
);
- ret &= modifier_manager.add_modifier_effect(
- StringUtils::append_string_views(min_prefix, building_type.get_identifier()), false, ModifierEffect::format_t::INT
+ // TODO - add custom localisation for "min_build_$building_type$" modifiers
+ ret &= modifier_manager.register_terrain_modifier_effect(
+ this_building_type_effects.min_level, StringUtils::append_string_views(min_prefix, building_type.get_identifier()),
+ false, INT
);
if (building_type.is_in_province()) {
@@ -150,6 +166,7 @@ bool BuildingTypeManager::load_buildings_file(
Logger::error("No port building type found!");
ret = false;
}
+
if (province_building_types.empty()) {
Logger::error("No province building types found!");
ret = false;
diff --git a/src/openvic-simulation/economy/BuildingType.hpp b/src/openvic-simulation/economy/BuildingType.hpp
index ab999cd..b8cfecf 100644
--- a/src/openvic-simulation/economy/BuildingType.hpp
+++ b/src/openvic-simulation/economy/BuildingType.hpp
@@ -1,8 +1,8 @@
#pragma once
-#include "openvic-simulation/misc/Modifier.hpp"
#include "openvic-simulation/economy/GoodDefinition.hpp"
-#include "openvic-simulation/economy/ProductionType.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
+#include "openvic-simulation/modifier/Modifier.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
diff --git a/src/openvic-simulation/economy/EconomyManager.hpp b/src/openvic-simulation/economy/EconomyManager.hpp
index 2464912..5257e6a 100644
--- a/src/openvic-simulation/economy/EconomyManager.hpp
+++ b/src/openvic-simulation/economy/EconomyManager.hpp
@@ -1,9 +1,10 @@
#pragma once
+#include <openvic-dataloader/v2script/Parser.hpp>
+
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/economy/GoodDefinition.hpp"
-#include "openvic-simulation/economy/ProductionType.hpp"
-#include "openvic-dataloader/v2script/Parser.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
namespace OpenVic {
struct EconomyManager {
diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp
index f21ea18..5440b94 100644
--- a/src/openvic-simulation/economy/GoodDefinition.cpp
+++ b/src/openvic-simulation/economy/GoodDefinition.cpp
@@ -1,5 +1,7 @@
#include "GoodDefinition.hpp"
+#include "openvic-simulation/modifier/ModifierManager.hpp"
+
using namespace OpenVic;
using namespace OpenVic::NodeTools;
@@ -11,18 +13,18 @@ GoodDefinition::GoodDefinition(
index_t new_index,
GoodCategory const& new_category,
fixed_point_t new_base_price,
- bool new_available_from_start,
- bool new_tradeable,
- bool new_money,
- bool new_overseas_penalty
+ bool new_is_available_from_start,
+ bool new_is_tradeable,
+ bool new_is_money,
+ bool new_counters_overseas_penalty
) : HasIdentifierAndColour { new_identifier, new_colour, false },
HasIndex { new_index },
category { new_category },
base_price { new_base_price },
- available_from_start { new_available_from_start },
- tradeable { new_tradeable },
- money { new_money },
- overseas_penalty { new_overseas_penalty } {}
+ is_available_from_start { new_is_available_from_start },
+ is_tradeable { new_is_tradeable },
+ is_money { new_is_money },
+ counters_overseas_penalty { new_counters_overseas_penalty } {}
bool GoodDefinitionManager::add_good_category(std::string_view identifier) {
if (identifier.empty()) {
@@ -34,7 +36,7 @@ bool GoodDefinitionManager::add_good_category(std::string_view identifier) {
bool GoodDefinitionManager::add_good_definition(
std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price,
- bool available_from_start, bool tradeable, bool money, bool overseas_penalty
+ bool is_available_from_start, bool is_tradeable, bool is_money, bool has_overseas_penalty
) {
if (identifier.empty()) {
Logger::error("Invalid good identifier - empty!");
@@ -45,8 +47,8 @@ bool GoodDefinitionManager::add_good_definition(
return false;
}
return good_definitions.add_item({
- identifier, colour, get_good_definition_count(), category, base_price, available_from_start,
- tradeable, money, overseas_penalty
+ identifier, colour, get_good_definition_count(), category, base_price, is_available_from_start,
+ is_tradeable, is_money, has_overseas_penalty
});
}
@@ -66,19 +68,19 @@ bool GoodDefinitionManager::load_goods_file(ast::NodeCPtr root) {
return expect_dictionary([this, &good_category](std::string_view key, ast::NodeCPtr value) -> bool {
colour_t colour = colour_t::null();
fixed_point_t base_price;
- bool available_from_start = true, tradeable = true;
- bool money = false, overseas_penalty = false;
+ bool is_available_from_start = true, is_tradeable = true;
+ bool is_money = false, has_overseas_penalty = false;
bool ret = expect_dictionary_keys(
"color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)),
"cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base_price)),
- "available_from_start", ZERO_OR_ONE, expect_bool(assign_variable_callback(available_from_start)),
- "tradeable", ZERO_OR_ONE, expect_bool(assign_variable_callback(tradeable)),
- "money", ZERO_OR_ONE, expect_bool(assign_variable_callback(money)),
- "overseas_penalty", ZERO_OR_ONE, expect_bool(assign_variable_callback(overseas_penalty))
+ "available_from_start", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_available_from_start)),
+ "tradeable", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_tradeable)),
+ "money", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_money)),
+ "overseas_penalty", ZERO_OR_ONE, expect_bool(assign_variable_callback(has_overseas_penalty))
)(value);
ret &= add_good_definition(
- key, colour, good_category, base_price, available_from_start, tradeable, money, overseas_penalty
+ key, colour, good_category, base_price, is_available_from_start, is_tradeable, is_money, has_overseas_penalty
);
return ret;
})(good_category_value);
@@ -88,29 +90,83 @@ bool GoodDefinitionManager::load_goods_file(ast::NodeCPtr root) {
}
bool GoodDefinitionManager::generate_modifiers(ModifierManager& modifier_manager) const {
+ constexpr bool has_no_effect = true;
+ using enum ModifierEffect::format_t;
+ using enum ModifierEffect::target_t;
+
+ IndexedMap<GoodDefinition, ModifierEffectCache::good_effects_t>& good_effects =
+ modifier_manager.modifier_effect_cache.good_effects;
+
+ good_effects.set_keys(&get_good_definitions());
+
bool ret = true;
- const auto good_modifier = [this, &modifier_manager, &ret](std::string_view name, bool is_positive_good) -> void {
- ret &= modifier_manager.register_complex_modifier(name);
- for (GoodDefinition const& good : get_good_definitions()) {
- ret &= modifier_manager.add_modifier_effect(
- ModifierManager::get_flat_identifier(name, good.get_identifier()), is_positive_good
- );
- }
- };
-
- good_modifier("artisan_goods_input", false);
- good_modifier("artisan_goods_output", true);
- good_modifier("artisan_goods_throughput", true);
- good_modifier("factory_goods_input", false);
- good_modifier("factory_goods_output", true);
- good_modifier("factory_goods_throughput", true);
- good_modifier("rgo_goods_output", true);
- good_modifier("rgo_goods_throughput", true);
- good_modifier("rgo_size", true);
+ ret &= modifier_manager.register_complex_modifier("artisan_goods_input");
+ ret &= modifier_manager.register_complex_modifier("artisan_goods_output");
+ ret &= modifier_manager.register_complex_modifier("artisan_goods_throughput");
+ ret &= modifier_manager.register_complex_modifier("factory_goods_input");
+ ret &= modifier_manager.register_complex_modifier("factory_goods_output");
+ ret &= modifier_manager.register_complex_modifier("factory_goods_throughput");
+ ret &= modifier_manager.register_complex_modifier("rgo_goods_output");
+ ret &= modifier_manager.register_complex_modifier("rgo_goods_throughput");
+ ret &= modifier_manager.register_complex_modifier("rgo_size");
for (GoodDefinition const& good : get_good_definitions()) {
- ret &= modifier_manager.add_modifier_effect(good.get_identifier(), true, ModifierEffect::format_t::PERCENTAGE_DECIMAL);
+ const std::string_view good_identifier = good.get_identifier();
+ ModifierEffectCache::good_effects_t& this_good_effects = good_effects[good];
+
+ const auto good_modifier = [&modifier_manager, &ret, &good_identifier](
+ ModifierEffect const*& effect_cache, std::string_view name, bool is_positive_good,
+ std::string_view localisation_key, bool has_no_effect = false
+ ) -> void {
+ ret &= modifier_manager.register_technology_modifier_effect(
+ effect_cache, ModifierManager::get_flat_identifier(name, good_identifier), is_positive_good,
+ PROPORTION_DECIMAL, localisation_key, has_no_effect
+ );
+ };
+
+ const auto make_production_localisation_suffix = [&good_identifier](
+ std::string_view localisation_suffix
+ ) -> std::string {
+ return StringUtils::append_string_views("$", good_identifier, "$ $", localisation_suffix, "$");
+ };
+
+ good_modifier(
+ this_good_effects.artisan_goods_input, "artisan_goods_input", false,
+ make_production_localisation_suffix("TECH_INPUT"), has_no_effect
+ );
+ good_modifier(
+ this_good_effects.artisan_goods_output, "artisan_goods_output", true,
+ make_production_localisation_suffix("TECH_OUTPUT"), has_no_effect
+ );
+ good_modifier(
+ this_good_effects.artisan_goods_throughput, "artisan_goods_throughput", true,
+ make_production_localisation_suffix("TECH_THROUGHPUT"), has_no_effect
+ );
+ good_modifier(
+ this_good_effects.factory_goods_input, "factory_goods_input", false,
+ make_production_localisation_suffix("TECH_INPUT")
+ );
+ good_modifier(
+ this_good_effects.factory_goods_output, "factory_goods_output", true,
+ make_production_localisation_suffix("TECH_OUTPUT")
+ );
+ good_modifier(
+ this_good_effects.factory_goods_throughput, "factory_goods_throughput", true,
+ make_production_localisation_suffix("TECH_THROUGHPUT")
+ );
+ good_modifier(
+ this_good_effects.rgo_goods_output, "rgo_goods_output", true,
+ make_production_localisation_suffix("TECH_OUTPUT")
+ );
+ good_modifier(
+ this_good_effects.rgo_goods_throughput, "rgo_goods_throughput", true,
+ make_production_localisation_suffix("TECH_THROUGHPUT")
+ );
+ good_modifier(
+ this_good_effects.rgo_size, "rgo_size", true,
+ StringUtils::append_string_views(good_identifier, "_RGO_SIZE")
+ );
}
return ret;
diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp
index 15eb4e8..7cb87cc 100644
--- a/src/openvic-simulation/economy/GoodDefinition.hpp
+++ b/src/openvic-simulation/economy/GoodDefinition.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include "openvic-simulation/misc/Modifier.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -36,21 +35,23 @@ namespace OpenVic {
private:
GoodCategory const& PROPERTY(category);
const fixed_point_t PROPERTY(base_price);
- const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is);
- const bool PROPERTY_CUSTOM_PREFIX(tradeable, is);
- const bool PROPERTY(money);
- const bool PROPERTY(overseas_penalty);
+ const bool PROPERTY(is_available_from_start);
+ const bool PROPERTY(is_tradeable);
+ const bool PROPERTY(is_money);
+ const bool PROPERTY(counters_overseas_penalty);
GoodDefinition(
std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category,
- fixed_point_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money,
- bool new_overseas_penalty
+ fixed_point_t new_base_price, bool new_is_available_from_start, bool new_is_tradeable, bool new_is_money,
+ bool new_counters_overseas_penalty
);
public:
GoodDefinition(GoodDefinition&&) = default;
};
+ struct ModifierManager;
+
struct GoodDefinitionManager {
private:
IdentifierRegistry<GoodCategory> IDENTIFIER_REGISTRY_CUSTOM_PLURAL(good_category, good_categories);
@@ -61,7 +62,7 @@ namespace OpenVic {
bool add_good_definition(
std::string_view identifier, colour_t colour, GoodCategory const& category, fixed_point_t base_price,
- bool available_from_start, bool tradeable, bool money, bool overseas_penalty
+ bool is_available_from_start, bool is_tradeable, bool is_money, bool has_overseas_penalty
);
bool load_goods_file(ast::NodeCPtr root);
diff --git a/src/openvic-simulation/economy/GoodInstance.cpp b/src/openvic-simulation/economy/GoodInstance.cpp
index 6fe3a2f..ac081c9 100644
--- a/src/openvic-simulation/economy/GoodInstance.cpp
+++ b/src/openvic-simulation/economy/GoodInstance.cpp
@@ -4,7 +4,7 @@ using namespace OpenVic;
GoodInstance::GoodInstance(GoodDefinition const& new_good_definition)
: HasIdentifierAndColour { new_good_definition }, good_definition { new_good_definition },
- price { new_good_definition.get_base_price() }, available { new_good_definition.is_available_from_start() } {}
+ price { new_good_definition.get_base_price() }, is_available { new_good_definition.get_is_available_from_start() } {}
bool GoodInstanceManager::setup(GoodDefinitionManager const& good_definition_manager) {
if (good_instances_are_locked()) {
diff --git a/src/openvic-simulation/economy/GoodInstance.hpp b/src/openvic-simulation/economy/GoodInstance.hpp
index 20370ef..74ec939 100644
--- a/src/openvic-simulation/economy/GoodInstance.hpp
+++ b/src/openvic-simulation/economy/GoodInstance.hpp
@@ -14,7 +14,7 @@ namespace OpenVic {
private:
GoodDefinition const& PROPERTY(good_definition);
fixed_point_t PROPERTY(price);
- bool PROPERTY(available);
+ bool PROPERTY(is_available);
// TODO - supply, demand, actual bought
GoodInstance(GoodDefinition const& new_good_definition);
diff --git a/src/openvic-simulation/economy/ResourceGatheringOperation.cpp b/src/openvic-simulation/economy/ResourceGatheringOperation.cpp
deleted file mode 100644
index 9bf6f49..0000000
--- a/src/openvic-simulation/economy/ResourceGatheringOperation.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "ResourceGatheringOperation.hpp"
-
-using namespace OpenVic;
-
-ResourceGatheringOperation::ResourceGatheringOperation(
- ProductionType const& new_production_type,
- fixed_point_t new_size_multiplier,
- fixed_point_t new_revenue_yesterday,
- fixed_point_t new_output_quantity_yesterday,
- fixed_point_t new_unsold_quantity_yesterday,
- ordered_map<Pop*, Pop::pop_size_t>&& new_employees
-) : production_type { new_production_type },
- revenue_yesterday { new_revenue_yesterday },
- output_quantity_yesterday { new_output_quantity_yesterday },
- unsold_quantity_yesterday { new_unsold_quantity_yesterday },
- size_multiplier { new_size_multiplier },
- employees { std::move(new_employees) } {}
-
-ResourceGatheringOperation::ResourceGatheringOperation(
- ProductionType const& new_production_type, fixed_point_t new_size_multiplier
-) : ResourceGatheringOperation { new_production_type, new_size_multiplier, 0, 0, 0, {} } {}
diff --git a/src/openvic-simulation/economy/ResourceGatheringOperation.hpp b/src/openvic-simulation/economy/ResourceGatheringOperation.hpp
deleted file mode 100644
index 73b4261..0000000
--- a/src/openvic-simulation/economy/ResourceGatheringOperation.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include "openvic-simulation/economy/ProductionType.hpp"
-#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
-#include "openvic-simulation/utility/Getters.hpp"
-
-namespace OpenVic {
- class ResourceGatheringOperation final {
- private:
- ProductionType const& PROPERTY(production_type);
- fixed_point_t PROPERTY(revenue_yesterday);
- fixed_point_t PROPERTY(output_quantity_yesterday);
- fixed_point_t PROPERTY(unsold_quantity_yesterday);
- fixed_point_t PROPERTY(size_multiplier);
- ordered_map<Pop*, Pop::pop_size_t> PROPERTY(employees);
-
- public:
- ResourceGatheringOperation(
- ProductionType const& new_production_type,
- fixed_point_t new_size_multiplier,
- fixed_point_t new_revenue_yesterday,
- fixed_point_t new_output_quantity_yesterday,
- fixed_point_t new_unsold_quantity_yesterday,
- ordered_map<Pop*, Pop::pop_size_t>&& new_employees
- );
- ResourceGatheringOperation(ProductionType const& new_production_type, fixed_point_t new_size_multiplier);
- };
-}
diff --git a/src/openvic-simulation/economy/ArtisanalProducer.cpp b/src/openvic-simulation/economy/production/ArtisanalProducer.cpp
index d5cc3d3..d5cc3d3 100644
--- a/src/openvic-simulation/economy/ArtisanalProducer.cpp
+++ b/src/openvic-simulation/economy/production/ArtisanalProducer.cpp
diff --git a/src/openvic-simulation/economy/ArtisanalProducer.hpp b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp
index ed5b231..65aa3fa 100644
--- a/src/openvic-simulation/economy/ArtisanalProducer.hpp
+++ b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp
@@ -1,12 +1,12 @@
#pragma once
#include "openvic-simulation/economy/GoodDefinition.hpp"
-#include "openvic-simulation/economy/ProductionType.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
#include "openvic-simulation/utility/Getters.hpp"
namespace OpenVic {
- class ArtisanalProducer final {
+ struct ArtisanalProducer {
private:
ProductionType const& PROPERTY(production_type);
GoodDefinition::good_definition_map_t PROPERTY(stockpile);
@@ -15,10 +15,8 @@ namespace OpenVic {
public:
ArtisanalProducer(
- ProductionType const& new_production_type,
- GoodDefinition::good_definition_map_t&& new_stockpile,
- fixed_point_t new_current_production,
- GoodDefinition::good_definition_map_t&& new_current_needs
+ ProductionType const& new_production_type, GoodDefinition::good_definition_map_t&& new_stockpile,
+ fixed_point_t new_current_production, GoodDefinition::good_definition_map_t&& new_current_needs
);
};
}
diff --git a/src/openvic-simulation/economy/production/Employee.cpp b/src/openvic-simulation/economy/production/Employee.cpp
new file mode 100644
index 0000000..569299a
--- /dev/null
+++ b/src/openvic-simulation/economy/production/Employee.cpp
@@ -0,0 +1,8 @@
+#include "Employee.hpp"
+
+using namespace OpenVic;
+
+Employee::Employee(Pop& new_pop, const Pop::pop_size_t new_size)
+ : pop { new_pop },
+ size { new_size }
+ {} \ No newline at end of file
diff --git a/src/openvic-simulation/economy/production/Employee.hpp b/src/openvic-simulation/economy/production/Employee.hpp
new file mode 100644
index 0000000..8a09c31
--- /dev/null
+++ b/src/openvic-simulation/economy/production/Employee.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "openvic-simulation/pop/Pop.hpp"
+
+namespace OpenVic {
+ struct Employee {
+ private:
+ Pop::pop_size_t PROPERTY_RW(size);
+ public:
+ Pop& pop;
+ Employee(Pop& new_pop, const Pop::pop_size_t new_size);
+ };
+} \ No newline at end of file
diff --git a/src/openvic-simulation/economy/FactoryProducer.cpp b/src/openvic-simulation/economy/production/FactoryProducer.cpp
index 2ef9fa8..2ef9fa8 100644
--- a/src/openvic-simulation/economy/FactoryProducer.cpp
+++ b/src/openvic-simulation/economy/production/FactoryProducer.cpp
diff --git a/src/openvic-simulation/economy/FactoryProducer.hpp b/src/openvic-simulation/economy/production/FactoryProducer.hpp
index ee658a5..9e660ba 100644
--- a/src/openvic-simulation/economy/FactoryProducer.hpp
+++ b/src/openvic-simulation/economy/production/FactoryProducer.hpp
@@ -3,12 +3,12 @@
#include <cstdint>
#include "openvic-simulation/economy/GoodDefinition.hpp"
-#include "openvic-simulation/economy/ProductionType.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
#include "openvic-simulation/utility/Getters.hpp"
namespace OpenVic {
- class FactoryProducer final {
+ struct FactoryProducer {
private:
static constexpr uint8_t DAYS_OF_HISTORY = 7;
using daily_profit_history_t = std::array<fixed_point_t, DAYS_OF_HISTORY>;
@@ -34,24 +34,13 @@ namespace OpenVic {
public:
FactoryProducer(
- ProductionType const& new_production_type,
- fixed_point_t new_size_multiplier,
- fixed_point_t new_revenue_yesterday,
- fixed_point_t new_output_quantity_yesterday,
- fixed_point_t new_unsold_quantity_yesterday,
- ordered_map<Pop*, Pop::pop_size_t>&& new_employees,
- GoodDefinition::good_definition_map_t&& new_stockpile,
- fixed_point_t new_budget,
- fixed_point_t new_balance_yesterday,
- fixed_point_t new_received_investments_yesterday,
- fixed_point_t new_market_spendings_yesterday,
- fixed_point_t new_paychecks_yesterday,
- uint32_t new_unprofitable_days,
- uint32_t new_subsidised_days,
- uint32_t new_days_without_input,
- uint8_t new_hiring_priority,
- uint8_t new_profit_history_current,
- daily_profit_history_t&& new_daily_profit_history
+ ProductionType const& new_production_type, fixed_point_t new_size_multiplier, fixed_point_t new_revenue_yesterday,
+ fixed_point_t new_output_quantity_yesterday, fixed_point_t new_unsold_quantity_yesterday,
+ ordered_map<Pop*, Pop::pop_size_t>&& new_employees, GoodDefinition::good_definition_map_t&& new_stockpile,
+ fixed_point_t new_budget, fixed_point_t new_balance_yesterday, fixed_point_t new_received_investments_yesterday,
+ fixed_point_t new_market_spendings_yesterday, fixed_point_t new_paychecks_yesterday, uint32_t new_unprofitable_days,
+ uint32_t new_subsidised_days, uint32_t new_days_without_input, uint8_t new_hiring_priority,
+ uint8_t new_profit_history_current, daily_profit_history_t&& new_daily_profit_history
);
FactoryProducer(ProductionType const& new_production_type, fixed_point_t new_size_multiplier);
diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/production/ProductionType.cpp
index 65f3eba..033026d 100644
--- a/src/openvic-simulation/economy/ProductionType.cpp
+++ b/src/openvic-simulation/economy/production/ProductionType.cpp
@@ -9,33 +9,33 @@ Job::Job(
PopType const* new_pop_type,
effect_t new_effect_type,
fixed_point_t new_effect_multiplier,
- fixed_point_t new_desired_workforce_share
+ fixed_point_t new_amount
) : pop_type { new_pop_type },
effect_type { new_effect_type },
effect_multiplier { new_effect_multiplier },
- desired_workforce_share { new_desired_workforce_share } {}
+ amount { new_amount } {}
ProductionType::ProductionType(
- std::string_view new_identifier,
- std::optional<Job> new_owner,
+ const std::string_view new_identifier,
+ const std::optional<Job> new_owner,
std::vector<Job>&& new_jobs,
- template_type_t new_template_type,
- Pop::pop_size_t new_base_workforce_size,
+ const template_type_t new_template_type,
+ const Pop::pop_size_t new_base_workforce_size,
GoodDefinition::good_definition_map_t&& new_input_goods,
- GoodDefinition const* new_output_goods,
- fixed_point_t new_base_output_quantity,
+ GoodDefinition const& new_output_good,
+ const fixed_point_t new_base_output_quantity,
std::vector<bonus_t>&& new_bonuses,
GoodDefinition::good_definition_map_t&& new_maintenance_requirements,
- bool new_is_coastal,
- bool new_is_farm,
- bool new_is_mine
+ const bool new_is_coastal,
+ const bool new_is_farm,
+ const bool new_is_mine
) : HasIdentifier { new_identifier },
owner { new_owner },
jobs { std::move(new_jobs) },
template_type { new_template_type },
base_workforce_size { new_base_workforce_size },
input_goods { std::move(new_input_goods) },
- output_goods { new_output_goods },
+ output_good { new_output_good },
base_output_quantity { new_base_output_quantity },
bonuses { std::move(new_bonuses) },
maintenance_requirements { std::move(new_maintenance_requirements) },
@@ -51,7 +51,9 @@ bool ProductionType::parse_scripts(DefinitionManager const& definition_manager)
return ret;
}
-ProductionTypeManager::ProductionTypeManager() : rgo_owner_sprite { 0 } {}
+ProductionTypeManager::ProductionTypeManager() :
+ good_to_rgo_production_type { nullptr },
+ rgo_owner_sprite { 0 } {}
node_callback_t ProductionTypeManager::_expect_job(
GoodDefinitionManager const& good_definition_manager, PopManager const& pop_manager, callback_t<Job&&> callback
@@ -60,7 +62,7 @@ node_callback_t ProductionTypeManager::_expect_job(
using enum Job::effect_t;
std::string_view pop_type {};
- Job::effect_t effect_type {THROUGHPUT};
+ Job::effect_t effect_type { THROUGHPUT };
fixed_point_t effect_multiplier = 1, desired_workforce_share = 1;
static const string_map_t<Job::effect_t> effect_map = {
@@ -92,19 +94,19 @@ node_callback_t ProductionTypeManager::_expect_job_list(
}
bool ProductionTypeManager::add_production_type(
- std::string_view identifier,
+ const std::string_view identifier,
std::optional<Job> owner,
std::vector<Job>&& jobs,
- ProductionType::template_type_t template_type,
- Pop::pop_size_t base_workforce_size,
+ const ProductionType::template_type_t template_type,
+ const Pop::pop_size_t base_workforce_size,
GoodDefinition::good_definition_map_t&& input_goods,
- GoodDefinition const* output_goods,
- fixed_point_t base_output_quantity,
+ GoodDefinition const* const output_good,
+ const fixed_point_t base_output_quantity,
std::vector<ProductionType::bonus_t>&& bonuses,
GoodDefinition::good_definition_map_t&& maintenance_requirements,
- bool is_coastal,
- bool is_farm,
- bool is_mine
+ const bool is_coastal,
+ const bool is_farm,
+ const bool is_mine
) {
if (identifier.empty()) {
Logger::error("Invalid production type identifier - empty!");
@@ -121,7 +123,7 @@ bool ProductionTypeManager::add_production_type(
return false;
}
- if (output_goods == nullptr) {
+ if (output_good == nullptr) {
Logger::error("Output good for production type ", identifier, " was null!");
return false;
}
@@ -167,13 +169,25 @@ bool ProductionTypeManager::add_production_type(
}
const bool ret = production_types.add_item({
- identifier, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods,
+ identifier, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), *output_good,
base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine
});
+
+ if (ret && (template_type == RGO)) {
+ ProductionType const& production_type = production_types.get_items().back();
+ ProductionType const*& current_rgo_pt = good_to_rgo_production_type[*output_good];
+ if (current_rgo_pt == nullptr || (is_farm && !current_rgo_pt->is_farm())) {
+ // first rgo pt or farms are preferred (over mines) in V2
+ current_rgo_pt = &production_type;
+ }
+ //else ignore, we already have an rgo pt
+ }
+
if (rgo_owner_sprite <= 0 && ret && template_type == RGO && owner.has_value() && owner->get_pop_type() != nullptr) {
/* Set rgo owner sprite to that of the first RGO owner we find. */
rgo_owner_sprite = owner->get_pop_type()->get_sprite();
}
+
return ret;
}
@@ -224,7 +238,10 @@ bool ProductionTypeManager::load_production_types_file(
}
)(parser.get_file_node());
+
/* Pass #3: actually load production types */
+ good_to_rgo_production_type.set_keys(&good_definition_manager.get_good_definitions());
+
reserve_more_production_types(expected_types);
ret &= expect_dictionary(
[this, &good_definition_manager, &pop_manager, &template_target_map, &template_node_map](
@@ -238,7 +255,7 @@ bool ProductionTypeManager::load_production_types_file(
std::optional<Job> owner;
std::vector<Job> jobs;
ProductionType::template_type_t template_type { FACTORY };
- GoodDefinition const* output_goods = nullptr;
+ GoodDefinition const* output_good = nullptr;
Pop::pop_size_t base_workforce_size = 0;
GoodDefinition::good_definition_map_t input_goods, maintenance_requirements;
fixed_point_t base_output_quantity = 0;
@@ -254,13 +271,18 @@ bool ProductionTypeManager::load_production_types_file(
auto parse_node = expect_dictionary_keys(
"template", ZERO_OR_ONE, success_callback, /* Already parsed using expect_key in Pass #1 above. */
"bonus", ZERO_OR_MORE, [&bonuses](ast::NodeCPtr bonus_node) -> bool {
- ConditionScript trigger { scope_t::STATE, scope_t::NO_SCOPE, scope_t::NO_SCOPE };
+ using enum scope_type_t;
+
+ ConditionScript trigger { STATE, NO_SCOPE, NO_SCOPE };
fixed_point_t bonus_value {};
+
const bool ret = expect_dictionary_keys(
"trigger", ONE_EXACTLY, trigger.expect_script(),
"value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(bonus_value))
)(bonus_node);
+
bonuses.emplace_back(std::move(trigger), bonus_value);
+
return ret;
},
"owner", ZERO_OR_ONE, _expect_job(good_definition_manager, pop_manager, move_variable_callback(owner)),
@@ -271,7 +293,7 @@ bool ProductionTypeManager::load_production_types_file(
"input_goods", ZERO_OR_ONE,
good_definition_manager.expect_good_definition_decimal_map(move_variable_callback(input_goods)),
"output_goods", ZERO_OR_ONE,
- good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer(output_goods)),
+ good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer(output_good)),
"value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base_output_quantity)),
"efficiency", ZERO_OR_ONE, good_definition_manager.expect_good_definition_decimal_map(
move_variable_callback(maintenance_requirements)
@@ -300,9 +322,10 @@ bool ProductionTypeManager::load_production_types_file(
ret &= parse_node(node);
ret &= add_production_type(
- key, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_goods,
+ key, owner, std::move(jobs), template_type, base_workforce_size, std::move(input_goods), output_good,
base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine
);
+
return ret;
}
)(parser.get_file_node());
diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/production/ProductionType.hpp
index 5394938..f9b1778 100644
--- a/src/openvic-simulation/economy/ProductionType.hpp
+++ b/src/openvic-simulation/economy/production/ProductionType.hpp
@@ -20,13 +20,13 @@ namespace OpenVic {
PopType const* PROPERTY(pop_type);
effect_t PROPERTY(effect_type);
fixed_point_t PROPERTY(effect_multiplier);
- fixed_point_t PROPERTY(desired_workforce_share);
+ fixed_point_t PROPERTY(amount);
Job(
PopType const* new_pop_type,
effect_t new_effect_type,
fixed_point_t new_effect_multiplier,
- fixed_point_t new_desired_workforce_share
+ fixed_point_t new_amount
);
public:
@@ -47,7 +47,7 @@ namespace OpenVic {
const Pop::pop_size_t PROPERTY(base_workforce_size);
GoodDefinition::good_definition_map_t PROPERTY(input_goods);
- GoodDefinition const* PROPERTY(output_goods);
+ GoodDefinition const& PROPERTY(output_good);
const fixed_point_t PROPERTY(base_output_quantity);
std::vector<bonus_t> PROPERTY(bonuses);
@@ -58,19 +58,19 @@ namespace OpenVic {
const bool PROPERTY_CUSTOM_PREFIX(mine, is);
ProductionType(
- std::string_view new_identifier,
- std::optional<Job> new_owner,
+ const std::string_view new_identifier,
+ const std::optional<Job> new_owner,
std::vector<Job>&& new_jobs,
- template_type_t new_template_type,
- Pop::pop_size_t new_base_workforce_size,
+ const template_type_t new_template_type,
+ const Pop::pop_size_t new_base_workforce_size,
GoodDefinition::good_definition_map_t&& new_input_goods,
- GoodDefinition const* new_output_goods,
- fixed_point_t new_base_output_quantity,
+ GoodDefinition const& new_output_good,
+ const fixed_point_t new_base_output_quantity,
std::vector<bonus_t>&& new_bonuses,
GoodDefinition::good_definition_map_t&& new_maintenance_requirements,
- bool new_is_coastal,
- bool new_is_farm,
- bool new_is_mine
+ const bool new_is_coastal,
+ const bool new_is_farm,
+ const bool new_is_mine
);
bool parse_scripts(DefinitionManager const& definition_manager);
@@ -83,6 +83,7 @@ namespace OpenVic {
private:
IdentifierRegistry<ProductionType> IDENTIFIER_REGISTRY(production_type);
PopType::sprite_t PROPERTY(rgo_owner_sprite);
+ IndexedMap<GoodDefinition, ProductionType const*> PROPERTY(good_to_rgo_production_type);
NodeTools::node_callback_t _expect_job(
GoodDefinitionManager const& good_definition_manager, PopManager const& pop_manager,
@@ -97,19 +98,19 @@ namespace OpenVic {
ProductionTypeManager();
bool add_production_type(
- std::string_view identifier,
+ const std::string_view identifier,
std::optional<Job> owner,
- std::vector<Job>&& employees,
- ProductionType::template_type_t template_type,
- Pop::pop_size_t workforce,
+ std::vector<Job>&& jobs,
+ const ProductionType::template_type_t template_type,
+ const Pop::pop_size_t base_workforce_size,
GoodDefinition::good_definition_map_t&& input_goods,
- GoodDefinition const* output_goods,
- fixed_point_t value,
+ GoodDefinition const* const output_good,
+ const fixed_point_t base_output_quantity,
std::vector<ProductionType::bonus_t>&& bonuses,
GoodDefinition::good_definition_map_t&& maintenance_requirements,
- bool coastal,
- bool farm,
- bool mine
+ const bool is_coastal,
+ const bool is_farm,
+ const bool is_mine
);
bool load_production_types_file(
diff --git a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp
new file mode 100644
index 0000000..70cb64d
--- /dev/null
+++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp
@@ -0,0 +1,351 @@
+#include "ResourceGatheringOperation.hpp"
+
+#include <vector>
+
+#include "openvic-simulation/economy/production/Employee.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
+#include "openvic-simulation/map/ProvinceInstance.hpp"
+#include "openvic-simulation/map/State.hpp"
+#include "openvic-simulation/modifier/ModifierEffectCache.hpp"
+#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/utility/Logger.hpp"
+
+using namespace OpenVic;
+
+ResourceGatheringOperation::ResourceGatheringOperation(
+ ProductionType const* new_production_type_nullable,
+ fixed_point_t new_size_multiplier,
+ fixed_point_t new_revenue_yesterday,
+ fixed_point_t new_output_quantity_yesterday,
+ fixed_point_t new_unsold_quantity_yesterday,
+ std::vector<Employee>&& new_employees,
+ decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys
+) : production_type_nullable { new_production_type_nullable },
+ revenue_yesterday { new_revenue_yesterday },
+ output_quantity_yesterday { new_output_quantity_yesterday },
+ unsold_quantity_yesterday { new_unsold_quantity_yesterday },
+ size_multiplier { new_size_multiplier },
+ employees { std::move(new_employees) },
+ max_employee_count_cache { 0 },
+ total_employees_count_cache { 0 },
+ total_paid_employees_count_cache { 0 },
+ total_owner_income_cache { },
+ total_employee_income_cache { },
+ employee_count_per_type_cache { &pop_type_keys }
+{ }
+
+ResourceGatheringOperation::ResourceGatheringOperation(decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys) : ResourceGatheringOperation {
+ nullptr, fixed_point_t::_0(),
+ fixed_point_t::_0(), fixed_point_t::_0(),
+ fixed_point_t::_0(), {}, pop_type_keys
+} {}
+
+void ResourceGatheringOperation::initialise_for_new_game(ProvinceInstance& location, ModifierEffectCache const& modifier_effect_cache) {
+ if (production_type_nullable == nullptr) {
+ output_quantity_yesterday = 0;
+ revenue_yesterday = 0;
+ return;
+ }
+
+ ProductionType const& production_type = *production_type_nullable;
+ const fixed_point_t size_modifier = calculate_size_modifier(location, modifier_effect_cache);
+ const Pop::pop_size_t total_worker_count_in_province = update_size_and_return_total_worker_count(location, modifier_effect_cache, size_modifier);
+ hire(location, total_worker_count_in_province);
+ Pop::pop_size_t total_owner_count_in_state_cache = 0;
+ std::vector<Pop*> owner_pops_cache {};
+ output_quantity_yesterday = produce(location, owner_pops_cache, total_owner_count_in_state_cache, modifier_effect_cache, size_modifier);
+ revenue_yesterday = output_quantity_yesterday * production_type.get_output_good().get_base_price(); //TODO sell on market
+ pay_employees(location, revenue_yesterday, total_worker_count_in_province, owner_pops_cache, total_owner_count_in_state_cache);
+}
+
+Pop::pop_size_t ResourceGatheringOperation::update_size_and_return_total_worker_count(
+ ProvinceInstance& location,
+ ModifierEffectCache const& modifier_effect_cache,
+ const fixed_point_t size_modifier
+) {
+ if (production_type_nullable == nullptr) {
+ size_multiplier = fixed_point_t::_0();
+ max_employee_count_cache = fixed_point_t::_0();
+ return fixed_point_t::_0();
+ }
+
+ Pop::pop_size_t total_worker_count_in_province = 0; //not counting equivalents
+ ProductionType const& production_type = *production_type_nullable;
+ std::vector<Job> const& jobs = production_type.get_jobs();
+ //can't use pop_type_distribution as it is not filled correctly yet (possibly due to equivalent pop type conversion)
+ for (Pop const& pop : location.get_pops()){
+ PopType const* pop_type = pop.get_type();
+ for(Job const& job : jobs) {
+ if (job.get_pop_type() == pop_type) {
+ total_worker_count_in_province += pop.get_size();
+ break;
+ }
+ }
+ }
+
+ fixed_point_t base_size_modifier = fixed_point_t::_1();
+ if (production_type.is_farm()) {
+ base_size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_local());
+ }
+ if (production_type.is_mine()) {
+ base_size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_local());
+ }
+
+ const fixed_point_t base_workforce_size = production_type.get_base_workforce_size();
+ if (base_size_modifier == fixed_point_t::_0()) {
+ size_multiplier = 0;
+ } else {
+ size_multiplier = ((total_worker_count_in_province / (base_size_modifier * base_workforce_size)).ceil() * fixed_point_t::_1_50()).floor();
+ }
+ max_employee_count_cache = (size_modifier * size_multiplier * base_workforce_size).floor();
+ return total_worker_count_in_province;
+}
+
+fixed_point_t ResourceGatheringOperation::calculate_size_modifier(ProvinceInstance const& location, ModifierEffectCache const& modifier_effect_cache) const {
+ if (production_type_nullable == nullptr) {
+ return fixed_point_t::_1();
+ }
+
+ ProductionType const& production_type = *production_type_nullable;
+
+ fixed_point_t size_modifier = fixed_point_t::_1();
+ if (production_type.is_farm()) {
+ size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_global())
+ + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_size_local());
+ }
+ if (production_type.is_mine()) {
+ size_modifier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_global())
+ + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_size_local());
+ }
+ auto const& good_effects = modifier_effect_cache.get_good_effects()[production_type.get_output_good()];
+ size_modifier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_size());
+ return size_modifier > fixed_point_t::_0() ? size_modifier : fixed_point_t::_0();
+}
+
+void ResourceGatheringOperation::hire(ProvinceInstance& location, Pop::pop_size_t available_worker_count) {
+ total_employees_count_cache = 0;
+ total_paid_employees_count_cache=0;
+ if (production_type_nullable == nullptr) {
+ employees.clear();
+ employee_count_per_type_cache.fill(fixed_point_t::_0());
+ return;
+ }
+
+ ProductionType const& production_type = *production_type_nullable;
+ if (max_employee_count_cache <= 0) { return; }
+ if (available_worker_count <= 0) { return; }
+
+ fixed_point_t proportion_to_hire;
+ if (max_employee_count_cache >= available_worker_count) {
+ //hire everyone
+ proportion_to_hire = fixed_point_t::_1();
+ } else {
+ //hire all pops proportionally
+ const fixed_point_t max_worker_count_real = max_employee_count_cache, available_worker_count_real = available_worker_count;
+ proportion_to_hire = max_worker_count_real / available_worker_count_real;
+ }
+
+ std::vector<Job> const& jobs = production_type.get_jobs();
+ for (Pop& pop : location.get_mutable_pops()){
+ PopType const& pop_type = *pop.get_type();
+ for(Job const& job : jobs) {
+ if (job.get_pop_type() == &pop_type) {
+ const Pop::pop_size_t pop_size_to_hire = static_cast<Pop::pop_size_t>((proportion_to_hire * pop.get_size()).floor());
+ employee_count_per_type_cache[pop_type] += pop_size_to_hire;
+ employees.emplace_back(pop, pop_size_to_hire);
+ total_employees_count_cache += pop_size_to_hire;
+ if (!pop_type.get_is_slave()) {
+ total_paid_employees_count_cache += pop_size_to_hire;
+ }
+ break;
+ }
+ }
+ }
+}
+
+fixed_point_t ResourceGatheringOperation::produce(
+ ProvinceInstance& location,
+ std::vector<Pop*>& owner_pops_cache,
+ Pop::pop_size_t& total_owner_count_in_state_cache,
+ ModifierEffectCache const& modifier_effect_cache,
+ const fixed_point_t size_modifier
+) {
+ if (size_modifier == fixed_point_t::_0()){
+ return fixed_point_t::_0();
+ }
+
+ total_owner_count_in_state_cache = 0;
+ owner_pops_cache = {};
+ if (production_type_nullable == nullptr || max_employee_count_cache <= 0) {
+ return fixed_point_t::_0();
+ }
+
+ ProductionType const& production_type = *production_type_nullable;
+ fixed_point_t throughput_multiplier = fixed_point_t::_1();
+ fixed_point_t output_multilpier = fixed_point_t::_1();
+
+ std::optional<Job> const& owner = production_type.get_owner();
+ if (owner.has_value()) {
+ Job const& owner_job = owner.value();
+ PopType const* owner_job_pop_type_nullable = owner_job.get_pop_type();
+ if (owner_job_pop_type_nullable == nullptr) {
+ Logger::error("Owner job for ", production_type.get_identifier(), " has nullptr as pop_type.");
+ return fixed_point_t::_0();
+ }
+ PopType const& owner_pop_type = *owner_job_pop_type_nullable;
+ State const* state_nullable = location.get_state();
+ if (state_nullable == nullptr) {
+ Logger::error("Province ", location.get_identifier(), " has no state.");
+ return fixed_point_t::_0();
+ }
+ State const& state = *state_nullable;
+ Pop::pop_size_t state_population = 0; //state.get_total_population() is not filled yet
+ std::vector<ProvinceInstance*> const& provinces_in_state = state.get_provinces();
+ for (ProvinceInstance* const province_nullable : provinces_in_state) {
+ if (province_nullable == nullptr) {
+ Logger::error("State ", state.get_identifier(), " has nullptr in provinces.");
+ return fixed_point_t::_0();
+ }
+ ProvinceInstance& province = *province_nullable;
+ for (Pop& pop : province.get_mutable_pops()){
+ state_population += pop.get_size();
+ if (&owner_pop_type == pop.get_type()) {
+ owner_pops_cache.push_back(&pop);
+ total_owner_count_in_state_cache += pop.get_size();
+ }
+ }
+ }
+
+ if (total_owner_count_in_state_cache > 0) {
+ switch (owner_job.get_effect_type()) {
+ case Job::effect_t::OUTPUT:
+ output_multilpier += owner_job.get_effect_multiplier() * total_owner_count_in_state_cache / state_population;
+ break;
+ case Job::effect_t::THROUGHPUT:
+ throughput_multiplier += owner_job.get_effect_multiplier() * total_owner_count_in_state_cache / state_population;
+ break;
+ default:
+ Logger::error("Invalid job effect in RGO ",production_type.get_identifier());
+ break;
+ }
+ }
+ }
+
+ throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_rgo_throughput())
+ +location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_local_rgo_throughput());
+ output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_rgo_output())
+ +location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_local_rgo_output());
+
+ if (production_type.is_farm()) {
+ throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_throughput_global());
+ output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_output_global())
+ + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_farm_rgo_output_local());
+ }
+ if (production_type.is_mine()) {
+ throughput_multiplier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_throughput_global());
+ output_multilpier += location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_output_global())
+ + location.get_modifier_effect_value_nullcheck(modifier_effect_cache.get_mine_rgo_output_local());
+ }
+ auto const& good_effects = modifier_effect_cache.get_good_effects()[production_type.get_output_good()];
+ throughput_multiplier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_goods_throughput());
+ output_multilpier += location.get_modifier_effect_value_nullcheck(good_effects.get_rgo_goods_output());
+
+ fixed_point_t throughput_from_workers = fixed_point_t::_0();
+ fixed_point_t output_from_workers = fixed_point_t::_1();
+ for (PopType const& pop_type : *employee_count_per_type_cache.get_keys()) {
+ const Pop::pop_size_t employees_of_type = employee_count_per_type_cache[pop_type];
+
+ for(Job const& job : production_type.get_jobs()) {
+ if (job.get_pop_type() != &pop_type) {
+ continue;
+ }
+
+ fixed_point_t const effect_multiplier = job.get_effect_multiplier();
+ fixed_point_t relative_to_workforce = fixed_point_t::parse(employees_of_type) / fixed_point_t::parse(max_employee_count_cache);
+ fixed_point_t const amount = job.get_amount();
+ if (effect_multiplier != fixed_point_t::_1() && relative_to_workforce > amount) {
+ relative_to_workforce = amount;
+ }
+ switch (job.get_effect_type()) {
+ case Job::effect_t::OUTPUT:
+ output_from_workers += effect_multiplier * relative_to_workforce;
+ break;
+ case Job::effect_t::THROUGHPUT:
+ throughput_from_workers += effect_multiplier * relative_to_workforce;
+ break;
+ default:
+ Logger::error("Invalid job effect in RGO ",production_type.get_identifier());
+ break;
+ }
+ }
+ }
+
+ //if province is overseas multiply by (1 + overseas penalty)
+
+ return production_type.get_base_output_quantity()
+ * size_modifier * size_multiplier
+ * throughput_multiplier * throughput_from_workers
+ * output_multilpier * output_from_workers;
+}
+
+void ResourceGatheringOperation::pay_employees(
+ ProvinceInstance& location,
+ const fixed_point_t revenue,
+ const Pop::pop_size_t total_worker_count_in_province,
+ std::vector<Pop*>& owner_pops_cache,
+ const Pop::pop_size_t total_owner_count_in_state_cache
+) {
+ total_owner_income_cache = 0;
+ total_employee_income_cache = 0;
+ if (production_type_nullable == nullptr || revenue <= 0 || total_worker_count_in_province <= 0) {
+ if (revenue < 0) { Logger::error("Negative revenue for province ", location.get_identifier()); }
+ if (total_worker_count_in_province < 0) { Logger::error("Negative total worker count for province ", location.get_identifier()); }
+ return;
+ }
+
+ ProductionType const& production_type = *production_type_nullable;
+
+ fixed_point_t revenue_left = revenue;
+ if (total_owner_count_in_state_cache > 0) {
+ Job const& owner_job = production_type.get_owner().value();
+ PopType const* owner_job_pop_type_nullable = owner_job.get_pop_type();
+
+ fixed_point_t owner_share = (fixed_point_t::_2() * total_owner_count_in_state_cache / total_worker_count_in_province);
+ constexpr fixed_point_t upper_limit = fixed_point_t::_0_50();
+ if (owner_share > upper_limit) {
+ owner_share = upper_limit;
+ }
+
+ for(Pop* owner_pop_nullable : owner_pops_cache) {
+ Pop& owner_pop = *owner_pop_nullable;
+ const fixed_point_t income_for_this_pop = revenue_left * owner_share * owner_pop.get_size() / total_owner_count_in_state_cache;
+ owner_pop.add_rgo_owner_income(income_for_this_pop);
+ total_owner_income_cache += income_for_this_pop;
+ }
+ revenue_left *= (fixed_point_t::_1() - owner_share);
+ }
+
+ if (total_paid_employees_count_cache > 0) {
+ for (Employee& employee : employees) {
+ Pop& employee_pop = employee.pop;
+ PopType const* employee_pop_type_nullable = employee_pop.get_type();
+ if (employee_pop_type_nullable == nullptr) {
+ Logger::error("employee has nullptr pop_type.");
+ return;
+ }
+ PopType const& employee_pop_type = *employee_pop_type_nullable;
+ if (employee_pop_type.get_is_slave()) {
+ continue;
+ }
+
+ const Pop::pop_size_t employee_size = employee.get_size();
+ const fixed_point_t income_for_this_pop = revenue_left * employee_size / total_paid_employees_count_cache;
+ employee_pop.add_rgo_worker_income(income_for_this_pop);
+ total_employee_income_cache += income_for_this_pop;
+ }
+ } else {
+ //scenario slaves only
+ //Money is removed from system in Victoria 2.
+ }
+} \ No newline at end of file
diff --git a/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp b/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp
new file mode 100644
index 0000000..a15e87d
--- /dev/null
+++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include "openvic-simulation/economy/production/Employee.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
+#include "openvic-simulation/modifier/ModifierEffectCache.hpp"
+#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/utility/Getters.hpp"
+
+namespace OpenVic {
+ struct ResourceGatheringOperation {
+ private:
+ ProductionType const* PROPERTY_RW(production_type_nullable);
+ fixed_point_t PROPERTY(revenue_yesterday);
+ fixed_point_t PROPERTY(output_quantity_yesterday);
+ fixed_point_t PROPERTY(unsold_quantity_yesterday);
+ fixed_point_t PROPERTY_RW(size_multiplier);
+ std::vector<Employee> PROPERTY(employees);
+ Pop::pop_size_t PROPERTY(max_employee_count_cache);
+ Pop::pop_size_t PROPERTY(total_employees_count_cache);
+ Pop::pop_size_t PROPERTY(total_paid_employees_count_cache);
+ fixed_point_t PROPERTY(total_owner_income_cache);
+ fixed_point_t PROPERTY(total_employee_income_cache);
+ IndexedMap<PopType, Pop::pop_size_t> PROPERTY(employee_count_per_type_cache);
+
+ Pop::pop_size_t update_size_and_return_total_worker_count(
+ ProvinceInstance& location,
+ ModifierEffectCache const& modifier_effect_cache,
+ const fixed_point_t size_modifier
+ );
+ fixed_point_t calculate_size_modifier(ProvinceInstance const& location, ModifierEffectCache const& modifier_effect_cache) const;
+ void hire(ProvinceInstance& location, const Pop::pop_size_t available_worker_count);
+ fixed_point_t produce(
+ ProvinceInstance& location,
+ std::vector<Pop*>& owner_pops_cache,
+ Pop::pop_size_t& total_owner_count_in_state_cache,
+ ModifierEffectCache const& modifier_effect_cache,
+ const fixed_point_t size_modifier
+ );
+ void pay_employees(
+ ProvinceInstance& location,
+ const fixed_point_t revenue,
+ const Pop::pop_size_t total_worker_count_in_province,
+ std::vector<Pop*>& owner_pops_cache,
+ const Pop::pop_size_t total_owner_count_in_state_cache
+ );
+
+ public:
+ ResourceGatheringOperation(
+ ProductionType const* new_production_type_nullable,
+ fixed_point_t new_size_multiplier,
+ fixed_point_t new_revenue_yesterday,
+ fixed_point_t new_output_quantity_yesterday,
+ fixed_point_t new_unsold_quantity_yesterday,
+ std::vector<Employee>&& new_employees,
+ decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys
+ );
+ ResourceGatheringOperation(decltype(employee_count_per_type_cache)::keys_t const& pop_type_keys);
+ constexpr bool is_valid() const {
+ return production_type_nullable != nullptr;
+ }
+ void initialise_for_new_game(ProvinceInstance& location, ModifierEffectCache const& modifier_effect_cache);
+ };
+}