Merge branch 'master' of https://github.com/BitPatty/gctGenerator
This commit is contained in:
commit
2b0fb10cf7
15 changed files with 1269 additions and 1018 deletions
|
@ -1,13 +1,9 @@
|
||||||
ARG VARIANT=12
|
# Update the VARIANT arg in docker-compose.yml to pick a Node version: 10, 12, 14
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}
|
ARG VARIANT=14
|
||||||
|
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||||
|
|
||||||
# [Optional] Uncomment this section to install additional OS packages.
|
|
||||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
||||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
|
||||||
|
|
||||||
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
# Update args in docker-compose.yaml to set the UID/GID of the "node" user.
|
||||||
# ARG EXTRA_NODE_VERSION=10
|
ARG USER_UID=1000
|
||||||
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
ARG USER_GID=$USER_UID
|
||||||
|
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then groupmod --gid $USER_GID node && usermod --uid $USER_UID --gid $USER_GID node; fi
|
||||||
# [Optional] Uncomment if you want to install more global node modules
|
|
||||||
# RUN sudo -u node npm install -g <your-package-list-here>
|
|
|
@ -1,25 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "Node.js",
|
"name": "GCT Generator",
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
// Update 'VARIANT' to pick a Node version: 10, 12, 14
|
"args": { "VARIANT": "14" }
|
||||||
"args": { "VARIANT": "12" }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Set *default* container specific settings.json values on container create.
|
|
||||||
"settings": {
|
"settings": {
|
||||||
"terminal.integrated.shell.linux": "/bin/bash"
|
"terminal.integrated.defaultProfile.linux": "/bin/bash"
|
||||||
},
|
},
|
||||||
|
"extensions": [
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
"dbaeumer.vscode-eslint",
|
||||||
"extensions": ["dbaeumer.vscode-eslint"],
|
"esbenp.prettier-vscode",
|
||||||
|
"ms-vsliveshare.vsliveshare",
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
"wayou.vscode-todo-highlight",
|
||||||
|
],
|
||||||
"forwardPorts": [8080],
|
"forwardPorts": [8080],
|
||||||
|
"postCreateCommand": "yarn install",
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
"remoteUser": "node"
|
||||||
"postCreateCommand": "yarn install"
|
|
||||||
|
|
||||||
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
|
|
||||||
// "remoteUser": "node"
|
|
||||||
}
|
}
|
||||||
|
|
59
.vscode/settings.json
vendored
59
.vscode/settings.json
vendored
|
@ -1,7 +1,58 @@
|
||||||
{
|
{
|
||||||
|
"[html]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.quickSuggestions": {
|
||||||
|
"strings": true
|
||||||
|
},
|
||||||
|
"editor.suggest.insertMode": "replace",
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"breadcrumbs.symbolSortOrder": "type",
|
||||||
|
"editor.codeLens": true,
|
||||||
|
"editor.detectIndentation": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.minimap.maxColumn": 150,
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"explorer.confirmDragAndDrop": false,
|
||||||
|
"files.associations": {
|
||||||
|
"*.erb": "html",
|
||||||
|
"*.html.erb": "html"
|
||||||
|
},
|
||||||
|
"git.confirmSync": false,
|
||||||
|
"git.enableSmartCommit": true,
|
||||||
|
"html.format.wrapLineLength": 150,
|
||||||
|
"javascript.updateImportsOnFileMove.enabled": "always",
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"**/dist": true,
|
"**/*.eot": true,
|
||||||
|
"**/*.png": true,
|
||||||
|
"**/*.svg": true,
|
||||||
|
"**/*.ttf": true,
|
||||||
|
"**/*.woff": true,
|
||||||
|
"**/*.woff2": true,
|
||||||
|
"**/.git": true,
|
||||||
|
"**/bower_components": true,
|
||||||
|
"**/dist/": true,
|
||||||
"**/node_modules": true,
|
"**/node_modules": true,
|
||||||
"yarn.lock": true
|
"**/tmp": true
|
||||||
}
|
},
|
||||||
}
|
"telemetry.enableCrashReporter": false,
|
||||||
|
"todohighlight.keywords": [
|
||||||
|
"@TODO"
|
||||||
|
],
|
||||||
|
"typescript.preferences.importModuleSpecifier": "relative",
|
||||||
|
"typescript.referencesCodeLens.enabled": true,
|
||||||
|
"typescript.referencesCodeLens.showOnAllFunctions": true,
|
||||||
|
"typescript.reportStyleChecksAsWarnings": true,
|
||||||
|
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||||
|
"window.zoomLevel": 0,
|
||||||
|
"workbench.editor.enablePreview": false,
|
||||||
|
"workbench.editor.enablePreviewFromQuickOpen": false
|
||||||
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
"jsdom": "16.6.0",
|
"jsdom": "16.6.0",
|
||||||
"markdown-it-attrs": "4.0.0",
|
"markdown-it-attrs": "4.0.0",
|
||||||
"pre-commit": "1.2.2",
|
"pre-commit": "1.2.2",
|
||||||
"prettier": "2.3.1",
|
"prettier": "2.3.2",
|
||||||
"vuepress": "1.8.2"
|
"vuepress": "1.8.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="code in availableCodes"
|
v-for="(code, idx) in availableCodes"
|
||||||
|
v-bind:key="idx"
|
||||||
:class="code.selected ? 'checked' : ''"
|
:class="code.selected ? 'checked' : ''"
|
||||||
@click="toggle(code)"
|
@click="toggle(code)"
|
||||||
@mouseover="inspect(code)"
|
@mouseover="inspect(code)"
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<ButtonComponent
|
<div>
|
||||||
label="Download"
|
<ButtonComponent
|
||||||
:onClick="onClick"
|
label="Download"
|
||||||
:disabled="(!codes || codes.length === 0) && !stageLoaderCode"
|
:onClick="onClick"
|
||||||
/>
|
:disabled="(!codes || codes.length === 0) && !stageLoaderCode"
|
||||||
|
></ButtonComponent>
|
||||||
|
<FeedbackModal v-if="showFeedbackModal" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Components
|
// Components
|
||||||
import ButtonComponent from './ButtonComponent';
|
import FeedbackModal from './FeedbackModal';
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
import gameVersions from '../data/gameVersions.json';
|
import gameVersions from '../data/gameVersions.json';
|
||||||
|
@ -23,6 +26,11 @@ export default {
|
||||||
format: { type: String },
|
format: { type: String },
|
||||||
versionIdentifier: { type: String },
|
versionIdentifier: { type: String },
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showFeedbackModal: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onClick() {
|
onClick() {
|
||||||
if (!(this.codes || this.codes.length === 0) && !this.stageLoaderCode) {
|
if (!(this.codes || this.codes.length === 0) && !this.stageLoaderCode) {
|
||||||
|
@ -55,7 +63,7 @@ export default {
|
||||||
]);
|
]);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
console.log(`Preparing download for ${this.format}`);
|
console.log(`Preparing jdownload for ${this.format}`);
|
||||||
const fileName = gameVersions.find((v) => v.identifier === this.versionIdentifier).version;
|
const fileName = gameVersions.find((v) => v.identifier === this.versionIdentifier).version;
|
||||||
|
|
||||||
switch (this.format) {
|
switch (this.format) {
|
||||||
|
@ -69,6 +77,10 @@ export default {
|
||||||
this.generateCheatManagerTXT(c, fileName);
|
this.generateCheatManagerTXT(c, fileName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.showFeedbackModal && this.$lang === 'en-US') {
|
||||||
|
this.showFeedbackModal = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
generateGCT(codes, version) {
|
generateGCT(codes, version) {
|
||||||
let code = '00D0C0DE00D0C0DE';
|
let code = '00D0C0DE00D0C0DE';
|
||||||
|
|
109
site/.vuepress/components/FeedbackModal.vue
Normal file
109
site/.vuepress/components/FeedbackModal.vue
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<template>
|
||||||
|
<transition v-if="showModal" name="modal">
|
||||||
|
<div class="modal-mask">
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<div class="modal-container">
|
||||||
|
<div v-if="showModal" class="modal-body">
|
||||||
|
<p>
|
||||||
|
If you have 5 minutes please fill out our
|
||||||
|
<a @click="onFormClick" href="https://forms.gle/WYdGEYARPArd7uYx5" target="_blank"
|
||||||
|
>feedback form</a
|
||||||
|
>. Thanks!
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<ButtonComponent
|
||||||
|
label="Ok"
|
||||||
|
:onClick="
|
||||||
|
() => {
|
||||||
|
this.showModal = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Components
|
||||||
|
import ButtonComponent from './ButtonComponent';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FeedbackModal',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showModal: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (localStorage.getItem('feedback-modal-displayed') !== 'y') {
|
||||||
|
this.showModal = true;
|
||||||
|
localStorage.setItem('feedback-modal-displayed', 'y');
|
||||||
|
try {
|
||||||
|
window._paq.push(['trackEvent', 'GCT Generator', 'Feedback', 'Open Modal']);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFormClick() {
|
||||||
|
try {
|
||||||
|
window._paq.push(['trackEvent', 'GCT Generator', 'Feedback', 'Open Form']);
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: table;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-wrapper {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
width: 300px;
|
||||||
|
margin: 0px auto;
|
||||||
|
padding: 20px 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-enter .modal-container,
|
||||||
|
.modal-leave-active .modal-container {
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -99,15 +99,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Components
|
|
||||||
import VersionSelect from './VersionSelect';
|
|
||||||
import FormatSelect from './FormatSelect';
|
|
||||||
import SelectComponent from './SelectComponent';
|
|
||||||
import StageLoader from './StageLoader';
|
|
||||||
import CodeInfo from './CodeInfo';
|
|
||||||
import CodeList from './CodeList';
|
|
||||||
import DownloadButton from './DownloadButton';
|
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
import gameVersions from '../data/gameVersions.json';
|
import gameVersions from '../data/gameVersions.json';
|
||||||
|
|
||||||
|
@ -141,16 +132,43 @@ export default {
|
||||||
this.codes = gameVersions.find((c) => c.identifier === e).codes;
|
this.codes = gameVersions.find((c) => c.identifier === e).codes;
|
||||||
this.stageLoaderCodes = gameVersions.find((c) => c.identifier === e).fastCode;
|
this.stageLoaderCodes = gameVersions.find((c) => c.identifier === e).fastCode;
|
||||||
this.inspectingCode = null;
|
this.inspectingCode = null;
|
||||||
|
try {
|
||||||
|
window._paq.push([
|
||||||
|
'trackEvent',
|
||||||
|
'GCT Generator',
|
||||||
|
'Change Version',
|
||||||
|
JSON.stringify({ version: e }),
|
||||||
|
]);
|
||||||
|
} catch {}
|
||||||
},
|
},
|
||||||
onFormatChanged(e) {
|
onFormatChanged(e) {
|
||||||
this.selectedFormat = e;
|
this.selectedFormat = e;
|
||||||
|
try {
|
||||||
|
window._paq.push([
|
||||||
|
'trackEvent',
|
||||||
|
'GCT Generator',
|
||||||
|
'Change Format',
|
||||||
|
JSON.stringify({ format: e }),
|
||||||
|
]);
|
||||||
|
} catch {}
|
||||||
},
|
},
|
||||||
onStageLoaderChanged(e) {
|
onStageLoaderChanged(e) {
|
||||||
this.useStageLoader = e === true || e === 'true';
|
this.useStageLoader = e === true || e === 'true';
|
||||||
if (!this.useStageLoader) this.selectedStageLoader = null;
|
if (!this.useStageLoader) this.selectedStageLoader = null;
|
||||||
|
try {
|
||||||
|
window._paq.push([
|
||||||
|
'trackEvent',
|
||||||
|
'GCT Generator',
|
||||||
|
'Change StageLoader State',
|
||||||
|
JSON.stringify({ enabled: e }),
|
||||||
|
]);
|
||||||
|
} catch {}
|
||||||
},
|
},
|
||||||
onCheatSelectionChanged(e) {
|
onCheatSelectionChanged(e) {
|
||||||
this.selectedCheats = e;
|
this.selectedCheats = e;
|
||||||
|
try {
|
||||||
|
window._paq.push(['trackEvent', 'GCT Generator', 'Change Cheat Selection', '']);
|
||||||
|
} catch {}
|
||||||
},
|
},
|
||||||
onStageLoaderCodeChanged(e) {
|
onStageLoaderCodeChanged(e) {
|
||||||
this.selectedStageLoader = e;
|
this.selectedStageLoader = e;
|
||||||
|
|
|
@ -4,9 +4,14 @@
|
||||||
<option v-if="placeholder != null" value="placeholder" selected disabled>
|
<option v-if="placeholder != null" value="placeholder" selected disabled>
|
||||||
{{ placeholder }}
|
{{ placeholder }}
|
||||||
</option>
|
</option>
|
||||||
<optgroup v-for="optGroup in optGroups" :label="getLabel(optGroup.label)">
|
<optgroup
|
||||||
|
v-for="(optGroup, oIdx) in optGroups"
|
||||||
|
v-bind:key="oIdx"
|
||||||
|
:label="getLabel(optGroup.label)"
|
||||||
|
>
|
||||||
<option
|
<option
|
||||||
v-for="option in optGroup.options"
|
v-for="(option, iIdx) in optGroup.options"
|
||||||
|
v-bind:key="iIdx"
|
||||||
:value="option.value"
|
:value="option.value"
|
||||||
:selected="selectedValue && option.value === selectedValue"
|
:selected="selectedValue && option.value === selectedValue"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
{{ placeholder }}
|
{{ placeholder }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
v-for="option in options"
|
v-for="(option, idx) in options"
|
||||||
|
v-bind:key="idx"
|
||||||
:value="option.value"
|
:value="option.value"
|
||||||
:selected="selectedValue && option.value === selectedValue"
|
:selected="selectedValue && option.value === selectedValue"
|
||||||
>
|
>
|
||||||
|
|
|
@ -42,18 +42,16 @@
|
||||||
ghost-class="ghost"
|
ghost-class="ghost"
|
||||||
@end="onDragEnd"
|
@end="onDragEnd"
|
||||||
>
|
>
|
||||||
<li v-for="(level, index) in selectedRoute">
|
<li v-for="(level, idx) in selectedRoute" v-bind:key="idx">
|
||||||
<div class="route-drag">≡</div>
|
<div class="route-drag">≡</div>
|
||||||
|
|
||||||
<GroupSelectComponent
|
<GroupSelectComponent
|
||||||
:selectedValue="level.value"
|
:selectedValue="level.value"
|
||||||
:optGroups="stageLoaderLevelOptions"
|
:optGroups="stageLoaderLevelOptions"
|
||||||
:onChange="(e) => onStageLoaderLevelChanged(index, e)"
|
:onChange="(e) => onStageLoaderLevelChanged(idx, e)"
|
||||||
:key="index"
|
:key="idx"
|
||||||
/>
|
/>
|
||||||
<button @click="onLevelDeleted(index)" type="button" class="route-remove">
|
<button @click="onLevelDeleted(idx)" type="button" class="route-remove">×</button>
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</li>
|
</li>
|
||||||
</draggable>
|
</draggable>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div v-for="version in gameVersions" class="card" @click="onCardClick(version)">
|
<div
|
||||||
|
v-for="(version, idx) in gameVersions"
|
||||||
|
v-bind:key="idx"
|
||||||
|
class="card"
|
||||||
|
@click="onCardClick(version)"
|
||||||
|
>
|
||||||
<h3>{{ getLabel(`common.${version.identifier}`) }}</h3>
|
<h3>{{ getLabel(`common.${version.identifier}`) }}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,8 +27,6 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onCardClick(v) {
|
onCardClick(v) {
|
||||||
const localePaths = Object.keys(locales);
|
|
||||||
|
|
||||||
let localePath = '';
|
let localePath = '';
|
||||||
|
|
||||||
Object.keys(locales).forEach((l) => {
|
Object.keys(locales).forEach((l) => {
|
||||||
|
|
|
@ -9,8 +9,10 @@ export default ({
|
||||||
options, // the options for the root Vue instance
|
options, // the options for the root Vue instance
|
||||||
router, // the router instance for the app
|
router, // the router instance for the app
|
||||||
siteData, // site metadata
|
siteData, // site metadata
|
||||||
|
isServer,
|
||||||
}) => {
|
}) => {
|
||||||
if (typeof document === 'undefined') return;
|
if (isServer) return;
|
||||||
|
|
||||||
document.onreadystatechange = () => {
|
document.onreadystatechange = () => {
|
||||||
if (document.readyState === 'complete') {
|
if (document.readyState === 'complete') {
|
||||||
if (location.hash && location.hash.length > 0) {
|
if (location.hash && location.hash.length > 0) {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"headers": {
|
"headers": {
|
||||||
"codelist": "Available Codes",
|
"codelist": "Available Codes",
|
||||||
"help": "Help",
|
"help": "Help",
|
||||||
"stageloader": "Stage Loader"
|
"stageloader": "Stage List Loader"
|
||||||
},
|
},
|
||||||
"codeinfo": {
|
"codeinfo": {
|
||||||
"author": "Author:",
|
"author": "Author:",
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
"label": "Game Version:",
|
"label": "Game Version:",
|
||||||
"placeholder": "Choose Version.."
|
"placeholder": "Choose Version.."
|
||||||
},
|
},
|
||||||
"usestageloader": "Use Stage Loader",
|
"usestageloader": "Use Stage List Loader",
|
||||||
"downloadformat": {
|
"downloadformat": {
|
||||||
"label": "Download Format:",
|
"label": "Download Format:",
|
||||||
"options": {
|
"options": {
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
},
|
},
|
||||||
"landingpage": {
|
"landingpage": {
|
||||||
"title": "Super Mario Sunshine Practice File Generator",
|
"title": "Super Mario Sunshine Practice File Generator",
|
||||||
"summary": "This is a cheatfile generator for Super Mario Sunshine speedrun practice. If this is your first time using the generator we highly recommend to check out the <a href='/guide.html' target='_blank'>guide</a> first. Visit the <a href='/guide.html#troubleshooting' target='_blank'>the troubleshooting section</a> if you encounter any issues.",
|
"summary": "This is a cheatfile generator for Super Mario Sunshine speedrun practice. If this is your first time using the generator we highly recommend to check out the <a href='/guide.html' target='_blank'>guide</a> first. Visit the <a href='/guide.html#troubleshooting' target='_blank'>the troubleshooting section</a> if you encounter any issues. For an overview of all available codes check out the <a href='/code-reference' target='_blank'>code reference</a> for your version.",
|
||||||
"community": "The SMS Speedrunning Community",
|
"community": "The SMS Speedrunning Community",
|
||||||
"links": {
|
"links": {
|
||||||
"discord": "Discord",
|
"discord": "Discord",
|
||||||
|
|
Loading…
Reference in a new issue