about summary refs log tree commit diff stats
path: root/apworld/client/textclient.gd
diff options
context:
space:
mode:
Diffstat (limited to 'apworld/client/textclient.gd')
-rw-r--r--apworld/client/textclient.gd359
1 files changed, 332 insertions, 27 deletions
diff --git a/apworld/client/textclient.gd b/apworld/client/textclient.gd index 1a0ce5c..ce28a3a 100644 --- a/apworld/client/textclient.gd +++ b/apworld/client/textclient.gd
@@ -4,13 +4,29 @@ var tabs
4var panel 4var panel
5var label 5var label
6var entry 6var entry
7var tracker_label
8var is_open = false 7var is_open = false
9 8
10var locations_overlay 9var locations_overlay
11
12var location_texture 10var location_texture
13var worldport_texture 11var worldport_texture
12var goal_texture
13
14var tracker_tree
15var tracker_loc_tree_item_by_id = {}
16var tracker_port_tree_item_by_id = {}
17var tracker_goal_tree_item = null
18var tracker_object_by_index = {}
19var tracker_object_by_ignored_index = {}
20var tracker_ignored_group = null
21
22var worldports_tab
23var worldports_tree
24var port_tree_item_by_map = {}
25var port_tree_item_by_map_port = {}
26
27const kLocation = 0
28const kWorldport = 1
29const kGoal = 2
14 30
15 31
16func _ready(): 32func _ready():
@@ -56,7 +72,7 @@ func _ready():
56 label.size_flags_horizontal = Control.SIZE_EXPAND_FILL 72 label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
57 label.size_flags_vertical = Control.SIZE_EXPAND_FILL 73 label.size_flags_vertical = Control.SIZE_EXPAND_FILL
58 label.push_font(preload("res://assets/fonts/Lingo2.ttf")) 74 label.push_font(preload("res://assets/fonts/Lingo2.ttf"))
59 label.push_font_size(36) 75 label.push_font_size(30)
60 76
61 var entry_style = StyleBoxFlat.new() 77 var entry_style = StyleBoxFlat.new()
62 entry_style.bg_color = Color(0.9, 0.9, 0.9, 1) 78 entry_style.bg_color = Color(0.9, 0.9, 0.9, 1)
@@ -84,8 +100,36 @@ func _ready():
84 tracker_margins.add_theme_constant_override("margin_bottom", 60) 100 tracker_margins.add_theme_constant_override("margin_bottom", 60)
85 tabs.add_child(tracker_margins) 101 tabs.add_child(tracker_margins)
86 102
87 tracker_label = RichTextLabel.new() 103 tracker_tree = Tree.new()
88 tracker_margins.add_child(tracker_label) 104 tracker_tree.columns = 4
105 tracker_tree.hide_root = true
106 tracker_tree.add_theme_font_size_override("font_size", 24)
107 tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1))
108 tracker_tree.add_theme_constant_override("v_separation", 1)
109 tracker_tree.item_edited.connect(_on_tracker_button_clicked)
110 tracker_tree.set_column_expand(0, false)
111 tracker_tree.set_column_expand(1, true)
112 tracker_tree.set_column_expand(2, false)
113 tracker_tree.set_column_expand(3, false)
114 tracker_tree.set_column_custom_minimum_width(2, 200)
115 tracker_tree.set_column_custom_minimum_width(3, 200)
116 tracker_margins.add_child(tracker_tree)
117
118 worldports_tab = MarginContainer.new()
119 worldports_tab.name = "Worldports"
120 worldports_tab.add_theme_constant_override("margin_top", 60)
121 worldports_tab.add_theme_constant_override("margin_left", 60)
122 worldports_tab.add_theme_constant_override("margin_right", 60)
123 worldports_tab.add_theme_constant_override("margin_bottom", 60)
124 tabs.add_child(worldports_tab)
125 tabs.set_tab_hidden(2, true)
126
127 worldports_tree = Tree.new()
128 worldports_tree.columns = 2
129 worldports_tree.hide_root = true
130 worldports_tree.theme = preload("res://assets/themes/baseUI.tres")
131 worldports_tree.add_theme_font_size_override("font_size", 24)
132 worldports_tab.add_child(worldports_tree)
89 133
90 var runtime = global.get_node("Runtime") 134 var runtime = global.get_node("Runtime")
91 var location_image = Image.new() 135 var location_image = Image.new()
@@ -96,6 +140,10 @@ func _ready():
96 worldport_image.load_png_from_buffer(runtime.read_path("assets/worldport.png")) 140 worldport_image.load_png_from_buffer(runtime.read_path("assets/worldport.png"))
97 worldport_texture = ImageTexture.create_from_image(worldport_image) 141 worldport_texture = ImageTexture.create_from_image(worldport_image)
98 142
143 var goal_image = Image.new()
144 goal_image.load_png_from_buffer(runtime.read_path("assets/goal.png"))
145 goal_texture = ImageTexture.create_from_image(goal_image)
146
99 147
100func _input(event): 148func _input(event):
101 if global.loaded and event is InputEventKey and event.pressed: 149 if global.loaded and event is InputEventKey and event.pressed:
@@ -142,14 +190,10 @@ func text_entered(text):
142 ap.client.say(cmd) 190 ap.client.say(cmd)
143 191
144 192
145func update_locations(): 193func update_locations(reset_locations = true):
146 var ap = global.get_node("Archipelago") 194 var ap = global.get_node("Archipelago")
147 var gamedata = global.get_node("Gamedata") 195 var gamedata = global.get_node("Gamedata")
148 196
149 tracker_label.clear()
150 tracker_label.push_font(preload("res://assets/fonts/Lingo2.ttf"))
151 tracker_label.push_font_size(24)
152
153 locations_overlay.clear() 197 locations_overlay.clear()
154 locations_overlay.push_font(preload("res://assets/fonts/Lingo2.ttf")) 198 locations_overlay.push_font(preload("res://assets/fonts/Lingo2.ttf"))
155 locations_overlay.push_font_size(24) 199 locations_overlay.push_font_size(24)
@@ -157,47 +201,308 @@ func update_locations():
157 locations_overlay.push_outline_color(Color(0, 0, 0, 1)) 201 locations_overlay.push_outline_color(Color(0, 0, 0, 1))
158 locations_overlay.push_outline_size(2) 202 locations_overlay.push_outline_size(2)
159 203
160 const kLocation = 0 204 var locations = []
161 const kWorldport = 1
162
163 var location_names = []
164 var type_by_name = {}
165 for location_id in ap.client._accessible_locations: 205 for location_id in ap.client._accessible_locations:
166 if not ap.client._checked_locations.has(location_id): 206 if not ap.client._checked_locations.has(location_id):
167 var location_name = gamedata.location_name_by_id.get(location_id, "(Unknown)") 207 var location_name = gamedata.location_name_by_id.get(location_id, "(Unknown)")
168 location_names.append(location_name) 208 (
169 type_by_name[location_name] = kLocation 209 locations
210 . append(
211 {
212 "name": location_name,
213 "type": kLocation,
214 "id": location_id,
215 "ignored": ap._ignored_locations.has(location_id),
216 "hint": ap.client._hinted_locations.has(location_id),
217 }
218 )
219 )
170 220
171 for port_id in ap.client._accessible_worldports: 221 for port_id in ap.client._accessible_worldports:
172 if not ap.client._checked_worldports.has(port_id): 222 if not ap.client._checked_worldports.has(port_id):
173 var port_name = gamedata.get_worldport_display_name(port_id) 223 var port_name = gamedata.get_worldport_display_name(port_id)
174 location_names.append(port_name) 224 (
175 type_by_name[port_name] = kWorldport 225 locations
176 226 . append(
177 location_names.sort() 227 {
228 "name": port_name,
229 "type": kWorldport,
230 "id": port_id,
231 "ignored": false,
232 "hint": false,
233 }
234 )
235 )
236
237 locations.sort_custom(_cmp_tracker_objects)
238
239 if ap.client._goal_accessible:
240 var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[
241 ap.victory_condition
242 ]]
243 (
244 locations
245 . push_front(
246 {
247 "name": location_name,
248 "type": kGoal,
249 "ignored": false,
250 "hint": false,
251 }
252 )
253 )
178 254
179 var count = 0 255 var count = 0
180 for location_name in location_names: 256 for location in locations:
181 tracker_label.append_text("[p]%s[/p]" % location_name) 257 if count < 18 and not location["ignored"]:
182 if count < 18:
183 locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT) 258 locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT)
184 locations_overlay.append_text(location_name) 259 if location["hint"]:
260 locations_overlay.push_color(Color("#fafad2"))
261 locations_overlay.append_text(location["name"])
185 locations_overlay.append_text(" ") 262 locations_overlay.append_text(" ")
186 if type_by_name[location_name] == kLocation: 263 if location["type"] == kLocation:
187 locations_overlay.add_image(location_texture) 264 locations_overlay.add_image(location_texture)
188 elif type_by_name[location_name] == kWorldport: 265 elif location["type"] == kWorldport:
189 locations_overlay.add_image(worldport_texture) 266 locations_overlay.add_image(worldport_texture)
267 elif location["type"] == kGoal:
268 locations_overlay.add_image(goal_texture)
269 if location["hint"]:
270 locations_overlay.pop()
190 locations_overlay.pop() 271 locations_overlay.pop()
191 count += 1 272 count += 1
192 273
193 if count > 18: 274 if count > 18:
194 locations_overlay.append_text("[p align=right][lb]...[rb][/p]") 275 locations_overlay.append_text("[p align=right][lb]...[rb][/p]")
195 276
277 if reset_locations:
278 reset_tracker_tab()
279
280 var root_ti = tracker_tree.create_item(null)
281
282 for location in locations:
283 var loc_row
284
285 if location["ignored"]:
286 if tracker_ignored_group == null:
287 tracker_ignored_group = root_ti.create_child()
288 tracker_ignored_group.set_text(1, "Ignored Locations")
289 tracker_ignored_group.set_selectable(0, false)
290 tracker_ignored_group.set_selectable(1, false)
291 tracker_ignored_group.set_selectable(2, false)
292 tracker_ignored_group.set_selectable(3, false)
293
294 loc_row = tracker_ignored_group.create_child()
295 else:
296 loc_row = root_ti.create_child()
297
298 loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON)
299 loc_row.set_selectable(0, false)
300 loc_row.set_text(1, location["name"])
301 loc_row.set_selectable(1, false)
302 if location["hint"]:
303 loc_row.set_custom_color(1, Color("#fafad2"))
304 loc_row.set_cell_mode(2, TreeItem.CELL_MODE_CUSTOM)
305 loc_row.set_text(2, "Show Path")
306 loc_row.set_custom_as_button(2, true)
307 loc_row.set_editable(2, true)
308 loc_row.set_selectable(2, false)
309 loc_row.set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER)
310 loc_row.set_selectable(3, false)
311 if location["type"] == kLocation:
312 loc_row.set_cell_mode(3, TreeItem.CELL_MODE_CUSTOM)
313 if location["ignored"]:
314 loc_row.set_text(3, "Unignore")
315 else:
316 loc_row.set_text(3, "Ignore")
317 loc_row.set_custom_as_button(3, true)
318 loc_row.set_editable(3, true)
319 loc_row.set_text_alignment(3, HORIZONTAL_ALIGNMENT_CENTER)
320
321 if location["type"] == kLocation:
322 loc_row.set_icon(0, location_texture)
323 tracker_loc_tree_item_by_id[location["id"]] = loc_row
324 elif location["type"] == kWorldport:
325 loc_row.set_icon(0, worldport_texture)
326 tracker_port_tree_item_by_id[location["id"]] = loc_row
327 elif location["type"] == kGoal:
328 loc_row.set_icon(0, goal_texture)
329 tracker_goal_tree_item = loc_row
330
331 if location["ignored"]:
332 tracker_object_by_ignored_index[loc_row.get_index()] = location
333 else:
334 tracker_object_by_index[loc_row.get_index()] = location
335 else:
336 for loc_row in tracker_tree.get_root().get_children():
337 loc_row.visible = false
338
339 for location_id in tracker_loc_tree_item_by_id.keys():
340 if (
341 ap.client._accessible_locations.has(location_id)
342 and not ap.client._checked_locations.has(location_id)
343 ):
344 tracker_loc_tree_item_by_id[location_id].visible = true
345
346 for port_id in tracker_port_tree_item_by_id.keys():
347 if (
348 ap.client._accessible_worldports.has(port_id)
349 and not ap.client._checked_worldports.has(port_id)
350 ):
351 tracker_port_tree_item_by_id[port_id].visible = true
352
353 if tracker_goal_tree_item != null and ap.client._goal_accessible:
354 tracker_goal_tree_item.visible = true
355
356 if tracker_ignored_group != null:
357 tracker_ignored_group.visible = true
358
359
360func _cmp_tracker_objects(a, b) -> bool:
361 if a["ignored"] != b["ignored"]:
362 return !a["ignored"]
363 elif a["hint"] != b["hint"]:
364 return a["hint"]
365 else:
366 return a["name"] < b["name"]
367
196 368
197func update_locations_visibility(): 369func update_locations_visibility():
198 var ap = global.get_node("Archipelago") 370 var ap = global.get_node("Archipelago")
199 locations_overlay.visible = ap.show_locations 371 locations_overlay.visible = ap.show_locations
200 372
201 373
374func _on_tracker_button_clicked():
375 var ap = global.get_node("Archipelago")
376
377 var edited_item = tracker_tree.get_edited()
378 var edited_index = edited_item.get_index()
379
380 if edited_item.get_parent() == tracker_tree.get_root():
381 if tracker_object_by_index.has(edited_index):
382 var tracker_object = tracker_object_by_index[edited_index]
383 if tracker_tree.get_edited_column() == 2:
384 var type_str = ""
385 if tracker_object["type"] == kLocation:
386 type_str = "location"
387 elif tracker_object["type"] == kWorldport:
388 type_str = "worldport"
389 elif tracker_object["type"] == kGoal:
390 type_str = "goal"
391 ap.client.getLogicalPath(type_str, tracker_object.get("id", null))
392 elif tracker_tree.get_edited_column() == 3:
393 ap.toggle_ignored_location(tracker_object["id"])
394 elif edited_item.get_parent() == tracker_ignored_group:
395 # This is the ignored locations group.
396 if (
397 tracker_object_by_ignored_index.has(edited_index)
398 and tracker_tree.get_edited_column() == 3
399 ):
400 var tracker_object = tracker_object_by_ignored_index[edited_index]
401 ap.toggle_ignored_location(tracker_object["id"])
402
403
404func display_logical_path(object_type, object_id, paths):
405 var ap = global.get_node("Archipelago")
406 var gamedata = global.get_node("Gamedata")
407
408 var location_name = "(Unknown)"
409 if object_type == "location" and object_id != null:
410 location_name = gamedata.location_name_by_id.get(object_id, "(Unknown)")
411 elif object_type == "worldport" and object_id != null:
412 location_name = gamedata.get_worldport_display_name(object_id)
413 elif object_type == "goal":
414 location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[
415 ap.victory_condition
416 ]]
417
418 label.append_text("[p]Path to %s:[/p]" % location_name)
419 label.append_text("[ol]" + "\n".join(paths) + "[/ol]")
420
421 panel.visible = true
422
423
424func setup_worldports():
425 tabs.set_tab_hidden(2, false)
426
427 var root_ti = worldports_tree.create_item(null)
428
429 var ports_by_map_id = {}
430 var display_names_by_map_id = {}
431 var display_names_by_port_id = {}
432
433 var ap = global.get_node("Archipelago")
434 var gamedata = global.get_node("Gamedata")
435 for fpid in ap.port_pairings:
436 var port = gamedata.objects.get_ports()[fpid]
437 var room = gamedata.objects.get_rooms()[port.get_room_id()]
438
439 if not ports_by_map_id.has(room.get_map_id()):
440 ports_by_map_id[room.get_map_id()] = []
441
442 var map = gamedata.objects.get_maps()[room.get_map_id()]
443 display_names_by_map_id[map.get_id()] = map.get_display_name()
444
445 ports_by_map_id[room.get_map_id()].append(fpid)
446 display_names_by_port_id[fpid] = port.get_display_name()
447
448 var sorted_map_ids = ports_by_map_id.keys().duplicate()
449 sorted_map_ids.sort_custom(
450 func(a, b): return display_names_by_map_id[a] < display_names_by_map_id[b]
451 )
452
453 for map_id in sorted_map_ids:
454 var map_ti = root_ti.create_child()
455 map_ti.set_text(0, display_names_by_map_id[map_id])
456 map_ti.visible = false
457 map_ti.collapsed = true
458 port_tree_item_by_map[map_id] = map_ti
459 port_tree_item_by_map_port[map_id] = {}
460
461 var port_ids = ports_by_map_id[map_id]
462 port_ids.sort_custom(
463 func(a, b): return display_names_by_port_id[a] < display_names_by_port_id[b]
464 )
465
466 for port_id in port_ids:
467 var port_ti = map_ti.create_child()
468 port_ti.set_text(0, display_names_by_port_id[port_id])
469 port_ti.set_text(1, gamedata.get_worldport_display_name(ap.port_pairings[port_id]))
470 port_ti.visible = false
471 port_tree_item_by_map_port[map_id][port_id] = port_ti
472
473 update_worldports()
474
475
476func update_worldports():
477 var ap = global.get_node("Archipelago")
478
479 for map_id in port_tree_item_by_map_port.keys():
480 var map_visible = false
481
482 for port_id in port_tree_item_by_map_port[map_id].keys():
483 var ti = port_tree_item_by_map_port[map_id][port_id]
484 ti.visible = ap.client._checked_worldports.has(port_id)
485
486 if ti.visible:
487 map_visible = true
488
489 port_tree_item_by_map[map_id].visible = map_visible
490
491
202func reset(): 492func reset():
203 locations_overlay.clear() 493 locations_overlay.clear()
494 tabs.set_tab_hidden(2, true)
495 port_tree_item_by_map.clear()
496 port_tree_item_by_map_port.clear()
497 worldports_tree.clear()
498 reset_tracker_tab()
499
500
501func reset_tracker_tab():
502 tracker_loc_tree_item_by_id.clear()
503 tracker_port_tree_item_by_id.clear()
504 tracker_goal_tree_item = null
505 tracker_object_by_index.clear()
506 tracker_object_by_ignored_index.clear()
507 tracker_ignored_group = null
508 tracker_tree.clear()