aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/InstanceManager.cpp59
-rw-r--r--src/openvic-simulation/InstanceManager.hpp1
-rw-r--r--src/openvic-simulation/country/CountryInstance.hpp2
-rw-r--r--src/openvic-simulation/dataloader/Vic2PathSearch.cpp2
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.cpp36
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.hpp14
-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/production/ArtisanalProducer.hpp2
-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.hpp2
-rw-r--r--src/openvic-simulation/economy/production/ProductionType.cpp70
-rw-r--r--src/openvic-simulation/economy/production/ProductionType.hpp43
-rw-r--r--src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp336
-rw-r--r--src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp55
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.cpp20
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.hpp2
-rw-r--r--src/openvic-simulation/map/MapInstance.cpp13
-rw-r--r--src/openvic-simulation/map/MapInstance.hpp1
-rw-r--r--src/openvic-simulation/map/Mapmode.cpp2
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.cpp55
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.hpp15
-rw-r--r--src/openvic-simulation/map/State.cpp17
-rw-r--r--src/openvic-simulation/map/State.hpp2
-rw-r--r--src/openvic-simulation/pop/Pop.cpp20
-rw-r--r--src/openvic-simulation/pop/Pop.hpp6
27 files changed, 660 insertions, 140 deletions
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp
index eaa0692..670cbfc 100644
--- a/src/openvic-simulation/InstanceManager.cpp
+++ b/src/openvic-simulation/InstanceManager.cpp
@@ -38,32 +38,7 @@ void InstanceManager::update_gamestate() {
currently_updating_gamestate = true;
Logger::info("Update: ", today);
-
- if constexpr (ProvinceInstance::ADD_OWNER_CONTRIBUTION) {
- // Calculate local province modifier sums first, then national country modifier sums, then loop over owned provinces
- // adding their contributions to the owner country's modifier sum and loop over them again to add the country's total
- // (including province contributions) to the provinces' modifier sum. This results in every country and province
- // having a full copy of all the modifiers affecting them in their modifier sum.
- map_instance.update_modifier_sums(
- today, definition_manager.get_modifier_manager().get_static_modifier_cache()
- );
- country_instance_manager.update_modifier_sums(
- today, definition_manager.get_modifier_manager().get_static_modifier_cache()
- );
- } else {
- // Calculate national country modifier sums first, then local province modifier sums, adding province contributions
- // to owner countries' modifier sums if each province has an owner. This results in every country having a full copy
- // of all the modifiers affecting them in their modifier sum, but provinces only having their directly/locally applied
- // modifiers in their modifier sum, hence requiring both province and owner country modifier effect values to be looked
- // up and added together to get the full effect on the province.
- country_instance_manager.update_modifier_sums(
- today, definition_manager.get_modifier_manager().get_static_modifier_cache()
- );
- map_instance.update_modifier_sums(
- today, definition_manager.get_modifier_manager().get_static_modifier_cache()
- );
- }
-
+ update_modifier_sums();
// Update gamestate...
map_instance.update_gamestate(today, definition_manager.get_define_manager());
country_instance_manager.update_gamestate(
@@ -163,6 +138,11 @@ bool InstanceManager::load_bookmark(Bookmark const* new_bookmark) {
map_instance, definition_manager.get_pop_manager().get_pop_types()
);
+ if (ret) {
+ update_modifier_sums();
+ map_instance.initialise_for_new_game(definition_manager.get_modifier_manager().get_modifier_effect_cache());
+ }
+
return ret;
}
@@ -204,3 +184,30 @@ bool InstanceManager::expand_selected_province_building(size_t building_index) {
}
return province->expand_building(building_index);
}
+
+void InstanceManager::update_modifier_sums() {
+ if constexpr (ProvinceInstance::ADD_OWNER_CONTRIBUTION) {
+ // Calculate local province modifier sums first, then national country modifier sums, then loop over owned provinces
+ // adding their contributions to the owner country's modifier sum and loop over them again to add the country's total
+ // (including province contributions) to the provinces' modifier sum. This results in every country and province
+ // having a full copy of all the modifiers affecting them in their modifier sum.
+ map_instance.update_modifier_sums(
+ today, definition_manager.get_modifier_manager().get_static_modifier_cache()
+ );
+ country_instance_manager.update_modifier_sums(
+ today, definition_manager.get_modifier_manager().get_static_modifier_cache()
+ );
+ } else {
+ // Calculate national country modifier sums first, then local province modifier sums, adding province contributions
+ // to owner countries' modifier sums if each province has an owner. This results in every country having a full copy
+ // of all the modifiers affecting them in their modifier sum, but provinces only having their directly/locally applied
+ // modifiers in their modifier sum, hence requiring both province and owner country modifier effect values to be looked
+ // up and added together to get the full effect on the province.
+ country_instance_manager.update_modifier_sums(
+ today, definition_manager.get_modifier_manager().get_static_modifier_cache()
+ );
+ map_instance.update_modifier_sums(
+ today, definition_manager.get_modifier_manager().get_static_modifier_cache()
+ );
+ }
+} \ No newline at end of file
diff --git a/src/openvic-simulation/InstanceManager.hpp b/src/openvic-simulation/InstanceManager.hpp
index cfb5447..05ae412 100644
--- a/src/openvic-simulation/InstanceManager.hpp
+++ b/src/openvic-simulation/InstanceManager.hpp
@@ -33,6 +33,7 @@ namespace OpenVic {
bool PROPERTY_CUSTOM_PREFIX(game_instance_setup, is);
bool PROPERTY_CUSTOM_PREFIX(game_session_started, is);
+ void update_modifier_sums();
public:
inline constexpr bool is_bookmark_loaded() const {
return bookmark != nullptr;
diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp
index ea30c0d..6e01649 100644
--- a/src/openvic-simulation/country/CountryInstance.hpp
+++ b/src/openvic-simulation/country/CountryInstance.hpp
@@ -139,7 +139,7 @@ namespace OpenVic {
// TODO - population change over last 30 days
fixed_point_t PROPERTY(national_consciousness);
fixed_point_t PROPERTY(national_militancy);
- IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution);
+ IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution);
size_t PROPERTY(national_focus_capacity)
// TODO - national foci
diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp
index a23d0ce..a1a125d 100644
--- a/src/openvic-simulation/dataloader/Vic2PathSearch.cpp
+++ b/src/openvic-simulation/dataloader/Vic2PathSearch.cpp
@@ -206,7 +206,7 @@ static fs::path _search_for_game_path(fs::path hint_path = {}) {
}
return empty_fail_result_callback("Could not parse VDF at '", current_path, "'.");
}
- std::optional current_node = *(parser.get_key_values());
+ std::optional current_node = *parser.get_key_values();
// check "libraryfolders" list
auto it = current_node.value().find("libraryfolders");
diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp
index 7ad5a87..ba5aff8 100644
--- a/src/openvic-simulation/economy/GoodDefinition.cpp
+++ b/src/openvic-simulation/economy/GoodDefinition.cpp
@@ -13,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()) {
@@ -36,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!");
@@ -47,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
});
}
@@ -68,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);
diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp
index 823c1a3..7cb87cc 100644
--- a/src/openvic-simulation/economy/GoodDefinition.hpp
+++ b/src/openvic-simulation/economy/GoodDefinition.hpp
@@ -35,15 +35,15 @@ 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:
@@ -62,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/production/ArtisanalProducer.hpp b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp
index e5c0b80..65aa3fa 100644
--- a/src/openvic-simulation/economy/production/ArtisanalProducer.hpp
+++ b/src/openvic-simulation/economy/production/ArtisanalProducer.hpp
@@ -6,7 +6,7 @@
#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);
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/production/FactoryProducer.hpp b/src/openvic-simulation/economy/production/FactoryProducer.hpp
index 54ddfb8..9e660ba 100644
--- a/src/openvic-simulation/economy/production/FactoryProducer.hpp
+++ b/src/openvic-simulation/economy/production/FactoryProducer.hpp
@@ -8,7 +8,7 @@
#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>;
diff --git a/src/openvic-simulation/economy/production/ProductionType.cpp b/src/openvic-simulation/economy/production/ProductionType.cpp
index 7c4dfef..c5db641 100644
--- a/src/openvic-simulation/economy/production/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
@@ -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;
@@ -271,7 +288,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 +317,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/production/ProductionType.hpp b/src/openvic-simulation/economy/production/ProductionType.hpp
index 5394938..f9b1778 100644
--- a/src/openvic-simulation/economy/production/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
index 9bf6f49..df91645 100644
--- a/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp
+++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.cpp
@@ -1,21 +1,343 @@
#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,
+ 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,
- ordered_map<Pop*, Pop::pop_size_t>&& new_employees
-) : production_type { new_production_type },
+ 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) } {}
+ 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(
- ProductionType const& new_production_type, fixed_point_t new_size_multiplier
-) : ResourceGatheringOperation { new_production_type, new_size_multiplier, 0, 0, 0, {} } {}
+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;
+ }
+ }
+ }
+
+ const fixed_point_t base_workforce_size = production_type.get_base_workforce_size();
+ if (size_modifier == fixed_point_t::_0()) {
+ size_multiplier = 0;
+ } else {
+ size_multiplier = ((total_worker_count_in_province / (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
index d71c569..a15e87d 100644
--- a/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp
+++ b/src/openvic-simulation/economy/production/ResourceGatheringOperation.hpp
@@ -1,25 +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 {
- class ResourceGatheringOperation final {
+ struct ResourceGatheringOperation {
private:
- ProductionType const& PROPERTY(production_type);
+ 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(size_multiplier);
- ordered_map<Pop*, Pop::pop_size_t> PROPERTY(employees);
+ 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, 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
+ 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(ProductionType const& new_production_type, fixed_point_t new_size_multiplier);
+ 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);
};
}
diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp
index 60fcbe4..bc92f48 100644
--- a/src/openvic-simulation/history/ProvinceHistory.cpp
+++ b/src/openvic-simulation/history/ProvinceHistory.cpp
@@ -1,7 +1,9 @@
#include "ProvinceHistory.hpp"
#include "openvic-simulation/DefinitionManager.hpp"
+#include "openvic-simulation/economy/GoodDefinition.hpp"
#include "openvic-simulation/map/ProvinceDefinition.hpp"
+#include "openvic-simulation/utility/Logger.hpp"
using namespace OpenVic;
using namespace OpenVic::NodeTools;
@@ -57,6 +59,9 @@ bool ProvinceHistoryMap::_load_history_entry(
};
};
+ constexpr bool allow_empty_true = true;
+ constexpr bool do_warn = true;
+
return expect_dictionary_keys_and_default(
[this, &definition_manager, &building_type_manager, &entry](
std::string_view key, ast::NodeCPtr value) -> bool {
@@ -98,7 +103,20 @@ bool ProvinceHistoryMap::_load_history_entry(
expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))),
"is_slave", ZERO_OR_ONE, expect_bool(assign_variable_callback(entry.slave)),
"trade_goods", ZERO_OR_ONE,
- good_definition_manager.expect_good_definition_identifier(assign_variable_callback_pointer_opt(entry.rgo)),
+ good_definition_manager.expect_good_definition_identifier_or_string(
+ [&definition_manager, &entry](GoodDefinition const& rgo_good) ->bool {
+ entry.rgo_production_type_nullable = definition_manager.get_economy_manager().get_production_type_manager().get_good_to_rgo_production_type()[rgo_good];
+ if (entry.rgo_production_type_nullable == nullptr) {
+ Logger::error(entry.province.get_identifier(), " has trade_goods ", rgo_good.get_identifier(), " which has no rgo production type defined.");
+ //we expect the good to have an rgo production type
+ //Victoria 2 treats this as null, but clearly the modder wanted there to be a good
+ return false;
+ }
+ return true;
+ },
+ allow_empty_true, //could be explicitly setting trade_goods to null
+ do_warn //could be typo in good identifier
+ ),
"life_rating", ZERO_OR_ONE, expect_uint<ProvinceInstance::life_rating_t>(assign_variable_callback(entry.life_rating)),
"terrain", ZERO_OR_ONE, terrain_type_manager.expect_terrain_type_identifier(
assign_variable_callback_pointer_opt(entry.terrain_type)
diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp
index 99ea2af..f44fc81 100644
--- a/src/openvic-simulation/history/ProvinceHistory.hpp
+++ b/src/openvic-simulation/history/ProvinceHistory.hpp
@@ -32,7 +32,7 @@ namespace OpenVic {
std::optional<ProvinceInstance::colony_status_t> PROPERTY(colonial);
std::optional<bool> PROPERTY(slave);
ordered_map<CountryDefinition const*, bool> PROPERTY(cores);
- std::optional<GoodDefinition const*> PROPERTY(rgo);
+ std::optional<ProductionType const*> PROPERTY(rgo_production_type_nullable);
std::optional<ProvinceInstance::life_rating_t> PROPERTY(life_rating);
std::optional<TerrainType const*> PROPERTY(terrain_type);
ordered_map<BuildingType const*, BuildingType::level_t> PROPERTY(province_buildings);
diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp
index 47ae40e..4a4a1e5 100644
--- a/src/openvic-simulation/map/MapInstance.cpp
+++ b/src/openvic-simulation/map/MapInstance.cpp
@@ -93,6 +93,7 @@ bool MapInstance::apply_history_to_provinces(
if (history_map != nullptr) {
ProvinceHistoryEntry const* pop_history_entry = nullptr;
+ ProductionType const* rgo_production_type_nullable = nullptr;
for (auto const& [entry_date, entry] : history_map->get_entries()) {
if(entry_date > date) {
@@ -101,6 +102,10 @@ bool MapInstance::apply_history_to_provinces(
}
} else {
province.apply_history_to_province(*entry, country_manager);
+ std::optional<ProductionType const*> const& rgo_production_type_nullable_optional = entry->get_rgo_production_type_nullable();
+ if (rgo_production_type_nullable_optional.has_value()) {
+ rgo_production_type_nullable = rgo_production_type_nullable_optional.value();
+ }
}
if (!entry->get_pops().empty()) {
@@ -114,6 +119,8 @@ bool MapInstance::apply_history_to_provinces(
province.add_pop_vec(pop_history_entry->get_pops());
province.setup_pop_test_values(issue_manager);
}
+
+ ret&=province.set_rgo_production_type_nullable(rgo_production_type_nullable);
}
}
}
@@ -153,3 +160,9 @@ void MapInstance::tick(Date today) {
province.tick(today);
}
}
+
+void MapInstance::initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache){
+ for (ProvinceInstance& province : province_instances.get_items()) {
+ province.initialise_for_new_game(modifier_effect_cache);
+ }
+} \ No newline at end of file
diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp
index e7c623e..a580c55 100644
--- a/src/openvic-simulation/map/MapInstance.hpp
+++ b/src/openvic-simulation/map/MapInstance.hpp
@@ -55,5 +55,6 @@ namespace OpenVic {
void update_modifier_sums(Date today, StaticModifierCache const& static_modifier_cache);
void update_gamestate(Date today, DefineManager const& define_manager);
void tick(Date today);
+ void initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache);
};
}
diff --git a/src/openvic-simulation/map/Mapmode.cpp b/src/openvic-simulation/map/Mapmode.cpp
index f951a05..88eb2eb 100644
--- a/src/openvic-simulation/map/Mapmode.cpp
+++ b/src/openvic-simulation/map/Mapmode.cpp
@@ -179,7 +179,7 @@ bool MapmodeManager::setup_mapmodes() {
"mapmode_terrain_type", get_colour_mapmode(&ProvinceInstance::get_terrain_type)
},
{
- "mapmode_rgo", get_colour_mapmode(&ProvinceInstance::get_rgo)
+ "mapmode_rgo", get_colour_mapmode(&ProvinceInstance::get_rgo_good)
},
{
"mapmode_infrastructure",
diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp
index cbb23bd..64a104b 100644
--- a/src/openvic-simulation/map/ProvinceInstance.cpp
+++ b/src/openvic-simulation/map/ProvinceInstance.cpp
@@ -1,6 +1,8 @@
#include "ProvinceInstance.hpp"
#include "openvic-simulation/country/CountryInstance.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
+#include "openvic-simulation/economy/production/ResourceGatheringOperation.hpp"
#include "openvic-simulation/history/ProvinceHistory.hpp"
#include "openvic-simulation/map/Crime.hpp"
#include "openvic-simulation/map/ProvinceDefinition.hpp"
@@ -10,6 +12,8 @@
#include "openvic-simulation/misc/Define.hpp"
#include "openvic-simulation/modifier/StaticModifierCache.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
+#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/utility/Logger.hpp"
using namespace OpenVic;
@@ -29,7 +33,7 @@ ProvinceInstance::ProvinceInstance(
event_modifiers {},
slave { false },
crime { nullptr },
- rgo { nullptr },
+ rgo { pop_type_keys },
buildings { "buildings", false },
armies {},
navies {},
@@ -41,6 +45,25 @@ ProvinceInstance::ProvinceInstance(
religion_distribution {},
max_supported_regiments { 0 } {}
+GoodDefinition const* ProvinceInstance::get_rgo_good() const {
+ if (!rgo.is_valid()) { return nullptr; }
+ return &(rgo.get_production_type_nullable()->get_output_good());
+}
+bool ProvinceInstance::set_rgo_production_type_nullable(ProductionType const* rgo_production_type_nullable) {
+ bool is_valid_operation = true;
+ if (rgo_production_type_nullable != nullptr) {
+ ProductionType const& rgo_production_type = *rgo_production_type_nullable;
+ if (rgo_production_type.get_template_type() != ProductionType::template_type_t::RGO) {
+ Logger::error("Tried setting province ", get_identifier(), " rgo to ", rgo_production_type.get_identifier(), " which is not of template_type RGO.");
+ is_valid_operation = false;
+ }
+ is_valid_operation&=convert_rgo_worker_pops_to_equivalent(rgo_production_type);
+ }
+
+ rgo.set_production_type_nullable(rgo_production_type_nullable);
+ return is_valid_operation;
+}
+
bool ProvinceInstance::set_owner(CountryInstance* new_owner) {
bool ret = true;
@@ -176,7 +199,7 @@ void ProvinceInstance::_update_pops(DefineManager const& define_manager) {
average_consciousness += pop.get_consciousness();
average_militancy += pop.get_militancy();
- pop_type_distribution[pop.get_type()] += pop.get_size();
+ pop_type_distribution[*pop.get_type()] += pop.get_size();
ideology_distribution += pop.get_ideologies();
culture_distribution[&pop.get_culture()] += pop.get_size();
religion_distribution[&pop.get_religion()] += pop.get_size();
@@ -311,6 +334,24 @@ std::vector<ModifierSum::modifier_entry_t> ProvinceInstance::get_contributing_mo
}
}
+bool ProvinceInstance::convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type) {
+ bool is_valid_operation = true;
+ std::vector<Job> const& jobs = production_type.get_jobs();
+ for(Pop& pop : pops) {
+ for(Job const& job : jobs) {
+ PopType const* const job_pop_type = job.get_pop_type();
+ PopType const* old_pop_type = pop.get_type();
+ if (job_pop_type != old_pop_type) {
+ PopType const* const equivalent = old_pop_type->get_equivalent();
+ if (job_pop_type == equivalent) {
+ is_valid_operation&=pop.convert_to_equivalent();
+ }
+ }
+ }
+ }
+ return is_valid_operation;
+}
+
void ProvinceInstance::update_gamestate(Date today, DefineManager const& define_manager) {
for (BuildingInstance& building : buildings.get_items()) {
building.update_gamestate(today);
@@ -405,7 +446,7 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& ent
ret &= remove_core(country_manager.get_country_instance_from_definition(*country));
}
}
- set_optional(rgo, entry.get_rgo());
+
set_optional(life_rating, entry.get_life_rating());
set_optional(terrain_type, entry.get_terrain_type());
for (auto const& [building, level] : entry.get_province_buildings()) {
@@ -425,8 +466,16 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& ent
return ret;
}
+void ProvinceInstance::initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache) {
+ rgo.initialise_for_new_game(*this, modifier_effect_cache);
+}
+
void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) {
for (Pop& pop : pops) {
pop.setup_pop_test_values(issue_manager);
}
}
+
+plf::colony<Pop>& ProvinceInstance::get_mutable_pops() {
+ return pops;
+} \ No newline at end of file
diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp
index e7c0326..ba800a9 100644
--- a/src/openvic-simulation/map/ProvinceInstance.hpp
+++ b/src/openvic-simulation/map/ProvinceInstance.hpp
@@ -3,11 +3,12 @@
#include <plf_colony.h>
#include "openvic-simulation/economy/BuildingInstance.hpp"
+#include "openvic-simulation/economy/production/ProductionType.hpp"
+#include "openvic-simulation/economy/production/ResourceGatheringOperation.hpp"
#include "openvic-simulation/military/UnitInstance.hpp"
#include "openvic-simulation/military/UnitType.hpp"
#include "openvic-simulation/modifier/ModifierSum.hpp"
#include "openvic-simulation/pop/Pop.hpp"
-#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
@@ -81,8 +82,7 @@ namespace OpenVic {
bool PROPERTY(slave);
Crime const* PROPERTY_RW(crime);
- // TODO - change this into a factory-like structure
- GoodDefinition const* PROPERTY(rgo);
+ ResourceGatheringOperation PROPERTY(rgo);
IdentifierRegistry<BuildingInstance> IDENTIFIER_REGISTRY(building);
ordered_set<ArmyInstance*> PROPERTY(armies);
ordered_set<NavyInstance*> PROPERTY(navies);
@@ -95,7 +95,7 @@ namespace OpenVic {
fixed_point_t PROPERTY(average_literacy);
fixed_point_t PROPERTY(average_consciousness);
fixed_point_t PROPERTY(average_militancy);
- IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution);
+ IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution);
IndexedMap<Ideology, fixed_point_t> PROPERTY(ideology_distribution);
fixed_point_map_t<Culture const*> PROPERTY(culture_distribution);
fixed_point_map_t<Religion const*> PROPERTY(religion_distribution);
@@ -108,6 +108,7 @@ namespace OpenVic {
void _add_pop(Pop&& pop);
void _update_pops(DefineManager const& define_manager);
+ bool convert_rgo_worker_pops_to_equivalent(ProductionType const& production_type);
public:
ProvinceInstance(ProvinceInstance&&) = default;
@@ -123,6 +124,9 @@ namespace OpenVic {
return controller;
}
+ GoodDefinition const* get_rgo_good() const;
+ bool set_rgo_production_type_nullable(ProductionType const* rgo_production_type_nullable);
+
bool set_owner(CountryInstance* new_owner);
bool set_controller(CountryInstance* new_controller);
bool add_core(CountryInstance& new_core);
@@ -155,6 +159,9 @@ namespace OpenVic {
bool setup(BuildingTypeManager const& building_type_manager);
bool apply_history_to_province(ProvinceHistoryEntry const& entry, CountryInstanceManager& country_manager);
+ void initialise_for_new_game(ModifierEffectCache const& modifier_effect_cache);
+
void setup_pop_test_values(IssueManager const& issue_manager);
+ plf::colony<Pop>& get_mutable_pops();
};
}
diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp
index 619f97b..31ea05f 100644
--- a/src/openvic-simulation/map/State.cpp
+++ b/src/openvic-simulation/map/State.cpp
@@ -66,16 +66,19 @@ void State::update_gamestate() {
const int32_t potential_workforce_in_state = 0; // sum of worker pops, regardless of employment
const int32_t potential_employment_in_state = 0; // sum of (factory level * production method base_workforce_size)
- fixed_point_t unclamped_score_per_factory = fixed_point_t::_0();
-
- if (potential_employment_in_state > 0) {
- unclamped_score_per_factory = (fixed_point_t { potential_workforce_in_state } / fixed_point_t::_100()).floor() * 400 / potential_employment_in_state;
+ fixed_point_t workforce_scalar;
+ constexpr fixed_point_t min_workforce_scalar = fixed_point_t::_0_20();
+ constexpr fixed_point_t max_workforce_scalar = fixed_point_t::_4();
+ if (potential_employment_in_state <= 0) {
+ workforce_scalar = min_workforce_scalar;
} else {
- industrial_power = total_factory_levels_in_state * std::clamp(
- unclamped_score_per_factory,
- fixed_point_t::_0_20(), fixed_point_t::_4()
+ workforce_scalar = std::clamp(
+ (fixed_point_t { potential_workforce_in_state } / 100).floor() * 400 / potential_employment_in_state,
+ min_workforce_scalar, max_workforce_scalar
);
}
+
+ industrial_power = total_factory_levels_in_state * workforce_scalar;
}
/* Whether two provinces in the same region should be grouped into the same state or not.
diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp
index 596206a..a39eea6 100644
--- a/src/openvic-simulation/map/State.hpp
+++ b/src/openvic-simulation/map/State.hpp
@@ -29,7 +29,7 @@ namespace OpenVic {
fixed_point_t PROPERTY(average_literacy);
fixed_point_t PROPERTY(average_consciousness);
fixed_point_t PROPERTY(average_militancy);
- IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution);
+ IndexedMap<PopType, Pop::pop_size_t> PROPERTY(pop_type_distribution);
fixed_point_t PROPERTY(industrial_power);
diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp
index 4b81e5d..0f0de69 100644
--- a/src/openvic-simulation/pop/Pop.cpp
+++ b/src/openvic-simulation/pop/Pop.cpp
@@ -9,6 +9,7 @@
#include "openvic-simulation/politics/Ideology.hpp"
#include "openvic-simulation/politics/Issue.hpp"
#include "openvic-simulation/politics/Rebel.hpp"
+#include "openvic-simulation/utility/Logger.hpp"
#include "openvic-simulation/utility/TslHelper.hpp"
using namespace OpenVic;
@@ -19,7 +20,7 @@ using enum PopType::income_type_t;
PopBase::PopBase(
PopType const& new_type, Culture const& new_culture, Religion const& new_religion, pop_size_t new_size,
fixed_point_t new_militancy, fixed_point_t new_consciousness, RebelType const* new_rebel_type
-) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy },
+) : type { &new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy },
consciousness { new_consciousness }, rebel_type { new_rebel_type } {}
Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys)
@@ -115,6 +116,17 @@ void Pop::setup_pop_test_values(IssueManager const& issue_manager) {
luxury_needs_fulfilled = test_range();
}
+bool Pop::convert_to_equivalent() {
+ PopType const* const equivalent = get_type()->get_equivalent();
+ if (equivalent == nullptr) {
+ Logger::error("Tried to convert pop of type ", get_type()->get_identifier(), " to equivalent, but there is no equivalent.");
+ return false;
+ }
+
+ type = equivalent;
+ return true;
+}
+
void Pop::set_location(ProvinceInstance const& new_location) {
if (location != &new_location) {
location = &new_location;
@@ -131,7 +143,7 @@ void Pop::set_location(ProvinceInstance const& new_location) {
void Pop::update_gamestate(
DefineManager const& define_manager, CountryInstance const* owner, fixed_point_t const& pop_size_per_regiment_multiplier
) {
- if (type.get_can_be_recruited()) {
+ if (type->get_can_be_recruited()) {
if (
size < define_manager.get_min_pop_size_for_regiment() || owner == nullptr ||
!RegimentType::allowed_cultures_check_culture_in_country(owner->get_allowed_regiment_cultures(), culture, *owner)
@@ -145,6 +157,10 @@ void Pop::update_gamestate(
}
}
+//TODO store income
+void Pop::add_rgo_owner_income(const fixed_point_t income) {}
+void Pop::add_rgo_worker_income(const fixed_point_t income) {}
+
Strata::Strata(std::string_view new_identifier) : HasIdentifier { new_identifier } {}
PopType::PopType(
diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp
index 59a7794..88c397a 100644
--- a/src/openvic-simulation/pop/Pop.hpp
+++ b/src/openvic-simulation/pop/Pop.hpp
@@ -35,7 +35,7 @@ namespace OpenVic {
using pop_size_t = int32_t;
protected:
- PopType const& PROPERTY_ACCESS(type, protected);
+ PopType const* PROPERTY_ACCESS(type, protected);
Culture const& PROPERTY_ACCESS(culture, protected);
Religion const& PROPERTY_ACCESS(religion, protected);
pop_size_t PROPERTY_ACCESS(size, protected);
@@ -95,6 +95,7 @@ namespace OpenVic {
Pop& operator=(Pop&&) = delete;
void setup_pop_test_values(IssueManager const& issue_manager);
+ bool convert_to_equivalent();
void set_location(ProvinceInstance const& new_location);
@@ -102,6 +103,9 @@ namespace OpenVic {
DefineManager const& define_manager, CountryInstance const* owner,
fixed_point_t const& pop_size_per_regiment_multiplier
);
+
+ void add_rgo_owner_income(const fixed_point_t income);
+ void add_rgo_worker_income(const fixed_point_t income);
};
struct Strata : HasIdentifier {