| 
									
										
										
										
											2023-11-25 16:00:15 +01:00
										 |  |  | from typing import Dict, List, NamedTuple, Optional, TYPE_CHECKING | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from BaseClasses import MultiWorld, Region | 
					
						
							|  |  |  | from .data.world_node import WORLD_NODES_JSON | 
					
						
							|  |  |  | from .data.world_path import WORLD_PATHS_JSON | 
					
						
							|  |  |  | from .data.world_region import WORLD_REGIONS_JSON | 
					
						
							|  |  |  | from .data.world_teleport_tree import WORLD_TELEPORT_TREES_JSON | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if TYPE_CHECKING: | 
					
						
							|  |  |  |     from . import LandstalkerWorld | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LandstalkerRegion(Region): | 
					
						
							|  |  |  |     code: str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, code: str, name: str, player: int, multiworld: MultiWorld, hint: Optional[str] = None): | 
					
						
							|  |  |  |         super().__init__(name, player, multiworld, hint) | 
					
						
							|  |  |  |         self.code = code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LandstalkerRegionData(NamedTuple): | 
					
						
							|  |  |  |     locations: Optional[List[str]] | 
					
						
							|  |  |  |     region_exits: Optional[List[str]] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_regions(world: "LandstalkerWorld"): | 
					
						
							|  |  |  |     regions_table: Dict[str, LandstalkerRegion] = {} | 
					
						
							|  |  |  |     multiworld = world.multiworld | 
					
						
							|  |  |  |     player = world.player | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Create the hardcoded starting "Menu" region | 
					
						
							|  |  |  |     menu_region = LandstalkerRegion("menu", "Menu", player, multiworld) | 
					
						
							|  |  |  |     regions_table["menu"] = menu_region | 
					
						
							|  |  |  |     multiworld.regions.append(menu_region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Create regions from world_nodes | 
					
						
							|  |  |  |     for code, region_data in WORLD_NODES_JSON.items(): | 
					
						
							|  |  |  |         random_hint_name = None | 
					
						
							|  |  |  |         if "hints" in region_data: | 
					
						
							| 
									
										
										
										
											2024-06-01 13:39:57 +02:00
										 |  |  |             random_hint_name = world.random.choice(region_data["hints"]) | 
					
						
							| 
									
										
										
										
											2023-11-25 16:00:15 +01:00
										 |  |  |         region = LandstalkerRegion(code, region_data["name"], player, multiworld, random_hint_name) | 
					
						
							|  |  |  |         regions_table[code] = region | 
					
						
							|  |  |  |         multiworld.regions.append(region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Create exits/entrances from world_paths | 
					
						
							|  |  |  |     for data in WORLD_PATHS_JSON: | 
					
						
							|  |  |  |         two_way = data["twoWay"] if "twoWay" in data else False | 
					
						
							|  |  |  |         create_entrance(data["fromId"], data["toId"], two_way, regions_table) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Create a path between the fake Menu location and the starting location | 
					
						
							|  |  |  |     starting_region = get_starting_region(world, regions_table) | 
					
						
							|  |  |  |     menu_region.connect(starting_region, f"menu -> {starting_region.code}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     add_specific_paths(world, regions_table) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return regions_table | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def add_specific_paths(world: "LandstalkerWorld", regions_table: Dict[str, LandstalkerRegion]): | 
					
						
							|  |  |  |     # If Gumi boulder is removed, add a path from "route_gumi_ryuma" to "gumi" | 
					
						
							|  |  |  |     if world.options.remove_gumi_boulder == 1: | 
					
						
							|  |  |  |         create_entrance("route_gumi_ryuma", "gumi", False, regions_table) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # If enemy jumping is in logic, Mountainous Area can be reached from route to Lake Shrine by doing a "ghost jump" | 
					
						
							|  |  |  |     # at crossroads map | 
					
						
							|  |  |  |     if world.options.handle_enemy_jumping_in_logic == 1: | 
					
						
							|  |  |  |         create_entrance("route_lake_shrine", "route_lake_shrine_cliff", False, regions_table) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # If using Einstein Whistle behind trees is allowed, add a new logic path there to reflect that change | 
					
						
							|  |  |  |     if world.options.allow_whistle_usage_behind_trees == 1: | 
					
						
							|  |  |  |         create_entrance("greenmaze_post_whistle", "greenmaze_pre_whistle", False, regions_table) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_entrance(from_id: str, to_id: str, two_way: bool, regions_table: Dict[str, LandstalkerRegion]): | 
					
						
							|  |  |  |     created_entrances = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     name = from_id + " -> " + to_id | 
					
						
							|  |  |  |     from_region = regions_table[from_id] | 
					
						
							|  |  |  |     to_region = regions_table[to_id] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     created_entrances.append(from_region.connect(to_region, name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if two_way: | 
					
						
							|  |  |  |         reverse_name = to_id + " -> " + from_id | 
					
						
							|  |  |  |         created_entrances.append(to_region.connect(from_region, reverse_name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return created_entrances | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_starting_region(world: "LandstalkerWorld", regions_table: Dict[str, LandstalkerRegion]): | 
					
						
							|  |  |  |     # Most spawn locations have the same name as the region they are bound to, but a few vary. | 
					
						
							|  |  |  |     spawn_id = world.options.spawn_region.current_key | 
					
						
							|  |  |  |     if spawn_id == "waterfall": | 
					
						
							|  |  |  |         return regions_table["greenmaze_post_whistle"] | 
					
						
							|  |  |  |     elif spawn_id == "kado": | 
					
						
							|  |  |  |         return regions_table["route_gumi_ryuma"] | 
					
						
							|  |  |  |     elif spawn_id == "greenmaze": | 
					
						
							|  |  |  |         return regions_table["greenmaze_pre_whistle"] | 
					
						
							|  |  |  |     return regions_table[spawn_id] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_darkenable_regions(): | 
					
						
							|  |  |  |     return {data["name"]: data["nodeIds"] for data in WORLD_REGIONS_JSON if "darkMapIds" in data} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_teleport_trees(): | 
					
						
							|  |  |  |     pairs = [] | 
					
						
							|  |  |  |     for pair in WORLD_TELEPORT_TREES_JSON: | 
					
						
							|  |  |  |         first_tree = { | 
					
						
							|  |  |  |             'name':   pair[0]["name"], | 
					
						
							|  |  |  |             'region': pair[0]["nodeId"] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         second_tree = { | 
					
						
							|  |  |  |             'name':   pair[1]["name"], | 
					
						
							|  |  |  |             'region': pair[1]["nodeId"] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pairs.append([first_tree, second_tree]) | 
					
						
							|  |  |  |     return pairs |