sm64ex: Refactor Regions (#2546)

Refactors region code to remove references to course index.
There were bugs somewhere, but I dont know where tbh.
This fixes them but leaves logic otherwise intact, and much cleaner to look at as there's one list less to take care of.

Additionally, this fixes stopping the clock from Big Boos Haunt.
This commit is contained in:
Yussur Mustafa Oraji
2023-12-06 18:19:03 +01:00
committed by GitHub
parent 229a263131
commit 530617c9a7
3 changed files with 107 additions and 82 deletions

View File

@@ -1,77 +1,84 @@
from ..generic.Rules import add_rule
from .Regions import connect_regions, sm64courses, sm64paintings, sm64secrets, sm64entrances
from .Regions import connect_regions, sm64_level_to_paintings, sm64_paintings_to_level, sm64_level_to_secrets, sm64_entrances_to_level, sm64_level_to_entrances
def fix_reg(entrance_ids, reg, invalidspot, swaplist, world):
if entrance_ids.index(reg) == invalidspot: # Unlucky :C
swaplist.remove(invalidspot)
rand = world.random.choice(swaplist)
entrance_ids[invalidspot], entrance_ids[rand] = entrance_ids[rand], entrance_ids[invalidspot]
swaplist.append(invalidspot)
swaplist.remove(rand)
def shuffle_dict_keys(world, obj: dict) -> dict:
keys = list(obj.keys())
values = list(obj.values())
world.random.shuffle(keys)
return dict(zip(keys,values))
def set_rules(world, player: int, area_connections):
destination_regions = list(range(13)) + [12,13,14] + list(range(15,15+len(sm64secrets))) # Two instances of Destination Course THI. Past normal course idx are secret regions
secret_entrance_ids = list(range(len(sm64paintings), len(sm64paintings) + len(sm64secrets)))
course_entrance_ids = list(range(len(sm64paintings)))
if world.AreaRandomizer[player].value >= 1: # Some randomization is happening, randomize Courses
world.random.shuffle(course_entrance_ids)
def fix_reg(entrance_ids, entrance, destination, swapdict, world):
if entrance_ids[entrance] == destination: # Unlucky :C
rand = world.random.choice(swapdict.keys())
entrance_ids[entrance], entrance_ids[swapdict[rand]] = rand, entrance_ids[entrance]
swapdict[rand] = entrance_ids[entrance]
swapdict.pop(entrance)
def set_rules(world, player: int, area_connections: dict):
randomized_level_to_paintings = sm64_level_to_paintings.copy()
randomized_level_to_secrets = sm64_level_to_secrets.copy()
if world.AreaRandomizer[player].value == 1: # Some randomization is happening, randomize Courses
randomized_level_to_paintings = shuffle_dict_keys(world,sm64_level_to_paintings)
if world.AreaRandomizer[player].value == 2: # Randomize Secrets as well
world.random.shuffle(secret_entrance_ids)
entrance_ids = course_entrance_ids + secret_entrance_ids
randomized_level_to_secrets = shuffle_dict_keys(world,sm64_level_to_secrets)
randomized_entrances = { **randomized_level_to_paintings, **randomized_level_to_secrets }
if world.AreaRandomizer[player].value == 3: # Randomize Courses and Secrets in one pool
world.random.shuffle(entrance_ids)
randomized_entrances = shuffle_dict_keys(world,randomized_entrances)
# Guarantee first entrance is a course
swaplist = list(range(len(entrance_ids)))
if entrance_ids.index(0) > 15: # Unlucky :C
rand = world.random.randint(0,15)
entrance_ids[entrance_ids.index(0)], entrance_ids[rand] = entrance_ids[rand], entrance_ids[entrance_ids.index(0)]
swaplist.remove(entrance_ids.index(0))
swapdict = { entrance: level for (level,entrance) in randomized_entrances }
if randomized_entrances[91] not in sm64_paintings_to_level.keys(): # Unlucky :C (91 -> BoB Entrance)
rand = world.random.choice(sm64_paintings_to_level.values())
randomized_entrances[91], randomized_entrances[swapdict[rand]] = rand, randomized_entrances[91]
swapdict[rand] = randomized_entrances[91]
swapdict.pop("Bob-omb Battlefield")
# Guarantee COTMC is not mapped to HMC, cuz thats impossible
fix_reg(entrance_ids, 20, 5, swaplist, world)
fix_reg(randomized_entrances, "Cavern of the Metal Cap", "Hazy Maze Cave", swapdict, world)
# Guarantee BITFS is not mapped to DDD
fix_reg(entrance_ids, 22, 8, swaplist, world)
if entrance_ids.index(22) == 5: # If BITFS is mapped to HMC...
fix_reg(entrance_ids, 20, 8, swaplist, world) # ... then dont allow COTMC to be mapped to DDD
temp_assign = dict(zip(entrance_ids,destination_regions)) # Used for Rules only
fix_reg(randomized_entrances, "Bowser in the Fire Sea", "Dire, Dire Docks", swapdict, world)
if randomized_entrances[191] == "Hazy Maze Cave": # If BITFS is mapped to HMC...
fix_reg(randomized_entrances, "Cavern of the Metal Cap", "Dire, Dire Docks", swapdict, world) # ... then dont allow COTMC to be mapped to DDD
# Destination Format: LVL | AREA with LVL = LEVEL_x, AREA = Area as used in sm64 code
area_connections.update({sm64entrances[entrance]: destination for entrance, destination in zip(entrance_ids,sm64entrances)})
area_connections.update({entrance_lvl: sm64_entrances_to_level[destination] for (entrance_lvl,destination) in randomized_entrances.items()})
randomized_entrances_s = {sm64_level_to_entrances[entrance_lvl]: destination for (entrance_lvl,destination) in randomized_entrances.items()}
connect_regions(world, player, "Menu", sm64courses[temp_assign[0]]) # BOB
connect_regions(world, player, "Menu", sm64courses[temp_assign[1]], lambda state: state.has("Power Star", player, 1)) # WF
connect_regions(world, player, "Menu", sm64courses[temp_assign[2]], lambda state: state.has("Power Star", player, 3)) # JRB
connect_regions(world, player, "Menu", sm64courses[temp_assign[3]], lambda state: state.has("Power Star", player, 3)) # CCM
connect_regions(world, player, "Menu", sm64courses[temp_assign[4]], lambda state: state.has("Power Star", player, 12)) # BBH
connect_regions(world, player, "Menu", sm64courses[temp_assign[16]], lambda state: state.has("Power Star", player, 1)) # PSS
connect_regions(world, player, "Menu", sm64courses[temp_assign[17]], lambda state: state.has("Power Star", player, 3)) # SA
connect_regions(world, player, "Menu", sm64courses[temp_assign[19]], lambda state: state.has("Power Star", player, 10)) # TOTWC
connect_regions(world, player, "Menu", sm64courses[temp_assign[18]], lambda state: state.has("Power Star", player, world.FirstBowserStarDoorCost[player].value)) # BITDW
connect_regions(world, player, "Menu", randomized_entrances_s["Bob-omb Battlefield"])
connect_regions(world, player, "Menu", randomized_entrances_s["Whomp's Fortress"], lambda state: state.has("Power Star", player, 1))
connect_regions(world, player, "Menu", randomized_entrances_s["Jolly Roger Bay"], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", randomized_entrances_s["Cool, Cool Mountain"], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", randomized_entrances_s["Big Boo's Haunt"], lambda state: state.has("Power Star", player, 12))
connect_regions(world, player, "Menu", randomized_entrances_s["The Princess's Secret Slide"], lambda state: state.has("Power Star", player, 1))
connect_regions(world, player, "Menu", randomized_entrances_s["The Secret Aquarium"], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", randomized_entrances_s["Tower of the Wing Cap"], lambda state: state.has("Power Star", player, 10))
connect_regions(world, player, "Menu", randomized_entrances_s["Bowser in the Dark World"], lambda state: state.has("Power Star", player, world.FirstBowserStarDoorCost[player].value))
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", sm64courses[temp_assign[5]]) # HMC
connect_regions(world, player, "Basement", sm64courses[temp_assign[6]]) # LLL
connect_regions(world, player, "Basement", sm64courses[temp_assign[7]]) # SSL
connect_regions(world, player, "Basement", sm64courses[temp_assign[8]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value)) # DDD
connect_regions(world, player, "Hazy Maze Cave", sm64courses[temp_assign[20]]) # COTMC
connect_regions(world, player, "Basement", sm64courses[temp_assign[21]]) # VCUTM
connect_regions(world, player, "Basement", sm64courses[temp_assign[22]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value) and
state.can_reach("DDD: Board Bowser's Sub", 'Location', player)) # BITFS
connect_regions(world, player, "Basement", randomized_entrances_s["Hazy Maze Cave"])
connect_regions(world, player, "Basement", randomized_entrances_s["Lethal Lava Land"])
connect_regions(world, player, "Basement", randomized_entrances_s["Shifting Sand Land"])
connect_regions(world, player, "Basement", randomized_entrances_s["Dire, Dire Docks"], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value))
connect_regions(world, player, "Hazy Maze Cave", randomized_entrances_s["Cavern of the Metal Cap"])
connect_regions(world, player, "Basement", randomized_entrances_s["Vanish Cap under the Moat"])
connect_regions(world, player, "Basement", randomized_entrances_s["Bowser in the Fire Sea"], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value) and
state.can_reach("DDD: Board Bowser's Sub", 'Location', player))
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[temp_assign[9]]) # SL
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[10]]) # WDW
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[11]]) # TTM
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[12]]) # THI Tiny
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[13]]) # THI Huge
connect_regions(world, player, "Second Floor", randomized_entrances_s["Snowman's Land"])
connect_regions(world, player, "Second Floor", randomized_entrances_s["Wet-Dry World"])
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tall, Tall Mountain"])
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Tiny)"])
connect_regions(world, player, "Second Floor", randomized_entrances_s["Tiny-Huge Island (Huge)"])
connect_regions(world, player, "Tiny-Huge Island (Tiny)", "Tiny-Huge Island (Huge)")
connect_regions(world, player, "Tiny-Huge Island (Huge)", "Tiny-Huge Island (Tiny)")
connect_regions(world, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, world.SecondFloorStarDoorCost[player].value))
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[14]]) # TTC
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[15]]) # RR
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[23]]) # WMOTR
connect_regions(world, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, world.StarsToFinish[player].value)) # BITS
connect_regions(world, player, "Third Floor", randomized_entrances_s["Tick Tock Clock"])
connect_regions(world, player, "Third Floor", randomized_entrances_s["Rainbow Ride"])
connect_regions(world, player, "Third Floor", randomized_entrances_s["Wing Mario over the Rainbow"])
connect_regions(world, player, "Third Floor", "Bowser in the Sky", lambda state: state.has("Power Star", player, world.StarsToFinish[player].value))
#Special Rules for some Locations
add_rule(world.get_location("BoB: Mario Wings to the Sky", player), lambda state: state.has("Cannon Unlock BoB", player))