diff --git a/.github/workflows/jest-tests.yml b/.github/workflows/jest-tests.yml index 8fd070dd..4f68124e 100644 --- a/.github/workflows/jest-tests.yml +++ b/.github/workflows/jest-tests.yml @@ -2,9 +2,6 @@ name: Run Jest Tests on: push: - branches: - - main - - canary jobs: test: diff --git a/.gitignore b/.gitignore index ac66d430..c023481e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ node_modules/ .turbo packages/stats/bin/ -packages/stats/results/*.html \ No newline at end of file +packages/stats/results/*.html +.env*.local diff --git a/LICENSE.md b/LICENSE.md index 1455c0ae..e7f812a9 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Dash Randomizer +Copyright (c) 2024 Dash Randomizer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 7144d9c5..9f3089cd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ DASH is a Super Metroid randomizer aimed at competitive play. This is a monorepo which consists of all the DASH projects, which are located in the [`apps`](apps) and [`packages`](packages) folders. * [`web`](apps/web): the website for [dashrando.net](https://www.dashrando.net) -* [`headless`](apps/headless/): a standalone Node.js version which can be used to generate seeds outside of the website (such as bots). * [`core`](packages/core): the logic for seeds for each mode. ## Local Development diff --git a/apps/headless/.gitignore b/apps/headless/.gitignore deleted file mode 100644 index c9c2782a..00000000 --- a/apps/headless/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -public/* -!public/.keep \ No newline at end of file diff --git a/apps/headless/README.md b/apps/headless/README.md deleted file mode 100644 index c4badf1a..00000000 --- a/apps/headless/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# DASH Headless - -This is a standalone file for rolling a DASH Randomizer seed. It is meant to be used by bots in a Node.js environment. - -## Usage -```sh -node ./dash.headless.js [options] - -Usage: dash.headless.js -r -p [options] - -Generate a randomized DASH seed from the command line - -Options: - -r --vanillaPath path to vanilla rom - -p --preset preset to use - -b --base-url base url for rolling the seed (default: "https://dashrando.net/") - -h, --help display help for command -``` diff --git a/apps/headless/build.js b/apps/headless/build.js deleted file mode 100644 index 0137680f..00000000 --- a/apps/headless/build.js +++ /dev/null @@ -1,25 +0,0 @@ -import ncc from "@vercel/ncc" -import path from "node:path" -import fs from "node:fs/promises" - -async function build() { - const entry = path.resolve(process.cwd(), 'index.ts') - console.log(entry) - const output = await ncc(entry, { - minify: true, - sourceMapRegister: false, - cache: false, - }) - await fs.writeFile(path.resolve(process.cwd(), 'public/dash.headless.js'), output.code) -} - -build() - .then(() => { - console.log("build successful"); - process.exit(0); - }) - .catch((err) => { - console.error("build failed"); - console.error(err); - process.exit(1); - }); \ No newline at end of file diff --git a/apps/headless/index.ts b/apps/headless/index.ts deleted file mode 100644 index 3ba71c0a..00000000 --- a/apps/headless/index.ts +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env node - -import fs from "fs"; -import crypto from "crypto"; -import { program } from "commander"; -import { BpsPatch, patchRom } from "core"; -import got, { HTTPError, RequestError } from "got"; -import chalk from "chalk"; -import path from "path"; - -export type SeedAPIResponse = { - basePatchUrl: string; - seedPatch: SeedPatchPart[]; - fileName: string; - preset: string; -}; - -export type SeedPatchPart = [ - number, - number, - { - [key: number]: number; - } -]; - -export type SeedPatchRequestBody = { - preset: string; - seedNumber: number; -}; - -export type HeadlessOptions = { - baseUrl: string; -}; - -const vanillaHash = - "12b77c4bc9c1832cee8881244659065ee1d84c70c3d29e6eaf92e6798cc2ca72"; -const headeredHash = - "9a4441809ac9331cdbc6a50fba1a8fbfd08bc490bc8644587ee84a4d6f924fea"; - -const verify = (rom) => { - let hash = crypto.createHash("sha256"); - hash.update(rom); - const signature = hash.digest("hex"); - if (signature === vanillaHash) { - return rom; - } else if (signature === headeredHash) { - console.warn( - `${chalk.yellow( - "You have entered a headered ROM" - )}. The header will now be removed.` - ); - const unheaderedContent = rom.slice(512); - return verify(unheaderedContent); - } - throw Error("Invalid vanilla ROM"); -}; - -function getVanilla(vanillaPath: string) { - const fileExists = fs.existsSync(vanillaPath); - if (!fileExists) { - throw new Error(`Could not find ROM: ${vanillaPath}`); - } - const contents = fs.readFileSync(vanillaPath); - return verify(contents); -} - -const fetchSeedData = async (input: SeedPatchRequestBody, options) => { - const url = new URL("/api/seed", options.baseUrl); - try { - const res: SeedAPIResponse = await got - .post(url.href, { - json: input, - }) - .json(); - return res; - } catch (err: HTTPError | unknown) { - if (err instanceof HTTPError) { - const error = err as HTTPError; - const body = JSON.parse(error.response.body as any); - if (typeof body.error == "object") { - throw new Error(`${body.error.code}: ${url.href}`); - } else { - const msg = body.error || "Error fetching seed data"; - throw new Error(msg); - } - } else if (err instanceof RequestError) { - const error = err as RequestError; - let msg; - switch (true) { - case error.code === "ECONNREFUSED": - msg = `Could not connect to server: ${options.baseUrl}`; - break; - default: - msg = error.message || "Error fetching seed data"; - break; - } - throw new Error(msg); - } else { - const error = err as Error; - const msg = error.message || "Error fetching seed data"; - throw new Error(msg); - } - } -}; - -const fetchBasePatch = async (basePatchUrl: string, baseUrl: string) => { - const url = new URL(basePatchUrl, baseUrl).href; - const { body } = await got.get(url, { responseType: "buffer" }); - return body; -}; - -const createFile = async (vanilla, seedPatch, basePatch, fileName) => { - const seedData = seedPatch.map((h: any[]) => [ - h[0], - h[1], - new Uint8Array(Object.values(h[2])), - ]); - - const rom = patchRom( - vanilla, - new BpsPatch(new Uint8Array(basePatch)), - seedData - ); - fs.writeFileSync(fileName, rom); - const filePath = path.join(process.cwd(), fileName); - console.log( - `Generated ${chalk.cyan(fileName)} at ${chalk.magenta(filePath)}` - ); -}; - -async function main() { - // Setup CLI with arguments and options - program - .name("dash.headless.js") - .usage(`-r -p [options]`) - .description("Generate a randomized DASH seed from the command line") - .requiredOption("-r --vanillaPath ", "path to vanilla rom") - .requiredOption("-p --preset ", "preset to use") - .option("-s --seed ", "number between 1 - 999999", "") - .option( - "-b --base-url ", - "base url for rolling the seed", - "https://dashrando.net/" - ); - program.parse(); - - const options = program.opts(); - const { vanillaPath, preset, baseUrl, seed } = options; - - const seedNumber: number = parseInt(seed, 10); - if (seed && (isNaN(seedNumber) || seedNumber < 1 || seedNumber > 999999)) { - throw new Error("seed must be an integer between 1 - 999999"); - } - - // Check and verify `vanillaRom` - const vanilla = await getVanilla(vanillaPath); - - // Setup options for fetching patch - const seedData = await fetchSeedData({ preset, seedNumber }, options); - const basePatch = await fetchBasePatch(seedData.basePatchUrl, baseUrl); - await createFile(vanilla, seedData.seedPatch, basePatch, seedData.fileName); - - return 0; -} - -main() - .then((code: number) => { - process.exit(code); - }) - .catch((e) => { - console.error(chalk.red(e.message)); - process.exit(1); - }); diff --git a/apps/headless/package.json b/apps/headless/package.json deleted file mode 100644 index 683ae167..00000000 --- a/apps/headless/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "headless", - "version": "1.0.0", - "description": "", - "main": "index.ts", - "type": "module", - "scripts": { - "build": "node build.js" - }, - "author": "", - "license": "MIT", - "devDependencies": { - "@types/node": "^18.15.11", - "@vercel/ncc": "^0.36.1", - "typescript": "^5.0.3" - }, - "dependencies": { - "chalk": "^4.1.2", - "commander": "^10.0.0", - "core": "*", - "got": "^12.6.0" - } -} diff --git a/apps/headless/public/.keep b/apps/headless/public/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/headless/tsconfig.json b/apps/headless/tsconfig.json deleted file mode 100644 index e817ff15..00000000 --- a/apps/headless/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "target": "es2021", - "moduleResolution": "node", - "strict": false, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": false - }, - "exclude": ["dist"] -} diff --git a/apps/headless/vercel.json b/apps/headless/vercel.json deleted file mode 100644 index 5a9a48ae..00000000 --- a/apps/headless/vercel.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rewrites": [ - { - "source": "/", - "destination": "/dash.headless.js" - } - ] -} diff --git a/apps/web/app/api/seed/route.ts b/apps/web/app/api/seed/route.ts deleted file mode 100644 index 2f0bfba5..00000000 --- a/apps/web/app/api/seed/route.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NextRequest } from "next/server"; -import { generateFromPreset, getAllPresets } from "core"; - -export const runtime = "nodejs"; - -export type HTTPError = Error & { status?: number }; - -const resJSON = (data: any, status = 200, headers = {}) => - new Response(JSON.stringify(data), { - status, - headers, - }); - -export async function POST(req: NextRequest) { - try { - const body = await req.json(); - if (!body.preset) { - throw new Error("Missing preset"); - } - const { preset, seedNumber } = body; - const validPresets = getAllPresets().map(p => p.tags).reduce((acc, cur) => { - return acc.concat(cur) - }, []); - const isValidPreset = validPresets.includes(preset); - if (!isValidPreset) { - const msg = `Invalid preset. Valid presets are: ${validPresets - .slice(0, -1) - .join(", ")} or ${validPresets.slice(-1)}`; - const err = new Error(msg) as HTTPError; - err.status = 422; - throw err; - } - const [basePatchUrl, seedPatch, fileName] = await generateFromPreset( - preset, - seedNumber - ); - return resJSON( - { - basePatchUrl, - seedPatch, - fileName, - preset, - }, - 200, - { - "Cache-Control": "s-maxage=86400", - "Content-Type": "application/json", - } - ); - } catch (err: unknown) { - console.error(err); - const error = err as HTTPError; - const status = error.status || 500; - return resJSON({ error: error.message }, status); - } -} diff --git a/apps/web/app/components/file-drop.tsx b/apps/web/app/components/file-drop.tsx index acd812d1..5b9c36ac 100644 --- a/apps/web/app/components/file-drop.tsx +++ b/apps/web/app/components/file-drop.tsx @@ -3,33 +3,17 @@ import { useDropzone } from 'react-dropzone' import { useCallback, useEffect, useState } from 'react' import { + encodeSeed, isDASHSeed, - paramsToString, - readParams, + readRom, + readSeedKey, vanilla as vanillaData, } from "core"; import styles from './file-drop.module.css' import { useRouter } from 'next/navigation' import { useVanilla } from '../generate/vanilla' import { toast } from 'sonner' - -const getParamsFromFile = (bytes: Uint8Array) => { - try { - const byteParams = readParams(bytes) - const seedKey = paramsToString( - byteParams.seed, - byteParams.settings, - byteParams.options - ) - return seedKey - } catch (e) { - const err = e as Error; - console.error(err.message) - // TODO: Present a friendly error message to the user instead of an alert. - //alert(err.message) - return null - } -} +import { getNewSeedKey, getSeedData, saveSeedData } from '@/lib/seed-data'; async function getVanilla(value: Uint8Array): Promise { const { getSignature, isVerified, isHeadered } = vanillaData @@ -111,10 +95,37 @@ const FileDrop = (props: React.PropsWithChildren) => { // return null } - const isDASH = isDASHSeed(data) - if (isDASH) { - const seedKey = getParamsFromFile(data) - if (seedKey) { + if (!isDASHSeed(data)) { + // Not a vanilla or DASH file + toast.error(`Not vanilla ROM or DASH seed`) + return + } + + // Try to read a seed key from the ROM and load it + const { key, race } = readSeedKey(data); + if (key.length > 0) { + const data = await getSeedData(key) + if (data != null) { + toast('Loading DASH seed...') + router.push(`/seed/${key}`) + return + } + } + + // No seed key so try to read the parameters from the + // ROM and regenerate it; does not work for race seeds + if (!race) { + const { params, graph } = readRom(data); + if (params !== undefined && graph !== undefined) { + const hash = encodeSeed(params, graph) + const seedKey = key.length > 0 ? key : await getNewSeedKey() + await saveSeedData( + seedKey, + hash, + params.options.Mystery, + false, + params.options.Spoiler + ); toast('Loading DASH seed...') router.push(`/seed/${seedKey}`) return diff --git a/apps/web/app/demo/globals.css b/apps/web/app/demo/globals.css deleted file mode 100644 index 36683004..00000000 --- a/apps/web/app/demo/globals.css +++ /dev/null @@ -1,88 +0,0 @@ -:root { - --color-background: #000; - --color-foreground: #cbcec8; - --color-highlight: #fff; - --color-green: #5aad36; - --color-magenta: #d12ebb; - - --selection-background: var(--color-magenta); - --selection-foreground: var(--color-background); - - --type-mono: "SFMono Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace; - - --spacer: 4px; - --spacer-2x: 8px; - --spacer-3x: 12px; - --spacer-4x: 16px; - --spacer-5x: 20px; - --spacer-6x: 24px; - --spacer-7x: 28px; - --spacer-8x: 32px; - --spacer-9x: 36px; - --spacer-10x: 40px; - --spacer-11x: 44px; - --spacer-12x: 48px; - --spacer-13x: 52px; - --spacer-14x: 56px; - --spacer-15x: 60px; - --spacer-16x: 64px; - --spacer-17x: 68px; - --spacer-18x: 72px; - --spacer-19x: 76px; - --spacer-20x: 80px; - - --spacer-negative: -4px; - --spacer-2x-negative: -8px; - --spacer-3x-negative: -12px; - --spacer-4x-negative: -16px; - --spacer-5x-negative: -20px; - --spacer-6x-negative: -24px; - --spacer-7x-negative: -28px; - --spacer-8x-negative: -32px; - --spacer-9x-negative: -36px; - --spacer-10x-negative: -40px; - --spacer-11x-negative: -44px; - --spacer-12x-negative: -48px; - --spacer-13x-negative: -52px; - --spacer-14x-negative: -56px; - --spacer-15x-negative: -60px; - --spacer-16x-negative: -64px; - --spacer-17x-negative: -68px; - --spacer-18x-negative: -72px; - --spacer-19x-negative: -76px; - --spacer-20x-negative: -80px; - - --mq-mobile: 600px; -} - -html { box-sizing: border-box; } -*, *:before, *:after { box-sizing: inherit; } - -html, body { - height: 100%; -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - text-rendering: optimizelegibility; - -webkit-font-smoothing: antialiased; - color: var(--color-foreground); - background-color: var(--color-background); - margin: 0; - padding: 0; -} - -::-moz-selection { - background-color: var(--selection-background); - color: var(--selection-foreground); -} - -::selection { - background-color: var(--selection-background); - color: var(--selection-foreground); -} diff --git a/apps/web/app/demo/layout.tsx b/apps/web/app/demo/layout.tsx deleted file mode 100644 index 2540a7a0..00000000 --- a/apps/web/app/demo/layout.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import './globals.css' -import { Inter } from 'next/font/google' - -const inter = Inter({ subsets: ['latin'] }) - -export const metadata = { - title: 'DASH Randomizer', - description: 'Super Metroid Randomizer for competitive play', -} - -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { - return ( - - {children} - - ) -} diff --git a/apps/web/app/demo/page.tsx b/apps/web/app/demo/page.tsx deleted file mode 100644 index 6c5ae676..00000000 --- a/apps/web/app/demo/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Typography from '@/app/components/typography' -import Spacer from '@/app/components/spacer' -import { Headline, Heading, Body } from '@/app/components/text' - -export default function Home() { - return ( -
- This is a X-Large - - This is a Large - - This is Medium - - This is Small - - This is Compact - -
- - DASH: Recall - - - The DASH Dev Team is excited to announce our newest project - DASH: Recall! This mode is a reimagining and rebalancing of vanilla map with the goal of offering up even more routing possibilities in a variety of seeds and further diversity in how seeds can be completed within a competitive racing situation. The following changes are introduced along with the existing DASH modifications: - - - DASH Cash Tournament on SpeedGaming - - - There will be a special DASH Randomizer one-day tournament on January 18, 2020 that will be featured on the SpeedGaming Twitch channel. This tournament will feature 16 players who qualify for the tournament with the top 8 finishers winning cash prizes. The tournament will begin at 12:00 p.m. ET and will continue throughout the full day until it is completed. For more information and a complete set of rules, click here. - -
-
- ) -} diff --git a/apps/web/app/generate/[preset]/route.ts b/apps/web/app/generate/[preset]/route.ts index 3a8d3235..dac601ef 100644 --- a/apps/web/app/generate/[preset]/route.ts +++ b/apps/web/app/generate/[preset]/route.ts @@ -1,8 +1,7 @@ import { NextRequest } from "next/server" -import { getAllPresets, getPreset, getSeedNumber, paramsToString } from "core" -import { customAlphabet } from 'nanoid' -import { kv } from '@vercel/kv' -import { getSpoiler } from "@/lib/spoiler" +import { encodeSeed, getAllPresets, getPreset, getSeedNumber } from "core" +import { generateSeed } from "core/data" +import { getNewSeedKey, saveSeedData } from "@/lib/seed-data" export const runtime = "nodejs" @@ -22,15 +21,13 @@ const redirect = (url: URL) => ( ) export async function GET(req: NextRequest, { params }: { params: GenerateParams} ) { - const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 12) - try { - const seedNum = getSeedNumber() + const seed = getSeedNumber() const preset = getPreset(params.preset) - const mystery = preset?.tags.includes('mystery') + const mystery = preset?.tags.includes('mystery') || false const searchParams = req.nextUrl.searchParams const spoiler = searchParams.get('spoiler') || 0 - const race = mystery ? 1 : searchParams.get('race') || 0 + const race = mystery || searchParams.get('race') === '1' if (preset == undefined) { const validPresets = getAllPresets() @@ -46,27 +43,22 @@ export async function GET(req: NextRequest, { params }: { params: GenerateParams throw err } - if (spoiler && !race) { - const err = new Error('Spoilers are currently only valid for race seeds') as HTTPError - err.status = 422 - throw err - } - - if (race) { - const hash = paramsToString(seedNum, preset.settings, preset.options) - const raceObj = { - key: nanoid(), - hash, - mystery, - spoiler: spoiler ? getSpoiler(hash) : null - } - await kv.hset(`race-${raceObj.key}`, raceObj) - const url = new URL(`race/${raceObj.key}`, req.nextUrl.origin) - return redirect(url) - } + const { settings, options } = preset; + options.Spoiler = spoiler ? true : false; - const hash = paramsToString(seedNum, preset.settings, preset.options) - const url = new URL(`seed/${hash}`, req.nextUrl.origin) + const graph = generateSeed(seed, settings, options); + const hash = encodeSeed({ seed, settings, options }, graph) + + const seedKey = await getNewSeedKey() + await saveSeedData( + seedKey, + hash, + mystery, + race, + options.Spoiler + ) + + const url = new URL(`seed/${seedKey}`, req.nextUrl.origin) return redirect(url) } catch (err: unknown) { console.error(err) diff --git a/apps/web/app/generate/form.tsx b/apps/web/app/generate/form.tsx index ee61580d..abbb0621 100644 --- a/apps/web/app/generate/form.tsx +++ b/apps/web/app/generate/form.tsx @@ -5,13 +5,13 @@ import Select from '../components/select' import Numeric from '../components/numeric' import styles from './page.module.css' import { downloadFile } from '@/lib/downloads' -import { cn, deepEqual } from '@/lib/utils' +import { cn, deepEqual } from '@/lib/utils' import VanillaButton, { useVanilla } from './vanilla' import { useForm } from 'react-hook-form' import { Button } from '../components/button' import Badge from '../components/badge' import useMounted from '../hooks/useMounted' -import { Item, RandomizeRom, paramsToString } from 'core' +import { Item, RandomizeRom } from 'core' import { BeamMode, BossMode, @@ -24,6 +24,7 @@ import { import { fetchSignature } from 'core' import { useCallback, useEffect, useState } from 'react' import Spacer from '../components/spacer' +import { getNewSeedKey, saveSeedData } from '@/lib/seed-data' const Sidebar = ({ name = null, @@ -148,10 +149,10 @@ const Option = ( export interface GenerateSeedSettings { 'item-split': 'standard-mm' | 'full' | 'chozo', - 'map-layout': 'standard' | 'randomized' | 'recall', + 'map-layout': 'standard' | 'randomized', boss: 'vanilla' | 'shifted' | 'shuffled' | 'surprise', minors: 'standard' | 'dash', - 'environment': 'standard' | 'dash-recall' | 'dash-classic', + 'environment': 'standard' | 'dash-classic', 'charge-beam': 'vanilla' | 'starter' | 'starter-plus', 'gravity-heat-reduction': 'off' | 'on', 'double-jump': 'off' | 'on', @@ -173,7 +174,6 @@ export interface GenerateFormParams extends GenerateSeedParams { | "chozo-bozo" | "sgl23" | "sgl24" - | "dash-recall" | "dash-classic" | "2017" | "custom" @@ -241,18 +241,6 @@ const MODES = { 'heat-shield': 'off', 'pressure-valve': 'none', }, - 'dash-recall': { - 'item-split': 'standard-mm', - 'map-layout': 'recall', - boss: 'vanilla', - minors: 'dash', - 'environment': 'dash-recall', - 'charge-beam': 'starter-plus', - 'gravity-heat-reduction': 'on', - 'double-jump': 'on', - 'heat-shield': 'on', - 'pressure-valve': 'one', - }, 'dash-classic': { 'item-split': 'standard-mm', 'map-layout': 'standard', @@ -316,6 +304,7 @@ type RolledSeed = { seed: any name: string hash: string + key: string } export default function Form() { @@ -355,7 +344,7 @@ export default function Form() { const onSubmit = async (data: GenerateFormParams) => { try { - const config = { vanillaBytes: vanilla, presetName: "Custom" }; + const config = { vanillaBytes: vanilla, presetName: "Custom", seedKey: "" }; const getSeed = () => { if (data['seed-mode'] === 'fixed') { @@ -370,9 +359,6 @@ export default function Form() { } let mapLayout = MapLayout.Standard; - if (data['environment'] == 'dash-recall') { - mapLayout = MapLayout.Recall; - } if (data['environment'] == 'dash-classic') { mapLayout = MapLayout.Classic; } @@ -383,9 +369,6 @@ export default function Form() { MinorDistributionMode.Standard let majorDistribution = MajorDistributionMode.Standard; - if (data['map-layout'] == 'recall') { - majorDistribution = MajorDistributionMode.Recall; - } if (data['item-split'] == "full") { majorDistribution = MajorDistributionMode.Full; } @@ -416,9 +399,7 @@ export default function Form() { bossMode: BossMode.Vanilla, }; - if (data.mode == 'dash-recall') { - config.presetName = "RecallMM"; - } else if (data.mode == 'dash-classic') { + if (data.mode == 'dash-classic') { config.presetName = "ClassicMM"; } else if (data.mode == '2017') { config.presetName = "2017MM"; @@ -459,6 +440,8 @@ export default function Form() { const options = { DisableFanfare: false, RelaxedLogic: false, + Mystery: false, + Spoiler: false }; if (data.fanfare == 'off') { options.DisableFanfare = true; @@ -468,13 +451,25 @@ export default function Form() { }; const seedNumber = getSeed(); - const { data: seed, name } = await RandomizeRom( - seedNumber, settings, options, config); - const hash = paramsToString(seedNumber, settings, options); + config.seedKey = await getNewSeedKey() + const { data: seed, hash } = await RandomizeRom( + seedNumber, + settings, + options, + config + ); + await saveSeedData( + config.seedKey, + hash, + options.Mystery, + false, + options.Spoiler + ); + const name = `DASH_${config.presetName}_${config.seedKey}.sfc` if (seed !== null) { downloadFile(seed, name, hash) } - setRolledSeed({ seed, name, hash }) + setRolledSeed({ seed, name, hash, key: config.seedKey }) } catch (error) { console.error('SEED ERROR', error) } @@ -497,17 +492,6 @@ export default function Form() { return } - if (name === 'map-layout') { - if (value['environment'] === 'dash-recall' && value['map-layout'] !== 'recall') { - setValue('environment', 'standard'); - value['environment'] = 'standard'; - } - if (value['environment'] !== 'dash-recall' && value['map-layout'] === 'recall') { - setValue('environment', 'dash-recall'); - value['environment'] = 'dash-recall'; - } - } - // Update mode if necessary updateMode(value) }) @@ -547,7 +531,6 @@ export default function Form() { { label: 'Surprise Surprise', value: 'surprise-surprise' }, { label: 'Chozo Bozo', value: 'chozo-bozo' }, { label: 'SG Live 2023', value: 'sgl23' }, - { label: 'DASH: Recall', value: 'dash-recall' }, { label: 'DASH: Classic', value: 'dash-classic' }, { label: 'Throwback 2017', value: '2017' }, { label: 'Custom', value: 'custom', hidden: true } @@ -609,7 +592,6 @@ export default function Form() { options={[ { label: 'Area Randomization', value: 'randomized' }, { label: 'Vanilla', value: 'standard' }, - { label: 'DASH: Recall', value: 'recall' }, ]} name="map-layout" register={register} @@ -637,13 +619,10 @@ export default function Form() {