Пример #1
0
 def canPassCacatacAlley(self):
     sm = self.smbm
     return sm.wand(Bosses.bossDead(sm, 'Draygon'),
                    sm.wor(sm.haveItem('Gravity'),
                           sm.wand(sm.knowsGravLessLevel2(),
                                   sm.haveItem('HiJump'),
                                   sm.haveItem('SpaceJump'))))
 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")))
Пример #3
0
 def canPassBowling(self):
     sm = self.smbm
     return sm.wand(Bosses.bossDead(sm, 'Phantoon'),
                    sm.wor(sm.heatProof(),
                           sm.energyReserveCountOk(1),
                           sm.haveItem("SpaceJump"),
                           sm.haveItem("Grapple")))
 def canPassCacatacAlley(self):
     sm = self.smbm
     return sm.wand(Bosses.bossDead(sm, 'Draygon'),
                    # cacatac alley suitless: hijump + gravless level 1
                    # butterfly room suitless: hijump + ice + gravless level 2
                    sm.wor(sm.haveItem('Gravity'),
                           sm.wand(sm.haveItem('HiJump'),
                                   sm.haveItem('Ice'),
                                   sm.knowsGravLessLevel2())))
Пример #5
0
 def fullComebackCheck(self, container, ap, item, loc, comebackCheck):
     sm = container.sm
     tmpItems = []
     # draygon special case: there are two locations, and we can
     # place one item, but we might need both the item and the boss
     # dead to get out
     if loc.SolveArea == "Draygon Boss" and Bosses.bossDead(sm, 'Draygon').bool == False:
         # temporary kill draygon
         tmpItems.append('Draygon')
     sm.addItems(tmpItems)
     ret = self.locPostAvailable(sm, loc, item.Type if item is not None else None) and not self.isSoftlockPossible(container, ap, item, loc, comebackCheck)
     for tmp in tmpItems:
         sm.removeItem(tmp)
     return ret
