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/animationListener.gd38
-rw-r--r--client/Archipelago/client.gd415
-rw-r--r--client/Archipelago/collectable.gd16
-rw-r--r--client/Archipelago/door.gd38
-rw-r--r--client/Archipelago/gamedata.gd86
-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/locationListener.gd20
-rw-r--r--client/Archipelago/manager.gd507
-rw-r--r--client/Archipelago/messages.gd61
-rw-r--r--client/Archipelago/painting.gd38
-rw-r--r--client/Archipelago/pauseMenu.gd12
-rw-r--r--client/Archipelago/player.gd213
-rw-r--r--client/Archipelago/saver.gd9
-rw-r--r--client/Archipelago/settings_buttons.gd24
-rw-r--r--client/Archipelago/settings_screen.gd199
-rw-r--r--client/Archipelago/teleportListener.gd38
-rw-r--r--client/Archipelago/textclient.gd86
-rw-r--r--client/Archipelago/vendor/LICENSE21
-rw-r--r--client/Archipelago/vendor/uuid.gd195
-rw-r--r--client/Archipelago/victoryListener.gd20
-rw-r--r--client/Archipelago/worldportListener.gd8
24 files changed, 0 insertions, 2292 deletions
diff --git a/client/Archipelago/animationListener.gd b/client/Archipelago/animationListener.gd deleted file mode 100644 index c3b26db..0000000 --- a/client/Archipelago/animationListener.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/listeners/animationListener.gd"
2
3var item_id
4var item_amount
5
6
7func _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 call_deferred("_readier")
30
31 super._ready()
32
33
34func _readier():
35 var ap = global.get_node("Archipelago")
36
37 if ap.client.getItemAmount(item_id) >= item_amount:
38 handleTriggered()
diff --git a/client/Archipelago/client.gd b/client/Archipelago/client.gd deleted file mode 100644 index 2e080fd..0000000 --- a/client/Archipelago/client.gd +++ /dev/null
@@ -1,415 +0,0 @@
1extends Node
2
3const ap_version = {"major": 0, "minor": 6, "build": 3, "class": "Version"}
4
5var SCRIPT_uuid
6
7var _ws = WebSocketPeer.new()
8var _should_process = false
9var _initiated_disconnect = false
10var _try_wss = false
11var _has_connected = false
12
13var _datapackages = {}
14var _pending_packages = []
15var _item_id_to_name = {} # All games
16var _location_id_to_name = {} # All games
17var _item_name_to_id = {} # Lingo 2 only
18var _location_name_to_id = {} # Lingo 2 only
19
20var _remote_version = {"major": 0, "minor": 0, "build": 0}
21var _gen_version = {"major": 0, "minor": 0, "build": 0}
22
23var ap_server = ""
24var ap_user = ""
25var ap_pass = ""
26
27var _authenticated = false
28var _seed = ""
29var _team = 0
30var _slot = 0
31var _players = []
32var _player_name_by_slot = {}
33var _game_by_player = {}
34var _checked_locations = []
35var _received_indexes = []
36var _received_items = {}
37var _slot_data = {}
38
39signal could_not_connect
40signal connect_status
41signal client_connected(slot_data)
42signal item_received(item_id, index, player, flags, amount)
43signal message_received(message)
44signal location_scout_received(item_id, location_id, player, flags)
45
46
47func _init():
48 set_process_mode(Node.PROCESS_MODE_ALWAYS)
49
50 global._print("Instantiated APClient")
51
52 # Read AP datapackages from file, if there are any
53 if FileAccess.file_exists("user://ap_datapackages"):
54 var file = FileAccess.open("user://ap_datapackages", FileAccess.READ)
55 var data = file.get_var(true)
56 file.close()
57
58 if typeof(data) != TYPE_DICTIONARY:
59 global._print("AP datapackages file is corrupted")
60 data = {}
61
62 _datapackages = data
63
64 processDatapackages()
65
66
67func _ready():
68 pass
69 #_ws.connect("connection_closed", _closed)
70 #_ws.connect("connection_failed", _closed)
71 #_ws.connect("server_disconnected", _closed)
72 #_ws.connect("connection_error", _errored)
73 #_ws.connect("connection_established", _connected)
74
75
76func _reset_state():
77 _should_process = false
78 _authenticated = false
79 _try_wss = false
80 _has_connected = false
81 _received_items = {}
82 _received_indexes = []
83
84
85func _errored():
86 if _try_wss:
87 global._print("Could not connect to AP with ws://, now trying wss://")
88 connectToServer(ap_server, ap_user, ap_pass)
89 else:
90 global._print("AP connection failed")
91 _reset_state()
92
93 emit_signal(
94 "could_not_connect",
95 "Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information."
96 )
97
98
99func _closed(_was_clean = true):
100 global._print("Connection closed")
101 _reset_state()
102
103 if not _initiated_disconnect:
104 emit_signal("could_not_connect", "Disconnected from Archipelago")
105
106 _initiated_disconnect = false
107
108
109func _connected(_proto = ""):
110 global._print("Connected!")
111 _try_wss = false
112
113
114func disconnect_from_ap():
115 _initiated_disconnect = true
116 _ws.close()
117
118
119func _process(_delta):
120 if _should_process:
121 _ws.poll()
122
123 var state = _ws.get_ready_state()
124 if state == WebSocketPeer.STATE_OPEN:
125 if not _has_connected:
126 _has_connected = true
127
128 _connected()
129
130 while _ws.get_available_packet_count():
131 var packet = _ws.get_packet()
132 global._print("Got data from server: " + packet.get_string_from_utf8())
133 var json = JSON.new()
134 var jserror = json.parse(packet.get_string_from_utf8())
135 if jserror != OK:
136 global._print("Error parsing packet from AP: " + jserror.error_string)
137 return
138
139 for message in json.data:
140 var cmd = message["cmd"]
141 global._print("Received command: " + cmd)
142
143 if cmd == "RoomInfo":
144 _seed = message["seed_name"]
145 _remote_version = message["version"]
146 _gen_version = message["generator_version"]
147
148 var needed_games = []
149 for game in message["datapackage_checksums"].keys():
150 if (
151 !_datapackages.has(game)
152 or (
153 _datapackages[game]["checksum"]
154 != message["datapackage_checksums"][game]
155 )
156 ):
157 needed_games.append(game)
158
159 if !needed_games.is_empty():
160 _pending_packages = needed_games
161 var cur_needed = _pending_packages.pop_front()
162 requestDatapackages([cur_needed])
163 else:
164 connectToRoom()
165
166 elif cmd == "DataPackage":
167 for game in message["data"]["games"].keys():
168 _datapackages[game] = message["data"]["games"][game]
169 saveDatapackages()
170
171 if !_pending_packages.is_empty():
172 var cur_needed = _pending_packages.pop_front()
173 requestDatapackages([cur_needed])
174 else:
175 processDatapackages()
176 connectToRoom()
177
178 elif cmd == "Connected":
179 _authenticated = true
180 _team = message["team"]
181 _slot = message["slot"]
182 _players = message["players"]
183 _checked_locations = message["checked_locations"]
184 _slot_data = message["slot_data"]
185
186 for player in _players:
187 _player_name_by_slot[player["slot"]] = player["alias"]
188 _game_by_player[player["slot"]] = message["slot_info"][str(
189 player["slot"]
190 )]["game"]
191
192 emit_signal("client_connected", _slot_data)
193
194 elif cmd == "ConnectionRefused":
195 var error_message = ""
196 for error in message["errors"]:
197 var submsg = ""
198 if error == "InvalidSlot":
199 submsg = "Invalid player name."
200 elif error == "InvalidGame":
201 submsg = "The specified player is not playing Lingo."
202 elif error == "IncompatibleVersion":
203 submsg = (
204 "The Archipelago server is not the correct version for this client. Expected v%d.%d.%d. Found v%d.%d.%d."
205 % [
206 ap_version["major"],
207 ap_version["minor"],
208 ap_version["build"],
209 _remote_version["major"],
210 _remote_version["minor"],
211 _remote_version["build"]
212 ]
213 )
214 elif error == "InvalidPassword":
215 submsg = "Incorrect password."
216 elif error == "InvalidItemsHandling":
217 submsg = "Invalid item handling flag. This is a bug with the client."
218
219 if submsg != "":
220 if error_message != "":
221 error_message += " "
222 error_message += submsg
223
224 if error_message == "":
225 error_message = "Unknown error."
226
227 _initiated_disconnect = true
228 _ws.disconnect_from_host()
229
230 emit_signal("could_not_connect", error_message)
231 global._print("Connection to AP refused")
232 global._print(message)
233
234 elif cmd == "ReceivedItems":
235 var i = 0
236 for item in message["items"]:
237 var index = int(message["index"] + i)
238 i += 1
239
240 if _received_indexes.has(index):
241 # Do not re-process items.
242 continue
243
244 _received_indexes.append(index)
245
246 var item_id = int(item["item"])
247 _received_items[item_id] = _received_items.get(item_id, 0) + 1
248
249 emit_signal(
250 "item_received",
251 item_id,
252 index,
253 int(item["player"]),
254 int(item["flags"]),
255 _received_items[item_id]
256 )
257
258 elif cmd == "PrintJSON":
259 emit_signal("message_received", message)
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
271 elif state == WebSocketPeer.STATE_CLOSED:
272 if _has_connected:
273 _closed()
274 else:
275 _errored()
276
277
278func saveDatapackages():
279 # Save the AP datapackages to disk.
280 var file = FileAccess.open("user://ap_datapackages", FileAccess.WRITE)
281 file.store_var(_datapackages, true)
282 file.close()
283
284
285func connectToServer(server, un, pw):
286 ap_server = server
287 ap_user = un
288 ap_pass = pw
289
290 _initiated_disconnect = false
291
292 var url = ""
293 if ap_server.begins_with("ws://") or ap_server.begins_with("wss://"):
294 url = ap_server
295 _try_wss = false
296 elif _try_wss:
297 url = "wss://" + ap_server
298 _try_wss = false
299 else:
300 url = "ws://" + ap_server
301 _try_wss = true
302
303 var err = _ws.connect_to_url(url)
304 if err != OK:
305 emit_signal(
306 "could_not_connect",
307 (
308 "Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information. Error code: %d."
309 % err
310 )
311 )
312 global._print("Could not connect to AP: " + err)
313 return
314 _should_process = true
315
316 emit_signal("connect_status", "Connecting...")
317
318
319func sendMessage(msg):
320 var payload = JSON.stringify(msg)
321 _ws.send_text(payload)
322
323
324func requestDatapackages(games):
325 emit_signal("connect_status", "Downloading %s data package..." % games[0])
326
327 sendMessage([{"cmd": "GetDataPackage", "games": games}])
328
329
330func processDatapackages():
331 _item_id_to_name = {}
332 _location_id_to_name = {}
333 for game in _datapackages.keys():
334 var package = _datapackages[game]
335
336 _item_id_to_name[game] = {}
337 for item_name in package["item_name_to_id"].keys():
338 _item_id_to_name[game][int(package["item_name_to_id"][item_name])] = item_name
339
340 _location_id_to_name[game] = {}
341 for location_name in package["location_name_to_id"].keys():
342 _location_id_to_name[game][int(package["location_name_to_id"][location_name])] = location_name
343
344 if _datapackages.has("Lingo 2"):
345 _item_name_to_id = _datapackages["Lingo 2"]["item_name_to_id"]
346 _location_name_to_id = _datapackages["Lingo 2"]["location_name_to_id"]
347
348
349func connectToRoom():
350 emit_signal("connect_status", "Authenticating...")
351
352 sendMessage(
353 [
354 {
355 "cmd": "Connect",
356 "password": ap_pass,
357 "game": "Lingo 2",
358 "name": ap_user,
359 "uuid": SCRIPT_uuid.v4(),
360 "version": ap_version,
361 "items_handling": 0b111, # always receive our items
362 "tags": [],
363 "slot_data": true
364 }
365 ]
366 )
367
368
369func sendConnectUpdate(tags):
370 sendMessage([{"cmd": "ConnectUpdate", "tags": tags}])
371
372
373func requestSync():
374 sendMessage([{"cmd": "Sync"}])
375
376
377func sendLocation(loc_id):
378 sendMessage([{"cmd": "LocationChecks", "locations": [loc_id]}])
379
380
381func sendLocations(loc_ids):
382 sendMessage([{"cmd": "LocationChecks", "locations": loc_ids}])
383
384
385func setValue(key, value, operation = "replace"):
386 sendMessage(
387 [
388 {
389 "cmd": "Set",
390 "key": "Lingo2_%d_%s" % [_slot, key],
391 "want_reply": false,
392 "operations": [{"operation": operation, "value": value}]
393 }
394 ]
395 )
396
397
398func say(textdata):
399 sendMessage([{"cmd": "Say", "text": textdata}])
400
401
402func completedGoal():
403 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
404
405
406func scoutLocations(loc_ids):
407 sendMessage([{"cmd": "LocationScouts", "locations": loc_ids}])
408
409
410func hasItem(item_id):
411 return _received_items.has(item_id)
412
413
414func getItemAmount(item_id):
415 return _received_items.get(item_id, 0)
diff --git a/client/Archipelago/collectable.gd b/client/Archipelago/collectable.gd deleted file mode 100644 index 4a17a2a..0000000 --- a/client/Archipelago/collectable.gd +++ /dev/null
@@ -1,16 +0,0 @@
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/door.gd b/client/Archipelago/door.gd deleted file mode 100644 index fead818..0000000 --- a/client/Archipelago/door.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/door.gd"
2
3var item_id
4var item_amount
5
6
7func _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 call_deferred("_readier")
30
31 super._ready()
32
33
34func _readier():
35 var ap = global.get_node("Archipelago")
36
37 if ap.client.getItemAmount(item_id) >= item_amount:
38 handleTriggered()
diff --git a/client/Archipelago/gamedata.gd b/client/Archipelago/gamedata.gd deleted file mode 100644 index f7a5d90..0000000 --- a/client/Archipelago/gamedata.gd +++ /dev/null
@@ -1,86 +0,0 @@
1extends Node
2
3var SCRIPT_proto
4
5var objects
6var door_id_by_map_node_path = {}
7var painting_id_by_map_node_path = {}
8var door_id_by_ap_id = {}
9var map_id_by_name = {}
10var progressive_id_by_ap_id = {}
11var letter_id_by_ap_id = {}
12
13
14func _init(proto_script):
15 SCRIPT_proto = proto_script
16
17
18func load(data_bytes):
19 objects = SCRIPT_proto.AllObjects.new()
20
21 var result_code = objects.from_bytes(data_bytes)
22 if result_code != SCRIPT_proto.PB_ERR.NO_ERRORS:
23 print("Could not load generated data: %d" % result_code)
24 return
25
26 for map in objects.get_maps():
27 map_id_by_name[map.get_name()] = map.get_id()
28
29 for door in objects.get_doors():
30 var map = objects.get_maps()[door.get_map_id()]
31
32 if not map.get_name() in door_id_by_map_node_path:
33 door_id_by_map_node_path[map.get_name()] = {}
34
35 var map_data = door_id_by_map_node_path[map.get_name()]
36 for receiver in door.get_receivers():
37 map_data[receiver] = door.get_id()
38
39 for painting_id in door.get_move_paintings():
40 var painting = objects.get_paintings()[painting_id]
41 map_data[painting.get_path()] = door.get_id()
42
43 if door.has_ap_id():
44 door_id_by_ap_id[door.get_ap_id()] = door.get_id()
45
46 for painting in objects.get_paintings():
47 var room = objects.get_rooms()[painting.get_room_id()]
48 var map = objects.get_maps()[room.get_map_id()]
49
50 if not map.get_name() in painting_id_by_map_node_path:
51 painting_id_by_map_node_path[map.get_name()] = {}
52
53 var _map_data = painting_id_by_map_node_path[map.get_name()]
54
55 for progressive in objects.get_progressives():
56 progressive_id_by_ap_id[progressive.get_ap_id()] = progressive.get_id()
57
58 for letter in objects.get_letters():
59 letter_id_by_ap_id[letter.get_ap_id()] = letter.get_id()
60
61
62func get_door_for_map_node_path(map_name, node_path):
63 if not door_id_by_map_node_path.has(map_name):
64 return null
65
66 var map_data = door_id_by_map_node_path[map_name]
67 return map_data.get(node_path, null)
68
69
70func get_door_ap_id(door_id):
71 var door = objects.get_doors()[door_id]
72 if door.has_ap_id():
73 return door.get_ap_id()
74 else:
75 return null
76
77
78func get_door_receivers(door_id):
79 var door = objects.get_doors()[door_id]
80 return door.get_receivers()
81
82
83func get_door_map_name(door_id):
84 var door = objects.get_doors()[door_id]
85 var map = objects.get_maps()[door.get_map_id()]
86 return map.get_name()
diff --git a/client/Archipelago/keyHolder.gd b/client/Archipelago/keyHolder.gd deleted file mode 100644 index 3c037ff..0000000 --- a/client/Archipelago/keyHolder.gd +++ /dev/null
@@ -1,38 +0,0 @@
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 deleted file mode 100644 index a75a9e4..0000000 --- a/client/Archipelago/keyHolderChecker.gd +++ /dev/null
@@ -1,24 +0,0 @@
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 deleted file mode 100644 index d5300f3..0000000 --- a/client/Archipelago/keyHolderResetterListener.gd +++ /dev/null
@@ -1,8 +0,0 @@
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 deleted file mode 100644 index 600a047..0000000 --- a/client/Archipelago/keyboard.gd +++ /dev/null
@@ -1,178 +0,0 @@
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/locationListener.gd b/client/Archipelago/locationListener.gd deleted file mode 100644 index 71792ed..0000000 --- a/client/Archipelago/locationListener.gd +++ /dev/null
@@ -1,20 +0,0 @@
1extends Receiver
2
3var location_id
4
5
6func _ready():
7 super._ready()
8
9
10func handleTriggered():
11 triggered += 1
12 if triggered >= total:
13 var ap = global.get_node("Archipelago")
14 ap.send_location(location_id)
15
16
17func handleUntriggered():
18 triggered -= 1
19 if triggered < total:
20 pass
diff --git a/client/Archipelago/manager.gd b/client/Archipelago/manager.gd deleted file mode 100644 index cd0654f..0000000 --- a/client/Archipelago/manager.gd +++ /dev/null
@@ -1,507 +0,0 @@
1extends Node
2
3const my_version = "0.1.0"
4
5var SCRIPT_client
6var SCRIPT_keyboard
7var SCRIPT_locationListener
8var SCRIPT_uuid
9var SCRIPT_victoryListener
10
11var ap_server = ""
12var ap_user = ""
13var ap_pass = ""
14var connection_history = []
15
16var client
17var keyboard
18
19var _localdata_file = ""
20var _last_new_item = -1
21var _batch_locations = false
22var _held_locations = []
23var _held_location_scouts = []
24var _location_scouts = {}
25var _item_locks = {}
26var _inverse_item_locks = {}
27var _held_letters = {}
28var _letters_setup = false
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
45var daedalus_roof_access = false
46var keyholder_sanity = false
47var shuffle_control_center_colors = false
48var shuffle_doors = false
49var shuffle_letters = kSHUFFLE_LETTERS_VANILLA
50var victory_condition = -1
51
52signal could_not_connect
53signal connect_status
54signal ap_connected
55
56
57func _init():
58 # Read AP settings from file, if there are any
59 if FileAccess.file_exists("user://ap_settings"):
60 var file = FileAccess.open("user://ap_settings", FileAccess.READ)
61 var data = file.get_var(true)
62 file.close()
63
64 if typeof(data) != TYPE_ARRAY:
65 global._print("AP settings file is corrupted")
66 data = []
67
68 if data.size() > 0:
69 ap_server = data[0]
70
71 if data.size() > 1:
72 ap_user = data[1]
73
74 if data.size() > 2:
75 ap_pass = data[2]
76
77 if data.size() > 3:
78 connection_history = data[3]
79
80
81func _ready():
82 client = SCRIPT_client.new()
83 client.SCRIPT_uuid = SCRIPT_uuid
84
85 client.connect("item_received", _process_item)
86 client.connect("message_received", _process_message)
87 client.connect("location_scout_received", _process_location_scout)
88 client.connect("could_not_connect", _client_could_not_connect)
89 client.connect("connect_status", _client_connect_status)
90 client.connect("client_connected", _client_connected)
91
92 add_child(client)
93
94 keyboard = SCRIPT_keyboard.new()
95 add_child(keyboard)
96
97
98func saveSettings():
99 # Save the AP settings to disk.
100 var path = "user://ap_settings"
101 var file = FileAccess.open(path, FileAccess.WRITE)
102
103 var data = [
104 ap_server,
105 ap_user,
106 ap_pass,
107 connection_history,
108 ]
109 file.store_var(data, true)
110 file.close()
111
112
113func saveLocaldata():
114 # Save the MW/slot specific settings to disk.
115 var dir = DirAccess.open("user://")
116 var folder = "archipelago_data"
117 if not dir.dir_exists(folder):
118 dir.make_dir(folder)
119
120 var file = FileAccess.open(_localdata_file, FileAccess.WRITE)
121
122 var data = [
123 _last_new_item,
124 ]
125 file.store_var(data, true)
126 file.close()
127
128
129func connectToServer():
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 = {}
137
138 client.connectToServer(ap_server, ap_user, ap_pass)
139
140
141func getSaveFileName():
142 return "zzAP_%s_%d" % [client._seed, client._slot]
143
144
145func disconnect_from_ap():
146 client.disconnect_from_ap()
147
148
149func get_item_id_for_door(door_id):
150 return _item_locks.get(door_id, null)
151
152
153func _process_item(item, index, from, flags, amount):
154 var item_name = "Unknown"
155 if client._item_id_to_name["Lingo 2"].has(item):
156 item_name = client._item_id_to_name["Lingo 2"][item]
157
158 var gamedata = global.get_node("Gamedata")
159
160 var prog_id = null
161 if _inverse_item_locks.has(item):
162 for lock in _inverse_item_locks.get(item):
163 if lock[1] != amount:
164 continue
165
166 if gamedata.progressive_id_by_ap_id.has(item):
167 prog_id = lock[0]
168
169 if gamedata.get_door_map_name(lock[0]) != global.map:
170 continue
171
172 var receivers = gamedata.get_door_receivers(lock[0])
173 var scene = get_tree().get_root().get_node_or_null("scene")
174 if scene != null:
175 for receiver in receivers:
176 var rnode = scene.get_node_or_null(receiver)
177 if rnode != null:
178 rnode.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)
185
186 # Show a message about the item if it's new.
187 if index != null and index > _last_new_item:
188 _last_new_item = index
189 saveLocaldata()
190
191 var player_name = "Unknown"
192 if client._player_name_by_slot.has(float(from)):
193 player_name = client._player_name_by_slot[float(from)]
194
195 var item_color = colorForItemType(flags)
196
197 var full_item_name = item_name
198 if prog_id != null:
199 var door = gamedata.objects.get_doors()[prog_id]
200 full_item_name = "%s (%s)" % [item_name, door.get_name()]
201
202 var message
203 if from == client._slot:
204 message = "Found [color=%s]%s[/color]" % [item_color, full_item_name]
205 else:
206 message = (
207 "Received [color=%s]%s[/color] from %s" % [item_color, full_item_name, player_name]
208 )
209
210 global._print(message)
211
212 global.get_node("Messages").showMessage(message)
213
214
215func _process_message(message):
216 parse_printjson_for_textclient(message)
217
218 if (
219 !message.has("receiving")
220 or !message.has("item")
221 or message["item"]["player"] != client._slot
222 ):
223 return
224
225 var item_name = "Unknown"
226 var item_player_game = client._game_by_player[message["receiving"]]
227 if client._item_id_to_name[item_player_game].has(int(message["item"]["item"])):
228 item_name = client._item_id_to_name[item_player_game][int(message["item"]["item"])]
229
230 var location_name = "Unknown"
231 var location_player_game = client._game_by_player[message["item"]["player"]]
232 if client._location_id_to_name[location_player_game].has(int(message["item"]["location"])):
233 location_name = (client._location_id_to_name[location_player_game][int(
234 message["item"]["location"]
235 )])
236
237 var player_name = "Unknown"
238 if client._player_name_by_slot.has(message["receiving"]):
239 player_name = client._player_name_by_slot[message["receiving"]]
240
241 var item_color = colorForItemType(message["item"]["flags"])
242
243 if message["type"] == "Hint":
244 var is_for = ""
245 if message["receiving"] != client._slot:
246 is_for = " for %s" % player_name
247 if !message.has("found") || !message["found"]:
248 global.get_node("Messages").showMessage(
249 (
250 "Hint: [color=%s]%s[/color]%s is on %s"
251 % [item_color, item_name, is_for, location_name]
252 )
253 )
254 else:
255 if message["receiving"] != client._slot:
256 var sentMsg = "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
257 #if _hinted_locations.has(message["item"]["location"]):
258 # sentMsg += " ([color=#fafad2]Hinted![/color])"
259 global.get_node("Messages").showMessage(sentMsg)
260
261
262func parse_printjson_for_textclient(message):
263 var parts = []
264 for message_part in message["data"]:
265 if !message_part.has("type") and message_part.has("text"):
266 parts.append(message_part["text"])
267 elif message_part["type"] == "player_id":
268 if int(message_part["text"]) == client._slot:
269 parts.append(
270 "[color=#ee00ee]%s[/color]" % client._player_name_by_slot[client._slot]
271 )
272 else:
273 var from = float(message_part["text"])
274 parts.append("[color=#fafad2]%s[/color]" % client._player_name_by_slot[from])
275 elif message_part["type"] == "item_id":
276 var item_name = "Unknown"
277 var item_player_game = client._game_by_player[message_part["player"]]
278 if client._item_id_to_name[item_player_game].has(int(message_part["text"])):
279 item_name = client._item_id_to_name[item_player_game][int(message_part["text"])]
280
281 parts.append(
282 "[color=%s]%s[/color]" % [colorForItemType(message_part["flags"]), item_name]
283 )
284 elif message_part["type"] == "location_id":
285 var location_name = "Unknown"
286 var location_player_game = client._game_by_player[message_part["player"]]
287 if client._location_id_to_name[location_player_game].has(int(message_part["text"])):
288 location_name = client._location_id_to_name[location_player_game][int(
289 message_part["text"]
290 )]
291
292 parts.append("[color=#00ff7f]%s[/color]" % location_name)
293 elif message_part.has("text"):
294 parts.append(message_part["text"])
295
296 var textclient_node = global.get_node("Textclient")
297 if textclient_node != null:
298 textclient_node.parse_printjson("".join(parts))
299
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
324func _client_could_not_connect():
325 emit_signal("could_not_connect")
326
327
328func _client_connect_status(message):
329 emit_signal("connect_status", message)
330
331
332func _client_connected(slot_data):
333 var gamedata = global.get_node("Gamedata")
334
335 _localdata_file = "user://archipelago_data/%s_%d" % [client._seed, client._slot]
336 _last_new_item = -1
337
338 if FileAccess.file_exists(_localdata_file):
339 var ap_file = FileAccess.open(_localdata_file, FileAccess.READ)
340 var localdata = []
341 if ap_file != null:
342 localdata = ap_file.get_var(true)
343 ap_file.close()
344
345 if typeof(localdata) != TYPE_ARRAY:
346 print("AP localdata file is corrupted")
347 localdata = []
348
349 if localdata.size() > 0:
350 _last_new_item = localdata[0]
351
352 # Read slot data.
353 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0))
354 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", 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))
357 shuffle_doors = bool(slot_data.get("shuffle_doors", false))
358 shuffle_letters = int(slot_data.get("shuffle_letters", 0))
359 victory_condition = int(slot_data.get("victory_condition", 0))
360
361 # Set up item locks.
362 _item_locks = {}
363
364 if shuffle_doors:
365 for door in gamedata.objects.get_doors():
366 if (
367 door.get_type() == gamedata.SCRIPT_proto.DoorType.STANDARD
368 or door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY
369 ):
370 _item_locks[door.get_id()] = [door.get_ap_id(), 1]
371
372 for progressive in gamedata.objects.get_progressives():
373 for i in range(0, progressive.get_doors().size()):
374 var door = gamedata.objects.get_doors()[progressive.get_doors()[i]]
375 _item_locks[door.get_id()] = [progressive.get_ap_id(), i + 1]
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
413 emit_signal("ap_connected")
414
415
416func start_batching_locations():
417 _batch_locations = true
418
419
420func send_location(loc_id):
421 if _batch_locations:
422 _held_locations.append(loc_id)
423 else:
424 client.sendLocation(loc_id)
425
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
439func stop_batching_locations():
440 _batch_locations = false
441
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()
449
450
451func colorForItemType(flags):
452 var int_flags = int(flags)
453 if int_flags & 1: # progression
454 if int_flags & 2: # proguseful
455 return "#f0d200"
456 else:
457 return "#bc51e0"
458 elif int_flags & 2: # useful
459 return "#2b67ff"
460 elif int_flags & 4: # trap
461 return "#d63a22"
462 else: # filler
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/messages.gd b/client/Archipelago/messages.gd deleted file mode 100644 index 52f38b9..0000000 --- a/client/Archipelago/messages.gd +++ /dev/null
@@ -1,61 +0,0 @@
1extends CanvasLayer
2
3var _message_queue = []
4var _font
5var _container
6var _ordered_labels = []
7
8
9func _ready():
10 _container = VBoxContainer.new()
11 _container.set_name("Container")
12 _container.anchor_bottom = 1
13 _container.offset_left = 20.0
14 _container.offset_right = 1920.0
15 _container.offset_top = 0.0
16 _container.offset_bottom = -20.0
17 _container.alignment = BoxContainer.ALIGNMENT_END
18 _container.mouse_filter = Control.MOUSE_FILTER_IGNORE
19 self.add_child(_container)
20
21 _font = load("res://assets/fonts/Lingo2.ttf")
22
23
24func _add_message(text):
25 var new_label = RichTextLabel.new()
26 new_label.push_font(_font)
27 new_label.push_font_size(36)
28 new_label.push_outline_color(Color(0, 0, 0, 1))
29 new_label.push_outline_size(2)
30 new_label.append_text(text)
31 new_label.fit_content = true
32
33 _container.add_child(new_label)
34 _ordered_labels.push_back(new_label)
35
36
37func showMessage(text):
38 if _ordered_labels.size() >= 9:
39 _message_queue.append(text)
40 return
41
42 _add_message(text)
43
44 if _ordered_labels.size() > 1:
45 return
46
47 var timeout = 10.0
48 while !_ordered_labels.is_empty():
49 await get_tree().create_timer(timeout).timeout
50
51 var to_remove = _ordered_labels.pop_front()
52 var to_tween = get_tree().create_tween().bind_node(to_remove)
53 to_tween.tween_property(to_remove, "modulate:a", 0.0, 0.5)
54 to_tween.tween_callback(to_remove.queue_free)
55
56 if !_message_queue.is_empty():
57 var next_msg = _message_queue.pop_front()
58 _add_message(next_msg)
59
60 if timeout > 4:
61 timeout -= 3
diff --git a/client/Archipelago/painting.gd b/client/Archipelago/painting.gd deleted file mode 100644 index 276d4eb..0000000 --- a/client/Archipelago/painting.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/painting.gd"
2
3var item_id
4var item_amount
5
6
7func _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 call_deferred("_readier")
30
31 super._ready()
32
33
34func _readier():
35 var ap = global.get_node("Archipelago")
36
37 if ap.client.getItemAmount(item_id) >= item_amount:
38 handleTriggered()
diff --git a/client/Archipelago/pauseMenu.gd b/client/Archipelago/pauseMenu.gd deleted file mode 100644 index 5da114a..0000000 --- a/client/Archipelago/pauseMenu.gd +++ /dev/null
@@ -1,12 +0,0 @@
1extends "res://scripts/ui/pauseMenu.gd"
2
3
4func _pause_game():
5 global.get_node("Textclient").dismiss()
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 deleted file mode 100644 index dd6aa2b..0000000 --- a/client/Archipelago/player.gd +++ /dev/null
@@ -1,213 +0,0 @@
1extends "res://scripts/nodes/player.gd"
2
3const kEndingNameByVictoryValue = {
4 0: "GRAY",
5 1: "PURPLE",
6 2: "MINT",
7 3: "BLACK",
8 4: "BLUE",
9 5: "CYAN",
10 6: "RED",
11 7: "PLUM",
12 8: "ORANGE",
13 9: "GOLD",
14 10: "YELLOW",
15 11: "GREEN",
16 12: "WHITE",
17}
18
19
20func _ready():
21 var khl_script = load("res://scripts/nodes/keyHolderListener.gd")
22
23 var ap = global.get_node("Archipelago")
24 var gamedata = global.get_node("Gamedata")
25
26 ap.start_batching_locations()
27
28 # Set up door locations.
29 var map_id = gamedata.map_id_by_name.get(global.map)
30 for door in gamedata.objects.get_doors():
31 if door.get_map_id() != map_id:
32 continue
33
34 if not door.has_ap_id():
35 continue
36
37 if door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY:
38 continue
39
40 var locationListener = ap.SCRIPT_locationListener.new()
41 locationListener.location_id = door.get_ap_id()
42 locationListener.name = "locationListener_%d" % door.get_ap_id()
43
44 for panel_ref in door.get_panels():
45 var panel_data = gamedata.objects.get_panels()[panel_ref.get_panel()]
46 var panel_path = panel_data.get_path()
47
48 if panel_ref.has_answer():
49 for proxy in panel_data.get_proxies():
50 if proxy.get_answer() == panel_ref.get_answer():
51 panel_path = proxy.get_path()
52 break
53
54 locationListener.senders.append(NodePath("/root/scene/" + panel_path))
55
56 for keyholder_ref in door.get_keyholders():
57 var keyholder_data = gamedata.objects.get_keyholders()[keyholder_ref.get_keyholder()]
58
59 var khl = khl_script.new()
60 khl.name = (
61 "location_%d_keyholder_%d" % [door.get_ap_id(), keyholder_ref.get_keyholder()]
62 )
63 khl.answer = keyholder_ref.get_key()
64 khl.senders.append(NodePath("/root/scene/" + keyholder_data.get_path()))
65 get_parent().add_child.call_deferred(khl)
66
67 locationListener.senders.append(NodePath("../" + khl.name))
68
69 get_parent().add_child.call_deferred(locationListener)
70
71 # Set up letter locations.
72 for letter in gamedata.objects.get_letters():
73 var room = gamedata.objects.get_rooms()[letter.get_room_id()]
74 if room.get_map_id() != map_id:
75 continue
76
77 var locationListener = ap.SCRIPT_locationListener.new()
78 locationListener.location_id = letter.get_ap_id()
79 locationListener.name = "locationListener_%d" % letter.get_ap_id()
80 locationListener.senders.append(NodePath("/root/scene/" + letter.get_path()))
81
82 get_parent().add_child.call_deferred(locationListener)
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
101 # Set up mastery locations.
102 for mastery in gamedata.objects.get_masteries():
103 var room = gamedata.objects.get_rooms()[mastery.get_room_id()]
104 if room.get_map_id() != map_id:
105 continue
106
107 var locationListener = ap.SCRIPT_locationListener.new()
108 locationListener.location_id = mastery.get_ap_id()
109 locationListener.name = "locationListener_%d" % mastery.get_ap_id()
110 locationListener.senders.append(NodePath("/root/scene/" + mastery.get_path()))
111
112 get_parent().add_child.call_deferred(locationListener)
113
114 # Set up ending locations.
115 for ending in gamedata.objects.get_endings():
116 var room = gamedata.objects.get_rooms()[ending.get_room_id()]
117 if room.get_map_id() != map_id:
118 continue
119
120 var locationListener = ap.SCRIPT_locationListener.new()
121 locationListener.location_id = ending.get_ap_id()
122 locationListener.name = "locationListener_%d" % ending.get_ap_id()
123 locationListener.senders.append(NodePath("/root/scene/" + ending.get_path()))
124
125 get_parent().add_child.call_deferred(locationListener)
126
127 if kEndingNameByVictoryValue.get(ap.victory_condition, null) == ending.get_name():
128 var victoryListener = ap.SCRIPT_victoryListener.new()
129 victoryListener.name = "victoryListener"
130 victoryListener.senders.append(NodePath("/root/scene/" + ending.get_path()))
131
132 get_parent().add_child.call_deferred(victoryListener)
133
134 # Set up keyholder locations, in keyholder sanity.
135 if ap.keyholder_sanity:
136 for keyholder in gamedata.objects.get_keyholders():
137 if not keyholder.has_key():
138 continue
139
140 var room = gamedata.objects.get_rooms()[keyholder.get_room_id()]
141 if room.get_map_id() != map_id:
142 continue
143
144 var locationListener = ap.SCRIPT_locationListener.new()
145 locationListener.location_id = keyholder.get_ap_id()
146 locationListener.name = "locationListener_%d" % keyholder.get_ap_id()
147
148 var khl = khl_script.new()
149 khl.name = "location_%d_keyholder" % keyholder.get_ap_id()
150 khl.answer = keyholder.get_key()
151 khl.senders.append(NodePath("/root/scene/" + keyholder.get_path()))
152 get_parent().add_child.call_deferred(khl)
153
154 locationListener.senders.append(NodePath("../" + khl.name))
155
156 get_parent().add_child.call_deferred(locationListener)
157
158 # Block off roof access in Daedalus.
159 if global.map == "daedalus" and not ap.daedalus_roof_access:
160 _set_up_invis_wall(75.5, 11, -24.5, 1, 10, 49)
161 _set_up_invis_wall(51.5, 11, -17, 16, 10, 1)
162 _set_up_invis_wall(46, 10, -9.5, 1, 10, 10)
163 _set_up_invis_wall(67.5, 11, 17, 16, 10, 1)
164 _set_up_invis_wall(50.5, 11, 14, 10, 10, 1)
165 _set_up_invis_wall(39, 10, 18.5, 1, 10, 22)
166 _set_up_invis_wall(20, 15, 18.5, 1, 10, 16)
167 _set_up_invis_wall(11.5, 15, 3, 32, 10, 1)
168 _set_up_invis_wall(11.5, 16, -20, 14, 20, 1)
169 _set_up_invis_wall(14, 16, -26.5, 1, 20, 4)
170 _set_up_invis_wall(28.5, 20.5, -26.5, 1, 15, 25)
171 _set_up_invis_wall(40.5, 20.5, -11, 30, 15, 1)
172 _set_up_invis_wall(50.5, 15, 5.5, 7, 10, 1)
173 _set_up_invis_wall(83.5, 33.5, 5.5, 1, 7, 11)
174 _set_up_invis_wall(83.5, 33.5, -5.5, 1, 7, 11)
175
176 var warp_exit_prefab = preload("res://objects/nodes/exit.tscn")
177 var warp_exit = warp_exit_prefab.instantiate()
178 warp_exit.name = "roof_access_blocker_warp_exit"
179 warp_exit.position = Vector3(58, 10, 0)
180 warp_exit.rotation_degrees.y = 90
181 get_parent().add_child.call_deferred(warp_exit)
182
183 var warp_enter_prefab = preload("res://objects/nodes/teleportAuto.tscn")
184 var warp_enter = warp_enter_prefab.instantiate()
185 warp_enter.target = warp_exit
186 warp_enter.position = Vector3(76.5, 30, 1)
187 warp_enter.scale = Vector3(4, 1.5, 1)
188 warp_enter.rotation_degrees.y = 90
189 get_parent().add_child.call_deferred(warp_enter)
190
191 super._ready()
192
193 await get_tree().process_frame
194 await get_tree().process_frame
195
196 ap.stop_batching_locations()
197
198
199func _set_up_invis_wall(x, y, z, sx, sy, sz):
200 var prefab = preload("res://objects/nodes/block.tscn")
201 var newwall = prefab.instantiate()
202 newwall.position.x = x
203 newwall.position.y = y
204 newwall.position.z = z
205 newwall.scale.x = sz
206 newwall.scale.y = sy
207 newwall.scale.z = sx
208 newwall.set_surface_override_material(0, preload("res://assets/materials/blackMatte.material"))
209 newwall.visibility_range_end = 3
210 newwall.visibility_range_end_margin = 1
211 newwall.visibility_range_fade_mode = RenderingServer.VISIBILITY_RANGE_FADE_SELF
212 newwall.skeleton = ".."
213 get_parent().add_child.call_deferred(newwall)
diff --git a/client/Archipelago/saver.gd b/client/Archipelago/saver.gd deleted file mode 100644 index 0fba9e7..0000000 --- a/client/Archipelago/saver.gd +++ /dev/null
@@ -1,9 +0,0 @@
1extends "res://scripts/nodes/saver.gd"
2
3
4func levelLoaded():
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_buttons.gd b/client/Archipelago/settings_buttons.gd deleted file mode 100644 index 9e61cb0..0000000 --- a/client/Archipelago/settings_buttons.gd +++ /dev/null
@@ -1,24 +0,0 @@
1extends Button
2
3
4func _ready():
5 pass
6
7
8func _connect_pressed():
9 self.disabled = true
10
11 var ap = global.get_node("Archipelago")
12 ap.ap_server = self.get_parent().get_node("server_box").text
13 ap.ap_user = self.get_parent().get_node("player_box").text
14 ap.ap_pass = self.get_parent().get_node("password_box").text
15 ap.saveSettings()
16
17 ap.connectToServer()
18
19
20func _back_pressed():
21 var ap = global.get_node("Archipelago")
22 ap.disconnect_from_ap()
23
24 get_tree().change_scene_to_file("res://objects/scenes/menus/main_menu.tscn")
diff --git a/client/Archipelago/settings_screen.gd b/client/Archipelago/settings_screen.gd deleted file mode 100644 index aaaf72a..0000000 --- a/client/Archipelago/settings_screen.gd +++ /dev/null
@@ -1,199 +0,0 @@
1extends Node2D
2
3
4func _ready():
5 # Some helpful logging.
6 if Steam.isSubscribed():
7 global._print("Provisioning successful! Build ID: %d" % Steam.getAppBuildId())
8 else:
9 global._print("Provisioning failed.")
10
11 # Undo the load screen removing our cursor
12 get_tree().get_root().set_disable_input(false)
13 Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
14
15 # Increase the WebSocket input buffer size so that we can download large
16 # data packages.
17 ProjectSettings.set_setting("network/limits/websocket_client/max_in_buffer_kb", 8192)
18
19 # Create the global AP manager, if it doesn't already exist.
20 if not global.has_node("Archipelago"):
21 var ap_script = ResourceLoader.load("user://maps/Archipelago/manager.gd")
22 var ap_instance = ap_script.new()
23 ap_instance.name = "Archipelago"
24
25 ap_instance.SCRIPT_client = load("user://maps/Archipelago/client.gd")
26 ap_instance.SCRIPT_keyboard = load("user://maps/Archipelago/keyboard.gd")
27 ap_instance.SCRIPT_locationListener = load("user://maps/Archipelago/locationListener.gd")
28 ap_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd")
29 ap_instance.SCRIPT_victoryListener = load("user://maps/Archipelago/victoryListener.gd")
30
31 global.add_child(ap_instance)
32
33 # Let's also inject any scripts we need to inject now.
34 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/animationListener.gd"))
35 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/collectable.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"))
43 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/pauseMenu.gd"))
44 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/player.gd"))
45 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/saver.gd"))
46 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/teleportListener.gd"))
47 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/worldportListener.gd"))
48
49 var proto_script = load("user://maps/Archipelago/generated/proto.gd")
50 var gamedata_script = load("user://maps/Archipelago/gamedata.gd")
51 var gamedata_instance = gamedata_script.new(proto_script)
52 gamedata_instance.load(
53 FileAccess.get_file_as_bytes("user://maps/Archipelago/generated/data.binpb")
54 )
55 gamedata_instance.name = "Gamedata"
56 global.add_child(gamedata_instance)
57
58 var messages_script = load("user://maps/Archipelago/messages.gd")
59 var messages_instance = messages_script.new()
60 messages_instance.name = "Messages"
61 global.add_child(messages_instance)
62
63 var textclient_script = load("user://maps/Archipelago/textclient.gd")
64 var textclient_instance = textclient_script.new()
65 textclient_instance.name = "Textclient"
66 global.add_child(textclient_instance)
67
68 var ap = global.get_node("Archipelago")
69 ap.connect("ap_connected", connectionSuccessful)
70 ap.connect("could_not_connect", connectionUnsuccessful)
71 ap.connect("connect_status", connectionStatus)
72
73 # Populate textboxes with AP settings.
74 $Panel/server_box.text = ap.ap_server
75 $Panel/player_box.text = ap.ap_user
76 $Panel/password_box.text = ap.ap_pass
77
78 var history_box = $Panel/connection_history
79 if ap.connection_history.is_empty():
80 history_box.disabled = true
81 else:
82 history_box.disabled = false
83
84 var i = 0
85 for details in ap.connection_history:
86 history_box.get_popup().add_item("%s (%s)" % [details[1], details[0]], i)
87 i += 1
88
89 history_box.get_popup().connect("id_pressed", historySelected)
90
91 # Show client version.
92 $Panel/title.text = "ARCHIPELAGO (%s)" % ap.my_version
93
94 # Increase font size in text boxes.
95 $Panel/server_box.add_theme_font_size_override("font_size", 36)
96 $Panel/player_box.add_theme_font_size_override("font_size", 36)
97 $Panel/password_box.add_theme_font_size_override("font_size", 36)
98
99
100# Adapted from https://gitlab.com/Delta-V-Modding/Mods/-/blob/main/game/ModLoader.gd
101func installScriptExtension(childScript: Resource):
102 # Force Godot to compile the script now.
103 # We need to do this here to ensure that the inheritance chain is
104 # properly set up, and multiple mods can chain-extend the same
105 # class multiple times.
106 # This is also needed to make Godot instantiate the extended class
107 # when creating singletons.
108 # The actual instance is thrown away.
109 childScript.new()
110
111 var parentScript = childScript.get_base_script()
112 var parentScriptPath = parentScript.resource_path
113 global._print("ModLoader: Installing script extension over %s" % parentScriptPath)
114 childScript.take_over_path(parentScriptPath)
115
116
117func connectionStatus(message):
118 var popup = self.get_node("Panel/AcceptDialog")
119 popup.title = "Connecting to Archipelago"
120 popup.dialog_text = message
121 popup.exclusive = true
122 popup.get_ok_button().visible = false
123 popup.popup_centered()
124
125
126func connectionSuccessful():
127 var ap = global.get_node("Archipelago")
128
129 # Save connection details
130 var connection_details = [ap.ap_server, ap.ap_user, ap.ap_pass]
131 if ap.connection_history.has(connection_details):
132 ap.connection_history.erase(connection_details)
133 ap.connection_history.push_front(connection_details)
134 if ap.connection_history.size() > 10:
135 ap.connection_history.resize(10)
136 ap.saveSettings()
137
138 # Switch to the_entry
139 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
140 global.user = ap.getSaveFileName()
141 global.universe = "lingo"
142 global.map = "the_entry"
143
144 unlocks.resetCollectables()
145 unlocks.resetData()
146
147 ap.setup_keys()
148
149 unlocks.loadCollectables()
150 unlocks.loadData()
151 unlocks.unlockKey("capslock", 1)
152
153 clearResourceCache("res://objects/meshes/gridDoor.tscn")
154 clearResourceCache("res://objects/nodes/collectable.tscn")
155 clearResourceCache("res://objects/nodes/door.tscn")
156 clearResourceCache("res://objects/nodes/keyHolder.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")
160 clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn")
161 clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn")
162 clearResourceCache("res://objects/nodes/player.tscn")
163 clearResourceCache("res://objects/nodes/saver.tscn")
164 clearResourceCache("res://objects/scenes/menus/pause_menu.tscn")
165
166 var paintings_dir = DirAccess.open("res://objects/meshes/paintings")
167 if paintings_dir:
168 paintings_dir.list_dir_begin()
169 var file_name = paintings_dir.get_next()
170 while file_name != "":
171 if not paintings_dir.current_is_dir() and file_name.ends_with(".tscn"):
172 clearResourceCache("res://objects/meshes/paintings/" + file_name)
173 file_name = paintings_dir.get_next()
174
175 switcher.switch_map.call_deferred("res://objects/scenes/the_entry.tscn")
176
177
178func connectionUnsuccessful(error_message):
179 $Panel/connect_button.disabled = false
180
181 var popup = $Panel/AcceptDialog
182 popup.title = "Could not connect to Archipelago"
183 popup.dialog_text = error_message
184 popup.exclusive = true
185 popup.get_ok_button().visible = true
186 popup.popup_centered()
187
188
189func historySelected(index):
190 var ap = global.get_node("Archipelago")
191 var details = ap.connection_history[index]
192
193 $Panel/server_box.text = details[0]
194 $Panel/player_box.text = details[1]
195 $Panel/password_box.text = details[2]
196
197
198func clearResourceCache(path):
199 ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE)
diff --git a/client/Archipelago/teleportListener.gd b/client/Archipelago/teleportListener.gd deleted file mode 100644 index 4a7deec..0000000 --- a/client/Archipelago/teleportListener.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/listeners/teleportListener.gd"
2
3var item_id
4var item_amount
5
6
7func _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 call_deferred("_readier")
30
31 super._ready()
32
33
34func _readier():
35 var ap = global.get_node("Archipelago")
36
37 if ap.client.getItemAmount(item_id) >= item_amount:
38 handleTriggered()
diff --git a/client/Archipelago/textclient.gd b/client/Archipelago/textclient.gd deleted file mode 100644 index 85cc6d2..0000000 --- a/client/Archipelago/textclient.gd +++ /dev/null
@@ -1,86 +0,0 @@
1extends CanvasLayer
2
3var panel
4var label
5var entry
6var is_open = false
7
8
9func _ready():
10 process_mode = ProcessMode.PROCESS_MODE_ALWAYS
11
12 panel = Panel.new()
13 panel.set_name("Panel")
14 panel.offset_left = 100
15 panel.offset_right = 1820
16 panel.offset_top = 100
17 panel.offset_bottom = 980
18 panel.visible = false
19 add_child(panel)
20
21 label = RichTextLabel.new()
22 label.set_name("Label")
23 label.offset_left = 80
24 label.offset_right = 1640
25 label.offset_top = 80
26 label.offset_bottom = 720
27 label.scroll_following = true
28 label.selection_enabled = true
29 panel.add_child(label)
30
31 label.push_font(load("res://assets/fonts/Lingo2.ttf"))
32 label.push_font_size(36)
33
34 var entry_style = StyleBoxFlat.new()
35 entry_style.bg_color = Color(0.9, 0.9, 0.9, 1)
36
37 entry = LineEdit.new()
38 entry.set_name("Entry")
39 entry.offset_left = 80
40 entry.offset_right = 1640
41 entry.offset_top = 760
42 entry.offset_bottom = 840
43 entry.add_theme_font_override("font", load("res://assets/fonts/Lingo2.ttf"))
44 entry.add_theme_font_size_override("font_size", 36)
45 entry.add_theme_color_override("font_color", Color(0, 0, 0, 1))
46 entry.add_theme_color_override("cursor_color", Color(0, 0, 0, 1))
47 entry.add_theme_stylebox_override("focus", entry_style)
48 panel.add_child(entry)
49 entry.connect("text_submitted", text_entered)
50
51
52func _input(event):
53 if global.loaded and event is InputEventKey and event.pressed:
54 if event.keycode == KEY_TAB and !Input.is_key_pressed(KEY_SHIFT):
55 if !get_tree().paused:
56 is_open = true
57 get_tree().paused = true
58 Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
59 panel.visible = true
60 entry.grab_focus()
61 get_viewport().set_input_as_handled()
62 else:
63 dismiss()
64 elif event.keycode == KEY_ESCAPE:
65 if is_open:
66 dismiss()
67 get_viewport().set_input_as_handled()
68
69
70func dismiss():
71 if is_open:
72 get_tree().paused = false
73 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
74 panel.visible = false
75 is_open = false
76
77
78func parse_printjson(text):
79 label.append_text("[p]" + text + "[/p]")
80
81
82func text_entered(text):
83 var ap = global.get_node("Archipelago")
84 var cmd = text.trim_suffix("\n")
85 ap.client.say(cmd)
86 entry.text = ""
diff --git a/client/Archipelago/vendor/LICENSE b/client/Archipelago/vendor/LICENSE deleted file mode 100644 index 115ba15..0000000 --- a/client/Archipelago/vendor/LICENSE +++ /dev/null
@@ -1,21 +0,0 @@
1MIT License
2
3Copyright (c) 2023 Xavier Sellier
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE. \ No newline at end of file
diff --git a/client/Archipelago/vendor/uuid.gd b/client/Archipelago/vendor/uuid.gd deleted file mode 100644 index b63fa04..0000000 --- a/client/Archipelago/vendor/uuid.gd +++ /dev/null
@@ -1,195 +0,0 @@
1# Note: The code might not be as pretty it could be, since it's written
2# in a way that maximizes performance. Methods are inlined and loops are avoided.
3extends Node
4
5const BYTE_MASK: int = 0b11111111
6
7
8static func uuidbin():
9 randomize()
10 # 16 random bytes with the bytes on index 6 and 8 modified
11 return [
12 randi() & BYTE_MASK,
13 randi() & BYTE_MASK,
14 randi() & BYTE_MASK,
15 randi() & BYTE_MASK,
16 randi() & BYTE_MASK,
17 randi() & BYTE_MASK,
18 ((randi() & BYTE_MASK) & 0x0f) | 0x40,
19 randi() & BYTE_MASK,
20 ((randi() & BYTE_MASK) & 0x3f) | 0x80,
21 randi() & BYTE_MASK,
22 randi() & BYTE_MASK,
23 randi() & BYTE_MASK,
24 randi() & BYTE_MASK,
25 randi() & BYTE_MASK,
26 randi() & BYTE_MASK,
27 randi() & BYTE_MASK,
28 ]
29
30
31static func uuidbinrng(rng: RandomNumberGenerator):
32 rng.randomize()
33 return [
34 rng.randi() & BYTE_MASK,
35 rng.randi() & BYTE_MASK,
36 rng.randi() & BYTE_MASK,
37 rng.randi() & BYTE_MASK,
38 rng.randi() & BYTE_MASK,
39 rng.randi() & BYTE_MASK,
40 ((rng.randi() & BYTE_MASK) & 0x0f) | 0x40,
41 rng.randi() & BYTE_MASK,
42 ((rng.randi() & BYTE_MASK) & 0x3f) | 0x80,
43 rng.randi() & BYTE_MASK,
44 rng.randi() & BYTE_MASK,
45 rng.randi() & BYTE_MASK,
46 rng.randi() & BYTE_MASK,
47 rng.randi() & BYTE_MASK,
48 rng.randi() & BYTE_MASK,
49 rng.randi() & BYTE_MASK,
50 ]
51
52
53static func v4():
54 # 16 random bytes with the bytes on index 6 and 8 modified
55 var b = uuidbin()
56
57 return (
58 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
59 % [
60 # low
61 b[0],
62 b[1],
63 b[2],
64 b[3],
65 # mid
66 b[4],
67 b[5],
68 # hi
69 b[6],
70 b[7],
71 # clock
72 b[8],
73 b[9],
74 # clock
75 b[10],
76 b[11],
77 b[12],
78 b[13],
79 b[14],
80 b[15]
81 ]
82 )
83
84
85static func v4_rng(rng: RandomNumberGenerator):
86 # 16 random bytes with the bytes on index 6 and 8 modified
87 var b = uuidbinrng(rng)
88
89 return (
90 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
91 % [
92 # low
93 b[0],
94 b[1],
95 b[2],
96 b[3],
97 # mid
98 b[4],
99 b[5],
100 # hi
101 b[6],
102 b[7],
103 # clock
104 b[8],
105 b[9],
106 # clock
107 b[10],
108 b[11],
109 b[12],
110 b[13],
111 b[14],
112 b[15]
113 ]
114 )
115
116
117var _uuid: Array
118
119
120func _init(rng := RandomNumberGenerator.new()) -> void:
121 _uuid = uuidbinrng(rng)
122
123
124func as_array() -> Array:
125 return _uuid.duplicate()
126
127
128func as_dict(big_endian := true) -> Dictionary:
129 if big_endian:
130 return {
131 "low": (_uuid[0] << 24) + (_uuid[1] << 16) + (_uuid[2] << 8) + _uuid[3],
132 "mid": (_uuid[4] << 8) + _uuid[5],
133 "hi": (_uuid[6] << 8) + _uuid[7],
134 "clock": (_uuid[8] << 8) + _uuid[9],
135 "node":
136 (
137 (_uuid[10] << 40)
138 + (_uuid[11] << 32)
139 + (_uuid[12] << 24)
140 + (_uuid[13] << 16)
141 + (_uuid[14] << 8)
142 + _uuid[15]
143 )
144 }
145 else:
146 return {
147 "low": _uuid[0] + (_uuid[1] << 8) + (_uuid[2] << 16) + (_uuid[3] << 24),
148 "mid": _uuid[4] + (_uuid[5] << 8),
149 "hi": _uuid[6] + (_uuid[7] << 8),
150 "clock": _uuid[8] + (_uuid[9] << 8),
151 "node":
152 (
153 _uuid[10]
154 + (_uuid[11] << 8)
155 + (_uuid[12] << 16)
156 + (_uuid[13] << 24)
157 + (_uuid[14] << 32)
158 + (_uuid[15] << 40)
159 )
160 }
161
162
163func as_string() -> String:
164 return (
165 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
166 % [
167 # low
168 _uuid[0],
169 _uuid[1],
170 _uuid[2],
171 _uuid[3],
172 # mid
173 _uuid[4],
174 _uuid[5],
175 # hi
176 _uuid[6],
177 _uuid[7],
178 # clock
179 _uuid[8],
180 _uuid[9],
181 # node
182 _uuid[10],
183 _uuid[11],
184 _uuid[12],
185 _uuid[13],
186 _uuid[14],
187 _uuid[15]
188 ]
189 )
190
191
192func is_equal(other) -> bool:
193 # Godot Engine compares Array recursively
194 # There's no need for custom comparison here.
195 return _uuid == other._uuid
diff --git a/client/Archipelago/victoryListener.gd b/client/Archipelago/victoryListener.gd deleted file mode 100644 index e9089d7..0000000 --- a/client/Archipelago/victoryListener.gd +++ /dev/null
@@ -1,20 +0,0 @@
1extends Receiver
2
3
4func _ready():
5 super._ready()
6
7
8func handleTriggered():
9 triggered += 1
10 if triggered >= total:
11 var ap = global.get_node("Archipelago")
12 ap.client.completedGoal()
13
14 global.get_node("Messages").showMessage("You have completed your goal!")
15
16
17func handleUntriggered():
18 triggered -= 1
19 if triggered < total:
20 pass
diff --git a/client/Archipelago/worldportListener.gd b/client/Archipelago/worldportListener.gd deleted file mode 100644 index c31c825..0000000 --- a/client/Archipelago/worldportListener.gd +++ /dev/null
@@ -1,8 +0,0 @@
1extends "res://scripts/nodes/listeners/worldportListener.gd"
2
3
4func changeScene():
5 if exit == "menus/credits":
6 return
7
8 super.changeScene()