diff options
author | Hop311 <Hop3114@gmail.com> | 2024-07-23 19:47:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-23 19:47:47 +0200 |
commit | 6cd55c452d1643666ff4169a89402fd3e3b66c61 (patch) | |
tree | 888b847a54c66b6e9d1b2f7ee3e3d0f8071eceda /src/openvic-simulation/country | |
parent | 9d57ca273e4b32ab82a51789ec58e08fefb5276a (diff) | |
parent | 67cbd14630c4344902d3fa1ddca178809da4293b (diff) |
Merge pull request #177 from OpenVicProject/country-instance
Fleshing out Country, State and Province instances + history
Diffstat (limited to 'src/openvic-simulation/country')
-rw-r--r-- | src/openvic-simulation/country/CountryInstance.cpp | 313 | ||||
-rw-r--r-- | src/openvic-simulation/country/CountryInstance.hpp | 167 |
2 files changed, 414 insertions, 66 deletions
diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 8d2955b..0b27b78 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -2,59 +2,156 @@ #include "openvic-simulation/country/CountryDefinition.hpp" #include "openvic-simulation/history/CountryHistory.hpp" -#include "openvic-simulation/military/UnitInstanceGroup.hpp" +#include "openvic-simulation/map/MapInstance.hpp" +#include "openvic-simulation/politics/Ideology.hpp" +#include "openvic-simulation/research/Invention.hpp" +#include "openvic-simulation/research/Technology.hpp" using namespace OpenVic; +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(upper_house)::keys_t const& ideology_keys -) : country_definition { new_country_definition }, - primary_culture { nullptr }, - religion { nullptr }, - ruling_party { nullptr }, - last_election {}, + decltype(upper_house)::keys_t const& ideology_keys, + decltype(pop_type_distribution)::keys_t const& pop_type_keys +) : /* Main attributes */ + country_definition { new_country_definition }, + colour { ERROR_COLOUR }, capital { nullptr }, + country_flags {}, + civilised { false }, + releasable_vassal { true }, + owned_provinces {}, + controlled_provinces {}, + core_provinces {}, + states {}, + + /* Production */ + + /* Budget */ + cash_stockpile { 0 }, + + /* Technology */ + technologies { &technology_keys }, + inventions { &invention_keys }, + current_research { nullptr }, + invested_research_points { 0 }, + expected_completion_date {}, + research_point_stockpile { 0 }, + daily_research_points { 0 }, + national_literacy { 0 }, + tech_school { nullptr }, + + /* Politics */ + national_value { nullptr }, government_type { nullptr }, + last_election {}, + ruling_party { nullptr }, + upper_house { &ideology_keys }, + reforms {}, + suppression_points { 0 }, + infamy { 0 }, plurality { 0 }, - national_value { nullptr }, - civilised { false }, + revanchism { 0 }, + + /* Population */ + primary_culture { nullptr }, + accepted_cultures {}, + religion { nullptr }, + total_population { 0 }, + national_consciousness { 0 }, + national_militancy { 0 }, + pop_type_distribution { &pop_type_keys }, + national_focus_capacity { 0 }, + + /* Trade */ + + /* Diplomacy */ + total_rank { 0 }, prestige { 0 }, - upper_house { &ideology_keys }, - technologies { &technology_keys }, - inventions { &invention_keys } {} + prestige_rank { 0 }, + industrial_power { 0 }, + industrial_rank { 0 }, + military_power { 0 }, + military_rank { 0 }, + diplomatic_points { 0 }, + + /* Military */ + generals {}, + admirals {}, + armies {}, + navies {}, + regiment_count { 0 }, + mobilisation_regiment_potential { 0 }, + ship_count { 0 }, + total_consumed_ship_supply { 0 }, + max_ship_supply { 0 }, + leadership_points { 0 }, + war_exhaustion { 0 } {} std::string_view CountryInstance::get_identifier() const { - return country_definition != nullptr ? country_definition->get_identifier() : "NULL"; + return country_definition->get_identifier(); } -bool CountryInstance::add_accepted_culture(Culture const* new_accepted_culture) { - if (std::find(accepted_cultures.begin(), accepted_cultures.end(), new_accepted_culture) != accepted_cultures.end()) { +bool CountryInstance::set_country_flag(std::string_view flag, bool warn) { + if (flag.empty()) { + Logger::error("Attempted to set empty country flag for country ", get_identifier()); + return false; + } + if (!country_flags.emplace(flag).second && warn) { Logger::warning( - "Attempted to add accepted culture ", new_accepted_culture->get_identifier(), " to country ", - country_definition->get_identifier(), ": already present!" + "Attempted to set country flag \"", flag, "\" for country ", get_identifier(), ": already set!" ); - return false; } - accepted_cultures.push_back(new_accepted_culture); return true; } -bool CountryInstance::remove_accepted_culture(Culture const* culture_to_remove) { - auto existing_entry = std::find(accepted_cultures.begin(), accepted_cultures.end(), culture_to_remove); - if (existing_entry == accepted_cultures.end()) { +bool CountryInstance::clear_country_flag(std::string_view flag, bool warn) { + if (flag.empty()) { + Logger::error("Attempted to clear empty country flag from country ", get_identifier()); + return false; + } + if (country_flags.erase(flag) == 0 && warn) { Logger::warning( - "Attempted to remove accepted culture ", culture_to_remove->get_identifier(), " from country ", - country_definition->get_identifier(), ": not present!" + "Attempted to clear country flag \"", flag, "\" from country ", get_identifier(), ": not set!" ); - return false; } - accepted_cultures.erase(existing_entry); return true; } +#define ADD_AND_REMOVE(item) \ + bool CountryInstance::add_##item(std::remove_pointer_t<decltype(item##s)::value_type>& new_item) { \ + if (!item##s.emplace(&new_item).second) { \ + Logger::error( \ + "Attempted to add " #item " \"", new_item.get_identifier(), "\" to country ", get_identifier(), \ + ": already present!" \ + ); \ + return false; \ + } \ + return true; \ + } \ + bool CountryInstance::remove_##item(std::remove_pointer_t<decltype(item##s)::value_type>& item_to_remove) { \ + if (item##s.erase(&item_to_remove) == 0) { \ + Logger::error( \ + "Attempted to remove " #item " \"", item_to_remove.get_identifier(), "\" from country ", get_identifier(), \ + ": not present!" \ + ); \ + return false; \ + } \ + return true; \ + } + +ADD_AND_REMOVE(owned_province) +ADD_AND_REMOVE(controlled_province) +ADD_AND_REMOVE(core_province) +ADD_AND_REMOVE(state) +ADD_AND_REMOVE(accepted_culture) + +#undef ADD_AND_REMOVE + bool CountryInstance::set_upper_house(Ideology const* ideology, fixed_point_t popularity) { if (ideology != nullptr) { upper_house[*ideology] = popularity; @@ -145,7 +242,7 @@ template void CountryInstance::add_leader(LeaderBranched<UnitType::branch_t::NAV template bool CountryInstance::remove_leader(LeaderBranched<UnitType::branch_t::LAND> const*); template bool CountryInstance::remove_leader(LeaderBranched<UnitType::branch_t::NAVAL> const*); -bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) { +bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry, MapInstance& map_instance) { if (entry == nullptr) { Logger::error("Trying to apply null country history to ", get_identifier()); return false; @@ -161,13 +258,15 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) set_optional(primary_culture, entry->get_primary_culture()); for (Culture const* culture : entry->get_accepted_cultures()) { - ret &= add_accepted_culture(culture); + ret &= add_accepted_culture(*culture); } set_optional(religion, entry->get_religion()); set_optional(ruling_party, entry->get_ruling_party()); set_optional(last_election, entry->get_last_election()); ret &= upper_house.copy(entry->get_upper_house()); - set_optional(capital, entry->get_capital()); + if (entry->get_capital()) { + capital = &map_instance.get_province_instance_from_definition(**entry->get_capital()); + } set_optional(government_type, entry->get_government_type()); set_optional(plurality, entry->get_plurality()); set_optional(national_value, entry->get_national_value()); @@ -176,20 +275,158 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) for (Reform const* reform : entry->get_reforms()) { ret &= add_reform(reform); } + set_optional(tech_school, entry->get_tech_school()); + constexpr auto set_bool_map_to_indexed_map = + []<typename T>(IndexedMap<T, bool>& target, ordered_map<T const*, bool> source) { + for (auto const& [key, value] : source) { + target[*key] = value; + } + }; + set_bool_map_to_indexed_map(technologies, entry->get_technologies()); + set_bool_map_to_indexed_map(inventions, entry->get_inventions()); + // entry->get_foreign_investment(); + + // These need to be applied to pops + // entry->get_consciousness(); + // entry->get_nonstate_consciousness(); + // entry->get_literacy(); + // entry->get_nonstate_culture_literacy(); + + set_optional(releasable_vassal, entry->is_releasable_vassal()); + // entry->get_colonial_points(); + for (std::string const& flag : entry->get_country_flags()) { + ret &= set_country_flag(flag, true); + } + for (std::string const& flag : entry->get_global_flags()) { + // TODO - set global flag + } + // entry->get_government_flag_overrides(); + for (Decision const* decision : entry->get_decisions()) { + // TODO - take decision + } return ret; } +void CountryInstance::_update_production() { + +} + +void CountryInstance::_update_budget() { + +} + +void CountryInstance::_update_technology() { + +} + +void CountryInstance::_update_politics() { + +} + +void CountryInstance::_update_population() { + total_population = 0; + national_literacy = 0; + national_consciousness = 0; + national_militancy = 0; + pop_type_distribution.clear(); + + for (auto const& state : states) { + total_population += state->get_total_population(); + + // TODO - change casting if Pop::pop_size_t changes type + const fixed_point_t state_population = fixed_point_t::parse(state->get_total_population()); + national_literacy += state->get_average_literacy() * state_population; + national_consciousness += state->get_average_consciousness() * state_population; + national_militancy += state->get_average_militancy() * state_population; + + pop_type_distribution += state->get_pop_type_distribution(); + } + + if (total_population > 0) { + national_literacy /= total_population; + national_consciousness /= total_population; + national_militancy /= total_population; + } + + // TODO - update national focus capacity +} + +void CountryInstance::_update_trade() { + // TODO - update total amount of each good exported and imported +} + +void CountryInstance::_update_diplomacy() { + // TODO - update prestige, industrial_power, military_power (ranks will be updated after all countries have calculated their scores) + // TODO - update diplomatic points and colonial power +} + +void CountryInstance::_update_military() { + regiment_count = 0; + + for (ArmyInstance const* army : armies) { + regiment_count += army->get_unit_count(); + } + + ship_count = 0; + total_consumed_ship_supply = 0; + + for (NavyInstance const* navy : navies) { + ship_count += navy->get_unit_count(); + total_consumed_ship_supply += navy->get_total_consumed_supply(); + } + + // TODO - update mobilisation_regiment_potential, max_ship_supply, leadership_points, war_exhaustion +} + +void CountryInstance::update_gamestate() { + if (country_definition != nullptr) { + const CountryDefinition::government_colour_map_t::const_iterator it = + country_definition->get_alternative_colours().find(government_type); + + if (it != country_definition->get_alternative_colours().end()) { + colour = it->second; + } else { + colour = country_definition->get_colour(); + } + } else { + colour = ERROR_COLOUR; + } + + // Order of updates might need to be changed/functions split up to account for dependencies + _update_production(); + _update_budget(); + _update_technology(); + _update_politics(); + _update_population(); + _update_trade(); + _update_diplomacy(); + _update_military(); +} + +void CountryInstance::tick() { + +} + +CountryInstance& CountryInstanceManager::get_country_instance_from_definition(CountryDefinition const& country) { + return country_instances.get_items()[country.get_index()]; +} + +CountryInstance const& CountryInstanceManager::get_country_instance_from_definition(CountryDefinition const& country) const { + return country_instances.get_items()[country.get_index()]; +} + 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::upper_house)::keys_t const& ideology_keys + decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys ) { reserve_more(country_instances, country_definition_manager.get_country_definition_count()); for (CountryDefinition const& country_definition : country_definition_manager.get_country_definitions()) { - country_instances.add_item({ &country_definition, technology_keys, invention_keys, ideology_keys }); + country_instances.add_item({ &country_definition, technology_keys, invention_keys, ideology_keys, pop_type_keys }); } return true; @@ -210,7 +447,7 @@ bool CountryInstanceManager::apply_history_to_countries( CountryHistoryEntry const* oob_history_entry = nullptr; for (CountryHistoryEntry const* entry : history_map->get_entries_up_to(date)) { - ret &= country_instance.apply_history_to_country(entry); + ret &= country_instance.apply_history_to_country(entry, map_instance); if (entry->get_inital_oob()) { oob_history_entry = entry; @@ -231,3 +468,15 @@ bool CountryInstanceManager::apply_history_to_countries( return ret; } + +void CountryInstanceManager::update_gamestate() { + for (CountryInstance& country : country_instances.get_items()) { + country.update_gamestate(); + } +} + +void CountryInstanceManager::tick() { + for (CountryInstance& country : country_instances.get_items()) { + country.tick(); + } +} diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 1eaf398..5b26f7f 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -6,8 +6,7 @@ #include "openvic-simulation/military/Leader.hpp" #include "openvic-simulation/military/UnitInstanceGroup.hpp" -#include "openvic-simulation/research/Invention.hpp" -#include "openvic-simulation/research/Technology.hpp" +#include "openvic-simulation/pop/Pop.hpp" #include "openvic-simulation/types/Date.hpp" #include "openvic-simulation/types/IdentifierRegistry.hpp" #include "openvic-simulation/types/IndexedMap.hpp" @@ -15,61 +14,140 @@ namespace OpenVic { struct CountryDefinition; - struct Culture; - struct Religion; + struct ProvinceInstance; + struct State; + struct Technology; + struct Invention; + struct TechnologySchool; + struct NationalValue; + struct GovernmentType; struct CountryParty; struct Ideology; - struct ProvinceDefinition; - struct GovernmentType; - struct NationalValue; struct Reform; + struct Culture; + struct Religion; struct CountryHistoryEntry; + struct MapInstance; - /* Representation of an existing country that is currently in-game. */ + /* Representation of a country's mutable attributes, with a CountryDefinition that is unique at any single time + * but can be swapped with other CountryInstance's CountryDefinition when switching tags. */ struct CountryInstance { friend struct CountryInstanceManager; private: - CountryDefinition const* PROPERTY_RW(country_definition); - Culture const* PROPERTY_RW(primary_culture); - std::vector<Culture const*> PROPERTY(accepted_cultures); - Religion const* PROPERTY_RW(religion); - CountryParty const* PROPERTY_RW(ruling_party); - Date PROPERTY_RW(last_election); - IndexedMap<Ideology, fixed_point_t> PROPERTY(upper_house); - // TODO - should this be ProvinceInstance and/or non-const pointer? - // Currently ProvinceDefinition as that's what CountryHistoryEntry has (loaded prior to ProvinceInstance generation) - ProvinceDefinition const* PROPERTY_RW(capital); - GovernmentType const* PROPERTY_RW(government_type); - fixed_point_t PROPERTY_RW(plurality); - NationalValue const* PROPERTY_RW(national_value); - bool PROPERTY_RW(civilised); - fixed_point_t PROPERTY_RW(prestige); - std::vector<Reform const*> PROPERTY(reforms); // TODO: should be map of reform groups to active reforms: must set defaults & validate applied history - + /* Main attributes */ + // We can always assume country_definition is not null, as it is initialised from a reference and only ever changed + // by swapping with another CountryInstance's country_definition. + CountryDefinition const* PROPERTY(country_definition); + colour_t PROPERTY(colour); // Cached to avoid searching government overrides for every province + ProvinceInstance const* PROPERTY(capital); + string_set_t PROPERTY(country_flags); + + bool PROPERTY(civilised); + bool PROPERTY_CUSTOM_PREFIX(releasable_vassal, is); + + ordered_set<ProvinceInstance*> PROPERTY(owned_provinces); + ordered_set<ProvinceInstance*> PROPERTY(controlled_provinces); + ordered_set<ProvinceInstance*> PROPERTY(core_provinces); + ordered_set<State*> PROPERTY(states); + + /* Production */ + // TODO - total amount of each good produced + + /* Budget */ + fixed_point_t PROPERTY(cash_stockpile); + // TODO - cash stockpile change over last 30 days + + /* Technology */ IndexedMap<Technology, bool> PROPERTY(technologies); IndexedMap<Invention, bool> PROPERTY(inventions); - - // TODO: Military units + OOBs; will probably need an extensible deployment class - + Technology const* PROPERTY(current_research); + fixed_point_t PROPERTY(invested_research_points); + Date PROPERTY(expected_completion_date); + fixed_point_t PROPERTY(research_point_stockpile); + fixed_point_t PROPERTY(daily_research_points); // TODO - breakdown by source + fixed_point_t PROPERTY(national_literacy); + TechnologySchool const* PROPERTY(tech_school); + // TODO - cached possible inventions with %age chance + + /* Politics */ + NationalValue const* PROPERTY(national_value); + GovernmentType const* PROPERTY(government_type); + 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 + // TODO - national issue support distribution (for just voters and for everyone) + fixed_point_t PROPERTY(suppression_points); + fixed_point_t PROPERTY(infamy); + fixed_point_t PROPERTY(plurality); + fixed_point_t PROPERTY(revanchism); + // TODO - rebel movements + + /* Population */ + Culture const* PROPERTY(primary_culture); + ordered_set<Culture const*> PROPERTY(accepted_cultures); + Religion const* PROPERTY(religion); + Pop::pop_size_t PROPERTY(total_population); + // TODO - population change over last 30 days + fixed_point_t PROPERTY(national_consciousness); + fixed_point_t PROPERTY(national_militancy); + IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution); + size_t PROPERTY(national_focus_capacity) + // TODO - national foci + + /* Trade */ + // TODO - total amount of each good exported and imported + + /* Diplomacy */ + size_t PROPERTY(total_rank); + fixed_point_t PROPERTY(prestige); + size_t PROPERTY(prestige_rank); + fixed_point_t PROPERTY(industrial_power); + size_t PROPERTY(industrial_rank); + fixed_point_t PROPERTY(military_power); + size_t PROPERTY(military_rank); + fixed_point_t PROPERTY(diplomatic_points); + // TODO - colonial power, current wars + + /* Military */ plf::colony<General> PROPERTY(generals); plf::colony<Admiral> PROPERTY(admirals); ordered_set<ArmyInstance*> PROPERTY(armies); ordered_set<NavyInstance*> PROPERTY(navies); + size_t PROPERTY(regiment_count); + size_t PROPERTY(mobilisation_regiment_potential); + size_t PROPERTY(ship_count); + fixed_point_t PROPERTY(total_consumed_ship_supply); + fixed_point_t PROPERTY(max_ship_supply); + fixed_point_t PROPERTY(leadership_points); + fixed_point_t PROPERTY(war_exhaustion); UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); CountryInstance( CountryDefinition const* new_country_definition, decltype(technologies)::keys_t const& technology_keys, - decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys + decltype(inventions)::keys_t const& invention_keys, decltype(upper_house)::keys_t const& ideology_keys, + decltype(pop_type_distribution)::keys_t const& pop_type_keys ); public: std::string_view get_identifier() const; - bool add_accepted_culture(Culture const* new_accepted_culture); - bool remove_accepted_culture(Culture const* culture_to_remove); + bool set_country_flag(std::string_view flag, bool warn); + bool clear_country_flag(std::string_view flag, bool warn); + bool add_owned_province(ProvinceInstance& new_province); + bool remove_owned_province(ProvinceInstance& province_to_remove); + bool add_controlled_province(ProvinceInstance& new_province); + bool remove_controlled_province(ProvinceInstance& province_to_remove); + bool add_core_province(ProvinceInstance& new_core); + bool remove_core_province(ProvinceInstance& core_to_remove); + bool add_state(State& new_state); + bool remove_state(State& state_to_remove); + + bool add_accepted_culture(Culture const& new_accepted_culture); + 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); @@ -85,29 +163,50 @@ namespace OpenVic { template<UnitType::branch_t Branch> bool remove_leader(LeaderBranched<Branch> const* leader); - bool apply_history_to_country(CountryHistoryEntry const* entry); + bool apply_history_to_country(CountryHistoryEntry const* entry, MapInstance& map_instance); + + private: + void _update_production(); + void _update_budget(); + void _update_technology(); + void _update_politics(); + void _update_population(); + void _update_trade(); + void _update_diplomacy(); + void _update_military(); + + public: + + void update_gamestate(); + void tick(); }; struct CountryDefinitionManager; struct CountryHistoryManager; struct UnitInstanceManager; - struct MapInstance; struct CountryInstanceManager { private: IdentifierRegistry<CountryInstance> IDENTIFIER_REGISTRY(country_instance); public: + CountryInstance& get_country_instance_from_definition(CountryDefinition const& country); + CountryInstance const& get_country_instance_from_definition(CountryDefinition const& country) const; + 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::upper_house)::keys_t const& ideology_keys + decltype(CountryInstance::upper_house)::keys_t const& ideology_keys, + decltype(CountryInstance::pop_type_distribution)::keys_t const& pop_type_keys ); bool apply_history_to_countries( CountryHistoryManager const& history_manager, Date date, UnitInstanceManager& unit_instance_manager, MapInstance& map_instance ); + + void update_gamestate(); + void tick(); }; } |