add stage loader code generator

This commit is contained in:
Matteias Collet 2020-06-28 03:45:44 +02:00
parent df1aef2c11
commit e2b9e2bd44
6 changed files with 224 additions and 29 deletions

View file

@ -1,5 +1,9 @@
<template> <template>
<ButtonComponent label="Download" :onClick="onClick" :disabled="!codes || codes.length === 0" /> <ButtonComponent
label="Download"
:onClick="onClick"
:disabled="(!codes || codes.length === 0) && !stageLoaderCode"
/>
</template> </template>
<script> <script>
@ -9,33 +13,39 @@ import CodeFormatter from "./scripts/codeFormatter";
export default { export default {
props: { props: {
codes: { type: Array }, codes: { type: Array },
stageLoaderCode: { type: String },
format: { type: String }, format: { type: String },
versionIdentifier: { type: String } versionIdentifier: { type: String },
}, },
methods: { methods: {
onClick() { onClick() {
if (!this.codes || this.codes.length === 0) { if (!(this.codes || this.codes.length === 0) && !this.stageLoaderCode) {
return; return;
} }
const c = [...(this.codes ?? [])];
if (this.stageLoaderCode)
c.push({
title: "Stage List Loader",
author: "Noki Doki",
date: "-",
version: "",
source: this.stageLoaderCode,
});
console.log(`Preparing download for ${this.format}`); console.log(`Preparing download for ${this.format}`);
switch (this.format) { switch (this.format) {
case "gct": case "gct":
CodeFormatter.generateGCT(this.codes, this.versionIdentifier); CodeFormatter.generateGCT(c, this.versionIdentifier);
break; break;
case "dolphin": case "dolphin":
CodeFormatter.generateDolphinINI(this.codes, this.versionIdentifier); CodeFormatter.generateDolphinINI(c, this.versionIdentifier);
break; break;
case "gcm": case "gcm":
CodeFormatter.generateCheatManagerTXT( CodeFormatter.generateCheatManagerTXT(c, this.versionIdentifier);
this.codes,
this.versionIdentifier
);
break; break;
} }
} },
} },
}; };
</script> </script>

View file

