Ejemplo n.º 1
0
 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))
Ejemplo n.º 2
0
    def loadTransitions(self, tourian):
        # return the transitions
        rooms = GraphUtils.getRooms()
        bossTransitions = {}
        areaTransitions = {}
        for accessPoint in Logic.accessPoints:
            if accessPoint.isInternal() == True:
                continue
            key = self.getTransition(accessPoint.ExitInfo['DoorPtr'])
            if key not in rooms:
                # can happen with race mode seeds
                continue
            destAP = rooms[key]
            if accessPoint.Boss == True or destAP.Boss == True:
                bossTransitions[accessPoint.Name] = destAP.Name
            else:
                areaTransitions[accessPoint.Name] = destAP.Name

        def removeBiTrans(transitions):
            # remove bidirectionnal transitions
            # can't del keys in a dict while iterating it
            transitionsCopy = copy.copy(transitions)
            for src in transitionsCopy:
                if src in transitions:
                    dest = transitions[src]
                    if dest in transitions:
                        if transitions[dest] == src:
                            del transitions[dest]

            return [(t, transitions[t]) for t in transitions]

        # get escape transition
        if tourian == 'Disabled':
            escapeSrcAP = getAccessPoint('Climb Bottom Left')
        else:
            escapeSrcAP = getAccessPoint('Tourian Escape Room 4 Top Right')
        key = self.getTransition(escapeSrcAP.ExitInfo['DoorPtr'])
        # may not be set in plandomizer
        if key in rooms:
            escapeDstAP = rooms[key]
            escapeTransition = [(escapeSrcAP.Name, escapeDstAP.Name)]
        else:
            escapeTransition = []

        areaTransitions = removeBiTrans(areaTransitions)
        bossTransitions = removeBiTrans(bossTransitions)

        return (areaTransitions, bossTransitions, escapeTransition, GraphUtils.hasMixedTransitions(areaTransitions, bossTransitions))
Ejemplo n.º 3
0
 def applyStartAP(self, apName, plms, doors):
     ap = getAccessPoint(apName)
     # if start loc is not Ceres or Landing Site, or the ceiling loc picked up before morph loc,
     # Zebes will be awake and morph loc item will disappear.
     # this PLM ensures the item will be here whenever zebes awakes
     plms.append('Morph_Zebes_Awake')
     (w0, w1) = getWord(ap.Start['spawn'])
     if 'doors' in ap.Start:
         doors += ap.Start['doors']
     doors.append(0x0)
     addr = 0x10F200
     patch = [w0, w1] + doors
     assert (addr +
             len(patch)) < 0x10F210, "Stopped before new_game overwrite"
     patchDict = {
         'StartAP': {
             addr: patch
         },
     }
     self.applyIPSPatch('StartAP', patchDict)
     # handle custom saves
     if 'save' in ap.Start:
         self.applyIPSPatch(ap.Start['save'])
         plms.append(ap.Start['save'])
     # handle optional rom patches
     if 'rom_patches' in ap.Start:
         for patch in ap.Start['rom_patches']:
             self.applyIPSPatch(patch)
Ejemplo n.º 4
0
 def applyStartAP(self, apName, plms, doors):
     ap = getAccessPoint(apName)
     if not GraphUtils.isStandardStart(apName):
         # not Ceres or Landing Site, so Zebes will be awake
         plms.append('Morph_Zebes_Awake')
     (w0, w1) = getWord(ap.Start['spawn'])
     if 'doors' in ap.Start:
         doors += ap.Start['doors']
     doors.append(0x0)
     addr = 0x10F200
     patch = [w0, w1] + doors
     assert (addr + len(patch)) < 0x10F210, "Stopped before new_game overwrite"
     patchDict = {
         'StartAP': {
             addr: patch
         },
     }
     self.applyIPSPatch('StartAP', patchDict)
     # handle custom saves
     if 'save' in ap.Start:
         self.applyIPSPatch(ap.Start['save'])
         plms.append(ap.Start['save'])
     # handle optional rom patches
     if 'rom_patches' in ap.Start:
         for patch in ap.Start['rom_patches']:
             self.applyIPSPatch(patch)
