about summary refs log tree commit diff stats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/Archipelago/animationListener.gd38
-rw-r--r--client/Archipelago/client.gd378
-rw-r--r--client/Archipelago/door.gd38
-rw-r--r--client/Archipelago/gamedata.gd78
-rw-r--r--client/Archipelago/locationListener.gd20
-rw-r--r--client/Archipelago/manager.gd303
-rw-r--r--client/Archipelago/messages.gd61
-rw-r--r--client/Archipelago/painting.gd38
-rw-r--r--client/Archipelago/pauseMenu.gd6
-rw-r--r--client/Archipelago/player.gd66
-rw-r--r--client/Archipelago/saver.gd5
-rw-r--r--client/Archipelago/settings_buttons.gd24
-rw-r--r--client/Archipelago/settings_screen.gd194
-rw-r--r--client/Archipelago/teleportListener.gd38
-rw-r--r--client/Archipelago/textclient.gd90
-rw-r--r--client/Archipelago/vendor/LICENSE21
-rw-r--r--client/Archipelago/vendor/uuid.gd195
-rw-r--r--client/Archipelago/worldportListener.gd8
-rw-r--r--client/archipelago.tscn281
19 files changed, 136 insertions, 1746 deletions
diff --git a/client/Archipelago/animationListener.gd b/client/Archipelago/animationListener.gd deleted file mode 100644 index f1fb5fb..0000000 --- a/client/Archipelago/animationListener.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/listeners/animationListener.gd"
2
3var item_id
4
5
6func _ready():
7 var node_path = String(
8 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
9 )
10
11 print("node: %s" % node_path)
12
13 var gamedata = global.get_node("Gamedata")
14 var door_id = gamedata.get_door_for_map_node_path(global.map, node_path)
15 if door_id != null:
16 print("door_id: %d" % door_id)
17
18 var ap = global.get_node("Archipelago")
19 item_id = ap.get_item_id_for_door(door_id)
20
21 if item_id != null:
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.has_item(item_id):
38 handleTriggered()
diff --git a/client/Archipelago/client.gd b/client/Archipelago/client.gd deleted file mode 100644 index 4c34e91..0000000 --- a/client/Archipelago/client.gd +++ /dev/null
@@ -1,378 +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_items = []
36var _slot_data = {}
37
38signal could_not_connect
39signal connect_status
40signal client_connected
41signal item_received(item_id, index, player, flags)
42signal message_received(message)
43
44
45func _init():
46 global._print("Instantiated APClient")
47
48 # Read AP datapackages from file, if there are any
49 if FileAccess.file_exists("user://ap_datapackages"):
50 var file = FileAccess.open("user://ap_datapackages", FileAccess.READ)
51 var data = file.get_var(true)
52 file.close()
53
54 if typeof(data) != TYPE_DICTIONARY:
55 global._print("AP datapackages file is corrupted")
56 data = {}
57
58 _datapackages = data
59
60 processDatapackages()
61
62
63func _ready():
64 pass
65 #_ws.connect("connection_closed", _closed)
66 #_ws.connect("connection_failed", _closed)
67 #_ws.connect("server_disconnected", _closed)
68 #_ws.connect("connection_error", _errored)
69 #_ws.connect("connection_established", _connected)
70
71
72func _reset_state():
73 _should_process = false
74 _authenticated = false
75 _try_wss = false
76 _has_connected = false
77
78
79func _errored():
80 if _try_wss:
81 global._print("Could not connect to AP with ws://, now trying wss://")
82 connectToServer(ap_server, ap_user, ap_pass)
83 else:
84 global._print("AP connection failed")
85 _reset_state()
86
87 emit_signal(
88 "could_not_connect",
89 "Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information."
90 )
91
92
93func _closed(_was_clean = true):
94 global._print("Connection closed")
95 _reset_state()
96
97 if not _initiated_disconnect:
98 emit_signal("could_not_connect", "Disconnected from Archipelago")
99
100 _initiated_disconnect = false
101
102
103func _connected(_proto = ""):
104 global._print("Connected!")
105 _try_wss = false
106
107
108func disconnect_from_ap():
109 _initiated_disconnect = true
110 _ws.close()
111
112
113func _process(_delta):
114 if _should_process:
115 _ws.poll()
116
117 var state = _ws.get_ready_state()
118 if state == WebSocketPeer.STATE_OPEN:
119 if not _has_connected:
120 _has_connected = true
121
122 _connected()
123
124 while _ws.get_available_packet_count():
125 var packet = _ws.get_packet()
126 global._print("Got data from server: " + packet.get_string_from_utf8())
127 var json = JSON.new()
128 var jserror = json.parse(packet.get_string_from_utf8())
129 if jserror != OK:
130 global._print("Error parsing packet from AP: " + jserror.error_string)
131 return
132
133 for message in json.data:
134 var cmd = message["cmd"]
135 global._print("Received command: " + cmd)
136
137 if cmd == "RoomInfo":
138 _seed = message["seed_name"]
139 _remote_version = message["version"]
140 _gen_version = message["generator_version"]
141
142 var needed_games = []
143 for game in message["datapackage_checksums"].keys():
144 if (
145 !_datapackages.has(game)
146 or (
147 _datapackages[game]["checksum"]
148 != message["datapackage_checksums"][game]
149 )
150 ):
151 needed_games.append(game)
152
153 if !needed_games.is_empty():
154 _pending_packages = needed_games
155 var cur_needed = _pending_packages.pop_front()
156 requestDatapackages([cur_needed])
157 else:
158 connectToRoom()
159
160 elif cmd == "DataPackage":
161 for game in message["data"]["games"].keys():
162 _datapackages[game] = message["data"]["games"][game]
163 saveDatapackages()
164
165 if !_pending_packages.is_empty():
166 var cur_needed = _pending_packages.pop_front()
167 requestDatapackages([cur_needed])
168 else:
169 processDatapackages()
170 connectToRoom()
171
172 elif cmd == "Connected":
173 _authenticated = true
174 _team = message["team"]
175 _slot = message["slot"]
176 _players = message["players"]
177 _checked_locations = message["checked_locations"]
178 _slot_data = message["slot_data"]
179
180 for player in _players:
181 _player_name_by_slot[player["slot"]] = player["alias"]
182 _game_by_player[player["slot"]] = message["slot_info"][str(
183 player["slot"]
184 )]["game"]
185
186 emit_signal("client_connected")
187
188 elif cmd == "ConnectionRefused":
189 var error_message = ""
190 for error in message["errors"]:
191 var submsg = ""
192 if error == "InvalidSlot":
193 submsg = "Invalid player name."
194 elif error == "InvalidGame":
195 submsg = "The specified player is not playing Lingo."
196 elif error == "IncompatibleVersion":
197 submsg = (
198 "The Archipelago server is not the correct version for this client. Expected v%d.%d.%d. Found v%d.%d.%d."
199 % [
200 ap_version["major"],
201 ap_version["minor"],
202 ap_version["build"],
203 _remote_version["major"],
204 _remote_version["minor"],
205 _remote_version["build"]
206 ]
207 )
208 elif error == "InvalidPassword":
209 submsg = "Incorrect password."
210 elif error == "InvalidItemsHandling":
211 submsg = "Invalid item handling flag. This is a bug with the client."
212
213 if submsg != "":
214 if error_message != "":
215 error_message += " "
216 error_message += submsg
217
218 if error_message == "":
219 error_message = "Unknown error."
220
221 _initiated_disconnect = true
222 _ws.disconnect_from_host()
223
224 emit_signal("could_not_connect", error_message)
225 global._print("Connection to AP refused")
226 global._print(message)
227
228 elif cmd == "ReceivedItems":
229 var i = 0
230 for item in message["items"]:
231 if not _received_items.has(int(item["item"])):
232 _received_items.append(int(item["item"]))
233
234 emit_signal(
235 "item_received",
236 int(item["item"]),
237 int(message["index"]) + i,
238 int(item["player"]),
239 int(item["flags"])
240 )
241 i += 1
242
243 elif cmd == "PrintJSON":
244 emit_signal("message_received", message)
245
246 elif state == WebSocketPeer.STATE_CLOSED:
247 if _has_connected:
248 _closed()
249 else:
250 _errored()
251
252
253func saveDatapackages():
254 # Save the AP datapackages to disk.
255 var file = FileAccess.open("user://ap_datapackages", FileAccess.WRITE)
256 file.store_var(_datapackages, true)
257 file.close()
258
259
260func connectToServer(server, un, pw):
261 ap_server = server
262 ap_user = un
263 ap_pass = pw
264
265 _initiated_disconnect = false
266
267 var url = ""
268 if ap_server.begins_with("ws://") or ap_server.begins_with("wss://"):
269 url = ap_server
270 _try_wss = false
271 elif _try_wss:
272 url = "wss://" + ap_server
273 _try_wss = false
274 else:
275 url = "ws://" + ap_server
276 _try_wss = true
277
278 var err = _ws.connect_to_url(url)
279 if err != OK:
280 emit_signal(
281 "could_not_connect",
282 (
283 "Could not connect to Archipelago. Check that your server and port are correct. See the error log for more information. Error code: %d."
284 % err
285 )
286 )
287 global._print("Could not connect to AP: " + err)
288 return
289 _should_process = true
290
291 emit_signal("connect_status", "Connecting...")
292
293
294func sendMessage(msg):
295 var payload = JSON.stringify(msg)
296 _ws.send_text(payload)
297
298
299func requestDatapackages(games):
300 emit_signal("connect_status", "Downloading %s data package..." % games[0])
301
302 sendMessage([{"cmd": "GetDataPackage", "games": games}])
303
304
305func processDatapackages():
306 _item_id_to_name = {}
307 _location_id_to_name = {}
308 for game in _datapackages.keys():
309 var package = _datapackages[game]
310
311 _item_id_to_name[game] = {}
312 for item_name in package["item_name_to_id"].keys():
313 _item_id_to_name[game][int(package["item_name_to_id"][item_name])] = item_name
314
315 _location_id_to_name[game] = {}
316 for location_name in package["location_name_to_id"].keys():
317 _location_id_to_name[game][int(package["location_name_to_id"][location_name])] = location_name
318
319 if _datapackages.has("Lingo 2"):
320 _item_name_to_id = _datapackages["Lingo 2"]["item_name_to_id"]
321 _location_name_to_id = _datapackages["Lingo 2"]["location_name_to_id"]
322
323
324func connectToRoom():
325 emit_signal("connect_status", "Authenticating...")
326
327 sendMessage(
328 [
329 {
330 "cmd": "Connect",
331 "password": ap_pass,
332 "game": "Lingo 2",
333 "name": ap_user,
334 "uuid": SCRIPT_uuid.v4(),
335 "version": ap_version,
336 "items_handling": 0b111, # always receive our items
337 "tags": [],
338 "slot_data": true
339 }
340 ]
341 )
342
343
344func sendConnectUpdate(tags):
345 sendMessage([{"cmd": "ConnectUpdate", "tags": tags}])
346
347
348func requestSync():
349 sendMessage([{"cmd": "Sync"}])
350
351
352func sendLocation(loc_id):
353 sendMessage([{"cmd": "LocationChecks", "locations": [loc_id]}])
354
355
356func setValue(key, value, operation = "replace"):
357 sendMessage(
358 [
359 {
360 "cmd": "Set",
361 "key": "Lingo2_%d_%s" % [_slot, key],
362 "want_reply": false,
363 "operations": [{"operation": operation, "value": value}]
364 }
365 ]
366 )
367
368
369func say(textdata):
370 sendMessage([{"cmd": "Say", "text": textdata}])
371
372
373func completedGoal():
374 sendMessage([{"cmd": "StatusUpdate", "status": 30}]) # CLIENT_GOAL
375
376
377func hasItem(item_id):
378 return _received_items.has(item_id)
diff --git a/client/Archipelago/door.gd b/client/Archipelago/door.gd deleted file mode 100644 index 731eca4..0000000 --- a/client/Archipelago/door.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/door.gd"
2
3var item_id
4
5
6func _ready():
7 var node_path = String(
8 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
9 )
10
11 print("node: %s" % node_path)
12
13 var gamedata = global.get_node("Gamedata")
14 var door_id = gamedata.get_door_for_map_node_path(global.map, node_path)
15 if door_id != null:
16 print("door_id: %d" % door_id)
17
18 var ap = global.get_node("Archipelago")
19 item_id = ap.get_item_id_for_door(door_id)
20
21 if item_id != null:
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.has_item(item_id):
38 handleTriggered()
diff --git a/client/Archipelago/gamedata.gd b/client/Archipelago/gamedata.gd deleted file mode 100644 index 16368a9..0000000 --- a/client/Archipelago/gamedata.gd +++ /dev/null
@@ -1,78 +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 = {}
10
11
12func _init(proto_script):
13 SCRIPT_proto = proto_script
14
15
16func load(data_bytes):
17 objects = SCRIPT_proto.AllObjects.new()
18
19 var result_code = objects.from_bytes(data_bytes)
20 if result_code != SCRIPT_proto.PB_ERR.NO_ERRORS:
21 print("Could not load generated data: %d" % result_code)
22 return
23
24 for map in objects.get_maps():
25 map_id_by_name[map.get_name()] = map.get_id()
26
27 for door in objects.get_doors():
28 var map = objects.get_maps()[door.get_map_id()]
29
30 if not map.get_name() in door_id_by_map_node_path:
31 door_id_by_map_node_path[map.get_name()] = {}
32
33 var map_data = door_id_by_map_node_path[map.get_name()]
34 for receiver in door.get_receivers():
35 map_data[receiver] = door.get_id()
36
37 for painting_id in door.get_move_paintings():
38 var painting = objects.get_paintings()[painting_id]
39 map_data[painting.get_path()] = door.get_id()
40
41 if door.has_ap_id():
42 door_id_by_ap_id[door.get_ap_id()] = door.get_id()
43
44 for painting in objects.get_paintings():
45 var room = objects.get_rooms()[painting.get_room_id()]
46 var map = objects.get_maps()[room.get_map_id()]
47
48 if not map.get_name() in painting_id_by_map_node_path:
49 painting_id_by_map_node_path[map.get_name()] = {}
50
51 var _map_data = painting_id_by_map_node_path[map.get_name()]
52
53
54func get_door_for_map_node_path(map_name, node_path):
55 if not door_id_by_map_node_path.has(map_name):
56 return null
57
58 var map_data = door_id_by_map_node_path[map_name]
59 return map_data.get(node_path, null)
60
61
62func get_door_ap_id(door_id):
63 var door = objects.get_doors()[door_id]
64 if door.has_ap_id():
65 return door.get_ap_id()
66 else:
67 return null
68
69
70func get_door_receivers(door_id):
71 var door = objects.get_doors()[door_id]
72 return door.get_receivers()
73
74
75func get_door_map_name(door_id):
76 var door = objects.get_doors()[door_id]
77 var map = objects.get_maps()[door.get_map_id()]
78 return map.get_name()
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 10c4096..0000000 --- a/client/Archipelago/manager.gd +++ /dev/null
@@ -1,303 +0,0 @@
1extends Node
2
3const my_version = "0.1.0"
4
5var SCRIPT_client
6var SCRIPT_locationListener
7var SCRIPT_uuid
8
9var ap_server = ""
10var ap_user = ""
11var ap_pass = ""
12var connection_history = []
13
14var client
15
16var _localdata_file = ""
17var _received_indexes = []
18var _last_new_item = -1
19
20signal could_not_connect
21signal connect_status
22signal ap_connected
23
24
25func _init():
26 # Read AP settings from file, if there are any
27 if FileAccess.file_exists("user://ap_settings"):
28 var file = FileAccess.open("user://ap_settings", FileAccess.READ)
29 var data = file.get_var(true)
30 file.close()
31
32 if typeof(data) != TYPE_ARRAY:
33 global._print("AP settings file is corrupted")
34 data = []
35
36 if data.size() > 0:
37 ap_server = data[0]
38
39 if data.size() > 1:
40 ap_user = data[1]
41
42 if data.size() > 2:
43 ap_pass = data[2]
44
45 if data.size() > 3:
46 connection_history = data[3]
47
48
49func _ready():
50 client = SCRIPT_client.new()
51 client.SCRIPT_uuid = SCRIPT_uuid
52
53 client.connect("item_received", _process_item)
54 client.connect("message_received", _process_message)
55 client.connect("could_not_connect", _client_could_not_connect)
56 client.connect("connect_status", _client_connect_status)
57 client.connect("client_connected", _client_connected)
58
59 add_child(client)
60
61
62func saveSettings():
63 # Save the AP settings to disk.
64 var path = "user://ap_settings"
65 var file = FileAccess.open(path, FileAccess.WRITE)
66
67 var data = [
68 ap_server,
69 ap_user,
70 ap_pass,
71 connection_history,
72 ]
73 file.store_var(data, true)
74 file.close()
75
76
77func saveLocaldata():
78 # Save the MW/slot specific settings to disk.
79 var dir = DirAccess.open("user://")
80 var folder = "archipelago_data"
81 if not dir.dir_exists(folder):
82 dir.make_dir(folder)
83
84 var file = FileAccess.open(_localdata_file, FileAccess.WRITE)
85
86 var data = [
87 _last_new_item,
88 ]
89 file.store_var(data, true)
90 file.close()
91
92
93func connectToServer():
94 _received_indexes = []
95 _last_new_item = -1
96
97 client.connectToServer(ap_server, ap_user, ap_pass)
98
99
100func getSaveFileName():
101 return "zzAP_%s_%d" % [client._seed, client._slot]
102
103
104func disconnect_from_ap():
105 client.disconnect_from_ap()
106
107
108func get_item_id_for_door(door_id):
109 var gamedata = global.get_node("Gamedata")
110 var door = gamedata.objects.get_doors()[door_id]
111 if (
112 door.get_type() == gamedata.SCRIPT_proto.DoorType.EVENT
113 or door.get_type() == gamedata.SCRIPT_proto.DoorType.LOCATION_ONLY
114 or door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR
115 ):
116 return null
117 return gamedata.get_door_ap_id(door_id)
118
119
120func has_item(item_id):
121 return client.hasItem(item_id)
122
123
124func _process_item(item, index, from, flags):
125 if index != null:
126 if _received_indexes.has(index):
127 # Do not re-process items.
128 return
129
130 _received_indexes.append(index)
131
132 var item_name = "Unknown"
133 if client._item_id_to_name["Lingo 2"].has(item):
134 item_name = client._item_id_to_name["Lingo 2"][item]
135
136 var gamedata = global.get_node("Gamedata")
137 var door_id = gamedata.door_id_by_ap_id.get(item, null)
138 if door_id != null and gamedata.get_door_map_name(door_id) == global.map:
139 var receivers = gamedata.get_door_receivers(door_id)
140 var scene = get_tree().get_root().get_node_or_null("scene")
141 if scene != null:
142 for receiver in receivers:
143 var rnode = scene.get_node_or_null(receiver)
144 if rnode != null:
145 rnode.handleTriggered()
146 #for painting_id in gamedata.objects.get_doors()[door_id].get_move_paintings():
147 # var painting = gamedata.objects.get_paintings()[painting_id]
148 # var pnode = scene.get_node_or_null(painting.get_path() + "/teleportListener")
149 # if pnode != null:
150 # pnode.handleTriggered()
151
152 # Show a message about the item if it's new.
153 if index != null and index > _last_new_item:
154 _last_new_item = index
155 saveLocaldata()
156
157 var player_name = "Unknown"
158 if client._player_name_by_slot.has(from):
159 player_name = client._player_name_by_slot[from]
160
161 var item_color = colorForItemType(flags)
162
163 var message
164 if from == client._slot:
165 message = "Found [color=%s]%s[/color]" % [item_color, item_name]
166 else:
167 message = "Received [color=%s]%s[/color] from %s" % [item_color, item_name, player_name]
168
169 global._print(message)
170
171 global.get_node("Messages").showMessage(message)
172
173
174func _process_message(message):
175 parse_printjson_for_textclient(message)
176
177 if (
178 !message.has("receiving")
179 or !message.has("item")
180 or message["item"]["player"] != client._slot
181 ):
182 return
183
184 var item_name = "Unknown"
185 var item_player_game = client._game_by_player[message["receiving"]]
186 if client._item_id_to_name[item_player_game].has(message["item"]["item"]):
187 item_name = client._item_id_to_name[item_player_game][message["item"]["item"]]
188
189 var location_name = "Unknown"
190 var location_player_game = client._game_by_player[message["item"]["player"]]
191 if client._location_id_to_name[location_player_game].has(message["item"]["location"]):
192 location_name = (
193 client._location_id_to_name[location_player_game][message["item"]["location"]]
194 )
195
196 var player_name = "Unknown"
197 if client._player_name_by_slot.has(message["receiving"]):
198 player_name = client._player_name_by_slot[message["receiving"]]
199
200 var item_color = colorForItemType(message["item"]["flags"])
201
202 if message["type"] == "Hint":
203 var is_for = ""
204 if message["receiving"] != client._slot:
205 is_for = " for %s" % player_name
206 if !message.has("found") || !message["found"]:
207 global.get_node("Messages").showMessage(
208 (
209 "Hint: [color=%s]%s[/color]%s is on %s"
210 % [item_color, item_name, is_for, location_name]
211 )
212 )
213 else:
214 if message["receiving"] != client._slot:
215 var sentMsg = "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
216 #if _hinted_locations.has(message["item"]["location"]):
217 # sentMsg += " ([color=#fafad2]Hinted![/color])"
218 global.get_node("Messages").showMessage(sentMsg)
219
220
221func parse_printjson_for_textclient(message):
222 var parts = []
223 for message_part in message["data"]:
224 if !message_part.has("type") and message_part.has("text"):
225 parts.append(message_part["text"])
226 elif message_part["type"] == "player_id":
227 if int(message_part["text"]) == client._slot:
228 parts.append(
229 "[color=#ee00ee]%s[/color]" % client._player_name_by_slot[client._slot]
230 )
231 else:
232 var from = float(message_part["text"])
233 parts.append("[color=#fafad2]%s[/color]" % client._player_name_by_slot[from])
234 elif message_part["type"] == "item_id":
235 var item_name = "Unknown"
236 var item_player_game = client._game_by_player[message_part["player"]]
237 if client._item_id_to_name[item_player_game].has(int(message_part["text"])):
238 item_name = client._item_id_to_name[item_player_game][int(message_part["text"])]
239
240 parts.append(
241 "[color=%s]%s[/color]" % [colorForItemType(message_part["flags"]), item_name]
242 )
243 elif message_part["type"] == "location_id":
244 var location_name = "Unknown"
245 var location_player_game = client._game_by_player[message_part["player"]]
246 if client._location_id_to_name[location_player_game].has(int(message_part["text"])):
247 location_name = client._location_id_to_name[location_player_game][int(
248 message_part["text"]
249 )]
250
251 parts.append("[color=#00ff7f]%s[/color]" % location_name)
252 elif message_part.has("text"):
253 parts.append(message_part["text"])
254
255 var textclient_node = global.get_node("Textclient")
256 if textclient_node != null:
257 textclient_node.parse_printjson("".join(parts))
258
259
260func _client_could_not_connect():
261 emit_signal("could_not_connect")
262
263
264func _client_connect_status(message):
265 emit_signal("connect_status", message)
266
267
268func _client_connected():
269 _localdata_file = "user://archipelago_data/%s_%d" % [client._seed, client._slot]
270 _last_new_item = -1
271
272 if FileAccess.file_exists(_localdata_file):
273 var ap_file = FileAccess.open(_localdata_file, FileAccess.READ)
274 var localdata = ap_file.get_var(true)
275 ap_file.close()
276
277 if typeof(localdata) != TYPE_ARRAY:
278 print("AP localdata file is corrupted")
279 localdata = []
280
281 if localdata.size() > 0:
282 _last_new_item = localdata[0]
283
284 emit_signal("ap_connected")
285
286
287func send_location(loc_id):
288 client.sendLocation(loc_id)
289
290
291func colorForItemType(flags):
292 var int_flags = int(flags)
293 if int_flags & 1: # progression
294 if int_flags & 2: # proguseful
295 return "#f0d200"
296 else:
297 return "#bc51e0"
298 elif int_flags & 2: # useful
299 return "#2b67ff"
300 elif int_flags & 4: # trap
301 return "#d63a22"
302 else: # filler
303 return "#14de9e"
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 6b3de0b..0000000 --- a/client/Archipelago/painting.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/painting.gd"
2
3var item_id
4
5
6func _ready():
7 var node_path = String(
8 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
9 )
10
11 print("node: %s" % node_path)
12
13 var gamedata = global.get_node("Gamedata")
14 var door_id = gamedata.get_door_for_map_node_path(global.map, node_path)
15 if door_id != null:
16 print("door_id: %d" % door_id)
17
18 var ap = global.get_node("Archipelago")
19 item_id = ap.get_item_id_for_door(door_id)
20
21 if item_id != null:
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.has_item(item_id):
38 handleTriggered()
diff --git a/client/Archipelago/pauseMenu.gd b/client/Archipelago/pauseMenu.gd deleted file mode 100644 index 6c013a5..0000000 --- a/client/Archipelago/pauseMenu.gd +++ /dev/null
@@ -1,6 +0,0 @@
1extends "res://scripts/ui/pauseMenu.gd"
2
3
4func _pause_game():
5 global.get_node("Textclient").dismiss()
6 super._pause_game()
diff --git a/client/Archipelago/player.gd b/client/Archipelago/player.gd deleted file mode 100644 index 082aa64..0000000 --- a/client/Archipelago/player.gd +++ /dev/null
@@ -1,66 +0,0 @@
1extends "res://scripts/nodes/player.gd"
2
3
4func _ready():
5 var ap = global.get_node("Archipelago")
6 var gamedata = global.get_node("Gamedata")
7
8 var map_id = gamedata.map_id_by_name.get(global.map)
9 for door in gamedata.objects.get_doors():
10 if door.get_map_id() != map_id:
11 continue
12
13 if not door.has_ap_id():
14 continue
15
16 if door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY:
17 continue
18
19 var locationListener = ap.SCRIPT_locationListener.new()
20 locationListener.location_id = door.get_ap_id()
21 locationListener.name = "locationListener_%d" % door.get_ap_id()
22
23 for panel_ref in door.get_panels():
24 # TODO: specific answers
25 var panel_data = gamedata.objects.get_panels()[panel_ref.get_panel()]
26 locationListener.senders.append(NodePath("/root/scene/" + panel_data.get_path()))
27
28 get_parent().add_child.call_deferred(locationListener)
29
30 for letter in gamedata.objects.get_letters():
31 var room = gamedata.objects.get_rooms()[letter.get_room_id()]
32 if room.get_map_id() != map_id:
33 continue
34
35 var locationListener = ap.SCRIPT_locationListener.new()
36 locationListener.location_id = letter.get_ap_id()
37 locationListener.name = "locationListener_%d" % letter.get_ap_id()
38 locationListener.senders.append(NodePath("/root/scene/" + letter.get_path()))
39
40 get_parent().add_child.call_deferred(locationListener)
41
42 for mastery in gamedata.objects.get_masteries():
43 var room = gamedata.objects.get_rooms()[mastery.get_room_id()]
44 if room.get_map_id() != map_id:
45 continue
46
47 var locationListener = ap.SCRIPT_locationListener.new()
48 locationListener.location_id = mastery.get_ap_id()
49 locationListener.name = "locationListener_%d" % mastery.get_ap_id()
50 locationListener.senders.append(NodePath("/root/scene/" + mastery.get_path()))
51
52 get_parent().add_child.call_deferred(locationListener)
53
54 for ending in gamedata.objects.get_endings():
55 var room = gamedata.objects.get_rooms()[ending.get_room_id()]
56 if room.get_map_id() != map_id:
57 continue
58
59 var locationListener = ap.SCRIPT_locationListener.new()
60 locationListener.location_id = ending.get_ap_id()
61 locationListener.name = "locationListener_%d" % ending.get_ap_id()
62 locationListener.senders.append(NodePath("/root/scene/" + ending.get_path()))
63
64 get_parent().add_child.call_deferred(locationListener)
65
66 super._ready()
diff --git a/client/Archipelago/saver.gd b/client/Archipelago/saver.gd deleted file mode 100644 index 7e788a8..0000000 --- a/client/Archipelago/saver.gd +++ /dev/null
@@ -1,5 +0,0 @@
1extends "res://scripts/nodes/saver.gd"
2
3
4func levelLoaded():
5 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 3697466..0000000 --- a/client/Archipelago/settings_screen.gd +++ /dev/null
@@ -1,194 +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 #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")
33 ap_instance.SCRIPT_locationListener = load("user://maps/Archipelago/locationListener.gd")
34 ap_instance.SCRIPT_uuid = load("user://maps/Archipelago/vendor/uuid.gd")
35
36 global.add_child(ap_instance)
37
38 # Let's also inject any scripts we need to inject now.
39 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/animationListener.gd"))
40 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/door.gd"))
41 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/painting.gd"))
42 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/pauseMenu.gd"))
43 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/player.gd"))
44 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/saver.gd"))
45 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/teleportListener.gd"))
46 installScriptExtension(ResourceLoader.load("user://maps/Archipelago/worldportListener.gd"))
47
48 var proto_script = load("user://maps/Archipelago/generated/proto.gd")
49 var gamedata_script = load("user://maps/Archipelago/gamedata.gd")
50 var gamedata_instance = gamedata_script.new(proto_script)
51 gamedata_instance.load(
52 FileAccess.get_file_as_bytes("user://maps/Archipelago/generated/data.binpb")
53 )
54 gamedata_instance.name = "Gamedata"
55 global.add_child(gamedata_instance)
56
57 var messages_script = load("user://maps/Archipelago/messages.gd")
58 var messages_instance = messages_script.new()
59 messages_instance.name = "Messages"
60 global.add_child(messages_instance)
61
62 var textclient_script = load("user://maps/Archipelago/textclient.gd")
63 var textclient_instance = textclient_script.new()
64 textclient_instance.name = "Textclient"
65 global.add_child(textclient_instance)
66
67 var ap = global.get_node("Archipelago")
68 ap.connect("ap_connected", connectionSuccessful)
69 ap.connect("could_not_connect", connectionUnsuccessful)
70 ap.connect("connect_status", connectionStatus)
71
72 # Populate textboxes with AP settings.
73 $Panel/server_box.text = ap.ap_server
74 $Panel/player_box.text = ap.ap_user
75 $Panel/password_box.text = ap.ap_pass
76
77 var history_box = $Panel/connection_history
78 if ap.connection_history.is_empty():
79 history_box.disabled = true
80 else:
81 history_box.disabled = false
82
83 var i = 0
84 for details in ap.connection_history:
85 history_box.get_popup().add_item("%s (%s)" % [details[1], details[0]], i)
86 i += 1
87
88 history_box.get_popup().connect("id_pressed", historySelected)
89
90 # Show client version.
91 $Panel/title.text = "ARCHIPELAGO (%s)" % ap.my_version
92
93 # Increase font size in text boxes.
94 $Panel/server_box.add_theme_font_size_override("font_size", 36)
95 $Panel/player_box.add_theme_font_size_override("font_size", 36)
96 $Panel/password_box.add_theme_font_size_override("font_size", 36)
97
98
99# Adapted from https://gitlab.com/Delta-V-Modding/Mods/-/blob/main/game/ModLoader.gd
100func installScriptExtension(childScript: Resource):
101 # Force Godot to compile the script now.
102 # We need to do this here to ensure that the inheritance chain is
103 # properly set up, and multiple mods can chain-extend the same
104 # class multiple times.
105 # This is also needed to make Godot instantiate the extended class
106 # when creating singletons.
107 # The actual instance is thrown away.
108 childScript.new()
109
110 var parentScript = childScript.get_base_script()
111 var parentScriptPath = parentScript.resource_path
112 global._print("ModLoader: Installing script extension over %s" % parentScriptPath)
113 childScript.take_over_path(parentScriptPath)
114
115
116func connectionStatus(message):
117 var popup = self.get_node("Panel/AcceptDialog")
118 popup.title = "Connecting to Archipelago"
119 popup.dialog_text = message
120 popup.exclusive = true
121 popup.get_ok_button().visible = false
122 popup.popup_centered()
123
124
125func connectionSuccessful():
126 var ap = global.get_node("Archipelago")
127
128 # Save connection details
129 var connection_details = [ap.ap_server, ap.ap_user, ap.ap_pass]
130 if ap.connection_history.has(connection_details):
131 ap.connection_history.erase(connection_details)
132 ap.connection_history.push_front(connection_details)
133 if ap.connection_history.size() > 10:
134 ap.connection_history.resize(10)
135 ap.saveSettings()
136
137 # Switch to the_entry
138 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
139 global.user = ap.getSaveFileName()
140 global.universe = "lingo"
141 global.map = "the_entry"
142
143 unlocks.resetKeys()
144 unlocks.resetCollectables()
145 unlocks.resetData()
146 unlocks.loadKeys()
147 unlocks.loadCollectables()
148 unlocks.loadData()
149 unlocks.unlockKey("capslock", 1)
150
151 clearResourceCache("res://objects/meshes/gridDoor.tscn")
152 clearResourceCache("res://objects/nodes/door.tscn")
153 clearResourceCache("res://objects/nodes/listeners/animationListener.tscn")
154 clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn")
155 clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn")
156 clearResourceCache("res://objects/nodes/player.tscn")
157 clearResourceCache("res://objects/nodes/saver.tscn")
158 clearResourceCache("res://objects/scenes/menus/pause_menu.tscn")
159
160 var paintings_dir = DirAccess.open("res://objects/meshes/paintings")
161 if paintings_dir:
162 paintings_dir.list_dir_begin()
163 var file_name = paintings_dir.get_next()
164 while file_name != "":
165 if not paintings_dir.current_is_dir() and file_name.ends_with(".tscn"):
166 clearResourceCache("res://objects/meshes/paintings/" + file_name)
167 file_name = paintings_dir.get_next()
168
169 switcher.switch_map("res://objects/scenes/the_entry.tscn")
170
171
172func connectionUnsuccessful(error_message):
173 $Panel/connect_button.disabled = false
174
175 var popup = $Panel/AcceptDialog
176 popup.title = "Could not connect to Archipelago"
177 popup.dialog_text = error_message
178 popup.exclusive = true
179 popup.get_ok_button().visible = true
180 popup.popup_centered()
181
182
183func historySelected(index):
184 var ap = global.get_node("Archipelago")
185 var details = ap.connection_history[index]
186
187 $Panel/server_box.text = details[0]
188 $Panel/player_box.text = details[1]
189 $Panel/password_box.text = details[2]
190
191
192func clearResourceCache(path):
193 ResourceLoader.load_threaded_request(path, "", false, ResourceLoader.CACHE_MODE_REPLACE)
194 ResourceLoader.load_threaded_get(path)
diff --git a/client/Archipelago/teleportListener.gd b/client/Archipelago/teleportListener.gd deleted file mode 100644 index 4bb08c9..0000000 --- a/client/Archipelago/teleportListener.gd +++ /dev/null
@@ -1,38 +0,0 @@
1extends "res://scripts/nodes/listeners/teleportListener.gd"
2
3var item_id
4
5
6func _ready():
7 var node_path = String(
8 get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names()
9 )
10
11 print("node: %s" % node_path)
12
13 var gamedata = global.get_node("Gamedata")
14 var door_id = gamedata.get_door_for_map_node_path(global.map, node_path)
15 if door_id != null:
16 print("door_id: %d" % door_id)
17
18 var ap = global.get_node("Archipelago")
19 item_id = ap.get_item_id_for_door(door_id)
20
21 if item_id != null:
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.has_item(item_id):
38 handleTriggered()
diff --git a/client/Archipelago/textclient.gd b/client/Archipelago/textclient.gd deleted file mode 100644 index 6a0aa95..0000000 --- a/client/Archipelago/textclient.gd +++ /dev/null
@@ -1,90 +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 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 if !label.text.is_empty():
80 #label.newline()
81 pass
82
83 label.append_text("[p]" + text + "[/p]")
84
85
86func text_entered(text):
87 var ap = global.get_node("Archipelago")
88 var cmd = text.trim_suffix("\n")
89 ap.client.say(cmd)
90 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/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()
diff --git a/client/archipelago.tscn b/client/archipelago.tscn index 40dd46f..1c156a3 100644 --- a/client/archipelago.tscn +++ b/client/archipelago.tscn
@@ -1,162 +1,153 @@
1[gd_scene load_steps=11 format=2] 1[gd_scene load_steps=3 format=3 uid="uid://b5mj3cq2bcesd"]
2 2
3[ext_resource path="user://maps/Archipelago/settings_buttons.gd" type="Script" id=4] 3[ext_resource type="Theme" uid="uid://7w454egydi41" path="res://assets/themes/baseUI.tres" id="1_mw3f1"]
4[ext_resource path="user://maps/Archipelago/settings_screen.gd" type="Script" id=5] 4
5[ext_resource path="res://images/unchecked.png" type="Texture" id=7] 5[sub_resource id=2 type="GDScript"]
6[ext_resource path="res://images/checked.png" type="Texture" id=8] 6script/source = "extends Node2D
7[ext_resource type="Theme" uid="uid://7w454egydi41" path="res://assets/themes/baseUI.tres" id="2_g4bvn"] 7
8 8const CACHE_PATH = \"user://apworld_path.txt\"
9[sub_resource type="StyleBoxFlat" id=1] 9
10bg_color = Color( 0, 0, 0, 0 ) 10
11 11func _ready():
12[sub_resource type="StyleBoxFlat" id=2] 12 if FileAccess.file_exists(CACHE_PATH):
13bg_color = Color( 1, 1, 1, 1 ) 13 var file = FileAccess.open(CACHE_PATH, FileAccess.READ)
14border_width_left = 1 14 $Panel/HBoxContainer/LineEdit.text = file.get_as_text()
15border_width_top = 1 15 file.close()
16border_width_right = 1 16
17border_width_bottom = 1 17
18border_color = Color( 1, 1, 0, 1 ) 18func _browse_pressed():
19border_blend = true 19 $FileDialog.popup_centered()
20corner_radius_top_left = 3 20
21corner_radius_top_right = 3 21
22corner_radius_bottom_right = 3 22func _file_selected(path):
23corner_radius_bottom_left = 3 23 $Panel/HBoxContainer/LineEdit.text = path
24expand_offset_left = 5.0 24
25expand_offset_right = 5.0 25
26expand_offset_top = 5.0 26func _start_pressed():
27expand_offset_bottom = 5.0 27 var apworld_path = $Panel/HBoxContainer/LineEdit.text
28 28
29[node name="settings_screen" type="Node2D"] 29 if not FileAccess.file_exists(apworld_path):
30script = ExtResource( 5 ) 30 $AcceptDialog.popup_centered()
31 return
32
33 var zip_reader = ZIPReader.new()
34 zip_reader.open(apworld_path)
35
36 var inner_path = \"lingo2/client/apworld_runtime.gd\"
37 if not zip_reader.file_exists(inner_path):
38 zip_reader.close()
39 $AcceptDialog.popup_centered()
40 return
41
42 var cache_file = FileAccess.open(CACHE_PATH, FileAccess.WRITE)
43 cache_file.store_string(apworld_path)
44 cache_file.close()
45
46 var runtime_script = GDScript.new()
47 runtime_script.source_code = zip_reader.read_file(inner_path).get_string_from_utf8()
48 runtime_script.reload()
49
50 zip_reader.close()
51
52 var runtime = runtime_script.new(apworld_path)
53 runtime.name = \"Runtime\"
54
55 global.add_child(runtime)
56
57 runtime.load_script_as_scene.call_deferred(\"settings_screen.gd\", \"settings_screen\")
58
59
60func _quit_pressed():
61 get_tree().change_scene_to_file(\"res://objects/scenes/menus/main_menu.tscn\")
62
63"
64
65[node name="Node2D" type="Node2D"]
66script = SubResource( 2 )
31 67
32[node name="Panel" type="Panel" parent="."] 68[node name="Panel" type="Panel" parent="."]
69anchors_preset = -1
33offset_right = 1920.0 70offset_right = 1920.0
34offset_bottom = 1080.0 71offset_bottom = 1080.0
35 72
36[node name="title" parent="Panel" type="Label"] 73[node name="Label" type="Label" parent="Panel"]
37offset_left = 0.0 74layout_mode = 1
75anchors_preset = -1
38offset_top = 75.0 76offset_top = 75.0
39offset_right = 1920.0 77offset_right = 1920.0
40offset_bottom = 225.0 78offset_bottom = 225.0
41text = "ARCHIPELAGO" 79theme = ExtResource("1_mw3f1")
42valign = 1 80text = "archipelago"
43theme = ExtResource("2_g4bvn") 81horizontal_alignment = 1
44 82vertical_alignment = 1
45[node name="credit" parent="Panel" type="Label"] 83
46visible = false 84[node name="Label2" type="Label" parent="Panel"]
47offset_left = 1278.0 85layout_mode = 1
48offset_top = 974.0 86anchors_preset = -1
49offset_right = 1868.0 87anchor_right = 1.0
50offset_bottom = 1034.0 88offset_left = 80.0
51text = "Brenton Wildes" 89offset_top = 300.0
52theme = ExtResource("2_g4bvn") 90offset_right = -80.0
53 91offset_bottom = 388.0
54[node name="connect_button" parent="Panel" type="Button"] 92theme = ExtResource("1_mw3f1")
93theme_override_font_sizes/font_size = 56
94text = "Put the path to your lingo2.apworld in the below field and click start. Then, open the archipelago launcher and click \"Lingo 2 Client\"."
95horizontal_alignment = 1
96autowrap_mode = 3
97
98[node name="HBoxContainer" type="HBoxContainer" parent="Panel"]
99layout_mode = 1
100anchors_preset = -1
101anchor_right = 1.0
102offset_left = 80.0
103offset_top = 595.0
104offset_right = -80.0
105offset_bottom = 755.0
106theme_override_constants/separation = 32
107
108[node name="LineEdit" type="LineEdit" parent="Panel/HBoxContainer"]
109layout_mode = 2
110size_flags_horizontal = 3
111
112[node name="Button" type="Button" parent="Panel/HBoxContainer"]
113layout_mode = 2
114theme = ExtResource("1_mw3f1")
115text = "browse"
116
117[node name="StartButton" type="Button" parent="Panel"]
118layout_mode = 1
119anchors_preset = -1
55offset_left = 255.0 120offset_left = 255.0
56offset_top = 875.0 121offset_top = 875.0
57offset_right = 891.0 122offset_right = 891.0
58offset_bottom = 1025.0 123offset_bottom = 1025.0
59custom_colors/font_color_hover = Color( 1, 0.501961, 0, 1 ) 124theme = ExtResource("1_mw3f1")
60text = "CONNECT" 125text = "start"
61theme = ExtResource("2_g4bvn")
62script = ExtResource( 4 )
63 126
64[node name="quit_button" parent="Panel" type="Button"] 127[node name="QuitButton" type="Button" parent="Panel"]
128layout_mode = 1
129anchors_preset = -1
65offset_left = 1102.0 130offset_left = 1102.0
66offset_top = 875.0 131offset_top = 875.0
67offset_right = 1738.0 132offset_right = 1738.0
68offset_bottom = 1025.0 133offset_bottom = 1025.0
69custom_colors/font_color_hover = Color( 1, 0, 0, 1 ) 134theme = ExtResource("1_mw3f1")
70text = "BACK" 135text = "back"
71theme = ExtResource("2_g4bvn") 136
72script = ExtResource( 4 ) 137[node name="FileDialog" type="FileDialog" parent="."]
73 138title = "Open a File"
74[node name="credit2" parent="Panel" type="Label"] 139size = Vector2i(512, 512)
75offset_left = -105.0 140ok_button_text = "Open"
76offset_top = 346.0 141file_mode = 0
77offset_right = 485.0 142access = 2
78offset_bottom = 410.0 143filters = PackedStringArray("*.apworld;Archipelago Worlds")
79custom_styles/normal = SubResource( 1 ) 144show_hidden_files = true
80text = "SERVER" 145use_native_dialog = true
81align = 2 146
82theme = ExtResource("2_g4bvn") 147[node name="AcceptDialog" type="AcceptDialog" parent="."]
83 148dialog_text = "Could not open Lingo 2 apworld. Please check that the path is correct."
84[node name="credit5" parent="Panel" type="Label"] 149
85offset_left = 1239.0 150[connection signal="pressed" from="Panel/HBoxContainer/Button" to="." method="_browse_pressed"]
86offset_top = 422.0 151[connection signal="pressed" from="Panel/StartButton" to="." method="_start_pressed"]
87offset_right = 1829.0 152[connection signal="pressed" from="Panel/QuitButton" to="." method="_quit_pressed"]
88offset_bottom = 486.0 153[connection signal="file_selected" from="FileDialog" to="." method="_file_selected"]
89custom_styles/normal = SubResource( 1 )
90text = "OPTIONS"
91theme = ExtResource("2_g4bvn")
92
93[node name="credit3" parent="Panel" type="Label"]
94offset_left = -105.0
95offset_top = 519.0
96offset_right = 485.0
97offset_bottom = 583.0
98custom_styles/normal = SubResource( 1 )
99text = "PLAYER"
100align = 2
101theme = ExtResource("2_g4bvn")
102
103[node name="credit4" parent="Panel" type="Label"]
104offset_left = -105.0
105offset_top = 704.0
106offset_right = 485.0
107offset_bottom = 768.0
108custom_styles/normal = SubResource( 1 )
109text = "PASSWORD"
110align = 2
111theme = ExtResource("2_g4bvn")
112
113[node name="server_box" type="LineEdit" parent="Panel"]
114offset_left = 502.0
115offset_top = 295.0
116offset_right = 1144.0
117offset_bottom = 445.0
118custom_colors/selection_color = Color( 0.482353, 0, 0, 1 )
119custom_colors/cursor_color = Color( 0, 0, 0, 1 )
120custom_colors/font_color = Color( 0, 0, 0, 1 )
121custom_styles/focus = SubResource( 2 )
122align = 1
123caret_blink = true
124
125[node name="player_box" type="LineEdit" parent="Panel"]
126offset_left = 502.0
127offset_top = 477.0
128offset_right = 1144.0
129offset_bottom = 627.0
130custom_colors/selection_color = Color( 0.482353, 0, 0, 1 )
131custom_colors/cursor_color = Color( 0, 0, 0, 1 )
132custom_colors/font_color = Color( 0, 0, 0, 1 )
133custom_styles/focus = SubResource( 2 )
134align = 1
135caret_blink = true
136
137[node name="password_box" type="LineEdit" parent="Panel"]
138offset_left = 502.0
139offset_top = 659.0
140offset_right = 1144.0
141offset_bottom = 809.0
142custom_colors/selection_color = Color( 0.482353, 0, 0, 1 )
143custom_colors/cursor_color = Color( 0, 0, 0, 1 )
144custom_colors/font_color = Color( 0, 0, 0, 1 )
145custom_styles/focus = SubResource( 2 )
146align = 1
147caret_blink = true
148
149[node name="AcceptDialog" type="AcceptDialog" parent="Panel"]
150offset_right = 83.0
151offset_bottom = 58.0
152
153[node name="connection_history" type="MenuButton" parent="Panel"]
154offset_left = 1239.0
155offset_top = 276.0
156offset_right = 1829.0
157offset_bottom = 372.0
158text = "connection history"
159flat = false
160
161[connection signal="pressed" from="Panel/connect_button" to="Panel/connect_button" method="_connect_pressed"]
162[connection signal="pressed" from="Panel/quit_button" to="Panel/quit_button" method="_back_pressed"]