@ -1,10 +1,17 @@
<template> <template>
<SelectComponent :options="options" :onChange="onChange" /> <SelectComponent
placeholder="Choose Format"
:options="options"
:selectedValue="selectedValue"
:onChange="onChange"
/>
</template> </template>
<script> <script>
// Components
import SelectComponent from "./SelectComponent"; import SelectComponent from "./SelectComponent";
// Data
import downloadFormats from "../data/downloadFormats.json"; import downloadFormats from "../data/downloadFormats.json";
export default { export default {
@ -12,9 +19,6 @@ export default {
selectedValue: { type: String }, selectedValue: { type: String },
onChange: { type: Function }, onChange: { type: Function },
}, },
mounted() {
this.onChange(downloadFormats[0].target);
},
data() { data() {
return { return {
options: downloadFormats.map((v) => ({ options: downloadFormats.map((v) => ({

View file

@ -6,28 +6,38 @@
<section class="config"> <section class="config">
<div> <div>
<span>Game Version:</span> <span>Game Version:</span>
<VersionSelect :onChange="onVersionChanged" /> <VersionSelect
:onChange="onVersionChanged"
:selectedValue="selectedVersion"
/>
</div> </div>
<div> <div>
<span>Download Format:</span> <span>Download Format:</span>
<FormatSelect :onChange="onFormatChanged" /> <FormatSelect
:onChange="onFormatChanged"
:selectedValue="selectedFormat"
/>
</div> </div>
<div> <div>
<span>Use Stage Loader:</span> <span>Use Stage Loader:</span>
<SelectComponent <SelectComponent
:options="useStageLoaderOptions" :options="useStageLoaderOptions"
:onChange="onStageLoaderChanged" :onChange="onStageLoaderChanged"
:value="useStageLoader"
/> />
</div> </div>
<div> <div>
<span>Download:</span> <span>Download:</span>
<DownloadButton <DownloadButton
:codes="selectedCheats" :codes="selectedCheats"
:stageLoaderCode="selectedStageLoader"
:versionIdentifier="selectedVersion" :versionIdentifier="selectedVersion"
:format="selectedFormat" :format="selectedFormat"
/> />
</div> </div>
</section> </section>
<br />
<hr />
<section> <section>
<div v-if="codes && codes.length > 0"> <div v-if="codes && codes.length > 0">
<h3>Available Codes</h3> <h3>Available Codes</h3>
@ -42,7 +52,10 @@
v-if="codes && codes.length > 0 && useStageLoader" v-if="codes && codes.length > 0 && useStageLoader"
> >
<h3>Stage Loader</h3> <h3>Stage Loader</h3>
<StageLoader :fastCodes="stageLoaderCodes" /> <StageLoader
:fastCodes="stageLoaderCodes"
:onChange="onStageLoaderCodeChanged"
/>
</div> </div>
<div v-if="codes && codes.length > 0" class="help"> <div v-if="codes && codes.length > 0" class="help">
@ -126,7 +139,7 @@ import DownloadButton from "./DownloadButton";
// Data // Data
import gameVersions from "../data/gameVersions.json"; import gameVersions from "../data/gameVersions.json";
// Helpers // Util
import parseXml from "./scripts/parseXml"; import parseXml from "./scripts/parseXml";
// Libs // Libs
@ -157,7 +170,7 @@ export default {
selectedStageLoader: null, selectedStageLoader: null,
inspectingCode: null, inspectingCode: null,
selectedVersion: null, selectedVersion: null,
selectedFormat: null, selectedFormat: "gct",
useStageLoader: false, useStageLoader: false,
stageLoaderCodes: [], stageLoaderCodes: [],
useStageLoaderOptions: [ useStageLoaderOptions: [
@ -182,10 +195,14 @@ export default {
}, },
onStageLoaderChanged(e) { onStageLoaderChanged(e) {
this.useStageLoader = e === true || e === "true"; this.useStageLoader = e === true || e === "true";
if (!this.useStageLoader) this.selectedStageLoader = null;
}, },
onCheatSelectionChanged(e) { onCheatSelectionChanged(e) {
this.selectedCheats = e; this.selectedCheats = e;
}, },
onStageLoaderCodeChanged(e) {
this.selectedStageLoader = e;
},
inspect(code) { inspect(code) {
this.inspectingCode = code; this.inspectingCode = code;
}, },

View file

@ -96,12 +96,16 @@ import GroupSelectComponent from "./GroupSelectComponent";
import stageLoaderLevels from "../data/stageLoaderLevels.json"; import stageLoaderLevels from "../data/stageLoaderLevels.json";
import stageLoaderPresets from "../data/stageLoaderPresets.json"; import stageLoaderPresets from "../data/stageLoaderPresets.json";
// Util
import generateStageLoaderCode from "./scripts/generateStageLoadercode";
// Lib // Lib
import draggable from "vuedraggable"; import draggable from "vuedraggable";
export default { export default {
props: { props: {
fastCodes: { type: Object }, fastCodes: { type: Object },
onChange: { type: Function },
}, },
components: { components: {
draggable, draggable,
@ -132,39 +136,46 @@ export default {
{ value: "3400", label: "Load post-Corona plaza" }, { value: "3400", label: "Load post-Corona plaza" },
{ value: "3C00", label: "Load the Bowser fight" }, { value: "3C00", label: "Load the Bowser fight" },
], ],
removeDialogSelection: null, removeDialogSelection: "yes",
skippableFMVsSelection: null, skippableFMVsSelection: "yes",
levelOrderSelection: null, levelOrderSelection: "list",
postGameSelection: null, postGameSelection: "0F00",
generation: 0, generation: 0,
}; };
}, },
methods: { methods: {
onRemoveDialogueSelectionChanged(e) { onRemoveDialogueSelectionChanged(e) {
this.removeDialogSelection = e; this.removeDialogSelection = e;
this.updateCode();
}, },
onSkippableFMVsSelectionChanged(e) { onSkippableFMVsSelectionChanged(e) {
this.skippableFMVsSelection = e; this.skippableFMVsSelection = e;
this.updateCode();
}, },
onLevelOrderSelectionChanged(e) { onLevelOrderSelectionChanged(e) {
this.levelOrderSelection = e; this.levelOrderSelection = e;
this.updateCode();
}, },
onPostGameSelectionChanged(e) { onPostGameSelectionChanged(e) {
this.postGameSelection = e; this.postGameSelection = e;
this.updateCode();
}, },
onStageLoaderLevelSelected(e) { onStageLoaderLevelSelected(e) {
this.generation++; this.generation++;
this.selectedRoute.push({ this.selectedRoute.push({
value: e, value: e,
}); });
this.updateCode();
}, },
onStageLoaderLevelChanged(index, e) { onStageLoaderLevelChanged(index, e) {
this.selectedRoute[index] = { this.selectedRoute[index] = {
value: e, value: e,
}; };
this.updateCode();
}, },
onLevelDeleted(e) { onLevelDeleted(e) {
this.selectedRoute.splice(e, 1); this.selectedRoute.splice(e, 1);
this.updateCode();
}, },
onStageLoaderPresetSelected(e) { onStageLoaderPresetSelected(e) {
this.generation++; this.generation++;
@ -185,7 +196,9 @@ export default {
newRoute.push({ value: preset.substr(i, 4) }); newRoute.push({ value: preset.substr(i, 4) });
this.selectedRoute = newRoute; this.selectedRoute = newRoute;
this.postGameSelection = ending;
if (ending) this.postGameSelection;
this.updateCode();
}, },
onClearList() { onClearList() {
if ( if (
@ -195,9 +208,31 @@ export default {
return; return;
this.selectedRoute = []; this.selectedRoute = [];
this.updateCode();
}, },
checkMove(e) { updateCode() {
window.console.log("Future index: " + e.draggedContext.futureIndex); if (
this.selectedRoute.length === 0 ||
this.levelOrderSelection == null ||
this.postGameSelection == null ||
this.skippableFMVsSelection == null ||
this.removeDialogSelection == null
) {
this.onChange(null);
return;
}
console.log("Generating new Stageloader-Code");
this.onChange(
generateStageLoaderCode(
this.fastCodes,
this.selectedRoute.map((v) => v.value),
this.levelOrderSelection,
this.postGameSelection,
this.skippableFMVsSelection,
this.removeDialogSelection
)
);
}, },
}, },
}; };
@ -208,6 +243,7 @@ export default {
display: block; display: block;
margin-bottom: 5px; margin-bottom: 5px;
padding-left: 2px; padding-left: 2px;
font-size: 0.9rem;
} }
.config:not(:first-child) span { .config:not(:first-child) span {

View file

@ -1,6 +1,7 @@
<template> <template>
<SelectComponent <SelectComponent
placeholder="Choose Version.." placeholder="Choose Version.."
:selectedValue="selectedValue"
:options="options" :options="options"
:onChange="onChange" :onChange="onChange"
/> />

View file

@ -0,0 +1,127 @@
const generateStageLoaderCode = (
gameConfig,
selectedLevels,
routeOrder,
routeEnding,
fmvSkips,
dialgueSkips
) => {
const loadStageLength = {
list: 0x20,
random: 0x2c,
shuffle: 0x40,
}[routeOrder];
let codes = "";
// Reset counter on file select
codes +=
"0" +
(0x04000000 + (gameConfig.fileSelect & 0x01ffffff)).toString(16) +
(
0x48000001 +
((gameConfig.system + 0x52c - gameConfig.fileSelect) & 0x03fffffc)
).toString(16);
// Load next stage on Shine get
codes +=
"0" +
(0x04000000 + (gameConfig.shineGet & 0x01ffffff)).toString(16) +
(
0x48000001 +
((gameConfig.system + 0x53c - gameConfig.shineGet) & 0x03fffffc)
).toString(16);
// Reload stage on exit area
codes +=
"0" +
(0x04000000 + (gameConfig.system & 0x01ffffff)).toString(16) +
"48000511";
// Set next stage on game over
codes +=
"0" +
(0x06000000 + ((gameConfig.system + 0xb4) & 0x01ffffff)).toString(16) +
"000000084800048948000044";
// Reset timer on secret death
codes +=
(0xc2000000 + ((gameConfig.system + 0x208) & 0x01ffffff)).toString(16) +
"000000033C60817F38000001980300FF881C00006000000000000000";
// Reset coin count on loading main world
codes +=
(0xc2000000 + ((gameConfig.shineGet - 0x674) & 0x01ffffff)).toString(16) +
"00000005887D00002C030002418000142C0300074182000C2C03000A418000087C0400406000000000000000";
// Overwrite decideNextStage(void) with useful routines
codes +=
"0" +
(0x06000000 + ((gameConfig.system + 0x510) & 0x01ffffff)).toString(16) +
("0000000" + (loadStageLength + 0x5c).toString(16)).slice(-8) +
"3C60817F38000001980300FFA00300023C60" +
gameConfig.gpAppHi +
"B003" +
gameConfig.gpAppLo +
"4E800020" + // reload current level
"3C60817F" +
(0x38800000 + ((selectedLevels.length * 2) & 0x0000ffff)).toString(16) +
"B08300004E800020" + // reset counter
"3C60817F38000001980300FFA00300002C00000038E0" +
routeEnding + // load next stage - the fun begins
(0x40810000 + (loadStageLength & 0x0000fffc)).toString(16) +
"7C8802A6600000007CC802A67C8803A6";
switch (routeOrder) {
case "list":
codes += "3400FFFEB00300007CE6022E";
break;
case "random":
codes += "7C8C42E67CA403967CA501D67C8520505484003C7CE6222E";
break;
case "shuffle":
codes +=
"7C8C42E67CA403967CA501D67C8520505484003C3400FFFEB00300007CE6222E7CA6022E7CA6232E7CE6032E";
}
codes +=
"B0E300023C60" +
gameConfig.gpAppHi +
"B0E3" +
gameConfig.gpAppLo +
"806D" +
gameConfig.fmOffset +
"98E300DF4E800020" +
(routeOrder === "random" ? "" : "00000000");
selectedLevels.reverse();
while (selectedLevels.length % 4) selectedLevels.push("0000");
// Insert the list of levels into the loader
codes +=
(0xc2000000 + ((gameConfig.system + 0x55c) & 0x01ffffff)).toString(16) +
("0000000" + (selectedLevels.length / 4 + 1).toString(16)).slice(-8) +
(0x48000001 + ((selectedLevels.length * 2 + 4) & 0x03fffffc)).toString(16) +
selectedLevels.join("") +
"00000000";
// Load next stage on setNextStage into main level
codes +=
"0" +
(0x06000000 + ((gameConfig.system + 0x118c) & 0x01ffffff)).toString(16) +
"00000028B07D00143C80817F38000000B00400FFA0010038B01D00122C1C00094181000C4BFFF391B0E10038";
// Setup timer
codes +=
(0xc2000000 + (gameConfig.proc & 0x01ffffff)).toString(16) +
"000000053CA0817F388000009085010C880500FF98050100988500FF38800001988501016000000000000000";
codes = codes.toUpperCase();
codes += gameConfig.notext[dialgueSkips] + gameConfig.nofmvs[fmvSkips];
return codes;
};
export default generateStageLoaderCode;