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>
<ButtonComponent label="Download" :onClick="onClick" :disabled="!codes || codes.length === 0" />
<ButtonComponent
label="Download"
:onClick="onClick"
:disabled="(!codes || codes.length === 0) && !stageLoaderCode"
/>
</template>
<script>
@ -9,33 +13,39 @@ import CodeFormatter from "./scripts/codeFormatter";
export default {
props: {
codes: { type: Array },
stageLoaderCode: { type: String },
format: { type: String },
versionIdentifier: { type: String }
versionIdentifier: { type: String },
},
methods: {
onClick() {
if (!this.codes || this.codes.length === 0) {
if (!(this.codes || this.codes.length === 0) && !this.stageLoaderCode) {
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}`);
switch (this.format) {
case "gct":
CodeFormatter.generateGCT(this.codes, this.versionIdentifier);
CodeFormatter.generateGCT(c, this.versionIdentifier);
break;
case "dolphin":
CodeFormatter.generateDolphinINI(this.codes, this.versionIdentifier);
CodeFormatter.generateDolphinINI(c, this.versionIdentifier);
break;
case "gcm":
CodeFormatter.generateCheatManagerTXT(
this.codes,
this.versionIdentifier
);
CodeFormatter.generateCheatManagerTXT(c, this.versionIdentifier);
break;
}
}
}
},
},
};
</script>

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
<template>
<SelectComponent
placeholder="Choose Version.."
:selectedValue="selectedValue"
:options="options"
: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;