コード例 #1
0
    def run(self):
        # init session
        if self.session.plando is None:
            self.session.plando = {
                "state": {},
                "preset": "regular",
                "seed": None,
                "startLocation": "Landing Site",

                # rando params
                "rando": {},

                # set to False in plando.html
                "firstTime": True
            }

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # access points
        vanillaAPs = []
        for (src, dest) in vanillaTransitions:
            vanillaAPs += [transition2isolver(src), transition2isolver(dest)]

        vanillaBossesAPs = []
        for (src, dest) in vanillaBossesTransitions:
            vanillaBossesAPs += [
                transition2isolver(src),
                transition2isolver(dest)
            ]

        escapeAPs = []
        for (src, dest) in vanillaEscapeTransitions:
            escapeAPs += [transition2isolver(src), transition2isolver(dest)]

        # generate list of addresses to read in the ROM
        addresses = getAddressesToRead(plando=True)

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [
            OPTGROUP(_label="Standard", *startAPs["regular"]),
            OPTGROUP(_label="Custom", *startAPs["custom"]),
            OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])
        ]

        return dict(stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    vanillaAPs=vanillaAPs,
                    vanillaBossesAPs=vanillaBossesAPs,
                    escapeAPs=escapeAPs,
                    curSession=self.session.plando,
                    addresses=addresses,
                    startAPs=startAPs,
                    version=displayedVersion)
コード例 #2
0
    def run(self):
        # init session
        if self.session.tracker is None:
            self.session.tracker = {
                "state": {},
                "preset": "regular",
                "seed": None,
                "startLocation": "Landing Site",
                # set to False in tracker.html
                "firstTime": True
            }

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # access points
        vanillaAPs = []
        for (src, dest) in vanillaTransitions:
            vanillaAPs += [transition2isolver(src), transition2isolver(dest)]

        vanillaBossesAPs = []
        for (src, dest) in vanillaBossesTransitions:
            vanillaBossesAPs += [
                transition2isolver(src),
                transition2isolver(dest)
            ]

        escapeAPs = []
        for (src, dest) in vanillaEscapeTransitions:
            escapeAPs += [transition2isolver(src), transition2isolver(dest)]

        # generate list of addresses to read in the ROM
        addresses = getAddressesToRead()

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [
            OPTGROUP(_label="Standard", *startAPs["regular"]),
            OPTGROUP(_label="Custom", *startAPs["custom"]),
            OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])
        ]

        # get ap -> grapharea for auto tracker
        apsGraphArea = {
            locName4isolver(ap.Name): ap.GraphArea
            for ap in accessPoints
        }

        return dict(stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    vanillaAPs=vanillaAPs,
                    vanillaBossesAPs=vanillaBossesAPs,
                    escapeAPs=escapeAPs,
                    curSession=self.session.tracker,
                    addresses=addresses,
                    startAPs=startAPs,
                    areaAccessPoints=InteractiveSolver.areaAccessPoints,
                    bossAccessPoints=InteractiveSolver.bossAccessPoints,
                    escapeAccessPoints=InteractiveSolver.escapeAccessPoints,
                    nothingScreens=InteractiveSolver.nothingScreens,
                    doorsScreen=InteractiveSolver.doorsScreen,
                    bossBitMasks=InteractiveSolver.bossBitMasks,
                    apsGraphArea=apsGraphArea)
コード例 #3
0
 def skillPresetListWebService(self):
     # load presets list
     (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)
     return json.dumps(stdPresets + tourPresets + comPresets)
