from typing import TYPE_CHECKING import BaseClasses from BaseClasses import Region, ItemClassification, Entrance from entrance_rando import randomize_entrances from .items import Lingo2Item from .locations import Lingo2Location from .player_logic import AccessRequirements from .rules import make_location_lambda if TYPE_CHECKING: from . import Lingo2World def create_region(room, world: "Lingo2World") -> Region: return Region(world.static_logic.get_room_region_name(room.id), world.player, world.multiworld) def create_locations(room, new_region: Region, world: "Lingo2World", regions: dict[str, Region]): for location in world.player_logic.locations_by_room.get(room.id, {}): reqs = location.reqs.copy() reqs.remove_room(new_region.name) new_location = Lingo2Location(world.player, world.static_logic.location_id_to_name[location.code], location.code, new_region) new_location.access_rule = make_location_lambda(reqs, world, regions) new_region.locations.append(new_location) for event_name, item_name in world.player_logic.event_loc_item_by_room.get(room.id, {}).items(): new_location = Lingo2Location(world.player, event_name, None, new_region) if world.for_tracker and item_name == "Victory": new_location.goal = True event_item = Lingo2Item(item_name, ItemClassification.progression, None, world.player) new_location.place_locked_item(event_item) new_region.locations.append(new_location) if world.for_tracker and world.options.shuffle_worldports: for port_id in room.ports: port = world.static_logic.objects.ports[port_id] if port.no_shuffle: continue new_location = Lingo2Location(world.player, f"Worldport {port.id} Entered", None, new_region) new_location.port_id = port.id if port.HasField("required_door"): new_location.access_rule = \ make_location_lambda(world.player_logic.get_door_open_reqs(port.required_door), world, regions) new_region.locations.append(new_location) def create_regions(world: "Lingo2World"): regions = { "Menu": Region("Menu", world.player, world.multiworld) } region_and_room = [] # Create the regions in two stages. First, make the actual region objects and memoize them. Then, add all of the # locations. This allows us to reference the actual region objects in the access rules for the locations, which is # faster than having to look them up during access checking. for room in world.static_logic.objects.rooms: if room.map_id not in world.player_logic.shuffled_maps: continue region = create_region(room, world) regions[region.name] = region region_and_room.append((region, room)) for (region, room) in region_and_room: create_locations(room, region, world, regions) regions["Menu"].connect(regions["The Entry - Starting Room"], "Start Game") for connection in world.static_logic.objects.connections: if connection.roof_access and not world.options.daedalus_roof_access: continue if connection.vanilla_only and world.options.shuffle_doors: continue from_region = world.static_logic.get_room_region_name(connection.from_room) to_region = world.static_logic.get_room_region_name(connection.to_room) if from_region not in regions or to_region not in regions: continue connection_name = f"{from_region} -> {to_region}" reqs = AccessRequirements() if connection.HasField("required_door"): reqs.merge(world.player_logic.get_door_open_reqs(connection.required_door)) door = world.static_logic.objects.doors[connection.required_door] wmap = world.static_logic.objects.maps[door.map_id] connection_name = f"{connection_name} (using {wmap.name} - {door.name})" if connection.HasField("port"): port = world.static_logic.objects.ports[connection.port] connection_name = f"{connection_name} (via {port.display_name})" if world.options.shuffle_worldports and not port.no_shuffle: continue if port.HasField("required_door"): reqs.merge(world.player_logic.get_door_open_reqs(port.required_door)) if connection.HasField
This map is a bit of a mess. The top areas should make sense but the bottom area
is confusing because of the fact that many panels can be seen from multiple
places in the grid, and it is intended for you to solve them through the
transparent doors. The approach to this is threefold.

1. Panels that can be solved without opening any doors are all in the Entry
   region. This includes the two panels physically accessible from the warp
   hallways, as well as the two panels each that can be seen while standing next
   to those panels, for a total of six panels in the Entry region (plus the two
   that are actually upstairs).
2. The part of the grid behind where you enter is actually completely linear.
   There is one region for each grid square in this area, except for the middle
   two in the orange row. The regions are named after the positions you stand
   in, not the panels at those positions in the grid. Instead, each region
   contains the panel you can see from that position. This is why the two middle
   orange grid squares do not have regions, because they are solvable from the
   red row and entering the regions does nothing.
3. For the rest of the grid, each panel is visible from two other grid
   positions. To handle this, there is a region for every grid position you can
   stand in, and a region for every panel. The standing regions are connected to
   each adjacent grid square using event doors, and there is a oneway connection
   from each standing region into the panel regions for each panel that can be
   seen from that standing position.