mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Added Super Metroid support (#46)
Varia Randomizer based implementation LttPClient -> SNIClient
This commit is contained in:
766
worlds/sm/variaRandomizer/graph/vanilla/graph_helpers.py
Normal file
766
worlds/sm/variaRandomizer/graph/vanilla/graph_helpers.py
Normal 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)))
|
Reference in New Issue
Block a user