aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-09-06 23:58:20 +0200
committer hop311 <hop3114@gmail.com>2024-09-08 18:24:57 +0200
commitb5407c8794c4626d010bd0856a146095daa1042d (patch)
tree19baa8e48c1cf6d2d3b0c152b47f16daa9745a21
parentdd65fa7dd431264caa08d083cb3a94922a4084d5 (diff)
Add country ranking system + great/secondary powers
-rw-r--r--src/headless/main.cpp28
-rw-r--r--src/openvic-simulation/InstanceManager.cpp2
-rw-r--r--src/openvic-simulation/country/CountryInstance.cpp186
-rw-r--r--src/openvic-simulation/country/CountryInstance.hpp53
-rw-r--r--src/openvic-simulation/misc/Define.cpp8
-rw-r--r--src/openvic-simulation/misc/Define.hpp3
6 files changed, 251 insertions, 29 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index fcb5e8d..21e9f7c 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -52,6 +52,34 @@ static bool run_headless(Dataloader::path_vector_t const& roots, bool run_tests)
// This triggers a gamestate update
ret &= game_manager.update_clock();
+ // TODO - REMOVE TEST CODE
+ Logger::info("===== Ranking system test... =====");
+ if (game_manager.get_instance_manager()) {
+ const auto print_ranking_list = [](std::string_view title, std::vector<CountryInstance*> const& countries) -> void {
+ std::string text;
+ for (CountryInstance const* country : countries) {
+ text += StringUtils::append_string_views(
+ "\n ", country->get_identifier(),
+ " - Total #", std::to_string(country->get_total_rank()), " (", country->get_total_score().to_string(1),
+ "), Prestige #", std::to_string(country->get_prestige_rank()), " (", country->get_prestige().to_string(1),
+ "), Industry #", std::to_string(country->get_industrial_rank()), " (", country->get_industrial_power().to_string(1),
+ "), Military #", std::to_string(country->get_military_rank()), " (", country->get_military_power().to_string(1), ")"
+ );
+ }
+ Logger::info(title, ":", text);
+ };
+
+ CountryInstanceManager const& country_instance_manager =
+ game_manager.get_instance_manager()->get_country_instance_manager();
+
+ print_ranking_list("Great Powers", country_instance_manager.get_great_powers());
+ print_ranking_list("Secondary Powers", country_instance_manager.get_secondary_powers());
+ print_ranking_list("All countries", country_instance_manager.get_total_ranking());
+ } else {
+ Logger::error("Instance manager not available!");
+ ret = false;
+ }
+
return ret;
}
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp
index ea30246..6f5ee4a 100644
--- a/src/openvic-simulation/InstanceManager.cpp
+++ b/src/openvic-simulation/InstanceManager.cpp
@@ -41,7 +41,7 @@ void InstanceManager::update_gamestate() {
// Update gamestate...
map_instance.update_gamestate(today);
- country_instance_manager.update_gamestate();
+ country_instance_manager.update_gamestate(today, definition_manager.get_define_manager());
gamestate_updated();
gamestate_needs_update = false;
diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp
index 3c2e7bb..2c7ff70 100644
--- a/src/openvic-simulation/country/CountryInstance.cpp
+++ b/src/openvic-simulation/country/CountryInstance.cpp
@@ -3,12 +3,15 @@
#include "openvic-simulation/country/CountryDefinition.hpp"
#include "openvic-simulation/history/CountryHistory.hpp"
#include "openvic-simulation/map/MapInstance.hpp"
+#include "openvic-simulation/misc/Define.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
#include "openvic-simulation/research/Invention.hpp"
#include "openvic-simulation/research/Technology.hpp"
using namespace OpenVic;
+using enum CountryInstance::country_status_t;
+
static constexpr colour_t ERROR_COLOUR = colour_t::from_integer(0xFF0000);
CountryInstance::CountryInstance(
@@ -23,14 +26,19 @@ CountryInstance::CountryInstance(
colour { ERROR_COLOUR },
capital { nullptr },
country_flags {},
- civilised { false },
releasable_vassal { true },
+ country_status { COUNTRY_STATUS_UNCIVILISED },
+ lose_great_power_date {},
+ total_score { 0 },
+ total_rank { 0 },
owned_provinces {},
controlled_provinces {},
core_provinces {},
states {},
/* Production */
+ industrial_power { 0 },
+ industrial_rank { 0 },
/* Budget */
cash_stockpile { 0 },
@@ -73,16 +81,13 @@ CountryInstance::CountryInstance(
/* Trade */
/* Diplomacy */
- total_rank { 0 },
prestige { 0 },
prestige_rank { 0 },
- industrial_power { 0 },
- industrial_rank { 0 },
- military_power { 0 },
- military_rank { 0 },
diplomatic_points { 0 },
/* Military */
+ military_power { 0 },
+ military_rank { 0 },
generals {},
admirals {},
armies {},
@@ -99,6 +104,26 @@ std::string_view CountryInstance::get_identifier() const {
return country_definition->get_identifier();
}
+bool CountryInstance::exists() const {
+ return !owned_provinces.empty();
+}
+
+bool CountryInstance::is_civilised() const {
+ return country_status <= COUNTRY_STATUS_CIVILISED;
+}
+
+bool CountryInstance::can_colonise() const {
+ return country_status <= COUNTRY_STATUS_SECONDARY_POWER;
+}
+
+bool CountryInstance::is_great_power() const {
+ return country_status == COUNTRY_STATUS_GREAT_POWER;
+}
+
+bool CountryInstance::is_secondary_power() const {
+ return country_status == COUNTRY_STATUS_SECONDARY_POWER;
+}
+
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());
@@ -273,7 +298,9 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry,
set_optional(government_type, entry->get_government_type());
set_optional(plurality, entry->get_plurality());
set_optional(national_value, entry->get_national_value());
- set_optional(civilised, entry->is_civilised());
+ if (entry->is_civilised()) {
+ country_status = *entry->is_civilised() ? COUNTRY_STATUS_CIVILISED : COUNTRY_STATUS_UNCIVILISED;
+ }
set_optional(prestige, entry->get_prestige());
for (Reform const* reform : entry->get_reforms()) {
ret &= add_reform(reform);
@@ -360,7 +387,7 @@ void CountryInstance::_update_trade() {
}
void CountryInstance::_update_diplomacy() {
- // TODO - update prestige, industrial_power, military_power (ranks will be updated after all countries have calculated their scores)
+ // TODO - add prestige from modifiers
// TODO - update diplomatic points and colonial power
}
@@ -383,6 +410,18 @@ void CountryInstance::_update_military() {
}
void CountryInstance::update_gamestate() {
+ // 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();
+
+ total_score = prestige + industrial_power + military_power;
+
if (country_definition != nullptr) {
const CountryDefinition::government_colour_map_t::const_iterator it =
country_definition->get_alternative_colours().find(government_type);
@@ -405,22 +444,129 @@ void CountryInstance::update_gamestate() {
} else {
flag_government_type = nullptr;
}
-
- // 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() {
}
+void CountryInstanceManager::update_rankings(Date today, DefineManager const& define_manager) {
+ total_ranking.clear();
+
+ for (CountryInstance& country : country_instances.get_items()) {
+ if (country.exists()) {
+ total_ranking.push_back(&country);
+ }
+ }
+
+ prestige_ranking = total_ranking;
+ industrial_power_ranking = total_ranking;
+ military_power_ranking = total_ranking;
+
+ std::sort(
+ total_ranking.begin(), total_ranking.end(),
+ [](CountryInstance const* a, CountryInstance const* b) -> bool {
+ const bool a_civilised = a->is_civilised();
+ const bool b_civilised = b->is_civilised();
+ return a_civilised != b_civilised ? a_civilised : a->get_total_score() > b->get_total_score();
+ }
+ );
+ std::sort(
+ prestige_ranking.begin(), prestige_ranking.end(),
+ [](CountryInstance const* a, CountryInstance const* b) -> bool {
+ return a->get_prestige() > b->get_prestige();
+ }
+ );
+ std::sort(
+ industrial_power_ranking.begin(), industrial_power_ranking.end(),
+ [](CountryInstance const* a, CountryInstance const* b) -> bool {
+ return a->get_industrial_power() > b->get_industrial_power();
+ }
+ );
+ std::sort(
+ military_power_ranking.begin(), military_power_ranking.end(),
+ [](CountryInstance const* a, CountryInstance const* b) -> bool {
+ return a->get_military_power() > b->get_military_power();
+ }
+ );
+
+ for (size_t index = 0; index < total_ranking.size(); ++index) {
+ const size_t rank = index + 1;
+ total_ranking[index]->total_rank = rank;
+ prestige_ranking[index]->prestige_rank = rank;
+ industrial_power_ranking[index]->industrial_rank = rank;
+ military_power_ranking[index]->military_rank = rank;
+ }
+
+ const size_t max_great_power_rank = define_manager.get_great_power_rank();
+ const size_t max_secondary_power_rank = define_manager.get_secondary_power_rank();
+ const Timespan lose_great_power_grace_days = define_manager.get_lose_great_power_grace_days();
+
+ // Demote great powers who have been below the max great power rank for longer than the demotion grace period and
+ // remove them from the list. We don't just demote them all and clear the list as when rebuilding we'd need to look
+ // ahead for countries below the max great power rank but still within the demotion grace period.
+ for (CountryInstance* great_power : great_powers) {
+ if (great_power->get_total_rank() > max_great_power_rank && great_power->get_lose_great_power_date() < today) {
+ great_power->country_status = COUNTRY_STATUS_CIVILISED;
+ }
+ }
+ std::erase_if(great_powers, [](CountryInstance const* country) -> bool {
+ return country->get_country_status() != COUNTRY_STATUS_GREAT_POWER;
+ });
+
+ // Demote all secondary powers and clear the list. We will rebuilt the whole list from scratch, so there's no need to
+ // keep countries which are still above the max secondary power rank (they might become great powers instead anyway).
+ for (CountryInstance* secondary_power : secondary_powers) {
+ secondary_power->country_status = COUNTRY_STATUS_CIVILISED;
+ }
+ secondary_powers.clear();
+
+ // Calculate the maximum number of countries eligible for great or secondary power status. This accounts for the
+ // possibility of the max secondary power rank being higher than the max great power rank or both being zero, just
+ // in case someone wants to experiment with only having secondary powers when some great power slots are filled by
+ // countries in the demotion grace period, or having no great or secondary powers at all.
+ const size_t max_power_index = std::clamp(max_secondary_power_rank, max_great_power_rank, total_ranking.size());
+
+ for (size_t index = 0; index < max_power_index; index++) {
+ CountryInstance* country = total_ranking[index];
+
+ if (!country->is_civilised()) {
+ // All further countries are civilised and so ineligible for great or secondary power status.
+ break;
+ }
+
+ if (country->is_great_power()) {
+ // The country already has great power status and is in the great powers list.
+ continue;
+ }
+
+ if (great_powers.size() < max_great_power_rank && country->get_total_rank() <= max_great_power_rank) {
+ // The country is eligible for great power status and there are still slots available,
+ // so it is promoted and added to the list.
+ country->country_status = COUNTRY_STATUS_GREAT_POWER;
+ great_powers.push_back(country);
+ } else if (country->get_total_rank() <= max_secondary_power_rank) {
+ // The country is eligible for secondary power status and so is promoted and added to the list.
+ country->country_status = COUNTRY_STATUS_SECONDARY_POWER;
+ secondary_powers.push_back(country);
+ }
+ }
+
+ // Sort the great powers list by total rank, as pre-existing great powers may have changed rank order and new great
+ // powers will have beeen added to the end of the list regardless of rank.
+ std::sort(great_powers.begin(), great_powers.end(), [](CountryInstance const* a, CountryInstance const* b) -> bool {
+ return a->get_total_rank() < b->get_total_rank();
+ });
+
+ // Update the lose great power date for all great powers which are above the max great power rank.
+ const Date new_lose_great_power_date = today + lose_great_power_grace_days;
+ for (CountryInstance* great_power : great_powers) {
+ if (great_power->get_total_rank() <= max_great_power_rank) {
+ great_power->lose_great_power_date = new_lose_great_power_date;
+ }
+ }
+}
+
CountryInstance& CountryInstanceManager::get_country_instance_from_definition(CountryDefinition const& country) {
return country_instances.get_items()[country.get_index()];
}
@@ -485,10 +631,12 @@ bool CountryInstanceManager::apply_history_to_countries(
return ret;
}
-void CountryInstanceManager::update_gamestate() {
+void CountryInstanceManager::update_gamestate(Date today, DefineManager const& define_manager) {
for (CountryInstance& country : country_instances.get_items()) {
country.update_gamestate();
}
+
+ update_rankings(today, define_manager);
}
void CountryInstanceManager::tick() {
diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp
index f4baf2d..3622e29 100644
--- a/src/openvic-simulation/country/CountryInstance.hpp
+++ b/src/openvic-simulation/country/CountryInstance.hpp
@@ -13,6 +13,7 @@
#include "openvic-simulation/utility/Getters.hpp"
namespace OpenVic {
+ struct CountryInstanceManager;
struct CountryDefinition;
struct ProvinceInstance;
struct State;
@@ -28,12 +29,30 @@ namespace OpenVic {
struct Religion;
struct CountryHistoryEntry;
struct MapInstance;
+ struct DefineManager;
/* 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;
+ /*
+ Westernisation Progress vs Status for Uncivilised Countries:
+ 15 - primitive
+ 16 - uncivilised
+ 50 - uncivilised
+ 51 - partially westernised
+ */
+
+ enum struct country_status_t : uint8_t {
+ COUNTRY_STATUS_GREAT_POWER,
+ COUNTRY_STATUS_SECONDARY_POWER,
+ COUNTRY_STATUS_CIVILISED,
+ COUNTRY_STATUS_PARTIALLY_CIVILISED,
+ COUNTRY_STATUS_UNCIVILISED,
+ COUNTRY_STATUS_PRIMITIVE
+ };
+
private:
/* Main attributes */
// We can always assume country_definition is not null, as it is initialised from a reference and only ever changed
@@ -42,16 +61,21 @@ namespace OpenVic {
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);
+ country_status_t PROPERTY(country_status);
+ Date PROPERTY(lose_great_power_date);
+ fixed_point_t PROPERTY(total_score);
+ size_t PROPERTY(total_rank);
+
ordered_set<ProvinceInstance*> PROPERTY(owned_provinces);
ordered_set<ProvinceInstance*> PROPERTY(controlled_provinces);
ordered_set<ProvinceInstance*> PROPERTY(core_provinces);
ordered_set<State*> PROPERTY(states);
/* Production */
+ fixed_point_t PROPERTY(industrial_power);
+ size_t PROPERTY(industrial_rank);
// TODO - total amount of each good produced
/* Budget */
@@ -102,17 +126,14 @@ namespace OpenVic {
// 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 */
+ fixed_point_t PROPERTY(military_power);
+ size_t PROPERTY(military_rank);
plf::colony<General> PROPERTY(generals);
plf::colony<Admiral> PROPERTY(admirals);
ordered_set<ArmyInstance*> PROPERTY(armies);
@@ -140,6 +161,12 @@ namespace OpenVic {
public:
std::string_view get_identifier() const;
+ bool exists() const;
+ bool is_civilised() const;
+ bool can_colonise() const;
+ bool is_great_power() const;
+ bool is_secondary_power() const;
+
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);
@@ -194,6 +221,16 @@ namespace OpenVic {
private:
IdentifierRegistry<CountryInstance> IDENTIFIER_REGISTRY(country_instance);
+ std::vector<CountryInstance*> PROPERTY(great_powers);
+ std::vector<CountryInstance*> PROPERTY(secondary_powers);
+
+ std::vector<CountryInstance*> PROPERTY(total_ranking);
+ std::vector<CountryInstance*> PROPERTY(prestige_ranking);
+ std::vector<CountryInstance*> PROPERTY(industrial_power_ranking);
+ std::vector<CountryInstance*> PROPERTY(military_power_ranking);
+
+ void update_rankings(Date today, DefineManager const& define_manager);
+
public:
CountryInstance& get_country_instance_from_definition(CountryDefinition const& country);
CountryInstance const& get_country_instance_from_definition(CountryDefinition const& country) const;
@@ -212,7 +249,7 @@ namespace OpenVic {
MapInstance& map_instance
);
- void update_gamestate();
+ void update_gamestate(Date today, DefineManager const& define_manager);
void tick();
};
}
diff --git a/src/openvic-simulation/misc/Define.cpp b/src/openvic-simulation/misc/Define.cpp
index 6161842..2437954 100644
--- a/src/openvic-simulation/misc/Define.cpp
+++ b/src/openvic-simulation/misc/Define.cpp
@@ -150,9 +150,12 @@ bool DefineManager::load_define_years(Timespan& value, Define::Type type, std::s
DefineManager::DefineManager()
: // Date
start_date { 1836, 1, 1 },
- end_date { 1936, 1, 1 }
+ end_date { 1936, 1, 1 },
// Country
+ great_power_rank { 8 },
+ lose_great_power_grace_days { Timespan::from_years(1) },
+ secondary_power_rank { 16 }
// Economy
@@ -231,6 +234,9 @@ bool DefineManager::load_defines_file(ast::NodeCPtr root) {
ret &= load_define(end_date, Date, "end_date");
// Country
+ ret &= load_define(great_power_rank, Country, "GREAT_NATIONS_COUNT");
+ ret &= load_define_days(lose_great_power_grace_days, Country, "GREATNESS_DAYS");
+ ret &= load_define(secondary_power_rank, Country, "COLONIAL_RANK");
// Economy
diff --git a/src/openvic-simulation/misc/Define.hpp b/src/openvic-simulation/misc/Define.hpp
index 7d8fbf7..4e63105 100644
--- a/src/openvic-simulation/misc/Define.hpp
+++ b/src/openvic-simulation/misc/Define.hpp
@@ -41,6 +41,9 @@ namespace OpenVic {
Date PROPERTY(end_date); // end_date
// Country
+ size_t PROPERTY(great_power_rank); // GREAT_NATIONS_COUNT
+ Timespan PROPERTY(lose_great_power_grace_days); // GREATNESS_DAYS
+ size_t PROPERTY(secondary_power_rank); // COLONIAL_RANK
// Economy