LTTP: Rip Lttp specific entrance code out of core and use Region helpers (#1960)

This commit is contained in:
Aaron Wagener
2025-04-18 16:34:34 -05:00
committed by GitHub
parent cb3d35faf9
commit 1b51714f3b
7 changed files with 37 additions and 33 deletions

View File

@@ -1022,9 +1022,6 @@ class Entrance:
connected_region: Optional[Region] = None connected_region: Optional[Region] = None
randomization_group: int randomization_group: int
randomization_type: EntranceType randomization_type: EntranceType
# LttP specific, TODO: should make a LttPEntrance
addresses = None
target = None
def __init__(self, player: int, name: str = "", parent: Optional[Region] = None, def __init__(self, player: int, name: str = "", parent: Optional[Region] = None,
randomization_group: int = 0, randomization_type: EntranceType = EntranceType.ONE_WAY) -> None: randomization_group: int = 0, randomization_type: EntranceType = EntranceType.ONE_WAY) -> None:
@@ -1043,10 +1040,8 @@ class Entrance:
return False return False
def connect(self, region: Region, addresses: Any = None, target: Any = None) -> None: def connect(self, region: Region) -> None:
self.connected_region = region self.connected_region = region
self.target = target
self.addresses = addresses
region.entrances.append(self) region.entrances.append(self)
def is_valid_source_transition(self, er_state: "ERPlacementState") -> bool: def is_valid_source_transition(self, er_state: "ERPlacementState") -> bool:

View File

@@ -2,8 +2,6 @@
Helper functions to deliver entrance/exit/region sets to OWG rules. Helper functions to deliver entrance/exit/region sets to OWG rules.
""" """
from BaseClasses import Entrance
from .StateHelpers import can_lift_heavy_rocks, can_boots_clip_lw, can_boots_clip_dw, can_get_glitched_speed_dw from .StateHelpers import can_lift_heavy_rocks, can_boots_clip_lw, can_boots_clip_dw, can_get_glitched_speed_dw
@@ -279,18 +277,14 @@ def create_no_logic_connections(player, world, connections):
for entrance, parent_region, target_region, *rule_override in connections: for entrance, parent_region, target_region, *rule_override in connections:
parent = world.get_region(parent_region, player) parent = world.get_region(parent_region, player)
target = world.get_region(target_region, player) target = world.get_region(target_region, player)
connection = Entrance(player, entrance, parent) parent.connect(target, entrance)
parent.exits.append(connection)
connection.connect(target)
def create_owg_connections(player, world, connections): def create_owg_connections(player, world, connections):
for entrance, parent_region, target_region, *rule_override in connections: for entrance, parent_region, target_region, *rule_override in connections:
parent = world.get_region(parent_region, player) parent = world.get_region(parent_region, player)
target = world.get_region(target_region, player) target = world.get_region(target_region, player)
connection = Entrance(player, entrance, parent) parent.connect(target, entrance)
parent.exits.append(connection)
connection.connect(target)
def set_owg_connection_rules(player, world, connections, default_rule): def set_owg_connection_rules(player, world, connections, default_rule):

View File

@@ -1,11 +1,11 @@
import collections import collections
import typing import typing
from BaseClasses import Entrance, MultiWorld from BaseClasses import MultiWorld
from .SubClasses import LTTPRegion, LTTPRegionType from .SubClasses import LTTPEntrance, LTTPRegion, LTTPRegionType
def is_main_entrance(entrance: Entrance) -> bool: def is_main_entrance(entrance: LTTPEntrance) -> bool:
return entrance.parent_region.type in {LTTPRegionType.DarkWorld, LTTPRegionType.LightWorld} if entrance.parent_region.type else True return entrance.parent_region.type in {LTTPRegionType.DarkWorld, LTTPRegionType.LightWorld} if entrance.parent_region.type else True
@@ -410,7 +410,7 @@ def _create_region(world: MultiWorld, player: int, name: str, type: LTTPRegionTy
ret = LTTPRegion(name, type, hint, player, world) ret = LTTPRegion(name, type, hint, player, world)
if exits: if exits:
for exit in exits: for exit in exits:
ret.exits.append(Entrance(player, exit, ret)) ret.create_exit(exit)
if locations: if locations:
for location in locations: for location in locations:
if location in key_drop_data: if location in key_drop_data:

View File

@@ -3,7 +3,7 @@ import logging
from typing import Iterator, Set from typing import Iterator, Set
from Options import ItemsAccessibility from Options import ItemsAccessibility
from BaseClasses import Entrance, MultiWorld from BaseClasses import MultiWorld
from worlds.generic.Rules import (add_item_rule, add_rule, forbid_item, from worlds.generic.Rules import (add_item_rule, add_rule, forbid_item,
item_name_in_location_names, location_item_name, set_rule, allow_self_locking_items) item_name_in_location_names, location_item_name, set_rule, allow_self_locking_items)
@@ -1071,9 +1071,8 @@ def swordless_rules(world, player):
def add_connection(parent_name, target_name, entrance_name, world, player): def add_connection(parent_name, target_name, entrance_name, world, player):
parent = world.get_region(parent_name, player) parent = world.get_region(parent_name, player)
target = world.get_region(target_name, player) target = world.get_region(target_name, player)
connection = Entrance(player, entrance_name, parent) parent.connect(target, entrance_name)
parent.exits.append(connection)
connection.connect(target)
def standard_rules(world, player): def standard_rules(world, player):
@@ -1108,6 +1107,7 @@ def standard_rules(world, player):
set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest', player), set_rule(world.get_location('Hyrule Castle - Zelda\'s Chest', player),
lambda state: state.has('Big Key (Hyrule Castle)', player)) lambda state: state.has('Big Key (Hyrule Castle)', player))
def toss_junk_item(world, player): def toss_junk_item(world, player):
items = ['Rupees (20)', 'Bombs (3)', 'Arrows (10)', 'Rupees (5)', 'Rupee (1)', 'Bombs (10)', items = ['Rupees (20)', 'Bombs (3)', 'Arrows (10)', 'Rupees (5)', 'Rupee (1)', 'Bombs (10)',
'Single Arrow', 'Rupees (50)', 'Rupees (100)', 'Single Bomb', 'Bee', 'Bee Trap', 'Single Arrow', 'Rupees (50)', 'Rupees (100)', 'Single Bomb', 'Bee', 'Bee Trap',

View File

@@ -2,11 +2,10 @@
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from enum import IntEnum from enum import IntEnum
from BaseClasses import Location, Item, ItemClassification, Region, MultiWorld from BaseClasses import Entrance, Location, Item, ItemClassification, Region, MultiWorld
if TYPE_CHECKING: if TYPE_CHECKING:
from .Dungeons import Dungeon from .Dungeons import Dungeon
from .Regions import LTTPRegion
class ALttPLocation(Location): class ALttPLocation(Location):
@@ -77,6 +76,19 @@ class ALttPItem(Item):
return self.type return self.type
Addresses = int | list[int] | tuple[int, int, int, int, int, int, int, int, int, int, int, int, int]
class LTTPEntrance(Entrance):
addresses: Addresses | None = None
target: int | None = None
def connect(self, region: Region, addresses: Addresses | None = None, target: int | None = None) -> None:
super().connect(region)
self.addresses = addresses
self.target = target
class LTTPRegionType(IntEnum): class LTTPRegionType(IntEnum):
LightWorld = 1 LightWorld = 1
DarkWorld = 2 DarkWorld = 2
@@ -90,6 +102,7 @@ class LTTPRegionType(IntEnum):
class LTTPRegion(Region): class LTTPRegion(Region):
entrance_type = LTTPEntrance
type: LTTPRegionType type: LTTPRegionType
# will be set after making connections. # will be set after making connections.

View File

@@ -1,6 +1,6 @@
from BaseClasses import Entrance
from worlds.generic.Rules import set_rule, add_rule from worlds.generic.Rules import set_rule, add_rule
from .StateHelpers import can_bomb_clip, has_sword, has_beam_sword, has_fire_source, can_melt_things, has_misery_mire_medallion from .StateHelpers import can_bomb_clip, has_sword, has_beam_sword, has_fire_source, can_melt_things, has_misery_mire_medallion
from .SubClasses import LTTPEntrance
# We actually need the logic to properly "mark" these regions as Light or Dark world. # We actually need the logic to properly "mark" these regions as Light or Dark world.
@@ -9,17 +9,15 @@ def underworld_glitch_connections(world, player):
specrock = world.get_region('Spectacle Rock Cave (Bottom)', player) specrock = world.get_region('Spectacle Rock Cave (Bottom)', player)
mire = world.get_region('Misery Mire (West)', player) mire = world.get_region('Misery Mire (West)', player)
kikiskip = Entrance(player, 'Kiki Skip', specrock) kikiskip = specrock.create_exit('Kiki Skip')
mire_to_hera = Entrance(player, 'Mire to Hera Clip', mire) mire_to_hera = mire.create_exit('Mire to Hera Clip')
mire_to_swamp = Entrance(player, 'Hera to Swamp Clip', mire) mire_to_swamp = mire.create_exit('Hera to Swamp Clip')
specrock.exits.append(kikiskip)
mire.exits.extend([mire_to_hera, mire_to_swamp])
if world.worlds[player].fix_fake_world: if world.worlds[player].fix_fake_world:
kikiskip.connect(world.get_entrance('Palace of Darkness Exit', player).connected_region) kikiskip.connect(world.get_entrance('Palace of Darkness Exit', player).connected_region)
mire_to_hera.connect(world.get_entrance('Tower of Hera Exit', player).connected_region) mire_to_hera.connect(world.get_entrance('Tower of Hera Exit', player).connected_region)
mire_to_swamp.connect(world.get_entrance('Swamp Palace Exit', player).connected_region) mire_to_swamp.connect(world.get_entrance('Swamp Palace Exit', player).connected_region)
else: else:
kikiskip.connect(world.get_region('Palace of Darkness (Entrance)', player)) kikiskip.connect(world.get_region('Palace of Darkness (Entrance)', player))
mire_to_hera.connect(world.get_region('Tower of Hera (Bottom)', player)) mire_to_hera.connect(world.get_region('Tower of Hera (Bottom)', player))
mire_to_swamp.connect(world.get_region('Swamp Palace (Entrance)', player)) mire_to_swamp.connect(world.get_region('Swamp Palace (Entrance)', player))
@@ -37,7 +35,7 @@ def fake_pearl_state(state, player):
# Sets the rules on where we can actually go using this clip. # Sets the rules on where we can actually go using this clip.
# Behavior differs based on what type of ER shuffle we're playing. # Behavior differs based on what type of ER shuffle we're playing.
def dungeon_reentry_rules(world, player, clip: Entrance, dungeon_region: str, dungeon_exit: str): def dungeon_reentry_rules(world, player, clip: LTTPEntrance, dungeon_region: str, dungeon_exit: str):
fix_dungeon_exits = world.worlds[player].fix_palaceofdarkness_exit fix_dungeon_exits = world.worlds[player].fix_palaceofdarkness_exit
fix_fake_worlds = world.worlds[player].fix_fake_world fix_fake_worlds = world.worlds[player].fix_fake_world

View File

@@ -2640,9 +2640,13 @@ class PokemonRBWarp(Entrance):
self.warp_id = warp_id self.warp_id = warp_id
self.address = address self.address = address
self.flags = flags self.flags = flags
self.addresses = None
self.target = None
def connect(self, entrance): def connect(self, entrance):
super().connect(entrance.parent_region, None, target=entrance.warp_id) super().connect(entrance.parent_region)
self.addresses = None
self.target = entrance.warp_id
def access_rule(self, state): def access_rule(self, state):
if self.connected_region is None: if self.connected_region is None: