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
153 lines
7.8 KiB
Python
153 lines
7.8 KiB
Python
from typing_extensions import Any
|
|
|
|
from BaseClasses import Item, ItemClassification, Location, Region, LocationProgressType
|
|
from ..World import OracleOfSeasonsWorld
|
|
from ..Options import OracleOfSeasonsGoal, OracleOfSeasonsOldMenShuffle, OracleOfSeasonsLogicDifficulty
|
|
from ..data import LOCATIONS_DATA
|
|
from ..data.Constants import GASHA_SPOT_REGIONS, ITEM_GROUPS, SCRUB_LOCATIONS, SUBROSIA_HIDDEN_DIGGING_SPOTS_LOCATIONS, RUPEE_OLD_MAN_LOCATIONS, \
|
|
SECRETS, LOCATION_GROUPS
|
|
from ..data.Regions import REGIONS, NATZU_REGIONS, GASHA_REGIONS, D11_REGIONS
|
|
|
|
|
|
def location_is_active(world: OracleOfSeasonsWorld, location_name: str, location_data: dict[str, Any]) -> Any:
|
|
if not location_data.get("conditional", False):
|
|
return True
|
|
|
|
region_id = location_data["region_id"]
|
|
if region_id == "advance shop":
|
|
return world.options.advance_shop
|
|
if location_name in SUBROSIA_HIDDEN_DIGGING_SPOTS_LOCATIONS:
|
|
return world.options.shuffle_golden_ore_spots
|
|
if location_name in RUPEE_OLD_MAN_LOCATIONS:
|
|
return world.options.shuffle_old_men == OracleOfSeasonsOldMenShuffle.option_turn_into_locations
|
|
if location_name in SCRUB_LOCATIONS:
|
|
return world.options.shuffle_business_scrubs
|
|
if location_name == "Horon Village: Shop #3":
|
|
return not world.options.enforce_potion_in_shop
|
|
if location_name.startswith("Gasha Nut #"):
|
|
return int(location_name[11:]) <= world.options.deterministic_gasha_locations
|
|
if location_name == "Horon Village: Item Inside Maku Tree (3+ Essences)":
|
|
return len(world.essences_in_game) >= 3
|
|
if location_name == "Horon Village: Item Inside Maku Tree (5+ Essences)":
|
|
return len(world.essences_in_game) >= 5
|
|
if location_name == "Horon Village: Item Inside Maku Tree (7+ Essences)":
|
|
return len(world.essences_in_game) >= 7
|
|
if location_name in SECRETS:
|
|
return world.options.secret_locations
|
|
if location_name in LOCATION_GROUPS["D11"]:
|
|
return world.options.linked_heros_cave
|
|
return False
|
|
|
|
|
|
def create_location(world: OracleOfSeasonsWorld, region_name: str, location_name: str, local: bool) -> None:
|
|
region = world.multiworld.get_region(region_name, world.player)
|
|
location = Location(world.player, location_name, world.location_name_to_id[location_name], region)
|
|
region.locations.append(location)
|
|
if local:
|
|
location.item_rule = lambda item: item.player == world.player
|
|
|
|
|
|
def create_regions(world: OracleOfSeasonsWorld) -> None:
|
|
# Create regions
|
|
for region_name in REGIONS:
|
|
region = Region(region_name, world.player, world.multiworld)
|
|
world.multiworld.regions.append(region)
|
|
|
|
for region_name in NATZU_REGIONS[world.options.animal_companion.current_key]:
|
|
region = Region(region_name, world.player, world.multiworld)
|
|
world.multiworld.regions.append(region)
|
|
|
|
if world.options.logic_difficulty == OracleOfSeasonsLogicDifficulty.option_hell:
|
|
region = Region("rooster adventure", world.player, world.multiworld)
|
|
world.multiworld.regions.append(region)
|
|
|
|
if world.options.deterministic_gasha_locations > 0:
|
|
for i in range(world.options.deterministic_gasha_locations):
|
|
region = Region(GASHA_REGIONS[i], world.player, world.multiworld)
|
|
world.multiworld.regions.append(region)
|
|
|
|
if world.options.linked_heros_cave:
|
|
for region_name in D11_REGIONS:
|
|
world.multiworld.regions.append(Region(region_name, world.player, world.multiworld))
|
|
|
|
# Create locations
|
|
for location_name, location_data in LOCATIONS_DATA.items():
|
|
if not location_is_active(world, location_name, location_data):
|
|
continue
|
|
|
|
is_local = "local" in location_data and location_data["local"] is True
|
|
create_location(world, location_data["region_id"], location_name, is_local)
|
|
create_events(world)
|
|
exclude_locations_automatically(world)
|
|
|
|
|
|
def create_event(world: OracleOfSeasonsWorld, region_name: str, event_item_name: str) -> None:
|
|
region = world.multiworld.get_region(region_name, world.player)
|
|
location = Location(world.player, region_name + ".event", None, region)
|
|
region.locations.append(location)
|
|
location.place_locked_item(Item(event_item_name, ItemClassification.progression, None, world.player))
|
|
|
|
|
|
def create_events(world: OracleOfSeasonsWorld) -> None:
|
|
# Events for beating golden beasts
|
|
create_event(world, "golden darknut", "_beat_golden_darknut")
|
|
create_event(world, "golden lynel", "_beat_golden_lynel")
|
|
create_event(world, "golden octorok", "_beat_golden_octorok")
|
|
create_event(world, "golden moblin", "_beat_golden_moblin")
|
|
# Events for "wild" seeds that can be found inside respawnable bushes in dungeons
|
|
create_event(world, "d2 wild bombs", "_wild_bombs")
|
|
create_event(world, "d4 miniboss room wild embers", "_wild_ember_seeds")
|
|
create_event(world, "d5 armos chest", "_wild_ember_seeds")
|
|
create_event(world, "d7 entrance wild embers", "_wild_ember_seeds")
|
|
create_event(world, "frypolar room wild mystery", "_wild_mystery_seeds")
|
|
# Various events to help with logic
|
|
create_event(world, "bomb temple remains", "_triggered_volcano")
|
|
create_event(world, "subrosia pirates sector", "_met_pirates")
|
|
if world.options.logic_difficulty >= OracleOfSeasonsLogicDifficulty.option_medium:
|
|
create_event(world, "d2 rupee room", "_reached_d2_rupee_room")
|
|
create_event(world, "d6 rupee room", "_reached_d6_rupee_room")
|
|
create_event(world, "maku seed", "Maku Seed")
|
|
|
|
if world.options.goal == OracleOfSeasonsGoal.option_beat_onox:
|
|
create_event(world, "onox beaten", "_beaten_game")
|
|
elif world.options.goal == OracleOfSeasonsGoal.option_beat_ganon:
|
|
create_event(world, "ganon beaten", "_beaten_game")
|
|
|
|
# Create events for reaching Gasha spots, used when Gasha-sanity is on
|
|
for region_name in GASHA_SPOT_REGIONS:
|
|
create_event(world, region_name, f"_reached_{region_name}")
|
|
|
|
# Create event items to represent rupees obtained from Old Men, unless they are turned into locations
|
|
if world.options.shuffle_old_men != OracleOfSeasonsOldMenShuffle.option_turn_into_locations:
|
|
for region_name in world.old_man_rupee_values:
|
|
create_event(world, region_name, "rupees from " + region_name)
|
|
|
|
|
|
def exclude_locations_automatically(world: OracleOfSeasonsWorld) -> None:
|
|
locations_to_exclude = set()
|
|
# If goal essence requirement is set to a specific value, prevent essence-bound checks which require more
|
|
# essences than this goal to hold anything of value
|
|
if world.options.required_essences < 7 <= len(world.essences_in_game):
|
|
locations_to_exclude.add("Horon Village: Item Inside Maku Tree (7+ Essences)")
|
|
if world.options.required_essences < 5 <= len(world.essences_in_game):
|
|
locations_to_exclude.add("Horon Village: Item Inside Maku Tree (5+ Essences)")
|
|
if world.options.required_essences < 3 <= len(world.essences_in_game):
|
|
locations_to_exclude.add("Horon Village: Item Inside Maku Tree (3+ Essences)")
|
|
if world.options.required_essences < world.options.treehouse_old_man_requirement:
|
|
locations_to_exclude.add("Holodrum Plain: Old Man in Treehouse")
|
|
|
|
# If dungeons without essence need to be excluded, do it if conditions are met
|
|
if world.options.exclude_dungeons_without_essence and not world.options.shuffle_essences:
|
|
for i, essence_name in enumerate(ITEM_GROUPS["Essences"]):
|
|
if essence_name not in world.essences_in_game:
|
|
locations_to_exclude.update(world.location_name_groups[f"D{i + 1}"])
|
|
|
|
if not world.options.shuffle_business_scrubs:
|
|
locations_to_exclude.difference_update(SCRUB_LOCATIONS)
|
|
|
|
if world.options.randomize_ai:
|
|
locations_to_exclude.add("Western Coast: Black Beast's Chest")
|
|
|
|
for name in locations_to_exclude:
|
|
world.multiworld.get_location(name, world.player).progress_type = LocationProgressType.EXCLUDED
|