forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
203 lines
8.3 KiB
Python
203 lines
8.3 KiB
Python
from BaseClasses import MultiWorld, Item, EntranceType
|
|
from ..data.logic.DungeonsLogic import *
|
|
from ..data.logic.OverworldLogic import *
|
|
from ..data.logic.SubrosiaLogic import *
|
|
|
|
|
|
def create_randomizable_connections(world: OracleOfSeasonsWorld, prefix: str,
|
|
vanilla_connections: dict[str, str], outer_group: int, inner_group: int):
|
|
for reg1, reg2 in vanilla_connections.items():
|
|
region_1 = world.get_region(reg1)
|
|
region_2 = world.get_region(reg2)
|
|
|
|
entrance = region_1.create_exit(f"{prefix}{reg1}")
|
|
entrance.randomization_group = outer_group
|
|
entrance.randomization_type = EntranceType.TWO_WAY
|
|
world.set_rule(entrance, True_())
|
|
|
|
entrance = region_1.create_er_target(f"{prefix}{reg1}")
|
|
entrance.randomization_group = outer_group
|
|
entrance.randomization_type = EntranceType.TWO_WAY
|
|
|
|
entrance = region_2.create_exit(f"{prefix}{reg2}")
|
|
entrance.randomization_group = inner_group
|
|
entrance.randomization_type = EntranceType.TWO_WAY
|
|
world.set_rule(entrance, True_())
|
|
|
|
entrance = region_2.create_er_target(f"{prefix}{reg2}")
|
|
entrance.randomization_group = inner_group
|
|
entrance.randomization_type = EntranceType.TWO_WAY
|
|
|
|
|
|
def create_connections(world: OracleOfSeasonsWorld, origin_name: str, options):
|
|
all_logic = [
|
|
make_holodrum_logic(origin_name, options),
|
|
make_subrosia_logic(),
|
|
make_d0_logic(),
|
|
make_d1_logic(),
|
|
make_d2_logic(),
|
|
make_d3_logic(),
|
|
make_d4_logic(),
|
|
make_d5_logic(),
|
|
make_d6_logic(),
|
|
make_d7_logic(),
|
|
make_d8_logic(),
|
|
|
|
make_samasa_d11_logic(options),
|
|
make_d11_logic(options)
|
|
]
|
|
|
|
if world.options.shuffle_dungeons:
|
|
create_randomizable_connections(world, "", world.dungeon_entrances,
|
|
OracleOfSeasonsConnectionType.CONNECT_DUNGEON_OVERWORLD,
|
|
OracleOfSeasonsConnectionType.CONNECT_DUNGEON_INSIDE)
|
|
else:
|
|
dungeon_entrances = []
|
|
for reg1, reg2 in world.dungeon_entrances.items():
|
|
dungeon_entrances.append([reg1, reg2, True, None])
|
|
all_logic.append(dungeon_entrances)
|
|
|
|
if world.options.shuffle_portals:
|
|
create_randomizable_connections(world, "enter ", PORTAL_CONNECTIONS,
|
|
OracleOfSeasonsConnectionType.CONNECT_PORTAL_OVERWORLD,
|
|
OracleOfSeasonsConnectionType.CONNECT_PORTAL_SUBROSIA)
|
|
else:
|
|
portal_connections = []
|
|
for reg1, reg2 in PORTAL_CONNECTIONS.items():
|
|
portal_connections.append([reg1, reg2, True, None])
|
|
all_logic.append(portal_connections)
|
|
|
|
true_rule = True_()
|
|
# Create connections
|
|
for logic_array in all_logic:
|
|
for entrance_desc in logic_array:
|
|
region_1 = world.get_region(entrance_desc[0])
|
|
region_2 = world.get_region(entrance_desc[1])
|
|
is_two_way = entrance_desc[2]
|
|
rule = entrance_desc[3]
|
|
if rule is None:
|
|
rule = true_rule
|
|
|
|
entrance = region_1.connect(region_2, None)
|
|
world.set_rule(entrance, rule)
|
|
if is_two_way:
|
|
entrance = region_2.connect(region_1, None)
|
|
world.set_rule(entrance, rule)
|
|
|
|
|
|
def apply_self_locking_rules(multiworld: MultiWorld, player: int):
|
|
if multiworld.worlds[player].options.accessibility == Accessibility.option_full:
|
|
return
|
|
|
|
# Process self-locking keys first
|
|
key_rules = {
|
|
"Hero's Cave: Final Chest": lambda state, item: any([
|
|
is_small_key(item, player, 0),
|
|
is_item(item, player, f"Master Key ({DUNGEON_NAMES[0]})")
|
|
]),
|
|
"Gnarled Root Dungeon: Item in Basement": lambda state, item: all([
|
|
is_small_key(item, player, 1),
|
|
oos_has_small_keys(1, 1).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Snake's Remains: Chest on Terrace": lambda state, item: all([
|
|
is_small_key(item, player, 2),
|
|
oos_has_small_keys(2, 2).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Poison Moth's Lair (1F): Chest in Mimics Room": lambda state, item: all([
|
|
is_small_key(item, player, 3),
|
|
oos_can_kill_normal_enemy().resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Dancing Dragon Dungeon (1F): Crumbling Room Chest": lambda state, item: all([
|
|
is_small_key(item, player, 4),
|
|
oos_has_small_keys(4, 2).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Dancing Dragon Dungeon (1F): Eye Diving Spot Item": lambda state, item: all([
|
|
is_small_key(item, player, 4),
|
|
(oos_has_small_keys(4, 2) & oos_can_swim(False)).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Unicorn's Cave: Magnet Gloves Chest": lambda state, item: is_small_key(item, player, 5),
|
|
"Unicorn's Cave: Treadmills Basement Item": lambda state, item: all([
|
|
is_small_key(item, player, 5),
|
|
And(
|
|
oos_has_small_keys(5, 3),
|
|
CanReachRegion("d5 drop ball"),
|
|
oos_has_magnet_gloves(),
|
|
Or(
|
|
oos_can_kill_magunesu(),
|
|
And(
|
|
oos_option_medium_logic(),
|
|
oos_has_feather()
|
|
)
|
|
)
|
|
).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Explorer's Crypt (B1F): Chest in Jumping Stalfos Room": lambda state, item: all([
|
|
is_small_key(item, player, 7),
|
|
And(
|
|
oos_has_small_keys(7, 4),
|
|
Or(
|
|
oos_can_jump_5_wide_pit(),
|
|
And(
|
|
oos_option_hard_logic(),
|
|
oos_can_jump_1_wide_pit(False)
|
|
)
|
|
),
|
|
oos_can_kill_stalfos(),
|
|
).resolve(multiworld.worlds[player])(state)
|
|
]),
|
|
"Explorer's Crypt (1F): Chest Right of Entrance": lambda state, item: all([
|
|
is_small_key(item, player, 7),
|
|
And(
|
|
oos_can_kill_normal_enemy(),
|
|
oos_has_small_keys(7, 1),
|
|
).resolve(multiworld.worlds[player])(state)
|
|
])
|
|
}
|
|
|
|
for location_name, key_rule in key_rules.items():
|
|
location = multiworld.get_location(location_name, player)
|
|
location.always_allow = key_rule
|
|
|
|
# Process other self-locking items
|
|
OTHER_SELF_LOCKING_ITEMS = {
|
|
"North Horon: Malon Trade": "Cuccodex",
|
|
"Maple Trade": "Lon Lon Egg",
|
|
"Holodrum Plain: Mrs. Ruul Trade": "Ghastly Doll",
|
|
"Subrosia: Subrosian Chef Trade": "Iron Pot",
|
|
"Sunken City: Ingo Trade": "Goron Vase",
|
|
"North Horon: Yelling Old Man Trade": "Fish",
|
|
"Horon Village: Tick Tock Trade": "Wooden Bird",
|
|
"Eastern Suburbs: Guru-Guru Trade": "Engine Grease",
|
|
"Subrosia: Smithy Hard Ore Reforge": "Hard Ore",
|
|
"Subrosia: Smithy Rusty Bell Reforge": "Rusty Bell",
|
|
"Sunken City: Master's Plaque Trade": "Master's Plaque",
|
|
"Subrosia: Market #1": "Star Ore",
|
|
}
|
|
if not multiworld.worlds[player].options.secret_locations:
|
|
OTHER_SELF_LOCKING_ITEMS["Goron Mountain: Biggoron Trade"] = "Lava Soup"
|
|
|
|
for loc_name, item_name in OTHER_SELF_LOCKING_ITEMS.items():
|
|
location = multiworld.get_location(loc_name, player)
|
|
location.always_allow = make_self_locking_item_lambda(player, item_name)
|
|
|
|
# Great Furnace special case
|
|
location = multiworld.get_location("Subrosia: Item Smelted in Great Furnace", player)
|
|
location.always_allow = lambda state, item: (item.player == player and item.name in ["Red Ore", "Blue Ore"])
|
|
|
|
|
|
def is_small_key(item: Item, player: int, dungeon: int):
|
|
return is_item(item, player, f"Small Key ({DUNGEON_NAMES[dungeon]})")
|
|
|
|
|
|
def is_item(item: Item, player: int, item_name: str):
|
|
return item.player == player and item.name == item_name
|
|
|
|
|
|
def make_self_locking_item_lambda(player: int, item_name: str, required_count: int = 0):
|
|
if required_count == 0:
|
|
return lambda state, item: (item.player == player and item.name == item_name)
|
|
|
|
return lambda state, item: (item.player == player
|
|
and item.name == item_name
|
|
and state.has(item_name, player, required_count))
|