Ejemplo n.º 5
0
 def isBoss(self):
     romFile = self.getROM()
     phOut = getAccessPoint('PhantoonRoomOut')
     doorPtr = phOut.ExitInfo['DoorPtr']
     romFile.seek((0x10000 | doorPtr) + 10)
     asmPtr = romFile.readWord()
     return asmPtr != 0  # this is at 0 in vanilla
Ejemplo n.º 6
0
 def updateLocationsClass(self, split):
     if split != 'Full' and split != 'Scavenger':
         startAP = getAccessPoint(self.graphSettings.startAP)
         possibleMajLocs, preserveMajLocs, nMaj, nChozo = Logic.LocationsHelper.getStartMajors(
             startAP.Name)
         if split == 'Major':
             n = nMaj
         elif split == 'Chozo':
             n = nChozo
         GraphUtils.updateLocClassesStart(startAP.GraphArea, split,
                                          possibleMajLocs, preserveMajLocs,
                                          n)
Ejemplo n.º 7
0
 def checkStart(self):
     ap = getAccessPoint(self.startAP)
     if not self.graphSettings.areaRando or ap.Start is None or \
        (('needsPreRando' not in ap.Start or not ap.Start['needsPreRando']) and\
         ('areaMode' not in ap.Start or not ap.Start['areaMode'])):
         return True
     self.log.debug("********* PRE RANDO START")
     container = copy.copy(self.container)
     filler = FrontFiller(self.startAP, self.areaGraph, self.restrictions, container)
     condition = filler.createStepCountCondition(4)
     (isStuck, itemLocations, progItems) = filler.generateItems(condition)
     self.log.debug("********* PRE RANDO END")
     return not isStuck and len(self.services.currentLocations(filler.ap, filler.container)) > 0
Ejemplo n.º 8
0
    def __init__(self,
                 majorsSplit,
                 startLocation,
                 areaGraph,
                 locations,
                 vcr=None):
        self.interactive = False
        self.checkDuplicateMajor = False
        self.vcr = vcr
        # for compatibility with some common methods of the interactive solver
        self.mode = 'standard'

        self.log = utils.log.get('Solver')

        # default conf
        self.setConf(easy, 'all', [], False)

        self.firstLogFile = None

        self.extStatsFilename = None
        self.extStatsStep = None

        self.type = 'rando'
        self.output = Out.factory(self.type, self)
        self.outputFileName = None

        self.locations = locations

        self.smbm = SMBoolManager()

        # preset already loaded by rando
        self.presetFileName = None

        self.pickup = Pickup(Conf.itemsPickup)

        self.comeBack = ComeBack(self)

        # load ROM info, patches are already loaded by the rando. get the graph from the rando too
        self.majorsSplit = majorsSplit
        self.startLocation = startLocation
        self.startArea = getAccessPoint(startLocation).Start['solveArea']
        self.areaGraph = areaGraph

        self.objectives = Objectives()

        # store at each step how many locations are available
        self.nbAvailLocs = []

        # limit to a few seconds to avoid cases with a lot of rewinds which could last for minutes
        self.runtimeLimit_s = 5
        self.startTime = time.process_time()
Ejemplo n.º 9
0
    def getRawPatches(self):
        # for interactive solver
        result = {}
        for patchName in self.patches:
            value = self.romFile.readByte(self.patches[patchName]['address'])
            result[self.patches[patchName]['address']] = value

        # add boss detection bytes
        doorPtr = getAccessPoint('PhantoonRoomOut').ExitInfo['DoorPtr']
        doorPtr = (0x10000 | doorPtr) + 10

        result[doorPtr] = self.romFile.readByte(doorPtr)
        result[doorPtr+1] = self.romFile.readByte()

        return result