コード例 #4
0
    def skillPresetActionWebService(self):
        print("skillPresetActionWebService call")

        if self.session.presets is None:
            self.session.presets = {}

        # for create/update, not load
        (ok, msg) = self.validatePresetsParams(self.vars.action)
        if not ok:
            raiseHttp(400, json.dumps(msg))
        else:
            self.session.presets['currentTab'] = self.vars.currenttab

        if self.vars.action == 'Create':
            preset = self.vars.presetCreate
        else:
            preset = self.vars.preset

        # check if the presets file already exists
        password = self.vars['password']
        password = password.encode('utf-8')
        passwordSHA256 = hashlib.sha256(password).hexdigest()
        fullPath = '{}/{}.json'.format(getPresetDir(preset), preset)
        if os.path.isfile(fullPath):
            # load it
            end = False
            try:
                oldParams = PresetLoader.factory(fullPath).params
            except Exception as e:
                msg = "UC:Error loading the preset {}: {}".format(preset, e)
                end = True
            if end == True:
                raiseHttp(400, json.dumps(msg))

            # check if password match
            if 'password' in oldParams and passwordSHA256 == oldParams[
                    'password']:
                # update the presets file
                paramsDict = self.genJsonFromParams(self.vars)
                paramsDict['password'] = passwordSHA256
                try:
                    PresetLoader.factory(paramsDict).dump(fullPath)
                    with DB() as db:
                        db.addPresetAction(preset, 'update')
                    self.updatePresetsSession()
                    msg = "Preset {} updated".format(preset)
                    return json.dumps(msg)
                except Exception as e:
                    msg = "Error writing the preset {}: {}".format(preset, e)
                    raiseHttp(400, json.dumps(msg))
            else:
                msg = "Password mismatch with existing presets file {}".format(
                    preset)
                raiseHttp(400, json.dumps(msg))
        else:
            # prevent a malicious user from creating presets in a loop
            if not self.maxPresetsReach():
                # write the presets file
                paramsDict = self.genJsonFromParams(self.vars)
                paramsDict['password'] = passwordSHA256
                try:
                    PresetLoader.factory(paramsDict).dump(fullPath)
                    with DB() as db:
                        db.addPresetAction(preset, 'create')
                    self.updatePresetsSession()

                    # add new preset in cache
                    (stdPresets, tourPresets,
                     comPresets) = loadPresetsList(self.cache)
                    comPresets.append(preset)
                    comPresets.sort(key=lambda v: v.upper())

                    msg = "Preset {} created".format(preset)
                    return json.dumps(msg)
                except Exception as e:
                    msg = "Error writing the preset {}: {}".format(preset, e)
                    raiseHttp(400, json.dumps(msg))
                redirect(URL(r=request, f='presets'))
            else:
                msg = "Sorry, maximum number of presets reached, can't add more"
                raiseHttp(400, json.dumps(msg))
コード例 #5
0
    def run(self):
        self.initPresetsSession()

        # use web2py builtin cache to avoid recomputing the hardrooms requirements
        hardRooms = self.cache.ram('hardRooms',
                                   lambda: dict(),
                                   time_expire=None)
        if len(hardRooms) == 0:
            self.computeHardRooms(hardRooms)

        hellRuns = self.cache.ram('hellRuns', lambda: dict(), time_expire=None)
        if len(hellRuns) == 0:
            self.computeHellruns(hellRuns)

        if self.vars.action is not None:
            (ok, msg) = self.validatePresetsParams(self.vars.action)
            if not ok:
                self.session.flash = msg
                redirect(URL(r=self.request, f='presets'))
            else:
                self.session.presets['currentTab'] = self.vars.currenttab

            preset = self.vars.preset

        # in web2py.js, in disableElement, remove 'working...' to have action with correct value
        if self.vars.action == 'Load':
            # check that the presets file exists
            fullPath = '{}/{}.json'.format(getPresetDir(preset), preset)
            if os.path.isfile(fullPath):
                # load it
                try:
                    params = PresetLoader.factory(fullPath).params
                    self.updatePresetsSession()
                    self.session.presets["presetDict"] = None
                except Exception as e:
                    self.session.flash = "L:Error loading the preset {}: {}".format(
                        preset, e)
            else:
                self.session.flash = "Presets file not found: {}".format(
                    fullPath)
            redirect(URL(r=self.request, f='presets'))

        # load conf from session if available
        error = False
        try:
            params = self.loadPreset()
        except Exception as e:
            self.session.presets['preset'] = 'regular'
            self.session.flash = "S:Error loading the preset: {}".format(e)
            error = True
        if error == True:
            redirect(URL(r=request, f='presets'))

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # add missing knows/settings
        completePreset(params)

        # compute score for skill bar
        skillBarData = self.getSkillLevelBarData(
            self.session.presets['preset'])

        # send values to view
        return dict(desc=Knows.desc,
                    difficulties=diff2text,
                    categories=Knows.categories,
                    settings=params['Settings'],
                    knows=params['Knows'],
                    easy=easy,
                    medium=medium,
                    hard=hard,
                    harder=harder,
                    hardcore=hardcore,
                    mania=mania,
                    controller=params['Controller'],
                    stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    skillBarData=skillBarData,
                    hardRooms=hardRooms,
                    hellRuns=hellRuns)
