Archipelago/worlds/sc2wol/Regions.py

163 lines
8.9 KiB
Python
Raw Normal View History

from typing import List, Set, Dict, Tuple, Optional, Callable
from BaseClasses import MultiWorld, Region, Entrance, Location, RegionType
from .Locations import LocationData
def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData, ...], location_cache: List[Location]):
locations_per_region = get_locations_per_region(locations)
regions = [
create_region(world, player, locations_per_region, location_cache, "Menu"),
create_region(world, player, locations_per_region, location_cache, "Liberation Day"),
create_region(world, player, locations_per_region, location_cache, "The Outlaws"),
create_region(world, player, locations_per_region, location_cache, "Zero Hour"),
create_region(world, player, locations_per_region, location_cache, "Evacuation"),
create_region(world, player, locations_per_region, location_cache, "Outbreak"),
create_region(world, player, locations_per_region, location_cache, "Safe Haven"),
create_region(world, player, locations_per_region, location_cache, "Haven's Fall"),
create_region(world, player, locations_per_region, location_cache, "Smash and Grab"),
create_region(world, player, locations_per_region, location_cache, "The Dig"),
create_region(world, player, locations_per_region, location_cache, "The Moebius Factor"),
create_region(world, player, locations_per_region, location_cache, "Supernova"),
create_region(world, player, locations_per_region, location_cache, "Maw of the Void"),
create_region(world, player, locations_per_region, location_cache, "Devil's Playground"),
create_region(world, player, locations_per_region, location_cache, "Welcome to the Jungle"),
create_region(world, player, locations_per_region, location_cache, "Breakout"),
create_region(world, player, locations_per_region, location_cache, "Ghost of a Chance"),
create_region(world, player, locations_per_region, location_cache, "The Great Train Robbery"),
create_region(world, player, locations_per_region, location_cache, "Cutthroat"),
create_region(world, player, locations_per_region, location_cache, "Engine of Destruction"),
create_region(world, player, locations_per_region, location_cache, "Media Blitz"),
create_region(world, player, locations_per_region, location_cache, "Piercing the Shroud"),
create_region(world, player, locations_per_region, location_cache, "Whispers of Doom"),
create_region(world, player, locations_per_region, location_cache, "A Sinister Turn"),
create_region(world, player, locations_per_region, location_cache, "Echoes of the Future"),
create_region(world, player, locations_per_region, location_cache, "In Utter Darkness"),
create_region(world, player, locations_per_region, location_cache, "Gates of Hell"),
create_region(world, player, locations_per_region, location_cache, "Belly of the Beast"),
create_region(world, player, locations_per_region, location_cache, "Shatter the Sky"),
create_region(world, player, locations_per_region, location_cache, "All-In")
]
if __debug__:
throwIfAnyLocationIsNotAssignedToARegion(regions, locations_per_region.keys())
world.regions += regions
names: Dict[str, int] = {}
connect(world, player, names, 'Menu', 'Liberation Day'),
connect(world, player, names, 'Liberation Day', 'The Outlaws',
lambda state: state._sc2wol_has_common_unit(world, player)),
connect(world, player, names, 'The Outlaws', 'Zero Hour'),
connect(world, player, names, 'Zero Hour', 'Evacuation',
lambda state: state._sc2wol_has_anti_air(world, player)),
connect(world, player, names, 'Evacuation', 'Outbreak'),
connect(world, player, names, "Outbreak", "Safe Haven",
lambda state: state._sc2wol_has_mobile_anti_air(world, player) and
state._sc2wol_cleared_missions(world, player, 7)),
connect(world, player, names, "Outbreak", "Haven's Fall",
lambda state: state._sc2wol_has_mobile_anti_air(world, player) and
state._sc2wol_cleared_missions(world, player, 7)),
connect(world, player, names, 'Zero Hour', 'Smash and Grab',
lambda state: state._sc2wol_has_anti_air(world, player)),
connect(world, player, names, 'Smash and Grab', 'The Dig',
lambda state: state._sc2wol_cleared_missions(world, player, 8) and
state._sc2wol_has_heavy_defense(world, player)),
connect(world, player, names, 'The Dig', 'The Moebius Factor',
lambda state: state._sc2wol_cleared_missions(world, player, 11) and
state._sc2wol_has_air(world, player)),
connect(world, player, names, 'The Moebius Factor', 'Supernova',
lambda state: state._sc2wol_cleared_missions(world, player, 14)),
connect(world, player, names, 'Supernova', 'Maw of the Void'),
connect(world, player, names, 'Zero Hour', "Devil's Playground",
lambda state: state._sc2wol_cleared_missions(world, player, 4)),
connect(world, player, names, "Devil's Playground", 'Welcome to the Jungle'),
connect(world, player, names, "Welcome to the Jungle", 'Breakout',
lambda state: state._sc2wol_cleared_missions(world, player, 8)),
connect(world, player, names, "Welcome to the Jungle", 'Ghost of a Chance',
lambda state: state._sc2wol_cleared_missions(world, player, 8)),
connect(world, player, names, "Zero Hour", 'The Great Train Robbery',
lambda state: state._sc2wol_cleared_missions(world, player, 6)),
connect(world, player, names, 'The Great Train Robbery', 'Cutthroat',
lambda state: state.has("Beat The Great Train Robbery", player)),
connect(world, player, names, 'Cutthroat', 'Engine of Destruction',
lambda state: state.has("Beat The Great Train Robbery", player)),
connect(world, player, names, 'Engine of Destruction', 'Media Blitz',
lambda state: state.has("Beat Engine of Destruction", player)),
connect(world, player, names, 'Media Blitz', 'Piercing the Shroud'),
connect(world, player, names, 'The Dig', 'Whispers of Doom',),
connect(world, player, names, 'Whispers of Doom', 'A Sinister Turn'),
connect(world, player, names, 'A Sinister Turn', 'Echoes of the Future',
lambda state: state.has("Beat A Sinister Turn", player)),
connect(world, player, names, 'Echoes of the Future', 'In Utter Darkness'),
connect(world, player, names, 'Maw of the Void', 'Gates of Hell'),
connect(world, player, names, 'Gates of Hell', 'Belly of the Beast'),
connect(world, player, names, 'Gates of Hell', 'Shatter the Sky'),
connect(world, player, names, 'Gates of Hell', 'All-In',
lambda state: state.has('Beat Gates of Hell', player) or state.has('Beat Shatter the Sky', player))
def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames: Set[str]):
existingRegions = set()
for region in regions:
existingRegions.add(region.name)
if (regionNames - existingRegions):
raise Exception("Starcraft: the following regions are used in locations: {}, but no such region exists".format(regionNames - existingRegions))
def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location:
location = Location(player, location_data.name, location_data.code, region)
location.access_rule = location_data.rule
if id is None:
location.event = True
location.locked = True
location_cache.append(location)
return location
def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region:
region = Region(name, RegionType.Generic, name, player)
region.world = world
if name in locations_per_region:
for location_data in locations_per_region[name]:
location = create_location(player, location_data, region, location_cache)
region.locations.append(location)
return region
def connect(world: MultiWorld, player: int, used_names: Dict[str, int], source: str, target: str, rule: Optional[Callable] = None):
sourceRegion = world.get_region(source, player)
targetRegion = world.get_region(target, player)
if target not in used_names:
used_names[target] = 1
name = target
else:
used_names[target] += 1
name = target + (' ' * used_names[target])
connection = Entrance(player, name, sourceRegion)
if rule:
connection.access_rule = rule
sourceRegion.exits.append(connection)
connection.connect(targetRegion)
def get_locations_per_region(locations: Tuple[LocationData, ...]) -> Dict[str, List[LocationData]]:
per_region: Dict[str, List[LocationData]] = {}
for location in locations:
per_region.setdefault(location.region, []).append(location)
return per_region