qft freezes rework + yoshi mount freeze
This commit is contained in:
parent
9dd72475f1
commit
d50a806a85
9 changed files with 116 additions and 98 deletions
|
@ -1234,10 +1234,10 @@
|
|||
<code>
|
||||
<id>qft</id>
|
||||
<category>timer</category>
|
||||
<title lang="en-US">Quarterframe Timer (Experimental)</title>
|
||||
<title lang="en-US">Quarterframe Timer</title>
|
||||
<title lang="ja-JP">QFタイマー</title>
|
||||
<author>Noki Doki, sup39(サポミク)</author>
|
||||
<version>1.3</version>
|
||||
<version>1.4</version>
|
||||
<date>Dec 16, 2022</date>
|
||||
<dependencies version="GMSJ01">drawText</dependencies>
|
||||
<dependencies version="GMSE01">drawText</dependencies>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
# Changelog
|
||||
## Jan 7, 2023
|
||||
### Updated 'Quarterframe Timer'
|
||||
Reworked the existing freezes and added the option to freeze when mounting Yoshi
|
||||
|
||||
## Dec 16, 2022
|
||||
### Updated 'Quarterframe Timer'
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
export const r13off = -0x6048;
|
||||
|
||||
/**
|
||||
* @type {{[key: string]: {addr: number, orig: number}}}
|
||||
* @type {{[key: string]: number}}
|
||||
*/
|
||||
export const freezeCodeInfo = {
|
||||
yellowCoin: { addr: 0x801becb4, orig: 0x8805000e },
|
||||
redCoin: { addr: 0x801be474, orig: 0x38a00000 },
|
||||
blueCoin: { addr: 0x801be288, orig: 0x7c030378 },
|
||||
item: { addr: 0x801bf3b4, orig: 0x8001001c },
|
||||
talk: { addr: 0x80298128, orig: 0x807f00b0 },
|
||||
demo: { addr: 0x802981a4, orig: 0x88e7013c },
|
||||
cleaned: { addr: 0x80215c58, orig: 0x80010044 },
|
||||
bowser: { addr: 0x801fc0a4, orig: 0x2c1d0003 },
|
||||
export const freezeCodeHooks = {
|
||||
yellowCoin: 0x801bee10,
|
||||
redCoin: 0x801be524,
|
||||
blueCoin: 0x801be32c,
|
||||
item: 0x801bf3c4,
|
||||
talk: 0x80153a34,
|
||||
demo: 0x80032bd8,
|
||||
cleaned: 0x80215c6c,
|
||||
bowser: 0x801fb7ac,
|
||||
yoshi: 0x802704d4,
|
||||
};
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
export const r13off = -0x6818;
|
||||
|
||||
/**
|
||||
* @type {{[key: string]: {addr: number, orig: number}}}
|
||||
* @type {{[key: string]: number}}
|
||||
*/
|
||||
export const freezeCodeInfo = {
|
||||
yellowCoin: { addr: 0x80196b54, orig: 0x8805000e },
|
||||
redCoin: { addr: 0x80196314, orig: 0x38a00000 },
|
||||
blueCoin: { addr: 0x80196128, orig: 0x7c030378 },
|
||||
item: { addr: 0x801971f8, orig: 0x8001001c },
|
||||
talk: { addr: 0x800eb6e4, orig: 0x807f00b0 },
|
||||
demo: { addr: 0x800eb760, orig: 0x88e7013c },
|
||||
cleaned: { addr: 0x8017a3c0, orig: 0x80010044 },
|
||||
bowser: { addr: 0x801d3c78, orig: 0x2c1d0003 },
|
||||
export const freezeCodeHooks = {
|
||||
yellowCoin: 0x80196cb0,
|
||||
redCoin: 0x801963c4,
|
||||
blueCoin: 0x801961cc,
|
||||
item: 0x80197208,
|
||||
talk: 0x80214f00,
|
||||
demo: 0x80362434,
|
||||
cleaned: 0x8017a3d4,
|
||||
bowser: 0x801d3380,
|
||||
yoshi: 0x8014f830,
|
||||
};
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
export const r13off = -0x6188;
|
||||
|
||||
/**
|
||||
* @type {{[key: string]: {addr: number, orig: number}}}
|
||||
* @type {{[key: string]: number}}
|
||||
*/
|
||||
export const freezeCodeInfo = {
|
||||
yellowCoin: { addr: 0x8019ea3c, orig: 0x8805000e },
|
||||
redCoin: { addr: 0x8019e1fc, orig: 0x38a00000 },
|
||||
blueCoin: { addr: 0x8019e010, orig: 0x7c030378 },
|
||||
item: { addr: 0x8019f13c, orig: 0x8001001c },
|
||||
talk: { addr: 0x80277dd0, orig: 0x807f00b0 },
|
||||
demo: { addr: 0x80277e4c, orig: 0x88e7013c },
|
||||
cleaned: { addr: 0x801f5af8, orig: 0x80010044 },
|
||||
bowser: { addr: 0x801dbe48, orig: 0x2c1d0003 },
|
||||
export const freezeCodeHooks = {
|
||||
yellowCoin: 0x8019eb98,
|
||||
redCoin: 0x8019e2ac,
|
||||
blueCoin: 0x8019e0b4,
|
||||
item: 0x8019f14c,
|
||||
talk: 0x80134e58,
|
||||
demo: 0x80364ae0,
|
||||
cleaned: 0x801f5b0c,
|
||||
bowser: 0x801db550,
|
||||
yoshi: 0x80250224,
|
||||
};
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
export const r13off = -0x6120;
|
||||
|
||||
/**
|
||||
* @type {{[key: string]: {addr: number, orig: number}}}
|
||||
* @type {{[key: string]: number}}}
|
||||
*/
|
||||
export const freezeCodeInfo = {
|
||||
yellowCoin: { addr: 0x801b6b6c, orig: 0x8805000e },
|
||||
redCoin: { addr: 0x801b632c, orig: 0x38a00000 },
|
||||
blueCoin: { addr: 0x801b6140, orig: 0x7c030378 },
|
||||
item: { addr: 0x801b726c, orig: 0x8001001c },
|
||||
talk: { addr: 0x8028ffc0, orig: 0x807f00b0 },
|
||||
demo: { addr: 0x8029003c, orig: 0x88e7013c },
|
||||
cleaned: { addr: 0x8020db3c, orig: 0x80010044 },
|
||||
bowser: { addr: 0x801f3f88, orig: 0x2c1d0003 },
|
||||
export const freezeCodeHooks = {
|
||||
yellowCoin: 0x801b6cc8,
|
||||
redCoin: 0x801b63dc,
|
||||
blueCoin: 0x801b61e4,
|
||||
item: 0x801b727c,
|
||||
talk: 0x801489b4,
|
||||
demo: 0x80032c90,
|
||||
cleaned: 0x8020db50,
|
||||
bowser: 0x801f3690,
|
||||
yoshi: 0x80268260,
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ export function getConfig() {
|
|||
}
|
||||
|
||||
/** @param {number} x */
|
||||
const inst2gecko = (x) => (x >>> 0).toString(16).toUpperCase().padStart(8, '0');
|
||||
const int2gecko = (x) => (x >>> 0).toString(16).toUpperCase().padStart(8, '0');
|
||||
|
||||
import * as GMSJ01 from './code/GMSJ01.js';
|
||||
import * as GMSE01 from './code/GMSE01.js';
|
||||
|
@ -49,22 +49,17 @@ export const codes = { GMSJ01, GMSE01, GMSP01, GMSJ0A };
|
|||
|
||||
/****
|
||||
## save freeze frame, load and save QF
|
||||
## this function destroys r11(freeze frame), r12
|
||||
## this function destroys r11 and r12
|
||||
077F0348:
|
||||
lwz r11, gpMarDirector-_SDA_BASE_(r13)
|
||||
lis r12, 0x817F
|
||||
stw r11, 0xBC(r12)
|
||||
lwz r11, -0x6818(r13)
|
||||
lwz r11, 0x5C(r11)
|
||||
stw r11, 0xB8(r12)
|
||||
li r11, freezeDuration
|
||||
stw r11, 0xBC(r12)
|
||||
blr
|
||||
|
||||
## for each code
|
||||
ORIG
|
||||
li r11, xxxx
|
||||
b 817f0348
|
||||
|
||||
04xxxxxx:
|
||||
bl 817fxxxx
|
||||
## for each hook (over a blr): b 817f0348
|
||||
****/
|
||||
const freezeCodeAddr = 0x817f0348;
|
||||
/**
|
||||
|
@ -75,24 +70,22 @@ export default function codegen(version, baseCode) {
|
|||
if (!baseCode) return '';
|
||||
|
||||
const config = getConfig();
|
||||
const { freezeCodeInfo, r13off } = codes[version] ?? {};
|
||||
const { freezeCodeHooks, r13off } = codes[version] ?? {};
|
||||
|
||||
let code = baseCode;
|
||||
const { freezeDuration: frame } = config;
|
||||
|
||||
// freezing code
|
||||
const freezeEnableds = [];
|
||||
const enabledFreezes = [];
|
||||
if (frame > 0) {
|
||||
for (const [key, enabled] of Object.entries(config.freeze)) {
|
||||
const info = freezeCodeInfo[key];
|
||||
if (enabled && info) {
|
||||
const { addr, orig } = info;
|
||||
const addr = freezeCodeHooks[key];
|
||||
if (enabled && addr) {
|
||||
if (key === 'blueCoin') {
|
||||
// special: needs to adjust QF -> use separate C2 instead
|
||||
code += [
|
||||
0xc2000000 + (addr & 0x1ffffff),
|
||||
0x00000005,
|
||||
orig,
|
||||
0x00000004,
|
||||
0x80a3005c,
|
||||
0x38a50003,
|
||||
0x54a0003a,
|
||||
|
@ -100,39 +93,45 @@ export default function codegen(version, baseCode) {
|
|||
0x900500b8,
|
||||
0x38000000 | (frame & 0xffff),
|
||||
0x900500bc,
|
||||
0x60000000,
|
||||
0x00000000,
|
||||
]
|
||||
.map(inst2gecko)
|
||||
.map(int2gecko)
|
||||
.join('');
|
||||
} else {
|
||||
// handle regular freezing code later
|
||||
freezeEnableds.push(info);
|
||||
enabledFreezes.push(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle regular freezing code
|
||||
if (freezeEnableds.length <= 1) {
|
||||
if (enabledFreezes.length <= 1) {
|
||||
// use C2 directly
|
||||
code += freezeEnableds
|
||||
.flatMap(({ addr, orig }) => [
|
||||
code += enabledFreezes
|
||||
.flatMap((addr) => [
|
||||
0xc2000000 + (addr & 0x1ffffff),
|
||||
0x00000004,
|
||||
orig,
|
||||
0x816d0000 | (r13off & 0xffff), // lwz r11, r13off(r13)
|
||||
0x3d80817f, // lis r12, 0x817F
|
||||
0x816b005c, // lwz r11, 0x5C(r11)
|
||||
0x916c00b8, // stw r11, 0xB8(r12)
|
||||
0x39600000 | (frame & 0xffff), // li r11, frame
|
||||
0x916c00bc, // stw r11, 0xBC(r12)
|
||||
0x60000000, // nop
|
||||
0x00000000,
|
||||
])
|
||||
.map(inst2gecko)
|
||||
.map(int2gecko)
|
||||
.join('');
|
||||
} else {
|
||||
const code04 = [];
|
||||
const code07 = [
|
||||
// could be shorter to turn this into a Gecko loop if enough freezes are enabled
|
||||
const hooks = enabledFreezes.flatMap((addr) => [
|
||||
0xc6000000 | (addr & 0x1ffffff),
|
||||
freezeCodeAddr,
|
||||
]);
|
||||
|
||||
const freezer = [
|
||||
0x06000000 | (freezeCodeAddr & 0x1ffffff),
|
||||
0x0000001c,
|
||||
0x816d0000 | (r13off & 0xffff), // lwz r11, r13off(r13)
|
||||
0x3d80817f, // lis r12, 0x817F
|
||||
0x816b005c, // lwz r11, 0x5C(r11)
|
||||
|
@ -140,31 +139,11 @@ export default function codegen(version, baseCode) {
|
|||
0x39600000 | (frame & 0xffff), // li r11, frame
|
||||
0x916c00bc, // stw r11, 0xBC(r12)
|
||||
0x4e800020, // blr
|
||||
0x00000000,
|
||||
];
|
||||
let dst = freezeCodeAddr + code07.length * 4;
|
||||
// put code together
|
||||
for (const { addr, orig } of freezeEnableds) {
|
||||
code07.push(
|
||||
orig, // [dst] original instruction
|
||||
0x4c000000 + (freezeCodeAddr - dst - 4), // b freezeCode
|
||||
);
|
||||
code04.push(
|
||||
0x04000000 | (addr & 0x1ffffff), // 04 addr
|
||||
0x48000001 | (dst - addr), // bl dst
|
||||
);
|
||||
dst += 8;
|
||||
}
|
||||
// make 07 code
|
||||
code07.unshift(
|
||||
0x06000000 | (freezeCodeAddr & 0x1ffffff), // 07 freezeCodeAddr
|
||||
code07.length * 4,
|
||||
);
|
||||
if (code07.length & 1) {
|
||||
// odd => pad with 0
|
||||
code07.push(0);
|
||||
}
|
||||
|
||||
// apply code
|
||||
code += [...code04, ...code07].map(inst2gecko).join('');
|
||||
code += [...hooks, ...freezer].map(int2gecko).join('');
|
||||
}
|
||||
|
||||
// ui
|
||||
|
@ -178,7 +157,7 @@ export default function codegen(version, baseCode) {
|
|||
x + width * scale, // x2
|
||||
y, // y2
|
||||
]
|
||||
.map(inst2gecko)
|
||||
.map(int2gecko)
|
||||
.join('');
|
||||
code += '25753a253032752e2530337500000000'; // fmt
|
||||
/* fontSize, fgColor, bgColor */
|
||||
|
@ -187,7 +166,7 @@ export default function codegen(version, baseCode) {
|
|||
const fgColor = (config.fgRGB & 0xffffff) * 256 + (config.fgA & 0xff);
|
||||
const fgColor2 =
|
||||
((config.fgRGB2 ?? config.fgRGB) & 0xffffff) * 256 + ((config.fgA2 ?? config.fgA) & 0xff);
|
||||
code += [fontSize, fgColor, fgColor2, bgColor].map(inst2gecko).join('');
|
||||
code += [fontSize, fgColor, fgColor2, bgColor].map(int2gecko).join('');
|
||||
|
||||
return code.replace(/\s/g, '');
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ export default {
|
|||
freeze,
|
||||
freezeDuration,
|
||||
// const
|
||||
freezeKeys: Object.keys(codes[this.version]?.freezeCodeInfo ?? {}),
|
||||
freezeKeys: Object.keys(codes[this.version]?.freezeCodeHooks ?? {}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
"talk": "会話開始時",
|
||||
"demo": "カットシーン開始時",
|
||||
"cleaned": "NPCを洗った時",
|
||||
"bowser": "クッパ戦の足場を破壊した時"
|
||||
"bowser": "クッパ戦の足場を破壊した時",
|
||||
"yoshi": "ヨッシーに乗った時"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -53,7 +54,38 @@
|
|||
"talk": "When dialogue starts",
|
||||
"demo": "When a cutscene starts",
|
||||
"cleaned": "When an NPC is cleaned",
|
||||
"bowser": "When a platform is destroyed in the Bowser fight"
|
||||
"bowser": "When a platform is destroyed in the Bowser fight",
|
||||
"yoshi": "When Yoshi is mounted"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr-FR": {
|
||||
"h3": "Apparence",
|
||||
"location": "Position : ",
|
||||
"fontSize": "Taille de police : ",
|
||||
"fgColor": "Couleur du texte : ",
|
||||
"fgColorGrad": "Dégradé",
|
||||
"fgColor1": "Couleur du texte (haut) : ",
|
||||
"fgColor2": "Couleur du texte (bas) : ",
|
||||
"bgColor": "Couleur de fond : ",
|
||||
"alpha": "Alpha = ",
|
||||
"preview": "Aperçu",
|
||||
"previewNote": "※ x doit être entre 0 et 600, et y entre 16 et 464.",
|
||||
"freeze": {
|
||||
"h3": "Temps intermédiaires",
|
||||
"duration": "Durée d'affichage : ",
|
||||
"frame": "(frames)",
|
||||
"sec": "(sec)",
|
||||
"rows": {
|
||||
"yellowCoin": "Quand une pièce jaune est ramassée",
|
||||
"redCoin": "Quand une pièce rouge est ramassée",
|
||||
"blueCoin": "Quand une pièce bleue est ramassée",
|
||||
"item": "Quand un power-up (buse, etc.) est ramassé",
|
||||
"talk": "Quand un dialogue commence",
|
||||
"demo": "Quand une cutscene commence",
|
||||
"cleaned": "Quand un PNJ est nettoyé",
|
||||
"bowser": "Quand une plate-forme est détruite dans le combat de Bowser",
|
||||
"yoshi": "Quand Yoshi est monté"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue