sm64ex: Various Features (#790)

* sm64ex: Course and Secret Randomizer

* sm64ex: Allow higher star door costs, raise minimum amount of stars, deprecate ExtraStars

* sm64ex: Support setting MIPS costs

* sm64ex: Safeguard MIPS Costs
This commit is contained in:
Yussur Mustafa Oraji
2022-07-25 18:39:31 +02:00
committed by GitHub
parent e6635cdd77
commit c3ff201b90
6 changed files with 235 additions and 150 deletions

View File

@@ -1,56 +1,76 @@
from ..generic.Rules import add_rule
from .Regions import connect_regions, sm64courses, sm64paintings
from .Regions import connect_regions, sm64courses, sm64paintings, sm64secrets, sm64entrances
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 set_rules(world, player: int, area_connections):
entrance_ids = list(range(len(sm64paintings)))
destination_courses = list(range(13)) + [12,13,14] # Two instances of Destination Course THI
if world.AreaRandomizer[player]:
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
if world.AreaRandomizer[player].value == 0:
entrance_ids = list(range(len(sm64paintings + sm64secrets)))
if world.AreaRandomizer[player].value >= 1: # Some randomization is happening, randomize Courses
entrance_ids = list(range(len(sm64paintings)))
world.random.shuffle(entrance_ids)
temp_assign = dict(zip(entrance_ids,destination_courses)) # Used for Rules only
entrance_ids = entrance_ids + list(range(len(sm64paintings), len(sm64paintings) + len(sm64secrets)))
if world.AreaRandomizer[player].value == 2: # Secret Regions as well
world.random.shuffle(entrance_ids)
# 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))
# Guarantee COTMC is not mapped to HMC, cuz thats impossible
fix_reg(entrance_ids, 20, 5, swaplist, world)
# Guarantee BITFS is not mapped to DDD
fix_reg(entrance_ids, 22, 8, swaplist, world)
temp_assign = dict(zip(entrance_ids,destination_regions)) # Used for Rules only
# Destination Format: LVL | AREA with LVL = Course ID, 0-indexed, AREA = Area as used in sm64 code
area_connections.update({entrance: (destination_course*10 + 1) for entrance, destination_course in temp_assign.items()})
for i in range(len(area_connections)):
if (int(area_connections[i]/10) == 12):
# Change first occurence of course 12 (THI) to Area 2 (THI Tiny)
area_connections[i] = 12*10 + 2
break
connect_regions(world, player, "Menu", sm64courses[temp_assign[0]])
connect_regions(world, player, "Menu", sm64courses[temp_assign[1]], lambda state: state.has("Power Star", player, 1))
connect_regions(world, player, "Menu", sm64courses[temp_assign[2]], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", sm64courses[temp_assign[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, world.FirstBowserStarDoorCost[player].value))
connect_regions(world, player, "Menu", sm64courses[temp_assign[4]], lambda state: state.has("Power Star", player, 12))
# 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)})
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", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
connect_regions(world, player, "Basement", sm64courses[temp_assign[5]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[6]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[7]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[8]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value))
connect_regions(world, player, "Basement", "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, "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, "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]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[10]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[11]])
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", "Third Floor", lambda state: state.has("Power Star", player, world.SecondFloorStarDoorCost[player].value))
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[14]])
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[15]])
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
#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("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("BoB: Mario Wings to the Sky", player), lambda state: state.has("Cannon Unlock BoB", 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("Vanish Cap", player))
@@ -89,18 +109,14 @@ def set_rules(world, player: int, area_connections):
add_rule(world.get_location("BoB: 100 Coins", player), lambda state: state.has("Cannon Unlock BoB", player) or state.has("Wing Cap", player))
#Rules for Secret Stars
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))
add_rule(world.get_location("Cavern of the Metal Cap Red Coins", player), lambda state: state.can_reach("Cavern of the Metal 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("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.has("Power Star", player, 3))
add_rule(world.get_location("Wing Mario Over the Rainbow", player), lambda state: state.has("Wing Cap", 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) 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))
world.completion_condition[player] = lambda state: state.can_reach("Third Floor", 'Region', player) and state.has("Power Star", player, world.StarsToFinish[player].value)
if world.MIPS1Cost[player].value > world.MIPS2Cost[player].value:
world.MIPS2Cost[player].value = world.MIPS1Cost[player].value
add_rule(world.get_location("MIPS 1", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, world.MIPS1Cost[player].value))
add_rule(world.get_location("MIPS 2", player), lambda state: state.can_reach("Basement", 'Region', player) and state.has("Power Star", player, world.MIPS2Cost[player].value))
world.completion_condition[player] = lambda state: state.can_reach("Bowser in the Sky", 'Region', player)