about summary refs log tree commit diff stats
path: root/apworld
diff options
context:
space:
mode:
Diffstat (limited to 'apworld')
-rw-r--r--apworld/__init__.py2
-rw-r--r--apworld/client/gamedata.gd6
-rw-r--r--apworld/client/main.gd6
-rw-r--r--apworld/client/manager.gd4
-rw-r--r--apworld/client/player.gd127
-rw-r--r--apworld/options.py22
-rw-r--r--apworld/player_logic.py29
-rw-r--r--apworld/static_logic.py2
8 files changed, 187 insertions, 11 deletions
diff --git a/apworld/__init__.py b/apworld/__init__.py index 4ebf845..f5774c6 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py
@@ -132,7 +132,9 @@ class Lingo2World(World):
132 "daedalus_roof_access", 132 "daedalus_roof_access",
133 "enable_gift_maps", 133 "enable_gift_maps",
134 "enable_icarus", 134 "enable_icarus",
135 "endings_requirement",
135 "keyholder_sanity", 136 "keyholder_sanity",
137 "masteries_requirement",
136 "shuffle_control_center_colors", 138 "shuffle_control_center_colors",
137 "shuffle_doors", 139 "shuffle_doors",
138 "shuffle_gallery_paintings", 140 "shuffle_gallery_paintings",
diff --git a/apworld/client/gamedata.gd b/apworld/client/gamedata.gd index 9305003..3a35125 100644 --- a/apworld/client/gamedata.gd +++ b/apworld/client/gamedata.gd
@@ -221,7 +221,11 @@ func _get_generated_door_location_name(door):
221 if door.get_type() != SCRIPT_proto.DoorType.STANDARD: 221 if door.get_type() != SCRIPT_proto.DoorType.STANDARD:
222 return null 222 return null
223 223
224 if door.get_keyholders().size() > 0 or door.get_endings().size() > 0 or door.has_complete_at(): 224 if (
225 door.get_keyholders().size() > 0
226 or (door.has_white_ending() and door.get_white_ending())
227 or door.has_complete_at()
228 ):
225 return null 229 return null
226 230
227 if door.get_panels().size() > 4: 231 if door.get_panels().size() > 4:
diff --git a/apworld/client/main.gd b/apworld/client/main.gd index 1d0df1f..a3b21c5 100644 --- a/apworld/client/main.gd +++ b/apworld/client/main.gd
@@ -83,6 +83,12 @@ func _ready():
83 compass_overlay_instance.SCRIPT_compass = runtime.load_script("compass.gd") 83 compass_overlay_instance.SCRIPT_compass = runtime.load_script("compass.gd")
84 global.add_child(compass_overlay_instance) 84 global.add_child(compass_overlay_instance)
85 85
86 unlocks.data["advanced_mastery"] = ""
87 unlocks.data["charismatic_mastery"] = ""
88 unlocks.data["crystalline_mastery"] = ""
89 unlocks.data["icarus_mastery"] = ""
90 unlocks.data["stellar_mastery"] = ""
91
86 var ap = global.get_node("Archipelago") 92 var ap = global.get_node("Archipelago")
87 var gamedata = global.get_node("Gamedata") 93 var gamedata = global.get_node("Gamedata")
88 ap.ap_connected.connect(connectionSuccessful) 94 ap.ap_connected.connect(connectionSuccessful)
diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 41ab648..399d6a5 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd
@@ -65,7 +65,9 @@ var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2
65var daedalus_roof_access = false 65var daedalus_roof_access = false
66var enable_gift_maps = [] 66var enable_gift_maps = []
67var enable_icarus = false 67var enable_icarus = false
68var endings_requirement = 0
68var keyholder_sanity = false 69var keyholder_sanity = false
70var masteries_requirement = 0
69var port_pairings = {} 71var port_pairings = {}
70var shuffle_control_center_colors = false 72var shuffle_control_center_colors = false
71var shuffle_doors = false 73var shuffle_doors = false
@@ -443,7 +445,9 @@ func _client_connected(slot_data):
443 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) 445 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false))
444 enable_gift_maps = slot_data.get("enable_gift_maps", []) 446 enable_gift_maps = slot_data.get("enable_gift_maps", [])
445 enable_icarus = bool(slot_data.get("enable_icarus", false)) 447 enable_icarus = bool(slot_data.get("enable_icarus", false))
448 endings_requirement = int(slot_data.get("endings_requirement", 0))
446 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false)) 449 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false))
450 masteries_requirement = int(slot_data.get("masteries_requirement", 0))
447 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false)) 451 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false))
448 shuffle_doors = bool(slot_data.get("shuffle_doors", false)) 452 shuffle_doors = bool(slot_data.get("shuffle_doors", false))
449 shuffle_gallery_paintings = bool(slot_data.get("shuffle_gallery_paintings", false)) 453 shuffle_gallery_paintings = bool(slot_data.get("shuffle_gallery_paintings", false))
diff --git a/apworld/client/player.gd b/apworld/client/player.gd index 789d1b7..9acb942 100644 --- a/apworld/client/player.gd +++ b/apworld/client/player.gd
@@ -19,6 +19,84 @@ func _ready():
19 19
20 ap.start_batching_locations() 20 ap.start_batching_locations()
21 21
22 if global.map == "control_center":
23 get_node("/root/scene/Components/Doors/entry_18").queue_free()
24
25 _set_up_mastery_listener("advanced")
26 _set_up_mastery_listener("charismatic")
27 _set_up_mastery_listener("crystalline")
28 _set_up_mastery_listener("icarus")
29 _set_up_mastery_listener("stellar")
30
31 if ap.endings_requirement != 12 or ap.masteries_requirement != 0:
32 # Set up listeners for the potential White Ending requirements.
33 var merging_prefab = preload("res://objects/nodes/listeners/mergingListener.tscn")
34
35 var old_door = get_node("/root/scene/Components/Doors/entry_19")
36 var new_door = old_door.duplicate()
37 new_door.name = "entry_19_new"
38 new_door.senders.clear()
39 new_door.senderGroup.clear()
40 new_door.excludeSenders.clear()
41
42 if ap.endings_requirement == 12:
43 new_door.senderGroup.append(NodePath("/root/scene/Meshes/Trophies/Listeners"))
44 elif ap.endings_requirement > 0:
45 if ap.masteries_requirement == 0:
46 new_door.senderGroup.append(NodePath("/root/scene/Meshes/Trophies/Listeners"))
47 new_door.complete_at = ap.endings_requirement
48 else:
49 var endings_merge = merging_prefab.instantiate()
50 endings_merge.name = "EndingsMerge"
51 endings_merge.senderGroup.append(
52 NodePath("/root/scene/Meshes/Trophies/Listeners")
53 )
54 endings_merge.complete_at = ap.endings_requirement
55 get_node("/root/scene/Components").add_child.call_deferred(endings_merge)
56 new_door.senders.append(NodePath("/root/scene/Components/EndingsMerge"))
57
58 var max_masteries = 13 + ap.enable_gift_maps.size()
59 if ap.enable_icarus:
60 max_masteries += 1
61
62 if ap.masteries_requirement == max_masteries:
63 new_door.senderGroup.append(
64 NodePath("/root/scene/Meshes/Trophies/MasteryListeners")
65 )
66 new_door.excludeSenders.append(
67 NodePath(
68 "/root/scene/Meshes/Trophies/MasteryListeners/unlockReaderListenerWhite"
69 )
70 )
71 elif ap.masteries_requirement > 0:
72 if ap.endings_requirement == 0:
73 new_door.senderGroup.append(
74 NodePath("/root/scene/Meshes/Trophies/MasteryListeners")
75 )
76 new_door.excludeSenders.append(
77 NodePath(
78 "/root/scene/Meshes/Trophies/MasteryListeners/unlockReaderListenerWhite"
79 )
80 )
81 new_door.complete_at = ap.masteries_requirement
82 else:
83 var masteries_merge = merging_prefab.instantiate()
84 masteries_merge.name = "MasteriesMerge"
85 masteries_merge.senderGroup.append(
86 NodePath("/root/scene/Meshes/Trophies/MasteryListeners")
87 )
88 masteries_merge.excludeSenders.append(
89 NodePath(
90 "/root/scene/Meshes/Trophies/MasteryListeners/unlockReaderListenerWhite"
91 )
92 )
93 masteries_merge.complete_at = ap.masteries_requirement
94 get_node("/root/scene/Components").add_child.call_deferred(masteries_merge)
95 new_door.senders.append(NodePath("/root/scene/Components/MasteriesMerge"))
96
97 old_door.queue_free()
98 get_node("/root/scene/Components/Doors").add_child.call_deferred(new_door)
99
22 # Block off roof access in Daedalus. 100 # Block off roof access in Daedalus.
23 if global.map == "daedalus" and not ap.daedalus_roof_access: 101 if global.map == "daedalus" and not ap.daedalus_roof_access:
24 _set_up_invis_wall(75.5, 11, -24.5, 1, 10, 49) 102 _set_up_invis_wall(75.5, 11, -24.5, 1, 10, 49)
@@ -297,6 +375,7 @@ func _ready():
297 var collectable_prefab = preload("res://objects/nodes/collectable.tscn") 375 var collectable_prefab = preload("res://objects/nodes/collectable.tscn")
298 var saver_prefab = preload("res://objects/nodes/saver.tscn") 376 var saver_prefab = preload("res://objects/nodes/saver.tscn")
299 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn") 377 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn")
378 var usl_prefab = preload("res://objects/nodes/listeners/unlockSetterListener.tscn")
300 379
301 var mastery = collectable_prefab.instantiate() 380 var mastery = collectable_prefab.instantiate()
302 mastery.name = "collectable" 381 mastery.name = "collectable"
@@ -314,6 +393,13 @@ func _ready():
314 tpl.nested = true 393 tpl.nested = true
315 mastery.add_child.call_deferred(tpl) 394 mastery.add_child.call_deferred(tpl)
316 395
396 var usl = usl_prefab.instantiate()
397 usl.name = "unlockSetterListenerMastery"
398 usl.key = "icarus_mastery"
399 usl.value = "unlocked"
400 usl.senders.append(NodePath("/root/scene/Components/Collectables/collectable"))
401 get_node("/root/scene/Components").add_child.call_deferred(usl)
402
317 var saver = saver_prefab.instantiate() 403 var saver = saver_prefab.instantiate()
318 saver.name = "saver_collectables" 404 saver.name = "saver_collectables"
319 saver.type = "collectables" 405 saver.type = "collectables"
@@ -325,6 +411,7 @@ func _ready():
325 var collectable_prefab = preload("res://objects/nodes/collectable.tscn") 411 var collectable_prefab = preload("res://objects/nodes/collectable.tscn")
326 var saver_prefab = preload("res://objects/nodes/saver.tscn") 412 var saver_prefab = preload("res://objects/nodes/saver.tscn")
327 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn") 413 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn")
414 var usl_prefab = preload("res://objects/nodes/listeners/unlockSetterListener.tscn")
328 415
329 var mastery = collectable_prefab.instantiate() 416 var mastery = collectable_prefab.instantiate()
330 mastery.name = "collectable" 417 mastery.name = "collectable"
@@ -343,6 +430,13 @@ func _ready():
343 tpl.senders.append(NodePath("/root/scene/Panels/Room_1/panel_31")) 430 tpl.senders.append(NodePath("/root/scene/Panels/Room_1/panel_31"))
344 mastery.add_child.call_deferred(tpl) 431 mastery.add_child.call_deferred(tpl)
345 432
433 var usl = usl_prefab.instantiate()
434 usl.name = "unlockSetterListenerMastery"
435 usl.key = "advanced_mastery"
436 usl.value = "unlocked"
437 usl.senders.append(NodePath("/root/scene/Components/Collectables/collectable"))
438 get_node("/root/scene/Components").add_child.call_deferred(usl)
439
346 var saver = saver_prefab.instantiate() 440 var saver = saver_prefab.instantiate()
347 saver.name = "saver_collectables" 441 saver.name = "saver_collectables"
348 saver.type = "collectables" 442 saver.type = "collectables"
@@ -353,6 +447,7 @@ func _ready():
353 if global.map == "the_charismatic": 447 if global.map == "the_charismatic":
354 var collectable_prefab = preload("res://objects/nodes/collectable.tscn") 448 var collectable_prefab = preload("res://objects/nodes/collectable.tscn")
355 var saver_prefab = preload("res://objects/nodes/saver.tscn") 449 var saver_prefab = preload("res://objects/nodes/saver.tscn")
450 var usl_prefab = preload("res://objects/nodes/listeners/unlockSetterListener.tscn")
356 451
357 var mastery = collectable_prefab.instantiate() 452 var mastery = collectable_prefab.instantiate()
358 mastery.name = "collectable" 453 mastery.name = "collectable"
@@ -362,6 +457,13 @@ func _ready():
362 mastery.material_override = load("res://assets/materials/gold.material") 457 mastery.material_override = load("res://assets/materials/gold.material")
363 get_node("/root/scene/Components/Collectables").add_child.call_deferred(mastery) 458 get_node("/root/scene/Components/Collectables").add_child.call_deferred(mastery)
364 459
460 var usl = usl_prefab.instantiate()
461 usl.name = "unlockSetterListenerMastery"
462 usl.key = "charismatic_mastery"
463 usl.value = "unlocked"
464 usl.senders.append(NodePath("/root/scene/Components/Collectables/collectable"))
465 get_node("/root/scene/Components").add_child.call_deferred(usl)
466
365 var saver = saver_prefab.instantiate() 467 var saver = saver_prefab.instantiate()
366 saver.name = "saver_collectables" 468 saver.name = "saver_collectables"
367 saver.type = "collectables" 469 saver.type = "collectables"
@@ -373,6 +475,7 @@ func _ready():
373 var collectable_prefab = preload("res://objects/nodes/collectable.tscn") 475 var collectable_prefab = preload("res://objects/nodes/collectable.tscn")
374 var saver_prefab = preload("res://objects/nodes/saver.tscn") 476 var saver_prefab = preload("res://objects/nodes/saver.tscn")
375 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn") 477 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn")
478 var usl_prefab = preload("res://objects/nodes/listeners/unlockSetterListener.tscn")
376 479
377 var mastery = collectable_prefab.instantiate() 480 var mastery = collectable_prefab.instantiate()
378 mastery.name = "collectable" 481 mastery.name = "collectable"
@@ -389,6 +492,13 @@ func _ready():
389 tpl.senders.append(NodePath("/root/scene/Panels/Room_1/panel_3")) 492 tpl.senders.append(NodePath("/root/scene/Panels/Room_1/panel_3"))
390 mastery.add_child.call_deferred(tpl) 493 mastery.add_child.call_deferred(tpl)
391 494
495 var usl = usl_prefab.instantiate()
496 usl.name = "unlockSetterListenerMastery"
497 usl.key = "crystalline_mastery"
498 usl.value = "unlocked"
499 usl.senders.append(NodePath("/root/scene/Components/Collectables/collectable"))
500 get_node("/root/scene/Components").add_child.call_deferred(usl)
501
392 var saver = saver_prefab.instantiate() 502 var saver = saver_prefab.instantiate()
393 saver.name = "saver_collectables" 503 saver.name = "saver_collectables"
394 saver.type = "collectables" 504 saver.type = "collectables"
@@ -399,6 +509,7 @@ func _ready():
399 if global.map == "the_stellar": 509 if global.map == "the_stellar":
400 var collectable_prefab = preload("res://objects/nodes/collectable.tscn") 510 var collectable_prefab = preload("res://objects/nodes/collectable.tscn")
401 var saver_prefab = preload("res://objects/nodes/saver.tscn") 511 var saver_prefab = preload("res://objects/nodes/saver.tscn")
512 var usl_prefab = preload("res://objects/nodes/listeners/unlockSetterListener.tscn")
402 513
403 var collectables = Node.new() 514 var collectables = Node.new()
404 collectables.name = "Collectables" 515 collectables.name = "Collectables"
@@ -412,6 +523,13 @@ func _ready():
412 collectables.add_child.call_deferred(mastery) 523 collectables.add_child.call_deferred(mastery)
413 get_node("/root/scene/Components").add_child.call_deferred(collectables) 524 get_node("/root/scene/Components").add_child.call_deferred(collectables)
414 525
526 var usl = usl_prefab.instantiate()
527 usl.name = "unlockSetterListenerMastery"
528 usl.key = "stellar_mastery"
529 usl.value = "unlocked"
530 usl.senders.append(NodePath("/root/scene/Components/Collectables/collectable"))
531 get_node("/root/scene/Components").add_child.call_deferred(usl)
532
415 var saver = saver_prefab.instantiate() 533 var saver = saver_prefab.instantiate()
416 saver.name = "saver_collectables" 534 saver.name = "saver_collectables"
417 saver.type = "collectables" 535 saver.type = "collectables"
@@ -585,5 +703,14 @@ func _set_up_invis_wall(x, y, z, sx, sy, sz):
585 get_parent().add_child.call_deferred(newwall) 703 get_parent().add_child.call_deferred(newwall)
586 704
587 705
706func _set_up_mastery_listener(name):
707 var prefab = preload("res://objects/nodes/listeners/unlockReaderListener.tscn")
708 var url = prefab.instantiate()
709 url.name = "unlockReaderListenerMastery_%s" % name
710 url.key = "%s_mastery" % name
711 url.value = "unlocked"
712 get_node("/root/scene/Meshes/Trophies/MasteryListeners").add_child.call_deferred(url)
713
714
588func _process(_dt): 715func _process(_dt):
589 compass.update_rotation(global_rotation.y) 716 compass.update_rotation(global_rotation.y)
diff --git a/apworld/options.py b/apworld/options.py index 7577e0c..a56b40d 100644 --- a/apworld/options.py +++ b/apworld/options.py
@@ -181,6 +181,26 @@ class VictoryCondition(Choice):
181 option_white_ending = 12 181 option_white_ending = 12
182 182
183 183
184class EndingsRequirement(Range):
185 """The number of endings required to unlock White Ending."""
186 display_name = "Endings Requirement"
187 range_start = 0
188 range_end = 12
189 default = 12
190
191
192class MasteriesRequirement(Range):
193 """The number of masteries required to unlock White Ending.
194
195 There are only 13 masteries in the base game, but some of the other slot options may add more masteries to the
196 world. If the chosen number of masteries is higher than the total in your world, it will be automatically lowered to
197 the maximum."""
198 display_name = "Masteries Requirement"
199 range_start = 0
200 range_end = 18
201 default = 0
202
203
184class TrapPercentage(Range): 204class TrapPercentage(Range):
185 """Replaces junk items with traps, at the specified rate.""" 205 """Replaces junk items with traps, at the specified rate."""
186 display_name = "Trap Percentage" 206 display_name = "Trap Percentage"
@@ -205,4 +225,6 @@ class Lingo2Options(PerGameCommonOptions):
205 strict_purple_ending: StrictPurpleEnding 225 strict_purple_ending: StrictPurpleEnding
206 strict_cyan_ending: StrictCyanEnding 226 strict_cyan_ending: StrictCyanEnding
207 victory_condition: VictoryCondition 227 victory_condition: VictoryCondition
228 endings_requirement: EndingsRequirement
229 masteries_requirement: MasteriesRequirement
208 trap_percentage: TrapPercentage 230 trap_percentage: TrapPercentage
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 67365b7..e21e2c3 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -249,6 +249,13 @@ class Lingo2PlayerLogic:
249 self.shuffled_maps = set(game_map.id for game_map in world.static_logic.objects.maps 249 self.shuffled_maps = set(game_map.id for game_map in world.static_logic.objects.maps
250 if should_shuffle_map(game_map)) 250 if should_shuffle_map(game_map))
251 251
252 maximum_masteries = 13 + len(world.options.enable_gift_maps.value)
253 if world.options.enable_icarus:
254 maximum_masteries += 1
255
256 if world.options.masteries_requirement > maximum_masteries:
257 world.options.masteries_requirement.value = maximum_masteries
258
252 if self.world.options.shuffle_doors: 259 if self.world.options.shuffle_doors:
253 for progressive in world.static_logic.objects.progressives: 260 for progressive in world.static_logic.objects.progressives:
254 for i in range(0, len(progressive.doors)): 261 for i in range(0, len(progressive.doors)):
@@ -362,18 +369,23 @@ class Lingo2PlayerLogic:
362 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id, 369 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id,
363 AccessRequirements())) 370 AccessRequirements()))
364 371
372 if world.options.masteries_requirement > 0:
373 event_name = f"{world.static_logic.get_room_object_map_name(mastery)} - Mastery (Collected)"
374 self.event_loc_item_by_room.setdefault(mastery.room_id, {})[event_name] = "Mastery"
375
365 for ending in world.static_logic.objects.endings: 376 for ending in world.static_logic.objects.endings:
366 if world.static_logic.get_room_object_map_id(ending) not in self.shuffled_maps: 377 if world.static_logic.get_room_object_map_id(ending) not in self.shuffled_maps:
367 continue 378 continue
368 379
369 # Don't create a location for your selected ending, and never create a location for White Ending. 380 # Don't create a location for your selected ending. Also don't create a location for White Ending if it's
381 # necessarily in the postgame, i.e. it requires all 12 other endings.
370 if world.options.victory_condition.current_key.removesuffix("_ending").upper() != ending.name\ 382 if world.options.victory_condition.current_key.removesuffix("_ending").upper() != ending.name\
371 and ending.name != "WHITE": 383 and (ending.name != "WHITE" or world.options.endings_requirement < 12):
372 self.locations_by_room.setdefault(ending.room_id, []).append(PlayerLocation(ending.ap_id, 384 self.locations_by_room.setdefault(ending.room_id, []).append(PlayerLocation(ending.ap_id,
373 AccessRequirements())) 385 AccessRequirements()))
374 386
375 event_name = f"{ending.name.capitalize()} Ending (Achieved)" 387 event_name = f"{ending.name.capitalize()} Ending (Achieved)"
376 item_name = event_name 388 item_name = "Ending"
377 389
378 if world.options.victory_condition.current_key.removesuffix("_ending").upper() == ending.name: 390 if world.options.victory_condition.current_key.removesuffix("_ending").upper() == ending.name:
379 item_name = "Victory" 391 item_name = "Victory"
@@ -520,13 +532,12 @@ class Lingo2PlayerLogic:
520 for room in door.rooms: 532 for room in door.rooms:
521 reqs.rooms.add(self.world.static_logic.get_room_region_name(room)) 533 reqs.rooms.add(self.world.static_logic.get_room_region_name(room))
522 534
523 for ending_id in door.endings: 535 if door.white_ending:
524 ending = self.world.static_logic.objects.endings[ending_id] 536 if self.world.options.endings_requirement > 0:
537 reqs.progressives["Ending"] = self.world.options.endings_requirement.value
525 538
526 if self.world.options.victory_condition.current_key.removesuffix("_ending").upper() == ending.name: 539 if self.world.options.masteries_requirement > 0:
527 reqs.items.add("Victory") 540 reqs.progressives["Mastery"] = self.world.options.masteries_requirement.value
528 else:
529 reqs.items.add(f"{ending.name.capitalize()} Ending (Achieved)")
530 541
531 for sub_door_id in door.doors: 542 for sub_door_id in door.doors:
532 sub_reqs = self.get_door_open_reqs(sub_door_id) 543 sub_reqs = self.get_door_open_reqs(sub_door_id)
diff --git a/apworld/static_logic.py b/apworld/static_logic.py index 2546007..fb23e4c 100644 --- a/apworld/static_logic.py +++ b/apworld/static_logic.py
@@ -105,7 +105,7 @@ class Lingo2StaticLogic:
105 if door.type != data_pb2.DoorType.STANDARD: 105 if door.type != data_pb2.DoorType.STANDARD:
106 return None 106 return None
107 107
108 if len(door.keyholders) > 0 or len(door.endings) > 0 or door.HasField("complete_at"): 108 if len(door.keyholders) > 0 or door.white_ending or door.HasField("complete_at"):
109 return None 109 return None
110 110
111 if len(door.panels) > 4: 111 if len(door.panels) > 4: