diff --git a/changelog.xml b/changelog.xml index 8c73077..bd81bec 100644 --- a/changelog.xml +++ b/changelog.xml @@ -1,5 +1,12 @@ + + Aug 29, 2018 + + Updated Stage Loader + The code is now able to load the airstrip and any version of the plaza. Added new presets with plaza movement, including 96 Shines and 120 Shines. Added new route endings. Changed the conditional FMV skips option from 'Not in Pinna 1' to 'Not in Pinna', no longer making the Pinna unlock cutscene skippable. + + Aug 24, 2018 diff --git a/codes/fast/GMSE01.json b/codes/fast/GMSE01.json index 31bb4f6..6213e1b 100644 --- a/codes/fast/GMSE01.json +++ b/codes/fast/GMSE01.json @@ -1 +1 @@ -{"injectAddr":"2A6710","fmOffset":"9FA0","notext":{"yes":"048D3A3C 21000000\r\n04153DA0 38000000\r\n0415317C 38005000\r\n04291340 60000000\r\n","pv5":"048D3A3C 21000000\r\n283E9712 00002A00\r\n04153DA0 801C0004\r\n0415317C A81C0340\r\n04291340 88030214\r\nE2000001 00000000\r\n2A3E9712 00002A00\r\n04153DA0 38000000\r\n0415317C 38005000\r\n04291340 60000000\r\nE2000001 00000000\r\n","no":""},"nofmvs":{"yes":"042B5EF4 38600001\r\n042B5E8C 38600001\r\n","pp1":"C22B5EF0 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\nC22B5E88 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\n","no":""}} \ No newline at end of file +{"fileSelect":2701876,"shineGet":2718852,"system":2724400,"proc":2778900,"gpAppHi":"803E","gpAppLo":"9712","fmOffset":"9FA0","notext":{"yes":"048D3A3C2100000004153DA0380000000415317C3800500004291340 60000000","pv5":"048D3A3C21000000283E971200002A0004153DA0801C00040415317CA81C03400429134088030214E2000001000000002A3E971200002A0004153DA0380000000415317C380050000429134060000000E200000100000000","no":""},"nofmvs":{"yes":"042B5EF438600001042B5E8C38600001","pp":"C22B5E88000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000C22B5EF0000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000","no":""}} \ No newline at end of file diff --git a/codes/fast/GMSJ01.json b/codes/fast/GMSJ01.json index 17d78c8..a97501d 100644 --- a/codes/fast/GMSJ01.json +++ b/codes/fast/GMSJ01.json @@ -1 +1 @@ -{"injectAddr":"0FA19C","fmOffset":"97D0","notext":{"yes":"048D8A7C D6008149\r\n048D8A80 81498149\r\n048D8A84 00000000\r\n04215290 38000000\r\n04214610 38005000\r\n040E4888 60000000\r\n","pv5":"048D8A7C D6008149\r\n048D8A80 81498149\r\n048D8A84 00000000\r\n283E6012 00002A00\r\n04215290 801C0004\r\n04214610 A81C0340\r\n040E4888 88030214\r\nE2000001 00000000\r\n2A3E6012 00002A00\r\n04215290 38000000\r\n04214610 38005000\r\n040E4888 60000000\r\nE2000001 00000000\r\n","no":""},"nofmvs":{"yes":"0410AF5C 38600001\r\n0410AFC0 38600001\r\n","pp1":"C210AF58 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\nC210AFBC 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\n","no":""}} \ No newline at end of file +{"fileSelect":946160,"shineGet":963136,"system":968628,"proc":1024280,"gpAppHi":"803E","gpAppLo":"6012","fmOffset":"97D0","notext":{"yes":"048D8A7CD6008149048D8A8081498149048D8A840000000004215290380000000421461038005000040E488860000000","pv5":"048D8A7CD6008149048D8A8081498149048D8A8400000000283E601200002A0004215290801C000404214610A81C0340040E488888030214E2000001000000002A3E601200002A0004215290380000000421461038005000040E488860000000E200000100000000","no":""},"nofmvs":{"yes":"0410AF5C386000010410AFC038600001","pp":"C210AF58000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000C210AFBC000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000","no":""}} \ No newline at end of file diff --git a/codes/fast/GMSJ0A.json b/codes/fast/GMSJ0A.json index 08b7907..178436c 100644 --- a/codes/fast/GMSJ0A.json +++ b/codes/fast/GMSJ0A.json @@ -1 +1 @@ -{"injectAddr":"2865F4","fmOffset":"9E60","notext":{"yes":"048CD55C D6008149\r\n048CD560 81498149\r\n048CD564 00000000\r\n041351C4 38000000\r\n04134524 38005000\r\n04271090 60000000\r\n","pv5":"048CD55C D6008149\r\n048CD560 81498149\r\n048CD564 00000000\r\n283DA8F2 00002A00\r\n041351C4 801C0004\r\n04134524 A81C0340\r\n04271090 88030214\r\nE2000001 00000000\r\n2A3DA8F2 00002A00\r\n041351C4 38000000\r\n04134524 38005000\r\n04271090 60000000\r\nE2000001 00000000\r\n","no":""},"nofmvs":{"yes":"04295AB4 38600001\r\n04295B18 38600001\r\n","pp1":"C2295AB0 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\nC2295B14 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\n","no":""}} \ No newline at end of file +{"fileSelect":2569968,"shineGet":2586924,"system":2592480,"proc":2647408,"gpAppHi":"803D","gpAppLo":"A8F2","fmOffset":"9E60","notext":{"yes":"048CD55CD6008149048CD56081498149048CD56400000000041351C43800000004134524380050000427109060000000","pv5":"048CD55CD6008149048CD56081498149048CD56400000000283DA8F200002A00041351C4801C000404134524A81C03400427109088030214E2000001000000002A3DA8F200002A00041351C43800000004134524380050000427109060000000E200000100000000","no":""},"nofmvs":{"yes":"04295AB43860000104295B1838600001","pp":"C2295AB0000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000C2295B18000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000","no":""}} \ No newline at end of file diff --git a/codes/fast/GMSP01.json b/codes/fast/GMSP01.json index 407b606..c676b5e 100644 --- a/codes/fast/GMSP01.json +++ b/codes/fast/GMSP01.json @@ -1 +1 @@ -{"injectAddr":"29E668","fmOffset":"9EC8","notext":{"yes":"20570B7C 00000000\r\n0474E87C 21000000\r\n20570B7D 00000001\r\n0474E9F4 21210000\r\n20570B7D 00000002\r\n0474ED38 00000000\r\n20570B7D 00000003\r\n0474EE04 A1000000\r\n20570B7D 00000004\r\n0474EBDC 21210000\r\nE2000001 00000000\r\n04148D20 38000000\r\n04147F98 38005000\r\n042890CC 60000000\r\n","pv5":"283E10D2 00002A00\r\n04148D20 801C0004\r\n04147F98 A81C0340\r\n042890CC 88030214\r\nE2000001 00000000\r\n2A3E10D2 00002A00\r\n04148D20 38000000\r\n04147F98 38005000\r\n042890CC 60000000\r\nE2000001 00000000\r\n20570B7C 00000000\r\n0474E87C 21000000\r\n20570B7D 00000001\r\n0474E9F4 21210000\r\n20570B7D 00000002\r\n0474ED38 00000000\r\n20570B7D 00000003\r\n0474EE04 A1000000\r\n20570B7D 00000004\r\n0474EBDC 21210000\r\nE2000001 00000000\r\n","no":""},"nofmvs":{"yes":"042ADE20 38600001\r\n042ADE88 38600001\r\n","pp1":"C22ADE1C 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\nC22ADE84 00000004\r\n38840391 5480043C\r\n2C000398 4182000C\r\n3C800001 6084039A\r\n60000000 00000000\r\n","no":""}} \ No newline at end of file +{"fileSelect":2668620,"shineGet":2685724,"system":2691272,"proc":2745964,"gpAppHi":"803E","gpAppLo":"10D2","fmOffset":"9EC8","notext":{"yes":"20570B7C000000000474E87C2100000020570B7D000000010474E9F42121000020570B7D000000020474ED380000000020570B7D000000030474EE04A100000020570B7D000000040474EBDC21210000E20000010000000004148D203800000004147F9838005000042890CC60000000","pv5":"283E10D200002A0004148D20801C000404147F98A81C0340042890CC88030214E2000001000000002A3E10D200002A0004148D203800000004147F9838005000042890CC60000000E20000010000000020570B7C000000000474E87C2100000020570B7D000000010474E9F42121000020570B7D000000020474ED380000000020570B7D000000030474EE04A100000020570B7D000000040474EBDC21210000E200000100000000","no":""},"nofmvs":{"yes":"042ADE2038600001042ADE8838600001","pp":"C22ADE1C000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000C22ADE84000000055480043F388403914182001C5480043C2C000398418200103C8000016084039A6000000000000000","no":""}} \ No newline at end of file diff --git a/gctGenerator.js b/gctGenerator.js index f93941e..b831d7a 100644 --- a/gctGenerator.js +++ b/gctGenerator.js @@ -186,7 +186,7 @@ function updateUIDescription(s) { if (s.id === "route_notext") 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.

"; + 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' - so don't use both simultaneously.

"; 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 === "route_ending") @@ -361,97 +361,64 @@ function getFastCode() { let game = JSON.parse(atob(document.getElementById("route_levels").getAttribute("data-json"))); const order = document.getElementById("route_order").value; const ending = document.getElementById("route_ending").value; - const branchBase = 0x18 + 0x24 * (order !== 'list'); - const asm = []; - asm.push("48" + ("00000" + (Math.ceil(levelCodes.length / 2) + 1 << 2 | 1).toString(16).toUpperCase()).slice(-6)); // bl code - for (let i = levelCodes.length - 1; i >= 0; i -= 2) { - asm.push(levelCodes[i] + (levelCodes[i - 1] || "0000")); - } - - // code: - //Timer compatibility - asm.push("3C80817F"); // lis r4, 0x817F - asm.push("38000000"); // li r0, 0 - asm.push("9004010C"); // stw r0, 0x010C(r4) - asm.push("38000001"); // li r0, 1 - asm.push("98040101"); // stb r0, 0x0101(r4) - - asm.push("887F0012"); // lbz r3, 0x12(r31) - asm.push("2C030001"); // cmpwi r3, 1 - asm.push("4181" + ("000" + (branchBase + 0x48).toString(16).toUpperCase()).slice(-4)); // bgt- done + const loadStageLength = {'list': 0x20, 'random': 0x2C, 'shuffle': 0x40}[order] + let codes = '' - asm.push("98040100"); // stb r0, 0x0100(r4) + // Reset counter on file select + codes += '0' + (0x04000000 + (game.fileSelect & 0x01FFFFFF)).toString(16) + + (0x48000001 + (game.system + 0x52C - game.fileSelect & 0x03FFFFFC)).toString(16) - asm.push("80AD" + game.fmOffset); // lwz r5, TFlagManager::smInstance - asm.push("7CC802A6"); // mflr r6 - asm.push("80640000"); // lwz r3, 0(r4) + // Load next stage on Shine get + codes += '0' + (0x04000000 + (game.shineGet & 0x01FFFFFF)).toString(16) + + (0x48000001 + (game.system + 0x53C - game.shineGet & 0x03FFFFFC)).toString(16) + + // Reload stage on exit area + codes += '0' + (0x04000000 + (game.system & 0x01FFFFFF)).toString(16) + '48000511' - asm.push("881F000E"); // lbz r0, 0x0E(r31) - asm.push("2C00000F"); // cmpwi r0, 15 - asm.push("40820010"); // bne- 0x10 - asm.push("3860" + ("000" + ((levelCodes.length - (order === 'random')) * 2).toString(16).toUpperCase()).slice(-4)); // li r3, length - asm.push("90640000"); // stw r3, 0(r4) - asm.push("48000018"); // b 0x18 - asm.push("2C030000"); // cmpwi r3, 0 - asm.push("4180" + ("000" + (0x1C + 0x14 * (order !== "list")).toString(16).toUpperCase()).slice(-4)); // blt- loadEnding - 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- loadIndex + // Set next stage on game over + codes += '0' + (0x06000000 + (game.system + 0xB4 & 0x01FFFFFF)).toString(16) + '000000084800048948000044' + + // Reset timer on secret death + codes += (0xC2000000 + (game.system + 0x208 & 0x01FFFFFF)).toString(16) + '000000033C60817F38000001980300FF881C00006000000000000000' + + // Overwrite decideNextStage(void) with useful routines + codes += '0' + (0x06000000 + (game.system + 0x510 & 0x01FFFFFF)).toString(16) + + ('0000000' + (loadStageLength + 0x5C).toString(16)).slice(-8) + + '3C60817F38000001980300FFA00300023C60' + game.gpAppHi + 'B003' + game.gpAppLo + '4E800020' + // reload current level + '3C60817F' + (0x38800000 + (levelCodes.length * 2 & 0x0000FFFF)).toString(16) + 'B08300004E800020' + // reset counter + '3C60817F38000001980300FFA00300002C00000038E0' + ending + // load next stage - the fun begins + (0x40810000 + (loadStageLength & 0x0000FFFC)).toString(16) + '7C8802A6600000007CC802A67C8803A6' - if (order === "random") { - asm.push("38630002"); // addi r3, r3, 2 - } - - 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("3463FFFE"); // subic. r3, r3, 2 - if (order !== "random") { - asm.push("90640000"); // stw r3, 0(r4) + switch (order) { + case 'list': codes += '3400FFFEB00300007CE6022E'; break + case 'random': codes += '7C8C42E67CA403967CA501D67C8520505484003C7CE6222E'; break + case 'shuffle': codes += '7C8C42E67CA403967CA501D67C8520505484003C3400FFFEB00300007CE6222E7CA6022E7CA6232E7CE6032E' } - asm.push("4080000C"); // bge- 0xC + codes += 'B0E300023C60' + game.gpAppHi + 'B0E3' + game.gpAppLo + '806D' + game.fmOffset + '98E300DF4E800020' + (order === 'random' ? '' : '00000000') - // loadEnding: - asm.push("3860" + ending); // li r3, ending - asm.push("4800" + ("000" + (0x8 + 0x10 * (order !== "list")).toString(16).toUpperCase()).slice(-4)); // b loadStage - - 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 - } + levelCodes.reverse() - // loadIndex: - asm.push("7C661A2E"); // lhzx r3, r6, r3 + while (levelCodes.length % 4) levelCodes.push('0000') - // loadStage: - asm.push("B07F0012"); // sth r3, 0x12(r31) - asm.push("986500DF"); // stb r3, 0xDF(r5) + // Insert the list of levels into the loader + codes += (0xC2000000 + (game.system + 0x55C & 0x01FFFFFF)).toString(16) + + ('0000000' + (levelCodes.length / 4 + 1).toString(16)).slice(-8) + + (0x48000001 + (levelCodes.length * 2 + 4 & 0x03FFFFFC)).toString(16) + + levelCodes.join('') + '00000000' + + // Load next stage on setNextStage into main level + codes += '0' + (0x06000000 + (game.system + 0x118C & 0x01FFFFFF)).toString(16) + + '00000028B07D00143C80817F38000000B00400FFA0010038B01D00122C1C00094181000C4BFFF391B0E10038' + + // Setup timer + codes += (0xC2000000 + (game.proc & 0x01FFFFFF)).toString(16) + + '000000053CA0817F388000009085010C880500FF98050100988500FF38800001988501016000000000000000' + + codes = codes.toUpperCase() - // done: - asm.push("807F0020"); // lwz r3, 0x20(r31) - - if (asm.length % 2 === 0) { - asm.push("60000000"); // nop - } - asm.push("00000000"); - - const geckoLines = asm.length / 2; - let gecko = "C2" + game.injectAddr + " " + ("0000000" + geckoLines.toString(16).toUpperCase()).slice(-8) + "\r\n"; - for (let i = 0; i < geckoLines; ++i) { - gecko += asm[2 * i] + " " + asm[2 * i + 1] + "\r\n"; - } - - let codes = gecko + - game.notext[document.getElementById("route_notext").value] + + codes += game.notext[document.getElementById("route_notext").value] + game.nofmvs[document.getElementById("route_nofmvs").value]; - return codes.replace(/[^0-9A-F]/g, ''); + return codes } diff --git a/index.html b/index.html index dcc884c..fbabc8a 100644 --- a/index.html +++ b/index.html @@ -88,7 +88,7 @@ @@ -112,6 +112,8 @@ @@ -126,6 +128,17 @@ @@ -238,11 +260,22 @@