Skip to content

Commit bfcb453

Browse files
committed
Improved validation of production types and renamed properties to be descriptive
1 parent 1d0dc56 commit bfcb453

File tree

2 files changed

+116
-112
lines changed

2 files changed

+116
-112
lines changed

src/openvic-simulation/economy/ProductionType.cpp

Lines changed: 91 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@
33
using namespace OpenVic;
44
using namespace OpenVic::NodeTools;
55

6-
EmployedPop::EmployedPop(
7-
PopType const* new_pop_type, bool new_artisan, effect_t new_effect, fixed_point_t new_effect_multiplier,
8-
fixed_point_t new_amount
9-
) : pop_type { new_pop_type }, artisan { new_artisan }, effect { new_effect }, effect_multiplier { new_effect_multiplier },
10-
amount { new_amount } {}
6+
Job::Job(
7+
PopType const* const new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier,
8+
fixed_point_t new_desired_workforce_share
9+
)
10+
: pop_type { new_pop_type }, effect_type { new_effect_type }, effect_multiplier { new_effect_multiplier },
11+
desired_workforce_share { new_desired_workforce_share } {}
1112

1213
ProductionType::ProductionType(
13-
std::string_view new_identifier, EmployedPop new_owner, std::vector<EmployedPop> new_employees, type_t new_type,
14-
Pop::pop_size_t new_workforce, Good::good_map_t&& new_input_goods, Good const* new_output_goods,
15-
fixed_point_t new_value, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_coastal,
16-
bool new_farm, bool new_mine
17-
) : HasIdentifier { new_identifier }, owner { new_owner }, employees { new_employees }, type { new_type },
18-
workforce { new_workforce }, input_goods { std::move(new_input_goods) }, output_goods { new_output_goods },
19-
value { new_value }, bonuses { std::move(new_bonuses) }, efficiency { std::move(new_efficiency) },
20-
coastal { new_coastal }, farm { new_farm }, mine { new_mine } {}
14+
std::string_view new_identifier, Job new_owner, std::vector<Job> new_jobs, template_type_t new_template_type,
15+
Pop::pop_size_t new_base_workforce_size, Good::good_map_t&& new_input_goods, Good const* const new_output_goods,
16+
fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency,
17+
bool new_is_coastal, bool new_is_farm, bool new_is_mine
18+
)
19+
: HasIdentifier { new_identifier }, owner { new_owner }, jobs { new_jobs }, template_type { new_template_type },
20+
base_workforce_size { new_base_workforce_size }, input_goods { std::move(new_input_goods) },
21+
output_goods { new_output_goods }, base_output_quantity { new_base_output_quantity }, bonuses { std::move(new_bonuses) },
22+
maintenance_requirements { std::move(new_efficiency) }, coastal { new_is_coastal }, farm { new_is_farm },
23+
mine { new_is_mine } {}
2124

