aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvic-simulation')
-rw-r--r--src/openvic-simulation/InstanceManager.cpp21
-rw-r--r--src/openvic-simulation/country/CountryDefinition.cpp4
-rw-r--r--src/openvic-simulation/country/CountryDefinition.hpp5
-rw-r--r--src/openvic-simulation/country/CountryInstance.cpp57
-rw-r--r--src/openvic-simulation/country/CountryInstance.hpp27
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp5
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp21
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.cpp2
-rw-r--r--src/openvic-simulation/economy/GoodDefinition.hpp5
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp25
-rw-r--r--src/openvic-simulation/history/CountryHistory.hpp21
-rw-r--r--src/openvic-simulation/map/MapInstance.cpp13
-rw-r--r--src/openvic-simulation/map/MapInstance.hpp11
-rw-r--r--src/openvic-simulation/map/Mapmode.cpp2
-rw-r--r--src/openvic-simulation/map/Mapmode.hpp4
-rw-r--r--src/openvic-simulation/map/ProvinceDefinition.cpp4
-rw-r--r--src/openvic-simulation/map/ProvinceDefinition.hpp4
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.cpp20
-rw-r--r--src/openvic-simulation/map/ProvinceInstance.hpp14
-rw-r--r--src/openvic-simulation/politics/NationalFocus.cpp5
-rw-r--r--src/openvic-simulation/politics/NationalFocus.hpp12
-rw-r--r--src/openvic-simulation/pop/Pop.cpp37
-rw-r--r--src/openvic-simulation/pop/Pop.hpp11
-rw-r--r--src/openvic-simulation/types/HasIdentifier.hpp18
-rw-r--r--src/openvic-simulation/types/IndexedMap.hpp220
25 files changed, 444 insertions, 124 deletions
diff --git a/src/openvic-simulation/InstanceManager.cpp b/src/openvic-simulation/InstanceManager.cpp
index c51dec7..d314acd 100644
--- a/src/openvic-simulation/InstanceManager.cpp
+++ b/src/openvic-simulation/InstanceManager.cpp
@@ -69,7 +69,18 @@ bool InstanceManager::setup() {
}
bool ret = good_instance_manager.setup(definition_manager.get_economy_manager().get_good_definition_manager());
- ret &= map_instance.setup(definition_manager.get_economy_manager().get_building_type_manager());
+ ret &= map_instance.setup(
+ definition_manager.get_economy_manager().get_building_type_manager(),
+ 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()
+ );
game_instance_setup = true;
@@ -104,14 +115,10 @@ 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,
- // TODO - the following arguments are for generating test pop attributes
- definition_manager.get_politics_manager().get_ideology_manager(),
- definition_manager.get_politics_manager().get_issue_manager(),
- *definition_manager.get_country_definition_manager().get_country_definition_by_identifier("ENG")
+ // TODO - the following argument is for generating test pop attributes
+ definition_manager.get_politics_manager().get_issue_manager()
);
- ret &= map_instance.get_state_manager().generate_states(map_instance);
- ret &= country_instance_manager.generate_country_instances(definition_manager.get_country_definition_manager());
ret &= country_instance_manager.apply_history_to_countries(
definition_manager.get_history_manager().get_country_manager(), today, unit_instance_manager, map_instance
);
diff --git a/src/openvic-simulation/country/CountryDefinition.cpp b/src/openvic-simulation/country/CountryDefinition.cpp
index e414e9e..e73629e 100644
--- a/src/openvic-simulation/country/CountryDefinition.cpp
+++ b/src/openvic-simulation/country/CountryDefinition.cpp
@@ -25,7 +25,7 @@ CountryParty::CountryParty(
CountryDefinition::CountryDefinition(
std::string_view new_identifier,
colour_t new_colour,
- size_t new_index,
+ index_t new_index,
GraphicalCultureType const& new_graphical_culture,
IdentifierRegistry<CountryParty>&& new_parties,
unit_names_map_t&& new_unit_names,
@@ -35,7 +35,7 @@ CountryDefinition::CountryDefinition(
colour_t new_secondary_unit_colour,
colour_t new_tertiary_unit_colour
) : HasIdentifierAndColour { new_identifier, new_colour, false },
- index { new_index },
+ HasIndex { new_index },
graphical_culture { new_graphical_culture },
parties { std::move(new_parties) },
unit_names { std::move(new_unit_names) },
diff --git a/src/openvic-simulation/country/CountryDefinition.hpp b/src/openvic-simulation/country/CountryDefinition.hpp
index 70e62b9..f04796a 100644
--- a/src/openvic-simulation/country/CountryDefinition.hpp
+++ b/src/openvic-simulation/country/CountryDefinition.hpp
@@ -41,14 +41,13 @@ namespace OpenVic {
};
/* Generic information about a TAG */
- struct CountryDefinition : HasIdentifierAndColour {
+ struct CountryDefinition : HasIdentifierAndColour, HasIndex<> {
friend struct CountryDefinitionManager;
using unit_names_map_t = ordered_map<UnitType const*, name_list_t>;
using government_colour_map_t = ordered_map<GovernmentType const*, colour_t>;
private:
- const size_t PROPERTY(index);
GraphicalCultureType const& PROPERTY(graphical_culture);
/* Not const to allow elements to be moved, otherwise a copy is forced
* which causes a compile error as the copy constructor has been deleted. */
@@ -62,7 +61,7 @@ namespace OpenVic {
// Unit colours not const due to being added after construction
CountryDefinition(
- std::string_view new_identifier, colour_t new_colour, size_t new_index,
+ std::string_view new_identifier, colour_t new_colour, index_t new_index,
GraphicalCultureType const& new_graphical_culture, IdentifierRegistry<CountryParty>&& new_parties,
unit_names_map_t&& new_unit_names, bool new_dynamic_tag, government_colour_map_t&& new_alternative_colours,
colour_t new_primary_unit_colour, colour_t new_secondary_unit_colour, colour_t new_tertiary_unit_colour
diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp
index a4086a7..3e21bab 100644
--- a/src/openvic-simulation/country/CountryInstance.cpp
+++ b/src/openvic-simulation/country/CountryInstance.cpp
@@ -2,15 +2,29 @@
#include "openvic-simulation/country/CountryDefinition.hpp"
#include "openvic-simulation/history/CountryHistory.hpp"
-#include "openvic-simulation/military/Deployment.hpp"
#include "openvic-simulation/military/UnitInstanceGroup.hpp"
using namespace OpenVic;
-CountryInstance::CountryInstance(CountryDefinition const* new_country_definition)
- : country_definition { new_country_definition }, primary_culture { nullptr }, religion { nullptr }, ruling_party { nullptr },
- last_election {}, capital { nullptr }, government_type { nullptr }, plurality { 0 }, national_value { nullptr },
- civilised { false }, prestige { 0 } {}
+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 {},
+ capital { nullptr },
+ government_type { nullptr },
+ plurality { 0 },
+ national_value { nullptr },
+ civilised { false },
+ prestige { 0 },
+ upper_house { &ideology_keys },
+ technologies { &technology_keys },
+ inventions { &invention_keys } {}
std::string_view CountryInstance::get_identifier() const {
return country_definition != nullptr ? country_definition->get_identifier() : "NULL";
@@ -41,19 +55,20 @@ bool CountryInstance::remove_accepted_culture(Culture const* culture_to_remove)
return true;
}
-void CountryInstance::add_to_upper_house(Ideology const* party, fixed_point_t popularity) {
- upper_house[party] = popularity;
-}
-
-bool CountryInstance::remove_from_upper_house(Ideology const* party) {
- return upper_house.erase(party) == 1;
+bool CountryInstance::set_upper_house(Ideology const* ideology, fixed_point_t popularity) {
+ if (ideology != nullptr) {
+ upper_house[*ideology] = popularity;
+ return true;
+ } else {
+ Logger::error("Trying to set null ideology in upper house of ", get_identifier());
+ return false;
+ }
}
bool CountryInstance::add_reform(Reform const* new_reform) {
if (std::find(reforms.begin(), reforms.end(), new_reform) != reforms.end()) {
Logger::warning(
- "Attempted to add reform ", new_reform->get_identifier(), " to country ", country_definition->get_identifier(),
- ": already present!"
+ "Attempted to add reform \"", new_reform, "\" to country ", get_identifier(), ": already present!"
);
return false;
}
@@ -65,8 +80,7 @@ bool CountryInstance::remove_reform(Reform const* reform_to_remove) {
auto existing_entry = std::find(reforms.begin(), reforms.end(), reform_to_remove);
if (existing_entry == reforms.end()) {
Logger::warning(
- "Attempted to remove reform ", reform_to_remove->get_identifier(), " from country ",
- country_definition->get_identifier(), ": not present!"
+ "Attempted to remove reform \"", reform_to_remove, "\" from country ", get_identifier(), ": not present!"
);
return false;
}
@@ -178,9 +192,7 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry)
set_optional(religion, entry->get_religion());
set_optional(ruling_party, entry->get_ruling_party());
set_optional(last_election, entry->get_last_election());
- for (auto const& [ideology, popularity] : entry->get_upper_house()) {
- add_to_upper_house(ideology, popularity);
- }
+ ret &= upper_house.copy(entry->get_upper_house());
set_optional(capital, entry->get_capital());
set_optional(government_type, entry->get_government_type());
set_optional(plurality, entry->get_plurality());
@@ -194,11 +206,16 @@ bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry)
return ret;
}
-bool CountryInstanceManager::generate_country_instances(CountryDefinitionManager const& country_definition_manager) {
+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
+) {
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 });
+ country_instances.add_item({ &country_definition, technology_keys, invention_keys, ideology_keys });
}
return true;
diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp
index 3022b6a..885a5fd 100644
--- a/src/openvic-simulation/country/CountryInstance.hpp
+++ b/src/openvic-simulation/country/CountryInstance.hpp
@@ -6,9 +6,11 @@
#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/types/Date.hpp"
-#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/types/IndexedMap.hpp"
#include "openvic-simulation/utility/Getters.hpp"
namespace OpenVic {
@@ -34,7 +36,7 @@ namespace OpenVic {
Religion const* PROPERTY_RW(religion);
CountryParty const* PROPERTY_RW(ruling_party);
Date PROPERTY_RW(last_election);
- fixed_point_map_t<Ideology const*> PROPERTY(upper_house);
+ 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);
@@ -44,21 +46,27 @@ namespace OpenVic {
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
+
+ IndexedMap<Technology, bool> PROPERTY(technologies);
+ IndexedMap<Invention, bool> PROPERTY(inventions);
+
// TODO: Military units + OOBs; will probably need an extensible deployment class
plf::colony<General> PROPERTY(generals);
plf::colony<Admiral> PROPERTY(admirals);
- CountryInstance(CountryDefinition const* new_country_definition);
+ 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
+ );
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);
- /* Add or modify a party in the upper house. */
- void add_to_upper_house(Ideology const* party, fixed_point_t popularity);
- bool remove_from_upper_house(Ideology const* party);
+ /* Set a party's popularity in the upper house. */
+ bool set_upper_house(Ideology const* ideology, fixed_point_t popularity);
bool add_reform(Reform const* new_reform);
bool remove_reform(Reform const* reform_to_remove);
@@ -83,7 +91,12 @@ namespace OpenVic {
IdentifierRegistry<CountryInstance> IDENTIFIER_REGISTRY(country_instance);
public:
- bool generate_country_instances(CountryDefinitionManager const& country_definition_manager);
+ 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
+ );
bool apply_history_to_countries(
CountryHistoryManager const& history_manager, Date date, UnitInstanceManager& unit_instance_manager,
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index f42a518..4fbd86b 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -538,7 +538,10 @@ bool Dataloader::_load_history(DefinitionManager& definition_manager, bool unuse
}
return country_history_manager.load_country_history_file(
- definition_manager, *this, *country, parse_defines(file).get_file_node()
+ definition_manager, *this, *country,
+ definition_manager.get_politics_manager().get_ideology_manager().get_ideologies(),
+ definition_manager.get_politics_manager().get_government_type_manager().get_government_types(),
+ parse_defines(file).get_file_node()
);
}
);
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index b0bb723..e53e896 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -12,6 +12,7 @@
#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"
#include "openvic-simulation/utility/Getters.hpp"
@@ -537,6 +538,26 @@ namespace OpenVic {
};
}
+ template<typename Key, typename Value>
+ Callback<Value> auto map_callback(
+ IndexedMap<Key, Value>& map, Key const* key, bool warn = false
+ ) {
+ return [&map, key, warn](Value value) -> bool {
+ if (key == nullptr) {
+ Logger::error("Null key in map_callback");
+ return false;
+ }
+ Value& map_value = map[*key];
+ bool ret = true;
+ if (map_value != Value {}) {
+ Logger::warn_or_error(warn, "Duplicate map entry with key: \"", key, "\"");
+ ret = warn;
+ }
+ map_value = std::move(value);
+ return ret;
+ };
+ }
+
/* Often used for rotations which must be negated due to OpenVic's coordinate system being orientated
* oppositely to Vic2's. */
template<typename T = fixed_point_t>
diff --git a/src/openvic-simulation/economy/GoodDefinition.cpp b/src/openvic-simulation/economy/GoodDefinition.cpp
index 5a3d632..104764b 100644
--- a/src/openvic-simulation/economy/GoodDefinition.cpp
+++ b/src/openvic-simulation/economy/GoodDefinition.cpp
@@ -10,7 +10,7 @@ GoodCategory::GoodCategory(std::string_view new_identifier) : HasIdentifier { ne
GoodDefinition::GoodDefinition(
std::string_view new_identifier, colour_t new_colour, index_t new_index, GoodCategory const& new_category,
price_t new_base_price, bool new_available_from_start, bool new_tradeable, bool new_money, bool new_overseas_penalty
-) : HasIdentifierAndColour { new_identifier, new_colour, false }, index { new_index }, category { new_category },
+) : HasIdentifierAndColour { new_identifier, new_colour, false }, HasIndex { new_index }, category { new_category },
base_price { new_base_price }, available_from_start { new_available_from_start }, tradeable { new_tradeable },
money { new_money }, overseas_penalty { new_overseas_penalty } {
assert(base_price > NULL_PRICE);
diff --git a/src/openvic-simulation/economy/GoodDefinition.hpp b/src/openvic-simulation/economy/GoodDefinition.hpp
index 0a3ad5c..3050243 100644
--- a/src/openvic-simulation/economy/GoodDefinition.hpp
+++ b/src/openvic-simulation/economy/GoodDefinition.hpp
@@ -28,18 +28,15 @@ namespace OpenVic {
* ECON-238, ECON-239, ECON-240, ECON-241, ECON-242, ECON-243, ECON-244, ECON-245, ECON-246, ECON-247, ECON-248, ECON-249,
* ECON-250, ECON-251, ECON-252, ECON-253, ECON-254, ECON-255, ECON-256, ECON-257, ECON-258, ECON-259, ECON-260, ECON-261
*/
- struct GoodDefinition : HasIdentifierAndColour {
+ struct GoodDefinition : HasIdentifierAndColour, HasIndex<> {
friend struct GoodDefinitionManager;
- using index_t = size_t;
-
using price_t = fixed_point_t;
static constexpr price_t NULL_PRICE = fixed_point_t::_0();
using good_definition_map_t = fixed_point_map_t<GoodDefinition const*>;
private:
- const index_t PROPERTY(index);
GoodCategory const& PROPERTY(category);
const price_t PROPERTY(base_price);
const bool PROPERTY_CUSTOM_PREFIX(available_from_start, is);
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
index 5eba9ee..935a769 100644
--- a/src/openvic-simulation/history/CountryHistory.cpp
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -6,13 +6,21 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-CountryHistoryEntry::CountryHistoryEntry(CountryDefinition const& new_country, Date new_date)
- : HistoryEntry { new_date }, country { new_country } {}
+CountryHistoryEntry::CountryHistoryEntry(
+ CountryDefinition const& new_country, Date new_date, decltype(upper_house)::keys_t const& ideology_keys,
+ decltype(government_flag_overrides)::keys_t const& government_type_keys
+) : HistoryEntry { new_date }, country { new_country }, upper_house { &ideology_keys },
+ government_flag_overrides { &government_type_keys } {}
-CountryHistoryMap::CountryHistoryMap(CountryDefinition const& new_country) : country { new_country } {}
+CountryHistoryMap::CountryHistoryMap(
+ CountryDefinition const& new_country, decltype(ideology_keys) new_ideology_keys,
+ decltype(government_type_keys) new_government_type_keys
+) : country { new_country }, ideology_keys { new_ideology_keys }, government_type_keys { new_government_type_keys } {}
std::unique_ptr<CountryHistoryEntry> CountryHistoryMap::_make_entry(Date date) const {
- return std::unique_ptr<CountryHistoryEntry> { new CountryHistoryEntry { country, date } };
+ return std::unique_ptr<CountryHistoryEntry> {
+ new CountryHistoryEntry { country, date, ideology_keys, government_type_keys }
+ };
}
bool CountryHistoryMap::_load_history_entry(
@@ -90,8 +98,7 @@ bool CountryHistoryMap::_load_history_entry(
"prestige", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(entry.prestige)),
"ruling_party", ZERO_OR_ONE, country.expect_party_identifier(assign_variable_callback_pointer_opt(entry.ruling_party)),
"last_election", ZERO_OR_ONE, expect_date(assign_variable_callback(entry.last_election)),
- "upper_house", ZERO_OR_ONE, politics_manager.get_ideology_manager().expect_ideology_dictionary_reserve_length(
- entry.upper_house,
+ "upper_house", ZERO_OR_ONE, politics_manager.get_ideology_manager().expect_ideology_dictionary(
[&entry](Ideology const& ideology, ast::NodeCPtr value) -> bool {
return expect_fixed_point(map_callback(entry.upper_house, &ideology))(value);
}
@@ -216,7 +223,9 @@ CountryHistoryMap const* CountryHistoryManager::get_country_history(CountryDefin
}
bool CountryHistoryManager::load_country_history_file(
- DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country, ast::NodeCPtr root
+ DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country,
+ decltype(CountryHistoryMap::ideology_keys) ideology_keys,
+ decltype(CountryHistoryMap::government_type_keys) government_type_keys, ast::NodeCPtr root
) {
if (locked) {
Logger::error("Attempted to load country history file for ", country, " after country history registry was locked!");
@@ -230,7 +239,7 @@ bool CountryHistoryManager::load_country_history_file(
decltype(country_histories)::iterator it = country_histories.find(&country);
if (it == country_histories.end()) {
const std::pair<decltype(country_histories)::iterator, bool> result =
- country_histories.emplace(&country, CountryHistoryMap { country });
+ country_histories.emplace(&country, CountryHistoryMap { country, ideology_keys, government_type_keys });
if (result.second) {
it = result.first;
} else {
diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp
index 0de76c6..c74841d 100644
--- a/src/openvic-simulation/history/CountryHistory.hpp
+++ b/src/openvic-simulation/history/CountryHistory.hpp
@@ -1,11 +1,11 @@
#pragma once
#include <optional>
-#include <vector>
#include "openvic-simulation/history/HistoryMap.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
+#include "openvic-simulation/types/IndexedMap.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
namespace OpenVic {
@@ -36,7 +36,7 @@ namespace OpenVic {
std::optional<Religion const*> PROPERTY(religion);
std::optional<CountryParty const*> PROPERTY(ruling_party);
std::optional<Date> PROPERTY(last_election);
- fixed_point_map_t<Ideology const*> PROPERTY(upper_house);
+ IndexedMap<Ideology, fixed_point_t> PROPERTY(upper_house);
std::optional<ProvinceDefinition const*> PROPERTY(capital);
std::optional<GovernmentType const*> PROPERTY(government_type);
std::optional<fixed_point_t> PROPERTY(plurality);
@@ -57,10 +57,13 @@ namespace OpenVic {
std::optional<fixed_point_t> PROPERTY(colonial_points);
string_set_t PROPERTY(country_flags);
string_set_t PROPERTY(global_flags);
- ordered_map<GovernmentType const*, GovernmentType const*> PROPERTY(government_flag_overrides);
+ IndexedMap<GovernmentType, GovernmentType const*> PROPERTY(government_flag_overrides);
ordered_set<Decision const*> PROPERTY(decisions);
- CountryHistoryEntry(CountryDefinition const& new_country, Date new_date);
+ CountryHistoryEntry(
+ CountryDefinition const& new_country, Date new_date, decltype(upper_house)::keys_t const& ideology_keys,
+ decltype(government_flag_overrides)::keys_t const& government_type_keys
+ );
};
class Dataloader;
@@ -72,9 +75,14 @@ namespace OpenVic {
private:
CountryDefinition const& PROPERTY(country);
+ decltype(CountryHistoryEntry::upper_house)::keys_t const& PROPERTY(ideology_keys);
+ decltype(CountryHistoryEntry::government_flag_overrides)::keys_t const& PROPERTY(government_type_keys);
protected:
- CountryHistoryMap(CountryDefinition const& new_country);
+ CountryHistoryMap(
+ CountryDefinition const& new_country, decltype(ideology_keys) new_ideology_keys,
+ decltype(government_type_keys) new_government_type_keys
+ );
std::unique_ptr<CountryHistoryEntry> _make_entry(Date date) const override;
bool _load_history_entry(
@@ -99,7 +107,8 @@ namespace OpenVic {
bool load_country_history_file(
DefinitionManager& definition_manager, Dataloader const& dataloader, CountryDefinition const& country,
- ast::NodeCPtr root
+ decltype(CountryHistoryMap::ideology_keys) ideology_keys,
+ decltype(CountryHistoryMap::government_type_keys) government_type_keys, ast::NodeCPtr root
);
};
diff --git a/src/openvic-simulation/map/MapInstance.cpp b/src/openvic-simulation/map/MapInstance.cpp
index 1547ade..986b102 100644
--- a/src/openvic-simulation/map/MapInstance.cpp
+++ b/src/openvic-simulation/map/MapInstance.cpp
@@ -49,7 +49,11 @@ ProvinceDefinition::index_t MapInstance::get_selected_province_index() const {
: ProvinceDefinition::NULL_INDEX;
}
-bool MapInstance::setup(BuildingTypeManager const& building_type_manager) {
+bool MapInstance::setup(
+ BuildingTypeManager const& building_type_manager,
+ decltype(ProvinceInstance::pop_type_distribution)::keys_t const& pop_type_keys,
+ decltype(ProvinceInstance::ideology_distribution)::keys_t const& ideology_keys
+) {
if (province_instances_are_locked()) {
Logger::error("Cannot setup map - province instances are locked!");
return false;
@@ -64,7 +68,7 @@ bool MapInstance::setup(BuildingTypeManager const& building_type_manager) {
province_instances.reserve(map_definition.get_province_definition_count());
for (ProvinceDefinition const& province : map_definition.get_province_definitions()) {
- ret &= province_instances.add_item({ province });
+ ret &= province_instances.add_item({ province, pop_type_keys, ideology_keys });
}
province_instances.lock();
@@ -85,8 +89,7 @@ bool MapInstance::setup(BuildingTypeManager const& building_type_manager) {
}
bool MapInstance::apply_history_to_provinces(
- ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager,
- IssueManager const& issue_manager, CountryDefinition const& country
+ ProvinceHistoryManager const& history_manager, Date date, IssueManager const& issue_manager
) {
bool ret = true;
@@ -109,7 +112,7 @@ bool MapInstance::apply_history_to_provinces(
if (pop_history_entry != nullptr) {
province.add_pop_vec(pop_history_entry->get_pops());
- province.setup_pop_test_values(ideology_manager, issue_manager, country);
+ province.setup_pop_test_values(issue_manager);
}
}
}
diff --git a/src/openvic-simulation/map/MapInstance.hpp b/src/openvic-simulation/map/MapInstance.hpp
index 2c0ff74..00bd638 100644
--- a/src/openvic-simulation/map/MapInstance.hpp
+++ b/src/openvic-simulation/map/MapInstance.hpp
@@ -10,9 +10,7 @@ namespace OpenVic {
struct MapDefinition;
struct BuildingTypeManager;
struct ProvinceHistoryManager;
- struct IdeologyManager;
struct IssueManager;
- struct CountryDefinition;
/* REQUIREMENTS:
* MAP-4
@@ -44,10 +42,13 @@ namespace OpenVic {
ProvinceInstance* get_selected_province();
ProvinceDefinition::index_t get_selected_province_index() const;
- bool setup(BuildingTypeManager const& building_type_manager);
+ bool setup(
+ BuildingTypeManager const& building_type_manager,
+ decltype(ProvinceInstance::pop_type_distribution)::keys_t const& pop_type_keys,
+ decltype(ProvinceInstance::ideology_distribution)::keys_t const& ideology_keys
+ );
bool apply_history_to_provinces(
- ProvinceHistoryManager const& history_manager, Date date, IdeologyManager const& ideology_manager,
- IssueManager const& issue_manager, CountryDefinition const& country
+ ProvinceHistoryManager const& history_manager, Date date, 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 f03b0e8..c47a07a 100644
--- a/src/openvic-simulation/map/Mapmode.cpp
+++ b/src/openvic-simulation/map/Mapmode.cpp
@@ -14,7 +14,7 @@ using namespace OpenVic::colour_literals;
Mapmode::Mapmode(
std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func
-) : HasIdentifier { new_identifier }, index { new_index }, colour_func { new_colour_func } {
+) : HasIdentifier { new_identifier }, HasIndex { new_index }, colour_func { new_colour_func } {
assert(colour_func != nullptr);
}
diff --git a/src/openvic-simulation/map/Mapmode.hpp b/src/openvic-simulation/map/Mapmode.hpp
index d514f7a..ad0ed16 100644
--- a/src/openvic-simulation/map/Mapmode.hpp
+++ b/src/openvic-simulation/map/Mapmode.hpp
@@ -11,7 +11,7 @@ namespace OpenVic {
struct MapInstance;
struct ProvinceInstance;
- struct Mapmode : HasIdentifier {
+ struct Mapmode : HasIdentifier, HasIndex<> {
friend struct MapmodeManager;
/* Bottom 32 bits are the base colour, top 32 are the stripe colour, both in ARGB format with the alpha channels
@@ -24,10 +24,8 @@ namespace OpenVic {
constexpr base_stripe_t(colour_argb_t both) : base_stripe_t { both, both } {}
};
using colour_func_t = std::function<base_stripe_t(MapInstance const&, ProvinceInstance const&)>;
- using index_t = size_t;
private:
- const index_t PROPERTY(index);
const colour_func_t colour_func;
Mapmode(std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func);
diff --git a/src/openvic-simulation/map/ProvinceDefinition.cpp b/src/openvic-simulation/map/ProvinceDefinition.cpp
index c40f8f0..4f34c1e 100644
--- a/src/openvic-simulation/map/ProvinceDefinition.cpp
+++ b/src/openvic-simulation/map/ProvinceDefinition.cpp
@@ -9,7 +9,7 @@ using namespace OpenVic::NodeTools;
ProvinceDefinition::ProvinceDefinition(
std::string_view new_identifier, colour_t new_colour, index_t new_index
-) : HasIdentifierAndColour { new_identifier, new_colour, true }, index { new_index }, region { nullptr },
+) : HasIdentifierAndColour { new_identifier, new_colour, true }, HasIndex { new_index }, region { nullptr },
climate { nullptr }, continent { nullptr }, on_map { false }, water { false }, coastal { false },
port { false }, port_adjacent_province { nullptr }, default_terrain_type { nullptr }, adjacencies {}, centre {},
positions {} {
@@ -22,7 +22,7 @@ bool ProvinceDefinition::operator==(ProvinceDefinition const& other) const {
std::string ProvinceDefinition::to_string() const {
std::stringstream stream;
- stream << "(#" << std::to_string(index) << ", " << get_identifier() << ", 0x" << get_colour() << ")";
+ stream << "(#" << std::to_string(get_index()) << ", " << get_identifier() << ", 0x" << get_colour() << ")";
return stream.str();
}
diff --git a/src/openvic-simulation/map/ProvinceDefinition.hpp b/src/openvic-simulation/map/ProvinceDefinition.hpp
index c66323c..c79af17 100644
--- a/src/openvic-simulation/map/ProvinceDefinition.hpp
+++ b/src/openvic-simulation/map/ProvinceDefinition.hpp
@@ -24,10 +24,9 @@ namespace OpenVic {
* MAP-5, MAP-7, MAP-8, MAP-43, MAP-47
* POP-22
*/
- struct ProvinceDefinition : HasIdentifierAndColour {
+ struct ProvinceDefinition : HasIdentifierAndColour, HasIndex<uint16_t> {
friend struct MapDefinition;
- using index_t = uint16_t;
using distance_t = fixed_point_t; // should this go inside adjacency_t?
struct adjacency_t {
@@ -84,7 +83,6 @@ namespace OpenVic {
private:
/* Immutable attributes (unchanged after initial game load) */
- const index_t PROPERTY(index);
Region const* PROPERTY(region);
Climate const* PROPERTY(climate);
Continent const* PROPERTY(continent);
diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp
index 8bb5345..1792fe0 100644
--- a/src/openvic-simulation/map/ProvinceInstance.cpp
+++ b/src/openvic-simulation/map/ProvinceInstance.cpp
@@ -7,8 +7,10 @@
using namespace OpenVic;
-ProvinceInstance::ProvinceInstance(ProvinceDefinition const& new_province_definition)
- : HasIdentifierAndColour { new_province_definition },
+ProvinceInstance::ProvinceInstance(
+ ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys,
+ decltype(ideology_distribution)::keys_t const& ideology_keys
+) : HasIdentifierAndColour { new_province_definition },
province_definition { new_province_definition },
terrain_type { new_province_definition.get_default_terrain_type() },
life_rating { 0 },
@@ -25,8 +27,8 @@ ProvinceInstance::ProvinceInstance(ProvinceDefinition const& new_province_defini
navies {},
pops {},
total_population { 0 },
- pop_type_distribution {},
- ideology_distribution {},
+ pop_type_distribution { &pop_type_keys },
+ ideology_distribution { &ideology_keys },
culture_distribution {},
religion_distribution {} {}
@@ -58,7 +60,7 @@ bool ProvinceInstance::add_pop_vec(std::vector<PopBase> const& pop_vec) {
if (!province_definition.is_water()) {
reserve_more(pops, pop_vec.size());
for (PopBase const& pop : pop_vec) {
- _add_pop(Pop { pop });
+ _add_pop(Pop { pop, *ideology_distribution.get_keys() });
}
return true;
} else {
@@ -82,7 +84,7 @@ void ProvinceInstance::_update_pops() {
religion_distribution.clear();
for (Pop const& pop : pops) {
total_population += pop.get_size();
- pop_type_distribution[&pop.get_type()] += pop.get_size();
+ 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();
@@ -214,10 +216,8 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const* ent
return ret;
}
-void ProvinceInstance::setup_pop_test_values(
- IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country
-) {
+void ProvinceInstance::setup_pop_test_values(IssueManager const& issue_manager) {
for (Pop& pop : pops) {
- pop.setup_pop_test_values(ideology_manager, issue_manager, country);
+ pop.setup_pop_test_values(issue_manager);
}
}
diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp
index a4f9e98..4398cd4 100644
--- a/src/openvic-simulation/map/ProvinceInstance.hpp
+++ b/src/openvic-simulation/map/ProvinceInstance.hpp
@@ -21,7 +21,6 @@ namespace OpenVic {
struct Religion;
struct BuildingTypeManager;
struct ProvinceHistoryEntry;
- struct IdeologyManager;
struct IssueManager;
template<UnitType::branch_t>
@@ -61,12 +60,15 @@ namespace OpenVic {
std::vector<Pop> PROPERTY(pops);
Pop::pop_size_t PROPERTY(total_population);
- fixed_point_map_t<PopType const*> PROPERTY(pop_type_distribution);
- fixed_point_map_t<Ideology const*> PROPERTY(ideology_distribution);
+ 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);
fixed_point_map_t<Religion const*> PROPERTY(religion_distribution);
- ProvinceInstance(ProvinceDefinition const& new_province_definition);
+ ProvinceInstance(
+ ProvinceDefinition const& new_province_definition, decltype(pop_type_distribution)::keys_t const& pop_type_keys,
+ decltype(ideology_distribution)::keys_t const& ideology_keys
+ );
void _add_pop(Pop&& pop);
void _update_pops();
@@ -116,8 +118,6 @@ namespace OpenVic {
bool setup(BuildingTypeManager const& building_type_manager);
bool apply_history_to_province(ProvinceHistoryEntry const* entry);
- void setup_pop_test_values(
- IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country
- );
+ void setup_pop_test_values(IssueManager const& issue_manager);
};
}
diff --git a/src/openvic-simulation/politics/NationalFocus.cpp b/src/openvic-simulation/politics/NationalFocus.cpp
index 85fcdc0..818021e 100644
--- a/src/openvic-simulation/politics/NationalFocus.cpp
+++ b/src/openvic-simulation/politics/NationalFocus.cpp
@@ -1,5 +1,7 @@
#include "NationalFocus.hpp"
+#include "openvic-simulation/politics/Ideology.hpp"
+
using namespace OpenVic;
using namespace OpenVic::NodeTools;
@@ -16,13 +18,12 @@ NationalFocus::NationalFocus(
Ideology const* new_loyalty_ideology,
fixed_point_t new_loyalty_value,
ConditionScript&& new_limit
-) : HasIdentifier { new_identifier },
+) : Modifier { new_identifier, std::move(new_modifiers), 0 },
group { new_group },
icon { new_icon },
has_flashpoint { new_has_flashpoint },
own_provinces { new_own_provinces },
outliner_show_as_percent { new_outliner_show_as_percent },
- modifiers { std::move(new_modifiers) },
loyalty_ideology { new_loyalty_ideology },
loyalty_value { new_loyalty_value },
limit { std::move(new_limit) } {}
diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp
index f27af43..04a4100 100644
--- a/src/openvic-simulation/politics/NationalFocus.hpp
+++ b/src/openvic-simulation/politics/NationalFocus.hpp
@@ -1,9 +1,6 @@
#pragma once
-#include "openvic-simulation/economy/GoodDefinition.hpp"
#include "openvic-simulation/misc/Modifier.hpp"
-#include "openvic-simulation/politics/Ideology.hpp"
-#include "openvic-simulation/pop/Pop.hpp"
#include "openvic-simulation/scripts/ConditionScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/utility/Getters.hpp"
@@ -18,7 +15,9 @@ namespace OpenVic {
NationalFocusGroup(std::string_view new_identifier);
};
- struct NationalFocus : HasIdentifier {
+ struct Ideology;
+
+ struct NationalFocus : Modifier {
friend struct NationalFocusManager;
private:
@@ -27,7 +26,6 @@ namespace OpenVic {
bool PROPERTY(has_flashpoint);
bool PROPERTY(own_provinces);
bool PROPERTY(outliner_show_as_percent);
- ModifierValue PROPERTY(modifiers);
Ideology const* PROPERTY(loyalty_ideology);
fixed_point_t PROPERTY(loyalty_value);
ConditionScript PROPERTY(limit);
@@ -51,6 +49,10 @@ namespace OpenVic {
NationalFocus(NationalFocus&&) = default;
};
+ struct PopManager;
+ struct IdeologyManager;
+ struct GoodDefinitionManager;
+
struct NationalFocusManager {
private:
IdentifierRegistry<NationalFocusGroup> IDENTIFIER_REGISTRY(national_focus_group);
diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp
index 8f4c445..0ecd937 100644
--- a/src/openvic-simulation/pop/Pop.cpp
+++ b/src/openvic-simulation/pop/Pop.cpp
@@ -19,7 +19,7 @@ PopBase::PopBase(
) : type { new_type }, culture { new_culture }, religion { new_religion }, size { new_size }, militancy { new_militancy },
consciousness { new_consciousness }, rebel_type { new_rebel_type } {}
-Pop::Pop(PopBase const& pop_base)
+Pop::Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys)
: PopBase { pop_base },
location { nullptr },
total_change { 0 },
@@ -29,9 +29,9 @@ Pop::Pop(PopBase const& pop_base)
num_migrated_internal { 0 },
num_migrated_external { 0 },
num_migrated_colonial { 0 },
- ideologies {},
+ ideologies { &ideology_keys },
issues {},
- votes {},
+ votes { nullptr },
unemployment { 0 },
cash { 0 },
income { 0 },
@@ -43,9 +43,7 @@ Pop::Pop(PopBase const& pop_base)
assert(size > 0);
}
-void Pop::setup_pop_test_values(
- IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country
-) {
+void Pop::setup_pop_test_values(IssueManager const& issue_manager) {
/* Returns +/- range% of size. */
const auto test_size = [this](int32_t range) -> pop_size_t {
return size * ((rand() % (2 * range + 1)) - range) / 100;
@@ -63,21 +61,23 @@ void Pop::setup_pop_test_values(
/* Generates a number between 0 and max (inclusive) and sets map[&key] to it if it's at least min. */
auto test_weight =
- []<typename T, std::derived_from<T> U>(
- fixed_point_map_t<T const*>& map, U const& key, int32_t min, int32_t max
- ) -> void {
+ []<typename T, typename U>(T& map, U const& key, int32_t min, int32_t max) -> void {
const int32_t value = rand() % (max + 1);
if (value >= min) {
- map.emplace(&key, value);
+ if constexpr (utility::is_specialization_of_v<T, IndexedMap>) {
+ map[key] = value;
+ } else {
+ map.emplace(&key, value);
+ }
}
};
/* All entries equally weighted for testing. */
ideologies.clear();
- for (Ideology const& ideology : ideology_manager.get_ideologies()) {
+ for (Ideology const& ideology : *ideologies.get_keys()) {
test_weight(ideologies, ideology, 1, 5);
}
- normalise_fixed_point_map(ideologies);
+ ideologies.normalise();
issues.clear();
for (Issue const& issue : issue_manager.get_issues()) {
@@ -90,11 +90,13 @@ void Pop::setup_pop_test_values(
}
normalise_fixed_point_map(issues);
- votes.clear();
- for (CountryParty const& party : country.get_parties()) {
- test_weight(votes, party, 4, 10);
+ if (votes.has_keys()) {
+ votes.clear();
+ for (CountryParty const& party : *votes.get_keys()) {
+ test_weight(votes, party, 4, 10);
+ }
+ votes.normalise();
}
- normalise_fixed_point_map(votes);
/* Returns a fixed point between 0 and max. */
const auto test_range = [](fixed_point_t max = 1) -> fixed_point_t {
@@ -116,6 +118,9 @@ void Pop::set_location(ProvinceInstance const& new_location) {
location = &new_location;
// TODO - update location dependent attributes
+
+ votes.set_keys(location->get_owner() != nullptr ? &location->get_owner()->get_parties() : nullptr);
+ // TODO - calculate vote distribution
}
}
diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp
index 8ac6d4c..c74840f 100644
--- a/src/openvic-simulation/pop/Pop.hpp
+++ b/src/openvic-simulation/pop/Pop.hpp
@@ -10,6 +10,7 @@
#include "openvic-simulation/scripts/ConditionalWeight.hpp"
#include "openvic-simulation/types/EnumBitfield.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+#include "openvic-simulation/types/IndexedMap.hpp"
namespace OpenVic {
@@ -68,9 +69,9 @@ namespace OpenVic {
fixed_point_t PROPERTY(literacy);
- fixed_point_map_t<Ideology const*> PROPERTY(ideologies);
+ IndexedMap<Ideology, fixed_point_t> PROPERTY(ideologies);
fixed_point_map_t<Issue const*> PROPERTY(issues);
- fixed_point_map_t<CountryParty const*> PROPERTY(votes);
+ IndexedMap<CountryParty, fixed_point_t> PROPERTY(votes);
fixed_point_t PROPERTY(unemployment);
fixed_point_t PROPERTY(cash);
@@ -81,7 +82,7 @@ namespace OpenVic {
fixed_point_t PROPERTY(everyday_needs_fulfilled);
fixed_point_t PROPERTY(luxury_needs_fulfilled);
- Pop(PopBase const& pop_base);
+ Pop(PopBase const& pop_base, decltype(ideologies)::keys_t const& ideology_keys);
public:
Pop(Pop const&) = delete;
@@ -89,9 +90,7 @@ namespace OpenVic {
Pop& operator=(Pop const&) = delete;
Pop& operator=(Pop&&) = delete;
- void setup_pop_test_values(
- IdeologyManager const& ideology_manager, IssueManager const& issue_manager, CountryDefinition const& country
- );
+ void setup_pop_test_values(IssueManager const& issue_manager);
void set_location(ProvinceInstance const& new_location);
};
diff --git a/src/openvic-simulation/types/HasIdentifier.hpp b/src/openvic-simulation/types/HasIdentifier.hpp
index 3f2d8a8..941eae9 100644
--- a/src/openvic-simulation/types/HasIdentifier.hpp
+++ b/src/openvic-simulation/types/HasIdentifier.hpp
@@ -85,4 +85,22 @@ namespace OpenVic {
using HasIdentifierAndColour = _HasIdentifierAndColour<colour_t>;
using HasIdentifierAndAlphaColour = _HasIdentifierAndColour<colour_argb_t>;
+
+ template<std::unsigned_integral T = size_t>
+ class HasIndex {
+ public:
+ using index_t = T;
+
+ private:
+ const index_t PROPERTY(index);
+
+ protected:
+ HasIndex(index_t new_index) : index { new_index } {}
+ HasIndex(HasIndex const&) = default;
+
+ public:
+ HasIndex(HasIndex&&) = default;
+ HasIndex& operator=(HasIndex const&) = delete;
+ HasIndex& operator=(HasIndex&&) = delete;
+ };
}
diff --git a/src/openvic-simulation/types/IndexedMap.hpp b/src/openvic-simulation/types/IndexedMap.hpp
new file mode 100644
index 0000000..68effb9
--- /dev/null
+++ b/src/openvic-simulation/types/IndexedMap.hpp
@@ -0,0 +1,220 @@
+#pragma once
+
+#include <concepts>
+#include <vector>
+
+#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp"
+#include "openvic-simulation/utility/Getters.hpp"
+#include "openvic-simulation/utility/Logger.hpp"
+
+namespace OpenVic {
+
+ template<typename Key, typename Value>
+ struct IndexedMap : private std::vector<Value> {
+ using container_t = std::vector<Value>;
+ using key_t = Key;
+ using value_t = Value;
+ using keys_t = std::vector<key_t>;
+
+ using container_t::operator[];
+ using container_t::size;
+ using container_t::begin;
+ using container_t::end;
+
+ private:
+ keys_t const* PROPERTY(keys);
+
+ public:
+ constexpr IndexedMap(keys_t const* new_keys) : keys { nullptr } {
+ set_keys(new_keys);
+ }
+
+ IndexedMap(IndexedMap const&) = default;
+ IndexedMap(IndexedMap&&) = default;
+ IndexedMap& operator=(IndexedMap const&) = default;
+ IndexedMap& operator=(IndexedMap&&) = default;
+
+ constexpr void fill(value_t const& value) {
+ std::fill(container_t::begin(), container_t::end(), value);
+ }
+
+ constexpr void clear() {
+ fill({});
+ }
+
+ constexpr bool has_keys() const {
+ return keys != nullptr;
+ }
+
+ constexpr void set_keys(keys_t const* new_keys) {
+ if (keys != new_keys) {
+ keys = new_keys;
+
+ container_t::resize(keys != nullptr ? keys->size() : 0);
+ clear();
+ }
+ }
+
+ constexpr size_t get_index_from_item(key_t const& key) const {
+ if (has_keys() && keys->data() <= &key && &key <= &keys->back()) {
+ return std::distance(keys->data(), &key);
+ } else {
+ return 0;
+ }
+ }
+
+ constexpr value_t* get_item_by_key(key_t const& key) {
+ const size_t index = get_index_from_item(key);
+ if (index < container_t::size()) {
+ return &container_t::operator[](index);
+ }
+ return nullptr;
+ }
+
+ constexpr value_t const* get_item_by_key(key_t const& key) const {
+ const size_t index = get_index_from_item(key);
+ if (index < container_t::size()) {
+ return &container_t::operator[](index);
+ }
+ return nullptr;
+ }
+
+ constexpr key_t const& operator()(size_t index) const {
+ return (*keys)[index];
+ }
+
+ constexpr key_t const* get_key_by_index(size_t index) const {
+ if (keys != nullptr && index < keys->size()) {
+ return &(*this)(index);
+ } else {
+ return nullptr;
+ }
+ }
+
+ constexpr value_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 {
+ return container_t::operator[](get_index_from_item(key));
+ }
+
+ constexpr IndexedMap& operator+=(IndexedMap const& other) {
+ const size_t count = std::min(container_t::size(), other.size());
+ for (size_t index = 0; index < count; ++index) {
+ container_t::operator[](index) += other[index];
+ }
+ return *this;
+ }
+
+ constexpr IndexedMap& operator*=(value_t factor) {
+ for (value_t& value : *this) {
+ value *= factor;
+ }
+ return *this;
+ }
+
+ constexpr IndexedMap& operator/=(value_t divisor) {
+ for (value_t& value : *this) {
+ value /= divisor;
+ }
+ return *this;
+ }
+
+ constexpr IndexedMap operator+(IndexedMap const& other) const {
+ IndexedMap ret = *this;
+ ret += other;
+ return ret;
+ }
+
+ constexpr IndexedMap operator*(value_t factor) const {
+ IndexedMap ret = *this;
+ ret *= factor;
+ return ret;
+ }
+
+ constexpr IndexedMap operator/(value_t divisor) const {
+ IndexedMap ret = *this;
+ ret /= divisor;
+ return ret;
+ }
+
+ constexpr value_t get_total() const {
+ value_t total {};
+ for (value_t const& value : *this) {
+ total += value;
+ }
+ return total;
+ }
+
+ constexpr IndexedMap& normalise() {
+ const value_t total = get_total();
+ if (total > 0) {
+ *this /= total;
+ }
+ return *this;
+ }
+
+ constexpr bool copy(IndexedMap const& other) {
+ if (keys != other.keys) {
+ Logger::error(
+ "Trying to copy IndexedMaps with different keys with sizes: from ", other.size(), " to ",
+ container_t::size()
+ );
+ return false;
+ }
+ static_cast<container_t&>(*this) = other;
+ return true;
+ }
+
+ fixed_point_map_t<key_t const *> to_fixed_point_map() const
+ requires(std::same_as<value_t, fixed_point_t>)
+ {
+ fixed_point_map_t<key_t const *> result;
+
+ for (size_t index = 0; index < container_t::size(); index++) {
+ fixed_point_t const& value = container_t::operator[](index);
+ if (value != 0) {
+ result[&(*this)(index)] = value;
+ }
+ }
+
+ return result;
+ }
+ };
+
+ template<typename FPMKey, std::derived_from<FPMKey> IMKey>
+ constexpr fixed_point_map_t<FPMKey const*>& operator+=(
+ fixed_point_map_t<FPMKey const*>& lhs, IndexedMap<IMKey, fixed_point_t> const& rhs
+ ) {
+ for (size_t index = 0; index < rhs.size(); index++) {
+ fixed_point_t const& value = rhs[index];
+ if (value != 0) {
+ lhs[&rhs(index)] += value;
+ }
+ }
+ return lhs;
+ }
+
+ /* Result is determined by comparing the first pair of unequal values,
+ * iterating from the highest index downward. */
+ template<typename Key, typename Value>
+ constexpr bool sorted_indexed_map_less_than(
+ IndexedMap<Key, Value> const& lhs, IndexedMap<Key, Value> const& rhs
+ ) {
+ if (lhs.get_keys() != rhs.get_keys() || lhs.size() != rhs.size()) {
+ Logger::error("Trying to compare IndexedMaps with different keys/sizes: ", lhs.size(), " vs ", rhs.size());
+ return false;
+ }
+
+ for (size_t index = lhs.size(); index > 0;) {
+ index--;
+ const std::strong_ordering value_cmp = lhs[index] <=> rhs[index];
+ if (value_cmp != std::strong_ordering::equal) {
+ return value_cmp == std::strong_ordering::less;
+ }
+ }
+
+ return false;
+ }
+}