From 3f53502a5907ed1982d28a392c54331f0c1c2c42 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Thu, 25 Sep 2025 12:09:50 -0400 Subject: Move the client into the apworld Only works on source right now, not as an apworld. --- client/Archipelago/manager.gd | 571 ------------------------------------------ 1 file changed, 571 deletions(-) delete mode 100644 client/Archipelago/manager.gd (limited to 'client/Archipelago/manager.gd') diff --git a/client/Archipelago/manager.gd b/client/Archipelago/manager.gd deleted file mode 100644 index b170c77..0000000 --- a/client/Archipelago/manager.gd +++ /dev/null @@ -1,571 +0,0 @@ -extends Node - -const MOD_VERSION = 7 - -var SCRIPT_client -var SCRIPT_keyboard -var SCRIPT_locationListener -var SCRIPT_minimap -var SCRIPT_uuid -var SCRIPT_victoryListener - -var ap_server = "" -var ap_user = "" -var ap_pass = "" -var connection_history = [] -var show_compass = false - -var client -var keyboard - -var _localdata_file = "" -var _last_new_item = -1 -var _batch_locations = false -var _held_locations = [] -var _held_location_scouts = [] -var _location_scouts = {} -var _item_locks = {} -var _inverse_item_locks = {} -var _held_letters = {} -var _letters_setup = false - -const kSHUFFLE_LETTERS_VANILLA = 0 -const kSHUFFLE_LETTERS_UNLOCKED = 1 -const kSHUFFLE_LETTERS_PROGRESSIVE = 2 -const kSHUFFLE_LETTERS_VANILLA_CYAN = 3 -const kSHUFFLE_LETTERS_ITEM_CYAN = 4 - -const kLETTER_BEHAVIOR_VANILLA = 0 -const kLETTER_BEHAVIOR_ITEM = 1 -const kLETTER_BEHAVIOR_UNLOCKED = 2 - -const kCYAN_DOOR_BEHAVIOR_H2 = 0 -const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 -const kCYAN_DOOR_BEHAVIOR_ITEM = 2 - -var apworld_version = [0, 0] -var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 -var daedalus_roof_access = false -var keyholder_sanity = false -var port_pairings = {} -var shuffle_control_center_colors = false -var shuffle_doors = false -var shuffle_gallery_paintings = false -var shuffle_letters = kSHUFFLE_LETTERS_VANILLA -var shuffle_symbols = false -var shuffle_worldports = false -var strict_cyan_ending = false -var strict_purple_ending = false -var victory_condition = -1 - -signal could_not_connect -signal connect_status -signal ap_connected - - -func _init(): - # Read AP settings from file, if there are any - if FileAccess.file_exists("user://ap_settings"): - var file = FileAccess.open("user://ap_settings", FileAccess.READ) - var data = file.get_var(true) - file.close() - - if typeof(data) != TYPE_ARRAY: - global._print("AP settings file is corrupted") - data = [] - - if data.size() > 0: - ap_server = data[0] - - if data.size() > 1: - ap_user = data[1] - - if data.size() > 2: - ap_pass = data[2] - - if data.size() > 3: - connection_history = data[3] - - if data.size() > 4: - show_compass = data[4] - - -func _ready(): - client = SCRIPT_client.new() - client.SCRIPT_uuid = SCRIPT_uuid - - client.connect("item_received", _process_item) - client.connect("message_received", _process_message) - client.connect("location_scout_received", _process_location_scout) - client.connect("could_not_connect", _client_could_not_connect) - client.connect("connect_status", _client_connect_status) - client.connect("client_connected", _client_connected) - - add_child(client) - - keyboard = SCRIPT_keyboard.new() - add_child(keyboard) - - -func saveSettings(): - # Save the AP settings to disk. - var path = "user://ap_settings" - var file = FileAccess.open(path, FileAccess.WRITE) - - var data = [ - ap_server, - ap_user, - ap_pass, - connection_history, - show_compass, - ] - file.store_var(data, true) - file.close() - - -func saveLocaldata(): - # Save the MW/slot specific settings to disk. - var dir = DirAccess.open("user://") - var folder = "archipelago_data" - if not dir.dir_exists(folder): - dir.make_dir(folder) - - var file = FileAccess.open(_localdata_file, FileAccess.WRITE) - - var data = [ - _last_new_item, - ] - file.store_var(data, true) - file.close() - - -func connectToServer(): - _last_new_item = -1 - _batch_locations = false - _held_locations = [] - _held_location_scouts = [] - _location_scouts = {} - _letters_setup = false - _held_letters = {} - - client.connectToServer(ap_server, ap_user, ap_pass) - - -func getSaveFileName(): - return "zzAP_%s_%d" % [client._seed, client._slot] - - -func disconnect_from_ap(): - client.disconnect_from_ap() - - -func get_item_id_for_door(door_id): - return _item_locks.get(door_id, null) - - -func _process_item(item, index, from, flags, amount): - var item_name = "Unknown" - if client._item_id_to_name["Lingo 2"].has(item): - item_name = client._item_id_to_name["Lingo 2"][item] - - var gamedata = global.get_node("Gamedata") - - var prog_id = null - if _inverse_item_locks.has(item): - for lock in _inverse_item_locks.get(item): - if lock[1] != amount: - continue - - if gamedata.progressive_id_by_ap_id.has(item): - prog_id = lock[0] - - if gamedata.get_door_map_name(lock[0]) != global.map: - continue - - var receivers = gamedata.get_door_receivers(lock[0]) - var scene = get_tree().get_root().get_node_or_null("scene") - if scene != null: - for receiver in receivers: - var rnode = scene.get_node_or_null(receiver) - if rnode != null: - rnode.handleTriggered() - - var letter_id = gamedata.letter_id_by_ap_id.get(item, null) - if letter_id != null: - var letter = gamedata.objects.get_letters()[letter_id] - if not letter.has_level2() or not letter.get_level2(): - _process_key_item(letter.get_key(), amount) - - if gamedata.symbol_item_ids.has(item): - var player = get_tree().get_root().get_node_or_null("scene/player") - if player != null: - player.emit_signal("evaluate_solvability") - - # Show a message about the item if it's new. - if index != null and index > _last_new_item: - _last_new_item = index - saveLocaldata() - - var player_name = "Unknown" - if client._player_name_by_slot.has(float(from)): - player_name = client._player_name_by_slot[float(from)] - - var full_item_name = item_name - if prog_id != null: - var door = gamedata.objects.get_doors()[prog_id] - full_item_name = "%s (%s)" % [item_name, door.get_name()] - - var message - if from == client._slot: - message = "Found %s" % wrapInItemColorTags(full_item_name, flags) - else: - message = ( - "Received %s from %s" % [wrapInItemColorTags(full_item_name, flags), player_name] - ) - - if gamedata.anti_trap_ids.has(item): - keyboard.block_letter(gamedata.anti_trap_ids[item]) - - global._print(message) - - global.get_node("Messages").showMessage(message) - - -func _process_message(message): - parse_printjson_for_textclient(message) - - if ( - !message.has("receiving") - or !message.has("item") - or message["item"]["player"] != client._slot - ): - return - - var item_name = "Unknown" - var item_player_game = client._game_by_player[message["receiving"]] - if client._item_id_to_name[item_player_game].has(int(message["item"]["item"])): - item_name = client._item_id_to_name[item_player_game][int(message["item"]["item"])] - - var location_name = "Unknown" - var location_player_game = client._game_by_player[message["item"]["player"]] - if client._location_id_to_name[location_player_game].has(int(message["item"]["location"])): - location_name = (client._location_id_to_name[location_player_game][int( - message["item"]["location"] - )]) - - var player_name = "Unknown" - if client._player_name_by_slot.has(message["receiving"]): - player_name = client._player_name_by_slot[message["receiving"]] - - var item_color = colorForItemType(message["item"]["flags"]) - - if message["type"] == "Hint": - var is_for = "" - if message["receiving"] != client._slot: - is_for = " for %s" % player_name - if !message.has("found") || !message["found"]: - global.get_node("Messages").showMessage( - ( - "Hint: %s%s is on %s" - % [ - wrapInItemColorTags(item_name, message["item"]["flags"]), - is_for, - location_name - ] - ) - ) - else: - if message["receiving"] != client._slot: - var sentMsg = ( - "Sent %s to %s" - % [wrapInItemColorTags(item_name, message["item"]["flags"]), player_name] - ) - #if _hinted_locations.has(message["item"]["location"]): - # sentMsg += " ([color=#fafad2]Hinted![/color])" - global.get_node("Messages").showMessage(sentMsg) - - -func parse_printjson_for_textclient(message): - var parts = [] - for message_part in message["data"]: - if !message_part.has("type") and message_part.has("text"): - parts.append(message_part["text"]) - elif message_part["type"] == "player_id": - if int(message_part["text"]) == client._slot: - parts.append( - "[color=#ee00ee]%s[/color]" % client._player_name_by_slot[client._slot] - ) - else: - var from = float(message_part["text"]) - parts.append("[color=#fafad2]%s[/color]" % client._player_name_by_slot[from]) - elif message_part["type"] == "item_id": - var item_name = "Unknown" - var item_player_game = client._game_by_player[message_part["player"]] - if client._item_id_to_name[item_player_game].has(int(message_part["text"])): - item_name = client._item_id_to_name[item_player_game][int(message_part["text"])] - - parts.append(wrapInItemColorTags(item_name, message_part["flags"])) - elif message_part["type"] == "location_id": - var location_name = "Unknown" - var location_player_game = client._game_by_player[message_part["player"]] - if client._location_id_to_name[location_player_game].has(int(message_part["text"])): - location_name = client._location_id_to_name[location_player_game][int( - message_part["text"] - )] - - parts.append("[color=#00ff7f]%s[/color]" % location_name) - elif message_part.has("text"): - parts.append(message_part["text"]) - - var textclient_node = global.get_node("Textclient") - if textclient_node != null: - textclient_node.parse_printjson("".join(parts)) - - -func _process_location_scout(item_id, location_id, player, flags): - _location_scouts[location_id] = {"item": item_id, "player": player, "flags": flags} - - if player == client._slot and flags & 4 != 0: - # This is a trap for us, so let's not display it. - return - - var gamedata = global.get_node("Gamedata") - var map_id = gamedata.map_id_by_name.get(global.map) - - var item_name = "Unknown" - var item_player_game = client._game_by_player[float(player)] - if client._item_id_to_name[item_player_game].has(item_id): - item_name = client._item_id_to_name[item_player_game][item_id] - - var letter_id = gamedata.letter_id_by_ap_id.get(location_id, null) - if letter_id != null: - var letter = gamedata.objects.get_letters()[letter_id] - var room = gamedata.objects.get_rooms()[letter.get_room_id()] - if room.get_map_id() == map_id: - var collectable = get_tree().get_root().get_node("scene").get_node_or_null( - letter.get_path() - ) - if collectable != null: - collectable.setScoutedText(item_name) - - -func _client_could_not_connect(message): - emit_signal("could_not_connect", message) - - -func _client_connect_status(message): - emit_signal("connect_status", message) - - -func _client_connected(slot_data): - var gamedata = global.get_node("Gamedata") - - _localdata_file = "user://archipelago_data/%s_%d" % [client._seed, client._slot] - _last_new_item = -1 - - if FileAccess.file_exists(_localdata_file): - var ap_file = FileAccess.open(_localdata_file, FileAccess.READ) - var localdata = [] - if ap_file != null: - localdata = ap_file.get_var(true) - ap_file.close() - - if typeof(localdata) != TYPE_ARRAY: - print("AP localdata file is corrupted") - localdata = [] - - if localdata.size() > 0: - _last_new_item = localdata[0] - - # Read slot data. - cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0)) - daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) - keyholder_sanity = bool(slot_data.get("keyholder_sanity", false)) - shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false)) - shuffle_doors = bool(slot_data.get("shuffle_doors", false)) - shuffle_gallery_paintings = bool(slot_data.get("shuffle_gallery_paintings", false)) - shuffle_letters = int(slot_data.get("shuffle_letters", 0)) - shuffle_symbols = bool(slot_data.get("shuffle_symbols", false)) - shuffle_worldports = bool(slot_data.get("shuffle_worldports", false)) - strict_cyan_ending = bool(slot_data.get("strict_cyan_ending", false)) - strict_purple_ending = bool(slot_data.get("strict_purple_ending", false)) - victory_condition = int(slot_data.get("victory_condition", 0)) - - if slot_data.has("version"): - apworld_version = [int(slot_data["version"][0]), int(slot_data["version"][1])] - - port_pairings.clear() - if slot_data.has("port_pairings"): - var raw_pp = slot_data.get("port_pairings") - - for p1 in raw_pp.keys(): - port_pairings[int(p1)] = int(raw_pp[p1]) - - # Set up item locks. - _item_locks = {} - - if shuffle_doors: - for door in gamedata.objects.get_doors(): - if ( - door.get_type() == gamedata.SCRIPT_proto.DoorType.STANDARD - or door.get_type() == gamedata.SCRIPT_proto.DoorType.ITEM_ONLY - ): - _item_locks[door.get_id()] = [door.get_ap_id(), 1] - - for progressive in gamedata.objects.get_progressives(): - for i in range(0, progressive.get_doors().size()): - var door = gamedata.objects.get_doors()[progressive.get_doors()[i]] - _item_locks[door.get_id()] = [progressive.get_ap_id(), i + 1] - - for door_group in gamedata.objects.get_door_groups(): - if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.CONNECTOR: - if shuffle_worldports: - continue - elif door_group.get_type() != gamedata.SCRIPT_proto.DoorGroupType.SHUFFLE_GROUP: - continue - - for door in door_group.get_doors(): - _item_locks[door] = [door_group.get_ap_id(), 1] - - if shuffle_control_center_colors: - for door in gamedata.objects.get_doors(): - if door.get_type() == gamedata.SCRIPT_proto.DoorType.CONTROL_CENTER_COLOR: - _item_locks[door.get_id()] = [door.get_ap_id(), 1] - - for door_group in gamedata.objects.get_door_groups(): - if ( - door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.COLOR_CONNECTOR - and not shuffle_worldports - ): - for door in door_group.get_doors(): - _item_locks[door] = [door_group.get_ap_id(), 1] - - if shuffle_gallery_paintings: - for door in gamedata.objects.get_doors(): - if door.get_type() == gamedata.SCRIPT_proto.DoorType.GALLERY_PAINTING: - _item_locks[door.get_id()] = [door.get_ap_id(), 1] - - if cyan_door_behavior == kCYAN_DOOR_BEHAVIOR_ITEM: - for door_group in gamedata.objects.get_door_groups(): - if door_group.get_type() == gamedata.SCRIPT_proto.DoorGroupType.CYAN_DOORS: - for door in door_group.get_doors(): - if not _item_locks.has(door): - _item_locks[door] = [door_group.get_ap_id(), 1] - - # Create a reverse item locks map for processing items. - _inverse_item_locks = {} - - for door_id in _item_locks.keys(): - var lock = _item_locks.get(door_id) - - if not _inverse_item_locks.has(lock[0]): - _inverse_item_locks[lock[0]] = [] - - _inverse_item_locks[lock[0]].append([door_id, lock[1]]) - - emit_signal("ap_connected") - - -func start_batching_locations(): - _batch_locations = true - - -func send_location(loc_id): - if _batch_locations: - _held_locations.append(loc_id) - else: - client.sendLocation(loc_id) - - -func scout_location(loc_id): - if _location_scouts.has(loc_id): - return _location_scouts.get(loc_id) - - if _batch_locations: - _held_location_scouts.append(loc_id) - else: - client.scoutLocation(loc_id) - - return null - - -func stop_batching_locations(): - _batch_locations = false - - if not _held_locations.is_empty(): - client.sendLocations(_held_locations) - _held_locations.clear() - - if not _held_location_scouts.is_empty(): - client.scoutLocations(_held_location_scouts) - _held_location_scouts.clear() - - -func colorForItemType(flags): - var int_flags = int(flags) - if int_flags & 1: # progression - if int_flags & 2: # proguseful - return "#f0d200" - else: - return "#bc51e0" - elif int_flags & 2: # useful - return "#2b67ff" - elif int_flags & 4: # trap - return "#d63a22" - else: # filler - return "#14de9e" - - -func wrapInItemColorTags(text, flags): - var int_flags = int(flags) - if int_flags & 1 and int_flags & 2: # proguseful - return "[rainbow]%s[/rainbow]" % text - else: - return "[color=%s]%s[/color]" % [colorForItemType(flags), text] - - -func get_letter_behavior(key, level2): - if shuffle_letters == kSHUFFLE_LETTERS_UNLOCKED: - return kLETTER_BEHAVIOR_UNLOCKED - - if [kSHUFFLE_LETTERS_VANILLA_CYAN, kSHUFFLE_LETTERS_ITEM_CYAN].has(shuffle_letters): - if level2: - if shuffle_letters == kSHUFFLE_LETTERS_VANILLA_CYAN: - return kLETTER_BEHAVIOR_VANILLA - else: - return kLETTER_BEHAVIOR_ITEM - else: - return kLETTER_BEHAVIOR_UNLOCKED - - if not level2 and ["h", "i", "n", "t"].has(key): - # This differs from the equivalent function in the apworld. Logically it is - # the same as UNLOCKED since they are in the starting room, but VANILLA - # means the player still has to actually pick up the letters. - return kLETTER_BEHAVIOR_VANILLA - - if shuffle_letters == kSHUFFLE_LETTERS_PROGRESSIVE: - return kLETTER_BEHAVIOR_ITEM - - return kLETTER_BEHAVIOR_VANILLA - - -func setup_keys(): - keyboard.load_seed() - - _letters_setup = true - - for k in _held_letters.keys(): - _process_key_item(k, _held_letters[k]) - - _held_letters.clear() - - -func _process_key_item(key, level): - if not _letters_setup: - _held_letters[key] = max(_held_letters.get(key, 0), level) - return - - if shuffle_letters == kSHUFFLE_LETTERS_ITEM_CYAN: - level += 1 - - keyboard.collect_remote_letter(key, level) -- cgit 1.4.1