Added Super Metroid support (#46)

Varia Randomizer based implementation
LttPClient -> SNIClient
This commit is contained in:
lordlou
2021-11-12 08:00:11 -05:00
committed by GitHub
parent 61ae51b30c
commit 77ec8d4141
141 changed files with 43859 additions and 106 deletions

View File

@@ -0,0 +1,758 @@
from graph.graph import AccessPoint
from utils.parameters import Settings
from rom.rom_patches import RomPatches
from logic.smbool import SMBool
from logic.helpers import Bosses
from logic.cache import Cache
# all access points and traverse functions
accessPoints = [
### Ceres Station
AccessPoint('Ceres', 'Ceres', {
'Landing Site': lambda sm: SMBool(True)
}, internal=True,
start={'spawn': 0xfffe, 'doors':[0x32], 'patches':[RomPatches.BlueBrinstarBlueDoor], 'solveArea': "Crateria Landing Site"}),
### Crateria and Blue Brinstar
AccessPoint('Landing Site', 'Crateria', {
'Lower Mushrooms Left': Cache.ldeco(lambda sm: sm.wand(sm.canPassTerminatorBombWall(),
sm.canPassCrateriaGreenPirates())),
'Keyhunter Room Bottom': Cache.ldeco(lambda sm: sm.traverse('LandingSiteRight')),
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}, internal=True,
start={'spawn': 0x0000, 'doors':[0x32], 'patches':[RomPatches.BlueBrinstarBlueDoor], 'solveArea': "Crateria Landing Site"}),
AccessPoint('Blue Brinstar Elevator Bottom', 'Crateria', {
'Morph Ball Room Left': lambda sm: sm.canUsePowerBombs(),
'Landing Site': lambda sm: SMBool(True)
}, internal=True),
AccessPoint('Gauntlet Top', 'Crateria', {
'Green Pirates Shaft Bottom Right': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'), sm.canPassCrateriaGreenPirates()))
}, internal=True,
start={'spawn': 0x0006, 'solveArea': "Crateria Gauntlet", 'save':"Save_Gauntlet", 'forcedEarlyMorph':True}),
AccessPoint('Lower Mushrooms Left', 'Crateria', {
'Landing Site': Cache.ldeco(lambda sm: sm.wand(sm.canPassTerminatorBombWall(False),
sm.canPassCrateriaGreenPirates())),
'Green Pirates Shaft Bottom Right': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0x9969, "area": 0x0, 'songs':[0x997a]},
exitInfo = {'DoorPtr':0x8c22, 'direction': 0x5, "cap": (0xe, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x36, 'SamusY':0x88, 'song': 0x9},
dotOrientation = 'nw'),
AccessPoint('Green Pirates Shaft Bottom Right', 'Crateria', {
'Lower Mushrooms Left': lambda sm: SMBool(True)
}, traverse = Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoMoreBlueDoors),
sm.traverse('GreenPiratesShaftBottomRight'))),
roomInfo = {'RoomPtr':0x99bd, "area": 0x0, 'songs':[0x99ce]},
# the doorAsmPtr 7FE00 is set by the g4_skip.ips patch, we have to call it
exitInfo = {'DoorPtr':0x8c52, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xfe00},
entryInfo = {'SamusX':0xcc, 'SamusY':0x688, 'song': 0x9},
dotOrientation = 'e'),
AccessPoint('Moat Right', 'Crateria', {
'Moat Left': lambda sm: sm.canPassMoatReverse()
}, roomInfo = {'RoomPtr':0x95ff, "area": 0x0, 'songs':[0x9610]},
exitInfo = {'DoorPtr':0x8aea, 'direction': 0x4, "cap": (0x1, 0x46), "bitFlag": 0x0,
"screen": (0x0, 0x4), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x1cf, 'SamusY':0x88, 'song': 0xc},
dotOrientation = 'ne'),
AccessPoint('Moat Left', 'Crateria', {
'Keyhunter Room Bottom': lambda sm: SMBool(True),
'Moat Right': lambda sm: sm.canPassMoatFromMoat()
}, internal=True),
AccessPoint('Keyhunter Room Bottom', 'Crateria', {
'Moat Left': Cache.ldeco(lambda sm: sm.traverse('KihunterRight')),
'Moat Right': Cache.ldeco(lambda sm: sm.wand(sm.traverse('KihunterRight'), sm.canPassMoat())),
'Landing Site': lambda sm: SMBool(True)
}, traverse = Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoMoreBlueDoors),
sm.traverse('KihunterBottom'))),
roomInfo = { 'RoomPtr':0x948c, "area": 0x0, 'songs':[0x949d] },
exitInfo = {'DoorPtr':0x8a42, 'direction': 0x6, "cap": (0x6, 0x2), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x14c, 'SamusY':0x2b8, 'song': 0xc},
dotOrientation = 'se'),
AccessPoint('Morph Ball Room Left', 'Crateria', {
'Blue Brinstar Elevator Bottom': lambda sm: sm.canUsePowerBombs()
}, roomInfo = { 'RoomPtr':0x9e9f, "area": 0x1},
exitInfo = {'DoorPtr':0x8e9e, 'direction': 0x5, "cap": (0x1e, 0x6), "bitFlag": 0x0,
"screen": (0x1, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x288},
dotOrientation = 'sw'),
# Escape APs
AccessPoint('Climb Bottom Left', 'Crateria', {
'Landing Site': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0x96ba, "area": 0x0},
exitInfo = {'DoorPtr':0x8b6e, 'direction': 0x5, "cap": (0x2e, 0x16), "bitFlag": 0x0,
"screen": (0x2, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x888},
escape = True,
dotOrientation = 'ne'),
AccessPoint('Flyway Right', 'Crateria', {},
roomInfo = {'RoomPtr':0x9879, "area": 0x0},
exitInfo = {'DoorPtr':0x8bc2, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000,
"exitAsmPtr": 0xf030}, # setup_next_escape in rando_escape.asm
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True),
AccessPoint('Bomb Torizo Room Left', 'Crateria', {},
roomInfo = {'RoomPtr':0x9804, "area": 0x0},
exitInfo = {'DoorPtr':0x8baa, 'direction': 0x5, "cap": (0x2e, 0x6), "bitFlag": 0x0,
"screen": (0x2, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0xb8},
escape = True),
### Green and Pink Brinstar
AccessPoint('Green Brinstar Elevator', 'GreenPinkBrinstar', {
'Big Pink': Cache.ldeco(lambda sm: sm.wand(sm.canPassDachoraRoom(),
sm.traverse('MainShaftBottomRight'))),
'Etecoons Bottom': lambda sm: sm.canAccessEtecoons()
}, roomInfo = {'RoomPtr':0x9938, "area": 0x0},
exitInfo = {'DoorPtr':0x8bfe, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xcc, 'SamusY':0x88},
start = {'spawn': 0x0108, 'doors':[0x1f, 0x21, 0x26], 'patches':[RomPatches.BrinReserveBlueDoors], 'solveArea': "Green Brinstar"}, # XXX test if it would be better in brin reserve room with custom save
dotOrientation = 'ne'),
AccessPoint('Big Pink', 'GreenPinkBrinstar', {
'Green Hill Zone Top Right': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'),
sm.traverse('BigPinkBottomRight'))),
'Green Brinstar Elevator': lambda sm: sm.canPassDachoraRoom()
}, internal=True, start={'spawn': 0x0100, 'solveArea': "Pink Brinstar"}),
AccessPoint('Green Hill Zone Top Right', 'GreenPinkBrinstar', {
'Noob Bridge Right': lambda sm: SMBool(True),
'Big Pink': Cache.ldeco(lambda sm: sm.haveItem('Morph'))
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoBlueDoors), sm.traverse('GreenHillZoneTopRight'))),
roomInfo = {'RoomPtr':0x9e52, "area": 0x1 },
exitInfo = {'DoorPtr':0x8e86, 'direction': 0x4, "cap": (0x1, 0x26), "bitFlag": 0x0,
"screen": (0x0, 0x2), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x1c7, 'SamusY':0x88},
dotOrientation = 'e'),
AccessPoint('Noob Bridge Right', 'GreenPinkBrinstar', {
'Green Hill Zone Top Right': Cache.ldeco(lambda sm: sm.wor(sm.haveItem('Wave'),
sm.wor(sm.canBlueGateGlitch(),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther))))
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoBlueDoors), sm.traverse('NoobBridgeRight'))),
roomInfo = {'RoomPtr':0x9fba, "area": 0x1 },
exitInfo = {'DoorPtr':0x8f0a, 'direction': 0x4, "cap": (0x1, 0x46), "bitFlag": 0x0,
"screen": (0x0, 0x4), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x5ce, 'SamusY':0x88},
dotOrientation = 'se'),
AccessPoint('Green Brinstar Main Shaft Top Left', 'GreenPinkBrinstar', {
'Green Brinstar Elevator': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0x9ad9, "area": 0x1},
exitInfo = {'DoorPtr':0x8cb2, 'direction': 0x5, "cap": (0x2e, 0x6), "bitFlag": 0x0,
"screen": (0x2, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x488},
escape = True,
dotOrientation = 'ne'),
AccessPoint('Brinstar Pre-Map Room Right', 'GreenPinkBrinstar', {
}, roomInfo = {'RoomPtr':0x9b9d, "area": 0x1},
exitInfo = {'DoorPtr':0x8d42, 'direction': 0x4, "cap": (0x1, 0x46), "bitFlag": 0x0,
"screen": (0x0, 0x4), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True,
dotOrientation = 'ne'),
AccessPoint('Etecoons Supers', 'GreenPinkBrinstar', {
'Etecoons Bottom': lambda sm: SMBool(True)
}, internal=True,
start={'spawn': 0x0107, 'doors':[0x34], 'patches':[RomPatches.EtecoonSupersBlueDoor],
'save':"Save_Etecoons" ,'solveArea': "Green Brinstar",
'forcedEarlyMorph':True, 'needsPreRando': True}),
AccessPoint('Etecoons Bottom', 'GreenPinkBrinstar', {
'Etecoons Supers': Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.EtecoonSupersBlueDoor),
sm.traverse('EtecoonEnergyTankLeft'))),
'Green Brinstar Elevator': lambda sm: sm.canUsePowerBombs()
}, internal=True),
### Wrecked Ship
AccessPoint('West Ocean Left', 'WreckedShip', {
'Wrecked Ship Main': Cache.ldeco(lambda sm: sm.traverse('WestOceanRight'))
}, roomInfo = {'RoomPtr':0x93fe, "area": 0x0},
exitInfo = {'DoorPtr':0x89ca, 'direction': 0x5, "cap": (0x1e, 0x6), "bitFlag": 0x0,
"screen": (0x1, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x488},
dotOrientation = 'w'),
AccessPoint('Wrecked Ship Main', 'WreckedShip', {
'West Ocean Left': lambda sm: SMBool(True),
'Wrecked Ship Back': Cache.ldeco(lambda sm: sm.wor(sm.wand(Bosses.bossDead(sm, 'Phantoon'),
sm.canPassSpongeBath()),
sm.wand(sm.wnot(Bosses.bossDead(sm, 'Phantoon')),
RomPatches.has(sm.player, RomPatches.SpongeBathBlueDoor)))),
'PhantoonRoomOut': Cache.ldeco(lambda sm: sm.wand(sm.traverse('WreckedShipMainShaftBottom'), sm.canPassBombPassages()))
}, internal=True,
start={'spawn':0x0300,
'doors':[0x83,0x8b], 'patches':[RomPatches.SpongeBathBlueDoor, RomPatches.WsEtankBlueDoor],
'solveArea': "WreckedShip Main",
'needsPreRando':True}),
AccessPoint('Wrecked Ship Back', 'WreckedShip', {
'Wrecked Ship Main': lambda sm: SMBool(True),
'Crab Maze Left': Cache.ldeco(lambda sm: sm.canPassForgottenHighway(True))
}, internal=True),
AccessPoint('Crab Maze Left', 'WreckedShip', {
'Wrecked Ship Back': Cache.ldeco(lambda sm: sm.canPassForgottenHighway(False))
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoBlueDoors),
sm.traverse('LeCoudeBottom'))), # it is not exactly coude's door
# but it's equivalent in vanilla anyway
roomInfo = {'RoomPtr':0x957d, "area": 0x0, 'songs':[0x958e]},
exitInfo = {'DoorPtr':0x8aae, 'direction': 0x5, "cap": (0xe, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x188, 'song': 0xc},
dotOrientation = 'e'),
AccessPoint('PhantoonRoomOut', 'WreckedShip', {
'Wrecked Ship Main': lambda sm: sm.canPassBombPassages()
}, boss = True,
roomInfo = {'RoomPtr':0xcc6f, "area": 0x3},
exitInfo = {'DoorPtr':0xa2ac, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x49f, 'SamusY':0xb8},
traverse=lambda sm: sm.canOpenEyeDoors(),
dotOrientation = 's'),
AccessPoint('PhantoonRoomIn', 'WreckedShip', {},
boss = True,
roomInfo = {'RoomPtr':0xcd13, "area": 0x3},
exitInfo = {'DoorPtr':0xa2c4, 'direction': 0x5, "cap": (0x4e, 0x6), "bitFlag": 0x0,
"screen": (0x4, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe1fe,
"exitAsmPtr": 0xf7f0},
entryInfo = {'SamusX':0x2e, 'SamusY':0xb8},
dotOrientation = 's'),
AccessPoint('Basement Left', 'WreckedShip', {
'Wrecked Ship Main': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0xcc6f, "area": 0x3},
exitInfo = {'DoorPtr':0xa2a0, 'direction': 0x5, "cap": (0xe, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x2e, 'SamusY':0x88},
escape = True,
dotOrientation = 'ne'),
AccessPoint('Wrecked Ship Map Room', 'WreckedShip', {
}, roomInfo = {'RoomPtr':0xcccb, "area": 0x3},
exitInfo = {'DoorPtr':0xa2b8, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True,
dotOrientation = 'ne'),
### Lower Norfair
AccessPoint('Lava Dive Right', 'LowerNorfair', {
'LN Entrance': lambda sm: sm.canPassLavaPit()
}, roomInfo = {'RoomPtr':0xaf14, "area": 0x2, 'songs':[0xaf25]},
exitInfo = {'DoorPtr':0x96d2, 'direction': 0x4, "cap": (0x11, 0x26), "bitFlag": 0x0,
"screen": (0x1, 0x2), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x3d0, 'SamusY':0x88, 'song': 0x15},
dotOrientation = 'w'),
AccessPoint('LN Entrance', 'LowerNorfair', {
'Lava Dive Right': lambda sm: sm.canPassLavaPitReverse(),
'LN Above GT': lambda sm: sm.canPassLowerNorfairChozo(),
'Screw Attack Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canGreenGateGlitch(),
sm.canDestroyBombWalls())),
'Firefleas': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canPassWorstRoom(),
sm.canUsePowerBombs()))
}, internal=True),
AccessPoint('LN Above GT', 'LowerNorfair', {
'Screw Attack Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.enoughStuffGT()))
}, internal=True),
AccessPoint('Screw Attack Bottom', 'LowerNorfair', {
'LN Entrance': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canExitScrewAttackArea(),
sm.haveItem('Super'),
sm.canUsePowerBombs()))
}, internal=True),
AccessPoint('Firefleas', 'LowerNorfair', {
'LN Entrance': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canPassAmphitheaterReverse(),
sm.canPassWorstRoomPirates(),
sm.canUsePowerBombs())),
'Three Muskateers Room Left': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.haveItem('Morph'),
# check for only 3 ki hunters this way
sm.canPassRedKiHunters())),
'Ridley Zone': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.traverse('WastelandLeft'),
sm.traverse('RedKihunterShaftBottom'),
sm.canGetBackFromRidleyZone(),
sm.canPassRedKiHunters(),
sm.canPassWastelandDessgeegas(),
sm.canPassNinjaPirates())),
'Screw Attack Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canPassAmphitheaterReverse(),
sm.canDestroyBombWalls(),
sm.canGreenGateGlitch())),
'Firefleas Top': Cache.ldeco(lambda sm: sm.wand(sm.canPassBombPassages(),
sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main'])))
}, internal=True),
AccessPoint('Firefleas Top', 'LowerNorfair', {
# this weird condition basically says: "if we start here, give heat protection"
'Firefleas': Cache.ldeco(lambda sm: sm.wor(sm.wnot(RomPatches.has(sm.player, RomPatches.LowerNorfairPBRoomHeatDisable)),
sm.heatProof()))
}, internal=True,
start={'spawn':0x0207,
'rom_patches': ['LN_PB_Heat_Disable', 'LN_Firefleas_Remove_Fune','firefleas_shot_block.ips'],
'patches':[RomPatches.LowerNorfairPBRoomHeatDisable, RomPatches.FirefleasRemoveFune],
'knows': ["FirefleasWalljump"],
'save': "Save_Firefleas", 'needsPreRando': True,
'solveArea': "Lower Norfair After Amphitheater",
'forcedEarlyMorph':True}),
AccessPoint('Ridley Zone', 'LowerNorfair', {
'Firefleas': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canGetBackFromRidleyZone(),
sm.canPassWastelandDessgeegas(),
sm.canPassRedKiHunters())),
'RidleyRoomOut': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']))
}, internal=True),
AccessPoint('Three Muskateers Room Left', 'LowerNorfair', {
'Firefleas': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.haveItem('Morph'),
sm.canPassThreeMuskateers()))
}, roomInfo = {'RoomPtr':0xb656, "area": 0x2},
exitInfo = {'DoorPtr':0x9a4a, 'direction': 0x5, "cap": (0x5e, 0x6), "bitFlag": 0x0,
"screen": (0x5, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x134, 'SamusY':0x88},
dotOrientation = 'n'),
AccessPoint('RidleyRoomOut', 'LowerNorfair', {
'Ridley Zone': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']))
}, boss = True,
roomInfo = {'RoomPtr':0xb37a, "area": 0x2},
exitInfo = {'DoorPtr':0x98ca, 'direction': 0x5, "cap": (0xe, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x2e, 'SamusY':0x98},
traverse=Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canOpenEyeDoors())),
dotOrientation = 'e'),
AccessPoint('RidleyRoomIn', 'LowerNorfair', {},
boss = True,
roomInfo = {'RoomPtr':0xb32e, "area": 0x2},
exitInfo = {'DoorPtr':0x98be, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0xbf, 'SamusY':0x198}, # on Ridley's platform. entry screen has to be changed (see getDoorConnections)
dotOrientation = 'e'),
### Kraid
AccessPoint('Warehouse Zeela Room Left', 'Kraid', {
'KraidRoomOut': lambda sm: sm.canPassBombPassages()
}, roomInfo = {'RoomPtr': 0xa471, "area": 0x1, 'songs':[0xa482]},
exitInfo = {'DoorPtr': 0x913e, 'direction': 0x5, "cap": (0x2e, 0x6), "bitFlag": 0x0,
"screen": (0x2, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xbd3f},
entryInfo = {'SamusX':0x34, 'SamusY':0x88, 'song':0x12},
dotOrientation = 'w'),
AccessPoint('KraidRoomOut', 'Kraid', {
'Warehouse Zeela Room Left': lambda sm: sm.canPassBombPassages()
}, boss = True,
roomInfo = {'RoomPtr':0xa56b, "area": 0x1,
# put red brin song in both pre-kraid rooms,
# (vanilla music only makes sense if kraid is
# vanilla)
"songs":[0xa57c,0xa537,0xa551]},
exitInfo = {'DoorPtr':0x91b6, 'direction': 0x4, "cap": (0x1, 0x16), "bitFlag": 0x0,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x1cd, 'SamusY':0x188, 'song':0x12},
traverse=lambda sm: sm.canOpenEyeDoors(),
dotOrientation = 'e'),
AccessPoint('KraidRoomIn', 'Kraid', {},
boss = True,
roomInfo = {'RoomPtr':0xa59f, "area": 0x1},
exitInfo = {'DoorPtr':0x91ce, 'direction': 0x5, "cap": (0x1e, 0x16), "bitFlag": 0x0,
"screen": (0x1, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x34, 'SamusY':0x188},
dotOrientation = 'e'),
### Norfair
AccessPoint('Warehouse Entrance Left', 'Norfair', {
'Warehouse Entrance Right': lambda sm: sm.canAccessKraidsLair(),
'Business Center': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0xa6a1, "area": 0x1},
exitInfo = {'DoorPtr':0x922e, 'direction': 0x5, "cap": (0xe, 0x16), "bitFlag": 0x40,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xbdd1},
entryInfo = {'SamusX':0x34, 'SamusY':0x88},
dotOrientation = 'sw'),
AccessPoint('Warehouse Entrance Right', 'Norfair', {
'Warehouse Entrance Left': Cache.ldeco(lambda sm: sm.haveItem('Super'))
}, roomInfo = {'RoomPtr': 0xa6a1, "area": 0x1},
exitInfo = {'DoorPtr': 0x923a, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX': 0x2c7, 'SamusY': 0x98},
dotOrientation = 'nw'),
AccessPoint('Business Center', 'Norfair', {
'Cathedral': Cache.ldeco(lambda sm: sm.canEnterCathedral(Settings.hellRunsTable['MainUpperNorfair']['Norfair Entrance -> Cathedral Missiles']['mult'])),
'Bubble Mountain': Cache.ldeco(# go through cathedral
lambda sm: sm.wand(sm.traverse('CathedralRight'),
sm.canEnterCathedral(Settings.hellRunsTable['MainUpperNorfair']['Norfair Entrance -> Bubble']['mult']))),
'Bubble Mountain Bottom': Cache.ldeco(lambda sm: sm.haveItem('SpeedBooster')), # frog speedway
'Crocomire Speedway Bottom': Cache.ldeco(lambda sm: sm.wor(sm.wand(sm.haveItem('SpeedBooster'), # frog speedway
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Norfair Entrance -> Croc via Frog w/Wave' if sm.haveItem('Wave') else 'Norfair Entrance -> Croc via Frog']),
sm.wor(sm.canBlueGateGlitch(),
sm.haveItem('Wave'))),
# below ice
sm.wand(sm.traverse('BusinessCenterTopLeft'),
sm.haveItem('SpeedBooster'),
sm.canUsePowerBombs(),
sm.canHellRun(**Settings.hellRunsTable['Ice']['Norfair Entrance -> Croc via Ice'])))),
'Warehouse Entrance Left': lambda sm: SMBool(True)
}, internal=True,
start={'spawn':0x0208, 'doors':[0x4d], 'patches':[RomPatches.HiJumpAreaBlueDoor], 'solveArea': "Norfair Entrance", 'needsPreRando':True}),
AccessPoint('Single Chamber Top Right', 'Norfair', {
'Bubble Mountain Top': Cache.ldeco(lambda sm: sm.wand(sm.canDestroyBombWalls(),
sm.haveItem('Morph'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Single Chamber <-> Bubble Mountain'])))
}, roomInfo = {'RoomPtr':0xad5e, "area": 0x2},
exitInfo = {'DoorPtr':0x95fa, 'direction': 0x4, "cap": (0x11, 0x6), "bitFlag": 0x0,
"screen": (0x1, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x5cf, 'SamusY':0x88},
dotOrientation = 'ne'),
AccessPoint('Cathedral', 'Norfair', {
'Business Center': Cache.ldeco(lambda sm: sm.canExitCathedral(Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Cathedral Missiles'])),
'Bubble Mountain': Cache.ldeco(lambda sm: sm.wand(sm.traverse('CathedralRight'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Norfair Entrance -> Cathedral Missiles'])))
}, internal=True),
AccessPoint('Kronic Boost Room Bottom Left', 'Norfair', {
'Bubble Mountain Bottom': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Single Chamber <-> Bubble Mountain'])),
'Bubble Mountain Top': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Kronic Boost Room -> Bubble Mountain Top']))), # go all the way around
'Crocomire Speedway Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Kronic Boost Room <-> Croc']),
sm.wor(sm.haveItem('Wave'),
sm.canBlueGateGlitch()))),
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoBlueDoors), sm.traverse('KronicBoostBottomLeft'))),
roomInfo = {'RoomPtr':0xae74, "area": 0x2, 'songs':[0xae85]},
exitInfo = {'DoorPtr':0x967e, 'direction': 0x5, "cap": (0x3e, 0x6), "bitFlag": 0x0,
"screen": (0x3, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x134, 'SamusY':0x288, 'song': 0x15},
dotOrientation = 'se'),
AccessPoint('Crocomire Speedway Bottom', 'Norfair', {
'Business Center': Cache.ldeco(lambda sm: sm.wor(sm.wand(sm.canPassFrogSpeedwayRightToLeft(),
sm.canHellRun(**Settings.hellRunsTable['Ice']['Croc -> Norfair Entrance'])),
sm.wand(sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Croc -> Norfair Entrance']),
sm.canGrappleEscape(),
sm.haveItem('Super')))),
'Bubble Mountain Bottom': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['Ice']['Croc -> Bubble Mountain'])),
'Kronic Boost Room Bottom Left': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Kronic Boost Room <-> Croc']),
sm.haveItem('Morph')))
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.CrocBlueDoors), sm.traverse('CrocomireSpeedwayBottom'))),
roomInfo = {'RoomPtr':0xa923, "area": 0x2},
exitInfo = {'DoorPtr':0x93d2, 'direction': 0x6, "cap": (0x36, 0x2), "bitFlag": 0x0,
"screen": (0x3, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xc57, 'SamusY':0x2b8},
dotOrientation = 'se'),
AccessPoint('Bubble Mountain', 'Norfair', {
'Business Center': lambda sm: sm.canExitCathedral(Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Norfair Entrance']),
'Bubble Mountain Top': lambda sm: sm.canClimbBubbleMountain(),
'Cathedral': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Cathedral Missiles'])),
'Bubble Mountain Bottom': lambda sm: sm.canPassBombPassages()
}, internal=True,
start={'spawn':0x0201, 'doors':[0x54,0x55], 'patches':[RomPatches.SpeedAreaBlueDoors], 'knows':['BubbleMountainWallJump'], 'solveArea': "Bubble Norfair Bottom"}),
AccessPoint('Bubble Mountain Top', 'Norfair', {
'Kronic Boost Room Bottom Left': Cache.ldeco(# go all the way around
lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Kronic Boost Room wo/Bomb']))),
'Single Chamber Top Right': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Single Chamber <-> Bubble Mountain']),
sm.canDestroyBombWalls(),
sm.haveItem('Morph'),
RomPatches.has(sm.player, RomPatches.SingleChamberNoCrumble))),
'Bubble Mountain': lambda sm: SMBool(True),
# all the way around
'Bubble Mountain Bottom': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble Top <-> Bubble Bottom'])))
}, internal=True),
AccessPoint('Bubble Mountain Bottom', 'Norfair', {
'Bubble Mountain': lambda sm: sm.canPassBombPassages(),
'Crocomire Speedway Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Croc']),
sm.wor(sm.canBlueGateGlitch(),
sm.haveItem('Wave')))),
'Kronic Boost Room Bottom Left': Cache.ldeco(lambda sm: sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Kronic Boost Room'])),
'Business Center': lambda sm: sm.canPassFrogSpeedwayRightToLeft(),
# all the way around
'Bubble Mountain Top': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble Top <-> Bubble Bottom'])))
}, internal=True),
AccessPoint('Business Center Mid Left', 'Norfair', {
'Warehouse Entrance Left': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0xa7de, "area": 0x2},
exitInfo = {'DoorPtr':0x9306, 'direction': 0x5, "cap": (0xe, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x488},
escape = True,
dotOrientation = 'ne'),
AccessPoint('Norfair Map Room', 'Norfair', {
}, roomInfo = {'RoomPtr':0xb0b4, "area": 0x2},
exitInfo = {'DoorPtr':0x97c2, 'direction': 0x4, "cap": (0x1, 0x46), "bitFlag": 0x0,
"screen": (0x0, 0x4), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True,
dotOrientation = 'ne'),
### Croc
AccessPoint('Crocomire Room Top', 'Crocomire', {
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.CrocBlueDoors), sm.enoughStuffCroc())),
roomInfo = {'RoomPtr':0xa98d, "area": 0x2, 'songs':[0xa9bd]},
exitInfo = {'DoorPtr':0x93ea, 'direction': 0x7, "cap": (0xc6, 0x2d), "bitFlag": 0x0,
"screen": (0xc, 0x2), "distanceToSpawn": 0x1c0, "doorAsmPtr": 0x0000,
"exitAsmPtr": 0xf7f0},
entryInfo = {'SamusX':0x383, 'SamusY':0x98, 'song': 0x15},
dotOrientation = 'se'),
### West Maridia
AccessPoint('Main Street Bottom', 'WestMaridia', {
'Red Fish Room Left': Cache.ldeco(lambda sm: sm.wand(sm.canGoUpMtEverest(),
sm.haveItem('Morph'))),
'Crab Hole Bottom Left': Cache.ldeco(lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canTraverseCrabTunnelLeftToRight())),
# this transition leads to EastMaridia directly
'Oasis Bottom': Cache.ldeco(lambda sm: sm.wand(sm.wnot(RomPatches.has(sm.player, RomPatches.MaridiaSandWarp)),
sm.traverse('MainStreetBottomRight'),
sm.wor(sm.haveItem('Super'),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther)),
sm.canTraverseWestSandHallLeftToRight())),
'Crab Shaft Left': lambda sm: sm.canPassMtEverest()
}, roomInfo = {'RoomPtr':0xcfc9, "area": 0x4},
exitInfo = {'DoorPtr':0xa39c, 'direction': 0x6, "cap": (0x6, 0x2), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x170, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x14a, 'SamusY':0x7a8},
dotOrientation = 's'),
AccessPoint('Mama Turtle', 'WestMaridia', {
'Main Street Bottom': lambda sm: sm.canJumpUnderwater()
}, internal=True,
start = {'spawn': 0x0406, 'solveArea': "Maridia Green",
'save':"Save_Mama", 'needsPreRando':True,
'patches':[RomPatches.MamaTurtleBlueDoor],
'rom_patches':['mama_save.ips'], 'doors': [0x8e]}),
AccessPoint('Crab Hole Bottom Left', 'WestMaridia', {
'Main Street Bottom': Cache.ldeco(lambda sm: sm.wand(sm.canExitCrabHole(),
sm.wor(sm.canGreenGateGlitch(),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther)))),
# this transition leads to EastMaridia directly
'Oasis Bottom': Cache.ldeco(lambda sm: sm.wand(sm.wnot(RomPatches.has(sm.player, RomPatches.MaridiaSandWarp)),
sm.canExitCrabHole(),
sm.canTraverseWestSandHallLeftToRight()))
}, roomInfo = {'RoomPtr':0xd21c, "area": 0x4},
exitInfo = {'DoorPtr':0xa510, 'direction': 0x5,
"cap": (0x3e, 0x6), "screen": (0x3, 0x0), "bitFlag": 0x0,
"distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x28, 'SamusY':0x188},
dotOrientation = 'se'),
AccessPoint('Red Fish Room Left', 'WestMaridia', {
'Main Street Bottom': Cache.ldeco(lambda sm: sm.haveItem('Morph')) # just go down
}, roomInfo = {'RoomPtr':0xd104, "area": 0x4},
exitInfo = {'DoorPtr':0xa480, 'direction': 0x5, "cap": (0x2e, 0x36), "bitFlag": 0x40,
"screen": (0x2, 0x3), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe367},
entryInfo = {'SamusX':0x34, 'SamusY':0x88},
dotOrientation = 'w'),
AccessPoint('Crab Shaft Left', 'WestMaridia', {
'Main Street Bottom': lambda sm: SMBool(True), # fall down
'Beach': lambda sm: sm.canDoOuterMaridia(),
'Crab Shaft Right': lambda sm: SMBool(True)
}, internal=True),
AccessPoint('Watering Hole', 'WestMaridia', {
'Beach': lambda sm: sm.haveItem('Morph'),
'Watering Hole Bottom': lambda sm: SMBool(True)
}, internal=True,
start = {'spawn': 0x0407, 'solveArea': "Maridia Pink Bottom", 'save':"Save_Watering_Hole",
'patches':[RomPatches.MaridiaTubeOpened], 'rom_patches':['wh_open_tube.ips'],
'forcedEarlyMorph':True}),
AccessPoint('Watering Hole Bottom', 'WestMaridia', {
'Watering Hole': lambda sm: sm.canJumpUnderwater()
}, internal=True),
AccessPoint('Beach', 'WestMaridia', {
'Crab Shaft Left': lambda sm: SMBool(True), # fall down
'Watering Hole': Cache.ldeco(lambda sm: sm.wand(sm.wor(sm.canPassBombPassages(),
sm.canUseSpringBall()),
sm.canDoOuterMaridia()))
}, internal=True),
AccessPoint('Crab Shaft Right', 'WestMaridia', {
'Crab Shaft Left': lambda sm: sm.canJumpUnderwater()
}, traverse=Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.CrabShaftBlueDoor),
sm.traverse('CrabShaftRight'))),
roomInfo = {'RoomPtr':0xd1a3, "area": 0x4},
exitInfo = {'DoorPtr':0xa4c8, 'direction': 0x4, "cap": (0x1, 0x16), "bitFlag": 0x0,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x1ca, 'SamusY':0x388},
dotOrientation = 'e'),
# escape APs
AccessPoint('Crab Hole Bottom Right', 'WestMaridia', {
'Crab Hole Bottom Left': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0xd21c, "area": 0x4},
exitInfo = {'DoorPtr':0xa51c, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x0,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xd7, 'SamusY':0x188},
escape = True,
dotOrientation = 'ne'),
AccessPoint('Maridia Map Room', 'WestMaridia', {
}, roomInfo = {'RoomPtr':0xd3b6, "area": 0x4},
exitInfo = {'DoorPtr':0xa5e8, 'direction': 0x5, "cap": (0xe, 0x16), "bitFlag": 0x0,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe356},
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True,
dotOrientation = 'ne'),
### East Maridia
AccessPoint('Aqueduct Top Left', 'EastMaridia', {
'Aqueduct Bottom': lambda sm: sm.canUsePowerBombs()
}, roomInfo = {'RoomPtr':0xd5a7, "area": 0x4},
exitInfo = {'DoorPtr':0xa708, 'direction': 0x5, "cap": (0x1e, 0x36), "bitFlag": 0x0,
"screen": (0x1, 0x3), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe398},
entryInfo = {'SamusX':0x34, 'SamusY':0x188},
dotOrientation = 'w'),
AccessPoint('Aqueduct Bottom', 'EastMaridia', {
'Aqueduct Top Left': Cache.ldeco(lambda sm: sm.wand(sm.canDestroyBombWallsUnderwater(), # top left bomb blocks
sm.canJumpUnderwater())),
'Post Botwoon': Cache.ldeco(lambda sm: sm.wand(sm.canJumpUnderwater(),
sm.canDefeatBotwoon())), # includes botwoon hallway conditions
'Left Sandpit': lambda sm: sm.canAccessSandPits(),
'Right Sandpit': lambda sm: sm.canAccessSandPits(),
'Aqueduct': Cache.ldeco(lambda sm: sm.wand(sm.wor(sm.haveItem('SpeedBooster'),
sm.wand(sm.knowsSnailClip(),
sm.haveItem('Morph'))),
sm.haveItem('Gravity')))
}, internal=True),
AccessPoint('Aqueduct', 'EastMaridia', {
'Aqueduct Bottom': lambda sm: SMBool(True) # go down
}, internal=True,
start = {'spawn': 0x0405, 'solveArea': "Maridia Pink Bottom",
'save':"Save_Aqueduct", 'needsPreRando':True,
'doors': [0x96]}),
AccessPoint('Post Botwoon', 'EastMaridia', {
'Aqueduct Bottom': Cache.ldeco(lambda sm: sm.wor(sm.wand(sm.canJumpUnderwater(), # can't access the sand pits from the right side of the room
sm.haveItem('Morph')),
sm.wand(sm.haveItem('Gravity'),
sm.haveItem('SpeedBooster')))),
'Colosseum Top Right': lambda sm: sm.canBotwoonExitToColosseum(),
'Toilet Top': Cache.ldeco(lambda sm: sm.wand(sm.canReachCacatacAlleyFromBotowoon(),
sm.canPassCacatacAlley()))
}, internal=True),
AccessPoint('West Sand Hall Left', 'EastMaridia', {
# XXX there might be some tech to do this suitless, but HJ+ice is not enough
'Oasis Bottom': Cache.ldeco(lambda sm: sm.haveItem('Gravity')),
'Aqueduct Bottom': Cache.ldeco(lambda sm: RomPatches.has(sm.player, RomPatches.MaridiaSandWarp)),
# this goes directly to WestMaridia
'Main Street Bottom': Cache.ldeco(lambda sm: sm.wand(sm.wnot(RomPatches.has(sm.player, RomPatches.MaridiaSandWarp)),
sm.wor(sm.canGreenGateGlitch(),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther)))),
# this goes directly to WestMaridia
'Crab Hole Bottom Left': Cache.ldeco(lambda sm: sm.wand(sm.wnot(RomPatches.has(sm.player, RomPatches.MaridiaSandWarp)),
sm.haveItem('Morph')))
}, internal=True),
AccessPoint('Left Sandpit', 'EastMaridia', {
'West Sand Hall Left': lambda sm: sm.canAccessSandPits(),
'Oasis Bottom': lambda sm: sm.canAccessSandPits()
}, internal=True),
AccessPoint('Oasis Bottom', 'EastMaridia', {
'Toilet Top': Cache.ldeco(lambda sm: sm.wand(sm.traverse('OasisTop'), sm.canDestroyBombWallsUnderwater())),
'West Sand Hall Left': lambda sm: sm.canAccessSandPits()
}, internal=True),
AccessPoint('Right Sandpit', 'EastMaridia', {
'Oasis Bottom': lambda sm: sm.canAccessSandPits()
}, internal=True),
AccessPoint('Le Coude Right', 'EastMaridia', {
'Toilet Top': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0x95a8, "area": 0x0},
exitInfo = {'DoorPtr':0x8aa2, 'direction': 0x4, "cap": (0x1, 0x16), "bitFlag": 0x0,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xd1, 'SamusY':0x88},
dotOrientation = 'ne'),
AccessPoint('Toilet Top', 'EastMaridia', {
'Oasis Bottom': Cache.ldeco(lambda sm: sm.wand(sm.traverse('PlasmaSparkBottom'), sm.canDestroyBombWallsUnderwater())),
'Le Coude Right': lambda sm: SMBool(True),
'Colosseum Top Right': Cache.ldeco(lambda sm: sm.wand(Bosses.bossDead(sm, 'Draygon'),
# suitless could be possible with this but unreasonable: https://youtu.be/rtLwytH-u8o
sm.haveItem('Gravity'),
sm.haveItem('Morph')))
}, internal=True),
AccessPoint('Colosseum Top Right', 'EastMaridia', {
'Post Botwoon': lambda sm: sm.canColosseumToBotwoonExit(),
'Precious Room Top': Cache.ldeco(lambda sm: sm.traverse('ColosseumBottomRight')), # go down
}, internal = True),
AccessPoint('Precious Room Top', 'EastMaridia', {
'Colosseum Top Right': lambda sm: sm.canClimbColosseum(),
'DraygonRoomOut': lambda sm: SMBool(True) # go down
}, internal = True),
# boss APs
AccessPoint('DraygonRoomOut', 'EastMaridia', {
'Precious Room Top': lambda sm: sm.canExitPreciousRoom()
}, boss = True,
roomInfo = {'RoomPtr':0xd78f, "area": 0x4, "songs":[0xd7a5]},
exitInfo = {'DoorPtr':0xa840, 'direction': 0x5, "cap": (0x1e, 0x6), "bitFlag": 0x0,
"screen": (0x1, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0},
entryInfo = {'SamusX':0x34, 'SamusY':0x288, 'song':0x1b},
traverse=lambda sm: sm.canOpenEyeDoors(),
dotOrientation = 'e'),
AccessPoint('DraygonRoomIn', 'EastMaridia', {
'Draygon Room Bottom': Cache.ldeco(lambda sm: sm.wor(Bosses.bossDead(sm, "Draygon"),
sm.wand(sm.canFightDraygon(),
sm.enoughStuffsDraygon())))
}, boss = True,
roomInfo = {'RoomPtr':0xda60, "area": 0x4},
exitInfo = {'DoorPtr':0xa96c, 'direction': 0x4, "cap": (0x1, 0x26), "bitFlag": 0x0,
"screen": (0x0, 0x2), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe3d9,
"exitAsmPtr": 0xf7f0},
entryInfo = {'SamusX':0x1c8, 'SamusY':0x88},
dotOrientation = 'e'),
AccessPoint('Draygon Room Bottom', 'EastMaridia', {
'DraygonRoomIn': Cache.ldeco(lambda sm: sm.wand(Bosses.bossDead(sm, 'Draygon'), sm.canExitDraygon()))
}, internal = True),
### Red Brinstar. Main nodes: Red Tower Top Left, East Tunnel Right
AccessPoint('Red Tower Top Left', 'RedBrinstar', {
# go up
'Red Brinstar Elevator': lambda sm: sm.canClimbRedTower(),
'Caterpillar Room Top Right': Cache.ldeco(lambda sm: sm.wand(sm.canPassRedTowerToMaridiaNode(),
sm.canClimbRedTower())),
# go down
'East Tunnel Right': lambda sm: SMBool(True)
}, roomInfo = {'RoomPtr':0xa253, "area": 0x1},
exitInfo = {'DoorPtr':0x902a, 'direction': 0x5, "cap": (0x5e, 0x6), "bitFlag": 0x0,
"screen": (0x5, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x2f, 'SamusY':0x488},
dotOrientation = 'w'),
AccessPoint('Caterpillar Room Top Right', 'RedBrinstar', {
'Red Brinstar Elevator': lambda sm: sm.canPassMaridiaToRedTowerNode()
}, roomInfo = {'RoomPtr':0xa322, "area": 0x1},
exitInfo = {'DoorPtr':0x90c6, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x40,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xbdaf},
entryInfo = {'SamusX':0x2cd, 'SamusY':0x388},
dotOrientation = 'ne'),
AccessPoint('Red Brinstar Elevator', 'RedBrinstar', {
'Caterpillar Room Top Right': lambda sm: sm.canPassRedTowerToMaridiaNode(),
'Red Tower Top Left': Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.HellwayBlueDoor), sm.traverse('RedTowerElevatorLeft')))
}, traverse=Cache.ldeco(lambda sm:sm.wor(RomPatches.has(sm.player, RomPatches.RedTowerBlueDoors), sm.traverse('RedBrinstarElevatorTop'))),
roomInfo = {'RoomPtr':0x962a, "area": 0x0},
exitInfo = {'DoorPtr':0x8af6, 'direction': 0x7, "cap": (0x16, 0x2d), "bitFlag": 0x0,
"screen": (0x1, 0x2), "distanceToSpawn": 0x1c0, "doorAsmPtr": 0xb9f1},
entryInfo = {'SamusX':0x80, 'SamusY':0x58},
start={'spawn':0x010a, 'doors':[0x3c], 'patches':[RomPatches.HellwayBlueDoor], 'solveArea': "Red Brinstar Top", 'areaMode':True},
dotOrientation = 'n'),
AccessPoint('East Tunnel Right', 'RedBrinstar', {
'East Tunnel Top Right': lambda sm: SMBool(True), # handled by room traverse function
'Glass Tunnel Top': Cache.ldeco(lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.wor(sm.haveItem('Gravity'),
sm.haveItem('HiJump')))),
'Red Tower Top Left': lambda sm: sm.canClimbBottomRedTower()
}, roomInfo = {'RoomPtr':0xcf80, "area": 0x4},
exitInfo = {'DoorPtr':0xa384, 'direction': 0x4, "cap": (0x1, 0x6), "bitFlag": 0x40,
"screen": (0x0, 0x0), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0xce, 'SamusY':0x188},
dotOrientation = 'se'),
AccessPoint('East Tunnel Top Right', 'RedBrinstar', {
'East Tunnel Right': Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoGatesBase),
sm.haveItem('Super')))
}, traverse=Cache.ldeco(lambda sm: RomPatches.has(sm.player, RomPatches.AreaRandoGatesBase)),
roomInfo = {'RoomPtr':0xcf80, "area": 0x4},
exitInfo = {'DoorPtr':0xa390, 'direction': 0x4, "cap": (0x1, 0x16), "bitFlag": 0x0,
"screen": (0x0, 0x1), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe356},
entryInfo = {'SamusX':0x3c6, 'SamusY':0x88},
dotOrientation = 'e'),
AccessPoint('Glass Tunnel Top', 'RedBrinstar', {
'East Tunnel Right': Cache.ldeco(lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.MaridiaTubeOpened),
sm.canUsePowerBombs()))
}, traverse=Cache.ldeco(lambda sm: sm.wand(sm.wor(sm.haveItem('Gravity'),
sm.haveItem('HiJump')),
sm.wor(RomPatches.has(sm.player, RomPatches.MaridiaTubeOpened),
sm.canUsePowerBombs()))),
roomInfo = {'RoomPtr':0xcefb, "area": 0x4},
exitInfo = {'DoorPtr':0xa330, 'direction': 0x7, "cap": (0x16, 0x7d), "bitFlag": 0x0,
"screen": (0x1, 0x7), "distanceToSpawn": 0x200, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x81, 'SamusY':0x78},
dotOrientation = 's'),
### Tourian
AccessPoint('Golden Four', 'Tourian', {},
roomInfo = {'RoomPtr':0xa5ed, "area": 0x0},
exitInfo = {'DoorPtr':0x91e6, 'direction': 0x5, "cap": (0xe, 0x66), "bitFlag": 0x0,
"screen": (0x0, 0x6), "distanceToSpawn": 0x8000, "doorAsmPtr": 0x0000},
entryInfo = {'SamusX':0x34, 'SamusY':0x88},
start={'spawn':0x0007, 'solveArea': "Tourian", "save": "Save_G4", 'areaMode':True},
dotOrientation = 'w'),
AccessPoint('Tourian Escape Room 4 Top Right', 'Tourian', {},
roomInfo = {'RoomPtr':0xdede, "area": 0x5},
exitInfo = {'DoorPtr':0xab34, 'direction': 0x4, "cap": (0x1, 0x86), "bitFlag": 0x40,
"screen": (0x0, 0x8), "distanceToSpawn": 0x8000, "doorAsmPtr": 0xe4cf},
entryInfo = {'SamusX':0xffff, 'SamusY':0xffff}, # unused
escape = True,
dotOrientation = 'ne'),
]