コード例 #6
0
 def maxPresetsReach(self):
     # to prevent a spammer to create presets in a loop and fill the fs
     maxPresets = 4096
     (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)
     return len(comPresets) >= maxPresets
コード例 #7
0
    def run(self):
        # init session
        self.initSolverSession()

        if self.vars.action == 'Solve':
            (ok, msg) = self.validateSolverParams()
            if not ok:
                self.session.flash = msg
                redirect(URL(r=self.request, f='solver'))

            self.updateSolverSession()

            preset = self.vars.preset

            # new uploaded rom ?
            error = False
            if self.vars.romJson != '':
                try:
                    (base,
                     jsonRomFileName) = generateJsonROM(self.vars.romJson)
                    self.session.solver['romFile'] = base
                    if base not in self.session.solver['romFiles']:
                        self.session.solver['romFiles'].append(base)
                except Exception as e:
                    print(
                        "Error loading the ROM file, exception: {}".format(e))
                    self.session.flash = "Error loading the json ROM file"
                    error = True

            elif self.vars['romFile'] is not None and len(
                    self.vars['romFile']) != 0:
                self.session.solver['romFile'] = os.path.splitext(
                    self.vars['romFile'])[0]
                jsonRomFileName = 'roms/' + self.session.solver[
                    'romFile'] + '.json'
            else:
                self.session.flash = "No rom file selected for upload"
                error = True

            if not error:
                # check that the json file exists
                if not os.path.isfile(jsonRomFileName):
                    self.session.flash = "Missing json ROM file on the server"
                else:
                    try:
                        (ok, result) = self.computeDifficulty(
                            jsonRomFileName, preset)
                        if not ok:
                            self.session.flash = result
                            redirect(URL(r=self.request, f='solver'))
                        self.session.solver['result'] = result
                    except Exception as e:
                        print(
                            "Error loading the ROM file, exception: {}".format(
                                e))
                        self.session.flash = "Error loading the ROM file"

            redirect(URL(r=self.request, f='solver'))

        # display result
        result = self.prepareResult()

        ROMs = self.getROMsList()

        # last solved ROM
        lastRomFile = self.getLastSolvedROM()

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # generate list of addresses to read in the ROM
        addresses = getAddressesToRead()

        # send values to view
        return dict(desc=Knows.desc,
                    stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    roms=ROMs,
                    lastRomFile=lastRomFile,
                    difficulties=diff2text,
                    categories=Knows.categories,
                    result=result,
                    addresses=addresses,
                    easy=easy,
                    medium=medium,
                    hard=hard,
                    harder=harder,
                    hardcore=hardcore,
                    mania=mania)
