mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			767 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			767 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 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)))
 | 
