diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation
index 34d32272..d1ee961a 160000
--- a/extension/deps/openvic-simulation
+++ b/extension/deps/openvic-simulation
@@ -1 +1 @@
-Subproject commit 34d3227224114e1c6ae56aeaab2550a14e5dff41
+Subproject commit d1ee961ab28bcd4f7388973b6cbcf1cb92fedc48
diff --git a/extension/doc_classes/GUIListBox.xml b/extension/doc_classes/GUIListBox.xml
index 608eb3f5..cdef05f2 100644
--- a/extension/doc_classes/GUIListBox.xml
+++ b/extension/doc_classes/GUIListBox.xml
@@ -73,6 +73,12 @@
+
+
+
+
+
+
diff --git a/extension/doc_classes/GameSingleton.xml b/extension/doc_classes/GameSingleton.xml
index ad0f53e2..f6ec7f46 100644
--- a/extension/doc_classes/GameSingleton.xml
+++ b/extension/doc_classes/GameSingleton.xml
@@ -119,24 +119,12 @@
Return a [Texture2DArray] containing all the textures that the province shape image was split into.
-
-
-
- Returns the [int] index of the currently selected province, or [code]0[/code] if there is no selected province.
-
-
Return a [Texture2DArray] containing all terrain textures, both the solid blue generated water texture and the loaded land terrain textures.
-
-
-
- Returns the viewed country's capital position as a normalized [Vector2], or [code](0.0, 0.0)[/code] if no country is being viewed.
-
-
@@ -177,20 +165,6 @@
Sets the active mapmode to that identified by [param index]. Returns [code]FAILED[/code] if the mapmode index is invalid, otherwise returns [code]OK[/code].
-
-
-
-
- Sets the currently selected province to that identified by [param index], or unselects the currently selected province if [param index] is [code]0[/code].
-
-
-
-
-
-
- Sets the viewed country to that which owns the province identified by [param province_index], or unsets the viewed country if the province has no owner/is uncolonised. Returns [code]FAILED[/code] if the [param province_index] is invalid, otherwise returns [code]OK[/code].
-
-
@@ -210,12 +184,6 @@
Sets up the simulation's clock and timestamps so that it can be unpaused, marking the move from the initialized but static game state used for the lobby to the dynamic game session that is ready to tick, update and simulate.
-
-
-
- Unselects the currently selected province, should there be one.
-
-
@@ -224,11 +192,6 @@
-
-
- Signal emitted when the simulation's clock changes state (paused vs unpaused, clock speed, etc.).
-
-
Signal emitted when the simulation's gamestate is updated (this happens after any event that changes the gamestate, e.g. a day tick, a player taking a decision, etc).
@@ -240,11 +203,5 @@
Signal emitted when the active mapmode changes, with the new mapmode's [param index] provided as a parameter.
-
-
-
- Signal emitted when the currently selected province changes, with the new province's [param index] provided as a parameter (or [code]0[/code] if there is no longer a selected province/the change was de-selecting a province).
-
-
diff --git a/extension/doc_classes/MenuSingleton.xml b/extension/doc_classes/MenuSingleton.xml
index b96d465d..fa2b08bd 100644
--- a/extension/doc_classes/MenuSingleton.xml
+++ b/extension/doc_classes/MenuSingleton.xml
@@ -7,24 +7,19 @@
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
@@ -191,11 +186,6 @@
-
-
-
-
-
@@ -248,12 +238,6 @@
-
-
-
-
-
-
@@ -270,11 +254,6 @@
-
-
-
-
-
diff --git a/extension/doc_classes/PlayerSingleton.xml b/extension/doc_classes/PlayerSingleton.xml
new file mode 100644
index 00000000..3f4f2aaa
--- /dev/null
+++ b/extension/doc_classes/PlayerSingleton.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extension/src/openvic-extension/classes/GUIListBox.cpp b/extension/src/openvic-extension/classes/GUIListBox.cpp
index 23da51f2..3b6a432d 100644
--- a/extension/src/openvic-extension/classes/GUIListBox.cpp
+++ b/extension/src/openvic-extension/classes/GUIListBox.cpp
@@ -116,6 +116,7 @@ void GUIListBox::_bind_methods() {
OV_BIND_METHOD(GUIListBox::get_gui_listbox_name);
OV_BIND_METHOD(GUIListBox::get_scrollbar);
+ OV_BIND_METHOD(GUIListBox::sort_children, { "callable" });
ADD_SIGNAL(MethodInfo(_signal_scroll_index_changed(), PropertyInfo(Variant::INT, "value")));
}
@@ -196,9 +197,12 @@ void GUIListBox::clear_children(int32_t remaining_child_count) {
child->queue_free();
}
- if (scrollbar != nullptr) {
- scrollbar->set_value(0);
- }
+ // TODO - reduce scroll level if it is now past the remaining children, but don't force it to 0 if the children it's
+ // viewing haven't been removed!
+
+ // if (scrollbar != nullptr) {
+ // scrollbar->set_value(0);
+ // }
}
void GUIListBox::set_scroll_index(int32_t new_scroll_index, bool signal) {
@@ -302,3 +306,24 @@ String GUIListBox::get_gui_listbox_name() const {
GUIScrollbar* GUIListBox::get_scrollbar() const {
return scrollbar;
}
+
+Error GUIListBox::sort_children(Callable const& callable) {
+ TypedArray children;
+ ERR_FAIL_COND_V(children.resize(get_child_count()) != OK, FAILED);
+
+ for (int64_t index = children.size() - 1; index >= 0; --index) {
+ Node* child = get_child(index);
+
+ children[index] = child;
+
+ remove_child(child);
+ }
+
+ children.sort_custom(callable);
+
+ for (int64_t index = 0; index < children.size(); ++index) {
+ add_child(Object::cast_to(children[index]));
+ }
+
+ return OK;
+}
diff --git a/extension/src/openvic-extension/classes/GUIListBox.hpp b/extension/src/openvic-extension/classes/GUIListBox.hpp
index a5c376e8..95f74607 100644
--- a/extension/src/openvic-extension/classes/GUIListBox.hpp
+++ b/extension/src/openvic-extension/classes/GUIListBox.hpp
@@ -57,5 +57,7 @@ namespace OpenVic {
godot::String get_gui_listbox_name() const;
GUIScrollbar* get_scrollbar() const;
+
+ godot::Error sort_children(godot::Callable const& callable);
};
}
diff --git a/extension/src/openvic-extension/classes/GUIScrollbar.cpp b/extension/src/openvic-extension/classes/GUIScrollbar.cpp
index f8d2e7b1..3c7ff747 100644
--- a/extension/src/openvic-extension/classes/GUIScrollbar.cpp
+++ b/extension/src/openvic-extension/classes/GUIScrollbar.cpp
@@ -426,13 +426,13 @@ Error GUIScrollbar::set_gui_scrollbar(GUI::Scrollbar const* new_gui_scrollbar) {
_calculate_rects();
- fixed_point_t step_size = gui_scrollbar->get_step_size();
+ step_size = gui_scrollbar->get_step_size();
if (step_size <= 0) {
UtilityFunctions::push_error(
"Invalid step size ", Utilities::fixed_point_to_string_dp(step_size, -1), " for GUIScrollbar ",
gui_scrollbar_name, " - not positive! Defaulting to 1."
);
- step_size = 1;
+ step_size = fixed_point_t::_1();
ret = false;
}
min_value = gui_scrollbar->get_min_value() / step_size;
diff --git a/extension/src/openvic-extension/classes/GUIScrollbar.hpp b/extension/src/openvic-extension/classes/GUIScrollbar.hpp
index beba50b5..df5ddf27 100644
--- a/extension/src/openvic-extension/classes/GUIScrollbar.hpp
+++ b/extension/src/openvic-extension/classes/GUIScrollbar.hpp
@@ -36,6 +36,7 @@ namespace OpenVic {
godot::Orientation PROPERTY(orientation, godot::HORIZONTAL);
real_t PROPERTY(length_override, 0.0);
+ fixed_point_t PROPERTY(step_size);
int32_t PROPERTY(value, 0);
int32_t PROPERTY(min_value, 0);
int32_t PROPERTY(max_value, 0);
diff --git a/extension/src/openvic-extension/register_types.cpp b/extension/src/openvic-extension/register_types.cpp
index c6c7649f..f1d80b31 100644
--- a/extension/src/openvic-extension/register_types.cpp
+++ b/extension/src/openvic-extension/register_types.cpp
@@ -30,6 +30,7 @@
#include "openvic-extension/singletons/MapItemSingleton.hpp"
#include "openvic-extension/singletons/MenuSingleton.hpp"
#include "openvic-extension/singletons/ModelSingleton.hpp"
+#include "openvic-extension/singletons/PlayerSingleton.hpp"
#include "openvic-extension/singletons/SoundSingleton.hpp"
using namespace godot;
@@ -44,6 +45,7 @@ static MenuSingleton* _menu_singleton = nullptr;
static ModelSingleton* _model_singleton = nullptr;
static AssetManager* _asset_manager_singleton = nullptr;
static SoundSingleton* _sound_singleton = nullptr;
+static PlayerSingleton* _player_singleton = nullptr;
void initialize_openvic_types(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
@@ -86,6 +88,10 @@ void initialize_openvic_types(ModuleInitializationLevel p_level) {
_sound_singleton = memnew(SoundSingleton);
Engine::get_singleton()->register_singleton("SoundSingleton", SoundSingleton::get_singleton());
+ ClassDB::register_class();
+ _player_singleton = memnew(PlayerSingleton);
+ Engine::get_singleton()->register_singleton("PlayerSingleton", PlayerSingleton::get_singleton());
+
ClassDB::register_class();
ClassDB::register_abstract_class();
@@ -151,6 +157,9 @@ void uninitialize_openvic_types(ModuleInitializationLevel p_level) {
Engine::get_singleton()->unregister_singleton("SoundSingleton");
memdelete(_sound_singleton);
+
+ Engine::get_singleton()->unregister_singleton("PlayerSingleton");
+ memdelete(_player_singleton);
}
extern "C" {
diff --git a/extension/src/openvic-extension/singletons/BudgetMenu.cpp b/extension/src/openvic-extension/singletons/BudgetMenu.cpp
new file mode 100644
index 00000000..418fe4a9
--- /dev/null
+++ b/extension/src/openvic-extension/singletons/BudgetMenu.cpp
@@ -0,0 +1,79 @@
+#include "MenuSingleton.hpp"
+
+using namespace OpenVic;
+using namespace godot;
+
+Dictionary MenuSingleton::get_budget_menu_setup_info() const {
+ static const StringName _key = "";
+
+ Dictionary dict;
+
+ return dict;
+}
+
+Dictionary MenuSingleton::get_budget_menu_info() const {
+ static const StringName tax_info_by_strata_key = "tax_info_by_strata";
+ // TODO - needs tooltip per pop type, or marker to disable their button and use tooltip: "there are no pops of this type"
+
+ // TODO - gold, total income
+ // TODO - national bank, total funds, total debt, interest, loans taken and given
+
+ static const StringName industrial_subsidies_key = "industrial_subsidies";
+ static const StringName industrial_subsidies_tooltip_key = "industrial_subsidies_tooltip";
+
+ static const StringName military_costs_key = "military_costs";
+ static const StringName military_costs_tooltip_key = "military_costs_tooltip";
+ static const StringName overseas_maintenance_key = "overseas_maintenance";
+ static const StringName overseas_maintenance_tooltip_key = "overseas_maintenance_tooltip";
+
+ static const StringName national_stockpile_today_key = "national_stockpile_today";
+ static const StringName national_stockpile_today_tooltip_key = "national_stockpile_today_tooltip";
+ static const StringName national_stockpile_tomorrow_key = "national_stockpile_tomorrow";
+ static const StringName national_stockpile_tomorrow_tooltip_key = "national_stockpile_tomorrow_tooltip";
+ static const StringName land_spending_slider_key = "land_spending_slider";
+ static const StringName land_spending_slider_tooltip_key = "land_spending_slider_tooltip";
+ static const StringName naval_spending_slider_key = "naval_spending_slider";
+ static const StringName naval_spending_slider_tooltip_key = "naval_spending_slider_tooltip";
+ static const StringName construction_spending_slider_key = "construction_spending_slider";
+ static const StringName construction_spending_slider_tooltip_key = "construction_spending_slider_tooltip";
+
+ // sliders may need tooltips for when they have custom min/max from modifiers!
+ static const StringName education_spending_slider_key = "education_spending_slider";
+ static const StringName education_spending_value_key = "education_spending_value";
+
+ static const StringName administrative_efficiency_key = "administrative_efficiency";
+ static const StringName administrative_efficiency_tooltip_key = "administrative_efficiency_tooltip";
+ static const StringName administration_spending_slider_key = "administration_spending_slider";
+ static const StringName administration_spending_value_key = "administration_spending_value";
+
+ static const StringName social_spending_slider_key = "social_spending_slider";
+ static const StringName social_spending_value_key = "social_spending_value";
+ static const StringName unemployment_subsidies_key = "unemployment_subsidies";
+ static const StringName pensions_key = "pensions";
+
+ static const StringName military_spending_slider_key = "military_spending_slider";
+ static const StringName military_spending_slider_tooltip_key = "military_spending_slider_tooltip";
+ static const StringName military_spending_value_key = "military_spending_value";
+ // double check these are hardcoded and not dynamic based on military pop types!
+ static const StringName officers_key = "officers";
+ static const StringName soldiers_key = "soldiers";
+
+ static const StringName total_expense_key = "total_expense";
+ static const StringName total_expense_tooltip_key = "total_expense_tooltip";
+
+ static const StringName tariff_slider_key = "tariff_slider";
+ static const StringName tariff_slider_tooltip_key = "tariff_slider_tooltip";
+ static const StringName tariff_value_key = "tariff_value";
+
+ // TODO - diplomatic balance, projected daily balance
+
+ // TODO - per strata
+ static const StringName tax_slider_pie_chart_key = "tax_slider_pie_chart";
+ static const StringName tax_slider_key = "tax_slider";
+
+ // slider data uses Vector3i (min, value, max)
+
+ Dictionary dict;
+
+ return dict;
+}
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index 37418c3a..4c927efd 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -10,6 +10,7 @@
#include "openvic-extension/singletons/AssetManager.hpp"
#include "openvic-extension/singletons/LoadLocalisation.hpp"
#include "openvic-extension/singletons/MenuSingleton.hpp"
+#include "openvic-extension/singletons/PlayerSingleton.hpp"
#include "openvic-extension/utility/ClassBindings.hpp"
#include "openvic-extension/utility/Utilities.hpp"
@@ -25,14 +26,6 @@ StringName const& GameSingleton::_signal_gamestate_updated() {
static const StringName signal_gamestate_updated = "gamestate_updated";
return signal_gamestate_updated;
}
-StringName const& GameSingleton::_signal_province_selected() {
- static const StringName signal_province_selected = "province_selected";
- return signal_province_selected;
-}
-StringName const& GameSingleton::_signal_clock_state_changed() {
- static const StringName signal_clock_state_changed = "clock_state_changed";
- return signal_clock_state_changed;
-}
StringName const& GameSingleton::_signal_mapmode_changed() {
static const StringName signal_mapmode_changed = "mapmode_changed";
return signal_mapmode_changed;
@@ -73,18 +66,10 @@ void GameSingleton::_bind_methods() {
OV_BIND_METHOD(GameSingleton::get_current_mapmode_index);
OV_BIND_METHOD(GameSingleton::set_mapmode, { "index" });
OV_BIND_METHOD(GameSingleton::is_parchment_mapmode_allowed);
- OV_BIND_METHOD(GameSingleton::get_selected_province_index);
- OV_BIND_METHOD(GameSingleton::set_selected_province, { "index" });
- OV_BIND_METHOD(GameSingleton::unset_selected_province);
-
- OV_BIND_METHOD(GameSingleton::set_viewed_country_by_province_index, { "province_index" });
- OV_BIND_METHOD(GameSingleton::get_viewed_country_capital_position);
OV_BIND_METHOD(GameSingleton::update_clock);
ADD_SIGNAL(MethodInfo(_signal_gamestate_updated()));
- ADD_SIGNAL(MethodInfo(_signal_province_selected(), PropertyInfo(Variant::INT, "index")));
- ADD_SIGNAL(MethodInfo(_signal_clock_state_changed()));
ADD_SIGNAL(MethodInfo(_signal_mapmode_changed(), PropertyInfo(Variant::INT, "index")));
}
@@ -97,16 +82,12 @@ void GameSingleton::_on_gamestate_updated() {
emit_signal(_signal_gamestate_updated());
}
-void GameSingleton::_on_clock_state_changed() {
- emit_signal(_signal_clock_state_changed());
-}
-
/* REQUIREMENTS:
* MAP-21, MAP-23, MAP-25, MAP-32, MAP-33, MAP-34
*/
GameSingleton::GameSingleton()
: game_manager {
- std::bind(&GameSingleton::_on_gamestate_updated, this), std::bind(&GameSingleton::_on_clock_state_changed, this)
+ std::bind(&GameSingleton::_on_gamestate_updated, this)
},
mapmode { &Mapmode::ERROR_MAPMODE } {
ERR_FAIL_COND(singleton != nullptr);
@@ -163,21 +144,20 @@ Error GameSingleton::setup_game(int32_t bookmark_index) {
for (ProvinceInstance& province : instance_manager->get_map_instance().get_province_instances()) {
province.set_crime(
get_definition_manager().get_crime_manager().get_crime_modifier_by_index(
- (province.get_province_definition().get_index() - 1)
- % get_definition_manager().get_crime_manager().get_crime_modifier_count()
+ (province.get_index() - 1) % get_definition_manager().get_crime_manager().get_crime_modifier_count()
)
);
}
- MenuSingleton* menu_singleton = MenuSingleton::get_singleton();
- ERR_FAIL_NULL_V(menu_singleton, FAILED);
- ret &= menu_singleton->_population_menu_update_provinces() == OK;
+ ret &= MenuSingleton::get_singleton()->_population_menu_update_provinces() == OK;
+
+ PlayerSingleton& player_singleton = *PlayerSingleton::get_singleton();
// TODO - replace with actual starting country
CountryInstance* starting_country =
instance_manager->get_country_instance_manager().get_country_instance_by_identifier("ENG");
- set_viewed_country(starting_country);
- ERR_FAIL_NULL_V(viewed_country, FAILED);
+ player_singleton.set_player_country(starting_country);
+ ERR_FAIL_NULL_V(player_singleton.get_player_country(), FAILED);
// TODO - remove this test starting research
for (
@@ -405,59 +385,6 @@ bool GameSingleton::is_parchment_mapmode_allowed() const {
return mapmode->is_parchment_mapmode_allowed();
}
-int32_t GameSingleton::get_selected_province_index() const {
- InstanceManager const* instance_manager = get_instance_manager();
- ERR_FAIL_NULL_V(instance_manager, 0);
-
- return instance_manager->get_map_instance().get_selected_province_index();
-}
-
-void GameSingleton::set_selected_province(int32_t index) {
- InstanceManager* instance_manager = get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- instance_manager->get_map_instance().set_selected_province(index);
- _update_colour_image();
- emit_signal(_signal_province_selected(), index);
-}
-
-void GameSingleton::unset_selected_province() {
- set_selected_province(ProvinceDefinition::NULL_INDEX);
-}
-
-void GameSingleton::set_viewed_country(CountryInstance const* new_viewed_country) {
- if (viewed_country != new_viewed_country) {
- viewed_country = new_viewed_country;
-
- Logger::info("Set viewed country to: ", viewed_country != nullptr ? viewed_country->get_identifier() : "NULL");
-
- _on_gamestate_updated();
- }
-}
-
-void GameSingleton::set_viewed_country_by_province_index(int32_t province_index) {
- InstanceManager* instance_manager = get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- ProvinceInstance const* province_instance =
- instance_manager->get_map_instance().get_province_instance_by_index(province_index);
- ERR_FAIL_NULL(province_instance);
-
- set_viewed_country(province_instance->get_owner());
-}
-
-Vector2 GameSingleton::get_viewed_country_capital_position() const {
- if (viewed_country != nullptr) {
- ProvinceInstance const* capital = viewed_country->get_capital();
-
- if (capital != nullptr) {
- return get_billboard_pos(capital->get_province_definition());
- }
- }
-
- return {};
-}
-
Error GameSingleton::update_clock() {
return ERR(game_manager.update_clock());
}
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.hpp b/extension/src/openvic-extension/singletons/GameSingleton.hpp
index 653d712b..c42a7e23 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.hpp
@@ -15,8 +15,6 @@ namespace OpenVic {
GameManager game_manager;
- CountryInstance const* PROPERTY(viewed_country, nullptr);
-
godot::Vector2i image_subdivisions;
godot::Ref province_shape_texture;
godot::Ref province_colour_image;
@@ -32,18 +30,16 @@ namespace OpenVic {
ordered_map flag_type_index_map;
static godot::StringName const& _signal_gamestate_updated();
- static godot::StringName const& _signal_province_selected();
- static godot::StringName const& _signal_clock_state_changed();
static godot::StringName const& _signal_mapmode_changed();
godot::Error _load_map_images();
godot::Error _load_terrain_variants();
godot::Error _load_flag_sheet();
+ public:
/* Generate the province_colour_texture from the current mapmode. */
godot::Error _update_colour_image();
void _on_gamestate_updated();
- void _on_clock_state_changed();
protected:
static void _bind_methods();
@@ -129,13 +125,6 @@ namespace OpenVic {
int32_t get_current_mapmode_index() const;
godot::Error set_mapmode(int32_t index);
bool is_parchment_mapmode_allowed() const;
- int32_t get_selected_province_index() const;
- void set_selected_province(int32_t index);
- void unset_selected_province();
-
- void set_viewed_country(CountryInstance const* new_viewed_country);
- void set_viewed_country_by_province_index(int32_t province_index);
- godot::Vector2 get_viewed_country_capital_position() const;
godot::Error update_clock();
};
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
index 20460979..ed1d04ba 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
@@ -9,6 +9,7 @@
#include "openvic-extension/classes/GFXPieChartTexture.hpp"
#include "openvic-extension/classes/GUINode.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
+#include "openvic-extension/singletons/PlayerSingleton.hpp"
#include "openvic-extension/utility/ClassBindings.hpp"
#include "openvic-extension/utility/Utilities.hpp"
@@ -263,16 +264,14 @@ String MenuSingleton::_make_rules_tooltip(RuleSet const& rules) const {
}
String MenuSingleton::_make_mobilisation_impact_tooltip() const {
- GameSingleton const* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL_V(game_singleton, {});
-
- CountryInstance const* country = game_singleton->get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
if (country == nullptr) {
return {};
}
- IssueManager const& issue_manager = game_singleton->get_definition_manager().get_politics_manager().get_issue_manager();
+ IssueManager const& issue_manager =
+ GameSingleton::get_singleton()->get_definition_manager().get_politics_manager().get_issue_manager();
static const StringName mobilisation_impact_tooltip_localisation_key = "MOBILIZATION_IMPACT_LIMIT_DESC";
static const String mobilisation_impact_tooltip_replace_impact_key = "$IMPACT$";
@@ -332,7 +331,6 @@ void MenuSingleton::_bind_methods() {
OV_BIND_METHOD(MenuSingleton::get_province_info_from_index, { "index" });
OV_BIND_METHOD(MenuSingleton::get_province_building_count);
OV_BIND_METHOD(MenuSingleton::get_province_building_identifier, { "building_index" });
- OV_BIND_METHOD(MenuSingleton::expand_selected_province_building, { "building_index" });
OV_BIND_METHOD(MenuSingleton::get_slave_pop_icon_index);
OV_BIND_METHOD(MenuSingleton::get_administrative_pop_icon_index);
OV_BIND_METHOD(MenuSingleton::get_rgo_owner_pop_icon_index);
@@ -341,16 +339,16 @@ void MenuSingleton::_bind_methods() {
OV_BIND_METHOD(MenuSingleton::get_topbar_info);
/* TIME/SPEED CONTROL PANEL */
- OV_BIND_METHOD(MenuSingleton::set_paused, { "paused" });
- OV_BIND_METHOD(MenuSingleton::toggle_paused);
OV_BIND_METHOD(MenuSingleton::is_paused);
- OV_BIND_METHOD(MenuSingleton::increase_speed);
- OV_BIND_METHOD(MenuSingleton::decrease_speed);
OV_BIND_METHOD(MenuSingleton::get_speed);
OV_BIND_METHOD(MenuSingleton::can_increase_speed);
OV_BIND_METHOD(MenuSingleton::can_decrease_speed);
OV_BIND_METHOD(MenuSingleton::get_longform_date);
+ /* BUDGET MENU */
+ OV_BIND_METHOD(MenuSingleton::get_budget_menu_setup_info);
+ OV_BIND_METHOD(MenuSingleton::get_budget_menu_info);
+
/* POPULATION MENU */
OV_BIND_METHOD(MenuSingleton::get_population_menu_province_list_row_count);
OV_BIND_METHOD(MenuSingleton::get_population_menu_province_list_rows, { "start", "count" });
@@ -408,6 +406,7 @@ void MenuSingleton::_bind_methods() {
OV_BIND_METHOD(MenuSingleton::get_trade_menu_good_categories_info);
OV_BIND_METHOD(MenuSingleton::get_trade_menu_trade_details_info, { "trade_detail_good_index" });
OV_BIND_METHOD(MenuSingleton::get_trade_menu_tables_info);
+ OV_BIND_SMETHOD(calculate_trade_menu_stockpile_cutoff_amount, { "slider" });
BIND_ENUM_CONSTANT(TRADE_SETTING_NONE);
BIND_ENUM_CONSTANT(TRADE_SETTING_AUTOMATED);
@@ -1065,19 +1064,6 @@ String MenuSingleton::get_province_building_identifier(int32_t building_index) c
return Utilities::std_to_godot_string(province_building_types[building_index]->get_identifier());
}
-Error MenuSingleton::expand_selected_province_building(int32_t building_index) {
- GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL_V(game_singleton, FAILED);
- InstanceManager* instance_manager = game_singleton->get_instance_manager();
- ERR_FAIL_NULL_V(instance_manager, FAILED);
-
- ERR_FAIL_COND_V_MSG(
- !instance_manager->expand_selected_province_building(building_index), FAILED,
- vformat("Failed to expand the currently selected province's building index %d", building_index)
- );
- return OK;
-}
-
int32_t MenuSingleton::get_slave_pop_icon_index() const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, 0);
@@ -1108,15 +1094,12 @@ int32_t MenuSingleton::get_rgo_owner_pop_icon_index() const {
/* TOPBAR */
Dictionary MenuSingleton::get_topbar_info() const {
- GameSingleton const* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL_V(game_singleton, {});
-
- CountryInstance const* country = game_singleton->get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
if (country == nullptr) {
return {};
}
- DefinitionManager const& definition_manager = game_singleton->get_definition_manager();
+ DefinitionManager const& definition_manager = GameSingleton::get_singleton()->get_definition_manager();
ModifierEffectCache const& modifier_effect_cache = definition_manager.get_modifier_manager().get_modifier_effect_cache();
Dictionary ret;
@@ -1467,24 +1450,6 @@ Dictionary MenuSingleton::get_topbar_info() const {
/* TIME/SPEED CONTROL PANEL */
-void MenuSingleton::set_paused(bool paused) {
- GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL(game_singleton);
- InstanceManager* instance_manager = game_singleton->get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- instance_manager->get_simulation_clock().set_paused(paused);
-}
-
-void MenuSingleton::toggle_paused() {
- GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL(game_singleton);
- InstanceManager* instance_manager = game_singleton->get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- instance_manager->get_simulation_clock().toggle_paused();
-}
-
bool MenuSingleton::is_paused() const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, true);
@@ -1494,24 +1459,6 @@ bool MenuSingleton::is_paused() const {
return instance_manager->get_simulation_clock().is_paused();
}
-void MenuSingleton::increase_speed() {
- GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL(game_singleton);
- InstanceManager* instance_manager = game_singleton->get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- instance_manager->get_simulation_clock().increase_simulation_speed();
-}
-
-void MenuSingleton::decrease_speed() {
- GameSingleton* game_singleton = GameSingleton::get_singleton();
- ERR_FAIL_NULL(game_singleton);
- InstanceManager* instance_manager = game_singleton->get_instance_manager();
- ERR_FAIL_NULL(instance_manager);
-
- instance_manager->get_simulation_clock().decrease_simulation_speed();
-}
-
int32_t MenuSingleton::get_speed() const {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, 0);
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
index 2623b2e8..034b963b 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
@@ -25,7 +25,8 @@ namespace OpenVic {
struct ModifierValue;
struct ModifierSum;
struct RuleSet;
- struct LeaderBase;
+ struct LeaderInstance;
+ struct GUIScrollbar;
class MenuSingleton : public godot::Object {
GDCLASS(MenuSingleton, godot::Object)
@@ -104,7 +105,7 @@ namespace OpenVic {
LEADER_SORT_NONE, LEADER_SORT_PRESTIGE, LEADER_SORT_TYPE, LEADER_SORT_NAME, LEADER_SORT_ASSIGNMENT,
MAX_LEADER_SORT_KEY
};
- ordered_map cached_leader_dicts;
+ ordered_map cached_leader_dicts;
enum UnitGroupSortKey {
UNIT_GROUP_SORT_NONE, UNIT_GROUP_SORT_NAME, UNIT_GROUP_SORT_STRENGTH, MAX_UNIT_GROUP_SORT_KEY
};
@@ -189,7 +190,6 @@ namespace OpenVic {
godot::Dictionary get_province_info_from_index(int32_t index) const;
int32_t get_province_building_count() const;
godot::String get_province_building_identifier(int32_t building_index) const;
- godot::Error expand_selected_province_building(int32_t building_index);
int32_t get_slave_pop_icon_index() const;
int32_t get_administrative_pop_icon_index() const;
int32_t get_rgo_owner_pop_icon_index() const;
@@ -198,16 +198,16 @@ namespace OpenVic {
godot::Dictionary get_topbar_info() const;
/* TIME/SPEED CONTROL PANEL */
- void set_paused(bool paused);
- void toggle_paused();
bool is_paused() const;
- void increase_speed();
- void decrease_speed();
int32_t get_speed() const;
bool can_increase_speed() const;
bool can_decrease_speed() const;
godot::String get_longform_date() const;
+ /* BUDGET MENU */
+ godot::Dictionary get_budget_menu_setup_info() const;
+ godot::Dictionary get_budget_menu_info() const;
+
/* POPULATION MENU */
godot::Error _population_menu_update_provinces();
int32_t get_population_menu_province_list_row_count() const;
@@ -241,11 +241,12 @@ namespace OpenVic {
godot::Dictionary get_trade_menu_good_categories_info() const;
godot::Dictionary get_trade_menu_trade_details_info(int32_t trade_detail_good_index) const;
godot::Dictionary get_trade_menu_tables_info() const;
+ static float calculate_trade_menu_stockpile_cutoff_amount(GUIScrollbar const* slider);
/* MILITARY MENU */
- godot::Dictionary make_leader_dict(LeaderBase const& leader);
+ godot::Dictionary make_leader_dict(LeaderInstance const& leader);
template
- godot::Dictionary make_unit_group_dict(UnitInstanceGroup const& unit_group);
+ godot::Dictionary make_unit_group_dict(UnitInstanceGroupBranched const& unit_group);
godot::Dictionary make_in_progress_unit_dict() const;
godot::Dictionary get_military_menu_info(
LeaderSortKey leader_sort_key, bool sort_leaders_descending,
diff --git a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp
index 0d4a9b8f..44886e79 100644
--- a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp
+++ b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp
@@ -7,6 +7,7 @@
#include "openvic-extension/classes/GUINode.hpp"
#include "openvic-extension/singletons/AssetManager.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
+#include "openvic-extension/singletons/PlayerSingleton.hpp"
#include "openvic-extension/utility/Utilities.hpp"
using namespace OpenVic;
@@ -14,28 +15,28 @@ using namespace godot;
/* MILITARY MENU */
-static Ref _get_leader_picture(LeaderBase const& leader) {
- AssetManager* asset_manager = AssetManager::get_singleton();
- ERR_FAIL_NULL_V(asset_manager, {});
+static Ref _get_leader_picture(LeaderInstance const& leader) {
+ AssetManager& asset_manager = *AssetManager::get_singleton();
if (!leader.get_picture().empty()) {
- const Ref texture = asset_manager->get_leader_texture_std(leader.get_picture());
+ const Ref texture = asset_manager.get_leader_texture_std(leader.get_picture());
if (texture.is_valid()) {
return texture;
}
}
- return asset_manager->get_missing_leader_texture();
+ return asset_manager.get_missing_leader_texture();
}
-Dictionary MenuSingleton::make_leader_dict(LeaderBase const& leader) {
+Dictionary MenuSingleton::make_leader_dict(LeaderInstance const& leader) {
const decltype(cached_leader_dicts)::const_iterator it = cached_leader_dicts.find(&leader);
if (it != cached_leader_dicts.end()) {
return it->second;
}
+ static const StringName military_info_leader_id_key = "leader_id";
static const StringName military_info_leader_name_key = "leader_name";
static const StringName military_info_leader_picture_key = "leader_picture";
static const StringName military_info_leader_prestige_key = "leader_prestige";
@@ -55,39 +56,36 @@ Dictionary MenuSingleton::make_leader_dict(LeaderBase const& leader) {
leader_dict[military_info_leader_picture_key] = _get_leader_picture(leader);
{
- // Branched (can be used, assignment, location, title)
- static const auto branched_section = [](
- LeaderBranched const& leader, Dictionary& leader_dict
- ) -> void {
- leader_dict[military_info_leader_can_be_used_key] = leader.get_can_be_used();
-
- UnitInstanceGroup const* group = leader.get_unit_instance_group();
- if (group != nullptr) {
- leader_dict[military_info_leader_assignment_key] = Utilities::std_to_godot_string(group->get_name());
-
- ProvinceInstance const* location = group->get_position();
- if (location != nullptr) {
- leader_dict[military_info_leader_location_key] =
- Utilities::std_to_godot_string(location->get_identifier());
- }
+ // Generic data
+ leader_dict[military_info_leader_id_key] = leader.get_unique_id();
+
+ leader_dict[military_info_leader_can_be_used_key] = leader.get_can_be_used();
+
+ UnitInstanceGroup const* group = leader.get_unit_instance_group();
+ if (group != nullptr) {
+ leader_dict[military_info_leader_assignment_key] = Utilities::std_to_godot_string(group->get_name());
+
+ ProvinceInstance const* location = group->get_position();
+ if (location != nullptr) {
+ leader_dict[military_info_leader_location_key] =
+ Utilities::std_to_godot_string(location->get_identifier());
}
- };
+ }
+ }
+ {
+ // Title
using enum UnitType::branch_t;
switch (leader.get_branch()) {
case LAND: {
static const StringName general_localisation_key = "MILITARY_GENERAL_TOOLTIP";
tooltip = tr(general_localisation_key) + " ";
-
- branched_section(static_cast(leader), leader_dict);
} break;
case NAVAL: {
static const StringName admiral_localisation_key = "MILITARY_ADMIRAL_TOOLTIP";
tooltip = tr(admiral_localisation_key) + " ";
-
- branched_section(static_cast(leader), leader_dict);
} break;
default:
@@ -96,9 +94,7 @@ Dictionary MenuSingleton::make_leader_dict(LeaderBase const& leader) {
Utilities::std_to_godot_string(leader.get_name()), "\""
);
}
- }
- {
// Name
String leader_name = Utilities::std_to_godot_string(leader.get_name());
@@ -210,7 +206,7 @@ static inline int32_t _scale_land_unit_strength(fixed_point_t strength) {
}
template
-Dictionary MenuSingleton::make_unit_group_dict(UnitInstanceGroup const& unit_group) {
+Dictionary MenuSingleton::make_unit_group_dict(UnitInstanceGroupBranched const& unit_group) {
static const StringName military_info_unit_group_leader_picture_key = "unit_group_leader_picture";
static const StringName military_info_unit_group_leader_tooltip_key = "unit_group_leader_tooltip";
static const StringName military_info_unit_group_name_key = "unit_group_name";
@@ -266,12 +262,11 @@ Dictionary MenuSingleton::make_unit_group_dict(UnitInstanceGroup const&
}
if constexpr (Branch == LAND) {
- ArmyInstance const& army = static_cast(unit_group);
-
- unit_group_dict[military_info_unit_group_men_count_key] = _scale_land_unit_strength(army.get_total_strength());
- unit_group_dict[military_info_unit_group_max_men_count_key] = _scale_land_unit_strength(army.get_total_max_strength());
+ unit_group_dict[military_info_unit_group_men_count_key] = _scale_land_unit_strength(unit_group.get_total_strength());
+ unit_group_dict[military_info_unit_group_max_men_count_key] =
+ _scale_land_unit_strength(unit_group.get_total_max_strength());
- const ArmyInstance::dig_in_level_t dig_in_level = army.get_dig_in_level();
+ const ArmyInstance::dig_in_level_t dig_in_level = unit_group.get_dig_in_level();
if (dig_in_level > 0) {
static const StringName dig_in_localisation_key = "MILITARY_DIGIN_TOOLTIP";
@@ -290,6 +285,7 @@ Dictionary MenuSingleton::make_unit_group_dict(UnitInstanceGroup const&
return unit_group_dict;
}
+// Only ever called if we know player country isn't null
Dictionary MenuSingleton::make_in_progress_unit_dict() const {
static const StringName military_info_unit_progress_key = "unit_progress";
static const StringName military_info_unit_icon_key = "unit_icon";
@@ -298,14 +294,13 @@ Dictionary MenuSingleton::make_in_progress_unit_dict() const {
static const StringName military_info_unit_eta_key = "unit_eta";
static const StringName military_info_unit_tooltip_key = "unit_tooltip";
- GameSingleton const* game_singleton = GameSingleton::get_singleton();
- DefinitionManager const& definition_manager = game_singleton->get_definition_manager();
+ DefinitionManager const& definition_manager = GameSingleton::get_singleton()->get_definition_manager();
GoodDefinitionManager const& good_definition_manager =
definition_manager.get_economy_manager().get_good_definition_manager();
// TODO - remove test data, read actual in-progress units from SIM
UnitType const* unit_type = definition_manager.get_military_manager().get_unit_type_manager().get_unit_type_by_index(0);
- ProvinceInstance const* location = game_singleton->get_viewed_country()->get_capital();
+ ProvinceInstance const* location = PlayerSingleton::get_singleton()->get_player_country()->get_capital();
const Date eta { 1900 };
const fixed_point_t progress = fixed_point_t::_0_50();
const ordered_map> required_goods {
@@ -329,7 +324,9 @@ Dictionary MenuSingleton::make_in_progress_unit_dict() const {
in_progress_unit_dict[military_info_unit_progress_key] = progress.to_float();
in_progress_unit_dict[military_info_unit_icon_key] = unit_type->get_icon();
in_progress_unit_dict[military_info_unit_name_key] = Utilities::std_to_godot_string(unit_type->get_identifier());
- in_progress_unit_dict[military_info_unit_location_key] = Utilities::std_to_godot_string(location->get_identifier());
+ if (location != nullptr) {
+ in_progress_unit_dict[military_info_unit_location_key] = Utilities::std_to_godot_string(location->get_identifier());
+ }
in_progress_unit_dict[military_info_unit_eta_key] = Utilities::date_to_string(eta);
String tooltip;
@@ -350,74 +347,52 @@ Dictionary MenuSingleton::make_in_progress_unit_dict() const {
return in_progress_unit_dict;
}
-using leader_sort_func_t = bool (*)(LeaderBase const*, LeaderBase const*);
+using leader_sort_func_t = bool (*)(LeaderInstance const*, LeaderInstance const*);
static leader_sort_func_t _get_leader_sort_func(MenuSingleton::LeaderSortKey leader_sort_key) {
- static const auto get_assignment = [](LeaderBase const* leader) -> std::string_view {
- static const auto get_assignment_template =
- [](LeaderBranched const* leader) -> std::string_view {
- UnitInstanceGroup const* group = leader->get_unit_instance_group();
- return group != nullptr ? group->get_name() : std::string_view {};
- };
-
- using enum UnitType::branch_t;
- switch (leader->get_branch()) {
- case LAND:
- return get_assignment_template(static_cast(leader));
- case NAVAL:
- return get_assignment_template(static_cast(leader));
- default:
- return {};
- }
- };
-
using enum MenuSingleton::LeaderSortKey;
switch (leader_sort_key) {
case LEADER_SORT_PRESTIGE:
- return [](LeaderBase const* a, LeaderBase const* b) -> bool {
+ return [](LeaderInstance const* a, LeaderInstance const* b) -> bool {
return a->get_prestige() < b->get_prestige();
};
case LEADER_SORT_TYPE:
- return [](LeaderBase const* a, LeaderBase const* b) -> bool {
+ return [](LeaderInstance const* a, LeaderInstance const* b) -> bool {
return a->get_branch() < b->get_branch();
};
case LEADER_SORT_NAME:
- return [](LeaderBase const* a, LeaderBase const* b) -> bool {
+ return [](LeaderInstance const* a, LeaderInstance const* b) -> bool {
return a->get_name() < b->get_name();
};
case LEADER_SORT_ASSIGNMENT:
- return [](LeaderBase const* a, LeaderBase const* b) -> bool {
- return get_assignment(a) < get_assignment(b);
+ return [](LeaderInstance const* a, LeaderInstance const* b) -> bool {
+ return (a->get_unit_instance_group() != nullptr ? a->get_unit_instance_group()->get_name() : std::string_view {})
+ < (b->get_unit_instance_group() != nullptr ? b->get_unit_instance_group()->get_name() : std::string_view {});
};
default:
UtilityFunctions::push_error("Invalid miltiary menu leader sort key: ", leader_sort_key);
- return [](LeaderBase const* a, LeaderBase const* b) -> bool { return false; };
+ return [](LeaderInstance const* a, LeaderInstance const* b) -> bool { return false; };
}
}
-template
-using unit_group_sort_func_t = bool (*)(UnitInstanceGroup const*, UnitInstanceGroup const*);
+using unit_group_sort_func_t = bool (*)(UnitInstanceGroup const*, UnitInstanceGroup const*);
-template
-static unit_group_sort_func_t _get_unit_group_sort_func(MenuSingleton::UnitGroupSortKey unit_group_sort_key) {
+static unit_group_sort_func_t _get_unit_group_sort_func(MenuSingleton::UnitGroupSortKey unit_group_sort_key) {
using enum MenuSingleton::UnitGroupSortKey;
switch (unit_group_sort_key) {
case UNIT_GROUP_SORT_NAME:
- return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
+ return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
return a->get_name() < b->get_name();
};
case UNIT_GROUP_SORT_STRENGTH:
- return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
+ return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
return a->get_unit_count() < b->get_unit_count();
};
default:
- UtilityFunctions::push_error(
- "Invalid miltiary menu ", Utilities::std_to_godot_string(UnitType::get_branched_unit_group_name(Branch)),
- " sort key: ", unit_group_sort_key
- );
- return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool { return false; };
+ UtilityFunctions::push_error("Invalid miltiary menu unit group sort key: ", unit_group_sort_key);
+ return [](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool { return false; };
}
}
@@ -436,7 +411,7 @@ Dictionary MenuSingleton::get_military_menu_info(
StaticModifierCache const& static_modifier_cache = definition_manager.get_modifier_manager().get_static_modifier_cache();
IssueManager const& issue_manager = definition_manager.get_politics_manager().get_issue_manager();
- CountryInstance const* country = game_singleton->get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
if (country == nullptr) {
return {};
}
@@ -657,13 +632,13 @@ Dictionary MenuSingleton::get_military_menu_info(
ret[military_info_auto_assign_leaders_key] = country->get_auto_assign_leaders();
if (country->has_leaders()) {
- std::vector sorted_leaders;
+ std::vector sorted_leaders;
sorted_leaders.reserve(country->get_leader_count());
- for (General const& general : country->get_generals()) {
- sorted_leaders.push_back(&general);
+ for (LeaderInstance const* general : country->get_generals()) {
+ sorted_leaders.push_back(general);
}
- for (Admiral const& admiral : country->get_admirals()) {
- sorted_leaders.push_back(&admiral);
+ for (LeaderInstance const* admiral : country->get_admirals()) {
+ sorted_leaders.push_back(admiral);
}
if (leader_sort_key != LEADER_SORT_NONE) {
@@ -672,7 +647,7 @@ Dictionary MenuSingleton::get_military_menu_info(
if (sort_leaders_descending) {
std::sort(
sorted_leaders.begin(), sorted_leaders.end(),
- [leader_sort_func](LeaderBase const* a, LeaderBase const* b) -> bool {
+ [leader_sort_func](LeaderInstance const* a, LeaderInstance const* b) -> bool {
return leader_sort_func(b, a);
}
);
@@ -707,8 +682,6 @@ Dictionary MenuSingleton::get_military_menu_info(
ret[military_info_is_disarmed_key] = country->is_disarmed();
- using enum UnitType::branch_t;
-
if (country->has_armies()) {
std::vector sorted_armies;
sorted_armies.reserve(country->get_army_count());
@@ -717,12 +690,12 @@ Dictionary MenuSingleton::get_military_menu_info(
}
if (army_sort_key != UNIT_GROUP_SORT_NONE) {
- const unit_group_sort_func_t army_sort_func = _get_unit_group_sort_func(army_sort_key);
+ const unit_group_sort_func_t army_sort_func = _get_unit_group_sort_func(army_sort_key);
if (sort_armies_descending) {
std::sort(
sorted_armies.begin(), sorted_armies.end(),
- [army_sort_func](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
+ [army_sort_func](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
return army_sort_func(b, a);
}
);
@@ -764,12 +737,12 @@ Dictionary MenuSingleton::get_military_menu_info(
}
if (navy_sort_key != UNIT_GROUP_SORT_NONE) {
- const unit_group_sort_func_t navy_sort_func = _get_unit_group_sort_func(navy_sort_key);
+ const unit_group_sort_func_t navy_sort_func = _get_unit_group_sort_func(navy_sort_key);
if (sort_navies_descending) {
std::sort(
sorted_navies.begin(), sorted_navies.end(),
- [navy_sort_func](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
+ [navy_sort_func](UnitInstanceGroup const* a, UnitInstanceGroup const* b) -> bool {
return navy_sort_func(b, a);
}
);
diff --git a/extension/src/openvic-extension/singletons/ModelSingleton.cpp b/extension/src/openvic-extension/singletons/ModelSingleton.cpp
index f51ae77f..5b2fa8b8 100644
--- a/extension/src/openvic-extension/singletons/ModelSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/ModelSingleton.cpp
@@ -195,7 +195,7 @@ Dictionary ModelSingleton::get_model_dict(GFX::Actor const& actor) {
* Returning true doesn't necessarily mean a unit was added, e.g. when units is empty. */
template
bool ModelSingleton::add_unit_dict(
- ordered_set*> const& units, TypedArray& unit_array
+ std::vector*> const& units, TypedArray& unit_array
) {
using _UnitInstanceGroup = UnitInstanceGroupBranched;
diff --git a/extension/src/openvic-extension/singletons/ModelSingleton.hpp b/extension/src/openvic-extension/singletons/ModelSingleton.hpp
index f0c45be0..ebec7504 100644
--- a/extension/src/openvic-extension/singletons/ModelSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/ModelSingleton.hpp
@@ -40,7 +40,7 @@ namespace OpenVic {
template
bool add_unit_dict(
- ordered_set*> const& units, godot::TypedArray& unit_array
+ std::vector*> const& units, godot::TypedArray& unit_array
);
bool add_building_dict(
diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.cpp b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp
new file mode 100644
index 00000000..f3bc8265
--- /dev/null
+++ b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp
@@ -0,0 +1,404 @@
+#include "PlayerSingleton.hpp"
+
+#include
+#include
+
+#include "openvic-extension/singletons/GameSingleton.hpp"
+#include "openvic-extension/utility/ClassBindings.hpp"
+
+using namespace OpenVic;
+using namespace godot;
+
+/* StringNames cannot be constructed until Godot has called StringName::setup(),
+ * so we must use these wrapper functions to delay their initialisation. */
+StringName const& PlayerSingleton::_signal_province_selected() {
+ static const StringName signal_province_selected = "province_selected";
+ return signal_province_selected;
+}
+
+void PlayerSingleton::_bind_methods() {
+ // Player country
+ OV_BIND_METHOD(PlayerSingleton::set_player_country_by_province_index, { "province_index" });
+ OV_BIND_METHOD(PlayerSingleton::get_player_country_capital_position);
+
+ // Selected province
+ OV_BIND_METHOD(PlayerSingleton::set_selected_province_by_index, { "province_index" });
+ OV_BIND_METHOD(PlayerSingleton::unset_selected_province);
+ OV_BIND_METHOD(PlayerSingleton::get_selected_province_index);
+
+ // Core
+ OV_BIND_METHOD(PlayerSingleton::toggle_paused);
+ OV_BIND_METHOD(PlayerSingleton::increase_speed);
+ OV_BIND_METHOD(PlayerSingleton::decrease_speed);
+
+ // Production
+ OV_BIND_METHOD(PlayerSingleton::expand_selected_province_building, { "building_index" });
+
+ // Budget
+ OV_BIND_METHOD(PlayerSingleton::set_strata_tax, { "strata", "tax" });
+ OV_BIND_METHOD(PlayerSingleton::set_land_spending, { "land_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_naval_spending, { "naval_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_construction_spending, { "construction_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_education_spending, { "education_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_administration_spending, { "administration_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_social_spending, { "social_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_military_spending, { "military_spending" });
+ OV_BIND_METHOD(PlayerSingleton::set_tariff_rate, { "tariff_rate" });
+
+ // Technology
+
+ // Politics
+
+ // Population
+
+ // Trade
+ OV_BIND_METHOD(PlayerSingleton::set_good_automated, { "good_index", "is_automated" });
+
+ // Diplomacy
+
+ // Military
+ OV_BIND_METHOD(PlayerSingleton::create_leader, { "is_general" });
+ OV_BIND_METHOD(PlayerSingleton::set_can_use_leader, { "leader_id", "can_use" });
+ OV_BIND_METHOD(PlayerSingleton::set_auto_create_leaders, { "value" });
+ OV_BIND_METHOD(PlayerSingleton::set_auto_assign_leaders, { "value" });
+ OV_BIND_METHOD(PlayerSingleton::set_mobilise, { "value" });
+
+ ADD_SIGNAL(MethodInfo(_signal_province_selected(), PropertyInfo(Variant::INT, "index")));
+}
+
+PlayerSingleton* PlayerSingleton::get_singleton() {
+ return singleton;
+}
+
+PlayerSingleton::PlayerSingleton() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+}
+
+PlayerSingleton::~PlayerSingleton() {
+ ERR_FAIL_COND(singleton != this);
+ singleton = nullptr;
+}
+
+// Player country
+void PlayerSingleton::set_player_country(CountryInstance const* new_player_country) {
+ if (player_country != new_player_country) {
+ GameSingleton& game_singleton = *GameSingleton::get_singleton();
+ InstanceManager* instance_manager = game_singleton.get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ if (player_country != nullptr) {
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_AI,
+ std::pair { player_country->get_index(), true }
+ );
+ }
+
+ player_country = new_player_country;
+
+ if (player_country != nullptr) {
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_AI,
+ std::pair { player_country->get_index(), false }
+ );
+ }
+
+ Logger::info("Set player country to: ", player_country != nullptr ? player_country->get_identifier() : "");
+
+ game_singleton._on_gamestate_updated();
+ }
+}
+
+void PlayerSingleton::set_player_country_by_province_index(int32_t province_index) {
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ ProvinceInstance* province_instance = instance_manager->get_map_instance().get_province_instance_by_index(province_index);
+ ERR_FAIL_NULL(province_instance);
+
+ set_player_country(province_instance->get_owner());
+}
+
+Vector2 PlayerSingleton::get_player_country_capital_position() const {
+ if (player_country != nullptr) {
+ ProvinceInstance const* capital = player_country->get_capital();
+
+ if (capital != nullptr) {
+ return GameSingleton::get_singleton()->get_billboard_pos(capital->get_province_definition());
+ }
+ }
+
+ return {};
+}
+
+// Selected province
+void PlayerSingleton::set_selected_province(ProvinceInstance const* new_selected_province) {
+ if (selected_province != new_selected_province) {
+ selected_province = new_selected_province;
+
+ GameSingleton::get_singleton()->_update_colour_image();
+
+ emit_signal(_signal_province_selected(), get_selected_province_index());
+ }
+}
+
+void PlayerSingleton::set_selected_province_by_index(int32_t province_index) {
+ if (province_index == ProvinceDefinition::NULL_INDEX) {
+ unset_selected_province();
+ } else {
+ InstanceManager const* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ MapInstance const& map_instance = instance_manager->get_map_instance();
+
+ set_selected_province(map_instance.get_province_instance_by_index(province_index));
+
+ if (selected_province == nullptr) {
+ Logger::error(
+ "Trying to set selected province to an invalid index ", province_index, " (max index is ",
+ map_instance.get_province_instance_count(), ")"
+ );
+ }
+ }
+}
+
+void PlayerSingleton::unset_selected_province() {
+ set_selected_province(nullptr);
+}
+
+int32_t PlayerSingleton::get_selected_province_index() const {
+ return selected_province != nullptr ? selected_province->get_index() : ProvinceDefinition::NULL_INDEX;
+}
+
+// Core
+void PlayerSingleton::toggle_paused() const {
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_PAUSE,
+ !instance_manager->get_simulation_clock().is_paused()
+ );
+}
+
+void PlayerSingleton::increase_speed() const {
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_SPEED,
+ instance_manager->get_simulation_clock().get_simulation_speed() + 1
+ );
+}
+
+void PlayerSingleton::decrease_speed() const {
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_SPEED,
+ instance_manager->get_simulation_clock().get_simulation_speed() - 1
+ );
+}
+
+// Production
+void PlayerSingleton::expand_selected_province_building(int32_t building_index) const {
+ ERR_FAIL_NULL(selected_province);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_EXPAND_PROVINCE_BUILDING,
+ std::pair { selected_province->get_index(), building_index }
+ );
+}
+
+// Budget
+void PlayerSingleton::set_strata_tax(int32_t strata, int32_t tax) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_STRATA_TAX,
+ std::pair { player_country->get_index(), tax }
+ );
+}
+
+void PlayerSingleton::set_land_spending(int32_t land_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_LAND_SPENDING,
+ std::pair { player_country->get_index(), land_spending }
+ );
+}
+
+void PlayerSingleton::set_naval_spending(int32_t naval_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_NAVAL_SPENDING,
+ std::pair { player_country->get_index(), naval_spending }
+ );
+}
+
+void PlayerSingleton::set_construction_spending(int32_t construction_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_CONSTRUCTION_SPENDING,
+ std::pair { player_country->get_index(), construction_spending }
+ );
+}
+
+void PlayerSingleton::set_education_spending(int32_t education_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_EDUCATION_SPENDING,
+ std::pair { player_country->get_index(), education_spending }
+ );
+}
+
+void PlayerSingleton::set_administration_spending(int32_t administration_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_ADMINISTRATION_SPENDING,
+ std::pair { player_country->get_index(), administration_spending }
+ );
+}
+
+void PlayerSingleton::set_social_spending(int32_t social_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_SOCIAL_SPENDING,
+ std::pair { player_country->get_index(), social_spending }
+ );
+}
+
+void PlayerSingleton::set_military_spending(int32_t military_spending) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_MILITARY_SPENDING,
+ std::pair { player_country->get_index(), military_spending }
+ );
+}
+
+void PlayerSingleton::set_tariff_rate(int32_t tariff_rate) {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_TARIFF_RATE,
+ std::pair { player_country->get_index(), tariff_rate }
+ );
+}
+
+// Technology
+
+// Politics
+
+// Population
+
+// Trade
+void PlayerSingleton::set_good_automated(int32_t good_index, bool is_automated) const {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_GOOD_AUTOMATED,
+ std::tuple { player_country->get_index(), good_index, is_automated }
+ );
+}
+
+// Diplomacy
+
+// Military
+void PlayerSingleton::create_leader(bool is_general) const {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_CREATE_LEADER,
+ std::pair { player_country->get_index(), is_general }
+ );
+}
+
+void PlayerSingleton::set_can_use_leader(uint64_t leader_id, bool can_use) const {
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_USE_LEADER,
+ std::pair { leader_id, can_use }
+ );
+}
+
+void PlayerSingleton::set_auto_create_leaders(bool value) const {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_AUTO_CREATE_LEADERS,
+ std::pair { player_country->get_index(), value }
+ );
+}
+
+void PlayerSingleton::set_auto_assign_leaders(bool value) const {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_AUTO_ASSIGN_LEADERS,
+ std::pair { player_country->get_index(), value }
+ );
+}
+
+void PlayerSingleton::set_mobilise(bool value) const {
+ ERR_FAIL_NULL(player_country);
+
+ InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
+ ERR_FAIL_NULL(instance_manager);
+
+ instance_manager->queue_game_action(
+ game_action_type_t::GAME_ACTION_SET_MOBILISE,
+ std::pair { player_country->get_index(), value }
+ );
+}
diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp
new file mode 100644
index 00000000..5f6d78c7
--- /dev/null
+++ b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp
@@ -0,0 +1,81 @@
+#pragma once
+
+#include
+
+#include
+
+namespace OpenVic {
+ struct CountryInstance;
+ struct ProvinceInstance;
+
+ class PlayerSingleton : public godot::Object {
+ GDCLASS(PlayerSingleton, godot::Object)
+
+ static inline PlayerSingleton* singleton = nullptr;
+
+ // TODO - move selected province here!
+
+ CountryInstance const* PROPERTY(player_country, nullptr);
+ ProvinceInstance const* PROPERTY(selected_province, nullptr);
+
+ static godot::StringName const& _signal_province_selected();
+
+ protected:
+ static void _bind_methods();
+
+ public:
+ static PlayerSingleton* get_singleton();
+
+ PlayerSingleton();
+ ~PlayerSingleton();
+
+ // Player country
+ void set_player_country(CountryInstance const* new_player_country);
+ void set_player_country_by_province_index(int32_t province_index);
+ godot::Vector2 get_player_country_capital_position() const;
+
+ // Selected province
+ void set_selected_province(ProvinceInstance const* new_selected_province);
+ void set_selected_province_by_index(int32_t province_index);
+ void unset_selected_province();
+ int32_t get_selected_province_index() const;
+
+ // Core
+ void toggle_paused() const;
+ void increase_speed() const;
+ void decrease_speed() const;
+
+ // Production
+ void expand_selected_province_building(int32_t building_index) const;
+
+ // Budget
+ void set_strata_tax(int32_t strata, int32_t tax);
+ void set_land_spending(int32_t land_spending);
+ void set_naval_spending(int32_t naval_spending);
+ void set_construction_spending(int32_t construction_spending);
+ void set_education_spending(int32_t education_spending);
+ void set_administration_spending(int32_t administration_spending);
+ void set_social_spending(int32_t social_spending);
+ void set_military_spending(int32_t military_spending);
+ void set_tariff_rate(int32_t tariff_rate);
+
+ // Technology
+
+ // Politics
+
+ // Population
+
+ // Trade
+ void set_good_automated(int32_t good_index, bool is_automated) const;
+
+ // Diplomacy
+
+ // Military
+ // Argument true for general, false for admiral
+ void create_leader(bool is_general) const;
+ void set_can_use_leader(uint64_t leader_id, bool can_use) const;
+ void set_auto_create_leaders(bool value) const;
+ void set_auto_assign_leaders(bool value) const;
+ void set_mobilise(bool value) const;
+ };
+}
diff --git a/extension/src/openvic-extension/singletons/PopulationMenu.cpp b/extension/src/openvic-extension/singletons/PopulationMenu.cpp
index 7f7fa8db..cb976d22 100644
--- a/extension/src/openvic-extension/singletons/PopulationMenu.cpp
+++ b/extension/src/openvic-extension/singletons/PopulationMenu.cpp
@@ -291,7 +291,7 @@ Error MenuSingleton::population_menu_select_province(int32_t province_index) {
}
bool operator()(population_menu_t::province_entry_t& province_entry) {
- if (province_entry.province.get_province_definition().get_index() == _province_index) {
+ if (province_entry.province.get_index() == _province_index) {
if (state_entry_to_expand >= 0) {
ret &= menu_singleton.population_menu_toggle_expanded(state_entry_to_expand, false) == OK;
diff --git a/extension/src/openvic-extension/singletons/TradeMenu.cpp b/extension/src/openvic-extension/singletons/TradeMenu.cpp
index 8a65d7fb..6074032c 100644
--- a/extension/src/openvic-extension/singletons/TradeMenu.cpp
+++ b/extension/src/openvic-extension/singletons/TradeMenu.cpp
@@ -3,7 +3,9 @@
#include
#include "openvic-extension/classes/GUILabel.hpp"
+#include "openvic-extension/classes/GUIScrollbar.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
+#include "openvic-extension/singletons/PlayerSingleton.hpp"
#include "openvic-extension/utility/Utilities.hpp"
using namespace OpenVic;
@@ -18,14 +20,13 @@ Dictionary MenuSingleton::get_trade_menu_good_categories_info() const {
static const StringName demand_tooltip_key = "demand_tooltip";
static const StringName trade_settings_key = "trade_settings";
- GameSingleton const& game_singleton = *GameSingleton::get_singleton();
- InstanceManager const* instance_manager = game_singleton.get_instance_manager();
+ InstanceManager const* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, {});
GoodInstanceManager const& good_instance_manager = instance_manager->get_good_instance_manager();
GoodDefinitionManager const& good_definition_manager = good_instance_manager.get_good_definition_manager();
- CountryInstance const* country = game_singleton.get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
Dictionary ret;
@@ -35,7 +36,7 @@ Dictionary MenuSingleton::get_trade_menu_good_categories_info() const {
for (GoodDefinition const* good_definition : good_category.get_good_definitions()) {
GoodInstance const& good_instance = good_instance_manager.get_good_instance_from_definition(*good_definition);
- if (!good_instance.get_is_available() || !good_definition->get_is_tradeable()) {
+ if (!good_instance.is_trading_good()) {
continue;
}
@@ -68,7 +69,7 @@ Dictionary MenuSingleton::get_trade_menu_good_categories_info() const {
}
if (country != nullptr) {
- CountryInstance::good_data_t const& good_data = country->get_goods_data()[good_instance];
+ CountryInstance::good_data_t const& good_data = country->get_good_data(good_instance);
// Trade settings:
// - 1 bit: automated (1) or not (0)
@@ -123,15 +124,14 @@ Dictionary MenuSingleton::get_trade_menu_trade_details_info(int32_t trade_detail
static const StringName trade_detail_pop_needs_key = "trade_detail_pop_needs";
static const StringName trade_detail_available_key = "trade_detail_available";
- GameSingleton const& game_singleton = *GameSingleton::get_singleton();
- InstanceManager const* instance_manager = game_singleton.get_instance_manager();
+ InstanceManager const* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, {});
GoodInstance const* good_instance =
instance_manager->get_good_instance_manager().get_good_instance_by_index(trade_detail_good_index);
ERR_FAIL_NULL_V(good_instance, {});
- CountryInstance const* country = game_singleton.get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
Dictionary ret;
@@ -161,7 +161,7 @@ Dictionary MenuSingleton::get_trade_menu_trade_details_info(int32_t trade_detail
return ret;
}
- CountryInstance::good_data_t const& good_data = country->get_goods_data()[*good_instance];
+ CountryInstance::good_data_t const& good_data = country->get_good_data(*good_instance);
ret[trade_detail_is_automated_key] = good_data.is_automated;
ret[trade_detail_is_selling_key] = good_data.is_selling;
@@ -190,12 +190,11 @@ Dictionary MenuSingleton::get_trade_menu_tables_info() const {
static const StringName stockpile_key = "stockpile";
static const StringName common_market_key = "common_market";
- GameSingleton const& game_singleton = *GameSingleton::get_singleton();
- InstanceManager const* instance_manager = game_singleton.get_instance_manager();
+ InstanceManager const* instance_manager = GameSingleton::get_singleton()->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, {});
GoodInstanceManager const& good_instance_manager = instance_manager->get_good_instance_manager();
- CountryInstance const* country = game_singleton.get_viewed_country();
+ CountryInstance const* country = PlayerSingleton::get_singleton()->get_player_country();
Dictionary ret;
@@ -241,7 +240,7 @@ Dictionary MenuSingleton::get_trade_menu_tables_info() const {
PackedVector4Array common_market;
for (auto const& [good, good_data] : country->get_goods_data()) {
- if (!good.get_is_available() || !good.get_good_definition().get_is_tradeable()) {
+ if (!good.is_trading_good()) {
continue;
}
@@ -321,3 +320,19 @@ Dictionary MenuSingleton::get_trade_menu_tables_info() const {
return ret;
}
+
+// TODO - improve accuracy of this calculation (at least so an input of 2000 gives a result of 2000.00)
+
+static constexpr fixed_point_t calculate_trade_menu_stockpile_cutoff_amount_fp(fixed_point_t value) {
+ // ln(2001) * 2^16 = 498165.503399
+ constexpr fixed_point_t C = fixed_point_t::parse_raw(498168); // This gives 2000.01 for value = 2000
+ constexpr int32_t D = 2000;
+
+ return fixed_point_t::exp(value * C / D) - fixed_point_t::_1();
+}
+
+float MenuSingleton::calculate_trade_menu_stockpile_cutoff_amount(GUIScrollbar const* slider) {
+ ERR_FAIL_NULL_V(slider, 0.0f);
+
+ return calculate_trade_menu_stockpile_cutoff_amount_fp(slider->get_value() * slider->get_step_size());
+}
diff --git a/game/src/Game/GameSession/GameSession.gd b/game/src/Game/GameSession/GameSession.gd
index f9c29824..f2cb5518 100644
--- a/game/src/Game/GameSession/GameSession.gd
+++ b/game/src/Game/GameSession/GameSession.gd
@@ -28,7 +28,7 @@ func _on_map_view_ready() -> void:
# Set the camera's starting position
_map_view._camera.position = _map_view._map_to_world_coords(
# Start at the player country's capital position (when loading a save game in the lobby or entering the actual game)
- GameSingleton.get_viewed_country_capital_position()
+ PlayerSingleton.get_player_country_capital_position()
)
func _on_map_view_province_hovered(index: int) -> void:
@@ -38,9 +38,9 @@ func _on_map_view_province_unhovered() -> void:
_map_view.unset_hovered_province()
func _on_map_view_province_clicked(index: int) -> void:
- GameSingleton.set_selected_province(index)
+ PlayerSingleton.set_selected_province_by_index(index)
func _on_map_view_province_right_clicked(index: int) -> void:
# TODO - open diplomacy screen on province owner or viewed country if province has no owner
#Events.NationManagementScreens.open_nation_management_screen(NationManagement.Screen.DIPLOMACY)
- GameSingleton.set_viewed_country_by_province_index(index)
+ PlayerSingleton.set_player_country_by_province_index(index)
diff --git a/game/src/Game/GameSession/MapView.gd b/game/src/Game/GameSession/MapView.gd
index 7cc69b25..80f0bc5d 100644
--- a/game/src/Game/GameSession/MapView.gd
+++ b/game/src/Game/GameSession/MapView.gd
@@ -105,7 +105,7 @@ func _ready() -> void:
map_mesh_aabb.position.z - map_mesh_aabb.end.z
))
- GameSingleton.province_selected.connect(_on_province_selected)
+ PlayerSingleton.province_selected.connect(_on_province_selected)
# Start zoomed out with the parchment map active
_camera.position.y = _zoom_parchment_threshold * 1.5
diff --git a/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd b/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd
index ce9a2731..30d82c58 100644
--- a/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd
+++ b/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd
@@ -88,10 +88,10 @@ func _ready() -> void:
# Mobilisation
_mobilise_button = GUINode.get_gui_icon_button_from_node(military_menu.get_node(^"./mobilize"))
if _mobilise_button:
- _mobilise_button.pressed.connect(func() -> void: print("MOBILISE PRESSED"))
+ _mobilise_button.pressed.connect(PlayerSingleton.set_mobilise.bind(true))
_demobilise_button = GUINode.get_gui_icon_button_from_node(military_menu.get_node(^"./demobilize"))
if _demobilise_button:
- _demobilise_button.pressed.connect(func() -> void: print("DEMOBILISE PRESSED"))
+ _demobilise_button.pressed.connect(PlayerSingleton.set_mobilise.bind(false))
_demobilise_button.set_tooltip_string("$MILITARY_DEMOBILIZE$" + MenuSingleton.get_tooltip_separator() + "$MILITARY_DEMOBILIZE_DESC$")
_mobilisation_progress_bar = GUINode.get_gui_progress_bar_from_node(military_menu.get_node(^"./mobilize_progress"))
_mobilisation_progress_label = GUINode.get_gui_label_from_node(military_menu.get_node(^"./mobilize_progress_text"))
@@ -146,17 +146,17 @@ func _ready() -> void:
sort_leader_army_button.set_tooltip_string("MILITARY_SORT_BY_ASSIGNMENT_TOOLTIP")
_create_general_button = GUINode.get_gui_icon_button_from_node(leaders_panel.get_node(^"./new_general"))
if _create_general_button:
- _create_general_button.pressed.connect(func() -> void: print("CREATE GENERAL"))
+ _create_general_button.pressed.connect(PlayerSingleton.create_leader.bind(true))
_create_admiral_button = GUINode.get_gui_icon_button_from_node(leaders_panel.get_node(^"./new_admiral"))
if _create_admiral_button:
- _create_admiral_button.pressed.connect(func() -> void: print("CREATE ADMIRAL"))
+ _create_admiral_button.pressed.connect(PlayerSingleton.create_leader.bind(false))
_auto_create_leader_button = GUINode.get_gui_icon_button_from_node(leaders_panel.get_node(^"./auto_create"))
if _auto_create_leader_button:
- _auto_create_leader_button.toggled.connect(func(state : bool) -> void: print("AUTO CREATE LEADERS = ", state))
+ _auto_create_leader_button.toggled.connect(PlayerSingleton.set_auto_create_leaders)
_auto_create_leader_button.set_tooltip_string("MILITARY_AUTOCREATE_TOOLTIP")
_auto_assign_leader_button = GUINode.get_gui_icon_button_from_node(leaders_panel.get_node(^"./auto_assign"))
if _auto_assign_leader_button:
- _auto_assign_leader_button.toggled.connect(func(state : bool) -> void: print("AUTO ASSIGN LEADERS = ", state))
+ _auto_assign_leader_button.toggled.connect(PlayerSingleton.set_auto_assign_leaders)
_auto_assign_leader_button.set_tooltip_string("MILITARY_AUTOASSIGN_TOOLTIP")
_leader_listbox = GUINode.get_gui_listbox_from_node(military_menu.get_node(^"./leaders/leader_listbox"))
@@ -582,6 +582,7 @@ func _update_info() -> void:
break
_leader_listbox.add_child(unit_entry)
+ const military_info_leader_id_key : StringName = &"leader_id"
const military_info_leader_name_key : StringName = &"leader_name"
const military_info_leader_picture_key : StringName = &"leader_picture"
const military_info_leader_prestige_key : StringName = &"leader_prestige"
@@ -597,6 +598,13 @@ func _update_info() -> void:
var entry_menu : Panel = GUINode.get_panel_from_node(_leader_listbox.get_child(index))
var leader_dict : Dictionary = leader_entries[index]
+ var leader_id : int = leader_dict.get(military_info_leader_id_key, 0)
+ if leader_id == 0:
+ push_error("Leader ID is 0 or missing in leader dictionary for entry index ", index, ", skipping!")
+ continue
+ else:
+ entry_menu.set_meta(military_info_leader_id_key, leader_id)
+
var prestige_progress_bar : GUIProgressBar = GUINode.get_gui_progress_bar_from_node(entry_menu.get_node(^"./leader_prestige_bar"))
if prestige_progress_bar:
prestige_progress_bar.set_value_no_signal(leader_dict.get(military_info_leader_prestige_key, 0))
@@ -634,7 +642,10 @@ func _update_info() -> void:
# TODO - investigate why "set_pressed_no_signal" wasn't enough
use_leader_button.set_pressed(leader_dict.get(military_info_leader_can_be_used_key, false))
# TODO - ensure only one connection?
- use_leader_button.toggled.connect(func(state : bool) -> void: print("Toggled use_leader to ", state))
+ use_leader_button.toggled.connect(
+ func(state : bool) -> void:
+ PlayerSingleton.set_can_use_leader(entry_menu.get_meta(military_info_leader_id_key, 0) as int, state)
+ )
use_leader_button.set_tooltip_string("USE_LEADER" if use_leader_button.is_pressed() else "")
var army_label : GUILabel = GUINode.get_gui_label_from_node(entry_menu.get_node(^"./army"))
diff --git a/game/src/Game/GameSession/NationManagementScreen/TradeMenu.gd b/game/src/Game/GameSession/NationManagementScreen/TradeMenu.gd
index a5aa33cc..1ed2fb6a 100644
--- a/game/src/Game/GameSession/NationManagementScreen/TradeMenu.gd
+++ b/game/src/Game/GameSession/NationManagementScreen/TradeMenu.gd
@@ -171,6 +171,10 @@ func _ready() -> void:
trade_detail_automate_label.set_tooltip_string("AUTOMATE_TRADE_CHECK")
_trade_detail_automate_checkbox = get_gui_icon_button_from_nodepath(^"./country_trade/trade_details/automate")
if _trade_detail_automate_checkbox:
+ _trade_detail_automate_checkbox.toggled.connect(
+ func(state : bool) -> void:
+ PlayerSingleton.set_good_automated(_trade_detail_good_index, state)
+ )
_trade_detail_automate_checkbox.set_tooltip_string("AUTOMATE_TRADE_CHECK")
_trade_detail_buy_sell_stockpile_checkbox = get_gui_icon_button_from_nodepath(^"./country_trade/trade_details/sell_stockpile")
_trade_detail_buy_sell_stockpile_label = get_gui_label_from_nodepath(^"./country_trade/trade_details/sell_stockpile_label")
@@ -179,6 +183,15 @@ func _ready() -> void:
_trade_detail_stockpile_slider_amount_label = get_gui_label_from_nodepath(^"./country_trade/trade_details/slider_value")
if _trade_detail_stockpile_slider_amount_label:
_trade_detail_stockpile_slider_amount_label.set_auto_translate(false)
+ if _trade_detail_stockpile_slider_scrollbar:
+ _trade_detail_stockpile_slider_scrollbar.value_changed.connect(
+ func(value : int) -> void:
+ # const step_size : float = 2.0
+ # const c : float = log(2001.0) / 2000.0 * step_size
+ # var slider_amount : float = exp(c * value) - 1.0
+ var slider_amount : float = MenuSingleton.calculate_trade_menu_stockpile_cutoff_amount(_trade_detail_stockpile_slider_scrollbar)
+ _trade_detail_stockpile_slider_amount_label.set_text(GUINode.float_to_string_dp(slider_amount, 3 if slider_amount < 10.0 else 2))
+ )
_trade_detail_confirm_trade_button = get_gui_icon_button_from_nodepath(^"./country_trade/trade_details/confirm_trade")
if _trade_detail_confirm_trade_button:
_trade_detail_confirm_trade_button.pressed.connect(
@@ -339,12 +352,12 @@ func _update_trade_details(new_trade_detail_good_index : int = -1) -> void:
if _trade_detail_stockpile_slider_description_label:
_trade_detail_stockpile_slider_description_label.set_text("MINIMUM_STOCKPILE_TARGET" if is_selling else "MAXIMUM_STOCKPILE_TARGET")
- if _trade_detail_stockpile_slider_scrollbar:
- _trade_detail_stockpile_slider_scrollbar.set_value(trade_info.get(trade_detail_slider_value_key, 0), false)
+ #if _trade_detail_stockpile_slider_scrollbar:
+ #_trade_detail_stockpile_slider_scrollbar.set_value(trade_info.get(trade_detail_slider_value_key, 0), false)
- if _trade_detail_stockpile_slider_amount_label:
- var slider_amount : float = trade_info.get(trade_detail_slider_amount_key, 0)
- _trade_detail_stockpile_slider_amount_label.set_text(GUINode.float_to_string_dp(slider_amount, 3 if slider_amount < 10.0 else 2))
+ #if _trade_detail_stockpile_slider_amount_label:
+ #var slider_amount : float = trade_info.get(trade_detail_slider_amount_key, 0)
+ #_trade_detail_stockpile_slider_amount_label.set_text(GUINode.float_to_string_dp(slider_amount, 3 if slider_amount < 10.0 else 2))
if _trade_detail_confirm_trade_button:
_trade_detail_confirm_trade_button.set_disabled(is_automated)
@@ -394,24 +407,14 @@ func _sort_table(table : Table) -> void:
if column == TABLE_UNSORTED:
return
- var listbox : GUIListBox = _table_listboxes[table]
var sort_key : StringName = TABLE_COLUMN_KEYS[column]
- var descending : bool = _table_sort_directions[table] == SORT_DESCENDING
- var items : Array[Node] = listbox.get_children()
-
- for child : Node in items:
- listbox.remove_child(child)
-
- items.sort_custom(
+ _table_listboxes[table].sort_children(
(func(a : Node, b : Node) -> bool: return a.get_meta(sort_key) > b.get_meta(sort_key))
- if descending else
+ if _table_sort_directions[table] == SORT_DESCENDING else
(func(a : Node, b : Node) -> bool: return a.get_meta(sort_key) < b.get_meta(sort_key))
)
- for child : Node in items:
- listbox.add_child(child)
-
func _float_to_string_suffixed_dp(value : float, decimals : int) -> String:
if value < 1000:
return GUINode.float_to_string_dp(value, decimals)
diff --git a/game/src/Game/GameSession/ProvinceOverviewPanel.gd b/game/src/Game/GameSession/ProvinceOverviewPanel.gd
index 36040034..684da5d2 100644
--- a/game/src/Game/GameSession/ProvinceOverviewPanel.gd
+++ b/game/src/Game/GameSession/ProvinceOverviewPanel.gd
@@ -72,7 +72,7 @@ class BuildingSlot:
building_name.text = MenuSingleton.get_province_building_identifier(_slot_index)
_expand_button = GUINode.get_gui_icon_button_from_node(_slot_node.get_node(^"./expand"))
if _expand_button:
- _expand_button.pressed.connect(func() -> void: MenuSingleton.expand_selected_province_building(_slot_index))
+ _expand_button.pressed.connect(func() -> void: PlayerSingleton.expand_selected_province_building(_slot_index))
_expanding_icon = GUINode.get_gui_icon_from_node(_slot_node.get_node(^"./underconstruction_icon"))
_expanding_progress_bar = GUINode.get_gui_progress_bar_from_node(_slot_node.get_node(^"./building_progress"))
if _expanding_progress_bar:
@@ -117,7 +117,7 @@ var _selected_index : int:
var _province_info : Dictionary
func _ready() -> void:
- GameSingleton.province_selected.connect(_on_province_selected)
+ PlayerSingleton.province_selected.connect(_on_province_selected)
GameSingleton.gamestate_updated.connect(_update_info)
if add_gui_element("province_interface", "province_view") != OK:
@@ -394,4 +394,4 @@ func _on_province_selected(index : int) -> void:
_selected_index = index
func _on_close_button_pressed() -> void:
- GameSingleton.unset_selected_province()
+ PlayerSingleton.unset_selected_province()
diff --git a/game/src/Game/GameSession/Topbar.gd b/game/src/Game/GameSession/Topbar.gd
index ac9019f9..d0f3c29f 100644
--- a/game/src/Game/GameSession/Topbar.gd
+++ b/game/src/Game/GameSession/Topbar.gd
@@ -76,7 +76,6 @@ var _military_leadership_points_label : GUILabel
func _ready() -> void:
GameSingleton.gamestate_updated.connect(_update_info)
- GameSingleton.clock_state_changed.connect(_update_speed_controls)
add_gui_element("topbar", "topbar")
@@ -109,7 +108,7 @@ func _ready() -> void:
# Time controls
_speed_up_button = get_gui_icon_button_from_nodepath(^"./topbar/button_speedup")
if _speed_up_button:
- _speed_up_button.pressed.connect(_on_increase_speed_button_pressed)
+ _speed_up_button.pressed.connect(PlayerSingleton.increase_speed)
_speed_up_button.set_tooltip_string("TOPBAR_INC_SPEED")
var speed_up_action := InputEventAction.new()
speed_up_action.action = "time_speed_increase"
@@ -117,7 +116,7 @@ func _ready() -> void:
_speed_up_button.shortcut.events.append(speed_up_action)
_speed_down_button = get_gui_icon_button_from_nodepath(^"./topbar/button_speeddown")
if _speed_down_button:
- _speed_down_button.pressed.connect(_on_decrease_speed_button_pressed)
+ _speed_down_button.pressed.connect(PlayerSingleton.decrease_speed)
_speed_down_button.set_tooltip_string("TOPBAR_DEC_SPEED")
var speed_down_action := InputEventAction.new()
speed_down_action.action = "time_speed_decrease"
@@ -125,14 +124,14 @@ func _ready() -> void:
_speed_down_button.shortcut.events.append(speed_down_action)
_pause_bg_button = get_gui_icon_button_from_nodepath(^"./topbar/pause_bg")
if _pause_bg_button:
- _pause_bg_button.pressed.connect(_on_play_pause_button_pressed)
+ _pause_bg_button.pressed.connect(PlayerSingleton.toggle_paused)
var time_pause_action := InputEventAction.new()
time_pause_action.action = "time_pause"
_pause_bg_button.shortcut = Shortcut.new()
_pause_bg_button.shortcut.events.append(time_pause_action)
_speed_indicator_button = get_gui_icon_button_from_nodepath(^"./topbar/speed_indicator")
if _speed_indicator_button:
- _speed_indicator_button.pressed.connect(_on_play_pause_button_pressed)
+ _speed_indicator_button.pressed.connect(PlayerSingleton.toggle_paused)
_date_label = get_gui_label_from_nodepath(^"./topbar/DateText")
# Nation management screens
@@ -280,13 +279,11 @@ func _ready() -> void:
_military_leadership_points_label.set_auto_translate(false)
_update_info()
- _update_speed_controls()
func _notification(what : int) -> void:
match what:
NOTIFICATION_TRANSLATION_CHANGED:
_update_info()
- _update_speed_controls()
enum CountryStatus {
GREAT_POWER,
@@ -298,6 +295,8 @@ enum CountryStatus {
}
func _update_info() -> void:
+ _update_speed_controls()
+
var topbar_info : Dictionary = MenuSingleton.get_topbar_info()
## Country info
@@ -604,24 +603,6 @@ func _update_speed_controls() -> void:
)
_speed_indicator_button.set_icon_index(index)
-# REQUIREMENTS:
-# * UIFUN-71
-func _on_play_pause_button_pressed() -> void:
- print("Toggling pause!")
- MenuSingleton.toggle_paused()
-
-# REQUIREMENTS:
-# * UIFUN-72
-func _on_increase_speed_button_pressed() -> void:
- print("Speed up!")
- MenuSingleton.increase_speed()
-
-# REQUIREMENTS:
-# * UIFUN-73
-func _on_decrease_speed_button_pressed() -> void:
- print("Speed down!")
- MenuSingleton.decrease_speed()
-
func _on_update_active_nation_management_screen(active_screen : NationManagement.Screen) -> void:
for screen : NationManagement.Screen in _nation_management_buttons:
_nation_management_buttons[screen].set_icon_index(1 + int(screen == active_screen))
diff --git a/game/src/Game/GameStart.tscn b/game/src/Game/GameStart.tscn
index 3b3a41fb..dc264813 100644
--- a/game/src/Game/GameStart.tscn
+++ b/game/src/Game/GameStart.tscn
@@ -56,8 +56,8 @@ expand = true
process_mode = 2
disable_3d = true
title = "VIC2_DIR_DIALOG_TITLE"
-size = Vector2i(935, 159)
-ok_button_text = "VIC2_DIR_DIALOG_SELECT"
+size = Vector2i(935, 175)
+ok_button_text = "Select Current Folder"
cancel_button_text = "VIC2_DIR_DIALOG_CANCEL"
mode_overrides_title = false
file_mode = 2
diff --git a/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd b/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
index bb8026b0..992da99d 100644
--- a/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
+++ b/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
@@ -183,5 +183,5 @@ func _on_map_view_ready() -> void:
pass
func _on_map_view_province_clicked(_index: int) -> void:
- # TODO: need to be able to call something like GameSingleton.set_viewed_country_by_province_index(index) here
+ # TODO: need to be able to call something like PlayerSingleton.set_player_country_by_province_index(index) here
pass
diff --git a/game/src/Game/MusicConductor/MusicConductor.gd b/game/src/Game/MusicConductor/MusicConductor.gd
index ade8fb4d..df1b1ed3 100644
--- a/game/src/Game/MusicConductor/MusicConductor.gd
+++ b/game/src/Game/MusicConductor/MusicConductor.gd
@@ -67,7 +67,7 @@ func toggle_play_pause() -> void:
func start_current_song() -> void:
_audio_stream_player.stream = _available_songs[_selected_track].song_stream
- _audio_stream_player.play()
+ # _audio_stream_player.play()
song_started.emit(_selected_track)
# REQUIREMENTS