aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/economy
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-10-13 10:16:44 +0200
committer GitHub <noreply@github.com>2023-10-13 10:16:44 +0200
commit32fdf7c38b2e56339a2fffa71a7a61a854759e2c (patch)
tree4ad745778dea488ad10509cf17d349c3ef0cc229 /src/openvic-simulation/economy
parentbb22324da1225a0ac458c1d69893bb3bd28bd6b7 (diff)
parentd95c3c9da75018e3e959e5493ebd9c520e00bf7a (diff)
Merge pull request #50 from OpenVicProject/changes
Lots of accumulated changes
Diffstat (limited to 'src/openvic-simulation/economy')
-rw-r--r--src/openvic-simulation/economy/Building.cpp292
-rw-r--r--src/openvic-simulation/economy/Building.hpp174
-rw-r--r--src/openvic-simulation/economy/EconomyManager.hpp26
-rw-r--r--src/openvic-simulation/economy/Good.hpp4
-rw-r--r--src/openvic-simulation/economy/ProductionType.cpp84
-rw-r--r--src/openvic-simulation/economy/ProductionType.hpp10
6 files changed, 539 insertions, 51 deletions
diff --git a/src/openvic-simulation/economy/Building.cpp b/src/openvic-simulation/economy/Building.cpp
new file mode 100644
index 0000000..23bd04c
--- /dev/null
+++ b/src/openvic-simulation/economy/Building.cpp
@@ -0,0 +1,292 @@
+#include "Building.hpp"
+
+#include "openvic-simulation/map/Province.hpp" //imported here so the hpp doesn't get circular imports
+
+using namespace OpenVic;
+using namespace OpenVic::NodeTools;
+
+Building::Building(std::string_view identifier, BuildingType const& type, ARGS) : HasIdentifier { identifier }, ModifierValue { std::move(modifiers) }, type { type },
+ on_completion { on_completion }, completion_size { completion_size }, max_level { max_level }, goods_cost { goods_cost }, cost { cost }, build_time { build_time },
+ visibility { visibility }, on_map { on_map }, default_enabled { default_enabled }, production_type { production_type }, pop_build_factory { pop_build_factory },
+ strategic_factory { strategic_factory }, advanced_factory { advanced_factory }, fort_level { fort_level }, naval_capacity { naval_capacity },
+ colonial_points { colonial_points }, in_province { in_province }, one_per_state { one_per_state }, colonial_range { colonial_range },
+ infrastructure { infrastructure }, movement_cost { movement_cost }, local_ship_build { local_ship_build }, spawn_railway_track { spawn_railway_track },
+ sail { sail }, steam { steam }, capital { capital }, port { port } {}
+
+BuildingType const& Building::get_type() const {
+ return type;
+}
+
+std::string_view Building::get_on_completion() const {
+ return on_completion;
+}
+
+fixed_point_t Building::get_completion_size() const {
+ return completion_size;
+}
+
+Building::level_t Building::get_max_level() const {
+ return max_level;
+}
+
+std::map<Good const*, fixed_point_t> const& Building::get_goods_cost() const {
+ return goods_cost;
+}
+
+fixed_point_t Building::get_cost() const {
+ return cost;
+}
+
+Timespan Building::get_build_time() const {
+ return build_time;
+}
+
+bool Building::has_visibility() const {
+ return visibility;
+}
+
+bool Building::is_on_map() const {
+ return on_map;
+}
+
+bool Building::is_default_enabled() const {
+ return default_enabled;
+}
+
+ProductionType const* Building::get_production_type() const {
+ return production_type;
+}
+
+bool Building::is_pop_built_factory() const {
+ return pop_build_factory;
+}
+
+bool Building::is_strategic_factory() const {
+ return strategic_factory;
+}
+
+bool Building::is_advanced_factory() const {
+ return advanced_factory;
+}
+
+Building::level_t Building::get_fort_level() const {
+ return fort_level;
+}
+
+uint64_t Building::get_naval_capacity() const {
+ return naval_capacity;
+}
+
+std::vector<fixed_point_t> const& Building::get_colonial_points() const {
+ return colonial_points;
+}
+
+bool Building::is_in_province() const {
+ return in_province;
+}
+
+bool Building::is_one_per_state() const {
+ return one_per_state;
+}
+
+fixed_point_t Building::get_colonial_range() const {
+ return colonial_range;
+}
+
+fixed_point_t Building::get_infrastructure() const {
+ return infrastructure;
+}
+
+fixed_point_t Building::get_movement_cost() const {
+ return movement_cost;
+}
+
+bool Building::spawned_railway_track() const {
+ return spawn_railway_track;
+}
+
+BuildingType::BuildingType(std::string_view new_identifier) : HasIdentifier { new_identifier } {}
+
+BuildingInstance::BuildingInstance(Building const& building) : HasIdentifier { building.get_identifier() }, building { building } {}
+
+Building const& BuildingInstance::get_building() const {
+ return building;
+}
+
+bool BuildingInstance::_can_expand() const {
+ return level < building.get_max_level();
+}
+
+BuildingInstance::level_t BuildingInstance::get_current_level() const {
+ return level;
+}
+
+ExpansionState BuildingInstance::get_expansion_state() const {
+ return expansion_state;
+}
+
+Date const& BuildingInstance::get_start_date() const {
+ return start;
+}
+
+Date const& BuildingInstance::get_end_date() const {
+ return end;
+}
+
+float BuildingInstance::get_expansion_progress() const {
+ return expansion_progress;
+}
+
+bool BuildingInstance::expand() {
+ if (expansion_state == ExpansionState::CanExpand) {
+ expansion_state = ExpansionState::Preparing;
+ expansion_progress = 0.0f;
+ return true;
+ }
+ return false;
+}
+
+/* REQUIREMENTS:
+ * MAP-71, MAP-74, MAP-77
+ */
+void BuildingInstance::update_state(Date const& today) {
+ switch (expansion_state) {
+ case ExpansionState::Preparing:
+ start = today;
+ end = start + building.get_build_time();
+ break;
+ case ExpansionState::Expanding:
+ expansion_progress = static_cast<double>(today - start) / static_cast<double>(end - start);
+ break;
+ default: expansion_state = _can_expand() ? ExpansionState::CanExpand : ExpansionState::CannotExpand;
+ }
+}
+
+void BuildingInstance::tick(Date const& today) {
+ if (expansion_state == ExpansionState::Preparing) {
+ expansion_state = ExpansionState::Expanding;
+ }
+ if (expansion_state == ExpansionState::Expanding) {
+ if (end <= today) {
+ level++;
+ expansion_state = ExpansionState::CannotExpand;
+ }
+ }
+}
+
+BuildingManager::BuildingManager() : building_types { "building types" }, buildings { "buildings" } {}
+
+bool BuildingManager::add_building_type(std::string_view identifier) {
+ if (identifier.empty()) {
+ Logger::error("Invalid building type identifier - empty!");
+ return false;
+ }
+ return building_types.add_item({ identifier });
+}
+
+bool BuildingManager::add_building(std::string_view identifier, BuildingType const* type, ARGS) {
+ if (identifier.empty()) {
+ Logger::error("Invalid building identifier - empty!");
+ return false;
+ }
+ if (type == nullptr) {
+ Logger::error("Invalid building type for ", identifier, ": null");
+ return false;
+ }
+
+ return buildings.add_item({
+ identifier, *type, on_completion, completion_size, max_level, goods_cost, cost, build_time, visibility, on_map, default_enabled,
+ production_type, pop_build_factory, strategic_factory, advanced_factory, fort_level, naval_capacity, colonial_points, in_province, one_per_state,
+ colonial_range, infrastructure, movement_cost, local_ship_build, spawn_railway_track, sail, steam, capital, port, std::move(modifiers)
+ });
+}
+
+bool BuildingManager::load_buildings_file(GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ bool ret = expect_dictionary_reserve_length(buildings, [this](std::string_view, ast::NodeCPtr value) -> bool {
+ return expect_key("type", expect_identifier(
+ [this](std::string_view identifier) -> bool {
+ if (!building_types.has_identifier(identifier)) {
+ return building_types.add_item({ identifier });
+ }
+ return true;
+ }
+ ))(value);
+ })(root);
+ lock_building_types();
+
+ ret &= expect_dictionary([this, &good_manager, &production_type_manager, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool {
+ BuildingType const* type = nullptr;
+ ProductionType const* production_type = nullptr;
+ std::string_view on_completion;
+ fixed_point_t completion_size = 0, cost = 0, infrastructure = 0, movement_cost = 0, colonial_range = 0, local_ship_build = 0;
+ Building::level_t max_level = 0, fort_level = 0;
+ std::map<Good const*, fixed_point_t> goods_cost;
+ Timespan build_time;
+ bool visibility = false, on_map = false, default_enabled = false, pop_build_factory = false, strategic_factory = false, advanced_factory = false;
+ bool in_province = false, one_per_state = false, spawn_railway_track = false, sail = false, steam = false, capital = false, port = false;
+ uint64_t naval_capacity = 0;
+ std::vector<fixed_point_t> colonial_points;
+ ModifierValue modifiers;
+
+ bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifiers),
+ "type", ONE_EXACTLY, expect_identifier(expect_building_type_identifier(assign_variable_callback_pointer(type))),
+ "on_completion", ZERO_OR_ONE, expect_identifier(assign_variable_callback(on_completion)),
+ "completion_size", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(completion_size)),
+ "max_level", ONE_EXACTLY, expect_uint(assign_variable_callback(max_level)),
+ "goods_cost", ONE_EXACTLY, good_manager.expect_good_decimal_map(move_variable_callback(goods_cost)),
+ "cost", ZERO_OR_MORE, expect_fixed_point(assign_variable_callback(cost)),
+ "time", ONE_EXACTLY, expect_days(assign_variable_callback(build_time)),
+ "visibility", ONE_EXACTLY, expect_bool(assign_variable_callback(visibility)),
+ "onmap", ONE_EXACTLY, expect_bool(assign_variable_callback(on_map)),
+ "default_enabled", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_enabled)),
+ "production_type", ZERO_OR_ONE, expect_identifier(production_type_manager.expect_production_type_identifier(assign_variable_callback_pointer(production_type))),
+ "pop_build_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(pop_build_factory)),
+ "strategic_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(strategic_factory)),
+ "advanced_factory", ZERO_OR_ONE, expect_bool(assign_variable_callback(advanced_factory)),
+ "fort_level", ZERO_OR_ONE, expect_uint(assign_variable_callback(fort_level)),
+ "naval_capacity", ZERO_OR_ONE, expect_uint(assign_variable_callback(naval_capacity)),
+ "colonial_points", ZERO_OR_ONE, expect_list(expect_fixed_point([&colonial_points](fixed_point_t points) -> bool {
+ colonial_points.push_back(points);
+ return true;
+ })),
+ "province", ZERO_OR_ONE, expect_bool(assign_variable_callback(in_province)),
+ "one_per_state", ZERO_OR_ONE, expect_bool(assign_variable_callback(one_per_state)),
+ "colonial_range", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(colonial_range)),
+ "infrastructure", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(infrastructure)),
+ "movement_cost", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(movement_cost)),
+ "local_ship_build", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(local_ship_build)),
+ "spawn_railway_track", ZERO_OR_ONE, expect_bool(assign_variable_callback(spawn_railway_track)),
+ "sail", ZERO_OR_ONE, expect_bool(assign_variable_callback(sail)),
+ "steam", ZERO_OR_ONE, expect_bool(assign_variable_callback(steam)),
+ "capital", ZERO_OR_ONE, expect_bool(assign_variable_callback(capital)),
+ "port", ZERO_OR_ONE, expect_bool(assign_variable_callback(port))
+ )(value);
+
+ ret &= add_building(
+ key, type, on_completion, completion_size, max_level, goods_cost, cost, build_time, visibility, on_map, default_enabled,
+ production_type, pop_build_factory, strategic_factory, advanced_factory, fort_level, naval_capacity, colonial_points, in_province,
+ one_per_state, colonial_range, infrastructure, movement_cost, local_ship_build, spawn_railway_track, sail, steam, capital, port, std::move(modifiers)
+ );
+
+ return ret;
+ })(root);
+ lock_buildings();
+
+ return ret;
+}
+
+bool BuildingManager::generate_province_buildings(Province& province) const {
+ province.reset_buildings();
+ if (!building_types.is_locked()) {
+ Logger::error("Cannot generate buildings until building types are locked!");
+ return false;
+ }
+ bool ret = true;
+ if (!province.get_water()) {
+ for (Building const& building : buildings.get_items()) {
+ ret &= province.add_building({ building });
+ }
+ }
+ province.lock_buildings();
+ return ret;
+}
diff --git a/src/openvic-simulation/economy/Building.hpp b/src/openvic-simulation/economy/Building.hpp
new file mode 100644
index 0000000..3d1e24b
--- /dev/null
+++ b/src/openvic-simulation/economy/Building.hpp
@@ -0,0 +1,174 @@
+#pragma once
+
+#include "openvic-simulation/types/Date.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/economy/Good.hpp"
+#include "openvic-simulation/economy/ProductionType.hpp"
+#include "openvic-simulation/Modifier.hpp"
+
+#define ARGS std::string_view on_completion, fixed_point_t completion_size, level_t max_level, \
+ std::map<Good const*, fixed_point_t> goods_cost, fixed_point_t cost, Timespan build_time, bool visibility, bool on_map, bool default_enabled, \
+ ProductionType const* production_type, bool pop_build_factory, bool strategic_factory, bool advanced_factory, level_t fort_level, \
+ uint64_t naval_capacity, std::vector<fixed_point_t> colonial_points, bool in_province, bool one_per_state, fixed_point_t colonial_range, \
+ fixed_point_t infrastructure, fixed_point_t movement_cost, fixed_point_t local_ship_build, bool spawn_railway_track, bool sail, bool steam, \
+ bool capital, bool port, ModifierValue&& modifiers
+
+namespace OpenVic {
+
+ struct BuildingManager;
+ struct BuildingType;
+
+ /* REQUIREMENTS:
+ * MAP-11, MAP-72, MAP-73
+ * MAP-12, MAP-75, MAP-76
+ * MAP-13, MAP-78, MAP-79
+ */
+ struct Building : HasIdentifier, ModifierValue {
+ friend struct BuildingManager;
+
+ using level_t = int16_t;
+
+ private:
+ BuildingType const& type;
+ const std::string on_completion; //probably sound played on completion
+ const fixed_point_t completion_size;
+ const level_t max_level;
+ const std::map<Good const*, fixed_point_t> goods_cost;
+ const fixed_point_t cost;
+ const Timespan build_time; //time
+ const bool visibility;
+ const bool on_map; //onmap
+
+ const bool default_enabled;
+ ProductionType const* production_type;
+ const bool pop_build_factory;
+ const bool strategic_factory;
+ const bool advanced_factory;
+
+ const level_t fort_level; //probably the step-per-level
+
+ const uint64_t naval_capacity;
+ const std::vector<fixed_point_t> colonial_points;
+ const bool in_province; //province
+ const bool one_per_state;
+ const fixed_point_t colonial_range;
+
+ const fixed_point_t infrastructure;
+ const fixed_point_t movement_cost;
+ const fixed_point_t local_ship_build;
+ const bool spawn_railway_track;
+
+ const bool sail; //only in clipper shipyard
+ const bool steam; //only in steamer shipyard
+ const bool capital; //only in naval base
+ const bool port; //only in naval base
+
+ Building(std::string_view identifier, BuildingType const& type, ARGS);
+
+ public:
+ Building(Building&&) = default;
+
+ BuildingType const& get_type() const;
+ std::string_view get_on_completion() const;
+ fixed_point_t get_completion_size() const;
+ level_t get_max_level() const;
+ std::map<Good const*, fixed_point_t> const& get_goods_cost() const;
+ fixed_point_t get_cost() const;
+ Timespan get_build_time() const;
+ bool has_visibility() const;
+ bool is_on_map() const;
+
+ bool is_default_enabled() const;
+ ProductionType const* get_production_type() const;
+ bool is_pop_built_factory() const;
+ bool is_strategic_factory() const;
+ bool is_advanced_factory() const;
+
+ level_t get_fort_level() const;
+
+ uint64_t get_naval_capacity() const;
+ std::vector<fixed_point_t> const& get_colonial_points() const;
+ bool is_in_province() const;
+ bool is_one_per_state() const;
+ fixed_point_t get_colonial_range() const;
+
+ fixed_point_t get_infrastructure() const;
+ fixed_point_t get_movement_cost() const;
+ fixed_point_t get_local_ship_build() const;
+ bool spawned_railway_track() const;
+ };
+
+ struct BuildingType : HasIdentifier {
+ friend struct BuildingManager;
+
+ private:
+ BuildingType(std::string_view new_identifier);
+
+ public:
+ BuildingType(BuildingType&&) = default;
+ };
+
+ enum class ExpansionState {
+ CannotExpand,
+ CanExpand,
+ Preparing,
+ Expanding
+ };
+
+ struct BuildingInstance : HasIdentifier { //used in the actual game
+ friend struct BuildingManager;
+ using level_t = Building::level_t;
+
+ private:
+ Building const& building;
+
+ level_t level = 0;
+ ExpansionState expansion_state = ExpansionState::CannotExpand;
+ Date start, end;
+ float expansion_progress;
+
+ bool _can_expand() const;
+
+ BuildingInstance(Building const& building);
+
+ public:
+ BuildingInstance(BuildingInstance&&) = default;
+
+ Building const& get_building() const;
+
+ level_t get_current_level() const;
+ ExpansionState get_expansion_state() const;
+ Date const& get_start_date() const;
+ Date const& get_end_date() const;
+ float get_expansion_progress() const;
+
+ bool expand();
+ void update_state(Date const& today);
+ void tick(Date const& today);
+
+ };
+
+ struct Province;
+
+ struct BuildingManager {
+ using level_t = Building::level_t; //this is getting ridiculous
+
+ private:
+ IdentifierRegistry<BuildingType> building_types;
+ IdentifierRegistry<Building> buildings;
+
+ public:
+ BuildingManager();
+
+ bool add_building_type(std::string_view identifier);
+ IDENTIFIER_REGISTRY_ACCESSORS(building_type)
+
+ bool add_building(std::string_view identifier, BuildingType const* type, ARGS);
+ IDENTIFIER_REGISTRY_ACCESSORS(building)
+
+ bool load_buildings_file(GoodManager const& good_manager, ProductionTypeManager const& production_type_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root);
+
+ bool generate_province_buildings(Province& province) const;
+ };
+}
diff --git a/src/openvic-simulation/economy/EconomyManager.hpp b/src/openvic-simulation/economy/EconomyManager.hpp
new file mode 100644
index 0000000..05dfc91
--- /dev/null
+++ b/src/openvic-simulation/economy/EconomyManager.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "openvic-simulation/economy/Building.hpp"
+#include "openvic-simulation/economy/Good.hpp"
+#include "openvic-simulation/economy/ProductionType.hpp"
+
+namespace OpenVic {
+ struct EconomyManager {
+ private:
+ BuildingManager building_manager;
+ GoodManager good_manager;
+ ProductionTypeManager production_type_manager;
+ public:
+ REF_GETTERS(building_manager)
+ REF_GETTERS(good_manager)
+ REF_GETTERS(production_type_manager)
+
+ inline bool load_production_types_file(PopManager const& pop_manager, ast::NodeCPtr root) {
+ return production_type_manager.load_production_types_file(good_manager, pop_manager, root);
+ }
+
+ inline bool load_buildings_file(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
+ return building_manager.load_buildings_file(good_manager, production_type_manager, modifier_manager, root);
+ }
+ };
+}
diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp
index 7f020fe..1dce41f 100644
--- a/src/openvic-simulation/economy/Good.hpp
+++ b/src/openvic-simulation/economy/Good.hpp
@@ -66,11 +66,11 @@ namespace OpenVic {
GoodManager();
bool add_good_category(std::string_view identifier);
- IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(GoodCategory, good_category, good_categories)
+ IDENTIFIER_REGISTRY_ACCESSORS_CUSTOM_PLURAL(good_category, good_categories)
bool add_good(std::string_view identifier, colour_t colour, GoodCategory const* category, Good::price_t base_price,
bool available_from_start, bool tradeable, bool money, bool overseas_penalty);
- IDENTIFIER_REGISTRY_ACCESSORS(Good, good)
+ IDENTIFIER_REGISTRY_ACCESSORS(good)
void reset_to_defaults();
bool load_goods_file(ast::NodeCPtr root);
diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp
index 2c7c431..01d45be 100644
--- a/src/openvic-simulation/economy/ProductionType.cpp
+++ b/src/openvic-simulation/economy/ProductionType.cpp
@@ -82,16 +82,22 @@ bool ProductionType::is_mine() const {
ProductionTypeManager::ProductionTypeManager() : production_types { "production types" } {}
-node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager,
+node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager,
callback_t<EmployedPop> cb) {
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
- std::string_view pop_type, effect;
+ std::string_view pop_type;
+ EmployedPop::effect_t effect;
fixed_point_t effect_multiplier = 1, amount = 1;
+ using enum EmployedPop::effect_t;
+ static const string_map_t<EmployedPop::effect_t> effect_map = {
+ { "input", INPUT }, { "output", OUTPUT }, { "throughput", THROUGHPUT }
+ };
+
bool res = expect_dictionary_keys(
"poptype", ONE_EXACTLY, expect_identifier(assign_variable_callback(pop_type)),
- "effect", ONE_EXACTLY, expect_identifier(assign_variable_callback(effect)),
+ "effect", ONE_EXACTLY, expect_identifier(expect_mapped_string(effect_map, assign_variable_callback(effect))),
"effect_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(effect_multiplier)),
"amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(amount))
)(node);
@@ -107,20 +113,11 @@ node_callback_t ProductionTypeManager::_expect_employed_pop(GoodManager& good_ma
}
}
- EmployedPop::effect_t found_effect;
- if (effect == "input") found_effect = EmployedPop::effect_t::INPUT;
- else if (effect == "output") found_effect = EmployedPop::effect_t::OUTPUT;
- else if (effect == "throughput") found_effect = EmployedPop::effect_t::THROUGHPUT;
- else {
- Logger::error("Found invalid effect ", effect, " while parsing production types!");
- return false;
- }
-
- return res & cb(EmployedPop { found_pop_type, artisan, found_effect, effect_multiplier, amount });
+ return res & cb(EmployedPop { found_pop_type, artisan, effect, effect_multiplier, amount });
};
}
-node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager,
+node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager,
callback_t<std::vector<EmployedPop>> cb) {
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
@@ -141,7 +138,7 @@ node_callback_t ProductionTypeManager::_expect_employed_pop_list(GoodManager& go
return false; \
}
-bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManager& good_manager) {
+bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManager const& good_manager) {
if (identifier.empty()) {
Logger::error("Invalid production type identifier - empty!");
return false;
@@ -174,21 +171,22 @@ bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS, GoodManage
});
}
-#define PARSE_NODE(target_node) expect_dictionary_keys(ALLOW_OTHER_KEYS, \
+#define PARSE_NODE expect_dictionary_keys_and_default( \
+ key_value_success_callback, \
"owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)), \
"employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)), \
- "type", ZERO_OR_ONE, expect_identifier(assign_variable_callback(type)), \
- "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback_uint(workforce)), \
+ "type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))), \
+ "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)), \
"input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)), \
- "output_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods)), \
+ "output_goods", ZERO_OR_ONE, expect_identifier(good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods))), \
"value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)), \
"efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)), \
"is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)), \
"farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)), \
"mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine)) \
- )(target_node)
+ )
-bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root) {
+bool ProductionTypeManager::load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root) {
size_t expected_types = 0;
// pass 1: find and store template identifiers
@@ -196,25 +194,27 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager
std::map<std::string_view, std::string_view> template_target_map;
bool ret = expect_dictionary(
[this, &expected_types, &templates, &template_target_map](std::string_view key, ast::NodeCPtr value) -> bool {
- std::string_view template_id = "";
- bool ret = expect_dictionary_keys(ALLOW_OTHER_KEYS,
- "template", ZERO_OR_ONE, expect_identifier(assign_variable_callback(template_id))
- )(value);
-
- if (!template_id.empty()) {
- templates.emplace(template_id);
- template_target_map.emplace(key, template_id);
- }
-
expected_types++;
- return ret;
+ std::string_view template_id = "";
+ bool found_template = false;
+ const bool ret = expect_key("template", expect_identifier(assign_variable_callback(template_id)), &found_template)(value);
+ if (found_template) {
+ if (ret) {
+ templates.emplace(template_id);
+ template_target_map.emplace(key, template_id);
+ } else {
+ Logger::error("Failed get template identifier for ", key);
+ return false;
+ }
+ }
+ return true;
}
)(root);
// pass 2: create and populate the template map
std::map<std::string_view, ast::NodeCPtr> template_node_map;
- expect_dictionary(
+ ret &= expect_dictionary(
[this, &expected_types, &templates, &template_node_map](std::string_view key, ast::NodeCPtr value) -> bool {
if (templates.contains(key)) {
template_node_map.emplace(key, value);
@@ -233,7 +233,7 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager
EmployedPop owner;
std::vector<EmployedPop> employees;
- std::string_view type;
+ ProductionType::type_t type;
Good const* output_goods = nullptr;
Pop::pop_size_t workforce = 0; // 0 is a meaningless value -> unset
std::map<Good const*, fixed_point_t> input_goods, efficiency;
@@ -243,6 +243,11 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager
bool ret = true;
+ using enum ProductionType::type_t;
+ static const string_map_t<ProductionType::type_t> type_map = {
+ { "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN }
+ };
+
// apply template first
if (template_target_map.contains(key)) {
std::string_view template_id = template_target_map[key];
@@ -254,17 +259,8 @@ bool ProductionTypeManager::load_production_types_file(GoodManager& good_manager
ret &= PARSE_NODE(node);
- ProductionType::type_t type_enum;
- if (type == "factory") type_enum = ProductionType::type_t::FACTORY;
- else if (type == "rgo") type_enum = ProductionType::type_t::RGO;
- else if (type == "artisan") type_enum = ProductionType::type_t::ARTISAN;
- else {
- Logger::error("Invalid production type for ", key, ": ", type);
- ret = false;
- }
-
ret &= add_production_type(
- key, owner, employees, type_enum, workforce, input_goods, output_goods, value,
+ key, owner, employees, type, workforce, input_goods, output_goods, value,
bonuses, efficiency, coastal, farm, mine, good_manager
);
return ret;
diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp
index 755eda8..420e70e 100644
--- a/src/openvic-simulation/economy/ProductionType.hpp
+++ b/src/openvic-simulation/economy/ProductionType.hpp
@@ -95,17 +95,17 @@ namespace OpenVic {
private:
IdentifierRegistry<ProductionType> production_types;
- NodeTools::node_callback_t _expect_employed_pop(GoodManager& good_manager, PopManager& pop_manager,
+ NodeTools::node_callback_t _expect_employed_pop(GoodManager const& good_manager, PopManager const& pop_manager,
NodeTools::callback_t<EmployedPop> cb);
- NodeTools::node_callback_t _expect_employed_pop_list(GoodManager& good_manager, PopManager& pop_manager,
+ NodeTools::node_callback_t _expect_employed_pop_list(GoodManager const& good_manager, PopManager const& pop_manager,
NodeTools::callback_t<std::vector<EmployedPop>> cb);
public:
ProductionTypeManager();
- bool add_production_type(PRODUCTION_TYPE_ARGS, GoodManager& good_manager);
- IDENTIFIER_REGISTRY_ACCESSORS(ProductionType, production_type)
+ bool add_production_type(PRODUCTION_TYPE_ARGS, GoodManager const& good_manager);
+ IDENTIFIER_REGISTRY_ACCESSORS(production_type)
- bool load_production_types_file(GoodManager& good_manager, PopManager& pop_manager, ast::NodeCPtr root);
+ bool load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root);
};
} \ No newline at end of file