sm64ex: Add Course Randomizer and Progressive Keys (#256)

This commit is contained in:
Yussur Mustafa Oraji 2022-02-09 20:57:38 +01:00 committed by GitHub
parent ee5ea09cbc
commit 3d17f0d588
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 79 deletions

View File

@ -7,8 +7,9 @@ item_table = {
"Power Star": 3626000, "Power Star": 3626000,
"Basement Key": 3626178, "Basement Key": 3626178,
"Second Floor Key": 3626179, "Second Floor Key": 3626179,
"Wing Cap": 3626180, "Progressive Key": 3626180,
"Metal Cap": 3626181, "Wing Cap": 3626181,
"Vanish Cap": 3626182, "Metal Cap": 3626182,
"1Up Mushroom": 3626183 "Vanish Cap": 3626183,
"1Up Mushroom": 3626184
} }

View File

@ -172,10 +172,18 @@ loc100Coin_table = {
"RR: 100 Coins": 3626104 "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 #Secret Stars and Stages
locSS_table = { 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, "Bowser in the Sky Red Coins": 3626119,
"The Princess's Secret Slide Block": 3626126, "The Princess's Secret Slide Block": 3626126,
"The Princess's Secret Slide Fast": 3626127, "The Princess's Secret Slide Fast": 3626127,
@ -191,21 +199,15 @@ locSS_table = {
"MIPS 2": 3626172 "MIPS 2": 3626172
} }
#Keys
locKey_table = {
"Bowser in the Dark World Key": 3626178,
"Bowser in the Fire Sea Key": 3626179
}
#Caps #Caps
locCap_table = { locCap_table = {
"Tower of the Wing Cap Switch": 3626180, "Tower of the Wing Cap Switch": 3626181,
"Cavern of the Metal Cap Switch": 3626181, "Cavern of the Metal Cap Switch": 3626182,
"Vanish Cap Under the Moat 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 # 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, \ location_table = {**locBoB_table,**locWhomp_table,**locJRB_table,**locCCM_table,**locBBH_table, \
**locHMC_table,**locLLL_table,**locSSL_table,**locDDD_table,**locSL_table, \ **locHMC_table,**locLLL_table,**locSSL_table,**locDDD_table,**locSL_table, \
**locWDW_table,**locTTM_table,**locTHI_table,**locTTC_table,**locRR_table, \ **locWDW_table,**locTTM_table,**locTHI_table,**locTTC_table,**locRR_table, \
**loc100Coin_table,**locSS_table,**locKey_table,**locCap_table} **loc100Coin_table,**locBitDW_table,**locBitFS_table,**locSS_table,**locCap_table}

View File

@ -1,5 +1,5 @@
import typing import typing
from Options import Option, DefaultOnToggle, Range from Options import Option, DefaultOnToggle, Range, Toggle
class EnableCoinStars(DefaultOnToggle): class EnableCoinStars(DefaultOnToggle):
"""Disable to Ignore 100 Coin Stars. You can still collect them, but they don't do anything""" """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 range_end = 50
default = 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)] = { sm64_options: typing.Dict[str,type(Option)] = {
"AreaRandomizer": AreaRandomizer,
"ProgressiveKeys": ProgressiveKeys,
"EnableCoinStars": EnableCoinStars, "EnableCoinStars": EnableCoinStars,
"StrictCapRequirements": StrictCapRequirements, "StrictCapRequirements": StrictCapRequirements,
"StarsToFinish": StarsToFinish, "StarsToFinish": StarsToFinish,

View File

@ -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, \ 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, \ locHMC_table,locLLL_table,locSSL_table,locDDD_table,locSL_table, \
locWDW_table,locTTM_table,locTHI_table,locTTC_table,locRR_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): def create_regions(world: MultiWorld, player: int):
regSS = Region("Menu", RegionType.Generic, "Castle Area", player, world) 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 locSS_table.items()]
locSS_names += [name for name, id in locKey_table.items()]
locSS_names += [name for name, id in locCap_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] regSS.locations += [SM64Location(player, loc_name, location_table[loc_name], regSS) for loc_name in locSS_names]
world.regions.append(regSS) 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)) regBBH.locations.append(SM64Location(player, "BBH: 100 Coins", location_table["BBH: 100 Coins"], regBBH))
world.regions.append(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) regBasement = Region("Basement", RegionType.Generic, "Basement", player, world)
world.regions.append(regBasement) 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)) regDDD.locations.append(SM64Location(player, "DDD: 100 Coins", location_table["DDD: 100 Coins"], regDDD))
world.regions.append(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) regFloor2 = Region("Second Floor", RegionType.Generic, "Second Floor", player, world)
world.regions.append(regFloor2) world.regions.append(regFloor2)

View File

@ -1,60 +1,50 @@
import typing import typing
from ..generic.Rules import add_rule from ..generic.Rules import add_rule
from .Regions import connect_regions from .Regions import connect_regions, sm64courses
def set_rules(world,player): def set_rules(world,player,area_connections):
connect_regions(world, player, "Menu", "Bob-omb Battlefield", lambda state: True) courseshuffle = list(range(len(sm64courses)))
connect_regions(world, player, "Menu", "Whomp's Fortress", lambda state: state.has("Power Star", player, 1)) if (world.AreaRandomizer[player].value):
connect_regions(world, player, "Menu", "Jolly Roger Bay", lambda state: state.has("Power Star", player, 3)) world.random.shuffle(courseshuffle)
connect_regions(world, player, "Menu", "Cool, Cool Mountain", lambda state: state.has("Power Star", player, 3)) area_connections.update({index: value for index, value in enumerate(courseshuffle)})
connect_regions(world, player, "Menu", "Big Boo's Haunt", lambda state: state.has("Power Star", player, 12))
connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player)) connect_regions(world, player, "Menu", sm64courses[area_connections[0]], lambda state: True)
connect_regions(world, player, "Basement", "Menu", 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, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
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", "Second Floor", lambda state: state.has("Second Floor Key", player)) connect_regions(world, player, "Basement", sm64courses[area_connections[5]], lambda state: True)
connect_regions(world, player, "Second Floor", "Menu", 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, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2))
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", sm64courses[area_connections[9]], lambda state: True)
connect_regions(world, player, "Second Floor", "Tiny-Huge Island", 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, "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", sm64courses[area_connections[13]], lambda state: True)
connect_regions(world, player, "Third Floor", "Rainbow Ride", lambda state: True) connect_regions(world, player, "Third Floor", sm64courses[area_connections[14]], 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)
#Special Rules for some Locations #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("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("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("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 add_rule(world.get_location("DDD: Collect the Caps...", player), lambda state: state.has("Metal Cap", player) and
state.has("Vanish Cap", player)) 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("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)) add_rule(world.get_location("WDW: Quick Race Through Downtown!", player), lambda state: state.has("Vanish Cap", player))
if (world.StrictCapRequirements[player].value): 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)) add_rule(world.get_location("Vanish Cap Under the Moat Red Coins", player), lambda state: state.has("Vanish Cap", player))
#Rules for Secret Stars #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("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 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)) 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("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("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("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("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)) 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)) 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)) 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 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)) 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) world.completion_condition[player] = lambda state: state.can_reach("Third Floor",'Region',player) and state.has("Power Star", player, world.StarsToFinish[player].value)

View File

@ -1,4 +1,4 @@
import string import typing
from .Items import item_table, SM64Item from .Items import item_table, SM64Item
from .Locations import location_table, SM64Location from .Locations import location_table, SM64Location
from .Options import sm64_options from .Options import sm64_options
@ -21,17 +21,22 @@ class SM64World(World):
item_name_to_id = item_table item_name_to_id = item_table
location_name_to_id = location_table location_name_to_id = location_table
data_version = 4 data_version = 5
forced_auto_forfeit = False forced_auto_forfeit = False
area_connections: typing.Dict[int, int]
options = sm64_options options = sm64_options
def generate_early(self):
self.topology_present = self.world.AreaRandomizer[self.player].value
def create_regions(self): def create_regions(self):
create_regions(self.world,self.player) create_regions(self.world,self.player)
def set_rules(self): 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: def create_item(self, name: str) -> Item:
item_id = item_table[name] item_id = item_table[name]
@ -40,16 +45,20 @@ class SM64World(World):
def generate_basic(self): def generate_basic(self):
staritem = self.create_item("Power Star") staritem = self.create_item("Power Star")
starcount = self.world.StarsToFinish[self.player].value + self.world.ExtraStars[self.player].value starcount = min(self.world.StarsToFinish[self.player].value + self.world.ExtraStars[self.player].value,120)
if (self.world.EnableCoinStars[self.player].value and (starcount-15) >= self.world.StarsToFinish[self.player].value): if (not self.world.EnableCoinStars[self.player].value):
starcount -= 15 starcount = max(starcount - 15,self.world.StarsToFinish[self.player].value)
self.world.itempool += [staritem for i in range(0,starcount)] self.world.itempool += [staritem for i in range(0,starcount)]
mushroomitem = self.create_item("1Up Mushroom") 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") if (not self.world.ProgressiveKeys[self.player].value):
key2 = self.create_item("Second Floor Key") key1 = self.create_item("Basement Key")
self.world.itempool += [key1,key2] 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") wingcap = self.create_item("Wing Cap")
metalcap = self.create_item("Metal Cap") metalcap = self.create_item("Metal Cap")
@ -58,5 +67,6 @@ class SM64World(World):
def fill_slot_data(self): def fill_slot_data(self):
return { return {
"AreaRando": self.area_connections,
"StarsToFinish": self.world.StarsToFinish[self.player].value "StarsToFinish": self.world.StarsToFinish[self.player].value
} }