コード例 #8
0
    def run(self):
        self.initCustomSprites()
        self.initCustomizerSession()
        musics = self.loadMusics()
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        url = self.request.env.request_uri.split('/')
        msg = ""
        seedInfo = None
        seedParams = None
        defaultParams = None
        if len(url) > 0 and url[-1] != 'customizer':
            # a seed unique key was passed as parameter
            key = url[-1]

            # decode url
            key = urllib.parse.unquote(key)

            # sanity check
            if IS_MATCH('^[0-9a-z-]*$')(key)[1] is not None:
                msg = "Seed key can only contain [0-9a-z-]"
            elif IS_LENGTH(maxsize=36, minsize=36)(key)[1] is not None:
                msg = "Seed key must be 36 chars long"
            else:
                with DB() as db:
                    seedInfo = db.getSeedInfo(key)
                if seedInfo is None or len(seedInfo) == 0:
                    msg = "Seed {} not found".format(key)
                    seedInfo = None
                else:
                    # get a dict with seed info and another one with seed parameters
                    info = {}
                    seedParams = {}
                    infoKeys = [
                        'time', 'filename', 'preset', 'runtime', 'complexity',
                        'upload_status', 'seed', 'raceMode'
                    ]
                    for (k, value) in seedInfo:
                        if k in infoKeys:
                            info[k] = value
                        else:
                            seedParams[k] = updateParameterDisplay(value)
                    seedInfo = info
                    seedInfo['key'] = key

                    # if new parameters have been added since the seed creation, add them with value "n/a"
                    defaultParams = getRandomizerDefaultParameters()
                    for k in defaultParams:
                        if k not in infoKeys and k not in seedParams:
                            seedParams[k] = "n/a"

                    # check that the seed ips is available
                    if seedInfo["upload_status"] not in [
                            'pending', 'uploaded', 'local'
                    ]:
                        msg = "Seed {} not available".format(key)
                        seedInfo = None
                        seedParams = None
                    # accessing the url tell us to store the ips for more than 7 days
                    elif seedInfo["upload_status"] == 'local':
                        with DB() as db:
                            db.updateSeedUploadStatus(key, 'pending')

        return dict(customSprites=customSprites,
                    customShips=customShips,
                    musics=musics,
                    comPresets=comPresets,
                    seedInfo=seedInfo,
                    seedParams=seedParams,
                    msg=msg,
                    defaultParams=defaultParams)
