about summary refs log tree commit diff stats
path: root/data/maps/the_keen/rooms
diff options
context:
space:
mode:
Diffstat (limited to 'data/maps/the_keen/rooms')
0 files changed, 0 insertions, 0 deletions
/a> 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 216 217 218 219 220 221
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.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("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)

        if to_region in reqs.rooms:
            # This connection can't ever increase access because you're required to have access to the other side in
            # order for it to be usable. We will just not create the connection at all, in order to help GER figure out
            # what regions are dead ends.
            continue

        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.display_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.display_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)