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:
parent
12c9379f7e
commit
527ed6fbc5
18 changed files with 12157 additions and 8441 deletions
|
@ -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"
|
||||
}
|
||||
|
|
47
Codes.xml
47
Codes.xml
|
@ -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>
|
||||
|
|
17
Readme.md
17
Readme.md
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
11728
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -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": {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
38
site/.vuepress/data/codeCategories.json
Normal file
38
site/.vuepress/data/codeCategories.json
Normal 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": []
|
||||
}
|
||||
]
|
22
site/.vuepress/data/presetCategories.json
Normal file
22
site/.vuepress/data/presetCategories.json
Normal 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"
|
||||
}
|
||||
]
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
|
@ -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": "リストをクリア"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue