diff options
author | wvpm <24685035+wvpm@users.noreply.github.com> | 2024-09-22 01:07:51 +0200 |
---|---|---|
committer | wvpm <24685035+wvpm@users.noreply.github.com> | 2024-10-30 22:04:41 +0100 |
commit | 0d861669d9e1f5d487c810ae01be50f142790f1e (patch) | |
tree | 187df50130475006b404c5ab57f0fa679173ad04 /src/openvic-simulation/economy/production | |
parent | 48e4e92682db99239e928a67e6677cdd2c53a375 (diff) |
Implement rgo for new gameprepare_for_rgo
Map province history rgo to production type for province instance
output_goods back to ZERO_OR_ONE
Link trade_goods in history to RGO instance for province.
Other producer types as structs instead of classes
Convert pops to equivalents & calculate rgo size
Also convert pops when changing rgo
Clean up
Refactored RGO into part of ProvinceInstance
ProductionType const& output_good
Remove unused imports
Clean up unused imports
Restore constructor for ResourceGatheringOperation to initialise from savegame
Move rgo size calculation to rgo
Use terrain modifiers to calculate rgo size (placeholder code)
Clean up
Basic production & sales for rgo when initialising new game
Use mutable pops
Paychecks for owners, workers and slaves
Clean up
Simplify rgo instantiation
Co-authored-by: Hop311 <Hop3114@gmail.com>
Simplify good_to_rgo_production_type assignment
Co-authored-by: Hop311 <Hop3114@gmail.com>
Fix import
Co-authored-by: Hop311 <Hop3114@gmail.com>
min(3, great_powers.size())
Co-authored-by: Hop311 <Hop3114@gmail.com>
Fix import
Co-authored-by: Hop311 <Hop3114@gmail.com>
Apply comments
Log errors and return result when applying history
Cleanup
Diffstat (limited to 'src/openvic-simulation/economy/production')
8 files changed, 465 insertions, 64 deletions
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); }; } |