Ejemplo n.º 10
0
    def getDefaultPatches():
        # called by the isolver in seedless mode
        # activate only layout patch (the most common one) and blue bt/red tower blue doors
        ret = {}
        for patch in RomReader.patches:
            if patch in ['layout', 'startLS']:
                ret[RomReader.patches[patch]['address']] = RomReader.patches[patch]['value']
            else:
                ret[RomReader.patches[patch]['address']] = 0xFF

        # add phantoon door ptr used by boss rando detection
        doorPtr = getAccessPoint('PhantoonRoomOut').ExitInfo['DoorPtr']
        doorPtr = (0x10000 | doorPtr) + 10
        ret[doorPtr] = 0
        ret[doorPtr+1] = 0

        return ret
 def generateItem(self, comeback=ComebackCheckType.Undefined):
     comebackCheck = comeback if comeback != ComebackCheckType.Undefined else self.getComebackCheck()
     itemLocDict, possibleProg = self.services.getPossiblePlacements(self.ap, self.container, comebackCheck)
     if self.isEarlyGame() and possibleProg == True:
         # cheat a little bit if non-standard start: place early
         # progression away from crateria/blue brin if possible
         startAp = getAccessPoint(self.startAP)
         if startAp.GraphArea != "Crateria":
             newItemLocDict = {}
             for w, locs in itemLocDict.items():
                 filtered = [loc for loc in locs if loc.GraphArea != 'Crateria']
                 if len(filtered) > 0:
                     newItemLocDict[w] = filtered
             if len(newItemLocDict) > 0:
                 itemLocDict = newItemLocDict
     itemLoc = self.chooseItemLoc(itemLocDict, possibleProg)
     self.log.debug("generateItem. itemLoc="+"None" if itemLoc is None else getItemLocStr(itemLoc))
     return itemLoc
Ejemplo n.º 12
0
    def loadTransitions(self):
        # return the transitions
        rooms = GraphUtils.getRooms()
        bossTransitions = {}
        areaTransitions = {}
        for accessPoint in Logic.accessPoints:
            if accessPoint.isInternal() == True:
                continue
            key = self.getTransition(accessPoint.ExitInfo['DoorPtr'])

            destAP = rooms[key]
            if accessPoint.Boss == True or destAP.Boss == True:
                bossTransitions[accessPoint.Name] = destAP.Name
            else:
                areaTransitions[accessPoint.Name] = destAP.Name

        def removeBiTrans(transitions):
            # remove bidirectionnal transitions
            # can't del keys in a dict while iterating it
            transitionsCopy = copy.copy(transitions)
            for src in transitionsCopy:
                if src in transitions:
                    dest = transitions[src]
                    if dest in transitions:
                        if transitions[dest] == src:
                            del transitions[dest]

            return [(t, transitions[t]) for t in transitions]

        # get escape transition
        escapeSrcAP = getAccessPoint('Tourian Escape Room 4 Top Right')
        key = self.getTransition(escapeSrcAP.ExitInfo['DoorPtr'])
        escapeDstAP = rooms[key]
        escapeTransition = [(escapeSrcAP.Name, escapeDstAP.Name)]

        areaTransitions = removeBiTrans(areaTransitions)
        bossTransitions = removeBiTrans(bossTransitions)

        return (areaTransitions, bossTransitions, escapeTransition,
                GraphUtils.hasMixedTransitions(areaTransitions,
                                               bossTransitions))
Ejemplo n.º 13
0
 def lateMorphInit(self, ap, emptyContainer, services):
     assert self.isLateMorph()
     morph = emptyContainer.getNextItemInPool('Morph')
     assert morph is not None
     locs = services.possibleLocations(morph,
                                       ap,
                                       emptyContainer,
                                       bossesKilled=False)
     self.lateMorphLimit = len(locs)
     self.log.debug('lateMorphInit. {} locs: {}'.format(
         self.lateMorphLimit, getLocListStr(locs)))
     areas = {}
     for loc in locs:
         areas[loc.GraphArea] = areas.get(loc.GraphArea, 0) + 1
     self.log.debug('lateMorphLimit. areas: {}'.format(areas))
     if len(areas) > 1:
         self.lateMorphForbiddenArea = getAccessPoint(ap).GraphArea
         self.log.debug('lateMorphLimit. forbid start area: {}'.format(
             self.lateMorphForbiddenArea))
     else:
         self.lateMorphForbiddenArea = None
 def isVanillaCroc(self):
     crocRoom = getAccessPoint('Crocomire Room Top')
     return SMBool(crocRoom.ConnectedTo == 'Crocomire Speedway Bottom')
 def getDraygonConnection(self):
     return getAccessPoint('DraygonRoomOut').ConnectedTo
Ejemplo n.º 16
0
                     if apName in startLocationList
                 ]
                 optErrMsgs.append(
                     'Invalid start locations list with your settings.')
                 dumpErrorMsgs(args.output, optErrMsgs)
                 sys.exit(-1)
         args.startAP = random.choice(possibleStartAPs)
     elif args.startAP not in possibleStartAPs:
         optErrMsgs.append('Invalid start location: {}.  {}'.format(
             args.startAP, reasons[args.startAP]))
         optErrMsgs.append(
             'Possible start locations with these settings: {}'.format(
                 possibleStartAPs))
         dumpErrorMsgs(args.output, optErrMsgs)
         sys.exit(-1)
 ap = getAccessPoint(args.startAP)
 if 'forcedEarlyMorph' in ap.Start and ap.Start['forcedEarlyMorph'] == True:
     forceArg(
         'morphPlacement', 'early',
         "'Morph Placement' forced to early for custom start location")
 else:
     if progSpeed == 'speedrun':
         if args.morphPlacement == 'late':
             forceArg('morphPlacement', 'normal',
                      "'Morph Placement' forced to normal instead of late")
         elif (not GraphUtils.isStandardStart(
                 args.startAP)) and args.morphPlacement != 'normal':
             forceArg(
                 'morphPlacement', 'normal',
                 "'Morph Placement' forced to normal for custom start location"
             )