2225
bool ProductionType::parse_scripts(GameManager const& game_manager) {
2326
bool ret = true;
@@ -29,96 +32,98 @@ bool ProductionType::parse_scripts(GameManager const& game_manager) {
2932

3033
ProductionTypeManager::ProductionTypeManager() : rgo_owner_sprite { 0 } {}
3134

32-
node_callback_t ProductionTypeManager::_expect_employed_pop(
33-
GoodManager const& good_manager, PopManager const& pop_manager, callback_t<EmployedPop&&> cb
35+
node_callback_t ProductionTypeManager::_expect_job(
36+
GoodManager const& good_manager, PopManager const& pop_manager, callback_t<Job&&> cb
3437
) {
3538

3639
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
37-
std::string_view pop_type;
38-
EmployedPop::effect_t effect;
39-
fixed_point_t effect_multiplier = 1, amount = 1;
40+
using enum Job::effect_t;
4041

41-
using enum EmployedPop::effect_t;
42-
static const string_map_t<EmployedPop::effect_t> effect_map = {
42+
std::string_view pop_type {};
43+
Job::effect_t effect_type {THROUGHPUT};
44+
fixed_point_t effect_multiplier = 1, desired_workforce_share = 1;
45+
46+
static const string_map_t<Job::effect_t> effect_map = {
4347
{ "input", INPUT }, { "output", OUTPUT }, { "throughput", THROUGHPUT }
4448
};
4549

4650
bool res = expect_dictionary_keys(
4751
"poptype", ONE_EXACTLY, expect_identifier(assign_variable_callback(pop_type)),
48-
"effect", ONE_EXACTLY, expect_identifier(expect_mapped_string(effect_map, assign_variable_callback(effect))),
52+
"effect", ONE_EXACTLY, expect_identifier(expect_mapped_string(effect_map, assign_variable_callback(effect_type))),
4953
"effect_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(effect_multiplier)),
50-
"amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(amount))
54+
"amount", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(desired_workforce_share))
5155
)(node);
5256

53-
const PopType* found_pop_type = pop_manager.get_pop_type_by_identifier(pop_type);
54-
bool artisan = false;
55-
if (found_pop_type == nullptr) {
56-
if (pop_type == "artisan") {
57-
artisan = true;
58-
} else {
59-
Logger::error("Found invalid pop type ", pop_type, " while parsing production types!");
60-
return false;
61-
}
62-
}
63-
64-
return res & cb({ found_pop_type, artisan, effect, effect_multiplier, amount });
57+
PopType const* const found_pop_type = pop_manager.get_pop_type_by_identifier(pop_type);
58+
return res & cb({ found_pop_type, effect_type, effect_multiplier, desired_workforce_share });
6559
};
6660
}
6761

68-
node_callback_t ProductionTypeManager::_expect_employed_pop_list(
69-
GoodManager const& good_manager, PopManager const& pop_manager, callback_t<std::vector<EmployedPop>&&> cb
62+
node_callback_t ProductionTypeManager::_expect_job_list(
63+
GoodManager const& good_manager, PopManager const& pop_manager, callback_t<std::vector<Job>&&> cb
7064
) {
7165
return [this, &good_manager, &pop_manager, cb](ast::NodeCPtr node) -> bool {
72-
std::vector<EmployedPop> employed_pops;
73-
bool ret = expect_list(_expect_employed_pop(good_manager, pop_manager, vector_callback(employed_pops)))(node);
74-
ret &= cb(std::move(employed_pops));
66+
std::vector<Job> jobs;
67+
bool ret = expect_list(_expect_job(good_manager, pop_manager, vector_callback(jobs)))(node);
68+
ret &= cb(std::move(jobs));
7569
return ret;
7670
};
7771
}
7872

79-
#define POPTYPE_CHECK(employed_pop) \
80-
if ((employed_pop.pop_type == nullptr && !employed_pop.artisan) || \
81-
(employed_pop.pop_type != nullptr && employed_pop.artisan)) { \
82-
Logger::error("Invalid pop type parsed for owner of production type ", identifier, "!"); \
83-
return false; \
84-
}
85-
8673
bool ProductionTypeManager::add_production_type(
87-
std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type,
88-
Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value,
89-
std::vector<ProductionType::bonus_t>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
74+
std::string_view identifier, Job owner, std::vector<Job> jobs, ProductionType::template_type_t template_type,
75+
Pop::pop_size_t base_workforce_size, Good::good_map_t&& input_goods, Good const* const output_goods,
76+
fixed_point_t base_output_quantity, std::vector<ProductionType::bonus_t>&& bonuses,
77+
Good::good_map_t&& maintenance_requirements, bool is_coastal, bool is_farm, bool is_mine
9078
) {
9179
if (identifier.empty()) {
9280
Logger::error("Invalid production type identifier - empty!");
9381
return false;
9482
}
9583

96-
if (workforce <= 0) {
97-
Logger::error("Workforce for production type ", identifier, " was 0 or unset!");
84+
if (base_workforce_size <= 0) {
85+
Logger::error("Base workforce size ('workforce') for production type ", identifier, " was 0 or unset!");
9886
return false;
9987
}
10088

101-
if (value <= 0) {
102-
Logger::error("Value for production type ", identifier, " was 0 or unset!");
89+
if (base_output_quantity <= 0) {
90+
Logger::error("Base output quantity ('value') for production type ", identifier, " was 0 or unset!");
10391
return false;
10492
}
10593

106-
POPTYPE_CHECK(owner)
107-
108-
for (EmployedPop const& ep : employees) {
109-
POPTYPE_CHECK(ep)
110-
}
111-
11294
if (output_goods == nullptr) {
11395
Logger::error("Output good for production type ", identifier, " was null!");
11496
return false;
11597
}
11698

99+
if (template_type == ProductionType::template_type_t::ARTISAN) {
100+
if (owner.get_pop_type() != nullptr || !jobs.empty()) {
101+
Logger::warning("Artisanal production types don't use owner and employees. Effects are ignored.");
102+
}
103+
} else {
104+
if (owner.get_pop_type() == nullptr) {
105+
Logger::error("Production type ", identifier, " lacks owner or has an invalid pop type.");
106+
return false;
107+
}
108+
109+
if (jobs.empty()) {
110+
Logger::error("Production type ", identifier, " lacks jobs ('employees').");
111+
return false;
112+
}
113+
114+
for (size_t i = 0; i < jobs.size(); i++) {
115+
if (jobs[i].get_pop_type() == nullptr) {
116+
Logger::error("Production type ", identifier, " has invalid pop type in employees[", i, "].");
117+
return false;
118+
}
119+
}
120+
}
121+
117122
const bool ret = production_types.add_item({
118-
identifier, owner, employees, type, workforce, std::move(input_goods),
119-
output_goods, value, std::move(bonuses), std::move(efficiency), coastal, farm, mine
123+
identifier, owner, jobs, template_type, base_workforce_size, std::move(input_goods),
124+
output_goods, base_output_quantity, std::move(bonuses), std::move(maintenance_requirements), is_coastal, is_farm, is_mine
120125
});
121-
if (rgo_owner_sprite <= 0 && ret && type == ProductionType::type_t::RGO && owner.get_pop_type() != nullptr) {
126+
if (rgo_owner_sprite <= 0 && ret && template_type == ProductionType::template_type_t::RGO && owner.get_pop_type() != nullptr) {
122127
/* Set rgo owner sprite to that of the first RGO owner we find. */
123128
rgo_owner_sprite = owner.get_pop_type()->get_sprite();
124129
}
@@ -171,50 +176,51 @@ bool ProductionTypeManager::load_production_types_file(
171176
ret &= expect_dictionary(
172177
[this, &good_manager, &pop_manager, &template_target_map, &template_node_map](
173178
std::string_view key, ast::NodeCPtr node) -> bool {
179+
using enum ProductionType::template_type_t;
180+
174181
if (template_node_map.contains(key)) {
175182
return true;
176183
}
177184

178-
EmployedPop owner;
179-
std::vector<EmployedPop> employees;
180-
ProductionType::type_t type;
185+
Job owner {};
186+
std::vector<Job> jobs;
187+
ProductionType::template_type_t template_type { FACTORY };
181188
Good const* output_goods = nullptr;
182-
Pop::pop_size_t workforce = 0; // 0 is a meaningless value -> unset
183-
Good::good_map_t input_goods, efficiency;
184-
fixed_point_t value = 0; // 0 is a meaningless value -> unset
189+
Pop::pop_size_t base_workforce_size = 0; // 0 is a meaningless value -> unset
190+
Good::good_map_t input_goods, maintenance_requirements;
191+
fixed_point_t base_output_quantity = 0; // 0 is a meaningless value -> unset
185192
std::vector<ProductionType::bonus_t> bonuses;
186-
bool coastal = false, farm = false, mine = false;
193+
bool is_coastal = false, is_farm = false, is_mine = false;
187194

188195
bool ret = true;
189196

190-
using enum ProductionType::type_t;
191-
static const string_map_t<ProductionType::type_t> type_map = {
197+
static const string_map_t<ProductionType::template_type_t> template_type_map = {
192198
{ "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN }
193199
};
194200

195201
const node_callback_t parse_node = expect_dictionary_keys(
196202
"template", ZERO_OR_ONE, success_callback,
197203
"bonus", ZERO_OR_MORE, [&bonuses](ast::NodeCPtr bonus_node) -> bool {
198204
ConditionScript trigger { scope_t::STATE, scope_t::NO_SCOPE, scope_t::NO_SCOPE };
199-
fixed_point_t value {};
205+
fixed_point_t bonus_value {};
200206
const bool ret = expect_dictionary_keys(
201207
"trigger", ONE_EXACTLY, trigger.expect_script(),
202-
"value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(value))
208+
"value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(bonus_value))
203209
)(bonus_node);
204-
bonuses.emplace_back(std::move(trigger), value);
210+
bonuses.emplace_back(std::move(trigger), bonus_value);
205211
return ret;
206212
},
207-
"owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)),
208-
"employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)),
209-
"type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))),
210-
"workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)),
213+
"owner", ZERO_OR_ONE, _expect_job(good_manager, pop_manager, move_variable_callback(owner)),
214+
"employees", ZERO_OR_ONE, _expect_job_list(good_manager, pop_manager, move_variable_callback(jobs)),
215+
"type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(template_type_map, assign_variable_callback(template_type))),
216+
"workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(base_workforce_size)),
211217
"input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)),
212218
"output_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods)),
213-
"value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)),
214-
"efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)),
215-
"is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)),
216-
"farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)),
217-
"mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine))
219+
"value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(base_output_quantity)),
220+
"efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(maintenance_requirements)),
221+
"is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_coastal)),
222+
"farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_farm)),
223+
"mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(is_mine))
218224
);
219225

220226
// apply template first
@@ -235,8 +241,8 @@ bool ProductionTypeManager::load_production_types_file(
235241
ret &= parse_node(node);
236242

237243
ret &= add_production_type(
238-
key, owner, employees, type, workforce, std::move(input_goods), output_goods, value, std::move(bonuses),
239-
std::move(efficiency), coastal, farm, mine
244+
key, owner, jobs, template_type, base_workforce_size, std::move(input_goods), output_goods, base_output_quantity, std::move(bonuses),
245+
std::move(maintenance_requirements), is_coastal, is_farm, is_mine
240246
);
241247
return ret;
242248
}

src/openvic-simulation/economy/ProductionType.hpp

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,55 @@
99
namespace OpenVic {
1010
struct ProductionTypeManager;
1111

12-
struct EmployedPop {
12+
struct Job {
1313
friend struct ProductionTypeManager;
1414

1515
enum struct effect_t { INPUT, OUTPUT, THROUGHPUT };
1616

1717
private:
18-
PopType const* PROPERTY(pop_type); // poptype
19-
bool PROPERTY(artisan); // set by the parser if the magic "artisan" poptype is passed
20-
effect_t PROPERTY(effect);
18+
PopType const* PROPERTY(pop_type);
19+
effect_t PROPERTY(effect_type);
2120
fixed_point_t PROPERTY(effect_multiplier);
22-
fixed_point_t PROPERTY(amount);
21+
fixed_point_t PROPERTY(desired_workforce_share);
2322

24-
EmployedPop(
25-
PopType const* new_pop_type, bool new_artisan, effect_t new_effect, fixed_point_t new_effect_multiplier,
26-
fixed_point_t new_amount
23+
Job(
24+
PopType const* new_pop_type, effect_t new_effect_type, fixed_point_t new_effect_multiplier,
25+
fixed_point_t new_desired_workforce_share
2726
);
2827

2928
public:
30-
EmployedPop() = default;
29+
Job() = default;
3130
};
3231

3332
struct ProductionType : HasIdentifier {
3433
friend struct ProductionTypeManager;
3534

36-
enum struct type_t { FACTORY, RGO, ARTISAN };
35+
enum struct template_type_t { FACTORY, RGO, ARTISAN };
3736

3837
using bonus_t = std::pair<ConditionScript, fixed_point_t>;
3938

4039
private:
41-
const EmployedPop PROPERTY(owner);
42-
std::vector<EmployedPop> PROPERTY(employees);
43-
const type_t PROPERTY(type);
44-
const Pop::pop_size_t workforce;
40+
const Job PROPERTY(owner);
41+
std::vector<Job> PROPERTY(jobs);
42+
const template_type_t PROPERTY(template_type);
43+
const Pop::pop_size_t PROPERTY(base_workforce_size);
4544

4645
Good::good_map_t PROPERTY(input_goods);
4746
Good const* PROPERTY(output_goods);
48-
const fixed_point_t PROPERTY(value);
47+
const fixed_point_t PROPERTY(base_output_quantity);
4948
std::vector<bonus_t> PROPERTY(bonuses);
5049

51-
Good::good_map_t PROPERTY(efficiency);
52-
const bool PROPERTY_CUSTOM_PREFIX(coastal, is); // is_coastal
50+
Good::good_map_t PROPERTY(maintenance_requirements);
51+
const bool PROPERTY_CUSTOM_PREFIX(coastal, is);
5352

5453
const bool PROPERTY_CUSTOM_PREFIX(farm, is);
5554
const bool PROPERTY_CUSTOM_PREFIX(mine, is);
5655

5756
ProductionType(
58-
std::string_view new_identifier, EmployedPop new_owner, std::vector<EmployedPop> new_employees, type_t new_type,
59-
Pop::pop_size_t new_workforce, Good::good_map_t&& new_input_goods, Good const* new_output_goods,
60-
fixed_point_t new_value, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_coastal,
61-
bool new_farm, bool new_mine
57+
std::string_view new_identifier, Job new_owner, std::vector<Job> new_jobs, template_type_t new_template_type,
58+
Pop::pop_size_t new_base_workforce_size, Good::good_map_t&& new_input_goods, Good const* new_output_goods,
59+
fixed_point_t new_base_output_quantity, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_is_coastal,
60+
bool new_is_farm, bool new_is_mine
6261
);
6362

6463
bool parse_scripts(GameManager const& game_manager);
@@ -71,19 +70,18 @@ namespace OpenVic {
7170
IdentifierRegistry<ProductionType> IDENTIFIER_REGISTRY(production_type);
7271
PopType::sprite_t PROPERTY(rgo_owner_sprite);
7372

74-
NodeTools::node_callback_t _expect_employed_pop(
75-
GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<EmployedPop&&> cb
73+
NodeTools::node_callback_t _expect_job(
74+
GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<Job&&> cb
7675
);
77-
NodeTools::node_callback_t _expect_employed_pop_list(
78-
GoodManager const& good_manager, PopManager const& pop_manager,
79-
NodeTools::callback_t<std::vector<EmployedPop>&&> cb
76+
NodeTools::node_callback_t _expect_job_list(
77+
GoodManager const& good_manager, PopManager const& pop_manager, NodeTools::callback_t<std::vector<Job>&&> cb
8078
);
8179

8280
public:
8381
ProductionTypeManager();
8482

8583
bool add_production_type(
86-
std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type,
84+
std::string_view identifier, Job owner, std::vector<Job> employees, ProductionType::template_type_t template_type,
8785
Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value,
8886
std::vector<ProductionType::bonus_t>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
8987
);

0 commit comments

Comments
 (0)