about summary refs log tree commit diff stats
path: root/data/maps/the_extravagant/rooms/X Plus.txtpb
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-09-01 14:50:47 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-09-01 14:50:47 -0400
commit7f5f14ddb5a67e1ccfdc7aa3d68d829473d0b745 (patch)
tree3fa17e011d0b4b4824e8d887949bffa476eb8cb2 /data/maps/the_extravagant/rooms/X Plus.txtpb
parentffc3276b11308bdf0d42a07820aaaa44e3534b4e (diff)
downloadlingo2-archipelago-7f5f14ddb5a67e1ccfdc7aa3d68d829473d0b745.tar.gz
lingo2-archipelago-7f5f14ddb5a67e1ccfdc7aa3d68d829473d0b745.tar.bz2
lingo2-archipelago-7f5f14ddb5a67e1ccfdc7aa3d68d829473d0b745.zip
[Client] Handle progressive doors
Diffstat (limited to 'data/maps/the_extravagant/rooms/X Plus.txtpb')
0 files changed, 0 insertions, 0 deletions
a> 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
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:
        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 {port.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("painting"):
            painting = world.static_logic.objects.paintings[connection.painting]
            connection_name = f"{connection_name} (via painting {painting.name})"

            if painting.HasField("required_door"):
                reqs.merge(world.player_logic.get_door_open_reqs(painting.required_door))

        if connection.HasField("panel"):
            proxy = connection.panel
            reqs.merge(world.player_logic.get_panel_reqs(proxy.panel,
                                                         proxy.answer if proxy.HasField("answer") else None))

            panel = world.static_logic.objects.panels[proxy.panel]
            if proxy.HasField("answer"):
                connection_name = f"{connection_name} (via panel {panel.name}/{proxy.answer})"
            else:
                connection_name = f"{connection_name} (via panel {panel.name})"

        if connection.HasField("purple_ending") and connection.purple_ending and world.options.strict_purple_ending:
            world.player_logic.add_solution_reqs(reqs, "abcdefghijklmnopqrstuvwxyz")

        if connection.HasField("cyan_ending") and connection.cyan_ending and world.options.strict_cyan_ending:
            world.player_logic.add_solution_reqs(reqs, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")

        reqs.simplify()
        reqs.remove_room(from_region)

        connection = Entrance(world.player, connection_name, regions[from_region])
        connection.access_rule = make_location_lambda(reqs, world, regions)

        regions[from_region].exits.append(connection)
        connection.connect(regions[to_region])

        for region in reqs.get_referenced_rooms():
            world.multiworld.register_indirect_condition(regions[region], connection)

    world.multiworld.regions += regions.values()


def shuffle_entrances(world: "Lingo2World"):
    er_entrances: list[Entrance] = []
    er_exits: list[Entrance] = []

    port_id_by_name: dict[str, int] = {}

    for port in world.static_logic.objects.ports:
        if port.no_shuffle:
            continue

        port_region_name = world.static_logic.get_room_region_name(port.room_id)
        port_region = world.multiworld.get_region(port_region_name, world.player)

        connection_name = f"{port_region_name} - {port.name}"
        port_id_by_name[connection_name] = port.id

        entrance = port_region.create_er_target(connection_name)
        entrance.randomization_type = BaseClasses.EntranceType.TWO_WAY

        er_exit = port_region.create_exit(connection_name)
        er_exit.randomization_type = BaseClasses.EntranceType.TWO_WAY

        if port.HasField("required_door"):
            door_reqs = world.player_logic.get_door_open_reqs(port.required_door)
            er_exit.access_rule = make_location_lambda(door_reqs, world, None)

            for region in door_reqs.get_referenced_rooms():
                world.multiworld.register_indirect_condition(world.multiworld.get_region(region, world.player),
                                                             er_exit)

        er_entrances.append(entrance)
        er_exits.append(er_exit)

    result = randomize_entrances(world, True, {0:[0]}, False, er_entrances,
                                 er_exits)

    for (f, to) in result.pairings:
        world.port_pairings[port_id_by_name[f]] = port_id_by_name[to]


def connect_ports_from_ut(port_pairings: dict[int, int], world: "Lingo2World"):
    for fpid, tpid in port_pairings.items():
        from_port = world.static_logic.objects.ports[fpid]
        to_port = world.static_logic.objects.ports[tpid]

        from_region_name = world.static_logic.get_room_region_name(from_port.room_id)
        to_region_name = world.static_logic.get_room_region_name(to_port.room_id)

        from_region = world.multiworld.get_region(from_region_name, world.player)
        to_region = world.multiworld.get_region(to_region_name, world.player)

        connection = Entrance(world.player, f"{from_region_name} - {from_port.name}", from_region)

        reqs = AccessRequirements()
        if from_port.HasField("required_door"):
            reqs = world.player_logic.get_door_open_reqs(from_port.required_door).copy()

        if world.for_tracker:
            reqs.items.add(f"Worldport {fpid} Entered")

        if not reqs.is_empty():
            connection.access_rule = make_location_lambda(reqs, world, None)

            for region in reqs.get_referenced_rooms():
                world.multiworld.register_indirect_condition(world.multiworld.get_region(region, world.player),
                                                             connection)

        from_region.exits.append(connection)
        connection.connect(to_region)