コード例 #9
0
    def run(self):
        self.initRandomizerSession()

        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        randoPresetsDesc = {
            "all_random": "all the parameters set to random",
            "Chozo_Speedrun": "speedrun progression speed with Chozo split",
            "default": "VARIA randomizer default settings",
            "doors_long": "be prepared to hunt for beams and ammo to open doors",
            "doors_short": "uses Chozo/speedrun settings for a quicker door color rando",
            "free": "easiest possible settings",
            "hardway2hell": "harder highway2hell",
            "haste": "inspired by DASH randomizer with Nerfed Charge / Progressive Suits",
            "highway2hell": "favors suitless seeds",
            "hud": "Full rando with remaining major upgrades in the area shown in the HUD",
            "hud_hard": "Low resources and VARIA HUD enabled to help you track of actual items count",
            "hud_start": "Non-vanilla start with Major or Chozo split",
            "minimizer":"Typical 'boss rush' settings with random start and nerfed charge",
            "minimizer_hardcore":"Have fun 'rushing' bosses with no equipment on a tiny map",
            "minimizer_maximizer":"No longer a boss rush",
            "quite_random": "randomizes a few significant settings to have various seeds",
            "scavenger_hard":"Pretty hostile Scavenger mode",
            "scavenger_random":"Randomize everything within Scavenger mode",
            "scavenger_speedrun":"Quickest Scavenger settings",
            "scavenger_vanilla_but_not":"Items are vanilla, but area and bosses are not",
            "stupid_hard": "hardest possible settings",
            "surprise": "quite_random with Area/Boss/Doors/Start settings randomized",
            "vanilla": "closest possible to vanilla Super Metroid",
            "way_of_chozo": "chozo split with boss randomization",
            "where_am_i": "Area mode with random start location and early morph",
            "where_is_morph": "Area mode with late Morph",
            "Multi_Category_Randomizer_Week_1": "Multi-Category Randomizer Tournament week 1",
            "Multi_Category_Randomizer_Week_2": "Multi-Category Randomizer Tournament week 2",
            "Multi_Category_Randomizer_Week_3": "Multi-Category Randomizer Tournament week 3",
            "Multi_Category_Randomizer_Week_4": "Multi-Category Randomizer Tournament week 4",
            "Multi_Category_Randomizer_Week_5": "Multi-Category Randomizer Tournament week 5",
            "Multi_Category_Randomizer_Week_6": "Multi-Category Randomizer Tournament week 6",
            "Multi_Category_Randomizer_Week_7": "Multi-Category Randomizer Tournament week 7",
            "Season_Races": "rando league races (Majors/Minors split)",
            "SGLive2022_Race_1": "SGLive 2022 Super Metroid randomizer tournament race 1",
            "SGLive2022_Race_2": "SGLive 2022 Super Metroid randomizer tournament race 2",
            "SGLive2022_Race_3": "SGLive 2022 Super Metroid randomizer tournament race 3",
            "SMRAT2021": "Super Metroid Randomizer Accessible Tournament 2021",
            "VARIA_Weekly": "Casual logic community races"
        }

        randoPresetsCategories = {
            "Standard": ["", "default", "Chozo_Speedrun", "free", "haste", "vanilla"],
            "Hud": ["hud", "hud_hard", "hud_start"],
            "Scavenger": ["scavenger_hard", "scavenger_random", "scavenger_speedrun", "scavenger_vanilla_but_not"],
            "Area": ["way_of_chozo", "where_am_i", "where_is_morph"],
            "Doors": ["doors_long", "doors_short"],
            "Minimizer": ["minimizer", "minimizer_hardcore", "minimizer_maximizer"],
            "Hard": ["hardway2hell", "highway2hell", "stupid_hard"],
            "Random": ["all_random", "quite_random", "surprise"],
            "Tournament": ["Season_Races", "SMRAT2021", "VARIA_Weekly", "SGLive2022_Race_1", "SGLive2022_Race_2", "SGLive2022_Race_3", "Multi_Category_Randomizer_Week_1", "Multi_Category_Randomizer_Week_2", "Multi_Category_Randomizer_Week_3", "Multi_Category_Randomizer_Week_4", "Multi_Category_Randomizer_Week_5", "Multi_Category_Randomizer_Week_6", "Multi_Category_Randomizer_Week_7"]
        }

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [OPTGROUP(_label="Standard", *startAPs["regular"]),
                    OPTGROUP(_label="Custom", *startAPs["custom"]),
                    OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])]

        # get multi
        currentMultiValues = self.getCurrentMultiValues()
        defaultMultiValues = getDefaultMultiValues()

        # objectives self exclusions
        objectivesExclusions = Objectives.getExclusions()
        objectivesTypes = Objectives.getObjectivesTypes()
        objectivesSort = Objectives.getObjectivesSort()
        objectivesCategories = Objectives.getObjectivesCategories()

        # check if we have a guid in the url
        url = self.request.env.request_uri.split('/')
        if len(url) > 0 and url[-1] != 'randomizer':
            # a seed unique key was passed as parameter
            key = url[-1]

            # decode url
            key = urllib.parse.unquote(key)

            # sanity check
            if IS_MATCH('^[0-9a-z-]*$')(key)[1] is None and IS_LENGTH(maxsize=36, minsize=36)(key)[1] is None:
                with DB() as db:
                    seedInfo = db.getSeedInfo(key)
                if seedInfo is not None and len(seedInfo) > 0:
                    defaultParams = getRandomizerDefaultParameters()
                    defaultParams.update(seedInfo)
                    seedInfo = defaultParams

                    # check that the seed ips is available
                    if seedInfo["upload_status"] in ['pending', 'uploaded', 'local']:
                        # load parameters in session
                        for key, value in seedInfo.items():
                            if key in ["complexity", "randoPreset", "raceMode"]:
                                continue
                            elif key in defaultMultiValues:
                                keyMulti = key + 'MultiSelect'
                                if keyMulti in seedInfo:
                                    if key == 'objective' and value == 'nothing':
                                        self.session.randomizer[key] = ""
                                    else:
                                        self.session.randomizer[key] = seedInfo[key]
                                    valueMulti = seedInfo[keyMulti]
                                    if type(valueMulti) == str:
                                        valueMulti = valueMulti.split(',')
                                    self.session.randomizer[keyMulti] = valueMulti
                                    currentMultiValues[key] = valueMulti
                            elif key in self.session.randomizer and 'MultiSelect' not in key:
                                self.session.randomizer[key] = value

        return dict(stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets,
                    randoPresetsDesc=randoPresetsDesc, randoPresetsCategories=randoPresetsCategories,
                    startAPs=startAPs, currentMultiValues=currentMultiValues, defaultMultiValues=defaultMultiValues,
                    maxsize=sys.maxsize, displayNames=displayNames, objectivesExclusions=objectivesExclusions,
                    objectivesTypes=objectivesTypes, objectivesSort=objectivesSort,
                    objectivesCategories=objectivesCategories)
