about summary refs log tree commit diff stats
path: root/client/Archipelago
diff options
context:
space:
mode:
Diffstat (limited to 'client/Archipelago')
-rw-r--r--client/Archipelago/client.gd15
-rw-r--r--client/Archipelago/collectable.gd16
-rw-r--r--client/Archipelago/gamedata.gd4
-rw-r--r--client/Archipelago/keyHolder.gd38
-rw-r--r--client/Archipelago/keyHolderChecker.gd24
-rw-r--r--client/Archipelago/keyHolderResetterListener.gd8
-rw-r--r--client/Archipelago/keyboard.gd178
-rw-r--r--client/Archipelago/manager.gd213
-rw-r--r--client/Archipelago/pauseMenu.gd6
-rw-r--r--client/Archipelago/player.gd17
-rw-r--r--client/Archipelago/saver.gd6
-rw-r--r--client/Archipelago/settings_screen.gd23
-rw-r--r--client/Archipelago/textclient.gd2
13 files changed, 513 insertions, 37 deletions
diff --git a/client/Archipelago/client.gd b/client/Archipelago/client.gd index 428560e..2e080fd 100644 --- a/client/Archipelago/client.gd +++ b/client/Archipelago/client.gd
@@ -41,6 +41,7 @@ signal connect_status
41signal client_connected(slot_data) 41signal client_connected(slot_data)
42signal item_received(item_id, index, player, flags, amount) 42signal item_received(item_id, index, player, flags, amount)
43signal message_received(message) 43signal message_received(message)
44signal location_scout_received(item_id, location_id, player, flags)
44 45
45 46
46func _init(): 47func _init():
@@ -257,6 +258,16 @@ func _process(_delta):
257 elif cmd == "PrintJSON": 258 elif cmd == "PrintJSON":
258 emit_signal("message_received", message) 259 emit_signal("message_received", message)
259 260
261 elif cmd == "LocationInfo":
262 for loc in message["locations"]:
263 emit_signal(
264 "location_scout_received",
265 int(loc["item"]),
266 int(loc["location"]),
267 int(loc["player"]),
268 int(loc["flags"])
269 )
270
260 elif state == WebSocketPeer.STATE_CLOSED: 271 elif state == WebSocketPeer.STATE_CLOSED:
261 if _has_connected: 272 if _has_connected:
262 _closed() 273 _closed()
@@ -392,6 +403,10 @@ func completedGoal():
392 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL 403 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
393 404
394 405
406func scoutLocations(loc_ids):
407 sendMessage([{"cmd": "LocationScouts", "locations": loc_ids}])
408
409
395func hasItem(item_id): 410func hasItem(item_id):
396 return _received_items.has(item_id) 411 return _received_items.has(item_id)
397 412
diff --git a/client/Archipelago/collectable.gd b/client/Archipelago/collectable.gd new file mode 100644 index 0000000..4a17a2a --- /dev/null +++ b/client/Archipelago/collectable.gd
@@ -0,0 +1,16 @@
1extends "res://scripts/nodes/collectable.gd"
2
3
4func pickedUp():
5 if unlock_type == "key":
6 var ap = global.get_node("Archipelago")
7 if ap.get_letter_behavior(unlock_key, level == 2) == ap.kLETTER_BEHAVIOR_VANILLA:
8 ap.keyboard.collect_local_letter(unlock_key, level)
9 else:
10 ap.keyboard.update_unlocks()
11
12 super.pickedUp()
13
14
15func setScoutedText(text):
16 get_node("MeshInstance3D").mesh.text = text.replace(" ", "\n")
diff --git a/client/Archipelago/gamedata.gd b/client/Archipelago/gamedata.gd index 669ad3d..f7a5d90 100644 --- a/client/Archipelago/gamedata.gd +++ b/client/Archipelago/gamedata.gd
@@ -8,6 +8,7 @@ var painting_id_by_map_node_path = {}
8var door_id_by_ap_id = {} 8var door_id_by_ap_id = {}
9var map_id_by_name = {} 9var map_id_by_name = {}
10var progressive_id_by_ap_id = {} 10var progressive_id_by_ap_id = {}
11var letter_id_by_ap_id = {}
11 12
12 13
13func _init(proto_script): 14func _init(proto_script):
@@ -54,6 +55,9 @@ func load(data_bytes):
54 for progressive in objects.get_progressives(): 55 for progressive in objects.get_progressives():
55 progressive_id_by_ap_id[progressive.get_ap_id()] = progressive.get_id() 56 progressive_id_by_ap_id[progressive.get_ap_id()] = progressive.get_id()
56 57
58 for letter in objects.get_letters():
59 letter_id_by_ap_id[letter.get_ap_id()] = letter.get_id()
60
57 61
58func get_door_for_map_node_path(map_name, node_path): 62func get_door_for_map_node_path(map_name, node_path):
59 if not door_id_by_map_node_path.has(map_name): 63 if not door_id_by_map_node_path.has(map_name):
diff --git a/client/Archipelago/keyHolder.gd b/client/Archipelago/keyHolder.gd new file mode 100644 index 0000000..3c037ff --- /dev/null +++ b/client/Archipelago/keyHolder.gd
@@ -0,0 +1,38 @@
1extends "res://scripts/nodes/keyHolder.gd"
2
3
4func setFromAp(key, level):
5 if level > 0:
6 has_key = true
7 is_complete = "%s%d" % [key, level]
8 held_key = key
9 held_level = level
10 get_node("Hinge/Letter").mesh.text = held_key
11 get_node("Hinge/Letter2").mesh.text = held_key
12 setMaterial()
13 emit_signal("trigger")
14 else:
15 has_key = false
16 held_key = ""
17 held_level = 0
18 setMaterial()
19 get_node("Hinge/Letter").mesh.text = "-"
20 get_node("Hinge/Letter2").mesh.text = "-"
21 is_complete = ""
22 emit_signal("untrigger")
23
24
25func addKey(key):
26 var node_path = String(
27 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
28 )
29 var ap = global.get_node("Archipelago")
30 ap.keyboard.put_in_keyholder(key, global.map, node_path)
31
32
33func removeKey():
34 var node_path = String(
35 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
36 )
37 var ap = global.get_node("Archipelago")
38 ap.keyboard.remove_from_keyholder(held_key, global.map, node_path)
diff --git a/client/Archipelago/keyHolderChecker.gd b/client/Archipelago/keyHolderChecker.gd new file mode 100644 index 0000000..a75a9e4 --- /dev/null +++ b/client/Archipelago/keyHolderChecker.gd
@@ -0,0 +1,24 @@
1extends "res://scripts/nodes/listeners/keyHolderChecker.gd"
2
3
4func check():
5 var ap = global.get_node("Archipelago")
6 var matches = []
7 for map in ap.keyboard.keyholder_state.keys():
8 var nodes = ap.keyboard.keyholder_state[map]
9 for node in nodes.keys():
10 matches.append([nodes[node], 1, map, "/root/scene/%s" % node])
11
12 var count = 0
13 for key_match in matches:
14 var active = (
15 key_match[2] + String(key_match[3]).replace("/root/scene/Components/KeyHolders/", ".")
16 )
17 if map[active] == key_match[0]:
18 emit_signal("trigger_letter", key_match[0], true)
19 count += 1
20 else:
21 emit_signal("trigger_letter", key_match[0], false)
22
23 if count > 25:
24 emit_signal("trigger")
diff --git a/client/Archipelago/keyHolderResetterListener.gd b/client/Archipelago/keyHolderResetterListener.gd new file mode 100644 index 0000000..d5300f3 --- /dev/null +++ b/client/Archipelago/keyHolderResetterListener.gd
@@ -0,0 +1,8 @@
1extends "res://scripts/nodes/listeners/keyHolderResetterListener.gd"
2
3
4func reset():
5 var ap = global.get_node("Archipelago")
6 var was_removed = ap.keyboard.reset_keyholders()
7 if was_removed:
8 sfxPlayer.sfx_play("pickup")
diff --git a/client/Archipelago/keyboard.gd b/client/Archipelago/keyboard.gd new file mode 100644 index 0000000..600a047 --- /dev/null +++ b/client/Archipelago/keyboard.gd
@@ -0,0 +1,178 @@
1extends Node
2
3const kALL_LETTERS = "abcdefghjiklmnopqrstuvwxyz"
4
5var letters_saved = {}
6var letters_in_keyholders = []
7var letters_dynamic = {}
8var keyholder_state = {}
9
10var filename = ""
11
12
13func _init():
14 reset()
15
16
17func reset():
18 letters_saved.clear()
19 letters_in_keyholders.clear()
20 letters_dynamic.clear()
21 keyholder_state.clear()
22
23
24func load_seed():
25 var ap = global.get_node("Archipelago")
26
27 reset()
28
29 filename = "user://archipelago_keys/%s_%d" % [ap.client._seed, ap.client._slot]
30
31 if FileAccess.file_exists(filename):
32 var ap_file = FileAccess.open(filename, FileAccess.READ)
33 var localdata = []
34 if ap_file != null:
35 localdata = ap_file.get_var(true)
36 ap_file.close()
37
38 if typeof(localdata) != TYPE_ARRAY:
39 print("AP keyboard file is corrupted")
40 localdata = []
41
42 if localdata.size() > 0:
43 letters_saved = localdata[0]
44 if localdata.size() > 1:
45 letters_in_keyholders = localdata[1]
46 if localdata.size() > 2:
47 keyholder_state = localdata[2]
48
49 for k in kALL_LETTERS:
50 var level = 0
51
52 if ap.get_letter_behavior(k, false) == ap.kLETTER_BEHAVIOR_UNLOCKED:
53 level += 1
54 if ap.get_letter_behavior(k, true) == ap.kLETTER_BEHAVIOR_UNLOCKED:
55 level += 1
56
57 letters_dynamic[k] = level
58
59 update_unlocks()
60
61
62func save():
63 var dir = DirAccess.open("user://")
64 var folder = "archipelago_keys"
65 if not dir.dir_exists(folder):
66 dir.make_dir(folder)
67
68 var file = FileAccess.open(filename, FileAccess.WRITE)
69
70 var data = [
71 letters_saved,
72 letters_in_keyholders,
73 keyholder_state,
74 ]
75 file.store_var(data, true)
76 file.close()
77
78
79func update_unlocks():
80 unlocks.resetKeys()
81
82 var has_doubles = false
83
84 for k in kALL_LETTERS:
85 var level = 0
86
87 if not letters_in_keyholders.has(k):
88 level = letters_saved.get(k, 0) + letters_dynamic.get(k, 0)
89
90 if level >= 2:
91 level = 2
92 has_doubles = true
93
94 unlocks.unlockKey(k, level)
95
96 if has_doubles and unlocks.data["double_letters"] != "unlocked":
97 var ap = global.get_node("Archipelago")
98 if ap.cyan_door_behavior == ap.kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER:
99 unlocks.setData("double_letters", "unlocked")
100
101
102func collect_local_letter(key, level):
103 if level < 0 or level > 2 or level < letters_saved.get(key, 0):
104 return
105
106 letters_saved[key] = level
107
108 update_unlocks()
109 save()
110
111
112func collect_remote_letter(key, level):
113 if level < 0 or level > 2 or level < letters_dynamic.get(key, 0):
114 return
115
116 letters_dynamic[key] = level
117
118 update_unlocks()
119 save()
120
121
122func put_in_keyholder(key, map, kh_path):
123 if not keyholder_state.has(map):
124 keyholder_state[map] = {}
125
126 keyholder_state[map][kh_path] = key
127 letters_in_keyholders.append(key)
128
129 get_tree().get_root().get_node("scene").get_node(kh_path).setFromAp(
130 key, min(letters_saved.get(key, 0) + letters_dynamic.get(key, 0), 2)
131 )
132
133 update_unlocks()
134 save()
135
136
137func remove_from_keyholder(key, map, kh_path):
138 if not keyholder_state.has(map):
139 # This... shouldn't happen.
140 keyholder_state[map] = {}
141
142 keyholder_state[map].erase(kh_path)
143 letters_in_keyholders.erase(key)
144
145 get_tree().get_root().get_node("scene").get_node(kh_path).setFromAp(key, 0)
146
147 update_unlocks()
148 save()
149
150
151func load_keyholders(map):
152 if keyholder_state.has(map):
153 var khs = keyholder_state[map]
154
155 for path in khs.keys():
156 var key = khs[path]
157 get_tree().get_root().get_node("scene").get_node(path).setFromAp(
158 key, min(letters_saved.get(key, 0) + letters_dynamic.get(key, 0), 2)
159 )
160
161
162func reset_keyholders():
163 if letters_in_keyholders.is_empty():
164 return false
165
166 if keyholder_state.has(global.map):
167 for path in keyholder_state[global.map]:
168 get_tree().get_root().get_node("scene").get_node(path).setFromAp(
169 keyholder_state[global.map][path], 0
170 )
171
172 keyholder_state.clear()
173 letters_in_keyholders.clear()
174
175 update_unlocks()
176 save()
177
178 return true
diff --git a/client/Archipelago/manager.gd b/client/Archipelago/manager.gd index 609e645..cd0654f 100644 --- a/client/Archipelago/manager.gd +++ b/client/Archipelago/manager.gd
@@ -3,6 +3,7 @@ extends Node
3const my_version = "0.1.0" 3const my_version = "0.1.0"
4 4
5var SCRIPT_client 5var SCRIPT_client
6var SCRIPT_keyboard
6var SCRIPT_locationListener 7var SCRIPT_locationListener
7var SCRIPT_uuid 8var SCRIPT_uuid
8var SCRIPT_victoryListener 9var SCRIPT_victoryListener
@@ -13,16 +14,39 @@ var ap_pass = ""
13var connection_history = [] 14var connection_history = []
14 15
15var client 16var client
17var keyboard
16 18
17var _localdata_file = "" 19var _localdata_file = ""
18var _last_new_item = -1 20var _last_new_item = -1
19var _batch_locations = false 21var _batch_locations = false
20var _held_locations = [] 22var _held_locations = []
23var _held_location_scouts = []
24var _location_scouts = {}
21var _item_locks = {} 25var _item_locks = {}
26var _inverse_item_locks = {}
27var _held_letters = {}
28var _letters_setup = false
22 29
30const kSHUFFLE_LETTERS_VANILLA = 0
31const kSHUFFLE_LETTERS_UNLOCKED = 1
32const kSHUFFLE_LETTERS_PROGRESSIVE = 2
33const kSHUFFLE_LETTERS_VANILLA_CYAN = 3
34const kSHUFFLE_LETTERS_ITEM_CYAN = 4
35
36const kLETTER_BEHAVIOR_VANILLA = 0
37const kLETTER_BEHAVIOR_ITEM = 1
38const kLETTER_BEHAVIOR_UNLOCKED = 2
39
40const kCYAN_DOOR_BEHAVIOR_H2 = 0
41const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1
42const kCYAN_DOOR_BEHAVIOR_ITEM = 2
43
44var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2
23var daedalus_roof_access = false 45var daedalus_roof_access = false
24var keyholder_sanity = false 46var keyholder_sanity = false
47var shuffle_control_center_colors = false
25var shuffle_doors = false 48var shuffle_doors = false
49var shuffle_letters = kSHUFFLE_LETTERS_VANILLA
26var victory_condition = -1 50var victory_condition = -1
27 51
28signal could_not_connect 52signal could_not_connect
@@ -60,12 +84,16 @@ func _ready():
60 84
61 client.connect("item_received", _process_item) 85 client.connect("item_received", _process_item)
62 client.connect("message_received", _process_message) 86 client.connect("message_received", _process_message)
87 client.connect("location_scout_received", _process_location_scout)
63 client.connect("could_not_connect", _client_could_not_connect) 88 client.connect("could_not_connect", _client_could_not_connect)
64 client.connect("connect_status", _client_connect_status) 89 client.connect("connect_status", _client_connect_status)
65 client.connect("client_connected", _client_connected) 90 client.connect("client_connected", _client_connected)
66 91
67 add_child(client) 92 add_child(client)
68 93
94 keyboard = SCRIPT_keyboard.new()
95 add_child(keyboard)
96
69 97
70func saveSettings(): 98func saveSettings():
71 # Save the AP settings to disk. 99 # Save the AP settings to disk.
@@ -100,6 +128,12 @@ func saveLocaldata():
100 128
101func connectToServer(): 129func connectToServer():
102 _last_new_item = -1 130 _last_new_item = -1
131 _batch_locations = false
132 _held_locations = []
133 _held_location_scouts = []
134 _location_scouts = {}
135 _letters_setup = false
136 _held_letters = {}
103 137
104 client.connectToServer(ap_server, ap_user, ap_pass) 138 client.connectToServer(ap_server, ap_user, ap_pass)
105 139
@@ -122,29 +156,32 @@ func _process_item(item, index, from, flags, amount):
122 item_name = client._item_id_to_name["Lingo 2"][item] 156 item_name = client._item_id_to_name["Lingo 2"][item]
123 157
124 var gamedata = global.get_node("Gamedata") 158 var gamedata = global.get_node("Gamedata")
125 var door_id = gamedata.door_id_by_ap_id.get(item, null)
126 var prog_id = null
127 159
128 if door_id == null: 160 var prog_id = null
129 prog_id = gamedata.progressive_id_by_ap_id.get(item, null) 161 if _inverse_item_locks.has(item):
130 if prog_id != null: 162 for lock in _inverse_item_locks.get(item):
131 var progressive = gamedata.objects.get_progressives()[prog_id] 163 if lock[1] != amount:
132 if progressive.get_doors().size() >= amount: 164 continue
133 door_id = progressive.get_doors()[amount - 1] 165
134 166 if gamedata.progressive_id_by_ap_id.has(item):
135 if door_id != null and gamedata.get_door_map_name(door_id) == global.map: 167 prog_id = lock[0]
136 var receivers = gamedata.get_door_receivers(door_id) 168
137 var scene = get_tree().get_root().get_node_or_null("scene") 169 if gamedata.get_door_map_name(lock[0]) != global.map:
138 if scene != null: 170 continue
139 for receiver in receivers: 171
140 var rnode = scene.get_node_or_null(receiver) 172 var receivers = gamedata.get_door_receivers(lock[0])
141 if rnode != null: 173 var scene = get_tree().get_root().get_node_or_null("scene")
142 rnode.handleTriggered() 174 if scene != null:
143 #for painting_id in gamedata.objects.get_doors()[door_id].get_move_paintings(): 175 for receiver in receivers:
144 # var painting = gamedata.objects.get_paintings()[painting_id] 176 var rnode = scene.get_node_or_null(receiver)
145 # var pnode = scene.get_node_or_null(painting.get_path() + "/teleportListener") 177 if rnode != null:
146 # if pnode != null: 178 rnode.handleTriggered()
147 # pnode.handleTriggered() 179
180 var letter_id = gamedata.letter_id_by_ap_id.get(item, null)
181 if letter_id != null:
182 var letter = gamedata.objects.get_letters()[letter_id]
183 if not letter.has_level2() or not letter.get_level2():
184 _process_key_item(letter.get_key(), amount)
148 185
149 # Show a message about the item if it's new. 186 # Show a message about the item if it's new.
150 if index != null and index > _last_new_item: 187 if index != null and index > _last_new_item:
@@ -158,8 +195,8 @@ func _process_item(item, index, from, flags, amount):
158 var item_color = colorForItemType(flags) 195 var item_color = colorForItemType(flags)
159 196
160 var full_item_name = item_name 197 var full_item_name = item_name
161 if prog_id != null and door_id != null: 198 if prog_id != null:
162 var door = gamedata.objects.get_doors()[door_id] 199 var door = gamedata.objects.get_doors()[prog_id]
163 full_item_name = "%s (%s)" % [item_name, door.get_name()] 200 full_item_name = "%s (%s)" % [item_name, door.get_name()]
164 201
165 var message 202 var message
@@ -261,6 +298,29 @@ func parse_printjson_for_textclient(message):
261 textclient_node.parse_printjson("".join(parts)) 298 textclient_node.parse_printjson("".join(parts))
262 299
263 300
301func _process_location_scout(item_id, location_id, player, flags):
302 _location_scouts[location_id] = {"item": item_id, "player": player, "flags": flags}
303
304 var gamedata = global.get_node("Gamedata")
305 var map_id = gamedata.map_id_by_name.get(global.map)
306
307 var item_name = "Unknown"
308 var item_player_game = client._game_by_player[float(player)]
309 if client._item_id_to_name[item_player_game].has(item_id):
310 item_name = client._item_id_to_name[item_player_game][item_id]
311
312 var letter_id = gamedata.letter_id_by_ap_id.get(location_id, null)
313 if letter_id != null:
314 var letter = gamedata.objects.get_letters()[letter_id]
315 var room = gamedata.objects.get_rooms()[letter.get_room_id()]
316 if room.get_map_id() == map_id:
317 var collectable = get_tree().get_root().get_node("scene").get_node_or_null(
318 letter.get_path()
319 )
320 if collectable != null:
321 collectable.setScoutedText(item_name)
322
323
264func _client_could_not_connect(): 324func _client_could_not_connect():
265 emit_signal("could_not_connect") 325 emit_signal("could_not_connect")
266 326
@@ -290,9 +350,12 @@ func _client_connected(slot_data):
290 _last_new_item = localdata[0] 350 _last_new_item = localdata[0]
291 351
292 # Read slot data. 352 # Read slot data.
353 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0))
293 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) 354 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false))
294 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false)) 355 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false))
356 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false))
295 shuffle_doors = bool(slot_data.get("shuffle_doors", false)) 357 shuffle_doors = bool(slot_data.get("shuffle_doors", false))
358 shuffle_letters = int(slot_data.get("shuffle_letters", 0))
296 victory_condition = int(slot_data.get("victory_condition", 0)) 359 victory_condition = int(slot_data.get("victory_condition", 0))
297 360
298 # Set up item locks. 361 # Set up item locks.
@@ -311,6 +374,42 @@ func _client_connected(slot_data):
311 var door = gamedata.objects.get_doors()[progressive.get_doors()[i]] 374 var door = gamedata.objects.get_doors()[progressive.get_doors()[i]]
312 _item_locks[door.get_id()] = [progressive.get_ap_id(), i + 1] 375 _item_locks[door.get_id()] = [progressive.get_ap_id(), i + 1]
313 376
377 for door_group in gamedata.objects.get_door_groups():
378 if (
379 door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.CONNECTOR
380 or door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.SHUFFLE_GROUP
381 ):
382 for door in door_group.get_doors():
383 _item_locks[door] = [door_group.get_ap_id(), 1]
384
385 if shuffle_control_center_colors:
386 for door in gamedata.objects.get_doors():
387 if door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR:
388 _item_locks[door.get_id()] = [door.get_ap_id(), 1]
389
390 for door_group in gamedata.objects.get_door_groups():
391 if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.COLOR_CONNECTOR:
392 for door in door_group.get_doors():
393 _item_locks[door] = [door_group.get_ap_id(), 1]
394
395 if cyan_door_behavior == kCYAN_DOOR_BEHAVIOR_ITEM:
396 for door_group in gamedata.objects.get_door_groups():
397 if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.CYAN_DOORS:
398 for door in door_group.get_doors():
399 if not _item_locks.has(door):
400 _item_locks[door] = [door_group.get_ap_id(), 1]
401
402 # Create a reverse item locks map for processing items.
403 _inverse_item_locks = {}
404
405 for door_id in _item_locks.keys():
406 var lock = _item_locks.get(door_id)
407
408 if not _inverse_item_locks.has(lock[0]):
409 _inverse_item_locks[lock[0]] = []
410
411 _inverse_item_locks[lock[0]].append([door_id, lock[1]])
412
314 emit_signal("ap_connected") 413 emit_signal("ap_connected")
315 414
316 415
@@ -325,10 +424,28 @@ func send_location(loc_id):
325 client.sendLocation(loc_id) 424 client.sendLocation(loc_id)
326 425
327 426
427func scout_location(loc_id):
428 if _location_scouts.has(loc_id):
429 return _location_scouts.get(loc_id)
430
431 if _batch_locations:
432 _held_location_scouts.append(loc_id)
433 else:
434 client.scoutLocation(loc_id)
435
436 return null
437
438
328func stop_batching_locations(): 439func stop_batching_locations():
329 _batch_locations = false 440 _batch_locations = false
330 client.sendLocations(_held_locations) 441
331 _held_locations.clear() 442 if not _held_locations.is_empty():
443 client.sendLocations(_held_locations)
444 _held_locations.clear()
445
446 if not _held_location_scouts.is_empty():
447 client.scoutLocations(_held_location_scouts)
448 _held_location_scouts.clear()
332 449
333 450
334func colorForItemType(flags): 451func colorForItemType(flags):
@@ -344,3 +461,47 @@ func colorForItemType(flags):
344 return "#d63a22" 461 return "#d63a22"
345 else: # filler 462 else: # filler
346 return "#14de9e" 463 return "#14de9e"
464
465
466func get_letter_behavior(key, level2):
467 if shuffle_letters == kSHUFFLE_LETTERS_UNLOCKED:
468 return kLETTER_BEHAVIOR_UNLOCKED
469
470 if [kSHUFFLE_LETTERS_VANILLA_CYAN, kSHUFFLE_LETTERS_ITEM_CYAN].has(shuffle_letters):
471 if level2:
472 if shuffle_letters == kSHUFFLE_LETTERS_VANILLA_CYAN:
473 return kLETTER_BEHAVIOR_VANILLA
474 else:
475 return kLETTER_BEHAVIOR_ITEM
476 else:
477 return kLETTER_BEHAVIOR_UNLOCKED
478
479 if not level2 and ["h", "i", "n", "t"].has(key):
480 # This differs from the equivalent function in the apworld. Logically it is
481 # the same as UNLOCKED since they are in the starting room, but VANILLA
482 # means the player still has to actually pick up the letters.
483 return kLETTER_BEHAVIOR_VANILLA
484
485 if shuffle_letters == kSHUFFLE_LETTERS_PROGRESSIVE:
486 return kLETTER_BEHAVIOR_ITEM
487
488 return kLETTER_BEHAVIOR_VANILLA
489
490
491func setup_keys():
492 keyboard.load_seed()
493
494 _letters_setup = true
495
496 for k in _held_letters.keys():
497 _process_key_item(k, _held_letters[k])
498
499 _held_letters.clear()
500
501
502func _process_key_item(key, level):
503 if not _letters_setup:
504 _held_letters[key] = max(_held_letters.get(key, 0), level)
505 return
506
507 keyboard.collect_remote_letter(key, level)
diff --git a/client/Archipelago/pauseMenu.gd b/client/Archipelago/pauseMenu.gd index 6c013a5..5da114a 100644 --- a/client/Archipelago/pauseMenu.gd +++ b/client/Archipelago/pauseMenu.gd
@@ -4,3 +4,9 @@ extends "res://scripts/ui/pauseMenu.gd"
4func _pause_game(): 4func _pause_game():
5 global.get_node("Textclient").dismiss() 5 global.get_node("Textclient").dismiss()
6 super._pause_game() 6 super._pause_game()
7
8
9func _main_menu():
10 global.loaded = false
11 global.get_node("Archipelago").disconnect_from_ap()
12 super._main_menu()
diff --git a/client/Archipelago/player.gd b/client/Archipelago/player.gd index 4569af5..dd6aa2b 100644 --- a/client/Archipelago/player.gd +++ b/client/Archipelago/player.gd
@@ -81,6 +81,23 @@ func _ready():
81 81
82 get_parent().add_child.call_deferred(locationListener) 82 get_parent().add_child.call_deferred(locationListener)
83 83
84 if (
85 ap.get_letter_behavior(letter.get_key(), letter.has_level2() and letter.get_level2())
86 != ap.kLETTER_BEHAVIOR_VANILLA
87 ):
88 var scout = ap.scout_location(letter.get_ap_id())
89 if scout != null:
90 var item_name = "Unknown"
91 var item_player_game = ap.client._game_by_player[float(scout["player"])]
92 if ap.client._item_id_to_name[item_player_game].has(scout["item"]):
93 item_name = ap.client._item_id_to_name[item_player_game][scout["item"]]
94
95 var collectable = get_tree().get_root().get_node("scene").get_node_or_null(
96 letter.get_path()
97 )
98 if collectable != null:
99 collectable.setScoutedText.call_deferred(item_name)
100
84 # Set up mastery locations. 101 # Set up mastery locations.
85 for mastery in gamedata.objects.get_masteries(): 102 for mastery in gamedata.objects.get_masteries():
86 var room = gamedata.objects.get_rooms()[mastery.get_room_id()] 103 var room = gamedata.objects.get_rooms()[mastery.get_room_id()]
diff --git a/client/Archipelago/saver.gd b/client/Archipelago/saver.gd index 7e788a8..0fba9e7 100644 --- a/client/Archipelago/saver.gd +++ b/client/Archipelago/saver.gd
@@ -2,4 +2,8 @@ extends "res://scripts/nodes/saver.gd"
2 2
3 3
4func levelLoaded(): 4func levelLoaded():
5 reload.call_deferred() 5 if type == "keyholders":
6 var ap = global.get_node("Archipelago")
7 ap.keyboard.load_keyholders.call_deferred(global.map)
8 else:
9 reload.call_deferred()
diff --git a/client/Archipelago/settings_screen.gd b/client/Archipelago/settings_screen.gd index ed9571d..aaaf72a 100644 --- a/client/Archipelago/settings_screen.gd +++ b/client/Archipelago/settings_screen.gd
@@ -22,14 +22,8 @@ func _ready():
22 var ap_instance = ap_script.new() 22 var ap_instance = ap_script.new()
23 ap_instance.name = "Archipelago" 23 ap_instance.name = "Archipelago"
24 24
25 #apclient_instance.SCRIPT_doorControl = load("user://maps/Archipelago/doorControl.gd")
26 #apclient_instance.SCRIPT_effects = load("user://maps/Archipelago/effects.gd")
27 #apclient_instance.SCRIPT_location = load("user://maps/Archipelago/location.gd")
28 #apclient_instance.SCRIPT_mypainting = load("user://maps/Archipelago/mypainting.gd")
29 #apclient_instance.SCRIPT_panel = load("user://maps/Archipelago/panel.gd")
30 #apclient_instance.SCRIPT_textclient = load("user://maps/Archipelago/textclient.gd")
31
32 ap_instance.SCRIPT_client = load("user://maps/Archipelago/client.gd") 25 ap_instance.SCRIPT_client = load("user://maps/Archipelago/client.gd")
26 ap_instance.SCRIPT_keyboard = load("user://maps/Archipelago/keyboard.gd")
33 ap_instance.SCRIPT_locationListener = load("user://maps/Archipelago/locationListener.gd") 27 ap_instance.SCRIPT_locationListener = load("user://maps/Archipelago/locationListener.gd")
34 ap_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd") 28 ap_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd")
35 ap_instance.SCRIPT_victoryListener = load("user://maps/Archipelago/victoryListener.gd") 29 ap_instance.SCRIPT_victoryListener = load("user://maps/Archipelago/victoryListener.gd")
@@ -38,7 +32,13 @@ func _ready():
38 32
39 # Let's also inject any scripts we need to inject now. 33 # Let's also inject any scripts we need to inject now.
40 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/animationListener.gd")) 34 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/animationListener.gd"))
35 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/collectable.gd"))
41 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/door.gd")) 36 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/door.gd"))
37 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/keyHolder.gd"))
38 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/keyHolderChecker.gd"))
39 installScriptExtension(
40 ResourceLoader.load("user://maps/Archipelago/keyHolderResetterListener.gd")
41 )
42 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/painting.gd")) 42 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/painting.gd"))
43 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/pauseMenu.gd")) 43 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/pauseMenu.gd"))
44 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/player.gd")) 44 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/player.gd"))
@@ -141,17 +141,22 @@ func connectionSuccessful():
141 global.universe = "lingo" 141 global.universe = "lingo"
142 global.map = "the_entry" 142 global.map = "the_entry"
143 143
144 unlocks.resetKeys()
145 unlocks.resetCollectables() 144 unlocks.resetCollectables()
146 unlocks.resetData() 145 unlocks.resetData()
147 unlocks.loadKeys() 146
147 ap.setup_keys()
148
148 unlocks.loadCollectables() 149 unlocks.loadCollectables()
149 unlocks.loadData() 150 unlocks.loadData()
150 unlocks.unlockKey("capslock", 1) 151 unlocks.unlockKey("capslock", 1)
151 152
152 clearResourceCache("res://objects/meshes/gridDoor.tscn") 153 clearResourceCache("res://objects/meshes/gridDoor.tscn")
154 clearResourceCache("res://objects/nodes/collectable.tscn")
153 clearResourceCache("res://objects/nodes/door.tscn") 155 clearResourceCache("res://objects/nodes/door.tscn")
156 clearResourceCache("res://objects/nodes/keyHolder.tscn")
154 clearResourceCache("res://objects/nodes/listeners/animationListener.tscn") 157 clearResourceCache("res://objects/nodes/listeners/animationListener.tscn")
158 clearResourceCache("res://objects/nodes/listeners/keyHolderChecker.tscn")
159 clearResourceCache("res://objects/nodes/listeners/keyHolderResetterListener.tscn")
155 clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn") 160 clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn")
156 clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn") 161 clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn")
157 clearResourceCache("res://objects/nodes/player.tscn") 162 clearResourceCache("res://objects/nodes/player.tscn")
diff --git a/client/Archipelago/textclient.gd b/client/Archipelago/textclient.gd index 4b03151..85cc6d2 100644 --- a/client/Archipelago/textclient.gd +++ b/client/Archipelago/textclient.gd
@@ -50,7 +50,7 @@ func _ready():
50 50
51 51
52func _input(event): 52func _input(event):
53 if event is InputEventKey and event.pressed: 53 if global.loaded and event is InputEventKey and event.pressed:
54 if event.keycode == KEY_TAB and !Input.is_key_pressed(KEY_SHIFT): 54 if event.keycode == KEY_TAB and !Input.is_key_pressed(KEY_SHIFT):
55 if !get_tree().paused: 55 if !get_tree().paused:
56 is_open = true 56 is_open = true