diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp index a7975325..37418c3a 100644 --- a/extension/src/openvic-extension/singletons/GameSingleton.cpp +++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp @@ -174,9 +174,22 @@ Error GameSingleton::setup_game(int32_t bookmark_index) { ret &= menu_singleton->_population_menu_update_provinces() == OK; // TODO - replace with actual starting country - set_viewed_country(instance_manager->get_country_instance_manager().get_country_instance_by_identifier("ENG")); + 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); + // TODO - remove this test starting research + for ( + Technology const& technology : + get_definition_manager().get_research_manager().get_technology_manager().get_technologies() + ) { + if (starting_country->can_research_tech(technology, instance_manager->get_today())) { + starting_country->start_research(technology, *instance_manager); + break; + } + } + return ERR(ret); } diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp index 4c8a523d..a658c94e 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp @@ -184,13 +184,13 @@ template requires std::same_as || std::same_as String MenuSingleton::_make_modifier_effect_contributions_tooltip( T const& modifier_sum, ModifierEffect const& effect, fixed_point_t* tech_contributions, - fixed_point_t* other_contributions, String const& prefix + fixed_point_t* other_contributions, String const& prefix, String const& suffix ) const { String result; modifier_sum.for_each_contributing_modifier( effect, - [this, &effect, tech_contributions, other_contributions, &prefix, &result]( + [this, &effect, tech_contributions, other_contributions, &prefix, &suffix, &result]( modifier_entry_t const& modifier_entry, fixed_point_t value ) -> void { using enum Modifier::modifier_type_t; @@ -222,6 +222,7 @@ String MenuSingleton::_make_modifier_effect_contributions_tooltip( result += tr(Utilities::std_to_godot_string(modifier_entry.modifier.get_identifier())); result += ": "; result += _make_modifier_effect_value_coloured(effect, value, true); + result += suffix; } ); @@ -229,10 +230,10 @@ String MenuSingleton::_make_modifier_effect_contributions_tooltip( } template String OpenVic::MenuSingleton::_make_modifier_effect_contributions_tooltip( - CountryInstance const&, ModifierEffect const&, fixed_point_t*, fixed_point_t*, String const& + CountryInstance const&, ModifierEffect const&, fixed_point_t*, fixed_point_t*, String const&, String const& ) const; template String OpenVic::MenuSingleton::_make_modifier_effect_contributions_tooltip( - ProvinceInstance const&, ModifierEffect const&, fixed_point_t*, fixed_point_t*, String const& + ProvinceInstance const&, ModifierEffect const&, fixed_point_t*, fixed_point_t*, String const&, String const& ) const; String MenuSingleton::_make_rules_tooltip(RuleSet const& rules) const { @@ -789,6 +790,9 @@ Dictionary MenuSingleton::get_topbar_info() const { return {}; } + DefinitionManager const& definition_manager = game_singleton->get_definition_manager(); + ModifierEffectCache const& modifier_effect_cache = definition_manager.get_modifier_manager().get_modifier_effect_cache(); + Dictionary ret; // Country / Ranking @@ -898,6 +902,130 @@ Dictionary MenuSingleton::get_topbar_info() const { // Budget // Technology + { + static const StringName research_key = "research"; + static const StringName research_tooltip_key = "research_tooltip"; + static const StringName research_progress_key = "research_progress"; + static const StringName literacy_key = "literacy"; + static const StringName literacy_change_key = "literacy_change"; + static const StringName research_points_key = "research_points"; + static const StringName research_points_tooltip_key = "research_points_tooltip"; + + Technology const* current_research = country->get_current_research(); + if (current_research != nullptr) { + static const StringName research_localisation_key = "TECHNOLOGYVIEW_RESEARCH_TOOLTIP"; + static const String tech_replace_key = "$TECH$"; + static const String date_replace_key = "$DATE$"; + static const StringName research_invested_localisation_key = "TECHNOLOGYVIEW_RESEARCH_INVESTED_TOOLTIP"; + static const String invested_replace_key = "$INVESTED$"; + static const String cost_replace_key = "$COST$"; + + String current_tech_localised = tr(Utilities::std_to_godot_string(current_research->get_identifier())); + + ret[research_tooltip_key] = tr(research_localisation_key).replace( + tech_replace_key, current_tech_localised + ).replace( + date_replace_key, Utilities::date_to_formatted_string(country->get_expected_research_completion_date(), false) + ) + "\n" + tr(research_invested_localisation_key).replace( + invested_replace_key, String::num_uint64(country->get_invested_research_points().to_int64_t()) + ).replace(cost_replace_key, String::num_uint64(country->get_current_research_cost().to_int64_t())); + + ret[research_key] = std::move(current_tech_localised); + + ret[research_progress_key] = country->get_research_progress().to_float(); + } else if (country->is_civilised()) { + static const StringName civilised_no_research_localisation_key = "TB_TECH_NO_CURRENT"; + static const StringName civilised_no_research_tooltip_localisation_key = "TECHNOLOGYVIEW_NO_RESEARCH_TOOLTIP"; + + ret[research_key] = tr(civilised_no_research_localisation_key); + ret[research_tooltip_key] = tr(civilised_no_research_tooltip_localisation_key); + } else { + static const String red_prefix_text = GUILabel::get_colour_marker() + String { "R" }; + static const StringName uncivilised_no_research_localisation_key = "unciv_nation"; + static const StringName uncivilised_no_research_tooltip_localisation_key = + "TECHNOLOGYVIEW_NO_RESEARCH_UNCIV_TOOLTIP"; + + ret[research_key] = red_prefix_text + tr(uncivilised_no_research_localisation_key); + ret[research_tooltip_key] = tr(uncivilised_no_research_tooltip_localisation_key); + } + + ret[literacy_key] = country->get_national_literacy().to_float(); + // TODO - set monthly literacy change (test for precision issues) + ret[literacy_change_key] = 0.0f; + + ret[research_points_key] = country->get_daily_research_points().to_float(); + + String research_points_tooltip; + + fixed_point_t daily_base_research_points; + + static const String value_replace_key = "$VALUE$"; + + for (auto const& [pop_type, research_points] : country->get_research_points_from_pop_types()) { + static const StringName pop_type_research_localisation_key = "TECH_DAILY_RESEARCHPOINTS_TOOLTIP"; + static const String pop_type_replace_key = "$POPTYPE$"; + static const String fraction_replace_key = "$FRACTION$"; + static const String optimal_replace_key = "$OPTIMAL$"; + + daily_base_research_points += research_points; + + research_points_tooltip += tr(pop_type_research_localisation_key).replace( + pop_type_replace_key, tr(Utilities::std_to_godot_string(pop_type->get_identifier())) + ).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(research_points, 2) + ).replace( + fraction_replace_key, Utilities::fixed_point_to_string_dp( + 100 * country->get_pop_type_proportion(*pop_type) / country->get_total_population(), 2 + ) + ).replace( + optimal_replace_key, Utilities::fixed_point_to_string_dp(100 * pop_type->get_research_leadership_optimum(), 2) + ) + "\n"; + } + + // Empty prefix, "\n" suffix, fitting with the potential trailing "\n" from the pop type contributions and the upcoming + // guaranteed daily base research points line. All contributions are added to daily_base_research_points. + research_points_tooltip += _make_modifier_effect_contributions_tooltip( + *country, *modifier_effect_cache.get_research_points(), nullptr, &daily_base_research_points, {}, "\n" + ); + + // The daily base research points line is guaranteed to be present, but those directly above and below it aren't, + // so this line has no newline characters of its own. Instead, potential lines above finish with newlines and + // potential (and some guaranteed) lines below start with them. + static const StringName daily_base_research_points_localisation_key = "TECH_DAILY_RESEARCHPOINTS_BASE_TOOLTIP"; + research_points_tooltip += tr(daily_base_research_points_localisation_key).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(daily_base_research_points, 2) + ); + + research_points_tooltip += _make_modifier_effect_contributions_tooltip( + *country, *modifier_effect_cache.get_research_points_modifier() + ); + + const fixed_point_t research_points_modifier_from_tech = + country->get_modifier_effect_value(*modifier_effect_cache.get_increase_research()); + if (research_points_modifier_from_tech != fixed_point_t::_0()) { + static const StringName from_technology_localisation_key = "FROM_TECHNOLOGY"; + research_points_tooltip += "\n" + tr(from_technology_localisation_key) + ": " + + _make_modifier_effect_value_coloured( + *modifier_effect_cache.get_increase_research(), research_points_modifier_from_tech, true + ); + } + + static const StringName daily_research_points_localisation_key = "TECH_DAILY_RESEARCHPOINTS_TOTAL_TOOLTIP"; + research_points_tooltip += "\n" + tr(daily_research_points_localisation_key).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(country->get_daily_research_points(), 2) + ); + + // In the base game this section is only shown when no research is set, but it's useful to show it always + research_points_tooltip += "\n" + get_tooltip_separator(); + + static const StringName accumulated_research_points_localisation_key = "RP_ACCUMULATED"; + static const String val_replace_key = "$VAL$"; + research_points_tooltip += tr(accumulated_research_points_localisation_key).replace( + val_replace_key, Utilities::fixed_point_to_string_dp(country->get_research_point_stockpile(), 1) + ); + + ret[research_points_tooltip_key] = std::move(research_points_tooltip); + } // Politics @@ -925,6 +1053,77 @@ Dictionary MenuSingleton::get_topbar_info() const { ret[mobilisation_impact_tooltip_key] = _make_mobilisation_impact_tooltip(); } + { + static const StringName leadership_key = "leadership"; + static const StringName leadership_tooltip_key = "leadership_tooltip"; + + ret[leadership_key] = country->get_leadership_point_stockpile().to_int64_t(); + + String leadership_tooltip; + + fixed_point_t monthly_base_leadership_points; + + static const String value_replace_key = "$VALUE$"; + + for (auto const& [pop_type, leadership_points] : country->get_leadership_points_from_pop_types()) { + static const StringName pop_type_leadership_localisation_key = "TECH_DAILY_LEADERSHIP_TOOLTIP"; + static const String pop_type_replace_key = "$POPTYPE$"; + static const String fraction_replace_key = "$FRACTION$"; + static const String optimal_replace_key = "$OPTIMAL$"; + + monthly_base_leadership_points += leadership_points; + + leadership_tooltip += tr(pop_type_leadership_localisation_key).replace( + pop_type_replace_key, tr(Utilities::std_to_godot_string(pop_type->get_identifier())) + ).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(leadership_points, 2) + ).replace( + fraction_replace_key, Utilities::fixed_point_to_string_dp( + 100 * country->get_pop_type_proportion(*pop_type) / country->get_total_population(), 2 + ) + ).replace( + optimal_replace_key, Utilities::fixed_point_to_string_dp(100 * pop_type->get_research_leadership_optimum(), 2) + ) + "\n"; + } + + // Empty prefix, "\n" suffix, fitting with the potential trailing "\n" from the pop type contributions and the upcoming + // guaranteed monthly base leadership points line. All contributions are added to monthly_base_leadership_points. + leadership_tooltip += _make_modifier_effect_contributions_tooltip( + *country, *modifier_effect_cache.get_leadership(), nullptr, &monthly_base_leadership_points, {}, "\n" + ); + + // The monthly base leadership points line is guaranteed to be present, but those directly above and below it aren't, + // so this line has no newline characters of its own. Instead, potential lines above finish with newlines and + // potential (and some guaranteed) lines below start with them. + static const StringName monthly_base_leadership_localisation_key = "TECH_DAILY_LEADERSHIP_BASE_TOOLTIP"; + leadership_tooltip += tr(monthly_base_leadership_localisation_key).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(monthly_base_leadership_points, 2) + ); + + leadership_tooltip += _make_modifier_effect_contributions_tooltip( + *country, *modifier_effect_cache.get_leadership_modifier() + ); + + static const StringName monthly_leadership_points_localisation_key = "TECH_DAILY_LEADERSHIP_TOTAL_TOOLTIP"; + leadership_tooltip += "\n" + tr(monthly_leadership_points_localisation_key).replace( + value_replace_key, Utilities::fixed_point_to_string_dp(country->get_monthly_leadership_points(), 2) + ); + + const fixed_point_t max_leadership_point_stockpile = + definition_manager.get_define_manager().get_military_defines().get_max_leadership_point_stockpile(); + if (country->get_leadership_point_stockpile() >= max_leadership_point_stockpile) { + leadership_tooltip += "\n" + get_tooltip_separator() + "\n"; + + static const StringName max_leadership_points_localisation_key = "TOPBAR_LEADERSHIP_MAX"; + static const String max_replace_key = "$MAX$"; + leadership_tooltip += tr(max_leadership_points_localisation_key).trim_suffix("\n").replace( + max_replace_key, Utilities::fixed_point_to_string_dp(max_leadership_point_stockpile, 1) + ); + } + + ret[leadership_tooltip_key] = std::move(leadership_tooltip); + } + return ret; } diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp index e1650a96..fb5b1d4d 100644 --- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp @@ -150,7 +150,7 @@ namespace OpenVic { requires std::same_as || std::same_as godot::String _make_modifier_effect_contributions_tooltip( T const& modifier_sum, ModifierEffect const& effect, fixed_point_t* tech_contributions = nullptr, - fixed_point_t* other_contributions = nullptr, godot::String const& prefix = "\n" + fixed_point_t* other_contributions = nullptr, godot::String const& prefix = "\n", godot::String const& suffix = {} ) const; godot::String _make_rules_tooltip(RuleSet const& rules) const; diff --git a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd index e9c151f8..f61c177b 100644 --- a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd +++ b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd @@ -648,7 +648,7 @@ func _update_pop_list() -> void: tr(&"POPULATION_CHANGED_BY"), "G+" if pop_change > 0 else "Y+" if pop_change == 0 else "R", str(pop_change) ]) if _pop_list_literacy_labels[index]: - _pop_list_literacy_labels[index].set_text("%s%%" % GUINode.float_to_string_dp(pop_row[pop_literacy_key], 2)) + _pop_list_literacy_labels[index].set_text("%s%%" % GUINode.float_to_string_dp(pop_row[pop_literacy_key] * 100, 2)) _pop_list_literacy_labels[index].set_tooltip_string("%s: §G%s%%" % [ tr(&"LIT_CHANGE"), GUINode.float_to_string_dp(pop_row[pop_literacy_key] / 64.0, 2) ]) diff --git a/game/src/Game/GameSession/Topbar.gd b/game/src/Game/GameSession/Topbar.gd index 2efff3ab..ac9019f9 100644 --- a/game/src/Game/GameSession/Topbar.gd +++ b/game/src/Game/GameSession/Topbar.gd @@ -186,14 +186,20 @@ func _ready() -> void: if _technology_progress_bar and tech_button: _technology_progress_bar.reparent(tech_button) _technology_current_research_label = get_gui_label_from_nodepath(^"./topbar/tech_current_research") - if _technology_current_research_label and tech_button: - _technology_current_research_label.reparent(tech_button) + if _technology_current_research_label: + _technology_current_research_label.set_auto_translate(false) + if tech_button: + _technology_current_research_label.reparent(tech_button) _technology_literacy_label = get_gui_label_from_nodepath(^"./topbar/tech_literacy_value") - if _technology_literacy_label and tech_button: - _technology_literacy_label.reparent(tech_button) + if _technology_literacy_label: + _technology_literacy_label.set_auto_translate(false) + if tech_button: + _technology_literacy_label.reparent(tech_button) _technology_research_points_label = get_gui_label_from_nodepath(^"./topbar/topbar_researchpoints_value") - if _technology_research_points_label and tech_button: - _technology_research_points_label.reparent(tech_button) + if _technology_research_points_label: + _technology_research_points_label.set_auto_translate(false) + if tech_button: + _technology_research_points_label.reparent(tech_button) # Politics _politics_party_icon = get_gui_icon_from_nodepath(^"./topbar/politics_party_icon") @@ -260,11 +266,18 @@ func _ready() -> void: # Military _military_army_size_label = get_gui_label_from_nodepath(^"./topbar/military_army_value") if _military_army_size_label: + _military_army_size_label.set_auto_translate(false) _military_army_size_label.set_text("§Y$CURR$/$MAX$") _military_army_size_label.set_tooltip_string("TOPBAR_ARMY_TOOLTIP") _military_navy_size_label = get_gui_label_from_nodepath(^"./topbar/military_navy_value") + if _military_navy_size_label: + _military_navy_size_label.set_auto_translate(false) _military_mobilisation_size_label = get_gui_label_from_nodepath(^"./topbar/military_manpower_value") + if _military_mobilisation_size_label: + _military_mobilisation_size_label.set_auto_translate(false) _military_leadership_points_label = get_gui_label_from_nodepath(^"./topbar/military_leadership_value") + if _military_leadership_points_label: + _military_leadership_points_label.set_auto_translate(false) _update_info() _update_speed_controls() @@ -414,27 +427,33 @@ func _update_info() -> void: ]) ## Technology + const research_key : StringName = &"research" + const research_tooltip_key : StringName = &"research_tooltip" + const research_progress_key : StringName = &"research_progress" + const literacy_key : StringName = &"literacy" + const literacy_change_key : StringName = &"literacy_change" + const research_points_key : StringName = &"research_points" + const research_points_tooltip_key : StringName = &"research_points_tooltip" + if _technology_progress_bar: - pass # TODO - set tech progress + _technology_progress_bar.set_value(topbar_info.get(research_progress_key, 0)) if _technology_current_research_label: - # TODO - set current research or "unciv_nation" (in red) if uncivilised - _technology_current_research_label.set_text("TB_TECH_NO_CURRENT") - _technology_current_research_label.set_tooltip_string("TECHNOLOGYVIEW_NO_RESEARCH_TOOLTIP") + _technology_current_research_label.set_text(topbar_info.get(research_key, "")) + _technology_current_research_label.set_tooltip_string(topbar_info.get(research_tooltip_key, "")) if _technology_literacy_label: - var literacy_float : float = 80.0 - var literacy_string : String = GUINode.float_to_string_dp(80.0, 1) + var literacy_float : float = topbar_info.get(literacy_key, 0.0) * 100 + var literacy_string : String = GUINode.float_to_string_dp(literacy_float, 1) _technology_literacy_label.set_text("§Y%s§W%%" % literacy_string) - _technology_literacy_label.set_tooltip_string_and_substitution_dict("TOPBAR_AVG_LITERACY", { "AVG": literacy_string }) + _technology_literacy_label.set_tooltip_string( + tr(&"TOPBAR_AVG_LITERACY").replace("$AVG$", literacy_string) + "\n" + tr(&"TOPBAR_AVG_CHANGE").replace( + "$VAL$", GUINode.float_to_string_dp(topbar_info.get(literacy_change_key, 0.0), 4)) + ) if _technology_research_points_label: - _technology_research_points_label.set_text("§Y%s" % GUINode.float_to_string_dp(10.0, 2)) - # TODO - test tooltip, replace with actual values from the simulation - _technology_research_points_label.set_tooltip_string_and_substitution_dict("TECH_DAILY_RESEARCHPOINTS_TOOLTIP", { - "POPTYPE": "Clergymen", "VALUE": GUINode.float_to_string_dp(1.42, 2), - "FRACTION": GUINode.float_to_string_dp(0.95, 2), "OPTIMAL": GUINode.float_to_string_dp(2, 2) - }) + _technology_research_points_label.set_text("§Y%s" % GUINode.float_to_string_dp(topbar_info.get(research_points_key, 0), 2)) + _technology_research_points_label.set_tooltip_string(topbar_info.get(research_points_tooltip_key, "")) ## Politics if _politics_party_icon: @@ -545,9 +564,12 @@ func _update_info() -> void: tr(&"TOPBAR_MOBILIZE_TOOLTIP").replace("$CURR$", mobilisation_regiments) + "\n\n" + topbar_info.get(mobilisation_impact_tooltip_key, "") ) + const leadership_key : StringName = &"leadership" + const leadership_tooltip_key : StringName = &"leadership_tooltip" + if _military_leadership_points_label: - _military_leadership_points_label.set_text("§Y%d" % 0) - # TODO - leadership points tooltip + _military_leadership_points_label.set_text("§Y%d" % topbar_info.get(leadership_key, 0)) + _military_leadership_points_label.set_tooltip_string(topbar_info.get(leadership_tooltip_key, "")) func _update_speed_controls() -> void: var paused : bool = MenuSingleton.is_paused()