コード例 #10
0
    def run(self):
        self.initExtStatsSession()

        if self.vars.action == 'Load':
            (ok, msg) = self.validateExtStatsParams()
            if not ok:
                self.session.flash = msg
                redirect(URL(r=self.request, f='extStats'))

            self.updateExtStatsSession()

            skillPreset = self.vars.preset
            randoPreset = self.vars.randoPreset

            # load rando preset to get majors split
            fullPath = 'rando_presets/{}.json'.format(randoPreset)
            if not os.path.isfile(fullPath):
                raiseHttp(400, "Unknown rando preset: {}".format(e))
            try:
                with open(fullPath) as jsonFile:
                    randoPresetContent = json.load(jsonFile)
            except Exception as e:
                raiseHttp(400, "Can't load the rando preset: {}".format(e))
            majorsSplit = randoPresetContent["majorsSplit"]

            # load skill preset
            fullPath = '{}/{}.json'.format(getPresetDir(skillPreset),
                                           skillPreset)
            try:
                skillPresetContent = PresetLoader.factory(fullPath).params
                completePreset(skillPresetContent)
            except Exception as e:
                raiseHttp(400, "Error loading the skill preset: {}".format(e))

            with DB() as db:
                (itemsStats, techniquesStats, difficulties,
                 solverStatsRaw) = db.getExtStat(skillPreset, randoPreset)

            solverStats = {}
            if "avgLocs" in solverStatsRaw:
                solverStats["avgLocs"] = transformStats(
                    solverStatsRaw["avgLocs"])
                solverStats["avgLocs"].insert(
                    0, ['Available locations', 'Percentage'])
            if "open14" in solverStatsRaw:
                open14 = transformStats(solverStatsRaw["open14"])
                open24 = transformStats(solverStatsRaw["open24"])
                open34 = transformStats(solverStatsRaw["open34"])
                open44 = transformStats(solverStatsRaw["open44"])
                solverStats["open"] = zipStats(
                    [open14, open24, open34, open44])
                solverStats["open"].insert(0, [
                    'Collected items', '1/4 locations available',
                    '2/4 locations available', '3/4 locations available',
                    '4/4 locations available'
                ])

            # check that all items are present in the stats:
            nbItems = 19
            nbLocs = 109
            if itemsStats and len(itemsStats) != nbItems:
                for i, item in enumerate([
                        'Bomb', 'Charge', 'Grapple', 'Gravity', 'HiJump',
                        'Ice', 'Missile', 'Morph', 'Plasma', 'PowerBomb',
                        'ScrewAttack', 'SpaceJump', 'Spazer', 'SpeedBooster',
                        'SpringBall', 'Super', 'Varia', 'Wave', 'XRayScope'
                ]):
                    if itemsStats[i][1] != item:
                        itemsStats.insert(i, [itemsStats[0][0], item] +
                                          [0] * nbLocs)
        else:
            itemsStats = None
            techniquesStats = None
            difficulties = None
            solverStats = None
            skillPresetContent = None
            majorsSplit = None

        (randoPresets, tourRandoPresets) = loadRandoPresetsList(self.cache,
                                                                filter=True)
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        return dict(stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    randoPresets=randoPresets,
                    tourRandoPresets=tourRandoPresets,
                    itemsStats=itemsStats,
                    techniquesStats=techniquesStats,
                    categories=Knows.categories,
                    knowsDesc=Knows.desc,
                    skillPresetContent=skillPresetContent,
                    locations=locations,
                    majorsSplit=majorsSplit,
                    difficulties=difficulties,
                    solverStats=solverStats)