summary refs log tree commit diff stats
path: root/apworld/player_logic.py
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-08-14 12:30:12 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-08-14 12:32:43 -0400
commita17b7e1cbfb43141af21263f838f9593836a9c52 (patch)
tree453b8a6193e9c9c22863d6de5ecf6bffe3f6dfc6 /apworld/player_logic.py
parent0fbaff9e15d1214192bd2b70bf4bc90d873727b6 (diff)
downloadlingo2-archipelago-a17b7e1cbfb43141af21263f838f9593836a9c52.tar.gz
lingo2-archipelago-a17b7e1cbfb43141af21263f838f9593836a9c52.tar.bz2
lingo2-archipelago-a17b7e1cbfb43141af21263f838f9593836a9c52.zip
Fixed some issues with door logic
If a door is shuffled, the door's item should be used in connections and
in requirements specified by panels, ports, paintings, and other doors.
However, the original requirements still need to be used for locations.
Diffstat (limited to 'apworld/player_logic.py')
-rw-r--r--apworld/player_logic.py30
1 files changed, 25 insertions, 5 deletions
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 7209ee5..c2850d5 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -63,6 +63,7 @@ class Lingo2PlayerLogic:
63 world: "Lingo2World" 63 world: "Lingo2World"
64 64
65 locations_by_room: dict[int, list[PlayerLocation]] 65 locations_by_room: dict[int, list[PlayerLocation]]
66 item_by_door: dict[int, str]
66 67
67 panel_reqs: dict[int, AccessRequirements] 68 panel_reqs: dict[int, AccessRequirements]
68 proxy_reqs: dict[int, dict[str, AccessRequirements]] 69 proxy_reqs: dict[int, dict[str, AccessRequirements]]
@@ -73,19 +74,25 @@ class Lingo2PlayerLogic:
73 def __init__(self, world: "Lingo2World"): 74 def __init__(self, world: "Lingo2World"):
74 self.world = world 75 self.world = world
75 self.locations_by_room = {} 76 self.locations_by_room = {}
77 self.item_by_door = {}
76 self.panel_reqs = dict() 78 self.panel_reqs = dict()
77 self.proxy_reqs = dict() 79 self.proxy_reqs = dict()
78 self.door_reqs = dict() 80 self.door_reqs = dict()
79 self.real_items = list() 81 self.real_items = list()
80 82
83 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled
84 # before we calculate any access requirements.
85 for door in world.static_logic.objects.doors:
86 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and self.world.options.shuffle_doors:
87 door_item_name = self.world.static_logic.get_door_item_name(door.id)
88 self.item_by_door[door.id] = door_item_name
89 self.real_items.append(door_item_name)
90
81 for door in world.static_logic.objects.doors: 91 for door in world.static_logic.objects.doors:
82 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY]: 92 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY]:
83 self.locations_by_room.setdefault(door.room_id, []).append(PlayerLocation(door.ap_id, 93 self.locations_by_room.setdefault(door.room_id, []).append(PlayerLocation(door.ap_id,
84 self.get_door_reqs(door.id))) 94 self.get_door_reqs(door.id)))
85 95
86 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.ITEM_ONLY] and self.world.options.shuffle_doors:
87 self.real_items.append(self.world.static_logic.get_door_item_name(door.id))
88
89 for letter in world.static_logic.objects.letters: 96 for letter in world.static_logic.objects.letters:
90 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id, 97 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id,
91 AccessRequirements())) 98 AccessRequirements()))
@@ -127,7 +134,7 @@ class Lingo2PlayerLogic:
127 reqs.symbols.add(symbol) 134 reqs.symbols.add(symbol)
128 135
129 if panel.HasField("required_door"): 136 if panel.HasField("required_door"):
130 door_reqs = self.get_door_reqs(panel.required_door) 137 door_reqs = self.get_door_open_reqs(panel.required_door)
131 reqs.merge(door_reqs) 138 reqs.merge(door_reqs)
132 139
133 if panel.HasField("required_room"): 140 if panel.HasField("required_room"):
@@ -135,6 +142,8 @@ class Lingo2PlayerLogic:
135 142
136 return reqs 143 return reqs
137 144
145 # This gets/calculates the requirements described by the door object. This is most notably used as the requirements
146 # for clearing a location, or opening a door when the door is not shuffled.
138 def get_door_reqs(self, door_id: int) -> AccessRequirements: 147 def get_door_reqs(self, door_id: int) -> AccessRequirements:
139 if door_id not in self.door_reqs: 148 if door_id not in self.door_reqs:
140 self.door_reqs[door_id] = self.calculate_door_reqs(door_id) 149 self.door_reqs[door_id] = self.calculate_door_reqs(door_id)
@@ -161,7 +170,18 @@ class Lingo2PlayerLogic:
161 reqs.rooms.add(self.world.static_logic.get_room_region_name(room)) 170 reqs.rooms.add(self.world.static_logic.get_room_region_name(room))
162 171
163 for sub_door_id in door.doors: 172 for sub_door_id in door.doors:
164 sub_reqs = self.get_door_reqs(sub_door_id) 173 sub_reqs = self.get_door_open_reqs(sub_door_id)
165 reqs.merge(sub_reqs) 174 reqs.merge(sub_reqs)
166 175
167 return reqs 176 return reqs
177
178 # This gets the requirements to open a door within the world. When a door is shuffled, this means having the item
179 # that acts as the door's key.
180 def get_door_open_reqs(self, door_id: int) -> AccessRequirements:
181 if door_id in self.item_by_door:
182 reqs = AccessRequirements()
183 reqs.items.add(self.item_by_door.get(door_id))
184
185 return reqs
186 else:
187 return self.get_door_reqs(door_id)