about summary refs log tree commit diff stats
path: root/client/Archipelago/manager.gd
diff options
context:
space:
mode:
Diffstat (limited to 'client/Archipelago/manager.gd')
-rw-r--r--client/Archipelago/manager.gd473
1 files changed, 0 insertions, 473 deletions
diff --git a/client/Archipelago/manager.gd b/client/Archipelago/manager.gd deleted file mode 100644 index 72abf34..0000000 --- a/client/Archipelago/manager.gd +++ /dev/null
@@ -1,473 +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 _held_letters = {}
27var _letters_setup = false
28
29const kSHUFFLE_LETTERS_VANILLA = 0
30const kSHUFFLE_LETTERS_UNLOCKED = 1
31const kSHUFFLE_LETTERS_PROGRESSIVE = 2
32const kSHUFFLE_LETTERS_VANILLA_CYAN = 3
33const kSHUFFLE_LETTERS_ITEM_CYAN = 4
34
35const kLETTER_BEHAVIOR_VANILLA = 0
36const kLETTER_BEHAVIOR_ITEM = 1
37const kLETTER_BEHAVIOR_UNLOCKED = 2
38
39var daedalus_roof_access = false
40var keyholder_sanity = false
41var shuffle_control_center_colors = false
42var shuffle_doors = false
43var shuffle_letters = kSHUFFLE_LETTERS_VANILLA
44var victory_condition = -1
45
46signal could_not_connect
47signal connect_status
48signal ap_connected
49
50
51func _init():
52 # Read AP settings from file, if there are any
53 if FileAccess.file_exists("user://ap_settings"):
54 var file = FileAccess.open("user://ap_settings", FileAccess.READ)
55 var data = file.get_var(true)
56 file.close()
57
58 if typeof(data) != TYPE_ARRAY:
59 global._print("AP settings file is corrupted")
60 data = []
61
62 if data.size() > 0:
63 ap_server = data[0]
64
65 if data.size() > 1:
66 ap_user = data[1]
67
68 if data.size() > 2:
69 ap_pass = data[2]
70
71 if data.size() > 3:
72 connection_history = data[3]
73
74
75func _ready():
76 client = SCRIPT_client.new()
77 client.SCRIPT_uuid = SCRIPT_uuid
78
79 client.connect("item_received", _process_item)
80 client.connect("message_received", _process_message)
81 client.connect("location_scout_received", _process_location_scout)
82 client.connect("could_not_connect", _client_could_not_connect)
83 client.connect("connect_status", _client_connect_status)
84 client.connect("client_connected", _client_connected)
85
86 add_child(client)
87
88 keyboard = SCRIPT_keyboard.new()
89 add_child(keyboard)
90
91
92func saveSettings():
93 # Save the AP settings to disk.
94 var path = "user://ap_settings"
95 var file = FileAccess.open(path, FileAccess.WRITE)
96
97 var data = [
98 ap_server,
99 ap_user,
100 ap_pass,
101 connection_history,
102 ]
103 file.store_var(data, true)
104 file.close()
105
106
107func saveLocaldata():
108 # Save the MW/slot specific settings to disk.
109 var dir = DirAccess.open("user://")
110 var folder = "archipelago_data"
111 if not dir.dir_exists(folder):
112 dir.make_dir(folder)
113
114 var file = FileAccess.open(_localdata_file, FileAccess.WRITE)
115
116 var data = [
117 _last_new_item,
118 ]
119 file.store_var(data, true)
120 file.close()
121
122
123func connectToServer():
124 _last_new_item = -1
125 _letters_setup = false
126 _held_letters = {}
127
128 client.connectToServer(ap_server, ap_user, ap_pass)
129
130
131func getSaveFileName():
132 return "zzAP_%s_%d" % [client._seed, client._slot]
133
134
135func disconnect_from_ap():
136 client.disconnect_from_ap()
137
138
139func get_item_id_for_door(door_id):
140 return _item_locks.get(door_id, null)
141
142
143func _process_item(item, index, from, flags, amount):
144 var item_name = "Unknown"
145 if client._item_id_to_name["Lingo 2"].has(item):
146 item_name = client._item_id_to_name["Lingo 2"][item]
147
148 var gamedata = global.get_node("Gamedata")
149 var door_id = gamedata.door_id_by_ap_id.get(item, null)
150 var prog_id = null
151
152 if door_id == null:
153 prog_id = gamedata.progressive_id_by_ap_id.get(item, null)
154 if prog_id != null:
155 var progressive = gamedata.objects.get_progressives()[prog_id]
156 if progressive.get_doors().size() >= amount:
157 door_id = progressive.get_doors()[amount - 1]
158
159 if door_id != null and gamedata.get_door_map_name(door_id) == global.map:
160 var receivers = gamedata.get_door_receivers(door_id)
161 var scene = get_tree().get_root().get_node_or_null("scene")
162 if scene != null:
163 for receiver in receivers:
164 var rnode = scene.get_node_or_null(receiver)
165 if rnode != null:
166 rnode.handleTriggered()
167
168 var letter_id = gamedata.letter_id_by_ap_id.get(item, null)
169 if letter_id != null:
170 var letter = gamedata.objects.get_letters()[letter_id]
171 if not letter.has_level2() or not letter.get_level2():
172 _process_key_item(letter.get_key(), amount)
173
174 # Show a message about the item if it's new.
175 if index != null and index > _last_new_item:
176 _last_new_item = index
177 saveLocaldata()
178
179 var player_name = "Unknown"
180 if client._player_name_by_slot.has(float(from)):
181 player_name = client._player_name_by_slot[float(from)]
182
183 var item_color = colorForItemType(flags)
184
185 var full_item_name = item_name
186 if prog_id != null and door_id != null:
187 var door = gamedata.objects.get_doors()[door_id]
188 full_item_name = "%s (%s)" % [item_name, door.get_name()]
189
190 var message
191 if from == client._slot:
192 message = "Found [color=%s]%s[/color]" % [item_color, full_item_name]
193 else:
194 message = (
195 "Received [color=%s]%s[/color] from %s" % [item_color, full_item_name, player_name]
196 )
197
198 global._print(message)
199
200 global.get_node("Messages").showMessage(message)
201
202
203func _process_message(message):
204 parse_printjson_for_textclient(message)
205
206 if (
207 !message.has("receiving")
208 or !message.has("item")
209 or message["item"]["player"] != client._slot
210 ):
211 return
212
213 var item_name = "Unknown"
214 var item_player_game = client._game_by_player[message["receiving"]]
215 if client._item_id_to_name[item_player_game].has(int(message["item"]["item"])):
216 item_name = client._item_id_to_name[item_player_game][int(message["item"]["item"])]
217
218 var location_name = "Unknown"
219 var location_player_game = client._game_by_player[message["item"]["player"]]
220 if client._location_id_to_name[location_player_game].has(int(message["item"]["location"])):
221 location_name = (client._location_id_to_name[location_player_game][int(
222 message["item"]["location"]
223 )])
224
225 var player_name = "Unknown"
226 if client._player_name_by_slot.has(message["receiving"]):
227 player_name = client._player_name_by_slot[message["receiving"]]
228
229 var item_color = colorForItemType(message["item"]["flags"])
230
231 if message["type"] == "Hint":
232 var is_for = ""
233 if message["receiving"] != client._slot:
234 is_for = " for %s" % player_name
235 if !message.has("found") || !message["found"]:
236 global.get_node("Messages").showMessage(
237 (
238 "Hint: [color=%s]%s[/color]%s is on %s"
239 % [item_color, item_name, is_for, location_name]
240 )
241 )
242 else:
243 if message["receiving"] != client._slot:
244 var sentMsg = "Sent [color=%s]%s[/color] to %s" % [item_color, item_name, player_name]
245 #if _hinted_locations.has(message["item"]["location"]):
246 # sentMsg += " ([color=#fafad2]Hinted![/color])"
247 global.get_node("Messages").showMessage(sentMsg)
248
249
250func parse_printjson_for_textclient(message):
251 var parts = []
252 for message_part in message["data"]:
253 if !message_part.has("type") and message_part.has("text"):
254 parts.append(message_part["text"])
255 elif message_part["type"] == "player_id":
256 if int(message_part["text"]) == client._slot:
257 parts.append(
258 "[color=#ee00ee]%s[/color]" % client._player_name_by_slot[client._slot]
259 )
260 else:
261 var from = float(message_part["text"])
262 parts.append("[color=#fafad2]%s[/color]" % client._player_name_by_slot[from])
263 elif message_part["type"] == "item_id":
264 var item_name = "Unknown"
265 var item_player_game = client._game_by_player[message_part["player"]]
266 if client._item_id_to_name[item_player_game].has(int(message_part["text"])):
267 item_name = client._item_id_to_name[item_player_game][int(message_part["text"])]
268
269 parts.append(
270 "[color=%s]%s[/color]" % [colorForItemType(message_part["flags"]), item_name]
271 )
272 elif message_part["type"] == "location_id":
273 var location_name = "Unknown"
274 var location_player_game = client._game_by_player[message_part["player"]]
275 if client._location_id_to_name[location_player_game].has(int(message_part["text"])):
276 location_name = client._location_id_to_name[location_player_game][int(
277 message_part["text"]
278 )]
279
280 parts.append("[color=#00ff7f]%s[/color]" % location_name)
281 elif message_part.has("text"):
282 parts.append(message_part["text"])
283
284 var textclient_node = global.get_node("Textclient")
285 if textclient_node != null:
286 textclient_node.parse_printjson("".join(parts))
287
288
289func _process_location_scout(item_id, location_id, player, flags):
290 _location_scouts[location_id] = {"item": item_id, "player": player, "flags": flags}
291
292 var gamedata = global.get_node("Gamedata")
293 var map_id = gamedata.map_id_by_name.get(global.map)
294
295 var item_name = "Unknown"
296 var item_player_game = client._game_by_player[float(player)]
297 if client._item_id_to_name[item_player_game].has(item_id):
298 item_name = client._item_id_to_name[item_player_game][item_id]
299
300 var letter_id = gamedata.letter_id_by_ap_id.get(location_id, null)
301 if letter_id != null:
302 var letter = gamedata.objects.get_letters()[letter_id]
303 var room = gamedata.objects.get_rooms()[letter.get_room_id()]
304 if room.get_map_id() == map_id:
305 var collectable = get_tree().get_root().get_node("scene").get_node_or_null(
306 letter.get_path()
307 )
308 if collectable != null:
309 collectable.setScoutedText(item_name)
310
311
312func _client_could_not_connect():
313 emit_signal("could_not_connect")
314
315
316func _client_connect_status(message):
317 emit_signal("connect_status", message)
318
319
320func _client_connected(slot_data):
321 var gamedata = global.get_node("Gamedata")
322
323 _localdata_file = "user://archipelago_data/%s_%d" % [client._seed, client._slot]
324 _last_new_item = -1
325
326 if FileAccess.file_exists(_localdata_file):
327 var ap_file = FileAccess.open(_localdata_file, FileAccess.READ)
328 var localdata = []
329 if ap_file != null:
330 localdata = ap_file.get_var(true)
331 ap_file.close()
332
333 if typeof(localdata) != TYPE_ARRAY:
334 print("AP localdata file is corrupted")
335 localdata = []
336
337 if localdata.size() > 0:
338 _last_new_item = localdata[0]
339
340 # Read slot data.
341 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false))
342 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false))
343 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false))
344 shuffle_doors = bool(slot_data.get("shuffle_doors", false))
345 shuffle_letters = int(slot_data.get("shuffle_letters", 0))
346 victory_condition = int(slot_data.get("victory_condition", 0))
347
348 # Set up item locks.
349 _item_locks = {}
350
351 if shuffle_doors:
352 for door in gamedata.objects.get_doors():
353 if (
354 door.get_type() == gamedata.SCRIPT_proto.DoorType.STANDARD
355 or door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY
356 ):
357 _item_locks[door.get_id()] = [door.get_ap_id(), 1]
358
359 for progressive in gamedata.objects.get_progressives():
360 for i in range(0, progressive.get_doors().size()):
361 var door = gamedata.objects.get_doors()[progressive.get_doors()[i]]
362 _item_locks[door.get_id()] = [progressive.get_ap_id(), i + 1]
363
364 for door_group in gamedata.objects.get_door_groups():
365 if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.CONNECTOR:
366 for door in door_group.get_doors():
367 _item_locks[door] = [door_group.get_ap_id(), 1]
368
369 if shuffle_control_center_colors:
370 for door in gamedata.objects.get_doors():
371 if door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR:
372 _item_locks[door.get_id()] = [door.get_ap_id(), 1]
373
374 for door_group in gamedata.objects.get_door_groups():
375 if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.COLOR_CONNECTOR:
376 for door in door_group.get_doors():
377 _item_locks[door] = [door_group.get_ap_id(), 1]
378
379 emit_signal("ap_connected")
380
381
382func start_batching_locations():
383 _batch_locations = true
384
385
386func send_location(loc_id):
387 if _batch_locations:
388 _held_locations.append(loc_id)
389 else:
390 client.sendLocation(loc_id)
391
392
393func scout_location(loc_id):
394 if _location_scouts.has(loc_id):
395 return _location_scouts.get(loc_id)
396
397 if _batch_locations:
398 _held_location_scouts.append(loc_id)
399 else:
400 client.scoutLocation(loc_id)
401
402 return null
403
404
405func stop_batching_locations():
406 _batch_locations = false
407
408 if not _held_locations.is_empty():
409 client.sendLocations(_held_locations)
410 _held_locations.clear()
411
412 if not _held_location_scouts.is_empty():
413 client.scoutLocations(_held_location_scouts)
414 _held_location_scouts.clear()
415
416
417func colorForItemType(flags):
418 var int_flags = int(flags)
419 if int_flags & 1: # progression
420 if int_flags & 2: # proguseful
421 return "#f0d200"
422 else:
423 return "#bc51e0"
424 elif int_flags & 2: # useful
425 return "#2b67ff"
426 elif int_flags & 4: # trap
427 return "#d63a22"
428 else: # filler
429 return "#14de9e"
430
431
432func get_letter_behavior(key, level2):
433 if shuffle_letters == kSHUFFLE_LETTERS_UNLOCKED:
434 return kLETTER_BEHAVIOR_UNLOCKED
435
436 if [kSHUFFLE_LETTERS_VANILLA_CYAN, kSHUFFLE_LETTERS_ITEM_CYAN].has(shuffle_letters):
437 if level2:
438 if shuffle_letters == kSHUFFLE_LETTERS_VANILLA_CYAN:
439 return kLETTER_BEHAVIOR_VANILLA
440 else:
441 return kLETTER_BEHAVIOR_ITEM
442 else:
443 return kLETTER_BEHAVIOR_UNLOCKED
444
445 if not level2 and ["h", "i", "n", "t"].has(key):
446 # This differs from the equivalent function in the apworld. Logically it is
447 # the same as UNLOCKED since they are in the starting room, but VANILLA
448 # means the player still has to actually pick up the letters.
449 return kLETTER_BEHAVIOR_VANILLA
450
451 if shuffle_letters == kSHUFFLE_LETTERS_PROGRESSIVE:
452 return kLETTER_BEHAVIOR_ITEM
453
454 return kLETTER_BEHAVIOR_VANILLA
455
456
457func setup_keys():
458 keyboard.load_seed()
459
460 _letters_setup = true
461
462 for k in _held_letters.keys():
463 _process_key_item(k, _held_letters[k])
464
465 _held_letters.clear()
466
467
468func _process_key_item(key, level):
469 if not _letters_setup:
470 _held_letters[key] = max(_held_letters.get(key, 0), level)
471 return
472
473 keyboard.collect_remote_letter(key, level)