From a2abd188f762659c5e7595079d2925bc2869b455 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sat, 7 Feb 2026 07:49:30 -0500 Subject: Clientside RTE shuffle --- apworld/client/gamedata.gd | 8 +++++++ apworld/client/manager.gd | 18 ++++++++++++++++ apworld/client/player.gd | 29 ++++++++++++++++++++++++- apworld/client/rteMenu.gd | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/apworld/client/gamedata.gd b/apworld/client/gamedata.gd index d7e3136..373f981 100644 --- a/apworld/client/gamedata.gd +++ b/apworld/client/gamedata.gd @@ -16,6 +16,7 @@ var anti_trap_ids = {} var location_name_by_id = {} var ending_display_name_by_name = {} var port_id_by_ap_id = {} +var map_id_by_rte_ap_id = {} var kSYMBOL_ITEMS @@ -57,6 +58,9 @@ func load(data_bytes): for map in objects.get_maps(): map_id_by_name[map.get_name()] = map.get_id() + if map.has_rte_ap_id(): + map_id_by_rte_ap_id[map.get_rte_ap_id()] = map.get_id() + for door in objects.get_doors(): var map = objects.get_maps()[door.get_map_id()] @@ -300,3 +304,7 @@ func _get_keyholder_location_name(keyholder): "%s - %s Keyholder" % [_get_room_object_location_prefix(keyholder), keyholder.get_key().to_upper()] ) + + +func vec3d_to_vector3(input) -> Vector3: + return Vector3(input.get_x(), input.get_y(), input.get_z()) diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 1e0b549..00f03ea 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd @@ -46,6 +46,10 @@ const kCYAN_DOOR_BEHAVIOR_H2 = 0 const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 const kCYAN_DOOR_BEHAVIOR_ITEM = 2 +const kFAST_TRAVEL_ACCESS_VANILLA = 0 +const kFAST_TRAVEL_ACCESS_UNLOCKED = 1 +const kFAST_TRAVEL_ACCESS_ITEMS = 2 + const kEndingNameByVictoryValue = { 0: "GRAY", 1: "PURPLE", @@ -69,9 +73,11 @@ var daedalus_roof_access = false var enable_gift_maps = [] var enable_icarus = false var endings_requirement = 0 +var fast_travel_access = 0 var keyholder_sanity = false var masteries_requirement = 0 var port_pairings = {} +var rte_mapping = [] var shuffle_control_center_colors = false var shuffle_doors = false var shuffle_gallery_paintings = false @@ -269,6 +275,13 @@ func _process_item(item, amount): if item_id == gamedata.objects.get_special_ids()["Numbers"] and global.map == "the_fuzzy": global.allow_numbers = true + if gamedata.map_id_by_rte_ap_id.has(item_id): + var rteInner = get_tree().get_root().get_node_or_null( + "scene/player/pause_menu/menu/return/rteInner" + ) + if rteInner != null: + rteInner.refreshButtons() + # Show a message about the item if it's new. if int(item["index"]) > _last_new_item: _last_new_item = int(item["index"]) @@ -469,6 +482,7 @@ func _client_connected(slot_data): enable_gift_maps = slot_data.get("enable_gift_maps", []) enable_icarus = bool(slot_data.get("enable_icarus", false)) endings_requirement = int(slot_data.get("endings_requirement", 0)) + fast_travel_access = int(slot_data.get("fast_travel_access", 0)) keyholder_sanity = bool(slot_data.get("keyholder_sanity", false)) masteries_requirement = int(slot_data.get("masteries_requirement", 0)) shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false)) @@ -496,6 +510,10 @@ func _client_connected(slot_data): raw_pp[p1] )] + rte_mapping.clear() + if slot_data.has("rte"): + rte_mapping = slot_data.get("rte") + # Set up item locks. _item_locks = {} diff --git a/apworld/client/player.gd b/apworld/client/player.gd index 5fac9fd..95c05d7 100644 --- a/apworld/client/player.gd +++ b/apworld/client/player.gd @@ -13,6 +13,8 @@ func _ready(): var ap = global.get_node("Archipelago") var gamedata = global.get_node("Gamedata") + var map_id = gamedata.map_id_by_name.get(global.map) + var map_data = gamedata.objects.get_maps()[map_id] compass = global.get_node("Compass") compass.visible = ap.show_compass @@ -26,8 +28,33 @@ func _ready(): ap.update_job_well_done_sign() + # Set up the RTE trigger, if there is one. + if map_data.has_rte_trigger_pos(): + var oneShotListener_prefab = preload("res://objects/nodes/listeners/oneShotListener.tscn") + var triggerArea_prefab = preload("res://objects/nodes/triggerArea.tscn") + var unlockSetterListener_prefab = preload( + "res://objects/nodes/listeners/unlockSetterListener.tscn" + ) + + var triggerArea = triggerArea_prefab.instantiate() + triggerArea.name = "rte_triggerArea" + triggerArea.position = gamedata.vec3d_to_vector3(map_data.get_rte_trigger_pos()) + triggerArea.scale = gamedata.vec3d_to_vector3(map_data.get_rte_trigger_scale()) + get_parent().add_child.call_deferred(triggerArea) + + var osl = oneShotListener_prefab.instantiate() + osl.name = "rte_osl" + osl.senders.append(NodePath("/root/scene/rte_triggerArea")) + get_parent().add_child.call_deferred(osl) + + var usl = unlockSetterListener_prefab.instantiate() + usl.name = "rte_usl" + usl.key = "rte_%s" % global.map + usl.value = "unlocked" + usl.senders.append(NodePath("/root/scene/rte_osl")) + get_parent().add_child.call_deferred(usl) + # Set up door locations. - var map_id = gamedata.map_id_by_name.get(global.map) for door in gamedata.objects.get_doors(): if door.get_map_id() != map_id: continue diff --git a/apworld/client/rteMenu.gd b/apworld/client/rteMenu.gd index 5882d77..4b526cf 100644 --- a/apworld/client/rteMenu.gd +++ b/apworld/client/rteMenu.gd @@ -1,5 +1,7 @@ extends "res://scripts/ui/rteMenu.gd" +var buttons = [] + func _readier(): var ap = global.get_node("Archipelago") @@ -8,5 +10,57 @@ func _readier(): get_node("rte_daedalus").show() switcher.preload_map("res://objects/scenes/daedalus.tscn") + elif !ap.rte_mapping.is_empty(): + buttons = [$rte_the_plaza, $rte_the_gallery, $rte_daedalus, $rte_control_center] + for i in range(4): + buttons[i].name = "button_%d" % i + for i in range(4): + _setupButton(buttons[i], ap.rte_mapping[i]) + + refreshButtons() else: super()._readier() + + +func _setupButton(button, map_name): + switcher.preload_map("res://objects/scenes/%s.tscn" % map_name) + + button.hide() + button.text = map_name.replace("_", " ") + button.name = "rte_%s" % map_name + + var ap = global.get_node("Archipelago") + if ( + ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_VANILLA + and !unlocks.data.has("rte_%s" % map_name) + ): + unlocks.data["rte_%s" % map_name] = "" + + +func refreshButtons(): + var ap = global.get_node("Archipelago") + if ap.rte_mapping.is_empty(): + return + + for i in range(4): + if _shouldShowButton(ap.rte_mapping[i]): + buttons[i].show() + else: + buttons[i].hide() + + +func _shouldShowButton(map_name): + var ap = global.get_node("Archipelago") + + if ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_VANILLA: + return unlocks.data["rte_%s" % map_name] == "unlocked" + elif ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_UNLOCKED: + return true + elif ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_ITEMS: + var gamedata = global.get_node("Gamedata") + var map_id = gamedata.map_id_by_name[map_name] + var rte_ap_id = gamedata.objects.get_maps()[map_id].get_rte_ap_id() + + return ap.client.hasItem(rte_ap_id) + + return false -- cgit 1.4.1