diff --git a/worlds/earthbound/Locations.py b/worlds/earthbound/Locations.py index 8b5e5f78cd39..4be08560e54c 100644 --- a/worlds/earthbound/Locations.py +++ b/worlds/earthbound/Locations.py @@ -1,8 +1,5 @@ from typing import List, Optional, NamedTuple, TYPE_CHECKING -from .Options import MagicantMode, ShopRandomizer - -if TYPE_CHECKING: - from . import EarthBoundWorld +from .Options import MagicantMode, ShopRandomizer, EBOptions class LocationData(NamedTuple): @@ -11,7 +8,7 @@ class LocationData(NamedTuple): code: Optional[int] -def get_locations(world: "EarthBoundWorld") -> List[LocationData]: +def get_locations(options: EBOptions) -> List[LocationData]: location_table: List[LocationData] = [ LocationData("Northern Onett", "Onett - Tracy Gift", 0xEB0000), @@ -273,28 +270,28 @@ def get_locations(world: "EarthBoundWorld") -> List[LocationData]: LocationData("Global ATM Access", "Any ATM", None) ] - if world.options.giygas_required: + if options.giygas_required: location_table += [ LocationData("Cave of the Past", "Cave of the Past - Present", 0xEB00F0), LocationData("Endgame", "Giygas", None), ] - if world.options.alternate_sanctuary_goal: + if options.alternate_sanctuary_goal: location_table += [ LocationData("Ness's Mind", "+2 Sanctuaries", None) ] - if world.options.magicant_mode in range(1, 3): + if options.magicant_mode in range(1, 3): location_table += [ LocationData("Sea of Eden", "Magicant - Ness's Nightmare", None), ] - if not world.options.magicant_mode: + if not options.magicant_mode: location_table += [ LocationData("Sea of Eden", "Magicant - Ness's Nightmare", 0xEB00ED), ] - if world.options.magicant_mode < MagicantMode.option_alternate_goal: + if options.magicant_mode < MagicantMode.option_alternate_goal: location_table += [ LocationData("Magicant", "Magicant - Ness's Gift", 0xEB00E8), LocationData("Magicant", "Magicant - Present Near Ness", 0xEB00E9), @@ -303,12 +300,12 @@ def get_locations(world: "EarthBoundWorld") -> List[LocationData]: LocationData("Magicant", "Magicant - Hills Present", 0xEB00EC), LocationData("Magicant", "Magicant - Town Present", 0xEB00FA) ] - if world.options.magicant_mode == MagicantMode.option_alternate_goal: + if options.magicant_mode == MagicantMode.option_alternate_goal: location_table += [ LocationData("Ness's Mind", "+1 Sanctuary", None) ] - if world.options.shop_randomizer == ShopRandomizer.option_shopsanity: + if options.shop_randomizer == ShopRandomizer.option_shopsanity: location_table += [ LocationData("Onett", "Onett Drugstore - Right Counter Slot 1", 0xeb1000), LocationData("Onett", "Onett Drugstore - Right Counter Slot 2", 0xeb1001), @@ -585,7 +582,7 @@ def get_locations(world: "EarthBoundWorld") -> List[LocationData]: LocationData("Andonuts Lab Area", "Andonuts Lab - Caveman Shop Slot 5", 0xeb11c4) ] - if world.options.magicant_mode < MagicantMode.option_alternate_goal: + if options.magicant_mode < MagicantMode.option_alternate_goal: location_table += [ LocationData("Magicant", "Magicant - Shop Slot 1", 0xeb10f5), LocationData("Magicant", "Magicant - Shop Slot 2", 0xeb10f6) diff --git a/worlds/earthbound/Regions.py b/worlds/earthbound/Regions.py index b252bd019f74..203266d1387e 100644 --- a/worlds/earthbound/Regions.py +++ b/worlds/earthbound/Regions.py @@ -1,11 +1,27 @@ from typing import List, Dict, TYPE_CHECKING, Optional -from BaseClasses import Region, Location +from BaseClasses import Region, Location, MultiWorld from .Locations import LocationData -from .Options import MagicantMode -if TYPE_CHECKING: - from . import EarthBoundWorld +from .Options import MagicantMode, EBOptions +Starting_region_list = { + 0: "Northern Onett", + 1: "Onett", + 2: "Twoson", + 3: "Happy-Happy Village", + 4: "Threed", + 5: "Saturn Valley", + 6: "Fourside", + 7: "Winters", + 8: "Summers", + 9: "Dalaam", + 10: "Scaraba", + 11: "Deep Darkness", + 12: "Tenda Village", + 13: "Lost Underworld", + 14: "Magicant" + } + class EBLocation(Location): game: str = "EarthBound" region: str @@ -14,100 +30,97 @@ def __init__(self, player: int, name: str = " ", address: Optional[int] = None, super().__init__(player, name, address, parent) -def init_areas(world: "EarthBoundWorld", locations: List[LocationData]) -> None: - multiworld = world.multiworld - player = world.player +def init_areas(multiworld: MultiWorld, player: int, + options: EBOptions, locations: List[LocationData]) -> None: locations_per_region = get_locations_per_region(locations) regions = [ - create_region(world, player, locations_per_region, "Menu"), - create_region(world, player, locations_per_region, "Ness's Mind"), - create_region(world, player, locations_per_region, "Northern Onett"), - create_region(world, player, locations_per_region, "Onett"), - create_region(world, player, locations_per_region, "Arcade"), - create_region(world, player, locations_per_region, "Giant Step"), - create_region(world, player, locations_per_region, "Twoson"), - create_region(world, player, locations_per_region, "Everdred's House"), - create_region(world, player, locations_per_region, "Peaceful Rest Valley"), - create_region(world, player, locations_per_region, "Happy-Happy Village"), - create_region(world, player, locations_per_region, "Happy-Happy HQ"), - create_region(world, player, locations_per_region, "Lilliput Steps"), - create_region(world, player, locations_per_region, "Threed"), - create_region(world, player, locations_per_region, "Threed Underground"), - create_region(world, player, locations_per_region, "Boogey Tent"), - create_region(world, player, locations_per_region, "Grapefruit Falls"), - create_region(world, player, locations_per_region, "Belch's Factory"), - create_region(world, player, locations_per_region, "Saturn Valley"), - create_region(world, player, locations_per_region, "Upper Saturn Valley"), - create_region(world, player, locations_per_region, "Milky Well"), - create_region(world, player, locations_per_region, "Dusty Dunes Desert"), - create_region(world, player, locations_per_region, "Gold Mine"), - create_region(world, player, locations_per_region, "Monkey Caves"), - create_region(world, player, locations_per_region, "Fourside"), - create_region(world, player, locations_per_region, "Moonside"), - create_region(world, player, locations_per_region, "Fourside Dept. Store"), - create_region(world, player, locations_per_region, "Magnet Hill"), - create_region(world, player, locations_per_region, "Monotoli Building"), - create_region(world, player, locations_per_region, "Winters"), - create_region(world, player, locations_per_region, "Snow Wood Boarding School"), - create_region(world, player, locations_per_region, "Southern Winters"), - create_region(world, player, locations_per_region, "Brickroad Maze"), - create_region(world, player, locations_per_region, "Rainy Circle"), - create_region(world, player, locations_per_region, "Andonuts Lab Area"), - create_region(world, player, locations_per_region, "Stonehenge Base"), - create_region(world, player, locations_per_region, "Summers"), - create_region(world, player, locations_per_region, "Summers Museum"), - create_region(world, player, locations_per_region, "Dalaam"), - create_region(world, player, locations_per_region, "Pink Cloud"), - create_region(world, player, locations_per_region, "Scaraba"), - create_region(world, player, locations_per_region, "Pyramid"), - create_region(world, player, locations_per_region, "Southern Scaraba"), - create_region(world, player, locations_per_region, "Dungeon Man"), - create_region(world, player, locations_per_region, "Deep Darkness"), - create_region(world, player, locations_per_region, "Deep Darkness Darkness"), - create_region(world, player, locations_per_region, "Tenda Village"), - create_region(world, player, locations_per_region, "Lumine Hall"), - create_region(world, player, locations_per_region, "Lost Underworld"), - create_region(world, player, locations_per_region, "Fire Spring"), - create_region(world, player, locations_per_region, "Magicant"), - create_region(world, player, locations_per_region, "Sea of Eden"), - create_region(world, player, locations_per_region, "Cave of the Present"), - create_region(world, player, locations_per_region, "Global ATM Access"), - create_region(world, player, locations_per_region, "Common Condiment Shop") + create_region(multiworld, player, locations_per_region, "Menu"), + create_region(multiworld, player, locations_per_region, "Ness's Mind"), + create_region(multiworld, player, locations_per_region, "Northern Onett"), + create_region(multiworld, player, locations_per_region, "Onett"), + create_region(multiworld, player, locations_per_region, "Arcade"), + create_region(multiworld, player, locations_per_region, "Giant Step"), + create_region(multiworld, player, locations_per_region, "Twoson"), + create_region(multiworld, player, locations_per_region, "Everdred's House"), + create_region(multiworld, player, locations_per_region, "Peaceful Rest Valley"), + create_region(multiworld, player, locations_per_region, "Happy-Happy Village"), + create_region(multiworld, player, locations_per_region, "Happy-Happy HQ"), + create_region(multiworld, player, locations_per_region, "Lilliput Steps"), + create_region(multiworld, player, locations_per_region, "Threed"), + create_region(multiworld, player, locations_per_region, "Threed Underground"), + create_region(multiworld, player, locations_per_region, "Boogey Tent"), + create_region(multiworld, player, locations_per_region, "Grapefruit Falls"), + create_region(multiworld, player, locations_per_region, "Belch's Factory"), + create_region(multiworld, player, locations_per_region, "Saturn Valley"), + create_region(multiworld, player, locations_per_region, "Upper Saturn Valley"), + create_region(multiworld, player, locations_per_region, "Milky Well"), + create_region(multiworld, player, locations_per_region, "Dusty Dunes Desert"), + create_region(multiworld, player, locations_per_region, "Gold Mine"), + create_region(multiworld, player, locations_per_region, "Monkey Caves"), + create_region(multiworld, player, locations_per_region, "Fourside"), + create_region(multiworld, player, locations_per_region, "Moonside"), + create_region(multiworld, player, locations_per_region, "Fourside Dept. Store"), + create_region(multiworld, player, locations_per_region, "Magnet Hill"), + create_region(multiworld, player, locations_per_region, "Monotoli Building"), + create_region(multiworld, player, locations_per_region, "Winters"), + create_region(multiworld, player, locations_per_region, "Snow Wood Boarding School"), + create_region(multiworld, player, locations_per_region, "Southern Winters"), + create_region(multiworld, player, locations_per_region, "Brickroad Maze"), + create_region(multiworld, player, locations_per_region, "Rainy Circle"), + create_region(multiworld, player, locations_per_region, "Andonuts Lab Area"), + create_region(multiworld, player, locations_per_region, "Stonehenge Base"), + create_region(multiworld, player, locations_per_region, "Summers"), + create_region(multiworld, player, locations_per_region, "Summers Museum"), + create_region(multiworld, player, locations_per_region, "Dalaam"), + create_region(multiworld, player, locations_per_region, "Pink Cloud"), + create_region(multiworld, player, locations_per_region, "Scaraba"), + create_region(multiworld, player, locations_per_region, "Pyramid"), + create_region(multiworld, player, locations_per_region, "Southern Scaraba"), + create_region(multiworld, player, locations_per_region, "Dungeon Man"), + create_region(multiworld, player, locations_per_region, "Deep Darkness"), + create_region(multiworld, player, locations_per_region, "Deep Darkness Darkness"), + create_region(multiworld, player, locations_per_region, "Tenda Village"), + create_region(multiworld, player, locations_per_region, "Lumine Hall"), + create_region(multiworld, player, locations_per_region, "Lost Underworld"), + create_region(multiworld, player, locations_per_region, "Fire Spring"), + create_region(multiworld, player, locations_per_region, "Magicant"), + create_region(multiworld, player, locations_per_region, "Sea of Eden"), + create_region(multiworld, player, locations_per_region, "Cave of the Present"), + create_region(multiworld, player, locations_per_region, "Global ATM Access"), + create_region(multiworld, player, locations_per_region, "Common Condiment Shop") ] - if world.options.giygas_required: + if options.giygas_required: regions.extend([ - create_region(world, player, locations_per_region, "Cave of the Past"), - create_region(world, player, locations_per_region, "Endgame") + create_region(multiworld, player, locations_per_region, "Cave of the Past"), + create_region(multiworld, player, locations_per_region, "Endgame") ]) multiworld.regions += regions -def connect_area_exits(world): - multiworld = world.multiworld - player = world.player - - connect_menu_region(world) - arcade_connection = world.dungeon_connections["Arcade"] - giant_step_connection = world.dungeon_connections["Giant Step"] - lilliput_steps_connection = world.dungeon_connections["Lilliput Steps"] - happy_happy_hq_connection = world.dungeon_connections["Happy-Happy HQ"] - belch_factory_connection = world.dungeon_connections["Belch's Factory"] - milky_well_connection = world.dungeon_connections["Milky Well"] - gold_mine_connection = world.dungeon_connections["Gold Mine"] - moonside_connection = world.dungeon_connections["Moonside"] - monotoli_building_connection = world.dungeon_connections["Monotoli Building"] - magnet_hill_connection = world.dungeon_connections["Magnet Hill"] - pink_cloud_connection = world.dungeon_connections["Pink Cloud"] - pyramid_connection = world.dungeon_connections["Pyramid"] - dungeon_man_connection = world.dungeon_connections["Dungeon Man"] - rainy_circle_connection = world.dungeon_connections["Rainy Circle"] - stonehenge_connection = world.dungeon_connections["Stonehenge Base"] - lumine_hall_connection = world.dungeon_connections["Lumine Hall"] - fire_spring_connection = world.dungeon_connections["Fire Spring"] - sea_of_eden_connection = world.dungeon_connections["Sea of Eden"] - brickroad_maze_connection = world.dungeon_connections["Brickroad Maze"] +def connect_area_exits(multiworld: MultiWorld, player: int, starting_region:str, + options: EBOptions, dungeon_connections:dict[str,str]): + connect_menu_region(multiworld, player, starting_region) + arcade_connection = dungeon_connections["Arcade"] + giant_step_connection = dungeon_connections["Giant Step"] + lilliput_steps_connection = dungeon_connections["Lilliput Steps"] + happy_happy_hq_connection = dungeon_connections["Happy-Happy HQ"] + belch_factory_connection = dungeon_connections["Belch's Factory"] + milky_well_connection = dungeon_connections["Milky Well"] + gold_mine_connection = dungeon_connections["Gold Mine"] + moonside_connection = dungeon_connections["Moonside"] + monotoli_building_connection = dungeon_connections["Monotoli Building"] + magnet_hill_connection = dungeon_connections["Magnet Hill"] + pink_cloud_connection = dungeon_connections["Pink Cloud"] + pyramid_connection = dungeon_connections["Pyramid"] + dungeon_man_connection = dungeon_connections["Dungeon Man"] + rainy_circle_connection = dungeon_connections["Rainy Circle"] + stonehenge_connection = dungeon_connections["Stonehenge Base"] + lumine_hall_connection = dungeon_connections["Lumine Hall"] + fire_spring_connection = dungeon_connections["Fire Spring"] + sea_of_eden_connection = dungeon_connections["Sea of Eden"] + brickroad_maze_connection = dungeon_connections["Brickroad Maze"] multiworld.get_region("Ness's Mind", player).add_exits(["Onett", "Twoson", "Happy-Happy Village", "Threed", "Saturn Valley", "Dusty Dunes Desert", "Fourside", "Winters", "Summers", "Dalaam", "Scaraba", "Deep Darkness", "Tenda Village", "Lost Underworld", "Magicant"], {"Onett": lambda state: state.has("Onett Teleport", player), @@ -219,14 +232,14 @@ def connect_area_exits(world): multiworld.get_region("Lost Underworld", player).add_exits([fire_spring_connection]) - if world.options.giygas_required: + if options.giygas_required: multiworld.get_region("Cave of the Present", player).add_exits(["Cave of the Past"], {"Cave of the Past": lambda state: state.has("Power of the Earth", player)}) multiworld.get_region("Cave of the Past", player).add_exits(["Endgame"], {"Endgame": lambda state: state.has("Paula", player)}) - if world.options.magicant_mode < MagicantMode.option_optional_boost: # 3 + if options.magicant_mode < MagicantMode.option_optional_boost: # 3 multiworld.get_region("Magicant", player).add_exits(["Global ATM Access", sea_of_eden_connection], {sea_of_eden_connection: lambda state: state.has("Ness", player)}) @@ -238,8 +251,8 @@ def create_location(player: int, location_data: LocationData, region: Region) -> return location -def create_region(world: "EarthBoundWorld", player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region: - region = Region(name, player, world.multiworld) +def create_region(multiworld: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region: + region = Region(name, player, multiworld) if name in locations_per_region: for location_data in locations_per_region[name]: @@ -258,27 +271,8 @@ def get_locations_per_region(locations: List[LocationData]) -> Dict[str, List[Lo return per_region -def connect_menu_region(world: "EarthBoundWorld") -> None: - starting_region_list = { - 0: "Northern Onett", - 1: "Onett", - 2: "Twoson", - 3: "Happy-Happy Village", - 4: "Threed", - 5: "Saturn Valley", - 6: "Fourside", - 7: "Winters", - 8: "Summers", - 9: "Dalaam", - 10: "Scaraba", - 11: "Deep Darkness", - 12: "Tenda Village", - 13: "Lost Underworld", - 14: "Magicant" - } - - world.starting_region = starting_region_list[world.start_location] - world.multiworld.get_region("Menu", world.player).add_exits([world.starting_region, "Ness's Mind"], - {"Ness's Mind": lambda state: state.has_any({"Ness", "Paula", "Jeff", "Poo"}, world.player), - world.starting_region: lambda state: state.has_any({"Ness", "Paula", "Jeff", "Poo"}, world.player)}) - \ No newline at end of file +def connect_menu_region(multiworld: MultiWorld, player: int, starting_region: str) -> None: + multiworld.get_region("Menu", player).add_exits([starting_region, "Ness's Mind"], + {"Ness's Mind": lambda state: state.has_any({"Ness", "Paula", "Jeff", "Poo"}, player), + starting_region: lambda state: state.has_any({"Ness", "Paula", "Jeff", "Poo"}, player)}) + diff --git a/worlds/earthbound/__init__.py b/worlds/earthbound/__init__.py index 6808a4cc4035..896a7770127e 100644 --- a/worlds/earthbound/__init__.py +++ b/worlds/earthbound/__init__.py @@ -11,7 +11,7 @@ import settings from .Items import get_item_names_per_category, item_table from .Locations import get_locations -from .Regions import init_areas, connect_area_exits +from .Regions import init_areas, connect_area_exits, Starting_region_list from .Options import EBOptions, eb_option_groups from .setup_game import setup_gamevars, place_static_items from .modules.enemy_data import initialize_enemies @@ -82,6 +82,35 @@ class EarthBoundWorld(World): locked_locations: List[str] location_cache: List[Location] + event_count: int + progressive_filler_bats: int + progressive_filler_pans: int + progressive_filler_guns: int + progressive_filler_bracelets: int + progressive_filler_other: int + world_version = world_version + armor_list: Dict[str, EBArmor] + weapon_list: Dict[str, EBWeapon] + boss_slots: Dict[str, SlotInfo] + boss_info: Dict[str, BossData] + starting_character = str | None + rom_name = str | None + starting_area_teleport = str | None + common_items: list[str] + uncommon_items: list[str] + rare_items: list[str] + common_gear: list[str] + uncommon_gear: list[str] + rare_gear: list[str] + money: list[str] + get_all_spheres: threading.Event + boss_list: List[str] + start_location: int + starting_region: str + dungeon_connections:dict[str,str] + slime_pile_wanted_item: str | None + + def __init__(self, multiworld: MultiWorld, player: int): self.rom_name_available_event = threading.Event() super().__init__(multiworld, player) @@ -95,22 +124,14 @@ def __init__(self, multiworld: MultiWorld, player: int): self.progressive_filler_bracelets = 0 self.progressive_filler_other = 0 self.world_version = world_version - self.removed_teleports = [] - self.armor_list: Dict[str, EBArmor] - self.weapon_list: Dict[str, EBWeapon] - self.boss_slots: Dict[str, SlotInfo] - self.boss_info: Dict[str, BossData] self.starting_character = None - self.locals = [] self.rom_name = None self.starting_area_teleport = None - self.common_gear = [] - self.uncommon_gear = [] - self.rare_gear = [] self.get_all_spheres = threading.Event() - self.boss_list: List[str] = [] - self.starting_region = int + self.boss_list = [] + self.starting_location = 0 self.dungeon_connections = {} + self.slime_pile_wanted_item = None self.common_items = [ "Cookie", @@ -283,8 +304,9 @@ def generate_early(self) -> None: # Todo: place locked items in generate_early self.options.local_items.value |= self.item_name_groups["PSI"] def create_regions(self) -> None: - init_areas(self, get_locations(self)) - connect_area_exits(self) + self.starting_region = Starting_region_list[self.start_location] + init_areas(self.multiworld, self.player, self.options, get_locations(self.options)) + connect_area_exits(self.multiworld, self.player, self.starting_region, self.options, self.dungeon_connections) place_static_items(self) def create_items(self) -> None: