aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-01-02 15:40:00 +0100
committer GitHub <noreply@github.com>2024-01-02 15:40:00 +0100
commit4c8da86c3bede8834f381fa63edaa3e140131f69 (patch)
treeff3433a63e91b9239eb7226e75054314182d6c1f
parent66b80459c9d49895de902432bce11176b1270878 (diff)
parent5f64f983d0cead266a28791be42162c443fd2a75 (diff)
Merge pull request #112 from OpenVicProject/script-framework
Added framework for loading all Conditions and Effects
-rw-r--r--src/headless/main.cpp2
-rw-r--r--src/openvic-simulation/GameManager.cpp1
-rw-r--r--src/openvic-simulation/country/CountryInstance.cpp2
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp187
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.hpp34
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.cpp47
-rw-r--r--src/openvic-simulation/dataloader/NodeTools.hpp7
-rw-r--r--src/openvic-simulation/economy/BuildingInstance.hpp2
-rw-r--r--src/openvic-simulation/economy/ProductionType.cpp102
-rw-r--r--src/openvic-simulation/economy/ProductionType.hpp44
-rw-r--r--src/openvic-simulation/history/CountryHistory.cpp44
-rw-r--r--src/openvic-simulation/history/DiplomaticHistory.cpp2
-rw-r--r--src/openvic-simulation/interface/GFX.hpp2
-rw-r--r--src/openvic-simulation/map/Crime.cpp26
-rw-r--r--src/openvic-simulation/map/Crime.hpp10
-rw-r--r--src/openvic-simulation/map/Map.hpp2
-rw-r--r--src/openvic-simulation/map/State.cpp2
-rw-r--r--src/openvic-simulation/military/MilitaryManager.hpp2
-rw-r--r--src/openvic-simulation/military/Wargoal.cpp258
-rw-r--r--src/openvic-simulation/military/Wargoal.hpp115
-rw-r--r--src/openvic-simulation/misc/Decision.cpp43
-rw-r--r--src/openvic-simulation/misc/Decision.hpp26
-rw-r--r--src/openvic-simulation/misc/Event.cpp65
-rw-r--r--src/openvic-simulation/misc/Event.hpp27
-rw-r--r--src/openvic-simulation/misc/Modifier.cpp29
-rw-r--r--src/openvic-simulation/misc/Modifier.hpp15
-rw-r--r--src/openvic-simulation/politics/Ideology.cpp60
-rw-r--r--src/openvic-simulation/politics/Ideology.hpp21
-rw-r--r--src/openvic-simulation/politics/Issue.cpp62
-rw-r--r--src/openvic-simulation/politics/Issue.hpp30
-rw-r--r--src/openvic-simulation/politics/NationalFocus.cpp34
-rw-r--r--src/openvic-simulation/politics/NationalFocus.hpp27
-rw-r--r--src/openvic-simulation/politics/Rebel.cpp62
-rw-r--r--src/openvic-simulation/politics/Rebel.hpp24
-rw-r--r--src/openvic-simulation/pop/Pop.cpp144
-rw-r--r--src/openvic-simulation/pop/Pop.hpp54
-rw-r--r--src/openvic-simulation/research/Invention.cpp34
-rw-r--r--src/openvic-simulation/research/Invention.hpp11
-rw-r--r--src/openvic-simulation/research/Technology.cpp35
-rw-r--r--src/openvic-simulation/research/Technology.hpp17
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.cpp8
-rw-r--r--src/openvic-simulation/scripts/ConditionScript.hpp12
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.cpp64
-rw-r--r--src/openvic-simulation/scripts/ConditionalWeight.hpp44
-rw-r--r--src/openvic-simulation/scripts/EffectScript.cpp8
-rw-r--r--src/openvic-simulation/scripts/EffectScript.hpp12
-rw-r--r--src/openvic-simulation/scripts/Script.hpp38
-rw-r--r--src/openvic-simulation/types/Colour.hpp6
48 files changed, 1391 insertions, 512 deletions
diff --git a/src/headless/main.cpp b/src/headless/main.cpp
index d4c316a..7f33314 100644
--- a/src/headless/main.cpp
+++ b/src/headless/main.cpp
@@ -18,7 +18,7 @@ static void print_help(std::ostream& stream, char const* program_name) {
<< "(Paths with spaces need to be enclosed in \"quotes\").\n";
}
-static bool headless_load(GameManager& game_manager, Dataloader const& dataloader) {
+static bool headless_load(GameManager& game_manager, Dataloader& dataloader) {
bool ret = true;
if (!dataloader.load_defines(game_manager)) {
diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp
index 3f66352..c7dd470 100644
--- a/src/openvic-simulation/GameManager.cpp
+++ b/src/openvic-simulation/GameManager.cpp
@@ -66,7 +66,6 @@ bool GameManager::load_bookmark(Bookmark const* new_bookmark) {
ret &= map.apply_history_to_provinces(history_manager.get_province_manager(), today);
map.get_state_manager().generate_states(map);
// TODO - apply country history
- // TODO - apply pop history
return ret;
}
diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp
index 5da787e..11b1e90 100644
--- a/src/openvic-simulation/country/CountryInstance.cpp
+++ b/src/openvic-simulation/country/CountryInstance.cpp
@@ -3,7 +3,7 @@
using namespace OpenVic;
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()) {
+ if (std::find(accepted_cultures.begin(), accepted_cultures.end(), new_accepted_culture) != accepted_cultures.end()) {
Logger::warning("Attempted to add accepted culture ", new_accepted_culture->get_identifier(), " to country ", base_country->get_identifier(), ": already present!");
return false;
}
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index f78499c..a09b999 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -261,7 +261,7 @@ static bool _lua_parse(v2script::Parser& parser) {
return parser.lua_defines_parse();
}
-ovdl::v2script::Parser Dataloader::parse_lua_defines(fs::path const& path) {
+v2script::Parser Dataloader::parse_lua_defines(fs::path const& path) {
return _run_ovdl_parser<v2script::Parser, &_lua_parse>(path);
}
@@ -273,6 +273,14 @@ csv::Windows1252Parser Dataloader::parse_csv(fs::path const& path) {
return _run_ovdl_parser<csv::Windows1252Parser, &_csv_parse>(path);
}
+v2script::Parser& Dataloader::parse_defines_cached(fs::path const& path) {
+ return cached_parsers.emplace_back(parse_defines(path));
+}
+
+void Dataloader::free_cache() {
+ cached_parsers.clear();
+}
+
bool Dataloader::_load_interface_files(UIManager& ui_manager) const {
static constexpr std::string_view interface_directory = "interface/";
@@ -291,8 +299,7 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const {
};
for (std::string_view const& gui_file : gui_files) {
if (!ui_manager.load_gui_file(
- gui_file,
- parse_defines(lookup_file(append_string_views(interface_directory, gui_file))).get_file_node()
+ gui_file, parse_defines(lookup_file(append_string_views(interface_directory, gui_file))).get_file_node()
)) {
Logger::error("Failed to load interface gui file: ", gui_file);
ret = false;
@@ -303,19 +310,21 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const {
return ret;
}
-bool Dataloader::_load_pop_types(GameManager& game_manager) const {
+bool Dataloader::_load_pop_types(GameManager& game_manager) {
PopManager& pop_manager = game_manager.get_pop_manager();
UnitManager const& unit_manager = game_manager.get_military_manager().get_unit_manager();
GoodManager const& good_manager = game_manager.get_economy_manager().get_good_manager();
+ IdeologyManager const& ideology_manager = game_manager.get_politics_manager().get_ideology_manager();
static constexpr std::string_view pop_type_directory = "poptypes";
const path_vector_t pop_type_files = lookup_files_in_dir(pop_type_directory, ".txt");
pop_manager.reserve_pop_types(pop_type_files.size());
+
bool ret = apply_to_files(
pop_type_files,
- [&pop_manager, &unit_manager, &good_manager](fs::path const& file) -> bool {
+ [this, &pop_manager, &unit_manager, &good_manager, &ideology_manager](fs::path const& file) -> bool {
return pop_manager.load_pop_type_file(
- file.stem().string(), unit_manager, good_manager, parse_defines(file).get_file_node()
+ file.stem().string(), unit_manager, good_manager, ideology_manager, parse_defines_cached(file).get_file_node()
);
}
);
@@ -332,6 +341,10 @@ bool Dataloader::_load_pop_types(GameManager& game_manager) const {
}
ret &= pop_manager.generate_modifiers(game_manager.get_modifier_manager());
+
+ static constexpr std::string_view pop_type_chances_file = "common/pop_types.txt";
+ ret &= pop_manager.load_pop_type_chances_file(parse_defines_cached(lookup_file(pop_type_chances_file)).get_file_node());
+
return ret;
}
@@ -339,16 +352,19 @@ bool Dataloader::_load_units(GameManager& game_manager) const {
static constexpr std::string_view units_directory = "units";
UnitManager& unit_manager = game_manager.get_military_manager().get_unit_manager();
+
bool ret = apply_to_files(
lookup_files_in_dir(units_directory, ".txt"),
[&game_manager, &unit_manager](fs::path const& file) -> bool {
- return unit_manager.load_unit_file(game_manager.get_economy_manager().get_good_manager(), parse_defines(file).get_file_node());
+ return unit_manager.load_unit_file(
+ game_manager.get_economy_manager().get_good_manager(), parse_defines(file).get_file_node()
+ );
}
);
unit_manager.lock_units();
- if(!unit_manager.generate_modifiers(game_manager.get_modifier_manager())) {
+ if (!unit_manager.generate_modifiers(game_manager.get_modifier_manager())) {
Logger::error("Failed to generate unit-based modifiers!");
ret = false;
}
@@ -360,9 +376,10 @@ bool Dataloader::_load_goods(GameManager& game_manager) const {
static constexpr std::string_view goods_file = "common/goods.txt";
GoodManager& good_manager = game_manager.get_economy_manager().get_good_manager();
+
bool ret = good_manager.load_goods_file(parse_defines(lookup_file(goods_file)).get_file_node());
- if(!good_manager.generate_modifiers(game_manager.get_modifier_manager())) {
+ if (!good_manager.generate_modifiers(game_manager.get_modifier_manager())) {
Logger::error("Failed to generate good-based modifiers!");
ret = false;
}
@@ -370,15 +387,15 @@ bool Dataloader::_load_goods(GameManager& game_manager) const {
return ret;
}
-bool Dataloader::_load_rebel_types(GameManager& game_manager) const {
+bool Dataloader::_load_rebel_types(GameManager& game_manager) {
static constexpr std::string_view rebel_types_file = "common/rebel_types.txt";
PoliticsManager& politics_manager = game_manager.get_politics_manager();
RebelManager& rebel_manager = politics_manager.get_rebel_manager();
- bool ret = politics_manager.load_rebels_file(parse_defines(lookup_file(rebel_types_file)).get_file_node());
+ bool ret = politics_manager.load_rebels_file(parse_defines_cached(lookup_file(rebel_types_file)).get_file_node());
- if(!rebel_manager.generate_modifiers(game_manager.get_modifier_manager())) {
+ if (!rebel_manager.generate_modifiers(game_manager.get_modifier_manager())) {
Logger::error("Failed to generate rebel type-based modifiers!");
ret &= false;
}
@@ -386,7 +403,7 @@ bool Dataloader::_load_rebel_types(GameManager& game_manager) const {
return ret;
}
-bool Dataloader::_load_technologies(GameManager& game_manager) const {
+bool Dataloader::_load_technologies(GameManager& game_manager) {
static constexpr std::string_view technology_file = "common/technology.txt";
TechnologyManager& technology_manager = game_manager.get_research_manager().get_technology_manager();
@@ -395,32 +412,32 @@ bool Dataloader::_load_technologies(GameManager& game_manager) const {
const v2script::Parser technology_file_parser = parse_defines(lookup_file(technology_file));
- if(!technology_manager.load_technology_file_areas(technology_file_parser.get_file_node())) {
+ if (!technology_manager.load_technology_file_areas(technology_file_parser.get_file_node())) {
Logger::error("Failed to load technology areas and folders!");
ret = false;
}
ModifierManager& modifier_manager = game_manager.get_modifier_manager();
- if(!technology_manager.generate_modifiers(modifier_manager)) {
+ if (!technology_manager.generate_modifiers(modifier_manager)) {
Logger::error("Failed to generate technollogy-based modifiers!");
ret = false;
}
- if(!technology_manager.load_technology_file_schools(modifier_manager, technology_file_parser.get_file_node())) {
+ if (!technology_manager.load_technology_file_schools(modifier_manager, technology_file_parser.get_file_node())) {
Logger::error("Failed to load technology schools!");
ret = false;
}
static constexpr std::string_view technologies_directory = "technologies";
- if(!apply_to_files(
+ if (!apply_to_files(
lookup_files_in_dir(technologies_directory, ".txt"),
- [&game_manager, &technology_manager, &modifier_manager](fs::path const& file) -> bool {
+ [this, &game_manager, &technology_manager, &modifier_manager](fs::path const& file) -> bool {
return technology_manager.load_technologies_file(
modifier_manager,
game_manager.get_military_manager().get_unit_manager(),
game_manager.get_economy_manager().get_building_type_manager(),
- parse_defines(file).get_file_node()
+ parse_defines_cached(file).get_file_node()
);
}
)) {
@@ -432,20 +449,20 @@ bool Dataloader::_load_technologies(GameManager& game_manager) const {
return ret;
}
-bool Dataloader::_load_inventions(GameManager& game_manager) const {
+bool Dataloader::_load_inventions(GameManager& game_manager) {
static constexpr std::string_view inventions_directory = "inventions";
InventionManager& invention_manager = game_manager.get_research_manager().get_invention_manager();
bool ret = apply_to_files(
lookup_files_in_dir(inventions_directory, ".txt"),
- [&game_manager, &invention_manager](fs::path const& file) -> bool {
+ [this, &game_manager, &invention_manager](fs::path const& file) -> bool {
return invention_manager.load_inventions_file(
game_manager.get_modifier_manager(),
game_manager.get_military_manager().get_unit_manager(),
game_manager.get_economy_manager().get_building_type_manager(),
game_manager.get_crime_manager(),
- parse_defines(file).get_file_node()
+ parse_defines_cached(file).get_file_node()
);
}
);
@@ -455,14 +472,15 @@ bool Dataloader::_load_inventions(GameManager& game_manager) const {
return ret;
}
-bool Dataloader::_load_decisions(GameManager& game_manager) const {
+bool Dataloader::_load_decisions(GameManager& game_manager) {
static constexpr std::string_view decisions_directory = "decisions";
+
DecisionManager& decision_manager = game_manager.get_decision_manager();
bool ret = apply_to_files(
lookup_files_in_dir(decisions_directory, ".txt"),
- [&decision_manager](fs::path const& file) -> bool {
- return decision_manager.load_decision_file(parse_defines(file).get_file_node());
+ [this, &decision_manager](fs::path const& file) -> bool {
+ return decision_manager.load_decision_file(parse_defines_cached(file).get_file_node());
}
);
@@ -551,6 +569,7 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi
game_manager.get_history_manager().get_province_manager().lock_province_histories(game_manager.get_map(), false);
+ /* Diplomacy History */
static constexpr std::string_view diplomacy_history_directory = "history/diplomacy";
ret &= apply_to_files(
lookup_files_in_dir(diplomacy_history_directory, ".txt"),
@@ -560,11 +579,15 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi
);
}
);
+
+ /* War History */
static constexpr std::string_view war_history_directory = "history/wars";
ret &= apply_to_files(
lookup_files_in_dir(war_history_directory, ".txt"),
[this, &game_manager](fs::path const& file) -> bool {
- return game_manager.get_history_manager().get_diplomacy_manager().load_war_history_file(game_manager, parse_defines(file).get_file_node());
+ return game_manager.get_history_manager().get_diplomacy_manager().load_war_history_file(
+ game_manager, parse_defines(file).get_file_node()
+ );
}
);
game_manager.get_history_manager().get_diplomacy_manager().lock_diplomatic_history();
@@ -572,7 +595,7 @@ bool Dataloader::_load_history(GameManager& game_manager, bool unused_history_fi
return ret;
}
-bool Dataloader::_load_events(GameManager& game_manager) const {
+bool Dataloader::_load_events(GameManager& game_manager) {
static constexpr std::string_view events_directory = "events";
const bool ret = apply_to_files(
lookup_files_in_dir(events_directory, ".txt"),
@@ -595,15 +618,15 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const {
static constexpr std::string_view default_provinces = "provinces.bmp";
static constexpr std::string_view default_positions = "positions.txt";
static constexpr std::string_view default_terrain = "terrain.bmp";
- static constexpr std::string_view default_rivers = "rivers.bmp"; // TODO
+ static constexpr std::string_view default_rivers = "rivers.bmp"; // TODO - load rivers into map pixel data
static constexpr std::string_view default_terrain_definition = "terrain.txt";
- static constexpr std::string_view default_tree_definition = "trees.txt"; // TODO
- static constexpr std::string_view default_continent = "continent.txt"; // TODO
+ static constexpr std::string_view default_tree_definition = "trees.txt"; /* Tree textures and density values (unused). */
+ static constexpr std::string_view default_continent = "continent.txt";
static constexpr std::string_view default_adjacencies = "adjacencies.csv";
static constexpr std::string_view default_region = "region.txt";
- static constexpr std::string_view default_region_sea = "region_sea.txt"; // TODO
- static constexpr std::string_view default_province_flag_sprite = "province_flag_sprites"; // TODO
- static constexpr std::string_view climate_file = "climate.txt"; // TODO
+ static constexpr std::string_view default_region_sea = "region_sea.txt"; /* Some empty province sets (unused). */
+ static constexpr std::string_view default_province_flag_sprite = "province_flag_sprites"; /* Canal sprite/model names. */
+ static constexpr std::string_view climate_file = "climate.txt";
/* Parser stored so the filename string_views persist until the end of this function. */
const v2script::Parser parser = parse_defines(lookup_file(append_string_views(map_directory, defaults_filename)));
@@ -720,7 +743,12 @@ bool Dataloader::_load_map_dir(GameManager& game_manager) const {
return ret;
}
-bool Dataloader::load_defines(GameManager& game_manager) const {
+bool Dataloader::load_defines(GameManager& game_manager) {
+ if (roots.empty()) {
+ Logger::error("Cannot load defines - Dataloader has no roots!");
+ return false;
+ }
+
static constexpr std::string_view defines_file = "common/defines.lua";
static constexpr std::string_view buildings_file = "common/buildings.txt";
static constexpr std::string_view bookmark_file = "common/bookmarks.txt";
@@ -768,10 +796,6 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
Logger::error("Failed to load units!");
ret = false;
}
- if (!_load_pop_types(game_manager)) {
- Logger::error("Failed to load pop types!");
- ret = false;
- }
if (!game_manager.get_pop_manager().get_culture_manager().load_graphical_culture_type_file(
parse_defines(lookup_file(graphical_culture_type_file)).get_file_node()
)) {
@@ -791,7 +815,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
if (!game_manager.get_politics_manager().get_ideology_manager().load_ideology_file(
- parse_defines(lookup_file(ideology_file)).get_file_node()
+ parse_defines_cached(lookup_file(ideology_file)).get_file_node()
)) {
Logger::error("Failed to load ideologies!");
ret = false;
@@ -802,15 +826,25 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
Logger::error("Failed to load government types!");
ret = false;
}
+ if (!_load_pop_types(game_manager)) {
+ Logger::error("Failed to load pop types!");
+ ret = false;
+ }
if (!game_manager.get_politics_manager().load_issues_file(
game_manager.get_modifier_manager(),
- parse_defines(lookup_file(issues_file)).get_file_node()
+ parse_defines_cached(lookup_file(issues_file)).get_file_node()
+ )) {
+ Logger::error("Failed to load issues and reforms!");
+ ret = false;
+ }
+ if (!game_manager.get_pop_manager().load_delayed_parse_pop_type_data(
+ game_manager.get_politics_manager().get_issue_manager()
)) {
- Logger::error("Failed to load issues!");
+ Logger::error("Failed to load delayed parse pop type data (promotion and issue weights)!");
ret = false;
}
if (!game_manager.get_economy_manager().load_production_types_file(game_manager.get_pop_manager(),
- parse_defines(lookup_file(production_types_file)).get_file_node()
+ parse_defines_cached(lookup_file(production_types_file)).get_file_node()
)) {
Logger::error("Failed to load production types!");
ret = false;
@@ -830,7 +864,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
}
if (!game_manager.get_politics_manager().load_national_foci_file(
game_manager.get_pop_manager(), game_manager.get_economy_manager().get_good_manager(),
- game_manager.get_modifier_manager(), parse_defines(lookup_file(national_foci_file)).get_file_node()
+ game_manager.get_modifier_manager(), parse_defines_cached(lookup_file(national_foci_file)).get_file_node()
)) {
Logger::error("Failed to load national foci!");
ret = false;
@@ -842,7 +876,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
if (!game_manager.get_crime_manager().load_crime_modifiers(
- game_manager.get_modifier_manager(), parse_defines(lookup_file(crime_modifiers_file)).get_file_node()
+ game_manager.get_modifier_manager(), parse_defines_cached(lookup_file(crime_modifiers_file)).get_file_node()
)) {
Logger::error("Failed to load crime modifiers!");
ret = false;
@@ -860,7 +894,7 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
if (!game_manager.get_modifier_manager().load_triggered_modifiers(
- parse_defines(lookup_file(triggered_modifiers_file)).get_file_node()
+ parse_defines_cached(lookup_file(triggered_modifiers_file)).get_file_node()
)) {
Logger::error("Failed to load triggered modifiers!");
ret = false;
@@ -879,8 +913,8 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
Logger::error("Failed to load leader traits!");
ret = false;
}
- if (!game_manager.get_military_manager().get_wargoal_manager().load_wargoal_file(
- parse_defines(lookup_file(cb_types_file)).get_file_node()
+ if (!game_manager.get_military_manager().get_wargoal_type_manager().load_wargoal_file(
+ parse_defines_cached(lookup_file(cb_types_file)).get_file_node()
)) {
Logger::error("Failed to load wargoals!");
ret = false;
@@ -916,6 +950,65 @@ bool Dataloader::load_defines(GameManager& game_manager) const {
ret = false;
}
+ parse_scripts(game_manager);
+
+ free_cache();
+
+ return ret;
+}
+
+bool Dataloader::parse_scripts(GameManager& game_manager) const {
+ bool ret = true;
+
+ if (!game_manager.get_pop_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse pop scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_politics_manager().get_ideology_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse ideology scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_politics_manager().get_issue_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse reform scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_economy_manager().get_production_type_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse production type scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_politics_manager().get_rebel_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse rebel type scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_research_manager().get_technology_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse technology scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_crime_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse crime scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_modifier_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse triggered modifier scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_research_manager().get_invention_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse invention scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_military_manager().get_wargoal_type_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse wargoal type scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_decision_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse decision scripts!");
+ ret = false;
+ }
+ if (!game_manager.get_event_manager().parse_scripts(game_manager)) {
+ Logger::error("Failed to parse event scripts!");
+ ret = false;
+ }
+
return ret;
}
diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp
index 107c93a..069ccec 100644
--- a/src/openvic-simulation/dataloader/Dataloader.hpp
+++ b/src/openvic-simulation/dataloader/Dataloader.hpp
@@ -18,17 +18,18 @@ namespace OpenVic {
private:
path_vector_t roots;
+ std::vector<ovdl::v2script::Parser> cached_parsers;
bool _load_interface_files(UIManager& ui_manager) const;
- bool _load_pop_types(GameManager& game_manager) const;
+ bool _load_pop_types(GameManager& game_manager);
bool _load_units(GameManager& game_manager) const;
bool _load_goods(GameManager& game_manager) const;
- bool _load_rebel_types(GameManager& game_manager) const;
- bool _load_technologies(GameManager& game_manager) const;
- bool _load_inventions(GameManager& game_manager) const;
- bool _load_events(GameManager& game_manager) const;
+ bool _load_rebel_types(GameManager& game_manager);
+ bool _load_technologies(GameManager& game_manager);
+ bool _load_inventions(GameManager& game_manager);
+ bool _load_events(GameManager& game_manager);
bool _load_map_dir(GameManager& game_manager) const;
- bool _load_decisions(GameManager& game_manager) const;
+ bool _load_decisions(GameManager& game_manager);
bool _load_history(GameManager& game_manager, bool unused_history_file_warnings) const;
/* _DirIterator is fs::directory_iterator or fs::recursive_directory_iterator. _UniqueKey is the type of a callable
@@ -47,6 +48,17 @@ namespace OpenVic {
static ovdl::v2script::Parser parse_lua_defines(fs::path const& path);
static ovdl::csv::Windows1252Parser parse_csv(fs::path const& path);
+ /* Cache the Parser so it won't be freed until free_cache is called. This is used to preserve condition and effect
+ * script Nodes until all defines are loaded and the scripts can be parsed. The reference returned by this function
+ * is only guaranteed to be valid until the function is next called. */
+ ovdl::v2script::Parser& parse_defines_cached(fs::path const& path);
+
+ private:
+ /* Clear the cache vector, freeing all cached Parsers and their Node trees. Pointers to cached Parsers' Nodes should
+ * be set to null before this is called to avoid segfaults. */
+ void free_cache();
+
+ public:
Dataloader() = default;
/// @brief Searches for the Victoria 2 install directory
@@ -92,8 +104,16 @@ namespace OpenVic {
string_set_t lookup_dirs_in_dir(std::string_view path) const;
- bool load_defines(GameManager& game_manager) const;
+ /* Load and parse all of the text defines data, including parsing cached condition and effect scripts after all the
+ * static data is loaded. Paths to the base and mod defines must have been supplied with set_roots.*/
+ bool load_defines(GameManager& game_manager);
+ private:
+ /* Parse the cached Nodes of every condition and effect script in the defines.
+ * This is called by load_defines after all static data has been loaded. */
+ bool parse_scripts(GameManager& game_manager) const;
+
+ public:
enum locale_t : size_t {
English, French, German, Polish, Spanish, Italian, Swedish,
Czech, Hungarian, Dutch, Portugese, Russian, Finnish, _LocaleCount
diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp
index 1dbc99c..e429ed9 100644
--- a/src/openvic-simulation/dataloader/NodeTools.cpp
+++ b/src/openvic-simulation/dataloader/NodeTools.cpp
@@ -274,25 +274,42 @@ node_callback_t NodeTools::expect_length(callback_t<size_t> callback) {
};
}
-node_callback_t NodeTools::expect_key(std::string_view key, node_callback_t callback, bool* key_found) {
- return _expect_type<ast::AbstractListNode>([key, callback, key_found](ast::AbstractListNode const& list_node) -> bool {
- std::vector<ast::NodeUPtr> const& list = list_node._statements;
- for (ast::NodeUPtr const& sub_node : list_node._statements) {
- ast::AssignNode const* assign_node = sub_node->cast_to<ast::AssignNode>();
- if (assign_node != nullptr && assign_node->_name == key) {
+node_callback_t NodeTools::expect_key(std::string_view key, node_callback_t callback, bool* key_found, bool allow_duplicates) {
+ return _expect_type<ast::AbstractListNode>(
+ [key, callback, key_found, allow_duplicates](ast::AbstractListNode const& list_node) -> bool {
+ bool ret = true;
+ size_t keys_found = 0;
+ std::vector<ast::NodeUPtr> const& list = list_node._statements;
+ for (ast::NodeUPtr const& sub_node : list_node._statements) {
+ ast::AssignNode const* assign_node = sub_node->cast_to<ast::AssignNode>();
+ if (assign_node != nullptr && assign_node->_name == key) {
+ if (keys_found++ == 0) {
+ ret &= callback(&*assign_node->_initializer);
+ if (allow_duplicates) {
+ break;
+ }
+ }
+ }
+ }
+ if (keys_found == 0) {
+ if (key_found != nullptr) {
+ *key_found = false;
+ } else {
+ Logger::error("Failed to find expected key: \"", key, "\"");
+ }
+ ret = false;
+ } else {
if (key_found != nullptr) {
*key_found = true;
}
- return callback(&*assign_node->_initializer);
+ if (!allow_duplicates && keys_found > 1) {
+ Logger::error("Found ", keys_found, " instances of key: \"", key, "\" (expected 1)");
+ ret = false;
+ }
}
+ return ret;
}
- if (key_found != nullptr) {
- *key_found = false;
- } else {
- Logger::error("Failed to find expected key: ", key);
- }
- return false;
- });
+ );
}
node_callback_t NodeTools::expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback) {
@@ -315,7 +332,7 @@ bool NodeTools::add_key_map_entry(
}
bool NodeTools::remove_key_map_entry(key_map_t& key_map, std::string_view key) {
- if(key_map.erase(key) == 0) {
+ if (key_map.erase(key) == 0) {
Logger::error("Failed to find dictionary key to remove: ", key);
return false;
}
diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp
index f3224aa..f5f960f 100644
--- a/src/openvic-simulation/dataloader/NodeTools.hpp
+++ b/src/openvic-simulation/dataloader/NodeTools.hpp
@@ -1,11 +1,8 @@
#pragma once
-#include <concepts>
#include <cstdint>
#include <functional>
-#include <map>
#include <optional>
-#include <set>
#include <type_traits>
#include <openvic-dataloader/v2script/AbstractSyntaxTree.hpp>
@@ -134,7 +131,9 @@ namespace OpenVic {
node_callback_t expect_list(node_callback_t callback);
node_callback_t expect_length(callback_t<size_t> callback);
- node_callback_t expect_key(std::string_view key, node_callback_t callback, bool* key_found = nullptr);
+ node_callback_t expect_key(
+ std::string_view key, node_callback_t callback, bool* key_found = nullptr, bool allow_duplicates = false
+ );
node_callback_t expect_dictionary_and_length(length_callback_t length_callback, key_value_callback_t callback);
node_callback_t expect_dictionary(key_value_callback_t callback);
diff --git a/src/openvic-simulation/economy/BuildingInstance.hpp b/src/openvic-simulation/economy/BuildingInstance.hpp
index e027a69..5d48321 100644
--- a/src/openvic-simulation/economy/BuildingInstance.hpp
+++ b/src/openvic-simulation/economy/BuildingInstance.hpp
@@ -14,7 +14,7 @@ namespace OpenVic {
level_t PROPERTY_RW(level);
ExpansionState PROPERTY(expansion_state);
- Date PROPERTY(start_date)
+ Date PROPERTY(start_date);
Date PROPERTY(end_date);
float PROPERTY(expansion_progress);
diff --git a/src/openvic-simulation/economy/ProductionType.cpp b/src/openvic-simulation/economy/ProductionType.cpp
index f0ad6ea..4714ee5 100644
--- a/src/openvic-simulation/economy/ProductionType.cpp
+++ b/src/openvic-simulation/economy/ProductionType.cpp
@@ -6,15 +6,28 @@ using namespace OpenVic;
using namespace OpenVic::NodeTools;
EmployedPop::EmployedPop(
- PopType const* pop_type, bool artisan, effect_t effect, fixed_point_t effect_multiplier, fixed_point_t amount
-) : pop_type { pop_type }, artisan { artisan }, effect { effect }, effect_multiplier { effect_multiplier },
- amount { amount } {}
+ PopType const* new_pop_type, bool new_artisan, effect_t new_effect, fixed_point_t new_effect_multiplier,
+ fixed_point_t new_amount
+) : pop_type { new_pop_type }, artisan { new_artisan }, effect { new_effect }, effect_multiplier { new_effect_multiplier },
+ amount { new_amount } {}
ProductionType::ProductionType(
- PRODUCTION_TYPE_ARGS
-) : HasIdentifier { identifier }, owner { owner }, employees { employees }, type { type }, workforce { workforce },
- input_goods { std::move(input_goods) }, output_goods { output_goods }, value { value }, bonuses { std::move(bonuses) },
- efficiency { std::move(efficiency) }, coastal { coastal }, farm { farm }, mine { mine } {}
+ std::string_view new_identifier, EmployedPop new_owner, std::vector<EmployedPop> new_employees, type_t new_type,
+ Pop::pop_size_t new_workforce, Good::good_map_t&& new_input_goods, Good const* new_output_goods,
+ fixed_point_t new_value, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_coastal,
+ bool new_farm, bool new_mine
+) : HasIdentifier { new_identifier }, owner { new_owner }, employees { new_employees }, type { new_type },
+ workforce { new_workforce }, input_goods { std::move(new_input_goods) }, output_goods { new_output_goods },
+ value { new_value }, bonuses { std::move(new_bonuses) }, efficiency { std::move(new_efficiency) },
+ coastal { new_coastal }, farm { new_farm }, mine { new_mine } {}
+
+bool ProductionType::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (auto& [bonus_script, bonus_value] : bonuses) {
+ ret &= bonus_script.parse_script(false, game_manager);
+ }
+ return ret;
+}
ProductionTypeManager::ProductionTypeManager() : rgo_owner_sprite { 0 } {}
@@ -72,7 +85,11 @@ node_callback_t ProductionTypeManager::_expect_employed_pop_list(
return false; \
}
-bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS) {
+bool ProductionTypeManager::add_production_type(
+ std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type,
+ Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value,
+ std::vector<ProductionType::bonus_t>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
+) {
if (identifier.empty()) {
Logger::error("Invalid production type identifier - empty!");
return false;
@@ -110,22 +127,6 @@ bool ProductionTypeManager::add_production_type(PRODUCTION_TYPE_ARGS) {
return ret;
}
-#define PARSE_NODE \
- expect_dictionary_keys_and_default( \
- key_value_success_callback, \
- "owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)), \
- "employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)), \
- "type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))), \
- "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)), \
- "input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)), \
- "output_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods)), \
- "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)), \
- "efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)), \
- "is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)), \
- "farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)), \
- "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine)) \
- )
-
bool ProductionTypeManager::load_production_types_file(
GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root
) {
@@ -183,7 +184,7 @@ bool ProductionTypeManager::load_production_types_file(
Pop::pop_size_t workforce = 0; // 0 is a meaningless value -> unset
Good::good_map_t input_goods, efficiency;
fixed_point_t value = 0; // 0 is a meaningless value -> unset
- std::vector<Bonus> bonuses;
+ std::vector<ProductionType::bonus_t> bonuses;
bool coastal = false, farm = false, mine = false;
bool ret = true;
@@ -193,16 +194,47 @@ bool ProductionTypeManager::load_production_types_file(
{ "factory", FACTORY }, { "rgo", RGO }, { "artisan", ARTISAN }
};
+ const node_callback_t parse_node = expect_dictionary_keys(
+ "template", ZERO_OR_ONE, success_callback,
+ "bonus", ZERO_OR_MORE, [&bonuses](ast::NodeCPtr bonus_node) -> bool {
+ ConditionScript trigger;
+ fixed_point_t value {};
+ const bool ret = expect_dictionary_keys(
+ "trigger", ONE_EXACTLY, trigger.expect_script(),
+ "value", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(value))
+ )(bonus_node);
+ bonuses.emplace_back(std::move(trigger), value);
+ return ret;
+ },
+ "owner", ZERO_OR_ONE, _expect_employed_pop(good_manager, pop_manager, move_variable_callback(owner)),
+ "employees", ZERO_OR_ONE, _expect_employed_pop_list(good_manager, pop_manager, move_variable_callback(employees)),
+ "type", ZERO_OR_ONE, expect_identifier(expect_mapped_string(type_map, assign_variable_callback(type))),
+ "workforce", ZERO_OR_ONE, expect_uint(assign_variable_callback(workforce)),
+ "input_goods", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(input_goods)),
+ "output_goods", ZERO_OR_ONE, good_manager.expect_good_identifier(assign_variable_callback_pointer(output_goods)),
+ "value", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(value)),
+ "efficiency", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(efficiency)),
+ "is_coastal", ZERO_OR_ONE, expect_bool(assign_variable_callback(coastal)),
+ "farm", ZERO_OR_ONE, expect_bool(assign_variable_callback(farm)),
+ "mine", ZERO_OR_ONE, expect_bool(assign_variable_callback(mine))
+ );
+
// apply template first
- if (template_target_map.contains(key)) {
- std::string_view template_id = template_target_map[key];
- if (template_node_map.contains(template_id)) {
- ast::NodeCPtr template_node = template_node_map[template_id];
- ret &= PARSE_NODE(template_node);
+ {
+ const typename decltype(template_target_map)::const_iterator target_it = template_target_map.find(key);
+ if (target_it != template_target_map.end()) {
+ const std::string_view template_id = target_it->second;
+ const typename decltype(template_node_map)::const_iterator node_it = template_node_map.find(template_id);
+ if (node_it != template_node_map.end()) {
+ ret &= parse_node(node_it->second);
+ } else {
+ Logger::error("Missing template ", template_id, " for production type ", key, "!");
+ ret = false;
+ }
}
}
- ret &= PARSE_NODE(node);
+ ret &= parse_node(node);
ret &= add_production_type(
key, owner, employees, type, workforce, std::move(input_goods), output_goods, value, std::move(bonuses),
@@ -221,3 +253,11 @@ bool ProductionTypeManager::load_production_types_file(
return ret;
}
+
+bool ProductionTypeManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (ProductionType& production_type : production_types.get_items()) {
+ ret &= production_type.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/economy/ProductionType.hpp b/src/openvic-simulation/economy/ProductionType.hpp
index 4fdceda..5d51f60 100644
--- a/src/openvic-simulation/economy/ProductionType.hpp
+++ b/src/openvic-simulation/economy/ProductionType.hpp
@@ -2,14 +2,10 @@
#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/scripts/ConditionScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
-#define PRODUCTION_TYPE_ARGS \
- std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type, \
- Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value, \
- std::vector<Bonus>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
-
namespace OpenVic {
struct ProductionTypeManager;
@@ -26,40 +22,46 @@ namespace OpenVic {
fixed_point_t PROPERTY(amount);
EmployedPop(
- PopType const* pop_type, bool artisan, effect_t effect, fixed_point_t effect_multiplier, fixed_point_t amount
+ PopType const* new_pop_type, bool new_artisan, effect_t new_effect, fixed_point_t new_effect_multiplier,
+ fixed_point_t new_amount
);
public:
EmployedPop() = default;
};
- struct Bonus {
- // TODO: trigger condition(s)
- const fixed_point_t value;
- };
-
struct ProductionType : HasIdentifier {
friend struct ProductionTypeManager;
+ enum struct type_t { FACTORY, RGO, ARTISAN };
+
+ using bonus_t = std::pair<ConditionScript, fixed_point_t>;
+
private:
const EmployedPop PROPERTY(owner);
- const std::vector<EmployedPop> PROPERTY(employees);
- const enum struct type_t { FACTORY, RGO, ARTISAN } PROPERTY(type);
+ std::vector<EmployedPop> PROPERTY(employees);
+ const type_t PROPERTY(type);
const Pop::pop_size_t workforce;
- const Good::good_map_t PROPERTY(input_goods);
+ Good::good_map_t PROPERTY(input_goods);
Good const* PROPERTY(output_goods);
const fixed_point_t PROPERTY(value);
- const std::vector<Bonus> PROPERTY(bonuses);
+ std::vector<bonus_t> PROPERTY(bonuses);
- const Good::good_map_t PROPERTY(efficiency);
+ Good::good_map_t PROPERTY(efficiency);
const bool PROPERTY_CUSTOM_PREFIX(coastal, is); // is_coastal
const bool PROPERTY_CUSTOM_PREFIX(farm, is);
const bool PROPERTY_CUSTOM_PREFIX(mine, is);
- ProductionType(PRODUCTION_TYPE_ARGS);
+ ProductionType(
+ std::string_view new_identifier, EmployedPop new_owner, std::vector<EmployedPop> new_employees, type_t new_type,
+ Pop::pop_size_t new_workforce, Good::good_map_t&& new_input_goods, Good const* new_output_goods,
+ fixed_point_t new_value, std::vector<bonus_t>&& new_bonuses, Good::good_map_t&& new_efficiency, bool new_coastal,
+ bool new_farm, bool new_mine
+ );
+ bool parse_scripts(GameManager const& game_manager);
public:
ProductionType(ProductionType&&) = default;
};
@@ -80,8 +82,14 @@ namespace OpenVic {
public:
ProductionTypeManager();
- bool add_production_type(PRODUCTION_TYPE_ARGS);
+ bool add_production_type(
+ std::string_view identifier, EmployedPop owner, std::vector<EmployedPop> employees, ProductionType::type_t type,
+ Pop::pop_size_t workforce, Good::good_map_t&& input_goods, Good const* output_goods, fixed_point_t value,
+ std::vector<ProductionType::bonus_t>&& bonuses, Good::good_map_t&& efficiency, bool coastal, bool farm, bool mine
+ );
bool load_production_types_file(GoodManager const& good_manager, PopManager const& pop_manager, ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager const& game_manager);
};
}
diff --git a/src/openvic-simulation/history/CountryHistory.cpp b/src/openvic-simulation/history/CountryHistory.cpp
index 48b30e6..681b2b9 100644
--- a/src/openvic-simulation/history/CountryHistory.cpp
+++ b/src/openvic-simulation/history/CountryHistory.cpp
@@ -52,20 +52,40 @@ bool CountryHistoryMap::_load_history_entry(
})(value);
}
- Technology const* technology = technology_manager.get_technology_by_identifier(key);
- if (technology != nullptr) {
- bool flag;
- if (expect_int_bool(assign_variable_callback(flag))(value)) {
- return entry.technologies.emplace(technology, flag).second;
- } else return false;
+ {
+ Technology const* technology = technology_manager.get_technology_by_identifier(key);
+ if (technology != nullptr) {
+ return expect_int_bool(
+ [&entry, technology](bool flag) -> bool {
+ if (!entry.technologies.emplace(technology, flag).second) {
+ Logger::error(
+ "Duplicate entry for technology ", technology->get_identifier(), " in history of ",
+ entry.get_country().get_identifier(), " at date ", entry.get_date()
+ );
+ return false;
+ }
+ return true;
+ }
+ )(value);
+ }
}
- Invention const* invention = invention_manager.get_invention_by_identifier(key);
- if (invention != nullptr) {
- bool flag;
- if (expect_bool(assign_variable_callback(flag))(value)) {
- return entry.inventions.emplace(invention, flag).second;
- } else return false;
+ {
+ Invention const* invention = invention_manager.get_invention_by_identifier(key);
+ if (invention != nullptr) {
+ return expect_bool(
+ [&entry, invention](bool flag) -> bool {
+ if (!entry.inventions.emplace(invention, flag).second) {
+ Logger::error(
+ "Duplicate entry for invention ", invention->get_identifier(), " in history of ",
+ entry.get_country().get_identifier(), " at date ", entry.get_date()
+ );
+ return false;
+ }
+ return true;
+ }
+ )(value);
+ }
}
return _load_history_sub_entry_callback(
diff --git a/src/openvic-simulation/history/DiplomaticHistory.cpp b/src/openvic-simulation/history/DiplomaticHistory.cpp
index 9fd6060..088ec0a 100644
--- a/src/openvic-simulation/history/DiplomaticHistory.cpp
+++ b/src/openvic-simulation/history/DiplomaticHistory.cpp
@@ -221,7 +221,7 @@ bool DiplomaticHistoryManager::load_war_history_file(GameManager const& game_man
bool ret = expect_dictionary_keys(
"actor", ONE_EXACTLY, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(actor)),
"receiver", ONE_EXACTLY, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(receiver)),
- "casus_belli", ONE_EXACTLY, game_manager.get_military_manager().get_wargoal_manager().expect_wargoal_type_identifier(assign_variable_callback_pointer(type)),
+ "casus_belli", ONE_EXACTLY, game_manager.get_military_manager().get_wargoal_type_manager().expect_wargoal_type_identifier(assign_variable_callback_pointer(type)),
"country", ZERO_OR_ONE, game_manager.get_country_manager().expect_country_identifier(assign_variable_callback_pointer(*third_party)),
"state_province_id", ZERO_OR_ONE, game_manager.get_map().expect_province_identifier(assign_variable_callback_pointer(*target))
)(value);
diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp
index cdc49c2..2bae4b3 100644
--- a/src/openvic-simulation/interface/GFX.hpp
+++ b/src/openvic-simulation/interface/GFX.hpp
@@ -138,7 +138,7 @@ namespace OpenVic::GFX {
class MaskedFlag final : public Sprite {
friend std::unique_ptr<MaskedFlag> std::make_unique<MaskedFlag>();
- std::string PROPERTY(overlay_file)
+ std::string PROPERTY(overlay_file);
std::string PROPERTY(mask_file);
protected:
diff --git a/src/openvic-simulation/map/Crime.cpp b/src/openvic-simulation/map/Crime.cpp
index c0bc04e..65760a3 100644
--- a/src/openvic-simulation/map/Crime.cpp
+++ b/src/openvic-simulation/map/Crime.cpp
@@ -3,17 +3,22 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Crime::Crime(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, bool new_default_active)
- : TriggeredModifier { new_identifier, std::move(new_values), new_icon }, default_active { new_default_active } {}
+Crime::Crime(
+ std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger,
+ bool new_default_active
+) : TriggeredModifier { new_identifier, std::move(new_values), new_icon, std::move(new_trigger) },
+ default_active { new_default_active } {}
bool CrimeManager::add_crime_modifier(
- std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, bool default_active
+ std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, ConditionScript&& trigger, bool default_active
) {
if (identifier.empty()) {
Logger::error("Invalid crime modifier effect identifier - empty!");
return false;
}
- return crime_modifiers.add_item({ identifier, std::move(values), icon, default_active }, duplicate_warning_callback);
+ return crime_modifiers.add_item(
+ { identifier, std::move(values), icon, std::move(trigger), default_active }, duplicate_warning_callback
+ );
}
bool CrimeManager::load_crime_modifiers(ModifierManager const& modifier_manager, ast::NodeCPtr root) {
@@ -22,17 +27,26 @@ bool CrimeManager::load_crime_modifiers(ModifierManager const& modifier_manager,
[this, &modifier_manager](std::string_view key, ast::NodeCPtr value) -> bool {
ModifierValue modifier_value;
Modifier::icon_t icon = 0;
+ ConditionScript trigger;
bool default_active = false;
bool ret = modifier_manager.expect_modifier_value_and_keys(
move_variable_callback(modifier_value),
"icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)),
- "trigger", ONE_EXACTLY, success_callback, // TODO - load condition
+ "trigger", ONE_EXACTLY, trigger.expect_script(),
"active", ZERO_OR_ONE, expect_bool(assign_variable_callback(default_active))
)(value);
- ret &= add_crime_modifier(key, std::move(modifier_value), icon, default_active);
+ ret &= add_crime_modifier(key, std::move(modifier_value), icon, std::move(trigger), default_active);
return ret;
}
)(root);
lock_crime_modifiers();
return ret;
}
+
+bool CrimeManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (Crime& crime : crime_modifiers.get_items()) {
+ ret &= crime.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/map/Crime.hpp b/src/openvic-simulation/map/Crime.hpp
index 26f52ab..01044f9 100644
--- a/src/openvic-simulation/map/Crime.hpp
+++ b/src/openvic-simulation/map/Crime.hpp
@@ -9,7 +9,10 @@ namespace OpenVic {
private:
const bool PROPERTY(default_active);
- Crime(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, bool new_default_active);
+ Crime(
+ std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger,
+ bool new_default_active
+ );
public:
Crime(Crime&&) = default;
@@ -21,9 +24,12 @@ namespace OpenVic {
public:
bool add_crime_modifier(
- std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, bool default_active
+ std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, ConditionScript&& trigger,
+ bool default_active
);
bool load_crime_modifiers(ModifierManager const& modifier_manager, ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager const& game_manager);
};
}
diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp
index 3e7ff35..33ca4b2 100644
--- a/src/openvic-simulation/map/Map.hpp
+++ b/src/openvic-simulation/map/Map.hpp
@@ -75,7 +75,7 @@ namespace OpenVic {
Province::index_t PROPERTY(max_provinces);
Province* PROPERTY(selected_province);
- Pop::pop_size_t PROPERTY(highest_province_population)
+ Pop::pop_size_t PROPERTY(highest_province_population);
Pop::pop_size_t PROPERTY(total_map_population);
Province::index_t get_index_from_colour(colour_t colour) const;
diff --git a/src/openvic-simulation/map/State.cpp b/src/openvic-simulation/map/State.cpp
index faf8d1b..c1f802d 100644
--- a/src/openvic-simulation/map/State.cpp
+++ b/src/openvic-simulation/map/State.cpp
@@ -59,7 +59,7 @@ StateSet::states_t& StateSet::get_states() {
void StateManager::generate_states(Map& map) {
regions.clear();
regions.reserve(map.get_region_count());
- for(Region const& region : map.get_regions()) {
+ for (Region const& region : map.get_regions()) {
if (!region.get_meta()) {
regions.emplace_back(map, region);
}
diff --git a/src/openvic-simulation/military/MilitaryManager.hpp b/src/openvic-simulation/military/MilitaryManager.hpp
index aeb5a7b..2efa3ea 100644
--- a/src/openvic-simulation/military/MilitaryManager.hpp
+++ b/src/openvic-simulation/military/MilitaryManager.hpp
@@ -11,6 +11,6 @@ namespace OpenVic {
UnitManager PROPERTY_REF(unit_manager);
LeaderTraitManager PROPERTY_REF(leader_trait_manager);
DeploymentManager PROPERTY_REF(deployment_manager);
- WargoalTypeManager PROPERTY_REF(wargoal_manager);
+ WargoalTypeManager PROPERTY_REF(wargoal_type_manager);
};
}
diff --git a/src/openvic-simulation/military/Wargoal.cpp b/src/openvic-simulation/military/Wargoal.cpp
index 7a12b7e..28cbc51 100644
--- a/src/openvic-simulation/military/Wargoal.cpp
+++ b/src/openvic-simulation/military/Wargoal.cpp
@@ -6,84 +6,98 @@ using namespace OpenVic;
using namespace OpenVic::NodeTools;
WargoalType::WargoalType(
- std::string_view new_identifier,
- std::string_view new_sprite,
- std::string_view new_war_name,
- Timespan new_available_length,
- Timespan new_truce_length,
- bool new_triggered_only,
- bool new_civil_war,
- bool new_constructing,
- bool new_crisis,
- bool new_great_war,
- bool new_mutual,
- const peace_modifiers_t&& new_modifiers,
- peace_options_t new_peace_options
-) : HasIdentifier { new_identifier },
- sprite { new_sprite },
- war_name { new_war_name },
- available_length { new_available_length },
- truce_length { new_truce_length },
- triggered_only { new_triggered_only },
- civil_war { new_civil_war },
- constructing { new_constructing },
- crisis { new_crisis },
- great_war { new_great_war },
- mutual { new_mutual },
- modifiers { std::move(new_modifiers) },
- peace_options { new_peace_options } {}
-
-const std::vector<WargoalType const*>& WargoalTypeManager::get_peace_priority_list() const {
- return peace_priorities;
+ std::string_view new_identifier, std::string_view new_war_name, Timespan new_available_length,
+ Timespan new_truce_length, sprite_t new_sprite_index, bool new_triggered_only, bool new_civil_war,
+ bool new_constructing, bool new_crisis, bool new_great_war_obligatory, bool new_mutual,
+ bool new_all_allowed_states, bool new_always, peace_modifiers_t&& new_modifiers, peace_options_t new_peace_options,
+ ConditionScript&& new_can_use, ConditionScript&& new_is_valid, ConditionScript&& new_allowed_states,
+ ConditionScript&& new_allowed_substate_regions, ConditionScript&& new_allowed_states_in_crisis,
+ ConditionScript&& new_allowed_countries, EffectScript&& new_on_add, EffectScript&& new_on_po_accepted
+) : HasIdentifier { new_identifier }, war_name { new_war_name }, available_length { new_available_length },
+ truce_length { new_truce_length }, sprite_index { new_sprite_index }, triggered_only { new_triggered_only },
+ civil_war { new_civil_war }, constructing { new_constructing }, crisis { new_crisis },
+ great_war_obligatory { new_great_war_obligatory }, mutual { new_mutual }, all_allowed_states { new_all_allowed_states },
+ always { new_always }, modifiers { std::move(new_modifiers) }, peace_options { new_peace_options },
+ can_use { std::move(new_can_use) }, is_valid { std::move(new_is_valid) }, allowed_states { std::move(new_allowed_states) },
+ allowed_substate_regions { std::move(new_allowed_substate_regions) },
+ allowed_states_in_crisis { std::move(new_allowed_states_in_crisis) },
+ allowed_countries { std::move(new_allowed_countries) }, on_add { std::move(new_on_add) },
+ on_po_accepted { std::move(new_on_po_accepted) } {}
+
+bool WargoalType::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= can_use.parse_script(true, game_manager);
+ ret &= is_valid.parse_script(true, game_manager);
+ ret &= allowed_states.parse_script(true, game_manager);
+ ret &= allowed_substate_regions.parse_script(true, game_manager);
+ ret &= allowed_states_in_crisis.parse_script(true, game_manager);
+ ret &= allowed_countries.parse_script(true, game_manager);
+ ret &= on_add.parse_script(true, game_manager);
+ ret &= on_po_accepted.parse_script(true, game_manager);
+ return ret;
}
bool WargoalTypeManager::add_wargoal_type(
- std::string_view identifier,
- std::string_view sprite,
- std::string_view war_name,
- Timespan available_length,
- Timespan truce_length,
- bool triggered_only,
- bool civil_war,
- bool constructing,
- bool crisis,
- bool great_war,
- bool mutual,
- WargoalType::peace_modifiers_t&& modifiers,
- peace_options_t peace_options
+ std::string_view identifier, std::string_view war_name, Timespan available_length,
+ Timespan truce_length, WargoalType::sprite_t sprite_index, bool triggered_only, bool civil_war,
+ bool constructing, bool crisis, bool great_war_obligatory, bool mutual, bool all_allowed_states,
+ bool always, WargoalType::peace_modifiers_t&& modifiers, peace_options_t peace_options,
+ ConditionScript&& can_use, ConditionScript&& is_valid, ConditionScript&& allowed_states,
+ ConditionScript&& allowed_substate_regions, ConditionScript&& allowed_states_in_crisis,
+ ConditionScript&& allowed_countries, EffectScript&& on_add, EffectScript&& on_po_accepted
) {
if (identifier.empty()) {
Logger::error("Invalid wargoal identifier - empty!");
return false;
}
- if (sprite.empty()) {
- Logger::error("Invalid sprite for wargoal ", identifier, " - empty!");
- return false;
- }
-
if (war_name.empty()) {
Logger::error("Invalid war name for wargoal ", identifier, " - empty!");
return false;
}
+ if (sprite_index == 0) {
+ Logger::warning("Invalid sprite for wargoal ", identifier, " - 0");
+ }
+
return wargoal_types.add_item({
- identifier, sprite, war_name, available_length, truce_length, triggered_only, civil_war, constructing, crisis,
- great_war, mutual, std::move(modifiers), peace_options
+ identifier, war_name, available_length, truce_length, sprite_index, triggered_only, civil_war, constructing, crisis,
+ great_war_obligatory, mutual, all_allowed_states, always, std::move(modifiers), peace_options, std::move(can_use),
+ std::move(is_valid), std::move(allowed_states), std::move(allowed_substate_regions),
+ std::move(allowed_states_in_crisis), std::move(allowed_countries), std::move(on_add), std::move(on_po_accepted)
});
}
bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) {
bool ret = expect_dictionary(
[this](std::string_view identifier, ast::NodeCPtr value) -> bool {
- if (identifier == "peace_order") return true;
+ if (identifier == "peace_order") {
+ return true;
+ }
- std::string_view sprite, war_name;
- Timespan available, truce;
- bool triggered_only = false, civil_war = false, constructing = true, crisis = true, great_war = false,
- mutual = false;
- peace_options_t peace_options {};
+ using enum peace_options_t;
+
+ std::string_view war_name;
+ Timespan available {}, truce {};
+ WargoalType::sprite_t sprite_index = 0;
+ bool triggered_only = false, civil_war = false, constructing = true, crisis = true, great_war_obligatory = false,
+ mutual = false, all_allowed_states = false, always = false;
+ peace_options_t peace_options = NO_PEACE_OPTIONS;
WargoalType::peace_modifiers_t modifiers;
+ ConditionScript can_use, is_valid, allowed_states, allowed_substate_regions, allowed_states_in_crisis,
+ allowed_countries;
+ EffectScript on_add, on_po_accepted;
+
+ const auto expect_peace_option = [&peace_options](peace_options_t peace_option) -> node_callback_t {
+ return expect_bool([&peace_options, peace_option](bool val) -> bool {
+ if (val) {
+ peace_options |= peace_option;
+ } else {
+ peace_options &= ~peace_option;
+ }
+ return true;
+ });
+ };
bool ret = expect_dictionary_keys_and_default(
[&modifiers, &identifier](std::string_view key, ast::NodeCPtr value) -> bool {
@@ -113,105 +127,53 @@ bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) {
Logger::error("Modifier ", key, " in wargoal ", identifier, " is invalid.");
return false;
},
- "sprite_index", ONE_EXACTLY, expect_identifier(assign_variable_callback(sprite)),
"war_name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(war_name)),
"months", ZERO_OR_ONE, expect_months(assign_variable_callback(available)),
"truce_months", ONE_EXACTLY, expect_months(assign_variable_callback(truce)),
+ "sprite_index", ONE_EXACTLY, expect_uint(assign_variable_callback(sprite_index)),
"is_triggered_only", ZERO_OR_ONE, expect_bool(assign_variable_callback(triggered_only)),
"is_civil_war", ZERO_OR_ONE, expect_bool(assign_variable_callback(civil_war)),
"constructing_cb", ZERO_OR_ONE, expect_bool(assign_variable_callback(constructing)),
"crisis", ZERO_OR_ONE, expect_bool(assign_variable_callback(crisis)),
- "great_war_obligatory", ZERO_OR_ONE, expect_bool(assign_variable_callback(great_war)),
+ "great_war_obligatory", ZERO_OR_ONE, expect_bool(assign_variable_callback(great_war_obligatory)),
"mutual", ZERO_OR_ONE, expect_bool(assign_variable_callback(mutual)),
- /* PEACE OPTIONS */
- "po_annex", ZERO_OR_ONE, expect_bool([&peace_options](bool annex) -> bool {
- if (annex) peace_options |= peace_options_t::PO_ANNEX;
- return true;
- }),
- "po_demand_state", ZERO_OR_ONE, expect_bool([&peace_options](bool demand_state) -> bool {
- if (demand_state) peace_options |= peace_options_t::PO_DEMAND_STATE;
- return true;
- }),
- "po_add_to_sphere", ZERO_OR_ONE, expect_bool([&peace_options](bool add_to_sphere) -> bool {
- if (add_to_sphere) peace_options |= peace_options_t::PO_ADD_TO_SPHERE;
- return true;
- }),
- "po_disarmament", ZERO_OR_ONE, expect_bool([&peace_options](bool disarm) -> bool {
- if (disarm) peace_options |= peace_options_t::PO_DISARMAMENT;
- return true;
- }),
- "po_destroy_forts", ZERO_OR_ONE, expect_bool([&peace_options](bool disarm) -> bool {
- if (disarm) peace_options |= peace_options_t::PO_REMOVE_FORTS;
- return true;
- }),
- "po_destroy_naval_bases", ZERO_OR_ONE, expect_bool([&peace_options](bool disarm) -> bool {
- if (disarm) peace_options |= peace_options_t::PO_REMOVE_NAVAL_BASES;
- return true;
- }),
- "po_reparations", ZERO_OR_ONE, expect_bool([&peace_options](bool reps) -> bool {
- if (reps) peace_options |= peace_options_t::PO_REPARATIONS;
- return true;
- }),
- "po_transfer_provinces", ZERO_OR_ONE, expect_bool([&peace_options](bool provinces) -> bool {
- if (provinces) peace_options |= peace_options_t::PO_TRANSFER_PROVINCES;
- return true;
- }),
- "po_remove_prestige", ZERO_OR_ONE, expect_bool([&peace_options](bool humiliate) -> bool {
- if (humiliate) peace_options |= peace_options_t::PO_REMOVE_PRESTIGE;
- return true;
- }),
- "po_make_puppet", ZERO_OR_ONE, expect_bool([&peace_options](bool puppet) -> bool {
- if (puppet) peace_options |= peace_options_t::PO_MAKE_PUPPET;
- return true;
- }),
- "po_release_puppet", ZERO_OR_ONE, expect_bool([&peace_options](bool puppet) -> bool {
- if (puppet) peace_options |= peace_options_t::PO_RELEASE_PUPPET;
- return true;
- }),
- "po_status_quo", ZERO_OR_ONE, expect_bool([&peace_options](bool status_quo) -> bool {
- if (status_quo) peace_options |= peace_options_t::PO_STATUS_QUO;
- return true;
- }),
- "po_install_communist_gov_type", ZERO_OR_ONE, expect_bool([&peace_options](bool puppet) -> bool {
- if (puppet) peace_options |= peace_options_t::PO_INSTALL_COMMUNISM;
- return true;
- }),
- "po_uninstall_communist_gov_type", ZERO_OR_ONE, expect_bool([&peace_options](bool puppet) -> bool {
- if (puppet) peace_options |= peace_options_t::PO_REMOVE_COMMUNISM;
- return true;
- }),
- "po_remove_cores", ZERO_OR_ONE, expect_bool([&peace_options](bool uncore) -> bool {
- if (uncore) peace_options |= peace_options_t::PO_REMOVE_CORES;
- return true;
- }),
- "po_colony", ZERO_OR_ONE, expect_bool([&peace_options](bool colony) -> bool {
- if (colony) peace_options |= peace_options_t::PO_COLONY;
- return true;
- }),
- "po_gunboat", ZERO_OR_ONE, expect_bool([&peace_options](bool gunboat) -> bool {
- if (gunboat) peace_options |= peace_options_t::PO_REPAY_DEBT;
- return true;
- }),
- "po_clear_union_sphere", ZERO_OR_ONE, expect_bool([&peace_options](bool clear) -> bool {
- if (clear) peace_options |= peace_options_t::PO_CLEAR_UNION_SPHERE;
- return true;
- }),
- /* TODO: CONDITION & EFFECT BLOCKS */
- "can_use", ZERO_OR_ONE, success_callback,
- "is_valid", ZERO_OR_ONE, success_callback,
- "on_add", ZERO_OR_ONE, success_callback,
- "on_po_accepted", ZERO_OR_ONE, success_callback,
- "allowed_states", ZERO_OR_ONE, success_callback,
- "all_allowed_states", ZERO_OR_ONE, success_callback,
- "allowed_substate_regions", ZERO_OR_ONE, success_callback,
- "allowed_states_in_crisis", ZERO_OR_ONE, success_callback,
- "allowed_countries", ZERO_OR_ONE, success_callback,
- "always", ZERO_OR_ONE, success_callback // usage unknown / quirk
+ /* START PEACE OPTIONS */
+ "po_annex", ZERO_OR_ONE, expect_peace_option(PO_ANNEX),
+ "po_demand_state", ZERO_OR_ONE, expect_peace_option(PO_DEMAND_STATE),
+ "po_add_to_sphere", ZERO_OR_ONE, expect_peace_option(PO_ADD_TO_SPHERE),
+ "po_disarmament", ZERO_OR_ONE, expect_peace_option(PO_DISARMAMENT),
+ "po_destroy_forts", ZERO_OR_ONE, expect_peace_option(PO_REMOVE_FORTS),
+ "po_destroy_naval_bases", ZERO_OR_ONE, expect_peace_option(PO_REMOVE_NAVAL_BASES),
+ "po_reparations", ZERO_OR_ONE, expect_peace_option(PO_REPARATIONS),
+ "po_transfer_provinces", ZERO_OR_ONE, expect_peace_option(PO_TRANSFER_PROVINCES),
+ "po_remove_prestige", ZERO_OR_ONE, expect_peace_option(PO_REMOVE_PRESTIGE),
+ "po_make_puppet", ZERO_OR_ONE, expect_peace_option(PO_MAKE_PUPPET),
+ "po_release_puppet", ZERO_OR_ONE, expect_peace_option(PO_RELEASE_PUPPET),
+ "po_status_quo", ZERO_OR_ONE, expect_peace_option(PO_STATUS_QUO),
+ "po_install_communist_gov_type", ZERO_OR_ONE, expect_peace_option(PO_INSTALL_COMMUNISM),
+ "po_uninstall_communist_gov_type", ZERO_OR_ONE, expect_peace_option(PO_REMOVE_COMMUNISM),
+ "po_remove_cores", ZERO_OR_ONE, expect_peace_option(PO_REMOVE_CORES),
+ "po_colony", ZERO_OR_ONE, expect_peace_option(PO_COLONY),
+ "po_gunboat", ZERO_OR_ONE, expect_peace_option(PO_REPAY_DEBT),
+ "po_clear_union_sphere", ZERO_OR_ONE, expect_peace_option(PO_CLEAR_UNION_SPHERE),
+ /* END PEACE OPTIONS */
+ "can_use", ZERO_OR_ONE, can_use.expect_script(),
+ "is_valid", ZERO_OR_ONE, is_valid.expect_script(),
+ "on_add", ZERO_OR_ONE, on_add.expect_script(),
+ "on_po_accepted", ZERO_OR_ONE, on_po_accepted.expect_script(),
+ "allowed_states", ZERO_OR_ONE, allowed_states.expect_script(),
+ "all_allowed_states", ZERO_OR_ONE, expect_bool(assign_variable_callback(all_allowed_states)),
+ "allowed_substate_regions", ZERO_OR_ONE, allowed_substate_regions.expect_script(),
+ "allowed_states_in_crisis", ZERO_OR_ONE, allowed_states_in_crisis.expect_script(),
+ "allowed_countries", ZERO_OR_ONE, allowed_countries.expect_script(),
+ "always", ZERO_OR_ONE, expect_bool(assign_variable_callback(always))
)(value);
add_wargoal_type(
- identifier, sprite, war_name, available, truce, triggered_only, civil_war, constructing, crisis, great_war,
- mutual, std::move(modifiers), peace_options
+ identifier, war_name, available, truce, sprite_index, triggered_only, civil_war, constructing, crisis,
+ great_war_obligatory, mutual, all_allowed_states, always, std::move(modifiers), peace_options,
+ std::move(can_use), std::move(is_valid), std::move(allowed_states), std::move(allowed_substate_regions),
+ std::move(allowed_states_in_crisis), std::move(allowed_countries), std::move(on_add), std::move(on_po_accepted)
);
return ret;
}
@@ -237,4 +199,12 @@ bool WargoalTypeManager::load_wargoal_file(ast::NodeCPtr root) {
lock_wargoal_types();
return ret;
-} \ No newline at end of file
+}
+
+bool WargoalTypeManager::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ for (WargoalType& wargoal_type : wargoal_types.get_items()) {
+ ret &= wargoal_type.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/military/Wargoal.hpp b/src/openvic-simulation/military/Wargoal.hpp
index 66fce90..a4f2e7c 100644
--- a/src/openvic-simulation/military/Wargoal.hpp
+++ b/src/openvic-simulation/military/Wargoal.hpp
@@ -1,6 +1,8 @@
#pragma once
#include "openvic-simulation/misc/Modifier.hpp"
+#include "openvic-simulation/scripts/ConditionScript.hpp"
+#include "openvic-simulation/scripts/EffectScript.hpp"
#include "openvic-simulation/types/EnumBitfield.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/utility/Getters.hpp"
@@ -9,30 +11,33 @@ namespace OpenVic {
struct WargoalTypeManager;
enum class peace_options_t : uint32_t {
- PO_ANNEX = 0b100000000000000000,
- PO_DEMAND_STATE = 0b010000000000000000,
- PO_COLONY = 0b001000000000000000,
- PO_ADD_TO_SPHERE = 0b000100000000000000,
- PO_DISARMAMENT = 0b000010000000000000,
- PO_REMOVE_FORTS = 0b000001000000000000,
- PO_REMOVE_NAVAL_BASES = 0b000000100000000000,
- PO_REPARATIONS = 0b000000010000000000,
- PO_REPAY_DEBT = 0b000000001000000000,
- PO_REMOVE_PRESTIGE = 0b000000000100000000,
- PO_MAKE_PUPPET = 0b000000000010000000,
- PO_RELEASE_PUPPET = 0b000000000001000000,
- PO_STATUS_QUO = 0b000000000000100000,
- PO_INSTALL_COMMUNISM = 0b000000000000010000,
- PO_REMOVE_COMMUNISM = 0b000000000000001000,
- PO_REMOVE_CORES = 0b000000000000000100, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES
- PO_TRANSFER_PROVINCES = 0b000000000000000010,
- PO_CLEAR_UNION_SPHERE = 0b000000000000000001
+ NO_PEACE_OPTIONS = 0,
+ PO_ANNEX = 1 << 0,
+ PO_DEMAND_STATE = 1 << 1,
+ PO_COLONY = 1 << 2,
+ PO_ADD_TO_SPHERE = 1 << 3,
+ PO_DISARMAMENT = 1 << 4,
+ PO_REMOVE_FORTS = 1 << 5,
+ PO_REMOVE_NAVAL_BASES = 1 << 6,
+ PO_REPARATIONS = 1 << 7,
+ PO_REPAY_DEBT = 1 << 8,
+ PO_REMOVE_PRESTIGE = 1 << 9,
+ PO_MAKE_PUPPET = 1 << 10,
+ PO_RELEASE_PUPPET = 1 << 11,
+ PO_STATUS_QUO = 1 << 12,
+ PO_INSTALL_COMMUNISM = 1 << 13,
+ PO_REMOVE_COMMUNISM = 1 << 14,
+ PO_REMOVE_CORES = 1 << 15, // only usable with ANNEX, DEMAND_STATE, or TRANSFER_PROVINCES
+ PO_TRANSFER_PROVINCES = 1 << 16,
+ PO_CLEAR_UNION_SPHERE = 1 << 17
};
template<> struct enable_bitfield<peace_options_t> : std::true_type{};
struct WargoalType : HasIdentifier {
friend struct WargoalTypeManager;
+ using sprite_t = uint8_t;
+
enum class PEACE_MODIFIERS {
BADBOY_FACTOR,
PRESTIGE_FACTOR,
@@ -50,37 +55,41 @@ namespace OpenVic {
using peace_modifiers_t = fixed_point_map_t<PEACE_MODIFIERS>;
private:
- const std::string PROPERTY(sprite);
- const std::string PROPERTY(war_name);
+ std::string PROPERTY(war_name);
const Timespan PROPERTY(available_length);
const Timespan PROPERTY(truce_length);
- const bool PROPERTY(triggered_only); // only able to be added via effects (or within the code)
- const bool PROPERTY(civil_war);
+ const sprite_t PROPERTY(sprite_index);
+ const bool PROPERTY_CUSTOM_PREFIX(triggered_only, is); // only able to be added via effects or on_actions
+ const bool PROPERTY_CUSTOM_PREFIX(civil_war, is);
const bool PROPERTY(constructing); // can be added to existing wars or justified
const bool PROPERTY(crisis); // able to be added to crises
- const bool PROPERTY(great_war); // automatically add to great wars
- const bool PROPERTY(mutual); // attacked and defender share wargoal
- const peace_modifiers_t PROPERTY(modifiers);
- const peace_options_t PROPERTY(peace_options);
-
- // TODO: can_use, prerequisites, on_add, on_po_accepted
+ const bool PROPERTY_CUSTOM_PREFIX(great_war_obligatory, is); // automatically add to great war peace offers/demands
+ const bool PROPERTY_CUSTOM_PREFIX(mutual, is); // attacked and defender share wargoal
+ const bool PROPERTY(all_allowed_states); // take all valid states rather than just one
+ const bool PROPERTY(always); // available without justifying
+ peace_modifiers_t PROPERTY(modifiers);
+ peace_options_t PROPERTY(peace_options);
+ ConditionScript PROPERTY(can_use);
+ ConditionScript PROPERTY(is_valid);
+ ConditionScript PROPERTY(allowed_states);
+ ConditionScript PROPERTY(allowed_substate_regions);
+ ConditionScript PROPERTY(allowed_states_in_crisis);
+ ConditionScript PROPERTY(allowed_countries);
+ EffectScript PROPERTY(on_add);
+ EffectScript PROPERTY(on_po_accepted);
WargoalType(
- std::string_view new_identifier,
- std::string_view new_sprite,
- std::string_view new_war_name,
- Timespan new_available_length,
- Timespan new_truce_length,
- bool new_triggered_only,
- bool new_civil_war,
- bool new_constructing,
- bool new_crisis,
- bool new_great_war,
- bool new_mutual,
- const peace_modifiers_t&& new_modifiers,
- peace_options_t new_peace_options
+ std::string_view new_identifier, std::string_view new_war_name, Timespan new_available_length,
+ Timespan new_truce_length, sprite_t new_sprite_index, bool new_triggered_only, bool new_civil_war,
+ bool new_constructing, bool new_crisis, bool new_great_war_obligatory, bool new_mutual,
+ bool new_all_allowed_states, bool new_always, peace_modifiers_t&& new_modifiers, peace_options_t new_peace_options,
+ ConditionScript&& new_can_use, ConditionScript&& new_is_valid, ConditionScript&& new_allowed_states,
+ ConditionScript&& new_allowed_substate_regions, ConditionScript&& new_allowed_states_in_crisis,
+ ConditionScript&& new_allowed_countries, EffectScript&& new_on_add, EffectScript&& new_on_po_accepted
);
+ bool parse_scripts(GameManager& game_manager);
+
public:
WargoalType(WargoalType&&) = default;
};
@@ -91,24 +100,18 @@ namespace OpenVic {
std::vector<WargoalType const*> PROPERTY(peace_priorities);
public:
- const std::vector<WargoalType const*>& get_peace_priority_list() const;
-
bool add_wargoal_type(
- std::string_view identifier,
- std::string_view sprite,
- std::string_view war_name,
- Timespan available_length,
- Timespan truce_length,
- bool triggered_only,
- bool civil_war,
- bool constructing,
- bool crisis,
- bool great_war,
- bool mutual,
- WargoalType::peace_modifiers_t&& modifiers,
- peace_options_t peace_options
+ std::string_view identifier, std::string_view war_name, Timespan available_length,
+ Timespan truce_length, WargoalType::sprite_t sprite_index, bool triggered_only, bool civil_war,
+ bool constructing, bool crisis, bool great_war_obligatory, bool mutual, bool all_allowed_states,
+ bool always, WargoalType::peace_modifiers_t&& modifiers, peace_options_t peace_options,
+ ConditionScript&& can_use, ConditionScript&& is_valid, ConditionScript&& allowed_states,
+ ConditionScript&& allowed_substate_regions, ConditionScript&& allowed_states_in_crisis,
+ ConditionScript&& allowed_countries, EffectScript&& on_add, EffectScript&& on_po_accepted
);
bool load_wargoal_file(ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager& game_manager);
};
} // namespace OpenVic \ No newline at end of file
diff --git a/src/openvic-simulation/misc/Decision.cpp b/src/openvic-simulation/misc/Decision.cpp
index d50a16a..36eb871 100644
--- a/src/openvic-simulation/misc/Decision.cpp
+++ b/src/openvic-simulation/misc/Decision.cpp
@@ -6,14 +6,26 @@ using namespace OpenVic::NodeTools;
Decision::Decision(
std::string_view new_identifier, bool new_alert, bool new_news, std::string_view new_news_title,
std::string_view new_news_desc_long, std::string_view new_news_desc_medium, std::string_view new_news_desc_short,
- std::string_view new_picture
+ std::string_view new_picture, ConditionScript&& new_potential, ConditionScript&& new_allow,
+ ConditionalWeight&& new_ai_will_do, EffectScript&& new_effect
) : HasIdentifier { new_identifier }, alert { new_alert }, news { new_news }, news_title { new_news_title },
news_desc_long { new_news_desc_long }, news_desc_medium { new_news_desc_medium },
- news_desc_short { new_news_desc_short }, picture { new_picture } {}
+ news_desc_short { new_news_desc_short }, picture { new_picture }, potential { std::move(new_potential) },
+ allow { std::move(new_allow) }, ai_will_do { std::move(new_ai_will_do) }, effect { std::move(new_effect) } {}
+
+bool Decision::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= potential.parse_script(false, game_manager);
+ ret &= allow.parse_script(false, game_manager);
+ ret &= ai_will_do.parse_scripts(game_manager);
+ ret &= effect.parse_script(false, game_manager);
+ return ret;
+}
bool DecisionManager::add_decision(
std::string_view identifier, bool alert, bool news, std::string_view news_title, std::string_view news_desc_long,
- std::string_view news_desc_medium, std::string_view news_desc_short, std::string_view picture
+ std::string_view news_desc_medium, std::string_view news_desc_short, std::string_view picture, ConditionScript&& potential,
+ ConditionScript&& allow, ConditionalWeight&& ai_will_do, EffectScript&& effect
) {
if (identifier.empty()) {
Logger::error("Invalid decision identifier - empty!");
@@ -33,7 +45,8 @@ bool DecisionManager::add_decision(
}
return decisions.add_item({
- identifier, alert, news, news_title, news_desc_long, news_desc_medium, news_desc_short, picture
+ identifier, alert, news, news_title, news_desc_long, news_desc_medium, news_desc_short, picture, std::move(potential),
+ std::move(allow), std::move(ai_will_do), std::move(effect)
}, duplicate_warning_callback);
}
@@ -43,6 +56,9 @@ bool DecisionManager::load_decision_file(ast::NodeCPtr root) {
[this](std::string_view identifier, ast::NodeCPtr node) -> bool {
bool alert = true, news = false;
std::string_view news_title, news_desc_long, news_desc_medium, news_desc_short, picture;
+ ConditionScript potential, allow;
+ ConditionalWeight ai_will_do;
+ EffectScript effect;
bool ret = expect_dictionary_keys(
"alert", ZERO_OR_ONE, expect_bool(assign_variable_callback(alert)),
"news", ZERO_OR_ONE, expect_bool(assign_variable_callback(news)),
@@ -51,16 +67,25 @@ bool DecisionManager::load_decision_file(ast::NodeCPtr root) {
"news_desc_medium", ZERO_OR_ONE, expect_string(assign_variable_callback(news_desc_medium)),
"news_desc_short", ZERO_OR_ONE, expect_string(assign_variable_callback(news_desc_short)),
"picture", ZERO_OR_ONE, expect_identifier_or_string(assign_variable_callback(picture)),
- "potential", ONE_EXACTLY, success_callback, //TODO
- "allow", ONE_EXACTLY, success_callback, //TODO
- "effect", ONE_EXACTLY, success_callback, //TODO
- "ai_will_do", ZERO_OR_ONE, success_callback //TODO
+ "potential", ONE_EXACTLY, potential.expect_script(),
+ "allow", ONE_EXACTLY, allow.expect_script(),
+ "effect", ONE_EXACTLY, effect.expect_script(),
+ "ai_will_do", ZERO_OR_ONE, ai_will_do.expect_conditional_weight(ConditionalWeight::FACTOR)
)(node);
ret &= add_decision(
- identifier, alert, news, news_title, news_desc_long, news_desc_medium, news_desc_short, picture
+ identifier, alert, news, news_title, news_desc_long, news_desc_medium, news_desc_short, picture,
+ std::move(potential), std::move(allow), std::move(ai_will_do), std::move(effect)
);
return ret;
}
)
)(root);
}
+
+bool DecisionManager::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ for (Decision& decision : decisions.get_items()) {
+ ret &= decision.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/misc/Decision.hpp b/src/openvic-simulation/misc/Decision.hpp
index 32141fe..593b6e4 100644
--- a/src/openvic-simulation/misc/Decision.hpp
+++ b/src/openvic-simulation/misc/Decision.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
+#include "openvic-simulation/scripts/EffectScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -11,18 +13,25 @@ namespace OpenVic {
private:
const bool PROPERTY_CUSTOM_PREFIX(alert, has);
const bool PROPERTY_CUSTOM_PREFIX(news, is);
- const std::string PROPERTY(news_title);
- const std::string PROPERTY(news_desc_long);
- const std::string PROPERTY(news_desc_medium);
- const std::string PROPERTY(news_desc_short);
- const std::string PROPERTY(picture);
+ std::string PROPERTY(news_title);
+ std::string PROPERTY(news_desc_long);
+ std::string PROPERTY(news_desc_medium);
+ std::string PROPERTY(news_desc_short);
+ std::string PROPERTY(picture);
+ ConditionScript PROPERTY(potential);
+ ConditionScript PROPERTY(allow);
+ ConditionalWeight PROPERTY(ai_will_do);
+ EffectScript PROPERTY(effect);
Decision(
std::string_view new_identifier, bool new_alert, bool new_news, std::string_view new_news_title,
std::string_view new_news_desc_long, std::string_view new_news_desc_medium, std::string_view new_news_desc_short,
- std::string_view new_picture
+ std::string_view new_picture, ConditionScript&& new_potential, ConditionScript&& new_allow,
+ ConditionalWeight&& new_ai_will_do, EffectScript&& new_effect
);
+ bool parse_scripts(GameManager& game_manager);
+
public:
Decision(Decision&&) = default;
};
@@ -34,9 +43,12 @@ namespace OpenVic {
public:
bool add_decision(
std::string_view identifier, bool alert, bool news, std::string_view news_title, std::string_view news_desc_long,
- std::string_view news_desc_medium, std::string_view news_desc_short, std::string_view picture
+ std::string_view news_desc_medium, std::string_view news_desc_short, std::string_view picture,
+ ConditionScript&& potential, ConditionScript&& allow, ConditionalWeight&& ai_will_do, EffectScript&& effect
);
bool load_decision_file(ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager& game_manager);
};
}
diff --git a/src/openvic-simulation/misc/Event.cpp b/src/openvic-simulation/misc/Event.cpp
index 4507de4..fb97d63 100644
--- a/src/openvic-simulation/misc/Event.cpp
+++ b/src/openvic-simulation/misc/Event.cpp
@@ -6,19 +6,41 @@
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Event::EventOption::EventOption(std::string_view new_title) : title { new_title } {}
+Event::EventOption::EventOption(std::string_view new_title, EffectScript&& new_effect, ConditionalWeight&& new_ai_chance)
+ : title { new_title }, effect { std::move(new_effect) }, ai_chance { std::move(new_ai_chance) } {}
+
+bool Event::EventOption::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= effect.parse_script(false, game_manager);
+ ret &= ai_chance.parse_scripts(game_manager);
+ return ret;
+}
Event::Event(
std::string_view new_identifier, std::string_view new_title, std::string_view new_description,
std::string_view new_image, event_type_t new_type, bool new_triggered_only, bool new_major, bool new_fire_only_once,
bool new_allows_multiple_instances, bool new_news, std::string_view new_news_title, std::string_view new_news_desc_long,
std::string_view new_news_desc_medium, std::string_view new_news_desc_short, bool new_election,
- IssueGroup const* new_election_issue_group, std::vector<EventOption>&& new_options
+ IssueGroup const* new_election_issue_group, ConditionScript&& new_trigger, ConditionalWeight&& new_mean_time_to_happen,
+ EffectScript&& new_immediate, std::vector<EventOption>&& new_options
) : HasIdentifier { new_identifier }, title { new_title }, description { new_description }, image { new_image },
type { new_type }, triggered_only { new_triggered_only }, major { new_major }, fire_only_once { new_fire_only_once },
allows_multiple_instances { new_allows_multiple_instances }, news { new_news }, news_title { new_news_title },
news_desc_long { new_news_desc_long }, news_desc_medium { new_news_desc_medium }, news_desc_short { new_news_desc_short },
- election { new_election }, election_issue_group { new_election_issue_group }, options { std::move(new_options) } {}
+ election { new_election }, election_issue_group { new_election_issue_group }, trigger { std::move(new_trigger) },
+ mean_time_to_happen { std::move(new_mean_time_to_happen) }, immediate { std::move(new_immediate) },
+ options { std::move(new_options) } {}
+
+bool Event::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= trigger.parse_script(true, game_manager);
+ ret &= mean_time_to_happen.parse_scripts(game_manager);
+ ret &= immediate.parse_script(true, game_manager);
+ for (EventOption& option : options) {
+ ret &= option.parse_scripts(game_manager);
+ }
+ return ret;
+}
OnAction::OnAction(std::string_view new_identifier, weight_map_t&& new_weighted_events)
: HasIdentifier { new_identifier }, weighted_events { std::move(new_weighted_events) } {}
@@ -27,8 +49,8 @@ bool EventManager::register_event(
std::string_view identifier, std::string_view title, std::string_view description, std::string_view image,
Event::event_type_t type, bool triggered_only, bool major, bool fire_only_once, bool allows_multiple_instances, bool news,
std::string_view news_title, std::string_view news_desc_long, std::string_view news_desc_medium,
- std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group,
- std::vector<Event::EventOption>&& options
+ std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group, ConditionScript&& trigger,
+ ConditionalWeight&& mean_time_to_happen, EffectScript&& immediate, std::vector<Event::EventOption>&& options
) {
if (identifier.empty()) {
Logger::error("Invalid event ID - empty!");
@@ -68,7 +90,8 @@ bool EventManager::register_event(
return events.add_item({
identifier, title, description, image, type, triggered_only, major, fire_only_once, allows_multiple_instances, news,
- news_title, news_desc_long, news_desc_medium, news_desc_short, election, election_issue_group, std::move(options)
+ news_title, news_desc_long, news_desc_medium, news_desc_short, election, election_issue_group, std::move(trigger),
+ std::move(mean_time_to_happen), std::move(immediate), std::move(options)
}, duplicate_warning_callback);
}
@@ -90,6 +113,9 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC
bool triggered_only = false, major = false, fire_only_once = false, allows_multiple_instances = false,
news = false, election = false;
IssueGroup const* election_issue_group = nullptr;
+ ConditionScript trigger;
+ ConditionalWeight mean_time_to_happen;
+ EffectScript immediate;
std::vector<Event::EventOption> options;
if (key == "country_event") {
@@ -120,25 +146,28 @@ bool EventManager::load_event_file(IssueManager const& issue_manager, ast::NodeC
issue_manager.expect_issue_group_identifier(assign_variable_callback_pointer(election_issue_group)),
"option", ONE_OR_MORE, [&options](ast::NodeCPtr node) -> bool {
std::string_view title;
+ EffectScript effect;
+ ConditionalWeight ai_chance;
bool ret = expect_dictionary_keys_and_default(
key_value_success_callback,
- "name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(title))
+ "name", ONE_EXACTLY, expect_identifier_or_string(assign_variable_callback(title)),
+ "ai_chance", ZERO_OR_ONE, ai_chance.expect_conditional_weight(ConditionalWeight::FACTOR)
)(node);
- // TODO: option effects
+ ret &= effect.expect_script()(node);
- options.push_back({ title });
+ options.push_back({ title, std::move(effect), std::move(ai_chance) });
return ret;
},
- "trigger", ZERO_OR_ONE, success_callback, // TODO - trigger condition
- "mean_time_to_happen", ZERO_OR_ONE, success_callback, // TODO - MTTH weighted conditions
- "immediate", ZERO_OR_MORE, success_callback // TODO - immediate effects
+ "trigger", ZERO_OR_ONE, trigger.expect_script(),
+ "mean_time_to_happen", ZERO_OR_ONE, mean_time_to_happen.expect_conditional_weight(ConditionalWeight::MONTHS),
+ "immediate", ZERO_OR_MORE, immediate.expect_script()
)(value);
ret &= register_event(
identifier, title, description, image, type, triggered_only, major, fire_only_once, allows_multiple_instances,
news, news_title, news_desc_long, news_desc_medium, news_desc_short, election, election_issue_group,
- std::move(options)
+ std::move(trigger), std::move(mean_time_to_happen), std::move(immediate), std::move(options)
);
return ret;
}
@@ -176,4 +205,12 @@ bool EventManager::load_on_action_file(ast::NodeCPtr root) {
})(root);
on_actions.lock();
return ret;
-} \ No newline at end of file
+}
+
+bool EventManager::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ for (Event& event : events.get_items()) {
+ ret &= event.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/misc/Event.hpp b/src/openvic-simulation/misc/Event.hpp
index c41ef3f..37f9270 100644
--- a/src/openvic-simulation/misc/Event.hpp
+++ b/src/openvic-simulation/misc/Event.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
+#include "openvic-simulation/scripts/EffectScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
@@ -15,12 +17,16 @@ namespace OpenVic {
struct EventOption {
friend struct EventManager;
+ friend struct Event;
private:
std::string PROPERTY(title);
- // TODO: option effects
+ EffectScript PROPERTY(effect);
+ ConditionalWeight PROPERTY(ai_chance);
- EventOption(std::string_view new_title);
+ EventOption(std::string_view new_title, EffectScript&& new_effect, ConditionalWeight&& new_ai_chance);
+
+ bool parse_scripts(GameManager& game_manager);
public:
EventOption(EventOption const&) = delete;
@@ -48,18 +54,23 @@ namespace OpenVic {
bool PROPERTY_CUSTOM_PREFIX(election, is);
IssueGroup const* PROPERTY(election_issue_group);
- std::vector<EventOption> PROPERTY(options);
+ ConditionScript PROPERTY(trigger);
+ ConditionalWeight PROPERTY(mean_time_to_happen);
+ EffectScript PROPERTY(immediate);
- // TODO: triggers, MTTH, immediate effects
+ std::vector<EventOption> PROPERTY(options);
Event(
std::string_view new_identifier, std::string_view new_title, std::string_view new_description,
std::string_view new_image, event_type_t new_type, bool new_triggered_only, bool new_major,
bool new_fire_only_once, bool new_allows_multiple_instances, bool new_news, std::string_view new_news_title,
std::string_view new_news_desc_long, std::string_view new_news_desc_medium, std::string_view new_news_desc_short,
- bool new_election, IssueGroup const* new_election_issue_group, std::vector<EventOption>&& new_options
+ bool new_election, IssueGroup const* new_election_issue_group, ConditionScript&& new_trigger,
+ ConditionalWeight&& new_mean_time_to_happen, EffectScript&& new_immediate, std::vector<EventOption>&& new_options
);
+ bool parse_scripts(GameManager& game_manager);
+
public:
Event(Event&&) = default;
};
@@ -88,13 +99,15 @@ namespace OpenVic {
std::string_view identifier, std::string_view title, std::string_view description, std::string_view image,
Event::event_type_t type, bool triggered_only, bool major, bool fire_only_once, bool allows_multiple_instances,
bool news, std::string_view news_title, std::string_view news_desc_long, std::string_view news_desc_medium,
- std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group,
- std::vector<Event::EventOption>&& options
+ std::string_view news_desc_short, bool election, IssueGroup const* election_issue_group, ConditionScript&& trigger,
+ ConditionalWeight&& mean_time_to_happen, EffectScript&& immediate, std::vector<Event::EventOption>&& options
);
bool add_on_action(std::string_view identifier, OnAction::weight_map_t&& new_weighted_events);
bool load_event_file(IssueManager const& issue_manager, ast::NodeCPtr root);
bool load_on_action_file(ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager& game_manager);
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/misc/Modifier.cpp b/src/openvic-simulation/misc/Modifier.cpp
index 94d38e0..bbc8f59 100644
--- a/src/openvic-simulation/misc/Modifier.cpp
+++ b/src/openvic-simulation/misc/Modifier.cpp
@@ -82,8 +82,13 @@ ModifierValue ModifierValue::operator-(ModifierValue const& right) const {
Modifier::Modifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon)
: HasIdentifier { new_identifier }, ModifierValue { std::move(new_values) }, icon { new_icon } {}
-TriggeredModifier::TriggeredModifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon)
- : Modifier { new_identifier, std::move(new_values), new_icon } {}
+TriggeredModifier::TriggeredModifier(
+ std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger
+) : Modifier { new_identifier, std::move(new_values), new_icon }, trigger { std::move(new_trigger) } {}
+
+bool TriggeredModifier::parse_scripts(GameManager const& game_manager) {
+ return trigger.parse_script(false, game_manager);
+}
ModifierInstance::ModifierInstance(Modifier const& modifier, Date expiry_date)
: modifier { modifier }, expiry_date { expiry_date } {}
@@ -319,12 +324,14 @@ bool ModifierManager::load_static_modifiers(ast::NodeCPtr root) {
return ret;
}
-bool ModifierManager::add_triggered_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon) {
+bool ModifierManager::add_triggered_modifier(
+ std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, ConditionScript&& trigger
+) {
if (identifier.empty()) {
Logger::error("Invalid triggered modifier effect identifier - empty!");
return false;
}
- return triggered_modifiers.add_item({ identifier, std::move(values), icon }, duplicate_warning_callback);
+ return triggered_modifiers.add_item({ identifier, std::move(values), icon, std::move(trigger) }, duplicate_warning_callback);
}
bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) {
@@ -333,12 +340,14 @@ bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) {
[this](std::string_view key, ast::NodeCPtr value) -> bool {
ModifierValue modifier_value;
Modifier::icon_t icon = 0;
+ ConditionScript trigger;
+
bool ret = expect_modifier_value_and_keys(
move_variable_callback(modifier_value),
"icon", ZERO_OR_ONE, expect_uint(assign_variable_callback(icon)),
- "trigger", ONE_EXACTLY, success_callback // TODO - load condition
+ "trigger", ONE_EXACTLY, trigger.expect_script()
)(value);
- ret &= add_triggered_modifier(key, std::move(modifier_value), icon);
+ ret &= add_triggered_modifier(key, std::move(modifier_value), icon, std::move(trigger));
return ret;
}
)(root);
@@ -346,6 +355,14 @@ bool ModifierManager::load_triggered_modifiers(ast::NodeCPtr root) {
return ret;
}
+bool ModifierManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (TriggeredModifier& modifier : triggered_modifiers.get_items()) {
+ ret &= modifier.parse_scripts(game_manager);
+ }
+ return ret;
+}
+
key_value_callback_t ModifierManager::_modifier_effect_callback(
ModifierValue& modifier, key_value_callback_t default_callback, ModifierEffectValidator auto effect_validator
) const {
diff --git a/src/openvic-simulation/misc/Modifier.hpp b/src/openvic-simulation/misc/Modifier.hpp
index f3a2499..033cc47 100644
--- a/src/openvic-simulation/misc/Modifier.hpp
+++ b/src/openvic-simulation/misc/Modifier.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "openvic-simulation/scripts/ConditionScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -83,10 +84,14 @@ namespace OpenVic {
friend struct ModifierManager;
private:
- // TODO - trigger condition
+ ConditionScript trigger;
protected:
- TriggeredModifier(std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon);
+ TriggeredModifier(
+ std::string_view new_identifier, ModifierValue&& new_values, icon_t new_icon, ConditionScript&& new_trigger
+ );
+
+ bool parse_scripts(GameManager const& game_manager);
public:
TriggeredModifier(TriggeredModifier&&) = default;
@@ -139,9 +144,13 @@ namespace OpenVic {
bool add_static_modifier(std::string_view identifier, ModifierValue&& values);
bool load_static_modifiers(ast::NodeCPtr root);
- bool add_triggered_modifier(std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon);
+ bool add_triggered_modifier(
+ std::string_view identifier, ModifierValue&& values, Modifier::icon_t icon, ConditionScript&& trigger
+ );
bool load_triggered_modifiers(ast::NodeCPtr root);
+ bool parse_scripts(GameManager const& game_manager);
+
NodeTools::node_callback_t expect_validated_modifier_value_and_default(
NodeTools::callback_t<ModifierValue&&> modifier_callback, NodeTools::key_value_callback_t default_callback,
ModifierEffectValidator auto effect_validator
diff --git a/src/openvic-simulation/politics/Ideology.cpp b/src/openvic-simulation/politics/Ideology.cpp
index 577ab79..2678bee 100644
--- a/src/openvic-simulation/politics/Ideology.cpp
+++ b/src/openvic-simulation/politics/Ideology.cpp
@@ -9,9 +9,27 @@ IdeologyGroup::IdeologyGroup(std::string_view new_identifier) : HasIdentifier {
Ideology::Ideology(
std::string_view new_identifier, colour_t new_colour, IdeologyGroup const& new_group, bool new_uncivilised,
- bool new_can_reduce_militancy, Date new_spawn_date
+ bool new_can_reduce_militancy, Date new_spawn_date, ConditionalWeight&& new_add_political_reform,
+ ConditionalWeight&& new_remove_political_reform, ConditionalWeight&& new_add_social_reform,
+ ConditionalWeight&& new_remove_social_reform, ConditionalWeight&& new_add_military_reform,
+ ConditionalWeight&& new_add_economic_reform
) : HasIdentifierAndColour { new_identifier, new_colour, false }, group { new_group }, uncivilised { new_uncivilised },
- can_reduce_militancy { new_can_reduce_militancy }, spawn_date { new_spawn_date } {}
+ can_reduce_militancy { new_can_reduce_militancy }, spawn_date { new_spawn_date },
+ add_political_reform { std::move(new_add_political_reform) },
+ remove_political_reform { std::move(new_remove_political_reform) },
+ add_social_reform { std::move(new_add_social_reform) }, remove_social_reform { std::move(new_remove_social_reform) },
+ add_military_reform { std::move(new_add_military_reform) }, add_economic_reform { std::move(new_add_economic_reform) } {}
+
+bool Ideology::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ ret &= add_political_reform.parse_scripts(game_manager);
+ ret &= remove_political_reform.parse_scripts(game_manager);
+ ret &= add_social_reform.parse_scripts(game_manager);
+ ret &= remove_social_reform.parse_scripts(game_manager);
+ ret &= add_military_reform.parse_scripts(game_manager);
+ ret &= add_economic_reform.parse_scripts(game_manager);
+ return ret;
+}
bool IdeologyManager::add_ideology_group(std::string_view identifier) {
if (identifier.empty()) {
@@ -24,7 +42,9 @@ bool IdeologyManager::add_ideology_group(std::string_view identifier) {
bool IdeologyManager::add_ideology(
std::string_view identifier, colour_t colour, IdeologyGroup const* group, bool uncivilised, bool can_reduce_militancy,
- Date spawn_date
+ Date spawn_date, ConditionalWeight&& add_political_reform, ConditionalWeight&& remove_political_reform,
+ ConditionalWeight&& add_social_reform, ConditionalWeight&& remove_social_reform, ConditionalWeight&& add_military_reform,
+ ConditionalWeight&& add_economic_reform
) {
if (identifier.empty()) {
Logger::error("Invalid ideology identifier - empty!");
@@ -36,7 +56,11 @@ bool IdeologyManager::add_ideology(
return false;
}
- return ideologies.add_item({ identifier, colour, *group, uncivilised, can_reduce_militancy, spawn_date });
+ return ideologies.add_item({
+ identifier, colour, *group, uncivilised, can_reduce_militancy, spawn_date, std::move(add_political_reform),
+ std::move(remove_political_reform), std::move(add_social_reform), std::move(remove_social_reform),
+ std::move(add_military_reform), std::move(add_economic_reform)
+ });
}
/* REQUIREMENTS:
@@ -61,20 +85,26 @@ bool IdeologyManager::load_ideology_file(ast::NodeCPtr root) {
colour_t colour = colour_t::null();
bool uncivilised = true, can_reduce_militancy = false;
Date spawn_date;
+ ConditionalWeight add_political_reform, remove_political_reform, add_social_reform, remove_social_reform,
+ add_military_reform, add_economic_reform;
bool ret = expect_dictionary_keys(
"uncivilized", ZERO_OR_ONE, expect_bool(assign_variable_callback(uncivilised)),
"color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)),
"date", ZERO_OR_ONE, expect_date(assign_variable_callback(spawn_date)),
"can_reduce_militancy", ZERO_OR_ONE, expect_bool(assign_variable_callback(can_reduce_militancy)),
- "add_political_reform", ONE_EXACTLY, success_callback,
- "remove_political_reform", ONE_EXACTLY, success_callback,
- "add_social_reform", ONE_EXACTLY, success_callback,
- "remove_social_reform", ONE_EXACTLY, success_callback,
- "add_military_reform", ZERO_OR_ONE, success_callback,
- "add_economic_reform", ZERO_OR_ONE, success_callback
+ "add_political_reform", ONE_EXACTLY, add_political_reform.expect_conditional_weight(ConditionalWeight::BASE),
+ "remove_political_reform", ONE_EXACTLY, remove_political_reform.expect_conditional_weight(ConditionalWeight::BASE),
+ "add_social_reform", ONE_EXACTLY, add_social_reform.expect_conditional_weight(ConditionalWeight::BASE),
+ "remove_social_reform", ONE_EXACTLY, remove_social_reform.expect_conditional_weight(ConditionalWeight::BASE),
+ "add_military_reform", ZERO_OR_ONE, add_military_reform.expect_conditional_weight(ConditionalWeight::BASE),
+ "add_economic_reform", ZERO_OR_ONE, add_economic_reform.expect_conditional_weight(ConditionalWeight::BASE)
)(value);
- ret &= add_ideology(key, colour, ideology_group, uncivilised, can_reduce_militancy, spawn_date);
+ ret &= add_ideology(
+ key, colour, ideology_group, uncivilised, can_reduce_militancy, spawn_date, std::move(add_political_reform),
+ std::move(remove_political_reform), std::move(add_social_reform), std::move(remove_social_reform),
+ std::move(add_military_reform), std::move(add_economic_reform)
+ );
return ret;
})(ideology_group_value);
})(root);
@@ -82,3 +112,11 @@ bool IdeologyManager::load_ideology_file(ast::NodeCPtr root) {
return ret;
}
+
+bool IdeologyManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (Ideology& ideology : ideologies.get_items()) {
+ ideology.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/politics/Ideology.hpp b/src/openvic-simulation/politics/Ideology.hpp
index 8039dbd..ad07f06 100644
--- a/src/openvic-simulation/politics/Ideology.hpp
+++ b/src/openvic-simulation/politics/Ideology.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -23,14 +24,25 @@ namespace OpenVic {
const bool PROPERTY_CUSTOM_PREFIX(uncivilised, is);
const bool PROPERTY(can_reduce_militancy);
const Date PROPERTY(spawn_date);
+ ConditionalWeight PROPERTY(add_political_reform);
+ ConditionalWeight PROPERTY(remove_political_reform);
+ ConditionalWeight PROPERTY(add_social_reform);
+ ConditionalWeight PROPERTY(remove_social_reform);
+ ConditionalWeight PROPERTY(add_military_reform);
+ ConditionalWeight PROPERTY(add_economic_reform);
// TODO - willingness to repeal/pass reforms (and its modifiers)
Ideology(
std::string_view new_identifier, colour_t new_colour, IdeologyGroup const& new_group, bool new_uncivilised,
- bool new_can_reduce_militancy, Date new_spawn_date
+ bool new_can_reduce_militancy, Date new_spawn_date, ConditionalWeight&& new_add_political_reform,
+ ConditionalWeight&& new_remove_political_reform, ConditionalWeight&& new_add_social_reform,
+ ConditionalWeight&& new_remove_social_reform, ConditionalWeight&& new_add_military_reform,
+ ConditionalWeight&& new_add_economic_reform
);
+ bool parse_scripts(GameManager const& game_manager);
+
public:
Ideology(Ideology&&) = default;
};
@@ -45,9 +57,14 @@ namespace OpenVic {
bool add_ideology(
std::string_view identifier, colour_t colour, IdeologyGroup const* group, bool uncivilised,
- bool can_reduce_militancy, Date spawn_date
+ bool can_reduce_militancy, Date spawn_date, ConditionalWeight&& add_political_reform,
+ ConditionalWeight&& remove_political_reform, ConditionalWeight&& add_social_reform,
+ ConditionalWeight&& remove_social_reform, ConditionalWeight&& add_military_reform,
+ ConditionalWeight&& add_economic_reform
);
bool load_ideology_file(ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager const& game_manager);
};
}
diff --git a/src/openvic-simulation/politics/Issue.cpp b/src/openvic-simulation/politics/Issue.cpp
index 4ad1625..3e64af4 100644
--- a/src/openvic-simulation/politics/Issue.cpp
+++ b/src/openvic-simulation/politics/Issue.cpp
@@ -17,9 +17,19 @@ ReformGroup::ReformGroup(std::string_view new_identifier, ReformType const& new_
Reform::Reform(
std::string_view new_identifier, ModifierValue&& new_values, ReformGroup const& new_group, size_t new_ordinal,
- RuleSet&& new_rules, tech_cost_t new_technology_cost
-) : Issue { new_identifier, std::move(new_values), new_group, std::move(new_rules), false },
- ordinal { new_ordinal }, reform_group { new_group }, technology_cost { new_technology_cost } {}
+ RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow,
+ ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect
+) : Issue { new_identifier, std::move(new_values), new_group, std::move(new_rules), false }, ordinal { new_ordinal },
+ reform_group { new_group }, technology_cost { new_technology_cost }, allow { std::move(new_allow) },
+ on_execute_trigger { std::move(new_on_execute_trigger) }, on_execute_effect { std::move(new_on_execute_effect) } {}
+
+bool Reform::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= allow.parse_script(true, game_manager);
+ ret &= on_execute_trigger.parse_script(true, game_manager);
+ ret &= on_execute_effect.parse_script(true, game_manager);
+ return ret;
+}
bool IssueManager::add_issue_group(std::string_view identifier) {
if (identifier.empty()) {
@@ -30,7 +40,9 @@ bool IssueManager::add_issue_group(std::string_view identifier) {
return issue_groups.add_item({ identifier });
}
-bool IssueManager::add_issue(std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism) {
+bool IssueManager::add_issue(
+ std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism
+) {
if (identifier.empty()) {
Logger::error("Invalid issue identifier - empty!");
return false;
@@ -68,8 +80,9 @@ bool IssueManager::add_reform_group(std::string_view identifier, ReformType cons
}
bool IssueManager::add_reform(
- std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal,
- RuleSet&& rules, Reform::tech_cost_t technology_cost
+ std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal, RuleSet&& rules,
+ Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger,
+ EffectScript&& on_execute_effect
) {
if (identifier.empty()) {
Logger::error("Invalid issue identifier - empty!");
@@ -89,7 +102,10 @@ bool IssueManager::add_reform(
Logger::warning("Non-zero technology cost ", technology_cost, " found in civilised reform ", identifier, "!");
}
- return reforms.add_item({ identifier, std::move(values), *group, ordinal, std::move(rules), technology_cost });
+ return reforms.add_item({
+ identifier, std::move(values), *group, ordinal, std::move(rules), technology_cost, std::move(allow),
+ std::move(on_execute_trigger), std::move(on_execute_effect)
+ });
}
bool IssueManager::_load_issue_group(size_t& expected_issues, std::string_view identifier, ast::NodeCPtr node) {
@@ -129,17 +145,25 @@ bool IssueManager::_load_reform(
ModifierManager const& modifier_manager, RuleManager const& rule_manager, size_t ordinal, std::string_view identifier,
ReformGroup const* group, ast::NodeCPtr node
) {
- // TODO: conditions to allow, policy rule changes
ModifierValue values;
RuleSet rules;
Reform::tech_cost_t technology_cost = 0;
+ ConditionScript allow, on_execute_trigger;
+ EffectScript on_execute_effect;
+
bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(values),
"technology_cost", ZERO_OR_ONE, expect_uint(assign_variable_callback(technology_cost)),
- "allow", ZERO_OR_ONE, success_callback, //TODO: allow block
+ "allow", ZERO_OR_ONE, allow.expect_script(),
"rules", ZERO_OR_ONE, rule_manager.expect_rule_set(move_variable_callback(rules)),
- "on_execute", ZERO_OR_MORE, success_callback //TODO: trigger/effect blocks
+ "on_execute", ZERO_OR_ONE, expect_dictionary_keys(
+ "trigger", ZERO_OR_ONE, on_execute_trigger.expect_script(),
+ "effect", ONE_EXACTLY, on_execute_effect.expect_script()
+ )
)(node);
- ret &= add_reform(identifier, std::move(values), group, ordinal, std::move(rules), technology_cost);
+ ret &= add_reform(
+ identifier, std::move(values), group, ordinal, std::move(rules), technology_cost, std::move(allow),
+ std::move(on_execute_trigger), std::move(on_execute_effect)
+ );
return ret;
}
@@ -157,10 +181,12 @@ bool IssueManager::load_issues_file(ModifierManager const& modifier_manager, Rul
size_t expected_reform_groups = 0;
bool ret = expect_dictionary_reserve_length(reform_types,
[this, &expected_issue_groups, &expected_reform_groups](std::string_view key, ast::NodeCPtr value) -> bool {
- if (key == "party_issues")
+ if (key == "party_issues") {
return expect_length(add_variable_callback(expected_issue_groups))(value);
- else return expect_length(add_variable_callback(expected_reform_groups))(value)
- & add_reform_type(key, key == "economic_reforms" || "education_reforms" || "military_reforms");
+ } else {
+ return expect_length(add_variable_callback(expected_reform_groups))(value)
+ & add_reform_type(key, key == "economic_reforms" || key == "education_reforms" || key == "military_reforms");
+ }
}
)(root);
lock_reform_types();
@@ -216,3 +242,11 @@ bool IssueManager::load_issues_file(ModifierManager const& modifier_manager, Rul
return ret;
}
+
+bool IssueManager::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ for (Reform& reform : reforms.get_items()) {
+ ret &= reform.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/politics/Issue.hpp b/src/openvic-simulation/politics/Issue.hpp
index a034959..b836e6f 100644
--- a/src/openvic-simulation/politics/Issue.hpp
+++ b/src/openvic-simulation/politics/Issue.hpp
@@ -1,8 +1,10 @@
#pragma once
-#include "openvic-simulation/politics/Rule.hpp"
-#include "openvic-simulation/misc/Modifier.hpp"
#include "openvic-simulation/dataloader/NodeTools.hpp"
+#include "openvic-simulation/misc/Modifier.hpp"
+#include "openvic-simulation/politics/Rule.hpp"
+#include "openvic-simulation/scripts/ConditionScript.hpp"
+#include "openvic-simulation/scripts/EffectScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
namespace OpenVic {
@@ -76,12 +78,18 @@ namespace OpenVic {
ReformGroup const& PROPERTY(reform_group); // stores an already casted reference
const size_t PROPERTY(ordinal); // assigned by the parser to allow policy sorting
const tech_cost_t PROPERTY(technology_cost);
+ ConditionScript PROPERTY(allow);
+ ConditionScript PROPERTY(on_execute_trigger);
+ EffectScript PROPERTY(on_execute_effect);
Reform(
std::string_view new_identifier, ModifierValue&& new_values, ReformGroup const& new_group, size_t new_ordinal,
- RuleSet&& new_rules, tech_cost_t new_technology_cost
+ RuleSet&& new_rules, tech_cost_t new_technology_cost, ConditionScript&& new_allow,
+ ConditionScript&& new_on_execute_trigger, EffectScript&& new_on_execute_effect
);
+ bool parse_scripts(GameManager& game_manager);
+
public:
Reform(Reform&&) = default;
};
@@ -104,16 +112,24 @@ namespace OpenVic {
size_t& expected_reforms, std::string_view identifier, ReformType const* type, ast::NodeCPtr node
);
bool _load_reform(
- ModifierManager const& modifier_manager, RuleManager const& rule_manager, size_t ordinal, std::string_view identifier,
- ReformGroup const* group, ast::NodeCPtr node
+ ModifierManager const& modifier_manager, RuleManager const& rule_manager, size_t ordinal,
+ std::string_view identifier, ReformGroup const* group, ast::NodeCPtr node
);
public:
bool add_issue_group(std::string_view identifier);
- bool add_issue(std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism);
+ bool add_issue(
+ std::string_view identifier, ModifierValue&& values, IssueGroup const* group, RuleSet&& rules, bool jingoism
+ );
bool add_reform_type(std::string_view identifier, bool uncivilised);
bool add_reform_group(std::string_view identifier, ReformType const* type, bool ordered, bool administrative);
- bool add_reform(std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal, RuleSet&& rules, Reform::tech_cost_t technology_cost);
+ bool add_reform(
+ std::string_view identifier, ModifierValue&& values, ReformGroup const* group, size_t ordinal, RuleSet&& rules,
+ Reform::tech_cost_t technology_cost, ConditionScript&& allow, ConditionScript&& on_execute_trigger,
+ EffectScript&& on_execute_effect
+ );
bool load_issues_file(ModifierManager const& modifier_manager, RuleManager const& rule_manager, ast::NodeCPtr root);
+
+ bool parse_scripts(GameManager& game_manager);
};
}
diff --git a/src/openvic-simulation/politics/NationalFocus.cpp b/src/openvic-simulation/politics/NationalFocus.cpp
index a2003eb..d4066af 100644
--- a/src/openvic-simulation/politics/NationalFocus.cpp
+++ b/src/openvic-simulation/politics/NationalFocus.cpp
@@ -14,14 +14,20 @@ NationalFocus::NationalFocus(
ModifierValue&& new_modifiers,
pop_promotion_map_t&& new_encouraged_promotion,
party_loyalty_map_t&& new_encouraged_loyalty,
- production_map_t&& new_encouraged_production
+ production_map_t&& new_encouraged_production,
+ ConditionScript&& new_limit
) : HasIdentifier { new_identifier },
icon { new_icon },
group { new_group },
modifiers { std::move(new_modifiers) },
encouraged_promotion { std::move(new_encouraged_promotion) },
encouraged_loyalty { std::move(new_encouraged_loyalty) },
- encouraged_production { std::move(new_encouraged_production) } {}
+ encouraged_production { std::move(new_encouraged_production) },
+ limit { std::move(new_limit) } {}
+
+bool NationalFocus::parse_scripts(GameManager const& game_manager) {
+ return limit.parse_script(true, game_manager);
+}
inline bool NationalFocusManager::add_national_focus_group(std::string_view identifier) {
if (identifier.empty()) {
@@ -38,7 +44,8 @@ inline bool NationalFocusManager::add_national_focus(
ModifierValue&& modifiers,
NationalFocus::pop_promotion_map_t&& encouraged_promotion,
NationalFocus::party_loyalty_map_t&& encouraged_loyalty,
- NationalFocus::production_map_t&& encouraged_production
+ NationalFocus::production_map_t&& encouraged_production,
+ ConditionScript&& limit
) {
if (identifier.empty()) {
Logger::error("No identifier for national focus!");
@@ -48,7 +55,10 @@ inline bool NationalFocusManager::add_national_focus(
Logger::error("Invalid icon ", icon, " for national focus ", identifier);
return false;
}
- return national_foci.add_item({ identifier, icon, group, std::move(modifiers), std::move(encouraged_promotion), std::move(encouraged_loyalty), std::move(encouraged_production) });
+ return national_foci.add_item({
+ identifier, icon, group, std::move(modifiers), std::move(encouraged_promotion), std::move(encouraged_loyalty),
+ std::move(encouraged_production), std::move(limit)
+ });
}
bool NationalFocusManager::load_national_foci_file(PopManager const& pop_manager, IdeologyManager const& ideology_manager, GoodManager const& good_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root) {
@@ -64,6 +74,7 @@ bool NationalFocusManager::load_national_foci_file(PopManager const& pop_manager
NationalFocus::pop_promotion_map_t promotions;
NationalFocus::party_loyalty_map_t loyalties;
NationalFocus::production_map_t production;
+ ConditionScript limit;
Ideology const* last_specified_ideology = nullptr; // weird, I know
@@ -98,13 +109,16 @@ bool NationalFocusManager::load_national_foci_file(PopManager const& pop_manager
loyalties[last_specified_ideology] += boost;
return ret;
},
- "limit", ZERO_OR_ONE, success_callback, // TODO: implement conditions
+ "limit", ZERO_OR_ONE, limit.expect_script(),
"has_flashpoint", ZERO_OR_ONE, success_callback, // special case, include in limit
"own_provinces", ZERO_OR_ONE, success_callback, // special case, include in limit
"outliner_show_as_percent", ZERO_OR_ONE, success_callback // special case
)(node);
- add_national_focus(identifier, icon, group, std::move(modifiers), std::move(promotions), std::move(loyalties), std::move(production));
+ add_national_focus(
+ identifier, icon, group, std::move(modifiers), std::move(promotions), std::move(loyalties),
+ std::move(production), std::move(limit)
+ );
return ret;
})(node);
@@ -114,3 +128,11 @@ bool NationalFocusManager::load_national_foci_file(PopManager const& pop_manager
return ret;
}
+
+bool NationalFocusManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (NationalFocus& national_focus : national_foci.get_items()) {
+ ret &= national_focus.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp
index 0fe0ddc..44e58e3 100644
--- a/src/openvic-simulation/politics/NationalFocus.hpp
+++ b/src/openvic-simulation/politics/NationalFocus.hpp
@@ -1,13 +1,12 @@
#pragma once
-#include "openvic-simulation/types/IdentifierRegistry.hpp"
-#include "openvic-simulation/utility/Getters.hpp"
+#include "openvic-simulation/economy/Good.hpp"
#include "openvic-simulation/misc/Modifier.hpp"
-#include "openvic-simulation/pop/Pop.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
-#include "openvic-simulation/economy/Good.hpp"
-
-#include <optional>
+#include "openvic-simulation/pop/Pop.hpp"
+#include "openvic-simulation/scripts/ConditionScript.hpp"
+#include "openvic-simulation/types/IdentifierRegistry.hpp"
+#include "openvic-simulation/utility/Getters.hpp"
namespace OpenVic {
struct NationalFocusManager;
@@ -34,6 +33,7 @@ namespace OpenVic {
pop_promotion_map_t PROPERTY(encouraged_promotion);
party_loyalty_map_t PROPERTY(encouraged_loyalty);
production_map_t PROPERTY(encouraged_production);
+ ConditionScript PROPERTY(limit);
NationalFocus(
std::string_view new_identifier,
@@ -42,9 +42,12 @@ namespace OpenVic {
ModifierValue&& new_modifiers,
pop_promotion_map_t&& new_encouraged_promotion,
party_loyalty_map_t&& new_encouraged_loyalty,
- production_map_t&& new_encouraged_production
+ production_map_t&& new_encouraged_production,
+ ConditionScript&& new_limit
);
+ bool parse_scripts(GameManager const& game_manager);
+
public:
NationalFocus(NationalFocus&&) = default;
};
@@ -64,9 +67,15 @@ namespace OpenVic {
ModifierValue&& modifiers,
NationalFocus::pop_promotion_map_t&& encouraged_promotion,
NationalFocus::party_loyalty_map_t&& encouraged_loyalty,
- NationalFocus::production_map_t&& encouraged_production
+ NationalFocus::production_map_t&& encouraged_production,
+ ConditionScript&& limit
+ );
+
+ bool load_national_foci_file(
+ PopManager const& pop_manager, IdeologyManager const& ideology_manager, GoodManager const& good_manager,
+ ModifierManager const& modifier_manager, ast::NodeCPtr root
);
- bool load_national_foci_file(PopManager const& pop_manager, IdeologyManager const& ideology_manager, GoodManager const& good_manager, ModifierManager const& modifier_manager, ast::NodeCPtr root);
+ bool parse_scripts(GameManager const& game_manager);
};
} // namespace OpenVic
diff --git a/src/openvic-simulation/politics/Rebel.cpp b/src/openvic-simulation/politics/Rebel.cpp
index 6850e83..ca8e945 100644
--- a/src/openvic-simulation/politics/Rebel.cpp
+++ b/src/openvic-simulation/politics/Rebel.cpp
@@ -8,20 +8,41 @@ RebelType::RebelType(
RebelType::government_map_t&& desired_governments, RebelType::defection_t defection,
RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures,
bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, bool reinforcing,
- bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult
+ bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult, ConditionalWeight&& new_will_rise,
+ ConditionalWeight&& new_spawn_chance, ConditionalWeight&& new_movement_evaluation, ConditionScript&& new_siege_won_trigger,
+ EffectScript&& new_siege_won_effect, ConditionScript&& new_demands_enforced_trigger,
+ EffectScript&& new_demands_enforced_effect
) : HasIdentifier { new_identifier }, icon { icon }, area { area }, break_alliance_on_win { break_alliance_on_win },
desired_governments { std::move(desired_governments) }, defection { defection }, independence { independence },
defect_delay { defect_delay }, ideology { ideology }, allow_all_cultures { allow_all_cultures },
allow_all_culture_groups { allow_all_culture_groups }, allow_all_religions { allow_all_religions },
allow_all_ideologies { allow_all_ideologies }, resilient { resilient }, reinforcing { reinforcing }, general { general },
- smart { smart }, unit_transfer { unit_transfer }, occupation_mult { occupation_mult } {}
+ smart { smart }, unit_transfer { unit_transfer }, occupation_mult { occupation_mult },
+ will_rise { std::move(new_will_rise) }, spawn_chance { std::move(new_spawn_chance) },
+ movement_evaluation { std::move(new_movement_evaluation) }, siege_won_trigger { std::move(new_siege_won_trigger) },
+ siege_won_effect { std::move(new_siege_won_effect) }, demands_enforced_trigger { std::move(new_demands_enforced_trigger) },
+ demands_enforced_effect { std::move(new_demands_enforced_effect) } {}
+
+bool RebelType::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ ret &= will_rise.parse_scripts(game_manager);
+ ret &= spawn_chance.parse_scripts(game_manager);
+ ret &= movement_evaluation.parse_scripts(game_manager);
+ ret &= siege_won_trigger.parse_script(true, game_manager);
+ ret &= siege_won_effect.parse_script(true, game_manager);
+ ret &= demands_enforced_trigger.parse_script(true, game_manager);
+ ret &= demands_enforced_effect.parse_script(true, game_manager);
+ return ret;
+}
bool RebelManager::add_rebel_type(
std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win,
RebelType::government_map_t&& desired_governments, RebelType::defection_t defection,
RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures,
bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient, bool reinforcing,
- bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult
+ bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult, ConditionalWeight&& will_rise,
+ ConditionalWeight&& spawn_chance, ConditionalWeight&& movement_evaluation, ConditionScript&& siege_won_trigger,
+ EffectScript&& siege_won_effect, ConditionScript&& demands_enforced_trigger, EffectScript&& demands_enforced_effect
) {
if (new_identifier.empty()) {
Logger::error("Invalid rebel type identifier - empty!");
@@ -31,7 +52,9 @@ bool RebelManager::add_rebel_type(
return rebel_types.add_item({
new_identifier, icon, area, break_alliance_on_win, std::move(desired_governments), defection, independence,
defect_delay, ideology, allow_all_cultures, allow_all_culture_groups, allow_all_religions, allow_all_ideologies,
- resilient, reinforcing, general, smart, unit_transfer, occupation_mult
+ resilient, reinforcing, general, smart, unit_transfer, occupation_mult, std::move(will_rise), std::move(spawn_chance),
+ std::move(movement_evaluation), std::move(siege_won_trigger), std::move(siege_won_effect),
+ std::move(demands_enforced_trigger), std::move(demands_enforced_effect)
});
}
@@ -81,6 +104,9 @@ bool RebelManager::load_rebels_file(
allow_all_religions = true, allow_all_ideologies = true, resilient = true, reinforcing = true, general = true,
smart = true, unit_transfer = false;
fixed_point_t occupation_mult = 0;
+ ConditionalWeight will_rise, spawn_chance, movement_evaluation;
+ ConditionScript siege_won_trigger, demands_enforced_trigger;
+ EffectScript siege_won_effect, demands_enforced_effect;
bool ret = expect_dictionary_keys(
"icon", ONE_EXACTLY, expect_uint(assign_variable_callback(icon)),
@@ -118,19 +144,21 @@ bool RebelManager::load_rebels_file(
"smart", ONE_EXACTLY, expect_bool(assign_variable_callback(smart)),
"unit_transfer", ONE_EXACTLY, expect_bool(assign_variable_callback(unit_transfer)),
"occupation_mult", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(occupation_mult)),
- "will_rise", ONE_EXACTLY, success_callback, //TODO
- "spawn_chance", ONE_EXACTLY, success_callback, //TODO
- "movement_evaluation", ONE_EXACTLY, success_callback, //TODO
- "siege_won_trigger", ZERO_OR_ONE, success_callback, //TODO
- "siege_won_effect", ZERO_OR_ONE, success_callback, //TODO
- "demands_enforced_trigger", ZERO_OR_ONE, success_callback, //TODO
- "demands_enforced_effect", ZERO_OR_ONE, success_callback //TODO
+ "will_rise", ONE_EXACTLY, will_rise.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "spawn_chance", ONE_EXACTLY, spawn_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "movement_evaluation", ONE_EXACTLY, movement_evaluation.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "siege_won_trigger", ZERO_OR_ONE, siege_won_trigger.expect_script(),
+ "siege_won_effect", ZERO_OR_ONE, siege_won_effect.expect_script(),
+ "demands_enforced_trigger", ZERO_OR_ONE, demands_enforced_trigger.expect_script(),
+ "demands_enforced_effect", ZERO_OR_ONE, demands_enforced_effect.expect_script()
)(node);
ret &= add_rebel_type(
identifier, icon, area, break_alliance_on_win, std::move(desired_governments), defection, independence,
defect_delay, ideology, allow_all_cultures, allow_all_culture_groups, allow_all_religions,
- allow_all_ideologies, resilient, reinforcing, general, smart, unit_transfer, occupation_mult
+ allow_all_ideologies, resilient, reinforcing, general, smart, unit_transfer, occupation_mult,
+ std::move(will_rise), std::move(spawn_chance), std::move(movement_evaluation), std::move(siege_won_trigger),
+ std::move(siege_won_effect), std::move(demands_enforced_trigger), std::move(demands_enforced_effect)
);
return ret;
@@ -155,4 +183,12 @@ bool RebelManager::generate_modifiers(ModifierManager& modifier_manager) const {
);
}
return ret;
-} \ No newline at end of file
+}
+
+bool RebelManager::parse_scripts(GameManager& game_manager) {
+ bool ret = true;
+ for (RebelType& rebel_type : rebel_types.get_items()) {
+ ret &= rebel_type.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/politics/Rebel.hpp b/src/openvic-simulation/politics/Rebel.hpp
index f7e8795..f098fe0 100644
--- a/src/openvic-simulation/politics/Rebel.hpp
+++ b/src/openvic-simulation/politics/Rebel.hpp
@@ -5,6 +5,8 @@
#include "openvic-simulation/misc/Modifier.hpp"
#include "openvic-simulation/politics/Government.hpp"
#include "openvic-simulation/politics/Ideology.hpp"
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
+#include "openvic-simulation/scripts/EffectScript.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
@@ -51,15 +53,28 @@ namespace OpenVic {
const bool PROPERTY_CUSTOM_PREFIX(smart, is);
const bool PROPERTY_CUSTOM_NAME(unit_transfer, will_transfer_units);
const fixed_point_t PROPERTY(occupation_mult);
+ ConditionalWeight PROPERTY(will_rise);
+ ConditionalWeight PROPERTY(spawn_chance);
+ ConditionalWeight PROPERTY(movement_evaluation);
+ ConditionScript PROPERTY(siege_won_trigger);
+ EffectScript PROPERTY(siege_won_effect);
+ ConditionScript PROPERTY(demands_enforced_trigger);
+ EffectScript PROPERTY(demands_enforced_effect);
RebelType(
std::string_view new_identifier, RebelType::icon_t icon, RebelType::area_t area, bool break_alliance_on_win,
RebelType::government_map_t&& desired_governments, RebelType::defection_t defection,
RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures,
bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient,
- bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult
+ bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult,
+ ConditionalWeight&& new_will_rise, ConditionalWeight&& new_spawn_chance,
+ ConditionalWeight&& new_movement_evaluation, ConditionScript&& new_siege_won_trigger,
+ EffectScript&& new_siege_won_effect, ConditionScript&& new_demands_enforced_trigger,
+ EffectScript&& new_demands_enforced_effect
);
+ bool parse_scripts(GameManager& game_manager);
+
public:
RebelType(RebelType&&) = default;
};
@@ -74,10 +89,15 @@ namespace OpenVic {
RebelType::government_map_t&& desired_governments, RebelType::defection_t defection,
RebelType::independence_t independence, uint16_t defect_delay, Ideology const* ideology, bool allow_all_cultures,
bool allow_all_culture_groups, bool allow_all_religions, bool allow_all_ideologies, bool resilient,
- bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult
+ bool reinforcing, bool general, bool smart, bool unit_transfer, fixed_point_t occupation_mult,
+ ConditionalWeight&& will_rise, ConditionalWeight&& spawn_chance, ConditionalWeight&& movement_evaluation,
+ ConditionScript&& siege_won_trigger, EffectScript&& siege_won_effect, ConditionScript&& demands_enforced_trigger,
+ EffectScript&& demands_enforced_effect
);
bool load_rebels_file(IdeologyManager const& ideology_manager, GovernmentTypeManager const& government_type_manager, ast::NodeCPtr root);
bool generate_modifiers(ModifierManager& modifier_manager) const;
+
+ bool parse_scripts(GameManager& game_manager);
};
} \ No newline at end of file
diff --git a/src/openvic-simulation/pop/Pop.cpp b/src/openvic-simulation/pop/Pop.cpp
index 2b031c2..be664d5 100644
--- a/src/openvic-simulation/pop/Pop.cpp
+++ b/src/openvic-simulation/pop/Pop.cpp
@@ -4,9 +4,12 @@
#include "openvic-simulation/dataloader/NodeTools.hpp"
#include "openvic-simulation/map/Province.hpp"
+#include "openvic-simulation/politics/Ideology.hpp"
+#include "openvic-simulation/politics/Issue.hpp"
#include "openvic-simulation/politics/Rebel.hpp"
#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/utility/Logger.hpp"
+#include "openvic-simulation/utility/TslHelper.hpp"
using namespace OpenVic;
using namespace OpenVic::NodeTools;
@@ -32,7 +35,9 @@ PopType::PopType(
rebel_units_t&& new_rebel_units, Pop::pop_size_t new_max_size, Pop::pop_size_t new_merge_max_size,
bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote, bool new_is_slave,
bool new_can_be_recruited, bool new_can_reduce_consciousness, bool new_administrative_efficiency, bool new_can_build,
- bool new_factory, bool new_can_work_factory, bool new_unemployment
+ bool new_factory, bool new_can_work_factory, bool new_unemployment, ConditionalWeight&& new_country_migration_target,
+ ConditionalWeight&& new_migration_target, poptype_weight_map_t&& new_promote_to, ideology_weight_map_t&& new_ideologies,
+ issue_weight_map_t&& new_issues
) : HasIdentifierAndColour { new_identifier, new_colour, false }, strata { new_strata }, sprite { new_sprite },
life_needs { std::move(new_life_needs) }, everyday_needs { std::move(new_everyday_needs) },
luxury_needs { std::move(new_luxury_needs) }, rebel_units { std::move(new_rebel_units) }, max_size { new_max_size },
@@ -41,12 +46,30 @@ PopType::PopType(
is_slave { new_is_slave }, can_be_recruited { new_can_be_recruited },
can_reduce_consciousness { new_can_reduce_consciousness }, administrative_efficiency { new_administrative_efficiency },
can_build { new_can_build }, factory { new_factory }, can_work_factory { new_can_work_factory },
- unemployment { new_unemployment } {
+ unemployment { new_unemployment }, country_migration_target { std::move(new_country_migration_target) },
+ migration_target { std::move(new_migration_target) }, promote_to { std::move(new_promote_to) },
+ ideologies { std::move(new_ideologies) }, issues { std::move(new_issues) } {
assert(sprite > 0);
assert(max_size >= 0);
assert(merge_max_size >= 0);
}
+bool PopType::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ ret &= country_migration_target.parse_scripts(game_manager);
+ ret &= migration_target.parse_scripts(game_manager);
+ for (auto [pop_type, weight] : mutable_iterator(promote_to)) {
+ ret &= weight.parse_scripts(game_manager);
+ }
+ for (auto [ideology, weight] : mutable_iterator(ideologies)) {
+ ret &= weight.parse_scripts(game_manager);
+ }
+ for (auto [issue, weight] : mutable_iterator(issues)) {
+ ret &= weight.parse_scripts(game_manager);
+ }
+ return ret;
+}
+
PopManager::PopManager() : slave_sprite { 0 }, administrative_sprite { 0 } {}
bool PopManager::add_strata(std::string_view identifier) {
@@ -63,7 +86,8 @@ bool PopManager::add_pop_type(
PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size, bool state_capital_only,
bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave, bool can_be_recruited,
bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory, bool can_work_factory,
- bool unemployment
+ bool unemployment, ConditionalWeight&& country_migration_target, ConditionalWeight&& migration_target,
+ ast::NodeCPtr promote_to_node, PopType::ideology_weight_map_t&& ideologies, ast::NodeCPtr issues_node
) {
if (identifier.empty()) {
Logger::error("Invalid pop type identifier - empty!");
@@ -89,8 +113,12 @@ bool PopManager::add_pop_type(
identifier, colour, *strata, sprite, std::move(life_needs), std::move(everyday_needs),
std::move(luxury_needs), std::move(rebel_units), max_size, merge_max_size, state_capital_only,
demote_migrant, is_artisan, allowed_to_vote, is_slave, can_be_recruited, can_reduce_consciousness,
- administrative_efficiency, can_build, factory, can_work_factory, unemployment
+ administrative_efficiency, can_build, factory, can_work_factory, unemployment, std::move(country_migration_target),
+ std::move(migration_target), {}, std::move(ideologies), {}
});
+ if (ret) {
+ delayed_parse_promote_to_and_issues_nodes.emplace_back(promote_to_node, issues_node);
+ }
if (slave_sprite <= 0 && ret && is_slave) {
/* Set slave sprite to that of the first is_slave pop type we find. */
slave_sprite = sprite;
@@ -111,7 +139,8 @@ void PopManager::reserve_pop_types(size_t count) {
* POP-3, POP-4, POP-5, POP-6, POP-7, POP-8, POP-9, POP-10, POP-11, POP-12, POP-13, POP-14
*/
bool PopManager::load_pop_type_file(
- std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager, ast::NodeCPtr root
+ std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager,
+ IdeologyManager const& ideology_manager, ast::NodeCPtr root
) {
colour_t colour = colour_t::null();
Strata const* strata = nullptr;
@@ -122,6 +151,11 @@ bool PopManager::load_pop_type_file(
can_be_recruited = false, can_reduce_consciousness = false, administrative_efficiency = false, can_build = false,
factory = false, can_work_factory = false, unemployment = false;
Pop::pop_size_t max_size = 0, merge_max_size = 0;
+ ConditionalWeight country_migration_target, migration_target;
+ ast::NodeCPtr promote_to_node = nullptr;
+ PopType::ideology_weight_map_t ideologies;
+ ast::NodeCPtr issues_node = nullptr;
+
bool ret = expect_dictionary_keys(
"sprite", ONE_EXACTLY, expect_uint(assign_variable_callback(sprite)),
"color", ONE_EXACTLY, expect_colour(assign_variable_callback(colour)),
@@ -157,11 +191,21 @@ bool PopManager::load_pop_type_file(
"luxury_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(luxury_needs)),
"everyday_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(everyday_needs)),
"life_needs", ZERO_OR_ONE, good_manager.expect_good_decimal_map(move_variable_callback(life_needs)),
- "country_migration_target", ZERO_OR_ONE, success_callback, // TODO - pop migration weight scripts
- "migration_target", ZERO_OR_ONE, success_callback,
- "promote_to", ZERO_OR_ONE, success_callback, // TODO - pop promotion weight scripts
- "ideologies", ZERO_OR_ONE, success_callback, // TODO - pop politics weight scripts
- "issues", ZERO_OR_ONE, success_callback,
+ "country_migration_target", ZERO_OR_ONE, country_migration_target.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "migration_target", ZERO_OR_ONE, migration_target.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "promote_to", ZERO_OR_ONE, assign_variable_callback(promote_to_node),
+ "ideologies", ZERO_OR_ONE, ideology_manager.expect_ideology_dictionary(
+ [&filestem, &ideologies](Ideology const& ideology, ast::NodeCPtr node) -> bool {
+ ConditionalWeight weight;
+ bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node);
+ if (!ideologies.emplace(&ideology, std::move(weight)).second) {
+ Logger::error("Duplicate ideology in pop type ", filestem, " ideology weights: ", ideology);
+ ret = false;
+ }
+ return ret;
+ }
+ ),
+ "issues", ZERO_OR_ONE, assign_variable_callback(issues_node),
"demote_migrant", ZERO_OR_ONE, expect_bool(assign_variable_callback(demote_migrant)),
"administrative_efficiency", ZERO_OR_ONE, expect_bool(assign_variable_callback(administrative_efficiency)),
"tax_eff", ZERO_OR_ONE, success_callback, // TODO - tax collection modifier
@@ -178,11 +222,74 @@ bool PopManager::load_pop_type_file(
filestem, colour, strata, sprite, std::move(life_needs), std::move(everyday_needs), std::move(luxury_needs),
std::move(rebel_units), max_size, merge_max_size, state_capital_only, demote_migrant, is_artisan, allowed_to_vote,
is_slave, can_be_recruited, can_reduce_consciousness, administrative_efficiency, can_build, factory, can_work_factory,
- unemployment
+ unemployment, std::move(country_migration_target), std::move(migration_target), promote_to_node, std::move(ideologies),
+ issues_node
);
return ret;
}
+bool PopManager::load_delayed_parse_pop_type_data(IssueManager const& issue_manager) {
+ bool ret = true;
+ for (size_t index = 0; index < delayed_parse_promote_to_and_issues_nodes.size(); ++index) {
+ const auto [promote_to_node, issues_node] = delayed_parse_promote_to_and_issues_nodes[index];
+ PopType* pop_type = pop_types.get_item_by_index(index);
+ if (promote_to_node != nullptr && !expect_pop_type_dictionary(
+ [pop_type](PopType const& type, ast::NodeCPtr node) -> bool {
+ if (pop_type == &type) {
+ Logger::error("Pop type ", type, " cannot have promotion weight to itself!");
+ return false;
+ }
+ ConditionalWeight weight;
+ bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node);
+ if (!pop_type->promote_to.emplace(&type, std::move(weight)).second) {
+ Logger::error("Duplicate pop type in pop type ", pop_type, " promotion weights: ", type);
+ ret = false;
+ }
+ return ret;
+ }
+ )(promote_to_node)) {
+ Logger::error("Errors parsing pop type ", pop_type, " promotion weights!");
+ ret = false;
+ }
+ if (issues_node != nullptr && !expect_dictionary(
+ [pop_type, &issue_manager](std::string_view key, ast::NodeCPtr node) -> bool {
+ Issue const* issue = issue_manager.get_issue_by_identifier(key);
+ if (issue == nullptr) {
+ issue = issue_manager.get_reform_by_identifier(key);
+ }
+ if (issue == nullptr) {
+ Logger::error("Invalid issue in pop type ", pop_type, " issue weights: ", key);
+ return false;
+ }
+ ConditionalWeight weight;
+ bool ret = weight.expect_conditional_weight(ConditionalWeight::FACTOR)(node);
+ if (!pop_type->issues.emplace(issue, std::move(weight)).second) {
+ Logger::error("Duplicate issue in pop type ", pop_type, " issue weights: ", issue->get_identifier());
+ ret = false;
+ }
+ return ret;
+ }
+ )(issues_node)) {
+ Logger::error("Errors parsing pop type ", pop_type, " issue weights!");
+ ret = false;
+ }
+ }
+ delayed_parse_promote_to_and_issues_nodes.clear();
+ return ret;
+}
+
+bool PopManager::load_pop_type_chances_file(ast::NodeCPtr root) {
+ return expect_dictionary_keys(
+ "promotion_chance", ONE_EXACTLY, promotion_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "demotion_chance", ONE_EXACTLY, demotion_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "migration_chance", ONE_EXACTLY, migration_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "colonialmigration_chance", ONE_EXACTLY, colonialmigration_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "emigration_chance", ONE_EXACTLY, emigration_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "assimilation_chance", ONE_EXACTLY, assimilation_chance.expect_conditional_weight(ConditionalWeight::FACTOR),
+ "conversion_chance", ONE_EXACTLY, conversion_chance.expect_conditional_weight(ConditionalWeight::FACTOR)
+ )(root);
+}
+
bool PopManager::load_pop_into_vector(
RebelManager const& rebel_manager, std::vector<Pop>& vec, PopType const& type, ast::NodeCPtr pop_node,
bool *non_integer_size
@@ -235,3 +342,18 @@ bool PopManager::generate_modifiers(ModifierManager& modifier_manager) const {
}
return ret;
}
+
+bool PopManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (PopType& pop_type : pop_types.get_items()) {
+ ret &= pop_type.parse_scripts(game_manager);
+ }
+ ret &= promotion_chance.parse_scripts(game_manager);
+ ret &= demotion_chance.parse_scripts(game_manager);
+ ret &= migration_chance.parse_scripts(game_manager);
+ ret &= colonialmigration_chance.parse_scripts(game_manager);
+ ret &= emigration_chance.parse_scripts(game_manager);
+ ret &= assimilation_chance.parse_scripts(game_manager);
+ ret &= conversion_chance.parse_scripts(game_manager);
+ return ret;
+}
diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp
index 0c84aae..2304165 100644
--- a/src/openvic-simulation/pop/Pop.hpp
+++ b/src/openvic-simulation/pop/Pop.hpp
@@ -4,6 +4,7 @@
#include "openvic-simulation/military/Unit.hpp"
#include "openvic-simulation/pop/Culture.hpp"
#include "openvic-simulation/pop/Religion.hpp"
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
namespace OpenVic {
@@ -11,6 +12,10 @@ namespace OpenVic {
struct PopType;
struct RebelType;
struct RebelManager;
+ struct Ideology;
+ struct IdeologyManager;
+ struct Issue;
+ struct IssueManager;
/* REQUIREMENTS:
* POP-18, POP-19, POP-20, POP-21, POP-34, POP-35, POP-36, POP-37
@@ -65,14 +70,17 @@ namespace OpenVic {
using sprite_t = uint8_t;
using rebel_units_t = fixed_point_map_t<Unit const*>;
+ using poptype_weight_map_t = ordered_map<PopType const*, ConditionalWeight>;
+ using ideology_weight_map_t = ordered_map<Ideology const*, ConditionalWeight>;
+ using issue_weight_map_t = ordered_map<Issue const*, ConditionalWeight>;
private:
Strata const& PROPERTY(strata);
const sprite_t PROPERTY(sprite);
- const Good::good_map_t PROPERTY(life_needs);
- const Good::good_map_t PROPERTY(everyday_needs);
- const Good::good_map_t PROPERTY(luxury_needs);
- const rebel_units_t PROPERTY(rebel_units);
+ Good::good_map_t PROPERTY(life_needs);
+ Good::good_map_t PROPERTY(everyday_needs);
+ Good::good_map_t PROPERTY(luxury_needs);
+ rebel_units_t PROPERTY(rebel_units);
const Pop::pop_size_t PROPERTY(max_size);
const Pop::pop_size_t PROPERTY(merge_max_size);
const bool PROPERTY(state_capital_only);
@@ -88,7 +96,11 @@ namespace OpenVic {
const bool PROPERTY(can_work_factory);
const bool PROPERTY(unemployment);
- // TODO - country and province migration targets, promote_to targets, ideologies and issues
+ ConditionalWeight PROPERTY(country_migration_target); /* Scope - country, THIS - pop */
+ ConditionalWeight PROPERTY(migration_target); /* Scope - province, THIS - pop */
+ poptype_weight_map_t PROPERTY(promote_to); /* Scope - pop */
+ ideology_weight_map_t PROPERTY(ideologies); /* Scope - pop */
+ issue_weight_map_t PROPERTY(issues); /* Scope - province, THIS - country (?) */
PopType(
std::string_view new_identifier, colour_t new_colour, Strata const& new_strata, sprite_t new_sprite,
@@ -97,9 +109,12 @@ namespace OpenVic {
bool new_state_capital_only, bool new_demote_migrant, bool new_is_artisan, bool new_allowed_to_vote,
bool new_is_slave, bool new_can_be_recruited, bool new_can_reduce_consciousness,
bool new_administrative_efficiency, bool new_can_build, bool new_factory, bool new_can_work_factory,
- bool new_unemployment
+ bool new_unemployment, ConditionalWeight&& new_country_migration_target, ConditionalWeight&& new_migration_target,
+ poptype_weight_map_t&& new_promote_to, ideology_weight_map_t&& new_ideologies, issue_weight_map_t&& new_issues
);
+ bool parse_scripts(GameManager const& game_manager);
+
public:
PopType(PopType&&) = default;
};
@@ -111,6 +126,20 @@ namespace OpenVic {
/* Using strata/stratas instead of stratum/strata to avoid confusion. */
IdentifierRegistry<Strata> IDENTIFIER_REGISTRY(strata);
IdentifierRegistry<PopType> IDENTIFIER_REGISTRY(pop_type);
+ /* promote_to can't be parsed until after all PopTypes are registered, and issues requires Issues to be loaded,
+ * which themselves depend on pop strata. To get around this, the nodes for these variables are stored here and
+ * parsed after both PopTypes and Issues. The nodes will remain valid as PopType files' Parser objects are cached
+ * to preserve their condition script nodes until all other defines are loaded and the scripts can be parsed. */
+ std::vector<std::pair<ast::NodeCPtr, ast::NodeCPtr>> delayed_parse_promote_to_and_issues_nodes;
+
+ ConditionalWeight PROPERTY(promotion_chance);
+ ConditionalWeight PROPERTY(demotion_chance);
+ ConditionalWeight PROPERTY(migration_chance);
+ ConditionalWeight PROPERTY(colonialmigration_chance);
+ ConditionalWeight PROPERTY(emigration_chance);
+ ConditionalWeight PROPERTY(assimilation_chance);
+ ConditionalWeight PROPERTY(conversion_chance);
+
PopType::sprite_t PROPERTY(slave_sprite);
PopType::sprite_t PROPERTY(administrative_sprite);
@@ -128,19 +157,28 @@ namespace OpenVic {
PopType::rebel_units_t&& rebel_units, Pop::pop_size_t max_size, Pop::pop_size_t merge_max_size,
bool state_capital_only, bool demote_migrant, bool is_artisan, bool allowed_to_vote, bool is_slave,
bool can_be_recruited, bool can_reduce_consciousness, bool administrative_efficiency, bool can_build, bool factory,
- bool can_work_factory, bool unemployment
+ bool can_work_factory, bool unemployment, ConditionalWeight&& country_migration_target,
+ ConditionalWeight&& migration_target, ast::NodeCPtr promote_to_node, PopType::ideology_weight_map_t&& ideologies,
+ ast::NodeCPtr issues_node
);
void reserve_pop_types(size_t count);
bool load_pop_type_file(
- std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager, ast::NodeCPtr root
+ std::string_view filestem, UnitManager const& unit_manager, GoodManager const& good_manager,
+ IdeologyManager const& ideology_manager, ast::NodeCPtr root
);
+ bool load_delayed_parse_pop_type_data(IssueManager const& issue_manager);
+
+ bool load_pop_type_chances_file(ast::NodeCPtr root);
+
bool load_pop_into_vector(
RebelManager const& rebel_manager, std::vector<Pop>& vec, PopType const& type, ast::NodeCPtr pop_node,
bool *non_integer_size
) const;
bool generate_modifiers(ModifierManager& modifier_manager) const;
+
+ bool parse_scripts(GameManager const& game_manager);
};
}
diff --git a/src/openvic-simulation/research/Invention.cpp b/src/openvic-simulation/research/Invention.cpp
index f9f3f7b..473b0b4 100644
--- a/src/openvic-simulation/research/Invention.cpp
+++ b/src/openvic-simulation/research/Invention.cpp
@@ -10,16 +10,23 @@ using namespace OpenVic::NodeTools;
Invention::Invention(
std::string_view new_identifier, ModifierValue&& new_values, bool new_news, unit_set_t&& new_activated_units,
building_set_t&& new_activated_buildings, crime_set_t&& new_enabled_crimes, bool new_unlock_gas_attack,
- bool new_unlock_gas_defence
+ bool new_unlock_gas_defence, ConditionScript&& new_limit, ConditionalWeight&& new_chance
) : Modifier { new_identifier, std::move(new_values), 0 }, news { new_news },
activated_units { std::move(new_activated_units) }, activated_buildings { std::move(new_activated_buildings) },
enabled_crimes { std::move(new_enabled_crimes) }, unlock_gas_attack { new_unlock_gas_attack },
- unlock_gas_defence { new_unlock_gas_defence } {} //TODO icon
+ unlock_gas_defence { new_unlock_gas_defence }, limit { std::move(new_limit) }, chance { std::move(new_chance) } {}
+
+bool Invention::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ ret &= limit.parse_script(false, game_manager);
+ ret &= chance.parse_scripts(game_manager);
+ return ret;
+}
bool InventionManager::add_invention(
std::string_view identifier, ModifierValue&& values, bool news, Invention::unit_set_t&& activated_units,
Invention::building_set_t&& activated_buildings, Invention::crime_set_t&& enabled_crimes,
- bool unlock_gas_attack, bool unlock_gas_defence
+ bool unlock_gas_attack, bool unlock_gas_defence, ConditionScript&& limit, ConditionalWeight&& chance
) {
if (identifier.empty()) {
Logger::error("Invalid invention identifier - empty!");
@@ -28,7 +35,7 @@ bool InventionManager::add_invention(
return inventions.add_item({
identifier, std::move(values), news, std::move(activated_units), std::move(activated_buildings),
- std::move(enabled_crimes), unlock_gas_attack, unlock_gas_defence
+ std::move(enabled_crimes), unlock_gas_attack, unlock_gas_defence, std::move(limit), std::move(chance)
});
}
@@ -50,10 +57,13 @@ bool InventionManager::load_inventions_file(
bool unlock_gas_defence = false;
bool news = true; //defaults to true!
+ ConditionScript limit;
+ ConditionalWeight chance;
+
bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(loose_modifiers),
"news", ZERO_OR_ONE, expect_bool(assign_variable_callback(news)),
- "limit", ONE_EXACTLY, success_callback,
- "chance", ONE_EXACTLY, success_callback,
+ "limit", ONE_EXACTLY, limit.expect_script(),
+ "chance", ONE_EXACTLY, chance.expect_conditional_weight(ConditionalWeight::BASE),
"effect", ZERO_OR_ONE, modifier_manager.expect_modifier_value_and_keys(
move_variable_callback(modifiers),
"gas_attack", ZERO_OR_ONE, expect_bool(assign_variable_callback(unlock_gas_attack)),
@@ -72,10 +82,18 @@ bool InventionManager::load_inventions_file(
ret &= add_invention(
identifier, std::move(modifiers), news, std::move(activated_units), std::move(activated_buildings),
- std::move(enabled_crimes), unlock_gas_attack, unlock_gas_defence
+ std::move(enabled_crimes), unlock_gas_attack, unlock_gas_defence, std::move(limit), std::move(chance)
);
return ret;
}
)(root);
-} \ No newline at end of file
+}
+
+bool InventionManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (Invention& invention : inventions.get_items()) {
+ ret &= invention.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/research/Invention.hpp b/src/openvic-simulation/research/Invention.hpp
index 5d31155..2b8100d 100644
--- a/src/openvic-simulation/research/Invention.hpp
+++ b/src/openvic-simulation/research/Invention.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "openvic-simulation/misc/Modifier.hpp"
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
#include "openvic-simulation/types/IdentifierRegistry.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
@@ -27,13 +28,17 @@ namespace OpenVic {
crime_set_t PROPERTY(enabled_crimes);
const bool PROPERTY_CUSTOM_PREFIX(unlock_gas_attack, will);
const bool PROPERTY_CUSTOM_PREFIX(unlock_gas_defence, will);
+ ConditionScript PROPERTY(limit);
+ ConditionalWeight PROPERTY(chance);
Invention(
std::string_view new_identifier, ModifierValue&& new_values, bool new_news, unit_set_t&& new_activated_units,
building_set_t&& new_activated_buildings, crime_set_t&& new_enabled_crimes, bool new_unlock_gas_attack,
- bool new_unlock_gas_defence
+ bool new_unlock_gas_defence, ConditionScript&& new_limit, ConditionalWeight&& new_chance
);
+ bool parse_scripts(GameManager const& game_manager);
+
public:
Invention(Invention&&) = default;
};
@@ -45,12 +50,14 @@ namespace OpenVic {
bool add_invention(
std::string_view identifier, ModifierValue&& values, bool news, Invention::unit_set_t&& activated_units,
Invention::building_set_t&& activated_buildings, Invention::crime_set_t&& enabled_crimes, bool unlock_gas_attack,
- bool unlock_gas_defence
+ bool unlock_gas_defence, ConditionScript&& limit, ConditionalWeight&& chance
);
bool load_inventions_file(
ModifierManager const& modifier_manager, UnitManager const& unit_manager,
BuildingTypeManager const& building_type_manager, CrimeManager const& crime_manager, ast::NodeCPtr root
); // inventions/*.txt
+
+ bool parse_scripts(GameManager const& game_manager);
};
} \ No newline at end of file
diff --git a/src/openvic-simulation/research/Technology.cpp b/src/openvic-simulation/research/Technology.cpp
index 7851707..b151f1a 100644
--- a/src/openvic-simulation/research/Technology.cpp
+++ b/src/openvic-simulation/research/Technology.cpp
@@ -11,10 +11,14 @@ TechnologyArea::TechnologyArea(std::string_view new_identifier, TechnologyFolder
Technology::Technology(
std::string_view new_identifier, TechnologyArea const& new_area, Date::year_t new_year, fixed_point_t new_cost,
bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units, building_set_t&& new_activated_buildings,
- ModifierValue&& new_values
+ ModifierValue&& new_values, ConditionalWeight&& new_ai_chance
) : Modifier { new_identifier, std::move(new_values), 0 }, area { new_area }, year { new_year }, cost { new_cost },
unciv_military { new_unciv_military }, unit { new_unit }, activated_buildings { std::move(new_activated_units) },
- activated_units { std::move(new_activated_buildings) } {}
+ activated_units { std::move(new_activated_buildings) }, ai_chance { std::move(new_ai_chance) } {}
+
+bool Technology::parse_scripts(GameManager const& game_manager) {
+ return ai_chance.parse_scripts(game_manager);
+}
TechnologySchool::TechnologySchool(std::string_view new_identifier, ModifierValue&& new_values)
: Modifier { new_identifier, std::move(new_values), 0 } {}
@@ -45,7 +49,7 @@ bool TechnologyManager::add_technology_area(std::string_view identifier, Technol
bool TechnologyManager::add_technology(
std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost, bool unciv_military,
uint8_t unit, Technology::unit_set_t&& activated_units, Technology::building_set_t&& activated_buildings,
- ModifierValue&& values
+ ModifierValue&& values, ConditionalWeight&& ai_chance
) {
if (identifier.empty()) {
Logger::error("Invalid technology identifier - empty!");
@@ -59,7 +63,7 @@ bool TechnologyManager::add_technology(
return technologies.add_item({
identifier, *area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings),
- std::move(values)
+ std::move(values), std::move(ai_chance)
});
}
@@ -87,8 +91,9 @@ bool TechnologyManager::load_technology_file_areas(ast::NodeCPtr root) {
})(root_value);
lock_technology_folders();
lock_technology_areas();
- } else if (root_key == "schools") return true; //ignore
- else return false;
+ } else {
+ return root_key == "schools"; /* Ignore schools, error otherwise */
+ }
})(root);
}
@@ -102,8 +107,9 @@ bool TechnologyManager::load_technology_file_schools(ModifierManager const& modi
return ret;
})(root_value);
lock_technology_schools();
- } else if (root_key == "folders") return true; //ignore
- else return false;
+ } else {
+ return root_key == "folders"; /* Ignore folders, error otherwise */
+ }
})(root);
}
@@ -121,6 +127,7 @@ bool TechnologyManager::load_technologies_file(
uint8_t unit = 0;
Technology::unit_set_t activated_units;
Technology::building_set_t activated_buildings;
+ ConditionalWeight ai_chance;
bool ret = modifier_manager.expect_modifier_value_and_keys(move_variable_callback(modifiers),
"area", ONE_EXACTLY, expect_technology_area_identifier(assign_variable_callback_pointer(area)),
@@ -132,12 +139,12 @@ bool TechnologyManager::load_technologies_file(
"activate_building", ZERO_OR_MORE, building_type_manager.expect_building_type_identifier(
set_callback_pointer(activated_buildings)
),
- "ai_chance", ONE_EXACTLY, success_callback //TODO
+ "ai_chance", ONE_EXACTLY, ai_chance.expect_conditional_weight(ConditionalWeight::FACTOR)
)(tech_value);
ret &= add_technology(
tech_key, area, year, cost, unciv_military, unit, std::move(activated_units), std::move(activated_buildings),
- std::move(modifiers)
+ std::move(modifiers), std::move(ai_chance)
);
return ret;
})(root);
@@ -162,3 +169,11 @@ bool TechnologyManager::generate_modifiers(ModifierManager& modifier_manager) co
return ret;
}
+
+bool TechnologyManager::parse_scripts(GameManager const& game_manager) {
+ bool ret = true;
+ for (Technology& technology : technologies.get_items()) {
+ ret &= technology.parse_scripts(game_manager);
+ }
+ return ret;
+}
diff --git a/src/openvic-simulation/research/Technology.hpp b/src/openvic-simulation/research/Technology.hpp
index 3b0b1da..a4287a5 100644
--- a/src/openvic-simulation/research/Technology.hpp
+++ b/src/openvic-simulation/research/Technology.hpp
@@ -5,6 +5,7 @@
#include "openvic-simulation/economy/BuildingType.hpp"
#include "openvic-simulation/military/Unit.hpp"
#include "openvic-simulation/misc/Modifier.hpp"
+#include "openvic-simulation/scripts/ConditionalWeight.hpp"
#include "openvic-simulation/types/Date.hpp"
#include "openvic-simulation/types/OrderedContainers.hpp"
@@ -43,17 +44,18 @@ namespace OpenVic {
const fixed_point_t PROPERTY(cost);
const bool PROPERTY(unciv_military);
const uint8_t PROPERTY(unit);
- const unit_set_t PROPERTY(activated_buildings);
- const building_set_t PROPERTY(activated_units);
-
- //TODO: implement rules/modifiers and ai_chance
+ unit_set_t PROPERTY(activated_buildings);
+ building_set_t PROPERTY(activated_units);
+ ConditionalWeight PROPERTY(ai_chance);
Technology(
std::string_view new_identifier, TechnologyArea const& new_area, Date::year_t new_year, fixed_point_t new_cost,
bool new_unciv_military, uint8_t new_unit, unit_set_t&& new_activated_units,
- building_set_t&& new_activated_buildings, ModifierValue&& new_values
+ building_set_t&& new_activated_buildings, ModifierValue&& new_values, ConditionalWeight&& new_ai_chance
);
+ bool parse_scripts(GameManager const& game_manager);
+
public:
Technology(Technology&&) = default;
};
@@ -79,7 +81,8 @@ namespace OpenVic {
bool add_technology(
std::string_view identifier, TechnologyArea const* area, Date::year_t year, fixed_point_t cost,
bool unciv_military, uint8_t unit, Technology::unit_set_t&& activated_units,
- Technology::building_set_t&& activated_buildings, ModifierValue&& values);
+ Technology::building_set_t&& activated_buildings, ModifierValue&& values, ConditionalWeight&& ai_chance
+ );
bool add_technology_school(std::string_view identifier, ModifierValue&& values);
@@ -90,5 +93,7 @@ namespace OpenVic {
BuildingTypeManager const& building_type_manager, ast::NodeCPtr root
); // technologies/*.txt
bool generate_modifiers(ModifierManager& modifier_manager) const;
+
+ bool parse_scripts(GameManager const& game_manager);
};
} \ No newline at end of file
diff --git a/src/openvic-simulation/scripts/ConditionScript.cpp b/src/openvic-simulation/scripts/ConditionScript.cpp
new file mode 100644
index 0000000..af2faf7
--- /dev/null
+++ b/src/openvic-simulation/scripts/ConditionScript.cpp
@@ -0,0 +1,8 @@
+#include "ConditionScript.hpp"
+
+using namespace OpenVic;
+
+bool ConditionScript::_parse_script(ast::NodeCPtr root, GameManager const& game_manager) {
+ // TODO - parse condition script
+ return true;
+}
diff --git a/src/openvic-simulation/scripts/ConditionScript.hpp b/src/openvic-simulation/scripts/ConditionScript.hpp
new file mode 100644
index 0000000..cb967a2
--- /dev/null
+++ b/src/openvic-simulation/scripts/ConditionScript.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "openvic-simulation/scripts/Script.hpp"
+
+namespace OpenVic {
+ struct GameManager;
+
+ struct ConditionScript final : Script<GameManager const&> {
+ protected:
+ bool _parse_script(ast::NodeCPtr root, GameManager const& game_manager) override;
+ };
+}
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.cpp b/src/openvic-simulation/scripts/ConditionalWeight.cpp
new file mode 100644
index 0000000..29dc93b
--- /dev/null
+++ b/src/openvic-simulation/scripts/ConditionalWeight.cpp
@@ -0,0 +1,64 @@
+#include "ConditionalWeight.hpp"
+
+using namespace OpenVic;
+using namespace OpenVic::NodeTools;
+
+template<typename T>
+static NodeCallback auto expect_modifier(std::vector<T>& items) {
+ return [&items](ast::NodeCPtr node) -> bool {
+ fixed_point_t weight = 0;
+ bool successful = false;
+ bool ret = expect_key("factor", expect_fixed_point(assign_variable_callback(weight)), &successful)(node);
+ if (!successful) {
+ Logger::info("ConditionalWeight modifier missing factor key!");
+ return false;
+ }
+ ConditionScript condition;
+ ret &= condition.expect_script()(node);
+ items.emplace_back(std::make_pair(weight, std::move(condition)));
+ return ret;
+ };
+}
+
+node_callback_t ConditionalWeight::expect_conditional_weight(base_key_t base_key) {
+ return expect_dictionary_keys(
+ // TODO - add days and years as options with a shared expected count of ONE_EXACTLY
+ base_key_to_string(base_key), ONE_EXACTLY, expect_fixed_point(assign_variable_callback(base)),
+ "modifier", ZERO_OR_MORE, expect_modifier(condition_weight_items),
+ "group", ZERO_OR_MORE, [this](ast::NodeCPtr node) -> bool {
+ condition_weight_group_t items;
+ const bool ret = expect_dictionary_keys(
+ "modifier", ONE_OR_MORE, expect_modifier(items)
+ )(node);
+ if (!items.empty()) {
+ condition_weight_items.emplace_back(std::move(items));
+ return ret;
+ }
+ Logger::error("ConditionalWeight group must have at least one modifier!");
+ return false;
+ }
+ );
+}
+
+struct ConditionalWeight::parse_scripts_visitor_t {
+ GameManager const& game_manager;
+
+ bool operator()(condition_weight_t& condition_weight) const {
+ return condition_weight.second.parse_script(false, game_manager);
+ }
+ bool operator()(condition_weight_item_t& item) const {
+ return std::visit(*this, item);
+ }
+ template<typename T>
+ bool operator()(std::vector<T>& items) const {
+ bool ret = true;
+ for (T& item : items) {
+ ret &= (*this)(item);
+ }
+ return ret;
+ }
+};
+
+bool ConditionalWeight::parse_scripts(GameManager const& game_manager) {
+ return parse_scripts_visitor_t { game_manager }(condition_weight_items);
+}
diff --git a/src/openvic-simulation/scripts/ConditionalWeight.hpp b/src/openvic-simulation/scripts/ConditionalWeight.hpp
new file mode 100644
index 0000000..a965ae1
--- /dev/null
+++ b/src/openvic-simulation/scripts/ConditionalWeight.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <variant>
+#include <vector>
+
+#include "openvic-simulation/dataloader/NodeTools.hpp"
+#include "openvic-simulation/scripts/ConditionScript.hpp"
+#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
+
+namespace OpenVic {
+ struct ConditionalWeight {
+ using condition_weight_t = std::pair<fixed_point_t, ConditionScript>;
+ using condition_weight_group_t = std::vector<condition_weight_t>;
+ using condition_weight_item_t = std::variant<condition_weight_t, condition_weight_group_t>;
+
+ enum class base_key_t : uint8_t {
+ BASE, FACTOR, MONTHS
+ };
+ using enum base_key_t;
+
+ private:
+ fixed_point_t PROPERTY(base);
+ std::vector<condition_weight_item_t> PROPERTY(condition_weight_items);
+
+ struct parse_scripts_visitor_t;
+
+ public:
+ ConditionalWeight() = default;
+ ConditionalWeight(ConditionalWeight&&) = default;
+
+ static constexpr std::string_view base_key_to_string(base_key_t base_key) {
+ switch (base_key) {
+ case base_key_t::BASE: return "base";
+ case base_key_t::FACTOR: return "factor";
+ case base_key_t::MONTHS: return "months"; // TODO - add functionality for days or months or years
+ default: return "INVALID BASE KEY";
+ }
+ }
+
+ NodeTools::node_callback_t expect_conditional_weight(base_key_t base_key);
+
+ bool parse_scripts(GameManager const& game_manager);
+ };
+}
diff --git a/src/openvic-simulation/scripts/EffectScript.cpp b/src/openvic-simulation/scripts/EffectScript.cpp
new file mode 100644
index 0000000..f51c053
--- /dev/null
+++ b/src/openvic-simulation/scripts/EffectScript.cpp
@@ -0,0 +1,8 @@
+#include "EffectScript.hpp"
+
+using namespace OpenVic;
+
+bool EffectScript::_parse_script(ast::NodeCPtr root, GameManager& game_manager) {
+ // TODO - parse effect script
+ return true;
+}
diff --git a/src/openvic-simulation/scripts/EffectScript.hpp b/src/openvic-simulation/scripts/EffectScript.hpp
new file mode 100644
index 0000000..f5acf78
--- /dev/null
+++ b/src/openvic-simulation/scripts/EffectScript.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "openvic-simulation/scripts/Script.hpp"
+
+namespace OpenVic {
+ struct GameManager;
+
+ struct EffectScript final : Script<GameManager&> {
+ protected:
+ bool _parse_script(ast::NodeCPtr root, GameManager& game_manager) override;
+ };
+}
diff --git a/src/openvic-simulation/scripts/Script.hpp b/src/openvic-simulation/scripts/Script.hpp
new file mode 100644
index 0000000..8efc277
--- /dev/null
+++ b/src/openvic-simulation/scripts/Script.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "openvic-simulation/dataloader/NodeTools.hpp"
+
+namespace OpenVic {
+ template<typename... _Context>
+ struct Script {
+ private:
+ ast::NodeCPtr _root;
+
+ protected:
+ virtual bool _parse_script(ast::NodeCPtr root, _Context... context) = 0;
+
+ public:
+ Script() : _root { nullptr } {}
+ Script(Script&&) = default;
+
+ constexpr bool has_defines_node() const {
+ return _root != nullptr;
+ }
+
+ constexpr NodeTools::NodeCallback auto expect_script() {
+ return NodeTools::assign_variable_callback(_root);
+ }
+
+ bool parse_script(bool can_be_null, _Context... context) {
+ if (_root == nullptr) {
+ if (!can_be_null) {
+ Logger::error("Null/missing script node!");
+ }
+ return can_be_null;
+ }
+ const bool ret = _parse_script(_root, context...);
+ _root = nullptr;
+ return ret;
+ }
+ };
+}
diff --git a/src/openvic-simulation/types/Colour.hpp b/src/openvic-simulation/types/Colour.hpp
index 38a1468..38c7b1e 100644
--- a/src/openvic-simulation/types/Colour.hpp
+++ b/src/openvic-simulation/types/Colour.hpp
@@ -3,15 +3,9 @@
#include <algorithm>
#include <array>
#include <cassert>
-#include <charconv>
#include <climits>
-#include <cmath>
-#include <compare>
#include <cstdint>
-#include <iomanip>
#include <limits>
-#include <span>
-#include <sstream>
#include <string>
#include <string_view>
#include <tuple>