Пример #1
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
Пример #2
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)
Пример #3
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
Пример #4
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
Пример #5
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
Пример #6
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
Пример #7
0
    def __init__(self, majorsSplit, startAP, areaGraph, locations):
        self.interactive = False
        self.checkDuplicateMajor = False
        self.vcr = None
        # 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.plot = 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.startAP = startAP
        self.startArea = getAccessPoint(startAP).Start['solveArea']
        self.areaGraph = areaGraph

        # store at each step how many locations are available
        self.nbAvailLocs = []
Пример #8
0
    def loadTransitions(self):
        # return the transitions
        rooms = GraphUtils.getRooms()
        bossTransitions = {}
        areaTransitions = {}
        for accessPoint in 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))
 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
Пример #10
0
 def isVanillaCroc(self):
     crocRoom = getAccessPoint('Crocomire Room Top')
     return SMBool(crocRoom.ConnectedTo == 'Crocomire Speedway Bottom')
Пример #11
0
 def getDraygonConnection(self):
     return getAccessPoint('DraygonRoomOut').ConnectedTo
Пример #12
0
                     for apName, cause in reasons.items()
                     if apName in startLocationList
                 ])
                 '\nInvalid start locations list with your settings.\n' + reasonStr
                 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"
             )
Пример #13
0
    def loadRom(self, rom, interactive=False, magic=None, startAP=None):
        # startAP param is only use for seedless
        if rom == None:
            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
            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)
            self.romLoader.readNothingId()
            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.areaGraph = AccessGraph(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))