diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation
index 51e83e38..384f3d99 160000
--- a/extension/deps/openvic-simulation
+++ b/extension/deps/openvic-simulation
@@ -1 +1 @@
-Subproject commit 51e83e38986217aa6b5f5a5a1d714aa13a0bff64
+Subproject commit 384f3d99391cb8aad3e684c66035b1913adef8a3
diff --git a/extension/doc_classes/GameSingleton.xml b/extension/doc_classes/GameSingleton.xml
index a84a9f8e..628cc9af 100644
--- a/extension/doc_classes/GameSingleton.xml
+++ b/extension/doc_classes/GameSingleton.xml
@@ -7,6 +7,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/extension/src/openvic-extension/classes/GUIListBox.cpp b/extension/src/openvic-extension/classes/GUIListBox.cpp
index 958807fd..39ec9746 100644
--- a/extension/src/openvic-extension/classes/GUIListBox.cpp
+++ b/extension/src/openvic-extension/classes/GUIListBox.cpp
@@ -270,7 +270,7 @@ Error GUIListBox::set_gui_listbox(GUI::ListBox const* new_gui_listbox) {
if (scrollbar_control != nullptr) {
scrollbar = Object::cast_to(scrollbar_control);
if (scrollbar != nullptr) {
- add_child(scrollbar, false, INTERNAL_MODE_FRONT);
+ add_child(scrollbar, false, INTERNAL_MODE_BACK);
const Size2 size = Utilities::to_godot_fvec2(gui_listbox->get_size());
Vector2 position = Utilities::to_godot_fvec2(gui_listbox->get_scrollbar_offset());
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index d6148008..56d76701 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -47,6 +47,7 @@ void GameSingleton::_bind_methods() {
OV_BIND_SMETHOD(search_for_game_path, { "hint_path" }, DEFVAL(String {}));
OV_BIND_METHOD(GameSingleton::lookup_file_path, { "path" });
+ OV_BIND_METHOD(GameSingleton::get_bookmark_info);
OV_BIND_METHOD(GameSingleton::setup_game, { "bookmark_index" });
OV_BIND_METHOD(GameSingleton::start_game_session);
@@ -56,6 +57,7 @@ void GameSingleton::_bind_methods() {
OV_BIND_METHOD(GameSingleton::get_map_height);
OV_BIND_METHOD(GameSingleton::get_map_dims);
OV_BIND_METHOD(GameSingleton::get_map_aspect_ratio);
+ OV_BIND_METHOD(GameSingleton::get_bookmark_start_position);
OV_BIND_METHOD(GameSingleton::get_terrain_texture);
OV_BIND_METHOD(GameSingleton::get_flag_dims);
OV_BIND_METHOD(GameSingleton::get_flag_sheet_texture);
@@ -128,6 +130,27 @@ void GameSingleton::setup_logger() {
});
}
+TypedArray GameSingleton::get_bookmark_info() const {
+ static const StringName bookmark_info_name_key = "bookmark_name";
+ static const StringName bookmark_info_date_key = "bookmark_date";
+
+ TypedArray results;
+
+ BookmarkManager const& bookmark_manager =
+ game_manager.get_definition_manager().get_history_manager().get_bookmark_manager();
+
+ for (Bookmark const& bookmark : bookmark_manager.get_bookmarks()) {
+ Dictionary bookmark_info;
+
+ bookmark_info[bookmark_info_name_key] = Utilities::std_to_godot_string(bookmark.get_name());
+ bookmark_info[bookmark_info_date_key] = Utilities::date_to_formatted_string(bookmark.get_date(), false);
+
+ results.push_back(std::move(bookmark_info));
+ }
+
+ return results;
+}
+
Error GameSingleton::setup_game(int32_t bookmark_index) {
Bookmark const* bookmark = game_manager.get_definition_manager().get_history_manager().get_bookmark_manager()
.get_bookmark_by_index(bookmark_index);
@@ -186,6 +209,18 @@ Vector2 GameSingleton::normalise_map_position(fvec2_t const& position) const {
return Utilities::to_godot_fvec2(position) / get_map_dims();
}
+Vector2 GameSingleton::get_bookmark_start_position() const {
+ InstanceManager const* instance_manager = get_instance_manager();
+ ERR_FAIL_NULL_V(instance_manager, {});
+
+ // TODO - What if game started from save rather than bookmark? Does a save game store which bookmark it originated from?
+
+ Bookmark const* bookmark = instance_manager->get_bookmark();
+ ERR_FAIL_NULL_V(bookmark, {});
+
+ return normalise_map_position(bookmark->get_initial_camera_position());
+}
+
Ref GameSingleton::get_terrain_texture() const {
return terrain_texture;
}
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.hpp b/extension/src/openvic-extension/singletons/GameSingleton.hpp
index aa801415..e28bfa5c 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.hpp
@@ -80,6 +80,8 @@ namespace OpenVic {
static godot::String search_for_game_path(godot::String const& hint_path = {});
godot::String lookup_file_path(godot::String const& path) const;
+ godot::TypedArray get_bookmark_info() const;
+
/* Post-load/restart game setup - reset the game to post-load state and load the specified bookmark. */
godot::Error setup_game(int32_t bookmark_index);
godot::Error start_game_session();
@@ -91,6 +93,7 @@ namespace OpenVic {
godot::Vector2i get_map_dims() const;
float get_map_aspect_ratio() const;
godot::Vector2 normalise_map_position(fvec2_t const& position) const;
+ godot::Vector2 get_bookmark_start_position() const;
/* The cosmetic terrain textures stored in a Texture2DArray. */
godot::Ref get_terrain_texture() const;
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
index 75d03e5a..854b9bb6 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
@@ -51,6 +51,7 @@ String MenuSingleton::get_state_name(State const& state) const {
if (!named) {
// Capital province name
+ // TODO - confirm capital is never null?
name = tr(GUINode::format_province_name(Utilities::std_to_godot_string(state.get_capital()->get_identifier())));
if (!owned) {
@@ -117,18 +118,13 @@ String MenuSingleton::make_modifier_effects_tooltip(ModifierValue const& modifie
String result;
for (auto const& [effect, value] : modifier.get_values()) {
- if (!result.is_empty()) {
- result += "\n";
- }
-
- result += tr(Utilities::std_to_godot_string(effect->get_localisation_key()));
-
static const String post_name_text = ": " + GUILabel::get_colour_marker();
- result += post_name_text;
+
+ result += "\n" + tr(Utilities::std_to_godot_string(effect->get_localisation_key())) + post_name_text;
if (value == 0) {
result += "Y";
- } else if (effect->is_positive_good() == value > 0) {
+ } else if (effect->is_positive_good() == (value > 0)) {
result += "G";
} else {
result += "R";
@@ -183,11 +179,7 @@ String MenuSingleton::make_rules_tooltip(RuleSet const& rules) const {
for (auto const& [rule_group, rule_map] : rules.get_rule_groups()) {
for (auto const& [rule, enabled] : rule_map) {
- if (!result.is_empty()) {
- result += "\n";
- }
-
- result += tr(Utilities::std_to_godot_string(rule->get_localisation_key()))
+ result += "\n" + tr(Utilities::std_to_godot_string(rule->get_localisation_key()))
+ (enabled ? enabled_text : disabled_text);
}
}
@@ -730,11 +722,15 @@ Dictionary MenuSingleton::get_topbar_info() const {
{
String military_power_tooltip;
+ static const StringName military_power_from_land_key = "MIL_FROM_TROOPS";
+ static const StringName military_power_from_sea_key = "MIL_FROM_CAP_SHIPS";
+ static const StringName military_power_from_leaders_key = "MIL_FROM_LEADERS";
+
for (auto const& [source, power] : {
std::pair
- { "MIL_FROM_TROOPS", country->get_military_power_from_land() },
- { "MIL_FROM_CAP_SHIPS", country->get_military_power_from_sea() },
- { "MIL_FROM_LEADERS", country->get_military_power_from_leaders() }
+ { military_power_from_land_key, country->get_military_power_from_land() },
+ { military_power_from_sea_key, country->get_military_power_from_sea() },
+ { military_power_from_leaders_key, country->get_military_power_from_leaders() }
}) {
if (power != 0) {
military_power_tooltip += "\n" + tr(source) + ": " + GUILabel::get_colour_marker() + "Y"
@@ -873,9 +869,11 @@ String MenuSingleton::get_longform_date() const {
InstanceManager const* instance_manager = game_singleton->get_instance_manager();
ERR_FAIL_NULL_V(instance_manager, {});
- return Utilities::date_to_formatted_string(instance_manager->get_today());
+ return Utilities::date_to_formatted_string(instance_manager->get_today(), true);
}
+/* Find/Search Panel */
+
Error MenuSingleton::generate_search_cache() {
GameSingleton const* game_singleton = GameSingleton::get_singleton();
ERR_FAIL_NULL_V(game_singleton, FAILED);
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
index 0d38b649..786a277a 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
@@ -124,6 +124,8 @@ namespace OpenVic {
godot::String get_country_name(CountryInstance const& country) const;
godot::String get_country_adjective(CountryInstance const& country) const;
+ // Modifier effect and rule tooltips begin with a newline character (unless they're empty), as they're always
+ // added after a starting/title section.
godot::String make_modifier_effects_tooltip(ModifierValue const& modifier) const;
godot::String make_rules_tooltip(RuleSet const& rules) const;
diff --git a/extension/src/openvic-extension/utility/Utilities.cpp b/extension/src/openvic-extension/utility/Utilities.cpp
index 1fcdea8d..70d2aa34 100644
--- a/extension/src/openvic-extension/utility/Utilities.cpp
+++ b/extension/src/openvic-extension/utility/Utilities.cpp
@@ -68,15 +68,22 @@ String Utilities::float_to_string_dp_dynamic(float val) {
return float_to_string_dp(val, abs_val < 2.0f ? 3 : abs_val < 10.0f ? 2 : 1);
}
-/* Date formatted like this: "January 1, 1836" (with the month localised, if possible). */
-String Utilities::date_to_formatted_string(Date date) {
- const String month_name = Utilities::std_to_godot_string(date.get_month_name());
- const String day_and_year = " " + String::num_int64(date.get_day()) + ", " + String::num_int64(date.get_year());
+/* Date formatted like one of these, with the month localised if possible:
+ * - "1 January, 1836" (if month_first is false)
+ * - "January 1, 1836" (if month_first is true) */
+String Utilities::date_to_formatted_string(Date date, bool month_first) {
+ String day = String::num_int64(date.get_day());
+ String month = Utilities::std_to_godot_string(date.get_month_name());
TranslationServer const* server = TranslationServer::get_singleton();
if (server != nullptr) {
- return server->translate(month_name) + day_and_year;
+ month = server->translate(month);
+ }
+ String year = String::num_int64(date.get_year());
+
+ if (month_first) {
+ return month + " " + day + ", " + year;
} else {
- return month_name + day_and_year;
+ return day + " " + month + ", " + year;
}
}
diff --git a/extension/src/openvic-extension/utility/Utilities.hpp b/extension/src/openvic-extension/utility/Utilities.hpp
index c1739388..98eabac8 100644
--- a/extension/src/openvic-extension/utility/Utilities.hpp
+++ b/extension/src/openvic-extension/utility/Utilities.hpp
@@ -39,7 +39,7 @@ namespace OpenVic::Utilities {
return static_cast(val);
}
- godot::String date_to_formatted_string(Date date);
+ godot::String date_to_formatted_string(Date date, bool month_first);
_FORCE_INLINE_ godot::Color to_godot_color(IsColour auto colour) {
return { colour.redf(), colour.greenf(), colour.bluef(), colour.alphaf() };
diff --git a/game/src/Game/GameSession/MapView.gd b/game/src/Game/GameSession/MapView.gd
index 1d837f85..0326edd8 100644
--- a/game/src/Game/GameSession/MapView.gd
+++ b/game/src/Game/GameSession/MapView.gd
@@ -34,7 +34,7 @@ var _mouse_over_viewport : bool = true
# hence why it is not exported and just has _zoom_target_max as a placeholder.
var _zoom_target : float = _zoom_target_max:
get: return _zoom_target
- set(v): _zoom_target = clamp(v, _zoom_target_min, _zoom_target_max)
+ set(v): _zoom_target = clampf(v, _zoom_target_min, _zoom_target_max)
const _zoom_position_multiplier = 3.14159 # Horizontal movement coefficient during zoom
var _zoom_position : Vector2
@@ -72,11 +72,6 @@ func _ready() -> void:
push_error("MapView's _camera variable hasn't been set!")
return
- # Start just under the parchment threshold
- _camera.position.y = _zoom_parchment_threshold - _zoom_target_step
- _zoom_target = _camera.position.y
- _update_view_states(true)
-
if not _map_mesh_instance:
push_error("MapView's _map_mesh_instance variable hasn't been set!")
return
@@ -108,6 +103,17 @@ func _ready() -> void:
GameSingleton.province_selected.connect(_on_province_selected)
+ # TODO - start looking at the player country's capital (the bookmark start position is meant
+ # for the lobby map when first selecting the bookmark, not for when actually entering the game)
+
+ # Start at the bookmark's start position
+ _camera.position = _map_to_world_coords(GameSingleton.get_bookmark_start_position())
+
+ # Start zoomed out with the parchment map active
+ _camera.position.y = _zoom_parchment_threshold * 1.5
+ _zoom_target = _camera.position.y
+ _update_view_states(true)
+
if not _map_background_instance:
push_error("MapView's _map_background_instance variable hasn't been set!")
return
@@ -293,7 +299,7 @@ func _edge_scrolling_vector() -> Vector2:
func _clamp_over_map() -> void:
_camera.position.x = _map_mesh_corner.x + fposmod(_camera.position.x - _map_mesh_corner.x, _map_mesh_dims.x)
- _camera.position.z = clamp(_camera.position.z, _map_mesh_corner.y, _map_mesh_corner.y + _map_mesh_dims.y)
+ _camera.position.z = clampf(_camera.position.z, _map_mesh_corner.y, _map_mesh_corner.y + _map_mesh_dims.y)
func _update_view_states(force_signal : bool) -> void:
var new_is_parchment_view : bool = _camera.position.y >= _zoom_parchment_threshold - _zoom_epsilon
diff --git a/game/src/Game/GameSession/ModelManager.gd b/game/src/Game/GameSession/ModelManager.gd
index 8cec49dc..de9de547 100644
--- a/game/src/Game/GameSession/ModelManager.gd
+++ b/game/src/Game/GameSession/ModelManager.gd
@@ -32,8 +32,10 @@ func _generate_unit(unit_dict : Dictionary) -> void:
# This must be a UnitModel so we can attach the rider to it
var mount_model : Node3D = _generate_model(unit_dict[mount_model_key], unit_dict[culture_key], true)
if mount_model:
- mount_model.attach_model(unit_dict[mount_attach_node_key], model)
- model = mount_model
+ if mount_model.attach_model(unit_dict[mount_attach_node_key], model) == OK:
+ model = mount_model
+ else:
+ mount_model.free()
var rotation : float = unit_dict.get(rotation_key, 0.0)
@@ -127,8 +129,8 @@ func _generate_model(model_dict : Dictionary, culture : String = "", is_unit : b
# Attachments
for attachment_dict : Dictionary in model_dict.get(attachments_key, []):
var attachment_model : Node3D = _generate_model(attachment_dict[attachment_model_key], culture)
- if attachment_model:
- model.attach_model(attachment_dict[attachment_node_key], attachment_model)
+ if attachment_model and model.attach_model(attachment_dict[attachment_node_key], attachment_model) != OK:
+ attachment_model.free()
if culture:
const gun_bone_name : String = "GunNode"
@@ -136,15 +138,15 @@ func _generate_model(model_dict : Dictionary, culture : String = "", is_unit : b
var gun_dict : Dictionary = ModelSingleton.get_cultural_gun_model(culture)
if gun_dict:
var gun_model : Node3D = _generate_model(gun_dict, culture)
- if gun_model:
- model.attach_model(gun_bone_name, gun_model)
+ if gun_model and model.attach_model(gun_bone_name, gun_model) != OK:
+ gun_model.free()
const helmet_bone_name : String = "HelmetNode"
if model.has_bone(helmet_bone_name):
var helmet_dict : Dictionary = ModelSingleton.get_cultural_helmet_model(culture)
if helmet_dict:
var helmet_model : Node3D = _generate_model(helmet_dict, culture)
- if helmet_model:
- model.attach_model(helmet_bone_name, helmet_model)
+ if helmet_model and model.attach_model(helmet_bone_name, helmet_model) != OK:
+ helmet_model.free()
return model
diff --git a/game/src/Game/GameSession/NationManagementScreen/BudgetMenu.gd b/game/src/Game/GameSession/NationManagementScreen/BudgetMenu.gd
index 10446e3c..87b63ab0 100644
--- a/game/src/Game/GameSession/NationManagementScreen/BudgetMenu.gd
+++ b/game/src/Game/GameSession/NationManagementScreen/BudgetMenu.gd
@@ -43,11 +43,10 @@ var _debt_chart : GUIPieChart
const _screen : NationManagement.Screen = NationManagement.Screen.BUDGET
# TODO - testing function, should be replaced with calls to SIM which trigger UI updates through gamestate_updated
-func _on_tax_slider_changed(slider : GUIScrollbar, label : GUILabel, tooltip : String, value : int) -> void:
+func _on_tax_slider_changed(slider : GUIScrollbar, label : GUILabel, tooltip : StringName, value : int) -> void:
label.text = "%s¤" % GUINode.float_to_string_dp(value, 3 if abs(value) < 1000 else 1)
slider.set_tooltip_string("%s: §Y%s%%" % [tr(tooltip), GUINode.float_to_string_dp(value, 1)])
-
func _ready() -> void:
GameSingleton.gamestate_updated.connect(_update_info)
@@ -97,21 +96,21 @@ func _ready() -> void:
if _lower_class_slider and _lower_class_label:
_lower_class_slider.value_changed.connect(
func (value : int) -> void:
- _on_tax_slider_changed(_lower_class_slider, _lower_class_label, "BUDGET_TAX_POOR", value)
+ _on_tax_slider_changed(_lower_class_slider, _lower_class_label, &"BUDGET_TAX_POOR", value)
)
_lower_class_slider.emit_value_changed()
var _middle_class_slider : GUIScrollbar = get_gui_scrollbar_from_nodepath(^"./country_budget/tax_1_slider")
if _middle_class_slider and _middle_class_label:
_middle_class_slider.value_changed.connect(
func (value : int) -> void:
- _on_tax_slider_changed(_middle_class_slider, _middle_class_label, "BUDGET_TAX_MIDDLE", value)
+ _on_tax_slider_changed(_middle_class_slider, _middle_class_label, &"BUDGET_TAX_MIDDLE", value)
)
_middle_class_slider.emit_value_changed()
var _upper_class_slider : GUIScrollbar = get_gui_scrollbar_from_nodepath(^"./country_budget/tax_2_slider")
if _upper_class_slider and _upper_class_label:
_upper_class_slider.value_changed.connect(
func (value : int) -> void:
- _on_tax_slider_changed(_upper_class_slider, _upper_class_label, "BUDGET_TAX_RICH", value)
+ _on_tax_slider_changed(_upper_class_slider, _upper_class_label, &"BUDGET_TAX_RICH", value)
)
_upper_class_slider.emit_value_changed()
diff --git a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
index b872db0f..e9c151f8 100644
--- a/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
+++ b/game/src/Game/GameSession/NationManagementScreen/PopulationMenu.gd
@@ -600,7 +600,7 @@ func _update_pop_list() -> void:
var unemployment : float = pop_row[pop_unemployment_key]
_pop_list_unemployment_progressbars[index].set_value_no_signal(unemployment)
_pop_list_unemployment_progressbars[index].set_tooltip_string("%s: §Y%s%%" % [
- tr("UNEMPLOYMENT"), GUINode.float_to_string_dp(unemployment * 100.0, 3)
+ tr(&"UNEMPLOYMENT"), GUINode.float_to_string_dp(unemployment * 100.0, 3)
])
if _pop_list_cash_labels[index]:
_pop_list_cash_labels[index].set_text("%s¤" % GUINode.float_to_string_dp(pop_row[pop_cash_key], 2))
@@ -645,12 +645,12 @@ func _update_pop_list() -> void:
var pop_change : int = pop_row[pop_size_change_key]
_pop_list_size_change_icons[index].set_icon_index(get_growth_icon_index(pop_change))
_pop_list_size_change_icons[index].set_tooltip_string("%s §%s%s" % [
- tr("POPULATION_CHANGED_BY"), "G+" if pop_change > 0 else "Y+" if pop_change == 0 else "R", str(pop_change)
+ 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_tooltip_string("%s: §G%s%%" % [
- tr("LIT_CHANGE"), GUINode.float_to_string_dp(pop_row[pop_literacy_key] / 64.0, 2)
+ tr(&"LIT_CHANGE"), GUINode.float_to_string_dp(pop_row[pop_literacy_key] / 64.0, 2)
])
_pop_list_rows[index].show()
diff --git a/game/src/Game/GameSession/SearchPanel.gd b/game/src/Game/GameSession/SearchPanel.gd
index 3d96367f..82cbcb03 100644
--- a/game/src/Game/GameSession/SearchPanel.gd
+++ b/game/src/Game/GameSession/SearchPanel.gd
@@ -36,6 +36,10 @@ func _ready() -> void:
_search_line_edit = get_line_edit_from_nodepath(^"./goto_box/goto_edit")
if _search_line_edit:
_search_line_edit.text_changed.connect(_search_string_updated)
+ _search_line_edit.text_submitted.connect(
+ func(new_text : String) -> void:
+ _result_selected(0)
+ )
# Restrict to desired size (by default it's a bit too tall, probably due to font size)
_search_line_edit.set_size(_search_line_edit.get_minimum_size())
@@ -135,10 +139,11 @@ func _update_results_scroll(scroll_index : int = -1) -> void:
_result_buttons[index].set_text(results[index])
func _result_selected(index : int) -> void:
- if _map_view:
- _map_view.look_at_map_position(MenuSingleton.get_search_result_position(index))
- else:
- push_error("SearchPanel missing MapView reference!")
+ if not _result_buttons.is_empty():
+ if _map_view:
+ _map_view.look_at_map_position(MenuSingleton.get_search_result_position(index))
+ else:
+ push_error("SearchPanel missing MapView reference!")
if _search_line_edit:
# This triggers a search results update, preventing further get_search_result_position(index) calls
diff --git a/game/src/Game/GameSession/Topbar.gd b/game/src/Game/GameSession/Topbar.gd
index 11e584cd..4f917d29 100644
--- a/game/src/Game/GameSession/Topbar.gd
+++ b/game/src/Game/GameSession/Topbar.gd
@@ -153,7 +153,7 @@ func _ready() -> void:
Events.NationManagementScreens.toggle_nation_management_screen.bind(screen)
)
# TODO - test tooltip, replace with actual shortcut strings
- button.set_tooltip_string(tr("SHORTCUT") + "F3")
+ button.set_tooltip_string(tr(&"SHORTCUT") + "F3")
_nation_management_buttons[screen] = button
Events.NationManagementScreens.update_active_nation_management_screen.connect(
_on_update_active_nation_management_screen
@@ -311,7 +311,7 @@ func _update_info() -> void:
var country_name : String = MenuSingleton.get_country_name_from_identifier(country_identifier)
var country_status : int = topbar_info.get(country_status_key, CountryStatus.UNCIVILISED)
- var country_name_rank_tooltip : String = tr("PLAYER_COUNTRY_TOPBAR_RANK") + MenuSingleton.get_tooltip_separator() + tr("RANK_TOTAL_D")
+ var country_name_rank_tooltip : String = tr(&"PLAYER_COUNTRY_TOPBAR_RANK") + MenuSingleton.get_tooltip_separator() + tr(&"RANK_TOTAL_D")
var country_name_rank_dict : Dictionary = {
"NAME": country_name,
"RANK": COUNTRY_STATUS_NAMES[country_status]
@@ -335,7 +335,7 @@ func _update_info() -> void:
_country_rank_label.set_text(str(topbar_info.get(total_rank_key, 0)))
_country_rank_label.set_tooltip_string_and_substitution_dict(country_name_rank_tooltip, country_name_rank_dict)
- var prestige_tooltip : String = tr("RANK_PRESTIGE") + topbar_info.get(prestige_tooltip_key, "") + MenuSingleton.get_tooltip_separator() + tr("RANK_PRESTIGE_D")
+ var prestige_tooltip : String = tr(&"RANK_PRESTIGE") + topbar_info.get(prestige_tooltip_key, "") + MenuSingleton.get_tooltip_separator() + tr(&"RANK_PRESTIGE_D")
if _country_prestige_label:
_country_prestige_label.set_text(str(topbar_info.get(prestige_key, 0)))
@@ -345,7 +345,7 @@ func _update_info() -> void:
_country_prestige_rank_label.set_text(str(topbar_info.get(prestige_rank_key, 0)))
_country_prestige_rank_label.set_tooltip_string(prestige_tooltip)
- var industrial_power_tooltip : String = tr("RANK_INDUSTRY") + MenuSingleton.get_tooltip_separator() + tr("RANK_INDUSTRY_D") + topbar_info.get(industrial_power_tooltip_key, "")
+ var industrial_power_tooltip : String = tr(&"RANK_INDUSTRY") + MenuSingleton.get_tooltip_separator() + tr(&"RANK_INDUSTRY_D") + topbar_info.get(industrial_power_tooltip_key, "")
if _country_industrial_power_label:
_country_industrial_power_label.set_text(str(topbar_info.get(industrial_power_key, 0)))
@@ -355,7 +355,7 @@ func _update_info() -> void:
_country_industrial_power_rank_label.set_text(str(topbar_info.get(industrial_rank_key, 0)))
_country_industrial_power_rank_label.set_tooltip_string(industrial_power_tooltip)
- var military_power_tooltip : String = tr("RANK_MILITARY") + MenuSingleton.get_tooltip_separator() + tr("RANK_MILITARY_D") + topbar_info.get(military_power_tooltip_key, "")
+ var military_power_tooltip : String = tr(&"RANK_MILITARY") + MenuSingleton.get_tooltip_separator() + tr(&"RANK_MILITARY_D") + topbar_info.get(military_power_tooltip_key, "")
if _country_military_power_label:
_country_military_power_label.set_text(str(topbar_info.get(military_power_key, 0)))
@@ -371,8 +371,8 @@ func _update_info() -> void:
_country_colonial_power_label.set_text(
"§%s%s§!/%s" % ["W" if available_colonial_power > 0 else "R", available_colonial_power, max_colonial_power]
)
- _country_colonial_power_label.set_tooltip_string(tr("COLONIAL_POINTS") + MenuSingleton.get_tooltip_separator() + (
- topbar_info.get(colonial_power_tooltip_key, "") if country_status <= CountryStatus.SECONDARY_POWER else tr("NON_COLONIAL_POWER")
+ _country_colonial_power_label.set_tooltip_string(tr(&"COLONIAL_POINTS") + MenuSingleton.get_tooltip_separator() + (
+ topbar_info.get(colonial_power_tooltip_key, "") if country_status <= CountryStatus.SECONDARY_POWER else tr(&"NON_COLONIAL_POWER")
))
## Time control
@@ -536,7 +536,7 @@ func _update_info() -> void:
_military_mobilisation_size_label.set_text("§Y" + mobilisation_regiments)
_military_mobilisation_size_label.set_tooltip_string_and_substitution_dict(
- tr("TOPBAR_MOBILIZE_TOOLTIP") + "\n\n" + tr("MOBILIZATION_IMPACT_LIMIT_DESC") + "\n" + tr("MOBILIZATION_IMPACT_LIMIT_DESC2").replace("$CURR$", "$CURR2$"),
+ tr(&"TOPBAR_MOBILIZE_TOOLTIP") + "\n\n" + tr(&"MOBILIZATION_IMPACT_LIMIT_DESC") + "\n" + tr(&"MOBILIZATION_IMPACT_LIMIT_DESC2").replace("$CURR$", "$CURR2$"),
{
"CURR": mobilisation_regiments, "IMPACT": mobilisation_impact, "POLICY": topbar_info.get(war_policy_key, ""),
"UNITS": str(topbar_info.get(mobilisation_max_regiments_key, 0)), "CURR2": regiment_count
diff --git a/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd b/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
index ca6b3fb9..ef845ebb 100644
--- a/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
+++ b/game/src/Game/Menu/LobbyMenu/LobbyMenu.gd
@@ -31,14 +31,15 @@ func filter_for_tag(tag : StringName) -> void:
child.hide()
func _build_date_list() -> void:
- var start_date := lobby_panel_button.instantiate()
- start_date.set_text(&"1836")
- start_date.pressed.connect(_on_start_date_panel_button_pressed.bind(start_date))
- game_select_start_date.add_child(start_date)
- start_date = lobby_panel_button.instantiate()
- start_date.set_text(&"1863")
- start_date.pressed.connect(_on_start_date_panel_button_pressed.bind(start_date))
- game_select_start_date.add_child(start_date)
+ const bookmark_info_name_key : StringName = &"bookmark_name"
+ const bookmark_info_date_key : StringName = &"bookmark_date"
+
+ for bookmark_dict : Dictionary in GameSingleton.get_bookmark_info():
+ var start_date := lobby_panel_button.instantiate()
+ start_date.set_name_text(bookmark_dict.get(bookmark_info_name_key, "MISSING BOOKMARK NAME"))
+ start_date.set_date_text(bookmark_dict.get(bookmark_info_date_key, "MISSING BOOKMARK DATE"))
+ start_date.pressed.connect(_on_start_date_panel_button_pressed.bind(start_date))
+ game_select_start_date.add_child(start_date)
var _id_to_tag : Array[StringName] = []
@@ -116,11 +117,12 @@ func _on_session_tag_edit_text_submitted(new_text : String) -> void:
_on_start_button_pressed()
func _on_session_tag_dialog_confirmed() -> void:
- # TODO - get bookmarks from SIM and generated corresponding buttons,
- # then use the selected button's bookmark instead of always using 0
+ if _start_date_index < 0:
+ push_error("Cannot setup game, no start date selected!")
+ return
# Game has to be setup (bookmark loaded) before opening the GameSession scene
- if GameSingleton.setup_game(0) != OK:
+ if GameSingleton.setup_game(_start_date_index) != OK:
push_error("Failed to setup game")
get_tree().change_scene_to_file("res://src/Game/GameSession/GameSession.tscn")
@@ -131,7 +133,7 @@ func _on_save_node_delete_requested(node : Control) -> void:
delete_dialog.title = tr("GAMELOBBY_DELETE_DIALOG_TITLE").format({ "file_name": _requested_node_to_delete.resource.save_name })
delete_dialog.popup_centered()
-var _start_date_index := -1
+var _start_date_index : int = -1
func _on_start_date_panel_button_pressed(node : Control) -> void:
if node is LobbyPanelButton and node.get_index(true) == _start_date_index:
_on_start_button_pressed()
diff --git a/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.gd b/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.gd
index b50ee28b..2add942c 100644
--- a/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.gd
+++ b/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.gd
@@ -16,17 +16,28 @@ func _is_start_date() -> bool:
@export_group("Nodes")
@export var background_button : BaseButton
@export var name_label : Label
+@export var date_label : Label
-var text : StringName:
- get = get_text,
- set = set_text
+var name_text : String:
+ get = get_name_text,
+ set = set_name_text
-func get_text() -> StringName:
+var date_text : String:
+ get = get_date_text,
+ set = set_date_text
+
+func get_name_text() -> String:
return name_label.text
-func set_text(value : StringName) -> void:
+func set_name_text(value : String) -> void:
name_label.text = value
+func get_date_text() -> String:
+ return date_label.text
+
+func set_date_text(value : String) -> void:
+ date_label.text = value
+
func _get_minimum_size() -> Vector2:
var result := Vector2()
for child : Control in get_children():
@@ -35,9 +46,7 @@ func _get_minimum_size() -> Vector2:
if child.top_level:
continue
- var minsize : Vector2 = child.get_combined_minimum_size()
- result.x = max(result.x, minsize.x)
- result.y = max(result.y, minsize.y)
+ result = result.max(child.get_combined_minimum_size())
var draw_style := _get_draw_mode_style()
if draw_style != null:
diff --git a/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.tscn b/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.tscn
index f27ddac2..b9e2d60a 100644
--- a/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.tscn
+++ b/game/src/Game/Menu/LobbyMenu/LobbyPanelButton.tscn
@@ -1,20 +1,24 @@
-[gd_scene load_steps=2 format=3 uid="uid://k71f5gibwmtc"]
+[gd_scene load_steps=3 format=3 uid="uid://k71f5gibwmtc"]
[ext_resource type="Script" path="res://src/Game/Menu/LobbyMenu/LobbyPanelButton.gd" id="1_327u2"]
-[node name="LobbyPanelButton" type="Container" node_paths=PackedStringArray("background_button", "name_label")]
+[sub_resource type="FontVariation" id="FontVariation_xwn8e"]
+variation_embolden = 1.0
+
+[node name="LobbyPanelButton" type="Container" node_paths=PackedStringArray("background_button", "name_label", "date_label")]
editor_description = "UI-41"
offset_right = 113.0
offset_bottom = 48.0
script = ExtResource("1_327u2")
background_button = NodePath("BackgroundButton")
name_label = NodePath("SaveList/NameLabel")
+date_label = NodePath("SaveList/DateLabel")
[node name="BackgroundButton" type="Button" parent="."]
layout_mode = 2
theme_type_variation = &"ButtonContainer"
-[node name="SaveList" type="HBoxContainer" parent="."]
+[node name="SaveList" type="VBoxContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 0
mouse_filter = 2
@@ -22,6 +26,14 @@ mouse_filter = 2
[node name="NameLabel" type="Label" parent="SaveList"]
layout_mode = 2
size_flags_vertical = 1
+theme_override_fonts/font = SubResource("FontVariation_xwn8e")
+theme_override_font_sizes/font_size = 18
+text = "PLACEHOLDER"
+vertical_alignment = 1
+
+[node name="DateLabel" type="Label" parent="SaveList"]
+layout_mode = 2
+size_flags_vertical = 1
text = "PLACEHOLDER"
vertical_alignment = 1
diff --git a/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.gd b/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.gd
index 6dc43c9a..69a587d8 100644
--- a/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.gd
+++ b/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.gd
@@ -5,7 +5,6 @@ signal request_to_delete
@export_group("Nodes")
@export var country_flag : TextureRect
-@export var date_label : Label
@export var delete_button : BaseButton
var resource : SaveResource:
diff --git a/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.tscn b/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.tscn
index 94dc8a3a..077025c6 100644
--- a/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.tscn
+++ b/game/src/Game/Menu/SaveLoadMenu/SavePanelButton.tscn
@@ -2,16 +2,16 @@
[ext_resource type="Script" path="res://src/Game/Menu/SaveLoadMenu/SavePanelButton.gd" id="1_rtuo6"]
-[node name="SavePanelButton" type="Container" node_paths=PackedStringArray("country_flag", "date_label", "delete_button", "background_button", "name_label")]
+[node name="SavePanelButton" type="Container" node_paths=PackedStringArray("country_flag", "delete_button", "background_button", "name_label", "date_label")]
editor_description = "SS-18, UI-40, UI-84, UI-86, UI-91, UI-93"
offset_right = 276.0
offset_bottom = 48.0
script = ExtResource("1_rtuo6")
country_flag = NodePath("SaveList/CountryFlag")
-date_label = NodePath("SaveList/DateLabel")
delete_button = NodePath("SaveList/DeleteButton")
background_button = NodePath("BackgroundButton")
name_label = NodePath("SaveList/NameLabel")
+date_label = NodePath("SaveList/DateLabel")
[node name="BackgroundButton" type="Button" parent="."]
layout_mode = 2
diff --git a/game/src/Game/Model/UnitModel.gd b/game/src/Game/Model/UnitModel.gd
index e98d22a4..d482c12f 100644
--- a/game/src/Game/Model/UnitModel.gd
+++ b/game/src/Game/Model/UnitModel.gd
@@ -138,7 +138,7 @@ func attach_model(bone_name : String, model : Node3D) -> Error:
var bone_idx : int = skeleton.find_bone(bone_name)
if bone_idx < 0 or bone_idx >= skeleton.get_bone_count():
- push_error("Invalid bone \"", bone_name, "\" (index ", bone_idx, ") for attachment \"", model.get_name(), "\" to UnitModel \"", get_name(), "\"")
+ push_warning("Invalid bone \"", bone_name, "\" (index ", bone_idx, ") for attachment \"", model.get_name(), "\" to UnitModel \"", get_name(), "\"")
return FAILED
var bone_attachment := BoneAttachment3D.new()