def checkPool(self, forbidden=None): self.log.debug("checkPool. forbidden=" + str(forbidden) + ", self.forbiddenItems=" + str(self.forbiddenItems)) if not self.graphSettings.isMinimizer( ) and not self.settings.isPlandoRando() and len( self.allLocations) > len(self.locations): # invalid graph with looped areas self.log.debug( "checkPool: not all areas are connected, but minimizer param is off / not a plando rando" ) return False ret = True if forbidden is not None: pool = self.getItemPool(forbidden) else: pool = self.getItemPool() # get restricted locs totalAvailLocs = [] comeBack = {} try: container = ItemLocContainer(self.sm, pool, self.locations) except AssertionError as e: # invalid graph altogether self.log.debug( "checkPool: AssertionError when creating ItemLocContainer: {}". format(e)) return False # restrict item pool in chozo: game should be finishable with chozo items only contPool = [] if self.restrictions.isChozo(): container.restrictItemPool(isChozoItem) missile = container.getNextItemInPool('Missile') if missile is not None: # add missile (if zeb skip not known) contPool.append(missile) contPool += [item for item in pool if item in container.itemPool] # give us everything and beat every boss to see what we can access self.disableBossChecks() self.sm.resetItems() self.sm.addItems([item.Type for item in contPool]) # will add bosses as well poolDict = container.getPoolDict() self.log.debug('pool={}'.format( sorted([(t, len(poolDict[t])) for t in poolDict]))) locs = self.services.currentLocations(self.startAP, container, post=True) self.areaGraph.useCache(True) for loc in locs: ap = loc.accessPoint if ap not in comeBack: # we chose Golden Four because it is always there. # Start APs might not have comeback transitions # possible start AP issues are handled in checkStart comeBack[ap] = self.areaGraph.canAccess( self.sm, ap, 'Golden Four', self.settings.maxDiff) if comeBack[ap]: totalAvailLocs.append(loc) self.areaGraph.useCache(False) self.lastRestricted = [ loc for loc in self.locations if loc not in totalAvailLocs ] self.log.debug("restricted=" + str([loc.Name for loc in self.lastRestricted])) # check if all inter-area APs can reach each other interAPs = [ ap for ap in self.areaGraph.getAccessibleAccessPoints(self.startAP) if not ap.isInternal() and not ap.isLoop() ] for startAp in interAPs: availAccessPoints = self.areaGraph.getAvailableAccessPoints( startAp, self.sm, self.settings.maxDiff) for ap in interAPs: if not ap in availAccessPoints: self.log.debug( "checkPool: ap {} non accessible from {}".format( ap.Name, startAp.Name)) ret = False if not ret: self.log.debug("checkPool. inter-area APs check failed") # cleanup self.sm.resetItems() self.restoreBossChecks() # check if we can reach/beat all bosses if ret: for loc in self.lastRestricted: if loc.Name in self.bossesLocs: ret = False self.log.debug("unavail Boss: " + loc.Name) if ret: # revive bosses self.sm.addItems([ item.Type for item in contPool if item.Category != 'Boss' ]) maxDiff = self.settings.maxDiff # see if phantoon doesn't block himself, and if we can reach draygon if she's alive ret = self.areaGraph.canAccess(self.sm, self.startAP, 'PhantoonRoomIn', maxDiff)\ and self.areaGraph.canAccess(self.sm, self.startAP, 'DraygonRoomIn', maxDiff) if ret: # see if we can beat bosses with this equipment (infinity as max diff for a "onlyBossesLeft" type check beatableBosses = sorted([ loc.Name for loc in self.services.currentLocations( self.startAP, container, diff=infinity) if loc.isBoss() ]) self.log.debug("checkPool. beatableBosses=" + str(beatableBosses)) ret = beatableBosses == Bosses.Golden4() if ret: # check that we can then kill mother brain self.sm.addItems(Bosses.Golden4()) beatableMotherBrain = [ loc.Name for loc in self.services.currentLocations( self.startAP, container, diff=infinity) if loc.Name == 'Mother Brain' ] ret = len(beatableMotherBrain) > 0 self.log.debug( "checkPool. beatable Mother Brain={}".format(ret)) else: self.log.debug('checkPool. locked by Phantoon or Draygon') self.log.debug('checkPool. boss access sanity check: ' + str(ret)) if self.restrictions.isChozo(): # last check for chozo locations: don't put more restricted chozo locations than removed chozo items # (we cannot rely on removing ammo/energy in fillRestrictedLocations since it is already the bare minimum in chozo pool) # FIXME something to do there for ultra sparse, it gives us up to 3 more spots for nothing items restrictedLocs = self.restrictedLocs + [ loc for loc in self.lastRestricted if loc not in self.restrictedLocs ] nRestrictedChozo = sum(1 for loc in restrictedLocs if loc.isChozo()) nNothingChozo = sum( 1 for item in pool if 'Chozo' in item.Class and item.Category == 'Nothing') ret &= nRestrictedChozo <= nNothingChozo self.log.debug('checkPool. nRestrictedChozo=' + str(nRestrictedChozo) + ', nNothingChozo=' + str(nNothingChozo)) self.log.debug('checkPool. result: ' + str(ret)) return ret
def checkPool(self, forbidden=None): self.log.debug("checkPool. forbidden=" + str(forbidden) + ", self.forbiddenItems=" + str(self.forbiddenItems)) if not self.graphSettings.isMinimizer() and not self.settings.isPlandoRando() and len(self.allLocations) > len(self.locations): # invalid graph with looped areas self.log.debug("checkPool: not all areas are connected, but minimizer param is off / not a plando rando") return False ret = True if forbidden is not None: pool = self.getItemPool(forbidden) else: pool = self.getItemPool() # get restricted locs totalAvailLocs = [] comeBack = {} try: container = ItemLocContainer(self.sm, pool, self.locations) except AssertionError as e: # invalid graph altogether self.log.debug("checkPool: AssertionError when creating ItemLocContainer: {}".format(e)) return False # restrict item pool in chozo: game should be finishable with chozo items only contPool = [] if self.restrictions.isChozo(): container.restrictItemPool(isChozoItem) missile = container.getNextItemInPool('Missile') if missile is not None: # add missile (if zeb skip not known) contPool.append(missile) contPool += [item for item in pool if item in container.itemPool] # give us everything and beat every boss to see what we can access self.disableBossChecks() self.sm.resetItems() self.sm.addItems([item.Type for item in contPool]) # will add bosses as well self.log.debug('pool={}'.format(getItemListStr(container.itemPool))) locs = self.services.currentLocations(self.startAP, container, post=True) self.areaGraph.useCache(True) for loc in locs: ap = loc.accessPoint if ap not in comeBack: # we chose Golden Four because it is always there. # Start APs might not have comeback transitions # possible start AP issues are handled in checkStart comeBack[ap] = self.areaGraph.canAccess(self.sm, ap, 'Golden Four', self.settings.maxDiff) if comeBack[ap]: totalAvailLocs.append(loc) self.areaGraph.useCache(False) self.lastRestricted = [loc for loc in self.locations if loc not in totalAvailLocs] self.log.debug("restricted=" + str([loc.Name for loc in self.lastRestricted])) # check if objectives are compatible with accessible APs startAP = self.areaGraph.accessPoints[self.startAP] availAPs = [ap.Name for ap in self.areaGraph.getAvailableAccessPoints(startAP, self.sm, self.settings.maxDiff)] self.log.debug("availAPs="+str(availAPs)) for goal in Objectives.activeGoals: n, aps = goal.escapeAccessPoints if len(aps) == 0: continue escAPs = [ap for ap in aps if ap in availAPs] self.log.debug("escAPs="+str(escAPs)) if len(escAPs) < n: self.log.debug("checkPool. goal '"+goal.name+"' impossible to complete due to area layout") ret = False continue for ap in escAPs: if not self.areaGraph.canAccess(self.sm, ap, "Golden Four", self.settings.maxDiff): self.log.debug("checkPool. goal '"+goal.name+"' impossible to complete due to area layout") ret = False break # check if all inter-area APs can reach each other if ret: interAPs = [ap for ap in self.areaGraph.getAccessibleAccessPoints(self.startAP) if not ap.isInternal() and not ap.isLoop()] for startAp in interAPs: availAccessPoints = self.areaGraph.getAvailableAccessPoints(startAp, self.sm, self.settings.maxDiff) for ap in interAPs: if not ap in availAccessPoints: self.log.debug("checkPool: ap {} non accessible from {}".format(ap.Name, startAp.Name)) ret = False if not ret: self.log.debug("checkPool. inter-area APs check failed") # cleanup self.sm.resetItems() self.restoreBossChecks() # check if we can reach/beat all bosses if ret: # always add G4 to mandatory bosses, even if not required by objectives mandatoryBosses = set(Objectives.getMandatoryBosses() + Bosses.Golden4()) for loc in self.lastRestricted: if loc.Name in self.bossesLocs: ret = False self.log.debug("unavail Boss: " + loc.Name) if ret: # revive bosses self.sm.addItems([item.Type for item in contPool if item.Category != 'Boss']) maxDiff = self.settings.maxDiff # see if phantoon doesn't block himself, and if we can reach draygon if she's alive ret = self.areaGraph.canAccess(self.sm, self.startAP, 'PhantoonRoomIn', maxDiff)\ and self.areaGraph.canAccess(self.sm, self.startAP, 'DraygonRoomIn', maxDiff) if ret: # see if we can beat bosses with this equipment (infinity as max diff for a "onlyBossesLeft" type check beatableBosses = sorted([loc.BossItemType for loc in self.services.currentLocations(self.startAP, container, diff=infinity) if loc.isBoss()]) self.log.debug("checkPool. beatableBosses="+str(beatableBosses)) self.log.debug("checkPool. mandatoryBosses: {}".format(mandatoryBosses)) ret = mandatoryBosses.issubset(set(beatableBosses)) and Objectives.checkLimitObjectives(beatableBosses) if ret: # check that we can then kill mother brain self.sm.addItems(Bosses.Golden4() + Bosses.miniBosses()) beatableMotherBrain = [loc.Name for loc in self.services.currentLocations(self.startAP, container, diff=infinity) if loc.Name == 'Mother Brain'] ret = len(beatableMotherBrain) > 0 self.log.debug("checkPool. beatable Mother Brain={}".format(ret)) else: self.log.debug('checkPool. locked by Phantoon or Draygon') self.log.debug('checkPool. boss access sanity check: '+str(ret)) if self.restrictions.isChozo() or self.restrictions.isScavenger(): # in chozo or scavenger, we cannot put other items than NoEnergy in the restricted locations, # we would be forced to put majors in there, which can make seed generation fail: # don't put more restricted major locations than removed major items # FIXME something to do there for chozo/ultra sparse, it gives us up to 3 more spots for nothing items restrictedLocs = self.restrictedLocs + [loc for loc in self.lastRestricted if loc not in self.restrictedLocs] nRestrictedMajor = sum(1 for loc in restrictedLocs if self.restrictions.isLocMajor(loc)) nNothingMajor = sum(1 for item in pool if self.restrictions.isItemMajor(item) and item.Category == 'Nothing') ret &= nRestrictedMajor <= nNothingMajor self.log.debug('checkPool. nRestrictedMajor='+str(nRestrictedMajor)+', nNothingMajor='+str(nNothingMajor)) self.log.debug('checkPool. result: '+str(ret)) return ret