diff options
Diffstat (limited to 'apworld/player_logic.py')
-rw-r--r-- | apworld/player_logic.py | 30 |
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) | ||