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-27 18:53:50 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-08-27 18:53:50 -0400
commit18e64c9102f526b04c44623aa39c9b3cb6dee1ff (patch)
tree39b856ae472a1b9033a9122e63be28bddd55bea2 /apworld/player_logic.py
parent4ae885f392261b939e6f21b47d545f609c6e1965 (diff)
downloadlingo2-archipelago-18e64c9102f526b04c44623aa39c9b3cb6dee1ff.tar.gz
lingo2-archipelago-18e64c9102f526b04c44623aa39c9b3cb6dee1ff.tar.bz2
lingo2-archipelago-18e64c9102f526b04c44623aa39c9b3cb6dee1ff.zip
Letter requirements in apworld
Also fixed or logic so everything actually works now.
Diffstat (limited to 'apworld/player_logic.py')
-rw-r--r--apworld/player_logic.py46
1 files changed, 42 insertions, 4 deletions
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 83c16f2..6feef99 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -10,7 +10,11 @@ def calculate_letter_histogram(solution: str) -> dict[str, int]:
10 for l in solution: 10 for l in solution:
11 if l.isalpha(): 11 if l.isalpha():
12 real_l = l.upper() 12 real_l = l.upper()
13 histogram[real_l] = min(histogram.get(l, 0) + 1, 2) 13 histogram[real_l] = min(histogram.get(real_l, 0) + 1, 2)
14
15 for free_letter in "HINT":
16 if histogram.get(free_letter, 0) == 1:
17 del histogram[free_letter]
14 18
15 return histogram 19 return histogram
16 20
@@ -53,6 +57,20 @@ class AccessRequirements:
53 for disjunction in other.or_logic: 57 for disjunction in other.or_logic:
54 self.or_logic.append(disjunction) 58 self.or_logic.append(disjunction)
55 59
60 def __repr__(self):
61 parts = []
62 if len(self.items) > 0:
63 parts.append(f"items={self.items}")
64 if len(self.rooms) > 0:
65 parts.append(f"rooms={self.rooms}")
66 if len(self.symbols) > 0:
67 parts.append(f"symbols={self.symbols}")
68 if len(self.letters) > 0:
69 parts.append(f"letters={self.letters}")
70 if len(self.or_logic) > 0:
71 parts.append(f"or_logic={self.or_logic}")
72 return f"AccessRequirements({", ".join(parts)})"
73
56 74
57class PlayerLocation(NamedTuple): 75class PlayerLocation(NamedTuple):
58 code: int | None 76 code: int | None
@@ -100,6 +118,14 @@ class Lingo2PlayerLogic:
100 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id, 118 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id,
101 AccessRequirements())) 119 AccessRequirements()))
102 120
121 letter_name = f"{letter.key.upper()}{'2' if letter.level2 else '1'}"
122 event_name = f"{letter_name} (Collected)"
123 self.event_loc_item_by_room.setdefault(letter.room_id, {})[event_name] = letter.key.upper()
124
125 if letter.level2:
126 event_name = f"{letter_name} (Double Collected)"
127 self.event_loc_item_by_room.setdefault(letter.room_id, {})[event_name] = letter.key.upper()
128
103 for mastery in world.static_logic.objects.masteries: 129 for mastery in world.static_logic.objects.masteries:
104 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id, 130 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id,
105 AccessRequirements())) 131 AccessRequirements()))
@@ -137,17 +163,21 @@ class Lingo2PlayerLogic:
137 if answer is not None: 163 if answer is not None:
138 reqs.add_solution(answer) 164 reqs.add_solution(answer)
139 elif len(panel.proxies) > 0: 165 elif len(panel.proxies) > 0:
166 possibilities = []
167
140 for proxy in panel.proxies: 168 for proxy in panel.proxies:
141 proxy_reqs = AccessRequirements() 169 proxy_reqs = AccessRequirements()
142 proxy_reqs.add_solution(proxy.answer) 170 proxy_reqs.add_solution(proxy.answer)
143 171
144 reqs.or_logic.append([proxy_reqs]) 172 possibilities.append(proxy_reqs)
145 173
146 if not any(proxy.answer == panel.answer for proxy in panel.proxies): 174 if not any(proxy.answer == panel.answer for proxy in panel.proxies):
147 proxy_reqs = AccessRequirements() 175 proxy_reqs = AccessRequirements()
148 proxy_reqs.add_solution(panel.answer) 176 proxy_reqs.add_solution(panel.answer)
149 177
150 reqs.or_logic.append([proxy_reqs]) 178 possibilities.append(proxy_reqs)
179
180 reqs.or_logic.append(possibilities)
151 else: 181 else:
152 reqs.add_solution(panel.answer) 182 reqs.add_solution(panel.answer)
153 183
@@ -175,7 +205,7 @@ class Lingo2PlayerLogic:
175 door = self.world.static_logic.objects.doors[door_id] 205 door = self.world.static_logic.objects.doors[door_id]
176 reqs = AccessRequirements() 206 reqs = AccessRequirements()
177 207
178 # TODO: complete_at, control_center_color, switches, keyholders 208 # TODO: control_center_color, switches
179 if not door.HasField("complete_at") or door.complete_at == 0: 209 if not door.HasField("complete_at") or door.complete_at == 0:
180 for proxy in door.panels: 210 for proxy in door.panels:
181 panel_reqs = self.get_panel_reqs(proxy.panel, proxy.answer if proxy.HasField("answer") else None) 211 panel_reqs = self.get_panel_reqs(proxy.panel, proxy.answer if proxy.HasField("answer") else None)
@@ -188,6 +218,14 @@ class Lingo2PlayerLogic:
188 # TODO: Handle complete_at > 1 218 # TODO: Handle complete_at > 1
189 pass 219 pass
190 220
221 for keyholder_uses in door.keyholders:
222 key_name = keyholder_uses.key.upper()
223 if key_name not in reqs.letters:
224 reqs.letters[key_name] = 1
225
226 keyholder = self.world.static_logic.objects.keyholders[keyholder_uses.keyholder]
227 reqs.rooms.add(self.world.static_logic.get_room_region_name(keyholder.room_id))
228
191 for room in door.rooms: 229 for room in door.rooms:
192 reqs.rooms.add(self.world.static_logic.get_room_region_name(room)) 230 reqs.rooms.add(self.world.static_logic.get_room_region_name(room))
193 231