diff --git a/worlds/sm64ex/Items.py b/worlds/sm64ex/Items.py index 1f0c7713..ce125a2b 100644 --- a/worlds/sm64ex/Items.py +++ b/worlds/sm64ex/Items.py @@ -7,8 +7,9 @@ item_table = { "Power Star": 3626000, "Basement Key": 3626178, "Second Floor Key": 3626179, - "Wing Cap": 3626180, - "Metal Cap": 3626181, - "Vanish Cap": 3626182, - "1Up Mushroom": 3626183 + "Progressive Key": 3626180, + "Wing Cap": 3626181, + "Metal Cap": 3626182, + "Vanish Cap": 3626183, + "1Up Mushroom": 3626184 } \ No newline at end of file diff --git a/worlds/sm64ex/Locations.py b/worlds/sm64ex/Locations.py index c4077957..501c284b 100644 --- a/worlds/sm64ex/Locations.py +++ b/worlds/sm64ex/Locations.py @@ -172,10 +172,18 @@ loc100Coin_table = { "RR: 100 Coins": 3626104 } +locBitDW_table = { + "Bowser in the Dark World Red Coins": 3626105, + "Bowser in the Dark World Key": 3626178 +} + +locBitFS_table = { + "Bowser in the Fire Sea Red Coins": 3626112, + "Bowser in the Fire Sea Key": 3626179 +} + #Secret Stars and Stages locSS_table = { - "Bowser in the Dark World Red Coins": 3626105, - "Bowser in the Fire Sea Red Coins": 3626112, "Bowser in the Sky Red Coins": 3626119, "The Princess's Secret Slide Block": 3626126, "The Princess's Secret Slide Fast": 3626127, @@ -191,21 +199,15 @@ locSS_table = { "MIPS 2": 3626172 } -#Keys -locKey_table = { - "Bowser in the Dark World Key": 3626178, - "Bowser in the Fire Sea Key": 3626179 -} - #Caps locCap_table = { - "Tower of the Wing Cap Switch": 3626180, - "Cavern of the Metal Cap Switch": 3626181, - "Vanish Cap Under the Moat Switch": 3626182 + "Tower of the Wing Cap Switch": 3626181, + "Cavern of the Metal Cap Switch": 3626182, + "Vanish Cap Under the Moat Switch": 3626183 } # Correspond to 3626000 + course index * 7 + star index, then secret stars, then keys, then 100 Coin Stars location_table = {**locBoB_table,**locWhomp_table,**locJRB_table,**locCCM_table,**locBBH_table, \ **locHMC_table,**locLLL_table,**locSSL_table,**locDDD_table,**locSL_table, \ **locWDW_table,**locTTM_table,**locTHI_table,**locTTC_table,**locRR_table, \ - **loc100Coin_table,**locSS_table,**locKey_table,**locCap_table} \ No newline at end of file + **loc100Coin_table,**locBitDW_table,**locBitFS_table,**locSS_table,**locCap_table} \ No newline at end of file diff --git a/worlds/sm64ex/Options.py b/worlds/sm64ex/Options.py index 11b25812..f617651a 100644 --- a/worlds/sm64ex/Options.py +++ b/worlds/sm64ex/Options.py @@ -1,5 +1,5 @@ import typing -from Options import Option, DefaultOnToggle, Range +from Options import Option, DefaultOnToggle, Range, Toggle class EnableCoinStars(DefaultOnToggle): """Disable to Ignore 100 Coin Stars. You can still collect them, but they don't do anything""" @@ -21,7 +21,17 @@ class ExtraStars(Range): range_end = 50 default = 50 +class AreaRandomizer(Toggle): + """Randomize Entrances to Courses""" + display_name = "Course Randomizer" + +class ProgressiveKeys(DefaultOnToggle): + """Keys will first grant you access to the Basement, then to the Secound Floor""" + display_name = "Progressive Keys" + sm64_options: typing.Dict[str,type(Option)] = { + "AreaRandomizer": AreaRandomizer, + "ProgressiveKeys": ProgressiveKeys, "EnableCoinStars": EnableCoinStars, "StrictCapRequirements": StrictCapRequirements, "StarsToFinish": StarsToFinish, diff --git a/worlds/sm64ex/Regions.py b/worlds/sm64ex/Regions.py index 92046df7..d4d25031 100644 --- a/worlds/sm64ex/Regions.py +++ b/worlds/sm64ex/Regions.py @@ -3,13 +3,16 @@ from BaseClasses import MultiWorld, Region, Entrance, Location, RegionType from .Locations import SM64Location, location_table,locBoB_table,locWhomp_table,locJRB_table,locCCM_table,locBBH_table, \ locHMC_table,locLLL_table,locSSL_table,locDDD_table,locSL_table, \ locWDW_table,locTTM_table,locTHI_table,locTTC_table,locRR_table, \ - locSS_table, locKey_table, locCap_table + locBitDW_table, locBitFS_table, locSS_table, locCap_table + +sm64courses = ["Bob-omb Battlefield", "Whomp's Fortress", "Jolly Roger Bay", "Cool, Cool Mountain", "Big Boo's Haunt", + "Hazy Maze Cave", "Lethal Lava Land", "Shifting Sand Land", "Dire, Dire Docks", "Snowman's Land", "Wet-Dry World", + "Tall, Tall Mountain", "Tiny-Huge Island", "Tick Tock Clock", "Rainbow Ride"] def create_regions(world: MultiWorld, player: int): regSS = Region("Menu", RegionType.Generic, "Castle Area", player, world) locSS_names = [name for name, id in locSS_table.items()] - locSS_names += [name for name, id in locKey_table.items()] locSS_names += [name for name, id in locCap_table.items()] regSS.locations += [SM64Location(player, loc_name, location_table[loc_name], regSS) for loc_name in locSS_names] world.regions.append(regSS) @@ -49,6 +52,11 @@ def create_regions(world: MultiWorld, player: int): regBBH.locations.append(SM64Location(player, "BBH: 100 Coins", location_table["BBH: 100 Coins"], regBBH)) world.regions.append(regBBH) + regBitDW = Region("Bowser in the Dark World", RegionType.Generic, "Bowser in the Dark World", player, world) + locBitDW_names = [name for name, id in locBitDW_table.items()] + regBitDW.locations += [SM64Location(player, loc_name, location_table[loc_name], regBitDW) for loc_name in locBitDW_names] + world.regions.append(regBitDW) + regBasement = Region("Basement", RegionType.Generic, "Basement", player, world) world.regions.append(regBasement) @@ -80,6 +88,11 @@ def create_regions(world: MultiWorld, player: int): regDDD.locations.append(SM64Location(player, "DDD: 100 Coins", location_table["DDD: 100 Coins"], regDDD)) world.regions.append(regDDD) + regBitFS = Region("Bowser in the Fire Sea", RegionType.Generic, "Bowser in the Fire Sea", player, world) + locBitFS_names = [name for name, id in locBitFS_table.items()] + regBitFS.locations += [SM64Location(player, loc_name, location_table[loc_name], regBitFS) for loc_name in locBitFS_names] + world.regions.append(regBitFS) + regFloor2 = Region("Second Floor", RegionType.Generic, "Second Floor", player, world) world.regions.append(regFloor2) diff --git a/worlds/sm64ex/Rules.py b/worlds/sm64ex/Rules.py index ae812630..7aaa4125 100644 --- a/worlds/sm64ex/Rules.py +++ b/worlds/sm64ex/Rules.py @@ -1,60 +1,50 @@ import typing from ..generic.Rules import add_rule -from .Regions import connect_regions +from .Regions import connect_regions, sm64courses -def set_rules(world,player): - connect_regions(world, player, "Menu", "Bob-omb Battlefield", lambda state: True) - connect_regions(world, player, "Menu", "Whomp's Fortress", lambda state: state.has("Power Star", player, 1)) - connect_regions(world, player, "Menu", "Jolly Roger Bay", lambda state: state.has("Power Star", player, 3)) - connect_regions(world, player, "Menu", "Cool, Cool Mountain", lambda state: state.has("Power Star", player, 3)) - connect_regions(world, player, "Menu", "Big Boo's Haunt", lambda state: state.has("Power Star", player, 12)) +def set_rules(world,player,area_connections): + courseshuffle = list(range(len(sm64courses))) + if (world.AreaRandomizer[player].value): + world.random.shuffle(courseshuffle) + area_connections.update({index: value for index, value in enumerate(courseshuffle)}) - connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player)) - connect_regions(world, player, "Basement", "Menu", lambda state: True) + connect_regions(world, player, "Menu", sm64courses[area_connections[0]], lambda state: True) + connect_regions(world, player, "Menu", sm64courses[area_connections[1]], lambda state: state.has("Power Star", player, 1)) + connect_regions(world, player, "Menu", sm64courses[area_connections[2]], lambda state: state.has("Power Star", player, 3)) + connect_regions(world, player, "Menu", sm64courses[area_connections[3]], lambda state: state.has("Power Star", player, 3)) + connect_regions(world, player, "Menu", "Bowser in the Dark World", lambda state: state.has("Power Star", player, 8)) + connect_regions(world, player, "Menu", sm64courses[area_connections[4]], lambda state: state.has("Power Star", player, 12)) - connect_regions(world, player, "Basement", "Hazy Maze Cave", lambda state: True) - connect_regions(world, player, "Basement", "Lethal Lava Land", lambda state: True) - connect_regions(world, player, "Basement", "Shifting Sand Land", lambda state: True) - connect_regions(world, player, "Basement", "Dire, Dire Docks", lambda state: state.has("Power Star", player, 30)) + connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1)) - connect_regions(world, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player)) - connect_regions(world, player, "Second Floor", "Menu", lambda state: True) + connect_regions(world, player, "Basement", sm64courses[area_connections[5]], lambda state: True) + connect_regions(world, player, "Basement", sm64courses[area_connections[6]], lambda state: True) + connect_regions(world, player, "Basement", sm64courses[area_connections[7]], lambda state: True) + connect_regions(world, player, "Basement", sm64courses[area_connections[8]], lambda state: state.has("Power Star", player, 30)) + connect_regions(world, player, "Basement", "Bowser in the Fire Sea", lambda state: state.has("Power Star", player, 30) and + state.can_reach("Dire, Dire Docks", 'Region', player)) - connect_regions(world, player, "Second Floor", "Snowman's Land", lambda state: True) - connect_regions(world, player, "Second Floor", "Wet-Dry World", lambda state: True) - connect_regions(world, player, "Second Floor", "Tall, Tall Mountain", lambda state: True) - connect_regions(world, player, "Second Floor", "Tiny-Huge Island", lambda state: True) + connect_regions(world, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2)) + + connect_regions(world, player, "Second Floor", sm64courses[area_connections[9]], lambda state: True) + connect_regions(world, player, "Second Floor", sm64courses[area_connections[10]], lambda state: True) + connect_regions(world, player, "Second Floor", sm64courses[area_connections[11]], lambda state: True) + connect_regions(world, player, "Second Floor", sm64courses[area_connections[12]], lambda state: True) connect_regions(world, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, 50)) - connect_regions(world, player, "Third Floor", "Second Floor", lambda state: True) - connect_regions(world, player, "Third Floor", "Tick Tock Clock", lambda state: True) - connect_regions(world, player, "Third Floor", "Rainbow Ride", lambda state: True) - - connect_regions(world, player, "Bob-omb Battlefield", "Menu", lambda state: True) - connect_regions(world, player, "Whomp's Fortress", "Menu", lambda state: True) - connect_regions(world, player, "Jolly Roger Bay", "Menu", lambda state: True) - connect_regions(world, player, "Cool, Cool Mountain", "Menu", lambda state: True) - connect_regions(world, player, "Big Boo's Haunt", "Menu", lambda state: True) - connect_regions(world, player, "Hazy Maze Cave", "Basement", lambda state: True) - connect_regions(world, player, "Lethal Lava Land", "Basement", lambda state: True) - connect_regions(world, player, "Shifting Sand Land", "Basement", lambda state: True) - connect_regions(world, player, "Dire, Dire Docks", "Basement", lambda state: True) - connect_regions(world, player, "Snowman's Land", "Second Floor", lambda state: True) - connect_regions(world, player, "Wet-Dry World", "Second Floor", lambda state: True) - connect_regions(world, player, "Tall, Tall Mountain", "Second Floor", lambda state: True) - connect_regions(world, player, "Tiny-Huge Island", "Second Floor", lambda state: True) - connect_regions(world, player, "Tick Tock Clock", "Second Floor", lambda state: True) - connect_regions(world, player, "Rainbow Ride", "Second Floor", lambda state: True) + connect_regions(world, player, "Third Floor", sm64courses[area_connections[13]], lambda state: True) + connect_regions(world, player, "Third Floor", sm64courses[area_connections[14]], lambda state: True) #Special Rules for some Locations add_rule(world.get_location("Tower of the Wing Cap Switch", player), lambda state: state.has("Power Star", player, 10)) - add_rule(world.get_location("Cavern of the Metal Cap Switch", player), lambda state: state.can_reach("Basement", 'Region', player)) + add_rule(world.get_location("Cavern of the Metal Cap Switch", player), lambda state: state.can_reach("Hazy Maze Cave",'Region',player)) add_rule(world.get_location("Vanish Cap Under the Moat Switch", player), lambda state: state.can_reach("Basement", 'Region', player)) add_rule(world.get_location("BBH: Eye to Eye in the Secret Room", player), lambda state: state.has("Vanish Cap", player)) add_rule(world.get_location("DDD: Collect the Caps...", player), lambda state: state.has("Metal Cap", player) and state.has("Vanish Cap", player)) + add_rule(world.get_location("DDD: Pole-Jumping for Red Coins", player), lambda state: state.can_reach("Bowser in the Fire Sea",'Region',player)) add_rule(world.get_location("SL: Into the Igloo", player), lambda state: state.has("Vanish Cap", player)) add_rule(world.get_location("WDW: Quick Race Through Downtown!", player), lambda state: state.has("Vanish Cap", player)) if (world.StrictCapRequirements[player].value): @@ -66,8 +56,6 @@ def set_rules(world,player): add_rule(world.get_location("Vanish Cap Under the Moat Red Coins", player), lambda state: state.has("Vanish Cap", player)) #Rules for Secret Stars - add_rule(world.get_location("Bowser in the Dark World Red Coins", player), lambda state: state.has("Power Star", player, 8)) - add_rule(world.get_location("Bowser in the Fire Sea Red Coins", player), lambda state: state.can_reach("Basement",'Region',player) and state.has("Power Star", player, 30)) add_rule(world.get_location("Bowser in the Sky Red Coins", player), lambda state: state.can_reach("Third Floor",'Region',player) and state.has("Power Star", player, world.StarsToFinish[player].value)) add_rule(world.get_location("The Princess's Secret Slide Block", player), lambda state: state.has("Power Star", player, 1)) add_rule(world.get_location("The Princess's Secret Slide Fast", player), lambda state: state.has("Power Star", player, 1)) @@ -75,15 +63,11 @@ def set_rules(world,player): add_rule(world.get_location("Tower of the Wing Cap Red Coins", player), lambda state: state.can_reach("Tower of the Wing Cap Switch", 'Location', player)) add_rule(world.get_location("Vanish Cap Under the Moat Red Coins", player), lambda state: state.can_reach("Vanish Cap Under the Moat Switch", 'Location', player)) add_rule(world.get_location("Wing Mario Over the Rainbow", player), lambda state: state.can_reach("Third Floor", 'Region', player) and state.has("Wing Cap", player)) - add_rule(world.get_location("The Secret Aquarium", player), lambda state: state.can_reach("Jolly Roger Bay", 'Region', player)) - add_rule(world.get_location("Toad (Basement)", player), lambda state: state.can_reach("Basement",'Region',player)) - add_rule(world.get_location("Toad (Second Floor)", player), lambda state: state.can_reach("Second Floor",'Region',player)) - add_rule(world.get_location("Toad (Third Floor)", player), lambda state: state.can_reach("Third Floor",'Region',player)) + add_rule(world.get_location("The Secret Aquarium", player), lambda state: state.has("Power Star", player, 3)) + add_rule(world.get_location("Toad (Basement)", player), lambda state: state.can_reach("Basement",'Region',player) and state.has("Power Star", player, 12)) + add_rule(world.get_location("Toad (Second Floor)", player), lambda state: state.can_reach("Second Floor",'Region',player) and state.has("Power Star", player, 25)) + add_rule(world.get_location("Toad (Third Floor)", player), lambda state: state.can_reach("Third Floor",'Region',player) and state.has("Power Star", player, 35)) add_rule(world.get_location("MIPS 1", player), lambda state: state.can_reach("Basement",'Region',player) and state.has("Power Star", player, 15)) add_rule(world.get_location("MIPS 2", player), lambda state: state.can_reach("Basement",'Region',player) and state.has("Power Star", player, 50)) - #Rules for Keys - add_rule(world.get_location("Bowser in the Dark World Key", player), lambda state: state.has("Power Star", player, 8)) - add_rule(world.get_location("Bowser in the Fire Sea Key", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, 30)) - world.completion_condition[player] = lambda state: state.can_reach("Third Floor",'Region',player) and state.has("Power Star", player, world.StarsToFinish[player].value) diff --git a/worlds/sm64ex/__init__.py b/worlds/sm64ex/__init__.py index cb314e74..f577086c 100644 --- a/worlds/sm64ex/__init__.py +++ b/worlds/sm64ex/__init__.py @@ -1,4 +1,4 @@ -import string +import typing from .Items import item_table, SM64Item from .Locations import location_table, SM64Location from .Options import sm64_options @@ -21,17 +21,22 @@ class SM64World(World): item_name_to_id = item_table location_name_to_id = location_table - data_version = 4 + data_version = 5 forced_auto_forfeit = False + area_connections: typing.Dict[int, int] + options = sm64_options + def generate_early(self): + self.topology_present = self.world.AreaRandomizer[self.player].value + def create_regions(self): create_regions(self.world,self.player) - def set_rules(self): - set_rules(self.world,self.player) + self.area_connections = {} + set_rules(self.world, self.player, self.area_connections) def create_item(self, name: str) -> Item: item_id = item_table[name] @@ -40,16 +45,20 @@ class SM64World(World): def generate_basic(self): staritem = self.create_item("Power Star") - starcount = self.world.StarsToFinish[self.player].value + self.world.ExtraStars[self.player].value - if (self.world.EnableCoinStars[self.player].value and (starcount-15) >= self.world.StarsToFinish[self.player].value): - starcount -= 15 + starcount = min(self.world.StarsToFinish[self.player].value + self.world.ExtraStars[self.player].value,120) + if (not self.world.EnableCoinStars[self.player].value): + starcount = max(starcount - 15,self.world.StarsToFinish[self.player].value) self.world.itempool += [staritem for i in range(0,starcount)] mushroomitem = self.create_item("1Up Mushroom") - self.world.itempool += [mushroomitem for i in range(starcount,120)] + self.world.itempool += [mushroomitem for i in range(starcount,120 - (15 if not self.world.EnableCoinStars[self.player].value else 0))] - key1 = self.create_item("Basement Key") - key2 = self.create_item("Second Floor Key") - self.world.itempool += [key1,key2] + if (not self.world.ProgressiveKeys[self.player].value): + key1 = self.create_item("Basement Key") + key2 = self.create_item("Second Floor Key") + self.world.itempool += [key1,key2] + else: + key = self.create_item("Progressive Key") + self.world.itempool += [key,key] wingcap = self.create_item("Wing Cap") metalcap = self.create_item("Metal Cap") @@ -58,5 +67,6 @@ class SM64World(World): def fill_slot_data(self): return { + "AreaRando": self.area_connections, "StarsToFinish": self.world.StarsToFinish[self.player].value }