From 237e42fd1cdff02862c6a2279c7cad9786ab0e65 Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 11 Sep 2024 00:21:03 +0100 Subject: CountryInstance unlock tech, invention, crime, building, unit, gas etc. --- src/openvic-simulation/InstanceManager.cpp | 2 + src/openvic-simulation/country/CountryInstance.cpp | 371 +++++++++++++++++++-- src/openvic-simulation/country/CountryInstance.hpp | 66 +++- src/openvic-simulation/dataloader/NodeTools.hpp | 18 +- src/openvic-simulation/economy/BuildingType.cpp | 11 +- src/openvic-simulation/economy/BuildingType.hpp | 5 +- src/openvic-simulation/history/CountryHistory.cpp | 12 +- src/openvic-simulation/history/CountryHistory.hpp | 3 +- src/openvic-simulation/map/Crime.hpp | 2 +- src/openvic-simulation/research/Technology.cpp | 28 +- src/openvic-simulation/research/Technology.hpp | 17 +- 11 files changed, 466 insertions(+), 69 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index bcae82b..b731d12 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -79,10 +79,12 @@ 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_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/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 4fab010..e0932eb 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,12 @@ 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(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 +47,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 {}, @@ -72,6 +76,7 @@ CountryInstance::CountryInstance( infamy { 0 }, plurality { 0 }, revanchism { 0 }, + unlocked_crimes { &crime_keys }, /* Population */ primary_culture { nullptr }, @@ -115,7 +120,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()) { @@ -301,30 +321,311 @@ template bool CountryInstance::remove_leader(LeaderBranched const*); template -void CountryInstance::unlock_unit_type(UnitTypeBranched const& unit_type) { - IndexedMap, bool>& unlocked_unit_types = get_unlocked_unit_types(); +bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched const& unit_type, unlock_level_t unlock_level_change) { + IndexedMap, unlock_level_t>& unlocked_unit_types = get_unlocked_unit_types(); - decltype(unlocked_regiment_types)::value_ref_t unlock_value = unlocked_unit_types[unit_type]; + typename IndexedMap, 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(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) ); - return; + return false; } - unlock_value = true; + unlock_level += unlock_level_change; + + return true; +} + +template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched const&, unlock_level_t); +template bool CountryInstance::modify_unit_type_unlock(UnitTypeBranched 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; - if constexpr (Branch == UnitType::branch_t::LAND) { - allowed_regiment_cultures = RegimentType::allowed_cultures_get_most_permissive( - allowed_regiment_cultures, unit_type.get_allowed_cultures() + switch (unit_type.get_branch()) { + case LAND: + return modify_unit_type_unlock(static_cast const&>(unit_type), unlock_level_change); + case NAVAL: + return modify_unit_type_unlock(static_cast 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(unit_type.get_branch()), " is unlocked for country ", get_identifier() ); + return false; } } -template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); -template void CountryInstance::unlock_unit_type(UnitTypeBranched const&); +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 const&>(unit_type)] > 0; + case NAVAL: + return unlocked_ship_types[static_cast const&>(unit_type)] > 0; + default: + Logger::error( + "Attempted to check if unit type \"", unit_type.get_identifier(), "\" with invalid branch ", + static_cast(unit_type.get_branch()), " is unlocked for country ", get_identifier() + ); + 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(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(unlock_level + unlock_level_change) + ); + return false; + } + + 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(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(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; +} + +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(gas_attack_unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(gas_attack_unlock_level + unlock_level_change) + ); + return false; + } + + gas_attack_unlock_level += unlock_level_change; + + return true; +} + +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(gas_defence_unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(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(unit_variant), " in country ", + get_identifier(), " to invalid value: current level = ", static_cast(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(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(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(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(unlock_level), ", change = ", + static_cast(unlock_level_change), ", invalid new value = ", + static_cast(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; @@ -385,8 +686,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 @@ -751,24 +1056,36 @@ 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::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, + 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..c768a86 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -25,8 +25,10 @@ namespace OpenVic { struct CountryParty; struct Ideology; struct Reform; + struct Crime; struct Culture; struct Religion; + struct BuildingType; struct CountryHistoryEntry; struct MapInstance; struct DefineManager; @@ -53,6 +55,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 +84,7 @@ namespace OpenVic { std::vector> PROPERTY(industrial_power_from_investments); size_t PROPERTY(industrial_rank); fixed_point_map_t PROPERTY(foreign_investments); + IndexedMap PROPERTY(unlocked_building_types); // TODO - total amount of each good produced /* Budget */ @@ -86,8 +92,8 @@ namespace OpenVic { // TODO - cash stockpile change over last 30 days /* Technology */ - IndexedMap PROPERTY(technologies); - IndexedMap PROPERTY(inventions); + IndexedMap PROPERTY(unlocked_technologies); + IndexedMap PROPERTY(unlocked_inventions); Technology const* PROPERTY(current_research); fixed_point_t PROPERTY(invested_research_points); Date PROPERTY(expected_completion_date); @@ -111,6 +117,7 @@ namespace OpenVic { fixed_point_t PROPERTY(infamy); fixed_point_t PROPERTY(plurality); fixed_point_t PROPERTY(revanchism); + IndexedMap PROPERTY(unlocked_crimes); // TODO - rebel movements /* Population */ @@ -157,9 +164,12 @@ namespace OpenVic { fixed_point_t PROPERTY(war_exhaustion); bool PROPERTY_CUSTOM_PREFIX(mobilised, is); bool PROPERTY_CUSTOM_PREFIX(disarmed, is); - IndexedMap PROPERTY(unlocked_regiment_types); + IndexedMap PROPERTY(unlocked_regiment_types); RegimentType::allowed_cultures_t PROPERTY(allowed_regiment_cultures); - IndexedMap PROPERTY(unlocked_ship_types); + IndexedMap PROPERTY(unlocked_ship_types); + unlock_level_t PROPERTY(gas_attack_unlock_level); + unlock_level_t PROPERTY(gas_defence_unlock_level); + std::vector PROPERTY(unit_variant_unlock_levels); UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); @@ -167,10 +177,12 @@ 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(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 @@ -214,7 +226,41 @@ namespace OpenVic { bool remove_leader(LeaderBranched const* leader); template - void unlock_unit_type(UnitTypeBranched const& unit_type); + bool modify_unit_type_unlock(UnitTypeBranched 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. @@ -271,10 +317,12 @@ 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::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(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 + Callback auto assign_variable_callback_opt( + std::optional& 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 assign_variable_callback_string(std::string& var); template @@ -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( + [&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 +#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 PROPERTY(reforms); std::optional PROPERTY(inital_oob); std::optional PROPERTY(tech_school); - ordered_map PROPERTY(technologies); + ordered_map PROPERTY(technologies); ordered_map PROPERTY(inventions); fixed_point_map_t PROPERTY(foreign_investment); std::optional 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/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&& 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&& 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 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(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 +#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 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&& 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&& 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); -- cgit v1.2.3-56-ga3b1 From a424969548083a977480a6be0f078760a5789bbf Mon Sep 17 00:00:00 2001 From: hop311 Date: Wed, 11 Sep 2024 22:07:12 +0100 Subject: Country reforms and rules --- src/openvic-simulation/InstanceManager.cpp | 1 + .../country/CountryDefinition.cpp | 19 ++++-- .../country/CountryDefinition.hpp | 3 +- src/openvic-simulation/country/CountryInstance.cpp | 77 ++++++++++++++++------ src/openvic-simulation/country/CountryInstance.hpp | 14 +++- src/openvic-simulation/misc/Modifier.cpp | 9 ++- src/openvic-simulation/misc/Modifier.hpp | 4 +- src/openvic-simulation/politics/Issue.cpp | 32 ++++++--- src/openvic-simulation/politics/Issue.hpp | 10 +-- src/openvic-simulation/politics/Rule.cpp | 14 ++++ src/openvic-simulation/politics/Rule.hpp | 4 +- 11 files changed, 140 insertions(+), 47 deletions(-) diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp index b731d12..c9ce24a 100644 --- a/src/openvic-simulation/InstanceManager.cpp +++ b/src/openvic-simulation/InstanceManager.cpp @@ -83,6 +83,7 @@ bool InstanceManager::setup() { 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(), 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; + using policy_map_t = IndexedMap; private: const Date PROPERTY(start_date); diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index e0932eb..183b0c8 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -21,6 +21,7 @@ CountryInstance::CountryInstance( 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, @@ -69,7 +70,9 @@ 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 }, @@ -240,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 @@ -663,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()) { @@ -677,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 = @@ -888,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); @@ -1060,6 +1095,7 @@ bool CountryInstanceManager::generate_country_instances( 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, @@ -1077,6 +1113,7 @@ bool CountryInstanceManager::generate_country_instances( technology_keys, invention_keys, ideology_keys, + reform_keys, government_type_keys, crime_keys, pop_type_keys, diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index c768a86..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,6 +25,7 @@ namespace OpenVic { struct GovernmentType; struct CountryParty; struct Ideology; + struct ReformGroup; struct Reform; struct Crime; struct Culture; @@ -109,7 +111,9 @@ namespace OpenVic { Date PROPERTY(last_election); CountryParty const* PROPERTY(ruling_party); IndexedMap PROPERTY(upper_house); - std::vector PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history + IndexedMap 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 PROPERTY(government_flag_overrides); GovernmentType const* PROPERTY(flag_government_type); @@ -181,6 +185,7 @@ namespace OpenVic { 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, @@ -212,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 bool add_unit_instance_group(UnitInstanceGroup& group); @@ -287,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); @@ -321,6 +328,7 @@ namespace OpenVic { 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, 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; 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; 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; -- cgit v1.2.3-56-ga3b1