From f51d8fa1e7048d858747e4041c9ede3d79682f18 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 4 Feb 2025 23:58:20 +0000 Subject: [PATCH 1/2] WIP - PlayerSingleton managing game actions --- extension/deps/openvic-simulation | 2 +- extension/doc_classes/GameSingleton.xml | 43 ---- extension/doc_classes/MenuSingleton.xml | 27 --- extension/doc_classes/PlayerSingleton.xml | 78 +++++++ .../src/openvic-extension/register_types.cpp | 9 + .../singletons/GameSingleton.cpp | 89 +------- .../singletons/GameSingleton.hpp | 13 +- .../singletons/MenuSingleton.cpp | 70 +----- .../singletons/MenuSingleton.hpp | 13 +- .../singletons/MilitaryMenu.cpp | 155 +++++-------- .../singletons/ModelSingleton.cpp | 2 +- .../singletons/ModelSingleton.hpp | 2 +- .../singletons/PlayerSingleton.cpp | 205 ++++++++++++++++++ .../singletons/PlayerSingleton.hpp | 50 +++++ .../singletons/PopulationMenu.cpp | 2 +- .../singletons/TradeMenu.cpp | 16 +- game/src/Game/GameSession/GameSession.gd | 6 +- game/src/Game/GameSession/MapView.gd | 2 +- .../NationManagementScreen/MilitaryMenu.gd | 4 +- .../Game/GameSession/ProvinceOverviewPanel.gd | 6 +- game/src/Game/GameSession/Topbar.gd | 31 +-- game/src/Game/GameStart.tscn | 4 +- game/src/Game/Menu/LobbyMenu/LobbyMenu.gd | 2 +- .../src/Game/MusicConductor/MusicConductor.gd | 2 +- 24 files changed, 443 insertions(+), 390 deletions(-) create mode 100644 extension/doc_classes/PlayerSingleton.xml create mode 100644 extension/src/openvic-extension/singletons/PlayerSingleton.cpp create mode 100644 extension/src/openvic-extension/singletons/PlayerSingleton.hpp diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 4c64f2c6..675aefc1 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 4c64f2c6792cd101fe1dc81fa9671e8df7ae4601 +Subproject commit 675aefc12c26aab5e29d001dde9ac4e886f12689 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..5916e3d7 100644 --- a/extension/doc_classes/MenuSingleton.xml +++ b/extension/doc_classes/MenuSingleton.xml @@ -17,17 +17,6 @@ - - - - - - - - - - - @@ -191,11 +180,6 @@ - - - - - @@ -248,12 +232,6 @@ - - - - - - @@ -270,11 +248,6 @@ - - - - - diff --git a/extension/doc_classes/PlayerSingleton.xml b/extension/doc_classes/PlayerSingleton.xml new file mode 100644 index 00000000..f5fb60fb --- /dev/null +++ b/extension/doc_classes/PlayerSingleton.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extension/src/openvic-extension/register_types.cpp b/extension/src/openvic-extension/register_types.cpp index bfd5f0e5..15710452 100644 --- a/extension/src/openvic-extension/register_types.cpp +++ b/extension/src/openvic-extension/register_types.cpp @@ -29,6 +29,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; @@ -43,6 +44,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) { @@ -85,6 +87,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(); @@ -148,6 +154,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/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..4d455858 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,11 +339,7 @@ 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); @@ -1065,19 +1059,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 +1089,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 +1445,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 +1454,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..627713b0 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp @@ -25,7 +25,7 @@ namespace OpenVic { struct ModifierValue; struct ModifierSum; struct RuleSet; - struct LeaderBase; + struct LeaderInstance; class MenuSingleton : public godot::Object { GDCLASS(MenuSingleton, godot::Object) @@ -104,7 +104,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 +189,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,11 +197,7 @@ 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; @@ -243,9 +238,9 @@ namespace OpenVic { godot::Dictionary get_trade_menu_tables_info() const; /* 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..684e8519 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,22 +15,21 @@ 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()) { @@ -55,46 +55,18 @@ 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()); - } - } - }; - - 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) + " "; + // Generic data + leader_dict[military_info_leader_can_be_used_key] = leader.get_can_be_used(); - branched_section(static_cast(leader), leader_dict); - } break; + 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()); - default: - UtilityFunctions::push_error( - "Invalid branch type \"", static_cast(leader.get_branch()), "\" for leader \"", - Utilities::std_to_godot_string(leader.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()); + } } } @@ -210,7 +182,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 +238,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(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()); - 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()); - - 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 +261,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 +270,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 +300,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 +323,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 +387,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 +608,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 +623,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 +658,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 +666,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 +713,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..24f69bb4 --- /dev/null +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp @@ -0,0 +1,205 @@ +#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() { + OV_BIND_METHOD(PlayerSingleton::set_player_country_by_province_index, { "province_index" }); + OV_BIND_METHOD(PlayerSingleton::get_player_country_capital_position); + + 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); + + OV_BIND_METHOD(PlayerSingleton::toggle_paused); + OV_BIND_METHOD(PlayerSingleton::increase_speed); + OV_BIND_METHOD(PlayerSingleton::decrease_speed); + + OV_BIND_METHOD(PlayerSingleton::set_auto_create_leaders, { "value" }); + OV_BIND_METHOD(PlayerSingleton::set_auto_assign_leaders, { "value" }); + + OV_BIND_METHOD(PlayerSingleton::expand_selected_province_building, { "building_index" }); + + 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; +} + +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); + + 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 {}; +} + +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; +} + +void PlayerSingleton::toggle_paused() { + 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() { + 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() { + 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::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::expand_selected_province_building(int32_t building_index) { + 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 } + ); +} diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp new file mode 100644 index 00000000..e8260660 --- /dev/null +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp @@ -0,0 +1,50 @@ +#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(); + + 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; + + 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; + + void toggle_paused(); + void increase_speed(); + void decrease_speed(); + + void set_auto_create_leaders(bool value) const; + void set_auto_assign_leaders(bool value) const; + + void expand_selected_province_building(int32_t building_index); + }; +} 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..03f00e55 100644 --- a/extension/src/openvic-extension/singletons/TradeMenu.cpp +++ b/extension/src/openvic-extension/singletons/TradeMenu.cpp @@ -4,6 +4,7 @@ #include "openvic-extension/classes/GUILabel.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" +#include "openvic-extension/singletons/PlayerSingleton.hpp" #include "openvic-extension/utility/Utilities.hpp" using namespace OpenVic; @@ -18,14 +19,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; @@ -123,15 +123,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; @@ -190,12 +189,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; 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..de685b2d 100644 --- a/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd +++ b/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd @@ -152,11 +152,11 @@ func _ready() -> void: _create_admiral_button.pressed.connect(func() -> void: print("CREATE ADMIRAL")) _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(func(state : bool) -> void: PlayerSingleton.set_auto_create_leaders(state)) _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(func(state : bool) -> void: PlayerSingleton.set_auto_assign_leaders(state)) _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")) 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 2951c738..0b402132 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 From 17a6b16271faabb10ae2646abb0ff0c9962e4dbe Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 7 Feb 2025 00:16:23 +0000 Subject: [PATCH 2/2] Expand use of PlayerSingleton, add game action functionality --- extension/deps/openvic-simulation | 2 +- extension/doc_classes/GUIListBox.xml | 6 ++ extension/doc_classes/MenuSingleton.xml | 6 ++ extension/doc_classes/PlayerSingleton.xml | 34 +++++++++-- .../openvic-extension/classes/GUIListBox.cpp | 31 +++++++++- .../openvic-extension/classes/GUIListBox.hpp | 2 + .../classes/GUIScrollbar.cpp | 4 +- .../classes/GUIScrollbar.hpp | 1 + .../singletons/MenuSingleton.cpp | 1 + .../singletons/MenuSingleton.hpp | 2 + .../singletons/MilitaryMenu.cpp | 7 +++ .../singletons/PlayerSingleton.cpp | 60 +++++++++++++++++-- .../singletons/PlayerSingleton.hpp | 13 ++-- .../singletons/TradeMenu.cpp | 25 ++++++-- .../NationManagementScreen/MilitaryMenu.gd | 25 +++++--- .../NationManagementScreen/TradeMenu.gd | 37 ++++++------ 16 files changed, 209 insertions(+), 47 deletions(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 675aefc1..7fda8c06 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 675aefc12c26aab5e29d001dde9ac4e886f12689 +Subproject commit 7fda8c06a4d0e186a0df131dd005290899f2f8b3 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/MenuSingleton.xml b/extension/doc_classes/MenuSingleton.xml index 5916e3d7..fa2b08bd 100644 --- a/extension/doc_classes/MenuSingleton.xml +++ b/extension/doc_classes/MenuSingleton.xml @@ -7,6 +7,12 @@ + + + + + + diff --git a/extension/doc_classes/PlayerSingleton.xml b/extension/doc_classes/PlayerSingleton.xml index f5fb60fb..3f4f2aaa 100644 --- a/extension/doc_classes/PlayerSingleton.xml +++ b/extension/doc_classes/PlayerSingleton.xml @@ -7,12 +7,18 @@ - + + - + + + + + + @@ -28,7 +34,7 @@ - + @@ -45,6 +51,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -57,7 +83,7 @@ - + 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/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp index 4d455858..7c0b3eff 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp @@ -402,6 +402,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); diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp index 627713b0..51c7f97b 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp @@ -26,6 +26,7 @@ namespace OpenVic { struct ModifierSum; struct RuleSet; struct LeaderInstance; + struct GUIScrollbar; class MenuSingleton : public godot::Object { GDCLASS(MenuSingleton, godot::Object) @@ -236,6 +237,7 @@ 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(LeaderInstance const& leader); diff --git a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp index 684e8519..a77b08b2 100644 --- a/extension/src/openvic-extension/singletons/MilitaryMenu.cpp +++ b/extension/src/openvic-extension/singletons/MilitaryMenu.cpp @@ -36,6 +36,7 @@ Dictionary MenuSingleton::make_leader_dict(LeaderInstance const& leader) { 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"; @@ -56,6 +57,8 @@ Dictionary MenuSingleton::make_leader_dict(LeaderInstance const& leader) { { // 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(); @@ -70,6 +73,10 @@ Dictionary MenuSingleton::make_leader_dict(LeaderInstance const& leader) { } } + + // TODO - make tooltip include "General" or "Admiral" based on leader type !!! + + { // Name String leader_name = Utilities::std_to_godot_string(leader.get_name()); diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.cpp b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp index 24f69bb4..6013d8a5 100644 --- a/extension/src/openvic-extension/singletons/PlayerSingleton.cpp +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.cpp @@ -28,10 +28,14 @@ void PlayerSingleton::_bind_methods() { OV_BIND_METHOD(PlayerSingleton::increase_speed); OV_BIND_METHOD(PlayerSingleton::decrease_speed); + 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" }); OV_BIND_METHOD(PlayerSingleton::expand_selected_province_building, { "building_index" }); + OV_BIND_METHOD(PlayerSingleton::set_good_automated, { "good_index", "is_automated" }); ADD_SIGNAL(MethodInfo(_signal_province_selected(), PropertyInfo(Variant::INT, "index"))); } @@ -72,7 +76,7 @@ void PlayerSingleton::set_player_country(CountryInstance const* new_player_count ); } - Logger::info("Set player country to: ", player_country); + Logger::info("Set player country to: ", player_country != nullptr ? player_country->get_identifier() : ""); game_singleton._on_gamestate_updated(); } @@ -138,7 +142,7 @@ int32_t PlayerSingleton::get_selected_province_index() const { return selected_province != nullptr ? selected_province->get_index() : ProvinceDefinition::NULL_INDEX; } -void PlayerSingleton::toggle_paused() { +void PlayerSingleton::toggle_paused() const { InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); @@ -148,7 +152,7 @@ void PlayerSingleton::toggle_paused() { ); } -void PlayerSingleton::increase_speed() { +void PlayerSingleton::increase_speed() const { InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); @@ -158,7 +162,7 @@ void PlayerSingleton::increase_speed() { ); } -void PlayerSingleton::decrease_speed() { +void PlayerSingleton::decrease_speed() const { InstanceManager* instance_manager = GameSingleton::get_singleton()->get_instance_manager(); ERR_FAIL_NULL(instance_manager); @@ -168,6 +172,28 @@ void PlayerSingleton::decrease_speed() { ); } +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); @@ -192,7 +218,19 @@ void PlayerSingleton::set_auto_assign_leaders(bool value) const { ); } -void PlayerSingleton::expand_selected_province_building(int32_t building_index) { +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 } + ); +} + +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(); @@ -203,3 +241,15 @@ void PlayerSingleton::expand_selected_province_building(int32_t building_index) std::pair { selected_province->get_index(), building_index } ); } + +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 } + ); +} diff --git a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp index e8260660..8500576a 100644 --- a/extension/src/openvic-extension/singletons/PlayerSingleton.hpp +++ b/extension/src/openvic-extension/singletons/PlayerSingleton.hpp @@ -38,13 +38,18 @@ namespace OpenVic { void unset_selected_province(); int32_t get_selected_province_index() const; - void toggle_paused(); - void increase_speed(); - void decrease_speed(); + void toggle_paused() const; + void increase_speed() const; + void decrease_speed() const; + // 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; - void expand_selected_province_building(int32_t building_index); + void expand_selected_province_building(int32_t building_index) const; + void set_good_automated(int32_t good_index, bool is_automated) const; }; } diff --git a/extension/src/openvic-extension/singletons/TradeMenu.cpp b/extension/src/openvic-extension/singletons/TradeMenu.cpp index 03f00e55..6074032c 100644 --- a/extension/src/openvic-extension/singletons/TradeMenu.cpp +++ b/extension/src/openvic-extension/singletons/TradeMenu.cpp @@ -3,6 +3,7 @@ #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" @@ -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) @@ -160,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; @@ -239,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; } @@ -319,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/NationManagementScreen/MilitaryMenu.gd b/game/src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd index de685b2d..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: PlayerSingleton.set_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: PlayerSingleton.set_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)