aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openvic-simulation/InstanceManager.cpp3
-rw-r--r--src/openvic-simulation/country/CountryDefinition.cpp19
-rw-r--r--src/openvic-simulation/country/CountryDefinition.hpp3
-rw-r--r--src/openvic-simulation/country/CountryInstance.cpp448
-rw-r--r--src/openvic-simulation/country/CountryInstance.hpp80
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp18
-rw-r--r--src/openvic-simulation/economy/BuildingType.cpp11
-rw-r--r--src/openvic-simulation/economy/BuildingType.hpp5
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp12
-rw-r--r--src/openvic-simulation/history/CountryHistory.hpp3
-rw-r--r--src/openvic-simulation/map/Crime.hpp2
-rw-r--r--src/openvic-simulation/misc/Modifier.cpp9
-rw-r--r--src/openvic-simulation/misc/Modifier.hpp4
-rw-r--r--src/openvic-simulation/politics/Issue.cpp32
-rw-r--r--src/openvic-simulation/politics/Issue.hpp10
-rw-r--r--src/openvic-simulation/politics/Rule.cpp14
-rw-r--r--src/openvic-simulation/politics/Rule.hpp4
-rw-r--r--src/openvic-simulation/research/Technology.cpp28
-rw-r--r--src/openvic-simulation/research/Technology.hpp17
19 files changed, 606 insertions, 116 deletions
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp
index bcae82b..c9ce24a 100644
--- a/src/openvic-simulation/InstanceManager.cpp
+++ b/src/openvic-simulation/InstanceManager.cpp
@@ -79,10 +79,13 @@ bool InstanceManager::setup() {
);
ret &= country_instance_manager.generate_country_instances(
definition_manager.get_country_definition_manager(),
+ definition_manager.get_economy_manager().get_building_type_manager().get_building_types(),
definition_manager.get_research_manager().get_technology_manager().get_technologies(),
definition_manager.get_research_manager().get_invention_manager().get_inventions(),
definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(),
+ definition_manager.get_politics_manager().get_issue_manager().get_reform_groups(),
definition_manager.get_politics_manager().get_government_type_manager().get_government_types(),
+ definition_manager.get_crime_manager().get_crime_modifiers(),
definition_manager.get_pop_manager().get_pop_types(),
definition_manager.get_military_manager().get_unit_type_manager().get_regiment_types(),
definition_manager.get_military_manager().get_unit_type_manager().get_ship_types()
diff --git a/src/openvic-simulation/country/CountryDefinition.cpp b/src/openvic-simulation/country/CountryDefinition.cpp
index a9e7487..12a7a22 100644
--- a/src/openvic-simulation/country/CountryDefinition.cpp
+++ b/src/openvic-simulation/country/CountryDefinition.cpp
@@ -138,24 +138,31 @@ node_callback_t CountryDefinitionManager::load_country_party(
std::string_view party_name;
Date start_date, end_date;
Ideology const* ideology;
- CountryParty::policy_map_t policies;
+ CountryParty::policy_map_t policies { &politics_manager.get_issue_manager().get_issue_groups() };
bool ret = expect_dictionary_keys_and_default(
[&politics_manager, &policies, &party_name](std::string_view key, ast::NodeCPtr value) -> bool {
return politics_manager.get_issue_manager().expect_issue_group_str(
[&politics_manager, &policies, value, &party_name](IssueGroup const& group) -> bool {
- if (policies.contains(&group)) {
+ CountryParty::policy_map_t::value_ref_t policy = policies[group];
+
+ if (policy != nullptr) {
Logger::error("Country party ", party_name, " has duplicate entry for ", group.get_identifier());
return false;
}
+
return politics_manager.get_issue_manager().expect_issue_identifier(
- [&policies, &group](Issue const& issue) -> bool {
+ [&group, &policy](Issue const& issue) -> bool {
if (&issue.get_group() == &group) {
- return map_callback(policies, &group)(&issue);
+ policy = &issue;
+ return true;
}
+
// TODO - change this back to error/false once TGC no longer has this issue
- Logger::warning("Invalid policy ", issue.get_identifier(), ", group is ",
- issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected");
+ Logger::warning(
+ "Invalid policy ", issue.get_identifier(), ", group is ",
+ issue.get_group().get_identifier(), " when ", group.get_identifier(), " was expected."
+ );
return true;
}
)(value);
diff --git a/src/openvic-simulation/country/CountryDefinition.hpp b/src/openvic-simulation/country/CountryDefinition.hpp
index f04796a..6462be1 100644
--- a/src/openvic-simulation/country/CountryDefinition.hpp
+++ b/src/openvic-simulation/country/CountryDefinition.hpp
@@ -14,6 +14,7 @@
#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/types/IndexedMap.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
namespace OpenVic {
@@ -23,7 +24,7 @@ namespace OpenVic {
struct CountryParty : HasIdentifierAndColour {
friend struct CountryDefinitionManager;
- using policy_map_t = ordered_map<IssueGroup const*, Issue const*>;
+ using policy_map_t = IndexedMap<IssueGroup, Issue const*>;
private:
const Date PROPERTY(start_date);
diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp
index 4fab010..183b0c8 100644
--- a/src/openvic-simulation/country/CountryInstance.cpp
+++ b/src/openvic-simulation/country/CountryInstance.cpp
@@ -2,6 +2,7 @@
#include "openvic-simulation/country/CountryDefinition.hpp"
#include "openvic-simulation/history/CountryHistory.hpp"
+#include "openvic-simulation/map/Crime.hpp"
#include "openvic-simulation/map/MapInstance.hpp"
#include "openvic-simulation/misc/Define.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
@@ -16,10 +17,13 @@ static constexpr colour_t ERROR_COLOUR = colour_t::from_integer(0xFF0000);
CountryInstance::CountryInstance(
CountryDefinition const* new_country_definition,
- decltype(technologies)::keys_t const& technology_keys,
- decltype(inventions)::keys_t const& invention_keys,
+ decltype(unlocked_building_types)::keys_t const& building_type_keys,
+ decltype(unlocked_technologies)::keys_t const& technology_keys,
+ decltype(unlocked_inventions)::keys_t const& invention_keys,
decltype(upper_house)::keys_t const& ideology_keys,
+ decltype(reforms)::keys_t const& reform_keys,
decltype(government_flag_overrides)::keys_t const& government_type_keys,
+ decltype(unlocked_crimes)::keys_t const& crime_keys,
decltype(pop_type_distribution)::keys_t const& pop_type_keys,
decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys,
decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys
@@ -44,13 +48,14 @@ CountryInstance::CountryInstance(
industrial_power_from_investments {},
industrial_rank { 0 },
foreign_investments {},
+ unlocked_building_types { &building_type_keys },
/* Budget */
cash_stockpile { 0 },
/* Technology */
- technologies { &technology_keys },
- inventions { &invention_keys },
+ unlocked_technologies { &technology_keys },
+ unlocked_inventions { &invention_keys },
current_research { nullptr },
invested_research_points { 0 },
expected_completion_date {},
@@ -65,13 +70,16 @@ CountryInstance::CountryInstance(
last_election {},
ruling_party { nullptr },
upper_house { &ideology_keys },
- reforms {},
+ reforms { &reform_keys },
+ total_administrative_multiplier { 0 },
+ rule_set {},
government_flag_overrides { &government_type_keys },
flag_government_type { nullptr },
suppression_points { 0 },
infamy { 0 },
plurality { 0 },
revanchism { 0 },
+ unlocked_crimes { &crime_keys },
/* Population */
primary_culture { nullptr },
@@ -115,7 +123,22 @@ CountryInstance::CountryInstance(
disarmed { false },
unlocked_regiment_types { &unlocked_regiment_types_keys },
allowed_regiment_cultures { RegimentType::allowed_cultures_t::NO_CULTURES },
- unlocked_ship_types { &unlocked_ship_types_keys } {
+ unlocked_ship_types { &unlocked_ship_types_keys },
+ gas_attack_unlock_level { 0 },
+ gas_defence_unlock_level { 0 },
+ unit_variant_unlock_levels {} {
+
+ for (BuildingType const& building_type : *unlocked_building_types.get_keys()) {
+ if (building_type.is_default_enabled()) {
+ unlock_building_type(building_type);
+ }
+ }
+
+ for (Crime const& crime : *unlocked_crimes.get_keys()) {
+ if (crime.is_default_active()) {
+ unlock_crime(crime);
+ }
+ }
for (RegimentType const& regiment_type : *unlocked_regiment_types.get_keys()) {
if (regiment_type.is_active()) {
@@ -220,27 +243,37 @@ bool CountryInstance::set_upper_house(Ideology const* ideology, fixed_point_t po
}
}
-bool CountryInstance::add_reform(Reform const* new_reform) {
- if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) {
- Logger::warning(
- "Attempted to add reform \"", new_reform, "\" to country ", get_identifier(), ": already present!"
- );
- return false;
+bool CountryInstance::set_ruling_party(CountryParty const& new_ruling_party) {
+ if (ruling_party != &new_ruling_party) {
+ ruling_party = &new_ruling_party;
+
+ return update_rule_set();
+ } else {
+ return true;
}
- reforms.push_back(new_reform);
- return true;
}
-bool CountryInstance::remove_reform(Reform const* reform_to_remove) {
- auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove);
- if (existing_entry == reforms.end()) {
- Logger::warning(
- "Attempted to remove reform \"", reform_to_remove, "\" from country ", get_identifier(), ": not present!"
- );
- return false;
+bool CountryInstance::add_reform(Reform const& new_reform) {
+ ReformGroup const& reform_group = new_reform.get_reform_group();
+ decltype(reforms)::value_ref_t reform = reforms[reform_group];
+
+ if (reform != &new_reform) {
+ if (reform_group.is_administrative()) {
+ if (reform != nullptr) {
+ total_administrative_multiplier -= reform->get_administrative_multiplier();
+ }
+ total_administrative_multiplier += new_reform.get_administrative_multiplier();
+ }
+
+ reform = &new_reform;
+
+ // TODO - if new_reform.get_reform_group().get_type().is_uncivilised() ?
+ // TODO - new_reform.get_on_execute_trigger() / new_reform.get_on_execute_effect() ?
+
+ return update_rule_set();
+ } else {
+ return true;
}
- reforms.erase(existing_entry);
- return true;
}
template<UnitType::branch_t Branch>
@@ -301,30 +334,311 @@ template bool CountryInstance::remove_leader(LeaderBranched<UnitType::branch_t::
template bool CountryInstance::remove_leader(LeaderBranched<UnitType::branch_t::NAVAL> const*);
template<UnitType::branch_t Branch>
-void CountryInstance::unlock_unit_type(UnitTypeBranched<Branch> const& unit_type) {
- IndexedMap<UnitTypeBranched<Branch>, bool>& unlocked_unit_types = get_unlocked_unit_types<Branch>();
+bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched<Branch> const& unit_type, unlock_level_t unlock_level_change) {
+ IndexedMap<UnitTypeBranched<Branch>, unlock_level_t>& unlocked_unit_types = get_unlocked_unit_types<Branch>();
- decltype(unlocked_regiment_types)::value_ref_t unlock_value = unlocked_unit_types[unit_type];
+ typename IndexedMap<UnitTypeBranched<Branch>, unlock_level_t>::value_ref_t unlock_level = unlocked_unit_types[unit_type];
- if (unlock_value) {
- Logger::warning(
- "Attempted to unlock already-unlocked unit type \"", unit_type.get_identifier(),
- "\" for country ", get_identifier()
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for unit type ", unit_type.get_identifier(), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ return false;
+ }
+
+ unlock_level += unlock_level_change;
+
+ return true;
+}
+
+template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched<UnitType::branch_t::LAND> const&, unlock_level_t);
+template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched<UnitType::branch_t::NAVAL> const&, unlock_level_t);
+
+bool CountryInstance::modify_unit_type_unlock(UnitType const& unit_type, unlock_level_t unlock_level_change) {
+ using enum UnitType::branch_t;
+
+ switch (unit_type.get_branch()) {
+ case LAND:
+ return modify_unit_type_unlock(static_cast<UnitTypeBranched<LAND> const&>(unit_type), unlock_level_change);
+ case NAVAL:
+ return modify_unit_type_unlock(static_cast<UnitTypeBranched<NAVAL> const&>(unit_type), unlock_level_change);
+ default:
+ Logger::error(
+ "Attempted to change unlock level for unit type \"", unit_type.get_identifier(), "\" with invalid branch ",
+ static_cast<uint32_t>(unit_type.get_branch()), " is unlocked for country ", get_identifier()
+ );
+ return false;
+ }
+}
+
+bool CountryInstance::unlock_unit_type(UnitType const& unit_type) {
+ return modify_unit_type_unlock(unit_type, 1);
+}
+
+bool CountryInstance::is_unit_type_unlocked(UnitType const& unit_type) const {
+ using enum UnitType::branch_t;
+
+ switch (unit_type.get_branch()) {
+ case LAND:
+ return unlocked_regiment_types[static_cast<UnitTypeBranched<LAND> const&>(unit_type)] > 0;
+ case NAVAL:
+ return unlocked_ship_types[static_cast<UnitTypeBranched<NAVAL> const&>(unit_type)] > 0;
+ default:
+ Logger::error(
+ "Attempted to check if unit type \"", unit_type.get_identifier(), "\" with invalid branch ",
+ static_cast<uint32_t>(unit_type.get_branch()), " is unlocked for country ", get_identifier()
);
- return;
+ return false;
+ }
+}
+
+bool CountryInstance::modify_building_type_unlock(BuildingType const& building_type, unlock_level_t unlock_level_change) {
+ decltype(unlocked_building_types)::value_ref_t unlock_level = unlocked_building_types[building_type];
+
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for building type ", building_type.get_identifier(), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ return false;
}
- unlock_value = true;
+ unlock_level += unlock_level_change;
+
+ return true;
+}
+
+bool CountryInstance::unlock_building_type(BuildingType const& building_type) {
+ return modify_building_type_unlock(building_type, 1);
+}
+
+bool CountryInstance::is_building_type_unlocked(BuildingType const& building_type) const {
+ return unlocked_building_types[building_type] > 0;
+}
+
+bool CountryInstance::modify_crime_unlock(Crime const& crime, unlock_level_t unlock_level_change) {
+ decltype(unlocked_crimes)::value_ref_t unlock_level = unlocked_crimes[crime];
+
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for crime ", crime.get_identifier(), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ return false;
+ }
+
+ unlock_level += unlock_level_change;
+
+ return true;
+}
+
+bool CountryInstance::unlock_crime(Crime const& crime) {
+ return modify_crime_unlock(crime, 1);
+}
+
+bool CountryInstance::is_crime_unlocked(Crime const& crime) const {
+ return unlocked_crimes[crime] > 0;
+}
- if constexpr (Branch == UnitType::branch_t::LAND) {
- allowed_regiment_cultures = RegimentType::allowed_cultures_get_most_permissive(
- allowed_regiment_cultures, unit_type.get_allowed_cultures()
+bool CountryInstance::modify_gas_attack_unlock(unlock_level_t unlock_level_change) {
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (gas_attack_unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for gas attack in country ", get_identifier(),
+ " to invalid value: current level = ", static_cast<int64_t>(gas_attack_unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(gas_attack_unlock_level + unlock_level_change)
);
+ return false;
}
+
+ gas_attack_unlock_level += unlock_level_change;
+
+ return true;
}
-template void CountryInstance::unlock_unit_type(UnitTypeBranched<UnitType::branch_t::LAND> const&);
-template void CountryInstance::unlock_unit_type(UnitTypeBranched<UnitType::branch_t::NAVAL> const&);
+bool CountryInstance::unlock_gas_attack() {
+ return modify_gas_attack_unlock(1);
+}
+
+bool CountryInstance::is_gas_attack_unlocked() const {
+ return gas_attack_unlock_level > 0;
+}
+
+bool CountryInstance::modify_gas_defence_unlock(unlock_level_t unlock_level_change) {
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (gas_defence_unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for gas defence in country ", get_identifier(),
+ " to invalid value: current level = ", static_cast<int64_t>(gas_defence_unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(gas_defence_unlock_level + unlock_level_change)
+ );
+ return false;
+ }
+
+ gas_defence_unlock_level += unlock_level_change;
+
+ return true;
+}
+
+bool CountryInstance::unlock_gas_defence() {
+ return modify_gas_defence_unlock(1);
+}
+
+bool CountryInstance::is_gas_defence_unlocked() const {
+ return gas_defence_unlock_level > 0;
+}
+
+bool CountryInstance::modify_unit_variant_unlock(unit_variant_t unit_variant, unlock_level_t unlock_level_change) {
+ if (unit_variant < 1) {
+ Logger::error("Trying to modify unlock level for default unit variant 0");
+ return false;
+ }
+
+ if (unit_variant_unlock_levels.size() < unit_variant) {
+ unit_variant_unlock_levels.resize(unit_variant);
+ }
+
+ unlock_level_t& unlock_level = unit_variant_unlock_levels[unit_variant - 1];
+
+ bool ret = true;
+
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for unit variant ", static_cast<uint64_t>(unit_variant), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ ret = false;
+ } else {
+ unlock_level += unlock_level_change;
+ }
+
+ while (!unit_variant_unlock_levels.empty() && unit_variant_unlock_levels.back() < 1) {
+ unit_variant_unlock_levels.pop_back();
+ }
+
+ return ret;
+}
+
+bool CountryInstance::unlock_unit_variant(unit_variant_t unit_variant) {
+ return modify_unit_variant_unlock(unit_variant, 1);
+}
+
+CountryInstance::unit_variant_t CountryInstance::get_max_unlocked_unit_variant() const {
+ return unit_variant_unlock_levels.size();
+}
+
+bool CountryInstance::modify_technology_unlock(Technology const& technology, unlock_level_t unlock_level_change) {
+ decltype(unlocked_technologies)::value_ref_t unlock_level = unlocked_technologies[technology];
+
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for technology ", technology.get_identifier(), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ return false;
+ }
+
+ unlock_level += unlock_level_change;
+
+ bool ret = true;
+
+ // TODO - bool unciv_military ?
+
+ if (technology.get_unit_variant().has_value()) {
+ ret &= modify_unit_variant_unlock(*technology.get_unit_variant(), unlock_level_change);
+ }
+ for (UnitType const* unit : technology.get_activated_units()) {
+ ret &= modify_unit_type_unlock(*unit, unlock_level_change);
+ }
+ for (BuildingType const* building : technology.get_activated_buildings()) {
+ ret &= modify_building_type_unlock(*building, unlock_level_change);
+ }
+
+ return ret;
+}
+
+bool CountryInstance::set_technology_unlock_level(Technology const& technology, unlock_level_t unlock_level) {
+ const unlock_level_t unlock_level_change = unlock_level - unlocked_technologies[technology];
+ return unlock_level_change != 0 ? modify_technology_unlock(technology, unlock_level_change) : true;
+}
+
+bool CountryInstance::unlock_technology(Technology const& technology) {
+ return modify_technology_unlock(technology, 1);
+}
+
+bool CountryInstance::is_technology_unlocked(Technology const& technology) const {
+ return unlocked_technologies[technology] > 0;
+}
+
+bool CountryInstance::modify_invention_unlock(Invention const& invention, unlock_level_t unlock_level_change) {
+ decltype(unlocked_inventions)::value_ref_t unlock_level = unlocked_inventions[invention];
+
+ // This catches subtracting below 0 or adding above the int types maximum value
+ if (unlock_level + unlock_level_change < 0) {
+ Logger::error(
+ "Attempted to change unlock level for invention ", invention.get_identifier(), " in country ",
+ get_identifier(), " to invalid value: current level = ", static_cast<int64_t>(unlock_level), ", change = ",
+ static_cast<int64_t>(unlock_level_change), ", invalid new value = ",
+ static_cast<int64_t>(unlock_level + unlock_level_change)
+ );
+ return false;
+ }
+
+ unlock_level += unlock_level_change;
+
+ bool ret = true;
+
+ // TODO - handle invention.is_news()
+
+ for (UnitType const* unit : invention.get_activated_units()) {
+ ret &= modify_unit_type_unlock(*unit, unlock_level_change);
+ }
+ for (BuildingType const* building : invention.get_activated_buildings()) {
+ ret &= modify_building_type_unlock(*building, unlock_level_change);
+ }
+ for (Crime const* crime : invention.get_enabled_crimes()) {
+ ret &= modify_crime_unlock(*crime, unlock_level_change);
+ }
+ if (invention.will_unlock_gas_attack()) {
+ ret &= modify_gas_attack_unlock(unlock_level_change);
+ }
+ if (invention.will_unlock_gas_defence()) {
+ ret &= modify_gas_defence_unlock(unlock_level_change);
+ }
+
+ return ret;
+}
+
+bool CountryInstance::set_invention_unlock_level(Invention const& invention, unlock_level_t unlock_level) {
+ const unlock_level_t unlock_level_change = unlock_level - unlocked_inventions[invention];
+ return unlock_level_change != 0 ? modify_invention_unlock(invention, unlock_level_change) : true;
+}
+
+bool CountryInstance::unlock_invention(Invention const& invention) {
+ return modify_invention_unlock(invention, 1);
+}
+
+bool CountryInstance::is_invention_unlocked(Invention const& invention) const {
+ return unlocked_inventions[invention] > 0;
+}
bool CountryInstance::is_primary_culture(Culture const& culture) const {
return &culture == primary_culture;
@@ -362,7 +676,9 @@ bool CountryInstance::apply_history_to_country(
ret &= add_accepted_culture(*culture);
}
set_optional(religion, entry.get_religion());
- set_optional(ruling_party, entry.get_ruling_party());
+ if (entry.get_ruling_party()) {
+ ret &= set_ruling_party(**entry.get_ruling_party());
+ }
set_optional(last_election, entry.get_last_election());
ret &= upper_house.copy(entry.get_upper_house());
if (entry.get_capital()) {
@@ -376,7 +692,7 @@ bool CountryInstance::apply_history_to_country(
}
set_optional(prestige, entry.get_prestige());
for (Reform const* reform : entry.get_reforms()) {
- ret &= add_reform(reform);
+ ret &= add_reform(*reform);
}
set_optional(tech_school, entry.get_tech_school());
constexpr auto set_bool_map_to_indexed_map =
@@ -385,8 +701,12 @@ bool CountryInstance::apply_history_to_country(
target[*key] = value;
}
};
- set_bool_map_to_indexed_map(technologies, entry.get_technologies());
- set_bool_map_to_indexed_map(inventions, entry.get_inventions());
+ for (auto const& [technology, level] : entry.get_technologies()) {
+ ret &= set_technology_unlock_level(*technology, level);
+ }
+ for (auto const& [invention, activated] : entry.get_inventions()) {
+ ret &= set_invention_unlock_level(*invention, activated ? 1 : 0);
+ }
apply_foreign_investments(entry.get_foreign_investment(), country_instance_manager);
// These need to be applied to pops
@@ -583,6 +903,26 @@ void CountryInstance::_update_military(DefineManager const& define_manager, Unit
// TODO - update max_ship_supply, leadership_points, war_exhaustion
}
+bool CountryInstance::update_rule_set() {
+ rule_set.clear();
+
+ if (ruling_party != nullptr) {
+ for (Issue const* issue : ruling_party->get_policies()) {
+ if (issue != nullptr) {
+ rule_set |= issue->get_rules();
+ }
+ }
+ }
+
+ for (Reform const* reform : reforms) {
+ if (reform != nullptr) {
+ rule_set |= reform->get_rules();
+ }
+ }
+
+ return rule_set.trim_and_resolve_conflicts(true);
+}
+
void CountryInstance::update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager) {
// Order of updates might need to be changed/functions split up to account for dependencies
_update_production(define_manager);
@@ -751,24 +1091,38 @@ CountryInstance const& CountryInstanceManager::get_country_instance_from_definit
bool CountryInstanceManager::generate_country_instances(
CountryDefinitionManager const& country_definition_manager,
- decltype(CountryInstance::technologies)::keys_t const& technology_keys,
- decltype(CountryInstance::inventions)::keys_t const& invention_keys,
+ decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys,
+ decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys,
+ decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys,
decltype(CountryInstance::upper_house)::keys_t const& ideology_keys,
+ decltype(CountryInstance::reforms)::keys_t const& reform_keys,
decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys,
+ decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys,
decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys,
decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys,
decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys
) {
reserve_more(country_instances, country_definition_manager.get_country_definition_count());
+ bool ret = true;
+
for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) {
- country_instances.add_item({
- &country_definition, technology_keys, invention_keys, ideology_keys, government_type_keys, pop_type_keys,
- unlocked_regiment_types_keys, unlocked_ship_types_keys
+ ret &= country_instances.add_item({
+ &country_definition,
+ building_type_keys,
+ technology_keys,
+ invention_keys,
+ ideology_keys,
+ reform_keys,
+ government_type_keys,
+ crime_keys,
+ pop_type_keys,
+ unlocked_regiment_types_keys,
+ unlocked_ship_types_keys
});
}
- return true;
+ return ret;
}
bool CountryInstanceManager::apply_history_to_countries(
diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp
index c43f0cd..a7128aa 100644
--- a/src/openvic-simulation/country/CountryInstance.hpp
+++ b/src/openvic-simulation/country/CountryInstance.hpp
@@ -6,6 +6,7 @@
#include "openvic-simulation/military/Leader.hpp"
#include "openvic-simulation/military/UnitInstanceGroup.hpp"
+#include "openvic-simulation/politics/Rule.hpp"
#include "openvic-simulation/pop/Pop.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
@@ -24,9 +25,12 @@ namespace OpenVic {
struct GovernmentType;
struct CountryParty;
struct Ideology;
+ struct ReformGroup;
struct Reform;
+ struct Crime;
struct Culture;
struct Religion;
+ struct BuildingType;
struct CountryHistoryEntry;
struct MapInstance;
struct DefineManager;
@@ -53,6 +57,9 @@ namespace OpenVic {
COUNTRY_STATUS_PRIMITIVE
};
+ using unlock_level_t = int8_t;
+ using unit_variant_t = uint8_t;
+
private:
/* Main attributes */
// We can always assume country_definition is not null, as it is initialised from a reference and only ever changed
@@ -79,6 +86,7 @@ namespace OpenVic {
std::vector<std::pair<CountryInstance const*, fixed_point_t>> PROPERTY(industrial_power_from_investments);
size_t PROPERTY(industrial_rank);
fixed_point_map_t<CountryInstance const*> PROPERTY(foreign_investments);
+ IndexedMap<BuildingType, unlock_level_t> PROPERTY(unlocked_building_types);
// TODO - total amount of each good produced
/* Budget */
@@ -86,8 +94,8 @@ namespace OpenVic {
// TODO - cash stockpile change over last 30 days
/* Technology */
- IndexedMap<Technology, bool> PROPERTY(technologies);
- IndexedMap<Invention, bool> PROPERTY(inventions);
+ IndexedMap<Technology, unlock_level_t> PROPERTY(unlocked_technologies);
+ IndexedMap<Invention, unlock_level_t> PROPERTY(unlocked_inventions);
Technology const* PROPERTY(current_research);
fixed_point_t PROPERTY(invested_research_points);
Date PROPERTY(expected_completion_date);
@@ -103,7 +111,9 @@ namespace OpenVic {
Date PROPERTY(last_election);
CountryParty const* PROPERTY(ruling_party);
IndexedMap<Ideology, fixed_point_t> PROPERTY(upper_house);
- std::vector<Reform const*> PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history
+ IndexedMap<ReformGroup, Reform const*> PROPERTY(reforms);
+ fixed_point_t PROPERTY(total_administrative_multiplier);
+ RuleSet PROPERTY(rule_set);
// TODO - national issue support distribution (for just voters and for everyone)
IndexedMap<GovernmentType, GovernmentType const*> PROPERTY(government_flag_overrides);
GovernmentType const* PROPERTY(flag_government_type);
@@ -111,6 +121,7 @@ namespace OpenVic {
fixed_point_t PROPERTY(infamy);
fixed_point_t PROPERTY(plurality);
fixed_point_t PROPERTY(revanchism);
+ IndexedMap<Crime, unlock_level_t> PROPERTY(unlocked_crimes);
// TODO - rebel movements
/* Population */
@@ -157,9 +168,12 @@ namespace OpenVic {
fixed_point_t PROPERTY(war_exhaustion);
bool PROPERTY_CUSTOM_PREFIX(mobilised, is);
bool PROPERTY_CUSTOM_PREFIX(disarmed, is);
- IndexedMap<RegimentType, bool> PROPERTY(unlocked_regiment_types);
+ IndexedMap<RegimentType, unlock_level_t> PROPERTY(unlocked_regiment_types);
RegimentType::allowed_cultures_t PROPERTY(allowed_regiment_cultures);
- IndexedMap<ShipType, bool> PROPERTY(unlocked_ship_types);
+ IndexedMap<ShipType, unlock_level_t> PROPERTY(unlocked_ship_types);
+ unlock_level_t PROPERTY(gas_attack_unlock_level);
+ unlock_level_t PROPERTY(gas_defence_unlock_level);
+ std::vector<unlock_level_t> PROPERTY(unit_variant_unlock_levels);
UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies);
UNIT_BRANCHED_GETTER(get_leaders, generals, admirals);
@@ -167,10 +181,13 @@ namespace OpenVic {
CountryInstance(
CountryDefinition const* new_country_definition,
- decltype(technologies)::keys_t const& technology_keys,
- decltype(inventions)::keys_t const& invention_keys,
+ decltype(unlocked_building_types)::keys_t const& building_type_keys,
+ decltype(unlocked_technologies)::keys_t const& technology_keys,
+ decltype(unlocked_inventions)::keys_t const& invention_keys,
decltype(upper_house)::keys_t const& ideology_keys,
+ decltype(reforms)::keys_t const& reform_keys,
decltype(government_flag_overrides)::keys_t const& government_type_keys,
+ decltype(unlocked_crimes)::keys_t const& crime_keys,
decltype(pop_type_distribution)::keys_t const& pop_type_keys,
decltype(unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys,
decltype(unlocked_ship_types)::keys_t const& unlocked_ship_types_keys
@@ -200,8 +217,8 @@ namespace OpenVic {
bool remove_accepted_culture(Culture const& culture_to_remove);
/* Set a party's popularity in the upper house. */
bool set_upper_house(Ideology const* ideology, fixed_point_t popularity);
- bool add_reform(Reform const* new_reform);
- bool remove_reform(Reform const* reform_to_remove);
+ bool set_ruling_party(CountryParty const& new_ruling_party);
+ bool add_reform(Reform const& new_reform);
template<UnitType::branch_t Branch>
bool add_unit_instance_group(UnitInstanceGroup<Branch>& group);
@@ -214,7 +231,41 @@ namespace OpenVic {
bool remove_leader(LeaderBranched<Branch> const* leader);
template<UnitType::branch_t Branch>
- void unlock_unit_type(UnitTypeBranched<Branch> const& unit_type);
+ bool modify_unit_type_unlock(UnitTypeBranched<Branch> const& unit_type, unlock_level_t unlock_level_change);
+
+ bool modify_unit_type_unlock(UnitType const& unit_type, unlock_level_t unlock_level_change);
+ bool unlock_unit_type(UnitType const& unit_type);
+ bool is_unit_type_unlocked(UnitType const& unit_type) const;
+
+ bool modify_building_type_unlock(BuildingType const& building_type, unlock_level_t unlock_level_change);
+ bool unlock_building_type(BuildingType const& building_type);
+ bool is_building_type_unlocked(BuildingType const& building_type) const;
+
+ bool modify_crime_unlock(Crime const& crime, unlock_level_t unlock_level_change);
+ bool unlock_crime(Crime const& crime);
+ bool is_crime_unlocked(Crime const& crime) const;
+
+ bool modify_gas_attack_unlock(unlock_level_t unlock_level_change);
+ bool unlock_gas_attack();
+ bool is_gas_attack_unlocked() const;
+
+ bool modify_gas_defence_unlock(unlock_level_t unlock_level_change);
+ bool unlock_gas_defence();
+ bool is_gas_defence_unlocked() const;
+
+ bool modify_unit_variant_unlock(unit_variant_t unit_variant, unlock_level_t unlock_level_change);
+ bool unlock_unit_variant(unit_variant_t unit_variant);
+ unit_variant_t get_max_unlocked_unit_variant() const;
+
+ bool modify_technology_unlock(Technology const& technology, unlock_level_t unlock_level_change);
+ bool set_technology_unlock_level(Technology const& technology, unlock_level_t unlock_level);
+ bool unlock_technology(Technology const& technology);
+ bool is_technology_unlocked(Technology const& technology) const;
+
+ bool modify_invention_unlock(Invention const& invention, unlock_level_t unlock_level_change);
+ bool set_invention_unlock_level(Invention const& invention, unlock_level_t unlock_level);
+ bool unlock_invention(Invention const& invention);
+ bool is_invention_unlocked(Invention const& invention) const;
bool is_primary_culture(Culture const& culture) const;
// This only checks the accepted cultures list, ignoring the primary culture.
@@ -241,6 +292,8 @@ namespace OpenVic {
void _update_diplomacy();
void _update_military(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager);
+ bool update_rule_set();
+
public:
void update_gamestate(DefineManager const& define_manager, UnitTypeManager const& unit_type_manager);
@@ -271,10 +324,13 @@ namespace OpenVic {
bool generate_country_instances(
CountryDefinitionManager const& country_definition_manager,
- decltype(CountryInstance::technologies)::keys_t const& technology_keys,
- decltype(CountryInstance::inventions)::keys_t const& invention_keys,
+ decltype(CountryInstance::unlocked_building_types)::keys_t const& building_type_keys,
+ decltype(CountryInstance::unlocked_technologies)::keys_t const& technology_keys,
+ decltype(CountryInstance::unlocked_inventions)::keys_t const& invention_keys,
decltype(CountryInstance::upper_house)::keys_t const& ideology_keys,
+ decltype(CountryInstance::reforms)::keys_t const& reform_keys,
decltype(CountryInstance::government_flag_overrides)::keys_t const& government_type_keys,
+ decltype(CountryInstance::unlocked_crimes)::keys_t const& crime_keys,
decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys,
decltype(CountryInstance::unlocked_regiment_types)::keys_t const& unlocked_regiment_types_keys,
decltype(CountryInstance::unlocked_ship_types)::keys_t const& unlocked_ship_types_keys
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 79fb0ea..51e3e82 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -443,6 +443,22 @@ namespace OpenVic {
return assign_variable_callback_cast<T, T>(var);
}
+ /* By default this will only allow an optional to be set once. Set allow_overwrite
+ * to true to allow multiple assignments, with the last taking precedence. */
+ template<typename T>
+ Callback<T> auto assign_variable_callback_opt(
+ std::optional<T>& var, bool allow_overwrite = false
+ ) {
+ return [&var, allow_overwrite](T const& val) -> bool {
+ if (!allow_overwrite && var.has_value()) {
+ Logger::error("Cannot assign value to already-initialised optional!");
+ return false;
+ }
+ var = val;
+ return true;
+ };
+ }
+
callback_t<std::string_view> assign_variable_callback_string(std::string& var);
template<typename T>
@@ -487,7 +503,7 @@ namespace OpenVic {
) {
return [&var, allow_overwrite](T const& val) -> bool {
if (!allow_overwrite && var.has_value()) {
- Logger::error("Canoot assign pointer value to already-initialised optional!");
+ Logger::error("Cannot assign pointer value to already-initialised optional!");
return false;
}
var = &val;
diff --git a/src/openvic-simulation/economy/BuildingType.cpp b/src/openvic-simulation/economy/BuildingType.cpp
index d096166..f0fc8a8 100644
--- a/src/openvic-simulation/economy/BuildingType.cpp
+++ b/src/openvic-simulation/economy/BuildingType.cpp
@@ -5,9 +5,8 @@ using namespace OpenVic::NodeTools;
BuildingType::BuildingType(
std::string_view identifier, building_type_args_t& building_type_args
-) : HasIdentifier { identifier },
+) : Modifier { identifier, std::move(building_type_args.modifier) },
type { building_type_args.type },
- modifier { std::move(building_type_args.modifier) },
on_completion { building_type_args.on_completion },
completion_size { building_type_args.completion_size },
max_level { building_type_args.max_level },
@@ -133,13 +132,15 @@ bool BuildingTypeManager::load_buildings_file(
port_building_type = &building_type;
} else {
Logger::error(
- "Building type ", building_type, " is marked as a port, but we are already using ", port_building_type,
- " as the port building type!"
+ "Building type ", building_type.get_identifier(), " is marked as a port, but we are already using ",
+ port_building_type->get_identifier(), " as the port building type!"
);
ret = false;
}
} else {
- Logger::error("Building type ", building_type, " is marked as a port, but is not a province building!");
+ Logger::error(
+ "Building type ", building_type.get_identifier(), " is marked as a port, but is not a province building!"
+ );
ret = false;
}
}
diff --git a/src/openvic-simulation/economy/BuildingType.hpp b/src/openvic-simulation/economy/BuildingType.hpp
index 977d6ec..ab999cd 100644
--- a/src/openvic-simulation/economy/BuildingType.hpp
+++ b/src/openvic-simulation/economy/BuildingType.hpp
@@ -16,7 +16,7 @@ namespace OpenVic {
* MAP-12, MAP-75, MAP-76
* MAP-13, MAP-78, MAP-79
*/
- struct BuildingType : HasIdentifier {
+ struct BuildingType : Modifier {
friend struct BuildingTypeManager;
using level_t = int16_t;
@@ -42,7 +42,6 @@ namespace OpenVic {
private:
std::string PROPERTY(type);
- ModifierValue PROPERTY(modifier);
std::string PROPERTY(on_completion); // probably sound played on completion
fixed_point_t PROPERTY(completion_size);
level_t PROPERTY(max_level);
@@ -51,7 +50,7 @@ namespace OpenVic {
Timespan PROPERTY(build_time); // time
bool PROPERTY(on_map); // onmap
- bool PROPERTY(default_enabled);
+ bool PROPERTY_CUSTOM_PREFIX(default_enabled, is);
ProductionType const* PROPERTY(production_type);
bool PROPERTY(pop_build_factory);
bool PROPERTY(strategic_factory);
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
index 04f6292..cd51e19 100644
--- a/src/openvic-simulation/history/CountryHistory.cpp
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -54,7 +54,17 @@ bool CountryHistoryMap::_load_history_entry(
{
Technology const* technology = technology_manager.get_technology_by_identifier(key);
if (technology != nullptr) {
- return expect_int_bool(map_callback(entry.technologies, technology))(value);
+ return expect_uint<decltype(entry.technologies)::mapped_type>(
+ [&entry, technology](decltype(entry.technologies)::mapped_type value) -> bool {
+ if (value > 1) {
+ Logger::warning(
+ "Technology ", technology->get_identifier(),
+ " is applied multiple times in history of country ", entry.get_country().get_identifier()
+ );
+ }
+ return map_callback(entry.technologies, technology)(value);
+ }
+ )(value);
}
}
diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp
index d6a6997..04de653 100644
--- a/src/openvic-simulation/history/CountryHistory.hpp
+++ b/src/openvic-simulation/history/CountryHistory.hpp
@@ -2,6 +2,7 @@
#include <optional>
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/history/HistoryMap.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
@@ -46,7 +47,7 @@ namespace OpenVic {
ordered_set<Reform const*> PROPERTY(reforms);
std::optional<Deployment const*> PROPERTY(inital_oob);
std::optional<TechnologySchool const*> PROPERTY(tech_school);
- ordered_map<Technology const*, bool> PROPERTY(technologies);
+ ordered_map<Technology const*, CountryInstance::unlock_level_t> PROPERTY(technologies);
ordered_map<Invention const*, bool> PROPERTY(inventions);
fixed_point_map_t<CountryDefinition const*> PROPERTY(foreign_investment);
std::optional<fixed_point_t> PROPERTY(consciousness);
diff --git a/src/openvic-simulation/map/Crime.hpp b/src/openvic-simulation/map/Crime.hpp
index cb539f3..6aaf12c 100644
--- a/src/openvic-simulation/map/Crime.hpp
+++ b/src/openvic-simulation/map/Crime.hpp
@@ -7,7 +7,7 @@ namespace OpenVic {
friend struct CrimeManager;
private:
- const bool PROPERTY(default_active);
+ const bool PROPERTY_CUSTOM_PREFIX(default_active, is);
Crime(
std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger,
diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp
index 4d6abb7..9163af5 100644
--- a/src/openvic-simulation/misc/Modifier.cpp
+++ b/src/openvic-simulation/misc/Modifier.cpp
@@ -33,6 +33,14 @@ size_t ModifierValue::get_effect_count() const {
return values.size();
}
+void ModifierValue::clear() {
+ values.clear();
+}
+
+bool ModifierValue::empty() const {
+ return values.empty();
+}
+
fixed_point_t ModifierValue::get_effect(ModifierEffect const* effect, bool* successful) {
const effect_map_t::const_iterator it = values.find(effect);
if (it != values.end()) {
@@ -123,7 +131,6 @@ bool ModifierManager::setup_modifier_effects() {
/* Country Modifier Effects */
ret &= add_modifier_effect("administrative_efficiency", true);
ret &= add_modifier_effect("administrative_efficiency_modifier", true);
- ret &= add_modifier_effect("administrative_multiplier", true);
ret &= add_modifier_effect("artisan_input", false);
ret &= add_modifier_effect("artisan_output", true);
ret &= add_modifier_effect("artisan_throughput", true);
diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp
index 58b335d..bd72a1e 100644
--- a/src/openvic-simulation/misc/Modifier.hpp
+++ b/src/openvic-simulation/misc/Modifier.hpp
@@ -37,7 +37,7 @@ namespace OpenVic {
using effect_map_t = fixed_point_map_t<ModifierEffect const*>;
private:
- effect_map_t values;
+ effect_map_t PROPERTY(values);
public:
ModifierValue();
@@ -51,6 +51,8 @@ namespace OpenVic {
/* Removes effect entries with a value of zero. */
void trim();
size_t get_effect_count() const;
+ void clear();
+ bool empty() const;
fixed_point_t get_effect(ModifierEffect const* effect, bool* successful = nullptr);
bool has_effect(ModifierEffect const* effect) const;
diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp
index a03ffa3..1dca176 100644
--- a/src/openvic-simulation/politics/Issue.cpp
+++ b/src/openvic-simulation/politics/Issue.cpp
@@ -19,10 +19,11 @@ ReformGroup::ReformGroup(std::string_view new_identifier, ReformType const& new_
Reform::Reform(
std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, ReformGroup const& new_group,
- size_t new_ordinal, RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow,
- ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect
-) : Issue { new_identifier, new_colour, std::move(new_values), new_group, std::move(new_rules), false }, ordinal { new_ordinal },
- reform_group { new_group }, technology_cost { new_technology_cost }, allow { std::move(new_allow) },
+ size_t new_ordinal, fixed_point_t new_administrative_multiplier, RuleSet&& new_rules, tech_cost_t new_technology_cost,
+ ConditionScript&& new_allow, ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect
+) : Issue { new_identifier, new_colour, std::move(new_values), new_group, std::move(new_rules), false },
+ reform_group { new_group }, ordinal { new_ordinal }, administrative_multiplier { new_administrative_multiplier },
+ technology_cost { new_technology_cost }, allow { std::move(new_allow) },
on_execute_trigger { std::move(new_on_execute_trigger) }, on_execute_effect { std::move(new_on_execute_effect) } {}
bool Reform::parse_scripts(DefinitionManager const& definition_manager) {
@@ -84,8 +85,8 @@ bool IssueManager::add_reform_group(std::string_view identifier, ReformType cons
bool IssueManager::add_reform(
std::string_view identifier, colour_t new_colour, ModifierValue&& values, ReformGroup const* group, size_t ordinal,
- RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger,
- EffectScript&& on_execute_effect
+ fixed_point_t administrative_multiplier, RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow,
+ ConditionScript&& on_execute_trigger, EffectScript&& on_execute_effect
) {
if (identifier.empty()) {
Logger::error("Invalid issue identifier - empty!");
@@ -116,9 +117,16 @@ bool IssueManager::add_reform(
Logger::warning("Non-zero technology cost ", technology_cost, " found in civilised reform ", identifier, "!");
}
+ if (administrative_multiplier != 0 && !group->is_administrative()) {
+ Logger::warning(
+ "Non-zero administrative multiplier ", administrative_multiplier, " found in reform ", identifier,
+ " belonging to non-administrative group ", group->get_identifier(), "!"
+ );
+ }
+
return reforms.add_item({
- identifier, new_colour, std::move(values), *group, ordinal, std::move(rules), technology_cost, std::move(allow),
- std::move(on_execute_trigger), std::move(on_execute_effect)
+ identifier, new_colour, std::move(values), *group, ordinal, administrative_multiplier, std::move(rules),
+ technology_cost, std::move(allow), std::move(on_execute_trigger), std::move(on_execute_effect)
});
}
@@ -198,12 +206,15 @@ bool IssueManager::_load_reform(
) {
ModifierValue values;
RuleSet rules;
+ fixed_point_t administrative_multiplier = 0;
Reform::tech_cost_t technology_cost = 0;
ConditionScript allow { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE };
ConditionScript on_execute_trigger { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE };
EffectScript on_execute_effect;
- bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values),
+ bool ret = modifier_manager.expect_modifier_value_and_keys(
+ move_variable_callback(values),
+ "administrative_multiplier", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(administrative_multiplier)),
"technology_cost", ZERO_OR_ONE, expect_uint(assign_variable_callback(technology_cost)),
"allow", ZERO_OR_ONE, allow.expect_script(),
"rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)),
@@ -214,7 +225,8 @@ bool IssueManager::_load_reform(
)(node);
ret &= add_reform(
identifier, create_issue_reform_colour(get_issue_count() + get_reform_count()), std::move(values), group, ordinal,
- std::move(rules), technology_cost, std::move(allow), std::move(on_execute_trigger), std::move(on_execute_effect)
+ administrative_multiplier, std::move(rules), technology_cost, std::move(allow), std::move(on_execute_trigger),
+ std::move(on_execute_effect)
);
return ret;
}
diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp
index 70f082d..d49f897 100644
--- a/src/openvic-simulation/politics/Issue.hpp
+++ b/src/openvic-simulation/politics/Issue.hpp
@@ -76,6 +76,7 @@ namespace OpenVic {
private:
ReformGroup const& PROPERTY(reform_group); // stores an already casted reference
const size_t PROPERTY(ordinal); // assigned by the parser to allow policy sorting
+ const fixed_point_t PROPERTY(administrative_multiplier);
const tech_cost_t PROPERTY(technology_cost);
ConditionScript PROPERTY(allow);
ConditionScript PROPERTY(on_execute_trigger);
@@ -83,8 +84,9 @@ namespace OpenVic {
Reform(
std::string_view new_identifier, colour_t new_colour, ModifierValue&& new_values, ReformGroup const& new_group,
- size_t new_ordinal, RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow,
- ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect
+ size_t new_ordinal, fixed_point_t new_administrative_multiplier, RuleSet&& new_rules,
+ tech_cost_t new_technology_cost, ConditionScript&& new_allow, ConditionScript&& new_on_execute_trigger,
+ EffectScript&& new_on_execute_effect
);
bool parse_scripts(DefinitionManager const& definition_manager);
@@ -125,8 +127,8 @@ namespace OpenVic {
bool add_reform_group(std::string_view identifier, ReformType const* type, bool ordered, bool administrative);
bool add_reform(
std::string_view identifier, colour_t new_colour, ModifierValue&& values, ReformGroup const* group, size_t ordinal,
- RuleSet&& rules, Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger,
- EffectScript&& on_execute_effect
+ fixed_point_t administrative_multiplier, RuleSet&& rules, Reform::tech_cost_t technology_cost,
+ ConditionScript&& allow, ConditionScript&& on_execute_trigger, EffectScript&& on_execute_effect
);
bool load_issues_file(ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root);
diff --git a/src/openvic-simulation/politics/Rule.cpp b/src/openvic-simulation/politics/Rule.cpp
index 37aa22a..1d61652 100644
--- a/src/openvic-simulation/politics/Rule.cpp
+++ b/src/openvic-simulation/politics/Rule.cpp
@@ -62,6 +62,20 @@ size_t RuleSet::get_rule_count() const {
return ret;
}
+void RuleSet::clear() {
+ rule_groups.clear();
+}
+
+bool RuleSet::empty() const {
+ for (auto const& [group, rule_map] : rule_groups) {
+ if (!rule_map.empty()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
RuleSet::rule_map_t const& RuleSet::get_rule_group(Rule::rule_group_t group, bool* successful) const {
const rule_group_map_t::const_iterator it = rule_groups.find(group);
if (it != rule_groups.end()) {
diff --git a/src/openvic-simulation/politics/Rule.hpp b/src/openvic-simulation/politics/Rule.hpp
index 518c555..db0c926 100644
--- a/src/openvic-simulation/politics/Rule.hpp
+++ b/src/openvic-simulation/politics/Rule.hpp
@@ -42,7 +42,7 @@ namespace OpenVic {
using rule_group_map_t = ordered_map<Rule::rule_group_t, rule_map_t>;
private:
- rule_group_map_t rule_groups;
+ rule_group_map_t PROPERTY(rule_groups);
public:
RuleSet() = default;
@@ -59,6 +59,8 @@ namespace OpenVic {
bool trim_and_resolve_conflicts(bool log);
size_t get_rule_group_count() const;
size_t get_rule_count() const;
+ void clear();
+ bool empty() const;
rule_map_t const& get_rule_group(Rule::rule_group_t group, bool* successful = nullptr) const;
bool get_rule(Rule const* rule, bool* successful = nullptr) const;
diff --git a/src/openvic-simulation/research/Technology.cpp b/src/openvic-simulation/research/Technology.cpp
index 737650b..89c4a71 100644
--- a/src/openvic-simulation/research/Technology.cpp
+++ b/src/openvic-simulation/research/Technology.cpp
@@ -14,7 +14,7 @@ Technology::Technology(
Date::year_t new_year,
fixed_point_t new_cost,
bool new_unciv_military,
- uint8_t new_unit,
+ std::optional<CountryInstance::unit_variant_t>&& new_unit_variant,
unit_set_t&& new_activated_units,
building_set_t&& new_activated_buildings,
ModifierValue&& new_values,
@@ -24,9 +24,9 @@ Technology::Technology(
year { new_year },
cost { new_cost },
unciv_military { new_unciv_military },
- unit { new_unit },
- activated_buildings { std::move(new_activated_units) },
- activated_units { std::move(new_activated_buildings) },
+ unit_variant { std::move(new_unit_variant) },
+ activated_units { std::move(new_activated_units) },
+ activated_buildings { std::move(new_activated_buildings) },
ai_chance { std::move(new_ai_chance) } {}
bool Technology::parse_scripts(DefinitionManager const& definition_manager) {
@@ -61,8 +61,8 @@ bool TechnologyManager::add_technology_area(std::string_view identifier, Technol
bool TechnologyManager::add_technology(
std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost, bool unciv_military,
- uint8_t unit, Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings,
- ModifierValue&& values, ConditionalWeight&& ai_chance
+ std::optional<CountryInstance::unit_variant_t>&& unit_variant, Technology::unit_set_t&& activated_units,
+ Technology::building_set_t&& activated_buildings, ModifierValue&& values, ConditionalWeight&& ai_chance
) {
if (identifier.empty()) {
Logger::error("Invalid technology identifier - empty!");
@@ -75,8 +75,8 @@ bool TechnologyManager::add_technology(
}
return technologies.add_item({
- identifier, *area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings),
- std::move(values), std::move(ai_chance)
+ identifier, *area, year, cost, unciv_military, std::move(unit_variant), std::move(activated_units),
+ std::move(activated_buildings), std::move(values), std::move(ai_chance)
});
}
@@ -157,8 +157,8 @@ bool TechnologyManager::load_technology_file_schools(
}
bool TechnologyManager::load_technologies_file(
- ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager, BuildingTypeManager const& building_type_manager,
- ast::NodeCPtr root
+ ModifierManager const& modifier_manager, UnitTypeManager const& unit_type_manager,
+ BuildingTypeManager const& building_type_manager, ast::NodeCPtr root
) {
return expect_dictionary_reserve_length(technologies, [this, &modifier_manager, &unit_type_manager, &building_type_manager](
std::string_view tech_key, ast::NodeCPtr tech_value
@@ -168,7 +168,7 @@ bool TechnologyManager::load_technologies_file(
Date::year_t year = 0;
fixed_point_t cost = 0;
bool unciv_military = false;
- uint8_t unit = 0;
+ std::optional<CountryInstance::unit_variant_t> unit_variant;
Technology::unit_set_t activated_units;
Technology::building_set_t activated_buildings;
ConditionalWeight ai_chance { scope_t::COUNTRY, scope_t::COUNTRY, scope_t::NO_SCOPE };
@@ -179,7 +179,7 @@ bool TechnologyManager::load_technologies_file(
"year", ONE_EXACTLY, expect_uint(assign_variable_callback(year)),
"cost", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(cost)),
"unciv_military", ZERO_OR_ONE, expect_bool(assign_variable_callback(unciv_military)),
- "unit", ZERO_OR_ONE, expect_uint(assign_variable_callback(unit)),
+ "unit", ZERO_OR_ONE, expect_uint<decltype(unit_variant)::value_type>(assign_variable_callback_opt(unit_variant)),
"activate_unit", ZERO_OR_MORE, unit_type_manager.expect_unit_type_identifier(set_callback_pointer(activated_units)),
"activate_building", ZERO_OR_MORE, building_type_manager.expect_building_type_identifier(
set_callback_pointer(activated_buildings)
@@ -188,8 +188,8 @@ bool TechnologyManager::load_technologies_file(
)(tech_value);
ret &= add_technology(
- tech_key, area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings),
- std::move(modifiers), std::move(ai_chance)
+ tech_key, area, year, cost, unciv_military, std::move(unit_variant), std::move(activated_units),
+ std::move(activated_buildings), std::move(modifiers), std::move(ai_chance)
);
return ret;
})(root);
diff --git a/src/openvic-simulation/research/Technology.hpp b/src/openvic-simulation/research/Technology.hpp
index f13cca3..3afeb0b 100644
--- a/src/openvic-simulation/research/Technology.hpp
+++ b/src/openvic-simulation/research/Technology.hpp
@@ -2,6 +2,7 @@
#include <cstdint>
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/military/UnitType.hpp"
#include "openvic-simulation/misc/Modifier.hpp"
@@ -50,15 +51,16 @@ namespace OpenVic {
const Date::year_t PROPERTY(year);
const fixed_point_t PROPERTY(cost);
const bool PROPERTY(unciv_military);
- const uint8_t PROPERTY(unit);
- unit_set_t PROPERTY(activated_buildings);
- building_set_t PROPERTY(activated_units);
+ std::optional<CountryInstance::unit_variant_t> PROPERTY(unit_variant);
+ unit_set_t PROPERTY(activated_units);
+ building_set_t PROPERTY(activated_buildings);
ConditionalWeight PROPERTY(ai_chance);
Technology(
std::string_view new_identifier, TechnologyArea const& new_area, Date::year_t new_year, fixed_point_t new_cost,
- bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units,
- building_set_t&& new_activated_buildings, ModifierValue&& new_values, ConditionalWeight&& new_ai_chance
+ bool new_unciv_military, std::optional<CountryInstance::unit_variant_t>&& new_unit_variant,
+ unit_set_t&& new_activated_units, building_set_t&& new_activated_buildings, ModifierValue&& new_values,
+ ConditionalWeight&& new_ai_chance
);
bool parse_scripts(DefinitionManager const& definition_manager);
@@ -87,8 +89,9 @@ namespace OpenVic {
bool add_technology(
std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost,
- bool unciv_military, uint8_t unit, Technology::unit_set_t&& activated_units,
- Technology::building_set_t&& activated_buildings, ModifierValue&& values, ConditionalWeight&& ai_chance
+ bool unciv_military, std::optional<CountryInstance::unit_variant_t>&& unit_variant,
+ Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings,
+ ModifierValue&& values, ConditionalWeight&& ai_chance
);
bool add_technology_school(std::string_view identifier, ModifierValue&& values);