View File

@@ -0,0 +1,766 @@
from math import ceil
from logic.smbool import SMBool
from logic.helpers import Helpers, Bosses
from logic.cache import Cache
from rom.rom_patches import RomPatches
from graph.graph_utils import getAccessPoint
from utils.parameters import Settings
class HelpersGraph(Helpers):
def __init__(self, smbm):
self.smbm = smbm
def canEnterAndLeaveGauntletQty(self, nPB, nTanksSpark):
sm = self.smbm
# EXPLAINED: to access Gauntlet Entrance from Landing site we can either:
# -fly to it (infinite bomb jumps or space jump)
# -shinespark to it
# -wall jump with high jump boots
# -wall jump without high jump boots
# then inside it to break the bomb wals:
# -use screw attack (easy way)
# -use power bombs
# -use bombs
# -perform a simple short charge on the way in
# and use power bombs on the way out
return sm.wand(sm.wor(sm.canFly(),
sm.haveItem('SpeedBooster'),
sm.wand(sm.knowsHiJumpGauntletAccess(),
sm.haveItem('HiJump')),
sm.knowsHiJumpLessGauntletAccess()),
sm.wor(sm.haveItem('ScrewAttack'),
sm.wor(sm.wand(sm.energyReserveCountOkHardRoom('Gauntlet'),
sm.wand(sm.canUsePowerBombs(),
sm.wor(sm.itemCountOk('PowerBomb', nPB),
sm.wand(sm.haveItem('SpeedBooster'),
sm.energyReserveCountOk(nTanksSpark))))),
sm.wand(sm.energyReserveCountOkHardRoom('Gauntlet', 0.51),
sm.canUseBombs()))))
@Cache.decorator
def canEnterAndLeaveGauntlet(self):
sm = self.smbm
return sm.wor(sm.wand(sm.canShortCharge(),
sm.canEnterAndLeaveGauntletQty(2, 2)),
sm.canEnterAndLeaveGauntletQty(2, 3))
def canPassTerminatorBombWall(self, fromLandingSite=True):
sm = self.smbm
return sm.wor(sm.wand(sm.haveItem('SpeedBooster'),
sm.wor(SMBool(not fromLandingSite, 0), sm.knowsSimpleShortCharge(), sm.knowsShortCharge())),
sm.canDestroyBombWalls())
@Cache.decorator
def canPassCrateriaGreenPirates(self):
sm = self.smbm
return sm.wor(sm.canPassBombPassages(),
sm.haveMissileOrSuper(),
sm.energyReserveCountOk(1),
sm.wor(sm.haveItem('Charge'),
sm.haveItem('Ice'),
sm.haveItem('Wave'),
sm.wor(sm.haveItem('Spazer'),
sm.haveItem('Plasma'),
sm.haveItem('ScrewAttack'))))
# from blue brin elevator
@Cache.decorator
def canAccessBillyMays(self):
sm = self.smbm
return sm.wand(sm.wor(RomPatches.has(sm.player, RomPatches.BlueBrinstarBlueDoor),
sm.traverse('ConstructionZoneRight')),
sm.canUsePowerBombs(),
sm.wor(sm.knowsBillyMays(),
sm.haveItem('Gravity'),
sm.haveItem('SpaceJump')))
@Cache.decorator
def canAccessKraidsLair(self):
sm = self.smbm
# EXPLAINED: access the upper right platform with either:
# -hijump boots (easy regular way)
# -fly (space jump or infinite bomb jump)
# -know how to wall jump on the platform without the hijump boots
return sm.wand(sm.haveItem('Super'),
sm.wor(sm.haveItem('HiJump'),
sm.canFly(),
sm.knowsEarlyKraid()))
@Cache.decorator
def canPassMoat(self):
sm = self.smbm
# EXPLAINED: In the Moat we can either:
# -use grapple or space jump (easy way)
# -do a continuous wall jump (https://www.youtube.com/watch?v=4HVhTwwax6g)
# -do a diagonal bomb jump from the middle platform (https://www.youtube.com/watch?v=5NRqQ7RbK3A&t=10m58s)
# -do a short charge from the Keyhunter room (https://www.youtube.com/watch?v=kFAYji2gFok)
# -do a gravity jump from below the right platform
# -do a mock ball and a bounce ball (https://www.youtube.com/watch?v=WYxtRF--834)
# -with gravity, either hijump or IBJ
return sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.knowsContinuousWallJump(),
sm.wand(sm.knowsDiagonalBombJump(), sm.canUseBombs()),
sm.canSimpleShortCharge(),
sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.knowsGravityJump(),
sm.haveItem('HiJump'),
sm.canInfiniteBombJump())),
sm.wand(sm.knowsMockballWs(), sm.canUseSpringBall()))
@Cache.decorator
def canPassMoatFromMoat(self):
sm = self.smbm
return sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.wand(sm.knowsDiagonalBombJump(), sm.canUseBombs()),
sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.knowsGravityJump(),
sm.haveItem('HiJump'),
sm.canInfiniteBombJump())))
@Cache.decorator
def canPassMoatReverse(self):
sm = self.smbm
return sm.wor(RomPatches.has(sm.player, RomPatches.MoatShotBlock),
sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.haveItem('Gravity'),
sm.canPassBombPassages())
@Cache.decorator
def canPassSpongeBath(self):
sm = self.smbm
return sm.wor(sm.wand(sm.canPassBombPassages(),
sm.knowsSpongeBathBombJump()),
sm.wand(sm.haveItem('HiJump'),
sm.knowsSpongeBathHiJump()),
sm.haveItem('Gravity'),
sm.haveItem('SpaceJump'),
sm.wand(sm.haveItem('SpeedBooster'),
sm.knowsSpongeBathSpeed()),
sm.canSpringBallJump())
@Cache.decorator
def canPassBowling(self):
sm = self.smbm
return sm.wand(Bosses.bossDead(sm, 'Phantoon'),
sm.wor(SMBool(sm.getDmgReduction()[0] >= 2),
sm.energyReserveCountOk(1),
sm.haveItem("SpaceJump"),
sm.haveItem("Grapple")))
@Cache.decorator
def canAccessEtecoons(self):
sm = self.smbm
return sm.wor(sm.canUsePowerBombs(),
sm.wand(sm.knowsMoondance(), sm.canUseBombs(), sm.traverse('MainShaftBottomRight')))
@Cache.decorator
def canKillBeetoms(self):
sm = self.smbm
# can technically be killed with bomb, but it's harder
return sm.wor(sm.haveMissileOrSuper(), sm.canUsePowerBombs(), sm.haveItem('ScrewAttack'))
# the water zone east of WS
def canPassForgottenHighway(self, fromWs):
sm = self.smbm
suitless = sm.wand(sm.haveItem('HiJump'), sm.knowsGravLessLevel1())
if fromWs is True and RomPatches.has(sm.player, RomPatches.EastOceanPlatforms).bool is False:
suitless = sm.wand(suitless,
sm.wor(sm.canSpringBallJump(), # two sbj on the far right
# to break water line and go through the door on the right
sm.haveItem('SpaceJump')))
return sm.wand(sm.wor(sm.haveItem('Gravity'),
suitless),
sm.haveItem('Morph')) # for crab maze
@Cache.decorator
def canExitCrabHole(self):
sm = self.smbm
return sm.wand(sm.haveItem('Morph'), # morph to exit the hole
sm.wor(sm.wand(sm.haveItem('Gravity'), # even with gravity you need some way to climb...
sm.wor(sm.haveItem('Ice'), # ...on crabs...
sm.wand(sm.haveItem('HiJump'), sm.knowsMaridiaWallJumps()), # ...or by jumping
sm.knowsGravityJump(),
sm.canFly())),
sm.wand(sm.haveItem('Ice'), sm.canDoSuitlessOuterMaridia()), # climbing crabs
sm.canDoubleSpringBallJump()))
# bottom sandpits with the evirs except west sand hall left to right
@Cache.decorator
def canTraverseSandPits(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel3(),
sm.haveItem('HiJump'),
sm.haveItem('Ice')))
@Cache.decorator
def canTraverseWestSandHallLeftToRight(self):
sm = self.smbm
return sm.haveItem('Gravity') # FIXME find suitless condition
@Cache.decorator
def canPassMaridiaToRedTowerNode(self):
sm = self.smbm
return sm.wand(sm.haveItem('Morph'),
sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoGatesBase),
sm.haveItem('Super')))
@Cache.decorator
def canPassRedTowerToMaridiaNode(self):
sm = self.smbm
return sm.wand(sm.haveItem('Morph'),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesBase))
def canEnterCathedral(self, mult=1.0):
sm = self.smbm
return sm.wand(sm.traverse('CathedralEntranceRight'),
sm.wor(sm.wand(sm.canHellRun('MainUpperNorfair', mult),
sm.wor(sm.wor(RomPatches.has(sm.player, RomPatches.CathedralEntranceWallJump),
sm.haveItem('HiJump'),
sm.canFly()),
sm.wor(sm.haveItem('SpeedBooster'), # spark
sm.canSpringBallJump()))),
sm.wand(sm.canHellRun('MainUpperNorfair', 0.5*mult),
sm.haveItem('Morph'),
sm.knowsNovaBoost())))
@Cache.decorator
def canClimbBubbleMountain(self):
sm = self.smbm
return sm.wor(sm.haveItem('HiJump'),
sm.canFly(),
sm.haveItem('Ice'),
sm.knowsBubbleMountainWallJump())
@Cache.decorator
def canHellRunToSpeedBooster(self):
sm = self.smbm
return sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Speed Booster w/Speed' if sm.haveItem('SpeedBooster') else 'Bubble -> Speed Booster'])
@Cache.decorator
def canAccessDoubleChamberItems(self):
sm = self.smbm
hellRun = Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Wave']
return sm.wor(sm.wand(sm.traverse('SingleChamberRight'),
sm.canHellRun(**hellRun)),
sm.wand(sm.wor(sm.haveItem('HiJump'),
sm.canSimpleShortCharge(),
sm.canFly(),
sm.knowsDoubleChamberWallJump()),
sm.canHellRun(hellRun['hellRun'], hellRun['mult']*0.8, hellRun['minE'])))
def canExitCathedral(self, hellRun):
# from top: can use bomb/powerbomb jumps
# from bottom: can do a shinespark or use space jump
# can do it with highjump + wall jump
# can do it with only two wall jumps (the first one is delayed like on alcatraz)
# can do it with a spring ball jump from wall
sm = self.smbm
return sm.wand(sm.wor(sm.canHellRun(**hellRun),
sm.heatProof()),
sm.wor(sm.wor(sm.canPassBombPassages(),
sm.haveItem("SpeedBooster")),
sm.wor(sm.haveItem("SpaceJump"),
sm.haveItem("HiJump"),
sm.knowsWallJumpCathedralExit(),
sm.wand(sm.knowsSpringBallJumpFromWall(), sm.canUseSpringBall()))))
@Cache.decorator
def canGrappleEscape(self):
sm = self.smbm
return sm.wor(sm.wor(sm.haveItem('SpaceJump'),
sm.wand(sm.canInfiniteBombJump(), # IBJ from lava...either have grav or freeze the enemy there if hellrunning (otherwise single DBJ at the end)
sm.wor(sm.heatProof(),
sm.haveItem('Gravity'),
sm.haveItem('Ice')))),
sm.haveItem('Grapple'),
sm.wand(sm.haveItem('SpeedBooster'),
sm.wor(sm.haveItem('HiJump'), # jump from the blocks below
sm.knowsShortCharge())), # spark from across the grapple blocks
sm.wand(sm.haveItem('HiJump'), sm.canSpringBallJump())) # jump from the blocks below
@Cache.decorator
def canPassFrogSpeedwayRightToLeft(self):
sm = self.smbm
return sm.wor(sm.haveItem('SpeedBooster'),
sm.wand(sm.knowsFrogSpeedwayWithoutSpeed(),
sm.haveItem('Wave'),
sm.wor(sm.haveItem('Spazer'),
sm.haveItem('Plasma'))))
@Cache.decorator
def canEnterNorfairReserveAreaFromBubbleMoutain(self):
sm = self.smbm
return sm.wand(sm.traverse('BubbleMountainTopLeft'),
sm.wor(sm.canFly(),
sm.haveItem('Ice'),
sm.wand(sm.haveItem('HiJump'),
sm.knowsGetAroundWallJump()),
sm.wand(sm.canUseSpringBall(),
sm.knowsSpringBallJumpFromWall())))
@Cache.decorator
def canEnterNorfairReserveAreaFromBubbleMoutainTop(self):
sm = self.smbm
return sm.wand(sm.traverse('BubbleMountainTopLeft'),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.knowsNorfairReserveDBoost()))
@Cache.decorator
def canPassLavaPit(self):
sm = self.smbm
nTanks4Dive = 8 / sm.getDmgReduction()[0]
if sm.haveItem('HiJump').bool == False:
nTanks4Dive = ceil(nTanks4Dive * 1.25)
return sm.wand(sm.wor(sm.wand(sm.haveItem('Gravity'), sm.haveItem('SpaceJump')),
sm.wand(sm.knowsGravityJump(), sm.haveItem('Gravity'), sm.wor(sm.haveItem('HiJump'), sm.knowsLavaDive())),
sm.wand(sm.wor(sm.wand(sm.knowsLavaDive(), sm.haveItem('HiJump')),
sm.knowsLavaDiveNoHiJump()),
sm.energyReserveCountOk(nTanks4Dive))),
sm.canUsePowerBombs()) # power bomb blocks left and right of LN entrance without any items before
@Cache.decorator
def canPassLavaPitReverse(self):
sm = self.smbm
nTanks = 2
if sm.heatProof().bool == False:
nTanks = 6
return sm.energyReserveCountOk(nTanks)
@Cache.decorator
def canPassLowerNorfairChozo(self):
sm = self.smbm
# to require one more CF if no heat protection because of distance to cover, wait times, acid...
return sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Entrance -> GT via Chozo']),
sm.canUsePowerBombs(),
sm.wor(RomPatches.has(sm.player, RomPatches.LNChozoSJCheckDisabled), sm.haveItem('SpaceJump')))
@Cache.decorator
def canExitScrewAttackArea(self):
sm = self.smbm
return sm.wand(sm.canDestroyBombWalls(),
sm.wor(sm.canFly(),
sm.wand(sm.haveItem('HiJump'),
sm.haveItem('SpeedBooster'),
sm.wor(sm.wand(sm.haveItem('ScrewAttack'), sm.knowsScrewAttackExit()),
sm.knowsScrewAttackExitWithoutScrew())),
sm.wand(sm.canUseSpringBall(),
sm.knowsSpringBallJumpFromWall()),
sm.wand(sm.canSimpleShortCharge(), # fight GT and spark out
sm.enoughStuffGT())))
@Cache.decorator
def canPassWorstRoom(self):
sm = self.smbm
return sm.wand(sm.canDestroyBombWalls(),
sm.canPassWorstRoomPirates(),
sm.wor(sm.canFly(),
sm.wand(sm.knowsWorstRoomIceCharge(), sm.haveItem('Ice'), sm.canFireChargedShots()),
sm.wor(sm.wand(sm.knowsGetAroundWallJump(), sm.haveItem('HiJump')),
sm.knowsWorstRoomWallJump()),
sm.wand(sm.knowsSpringBallJumpFromWall(), sm.canUseSpringBall())))
# checks mix of super missiles/health
def canGoThroughLowerNorfairEnemy(self, nmyHealth, nbNmy, nmyHitDmg, supDmg=300.0):
sm = self.smbm
# supers only
if sm.itemCount('Super')*5*supDmg >= nbNmy*nmyHealth:
return SMBool(True, 0, items=['Super'])
# - or with taking damage as well?
(dmgRed, redItems) = sm.getDmgReduction(envDmg=False)
dmg = nmyHitDmg / dmgRed
if sm.heatProof() and (sm.itemCount('Super')*5*supDmg)/nmyHealth + (sm.energyReserveCount()*100 - 2)/dmg >= nbNmy:
# require heat proof as long as taking damage is necessary.
# display all the available energy in the solver.
return sm.wand(sm.heatProof(), SMBool(True, 0, items=redItems+['Super', '{}-ETank - {}-Reserve'.format(self.smbm.itemCount('ETank'), self.smbm.itemCount('Reserve'))]))
return sm.knowsDodgeLowerNorfairEnemies()
def canKillRedKiHunters(self, n):
sm = self.smbm
return sm.wor(sm.haveItem('Plasma'),
sm.haveItem('ScrewAttack'),
sm.wand(sm.heatProof(), # this takes a loooong time ...
sm.wor(sm.haveItem('Spazer'),
sm.haveItem('Ice'),
sm.wand(sm.haveItem('Charge'),
sm.haveItem('Wave')))),
sm.canGoThroughLowerNorfairEnemy(1800.0, float(n), 200.0))
@Cache.decorator
def canPassThreeMuskateers(self):
sm = self.smbm
return sm.canKillRedKiHunters(6)
@Cache.decorator
def canPassRedKiHunters(self):
sm = self.smbm
return sm.canKillRedKiHunters(3)
@Cache.decorator
def canPassWastelandDessgeegas(self):
sm = self.smbm
return sm.wor(sm.haveItem('Plasma'),
sm.haveItem('ScrewAttack'),
sm.wand(sm.heatProof(), # this takes a loooong time ...
sm.wor(sm.haveItem('Spazer'),
sm.wand(sm.haveItem('Charge'),
sm.haveItem('Wave')))),
sm.itemCountOk('PowerBomb', 4),
sm.canGoThroughLowerNorfairEnemy(800.0, 3.0, 160.0))
@Cache.decorator
def canPassNinjaPirates(self):
sm = self.smbm
return sm.wor(sm.itemCountOk('Missile', 10),
sm.itemCountOk('Super', 2),
sm.haveItem('Plasma'),
sm.wor(sm.haveItem('Spazer'),
sm.wand(sm.haveItem('Charge'),
sm.wor(sm.haveItem('Wave'),
sm.haveItem('Ice')))),
sm.canShortCharge()) # echoes kill
@Cache.decorator
def canPassWorstRoomPirates(self):
sm = self.smbm
return sm.wor(sm.haveItem('ScrewAttack'),
sm.itemCountOk('Missile', 6),
sm.itemCountOk('Super', 3),
sm.wand(sm.canFireChargedShots(), sm.haveItem('Plasma')),
sm.wand(sm.haveItem('Charge'),
sm.wor(sm.haveItem('Spazer'),
sm.haveItem('Wave'),
sm.haveItem('Ice'))),
sm.knowsDodgeLowerNorfairEnemies())
# go though the pirates room filled with acid
@Cache.decorator
def canPassAmphitheaterReverse(self):
sm = self.smbm
dmgRed = sm.getDmgReduction()[0]
nTanksGrav = 4 * 4/dmgRed
nTanksNoGrav = 6 * 4/dmgRed
return sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.energyReserveCountOk(nTanksGrav)),
sm.wand(sm.energyReserveCountOk(nTanksNoGrav),
sm.knowsLavaDive())) # should be a good enough skill filter for acid wall jumps with no grav...
@Cache.decorator
def canGetBackFromRidleyZone(self):
sm = self.smbm
return sm.wand(sm.canUsePowerBombs(),
sm.wor(sm.canUseSpringBall(),
sm.canUseBombs(),
sm.itemCountOk('PowerBomb', 2),
sm.haveItem('ScrewAttack'),
sm.canShortCharge()), # speedball
# in escape you don't have PBs and can't shoot bomb blocks in long tunnels
# in wasteland and ki hunter room
sm.wnot(sm.canUseHyperBeam()))
@Cache.decorator
def canClimbRedTower(self):
sm = self.smbm
return sm.wor(sm.knowsRedTowerClimb(),
sm.haveItem('Ice'),
sm.haveItem('SpaceJump'))
@Cache.decorator
def canClimbBottomRedTower(self):
sm = self.smbm
return sm.wor(RomPatches.has(sm.player, RomPatches.RedTowerLeftPassage),
sm.haveItem('HiJump'),
sm.haveItem('Ice'),
sm.canFly(),
sm.canShortCharge())
@Cache.decorator
def canGoUpMtEverest(self):
sm = self.smbm
return sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpeedBooster'),
sm.canFly(),
sm.wand(sm.knowsGravityJump(),
sm.wor(sm.haveItem('HiJump'),
sm.knowsMtEverestGravJump())))),
sm.wand(sm.canDoSuitlessOuterMaridia(),
sm.haveItem('Grapple')))
@Cache.decorator
def canPassMtEverest(self):
sm = self.smbm
return sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpeedBooster'),
sm.canFly(),
sm.knowsGravityJump())),
sm.wand(sm.canDoSuitlessOuterMaridia(),
sm.wor(sm.haveItem('Grapple'),
sm.wand(sm.haveItem('Ice'), sm.knowsTediousMountEverest(), sm.haveItem('Super')),
sm.canDoubleSpringBallJump())))
@Cache.decorator
def canJumpUnderwater(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel1(),
sm.haveItem('HiJump')))
@Cache.decorator
def canDoSuitlessOuterMaridia(self):
sm = self.smbm
return sm.wand(sm.knowsGravLessLevel1(),
sm.haveItem('HiJump'),
sm.wor(sm.haveItem('Ice'),
sm.canSpringBallJump()))
@Cache.decorator
def canDoOuterMaridia(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.canDoSuitlessOuterMaridia())
@Cache.decorator
def canPassBotwoonHallway(self):
sm = self.smbm
return sm.wor(sm.wand(sm.haveItem('SpeedBooster'),
sm.haveItem('Gravity')),
sm.wand(sm.knowsMochtroidClip(), sm.haveItem('Ice')),
sm.canCrystalFlashClip())
@Cache.decorator
def canDefeatBotwoon(self):
sm = self.smbm
return sm.wand(sm.enoughStuffBotwoon(),
sm.canPassBotwoonHallway())
# the sandpits from aqueduct
@Cache.decorator
def canAccessSandPits(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.haveItem('HiJump'),
sm.knowsGravLessLevel3()))
@Cache.decorator
def canReachCacatacAlleyFromBotowoon(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel2(),
sm.haveItem("HiJump"),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('Ice'),
sm.canDoubleSpringBallJump())))
@Cache.decorator
def canPassCacatacAlley(self):
sm = self.smbm
return sm.wand(Bosses.bossDead(sm, 'Draygon'),
sm.haveItem('Morph'),
sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel2(),
sm.haveItem('HiJump'),
sm.haveItem('SpaceJump'))))
@Cache.decorator
def canGoThroughColosseumSuitless(self):
sm = self.smbm
return sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.wand(sm.haveItem('Ice'),
sm.energyReserveCountOk(int(7.0/sm.getDmgReduction(False)[0])), # mochtroid dmg
sm.knowsBotwoonToDraygonWithIce()))
@Cache.decorator
def canBotwoonExitToColosseum(self):
sm = self.smbm
# traverse Botwoon Energy Tank Room
return sm.wand(sm.wor(sm.wand(sm.haveItem('Gravity'), sm.haveItem('SpeedBooster')),
sm.wand(sm.haveItem('Morph'), sm.canJumpUnderwater())),
# after Botwoon Energy Tank Room
sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel2(),
sm.haveItem("HiJump"),
# get to top right door
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('Ice'), # climb mochtroids
sm.wand(sm.canDoubleSpringBallJump(),
sm.haveItem('SpaceJump'))),
sm.canGoThroughColosseumSuitless())))
@Cache.decorator
def canColosseumToBotwoonExit(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel2(),
sm.haveItem("HiJump"),
sm.canGoThroughColosseumSuitless()))
@Cache.decorator
def canClimbColosseum(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel2(),
sm.haveItem("HiJump"),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('Ice'),
sm.knowsPreciousRoomGravJumpExit())))
@Cache.decorator
def canClimbWestSandHole(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.haveItem('HiJump'),
sm.knowsGravLessLevel3(),
sm.wor(sm.haveItem('SpaceJump'),
sm.canSpringBallJump(),
sm.knowsWestSandHoleSuitlessWallJumps())))
@Cache.decorator
def canAccessItemsInWestSandHole(self):
sm = self.smbm
return sm.wor(sm.wand(sm.haveItem('HiJump'), # vanilla strat
sm.canUseSpringBall()),
sm.wand(sm.haveItem('SpaceJump'), # alternate strat with possible double bomb jump but no difficult wj
sm.wor(sm.canUseSpringBall(),
sm.canUseBombs())),
sm.wand(sm.canPassBombPassages(), # wjs and/or 3 tile mid air morph
sm.knowsMaridiaWallJumps()))
@Cache.decorator
def getDraygonConnection(self):
return getAccessPoint('DraygonRoomOut').ConnectedTo
@Cache.decorator
def isVanillaDraygon(self):
return SMBool(self.getDraygonConnection() == 'DraygonRoomIn')
@Cache.decorator
def canUseCrocRoomToChargeSpeed(self):
sm = self.smbm
crocRoom = getAccessPoint('Crocomire Room Top')
speedway = getAccessPoint('Crocomire Speedway Bottom')
return sm.wand(SMBool(crocRoom.ConnectedTo == 'Crocomire Speedway Bottom'),
crocRoom.traverse(sm),
speedway.traverse(sm))
@Cache.decorator
def canFightDraygon(self):
sm = self.smbm
return sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.haveItem('HiJump'),
sm.wor(sm.knowsGravLessLevel2(),
sm.knowsGravLessLevel3())))
@Cache.decorator
def canDraygonCrystalFlashSuit(self):
sm = self.smbm
return sm.wand(sm.canCrystalFlash(),
sm.knowsDraygonRoomCrystalFlash(),
# ask for 4 PB pack as an ugly workaround for
# a rando bug which can place a PB at space
# jump to "get you out" (this check is in
# PostAvailable condition of the Dray/Space
# Jump locs)
sm.itemCountOk('PowerBomb', 4))
@Cache.decorator
def canExitDraygonRoomWithGravity(self):
sm = self.smbm
return sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.canFly(),
sm.knowsGravityJump(),
sm.wand(sm.haveItem('HiJump'),
sm.haveItem('SpeedBooster'))))
@Cache.decorator
def canGrappleExitDraygon(self):
sm = self.smbm
return sm.wand(sm.haveItem('Grapple'),
sm.knowsDraygonRoomGrappleExit())
@Cache.decorator
def canExitDraygonVanilla(self):
sm = self.smbm
# to get out of draygon room:
# with gravity but without highjump/bomb/space jump: gravity jump
# to exit draygon room: grapple or crystal flash (for free shine spark)
# to exit precious room: spring ball jump, xray scope glitch or stored spark
return sm.wor(sm.canExitDraygonRoomWithGravity(),
sm.wand(sm.canDraygonCrystalFlashSuit(),
# use the spark either to exit draygon room or precious room
sm.wor(sm.canGrappleExitDraygon(),
sm.wand(sm.haveItem('XRayScope'),
sm.knowsPreciousRoomXRayExit()),
sm.canSpringBallJump())),
# spark-less exit (no CF)
sm.wand(sm.canGrappleExitDraygon(),
sm.wor(sm.wand(sm.haveItem('XRayScope'),
sm.knowsPreciousRoomXRayExit()),
sm.canSpringBallJump())),
sm.canDoubleSpringBallJump())
@Cache.decorator
def canExitDraygonRandomized(self):
sm = self.smbm
# disregard precious room
return sm.wor(sm.canExitDraygonRoomWithGravity(),
sm.canDraygonCrystalFlashSuit(),
sm.canGrappleExitDraygon(),
sm.canDoubleSpringBallJump())
@Cache.decorator
def canExitDraygon(self):
sm = self.smbm
if self.isVanillaDraygon():
return self.canExitDraygonVanilla()
else:
return self.canExitDraygonRandomized()
@Cache.decorator
def canExitPreciousRoomVanilla(self):
return SMBool(True) # handled by canExitDraygonVanilla
@Cache.decorator
def canExitPreciousRoomRandomized(self):
sm = self.smbm
suitlessRoomExit = sm.canSpringBallJump()
if suitlessRoomExit.bool == False:
if self.getDraygonConnection() == 'KraidRoomIn':
suitlessRoomExit = sm.canShortCharge() # charge spark in kraid's room
elif self.getDraygonConnection() == 'RidleyRoomIn':
suitlessRoomExit = sm.wand(sm.haveItem('XRayScope'), # get doorstuck in compatible transition
sm.knowsPreciousRoomXRayExit())
return sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.canFly(),
sm.knowsGravityJump(),
sm.haveItem('HiJump'))),
suitlessRoomExit)
@Cache.decorator
def canExitPreciousRoom(self):
if self.isVanillaDraygon():
return self.canExitPreciousRoomVanilla()
else:
return self.canExitPreciousRoomRandomized()
@Cache.decorator
def canPassDachoraRoom(self):
sm = self.smbm
return sm.wor(sm.haveItem('SpeedBooster'), sm.canDestroyBombWalls())
@Cache.decorator
def canTraverseCrabTunnelLeftToRight(self):
sm = self.smbm
return sm.wand(sm.traverse('MainStreetBottomRight'),
sm.wor(sm.haveItem('Super'),
RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther)))

