summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--apworld/player_logic.py30
-rw-r--r--apworld/regions.py6
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