gctGenerator/site/.vuepress/components/codes/CustomizedDisplay/fields.js

125 lines
3.3 KiB
JavaScript

import { ASM } from '../asm.js';
import { makeDirectLoaderASM, makeFunctionLoader, rTmp, fTmp } from './loader.js';
import { addrs, r13offs } from '../addrs.js';
/**
* @typedef {ReturnType<import('./loader.js').makeFunctionLoader>} Loader
* @typedef {ReturnType<Loader['asm']>[number]} ASMInst
* @typedef {Parameters<Loader['asm']>[0]} GameVersion
*
* @typedef {Parameters<makeDirectLoaderASM>[1]} DirectLoadFunc
* @typedef {{
* dtype: Loader['dtype'],
* base: keyof typeof bases,
* offset: number,
* postprocess?: (rT: number)=>ASMInst[]
* }} DirectLoader
*/
const r13bases = /**@type{{[k in keyof typeof r13offs]: DirectLoadFunc}}*/ (
Object.fromEntries(
Object.entries(r13offs).map(([k, ver2off]) => [
k,
/** @type {DirectLoadFunc} */
(rT, ver) => [ASM.lwz(rT, 13, ver2off[ver])],
]),
)
);
export const bases = {
...r13bases,
};
/** @type {Array<(Loader|DirectLoader) & {id:string} & (
* {fmt: string, preview: number} |
* {fmt: '%s', preview: (ver: GameVersion) => string}
* )>}
*/
export const fields = [
{ id: 'x', base: 'gpMarioOriginal', dtype: 'float', offset: 0x10, fmt: '%.0f', preview: 426.39 },
{ id: 'y', base: 'gpMarioOriginal', dtype: 'float', offset: 0x14, fmt: '%.0f', preview: -427.39 },
{ id: 'z', base: 'gpMarioOriginal', dtype: 'float', offset: 0x18, fmt: '%.0f', preview: 428.39 },
{ id: 'angle', base: 'gpMarioOriginal', dtype: 16, offset: 0x96, fmt: '%hu', preview: 1207 },
{
id: 'HSpd',
base: 'gpMarioOriginal',
dtype: 'float',
offset: 0xb0,
fmt: '%.2f',
preview: 15.15,
},
{
id: 'VSpd',
base: 'gpMarioOriginal',
dtype: 'float',
offset: 0xa8,
fmt: '%.2f',
preview: -31.17,
},
{
id: 'QF',
base: 'gpMarDirector',
dtype: 32,
offset: 0x58,
fmt: '%u',
preview: 0,
postprocess: (rT) => [ASM.rlwinm(rT, rT, 0, 30, 31, false)],
},
{
id: 'CAngle',
base: 'gpCamera',
dtype: 16,
offset: 0xa6,
fmt: '%hu',
preview: 9,
postprocess: (rT) => [ASM.addi(rT, rT, -0x8000)], // offset by 0x8000
},
{
id: 'invinc',
base: 'gpMarioOriginal',
dtype: 16,
offset: 0x14c,
fmt: '%hd',
preview: 30,
postprocess: (rT) => [ASM.rlwinm(rT, rT, 30, 2, 31, false)], // QF to frame (>>2)
},
{
id: 'goop',
fmt: '%d',
preview: 600,
...makeFunctionLoader(-32, (ver) => [
{
type: 'call',
addr: addrs.getPollutionDegree[ver],
prep: [ASM.lwz(3, 13, r13offs.gpPollution[ver])],
},
]),
},
{
id: 'spin',
fmt: '%s',
// TODO better char mapping
preview: (ver) => String.fromCharCode(ver.startsWith('GMSJ') ? 0xff20 : 0x40),
dtype: 32,
calling: true,
asm: (ver, dst) => [
{
type: 'call',
addr: addrs.checkStickRotate[ver],
prep: [
ASM.lwz(3, 13, r13offs.gpMarioOriginal[ver]),
ASM.stwu(1, 1, -0x10),
ASM.addi(4, 1, 8),
],
},
// 0 (A) 0
{ type: 'struct', reg: rTmp, hex: ver.startsWith('GMSJ') ? '00819700' : '004000' },
...(dst.type === 'stack'
? [ASM.add(3, rTmp, 3), ASM.stw(3, 1, dst.off)]
: [ASM.add(dst.num, rTmp, 3)]),
// finalize
ASM.addi(1, 1, 0x10),
],
},
];
export const fieldDB = Object.fromEntries(fields.map((o) => [o.id.toLowerCase(), o]));