View File

@@ -0,0 +1,994 @@
from logic.helpers import Bosses
from utils.parameters import Settings
from rom.rom_patches import RomPatches
from logic.smbool import SMBool
from graph.location import locationsDict
locationsDict["Energy Tank, Gauntlet"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Gauntlet"].Available = (
lambda sm: sm.wor(sm.canEnterAndLeaveGauntlet(),
sm.wand(sm.canShortCharge(),
sm.canEnterAndLeaveGauntletQty(1, 0)), # thanks ponk! https://youtu.be/jil5zTBCF1s
sm.canDoLowGauntlet())
)
locationsDict["Bomb"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Bomb"].Available = (
lambda sm: sm.wand(sm.haveItem('Morph'),
sm.traverse('FlywayRight'))
)
locationsDict["Bomb"].PostAvailable = (
lambda sm: sm.wor(sm.knowsAlcatrazEscape(),
sm.canPassBombPassages())
)
locationsDict["Energy Tank, Terminator"].AccessFrom = {
'Landing Site': lambda sm: sm.canPassTerminatorBombWall(),
'Lower Mushrooms Left': lambda sm: sm.canPassCrateriaGreenPirates(),
'Gauntlet Top': lambda sm: sm.haveItem('Morph')
}
locationsDict["Energy Tank, Terminator"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Reserve Tank, Brinstar"].AccessFrom = {
'Green Brinstar Elevator': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('MainShaftRight'))
}
locationsDict["Reserve Tank, Brinstar"].Available = (
lambda sm: sm.wand(sm.wor(sm.canMockball(),
sm.haveItem('SpeedBooster')),
sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('EarlySupersRight')))
)
locationsDict["Charge Beam"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Charge Beam"].Available = (
lambda sm: sm.canPassBombPassages()
)
locationsDict["Morphing Ball"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}
locationsDict["Morphing Ball"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Energy Tank, Brinstar Ceiling"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BlueBrinstarBlueDoor), sm.traverse('ConstructionZoneRight'))
}
locationsDict["Energy Tank, Brinstar Ceiling"].Available = (
lambda sm: sm.wor(sm.knowsCeilingDBoost(),
sm.canFly(),
sm.wor(sm.haveItem('HiJump'),
sm.haveItem('Ice'),
sm.wand(sm.canUsePowerBombs(),
sm.haveItem('SpeedBooster')),
sm.canSimpleShortCharge()))
)
locationsDict["Energy Tank, Etecoons"].AccessFrom = {
'Etecoons Bottom': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Etecoons"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Energy Tank, Waterway"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Waterway"].Available = (
lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.traverse('BigPinkBottomLeft'),
sm.haveItem('SpeedBooster'),
sm.wor(sm.haveItem('Gravity'),
sm.canSimpleShortCharge())) # from the blocks above the water
)
locationsDict["Energy Tank, Brinstar Gate"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Brinstar Gate"].Available = (
lambda sm: sm.wand(sm.traverse('BigPinkRight'),
sm.wor(sm.haveItem('Wave'),
sm.wand(sm.haveItem('Super'),
sm.haveItem('HiJump'),
sm.knowsReverseGateGlitch()),
sm.wand(sm.haveItem('Super'),
sm.knowsReverseGateGlitchHiJumpLess())))
)
locationsDict["X-Ray Scope"].AccessFrom = {
'Red Tower Top Left': lambda sm: SMBool(True)
}
locationsDict["X-Ray Scope"].Available = (
lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.traverse('RedTowerLeft'),
sm.traverse('RedBrinstarFirefleaLeft'),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.wand(sm.energyReserveCountOkHardRoom('X-Ray'),
sm.wor(sm.knowsXrayDboost(),
sm.wand(sm.haveItem('Ice'),
sm.wor(sm.haveItem('HiJump'), sm.knowsXrayIce())),
sm.canInfiniteBombJump(),
sm.wand(sm.haveItem('HiJump'),
sm.wor(sm.haveItem('SpeedBooster'),
sm.canSpringBallJump()))))))
)
locationsDict["Spazer"].AccessFrom = {
'East Tunnel Right': lambda sm: SMBool(True)
}
locationsDict["Spazer"].Available = (
lambda sm: sm.wand(sm.traverse('BelowSpazerTopRight'),
sm.wor(sm.canPassBombPassages(),
sm.wand(sm.haveItem('Morph'),
RomPatches.has(sm.player, RomPatches.SpazerShotBlock))))
)
locationsDict["Energy Tank, Kraid"].AccessFrom = {
'Warehouse Zeela Room Left': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Kraid"].Available = (
lambda sm: sm.wand(Bosses.bossDead(sm, 'Kraid'),
# kill the beetoms to unlock the door to get out
sm.canKillBeetoms())
)
locationsDict["Kraid"].AccessFrom = {
'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Kraid"].Available = (
lambda sm: sm.enoughStuffsKraid()
)
locationsDict["Varia Suit"].AccessFrom = {
'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Varia Suit"].Available = (
lambda sm: Bosses.bossDead(sm, 'Kraid')
)
locationsDict["Ice Beam"].AccessFrom = {
'Business Center': lambda sm: sm.traverse('BusinessCenterTopLeft')
}
locationsDict["Ice Beam"].Available = (
lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['Ice']['Norfair Entrance -> Ice Beam']),
sm.wor(sm.canPassBombPassages(), # to exit, or if you fail entrance
sm.wand(sm.haveItem('Ice'), # harder strat
sm.haveItem('Morph'),
sm.knowsIceEscape())),
sm.wor(sm.wand(sm.haveItem('Morph'),
sm.knowsMockball()),
sm.haveItem('SpeedBooster')))
)
locationsDict["Energy Tank, Crocomire"].AccessFrom = {
'Crocomire Room Top': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Crocomire"].Available = (
lambda sm: sm.wand(sm.enoughStuffCroc(),
sm.wor(sm.haveItem('Grapple'),
sm.haveItem('SpaceJump'),
sm.energyReserveCountOk(3/sm.getDmgReduction()[0])))
)
locationsDict["Hi-Jump Boots"].AccessFrom = {
'Business Center': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.HiJumpAreaBlueDoor), sm.traverse('BusinessCenterBottomLeft'))
}
locationsDict["Hi-Jump Boots"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Hi-Jump Boots"].PostAvailable = (
lambda sm: sm.wor(sm.canPassBombPassages(),
sm.wand(sm.haveItem('Morph'), RomPatches.has(sm.player, RomPatches.HiJumpShotBlock)))
)
locationsDict["Grapple Beam"].AccessFrom = {
'Crocomire Room Top': lambda sm: SMBool(True)
}
locationsDict["Grapple Beam"].Available = (
lambda sm: sm.wand(sm.enoughStuffCroc(),
sm.wor(sm.wand(sm.haveItem('Morph'),
sm.canFly()),
sm.wand(sm.haveItem('SpeedBooster'),
sm.wor(sm.knowsShortCharge(),
sm.canUsePowerBombs())),
sm.wand(sm.haveItem('Morph'),
sm.wor(sm.haveItem('SpeedBooster'),
sm.canSpringBallJump()),
sm.haveItem('HiJump')), # jump from the yellow plateform ennemy
sm.canGreenGateGlitch()))
)
locationsDict["Grapple Beam"].PostAvailable = (
lambda sm: sm.wor(sm.haveItem('Morph'), # regular exit
sm.wand(sm.haveItem('Super'), # grapple escape reverse
sm.wor(sm.canFly(), # Grapple Tutorial Room 2
sm.haveItem('HiJump'),
sm.haveItem('Grapple')),
sm.wor(sm.haveItem('Gravity'), # Grapple Tutorial Room 3
sm.haveItem('SpaceJump'),
sm.haveItem('Grapple'))))
)
locationsDict["Reserve Tank, Norfair"].AccessFrom = {
'Bubble Mountain': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutain(),
'Bubble Mountain Top': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutainTop(),
}
locationsDict["Reserve Tank, Norfair"].Available = (
lambda sm: sm.wand(sm.haveItem('Morph'), sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Norfair Reserve']))
)
locationsDict["Speed Booster"].AccessFrom = {
'Bubble Mountain Top': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.SpeedAreaBlueDoors),
sm.wand(sm.traverse('BubbleMountainTopRight'),
sm.traverse('SpeedBoosterHallRight')))
}
locationsDict["Speed Booster"].Available = (
lambda sm: sm.canHellRunToSpeedBooster()
)
locationsDict["Wave Beam"].AccessFrom = {
'Bubble Mountain Top': lambda sm: sm.canAccessDoubleChamberItems()
}
locationsDict["Wave Beam"].Available = (
lambda sm: sm.traverse('DoubleChamberRight')
)
locationsDict["Wave Beam"].PostAvailable = (
lambda sm: sm.wor(sm.haveItem('Morph'), # exit through lower passage under the spikes
sm.wand(sm.wor(sm.haveItem('SpaceJump'), # exit through blue gate
sm.haveItem('Grapple')),
sm.wor(sm.wand(sm.canBlueGateGlitch(), sm.heatProof()), # hell run + green gate glitch is too much
sm.haveItem('Wave'))))
)
locationsDict["Ridley"].AccessFrom = {
'RidleyRoomIn': lambda sm: SMBool(True)
}
locationsDict["Ridley"].Available = (
lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']), sm.enoughStuffsRidley())
)
locationsDict["Energy Tank, Ridley"].AccessFrom = {
'RidleyRoomIn': lambda sm: sm.haveItem('Ridley')
}
locationsDict["Energy Tank, Ridley"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Screw Attack"].AccessFrom = {
'Screw Attack Bottom': lambda sm: SMBool(True)
}
locationsDict["Screw Attack"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Screw Attack"].PostAvailable = (
lambda sm: sm.canExitScrewAttackArea()
)
locationsDict["Energy Tank, Firefleas"].AccessFrom = {
'Firefleas': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Firefleas"].Available = (
lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.FirefleasRemoveFune),
# get past the fune
sm.haveItem('Super'),
sm.canPassBombPassages(),
sm.canUseSpringBall())
)
locationsDict["Energy Tank, Firefleas"].PostAvailable = (
lambda sm: sm.wor(sm.knowsFirefleasWalljump(),
sm.wor(sm.haveItem('Ice'),
sm.haveItem('HiJump'),
sm.canFly(),
sm.canSpringBallJump()))
)
locationsDict["Reserve Tank, Wrecked Ship"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Reserve Tank, Wrecked Ship"].Available = (
lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.haveItem('SpeedBooster'),
sm.canPassBowling())
)
locationsDict["Energy Tank, Wrecked Ship"].AccessFrom = {
'Wrecked Ship Back': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.WsEtankBlueDoor),
sm.traverse('ElectricDeathRoomTopLeft'))
}
locationsDict["Energy Tank, Wrecked Ship"].Available = (
lambda sm: sm.wor(Bosses.bossDead(sm, 'Phantoon'),
RomPatches.has(sm.player, RomPatches.WsEtankPhantoonAlive))
)
locationsDict["Phantoon"].AccessFrom = {
'PhantoonRoomIn': lambda sm: SMBool(True)
}
locationsDict["Phantoon"].Available = (
lambda sm: sm.enoughStuffsPhantoon()
)
locationsDict["Right Super, Wrecked Ship"].AccessFrom = {
'Wrecked Ship Main': lambda sm: Bosses.bossDead(sm, 'Phantoon')
}
locationsDict["Right Super, Wrecked Ship"].Available = (
lambda sm: sm.canPassBombPassages()
)
locationsDict["Gravity Suit"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Gravity Suit"].Available = (
lambda sm: sm.wand(sm.canPassBombPassages(),
sm.canPassBowling())
)
locationsDict["Energy Tank, Mama turtle"].AccessFrom = {
'Main Street Bottom': lambda sm: sm.wand(sm.canDoOuterMaridia(),
sm.wor(sm.traverse('FishTankRight'),
RomPatches.has(sm.player, RomPatches.MamaTurtleBlueDoor)),
sm.wor(sm.wor(sm.canFly(),
sm.wand(sm.haveItem('Gravity'),
sm.haveItem('SpeedBooster')),
sm.wand(sm.haveItem('HiJump'),
sm.haveItem('SpeedBooster'),
sm.knowsHiJumpMamaTurtle())),
sm.wor(sm.wand(sm.canUseSpringBall(),
sm.wor(sm.wand(sm.haveItem('HiJump'),
sm.knowsSpringBallJump()),
sm.knowsSpringBallJumpFromWall())),
sm.haveItem('Grapple')))),
'Mama Turtle': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Mama turtle"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Plasma Beam"].AccessFrom = {
'Toilet Top': lambda sm: SMBool(True)
}
locationsDict["Plasma Beam"].Available = (
lambda sm: Bosses.bossDead(sm, 'Draygon')
)
locationsDict["Plasma Beam"].PostAvailable = (
lambda sm: sm.wand(sm.wor(sm.wand(sm.canShortCharge(),
sm.knowsKillPlasmaPiratesWithSpark()),
sm.wand(sm.canFireChargedShots(),
sm.knowsKillPlasmaPiratesWithCharge(),
# 160/80/40 dmg * 4 ground plasma pirates
# => 640/320/160 damage take required
# check below is 1099/599/299 (give margin for taking dmg a bit)
# (* 4 for nerfed charge, since you need to take hits 4 times instead of one)
sm.energyReserveCountOk(int(10.0 * sm.getPiratesPseudoScrewCoeff()/sm.getDmgReduction(False)[0]))),
sm.haveItem('ScrewAttack'),
sm.haveItem('Plasma')),
sm.wor(sm.canFly(),
sm.wand(sm.haveItem('HiJump'),
sm.knowsGetAroundWallJump()),
sm.canShortCharge(),
sm.wand(sm.canSpringBallJump(),
sm.knowsSpringBallJumpFromWall())))
)
locationsDict["Reserve Tank, Maridia"].AccessFrom = {
'Left Sandpit': lambda sm: sm.canClimbWestSandHole()
}
locationsDict["Reserve Tank, Maridia"].Available = (
lambda sm: sm.canAccessItemsInWestSandHole()
)
locationsDict["Spring Ball"].AccessFrom = {
'Oasis Bottom': lambda sm: sm.canTraverseSandPits()
}
locationsDict["Spring Ball"].Available = (
lambda sm: sm.wand(sm.canUsePowerBombs(), # in Shaktool room to let Shaktool access the sand blocks
sm.wor(sm.wand(sm.haveItem('Ice'), # puyo clip
sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.knowsPuyoClip()),
sm.wand(sm.haveItem('Gravity'),
sm.haveItem('XRayScope'),
sm.knowsPuyoClipXRay()),
sm.knowsSuitlessPuyoClip())),
sm.wand(sm.haveItem('Grapple'), # go through grapple block
sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.wor(sm.wand(sm.haveItem('HiJump'), sm.knowsAccessSpringBallWithHiJump()),
sm.haveItem('SpaceJump')),
sm.knowsAccessSpringBallWithGravJump(),
sm.wand(sm.haveItem('Bomb'),
sm.wor(sm.knowsAccessSpringBallWithBombJumps(),
sm.wand(sm.haveItem('SpringBall'),
sm.knowsAccessSpringBallWithSpringBallBombJumps()))),
sm.wand(sm.haveItem('SpringBall'), sm.knowsAccessSpringBallWithSpringBallJump()))),
sm.wand(sm.haveItem('SpaceJump'), sm.knowsAccessSpringBallWithFlatley()))),
sm.wand(sm.haveItem('XRayScope'), sm.knowsAccessSpringBallWithXRayClimb()), # XRay climb
sm.canCrystalFlashClip()),
sm.wor(sm.haveItem('Gravity'), sm.canUseSpringBall())) # acess the item in spring ball room
)
locationsDict["Spring Ball"].PostAvailable = (
lambda sm: sm.wor(sm.wand(sm.haveItem('Gravity'),
sm.wor(sm.haveItem('HiJump'),
sm.canFly(),
sm.knowsMaridiaWallJumps())),
sm.canSpringBallJump())
)
locationsDict["Energy Tank, Botwoon"].AccessFrom = {
'Post Botwoon': lambda sm: sm.canJumpUnderwater()
}
locationsDict["Energy Tank, Botwoon"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Draygon"].AccessFrom = {
'Draygon Room Bottom': lambda sm: SMBool(True)
}
locationsDict["Draygon"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Space Jump"].AccessFrom = {
'Draygon Room Bottom': lambda sm: SMBool(True)
}
locationsDict["Space Jump"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Space Jump"].PostAvailable = (
lambda sm: Bosses.bossDead(sm, 'Draygon')
)
locationsDict["Mother Brain"].AccessFrom = {
'Golden Four': lambda sm: Bosses.allBossesDead(sm)
}
locationsDict["Mother Brain"].Available = (
lambda sm: sm.enoughStuffTourian()
)
locationsDict["Power Bomb (Crateria surface)"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (Crateria surface)"].Available = (
lambda sm: sm.wand(sm.traverse('LandingSiteTopRight'),
sm.wor(sm.haveItem('SpeedBooster'),
sm.canFly()))
)
locationsDict["Missile (outside Wrecked Ship bottom)"].AccessFrom = {
'West Ocean Left': lambda sm: SMBool(True)
}
locationsDict["Missile (outside Wrecked Ship bottom)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Missile (outside Wrecked Ship bottom)"].PostAvailable = (
lambda sm: sm.canPassBombPassages()
)
locationsDict["Missile (outside Wrecked Ship top)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Missile (outside Wrecked Ship top)"].Available = (
lambda sm: Bosses.bossDead(sm, 'Phantoon')
)
locationsDict["Missile (outside Wrecked Ship middle)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Missile (outside Wrecked Ship middle)"].Available = (
lambda sm: sm.wand(sm.haveItem('Super'), sm.haveItem('Morph'), Bosses.bossDead(sm, 'Phantoon'))
)
locationsDict["Missile (Crateria moat)"].AccessFrom = {
'Moat Left': lambda sm: SMBool(True)
}
locationsDict["Missile (Crateria moat)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (Crateria bottom)"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Missile (Crateria bottom)"].Available = (
lambda sm: sm.wor(sm.canDestroyBombWalls(),
sm.wand(sm.haveItem('SpeedBooster'),
sm.knowsOldMBWithSpeed()))
)
locationsDict["Missile (Crateria gauntlet right)"].AccessFrom = {
'Landing Site': lambda sm: sm.wor(sm.wand(sm.canEnterAndLeaveGauntlet(),
sm.canPassBombPassages()),
sm.canDoLowGauntlet()),
'Gauntlet Top': lambda sm: SMBool(True)
}
locationsDict["Missile (Crateria gauntlet right)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (Crateria gauntlet left)"].AccessFrom = {
'Landing Site': lambda sm: sm.wor(sm.wand(sm.canEnterAndLeaveGauntlet(),
sm.canPassBombPassages()),
sm.canDoLowGauntlet()),
'Gauntlet Top': lambda sm: SMBool(True)
}
locationsDict["Missile (Crateria gauntlet left)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Super Missile (Crateria)"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Super Missile (Crateria)"].Available = (
lambda sm: sm.wand(sm.canPassBombPassages(),
sm.traverse("ClimbRight"),
sm.haveItem('SpeedBooster'),
# reserves are hard to trigger midspark when not having ETanks
sm.wor(sm.wand(sm.energyReserveCountOk(2), sm.itemCountOk('ETank', 1)), # need energy to get out
sm.wand(sm.itemCountOk('ETank', 1),
sm.wor(sm.haveItem('Grapple'), # use grapple/space or dmg protection to get out
sm.haveItem('SpaceJump'),
sm.heatProof()))),
sm.wor(sm.haveItem('Ice'),
sm.wand(sm.canSimpleShortCharge(), sm.canUsePowerBombs()))) # there's also a dboost involved in simple short charge or you have to kill the yellow enemies with some power bombs
)
locationsDict["Missile (Crateria middle)"].AccessFrom = {
'Landing Site': lambda sm: SMBool(True)
}
locationsDict["Missile (Crateria middle)"].Available = (
lambda sm: sm.canPassBombPassages()
)
locationsDict["Power Bomb (green Brinstar bottom)"].AccessFrom = {
'Etecoons Bottom': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (green Brinstar bottom)"].Available = (
lambda sm: sm.wand(sm.haveItem('Morph'),
sm.canKillBeetoms())
)
locationsDict["Super Missile (pink Brinstar)"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Super Missile (pink Brinstar)"].Available = (
lambda sm: sm.wor(sm.wand(sm.traverse('BigPinkTopRight'),
sm.enoughStuffSporeSpawn()),
# back way into spore spawn
sm.wand(sm.canOpenGreenDoors(),
sm.canPassBombPassages()))
)
locationsDict["Super Missile (pink Brinstar)"].PostAvailable = (
lambda sm: sm.wand(sm.canOpenGreenDoors(),
sm.canPassBombPassages())
)
locationsDict["Missile (green Brinstar below super missile)"].AccessFrom = {
'Green Brinstar Elevator': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('MainShaftRight'))
}
locationsDict["Missile (green Brinstar below super missile)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (green Brinstar below super missile)"].PostAvailable = (
lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.EarlySupersShotBlock), sm.canPassBombPassages())
)
locationsDict["Super Missile (green Brinstar top)"].AccessFrom = {
'Green Brinstar Elevator': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('MainShaftRight'))
}
locationsDict["Super Missile (green Brinstar top)"].Available = (
lambda sm: sm.wor(sm.canMockball(),
sm.haveItem('SpeedBooster'))
)
locationsDict["Missile (green Brinstar behind missile)"].AccessFrom = {
'Green Brinstar Elevator': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('MainShaftRight'))
}
locationsDict["Missile (green Brinstar behind missile)"].Available = (
lambda sm: sm.wand(sm.haveItem('Morph'),
sm.wor(sm.canMockball(),
sm.haveItem('SpeedBooster')),
sm.traverse('EarlySupersRight'),
sm.wor(sm.canPassBombPassages(),
sm.wand(sm.knowsRonPopeilScrew(),
sm.haveItem('ScrewAttack'))))
)
locationsDict["Missile (green Brinstar behind reserve tank)"].AccessFrom = {
'Green Brinstar Elevator': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.BrinReserveBlueDoors), sm.traverse('MainShaftRight'))
}
locationsDict["Missile (green Brinstar behind reserve tank)"].Available = (
lambda sm: sm.wand(sm.traverse('EarlySupersRight'),
sm.haveItem('Morph'),
sm.wor(sm.canMockball(),
sm.haveItem('SpeedBooster')))
)
locationsDict["Missile (pink Brinstar top)"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Missile (pink Brinstar top)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (pink Brinstar bottom)"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Missile (pink Brinstar bottom)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Power Bomb (pink Brinstar)"].AccessFrom = {
'Big Pink': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (pink Brinstar)"].Available = (
lambda sm: sm.wand(sm.canUsePowerBombs(),
sm.haveItem('Super'))
)
locationsDict["Missile (green Brinstar pipe)"].AccessFrom = {
'Green Hill Zone Top Right': lambda sm: SMBool(True)
}
locationsDict["Missile (green Brinstar pipe)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Power Bomb (blue Brinstar)"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: sm.canUsePowerBombs(),
'Morph Ball Room Left': lambda sm: sm.wor(sm.canPassBombPassages(),
sm.wand(sm.haveItem('Morph'),
sm.canShortCharge())) # speedball
}
locationsDict["Power Bomb (blue Brinstar)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (blue Brinstar middle)"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (blue Brinstar middle)"].Available = (
lambda sm: sm.wand(sm.wor(RomPatches.has(sm.player, RomPatches.BlueBrinstarMissile), sm.haveItem('Morph')),
sm.wor(RomPatches.has(sm.player, RomPatches.BlueBrinstarBlueDoor), sm.traverse('ConstructionZoneRight')))
)
locationsDict["Super Missile (green Brinstar bottom)"].AccessFrom = {
'Etecoons Supers': lambda sm: SMBool(True)
}
locationsDict["Super Missile (green Brinstar bottom)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (blue Brinstar bottom)"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (blue Brinstar bottom)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Missile (blue Brinstar top)"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (blue Brinstar top)"].Available = (
lambda sm: sm.canAccessBillyMays()
)
locationsDict["Missile (blue Brinstar behind missile)"].AccessFrom = {
'Blue Brinstar Elevator Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (blue Brinstar behind missile)"].Available = (
lambda sm: sm.canAccessBillyMays()
)
locationsDict["Power Bomb (red Brinstar sidehopper room)"].AccessFrom = {
'Red Brinstar Elevator': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (red Brinstar sidehopper room)"].Available = (
lambda sm: sm.wand(sm.traverse('RedTowerElevatorTopLeft'),
sm.canUsePowerBombs())
)
locationsDict["Power Bomb (red Brinstar spike room)"].AccessFrom = {
'Red Brinstar Elevator': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (red Brinstar spike room)"].Available = (
lambda sm: sm.traverse('RedTowerElevatorBottomLeft')
)
locationsDict["Missile (red Brinstar spike room)"].AccessFrom = {
'Red Brinstar Elevator': lambda sm: SMBool(True)
}
locationsDict["Missile (red Brinstar spike room)"].Available = (
lambda sm: sm.wand(sm.traverse('RedTowerElevatorBottomLeft'),
sm.canUsePowerBombs())
)
locationsDict["Missile (Kraid)"].AccessFrom = {
'Warehouse Zeela Room Left': lambda sm: SMBool(True)
}
locationsDict["Missile (Kraid)"].Available = (
lambda sm: sm.canUsePowerBombs()
)
locationsDict["Missile (lava room)"].AccessFrom = {
'Cathedral': lambda sm: SMBool(True)
}
locationsDict["Missile (lava room)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Missile (below Ice Beam)"].AccessFrom = {
'Business Center': lambda sm: sm.wand(sm.traverse('BusinessCenterTopLeft'),
sm.canUsePowerBombs(),
sm.canHellRun(**Settings.hellRunsTable['Ice']['Norfair Entrance -> Ice Beam']),
sm.wor(sm.wand(sm.haveItem('Morph'),
sm.knowsMockball()),
sm.haveItem('SpeedBooster'))),
'Crocomire Speedway Bottom': lambda sm: sm.wand(sm.canUseCrocRoomToChargeSpeed(),
sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Croc -> Ice Missiles']),
sm.haveItem('SpeedBooster'),
sm.knowsIceMissileFromCroc())
}
locationsDict["Missile (below Ice Beam)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (above Crocomire)"].AccessFrom = {
'Crocomire Speedway Bottom': lambda sm: sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Croc -> Grapple Escape Missiles'])
}
locationsDict["Missile (above Crocomire)"].Available = (
lambda sm: sm.canGrappleEscape()
)
locationsDict["Missile (Hi-Jump Boots)"].AccessFrom = {
'Business Center': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.HiJumpAreaBlueDoor), sm.traverse('BusinessCenterBottomLeft'))
}
locationsDict["Missile (Hi-Jump Boots)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Missile (Hi-Jump Boots)"].PostAvailable = (
lambda sm: sm.wor(sm.canPassBombPassages(),
sm.wand(RomPatches.has(sm.player, RomPatches.HiJumpShotBlock), sm.haveItem('Morph')))
)
locationsDict["Energy Tank (Hi-Jump Boots)"].AccessFrom = {
'Business Center': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.HiJumpAreaBlueDoor), sm.traverse('BusinessCenterBottomLeft'))
}
locationsDict["Energy Tank (Hi-Jump Boots)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Power Bomb (Crocomire)"].AccessFrom = {
'Crocomire Room Top': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (Crocomire)"].Available = (
lambda sm: sm.wand(sm.traverse('PostCrocomireUpperLeft'),
sm.enoughStuffCroc(),
sm.wor(sm.wor(sm.canFly(),
sm.haveItem('Grapple'),
sm.wand(sm.haveItem('SpeedBooster'),
sm.wor(sm.heatProof(),
sm.energyReserveCountOk(1)))), # spark from the room before
sm.wor(sm.haveItem('HiJump'), # run and jump from yellow platform
sm.wand(sm.haveItem('Ice'),
sm.knowsCrocPBsIce()),
sm.knowsCrocPBsDBoost())))
)
locationsDict["Missile (below Crocomire)"].AccessFrom = {
'Crocomire Room Top': lambda sm: SMBool(True)
}
locationsDict["Missile (below Crocomire)"].Available = (
lambda sm: sm.wand(sm.traverse('PostCrocomireShaftRight'), sm.enoughStuffCroc(), sm.haveItem('Morph'))
)
locationsDict["Missile (Grapple Beam)"].AccessFrom = {
'Crocomire Room Top': lambda sm: SMBool(True)
}
locationsDict["Missile (Grapple Beam)"].Available = (
lambda sm: sm.wand(sm.enoughStuffCroc(),
sm.wor(sm.wor(sm.wand(sm.haveItem('Morph'), # from below
sm.canFly()),
sm.wand(sm.haveItem('SpeedBooster'),
sm.wor(sm.knowsShortCharge(),
sm.canUsePowerBombs()))),
sm.wand(sm.canGreenGateGlitch(), # from grapple room
sm.canFly()))) # TODO::test if accessible with a spark (short charge), and how many etanks required
)
locationsDict["Missile (Grapple Beam)"].PostAvailable = (
lambda sm: sm.wor(sm.haveItem('Morph'), # normal exit
sm.wand(sm.haveItem('Super'), # go back to grapple room
sm.wor(sm.haveItem('SpaceJump'),
sm.wand(sm.haveItem('SpeedBooster'), sm.haveItem('HiJump'))))) # jump from the yellow plateform ennemy
)
locationsDict["Missile (Norfair Reserve Tank)"].AccessFrom = {
'Bubble Mountain': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutain(),
'Bubble Mountain Top': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutainTop()
}
locationsDict["Missile (Norfair Reserve Tank)"].Available = (
lambda sm: sm.wand(sm.haveItem('Morph'), sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Norfair Reserve']))
)
locationsDict["Missile (bubble Norfair green door)"].AccessFrom = {
'Bubble Mountain': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutain(),
'Bubble Mountain Top': lambda sm: sm.canEnterNorfairReserveAreaFromBubbleMoutainTop()
}
locationsDict["Missile (bubble Norfair green door)"].Available = (
lambda sm: sm.canHellRun(**Settings.hellRunsTable['MainUpperNorfair']['Bubble -> Norfair Reserve Missiles'])
)
locationsDict["Missile (bubble Norfair)"].AccessFrom = {
'Bubble Mountain': lambda sm: SMBool(True)
}
locationsDict["Missile (bubble Norfair)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (Speed Booster)"].AccessFrom = {
'Bubble Mountain Top': lambda sm: sm.wor(RomPatches.has(sm.player, RomPatches.SpeedAreaBlueDoors),
sm.traverse('BubbleMountainTopRight'))
}
locationsDict["Missile (Speed Booster)"].Available = (
lambda sm: sm.canHellRunToSpeedBooster()
)
locationsDict["Missile (Wave Beam)"].AccessFrom = {
'Bubble Mountain Top': lambda sm: sm.canAccessDoubleChamberItems()
}
locationsDict["Missile (Wave Beam)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (Gold Torizo)"].AccessFrom = {
'LN Above GT': lambda sm: SMBool(True)
}
locationsDict["Missile (Gold Torizo)"].Available = (
lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main'])
)
locationsDict["Missile (Gold Torizo)"].PostAvailable = (
lambda sm: sm.enoughStuffGT()
)
locationsDict["Super Missile (Gold Torizo)"].AccessFrom = {
'Screw Attack Bottom': lambda sm: SMBool(True)
}
locationsDict["Super Missile (Gold Torizo)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Super Missile (Gold Torizo)"].PostAvailable = (
lambda sm: sm.enoughStuffGT()
)
locationsDict["Missile (Mickey Mouse room)"].AccessFrom = {
'LN Entrance': lambda sm: sm.wand(sm.canUsePowerBombs(), sm.canPassWorstRoom()),
}
locationsDict["Missile (Mickey Mouse room)"].Available = (
lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main'])
)
locationsDict["Missile (lower Norfair above fire flea room)"].AccessFrom = {
'Firefleas': lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main'])
}
locationsDict["Missile (lower Norfair above fire flea room)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Power Bomb (lower Norfair above fire flea room)"].AccessFrom = {
'Firefleas Top': lambda sm: SMBool(True)
}
locationsDict["Power Bomb (lower Norfair above fire flea room)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Power Bomb (Power Bombs of shame)"].AccessFrom = {
'Ridley Zone': lambda sm: sm.canUsePowerBombs()
}
locationsDict["Power Bomb (Power Bombs of shame)"].Available = (
lambda sm: sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main'])
)
locationsDict["Missile (lower Norfair near Wave Beam)"].AccessFrom = {
'Firefleas': lambda sm: SMBool(True)
}
locationsDict["Missile (lower Norfair near Wave Beam)"].Available = (
lambda sm: sm.wand(sm.canHellRun(**Settings.hellRunsTable['LowerNorfair']['Main']),
sm.canDestroyBombWalls(),
sm.haveItem('Morph'))
)
locationsDict["Missile (Wrecked Ship middle)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Missile (Wrecked Ship middle)"].Available = (
lambda sm: sm.canPassBombPassages()
)
locationsDict["Missile (Gravity Suit)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Missile (Gravity Suit)"].Available = (
lambda sm: sm.wand(sm.canPassBowling(),
sm.canPassBombPassages())
)
locationsDict["Missile (Wrecked Ship top)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Missile (Wrecked Ship top)"].Available = (
lambda sm: Bosses.bossDead(sm, 'Phantoon')
)
locationsDict["Super Missile (Wrecked Ship left)"].AccessFrom = {
'Wrecked Ship Main': lambda sm: SMBool(True)
}
locationsDict["Super Missile (Wrecked Ship left)"].Available = (
lambda sm: Bosses.bossDead(sm, 'Phantoon')
)
locationsDict["Missile (green Maridia shinespark)"].AccessFrom = {
'Main Street Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (green Maridia shinespark)"].Available = (
lambda sm: sm.wand(sm.haveItem('Gravity'),
sm.haveItem('SpeedBooster'),
sm.wor(sm.wand(sm.traverse('MainStreetBottomRight'), # run from room on the right
sm.wor(RomPatches.has(sm.player, RomPatches.AreaRandoGatesOther),
sm.haveItem('Super')),
sm.itemCountOk('ETank', 1)), # etank for the spark since sparking from low ground
sm.canSimpleShortCharge())) # run from above
)
locationsDict["Super Missile (green Maridia)"].AccessFrom = {
'Main Street Bottom': lambda sm: sm.canDoOuterMaridia()
}
locationsDict["Super Missile (green Maridia)"].Available = (
lambda sm: sm.haveItem('Morph')
)
locationsDict["Missile (green Maridia tatori)"].AccessFrom = {
'Main Street Bottom': lambda sm: sm.wand(sm.wor(sm.traverse('FishTankRight'),
RomPatches.has(sm.player, RomPatches.MamaTurtleBlueDoor)),
sm.canDoOuterMaridia()),
'Mama Turtle': lambda sm: SMBool(True)
}
locationsDict["Missile (green Maridia tatori)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Super Missile (yellow Maridia)"].AccessFrom = {
'Watering Hole Bottom': lambda sm: SMBool(True)
}
locationsDict["Super Missile (yellow Maridia)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (yellow Maridia super missile)"].AccessFrom = {
'Watering Hole Bottom': lambda sm: SMBool(True)
}
locationsDict["Missile (yellow Maridia super missile)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (yellow Maridia false wall)"].AccessFrom = {
'Beach': lambda sm: SMBool(True)
}
locationsDict["Missile (yellow Maridia false wall)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (left Maridia sand pit room)"].AccessFrom = {
'Left Sandpit': lambda sm: sm.canClimbWestSandHole()
}
locationsDict["Missile (left Maridia sand pit room)"].Available = (
lambda sm: sm.canAccessItemsInWestSandHole()
)
locationsDict["Missile (right Maridia sand pit room)"].AccessFrom = {
'Right Sandpit': lambda sm: SMBool(True)
}
locationsDict["Missile (right Maridia sand pit room)"].Available = (
lambda sm: sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.haveItem('HiJump'),
sm.knowsGravLessLevel3()))
)
locationsDict["Power Bomb (right Maridia sand pit room)"].AccessFrom = {
'Right Sandpit': lambda sm: sm.haveItem('Morph')
}
locationsDict["Power Bomb (right Maridia sand pit room)"].Available = (
lambda sm: sm.wor(sm.haveItem('Gravity'),
sm.wand(sm.knowsGravLessLevel3(),
sm.haveItem('HiJump'),
sm.canSpringBallJump())) # https://www.youtube.com/watch?v=7LYYxphRRT0
)
locationsDict["Missile (pink Maridia)"].AccessFrom = {
'Aqueduct': lambda sm: SMBool(True)
}
locationsDict["Missile (pink Maridia)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Super Missile (pink Maridia)"].AccessFrom = {
'Aqueduct': lambda sm: SMBool(True)
}
locationsDict["Super Missile (pink Maridia)"].Available = (
lambda sm: SMBool(True)
)
locationsDict["Missile (Draygon)"].AccessFrom = {
'Precious Room Top': lambda sm: SMBool(True)
}
locationsDict["Missile (Draygon)"].Available = (
lambda sm: SMBool(True)
)
# TODO::use the dict in solver/randomizer
# create the list that the solver/randomizer use
locations = [loc for loc in locationsDict.values()]
class LocationsHelper:
# used by FillerRandom to know how many front fill steps it must perform
def getRandomFillHelp(startLocation):
helpByAp = {
"Firefleas Top": 3,
"Aqueduct": 1,
"Mama Turtle": 1,
"Watering Hole": 2,
"Etecoons Supers": 2,
"Gauntlet Top":1,
"Bubble Mountain":1
}
return helpByAp[startLocation] if startLocation in helpByAp else 0
# for a given start AP, gives:
# - locations that can be used as majors/chozo in the start area
# - locations to preserve in the split
# - number of necessary majors locations to add in the start area,
# - number of necessary chozo locations to add in the start area
# locs are taken in the first n in the list
def getStartMajors(startLocation):
majLocsByAp = {
'Gauntlet Top': ([
"Missile (Crateria gauntlet right)",
"Missile (Crateria gauntlet left)"
], ["Energy Tank, Terminator"], 1, 2),
'Green Brinstar Elevator': ([
"Missile (green Brinstar below super missile)"
], ["Reserve Tank, Brinstar"], 1, 1),
'Big Pink': ([
"Missile (pink Brinstar top)",
"Missile (pink Brinstar bottom)"
], ["Charge Beam"], 1, 2),
'Etecoons Supers': ([
"Energy Tank, Etecoons",
"Super Missile (green Brinstar bottom)",
], ["Energy Tank, Etecoons"], 1, 2),
'Firefleas Top': ([
"Power Bomb (lower Norfair above fire flea room)",
"Energy Tank, Firefleas",
"Missile (lower Norfair near Wave Beam)",
"Missile (lower Norfair above fire flea room)"
], ["Energy Tank, Firefleas"], 3, 4),
'Business Center': ([
"Energy Tank (Hi-Jump Boots)",
], ["Hi-Jump Boots"], 1, 1),
'Bubble Mountain': ([
"Missile (bubble Norfair)"
], ["Speed Booster", "Wave Beam"], 1, 1),
'Mama Turtle': ([
"Energy Tank, Mama turtle",
"Missile (green Maridia tatori)",
"Super Missile (green Maridia)"
], ["Energy Tank, Mama turtle"], 2, 3),
'Watering Hole': ([
"Missile (yellow Maridia super missile)",
"Super Missile (yellow Maridia)",
"Missile (yellow Maridia false wall)"
], [], 2, 3),
'Aqueduct': ([
"Missile (pink Maridia)",
"Super Missile (pink Maridia)",
"Missile (right Maridia sand pit room)"
], ["Reserve Tank, Maridia"], 2, 3)
}
return majLocsByAp[startLocation] if startLocation in majLocsByAp else ([],[],0,0)