Пример #6
0
                                                            sm.canSpringBallJump()))))))
)
locationsDict["Spazer"].AccessFrom = {
    'East Tunnel Right': lambda sm: SMBool(True)
}
locationsDict["Spazer"].Available = (
    lambda sm: sm.wand(sm.traverse('BelowSpazerTopRight'),
                       sm.wor(sm.canPassBombPassages(),
                              sm.wand(sm.haveItem('Morph'),
                                      RomPatches.has(RomPatches.SpazerShotBlock))))
)
locationsDict["Energy Tank, Kraid"].AccessFrom = {
    'Warehouse Zeela Room Left': lambda sm: SMBool(True)
}
locationsDict["Energy Tank, Kraid"].Available = (
    lambda sm: Bosses.bossDead(sm, 'Kraid')
)
locationsDict["Kraid"].AccessFrom = {
    'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Kraid"].Available = (
    lambda sm: sm.enoughStuffsKraid()
)
locationsDict["Varia Suit"].AccessFrom = {
    'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Varia Suit"].Available = (
    lambda sm: Bosses.bossDead(sm, 'Kraid')
)
locationsDict["Ice Beam"].AccessFrom = {
    'Business Center': lambda sm: sm.traverse('BusinessCenterTopLeft')
locationsDict["Spazer"].Available = (
    lambda sm: sm.wand(sm.traverse('BelowSpazerTopRight'),
                       sm.wor(sm.canPassBombPassages(),
                              sm.wand(sm.haveItem('Morph'),
                                      RomPatches.has(RomPatches.SpazerShotBlock))))
)
locationsDict["Spazer"].PostAvailable = (
    # either with a bomb jump/springball to exit on top, or with bomb/pb to exit in the middle
    lambda sm: sm.wor(sm.canPassBombPassages(),
                      sm.wand(RomPatches.has(RomPatches.SpazerShotBlock), sm.canUseSpringBall())
)
locationsDict["Energy Tank, Kraid"].AccessFrom = {
    'Warehouse Zeela Room Left': lambda sm: sm.haveItem('Morph')
}
locationsDict["Energy Tank, Kraid"].Available = (
    lambda sm: Bosses.bossDead(sm, 'Kraid')
)
locationsDict["Kraid"].AccessFrom = {
    'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Kraid"].Available = (
    lambda sm: sm.enoughStuffsKraid()
)
locationsDict["Varia Suit"].AccessFrom = {
    'KraidRoomIn': lambda sm: SMBool(True)
}
locationsDict["Varia Suit"].Available = (
    lambda sm: Bosses.bossDead(sm, 'Kraid')
)
locationsDict["Ice Beam"].AccessFrom = {
    'Business Center': lambda sm: sm.traverse('BusinessCenterTopLeft')
Пример #8
0
def getMiniBossesEscapeAccessPoints(n):
    return (n, [Bosses.accessPoints[boss] for boss in Bosses.miniBosses()])


def getAreaEscapeAccessPoints(area):
    return (1,
            list({
                list(loc.AccessFrom.keys())[0]
                for loc in Logic.locations if loc.GraphArea == area
            }))


_goalsList = [
    Goal("kill kraid",
         "boss",
         lambda sm, ap: Bosses.bossDead(sm, 'Kraid'),
         "kraid_is_dead",
         escapeAccessPoints=getBossEscapeAccessPoint("Kraid"),
         exclusion={"list": ["kill all G4", "kill one G4"]},
         items=["Kraid"],
         text="{} kraid",
         category="Bosses"),
    Goal("kill phantoon",
         "boss",
         lambda sm, ap: Bosses.bossDead(sm, 'Phantoon'),
         "phantoon_is_dead",
         escapeAccessPoints=getBossEscapeAccessPoint("Phantoon"),
         exclusion={"list": ["kill all G4", "kill one G4"]},
         items=["Phantoon"],
         text="{} phantoon",
         category="Bosses"),
    def computeDifficulty(self):
        # loop on the available locations depending on the collected items.
        # before getting a new item, loop on all of them and get their difficulty,
        # the next collected item is the one with the smallest difficulty,
        # if equality between major and minor, take major first.

        # remove mother brain location (there items pickup conditions on top of going to mother brain location)
        mbLoc = self.getLoc('Mother Brain')
        self.locations.remove(mbLoc)

        if self.majorsSplit == 'Major':
            self.majorLocations = [
                loc for loc in self.locations if loc.isMajor() or loc.isBoss()
            ]
            self.minorLocations = [
                loc for loc in self.locations if loc.isMinor()
            ]
        elif self.majorsSplit == 'Chozo':
            self.majorLocations = [
                loc for loc in self.locations if loc.isChozo() or loc.isBoss()
            ]
            self.minorLocations = [
                loc for loc in self.locations
                if not loc.isChozo() and not loc.isBoss()
            ]
        else:
            # Full
            self.majorLocations = self.locations[:]  # copy
            self.minorLocations = self.majorLocations

        self.visitedLocations = []
        self.collectedItems = []

        self.log.debug(
            "{}: available major: {}, available minor: {}, visited: {}".format(
                Conf.itemsPickup, len(self.majorLocations),
                len(self.minorLocations), len(self.visitedLocations)))

        isEndPossible = False
        endDifficulty = mania
        diffThreshold = self.getDiffThreshold()
        while True:
            # actual while condition
            hasEnoughMinors = self.pickup.enoughMinors(self.smbm,
                                                       self.minorLocations)
            hasEnoughMajors = self.pickup.enoughMajors(self.smbm,
                                                       self.majorLocations)
            hasEnoughItems = hasEnoughMajors and hasEnoughMinors
            canEndGame = self.canEndGame()
            (isEndPossible, endDifficulty) = (canEndGame.bool,
                                              canEndGame.difficulty)
            if isEndPossible and hasEnoughItems and endDifficulty <= diffThreshold:
                if self.checkMB(mbLoc):
                    self.log.debug("END")
                    break
                else:
                    self.log.debug("canEnd but MB loc not accessible")

            # check time limit
            if self.runtimeLimit_s > 0:
                if time.process_time() - self.startTime > self.runtimeLimit_s:
                    self.log.debug("time limit exceeded ({})".format(
                        self.runtimeLimit_s))
                    return (-1, False)

            self.log.debug("Current AP/Area: {}/{}".format(
                self.lastAP, self.lastArea))

            # compute the difficulty of all the locations
            self.computeLocationsDifficulty(self.majorLocations)
            if self.majorsSplit != 'Full':
                self.computeLocationsDifficulty(self.minorLocations,
                                                phase="minor")

            # keep only the available locations
            majorsAvailable = [
                loc for loc in self.majorLocations
                if loc.difficulty is not None and loc.difficulty.bool == True
            ]
            minorsAvailable = [
                loc for loc in self.minorLocations
                if loc.difficulty is not None and loc.difficulty.bool == True
            ]

            if self.majorsSplit == 'Full':
                locs = majorsAvailable
            else:
                locs = majorsAvailable + minorsAvailable

            self.nbAvailLocs.append(len(locs))

            # check if we're stuck
            if len(majorsAvailable) == 0 and len(minorsAvailable) == 0:
                if not isEndPossible:
                    self.log.debug("STUCK MAJORS and MINORS")
                    if self.comeBack.rewind(len(self.collectedItems)) == True:
                        continue
                    else:
                        # we're really stucked
                        self.log.debug("STUCK CAN'T REWIND")
                        break
                else:
                    self.log.debug("HARD END 2")
                    self.checkMB(mbLoc)
                    break

            # handle no comeback locations
            rewindRequired = self.comeBack.handleNoComeBack(
                locs, len(self.collectedItems))
            if rewindRequired == True:
                if self.comeBack.rewind(len(self.collectedItems)) == True:
                    continue
                else:
                    # we're really stucked
                    self.log.debug("STUCK CAN'T REWIND")
                    break

            # sort them on difficulty and proximity
            self.log.debug("getAvailableItemsList majors")
            majorsAvailable = self.getAvailableItemsList(
                majorsAvailable, diffThreshold)
            if self.majorsSplit == 'Full':
                minorsAvailable = majorsAvailable
            else:
                self.log.debug("getAvailableItemsList minors")
                minorsAvailable = self.getAvailableItemsList(
                    minorsAvailable, diffThreshold)

            # choose one to pick up
            self.nextDecision(majorsAvailable, minorsAvailable,
                              hasEnoughMinors, diffThreshold)

            self.comeBack.cleanNoComeBack(locs)

        # compute difficulty value
        (difficulty, itemsOk) = self.computeDifficultyValue()

        if self.log.getEffectiveLevel() == logging.DEBUG:
            self.log.debug("difficulty={}".format(difficulty))
            self.log.debug("itemsOk={}".format(itemsOk))
            self.log.debug(
                "{}: remaining major: {}, remaining minor: {}, visited: {}".
                format(Conf.itemsPickup, len(self.majorLocations),
                       len(self.minorLocations), len(self.visitedLocations)))

            self.log.debug("remaining majors:")
            for loc in self.majorLocations:
                self.log.debug("{} ({})".format(loc.Name, loc.itemName))

            self.log.debug("bosses: {}".format([
                (boss, Bosses.bossDead(self.smbm, boss))
                for boss in Bosses.Golden4()
            ]))

        return (difficulty, itemsOk)
Пример #10
0
    def computeDifficulty(self):
        # loop on the available locations depending on the collected items.
        # before getting a new item, loop on all of them and get their difficulty,
        # the next collected item is the one with the smallest difficulty,
        # if equality between major and minor, take major first.

        # remove mother brain location (there items pickup conditions on top of going to mother brain location)
        mbLoc = self.getLoc('Mother Brain')
        self.locations.remove(mbLoc)

        if self.majorsSplit == 'Major':
            self.majorLocations = [
                loc for loc in self.locations if loc.isMajor() or loc.isBoss()
            ]
            self.minorLocations = [
                loc for loc in self.locations if loc.isMinor()
            ]
        elif self.majorsSplit == 'Chozo':
            self.majorLocations = [
                loc for loc in self.locations if loc.isChozo() or loc.isBoss()
            ]
            self.minorLocations = [
                loc for loc in self.locations
                if not loc.isChozo() and not loc.isBoss()
            ]
        elif self.majorsSplit == 'Scavenger':
            self.majorLocations = [
                loc for loc in self.locations
                if loc.isScavenger() or loc.isBoss()
            ]
            self.minorLocations = [
                loc for loc in self.locations
                if not loc.isScavenger() and not loc.isBoss()
            ]
        else:
            # Full
            self.majorLocations = self.locations[:]  # copy
            self.minorLocations = self.majorLocations

        self.visitedLocations = []
        self.collectedItems = []

        self.log.debug(
            "{}: available major: {}, available minor: {}, visited: {}".format(
                Conf.itemsPickup, len(self.majorLocations),
                len(self.minorLocations), len(self.visitedLocations)))

        isEndPossible = False
        endDifficulty = mania
        diffThreshold = self.getDiffThreshold()
        self.motherBrainKilled = False
        self.motherBrainCouldBeKilled = False
        while True:
            # actual while condition
            hasEnoughMinors = self.pickup.enoughMinors(self.smbm,
                                                       self.minorLocations)
            hasEnoughMajors = self.pickup.enoughMajors(self.smbm,
                                                       self.majorLocations)
            hasEnoughItems = hasEnoughMajors and hasEnoughMinors
            canEndGame = self.canEndGame()
            (isEndPossible, endDifficulty) = (canEndGame.bool,
                                              canEndGame.difficulty)
            if isEndPossible and hasEnoughItems:
                if not self.objectives.tourianRequired:
                    if self.checkEscape():
                        self.log.debug(
                            "checkMB: disabled, can escape to gunship, END")
                        break
                    else:
                        self.log.debug(
                            "checkMB: disabled, can't escape to gunship")
                else:
                    if endDifficulty <= diffThreshold:
                        if self.checkMB(mbLoc):
                            self.log.debug(
                                "checkMB: all end game checks are ok, END")
                            break
                        else:
                            self.log.debug(
                                "checkMB: canEnd but MB loc not accessible")
                    else:
                        if not self.motherBrainCouldBeKilled:
                            self.motherBrainCouldBeKilled = self.checkMB(
                                mbLoc, justCheck=True)
                        self.log.debug(
                            "checkMB: end checks ok except MB difficulty, MB could be killed: {}"
                            .format(self.motherBrainCouldBeKilled))

            # check time limit
            if self.runtimeLimit_s > 0:
                if time.process_time() - self.startTime > self.runtimeLimit_s:
                    self.log.debug("time limit exceeded ({})".format(
                        self.runtimeLimit_s))
                    return (-1, False)

            self.log.debug("Current AP/Area: {}/{}".format(
                self.lastAP, self.lastArea))

            # compute the difficulty of all the locations
            self.computeLocationsDifficulty(self.majorLocations)
            if self.majorsSplit != 'Full':
                self.computeLocationsDifficulty(self.minorLocations,
                                                phase="minor")

            # keep only the available locations
            majorsAvailable = [
                loc for loc in self.majorLocations
                if loc.difficulty is not None and loc.difficulty.bool == True
            ]
            minorsAvailable = [
                loc for loc in self.minorLocations
                if loc.difficulty is not None and loc.difficulty.bool == True
            ]

            self.nbAvailLocs.append(
                len(self.getAllLocs(majorsAvailable, minorsAvailable)))

            # remove next scavenger locs before checking if we're stuck
            if self.majorsSplit == 'Scavenger':
                majorsAvailable = self.filterScavengerLocs(majorsAvailable)

            # check if we're stuck
            if len(majorsAvailable) == 0 and len(minorsAvailable) == 0:
                if not isEndPossible:
                    self.log.debug("STUCK MAJORS and MINORS")
                    if self.comeBack.rewind(len(self.collectedItems)) == True:
                        continue
                    else:
                        # we're really stucked
                        self.log.debug("STUCK CAN'T REWIND")
                        break
                else:
                    self.log.debug("HARD END 2")
                    if self.checkMB(mbLoc):
                        self.log.debug("all end game checks are ok, END")
                        break
                    else:
                        self.log.debug(
                            "We're stucked somewhere and can't reach mother brain"
                        )
                        # check if we were able to access MB and kill it.
                        # we do it before rollbacks to avoid endless rollbacks.
                        if self.motherBrainCouldBeKilled:
                            self.log.debug(
                                "we're stucked but we could have killed MB before"
                            )
                            # add MB loc for the spoiler log, remove its path as it's not the correct one
                            # from when the loc was accessible
                            mbLoc.path = [getAccessPoint('Golden Four')]
                            self.visitedLocations.append(mbLoc)
                            self.motherBrainKilled = True
                            break
                        else:
                            # we're really stucked, try to rollback
                            if self.comeBack.rewind(len(
                                    self.collectedItems)) == True:
                                continue
                            else:
                                self.log.debug(
                                    "We could end but we're STUCK CAN'T REWIND"
                                )
                                return (-1, False)

            # handle no comeback locations
            rewindRequired = self.comeBack.handleNoComeBack(
                self.getAllLocs(majorsAvailable, minorsAvailable),
                len(self.collectedItems))
            if rewindRequired == True:
                if self.comeBack.rewind(len(self.collectedItems)) == True:
                    continue
                else:
                    # we're really stucked
                    self.log.debug("STUCK CAN'T REWIND")
                    break

            # sort them on difficulty and proximity
            self.log.debug("getAvailableItemsList majors")
            majorsAvailable = self.getAvailableItemsList(
                majorsAvailable, diffThreshold)
            if self.majorsSplit == 'Full':
                minorsAvailable = majorsAvailable
            else:
                self.log.debug("getAvailableItemsList minors")
                minorsAvailable = self.getAvailableItemsList(
                    minorsAvailable, diffThreshold)

            # choose one to pick up
            self.nextDecision(majorsAvailable, minorsAvailable,
                              hasEnoughMinors, diffThreshold)

            self.comeBack.cleanNoComeBack(
                self.getAllLocs(self.majorLocations, self.minorLocations))

        # compute difficulty value
        (difficulty, itemsOk) = self.computeDifficultyValue()

        if self.log.getEffectiveLevel() == logging.DEBUG:
            self.log.debug("difficulty={}".format(difficulty))
            self.log.debug("itemsOk={}".format(itemsOk))
            self.log.debug(
                "{}: remaining major: {}, remaining minor: {}, visited: {}".
                format(Conf.itemsPickup, len(self.majorLocations),
                       len(self.minorLocations), len(self.visitedLocations)))

            self.log.debug("remaining majors:")
            for loc in self.majorLocations:
                self.log.debug("{} ({})".format(loc.Name, loc.itemName))

            self.log.debug("bosses: {}".format([
                (boss, Bosses.bossDead(self.smbm, boss))
                for boss in Bosses.Golden4()
            ]))

        return (difficulty, itemsOk)