diff options
Diffstat (limited to 'apworld/client')
| -rw-r--r-- | apworld/client/client.gd | 26 | ||||
| -rw-r--r-- | apworld/client/gamedata.gd | 4 | ||||
| -rw-r--r-- | apworld/client/main.gd | 2 | ||||
| -rw-r--r-- | apworld/client/manager.gd | 28 | ||||
| -rw-r--r-- | apworld/client/player.gd | 107 | ||||
| -rw-r--r-- | apworld/client/textclient.gd | 102 | ||||
| -rw-r--r-- | apworld/client/unlockReaderListener.gd | 46 | 
7 files changed, 263 insertions, 52 deletions
| diff --git a/apworld/client/client.gd b/apworld/client/client.gd index ce5ac7e..c149482 100644 --- a/apworld/client/client.gd +++ b/apworld/client/client.gd | |||
| @@ -26,6 +26,7 @@ var _accessible_locations = [] | |||
| 26 | var _accessible_worldports = [] | 26 | var _accessible_worldports = [] | 
| 27 | var _goal_accessible = false | 27 | var _goal_accessible = false | 
| 28 | var _latched_doors = [] | 28 | var _latched_doors = [] | 
| 29 | var _hinted_locations = [] | ||
| 29 | 30 | ||
| 30 | signal could_not_connect | 31 | signal could_not_connect | 
| 31 | signal connect_status | 32 | signal connect_status | 
| @@ -38,8 +39,10 @@ signal hint_received(message) | |||
| 38 | signal door_latched(id) | 39 | signal door_latched(id) | 
| 39 | signal accessible_locations_updated | 40 | signal accessible_locations_updated | 
| 40 | signal checked_locations_updated | 41 | signal checked_locations_updated | 
| 42 | signal ignored_locations_updated(locations) | ||
| 41 | signal checked_worldports_updated | 43 | signal checked_worldports_updated | 
| 42 | signal keyboard_update_received | 44 | signal keyboard_update_received | 
| 45 | signal hinted_locations_updated | ||
| 43 | 46 | ||
| 44 | 47 | ||
| 45 | func _init(): | 48 | func _init(): | 
| @@ -199,6 +202,21 @@ func _on_web_socket_server_message_received(_peer_id: int, packet: String) -> vo | |||
| 199 | 202 | ||
| 200 | door_latched.emit(iid) | 203 | door_latched.emit(iid) | 
| 201 | 204 | ||
| 205 | elif cmd == "SetIgnoredLocations": | ||
| 206 | var locs = [] | ||
| 207 | for id in message["locations"]: | ||
| 208 | locs.append(int(id)) | ||
| 209 | |||
| 210 | ignored_locations_updated.emit(locs) | ||
| 211 | |||
| 212 | elif cmd == "UpdateHintedLocations": | ||
| 213 | for id in message["locations"]: | ||
| 214 | var iid = int(id) | ||
| 215 | if !_hinted_locations.has(iid): | ||
| 216 | _hinted_locations.append(iid) | ||
| 217 | |||
| 218 | hinted_locations_updated.emit() | ||
| 219 | |||
| 202 | 220 | ||
| 203 | func connectToServer(server, un, pw): | 221 | func connectToServer(server, un, pw): | 
| 204 | sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}]) | 222 | sendMessage([{"cmd": "Connect", "server": server, "player": un, "password": pw}]) | 
| @@ -280,6 +298,14 @@ func getLogicalPath(object_type, object_id): | |||
| 280 | sendMessage([msg]) | 298 | sendMessage([msg]) | 
| 281 | 299 | ||
| 282 | 300 | ||
| 301 | func addIgnoredLocation(loc_id): | ||
| 302 | sendMessage([{"cmd": "IgnoreLocation", "id": loc_id}]) | ||
| 303 | |||
| 304 | |||
| 305 | func removeIgnoredLocation(loc_id): | ||
| 306 | sendMessage([{"cmd": "UnignoreLocation", "id": loc_id}]) | ||
| 307 | |||
| 308 | |||
| 283 | func sendQuit(): | 309 | func sendQuit(): | 
| 284 | sendMessage([{"cmd": "Quit"}]) | 310 | sendMessage([{"cmd": "Quit"}]) | 
| 285 | 311 | ||
| diff --git a/apworld/client/gamedata.gd b/apworld/client/gamedata.gd index 3a35125..d7e3136 100644 --- a/apworld/client/gamedata.gd +++ b/apworld/client/gamedata.gd | |||
| @@ -15,6 +15,7 @@ var symbol_item_ids = [] | |||
| 15 | var anti_trap_ids = {} | 15 | var anti_trap_ids = {} | 
| 16 | var location_name_by_id = {} | 16 | var location_name_by_id = {} | 
| 17 | var ending_display_name_by_name = {} | 17 | var ending_display_name_by_name = {} | 
| 18 | var port_id_by_ap_id = {} | ||
| 18 | 19 | ||
| 19 | var kSYMBOL_ITEMS | 20 | var kSYMBOL_ITEMS | 
| 20 | 21 | ||
| @@ -99,6 +100,9 @@ func load(data_bytes): | |||
| 99 | var map_data = port_id_by_map_node_path[map.get_name()] | 100 | var map_data = port_id_by_map_node_path[map.get_name()] | 
| 100 | map_data[port.get_path()] = port.get_id() | 101 | map_data[port.get_path()] = port.get_id() | 
| 101 | 102 | ||
| 103 | if port.has_ap_id(): | ||
| 104 | port_id_by_ap_id[port.get_ap_id()] = port.get_id() | ||
| 105 | |||
| 102 | for progressive in objects.get_progressives(): | 106 | for progressive in objects.get_progressives(): | 
| 103 | progressive_id_by_ap_id[progressive.get_ap_id()] = progressive.get_id() | 107 | progressive_id_by_ap_id[progressive.get_ap_id()] = progressive.get_id() | 
| 104 | 108 | ||
| diff --git a/apworld/client/main.gd b/apworld/client/main.gd index a543678..c90d6e7 100644 --- a/apworld/client/main.gd +++ b/apworld/client/main.gd | |||
| @@ -51,6 +51,7 @@ func _ready(): | |||
| 51 | installScriptExtension(runtime.load_script("saver.gd")) | 51 | installScriptExtension(runtime.load_script("saver.gd")) | 
| 52 | installScriptExtension(runtime.load_script("teleport.gd")) | 52 | installScriptExtension(runtime.load_script("teleport.gd")) | 
| 53 | installScriptExtension(runtime.load_script("teleportListener.gd")) | 53 | installScriptExtension(runtime.load_script("teleportListener.gd")) | 
| 54 | installScriptExtension(runtime.load_script("unlockReaderListener.gd")) | ||
| 54 | installScriptExtension(runtime.load_script("visibilityListener.gd")) | 55 | installScriptExtension(runtime.load_script("visibilityListener.gd")) | 
| 55 | installScriptExtension(runtime.load_script("worldport.gd")) | 56 | installScriptExtension(runtime.load_script("worldport.gd")) | 
| 56 | installScriptExtension(runtime.load_script("worldportListener.gd")) | 57 | installScriptExtension(runtime.load_script("worldportListener.gd")) | 
| @@ -253,6 +254,7 @@ func startGame(): | |||
| 253 | clearResourceCache("res://objects/nodes/listeners/keyHolderChecker.tscn") | 254 | clearResourceCache("res://objects/nodes/listeners/keyHolderChecker.tscn") | 
| 254 | clearResourceCache("res://objects/nodes/listeners/keyHolderResetterListener.tscn") | 255 | clearResourceCache("res://objects/nodes/listeners/keyHolderResetterListener.tscn") | 
| 255 | clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn") | 256 | clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn") | 
| 257 | clearResourceCache("res://objects/nodes/listeners/unlockReaderListener.tscn") | ||
| 256 | clearResourceCache("res://objects/nodes/listeners/visibilityListener.tscn") | 258 | clearResourceCache("res://objects/nodes/listeners/visibilityListener.tscn") | 
| 257 | clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn") | 259 | clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn") | 
| 258 | clearResourceCache("res://objects/nodes/panel.tscn") | 260 | clearResourceCache("res://objects/nodes/panel.tscn") | 
| diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index aa07559..830ebb8 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd | |||
| @@ -29,6 +29,7 @@ var _inverse_item_locks = {} | |||
| 29 | var _held_letters = {} | 29 | var _held_letters = {} | 
| 30 | var _letters_setup = false | 30 | var _letters_setup = false | 
| 31 | var _already_connected = false | 31 | var _already_connected = false | 
| 32 | var _ignored_locations = [] | ||
| 32 | 33 | ||
| 33 | const kSHUFFLE_LETTERS_VANILLA = 0 | 34 | const kSHUFFLE_LETTERS_VANILLA = 0 | 
| 34 | const kSHUFFLE_LETTERS_UNLOCKED = 1 | 35 | const kSHUFFLE_LETTERS_UNLOCKED = 1 | 
| @@ -144,6 +145,8 @@ func _ready(): | |||
| 144 | client.hint_received.connect(_process_hint_received) | 145 | client.hint_received.connect(_process_hint_received) | 
| 145 | client.accessible_locations_updated.connect(_on_accessible_locations_updated) | 146 | client.accessible_locations_updated.connect(_on_accessible_locations_updated) | 
| 146 | client.checked_locations_updated.connect(_on_checked_locations_updated) | 147 | client.checked_locations_updated.connect(_on_checked_locations_updated) | 
| 148 | client.ignored_locations_updated.connect(_on_ignored_locations_updated) | ||
| 149 | client.hinted_locations_updated.connect(_on_hinted_locations_updated) | ||
| 147 | client.checked_worldports_updated.connect(_on_checked_worldports_updated) | 150 | client.checked_worldports_updated.connect(_on_checked_worldports_updated) | 
| 148 | client.door_latched.connect(_on_door_latched) | 151 | client.door_latched.connect(_on_door_latched) | 
| 149 | 152 | ||
| @@ -384,6 +387,20 @@ func _on_checked_worldports_updated(): | |||
| 384 | textclient_node.update_worldports() | 387 | textclient_node.update_worldports() | 
| 385 | 388 | ||
| 386 | 389 | ||
| 390 | func _on_ignored_locations_updated(locations): | ||
| 391 | _ignored_locations = locations | ||
| 392 | |||
| 393 | var textclient_node = global.get_node("Textclient") | ||
| 394 | if textclient_node != null: | ||
| 395 | textclient_node.update_locations() | ||
| 396 | |||
| 397 | |||
| 398 | func _on_hinted_locations_updated(): | ||
| 399 | var textclient_node = global.get_node("Textclient") | ||
| 400 | if textclient_node != null: | ||
| 401 | textclient_node.update_locations() | ||
| 402 | |||
| 403 | |||
| 387 | func _on_door_latched(door_id): | 404 | func _on_door_latched(door_id): | 
| 388 | var gamedata = global.get_node("Gamedata") | 405 | var gamedata = global.get_node("Gamedata") | 
| 389 | if gamedata.get_door_map_name(door_id) != global.map: | 406 | if gamedata.get_door_map_name(door_id) != global.map: | 
| @@ -472,7 +489,9 @@ func _client_connected(slot_data): | |||
| 472 | var raw_pp = slot_data.get("port_pairings") | 489 | var raw_pp = slot_data.get("port_pairings") | 
| 473 | 490 | ||
| 474 | for p1 in raw_pp.keys(): | 491 | for p1 in raw_pp.keys(): | 
| 475 | port_pairings[int(p1)] = int(raw_pp[p1]) | 492 | port_pairings[gamedata.port_id_by_ap_id[int(p1)]] = gamedata.port_id_by_ap_id[int( | 
| 493 | raw_pp[p1] | ||
| 494 | )] | ||
| 476 | 495 | ||
| 477 | # Set up item locks. | 496 | # Set up item locks. | 
| 478 | _item_locks = {} | 497 | _item_locks = {} | 
| @@ -675,3 +694,10 @@ func update_job_well_done_sign(): | |||
| 675 | 694 | ||
| 676 | sign2.get_node("MeshInstance3D").mesh.text = sign2.text | 695 | sign2.get_node("MeshInstance3D").mesh.text = sign2.text | 
| 677 | sign3.get_node("MeshInstance3D").mesh.text = sign3.text | 696 | sign3.get_node("MeshInstance3D").mesh.text = sign3.text | 
| 697 | |||
| 698 | |||
| 699 | func toggle_ignored_location(loc_id): | ||
| 700 | if loc_id in _ignored_locations: | ||
| 701 | client.removeIgnoredLocation(loc_id) | ||
| 702 | else: | ||
| 703 | client.addIgnoredLocation(loc_id) | ||
| diff --git a/apworld/client/player.gd b/apworld/client/player.gd index 0e3fb23..65bf54e 100644 --- a/apworld/client/player.gd +++ b/apworld/client/player.gd | |||
| @@ -98,38 +98,72 @@ func _ready(): | |||
| 98 | old_door.queue_free() | 98 | old_door.queue_free() | 
| 99 | get_node("/root/scene/Components/Doors").add_child.call_deferred(new_door) | 99 | get_node("/root/scene/Components/Doors").add_child.call_deferred(new_door) | 
| 100 | 100 | ||
| 101 | # Block off roof access in Daedalus. | 101 | if global.map == "daedalus": | 
| 102 | if global.map == "daedalus" and not ap.daedalus_roof_access: | 102 | # Teleport the direction panels when the stairs are there. | 
| 103 | _set_up_invis_wall(75.5, 11, -24.5, 1, 10, 49) | 103 | var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn") | 
| 104 | _set_up_invis_wall(51.5, 11, -17, 16, 10, 1) | 104 | |
| 105 | _set_up_invis_wall(46, 10, -9.5, 1, 10, 10) | 105 | var dir1 = get_node("/root/scene/Panels/Castle Entrance/castle_direction_1") | 
| 106 | _set_up_invis_wall(67.5, 11, 17, 16, 10, 1) | 106 | var dir1_tpl = tpl_prefab.instantiate() | 
| 107 | _set_up_invis_wall(50.5, 11, 14, 10, 10, 1) | 107 | dir1_tpl.target_path = dir1 | 
| 108 | _set_up_invis_wall(39, 10, 18.5, 1, 10, 22) | 108 | dir1_tpl.teleport_point = Vector3(59.5, 8, -6.5) | 
| 109 | _set_up_invis_wall(20, 15, 18.5, 1, 10, 16) | 109 | dir1_tpl.teleport_rotate = Vector3(-45, 0, 0) | 
| 110 | _set_up_invis_wall(11.5, 15, 3, 32, 10, 1) | 110 | dir1_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_south")) | 
| 111 | _set_up_invis_wall(11.5, 16, -20, 14, 20, 1) | 111 | dir1_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_north")) | 
| 112 | _set_up_invis_wall(14, 16, -26.5, 1, 20, 4) | 112 | dir1_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_west")) | 
| 113 | _set_up_invis_wall(28.5, 20.5, -26.5, 1, 15, 25) | 113 | dir1.add_child.call_deferred(dir1_tpl) | 
| 114 | _set_up_invis_wall(40.5, 20.5, -11, 30, 15, 1) | 114 | |
| 115 | _set_up_invis_wall(50.5, 15, 5.5, 7, 10, 1) | 115 | var dir2 = get_node("/root/scene/Panels/Castle Entrance/castle_direction_2") | 
| 116 | _set_up_invis_wall(83.5, 33.5, 5.5, 1, 7, 11) | 116 | var dir2_tpl = tpl_prefab.instantiate() | 
| 117 | _set_up_invis_wall(83.5, 33.5, -5.5, 1, 7, 11) | 117 | dir2_tpl.target_path = dir2 | 
| 118 | 118 | dir2_tpl.teleport_point = Vector3(59.5, 8, 6.5) | |
| 119 | var warp_exit_prefab = preload("res://objects/nodes/exit.tscn") | 119 | dir2_tpl.teleport_rotate = Vector3(-45, -180, 0) | 
| 120 | var warp_exit = warp_exit_prefab.instantiate() | 120 | dir2_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_south")) | 
| 121 | warp_exit.name = "roof_access_blocker_warp_exit" | 121 | dir2_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_north")) | 
| 122 | warp_exit.position = Vector3(58, 10, 0) | 122 | dir2_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_west")) | 
| 123 | warp_exit.rotation_degrees.y = 90 | 123 | dir2.add_child.call_deferred(dir2_tpl) | 
| 124 | get_parent().add_child.call_deferred(warp_exit) | 124 | |
| 125 | 125 | var dir3 = get_node("/root/scene/Panels/Castle Entrance/castle_direction_3") | |
| 126 | var warp_enter_prefab = preload("res://objects/nodes/teleportAuto.tscn") | 126 | var dir3_tpl = tpl_prefab.instantiate() | 
| 127 | var warp_enter = warp_enter_prefab.instantiate() | 127 | dir3_tpl.target_path = dir3 | 
| 128 | warp_enter.target = warp_exit | 128 | dir3_tpl.teleport_point = Vector3(54, 8, 0) | 
| 129 | warp_enter.position = Vector3(76.5, 30, 1) | 129 | dir3_tpl.teleport_rotate = Vector3(-45, 90, 0) | 
| 130 | warp_enter.scale = Vector3(4, 1.5, 1) | 130 | dir3_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_south")) | 
| 131 | warp_enter.rotation_degrees.y = 90 | 131 | dir3_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_north")) | 
| 132 | get_parent().add_child.call_deferred(warp_enter) | 132 | dir3_tpl.senders.append(NodePath("/root/scene/Panels/Castle Entrance/castle_west")) | 
| 133 | dir3.add_child.call_deferred(dir3_tpl) | ||
| 134 | |||
| 135 | # Block off roof access in Daedalus. | ||
| 136 | if not ap.daedalus_roof_access: | ||
| 137 | _set_up_invis_wall(75.5, 11, -24.5, 1, 10, 49) | ||
| 138 | _set_up_invis_wall(51.5, 11, -17, 16, 10, 1) | ||
| 139 | _set_up_invis_wall(46, 10, -9.5, 1, 10, 10) | ||
| 140 | _set_up_invis_wall(67.5, 11, 17, 16, 10, 1) | ||
| 141 | _set_up_invis_wall(50.5, 11, 14, 10, 10, 1) | ||
| 142 | _set_up_invis_wall(39, 10, 18.5, 1, 10, 22) | ||
| 143 | _set_up_invis_wall(20, 15, 18.5, 1, 10, 16) | ||
| 144 | _set_up_invis_wall(11.5, 15, 3, 32, 10, 1) | ||
| 145 | _set_up_invis_wall(11.5, 16, -20, 14, 20, 1) | ||
| 146 | _set_up_invis_wall(14, 16, -26.5, 1, 20, 4) | ||
| 147 | _set_up_invis_wall(28.5, 20.5, -26.5, 1, 15, 25) | ||
| 148 | _set_up_invis_wall(40.5, 20.5, -11, 30, 15, 1) | ||
| 149 | _set_up_invis_wall(50.5, 15, 5.5, 7, 10, 1) | ||
| 150 | _set_up_invis_wall(83.5, 33.5, 5.5, 1, 7, 11) | ||
| 151 | _set_up_invis_wall(83.5, 33.5, -5.5, 1, 7, 11) | ||
| 152 | |||
| 153 | var warp_exit_prefab = preload("res://objects/nodes/exit.tscn") | ||
| 154 | var warp_exit = warp_exit_prefab.instantiate() | ||
| 155 | warp_exit.name = "roof_access_blocker_warp_exit" | ||
| 156 | warp_exit.position = Vector3(58, 10, 0) | ||
| 157 | warp_exit.rotation_degrees.y = 90 | ||
| 158 | get_parent().add_child.call_deferred(warp_exit) | ||
| 159 | |||
| 160 | var warp_enter_prefab = preload("res://objects/nodes/teleportAuto.tscn") | ||
| 161 | var warp_enter = warp_enter_prefab.instantiate() | ||
| 162 | warp_enter.target = warp_exit | ||
| 163 | warp_enter.position = Vector3(76.5, 30, 1) | ||
| 164 | warp_enter.scale = Vector3(4, 1.5, 1) | ||
| 165 | warp_enter.rotation_degrees.y = 90 | ||
| 166 | get_parent().add_child.call_deferred(warp_enter) | ||
| 133 | 167 | ||
| 134 | if global.map == "the_entry": | 168 | if global.map == "the_entry": | 
| 135 | # Remove door behind X1. | 169 | # Remove door behind X1. | 
| @@ -604,9 +638,12 @@ func _ready(): | |||
| 604 | continue | 638 | continue | 
| 605 | 639 | ||
| 606 | if ( | 640 | if ( | 
| 607 | door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY | 641 | not (door.has_legacy_location() and door.get_legacy_location()) | 
| 608 | or door.get_type() == gamedata.SCRIPT_proto.DoorType.GALLERY_PAINTING | 642 | and ( | 
| 609 | or door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR | 643 | door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY | 
| 644 | or door.get_type() == gamedata.SCRIPT_proto.DoorType.GALLERY_PAINTING | ||
| 645 | or door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR | ||
| 646 | ) | ||
| 610 | ): | 647 | ): | 
| 611 | continue | 648 | continue | 
| 612 | 649 | ||
| diff --git a/apworld/client/textclient.gd b/apworld/client/textclient.gd index f785a03..ce28a3a 100644 --- a/apworld/client/textclient.gd +++ b/apworld/client/textclient.gd | |||
| @@ -16,6 +16,8 @@ var tracker_loc_tree_item_by_id = {} | |||
| 16 | var tracker_port_tree_item_by_id = {} | 16 | var tracker_port_tree_item_by_id = {} | 
| 17 | var tracker_goal_tree_item = null | 17 | var tracker_goal_tree_item = null | 
| 18 | var tracker_object_by_index = {} | 18 | var tracker_object_by_index = {} | 
| 19 | var tracker_object_by_ignored_index = {} | ||
| 20 | var tracker_ignored_group = null | ||
| 19 | 21 | ||
| 20 | var worldports_tab | 22 | var worldports_tab | 
| 21 | var worldports_tree | 23 | var worldports_tree | 
| @@ -99,7 +101,7 @@ func _ready(): | |||
| 99 | tabs.add_child(tracker_margins) | 101 | tabs.add_child(tracker_margins) | 
| 100 | 102 | ||
| 101 | tracker_tree = Tree.new() | 103 | tracker_tree = Tree.new() | 
| 102 | tracker_tree.columns = 3 | 104 | tracker_tree.columns = 4 | 
| 103 | tracker_tree.hide_root = true | 105 | tracker_tree.hide_root = true | 
| 104 | tracker_tree.add_theme_font_size_override("font_size", 24) | 106 | tracker_tree.add_theme_font_size_override("font_size", 24) | 
| 105 | tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1)) | 107 | tracker_tree.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1)) | 
| @@ -108,7 +110,9 @@ func _ready(): | |||
| 108 | tracker_tree.set_column_expand(0, false) | 110 | tracker_tree.set_column_expand(0, false) | 
| 109 | tracker_tree.set_column_expand(1, true) | 111 | tracker_tree.set_column_expand(1, true) | 
| 110 | tracker_tree.set_column_expand(2, false) | 112 | tracker_tree.set_column_expand(2, false) | 
| 113 | tracker_tree.set_column_expand(3, false) | ||
| 111 | tracker_tree.set_column_custom_minimum_width(2, 200) | 114 | tracker_tree.set_column_custom_minimum_width(2, 200) | 
| 115 | tracker_tree.set_column_custom_minimum_width(3, 200) | ||
| 112 | tracker_margins.add_child(tracker_tree) | 116 | tracker_margins.add_child(tracker_tree) | 
| 113 | 117 | ||
| 114 | worldports_tab = MarginContainer.new() | 118 | worldports_tab = MarginContainer.new() | 
| @@ -208,6 +212,8 @@ func update_locations(reset_locations = true): | |||
| 208 | "name": location_name, | 212 | "name": location_name, | 
| 209 | "type": kLocation, | 213 | "type": kLocation, | 
| 210 | "id": location_id, | 214 | "id": location_id, | 
| 215 | "ignored": ap._ignored_locations.has(location_id), | ||
| 216 | "hint": ap.client._hinted_locations.has(location_id), | ||
| 211 | } | 217 | } | 
| 212 | ) | 218 | ) | 
| 213 | ) | 219 | ) | 
| @@ -222,11 +228,13 @@ func update_locations(reset_locations = true): | |||
| 222 | "name": port_name, | 228 | "name": port_name, | 
| 223 | "type": kWorldport, | 229 | "type": kWorldport, | 
| 224 | "id": port_id, | 230 | "id": port_id, | 
| 231 | "ignored": false, | ||
| 232 | "hint": false, | ||
| 225 | } | 233 | } | 
| 226 | ) | 234 | ) | 
| 227 | ) | 235 | ) | 
| 228 | 236 | ||
| 229 | locations.sort_custom(func(a, b): return a["name"] < b["name"]) | 237 | locations.sort_custom(_cmp_tracker_objects) | 
| 230 | 238 | ||
| 231 | if ap.client._goal_accessible: | 239 | if ap.client._goal_accessible: | 
| 232 | var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[ | 240 | var location_name = gamedata.ending_display_name_by_name[ap.kEndingNameByVictoryValue[ | 
| @@ -238,14 +246,18 @@ func update_locations(reset_locations = true): | |||
| 238 | { | 246 | { | 
| 239 | "name": location_name, | 247 | "name": location_name, | 
| 240 | "type": kGoal, | 248 | "type": kGoal, | 
| 249 | "ignored": false, | ||
| 250 | "hint": false, | ||
| 241 | } | 251 | } | 
| 242 | ) | 252 | ) | 
| 243 | ) | 253 | ) | 
| 244 | 254 | ||
| 245 | var count = 0 | 255 | var count = 0 | 
| 246 | for location in locations: | 256 | for location in locations: | 
| 247 | if count < 18: | 257 | if count < 18 and not location["ignored"]: | 
| 248 | locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT) | 258 | locations_overlay.push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT) | 
| 259 | if location["hint"]: | ||
| 260 | locations_overlay.push_color(Color("#fafad2")) | ||
| 249 | locations_overlay.append_text(location["name"]) | 261 | locations_overlay.append_text(location["name"]) | 
| 250 | locations_overlay.append_text(" ") | 262 | locations_overlay.append_text(" ") | 
| 251 | if location["type"] == kLocation: | 263 | if location["type"] == kLocation: | 
| @@ -254,6 +266,8 @@ func update_locations(reset_locations = true): | |||
| 254 | locations_overlay.add_image(worldport_texture) | 266 | locations_overlay.add_image(worldport_texture) | 
| 255 | elif location["type"] == kGoal: | 267 | elif location["type"] == kGoal: | 
| 256 | locations_overlay.add_image(goal_texture) | 268 | locations_overlay.add_image(goal_texture) | 
| 269 | if location["hint"]: | ||
| 270 | locations_overlay.pop() | ||
| 257 | locations_overlay.pop() | 271 | locations_overlay.pop() | 
| 258 | count += 1 | 272 | count += 1 | 
| 259 | 273 | ||
| @@ -266,17 +280,43 @@ func update_locations(reset_locations = true): | |||
| 266 | var root_ti = tracker_tree.create_item(null) | 280 | var root_ti = tracker_tree.create_item(null) | 
| 267 | 281 | ||
| 268 | for location in locations: | 282 | for location in locations: | 
| 269 | var loc_row = root_ti.create_child() | 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 | |||
| 270 | loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON) | 298 | loc_row.set_cell_mode(0, TreeItem.CELL_MODE_ICON) | 
| 271 | loc_row.set_selectable(0, false) | 299 | loc_row.set_selectable(0, false) | 
| 272 | loc_row.set_text(1, location["name"]) | 300 | loc_row.set_text(1, location["name"]) | 
| 273 | loc_row.set_selectable(1, false) | 301 | loc_row.set_selectable(1, false) | 
| 302 | if location["hint"]: | ||
| 303 | loc_row.set_custom_color(1, Color("#fafad2")) | ||
| 274 | loc_row.set_cell_mode(2, TreeItem.CELL_MODE_CUSTOM) | 304 | loc_row.set_cell_mode(2, TreeItem.CELL_MODE_CUSTOM) | 
| 275 | loc_row.set_text(2, "Show Path") | 305 | loc_row.set_text(2, "Show Path") | 
| 276 | loc_row.set_custom_as_button(2, true) | 306 | loc_row.set_custom_as_button(2, true) | 
| 277 | loc_row.set_editable(2, true) | 307 | loc_row.set_editable(2, true) | 
| 278 | loc_row.set_selectable(2, false) | 308 | loc_row.set_selectable(2, false) | 
| 279 | loc_row.set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER) | 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) | ||
| 280 | 320 | ||
| 281 | if location["type"] == kLocation: | 321 | if location["type"] == kLocation: | 
| 282 | loc_row.set_icon(0, location_texture) | 322 | loc_row.set_icon(0, location_texture) | 
| @@ -288,7 +328,10 @@ func update_locations(reset_locations = true): | |||
| 288 | loc_row.set_icon(0, goal_texture) | 328 | loc_row.set_icon(0, goal_texture) | 
| 289 | tracker_goal_tree_item = loc_row | 329 | tracker_goal_tree_item = loc_row | 
| 290 | 330 | ||
| 291 | tracker_object_by_index[loc_row.get_index()] = location | 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 | ||
| 292 | else: | 335 | else: | 
| 293 | for loc_row in tracker_tree.get_root().get_children(): | 336 | for loc_row in tracker_tree.get_root().get_children(): | 
| 294 | loc_row.visible = false | 337 | loc_row.visible = false | 
| @@ -310,6 +353,18 @@ func update_locations(reset_locations = true): | |||
| 310 | if tracker_goal_tree_item != null and ap.client._goal_accessible: | 353 | if tracker_goal_tree_item != null and ap.client._goal_accessible: | 
| 311 | tracker_goal_tree_item.visible = true | 354 | tracker_goal_tree_item.visible = true | 
| 312 | 355 | ||
| 356 | if tracker_ignored_group != null: | ||
| 357 | tracker_ignored_group.visible = true | ||
| 358 | |||
| 359 | |||
| 360 | func _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 | |||
| 313 | 368 | ||
| 314 | func update_locations_visibility(): | 369 | func update_locations_visibility(): | 
| 315 | var ap = global.get_node("Archipelago") | 370 | var ap = global.get_node("Archipelago") | 
| @@ -317,20 +372,33 @@ func update_locations_visibility(): | |||
| 317 | 372 | ||
| 318 | 373 | ||
| 319 | func _on_tracker_button_clicked(): | 374 | func _on_tracker_button_clicked(): | 
| 375 | var ap = global.get_node("Archipelago") | ||
| 376 | |||
| 320 | var edited_item = tracker_tree.get_edited() | 377 | var edited_item = tracker_tree.get_edited() | 
| 321 | var edited_index = edited_item.get_index() | 378 | var edited_index = edited_item.get_index() | 
| 322 | 379 | ||
| 323 | if tracker_object_by_index.has(edited_index): | 380 | if edited_item.get_parent() == tracker_tree.get_root(): | 
| 324 | var tracker_object = tracker_object_by_index[edited_index] | 381 | if tracker_object_by_index.has(edited_index): | 
| 325 | var ap = global.get_node("Archipelago") | 382 | var tracker_object = tracker_object_by_index[edited_index] | 
| 326 | var type_str = "" | 383 | if tracker_tree.get_edited_column() == 2: | 
| 327 | if tracker_object["type"] == kLocation: | 384 | var type_str = "" | 
| 328 | type_str = "location" | 385 | if tracker_object["type"] == kLocation: | 
| 329 | elif tracker_object["type"] == kWorldport: | 386 | type_str = "location" | 
| 330 | type_str = "worldport" | 387 | elif tracker_object["type"] == kWorldport: | 
| 331 | elif tracker_object["type"] == kGoal: | 388 | type_str = "worldport" | 
| 332 | type_str = "goal" | 389 | elif tracker_object["type"] == kGoal: | 
| 333 | ap.client.getLogicalPath(type_str, tracker_object.get("id", null)) | 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"]) | ||
| 334 | 402 | ||
| 335 | 403 | ||
| 336 | func display_logical_path(object_type, object_id, paths): | 404 | func display_logical_path(object_type, object_id, paths): | 
| @@ -435,4 +503,6 @@ func reset_tracker_tab(): | |||
| 435 | tracker_port_tree_item_by_id.clear() | 503 | tracker_port_tree_item_by_id.clear() | 
| 436 | tracker_goal_tree_item = null | 504 | tracker_goal_tree_item = null | 
| 437 | tracker_object_by_index.clear() | 505 | tracker_object_by_index.clear() | 
| 506 | tracker_object_by_ignored_index.clear() | ||
| 507 | tracker_ignored_group = null | ||
| 438 | tracker_tree.clear() | 508 | tracker_tree.clear() | 
| diff --git a/apworld/client/unlockReaderListener.gd b/apworld/client/unlockReaderListener.gd new file mode 100644 index 0000000..a5754b9 --- /dev/null +++ b/apworld/client/unlockReaderListener.gd | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | extends "res://scripts/nodes/listeners/unlockReaderListener.gd" | ||
| 2 | |||
| 3 | var item_id = null | ||
| 4 | var item_amount | ||
| 5 | |||
| 6 | |||
| 7 | func _ready(): | ||
| 8 | var node_path = String( | ||
| 9 | get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names() | ||
| 10 | ) | ||
| 11 | |||
| 12 | var gamedata = global.get_node("Gamedata") | ||
| 13 | var door_id = gamedata.get_door_for_map_node_path(global.map, node_path) | ||
| 14 | if door_id != null: | ||
| 15 | var ap = global.get_node("Archipelago") | ||
| 16 | var item_lock = ap.get_item_id_for_door(door_id) | ||
| 17 | |||
| 18 | if item_lock != null: | ||
| 19 | item_id = item_lock[0] | ||
| 20 | item_amount = item_lock[1] | ||
| 21 | |||
| 22 | self.senders = [] | ||
| 23 | self.senderGroup = [] | ||
| 24 | self.nested = false | ||
| 25 | self.complete_at = 0 | ||
| 26 | self.max_length = 0 | ||
| 27 | self.excludeSenders = [] | ||
| 28 | |||
| 29 | super._ready() | ||
| 30 | |||
| 31 | |||
| 32 | func _readier(): | ||
| 33 | if item_id != null: | ||
| 34 | var ap = global.get_node("Archipelago") | ||
| 35 | |||
| 36 | if ap.client.getItemAmount(item_id) >= item_amount: | ||
| 37 | handleTriggered() | ||
| 38 | else: | ||
| 39 | super._readier() | ||
| 40 | |||
| 41 | |||
| 42 | func handleTriggered(): | ||
| 43 | if item_id != null: | ||
| 44 | emit_signal("trigger") | ||
| 45 | else: | ||
| 46 | super.handleTriggered() | ||
