def initialize(self, mode, rom, presetFileName, magic, debug, fill, startAP, trackerRace): # load rom and preset, return first state self.debug = debug self.mode = mode if self.mode != "seedless": self.seed = os.path.basename(os.path.splitext(rom)[0]) + '.sfc' else: self.seed = "seedless" self.smbm = SMBoolManager() self.presetFileName = presetFileName self.loadPreset(self.presetFileName) self.loadRom(rom, interactive=True, magic=magic, startAP=startAP) # in plando/tracker always consider that we're doing full self.majorsSplit = 'Full' # hide doors if self.doorsRando and mode == 'standard': DoorsManager.initTracker() self.clearItems() # in debug mode don't load plando locs/transitions if self.mode == 'plando' and self.debug == False: if fill == True: # load the source seed transitions and items/locations self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition self.areaGraph = AccessGraph(accessPoints, self.curGraphTransitions) self.fillPlandoLocs() else: if self.areaRando == True or self.bossRando == True: plandoTrans = self.loadPlandoTransitions() if len(plandoTrans) > 0: self.curGraphTransitions = plandoTrans self.areaGraph = AccessGraph(accessPoints, self.curGraphTransitions) self.loadPlandoLocs() # compute new available locations self.computeLocationsDifficulty(self.majorLocations) if trackerRace == True: self.mode = 'seedless' self.dumpState()
def createGraph(self): transitions = self.graphSettings.plandoRandoTransitions if transitions is None: transitions = [] if self.minimizerN is not None: transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN) else: if not self.bossRando: transitions += vanillaBossesTransitions else: transitions += GraphUtils.createBossesTransitions() if not self.areaRando: transitions += vanillaTransitions else: transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando) return AccessGraph(Logic.accessPoints, transitions, self.graphSettings.dotFile)
def fillGraph(self): # add self looping transitions on unused acces points usedAPs = {} for (src, dst) in self.curGraphTransitions: usedAPs[src] = True usedAPs[dst] = True singleAPs = [] for ap in accessPoints: if ap.isInternal() == True: continue if ap.Name not in usedAPs: singleAPs.append(ap.Name) transitions = self.curGraphTransitions[:] for apName in singleAPs: transitions.append((apName, apName)) return AccessGraph(accessPoints, transitions)
def savePlando(self, lock, escapeTimer): # store filled locations addresses in the ROM for next creating session from rando.Items import ItemManager locsItems = {} itemLocs = [] for loc in self.visitedLocations: locsItems[loc.Name] = loc.itemName for loc in self.locations: if loc.Name in locsItems: itemLocs.append( ItemLocation(ItemManager.getItem(loc.itemName), loc)) else: # put nothing items in unused locations itemLocs.append( ItemLocation(ItemManager.getItem("Nothing"), loc)) # patch the ROM if lock == True: import random magic = random.randint(1, 0xffff) else: magic = None romPatcher = RomPatcher(magic=magic, plando=True) patches = [ 'credits_varia.ips', 'tracking.ips', "Escape_Animals_Disable" ] if DoorsManager.isRandom(): patches += RomPatcher.IPSPatches['DoorsColors'] patches.append("Enable_Backup_Saves") if magic != None: patches.insert(0, 'race_mode.ips') patches.append('race_mode_credits.ips') romPatcher.addIPSPatches(patches) plms = [] if self.areaRando == True or self.bossRando == True or self.escapeRando == True: doors = GraphUtils.getDoorConnections( AccessGraph(Logic.accessPoints, self.fillGraph()), self.areaRando, self.bossRando, self.escapeRando, False) romPatcher.writeDoorConnections(doors) if magic == None: doorsPtrs = GraphUtils.getAps2DoorsPtrs() romPatcher.writePlandoTransitions( self.curGraphTransitions, doorsPtrs, len(vanillaBossesTransitions) + len(vanillaTransitions)) if self.escapeRando == True and escapeTimer != None: # convert from '03:00' to number of seconds escapeTimer = int(escapeTimer[0:2]) * 60 + int( escapeTimer[3:5]) romPatcher.applyEscapeAttributes( { 'Timer': escapeTimer, 'Animals': None }, plms) # write plm table & random doors romPatcher.writePlmTable(plms, self.areaRando, self.bossRando, self.startAP) romPatcher.writeItemsLocs(itemLocs) romPatcher.writeItemsNumber() romPatcher.writeSpoiler(itemLocs) # plando is considered Full romPatcher.writeSplitLocs(itemLocs, "Full") romPatcher.writeMajorsSplit("Full") class FakeRandoSettings: def __init__(self): self.qty = {'energy': 'plando'} self.progSpeed = 'plando' self.progDiff = 'plando' self.restrictions = {'Suits': False, 'Morph': 'plando'} self.superFun = {} randoSettings = FakeRandoSettings() romPatcher.writeRandoSettings(randoSettings, itemLocs) if magic != None: romPatcher.writeMagic() else: romPatcher.writePlandoAddresses(self.visitedLocations) romPatcher.commitIPS() romPatcher.end() data = romPatcher.romFile.data preset = os.path.splitext(os.path.basename(self.presetFileName))[0] seedCode = 'FX' if self.bossRando == True: seedCode = 'B' + seedCode if DoorsManager.isRandom(): seedCode = 'D' + seedCode if self.areaRando == True: seedCode = 'A' + seedCode from time import gmtime, strftime fileName = 'VARIA_Plandomizer_{}{}_{}.sfc'.format( seedCode, strftime("%Y%m%d%H%M%S", gmtime()), preset) data["fileName"] = fileName # error msg in json to be displayed by the web site data["errorMsg"] = "" with open(self.outputFileName, 'w') as jsonFile: json.dump(data, jsonFile)
def iterate(self, stateJson, scope, action, params): self.debug = params["debug"] self.smbm = SMBoolManager() state = SolverState() state.fromJson(stateJson) state.toSolver(self) self.loadPreset(self.presetFileName) # add already collected items to smbm self.smbm.addItems(self.collectedItems) if scope == 'item': if action == 'clear': self.clearItems(True) else: if action == 'add': if self.mode in ['plando', 'seedless', 'race', 'debug']: if params['loc'] != None: if self.mode == 'plando': self.setItemAt(params['loc'], params['item'], params['hide']) else: itemName = params.get('item', 'Nothing') if itemName is None: itemName = 'Nothing' self.setItemAt(params['loc'], itemName, False) else: self.increaseItem(params['item']) else: # pickup item at locName self.pickItemAt(params['loc']) elif action == 'remove': if 'loc' in params: self.removeItemAt(params['loc']) elif 'count' in params: # remove last collected item self.cancelLastItems(params['count']) else: self.decreaseItem(params['item']) elif action == 'replace': self.replaceItemAt(params['loc'], params['item'], params['hide']) elif action == 'toggle': self.toggleItem(params['item']) elif scope == 'area': if action == 'clear': self.clearTransitions() else: if action == 'add': startPoint = params['startPoint'] endPoint = params['endPoint'] self.addTransition(self.transWeb2Internal[startPoint], self.transWeb2Internal[endPoint]) elif action == 'remove': if 'startPoint' in params: self.cancelTransition( self.transWeb2Internal[params['startPoint']]) else: # remove last transition self.cancelLastTransition() elif scope == 'door': if action == 'replace': doorName = params['doorName'] newColor = params['newColor'] DoorsManager.setColor(doorName, newColor) elif action == 'toggle': doorName = params['doorName'] DoorsManager.switchVisibility(doorName) self.areaGraph = AccessGraph(Logic.accessPoints, self.curGraphTransitions) if scope == 'common': if action == 'save': return self.savePlando(params['lock'], params['escapeTimer']) elif action == 'randomize': self.randoPlando(params) # if last loc added was a sequence break, recompute its difficulty, # as it may be available with the newly placed item. if len(self.visitedLocations) > 0: lastVisited = self.visitedLocations[-1] if lastVisited.difficulty.difficulty == -1: self.visitedLocations.remove(lastVisited) self.majorLocations.append(lastVisited) else: lastVisited = None else: lastVisited = None # compute new available locations self.clearLocs(self.majorLocations) self.computeLocationsDifficulty(self.majorLocations) # put back last visited location if lastVisited != None: self.majorLocations.remove(lastVisited) self.visitedLocations.append(lastVisited) if lastVisited.difficulty == False: # if the loc is still sequence break, put it back as sequence break lastVisited.difficulty = SMBool(True, -1) # return them self.dumpState()
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))
def buildGraph(self): self.areaGraph = AccessGraph(Logic.accessPoints, self.curGraphTransitions) Objectives.setGraph(self.areaGraph, infinity)