Presets and categories (#73)

* add code categories

* add exclusives and dependencies

* add code selection presets

* remove standard category from some codes

* remove presets from nozzle lock

* reset preset selection on select & unselect stage loader

* update some translations

* remove stage loader from selection when changing versions

* add stage loader help text & warn when changing version if a code is selected

* prevent selecting disabled codes

* drop yarn in favor of npm

* Update Codes.xml

* reset code preset select on cancel

* minor style changes
This commit is contained in:
Matteias Collet 2021-10-10 15:45:53 +02:00 committed by GitHub
parent 12c9379f7e
commit 527ed6fbc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 12157 additions and 8441 deletions

View file

@ -5,7 +5,7 @@
"args": { "VARIANT": "14" }
},
"settings": {
"terminal.integrated.defaultProfile.linux": "/bin/bash"
"terminal.integrated.defaultProfile.linux": "bash"
},
"extensions": [
"dbaeumer.vscode-eslint",
@ -14,6 +14,6 @@
"wayou.vscode-todo-highlight",
],
"forwardPorts": [8080],
"postCreateCommand": "yarn install",
"postCreateCommand": "npm install",
"remoteUser": "node"
}

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<codes>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">DPad Functions</title>
<title lang="de-CH">DPad Funktionen</title>
<title lang="fr-FR">Fonctions de la croix directionnelle</title>
@ -234,6 +236,7 @@
</source>
</code>
<code>
<category>misc</category>
<title lang="en-US">Nozzle Lock</title>
<title lang="fr-FR">Verrouillage de buses</title>
<author>Psychonauter, Dan Salvato, Link Master, James0x57</author>
@ -325,6 +328,7 @@
</source>
</code>
<code>
<category>misc</category>
<title lang="en-US">Coin Count Savestate</title>
<title lang="de-CH">Münzenzahl Speicherstand</title>
<author>Psychonauter</author>
@ -384,6 +388,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Infinite Lives</title>
<title lang="de-CH">Unendlich Leben</title>
<title lang="fr-FR">Vies infinies</title>
@ -409,6 +415,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Disable Blue Coin Flag</title>
<title lang="de-CH">Deaktiviere Blaue-Münzen-Kennung</title>
<title lang="fr-FR">Désactiver la sauvegarde des pièces bleues</title>
@ -450,6 +458,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il,hfsetup</presets>
<title lang="en-US">FMV Skips</title>
<title lang="de-CH">FMV Skips</title>
<title lang="fr-FR">Passer les FMV</title>
@ -479,6 +489,7 @@
</source>
</code>
<code>
<category>cosmetic</category>
<title lang="en-US">Mute Background Music</title>
<title lang="de-CH">Hintergrundmusik stummschalten</title>
<title lang="fr-FR">Supprimer la musique de fond</title>
@ -504,6 +515,7 @@
</source>
</code>
<!--<code>
<category>misc</category>
<title lang="en-US">Remove Save Boxes</title>
<title lang="de-CH">Speicher-Schaltfläche entfernen</title>
<title lang="fr-FR">Supprimer les boîtes de sauvegarde</title>
@ -533,6 +545,8 @@
</source>
</code>-->
<code>
<category>qol</category>
<presets>recommended,il</presets>
<title lang="en-US">Unlock Yoshi</title>
<title lang="de-CH">Yoshi Freischalten</title>
<title lang="fr-FR">Débloquer Yoshi</title>
@ -562,6 +576,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>recommended,il</presets>
<title lang="en-US">Unlock Nozzles</title>
<title lang="de-CH">Düsen freischalten</title>
<title lang="fr-FR">Débloquer les buses</title>
@ -591,6 +607,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Free Pause</title>
<title lang="de-CH">Freies Pausieren</title>
<title lang="fr-FR">Pause libre</title>
@ -648,6 +666,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il,hfsetup</presets>
<title lang="en-US">Enable Exit Area Everywhere</title>
<title lang="de-CH">'Level Verlassen' überall aktivieren</title>
<title lang="fr-FR">Activer « Sortir de la zone » partout</title>
@ -673,6 +693,8 @@
</source>
</code>
<code>
<category>timer</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Shine Get Timer</title>
<title lang="de-CH">Shine Get Timer</title>
<title lang="fr-FR">Chronomètre Shine Get</title>
@ -1198,6 +1220,7 @@
</source>
</code>
<code>
<category>timer</category>
<title lang="en-US">Quarterframe Timer (Experimental)</title>
<author>Noki Doki</author>
<version>0.1</version>
@ -1419,6 +1442,8 @@
</source>
</code>
<code>
<category>loader</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Level Select</title>
<title lang="de-CH">Level Select</title>
<title lang="fr-FR">Sélecteur de niveau</title>
@ -1985,6 +2010,8 @@
</source>
</code>
<code>
<category>loader</category>
<presets>fap</presets>
<title lang="en-US">Fast Any%</title>
<title lang="de-CH">Fast Any%</title>
<title lang="fr-FR">Fast Any%</title>
@ -2532,6 +2559,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>recommended,il</presets>
<title lang="en-US">Any Fruit Opens Yoshi Eggs</title>
<title lang="de-CH">Jede Frucht öffnet Yoshi-Eier</title>
<title lang="fr-FR">Tous les fruits ouvrent les œufs de Yoshi</title>
@ -2557,6 +2586,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>recommended,il</presets>
<title lang="en-US">Infinite Juice</title>
<title lang="de-CH">Unendlich Saft</title>
<title lang="fr-FR">Jus infini</title>
@ -2582,6 +2613,7 @@
</source>
</code>
<!--<code>
<category>loader</category>
<title lang="en-US">Stage Randomizer (Experimental)</title>
<title lang="de-CH">Stage Randomizer (Experimentell)</title>
<title lang="fr-FR">Randomiseur de niveaux (expérimental)</title>
@ -2657,6 +2689,7 @@
</source>
</code>-->
<code>
<category>cosmetic</category>
<title lang="en-US">Replace Episode names with their ID</title>
<title lang="de-CH">Ersetze Episodennamen mit ihrer ID</title>
<title lang="fr-FR">Remplacer les noms d'épisodes par leur numéro</title>
@ -2710,6 +2743,7 @@
</source>
</code>
<code>
<category>misc</category>
<title lang="en-US">Position/angle/speed display</title>
<title lang="de-CH">Position/Winkel/Geschw. Display</title>
<title lang="fr-FR">Affichage de position/angle/vitesse</title>
@ -3015,6 +3049,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Intro Skip</title>
<title lang="de-CH">Überspringbare Intros</title>
<title lang="fr-FR">Passer l'intro</title>
@ -3066,7 +3102,7 @@
B07F000E B01F0010
4BFFFEB0 00000000
</source>
<source version="GMSP01">
<source version="GMSP01" exclude-from-presets="true">
0428D4C4 48000264
0428D9B8 48000014
0629E51C 00000014
@ -3076,6 +3112,8 @@
</source>
</code>
<code>
<category>qol</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Respawn One-Time Shines</title>
<title lang="de-CH">Einmalige Shines Respawnen</title>
<title lang="fr-FR">Restaurer les Shines uniques</title>
@ -3109,6 +3147,8 @@
</source>
</code>
<code>
<category>misc</category>
<presets>standard,recommended,il</presets>
<title lang="en-US">Force Plaza Events</title>
<title lang="de-CH">Erzwungene Plaza Events</title>
<title lang="fr-FR">Forcer les événements de la place Delfino</title>
@ -3162,6 +3202,7 @@
</source>
</code>
<code>
<category>memcardpatch</category>
<title lang="en-US">Force SJIS Memory Card Encoding</title>
<title lang="fr-FR">Forcer l'encodage SJIS pour la carte mémoire</title>
<author>Noki Doki</author>
@ -3177,6 +3218,7 @@
</source>
</code>
<code>
<category>memcardpatch</category>
<title lang="en-US">Force ANSI Memory Card Encoding</title>
<title lang="fr-FR">Forcer l'encodage ANSI pour la carte mémoire</title>
<author>Noki Doki</author>
@ -3195,6 +3237,8 @@
</source>
</code>
<code>
<category>misc</category>
<presets>standard,recommended,il,fap</presets>
<title lang="en-US">Fix Manta Splitting</title>
<title lang="de-CH">Fix Manta Splitting</title>
<title lang="fr-FR">Corriger la séparation de la raie manta</title>
@ -3243,6 +3287,7 @@
</source>
</code>
<code>
<category>cosmetic</category>
<title lang="en-US">Shine Outfit</title>
<title lang="de-CH">Shine Outfit</title>
<title lang="fr-FR">Tenue Shine</title>

