From 7f82beb120e222ace6c258fc3982b5988f9ae070 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Tue, 2 Sep 2025 14:09:35 -0400 Subject: Added keyholder sanity --- apworld/__init__.py | 4 +++- apworld/options.py | 10 ++++++++++ apworld/player_logic.py | 9 +++++++++ apworld/static_logic.py | 22 +++++++++++++++------- 4 files changed, 37 insertions(+), 8 deletions(-) (limited to 'apworld') diff --git a/apworld/__init__.py b/apworld/__init__.py index 4e5777a..1f1e6fe 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py @@ -65,7 +65,9 @@ class Lingo2World(World): def fill_slot_data(self): slot_options = [ - "victory_condition", "shuffle_doors", + "keyholder_sanity", + "shuffle_doors", + "victory_condition", ] slot_data = { diff --git a/apworld/options.py b/apworld/options.py index d984beb..dacbc46 100644 --- a/apworld/options.py +++ b/apworld/options.py @@ -8,6 +8,15 @@ class ShuffleDoors(Toggle): display_name = "Shuffle Doors" +class KeyholderSanity(Toggle): + """ + If enabled, 26 locations will be created for placing each key into its respective Green Ending keyholder. + + NOTE: This does not apply to the two disappearing keyholders in The Congruent, as they are not part of Green Ending. + """ + display_name = "Keyholder Sanity" + + class VictoryCondition(Choice): """Victory condition.""" display_name = "Victory Condition" @@ -29,4 +38,5 @@ class VictoryCondition(Choice): @dataclass class Lingo2Options(PerGameCommonOptions): shuffle_doors: ShuffleDoors + keyholder_sanity: KeyholderSanity victory_condition: VictoryCondition diff --git a/apworld/player_logic.py b/apworld/player_logic.py index e08f644..dc1bdf0 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py @@ -166,6 +166,15 @@ class Lingo2PlayerLogic: self.event_loc_item_by_room.setdefault(ending.room_id, {})[event_name] = item_name + if self.world.options.keyholder_sanity: + for keyholder in world.static_logic.objects.keyholders: + if keyholder.HasField("key"): + reqs = AccessRequirements() + reqs.letters[keyholder.key.upper()] = 1 + + self.locations_by_room.setdefault(keyholder.room_id, []).append(PlayerLocation(keyholder.ap_id, + reqs)) + def get_panel_reqs(self, panel_id: int, answer: str | None) -> AccessRequirements: if answer is None: if panel_id not in self.panel_reqs: diff --git a/apworld/static_logic.py b/apworld/static_logic.py index 0613474..a945bc0 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py @@ -44,6 +44,11 @@ class Lingo2StaticLogic: for progressive in self.objects.progressives: self.item_id_to_name[progressive.ap_id] = progressive.name + for keyholder in self.objects.keyholders: + if keyholder.HasField("key"): + location_name = f"{self.get_room_object_location_prefix(keyholder)} - {keyholder.key.upper()} Keyholder" + self.location_id_to_name[keyholder.ap_id] = location_name + self.item_id_to_name[self.objects.special_ids["Nothing"]] = "Nothing" self.item_name_to_id = {name: ap_id for ap_id, name in self.item_id_to_name.items()} @@ -57,13 +62,7 @@ class Lingo2StaticLogic: return self.get_door_item_name(door_id) def get_door_location_name(self, door: data_pb2.Door) -> str: - game_map = self.objects.maps[door.map_id] - room = self.objects.rooms[door.room_id] - - if room.HasField("panel_display_name"): - map_part = f"{game_map.display_name} ({room.panel_display_name})" - else: - map_part = game_map.display_name + map_part = self.get_room_object_location_prefix(door) if door.HasField("location_name"): return f"{map_part} - {door.location_name}" @@ -129,3 +128,12 @@ class Lingo2StaticLogic: def get_room_object_map_name(self, obj) -> str: return self.get_map_object_map_name(self.objects.rooms[obj.room_id]) + + def get_room_object_location_prefix(self, obj) -> str: + room = self.objects.rooms[obj.room_id] + game_map = self.objects.maps[room.map_id] + + if room.HasField("panel_display_name"): + return f"{game_map.display_name} ({room.panel_display_name})" + else: + return game_map.display_name -- cgit 1.4.1