From 2c6777b5004dcf27b603ec2b3a9545642ed908bd Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Tue, 9 Sep 2025 16:47:05 -0400 Subject: [Client] Handle symbol shuffle --- client/Archipelago/gamedata.gd | 47 ++++++++++++++++ client/Archipelago/manager.gd | 7 +++ client/Archipelago/panel.gd | 101 ++++++++++++++++++++++++++++++++++ client/Archipelago/player.gd | 2 + client/Archipelago/settings_screen.gd | 2 + 5 files changed, 159 insertions(+) create mode 100644 client/Archipelago/panel.gd diff --git a/client/Archipelago/gamedata.gd b/client/Archipelago/gamedata.gd index f7a5d90..d8d16ed 100644 --- a/client/Archipelago/gamedata.gd +++ b/client/Archipelago/gamedata.gd @@ -5,15 +5,41 @@ var SCRIPT_proto var objects var door_id_by_map_node_path = {} var painting_id_by_map_node_path = {} +var panel_id_by_map_node_path = {} var door_id_by_ap_id = {} var map_id_by_name = {} var progressive_id_by_ap_id = {} var letter_id_by_ap_id = {} +var symbol_item_ids = [] + +var kSYMBOL_ITEMS func _init(proto_script): SCRIPT_proto = proto_script + kSYMBOL_ITEMS = { + SCRIPT_proto.PuzzleSymbol.SUN: "Sun Symbol", + SCRIPT_proto.PuzzleSymbol.SPARKLES: "Sparkles Symbol", + SCRIPT_proto.PuzzleSymbol.ZERO: "Zero Symbol", + SCRIPT_proto.PuzzleSymbol.EXAMPLE: "Example Symbol", + SCRIPT_proto.PuzzleSymbol.BOXES: "Boxes Symbol", + SCRIPT_proto.PuzzleSymbol.PLANET: "Planet Symbol", + SCRIPT_proto.PuzzleSymbol.PYRAMID: "Pyramid Symbol", + SCRIPT_proto.PuzzleSymbol.CROSS: "Cross Symbol", + SCRIPT_proto.PuzzleSymbol.SWEET: "Sweet Symbol", + SCRIPT_proto.PuzzleSymbol.GENDER: "Gender Symbol", + SCRIPT_proto.PuzzleSymbol.AGE: "Age Symbol", + SCRIPT_proto.PuzzleSymbol.SOUND: "Sound Symbol", + SCRIPT_proto.PuzzleSymbol.ANAGRAM: "Anagram Symbol", + SCRIPT_proto.PuzzleSymbol.JOB: "Job Symbol", + SCRIPT_proto.PuzzleSymbol.STARS: "Stars Symbol", + SCRIPT_proto.PuzzleSymbol.NULL: "Null Symbol", + SCRIPT_proto.PuzzleSymbol.EVAL: "Eval Symbol", + SCRIPT_proto.PuzzleSymbol.LINGO: "Lingo Symbol", + SCRIPT_proto.PuzzleSymbol.QUESTION: "Question Symbol", + } + func load(data_bytes): objects = SCRIPT_proto.AllObjects.new() @@ -58,6 +84,19 @@ func load(data_bytes): for letter in objects.get_letters(): letter_id_by_ap_id[letter.get_ap_id()] = letter.get_id() + for panel in objects.get_panels(): + var room = objects.get_rooms()[panel.get_room_id()] + var map = objects.get_maps()[room.get_map_id()] + + if not map.get_name() in panel_id_by_map_node_path: + panel_id_by_map_node_path[map.get_name()] = {} + + var map_data = panel_id_by_map_node_path[map.get_name()] + map_data[panel.get_path()] = panel.get_id() + + for symbol_name in kSYMBOL_ITEMS.values(): + symbol_item_ids.append(objects.get_special_ids()[symbol_name]) + func get_door_for_map_node_path(map_name, node_path): if not door_id_by_map_node_path.has(map_name): @@ -67,6 +106,14 @@ func get_door_for_map_node_path(map_name, node_path): return map_data.get(node_path, null) +func get_panel_for_map_node_path(map_name, node_path): + if not panel_id_by_map_node_path.has(map_name): + return null + + var map_data = panel_id_by_map_node_path[map_name] + return map_data.get(node_path, null) + + func get_door_ap_id(door_id): var door = objects.get_doors()[door_id] if door.has_ap_id(): diff --git a/client/Archipelago/manager.gd b/client/Archipelago/manager.gd index cd0654f..336f154 100644 --- a/client/Archipelago/manager.gd +++ b/client/Archipelago/manager.gd @@ -47,6 +47,7 @@ var keyholder_sanity = false var shuffle_control_center_colors = false var shuffle_doors = false var shuffle_letters = kSHUFFLE_LETTERS_VANILLA +var shuffle_symbols = false var victory_condition = -1 signal could_not_connect @@ -183,6 +184,11 @@ func _process_item(item, index, from, flags, amount): 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 @@ -356,6 +362,7 @@ func _client_connected(slot_data): shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false)) shuffle_doors = bool(slot_data.get("shuffle_doors", false)) shuffle_letters = int(slot_data.get("shuffle_letters", 0)) + shuffle_symbols = bool(slot_data.get("shuffle_symbols", false)) victory_condition = int(slot_data.get("victory_condition", 0)) # Set up item locks. diff --git a/client/Archipelago/panel.gd b/client/Archipelago/panel.gd new file mode 100644 index 0000000..fdaaf0e --- /dev/null +++ b/client/Archipelago/panel.gd @@ -0,0 +1,101 @@ +extends "res://scripts/nodes/panel.gd" + +var panel_logic = null +var symbol_solvable = true + +var black = load("res://assets/materials/black.material") + + +func _ready(): + super._ready() + + var node_path = String( + get_tree().get_root().get_node("scene").get_path_to(self).get_concatenated_names() + ) + + var gamedata = global.get_node("Gamedata") + var panel_id = gamedata.get_panel_for_map_node_path(global.map, node_path) + if panel_id != null: + var ap = global.get_node("Archipelago") + if ap.shuffle_symbols: + if global.map == "the_entry" and node_path == "Panels/Entry/front_1": + clue = "i" + symbol = "" + + setField("clue", clue) + setField("symbol", symbol) + + panel_logic = gamedata.objects.get_panels()[panel_id] + checkSymbolSolvable() + + if not symbol_solvable: + get_tree().get_root().get_node("scene/player").connect( + "evaluate_solvability", evaluateSolvability + ) + + +func checkSymbolSolvable(): + var old_solvable = symbol_solvable + symbol_solvable = true + + if panel_logic == null: + # There's no logic for this panel. + return + + var ap = global.get_node("Archipelago") + if not ap.shuffle_symbols: + # Symbols aren't item-locked. + return + + var gamedata = global.get_node("Gamedata") + for symbol in panel_logic.get_symbols(): + var item_name = gamedata.kSYMBOL_ITEMS.get(symbol) + var item_id = gamedata.objects.get_special_ids()[item_name] + if ap.client.getItemAmount(item_id) < 1: + symbol_solvable = false + break + + if symbol_solvable != old_solvable: + if symbol_solvable: + setField("clue", clue) + setField("symbol", symbol) + setField("answer", answer) + else: + quad_mesh.surface_set_material(0, black) + get_node("Hinge/clue").text = "missing" + get_node("Hinge/answer").text = "symbols" + + +func checkSolvable(key): + checkSymbolSolvable() + if not symbol_solvable: + return false + + return super.checkSolvable(key) + + +func evaluateSolvability(): + checkSolvable("") + + +func passedInput(key, skip_focus_check = false): + if not symbol_solvable: + return + + super.passedInput(key, skip_focus_check) + + +func focus(): + if not symbol_solvable: + has_focus = false + return + + super.focus() + + +func unfocus(): + if not symbol_solvable: + has_focus = false + return + + super.unfocus() diff --git a/client/Archipelago/player.gd b/client/Archipelago/player.gd index 866d32b..4b995bc 100644 --- a/client/Archipelago/player.gd +++ b/client/Archipelago/player.gd @@ -16,6 +16,8 @@ const kEndingNameByVictoryValue = { 12: "WHITE", } +signal evaluate_solvability + func _ready(): var khl_script = load("res://scripts/nodes/keyHolderListener.gd") diff --git a/client/Archipelago/settings_screen.gd b/client/Archipelago/settings_screen.gd index aaaf72a..f5f994b 100644 --- a/client/Archipelago/settings_screen.gd +++ b/client/Archipelago/settings_screen.gd @@ -40,6 +40,7 @@ func _ready(): ResourceLoader.load("user://maps/Archipelago/keyHolderResetterListener.gd") ) installScriptExtension(ResourceLoader.load("user://maps/Archipelago/painting.gd")) + installScriptExtension(ResourceLoader.load("user://maps/Archipelago/panel.gd")) installScriptExtension(ResourceLoader.load("user://maps/Archipelago/pauseMenu.gd")) installScriptExtension(ResourceLoader.load("user://maps/Archipelago/player.gd")) installScriptExtension(ResourceLoader.load("user://maps/Archipelago/saver.gd")) @@ -159,6 +160,7 @@ func connectionSuccessful(): clearResourceCache("res://objects/nodes/listeners/keyHolderResetterListener.tscn") clearResourceCache("res://objects/nodes/listeners/teleportListener.tscn") clearResourceCache("res://objects/nodes/listeners/worldportListener.tscn") + clearResourceCache("res://objects/nodes/panel.tscn") clearResourceCache("res://objects/nodes/player.tscn") clearResourceCache("res://objects/nodes/saver.tscn") clearResourceCache("res://objects/scenes/menus/pause_menu.tscn") -- cgit 1.4.1