aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-07-23 19:47:47 +0200
committer GitHub <noreply@github.com>2024-07-23 19:47:47 +0200
commit6cd55c452d1643666ff4169a89402fd3e3b66c61 (patch)
tree888b847a54c66b6e9d1b2f7ee3e3d0f8071eceda
parent9d57ca273e4b32ab82a51789ec58e08fefb5276a (diff)
parent67cbd14630c4344902d3fa1ddca178809da4293b (diff)
Merge pull request #177 from OpenVicProject/country-instance
Fleshing out Country, State and Province instances + history
-rw-r--r--src/headless/main.cpp9
-rw-r--r--src/openvic-simulation/InstanceManager.cpp10
-rw-r--r--src/openvic-simulation/country/CountryInstance.cpp313
-rw-r--r--src/openvic-simulation/country/CountryInstance.hpp167
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp7
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp13
-rw-r--r--src/openvic-simulation/history/CountryHistory.hpp4
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.cpp31
-rw-r--r--src/openvic-simulation/history/ProvinceHistory.hpp3
-rw-r--r--src/openvic-simulation/map/MapInstance.cpp21
-rw-r--r--src/openvic-simulation/map/MapInstance.hpp7
-rw-r--r--src/openvic-simulation/map/Mapmode.cpp8
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.cpp130
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.hpp50
-rw-r--r--src/openvic-simulation/map/State.cpp58
-rw-r--r--src/openvic-simulation/map/State.hpp28
-rw-r--r--src/openvic-simulation/military/UnitInstanceGroup.cpp13
-rw-r--r--src/openvic-simulation/military/UnitInstanceGroup.hpp4
-rw-r--r--src/openvic-simulation/pop/Pop.cpp5
-rw-r--r--src/openvic-simulation/types/HasIdentifier.hpp17
-rw-r--r--src/openvic-simulation/types/IdentifierRegistry.hpp6
-rw-r--r--src/openvic-simulation/types/IndexedMap.hpp6
22 files changed, 735 insertions, 175 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index 1acf581..23b5c93 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -25,6 +25,7 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests)
Logger::info("State updated");
}, nullptr };
+ Logger::info("===== Loading definitions... =====");
ret &= game_manager.load_definitions(
roots,
[](std::string_view key, Dataloader::locale_t locale, std::string_view localisation) -> bool {
@@ -40,6 +41,14 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests)
std::cout << "Testing Executed" << std::endl << std::endl;
}
+ Logger::info("===== Setting up instance... =====");
+ ret &= game_manager.setup_instance(
+ game_manager.get_definition_manager().get_history_manager().get_bookmark_manager().get_bookmark_by_index(0)
+ );
+
+ Logger::info("===== Starting game session... =====");
+ ret &= game_manager.start_game_session();
+
return ret;
}
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp
index d314acd..cd5da59 100644
--- a/src/openvic-simulation/InstanceManager.cpp
+++ b/src/openvic-simulation/InstanceManager.cpp
@@ -41,6 +41,7 @@ void InstanceManager::update_gamestate() {
// Update gamestate...
map_instance.update_gamestate(today);
+ country_instance_manager.update_gamestate();
gamestate_updated();
gamestate_needs_update = false;
@@ -74,12 +75,12 @@ bool InstanceManager::setup() {
definition_manager.get_pop_manager().get_pop_types(),
definition_manager.get_politics_manager().get_ideology_manager().get_ideologies()
);
- ret &= map_instance.get_state_manager().generate_states(map_instance);
ret &= country_instance_manager.generate_country_instances(
definition_manager.get_country_definition_manager(),
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_ideology_manager().get_ideologies(),
+ definition_manager.get_pop_manager().get_pop_types()
);
game_instance_setup = true;
@@ -115,6 +116,7 @@ bool InstanceManager::load_bookmark(Bookmark const* new_bookmark) {
bool ret = map_instance.apply_history_to_provinces(
definition_manager.get_history_manager().get_province_manager(), today,
+ country_instance_manager,
// TODO - the following argument is for generating test pop attributes
definition_manager.get_politics_manager().get_issue_manager()
);
@@ -123,6 +125,10 @@ bool InstanceManager::load_bookmark(Bookmark const* new_bookmark) {
definition_manager.get_history_manager().get_country_manager(), today, unit_instance_manager, map_instance
);
+ ret &= map_instance.get_state_manager().generate_states(
+ map_instance, definition_manager.get_pop_manager().get_pop_types()
+ );
+
return ret;
}
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();
};
}
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index 18faffb..d019cce 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -12,7 +12,6 @@
#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/types/Date.hpp"
-#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/types/IndexedMap.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
#include "openvic-simulation/types/Vector.hpp"
@@ -528,7 +527,7 @@ namespace OpenVic {
};
}
- template<std::derived_from<HasIdentifier> T, typename... SetArgs>
+ template<typename T, typename... SetArgs>
Callback<T const&> auto set_callback_pointer(tsl::ordered_set<T const*, SetArgs...>& set, bool warn = false) {
return [&set, warn](T const& val) -> bool {
if (set.emplace(&val).second) {
@@ -539,7 +538,7 @@ namespace OpenVic {
};
}
- template<std::derived_from<HasIdentifier> Key, typename Value, typename... MapArgs>
+ template<typename Key, typename Value, typename... MapArgs>
Callback<Value> auto map_callback(
tsl::ordered_map<Key const*, Value, MapArgs...>& map, Key const* key, bool warn = false
) {
@@ -561,7 +560,7 @@ namespace OpenVic {
Logger::error("Null key in map_callback");
return false;
}
- Value& map_value = map[*key];
+ typename IndexedMap<Key, Value>::value_ref_t map_value = map[*key];
bool ret = true;
if (map_value != Value {}) {
Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\"");
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
index 935a769..145d26b 100644
--- a/src/openvic-simulation/history/CountryHistory.cpp
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -47,14 +47,7 @@ bool CountryHistoryMap::_load_history_entry(
" when it actually belongs to ", reform.get_reform_group(), " in history of ", entry.get_country()
);
}
- if (std::find(entry.reforms.begin(), entry.reforms.end(), &reform) != entry.reforms.end()) {
- Logger::error(
- "Redefinition of reform ", reform.get_identifier(), " in history of ", entry.get_country()
- );
- return false;
- }
- entry.reforms.push_back(&reform);
- return true;
+ return set_callback_pointer(entry.reforms)(reform);
})(value);
}
@@ -81,9 +74,7 @@ bool CountryHistoryMap::_load_history_entry(
),
"primary_culture", ZERO_OR_ONE,
culture_manager.expect_culture_identifier(assign_variable_callback_pointer_opt(entry.primary_culture)),
- "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier(
- vector_callback_pointer(entry.accepted_cultures)
- ),
+ "culture", ZERO_OR_MORE, culture_manager.expect_culture_identifier(set_callback_pointer(entry.accepted_cultures)),
"religion", ZERO_OR_ONE, definition_manager.get_pop_manager().get_religion_manager().expect_religion_identifier(
assign_variable_callback_pointer_opt(entry.religion)
),
diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp
index c74841d..d6a6997 100644
--- a/src/openvic-simulation/history/CountryHistory.hpp
+++ b/src/openvic-simulation/history/CountryHistory.hpp
@@ -32,7 +32,7 @@ namespace OpenVic {
CountryDefinition const& PROPERTY(country);
std::optional<Culture const*> PROPERTY(primary_culture);
- std::vector<Culture const*> PROPERTY(accepted_cultures);
+ ordered_set<Culture const*> PROPERTY(accepted_cultures);
std::optional<Religion const*> PROPERTY(religion);
std::optional<CountryParty const*> PROPERTY(ruling_party);
std::optional<Date> PROPERTY(last_election);
@@ -43,7 +43,7 @@ namespace OpenVic {
std::optional<NationalValue const*> PROPERTY(national_value);
std::optional<bool> PROPERTY_CUSTOM_PREFIX(civilised, is);
std::optional<fixed_point_t> PROPERTY(prestige);
- std::vector<Reform const*> PROPERTY(reforms);
+ 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);
diff --git a/src/openvic-simulation/history/ProvinceHistory.cpp b/src/openvic-simulation/history/ProvinceHistory.cpp
index 1fa6e90..ca0bf4e 100644
--- a/src/openvic-simulation/history/ProvinceHistory.cpp
+++ b/src/openvic-simulation/history/ProvinceHistory.cpp
@@ -30,6 +30,33 @@ bool ProvinceHistoryMap::_load_history_entry(
{ "0", STATE }, { "1", PROTECTORATE }, { "2", COLONY }
};
+ const auto set_core_instruction = [&entry](bool add) {
+ return [&entry, add](CountryDefinition const& country) -> bool {
+ const auto it = entry.cores.find(&country);
+ if (it == entry.cores.end()) {
+ // No current core instruction
+ entry.cores.emplace(&country, add);
+ return true;
+ } else if (it->second == add) {
+ // Desired core instruction already exists
+ Logger::warning(
+ "Duplicate attempt to ", add ? "add" : "remove", " core of country ", country.get_identifier(),
+ " ", add ? "to" : "from", " province history of ", entry.get_province()
+ );
+ return true;
+ } else {
+ // Opposite core instruction exists
+ entry.cores.erase(it);
+ Logger::warning(
+ "Attempted to ", add ? "add" : "remove", " core of country ", country.get_identifier(),
+ " ", add ? "to" : "from", " province history of ", entry.get_province(),
+ " after previously ", add ? "adding" : "removing", " it"
+ );
+ return true;
+ }
+ };
+ };
+
return expect_dictionary_keys_and_default(
[this, &definition_manager, &building_type_manager, &entry](
std::string_view key, ast::NodeCPtr value) -> bool {
@@ -60,10 +87,10 @@ bool ProvinceHistoryMap::_load_history_entry(
assign_variable_callback_pointer_opt(entry.controller, true)
),
"add_core", ZERO_OR_MORE, country_definition_manager.expect_country_definition_identifier(
- vector_callback_pointer(entry.add_cores)
+ set_core_instruction(true)
),
"remove_core", ZERO_OR_MORE, country_definition_manager.expect_country_definition_identifier(
- vector_callback_pointer(entry.remove_cores)
+ set_core_instruction(false)
),
"colonial", ZERO_OR_ONE,
expect_identifier(expect_mapped_string(colony_status_map, assign_variable_callback(entry.colonial))),
diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp
index 85853d7..99ea2af 100644
--- a/src/openvic-simulation/history/ProvinceHistory.hpp
+++ b/src/openvic-simulation/history/ProvinceHistory.hpp
@@ -31,8 +31,7 @@ namespace OpenVic {
std::optional<CountryDefinition const*> PROPERTY(controller);
std::optional<ProvinceInstance::colony_status_t> PROPERTY(colonial);
std::optional<bool> PROPERTY(slave);
- std::vector<CountryDefinition const*> PROPERTY(add_cores);
- std::vector<CountryDefinition const*> PROPERTY(remove_cores);
+ ordered_map<CountryDefinition const*, bool> PROPERTY(cores);
std::optional<GoodDefinition const*> PROPERTY(rgo);
std::optional<ProvinceInstance::life_rating_t> PROPERTY(life_rating);
std::optional<TerrainType const*> PROPERTY(terrain_type);
diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp
index 986b102..56b3642 100644
--- a/src/openvic-simulation/map/MapInstance.cpp
+++ b/src/openvic-simulation/map/MapInstance.cpp
@@ -10,20 +10,12 @@ MapInstance::MapInstance(MapDefinition const& new_map_definition)
: map_definition { new_map_definition }, selected_province { nullptr }, highest_province_population { 0 },
total_map_population { 0 } {}
-ProvinceInstance* MapInstance::get_province_instance_from_const(ProvinceDefinition const* province) {
- if (province != nullptr) {
- return get_province_instance_by_index(province->get_index());
- } else {
- return nullptr;
- }
+ProvinceInstance& MapInstance::get_province_instance_from_definition(ProvinceDefinition const& province) {
+ return province_instances.get_items()[province.get_index() - 1];
}
-ProvinceInstance const* MapInstance::get_province_instance_from_const(ProvinceDefinition const* province) const {
- if (province != nullptr) {
- return get_province_instance_by_index(province->get_index());
- } else {
- return nullptr;
- }
+ProvinceInstance const& MapInstance::get_province_instance_from_definition(ProvinceDefinition const& province) const {
+ return province_instances.get_items()[province.get_index() - 1];
}
void MapInstance::set_selected_province(ProvinceDefinition::index_t index) {
@@ -89,7 +81,8 @@ bool MapInstance::setup(
}
bool MapInstance::apply_history_to_provinces(
- ProvinceHistoryManager const& history_manager, Date date, IssueManager const& issue_manager
+ ProvinceHistoryManager const& history_manager, Date date, CountryInstanceManager& country_manager,
+ IssueManager const& issue_manager
) {
bool ret = true;
@@ -102,7 +95,7 @@ bool MapInstance::apply_history_to_provinces(
ProvinceHistoryEntry const* pop_history_entry = nullptr;
for (ProvinceHistoryEntry const* entry : history_map->get_entries_up_to(date)) {
- province.apply_history_to_province(entry);
+ province.apply_history_to_province(entry, country_manager);
if (!entry->get_pops().empty()) {
pop_history_entry = entry;
diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp
index 00bd638..d2d9a26 100644
--- a/src/openvic-simulation/map/MapInstance.hpp
+++ b/src/openvic-simulation/map/MapInstance.hpp
@@ -35,8 +35,8 @@ namespace OpenVic {
IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS_CUSTOM_INDEX_OFFSET(province_instance, 1);
- ProvinceInstance* get_province_instance_from_const(ProvinceDefinition const* province);
- ProvinceInstance const* get_province_instance_from_const(ProvinceDefinition const* province) const;
+ ProvinceInstance& get_province_instance_from_definition(ProvinceDefinition const& province);
+ ProvinceInstance const& get_province_instance_from_definition(ProvinceDefinition const& province) const;
void set_selected_province(ProvinceDefinition::index_t index);
ProvinceInstance* get_selected_province();
@@ -48,7 +48,8 @@ namespace OpenVic {
decltype(ProvinceInstance::ideology_distribution)::keys_t const& ideology_keys
);
bool apply_history_to_provinces(
- ProvinceHistoryManager const& history_manager, Date date, IssueManager const& issue_manager
+ ProvinceHistoryManager const& history_manager, Date date, CountryInstanceManager& country_manager,
+ IssueManager const& issue_manager
);
void update_gamestate(Date today);
diff --git a/src/openvic-simulation/map/Mapmode.cpp b/src/openvic-simulation/map/Mapmode.cpp
index c47a07a..cab67d1 100644
--- a/src/openvic-simulation/map/Mapmode.cpp
+++ b/src/openvic-simulation/map/Mapmode.cpp
@@ -2,7 +2,7 @@
#include <cassert>
-#include "openvic-simulation/country/CountryDefinition.hpp"
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/map/MapDefinition.hpp"
#include "openvic-simulation/map/MapInstance.hpp"
#include "openvic-simulation/map/ProvinceDefinition.hpp"
@@ -90,7 +90,7 @@ static constexpr colour_argb_t DEFAULT_COLOUR_WHITE = (0xFFFFFF_argb).with_alpha
* national focus, RGO, population density, sphere of influence, ranking and migration. */
static constexpr colour_argb_t DEFAULT_COLOUR_GREY = (0x7F7F7F_argb).with_alpha(ALPHA_VALUE);
-template<utility::is_derived_from_specialization_of<_HasColour> T, typename P>
+template<HasGetColour T, typename P>
requires(std::same_as<P, ProvinceDefinition> || std::same_as<P, ProvinceInstance>)
static constexpr auto get_colour_mapmode(T const*(P::*get_item)() const) {
return [get_item](MapInstance const&, ProvinceInstance const& province) -> Mapmode::base_stripe_t {
@@ -114,7 +114,7 @@ static constexpr auto get_colour_mapmode(T const*(P::*get_item)() const) {
};
}
-template<utility::is_derived_from_specialization_of<_HasColour> T>
+template<HasGetColour T>
static constexpr Mapmode::base_stripe_t shaded_mapmode(fixed_point_map_t<T const*> const& map) {
const std::pair<fixed_point_map_const_iterator_t<T const*>, fixed_point_map_const_iterator_t<T const*>> largest =
get_largest_two_items(map);
@@ -132,7 +132,7 @@ static constexpr Mapmode::base_stripe_t shaded_mapmode(fixed_point_map_t<T const
return colour_argb_t::null();
}
-template<utility::is_derived_from_specialization_of<_HasColour> T>
+template<HasGetColour T>
static constexpr auto shaded_mapmode(fixed_point_map_t<T const*> const&(ProvinceInstance::*get_map)() const) {
return [get_map](MapInstance const&, ProvinceInstance const& province) -> Mapmode::base_stripe_t {
return shaded_mapmode((province.*get_map)());
diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp
index 6b20cd2..ee20590 100644
--- a/src/openvic-simulation/map/ProvinceInstance.cpp
+++ b/src/openvic-simulation/map/ProvinceInstance.cpp
@@ -1,9 +1,10 @@
#include "ProvinceInstance.hpp"
-#include "openvic-simulation/country/CountryDefinition.hpp"
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/history/ProvinceHistory.hpp"
#include "openvic-simulation/map/ProvinceDefinition.hpp"
#include "openvic-simulation/military/UnitInstanceGroup.hpp"
+#include "openvic-simulation/politics/Ideology.hpp"
using namespace OpenVic;
@@ -32,6 +33,65 @@ ProvinceInstance::ProvinceInstance(
culture_distribution {},
religion_distribution {} {}
+bool ProvinceInstance::set_owner(CountryInstance* new_owner) {
+ bool ret = true;
+
+ if (owner != new_owner) {
+ if (owner != nullptr) {
+ ret &= owner->remove_owned_province(*this);
+ }
+
+ owner = new_owner;
+
+ if (owner != nullptr) {
+ ret &= owner->add_owned_province(*this);
+ }
+ }
+
+ return ret;
+}
+
+bool ProvinceInstance::set_controller(CountryInstance* new_controller) {
+ bool ret = true;
+
+ if (controller != new_controller) {
+ if (controller != nullptr) {
+ ret &= controller->remove_controlled_province(*this);
+ }
+
+ controller = new_controller;
+
+ if (controller != nullptr) {
+ ret &= controller->add_controlled_province(*this);
+ }
+ }
+
+ return ret;
+}
+
+bool ProvinceInstance::add_core(CountryInstance& new_core) {
+ if (cores.emplace(&new_core).second) {
+ return new_core.add_core_province(*this);
+ } else {
+ Logger::error(
+ "Attempted to add core \"", new_core.get_identifier(), "\" to country ", get_identifier(), ": already exists!"
+ );
+ return false;
+ }
+}
+
+bool ProvinceInstance::remove_core(CountryInstance& core_to_remove) {
+ if (cores.erase(&core_to_remove) > 0) {
+ return core_to_remove.remove_core_province(*this);
+ } else {
+ Logger::error(
+ "Attempted to remove core \"", core_to_remove.get_identifier(), "\" from country ", get_identifier(),
+ ": does not exist!"
+ );
+ return false;
+ }
+}
+
bool ProvinceInstance::expand_building(size_t building_index) {
BuildingInstance* building = buildings.get_item_by_index(building_index);
if (building == nullptr) {
@@ -43,7 +103,7 @@ bool ProvinceInstance::expand_building(size_t building_index) {
void ProvinceInstance::_add_pop(Pop&& pop) {
pop.set_location(*this);
- pops.push_back(std::move(pop));
+ pops.insert(std::move(pop));
}
bool ProvinceInstance::add_pop(Pop&& pop) {
@@ -78,17 +138,32 @@ size_t ProvinceInstance::get_pop_count() const {
*/
void ProvinceInstance::_update_pops() {
total_population = 0;
+ average_literacy = 0;
+ average_consciousness = 0;
+ average_militancy = 0;
+
pop_type_distribution.clear();
ideology_distribution.clear();
culture_distribution.clear();
religion_distribution.clear();
+
for (Pop const& pop : pops) {
total_population += pop.get_size();
+ average_literacy += pop.get_literacy();
+ average_consciousness += pop.get_consciousness();
+ average_militancy += pop.get_militancy();
+
pop_type_distribution[pop.get_type()] += pop.get_size();
ideology_distribution += pop.get_ideologies();
culture_distribution[&pop.get_culture()] += pop.get_size();
religion_distribution[&pop.get_religion()] += pop.get_size();
}
+
+ if (total_population > 0) {
+ average_literacy /= total_population;
+ average_consciousness /= total_population;
+ average_militancy /= total_population;
+ }
}
void ProvinceInstance::update_gamestate(Date today) {
@@ -161,39 +236,38 @@ bool ProvinceInstance::setup(BuildingTypeManager const& building_type_manager) {
return ret;
}
-bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* entry) {
+bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* entry, CountryInstanceManager& country_manager) {
if (entry == nullptr) {
Logger::error("Trying to apply null province history to ", get_identifier());
return false;
}
- if (entry->get_life_rating()) life_rating = *entry->get_life_rating();
- if (entry->get_colonial()) colony_status = *entry->get_colonial();
- if (entry->get_rgo()) rgo = *entry->get_rgo();
- if (entry->get_terrain_type()) terrain_type = *entry->get_terrain_type();
- if (entry->get_owner()) owner = *entry->get_owner();
- if (entry->get_controller()) controller = *entry->get_controller();
- if (entry->get_slave()) slave = *entry->get_slave();
- for (CountryDefinition const* core : entry->get_remove_cores()) {
- const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core);
- if (existing_core != cores.end()) {
- cores.erase(existing_core);
- } else {
- Logger::warning(
- "Trying to remove non-existent core ", core->get_identifier(), " from province ", get_identifier()
- );
+
+ bool ret = true;
+
+ constexpr auto set_optional = []<typename T>(T& target, std::optional<T> const& source) {
+ if (source) {
+ target = *source;
}
+ };
+
+ if (entry->get_owner()) {
+ ret &= set_owner(&country_manager.get_country_instance_from_definition(**entry->get_owner()));
}
- for (CountryDefinition const* core : entry->get_add_cores()) {
- const typename decltype(cores)::iterator existing_core = std::find(cores.begin(), cores.end(), core);
- if (existing_core == cores.end()) {
- cores.push_back(core);
+ if (entry->get_controller()) {
+ ret &= set_controller(&country_manager.get_country_instance_from_definition(**entry->get_controller()));
+ }
+ set_optional(colony_status, entry->get_colonial());
+ set_optional(slave, entry->get_slave());
+ for (auto const& [country, add] : entry->get_cores()) {
+ if (add) {
+ ret &= add_core(country_manager.get_country_instance_from_definition(*country));
} else {
- Logger::warning(
- "Trying to add already-existing core ", core->get_identifier(), " to province ", get_identifier()
- );
+ ret &= remove_core(country_manager.get_country_instance_from_definition(*country));
}
}
- bool ret = true;
+ set_optional(rgo, entry->get_rgo());
+ set_optional(life_rating, entry->get_life_rating());
+ set_optional(terrain_type, entry->get_terrain_type());
for (auto const& [building, level] : entry->get_province_buildings()) {
BuildingInstance* existing_entry = buildings.get_item_by_identifier(building->get_identifier());
if (existing_entry != nullptr) {
@@ -206,8 +280,8 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* ent
ret = false;
}
}
- // TODO: load state buildings
- // TODO: party loyalties for each POP when implemented on POP side
+ // TODO: load state buildings - entry->get_state_buildings()
+ // TODO: party loyalties for each POP when implemented on POP side - entry->get_party_loyalties()
return ret;
}
diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp
index ec06e0c..048ac3b 100644
--- a/src/openvic-simulation/map/ProvinceInstance.hpp
+++ b/src/openvic-simulation/map/ProvinceInstance.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <plf_colony.h>
+
#include "openvic-simulation/economy/BuildingInstance.hpp"
#include "openvic-simulation/military/UnitInstance.hpp"
#include "openvic-simulation/military/UnitType.hpp"
@@ -13,7 +15,7 @@ namespace OpenVic {
struct ProvinceDefinition;
struct TerrainType;
struct State;
- struct CountryDefinition;
+ struct CountryInstance;
struct Crime;
struct GoodDefinition;
struct Ideology;
@@ -22,6 +24,7 @@ namespace OpenVic {
struct BuildingTypeManager;
struct ProvinceHistoryEntry;
struct IssueManager;
+ struct CountryInstanceManager;
template<UnitType::branch_t>
struct UnitInstanceGroup;
@@ -39,17 +42,32 @@ namespace OpenVic {
enum struct colony_status_t : uint8_t { STATE, PROTECTORATE, COLONY };
+ static constexpr std::string_view get_colony_status_string(colony_status_t colony_status) {
+ using enum colony_status_t;
+ switch (colony_status) {
+ case STATE:
+ return "state";
+ case PROTECTORATE:
+ return "protectorate";
+ case COLONY:
+ return "colony";
+ default:
+ return "unknown colony status";
+ }
+ }
+
private:
ProvinceDefinition const& PROPERTY(province_definition);
TerrainType const* PROPERTY(terrain_type);
life_rating_t PROPERTY(life_rating);
colony_status_t PROPERTY(colony_status);
- State const* PROPERTY_RW(state);
- CountryDefinition const* PROPERTY(owner);
- CountryDefinition const* PROPERTY(controller);
- // Cores being CountryDefinitions means then they won't be affected by tag switched (as desired)
- std::vector<CountryDefinition const*> PROPERTY(cores);
+ State* PROPERTY_RW(state);
+
+ CountryInstance* PROPERTY(owner);
+ CountryInstance* PROPERTY(controller);
+ ordered_set<CountryInstance*> PROPERTY(cores);
+
bool PROPERTY(slave);
Crime const* PROPERTY_RW(crime);
// TODO - change this into a factory-like structure
@@ -60,8 +78,12 @@ namespace OpenVic {
UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies);
- std::vector<Pop> PROPERTY(pops);
+ plf::colony<Pop> PROPERTY(pops); // TODO - replace with a more easily vectorisable container?
Pop::pop_size_t PROPERTY(total_population);
+ // TODO - population change (growth + migration), monthly totals + breakdown by source/destination
+ fixed_point_t PROPERTY(average_literacy);
+ fixed_point_t PROPERTY(average_consciousness);
+ fixed_point_t PROPERTY(average_militancy);
IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution);
IndexedMap<Ideology, fixed_point_t> PROPERTY(ideology_distribution);
fixed_point_map_t<Culture const*> PROPERTY(culture_distribution);
@@ -82,6 +104,18 @@ namespace OpenVic {
return province_definition;
}
+ constexpr CountryInstance* get_owner() {
+ return owner;
+ }
+ constexpr CountryInstance* get_controller() {
+ return controller;
+ }
+
+ bool set_owner(CountryInstance* new_owner);
+ bool set_controller(CountryInstance* new_controller);
+ bool add_core(CountryInstance& new_core);
+ bool remove_core(CountryInstance& core_to_remove);
+
bool expand_building(size_t building_index);
bool add_pop(Pop&& pop);
@@ -97,7 +131,7 @@ namespace OpenVic {
bool remove_unit_instance_group(UnitInstanceGroup<Branch>& group);
bool setup(BuildingTypeManager const& building_type_manager);
- bool apply_history_to_province(ProvinceHistoryEntry const* entry);
+ bool apply_history_to_province(ProvinceHistoryEntry const* entry, CountryInstanceManager& country_manager);
void setup_pop_test_values(IssueManager const& issue_manager);
};
diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp
index 42d84cc..68f2f43 100644
--- a/src/openvic-simulation/map/State.cpp
+++ b/src/openvic-simulation/map/State.cpp
@@ -1,23 +1,51 @@
#include "State.hpp"
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/map/MapDefinition.hpp"
#include "openvic-simulation/map/MapInstance.hpp"
#include "openvic-simulation/map/ProvinceInstance.hpp"
#include "openvic-simulation/map/Region.hpp"
+#include "openvic-simulation/utility/StringUtils.hpp"
using namespace OpenVic;
State::State(
- StateSet const& new_state_set, CountryDefinition const* owner, ProvinceInstance* capital,
- std::vector<ProvinceInstance*>&& provinces, ProvinceInstance::colony_status_t colony_status
+ StateSet const& new_state_set, CountryInstance* owner, ProvinceInstance* capital,
+ std::vector<ProvinceInstance*>&& provinces, ProvinceInstance::colony_status_t colony_status,
+ decltype(pop_type_distribution)::keys_t const& pop_type_keys
) : state_set { new_state_set }, owner { owner }, capital { capital }, provinces { std::move(provinces) },
- colony_status { colony_status } {}
+ colony_status { colony_status }, pop_type_distribution { &pop_type_keys } {}
+
+std::string State::get_identifier() const {
+ return StringUtils::append_string_views(
+ state_set.get_region().get_identifier(), "_", owner->get_identifier(), "_",
+ ProvinceInstance::get_colony_status_string(colony_status)
+ );
+}
void State::update_gamestate() {
total_population = 0;
+ average_literacy = 0;
+ average_consciousness = 0;
+ average_militancy = 0;
+ pop_type_distribution.clear();
for (ProvinceInstance const* province : provinces) {
total_population += province->get_total_population();
+
+ // TODO - change casting if Pop::pop_size_t changes type
+ const fixed_point_t province_population = fixed_point_t::parse(province->get_total_population());
+ average_literacy += province->get_average_literacy() * province_population;
+ average_consciousness += province->get_average_consciousness() * province_population;
+ average_militancy += province->get_average_militancy() * province_population;
+
+ pop_type_distribution += province->get_pop_type_distribution();
+ }
+
+ if (total_population > 0) {
+ average_literacy /= total_population;
+ average_consciousness /= total_population;
+ average_militancy /= total_population;
}
}
@@ -39,7 +67,9 @@ void StateSet::update_gamestate() {
}
}
-bool StateManager::add_state_set(MapInstance& map_instance, Region const& region) {
+bool StateManager::add_state_set(
+ MapInstance& map_instance, Region const& region, decltype(State::pop_type_distribution)::keys_t const& pop_type_keys
+) {
if (region.get_meta()) {
Logger::error("Cannot use meta region \"", region.get_identifier(), "\" as state template!");
return false;
@@ -54,7 +84,7 @@ bool StateManager::add_state_set(MapInstance& map_instance, Region const& region
for (ProvinceDefinition const* province : region.get_provinces()) {
- ProvinceInstance* province_instance = map_instance.get_province_instance_from_const(province);
+ ProvinceInstance* province_instance = &map_instance.get_province_instance_from_definition(*province);
// add to existing state if shared owner & status...
for (std::vector<ProvinceInstance*>& provinces : temp_provinces) {
@@ -83,22 +113,28 @@ bool StateManager::add_state_set(MapInstance& map_instance, Region const& region
for (std::vector<ProvinceInstance*>& provinces : temp_provinces) {
ProvinceInstance* capital = provinces.front();
- state_set.states.push_back(
+ CountryInstance* owner = capital->get_owner();
+
+ State& state = *state_set.states.insert(
/* TODO: capital province logic */
- { state_set, capital->get_owner(), capital, std::move(provinces), capital->get_colony_status() }
+ { state_set, owner, capital, std::move(provinces), capital->get_colony_status(), pop_type_keys }
);
- State const& state = state_set.states.back();
-
for (ProvinceInstance* province : state.get_provinces()) {
province->set_state(&state);
}
+
+ if (owner != nullptr) {
+ owner->add_state(state);
+ }
}
return true;
}
-bool StateManager::generate_states(MapInstance& map_instance) {
+bool StateManager::generate_states(
+ MapInstance& map_instance, decltype(State::pop_type_distribution)::keys_t const& pop_type_keys
+) {
MapDefinition const& map_definition = map_instance.get_map_definition();
state_sets.clear();
@@ -109,7 +145,7 @@ bool StateManager::generate_states(MapInstance& map_instance) {
for (Region const& region : map_definition.get_regions()) {
if (!region.get_meta()) {
- if (add_state_set(map_instance, region)) {
+ if (add_state_set(map_instance, region, pop_type_keys)) {
state_count += state_sets.back().get_state_count();
} else {
ret = false;
diff --git a/src/openvic-simulation/map/State.hpp b/src/openvic-simulation/map/State.hpp
index 6111668..44b1947 100644
--- a/src/openvic-simulation/map/State.hpp
+++ b/src/openvic-simulation/map/State.hpp
@@ -1,7 +1,10 @@
#pragma once
+#include <string>
#include <vector>
+#include <plf_colony.h>
+
#include "openvic-simulation/map/ProvinceInstance.hpp"
#include "openvic-simulation/pop/Pop.hpp"
#include "openvic-simulation/utility/Getters.hpp"
@@ -9,7 +12,7 @@
namespace OpenVic {
struct StateManager;
struct StateSet;
- struct CountryDefinition;
+ struct CountryInstance;
struct ProvinceInstance;
struct State {
@@ -17,19 +20,26 @@ namespace OpenVic {
private:
StateSet const& PROPERTY(state_set);
- CountryDefinition const* PROPERTY(owner);
+ CountryInstance* PROPERTY(owner);
ProvinceInstance* PROPERTY(capital);
std::vector<ProvinceInstance*> PROPERTY(provinces);
ProvinceInstance::colony_status_t PROPERTY(colony_status);
Pop::pop_size_t PROPERTY(total_population);
+ fixed_point_t PROPERTY(average_literacy);
+ fixed_point_t PROPERTY(average_consciousness);
+ fixed_point_t PROPERTY(average_militancy);
+ IndexedMap<PopType, fixed_point_t> PROPERTY(pop_type_distribution);
State(
- StateSet const& new_state_set, CountryDefinition const* owner, ProvinceInstance* capital,
- std::vector<ProvinceInstance*>&& provinces, ProvinceInstance::colony_status_t colony_status
+ StateSet const& new_state_set, CountryInstance* owner, ProvinceInstance* capital,
+ std::vector<ProvinceInstance*>&& provinces, ProvinceInstance::colony_status_t colony_status,
+ decltype(pop_type_distribution)::keys_t const& pop_type_keys
);
public:
+ std::string get_identifier() const;
+
void update_gamestate();
};
@@ -38,8 +48,7 @@ namespace OpenVic {
struct StateSet {
friend struct StateManager;
- // TODO - use a container that supports adding and removing items without invalidating pointers
- using states_t = std::vector<State>;
+ using states_t = plf::colony<State>;
private:
Region const& PROPERTY(region);
@@ -60,13 +69,16 @@ namespace OpenVic {
private:
std::vector<StateSet> PROPERTY(state_sets);
- bool add_state_set(MapInstance& map_instance, Region const& region);
+ bool add_state_set(
+ MapInstance& map_instance, Region const& region,
+ decltype(State::pop_type_distribution)::keys_t const& pop_type_keys
+ );
public:
/* Creates states from current province gamestate & regions, sets province state value.
* After this function, the `regions` property is unmanaged and must be carefully updated and
* validated by functions that modify it. */
- bool generate_states(MapInstance& map_instance);
+ bool generate_states(MapInstance& map_instance, decltype(State::pop_type_distribution)::keys_t const& pop_type_keys);
void reset();
diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp
index 80ca3a9..07736f3 100644
--- a/src/openvic-simulation/military/UnitInstanceGroup.cpp
+++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp
@@ -155,6 +155,17 @@ UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>::UnitInstanceGroupBranched(
std::vector<ShipInstance*>&& new_units
) : UnitInstanceGroup { new_name, std::move(new_units) } {}
+
+fixed_point_t UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>::get_total_consumed_supply() const {
+ fixed_point_t total_consumed_supply = 0;
+
+ for (ShipInstance const* ship : get_units()) {
+ total_consumed_supply += ship->get_unit_type().get_supply_consumption_score();
+ }
+
+ return total_consumed_supply;
+}
+
template<UnitType::branch_t Branch>
bool UnitInstanceManager::generate_unit_instance(
UnitDeployment<Branch> const& unit_deployment, UnitInstanceBranched<Branch>*& unit_instance
@@ -220,7 +231,7 @@ bool UnitInstanceManager::generate_unit_instance_group(
});
ret &= unit_instance_group.set_position(
- map_instance.get_province_instance_from_const(unit_deployment_group.get_location())
+ &map_instance.get_province_instance_from_definition(*unit_deployment_group.get_location())
);
ret &= unit_instance_group.set_country(&country);
diff --git a/src/openvic-simulation/military/UnitInstanceGroup.hpp b/src/openvic-simulation/military/UnitInstanceGroup.hpp
index 4fe0cba..78ff289 100644
--- a/src/openvic-simulation/military/UnitInstanceGroup.hpp
+++ b/src/openvic-simulation/military/UnitInstanceGroup.hpp
@@ -90,7 +90,7 @@ namespace OpenVic {
friend struct UnitInstanceManager;
private:
- std::vector<ArmyInstance const*> PROPERTY(carried_armies);
+ std::vector<ArmyInstance*> PROPERTY(carried_armies);
UnitInstanceGroupBranched(
std::string_view new_name,
@@ -99,6 +99,8 @@ namespace OpenVic {
public:
UnitInstanceGroupBranched(UnitInstanceGroupBranched&&) = default;
+
+ fixed_point_t get_total_consumed_supply() const;
};
using NavyInstance = UnitInstanceGroupBranched<UnitType::branch_t::NAVAL>;
diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp
index 0ecd937..c421de3 100644
--- a/src/openvic-simulation/pop/Pop.cpp
+++ b/src/openvic-simulation/pop/Pop.cpp
@@ -1,6 +1,7 @@
#include "Pop.hpp"
#include "openvic-simulation/country/CountryDefinition.hpp"
+#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/map/ProvinceInstance.hpp"
#include "openvic-simulation/military/UnitType.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
@@ -119,7 +120,9 @@ void Pop::set_location(ProvinceInstance const& new_location) {
// TODO - update location dependent attributes
- votes.set_keys(location->get_owner() != nullptr ? &location->get_owner()->get_parties() : nullptr);
+ votes.set_keys(
+ location->get_owner() != nullptr ? &location->get_owner()->get_country_definition()->get_parties() : nullptr
+ );
// TODO - calculate vote distribution
}
}
diff --git a/src/openvic-simulation/types/HasIdentifier.hpp b/src/openvic-simulation/types/HasIdentifier.hpp
index 925d58b..74961e3 100644
--- a/src/openvic-simulation/types/HasIdentifier.hpp
+++ b/src/openvic-simulation/types/HasIdentifier.hpp
@@ -2,6 +2,8 @@
#include <algorithm>
#include <cassert>
+#include <string>
+#include <string_view>
#include <ostream>
#include "openvic-simulation/types/Colour.hpp"
@@ -49,6 +51,11 @@ namespace OpenVic {
return obj != nullptr ? stream << *obj : stream << "<NULL>";
}
+ template<typename T>
+ concept HasGetIdentifier = requires(T const& t) {
+ { t.get_identifier() } -> std::same_as<std::string_view>;
+ };
+
/*
* Base class for objects with associated colour information.
*/
@@ -71,6 +78,11 @@ namespace OpenVic {
using HasColour = _HasColour<colour_t>;
using HasAlphaColour = _HasColour<colour_argb_t>;
+ template<typename T>
+ concept HasGetColour = requires(T const& t) {
+ { t.get_colour() } -> IsColour;
+ };
+
/*
* Base class for objects with a unique string identifier and associated colour information.
*/
@@ -107,4 +119,9 @@ namespace OpenVic {
HasIndex& operator=(HasIndex const&) = delete;
HasIndex& operator=(HasIndex&&) = delete;
};
+
+ template<typename T>
+ concept HasGetIndex = requires(T const& t) {
+ { t.get_index() } -> std::unsigned_integral;
+ };
}
diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp
index a73ebcc..03cdbb1 100644
--- a/src/openvic-simulation/types/IdentifierRegistry.hpp
+++ b/src/openvic-simulation/types/IdentifierRegistry.hpp
@@ -4,6 +4,7 @@
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
+#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/utility/Getters.hpp"
#include "openvic-simulation/utility/Logger.hpp"
@@ -27,11 +28,6 @@ namespace OpenVic {
return true;
}
- template<typename T>
- concept HasGetIdentifier = requires(T const& t) {
- { t.get_identifier() } -> std::same_as<std::string_view>;
- };
-
/* Registry Value Info - the type that is being registered, and a unique identifier string getter. */
template<typename ValueInfo>
concept RegistryValueInfo = requires(
diff --git a/src/openvic-simulation/types/IndexedMap.hpp b/src/openvic-simulation/types/IndexedMap.hpp
index 68effb9..30cf5cd 100644
--- a/src/openvic-simulation/types/IndexedMap.hpp
+++ b/src/openvic-simulation/types/IndexedMap.hpp
@@ -14,6 +14,8 @@ namespace OpenVic {
using container_t = std::vector<Value>;
using key_t = Key;
using value_t = Value;
+ using value_ref_t = container_t::reference;
+ using value_const_ref_t = container_t::const_reference;
using keys_t = std::vector<key_t>;
using container_t::operator[];
@@ -91,11 +93,11 @@ namespace OpenVic {
}
}
- constexpr value_t& operator[](key_t const& key) {
+ constexpr value_ref_t operator[](key_t const& key) {
return container_t::operator[](get_index_from_item(key));
}
- constexpr value_t const& operator[](key_t const& key) const {
+ constexpr value_const_ref_t operator[](key_t const& key) const {
return container_t::operator[](get_index_from_item(key));
}