Ejemplo n.º 17
0
    def loadRom(self, rom, interactive=False, magic=None, startLocation=None):
        self.scavengerOrder = []
        self.plandoScavengerOrder = []
        # startLocation param is only use for seedless
        if rom == None:
            # TODO::add a --logic parameter for seedless
            Logic.factory('vanilla')
            self.romFileName = 'seedless'
            self.majorsSplit = 'Full'
            self.masterMajorsSplit = 'Full'
            self.areaRando = True
            self.bossRando = True
            self.escapeRando = False
            self.escapeTimer = "03:00"
            self.startLocation = startLocation
            RomPatches.setDefaultPatches(startLocation)
            self.startArea = getAccessPoint(startLocation).Start['solveArea']
            # in seedless load all the vanilla transitions
            self.areaTransitions = vanillaTransitions[:]
            self.bossTransitions = vanillaBossesTransitions[:]
            self.escapeTransition = [vanillaEscapeTransitions[0]]
            # in seedless we allow mixing of area and boss transitions
            self.hasMixedTransitions = True
            self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition
            self.locations = Logic.locations
            for loc in self.locations:
                loc.itemName = 'Nothing'
            # set doors related to default patches
            DoorsManager.setDoorsColor()
            self.doorsRando = False
            self.hasNothing = False
            self.objectives.setVanilla()
            self.tourian = 'Vanilla'
        else:
            self.romFileName = rom
            self.romLoader = RomLoader.factory(rom, magic)
            Logic.factory(self.romLoader.readLogic())
            self.locations = Logic.locations
            (self.majorsSplit,
             self.masterMajorsSplit) = self.romLoader.assignItems(
                 self.locations)
            (self.startLocation, self.startArea,
             startPatches) = self.romLoader.getStartAP()
            if not GraphUtils.isStandardStart(
                    self.startLocation) and self.majorsSplit != 'Full':
                # update major/chozo locs in non standard start
                self.romLoader.updateSplitLocs(self.majorsSplit,
                                               self.locations)
            (self.areaRando, self.bossRando, self.escapeRando, hasObjectives,
             self.tourian) = self.romLoader.loadPatches()
            RomPatches.ActivePatches += startPatches
            self.escapeTimer = self.romLoader.getEscapeTimer()
            self.doorsRando = self.romLoader.loadDoorsColor()
            self.hasNothing = self.checkLocsForNothing()
            if self.majorsSplit == 'Scavenger':
                self.scavengerOrder = self.romLoader.loadScavengerOrder(
                    self.locations)
            if hasObjectives:
                self.romLoader.loadObjectives(self.objectives)
            else:
                if self.majorsSplit == "Scavenger":
                    self.objectives.setScavengerHunt()
                    self.objectives.tourianRequired = not self.romLoader.hasPatch(
                        'Escape_Trigger')
                else:
                    self.objectives.setVanilla()
            self.majorUpgrades = self.romLoader.loadMajorUpgrades()
            self.splitLocsByArea = self.romLoader.getSplitLocsByArea(
                self.locations)
            self.objectives.setSolverMode(self)

            if interactive == False:
                print(
                    "ROM {} majors: {} area: {} boss: {} escape: {} patches: {} activePatches: {}"
                    .format(rom, self.majorsSplit, self.areaRando,
                            self.bossRando, self.escapeRando,
                            sorted(self.romLoader.getPatches()),
                            sorted(RomPatches.ActivePatches)))
            else:
                print(
                    "majors: {} area: {} boss: {} escape: {} activepatches: {}"
                    .format(self.majorsSplit, self.areaRando,
                            self.bossRando, self.escapeRando,
                            sorted(RomPatches.ActivePatches)))

            (self.areaTransitions, self.bossTransitions, self.escapeTransition,
             self.hasMixedTransitions) = self.romLoader.getTransitions(
                 self.tourian)
            if interactive == True and self.debug == False:
                # in interactive area mode we build the graph as we play along
                if self.areaRando == True and self.bossRando == True:
                    self.curGraphTransitions = []
                elif self.areaRando == True:
                    self.curGraphTransitions = self.bossTransitions[:]
                elif self.bossRando == True:
                    self.curGraphTransitions = self.areaTransitions[:]
                else:
                    self.curGraphTransitions = self.bossTransitions + self.areaTransitions
                if self.escapeRando == False:
                    self.curGraphTransitions += self.escapeTransition
            else:
                self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition

        self.smbm = SMBoolManager()
        self.buildGraph()

        # store at each step how many locations are available
        self.nbAvailLocs = []

        if self.log.getEffectiveLevel() == logging.DEBUG:
            self.log.debug("Display items at locations:")
            for loc in self.locations:
                self.log.debug('{:>50}: {:>16}'.format(loc.Name, loc.itemName))
