From a95ea19a024e3b697b1d746ea98c8d23d1427c00 Mon Sep 17 00:00:00 2001 From: QbeRoot Date: Sat, 3 Feb 2018 22:14:40 +0100 Subject: [PATCH] updated stage loader --- changelog.html | 6 +++- changelog.xml | 4 +++ gctGenerator.js | 84 +++++++++++++++++++++++++++++++------------------ index.html | 9 +++--- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/changelog.html b/changelog.html index 05baeb1..81b67b1 100644 --- a/changelog.html +++ b/changelog.html @@ -10,9 +10,13 @@

Full Changelog

+

Feb 03, 2018

+

Updated Stage Loader

+

Added "Random, no duplicates" order that will only load each stage once.

+

Exiting area or dying now reloads the current stage instead of moving on.

Feb 02, 2018

Site changes

-

Integrated Noki Dokis Stage Loader into the Generator.

+

Integrated Noki Doki’s Stage Loader into the Generator.

Jan 24, 2018

Optimized 'Fast Any%'

Shortens the code by a few lines

diff --git a/changelog.xml b/changelog.xml index f4216a8..23c15ee 100644 --- a/changelog.xml +++ b/changelog.xml @@ -1,5 +1,9 @@ + + Feb 03, 2018 + Updated Stage Loader. + Feb 02, 2018 Integrated Noki Dokis Stage Loader. diff --git a/gctGenerator.js b/gctGenerator.js index 5ac7f42..e7d67e7 100644 --- a/gctGenerator.js +++ b/gctGenerator.js @@ -187,8 +187,8 @@ function updateUIDescription(s) { document.getElementById("descriptionbox").innerHTML = "

Remove Dialogue

Replaces all Dialogue with \"!!!\". 'Always' and 'Not in Pianta 5' will override the dialogue skip from the DPad Functions.

"; else if (s.id === "route_nofmvs") document.getElementById("descriptionbox").innerHTML = "

Skippable Cutscenes

Makes FMVs Skippable. 'Always' has the same effect as the 'FMV Skips' code. Also, having 'FMV Skips' enabled will override 'Not in Pinna 1' - so don't use both simultaneously.

"; - else if (s.id === "route_random") - document.getElementById("descriptionbox").innerHTML = "

Random Level Order

Randomizes what level is loaded next - it can be any from the levels you choose on the list. Even levels that you've finished already.

"; + else if (s.id === "route_order") + document.getElementById("descriptionbox").innerHTML = "

Level Order

The order in which levels are loaded:

As specified

The code loads levels in the order of the list.

Random, no duplicates

The code picks levels at random, excluding levels that you’ve finished already.

Fully random

The code picks levels at random, even levels that you’ve finished already.

"; else if (s.id === "downloadformat") document.getElementById("descriptionbox").innerHTML = "

File Format

You can choose between 3 file formats:

GCT

Download a GCT file for use with Nintendont

Dolphin INI

Download a textfile containing the formatted codes for use with Dolphin. Copy the contents of the file on top of your games .ini file.

You can open the .ini file by right clicking the game in Dolphin. In the context menu select 'Properties' and then 'Edit configuration'.

Cheat Manager TXT

Download the cheats in a textfile formatted for use with the Gecko Cheat Manager. Place the txt file in SD:/txtcodes/.

A zip archive containing pregenerated txt files with all available codes on this site can be downloaded here.

"; else if (s.id === "stageloader") @@ -337,12 +337,13 @@ function getFastCode() { if (!(document.getElementById("usefastcode").checked) || levelCodes.length <= 1) return false; let game = JSON.parse(atob(document.getElementById("route_levels").getAttribute("data-json"))); - const randomize = (document.getElementById("route_random").value === "yes"); + const order = document.getElementById("route_order").value; const levelWords = Math.ceil(levelCodes.length / 2); + const branchBase = 0x14 + 0x24 * (order !== 'list'); const asm = []; - asm.push("48" + ("00000" + (levelWords + 1 << 2 | 1).toString(16).toUpperCase()).slice(-6)); // bl to the code - for (let i = 0; i < levelWords; ++i) { - asm.push(levelCodes[2 * i] + (levelCodes[2 * i + 1] || "0000")); + asm.push("48" + ("00000" + (Math.ceil(levelCodes.length / 2) + 1 << 2 | 1).toString(16).toUpperCase()).slice(-6)); // bl to the code + for (let i = levelCodes.length - 1; i >= 0; i -= 2) { + asm.push(levelCodes[i] + (levelCodes[i - 1] || "0000")); } //Timer compatibility @@ -354,36 +355,59 @@ function getFastCode() { asm.push("881F0012"); // lbz r0, 0x12(r31) - if (!randomize) { - asm.push("2C00000F"); // cmpwi r0, 15 - asm.push("40820010"); // bne- 0x10 - asm.push("38000000"); // li r0, 0 - asm.push("90040000"); // stw r0, 0(r4) - asm.push("4800002C"); // b 0x2C - } + asm.push("2C00000F"); // cmpwi r0, 15 + asm.push("40820010"); // bne- 0x10 + asm.push("3800" + ("000" + ((levelCodes.length - (order === 'random')) * 2).toString(16).toUpperCase()).slice(-4)); // li r0, length + asm.push("90040000"); // stw r0, 0(r4) + asm.push("4800" + ("000" + (branchBase + 0x38).toString(16).toUpperCase()).slice(-4)); // b done asm.push("2C000001"); // cmpwi r0, 1 + asm.push("4181" + ("000" + (branchBase + 0x30).toString(16).toUpperCase()).slice(-4)); // bgt- done - if (randomize) { - asm.push("41810030"); // bgt- 0x30 - asm.push("7C6C42E6"); // mftbl r3 - asm.push("3880" + ("000" + (levelCodes.length * 2).toString(16).toUpperCase()).slice(-4)); // li r4, length - asm.push("7C032396"); // divwu r0, r3, r4 - asm.push("7C0021D6"); // mullw r0, r0, r4 - asm.push("7C601850"); // sub r3, r3, r0 - asm.push("5463003C"); // rlwinm r3, r3, 0, 0, 30 - } else { - asm.push("41810024"); // bgt- 0x24 - asm.push("80640000"); // lwz r3, 0(r4) - asm.push("38030002"); // addi r0, r3, 2 - asm.push("90040000"); // stw r0, 0(r4) + asm.push("80AD" + game.fmOffset); // lwz r5, TFlagManager::smInstance + asm.push("7CC802A6"); // mflr r6 + asm.push("80640000"); // lwz r3, 0(r4) + + asm.push("881F000E"); // lbz r0, 0x0E(r31) + asm.push("2C00000F"); // cmpwi r0, 15 + asm.push("41820010"); // beq- 0x10 + asm.push("880500CC"); // lbz r0, 0xCC(r5) + asm.push("54000673"); // rlwinm. r0, r0, 0, 25, 25 + asm.push("4182" + ("000" + branchBase.toString(16).toUpperCase()).slice(-4)); // beq- loadStage + + if (order === "random") { + asm.push("38630002"); // addi r3, r3, 2 } - asm.push("7C8802A6"); // mflr r4 - asm.push("7C641A2E"); // lhzx r3, r4, r3 + asm.push("2C030000"); // cmpwi r3, 0 + asm.push("4081" + ("000" + (branchBase + 4 * (order !== "random")).toString(16).toUpperCase()).slice(-4)); // ble- done + + if (order !== "list") { + asm.push("7CEC42E6"); // mftbl r7 + asm.push("7C071B96"); // divwu r0, r7, r3 + asm.push("7C0019D6"); // mullw r0, r0, r3 + asm.push("7CE03850"); // sub r7, r7, r0 + asm.push("54E7003C"); // rlwinm r7, r7, 0, 0, 30 + } + + asm.push("3863FFFE"); // subi r3, r3, 2 + if (order !== "random") { + asm.push("90640000"); // stw r3, 0(r4) + } + + if (order !== "list") { + asm.push("7C061A2E"); // lhzx r0, r6, r3 + asm.push("7C863A2E"); // lhzx r4, r6, r7 + asm.push("7C063B2E"); // sthx r0, r6, r7 + asm.push("7C861B2E"); // sthx r4, r6, r3 + } + + // loadStage: + asm.push("7C661A2E"); // lhzx r3, r6, r3 asm.push("B07F0012"); // sth r3, 0x12(r31) - asm.push("808D" + game.fmOffset); // lwz r4, TFlagManager::smInstance - asm.push("986400DF"); // stb r3, 0xDF(r4) + asm.push("986500DF"); // stb r3, 0xDF(r5) + + // done: asm.push("807F0020"); // lwz r3, 0x20(r31) if (asm.length % 2 === 0) { diff --git a/index.html b/index.html index 9781c82..506e499 100644 --- a/index.html +++ b/index.html @@ -95,12 +95,13 @@ - + - + + +