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
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)
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
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
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 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 __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 = []
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
def isVanillaCroc(self): crocRoom = getAccessPoint('Crocomire Room Top') return SMBool(crocRoom.ConnectedTo == 'Crocomire Speedway Bottom')
def getDraygonConnection(self): return getAccessPoint('DraygonRoomOut').ConnectedTo
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" )
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))