def canPassThreeMuskateers(self): sm = self.smbm destroy = 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')))) if destroy.bool == True: return destroy # if no adapted beams or screw attack, check if we can go both ways # (no easy refill around) with supers and/or health # - super only? ki = 1800.0 sup = 300.0 nbKi = 6.0 if sm.itemCount('Super') * 5 * sup >= nbKi * ki: return SMBool(True, 0, items=['Super']) # - or with taking damage as well? dmgKi = 200.0 / sm.getDmgReduction(False) if (sm.itemCount('Super') * 5 * sup) / ki + ( sm.energyReserveCount() * 100 - 2) / dmgKi >= nbKi: return sm.wand( sm.heatProof(), SMBool(True, 0, items=[ 'Super', 'ETank' ])) # require heat proof as long as taking damage is necessary return SMBool(False, 0)
def enoughStuffGT(self): (ammoMargin, secs) = self.canInflictEnoughDamages(3000, ignoreMissiles=True) # requires 10 supers or charge for the fight if ammoMargin == 0: return SMBool(False) else: # TODO add energy check return SMBool(True, easy)
def itemCountOk(self, item, count, difficulty=0): if self.itemCount(item) >= count: if item in ['ETank', 'Reserve']: item = '{}-{}'.format(count, item) return SMBool(True, difficulty, items = [item]) else: return SMBool(False)
def enoughStuffCroc(self): # say croc has ~5000 energy, and ignore its useless drops (ammoMargin, secs) = self.canInflictEnoughDamages(5000, givesDrops=False) if ammoMargin == 0: return SMBool(False) else: return SMBool(True, easy)
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 enoughStuffsPhantoon(self): sm = self.smbm (ammoMargin, secs) = self.canInflictEnoughDamages(2500, doubleSuper=True) if ammoMargin == 0: return SMBool(False) # print('PHANTOON', ammoMargin, secs) difficulty = self.computeBossDifficulty(ammoMargin, secs, Settings.bossesDifficulty['Phantoon']) if difficulty < 0: return SMBool(False) hasCharge = sm.canFireChargedShots() hasScrew = sm.haveItem('ScrewAttack') if hasScrew: difficulty /= Settings.algoSettings['phantoonFlamesAvoidBonusScrew'] elif hasCharge: difficulty /= Settings.algoSettings['phantoonFlamesAvoidBonusCharge'] elif not hasCharge and sm.itemCount('Missile') <= 2: # few missiles is harder difficulty *= Settings.algoSettings['phantoonLowMissileMalus'] difficulty = self.adjustHealthDropDiff(difficulty) fight = SMBool(True, difficulty) return sm.wor(fight, sm.wand(sm.knowsMicrowavePhantoon(), sm.haveItem('Plasma'), sm.canFireChargedShots(), sm.haveItem('XRayScope')))
def canFly(self): sm = self.smbm if sm.haveItem('SpaceJump') == True: return SMBool(True, easy, items=['SpaceJump']) elif sm.canInfiniteBombJump() == True: return sm.knowsInfiniteBombJump() else: return SMBool(False)
def enoughStuffBotwoon(self): # say botwoon has 5000 energy : it is actually 3000 but account for missed shots (ammoMargin, secs) = self.canInflictEnoughDamages(5000, givesDrops=False) if ammoMargin == 0: return SMBool(False) else: return SMBool(True, easy)
def enoughStuffBotwoon(self): # say botwoon has 4000 energy : it is actually 3000 but account for missed shots # 4000 to allow for low% botwoon without charge beam (10 - 10 | missiles - supers) # there is a setup to "never" miss a shot by only shooting him when he exits through the top left hole (ammoMargin, secs) = self.canInflictEnoughDamages(4000, givesDrops=False) if ammoMargin == 0: return SMBool(False) else: return SMBool(True, easy)
def canFlyDiagonally(self): sm = self.smbm if sm.haveItem('SpaceJump') == True: return SMBool(True, easy, items=['SpaceJump']) elif sm.wand(sm.haveItem('Morph'), sm.haveItem('Bomb'), sm.knowsDiagonalBombJump()) == True: return sm.knowsDiagonalBombJump() else: return SMBool(False)
def getPathDifficulty(self, path, availAps): pdiff = SMBool(True, 0) for ap in path: diff = availAps[ap]['difficulty'] pdiff = SMBool(True, difficulty=max(pdiff.difficulty, diff.difficulty), knows=list(set(pdiff.knows + diff.knows)), items=pdiff.items + diff.items) return pdiff
def removeItem(self, item): # randomizer removed an item (or the item was added to test a post available) if self.isCountItem(item): count = getattr(self, item + 'Count') - 1 setattr(self, item + 'Count', count) if count == 0: setattr(self, item, SMBool(False)) else: setattr(self, item, SMBool(False)) Cache.reset()
def enoughStuffsRidley(self): (ammoMargin, secs) = self.canInflictEnoughDamages(18000, doubleSuper=True, power=True, givesDrops=False) if ammoMargin == 0: return SMBool(False) # print('RIDLEY', ammoMargin, secs) diff = self.computeBossDifficulty(ammoMargin, secs, Settings.bossesDifficulty['Ridley']) if diff < 0: return SMBool(False) else: return SMBool(True, diff)
def wor2(self, a, b): if a.bool is True and b.bool is True: if a.difficulty <= b.difficulty: return SMBool(True, a.difficulty, a.knows, a.items) else: return SMBool(True, b.difficulty, b.knows, b.items) elif a.bool is True: return SMBool(True, a.difficulty, a.knows, a.items) elif b.bool is True: return SMBool(True, b.difficulty, b.knows, b.items) else: return SMBool(False)
def enoughStuffsKraid(self): sm = self.smbm (ammoMargin, secs, ammoItems) = self.canInflictEnoughDamages(1000) if ammoMargin == 0: return SMBool(False) #print('KRAID True ', ammoMargin, secs) (diff, defenseItems) = self.computeBossDifficulty(ammoMargin, secs, Settings.bossesDifficulty['Kraid']) if diff < 0: return SMBool(False) return SMBool(True, diff, items=ammoItems+defenseItems)
def energyReserveCountOk(self, count, difficulty=0): if self.energyReserveCount() >= count: nEtank = self.itemCount('ETank') if nEtank > count: nEtank = int(count) items = '{}-ETank'.format(nEtank) nReserve = self.itemCount('Reserve') if nEtank < count: nReserve = int(count) - nEtank items += ' - {}-Reserve'.format(nReserve) else: nReserve = 0 return SMBool(True, difficulty, items = [items]) else: return SMBool(False)
def removeItem(self, item): # randomizer removed an item (or the item was added to test a post available) if self.isCountItem(item): count = getattr(self, item + 'Count') - 1 setattr(self, item + 'Count', count) if count == 0: setattr(self, item, SMBool(False)) else: dup = 'dup_' + item if getattr(self, dup, None) is None: setattr(self, item, SMBool(False)) else: delattr(self, dup) Cache.removeItem(item)
def __init__(self, name, graphArea, transitions, traverse=lambda sm: SMBool(True), exitInfo=None, entryInfo=None, roomInfo=None, shortName=None, internal=False, boss=False): self.Name = name self.GraphArea = graphArea self.ExitInfo = exitInfo self.EntryInfo = entryInfo self.RoomInfo = roomInfo self.Internal = internal self.Boss = boss self.transitions = transitions self.traverse = traverse if shortName is not None: self.ShortName = shortName else: self.ShortName = str(self) self.distance = 0 # inter-area connection self.ConnectedTo = None
def wand(self, *args): if False in args: return self.smboolFalse else: return SMBool(True, sum([smb.difficulty for smb in args]), [know for smb in args for know in smb.knows], [item for smb in args for item in smb.items])
def cleanLocsAfterSolver(self): # restricted locs can have their difficulty set, which can cause them to be reported in the # post randomization warning message about locs with diff > max diff. for il in self.itemLocations: loc = il['Location'] if loc.get('restricted') == True and loc.get('difficulty', False) == True: loc['difficulty'] = SMBool(False)
def itemCountOk(self, item, count, difficulty=0): if self.itemCount(item) >= count: if item in ['ETank', 'Reserve']: item = str(count) + '-' + item return SMBool(True, difficulty, items=[item]) else: return self.smboolFalse
def addItem(self, item): # a new item is available setattr(self, item, SMBool(True, items=[item])) if self.isCountItem(item): setattr(self, item + 'Count', getattr(self, item + 'Count') + 1) Cache.reset()
def enoughStuffsKraid(self): sm = self.smbm (ammoMargin, secs) = self.canInflictEnoughDamages(1000) if ammoMargin == 0: return SMBool(False) #print('KRAID True ', ammoMargin, secs) diff = self.computeBossDifficulty(ammoMargin, secs, Settings.bossesDifficulty['Kraid']) if diff < 0: return SMBool(False) # need missile or super to open the eye door if sm.wor(sm.haveItem('Missile'), sm.haveItem('Super')) == False: return SMBool(False) else: return SMBool(True, diff)
def __init__(self): self.smboolFalse = SMBool(False) Cache.reset() self.helpers = HelpersGraph(self) self.createFacadeFunctions() self.createKnowsFunctions() self.resetItems()
def load(self): # update the parameters in the parameters classes: Knows, Settings # Knows for param in self.params['Knows']: if isKnows(param) and hasattr(Knows, param): setattr(Knows, param, SMBool(self.params['Knows'][param][0], self.params['Knows'][param][1], ['{}'.format(param)])) # Settings ## hard rooms for hardRoom in ['X-Ray', 'Gauntlet']: if hardRoom in self.params['Settings']: Settings.hardRooms[hardRoom] = Settings.hardRoomsPresets[hardRoom][self.params['Settings'][hardRoom]] ## bosses for boss in ['Kraid', 'Phantoon', 'Draygon', 'Ridley', 'MotherBrain']: if boss in self.params['Settings']: Settings.bossesDifficulty[boss] = Settings.bossesDifficultyPresets[boss][self.params['Settings'][boss]] ## hellruns for hellRun in ['Ice', 'MainUpperNorfair', 'LowerNorfair']: if hellRun in self.params['Settings']: Settings.hellRuns[hellRun] = Settings.hellRunPresets[hellRun][self.params['Settings'][hellRun]] # Controller for button in self.params['Controller']: if isButton(button): setattr(Controller, button, self.params['Controller'][button])
def getNewAvailNodes(self, availNodes, nodesToCheck, smbm, maxDiff, item=None): newAvailNodes = {} # with python >= 3.6 the insertion order in a dict is keeps when looping on the keys, # so we no longer have to sort them. for src in nodesToCheck: for dstName in src.transitions: dst = self.accessPoints[dstName] if dst in availNodes or dst in newAvailNodes: continue if smbm is not None: if self._useCache == True and (src, dst, item) in self.apCache: diff = self.apCache[(src, dst, item)] else: tFunc = src.transitions[dstName] diff = smbm.eval(tFunc) if self._useCache == True: self.apCache[(src, dst, item)] = diff else: diff = SMBool(True) if diff.bool and diff.difficulty <= maxDiff: if src.GraphArea == dst.GraphArea: dst.distance = src.distance + 0.01 else: dst.distance = src.distance + 1 newAvailNodes[dst] = {'difficulty': diff, 'from': src} #self.log.debug("{} -> {}: {}".format(src.Name, dstName, diff)) return newAvailNodes
def __init__(self, name, graphArea, transitions, traverse=lambda sm: SMBool(True), exitInfo=None, entryInfo=None, roomInfo=None, internal=False, boss=False, escape=False, start=None, dotOrientation='w'): self.Name = name self.GraphArea = graphArea self.ExitInfo = exitInfo self.EntryInfo = entryInfo self.RoomInfo = roomInfo self.Internal = internal self.Boss = boss self.Escape = escape self.Start = start self.DotOrientation = dotOrientation self.intraTransitions = self.sortTransitions(transitions) self.transitions = copy.copy(self.intraTransitions) self.traverse = traverse self.distance = 0 # inter-area connection self.ConnectedTo = None
def computeLocDiff(self, tdiff, diff, pdiff): allDiff = SMBool(diff.bool, difficulty=max(tdiff.difficulty, diff.difficulty, pdiff.difficulty), knows=list(set(tdiff.knows + diff.knows + pdiff.knows)), items=tdiff.items + diff.items + pdiff.items) return (allDiff, None)
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())
def enoughStuffsDraygon(self): sm = self.smbm (ammoMargin, secs) = self.canInflictEnoughDamages(6000) # print('DRAY', ammoMargin, secs) if ammoMargin > 0: diff = self.computeBossDifficulty(ammoMargin, secs, Settings.bossesDifficulty['Draygon']) if diff < 0: fight = SMBool(False) else: fight = SMBool(True, diff) if sm.haveItem('Gravity') == False: fight.difficulty *= Settings.algoSettings['draygonNoGravityMalus'] fight.difficulty = self.adjustHealthDropDiff(fight.difficulty) else: fight = SMBool(False) return sm.wor(fight, sm.wand(sm.knowsDraygonGrappleKill(), sm.haveItem('Grapple')), sm.wand(sm.knowsMicrowaveDraygon(), sm.haveItem('Plasma'), sm.canFireChargedShots(), sm.haveItem('XRayScope')), sm.wand(sm.haveItem('Gravity'), sm.knowsDraygonSparkKill(), sm.haveItem('SpeedBooster')))