Files
dockipelago/worlds/mk64/Regions.py
Jonathan Tinney 7971961166
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
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

137 lines
5.9 KiB
Python

from typing import TYPE_CHECKING
from BaseClasses import Region
from . import Courses
from .Locations import (MK64Location, Group, item_cluster_locations, course_locations, shared_hazard_locations,
cup_locations)
from .Options import GameMode
from .Rules import course_qualify_rules
if TYPE_CHECKING:
from . import MK64World
def add_region(world: "MK64World", region_name: str, region_group: list[Region]) -> None:
region_group.append(Region(region_name, world.player, world.multiworld))
def add_location(player: int, loc_name: str, code: int, region: Region) -> MK64Location:
location = MK64Location(player, loc_name, code, region)
region.locations.append(location)
return location
def create_regions_locations_connections(world: "MK64World"):
multiworld = world.multiworld
player = world.player
opt = world.opt
shuffle_clusters = world.shuffle_clusters
filler_spots = world.filler_spots
location_group_mask = (Group.base
| (opt.hazards and Group.hazard)
| (opt.secrets and Group.secret)
| (opt.special_boxes and Group.blue_shell_item_spot))
# Prepare Region Handling
menu_region = Region("Menu", player, multiworld)
course_regions: list[Region] = []
shared_hazard_regions: list[Region] = []
cup_regions: list[Region] = []
# Construct item_spot_locations for shuffled item clusters and extra locations
world.random.shuffle(shuffle_clusters)
world.random.shuffle(filler_spots)
item_spot_data = []
c, s, t = 0, 0, -1
for region in item_cluster_locations:
item_spot_data.append([])
for cluster in region:
if shuffle_clusters[c]:
t = world.random.randrange(0, len(cluster))
c += 1
for i, spot_data in enumerate(cluster):
if i == t:
item_spot_data[-1].append(spot_data)
t = -1
else:
if filler_spots[s]:
item_spot_data[-1].append(spot_data)
s += 1
# Construct Course Regions and Locations
for (course_name, locs), spot_data_clusters in zip(course_locations.items(), item_spot_data):
add_region(world, course_name, course_regions)
for loc_name, (code, group) in locs.items():
if group & location_group_mask:
add_location(player, loc_name, code, course_regions[-1])
for spot in spot_data_clusters:
spot_location = add_location(player, spot.name, spot.code, course_regions[-1])
if opt.fences and spot.access:
spot_location.access_rule = lambda state, access=spot.access: state.has_any(access, player)
# Shared Hazard Regions & Locations & Connections
if opt.hazards:
for name, (code, courses) in shared_hazard_locations.items():
add_region(world, name, shared_hazard_regions)
add_location(player, name, code, shared_hazard_regions[-1])
for c, region in enumerate(course_regions):
if c in courses:
region.connect(shared_hazard_regions[-1])
# Cup Regions & Locations
if opt.mode == GameMode.option_cups:
for cup, locations in cup_locations.items():
add_region(world, cup, cup_regions)
for name, code in locations.items():
add_location(player, name, code, cup_regions[-1])
# Determine Course Order
order = Courses.determine_order(world)
course_regions = [course_regions[i] for i in order]
# Create Course & Cup Connections
if opt.mode == GameMode.option_cups:
entrance_names = ["Mushroom Cup 1", "Mushroom Cup 2", "Mushroom Cup 3", "Mushroom Cup 4",
"Flower Cup 1", "Flower Cup 2", "Flower Cup 3", "Flower Cup 4",
"Star Cup 1", "Star Cup 2", "Star Cup 3", "Star Cup 4",
"Special Cup 1", "Special Cup 2", "Special Cup 3", "Special Cup 4"]
for c in range(16):
if c % 4:
course_regions[c-1].connect(
course_regions[c],
entrance_names[c],
lambda state, qualify_rule=course_qualify_rules[order[c-1]]:
qualify_rule(state, player, opt.logic, opt)
)
else:
menu_region.connect(course_regions[c], entrance_names[c],
lambda state, count=c//4: state.has("Progressive Cup Unlock", player, count))
course_regions[c+3].connect(cup_regions[c//4], entrance_names[c][:-1] + "Finish")
else: # GameMode.option_courses
for i in range(16):
locks = max(0, i + opt.locked_courses - 15)
rule = (lambda state, k=locks: state.has("Progressive Course Unlock", player, k)) if locks > 0 else None
menu_region.connect(course_regions[i], f"Course {i + 1}", rule)
# Register regions (and locations)
multiworld.regions += [menu_region] + course_regions + shared_hazard_regions + cup_regions
# Write course order to spoiler log
for i in range(16):
entrance = course_regions[i].entrances[0]
multiworld.spoiler.set_entrance(entrance.name, entrance.connected_region.name, "entrance", player)
# Uncomment to print course order at generation time
# print(entrance.name + " => " + entrance.connected_region.name)
# Place Victory Event Location
if opt.mode == GameMode.option_cups:
cup_regions[-1].locations[-1].address = None
cup_regions[-1].locations[-1].event = True
victory_location = cup_regions[-1].locations[-1]
else:
course_regions[15].locations[2].address = None
course_regions[15].locations[2].event = True
victory_location = course_regions[15].locations[2]
world.course_order = order
world.victory_location = victory_location