about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2026-01-30 10:50:01 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2026-01-30 10:50:01 -0500
commit9b5c160f60a4e6c679b0c1afca82d9a58523eaab (patch)
tree3def18df041138da0a7656efdc99008f8b13ffad
parente9e4a7a42ca17e7dc1947b012c5f6a50047c159e (diff)
downloadlingo2-archipelago-9b5c160f60a4e6c679b0c1afca82d9a58523eaab.tar.gz
lingo2-archipelago-9b5c160f60a4e6c679b0c1afca82d9a58523eaab.tar.bz2
lingo2-archipelago-9b5c160f60a4e6c679b0c1afca82d9a58523eaab.zip
Worked on daed-only mode daed-only
-rw-r--r--apworld/__init__.py1
-rw-r--r--apworld/client/main.gd10
-rw-r--r--apworld/client/manager.gd2
-rw-r--r--apworld/client/rteMenu.gd12
-rw-r--r--apworld/options.py11
-rw-r--r--apworld/player_logic.py60
-rw-r--r--apworld/regions.py10
7 files changed, 87 insertions, 19 deletions
diff --git a/apworld/__init__.py b/apworld/__init__.py index 3d2f075..27ed95a 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py
@@ -132,6 +132,7 @@ class Lingo2World(World):
132 def fill_slot_data(self): 132 def fill_slot_data(self):
133 slot_options = [ 133 slot_options = [
134 "cyan_door_behavior", 134 "cyan_door_behavior",
135 "daedalus_only",
135 "daedalus_roof_access", 136 "daedalus_roof_access",
136 "enable_gift_maps", 137 "enable_gift_maps",
137 "enable_icarus", 138 "enable_icarus",
diff --git a/apworld/client/main.gd b/apworld/client/main.gd index c90d6e7..8cac24c 100644 --- a/apworld/client/main.gd +++ b/apworld/client/main.gd
@@ -48,6 +48,7 @@ func _ready():
48 installScriptExtension(runtime.load_script("panel.gd")) 48 installScriptExtension(runtime.load_script("panel.gd"))
49 installScriptExtension(runtime.load_script("pauseMenu.gd")) 49 installScriptExtension(runtime.load_script("pauseMenu.gd"))
50 installScriptExtension(runtime.load_script("player.gd")) 50 installScriptExtension(runtime.load_script("player.gd"))
51 installScriptExtension(runtime.load_script("rteMenu.gd"))
51 installScriptExtension(runtime.load_script("saver.gd")) 52 installScriptExtension(runtime.load_script("saver.gd"))
52 installScriptExtension(runtime.load_script("teleport.gd")) 53 installScriptExtension(runtime.load_script("teleport.gd"))
53 installScriptExtension(runtime.load_script("teleportListener.gd")) 54 installScriptExtension(runtime.load_script("teleportListener.gd"))
@@ -229,7 +230,11 @@ func startGame():
229 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 230 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
230 global.user = ap.getSaveFileName() 231 global.user = ap.getSaveFileName()
231 global.universe = "lingo" 232 global.universe = "lingo"
232 global.map = "the_entry" 233
234 if ap.daedalus_only:
235 global.map = "daedalus"
236 else:
237 global.map = "the_entry"
233 238
234 unlocks.resetCollectables() 239 unlocks.resetCollectables()
235 unlocks.resetData() 240 unlocks.resetData()
@@ -263,6 +268,7 @@ func startGame():
263 clearResourceCache("res://objects/nodes/teleport.tscn") 268 clearResourceCache("res://objects/nodes/teleport.tscn")
264 clearResourceCache("res://objects/nodes/worldport.tscn") 269 clearResourceCache("res://objects/nodes/worldport.tscn")
265 clearResourceCache("res://objects/scenes/menus/pause_menu.tscn") 270 clearResourceCache("res://objects/scenes/menus/pause_menu.tscn")
271 clearResourceCache("res://objects/scenes/menus/rte_inner.tscn")
266 272
267 var paintings_dir = DirAccess.open("res://objects/meshes/paintings") 273 var paintings_dir = DirAccess.open("res://objects/meshes/paintings")
268 if paintings_dir: 274 if paintings_dir:
@@ -273,7 +279,7 @@ func startGame():
273 clearResourceCache("res://objects/meshes/paintings/" + file_name) 279 clearResourceCache("res://objects/meshes/paintings/" + file_name)
274 file_name = paintings_dir.get_next() 280 file_name = paintings_dir.get_next()
275 281
276 switcher.switch_map.call_deferred("res://objects/scenes/the_entry.tscn") 282 switcher.switch_map.call_deferred("res://objects/scenes/%s.tscn" % global.map)
277 283
278 284
279func connectionUnsuccessful(error_message): 285func connectionUnsuccessful(error_message):
diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 8c981f9..381a779 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd
@@ -64,6 +64,7 @@ const kEndingNameByVictoryValue = {
64 64
65var apworld_version = [0, 0, 0] 65var apworld_version = [0, 0, 0]
66var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 66var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2
67var daedalus_only = false
67var daedalus_roof_access = false 68var daedalus_roof_access = false
68var enable_gift_maps = [] 69var enable_gift_maps = []
69var enable_icarus = false 70var enable_icarus = false
@@ -463,6 +464,7 @@ func _client_connected(slot_data):
463 464
464 # Read slot data. 465 # Read slot data.
465 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0)) 466 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0))
467 daedalus_only = bool(slot_data.get("daedalus_only", false))
466 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) 468 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false))
467 enable_gift_maps = slot_data.get("enable_gift_maps", []) 469 enable_gift_maps = slot_data.get("enable_gift_maps", [])
468 enable_icarus = bool(slot_data.get("enable_icarus", false)) 470 enable_icarus = bool(slot_data.get("enable_icarus", false))
diff --git a/apworld/client/rteMenu.gd b/apworld/client/rteMenu.gd new file mode 100644 index 0000000..5882d77 --- /dev/null +++ b/apworld/client/rteMenu.gd
@@ -0,0 +1,12 @@
1extends "res://scripts/ui/rteMenu.gd"
2
3
4func _readier():
5 var ap = global.get_node("Archipelago")
6 if ap.daedalus_only:
7 get_node("rte_the_entry").hide()
8 get_node("rte_daedalus").show()
9
10 switcher.preload_map("res://objects/scenes/daedalus.tscn")
11 else:
12 super()._readier()
diff --git a/apworld/options.py b/apworld/options.py index f687434..1323635 100644 --- a/apworld/options.py +++ b/apworld/options.py
@@ -121,6 +121,16 @@ class EnableGiftMaps(OptionSet):
121 valid_keys = ["The Advanced", "The Charismatic", "The Crystalline", "The Fuzzy", "The Stellar"] 121 valid_keys = ["The Advanced", "The Charismatic", "The Crystalline", "The Fuzzy", "The Stellar"]
122 122
123 123
124class DaedalusOnly(Toggle):
125 """
126 If enabled, all maps besides Daedalus, The Gold, and The Tenacious will be disabled. This overrides any other
127 map-based option, such as Enable Icarus. The player will start in Daedalus. The ending must be set to Orange or
128 Gold. Worldport shuffle must be enabled. Letter shuffle cannot be set to a vanilla value. Cyan Door Behavior cannot
129 be set to Collect H2.
130 """
131 display_name = "Daedalus Only"
132
133
124class DaedalusRoofAccess(Toggle): 134class DaedalusRoofAccess(Toggle):
125 """ 135 """
126 If enabled, the player will be logically expected to be able to go from the castle entrance to any part of Daedalus 136 If enabled, the player will be logically expected to be able to go from the castle entrance to any part of Daedalus
@@ -221,6 +231,7 @@ class Lingo2Options(PerGameCommonOptions):
221 cyan_door_behavior: CyanDoorBehavior 231 cyan_door_behavior: CyanDoorBehavior
222 enable_icarus: EnableIcarus 232 enable_icarus: EnableIcarus
223 enable_gift_maps: EnableGiftMaps 233 enable_gift_maps: EnableGiftMaps
234 daedalus_only: DaedalusOnly
224 daedalus_roof_access: DaedalusRoofAccess 235 daedalus_roof_access: DaedalusRoofAccess
225 strict_purple_ending: StrictPurpleEnding 236 strict_purple_ending: StrictPurpleEnding
226 strict_cyan_ending: StrictCyanEnding 237 strict_cyan_ending: StrictCyanEnding
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 3ee8f38..aea7698 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -203,6 +203,8 @@ class Lingo2PlayerLogic:
203 world: "Lingo2World" 203 world: "Lingo2World"
204 204
205 shuffled_maps: set[int] 205 shuffled_maps: set[int]
206 shuffled_rooms: set[int]
207 shuffled_doors: set[int]
206 208
207 locations_by_room: dict[int, list[PlayerLocation]] 209 locations_by_room: dict[int, list[PlayerLocation]]
208 event_loc_item_by_room: dict[int, dict[str, str]] 210 event_loc_item_by_room: dict[int, dict[str, str]]
@@ -220,6 +222,8 @@ class Lingo2PlayerLogic:
220 222
221 def __init__(self, world: "Lingo2World"): 223 def __init__(self, world: "Lingo2World"):
222 self.world = world 224 self.world = world
225 self.shuffled_rooms = set()
226 self.shuffled_doors = set()
223 self.locations_by_room = {} 227 self.locations_by_room = {}
224 self.event_loc_item_by_room = {} 228 self.event_loc_item_by_room = {}
225 self.item_by_door = {} 229 self.item_by_door = {}
@@ -229,7 +233,10 @@ class Lingo2PlayerLogic:
229 self.real_items = list() 233 self.real_items = list()
230 self.double_letter_amount = dict() 234 self.double_letter_amount = dict()
231 235
232 def should_shuffle_map(game_map) -> bool: 236 def should_shuffle_map(game_map) -> bool | set[int]:
237 if world.options.daedalus_only:
238 return game_map.daedalus_only_mode == data_pb2.DaedalusOnlyMode.DAED_ONLY_ALLOW
239
233 if game_map.type == data_pb2.MapType.NORMAL_MAP: 240 if game_map.type == data_pb2.MapType.NORMAL_MAP:
234 return True 241 return True
235 elif game_map.type == data_pb2.MapType.ICARUS: 242 elif game_map.type == data_pb2.MapType.ICARUS:
@@ -251,6 +258,14 @@ class Lingo2PlayerLogic:
251 self.shuffled_maps = set(game_map.id for game_map in world.static_logic.objects.maps 258 self.shuffled_maps = set(game_map.id for game_map in world.static_logic.objects.maps
252 if should_shuffle_map(game_map)) 259 if should_shuffle_map(game_map))
253 260
261 if world.options.daedalus_only:
262 for game_map in world.static_logic.objects.maps:
263 if game_map.daedalus_only_mode == data_pb2.DaedalusOnlyMode.DAED_ONLY_PARTIAL:
264 self.shuffled_rooms.update(set(room.id for room in world.static_logic.objects.rooms
265 if room.map_id == game_map.id and room.daedalus_only_allow))
266 self.shuffled_doors.update(set(door.id for door in world.static_logic.objects.doors
267 if door.map_id == game_map.id and door.daedalus_only_allow))
268
254 maximum_masteries = 13 + len(world.options.enable_gift_maps.value) 269 maximum_masteries = 13 + len(world.options.enable_gift_maps.value)
255 if world.options.enable_icarus: 270 if world.options.enable_icarus:
256 maximum_masteries += 1 271 maximum_masteries += 1
@@ -265,7 +280,7 @@ class Lingo2PlayerLogic:
265 for progressive in world.static_logic.objects.progressives: 280 for progressive in world.static_logic.objects.progressives:
266 for i in range(0, len(progressive.doors)): 281 for i in range(0, len(progressive.doors)):
267 door = world.static_logic.objects.doors[progressive.doors[i]] 282 door = world.static_logic.objects.doors[progressive.doors[i]]
268 if door.map_id not in self.shuffled_maps: 283 if not self.should_shuffle_door(door.id):
269 continue 284 continue
270 285
271 self.item_by_door[progressive.doors[i]] = (progressive.name, i + 1) 286 self.item_by_door[progressive.doors[i]] = (progressive.name, i + 1)
@@ -279,13 +294,15 @@ class Lingo2PlayerLogic:
279 if not self.world.options.shuffle_control_center_colors or self.world.options.shuffle_worldports: 294 if not self.world.options.shuffle_control_center_colors or self.world.options.shuffle_worldports:
280 continue 295 continue
281 elif door_group.type == data_pb2.DoorGroupType.SHUFFLE_GROUP: 296 elif door_group.type == data_pb2.DoorGroupType.SHUFFLE_GROUP:
282 if not self.world.options.shuffle_doors: 297 if door_group.name == "Lavender Cubes" and self.world.options.daedalus_only:
298 # Always shuffle this if we're in Daed-only mode.
299 pass
300 elif not self.world.options.shuffle_doors:
283 continue 301 continue
284 else: 302 else:
285 continue 303 continue
286 304
287 shuffleable_doors = [door_id for door_id in door_group.doors 305 shuffleable_doors = [door_id for door_id in door_group.doors if self.should_shuffle_door(door_id)]
288 if world.static_logic.objects.doors[door_id].map_id in self.shuffled_maps]
289 306
290 if len(shuffleable_doors) > 0: 307 if len(shuffleable_doors) > 0:
291 for door in shuffleable_doors: 308 for door in shuffleable_doors:
@@ -296,7 +313,7 @@ class Lingo2PlayerLogic:
296 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled 313 # We iterate through the doors in two parts because it is essential that we determine which doors are shuffled
297 # before we calculate any access requirements. 314 # before we calculate any access requirements.
298 for door in world.static_logic.objects.doors: 315 for door in world.static_logic.objects.doors:
299 if door.map_id not in self.shuffled_maps: 316 if not self.should_shuffle_door(door.id):
300 continue 317 continue
301 318
302 if door.type in [data_pb2.DoorType.EVENT, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]: 319 if door.type in [data_pb2.DoorType.EVENT, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]:
@@ -328,8 +345,7 @@ class Lingo2PlayerLogic:
328 continue 345 continue
329 346
330 shuffleable_doors = [door_id for door_id in door_group.doors 347 shuffleable_doors = [door_id for door_id in door_group.doors
331 if world.static_logic.objects.doors[door_id].map_id in self.shuffled_maps 348 if self.should_shuffle_door(door_id) and door_id not in self.item_by_door]
332 and door_id not in self.item_by_door]
333 349
334 if len(shuffleable_doors) > 0: 350 if len(shuffleable_doors) > 0:
335 for door in shuffleable_doors: 351 for door in shuffleable_doors:
@@ -338,7 +354,7 @@ class Lingo2PlayerLogic:
338 self.real_items.append(door_group.name) 354 self.real_items.append(door_group.name)
339 355
340 for door in world.static_logic.objects.doors: 356 for door in world.static_logic.objects.doors:
341 if door.map_id not in self.shuffled_maps: 357 if not self.should_shuffle_door(door.id):
342 continue 358 continue
343 359
344 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]: 360 if door.type in [data_pb2.DoorType.STANDARD, data_pb2.DoorType.LOCATION_ONLY, data_pb2.DoorType.GRAVESTONE]:
@@ -346,7 +362,7 @@ class Lingo2PlayerLogic:
346 self.get_door_reqs(door.id))) 362 self.get_door_reqs(door.id)))
347 363
348 for letter in world.static_logic.objects.letters: 364 for letter in world.static_logic.objects.letters:
349 if world.static_logic.get_room_object_map_id(letter) not in self.shuffled_maps: 365 if not self.should_shuffle_room(letter.room_id):
350 continue 366 continue
351 367
352 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id, 368 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id,
@@ -368,7 +384,7 @@ class Lingo2PlayerLogic:
368 self.double_letter_amount[letter.key.upper()] = self.double_letter_amount.get(letter.key.upper(), 0) + 1 384 self.double_letter_amount[letter.key.upper()] = self.double_letter_amount.get(letter.key.upper(), 0) + 1
369 385
370 for mastery in world.static_logic.objects.masteries: 386 for mastery in world.static_logic.objects.masteries:
371 if world.static_logic.get_room_object_map_id(mastery) not in self.shuffled_maps: 387 if not self.should_shuffle_room(mastery.room_id):
372 continue 388 continue
373 389
374 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id, 390 self.locations_by_room.setdefault(mastery.room_id, []).append(PlayerLocation(mastery.ap_id,
@@ -379,7 +395,7 @@ class Lingo2PlayerLogic:
379 self.event_loc_item_by_room.setdefault(mastery.room_id, {})[event_name] = "Mastery" 395 self.event_loc_item_by_room.setdefault(mastery.room_id, {})[event_name] = "Mastery"
380 396
381 for ending in world.static_logic.objects.endings: 397 for ending in world.static_logic.objects.endings:
382 if world.static_logic.get_room_object_map_id(ending) not in self.shuffled_maps: 398 if not self.should_shuffle_room(ending.room_id):
383 continue 399 continue
384 400
385 # Don't create a location for your selected ending. Also don't create a location for White Ending if it's 401 # Don't create a location for your selected ending. Also don't create a location for White Ending if it's
@@ -401,7 +417,7 @@ class Lingo2PlayerLogic:
401 if self.world.options.keyholder_sanity: 417 if self.world.options.keyholder_sanity:
402 for keyholder in world.static_logic.objects.keyholders: 418 for keyholder in world.static_logic.objects.keyholders:
403 if keyholder.HasField("key"): 419 if keyholder.HasField("key"):
404 if world.static_logic.get_room_object_map_id(keyholder) not in self.shuffled_maps: 420 if not self.should_shuffle_room(keyholder.room_id):
405 continue 421 continue
406 422
407 reqs = AccessRequirements() 423 reqs = AccessRequirements()
@@ -606,3 +622,21 @@ class Lingo2PlayerLogic:
606 622
607 if any(l.isnumeric() for l in solution): 623 if any(l.isnumeric() for l in solution):
608 reqs.items.add("Numbers") 624 reqs.items.add("Numbers")
625
626 def should_shuffle_room(self, room_id: int) -> bool:
627 if room_id in self.shuffled_rooms:
628 return True
629
630 room = self.world.static_logic.objects.rooms[room_id]
631 game_map = self.world.static_logic.objects.maps[room.map_id]
632
633 return game_map.id in self.shuffled_maps
634
635 def should_shuffle_door(self, door_id: int) -> bool:
636 if door_id in self.shuffled_doors:
637 return True
638
639 door = self.world.static_logic.objects.doors[door_id]
640 game_map = self.world.static_logic.objects.maps[door.map_id]
641
642 return game_map.id in self.shuffled_maps
diff --git a/apworld/regions.py b/apworld/regions.py index 1118603..2f9b571 100644 --- a/apworld/regions.py +++ b/apworld/regions.py
@@ -62,7 +62,7 @@ def create_regions(world: "Lingo2World"):
62 # locations. This allows us to reference the actual region objects in the access rules for the locations, which is 62 # locations. This allows us to reference the actual region objects in the access rules for the locations, which is
63 # faster than having to look them up during access checking. 63 # faster than having to look them up during access checking.
64 for room in world.static_logic.objects.rooms: 64 for room in world.static_logic.objects.rooms:
65 if room.map_id not in world.player_logic.shuffled_maps: 65 if not world.player_logic.should_shuffle_room(room.id):
66 continue 66 continue
67 67
68 region = create_region(room, world) 68 region = create_region(room, world)
@@ -72,7 +72,10 @@ def create_regions(world: "Lingo2World"):
72 for (region, room) in region_and_room: 72 for (region, room) in region_and_room:
73 create_locations(room, region, world, regions) 73 create_locations(room, region, world, regions)
74 74
75 regions["Menu"].connect(regions["The Entry - Starting Room"], "Start Game") 75 if world.options.daedalus_only:
76 regions["Menu"].connect(regions["Daedalus - Starting Room"], "Start Game")
77 else:
78 regions["Menu"].connect(regions["The Entry - Starting Room"], "Start Game")
76 79
77 for connection in world.static_logic.objects.connections: 80 for connection in world.static_logic.objects.connections:
78 if connection.roof_access and not world.options.daedalus_roof_access: 81 if connection.roof_access and not world.options.daedalus_roof_access:
@@ -160,8 +163,7 @@ def shuffle_entrances(world: "Lingo2World"):
160 port_id_by_name: dict[str, int] = {} 163 port_id_by_name: dict[str, int] = {}
161 164
162 shuffleable_ports = [port for port in world.static_logic.objects.ports 165 shuffleable_ports = [port for port in world.static_logic.objects.ports
163 if not port.no_shuffle 166 if not port.no_shuffle and world.player_logic.should_shuffle_room(port.room_id)]
164 and world.static_logic.get_room_object_map_id(port) in world.player_logic.shuffled_maps]
165 167
166 if len(shuffleable_ports) % 2 == 1: 168 if len(shuffleable_ports) % 2 == 1:
167 # We have an odd number of shuffleable ports! Pick a port from a room that has more than one, and make it a 169 # We have an odd number of shuffleable ports! Pick a port from a room that has more than one, and make it a