View file

@ -47,28 +47,25 @@ Note that in the code reference files everything following the `<!-- injectionpo
If you intend to change site code you need [NodeJS](https://nodejs.org/en/) version 14.X LTS installed on your local.
```sh
# Install yarn
npm i -g yarn
# Install dependencies
yarn
npm i
# Run project in watch mode
# This will serve the page in development mode on http://localhost:8080
yarn dev
npm run dev
# Build project
yarn build
npm run build
```
The XML codes will be written automatically to the json file and code reference during the following actions:
- Starting the development server with `yarn dev`
- Building the site with `yarn build`
- Starting the development server with `npm run dev`
- Building the site with `npm run build`
If you want to inject the codes at any given point you can use `yarn codes:inject`.
If you want to inject the codes at any given point you can use `npm run codes:inject`.
**!!! Note that if yarn was used, `yarn codes:clean` is ran automatically as a pre-commit hook, removing all injected codes and staging ALL changes.** If you want to commit changes without cleaning codes first you have to commit through `git commit --no-verify`.
**!!! Note that if npm was used, `npm run codes:clean` is ran automatically as a pre-commit hook, removing all injected codes and staging ALL changes.** If you want to commit changes without cleaning codes first you have to commit through `git commit --no-verify`.
### Build and preview the site (Docker)

View file

@ -6,8 +6,8 @@ RUN pwsh -File ./scripts/build_archives.ps1
FROM node:lts-buster AS build
WORKDIR /src
COPY --from=prebuild /src .
RUN yarn
RUN yarn build
RUN npm i
RUN npm run build
FROM mcr.microsoft.com/powershell:latest AS final
WORKDIR /src

View file

@ -6,8 +6,8 @@ RUN pwsh -File ./scripts/build_archives.ps1
FROM node:lts-buster AS build
WORKDIR /src
COPY --from=prebuild /src .
RUN yarn
RUN yarn build
RUN npm i
RUN npm run build
FROM httpd:latest AS final
WORKDIR /usr/local/apache2/htdocs/

11728
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,13 +9,13 @@
},
"repository": "https://github.com/BitPatty/gctGenerator/gctGenerator",
"scripts": {
"dev": "yarn codes:inject && yarn translations:compare && vuepress dev site",
"build": "node ./scripts/inject_codes.js && yarn translations:compare && vuepress build site",
"dev": "npm run codes:inject && npm run translations:compare && vuepress dev site",
"build": "node ./scripts/inject_codes.js && npm run translations:compare && vuepress build site",
"format": "prettier --write ./site/**/*{.md,.js,.json,.vue}",
"translations:compare": "node ./scripts/compare_translations.js",
"codes:inject": "node ./scripts/inject_codes.js && yarn format",
"codes:clean": "node ./scripts/clean_codes.js && yarn format",
"precommit": "yarn codes:clean && git add ."
"codes:inject": "node ./scripts/inject_codes.js && npm run format",
"codes:clean": "node ./scripts/clean_codes.js && npm run format",
"precommit": "npm run codes:clean && git add ."
},
"license": "Apache-2.0",
"devDependencies": {

View file

@ -10,6 +10,11 @@ const md = require('@vuepress/markdown')({
const themePlugins = require(path.join(__dirname, '../site/.vuepress/data/themePlugins.json'));
const locales = require(path.join(__dirname, '../site/.vuepress/i18n/locales.json'));
const codeCategories = require(path.join(__dirname, '../site/.vuepress/data/codeCategories.json'));
const presetCategories = require(path.join(
__dirname,
'../site/.vuepress/data/presetCategories.json',
));
const xml = fs.readFileSync(path.join(__dirname, `../Codes.xml`));
// Constants
@ -37,6 +42,22 @@ const validateXML = (xmlString) => {
if (!codeTitle || !codeTitle.textContent)
throw new Error(`Missing Fallback Title (en-US) in code nr ${i}`);
// Code has a valid category
const codeCategory = codes[i].querySelector('category');
if (!codeCategory || !codeCategory.textContent)
throw new Error(`Missing code category in ${codeTitle.textContent}`);
if (!codeCategories.map((c) => c.identifier).includes(codeCategory.textContent))
throw new Error(`Invalid code category for ${codeTitle.textContent}`);
const codePresets = codes[i].querySelector('presets');
if (codePresets && codePresets.textContent) {
for (const preset of codePresets.textContent.split(',')) {
if (!presetCategories.map((c) => c.identifier).includes(preset))
throw new Error(`Invalid preset ${preset} for ${codeTitle.textContent}`);
}
}
// All lang attributes on all titles are valid
const codeTitles = codes[i].querySelectorAll('title');
for (let j = 0; j < codeTitles.length; j++) {
@ -177,6 +198,23 @@ const readTextNode = (node, identifier, lang = null, fallbackLang = null) => {
throw new Error(`No fallback ${identifier} found on ${node.textContent}`);
};
/**
* Reads the presets from the specified code
* @param {*} node The parent node
* @param {*} gameVersion The target game version
* @returns The list of presets
*/
const readPresetList = (node, gameVersion) => {
if (!node) throw new Error('No node provided');
const presets = node.querySelector('presets');
if (!presets || !presets.textContent) return [];
const targetCode = node.querySelector(`source[version='${gameVersion}']`);
if (!targetCode) return [];
const exclusionAttribute = targetCode.getAttribute('exclude-from-presets');
if (exclusionAttribute === 'true') return [];
return presets.textContent.split(',');
};
/**
* Creates an object of localized child nodes
* @param {*} node The parent node
@ -247,6 +285,8 @@ const parseXml = (xmlString, gameVersion = null) => {
version: readTextNode(code, 'version'),
date: readTextNode(code, 'date'),
source: readCode(code, 'source', gameVersion),
presets: readPresetList(code, gameVersion),
category: readTextNode(code, 'category'),
}))
.filter((code) => code.source != null);
};

View file

@ -1,25 +1,52 @@
<template>
<ul>
<li
v-for="(code, idx) in availableCodes"
v-bind:key="idx"
:class="code.selected ? 'checked' : ''"
@click="toggle(code)"
@mouseover="inspect(code)"
>
{{ getCodeTitle(code) }}
</li>
</ul>
<div>
<div class="preset-select">
<SelectComponent
:options="getPresetOptions()"
:onChange="(v) => loadPreset(v)"
:placeholder="getPresetPlaceholder()"
:key="generation"
/>
</div>
<div v-for="category in codeCategories" v-bind:key="category.identifier" class="code-group">
<div class="category-title">{{ getCategoryTitle(category) }}</div>
<ul>
<li
v-for="(code, idx) in availableCodes.filter((c) => c.category === category.identifier)"
v-bind:key="idx"
:class="code.selected ? 'checked' : code.disabled ? 'disabled' : ''"
@click="toggle(code)"
@mouseover="inspect(code)"
>
{{ getCodeTitle(code) }}
</li>
<li
v-if="category.identifier === 'loader'"
:class="stageLoaderSelected ? 'checked' : ''"
@click="toggleStageLoader()"
@mouseover="showStageLoaderHelp()"
>
{{ getStageLoaderLabel() }}
</li>
</ul>
</div>
</div>
</template>
<script>
import { translateCode } from '../i18n/localeHelper';
import SelectComponent from './SelectComponent';
import { translateCode, translate } from '../i18n/localeHelper';
import codeCategories from '../data/codeCategories.json';
import presetCategories from '../data/presetCategories.json';
export default {
props: {
codes: { type: Array },
onSelectionChanged: { type: Function },
onInspect: { type: Function },
onStageLoaderToggle: { type: Function },
onInspectStageLoader: { type: Function },
},
mounted() {
this.populate();
@ -27,32 +54,150 @@ export default {
watch: {
codes: function () {
this.populate();
this.unselectStageLoader();
},
},
data() {
return {
availableCodes: [],
codeCategories,
presetCategories,
stageLoaderSelected: false,
generation: 0,
};
},
methods: {
getPresetOptions() {
return presetCategories.map((c) => ({
label: c.i18nKey,
value: c.identifier,
}));
},
loadPreset(identifier) {
if (
(this.stageLoaderSelected || this.availableCodes.find((c) => c.selected)) &&
!confirm(translate('common.selectionreset', this.$lang))
) {
this.generation++;
return;
}
for (const code of this.availableCodes) {
code.selected = code.presets.includes(identifier);
}
this.unselectStageLoader();
this.onSelectionChanged(this.availableCodes.filter((c) => c.selected));
this.refreshDisabledCodes();
this.generation++;
},
getPresetPlaceholder() {
return translate('common.loadpresetplaceholder', this.$lang);
},
unselectStageLoader() {
if (this.stageLoaderSelected) {
this.stageLoaderSelected = false;
this.onStageLoaderToggle(false);
}
},
getCodeTitle(code) {
return translateCode(code, this.$lang).title;
},
toggle(code) {
code.selected = !code.selected;
getCategoryTitle(category) {
return translate(category.i18nKey, this.$lang);
},
getStageLoaderLabel() {
return translate('headers.stageloader', this.$lang);
},
toggleStageLoader() {
for (const c of this.availableCodes.filter((c) => c.category === 'loader' && c.selected)) {
c.selected = false;
}
const newState = !this.stageLoaderSelected;
this.stageLoaderSelected = newState;
this.onStageLoaderToggle(newState);
this.onSelectionChanged(this.availableCodes.filter((c) => c.selected));
this.refreshDisabledCodes();
},
refreshDisabledCodes() {
for (const dependentCategory of codeCategories.filter((c) => c.dependsOn.length > 0)) {
for (const dependency of dependentCategory.dependsOn) {
const enableCodes =
(dependency === 'loader' && this.stageLoaderSelected) ||
this.availableCodes.find((c) => c.selected && c.category === dependency);
for (const code of this.availableCodes.filter(
(c) => c.category === dependentCategory.identifier && c.disabled !== !enableCodes,
)) {
code.disabled = !enableCodes;
if (code.disabled && code.selected) {
this.toggle(code);
}
}
}
}
},
toggle(code) {
if (!code.selected && codeCategories.find((c) => c.identifier === code.category).exclusive) {
for (const availableCode of this.availableCodes.filter(
(c) => c.category === code.category && c.selected,
)) {
availableCode.selected = false;
}
}
if (!code.selected && code.category === 'loader' && this.stageLoaderSelected) {
this.stageLoaderSelected = false;
this.onStageLoaderToggle(false);
}
code.selected = code.disabled ? false : !code.selected;
this.onSelectionChanged(this.availableCodes.filter((c) => c.selected));
this.refreshDisabledCodes();
},
populate() {
this.availableCodes = this.codes.map((c) => ({ ...c, selected: false }));
this.refreshDisabledCodes();
},
inspect(code) {
this.onInspect(code);
},
showStageLoaderHelp() {
this.onInspectStageLoader();
},
},
};
</script>
<style scoped>
.category-title {
color: white;
font-weight: 500;
text-align: center;
background: #383838b5;
padding-top: 2px;
padding-bottom: 2px;
margin-bottom: 0;
}
.category-title ~ ul {
margin-top: 0;
}
.preset-select {
margin-bottom: 20px;
}
.code-group {
border: 1px solid #d7d7d7;
margin-bottom: 20px;
}
.code-group ul {
margin-bottom: 0;
}
ul {
list-style-type: none;
padding-left: 0;
@ -74,11 +219,15 @@ ul li {
text-align: left;
}
ul li {
background: #f9f9f9;
}
ul li:nth-child(odd) {
background: #e7e7e7;
}
ul li:hover {
ul li:not(.disabled):hover {
background: #3eaf7c;
color: #fff;
}
@ -93,6 +242,15 @@ ul li.checked {
color: #fff;
}
ul li.disabled {
background: #c7c7c7;
color: #767676;
}
ul li.disabled:hover {
cursor: not-allowed;
}
li {
position: relative;
padding-left: 26px;
@ -111,7 +269,7 @@ li::before {
width: 10px;
}
li:hover::before {
li:not(.disabled):not(.checked):hover::before {
border-color: #fff;
background-color: #1fa76e;
}

View file

@ -3,20 +3,16 @@
<section class="config">
<div>
<span>{{ getLabel('generatorconfig.gameversion.label') }}</span>
<VersionSelect :onChange="onVersionChanged" :selectedValue="selectedVersion" />
<VersionSelect
:onChange="onVersionChanged"
:selectedValue="selectedVersion"
:key="generation"
/>
</div>
<div>
<span>{{ getLabel('generatorconfig.downloadformat.label') }}</span>
<FormatSelect :onChange="onFormatChanged" :selectedValue="selectedFormat" />
</div>
<div>
<span>{{ getLabel('generatorconfig.usestageloader') }}</span>
<SelectComponent
:options="useStageLoaderOptions"
:onChange="onStageLoaderChanged"
:value="useStageLoader"
/>
</div>
<div>
<span>{{ getLabel('common.download') }}</span>
<DownloadButton
@ -33,9 +29,11 @@
<div v-if="codes && codes.length > 0">
<h3>{{ getLabel('headers.codelist') }}</h3>
<CodeList
:onStageLoaderToggle="onStageLoaderToggle"
:codes="codes"
:onSelectionChanged="onCheatSelectionChanged"
:onInspect="inspect"
:onInspectStageLoader="displayStageLoaderHelp"
/>
</div>
<div class="prevent-shrink" v-if="codes && codes.length > 0 && useStageLoader">
@ -46,6 +44,12 @@
<div v-if="codes && codes.length > 0" class="help">
<h3>{{ getLabel('headers.help') }}</h3>
<CodeInfo v-if="!!inspectingCode" :code="inspectingCode" />
<div v-else-if="showStageLoaderHelp">
<h3>{{ getLabel('headers.stageloader') }}</h3>
<div>
{{ getLabel('stageloader.help') }}
</div>
</div>
<div v-else>{{ getLabel('misc.defaulthelpmessage') }}</div>
</div>
<div v-if="selectedVersion == null" class="help">
@ -116,10 +120,8 @@ export default {
selectedFormat: 'gct',
useStageLoader: false,
stageLoaderCodes: [],
useStageLoaderOptions: [
{ value: false, label: 'common.no' },
{ value: true, label: 'common.yes' },
],
showStageLoaderHelp: false,
generation: 0,
};
},
methods: {
@ -127,11 +129,20 @@ export default {
return translate(key, this.$lang);
},
onVersionChanged(e) {
if (
this.selectedCheats.length > 0 &&
!confirm(translate('common.selectionreset', this.$lang))
) {
this.generation++;
return;
}
this.selectedVersion = e;
this.selectedCheats = [];
this.codes = gameVersions.find((c) => c.identifier === e).codes;
this.stageLoaderCodes = gameVersions.find((c) => c.identifier === e).fastCode;
this.inspectingCode = null;
this.showStageLoaderHelp = false;
try {
window._paq.push([
'trackEvent',
@ -152,15 +163,15 @@ export default {
]);
} catch {}
},
onStageLoaderChanged(e) {
this.useStageLoader = e === true || e === 'true';
onStageLoaderToggle(enabled) {
this.useStageLoader = enabled;
if (!this.useStageLoader) this.selectedStageLoader = null;
try {
window._paq.push([
'trackEvent',
'GCT Generator',
'Change StageLoader State',
JSON.stringify({ enabled: e }),
JSON.stringify({ enabled }),
]);
} catch {}
},
@ -173,7 +184,12 @@ export default {
onStageLoaderCodeChanged(e) {
this.selectedStageLoader = e;
},
displayStageLoaderHelp() {
this.inspectingCode = null;
this.showStageLoaderHelp = true;
},
inspect(code) {
this.showStageLoaderHelp = false;
this.inspectingCode = code;
},
},
@ -183,6 +199,7 @@ export default {
section {
display: flex;
flex-wrap: nowrap;
position: relative;
}
.prevent-shrink {
@ -209,7 +226,11 @@ section > div:not(:first-child) {
}
.help {
position: sticky;
top: 80px;
text-align: left;
align-self: flex-start;
width: 100%;
}
.centered {

View file

@ -1,5 +1,14 @@
<template>
<div>
<div class="sub">
<GroupSelectComponent
:placeholder="getLabel('common.loadpresetplaceholder')"
:optGroups="stageLoaderPresetOptions"
:onChange="onStageLoaderPresetSelected"
selectedValue="placeholder"
:key="generation + 1"
/>
</div>
<div class="config">
<span>{{ getLabel('stageloader.removedialogue.label') }}</span>
<SelectComponent
@ -69,15 +78,6 @@
<div class="sub">
<ButtonComponent :label="getLabel('stageloader.clear')" :onClick="onClearList" />
</div>
<div class="sub">
<GroupSelectComponent
:placeholder="getLabel('stageloader.loadpresetplaceholder')"
:optGroups="stageLoaderPresetOptions"
:onChange="onStageLoaderPresetSelected"
selectedValue="placeholder"
:key="generation + 1"
/>
</div>
</div>
</div>
</template>
@ -188,7 +188,7 @@ export default {
if (
this.selectedRoute?.length > 0 &&
!confirm('Loading a preset will erase your current list. Continue?')
!confirm(translate('common.selectionreset', this.$lang))
) {
return;
}

View file

@ -0,0 +1,38 @@
[
{
"identifier": "qol",
"i18nKey": "generatorconfig.categories.qol",
"exclusive": false,
"dependsOn": []
},
{
"identifier": "loader",
"i18nKey": "generatorconfig.categories.loader",
"exclusive": true,
"dependsOn": []
},
{
"identifier": "timer",
"i18nKey": "generatorconfig.categories.timer",
"exclusive": false,
"dependsOn": ["loader"]
},
{
"identifier": "misc",
"i18nKey": "generatorconfig.categories.misc",
"exclusive": false,
"dependsOn": []
},
{
"identifier": "memcardpatch",
"i18nKey": "generatorconfig.categories.memcardpatch",
"exclusive": true,
"dependsOn": []
},
{
"identifier": "cosmetic",
"i18nKey": "generatorconfig.categories.cosmetic",
"exclusive": false,
"dependsOn": []
}
]

View file

@ -0,0 +1,22 @@
[
{
"identifier": "standard",
"i18nKey": "generatorconfig.presets.standard"
},
{
"identifier": "recommended",
"i18nKey": "generatorconfig.presets.recommended"
},
{
"identifier": "il",
"i18nKey": "generatorconfig.presets.il"
},
{
"identifier": "fap",
"i18nKey": "generatorconfig.presets.fap"
},
{
"identifier": "hfsetup",
"i18nKey": "generatorconfig.presets.hfsetup"
}
]

View file

@ -6,12 +6,14 @@
"GMSE01": "GMSE01 (NTSC-U)",
"GMSJ01": "GMSJ01 (NTSC-J 1.0)",
"GMSJ0A": "GMSJ01 (NTSC-J 1.1)",
"GMSP01": "GMSP01 (PAL)"
"GMSP01": "GMSP01 (PAL)",
"loadpresetplaceholder": "Lade eine Vorlage..",
"selectionreset": "Deine Auswahl wird zurückgesetzt. Fortfahren?"
},
"headers": {
"help": "Hilfe",
"codelist": "Verfügbare Codes",
"stageloader": "Stage Loader"
"stageloader": "Stage List Loader"
},
"codeinfo": {
"author": "Autor:",
@ -23,7 +25,6 @@
"label": "Spiel Version:",
"placeholder": "Wähle Version.."
},
"usestageloader": "Stage Loader verwenden:",
"downloadformat": {
"label": "Download Format:",
"options": {
@ -31,6 +32,21 @@
"dolphin": "Dolphin INI",
"gcm": "CheatManager TXT"
}
},
"categories": {
"qol": "Allgemein",
"loader": "Loader",
"timer": "Timer",
"misc": "Misc",
"memcardpatch": "Memory Card Patches",
"cosmetic": "Kosmetisch"
},
"presets": {
"standard": "Standard",
"recommended": "Empfohlen",
"il": "IL Runs",
"fap": "Fast Any%",
"hfsetup": "Hacked File Setup"
}
},
"landingpage": {
@ -46,6 +62,7 @@
}
},
"stageloader": {
"help": "Ladet die Level in einer benutzerdefinierten Reihenfolge.",
"levelorder": {
"label": "Level Reihenfolge:",
"options": {
@ -260,7 +277,6 @@
}
},
"levelselectplaceholder": "Wähle ein Level..",
"loadpresetplaceholder": "Lade eine Vorlage..",
"route": "Route",
"clear": "Liste leeren"
},

View file

@ -6,7 +6,9 @@
"GMSE01": "GMSE01 (NTSC-U)",
"GMSJ01": "GMSJ01 (NTSC-J 1.0)",
"GMSJ0A": "GMSJ01 (NTSC-J 1.1)",
"GMSP01": "GMSP01 (PAL)"
"GMSP01": "GMSP01 (PAL)",
"loadpresetplaceholder": "Load a preset..",
"selectionreset": "This will reset your selection, continue?"
},
"headers": {
"codelist": "Available Codes",
@ -23,7 +25,6 @@
"label": "Game Version:",
"placeholder": "Choose Version.."
},
"usestageloader": "Use Stage List Loader",
"downloadformat": {
"label": "Download Format:",
"options": {
@ -31,6 +32,21 @@
"dolphin": "Dolphin INI",
"gcm": "CheatManager TXT"
}
},
"categories": {
"qol": "Quality of Life",
"loader": "Loaders",
"timer": "Timers",
"misc": "Misc",
"memcardpatch": "Memory Card Patches",
"cosmetic": "Cosmetic"
},
"presets": {
"standard": "Standard",
"recommended": "Recommended",
"il": "IL Runs",
"fap": "Fast Any%",
"hfsetup": "Hacked File Setup"
}
},
"landingpage": {
@ -46,6 +62,7 @@
}
},
"stageloader": {
"help": "Loads levels in a customized order.",
"levelorder": {
"label": "Level Order",
"options": {
@ -260,7 +277,6 @@
}
},
"levelselectplaceholder": "Choose a level..",
"loadpresetplaceholder": "Load a preset..",
"route": "Route",
"clear": "Clear List"
},

View file

@ -6,7 +6,8 @@
"GMSE01": "GMSE01 (NTSC-U)",
"GMSJ01": "GMSJ01 (NTSC-J 1.0)",
"GMSJ0A": "GMSJ01 (NTSC-J 1.1)",
"GMSP01": "GMSP01 (PAL)"
"GMSP01": "GMSP01 (PAL)",
"loadpresetplaceholder": "Charger une liste prédéfinie…"
},
"headers": {
"codelist": "Codes disponibles",
@ -23,7 +24,6 @@
"label": "Version du jeu :",
"placeholder": "Choisissez une version…"
},
"usestageloader": "Utiliser le chargeur de liste",
"downloadformat": {
"label": "Format de fichier :",
"options": {
@ -260,7 +260,6 @@
}
},
"levelselectplaceholder": "Choisir un niveau…",
"loadpresetplaceholder": "Charger une liste prédéfinie…",
"route": "Route",
"clear": "Effacer la liste"
},

View file

@ -6,7 +6,8 @@
"GMSE01": "GMSE01 (NTSC-U)",
"GMSJ01": "GMSJ01 (NTSC-J 1.0)",
"GMSJ0A": "GMSJ01 (NTSC-J 1.1)",
"GMSP01": "GMSP01 (PAL)"
"GMSP01": "GMSP01 (PAL)",
"loadpresetplaceholder": "プリセットをロードします.."
},
"headers": {
"codelist": "利用可能なコード",
@ -23,7 +24,6 @@
"label": "ゲームバージョン",
"placeholder": "バージョンを選択…"
},
"usestageloader": "ステージローダーの使用",
"downloadformat": {
"label": "ダウンロードフォーマット",
"options": {
@ -259,7 +259,6 @@
}
},
"levelselectplaceholder": "レベルを選択します..",
"loadpresetplaceholder": "プリセットをロードします..",
"route": "ルート",
"clear": "リストをクリア"
},

8363
yarn.lock

File diff suppressed because it is too large Load diff