Ejemplo n.º 18
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)
    def loadRom(self, rom, interactive=False, magic=None, startAP=None):
        # startAP param is only use for seedless
        if rom == None:
            # TODO::add a --logic parameter for seedless
            Logic.factory('varia')
            self.romFileName = 'seedless'
            self.majorsSplit = 'Full'
            self.areaRando = True
            self.bossRando = True
            self.escapeRando = False
            self.escapeTimer = "03:00"
            self.startAP = startAP
            RomPatches.setDefaultPatches(startAP)
            self.startArea = getAccessPoint(startAP).Start['solveArea']
            # in seedless load all the vanilla transitions
            self.areaTransitions = vanillaTransitions[:]
            self.bossTransitions = vanillaBossesTransitions[:]
            self.escapeTransition = [vanillaEscapeTransitions[0]]
            # in seedless we allow mixing of area and boss transitions
            self.hasMixedTransitions = True
            self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition
            self.locations = Logic.locations
            for loc in self.locations:
                loc.itemName = 'Nothing'
            # set doors related to default patches
            DoorsManager.setDoorsColor()
            self.doorsRando = False
        else:
            self.romFileName = rom
            self.romLoader = RomLoader.factory(rom, magic)
            Logic.factory(self.romLoader.readLogic())
            self.romLoader.readNothingId()
            self.locations = Logic.locations
            self.majorsSplit = self.romLoader.assignItems(self.locations)
            (self.startAP, self.startArea,
             startPatches) = self.romLoader.getStartAP()
            (self.areaRando, self.bossRando,
             self.escapeRando) = self.romLoader.loadPatches()
            RomPatches.ActivePatches += startPatches
            self.escapeTimer = self.romLoader.getEscapeTimer()
            self.doorsRando = self.romLoader.loadDoorsColor()

            if interactive == False:
                print(
                    "ROM {} majors: {} area: {} boss: {} escape: {} patches: {} activePatches: {}"
                    .format(rom, self.majorsSplit, self.areaRando,
                            self.bossRando, self.escapeRando,
                            sorted(self.romLoader.getPatches()),
                            sorted(RomPatches.ActivePatches)))
            else:
                print(
                    "majors: {} area: {} boss: {} escape: {} activepatches: {}"
                    .format(self.majorsSplit, self.areaRando,
                            self.bossRando, self.escapeRando,
                            sorted(RomPatches.ActivePatches)))

            (self.areaTransitions, self.bossTransitions, self.escapeTransition,
             self.hasMixedTransitions) = self.romLoader.getTransitions()
            if interactive == True and self.debug == False:
                # in interactive area mode we build the graph as we play along
                if self.areaRando == True and self.bossRando == True:
                    self.curGraphTransitions = []
                elif self.areaRando == True:
                    self.curGraphTransitions = self.bossTransitions[:]
                elif self.bossRando == True:
                    self.curGraphTransitions = self.areaTransitions[:]
                else:
                    self.curGraphTransitions = self.bossTransitions + self.areaTransitions
                if self.escapeRando == False:
                    self.curGraphTransitions += self.escapeTransition
            else:
                self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition

        self.smbm = SMBoolManager()
        self.areaGraph = AccessGraph(Logic.accessPoints,
                                     self.curGraphTransitions)

        # store at each step how many locations are available
        self.nbAvailLocs = []

        if self.log.getEffectiveLevel() == logging.DEBUG:
            self.log.debug("Display items at locations:")
            for loc in self.locations:
                self.log.debug('{:>50}: {:>16}'.format(loc.Name, loc.itemName))
Ejemplo n.º 20
0
                startLocationList = args.startLocationList.replace('_', ' ')
                startLocationList = startLocationList.split(',')
                # intersection between user whishes and reality
                possibleStartAPs = sorted(list(set(possibleStartAPs).intersection(set(startLocationList))))
                if len(possibleStartAPs) == 0:
                    optErrMsgs += ["%s : %s" % (apName, cause) for apName, cause in reasons.items() if apName in startLocationList]
                    optErrMsgs.append('Invalid start locations list with your settings.')
                    dumpErrorMsgs(args.output, optErrMsgs)
                    sys.exit(-1)
            args.startLocation = random.choice(possibleStartAPs)
        elif args.startLocation not in possibleStartAPs:
            optErrMsgs.append('Invalid start location: {}.  {}'.format(args.startLocation, reasons[args.startLocation]))
            optErrMsgs.append('Possible start locations with these settings: {}'.format(possibleStartAPs))
            dumpErrorMsgs(args.output, optErrMsgs)
            sys.exit(-1)
    ap = getAccessPoint(args.startLocation)
    if 'forcedEarlyMorph' in ap.Start and ap.Start['forcedEarlyMorph'] == True:
        forceArg('morphPlacement', 'early', "'Morph Placement' forced to early for custom start location")
    else:
        if progSpeed == 'speedrun':
            if args.morphPlacement == 'late':
                forceArg('morphPlacement', 'normal', "'Morph Placement' forced to normal instead of late")
            elif (not GraphUtils.isStandardStart(args.startLocation)) and args.morphPlacement != 'normal':
                forceArg('morphPlacement', 'normal', "'Morph Placement' forced to normal for custom start location")
        if args.majorsSplit == 'Chozo' and args.morphPlacement == "late":
            forceArg('morphPlacement', 'normal', "'Morph Placement' forced to normal for Chozo")
    if args.patchOnly == False:
        print("SEED: " + str(seed))

        objectivesManager = Objectives(args.tourian != 'Disabled')
        addedObjectives = 0