aboutsummaryrefslogtreecommitdiff
path: root/game/src/Game/GameSession/Menubar.gd
blob: bff141826f3b5b4cba0f2e3e5103166088733175 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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()