aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-11-19 17:35:26 +0100
committer GitHub <noreply@github.com>2024-11-19 17:35:26 +0100
commit0da99047c2d5f30fa90798a3833134c78910c2ea (patch)
tree08979339133a902a9226ea1766de321ee1cc780c
parent9455c807d392e2cdd11c7f3cc89dd567422faa99 (diff)
parent2cdbcea72762822adedf948f43a61d38472b5c7d (diff)
Merge pull request #287 from OpenVicProject/mapmode-panel
Implement the V2 Minimap + Menubar GUI
m---------extension/deps/openvic-simulation0
-rw-r--r--extension/src/openvic-extension/singletons/GameSingleton.cpp56
-rw-r--r--extension/src/openvic-extension/singletons/GameSingleton.hpp7
-rw-r--r--extension/src/openvic-extension/singletons/MenuSingleton.cpp2
-rw-r--r--extension/src/openvic-extension/singletons/MenuSingleton.hpp14
-rw-r--r--extension/src/openvic-extension/utility/UITools.cpp8
-rw-r--r--game/src/Game/GameSession/GameSession.tscn34
-rw-r--r--game/src/Game/GameSession/Ledger.gd84
-rw-r--r--game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd62
-rw-r--r--game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn113
-rw-r--r--game/src/Game/GameSession/MapControlPanel/Minimap.gd105
-rw-r--r--game/src/Game/GameSession/MapControlPanel/Minimap.gdshader18
-rw-r--r--game/src/Game/GameSession/Menubar.gd224
13 files changed, 387 insertions, 340 deletions
diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation
-Subproject 8defcd5daa1acd2c61aa1cd0a26478d472fed9b
+Subproject dda680ccf0981fe4df70fe903d2fe4ec9dc594a
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.cpp b/extension/src/openvic-extension/singletons/GameSingleton.cpp
index f258fe1..553d17c 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.cpp
@@ -33,6 +33,10 @@ 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;
+}
void GameSingleton::_bind_methods() {
OV_BIND_SMETHOD(setup_logger);
@@ -63,7 +67,9 @@ void GameSingleton::_bind_methods() {
OV_BIND_METHOD(GameSingleton::get_mapmode_count);
OV_BIND_METHOD(GameSingleton::get_mapmode_identifier);
- OV_BIND_METHOD(GameSingleton::set_mapmode, { "identifier" });
+ OV_BIND_METHOD(GameSingleton::get_mapmode_localisation_key);
+ 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" });
@@ -76,6 +82,7 @@ void GameSingleton::_bind_methods() {
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")));
}
GameSingleton* GameSingleton::get_singleton() {
@@ -95,9 +102,11 @@ void GameSingleton::_on_clock_state_changed() {
* MAP-21, MAP-23, MAP-25, MAP-32, MAP-33, MAP-34
*/
GameSingleton::GameSingleton()
- : game_manager {
+ : game_manager {
std::bind(&GameSingleton::_on_gamestate_updated, this), std::bind(&GameSingleton::_on_clock_state_changed, this)
- }, viewed_country { nullptr } {
+ },
+ viewed_country { nullptr },
+ mapmode { &Mapmode::ERROR_MAPMODE } {
ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}
@@ -249,7 +258,7 @@ Error GameSingleton::_update_colour_image() {
InstanceManager const* instance_manager = get_instance_manager();
if (instance_manager != nullptr && !get_definition_manager().get_mapmode_manager().generate_mapmode_colours(
- instance_manager->get_map_instance(), mapmode_index, colour_data_array.ptrw()
+ instance_manager->get_map_instance(), mapmode, colour_data_array.ptrw()
)) {
err = FAILED;
}
@@ -311,28 +320,37 @@ int32_t GameSingleton::get_mapmode_count() const {
}
String GameSingleton::get_mapmode_identifier(int32_t index) const {
- Mapmode const* mapmode = get_definition_manager().get_mapmode_manager().get_mapmode_by_index(index);
- if (mapmode != nullptr) {
- return Utilities::std_to_godot_string(mapmode->get_identifier());
+ Mapmode const* identifier_mapmode = get_definition_manager().get_mapmode_manager().get_mapmode_by_index(index);
+ if (identifier_mapmode != nullptr) {
+ return Utilities::std_to_godot_string(identifier_mapmode->get_identifier());
+ }
+ return String {};
+}
+
+String GameSingleton::get_mapmode_localisation_key(int32_t index) const {
+ Mapmode const* localisation_key_mapmode = get_definition_manager().get_mapmode_manager().get_mapmode_by_index(index);
+ if (localisation_key_mapmode != nullptr) {
+ return Utilities::std_to_godot_string(localisation_key_mapmode->get_localisation_key());
}
return String {};
}
-Error GameSingleton::set_mapmode(String const& identifier) {
- Mapmode const* mapmode =
- get_definition_manager().get_mapmode_manager().get_mapmode_by_identifier(Utilities::godot_to_std_string(identifier));
- ERR_FAIL_NULL_V_MSG(mapmode, FAILED, vformat("Failed to find mapmode with identifier: %s", identifier));
- mapmode_index = mapmode->get_index();
- return _update_colour_image();
+int32_t GameSingleton::get_current_mapmode_index() const {
+ return mapmode->get_index();
+}
+
+Error GameSingleton::set_mapmode(int32_t index) {
+ Mapmode const* new_mapmode = get_definition_manager().get_mapmode_manager().get_mapmode_by_index(index);
+ ERR_FAIL_NULL_V_MSG(new_mapmode, FAILED, vformat("Failed to find mapmode with index: %d", index));
+ mapmode = new_mapmode;
+ const Error err = _update_colour_image();
+ emit_signal(_signal_mapmode_changed(), mapmode->get_index());
+ return err;
}
bool GameSingleton::is_parchment_mapmode_allowed() const {
- // TODO - parchment bool per mapmode?
- // TODO - move mapmode index to SIM/Map?
- /* Disallows parchment mapmode for the cosmetic terrain mapmode */
- static constexpr std::string_view cosmetic_terrain_mapmode = "mapmode_terrain";
- Mapmode const* mapmode = get_definition_manager().get_mapmode_manager().get_mapmode_by_index(mapmode_index);
- return mapmode != nullptr && mapmode->get_identifier() != cosmetic_terrain_mapmode;
+ /* Disallows parchment mapmode, e.g. for the cosmetic terrain mapmode */
+ return mapmode->is_parchment_mapmode_allowed();
}
int32_t GameSingleton::get_selected_province_index() const {
diff --git a/extension/src/openvic-extension/singletons/GameSingleton.hpp b/extension/src/openvic-extension/singletons/GameSingleton.hpp
index e737643..aa80141 100644
--- a/extension/src/openvic-extension/singletons/GameSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/GameSingleton.hpp
@@ -21,7 +21,7 @@ namespace OpenVic {
godot::Ref<godot::Texture2DArray> province_shape_texture;
godot::Ref<godot::Image> province_colour_image;
godot::Ref<godot::ImageTexture> province_colour_texture;
- Mapmode::index_t mapmode_index = 0;
+ Mapmode const* mapmode; // This should never be null, if no mapmode is set then it'll point to Mapmode::ERROR_MAPMODE
godot::Ref<godot::Texture2DArray> terrain_texture;
static const godot::Vector2i PROPERTY(flag_dims); /* The size in pixels of an individual flag. */
@@ -34,6 +34,7 @@ namespace OpenVic {
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();
@@ -120,7 +121,9 @@ namespace OpenVic {
int32_t get_mapmode_count() const;
godot::String get_mapmode_identifier(int32_t index) const;
- godot::Error set_mapmode(godot::String const& identifier);
+ godot::String get_mapmode_localisation_key(int32_t index) const;
+ 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);
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.cpp b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
index 81582c2..e5554c3 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.cpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.cpp
@@ -482,7 +482,7 @@ Dictionary MenuSingleton::get_province_info_from_index(int32_t index) const {
ret[province_info_rgo_output_quantity_yesterday_key] = rgo.get_output_quantity_yesterday().to_float();
ret[province_info_rgo_revenue_yesterday_key] = rgo.get_revenue_yesterday().to_float();
ret[province_info_rgo_total_employees_key] = rgo.get_total_employees_count_cache();
- const Pop::pop_size_t max_employee_count = rgo.get_max_employee_count_cache();
+ const pop_size_t max_employee_count = rgo.get_max_employee_count_cache();
if (max_employee_count == 0) {
ret[province_info_rgo_employment_percentage_key] = 100.0f;
} else {
diff --git a/extension/src/openvic-extension/singletons/MenuSingleton.hpp b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
index 0dcc8ff..169d519 100644
--- a/extension/src/openvic-extension/singletons/MenuSingleton.hpp
+++ b/extension/src/openvic-extension/singletons/MenuSingleton.hpp
@@ -1,16 +1,26 @@
#pragma once
+#include <variant>
+
#include <godot_cpp/classes/control.hpp>
#include <godot_cpp/classes/image.hpp>
-#include <openvic-simulation/pop/Pop.hpp>
#include <openvic-simulation/types/IndexedMap.hpp>
+#include <openvic-simulation/types/PopSize.hpp>
#include <openvic-simulation/types/OrderedContainers.hpp>
namespace OpenVic {
struct CountryInstance;
struct State;
struct ProvinceInstance;
+ struct Pop;
+ struct PopType;
+ struct Religion;
+ struct Ideology;
+ struct Culture;
+ struct Issue;
+ struct CountryParty;
+ struct RebelType;
struct ModifierValue;
struct RuleSet;
@@ -46,7 +56,7 @@ namespace OpenVic {
int32_t visible_province_list_entries = 0;
struct pop_filter_t {
- Pop::pop_size_t count, promotion_demotion_change;
+ pop_size_t count, promotion_demotion_change;
bool selected;
};
ordered_map<PopType const*, pop_filter_t> pop_filters;
diff --git a/extension/src/openvic-extension/utility/UITools.cpp b/extension/src/openvic-extension/utility/UITools.cpp
index 4bd537d..ecb35a8 100644
--- a/extension/src/openvic-extension/utility/UITools.cpp
+++ b/extension/src/openvic-extension/utility/UITools.cpp
@@ -482,14 +482,18 @@ static bool generate_window(generate_gui_args_t&& args) {
GUI::Window const& window = static_cast<GUI::Window const&>(args.element);
- // TODO - moveable, fullscreen, dontRender (disable visibility?)
+ // TODO - moveable, dontRender (disable visibility?)
const String window_name = Utilities::std_to_godot_string(window.get_name());
Panel* godot_panel = nullptr;
bool ret = new_control(godot_panel, window, args.name);
ERR_FAIL_NULL_V_MSG(godot_panel, false, vformat("Failed to create Panel for GUI window %s", window_name));
- godot_panel->set_custom_minimum_size(Utilities::to_godot_fvec2(window.get_size()));
+ if (window.get_fullscreen()) {
+ godot_panel->set_anchors_preset(godot::Control::PRESET_FULL_RECT);
+ } else {
+ godot_panel->set_custom_minimum_size(Utilities::to_godot_fvec2(window.get_size()));
+ }
Ref<StyleBoxEmpty> stylebox_empty;
stylebox_empty.instantiate();
diff --git a/game/src/Game/GameSession/GameSession.tscn b/game/src/Game/GameSession/GameSession.tscn
index 5925f3d..041e9c0 100644
--- a/game/src/Game/GameSession/GameSession.tscn
+++ b/game/src/Game/GameSession/GameSession.tscn
@@ -1,8 +1,7 @@
-[gd_scene load_steps=21 format=3 uid="uid://bgnupcshe1m7r"]
+[gd_scene load_steps=22 format=3 uid="uid://bgnupcshe1m7r"]
[ext_resource type="Script" path="res://src/Game/GameSession/GameSession.gd" id="1_eklvp"]
[ext_resource type="PackedScene" uid="uid://cvl76duuym1wq" path="res://src/Game/MusicConductor/MusicPlayer.tscn" id="2_kt6aa"]
-[ext_resource type="PackedScene" uid="uid://g524p8lr574w" path="res://src/Game/GameSession/MapControlPanel/MapControlPanel.tscn" id="3_afh6d"]
[ext_resource type="PackedScene" uid="uid://dvdynl6eir40o" path="res://src/Game/GameSession/GameSessionMenu.tscn" id="3_bvmqh"]
[ext_resource type="Script" path="res://src/Game/GameSession/ModelManager.gd" id="3_qwk4j"]
[ext_resource type="Script" path="res://src/Game/GameSession/Topbar.gd" id="4_2kbih"]
@@ -19,7 +18,9 @@
[ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/TradeMenu.gd" id="10_mv1r6"]
[ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/DiplomacyMenu.gd" id="11_fu7ys"]
[ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/MilitaryMenu.gd" id="12_6h6nc"]
+[ext_resource type="Script" path="res://src/Game/GameSession/Ledger.gd" id="15_vhb1p"]
[ext_resource type="Script" path="res://src/Game/GameSession/Tooltip.gd" id="20_3306e"]
+[ext_resource type="Script" path="res://src/Game/GameSession/Menubar.gd" id="20_s1i71"]
[node name="GameSession" type="Control" node_paths=PackedStringArray("_model_manager", "_game_session_menu")]
editor_description = "SS-102, UI-546"
@@ -103,15 +104,15 @@ layout_mode = 1
anchors_preset = 15
script = ExtResource("12_6h6nc")
-[node name="MapControlPanel" parent="UICanvasLayer/UI" instance=ExtResource("3_afh6d")]
+[node name="Menubar" type="GUINode" parent="UICanvasLayer/UI"]
layout_mode = 1
-anchors_preset = -1
-anchor_left = 1.0
-anchor_top = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 0
-grow_vertical = 0
+anchors_preset = 15
+script = ExtResource("20_s1i71")
+
+[node name="Ledger" type="GUINode" parent="UICanvasLayer/UI"]
+layout_mode = 1
+anchors_preset = 15
+script = ExtResource("15_vhb1p")
[node name="SearchPanel" type="GUINode" parent="UICanvasLayer/UI" node_paths=PackedStringArray("_map_view")]
layout_mode = 1
@@ -163,12 +164,13 @@ anchors_preset = 15
script = ExtResource("20_3306e")
[connection signal="detailed_view_changed" from="MapView" to="ModelManager" method="set_visible"]
-[connection signal="map_view_camera_changed" from="MapView" to="UICanvasLayer/UI/MapControlPanel" method="_on_map_view_camera_changed"]
-[connection signal="game_session_menu_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="." method="_on_game_session_menu_button_pressed"]
-[connection signal="minimap_clicked" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="_on_minimap_clicked"]
-[connection signal="search_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="UICanvasLayer/UI/SearchPanel" method="toggle_visibility"]
-[connection signal="zoom_in_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="zoom_in"]
-[connection signal="zoom_out_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="zoom_out"]
+[connection signal="map_view_camera_changed" from="MapView" to="UICanvasLayer/UI/Menubar" method="_on_map_view_camera_changed"]
+[connection signal="game_session_menu_button_pressed" from="UICanvasLayer/UI/Menubar" to="." method="_on_game_session_menu_button_pressed"]
+[connection signal="ledger_button_pressed" from="UICanvasLayer/UI/Menubar" to="UICanvasLayer/UI/Ledger" method="toggle_visibility"]
+[connection signal="minimap_clicked" from="UICanvasLayer/UI/Menubar" to="MapView" method="_on_minimap_clicked"]
+[connection signal="search_button_pressed" from="UICanvasLayer/UI/Menubar" to="UICanvasLayer/UI/SearchPanel" method="toggle_visibility"]
+[connection signal="zoom_in_button_pressed" from="UICanvasLayer/UI/Menubar" to="MapView" method="zoom_in"]
+[connection signal="zoom_out_button_pressed" from="UICanvasLayer/UI/Menubar" to="MapView" method="zoom_out"]
[connection signal="load_button_pressed" from="UICanvasLayer/UI/GameSessionMenu" to="UICanvasLayer/UI/SaveLoadMenu" method="show_for_load"]
[connection signal="options_button_pressed" from="UICanvasLayer/UI/GameSessionMenu" to="UICanvasLayer/UI/OptionsMenu" method="show"]
[connection signal="save_button_pressed" from="UICanvasLayer/UI/GameSessionMenu" to="UICanvasLayer/UI/SaveLoadMenu" method="show_for_save"]
diff --git a/game/src/Game/GameSession/Ledger.gd b/game/src/Game/GameSession/Ledger.gd
new file mode 100644
index 0000000..50bde07
--- /dev/null
+++ b/game/src/Game/GameSession/Ledger.gd
@@ -0,0 +1,84 @@
+extends GUINode
+
+enum Page {
+ NATION_RANKING,
+ NATIONAL_COMPARISON,
+ POLITICAL_SYSTEMS,
+ POLITICAL_REFORMS,
+ SOCIAL_REFORMS,
+ COUNTRY_POPULATION,
+ PROVINCES,
+ PROVINCE_POPULATION,
+ PROVINCE_PRODUCTION,
+ FACTORY_PRODUCTION,
+ PRICE_HISTORY,
+ NUMBER_OF_PAGES
+}
+const _page_titles : PackedStringArray = [
+ "LEDGER_HEADER_RANK",
+ "LEDGER_HEADER_COUNTRYCOMPARE",
+ "LEDGER_HEADER_COUNTRYPARTY",
+ "LEDGER_HEADER_COUNTRYPOLITICALREFORMS",
+ "LEDGER_HEADER_COUNTRYSOCIALREFORMS",
+ "LEDGER_HEADER_COUNTRY_POPS",
+ "LEDGER_HEADER_PROVINCES",
+ "LEDGER_HEADER_PROVINCE_POPS",
+ "LEDGER_HEADER_PROVINCEPRODUCTION",
+ "LEDGER_HEADER_FACTORYPRODUCTION",
+ "LEDGER_HEADER_GOODS_PRICEHISTORY"
+]
+
+var _current_page : Page = Page.NATION_RANKING:
+ get: return _current_page
+ set(new_page):
+ _current_page = new_page
+ while _current_page < 0:
+ _current_page += Page.NUMBER_OF_PAGES
+ _current_page %= Page.NUMBER_OF_PAGES
+ _update_info()
+
+var _page_title_label : GUILabel
+var _page_number_label : GUILabel
+# TODO - add variables to store any nodes you'll need to refer in more than one function call
+
+func _ready():
+ MenuSingleton.search_cache_changed.connect(_update_info)
+
+ add_gui_element("v2ledger", "ledger")
+
+ var close_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./ledger/close")
+ if close_button:
+ close_button.pressed.connect(hide)
+
+ var previous_page_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./ledger/prev")
+ if previous_page_button:
+ previous_page_button.pressed.connect(func() -> void: _current_page -= 1)
+
+ var next_page_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./ledger/next")
+ if next_page_button:
+ next_page_button.pressed.connect(func() -> void: _current_page += 1)
+
+ _page_title_label = get_gui_label_from_nodepath(^"./ledger/ledger_header")
+ _page_number_label = get_gui_label_from_nodepath(^"./ledger/page_number")
+
+ # TODO - get any nodes that need setting up or caching in the variables above
+
+ hide()
+
+func toggle_visibility() -> void:
+ if is_visible():
+ hide()
+ else:
+ show()
+ _update_info()
+
+func _update_info() -> void:
+ if is_visible():
+ if _page_title_label:
+ _page_title_label.set_text(_page_titles[_current_page])
+
+ if _page_number_label:
+ # Pages are indexed from 0 in the code, but from 1 in the UI
+ _page_number_label.set_text(str(_current_page + 1))
+
+ # TODO - set contents of current ledger page
diff --git a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd
deleted file mode 100644
index 61de6ae..0000000
--- a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd
+++ /dev/null
@@ -1,62 +0,0 @@
-extends PanelContainer
-
-signal game_session_menu_button_pressed
-signal search_button_pressed
-signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2)
-signal minimap_clicked(pos_clicked : Vector2)
-signal zoom_in_button_pressed
-signal zoom_out_button_pressed
-
-@export var _mapmodes_grid : GridContainer
-
-var _mapmode_button_group : ButtonGroup
-
-# REQUIREMENTS:
-# * UI-550, UI-552, UI-554, UI-561, UI-562, UI-563
-func _add_mapmode_button(identifier : String) -> void:
- var button := Button.new()
- button.text = identifier
- button.tooltip_text = identifier
- button.toggle_mode = true
- button.button_group = _mapmode_button_group
- button.mouse_filter = MOUSE_FILTER_PASS
- button.focus_mode = FOCUS_NONE
- _mapmodes_grid.add_child(button)
- if _mapmode_button_group.get_pressed_button() == null:
- button.button_pressed = true
-
-func _ready() -> void:
- _mapmode_button_group = ButtonGroup.new()
- _mapmode_button_group.pressed.connect(_mapmode_pressed)
- for index : int in GameSingleton.get_mapmode_count():
- _add_mapmode_button(GameSingleton.get_mapmode_identifier(index))
-
-# REQUIREMENTS:
-# * UIFUN-10
-func _on_game_session_menu_button_pressed() -> void:
- game_session_menu_button_pressed.emit()
-
-func _on_search_button_pressed() -> void:
- search_button_pressed.emit()
-
-# REQUIREMENTS:
-# * SS-76
-# * UIFUN-129, UIFUN-131, UIFUN-133, UIFUN-140, UIFUN-141, UIFUN-142
-func _mapmode_pressed(button : BaseButton) -> void:
- GameSingleton.set_mapmode(button.tooltip_text)
-
-func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void:
- map_view_camera_changed.emit(near_left, far_left, far_right, near_right)
-
-func _on_minimap_clicked(pos_clicked : Vector2) -> void:
- minimap_clicked.emit(pos_clicked)
-
-# REQUIREMENTS:
-# * UIFUN-269
-func _on_zoom_in_button_pressed() -> void:
- zoom_in_button_pressed.emit()
-
-# REQUIREMENTS:
-# * UIFUN-270
-func _on_zoom_out_button_pressed() -> void:
- zoom_out_button_pressed.emit()
diff --git a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn
deleted file mode 100644
index d49cf61..0000000
--- a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn
+++ /dev/null
@@ -1,113 +0,0 @@
-[gd_scene load_steps=7 format=3 uid="uid://g524p8lr574w"]
-
-[ext_resource type="Script" path="res://src/Game/GameSession/MapControlPanel/MapControlPanel.gd" id="1_ign64"]
-[ext_resource type="Shader" path="res://src/Game/GameSession/MapControlPanel/Minimap.gdshader" id="2_rinsg"]
-[ext_resource type="Script" path="res://src/Game/GameSession/MapControlPanel/Minimap.gd" id="3_s4dml"]
-
-[sub_resource type="ShaderMaterial" id="ShaderMaterial_bhuqb"]
-shader = ExtResource("2_rinsg")
-shader_parameter/province_shape_subdivisions = null
-shader_parameter/selected_index = null
-
-[sub_resource type="InputEventAction" id="InputEventAction_5nck3"]
-action = &"ui_cancel"
-
-[sub_resource type="Shortcut" id="Shortcut_fc1tk"]
-events = [SubResource("InputEventAction_5nck3")]
-
-[node name="MapControlPanel" type="PanelContainer" node_paths=PackedStringArray("_mapmodes_grid")]
-editor_description = "SS-103, UI-548"
-mouse_force_pass_scroll_events = false
-script = ExtResource("1_ign64")
-_mapmodes_grid = NodePath("MapPanelMargin/MapPanelList/MapDisplayList/MapmodesGrid")
-
-[node name="MapPanelMargin" type="MarginContainer" parent="."]
-layout_mode = 2
-theme_override_constants/margin_left = 5
-theme_override_constants/margin_top = 5
-theme_override_constants/margin_right = 5
-theme_override_constants/margin_bottom = 5
-
-[node name="MapPanelList" type="HBoxContainer" parent="MapPanelMargin"]
-layout_mode = 2
-theme_override_constants/separation = 6
-alignment = 1
-
-[node name="MapDisplayList" type="VBoxContainer" parent="MapPanelMargin/MapPanelList"]
-layout_mode = 2
-alignment = 1
-
-[node name="MapmodesGrid" type="GridContainer" parent="MapPanelMargin/MapPanelList/MapDisplayList"]
-editor_description = "UI-750"
-layout_mode = 2
-columns = 7
-
-[node name="Minimap" type="PanelContainer" parent="MapPanelMargin/MapPanelList/MapDisplayList"]
-editor_description = "UI-549"
-layout_mode = 2
-size_flags_horizontal = 4
-size_flags_vertical = 4
-mouse_filter = 1
-
-[node name="MinimapTexture" type="ColorRect" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap"]
-editor_description = "UI-751, FS-338"
-material = SubResource("ShaderMaterial_bhuqb")
-layout_mode = 2
-color = Color(0.921569, 0.835294, 0.701961, 1)
-
-[node name="ViewportQuad" type="Control" parent="MapPanelMargin/MapPanelList/MapDisplayList/Minimap" node_paths=PackedStringArray("_minimap_texture")]
-layout_mode = 2
-mouse_filter = 1
-script = ExtResource("3_s4dml")
-_minimap_texture = NodePath("../MinimapTexture")
-
-[node name="AuxiliaryPanel" type="VBoxContainer" parent="MapPanelMargin/MapPanelList"]
-editor_description = "UI-761"
-layout_mode = 2
-
-[node name="GameSessionMenuButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"]
-editor_description = "UI-9"
-layout_mode = 2
-focus_mode = 0
-mouse_filter = 1
-shortcut = SubResource("Shortcut_fc1tk")
-text = "ESC"
-
-[node name="LedgerButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"]
-editor_description = "UI-860"
-layout_mode = 2
-focus_mode = 0
-mouse_filter = 1
-text = "L"
-
-[node name="SearchButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"]
-editor_description = "UI-861"
-layout_mode = 2
-focus_mode = 0
-mouse_filter = 1
-text = "F"
-
-[node name="ZoomButtonsContainer" type="HBoxContainer" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"]
-layout_mode = 2
-alignment = 1
-
-[node name="ZoomInButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer"]
-editor_description = "UI-862"
-layout_mode = 2
-focus_mode = 0
-mouse_filter = 1
-text = "+"
-
-[node name="ZoomOutButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer"]
-editor_description = "UI-863"
-layout_mode = 2
-focus_mode = 0
-mouse_filter = 1
-text = "-"
-
-[connection signal="map_view_camera_changed" from="." to="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" method="_on_map_view_camera_changed"]
-[connection signal="minimap_clicked" from="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"]
-[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"]
-[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/SearchButton" to="." method="_on_search_button_pressed"]
-[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomInButton" to="." method="_on_zoom_in_button_pressed"]
-[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomOutButton" to="." method="_on_zoom_out_button_pressed"]
diff --git a/game/src/Game/GameSession/MapControlPanel/Minimap.gd b/game/src/Game/GameSession/MapControlPanel/Minimap.gd
deleted file mode 100644
index 7cf1794..0000000
--- a/game/src/Game/GameSession/MapControlPanel/Minimap.gd
+++ /dev/null
@@ -1,105 +0,0 @@
-extends Control
-
-signal minimap_clicked(pos_clicked : Vector2)
-
-const _action_click : StringName = &"map_click"
-
-@export var _minimap_texture : Control
-var _minimap_shader : ShaderMaterial
-
-var _viewport_points : PackedVector2Array
-
-func _ready() -> void:
- _minimap_texture.custom_minimum_size = Vector2(GameSingleton.get_map_aspect_ratio(), 1.0) * 150
- var minimap_material := _minimap_texture.get_material()
- if GameLoader.ShaderManager.set_up_shader(minimap_material, false) != OK:
- push_error("Failed to set up minimap shader")
- else:
- _minimap_shader = minimap_material
- GameSingleton.province_selected.connect(_on_province_selected)
-
-func _on_province_selected(index : int) -> void:
- if _minimap_shader != null:
- _minimap_shader.set_shader_parameter(GameLoader.ShaderManager.param_selected_index, index)
-
-# REQUIREMENTS
-# * SS-80
-# * UI-752
-func _draw() -> void:
- if _viewport_points.size() > 1:
- draw_multiline(_viewport_points, Color.WHITE, -1)
-
-# REQUIREMENTS
-# * SS-81
-# * UIFUN-127
-func _gui_input(event : InputEvent) -> void:
- if Input.is_action_pressed(_action_click):
- var pos_clicked := get_local_mouse_position() / size - Vector2(0.5, 0.5)
- if abs(pos_clicked.x) < 0.5 and abs(pos_clicked.y) < 0.5:
- minimap_clicked.emit(pos_clicked)
-
-# Returns the point on the line going through p and q with the specific x coord
-func _intersect_x(p : Vector2, q : Vector2, x : float) -> Vector2:
- if p.x == q.x:
- return Vector2(x, 0.5 * (p.y + q.y))
- var t := (x - q.x) / (p.x - q.x)
- return q + t * (p - q)
-
-# Returns the point on the line going through p and q with the specific y coord
-func _intersect_y(p : Vector2, q : Vector2, y : float) -> Vector2:
- if p.y == q.y:
- return Vector2(0.5 * (p.x + q.x), y)
- var t := (y - q.y) / (p.y - q.y)
- return q + t * (p - q)
-
-const _one_x := Vector2(1, 0)
-
-func _add_line_looped_over_x(left : Vector2, right : Vector2) -> void:
- if left.x < 0:
- if right.x < 0:
- _viewport_points.push_back(left + _one_x)
- _viewport_points.push_back(right + _one_x)
- else:
- var mid_point := _intersect_x(left, right, 0)
- _viewport_points.push_back(mid_point)
- _viewport_points.push_back(right)
- mid_point.x = 1
- _viewport_points.push_back(left + _one_x)
- _viewport_points.push_back(mid_point)
- elif right.x > 1:
- if left.x > 1:
- _viewport_points.push_back(left - _one_x)
- _viewport_points.push_back(right - _one_x)
- else:
- var mid_point := _intersect_x(left, right, 1)
- _viewport_points.push_back(left)
- _viewport_points.push_back(mid_point)
- mid_point.x = 0
- _viewport_points.push_back(mid_point)
- _viewport_points.push_back(right - _one_x)
- else:
- _viewport_points.push_back(left)
- _viewport_points.push_back(right)
-
-# This can break if the viewport is rotated too far!
-func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void:
- # Bound far y coords
- if far_left.y < 0:
- far_left = _intersect_y(near_left, far_left, 0)
- if far_right.y < 0:
- far_right = _intersect_y(near_right, far_right, 0)
- # Bound near y coords
- if near_left.y > 1:
- near_left = _intersect_y(near_left, far_left, 1)
- if near_right.y > 1:
- near_right = _intersect_y(near_right, far_right, 1)
-
- _viewport_points.clear()
- _add_line_looped_over_x(near_left, near_right)
- _add_line_looped_over_x(far_left, far_right)
- _add_line_looped_over_x(far_left, near_left)
- _add_line_looped_over_x(near_right, far_right)
-
- for i : int in _viewport_points.size():
- _viewport_points[i] *= size
- queue_redraw()
diff --git a/game/src/Game/GameSession/MapControlPanel/Minimap.gdshader b/game/src/Game/GameSession/MapControlPanel/Minimap.gdshader
deleted file mode 100644
index 271b809..0000000
--- a/game/src/Game/GameSession/MapControlPanel/Minimap.gdshader
+++ /dev/null
@@ -1,18 +0,0 @@
-shader_type canvas_item;
-
-#include "res://src/Game/GameSession/ProvinceIndexSampler.gdshaderinc"
-
-// Index of the currently selected province
-uniform uint selected_index;
-
-const vec3 land_colour = vec3(0.5);
-const vec3 selected_colour = vec3(1.0, 1.0, 0.0);
-
-void fragment() {
- uvec3 data = read_uvec3(UV);
- uint index = uvec2_to_uint(data.rg);
- float is_land = float(data.b != 0u);
- float is_selected = float(index == selected_index);
- COLOR.rgb = mix(COLOR.rgb, land_colour, is_land);
- COLOR.rgb = mix(COLOR.rgb, selected_colour, is_selected);
-}
diff --git a/game/src/Game/GameSession/Menubar.gd b/game/src/Game/GameSession/Menubar.gd
new file mode 100644
index 0000000..bff1418
--- /dev/null
+++ b/game/src/Game/GameSession/Menubar.gd
@@ -0,0 +1,224 @@
+extends GUINode
+
+signal game_session_menu_button_pressed
+signal ledger_button_pressed
+signal search_button_pressed
+signal zoom_in_button_pressed
+signal zoom_out_button_pressed
+signal minimap_clicked(pos_clicked : Vector2)
+
+var _mapmode_button_group : ButtonGroup
+# We use this instead of the ButtonGroup's get_buttons() as we can add null
+# entries for any missing buttons, ensuring each button is at the right index.
+var _mapmode_buttons : Array[GUIIconButton]
+var _minimap_icon : GUIIcon
+var _viewport_points : PackedVector2Array
+
+# REQUIREMENTS:
+# * UI-550, UI-552, UI-554, UI-561, UI-562, UI-563
+func _add_mapmode_button() -> void:
+ var index : int = _mapmode_buttons.size()
+ var button : GUIIconButton = get_gui_icon_button_from_nodepath("./menubar/mapmode_%d" % (index + 1))
+ if button:
+ button.tooltip_string = GameSingleton.get_mapmode_localisation_key(index)
+ button.toggle_mode = true
+ button.button_group = _mapmode_button_group
+ button.pressed.connect(_mapmode_pressed.bind(index))
+ _mapmode_buttons.push_back(button)
+
+func _ready() -> void:
+ add_gui_element("menubar", "menubar")
+
+ hide_nodes([
+ ^"./menubar/messagelog_window", # TODO: implement
+ ^"./menubar/OPENbutton", # not quite sure what this is
+ ^"./menubar/menubar_plans_toggle", # TODO: implement, v low priority
+ ^"./menubar/menubar_plans_open", # TODO: implement, v low priority
+ ^"./menubar/menubar_mail_bg", # TODO: implement
+ ^"./menubar/menubar_msg_diplo", # TODO: implement
+ ^"./menubar/menubar_msg_settings", # TODO: implement
+ ^"./menubar/menubar_msg_combat", # TODO: implement
+ ^"./menubar/menubar_msg_diplo", # TODO: implement
+ ^"./menubar/menubar_msg_unit", # TODO: implement
+ ^"./menubar/menubar_msg_province", # TODO: implement
+ ^"./menubar/menubar_msg_event", # TODO: implement
+ ^"./menubar/menubar_msg_other", # TODO: implement
+ ^"./menubar/chat_window", # TODO: Multiplayer
+ ])
+
+ var menubar : Panel = get_panel_from_nodepath(^"./menubar")
+ if menubar:
+ menubar.mouse_filter = Control.MOUSE_FILTER_IGNORE
+ var minimap_bg : GUIIcon = get_gui_icon_from_nodepath(^"./menubar/minimap_bg")
+ if minimap_bg:
+ minimap_bg.mouse_filter = Control.MOUSE_FILTER_PASS
+ var menubar_bg : GUIIcon = get_gui_icon_from_nodepath(^"./menubar/menubar_bg")
+ if menubar_bg:
+ menubar_bg.mouse_filter = Control.MOUSE_FILTER_PASS
+
+ # TODO: add keyboard shortcuts (and shortcut tooltips) where vanilla does by default + use key bindings in settings
+
+ var menu_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/menu_button")
+ if menu_button:
+ menu_button.tooltip_string = "M_MENU_BUTTON"
+ menu_button.pressed.connect(_on_game_session_menu_button_pressed)
+
+ # TODO: implement ledger
+ var ledger_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/ledger_button")
+ if ledger_button:
+ ledger_button.tooltip_string = "M_LEDGER_BUTTON"
+ ledger_button.pressed.connect(_on_ledger_button_pressed)
+
+ var search_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/button_goto")
+ if search_button:
+ search_button.tooltip_string = "M_GOTO_BUTTON"
+ search_button.pressed.connect(_on_search_button_pressed)
+
+ var zoom_in_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/map_zoom_in")
+ if zoom_in_button:
+ zoom_in_button.pressed.connect(_on_zoom_in_button_pressed)
+
+ var zoom_out_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/map_zoom_out")
+ if zoom_out_button:
+ zoom_out_button.pressed.connect(_on_zoom_out_button_pressed)
+
+ _minimap_icon = get_gui_icon_from_node(generate_gui_element("menubar", "minimap_pic"))
+ if _minimap_icon:
+ _minimap_icon.mouse_filter = Control.MOUSE_FILTER_PASS
+ _minimap_icon.gui_input.connect(_minimap_gui_input)
+ _minimap_icon.draw.connect(_minimap_draw)
+ add_child(_minimap_icon)
+
+ _mapmode_button_group = ButtonGroup.new()
+ for index : int in GameSingleton.get_mapmode_count():
+ _add_mapmode_button()
+
+ GameSingleton.mapmode_changed.connect(_on_mapmode_changed)
+
+ # This will set the mapmode in GameSingleton which in turn updates the buttons so that the right one is pressed
+ _mapmode_pressed(0)
+
+# REQUIREMENTS:
+# * UIFUN-10
+func _on_game_session_menu_button_pressed() -> void:
+ game_session_menu_button_pressed.emit()
+
+func _on_ledger_button_pressed() -> void:
+ ledger_button_pressed.emit()
+
+func _on_search_button_pressed() -> void:
+ search_button_pressed.emit()
+
+# REQUIREMENTS:
+# * SS-76
+# * UIFUN-129, UIFUN-131, UIFUN-133, UIFUN-140, UIFUN-141, UIFUN-142
+func _mapmode_pressed(index : int) -> void:
+ GameSingleton.set_mapmode(index)
+ print("Mapmode set to \"%s\" (index: %d, identifier: %s)" % [
+ tr(GameSingleton.get_mapmode_localisation_key(index)), index, GameSingleton.get_mapmode_identifier(index)
+ ])
+
+func _on_mapmode_changed(index : int) -> void:
+ var current_mapmode_button : GUIIconButton = _mapmode_button_group.get_pressed_button()
+ var new_mapmode_button : GUIIconButton = _mapmode_buttons[index] if 0 <= index and index < _mapmode_buttons.size() else null
+
+ if current_mapmode_button != new_mapmode_button:
+ if new_mapmode_button:
+ # This will also automatically unpress current_mapmode_button (if it isn't null)
+ new_mapmode_button.button_pressed = true
+ else:
+ # current_mapmode_button can't be null as it isn't equal to new_mapmode_button which is null
+ current_mapmode_button.button_pressed = false
+
+# REQUIREMENTS:
+# * UIFUN-269
+func _on_zoom_in_button_pressed() -> void:
+ zoom_in_button_pressed.emit()
+
+# REQUIREMENTS:
+# * UIFUN-270
+func _on_zoom_out_button_pressed() -> void:
+ zoom_out_button_pressed.emit()
+
+# REQUIREMENTS
+# * SS-80
+# * UI-752
+func _minimap_draw() -> void:
+ if _viewport_points.size() > 1:
+ _minimap_icon.draw_multiline(_viewport_points, Color.WHITE, -1)
+
+# REQUIREMENTS
+# * SS-81
+# * UIFUN-127
+func _minimap_gui_input(_event : InputEvent) -> void:
+ const _action_click : StringName = &"map_click"
+ if Input.is_action_pressed(_action_click):
+ var pos_clicked : Vector2 = _minimap_icon.get_local_mouse_position() / _minimap_icon.size - Vector2(0.5, 0.5)
+ if abs(pos_clicked.x) < 0.5 and abs(pos_clicked.y) < 0.5:
+ minimap_clicked.emit(pos_clicked)
+
+# Returns the point on the line going through p and q with the specific x coord
+func _intersect_x(p : Vector2, q : Vector2, x : float) -> Vector2:
+ if p.x == q.x:
+ return Vector2(x, 0.5 * (p.y + q.y))
+ var t : float = (x - q.x) / (p.x - q.x)
+ return q + t * (p - q)
+
+# Returns the point on the line going through p and q with the specific y coord
+func _intersect_y(p : Vector2, q : Vector2, y : float) -> Vector2:
+ if p.y == q.y:
+ return Vector2(0.5 * (p.x + q.x), y)
+ var t : float = (y - q.y) / (p.y - q.y)
+ return q + t * (p - q)
+
+func _add_line_looped_over_x(left : Vector2, right : Vector2) -> void:
+ const _one_x : Vector2 = Vector2(1, 0)
+ if left.x < 0:
+ if right.x < 0:
+ _viewport_points.push_back(left + _one_x)
+ _viewport_points.push_back(right + _one_x)
+ else:
+ var mid_point := _intersect_x(left, right, 0)
+ _viewport_points.push_back(mid_point)
+ _viewport_points.push_back(right)
+ mid_point.x = 1
+ _viewport_points.push_back(left + _one_x)
+ _viewport_points.push_back(mid_point)
+ elif right.x > 1:
+ if left.x > 1:
+ _viewport_points.push_back(left - _one_x)
+ _viewport_points.push_back(right - _one_x)
+ else:
+ var mid_point := _intersect_x(left, right, 1)
+ _viewport_points.push_back(left)
+ _viewport_points.push_back(mid_point)
+ mid_point.x = 0
+ _viewport_points.push_back(mid_point)
+ _viewport_points.push_back(right - _one_x)
+ else:
+ _viewport_points.push_back(left)
+ _viewport_points.push_back(right)
+
+# This can break if the viewport is rotated too far!
+func _on_map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) -> void:
+ # Bound far y coords
+ if far_left.y < 0:
+ far_left = _intersect_y(near_left, far_left, 0)
+ if far_right.y < 0:
+ far_right = _intersect_y(near_right, far_right, 0)
+ # Bound near y coords
+ if near_left.y > 1:
+ near_left = _intersect_y(near_left, far_left, 1)
+ if near_right.y > 1:
+ near_right = _intersect_y(near_right, far_right, 1)
+
+ _viewport_points.clear()
+ _add_line_looped_over_x(near_left, near_right)
+ _add_line_looped_over_x(far_left, far_right)
+ _add_line_looped_over_x(far_left, near_left)
+ _add_line_looped_over_x(near_right, far_right)
+
+ if _minimap_icon:
+ for i : int in _viewport_points.size():
+ _viewport_points[i] *= _minimap_icon.size
+ _minimap_icon.queue_redraw()