2022-01-23 20:34:30 +00:00
from . . generic . Rules import add_rule
2023-12-10 19:31:43 +00:00
from . Regions import connect_regions , SM64Levels , sm64_level_to_paintings , sm64_paintings_to_level , sm64_level_to_secrets , sm64_secrets_to_level , sm64_entrances_to_level , sm64_level_to_entrances
2022-01-23 20:34:30 +00:00
2023-12-06 17:19:03 +00:00
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 ) )
2022-02-20 18:10:08 +00:00
2023-12-10 19:31:43 +00:00
def fix_reg ( entrance_map : dict , entrance : SM64Levels , invalid_regions : set ,
swapdict : dict , world ) :
if entrance_map [ entrance ] in invalid_regions : # Unlucky :C
replacement_regions = [ ( rand_region , rand_entrance ) for rand_region , rand_entrance in swapdict . items ( )
if rand_region not in invalid_regions ]
rand_region , rand_entrance = world . random . choice ( replacement_regions )
old_dest = entrance_map [ entrance ]
entrance_map [ entrance ] , entrance_map [ rand_entrance ] = rand_region , old_dest
swapdict [ rand_region ] = entrance
swapdict . pop ( entrance_map [ entrance ] ) # Entrance now fixed to rand_region
2023-12-06 17:19:03 +00:00
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 )
2022-10-27 23:43:02 +00:00
if world . AreaRandomizer [ player ] . value == 2 : # Randomize Secrets as well
2023-12-06 17:19:03 +00:00
randomized_level_to_secrets = shuffle_dict_keys ( world , sm64_level_to_secrets )
randomized_entrances = { * * randomized_level_to_paintings , * * randomized_level_to_secrets }
2022-10-27 23:43:02 +00:00
if world . AreaRandomizer [ player ] . value == 3 : # Randomize Courses and Secrets in one pool
2023-12-06 17:19:03 +00:00
randomized_entrances = shuffle_dict_keys ( world , randomized_entrances )
2023-12-10 19:31:43 +00:00
swapdict = { entrance : level for ( level , entrance ) in randomized_entrances . items ( ) }
2022-07-25 16:39:31 +00:00
# Guarantee first entrance is a course
2023-12-10 19:31:43 +00:00
fix_reg ( randomized_entrances , SM64Levels . BOB_OMB_BATTLEFIELD , sm64_secrets_to_level . keys ( ) , swapdict , world )
2022-07-25 16:39:31 +00:00
# Guarantee BITFS is not mapped to DDD
2023-12-10 19:31:43 +00:00
fix_reg ( randomized_entrances , SM64Levels . BOWSER_IN_THE_FIRE_SEA , { " Dire, Dire Docks " } , swapdict , world )
# Guarantee COTMC is not mapped to HMC, cuz thats impossible. If BitFS -> HMC, also no COTMC -> DDD.
if randomized_entrances [ SM64Levels . BOWSER_IN_THE_FIRE_SEA ] == " Hazy Maze Cave " :
fix_reg ( randomized_entrances , SM64Levels . CAVERN_OF_THE_METAL_CAP , { " Hazy Maze Cave " , " Dire, Dire Docks " } , swapdict , world )
else :
fix_reg ( randomized_entrances , SM64Levels . CAVERN_OF_THE_METAL_CAP , { " Hazy Maze Cave " } , swapdict , world )
2022-07-25 16:39:31 +00:00
# Destination Format: LVL | AREA with LVL = LEVEL_x, AREA = Area as used in sm64 code
2023-12-13 22:46:46 +00:00
# Cast to int to not rely on availability of SM64Levels enum. Will cause crash in MultiServer otherwise
area_connections . update ( { int ( entrance_lvl ) : int ( sm64_entrances_to_level [ destination ] ) for ( entrance_lvl , destination ) in randomized_entrances . items ( ) } )
2023-12-06 17:19:03 +00:00
randomized_entrances_s = { sm64_level_to_entrances [ entrance_lvl ] : destination for ( entrance_lvl , destination ) in randomized_entrances . items ( ) }
2022-07-25 16:39:31 +00:00
2023-12-06 17:19:03 +00:00
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 ) )
2022-01-23 20:34:30 +00:00
2022-02-09 19:57:38 +00:00
connect_regions ( world , player , " Menu " , " Basement " , lambda state : state . has ( " Basement Key " , player ) or state . has ( " Progressive Key " , player , 1 ) )
2022-01-23 20:34:30 +00:00
2023-12-06 17:19:03 +00:00
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 ) )
2022-01-23 20:34:30 +00:00
2022-02-09 19:57:38 +00:00
connect_regions ( world , player , " Menu " , " Second Floor " , lambda state : state . has ( " Second Floor Key " , player ) or state . has ( " Progressive Key " , player , 2 ) )
2022-01-23 20:34:30 +00:00
2023-12-06 17:19:03 +00:00
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) " )
2022-01-23 20:34:30 +00:00
2022-07-14 16:37:14 +00:00
connect_regions ( world , player , " Second Floor " , " Third Floor " , lambda state : state . has ( " Power Star " , player , world . SecondFloorStarDoorCost [ player ] . value ) )
2022-01-23 20:34:30 +00:00
2023-12-06 17:19:03 +00:00
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 ) )
2022-01-23 20:34:30 +00:00
#Special Rules for some Locations
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " BoB: Mario Wings to the Sky " , player ) , lambda state : state . has ( " Cannon Unlock BoB " , player ) )
2022-01-27 16:42:10 +00:00
add_rule ( world . get_location ( " BBH: Eye to Eye in the Secret Room " , player ) , lambda state : state . has ( " Vanish Cap " , player ) )
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " DDD: Collect the Caps... " , player ) , lambda state : 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 ) )
2022-06-28 06:03:34 +00:00
if world . EnableCoinStars [ player ] :
add_rule ( world . get_location ( " DDD: 100 Coins " , player ) , lambda state : state . can_reach ( " Bowser in the Fire Sea " , ' Region ' , player ) )
2022-01-27 16:42:10 +00:00
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 ) )
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " RR: Somewhere Over the Rainbow " , player ) , lambda state : state . has ( " Cannon Unlock RR " , player ) )
if world . AreaRandomizer [ player ] or world . StrictCannonRequirements [ player ] :
# If area rando is on, it may not be possible to modify WDW's starting water level,
# which would make it impossible to reach downtown area without the cannon.
add_rule ( world . get_location ( " WDW: Quick Race Through Downtown! " , player ) , lambda state : state . has ( " Cannon Unlock WDW " , player ) )
add_rule ( world . get_location ( " WDW: Go to Town for Red Coins " , player ) , lambda state : state . has ( " Cannon Unlock WDW " , player ) )
2022-09-16 18:58:28 +00:00
add_rule ( world . get_location ( " WDW: 1Up Block in Downtown " , player ) , lambda state : state . has ( " Cannon Unlock WDW " , player ) )
2022-05-06 11:33:39 +00:00
if world . StrictCapRequirements [ player ] :
add_rule ( world . get_location ( " BoB: Mario Wings to the Sky " , player ) , lambda state : state . has ( " Wing Cap " , player ) )
2022-01-27 16:42:10 +00:00
add_rule ( world . get_location ( " HMC: Metal-Head Mario Can Move! " , player ) , lambda state : state . has ( " Metal Cap " , player ) )
2022-01-23 20:34:30 +00:00
add_rule ( world . get_location ( " JRB: Through the Jet Stream " , player ) , lambda state : state . has ( " Metal Cap " , player ) )
2022-01-27 16:42:10 +00:00
add_rule ( world . get_location ( " SSL: Free Flying for 8 Red Coins " , player ) , lambda state : state . has ( " Wing Cap " , player ) )
2022-01-23 20:34:30 +00:00
add_rule ( world . get_location ( " DDD: Through the Jet Stream " , player ) , lambda state : state . has ( " Metal Cap " , player ) )
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " DDD: Collect the Caps... " , player ) , lambda state : state . has ( " Metal Cap " , player ) )
2022-01-23 20:34:30 +00:00
add_rule ( world . get_location ( " Vanish Cap Under the Moat Red Coins " , player ) , lambda state : state . has ( " Vanish Cap " , player ) )
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " Cavern of the Metal Cap Red Coins " , player ) , lambda state : state . has ( " Metal Cap " , player ) )
if world . StrictCannonRequirements [ player ] :
2022-02-15 18:56:10 +00:00
add_rule ( world . get_location ( " WF: Blast Away the Wall " , player ) , lambda state : state . has ( " Cannon Unlock WF " , player ) )
add_rule ( world . get_location ( " JRB: Blast to the Stone Pillar " , player ) , lambda state : state . has ( " Cannon Unlock JRB " , player ) )
2022-05-06 11:33:39 +00:00
add_rule ( world . get_location ( " CCM: Wall Kicks Will Work " , player ) , lambda state : state . has ( " Cannon Unlock CCM " , player ) )
add_rule ( world . get_location ( " TTM: Blast to the Lonely Mushroom " , player ) , lambda state : state . has ( " Cannon Unlock TTM " , player ) )
if world . StrictCapRequirements [ player ] and world . StrictCannonRequirements [ player ] :
# Ability to reach the floating island. Need some of those coins to get 100 coin star as well.
2022-04-24 09:49:30 +00:00
add_rule ( world . get_location ( " BoB: Find the 8 Red Coins " , player ) , lambda state : state . has ( " Cannon Unlock BoB " , player ) or state . has ( " Wing Cap " , player ) )
add_rule ( world . get_location ( " BoB: Shoot to the Island in the Sky " , player ) , lambda state : state . has ( " Cannon Unlock BoB " , player ) or state . has ( " Wing Cap " , player ) )
2022-05-06 11:33:39 +00:00
if world . EnableCoinStars [ player ] :
add_rule ( world . get_location ( " BoB: 100 Coins " , player ) , lambda state : state . has ( " Cannon Unlock BoB " , player ) or state . has ( " Wing Cap " , player ) )
2022-01-23 20:34:30 +00:00
#Rules for Secret Stars
2022-08-21 18:45:39 +00:00
add_rule ( world . get_location ( " Wing Mario Over the Rainbow Red Coins " , player ) , lambda state : state . has ( " Wing Cap " , player ) )
add_rule ( world . get_location ( " Wing Mario Over the Rainbow 1Up Block " , player ) , lambda state : state . has ( " Wing Cap " , player ) )
2022-05-06 11:33:39 +00:00
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 ) )
2022-01-23 20:34:30 +00:00
2022-07-25 16:39:31 +00:00
if world . MIPS1Cost [ player ] . value > world . MIPS2Cost [ player ] . value :
2022-10-27 23:43:02 +00:00
( world . MIPS2Cost [ player ] . value , world . MIPS1Cost [ player ] . value ) = ( world . MIPS1Cost [ player ] . value , world . MIPS2Cost [ player ] . value )
2022-07-25 16:39:31 +00:00
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 ) )
2023-10-28 19:44:16 +00:00
if world . CompletionType [ player ] == " last_bowser_stage " :
world . completion_condition [ player ] = lambda state : state . can_reach ( " Bowser in the Sky " , ' Region ' , player )
elif world . CompletionType [ player ] == " all_bowser_stages " :
world . completion_condition [ player ] = lambda state : state . can_reach ( " Bowser in the Dark World " , ' Region ' , player ) and \
state . can_reach ( " Bowser in the Fire Sea " , ' Region ' , player ) and \
state . can_reach ( " Bowser in the Sky " , ' Region ' , player )