return $seed->toJson();
}
+ public function presets() {
+ return array_values(AosrPresetCommand::$presets);
+ }
+
public function retry($hash) {
$seed = AosSeed::where('hash', '=', $hash)->firstOrFail();
--- /dev/null
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Container, Form, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import i18n from '../../i18n';
+
+const settings = [
+ 'logic',
+ 'nodupes',
+ 'panther',
+ 'area',
+ 'boss',
+ 'enemy',
+ 'itempool',
+ 'weight',
+ 'grahm',
+ 'kicker',
+ 'startshop',
+ 'shopprice',
+ 'shopSouls',
+ 'levelexp',
+ 'telestart',
+ 'mapassist',
+ 'doublechaos',
+ 'reqallsouls',
+ 'noww',
+ 'palette',
+];
+
+const settingValues = {
+ area: [
+ 'AreaRandom',
+ 'DoorRandom',
+ 'Vanilla',
+ ],
+ boss: [
+ 'Dead-endShuffle',
+ 'Vanilla',
+ ],
+ doublechaos: [
+ 'false',
+ 'true',
+ ],
+ enemy: [
+ 'RandomNoLimit',
+ 'RandomP20M5',
+ 'RandomP30M10',
+ 'RandomPM10',
+ 'RandomPM20',
+ 'RandomPMaxM5',
+ 'Vanilla',
+ ],
+ grahm: [
+ 'AllBosses',
+ 'BookSouls',
+ 'NoCheck',
+ ],
+ itempool: [
+ 'AllSouls',
+ 'Standard',
+ ],
+ kicker: [
+ 'false',
+ 'true',
+ ],
+ levelexp: [
+ 'Casual',
+ 'Hard',
+ 'Lvl1',
+ 'Vanilla',
+ ],
+ logic: [
+ 'AreaTechTiers',
+ 'AreaTechTiersHard',
+ 'ForwardFeed',
+ 'ForwardFeedHard',
+ 'HybridProgression',
+ 'VeryRandom',
+ 'VeryRandomHard',
+ 'VeryRandomHardOnly',
+ ],
+ mapassist: [
+ 'false',
+ 'true',
+ ],
+ nodupes: [
+ 'false',
+ 'true',
+ ],
+ noww: [
+ 'false',
+ 'true',
+ ],
+ palette: [
+ 'Mode1',
+ 'Mode1.5',
+ 'Mode2',
+ 'Vanilla',
+ ],
+ panther: [
+ 'AlwaysRand',
+ 'ExtraFairRand',
+ 'FirstAlways',
+ 'NeverExists',
+ 'Rand70Dup',
+ ],
+ reqallsouls: [
+ 'false',
+ 'true',
+ ],
+ shopprice: [
+ 'RandHV',
+ 'Vanilla',
+ ],
+ shopSouls: [
+ '2PerGroup',
+ 'Half',
+ 'OnlySouls',
+ 'Vanilla',
+ ],
+ startshop: [
+ 'Unlocked',
+ 'Unlocked30k',
+ 'Vanilla',
+ ],
+ telestart: [
+ 'false',
+ 'true',
+ ],
+ weight: [
+ '0',
+ '1.0',
+ '1.5',
+ '2.0',
+ '2.5',
+ '3.0',
+ '3.5',
+ ],
+};
+
+const Generate = ({
+ handleBlur,
+ handleChange,
+ handleSubmit,
+ presets,
+ setFieldValue,
+ values,
+}) =>
+<Container>
+ <h1>{i18n.t('aosGenerate.heading')}</h1>
+ <Form noValidate onSubmit={handleSubmit}>
+ <Row>
+ <Col md={6}>
+ <Form.Group controlId="generate.preset">
+ <Form.Label>
+ {i18n.t('aosSeeds.preset')}
+ </Form.Label>
+ <Form.Select
+ name="preset"
+ onBlur={handleBlur}
+ onChange={e => {
+ const presetName = e.target.value;
+ const preset = presets.find(p => p.value === presetName);
+ if (preset) {
+ setFieldValue('settings', preset.settings);
+ }
+ return handleChange(e);
+ }}
+ value={values.preset}
+ >
+ <option value="custom">{i18n.t('aosSeeds.presets.custom')}</option>
+ {presets.map(preset =>
+ <option key={preset.value} value={preset.value}>
+ {i18n.t(`aosSeeds.presets.${preset.value}`)}
+ </option>
+ )}
+ </Form.Select>
+ </Form.Group>
+ </Col>
+ <Col sm={6} md={3}>
+ <Form.Group controlId="generate.submit">
+ <Form.Label>
+ {i18n.t('button.generate')}
+ </Form.Label>
+ <div>
+ <Button type="submit">
+ {i18n.t('button.generate')}
+ </Button>
+ </div>
+ </Form.Group>
+ </Col>
+ </Row>
+ <Row>
+ {settings.map(setting =>
+ <Form.Group as={Col} md={4} key={setting} controlId={`generate.${setting}`}>
+ <Form.Label>
+ {i18n.t(`aosSeeds.settingName.${setting}`)}
+ </Form.Label>
+ <Form.Select
+ name={`settings[${setting}]`}
+ onBlur={handleBlur}
+ onChange={e => {
+ setFieldValue('preset', 'custom');
+ return handleChange(e);
+ }}
+ value={values.settings[setting]}
+ >
+ {settingValues[setting].map(value =>
+ <option key={value} value={value}>
+ {i18n.t(`aosSeeds.settingValue.${setting}.${value}`)}
+ </option>
+ )}
+ </Form.Select>
+ </Form.Group>
+ )}
+ </Row>
+ </Form>
+</Container>;
+
+Generate.propTypes = {
+ handleBlur: PropTypes.func,
+ handleChange: PropTypes.func,
+ handleSubmit: PropTypes.func,
+ presets: PropTypes.arrayOf(PropTypes.shape({
+ settings: PropTypes.shape({
+ }),
+ value: PropTypes.string,
+ })),
+ setFieldValue: PropTypes.func,
+ values: PropTypes.shape({
+ preset: PropTypes.string,
+ settings: PropTypes.shape({
+ }),
+ }),
+};
+
+export default withFormik({
+ displayName: 'AosGenerateForm',
+ mapPropsToValues: () => ({
+ preset: 'Normal',
+ settings: {
+ area: 'Vanilla',
+ boss: 'Vanilla',
+ doublechaos: 'false',
+ enemy: 'Vanilla',
+ grahm: 'BookSouls',
+ itempool: 'Standard',
+ kicker: 'false',
+ levelexp: 'Vanilla',
+ logic: 'AreaTechTiers',
+ mapassist: 'false',
+ nodupes: 'false',
+ noww: 'false',
+ palette: 'Vanilla',
+ panther: 'Rand70Dup',
+ reqallsouls: 'false',
+ shopprice: 'Vanilla',
+ shopSouls: 'Vanilla',
+ startshop: 'Vanilla',
+ telestart: 'false',
+ weight: '2.5',
+ },
+ }),
+})(withTranslation()(Generate));
import Header from './Header';
import AosFront from '../pages/AosFront';
+import AosGenerate from '../pages/AosGenerate';
import AosSeed from '../pages/AosSeed';
import Tracker from '../pages/AosTracker';
import User from '../pages/User';
<UserContext.Provider value={user}>
<Header doLogout={doLogout} />
<Routes>
+ <Route path="generate" element={<AosGenerate />} />
<Route path="h/:hash" element={<AosSeed />} />
<Route path="tracker" element={<Tracker />} />
<Route path="users/:id" element={<User />} />
--- /dev/null
+import axios from 'axios';
+import React, { useCallback, useEffect, useState } from 'react';
+
+import Generate from '../aos-generate/Generate';
+import ErrorBoundary from '../common/ErrorBoundary';
+import ErrorMessage from '../common/ErrorMessage';
+import Loading from '../common/Loading';
+import i18n from '../../i18n';
+
+const AosGenerate = () => {
+ const [error, setError] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [presets, setPresets] = useState([]);
+
+ const loadPresets = useCallback(ctrl => {
+ axios
+ .get('/api/aos-presets', { signal: ctrl.signal })
+ .then(response => {
+ setError(null);
+ setLoading(false);
+ setPresets(response.data);
+ })
+ .catch(error => {
+ setError(error);
+ setLoading(false);
+ setPresets([]);
+ });
+ }, []);
+
+ useEffect(() => {
+ setLoading(true);
+ const ctrl = new AbortController();
+ loadPresets(ctrl);
+ return () => {
+ ctrl.abort();
+ };
+ }, []);
+
+ useEffect(() => {
+ window.document.title = i18n.t('aosGenerate.heading');
+ }, [i18n.language]);
+
+ if (loading) {
+ return <Loading />;
+ }
+
+ if (error) {
+ return <ErrorMessage error={error} />;
+ }
+
+ return <ErrorBoundary>
+ <Generate presets={presets} />
+ </ErrorBoundary>;
+};
+
+export default AosGenerate;
setBaseRom: 'Base ROM auswählen',
tourneyDiscord: 'Turnier Discord',
},
+ aosGenerate: {
+ heading: 'AoSR Seed Generieren',
+ },
aosSeeds: {
date: '{{ date, L LT }}',
fetchingPatch: 'Lade Patch',
AreaRequireAllSouls: 'Area alle Seelen',
AreaSpicy: 'Area spicy',
Beginner: 'Beginner',
+ custom: 'Custom',
DoorAllBosses: 'Door alle Bosse',
DoorAllBossesEasy: 'Door alle Bosses einfach',
ExtraFastNormal: 'Extra schnell normal',
chart: 'Diagramm',
close: 'Schließen',
edit: 'Bearbeiten',
+ generate: 'Generieren',
help: 'Hilfe',
login: 'Login',
logout: 'Logout',
setBaseRom: 'Set base ROM',
tourneyDiscord: 'Tournament Discord',
},
+ aosGenerate: {
+ heading: 'Generate AoSR Seed',
+ },
aosSeeds: {
date: '{{ date, L LT }}',
fetchingPatch: 'Fetching patch',
AreaRequireAllSouls: 'Area require all souls',
AreaSpicy: 'Area spicy',
Beginner: 'Beginner',
+ custom: 'Custom',
DoorAllBosses: 'Door all bosses',
DoorAllBossesEasy: 'Door all bosses easy',
ExtraFastNormal: 'Extra fast normal',
chart: 'Chart',
close: 'Close',
edit: 'Edit',
+ generate: 'Generate',
help: 'Help',
login: 'Login',
logout: 'Logout',
Route::post('alttp-seed/{hash}/retry', 'App\Http\Controllers\AlttpSeedController@retry');
Route::post('aos-generate', 'App\Http\Controllers\AosSeedController@generate');
+Route::get('aos-presets', 'App\Http\Controllers\AosSeedController@presets');
Route::get('aos-seed/{hash}', 'App\Http\Controllers\AosSeedController@byHash');
Route::post('aos-seed/{hash}/retry', 'App\Http\Controllers\AosSeedController@retry');