diff options
| -rw-r--r-- | apworld/player_logic.py | 30 | ||||
| -rw-r--r-- | apworld/regions.py | 6 |
2 files changed, 28 insertions, 8 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) | ||
| diff --git a/apworld/regions.py b/apworld/regions.py index 2a850ef..14fcaac 100644 --- a/apworld/regions.py +++ b/apworld/regions.py | |||
| @@ -41,7 +41,7 @@ def create_regions(world: "Lingo2World"): | |||
| 41 | reqs = AccessRequirements() | 41 | reqs = AccessRequirements() |
| 42 | 42 | ||
| 43 | if connection.HasField("required_door"): | 43 | if connection.HasField("required_door"): |
| 44 | reqs.merge(world.player_logic.get_door_reqs(connection.required_door)) | 44 | reqs.merge(world.player_logic.get_door_open_reqs(connection.required_door)) |
| 45 | 45 | ||
| 46 | door = world.static_logic.objects.doors[connection.required_door] | 46 | door = world.static_logic.objects.doors[connection.required_door] |
| 47 | wmap = world.static_logic.objects.maps[door.map_id] | 47 | wmap = world.static_logic.objects.maps[door.map_id] |
| @@ -52,14 +52,14 @@ def create_regions(world: "Lingo2World"): | |||
| 52 | connection_name = f"{connection_name} (via port {port.name})" | 52 | connection_name = f"{connection_name} (via port {port.name})" |
| 53 | 53 | ||
| 54 | if port.HasField("required_door"): | 54 | if port.HasField("required_door"): |
| 55 | reqs.merge(world.player_logic.get_door_reqs(port.required_door)) | 55 | reqs.merge(world.player_logic.get_door_open_reqs(port.required_door)) |
| 56 | 56 | ||
| 57 | if connection.HasField("painting"): | 57 | if connection.HasField("painting"): |
| 58 | painting = world.static_logic.objects.paintings[connection.painting] | 58 | painting = world.static_logic.objects.paintings[connection.painting] |
| 59 | connection_name = f"{connection_name} (via painting {painting.name})" | 59 | connection_name = f"{connection_name} (via painting {painting.name})" |
| 60 | 60 | ||
| 61 | if painting.HasField("required_door"): | 61 | if painting.HasField("required_door"): |
| 62 | reqs.merge(world.player_logic.get_door_reqs(painting.required_door)) | 62 | reqs.merge(world.player_logic.get_door_open_reqs(painting.required_door)) |
| 63 | 63 | ||
| 64 | if connection.HasField("panel"): | 64 | if connection.HasField("panel"): |
| 65 | proxy = connection.panel | 65 | proxy = connection.panel |
