diff --git a/Readme.md b/Readme.md index af3c021..8a278da 100644 --- a/Readme.md +++ b/Readme.md @@ -51,8 +51,8 @@ Some codes store some states in the games memory starting from address 0x817F000 | ![](./docs/buffer.svg) | `0x10D` | `0x10F` | Buffer (Ingame Timer) | | ![](./docs/reserved.svg) | `0x110` | `0x237` | QF Timer: Timer Textbox | | ![](./docs/reserved.svg) | `0x238` | `0x347` | General Function (`drawText`) | -| ![](./docs/buffer.svg) | `0x348` | `0x3BF` | Buffer (QF Timer) | -| ![](./docs/unallocated.svg) | `0x3C0` | `0xFFF` | Not Allocated | +| ![](./docs/buffer.svg) | `0x348` | `0x39B` | Buffer (QF Timer) | +| ![](./docs/unallocated.svg) | `0x39C` | `0xFFF` | Not Allocated | ### Adding translations diff --git a/changelog.md b/changelog.md index df7f499..ed8dc0c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,9 +1,11 @@ # Changelog ## Apr 22, 2022 -### Shortened QFT -- Shortened QFT's freeze code by replacing C2 with 04(bl@event) and 07. -- Reserve `817F0348`~`817F03BF` (120 bytes) +### Shortened QFT and simplified config +- Shorten QFT's freeze code by replacing C2 with 04(bl@event) and 07. +- Reserve `817F0348`~`817F039B` (84 bytes) +- Change freezing config from [duration for each event] to [one duration + toggle for each event] +## Apr 21, 2022 ### Reduced code size of Pattern Selector Reduce 240 bytes of PS by replacing switch case with lookup table. diff --git a/site/.vuepress/components/codes/qft/code/GMSE01.js b/site/.vuepress/components/codes/qft/code/GMSE01.js index 4f66692..7d9ec9c 100644 --- a/site/.vuepress/components/codes/qft/code/GMSE01.js +++ b/site/.vuepress/components/codes/qft/code/GMSE01.js @@ -1,11 +1,11 @@ export const r13off = -0x6048; /** - * @type {{[key: string]: [addr: number, orig: number]}} + * @type {{[key: string]: {addr: number, orig: number}}} */ export const freezeCodeInfo = { - redCoin: [0x801be474, 0x38a00000], - blueCoin: [0x801be288, 0x7c030378], // TODO QF+3 &0xfffffffc + redCoin: { addr: 0x801be474, orig: 0x38a00000 }, + blueCoin: { addr: 0x801be288, orig: 0x7c030378 }, }; export const baseCode = ` diff --git a/site/.vuepress/components/codes/qft/code/GMSJ01.js b/site/.vuepress/components/codes/qft/code/GMSJ01.js index 9b9b2ff..2fe3718 100644 --- a/site/.vuepress/components/codes/qft/code/GMSJ01.js +++ b/site/.vuepress/components/codes/qft/code/GMSJ01.js @@ -1,17 +1,17 @@ export const r13off = -0x6818; /** - * @type {{[key: string]: [addr: number, orig: number]}} + * @type {{[key: string]: {addr: number, orig: number}}} */ export const freezeCodeInfo = { - yellowCoin: [0x80196b54, 0x8805000e], - redCoin: [0x80196314, 0x38a00000], - blueCoin: [0x80196128, 0x7c030378], // TODO QF+3 &0xfffffffc - item: [0x801971f8, 0x8001001c], - talk: [0x800eb6e4, 0x807f00b0], - demo: [0x800eb74c, 0x806da8b0], - cleaned: [0x8017a3c0, 0x80010044], - bowser: [0x801d3c78, 0x2c1d0003], + 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: 0x800eb74c, orig: 0x806da8b0 }, + cleaned: { addr: 0x8017a3c0, orig: 0x80010044 }, + bowser: { addr: 0x801d3c78, orig: 0x2c1d0003 }, }; export const baseCode = ` diff --git a/site/.vuepress/components/codes/qft/code/GMSJ0A.js b/site/.vuepress/components/codes/qft/code/GMSJ0A.js index 2d38036..82c473b 100644 --- a/site/.vuepress/components/codes/qft/code/GMSJ0A.js +++ b/site/.vuepress/components/codes/qft/code/GMSJ0A.js @@ -1,11 +1,11 @@ export const r13off = -0x6188; /** - * @type {{[key: string]: [addr: number, orig: number]}} + * @type {{[key: string]: {addr: number, orig: number}}} */ export const freezeCodeInfo = { - redCoin: [0x8019e1fc, 0x38a00000], - blueCoin: [0x8019e010, 0x7c030378], // TODO QF+3 &0xfffffffc + redCoin: { addr: 0x8019e1fc, orig: 0x38a00000 }, + blueCoin: { addr: 0x8019e010, orig: 0x7c030378 }, }; export const baseCode = ` diff --git a/site/.vuepress/components/codes/qft/code/GMSP01.js b/site/.vuepress/components/codes/qft/code/GMSP01.js index 2168202..760a7ba 100644 --- a/site/.vuepress/components/codes/qft/code/GMSP01.js +++ b/site/.vuepress/components/codes/qft/code/GMSP01.js @@ -1,11 +1,11 @@ export const r13off = -0x6120; /** - * @type {{[key: string]: [addr: number, orig: number]}} + * @type {{[key: string]: {addr: number, orig: number}}} */ export const freezeCodeInfo = { - redCoin: [0x801b632c, 0x38a00000], - blueCoin: [0x801b6140, 0x7c030378], // TODO QF+3 &0xfffffffc + redCoin: { addr: 0x801b632c, orig: 0x38a00000 }, + blueCoin: { addr: 0x801b6140, orig: 0x7c030378 }, }; export const baseCode = ` diff --git a/site/.vuepress/components/codes/qft/codegen.js b/site/.vuepress/components/codes/qft/codegen.js index 91c7a0f..c1e77a3 100644 --- a/site/.vuepress/components/codes/qft/codegen.js +++ b/site/.vuepress/components/codes/qft/codegen.js @@ -12,15 +12,16 @@ export const defaultConfig = { fgA2: null, bgRGB: 0x000000, bgA: 0x80, + freezeDuration: 30, freeze: { - yellowCoin: 0, - redCoin: 30, - blueCoin: 30, - item: 30, - talk: 30, - demo: 30, - cleaned: 30, - bowser: 30, // onBathhubGripDestroyed + yellowCoin: false, + redCoin: true, + blueCoin: true, + item: true, + talk: true, + demo: true, + cleaned: true, + bowser: true, // onBathhubGripDestroyed }, }; @@ -36,8 +37,10 @@ export function getConfig() { }; } -const int16 = (x) => (x < 0 ? x + 0x10000 : x).toString(16).padStart(4, '0').slice(-4); -const int32 = (x) => (x < 0 ? x + 0x100000000 : x).toString(16).padStart(8, '0').slice(-8); +const int16 = (x) => + (x < 0 ? x + 0x10000 : x).toString(16).padStart(4, '0').slice(-4).toUpperCase(); +const int32 = (x) => + (x < 0 ? x + 0x100000000 : x).toString(16).padStart(8, '0').slice(-8).toUpperCase(); import * as GMSJ01 from './code/GMSJ01.js'; import * as GMSE01 from './code/GMSE01.js'; @@ -71,78 +74,81 @@ export default function codegen(version) { if (baseCode == null) return ''; let code = baseCode; + const { freezeDuration: frame } = config; // freezing code - const freezeConfigs = []; - for (const [key, frame] of Object.entries(config.freeze)) { - const info = freezeCodeInfo[key]; - if (frame > 0 && info) { - const [addr, orig] = info; - if (key === 'blueCoin') { - // special: needs to adjust QF -> use separate C2 instead - code += [ - 0xc2000000 + (addr & 0x1ffffff), - 0x00000005, - orig, - 0x80a3005c, - 0x38a50003, - 0x54a0003a, - 0x3ca0817f, - 0x900500b8, - 0x38000000 | (frame & 0xffff), - 0x900500bc, - 0x60000000, - 0x00000000, - ] - .map(int32) - .join(''); - } else { - // handle regular freezing code later - freezeConfigs.push({ frame, addr, orig }); + const freezeEnableds = []; + if (frame > 0) { + for (const [key, enabled] of Object.entries(config.freeze)) { + const info = freezeCodeInfo[key]; + if (enabled && info) { + const { addr, orig } = info; + if (key === 'blueCoin') { + // special: needs to adjust QF -> use separate C2 instead + code += [ + 0xc2000000 + (addr & 0x1ffffff), + 0x00000005, + orig, + 0x80a3005c, + 0x38a50003, + 0x54a0003a, + 0x3ca0817f, + 0x900500b8, + 0x38000000 | (frame & 0xffff), + 0x900500bc, + 0x60000000, + 0x00000000, + ] + .map(int32) + .join(''); + } else { + // handle regular freezing code later + freezeEnableds.push(info); + } } } } // handle regular freezing code - if (freezeConfigs.length <= 1) { + if (freezeEnableds.length <= 1) { // use C2 directly - code += freezeConfigs - .flatMap(({ frame, addr, orig }) => [ + code += freezeEnableds + .flatMap(({ addr, orig }) => [ 0xc2000000 + (addr & 0x1ffffff), 0x00000004, - 0x39600000 | (frame & 0xffff), // li r11, frame - 0x3d80817f, // lis r12, 0x817F - 0x916c00bc, // stw r11, 0xBC(r12) + orig, 0x816d0000 | (r13off & 0xffff), // lwz r11, r13off(r13) + 0x3d80817f, // lis r12, 0x817F 0x816b005c, // lwz r11, 0x5C(r11) 0x916c00b8, // stw r11, 0xB8(r12) - orig, + 0x39600000 | (frame & 0xffff), // li r11, frame + 0x916c00bc, // stw r11, 0xBC(r12) 0x00000000, ]) .map(int32) .join(''); } else { - let dst = freezeCodeAddr + 24; const code04 = []; const code07 = [ - 0x3d80817f, // lis r12, 0x817F - 0x916c00bc, // stw r11, 0xBC(r12) 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) 0x4e800020, // blr ]; + let dst = freezeCodeAddr + code07.length * 4; // put code together - for (const { frame, addr, orig } of freezeConfigs) { + for (const { addr, orig } of freezeEnableds) { code07.push( orig, // [dst] original instruction - 0x39600000 | (frame & 0xffff), // li r11, $frame - 0x4c000000 + (freezeCodeAddr - dst - 8), // b freezeCode + 0x4c000000 + (freezeCodeAddr - dst - 4), // b freezeCode ); code04.push( 0x04000000 | (addr & 0x1ffffff), // 04 addr 0x48000001 | (dst - addr), // bl dst ); - dst += 12; + dst += 8; } // make 07 code code07.unshift( diff --git a/site/.vuepress/components/codes/qft/config.vue b/site/.vuepress/components/codes/qft/config.vue index 675e3f8..1a606af 100644 --- a/site/.vuepress/components/codes/qft/config.vue +++ b/site/.vuepress/components/codes/qft/config.vue @@ -41,15 +41,15 @@

{{l.freeze.h3}}

+
+ {{l.freeze.duration}} {{l.freeze.frame}} + = {{(freezeDuration*1001/30000).toFixed(2)}} {{l.freeze.sec}} +
- - - - - +
{{s}}
{{l.freeze.rows[key]}}{{(freeze[key]*1001/30000).toFixed(2)}}
@@ -63,9 +63,9 @@ import labels from './labels.json'; import {getLabels} from '../codegen.js'; function updateConfig() { - const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze} = this; + const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration} = this; localStorage.setItem(lskey, JSON.stringify({ - x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, + x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration })); } @@ -76,7 +76,7 @@ export default { methods: { updateConfig, onChangeFreeze($event, key) { - this.freeze[key] = parseInt($event.target.value); + this.freeze[key] = $event.target.checked; this.updateConfig(); }, toggleGradient($event) { @@ -93,11 +93,11 @@ export default { rgbaI2S: (rgb, a) => '#'+rgb.toString(16).padStart(6, '0')+a.toString(16).padStart(2, '0'), }, data() { - const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze} = getConfig(); + const {x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, freeze, freezeDuration} = getConfig(); return { x, y, fontSize, width, fgRGB, fgA, fgRGB2, fgA2, bgRGB, bgA, - freeze, + freeze, freezeDuration, // const freezeKeys: Object.keys(codes[this.version]?.freezeCodeInfo ?? {}), }; @@ -118,6 +118,7 @@ export default { fgA2: updateConfig, bgRGB: updateConfig, bgA: updateConfig, + freezeDuration: updateConfig, }, } @@ -126,7 +127,7 @@ export default { input[type=number], td.right { text-align: right; } -.appearance input[type="number"] { +input[type="number"] { width: 3em; margin: 0 2px; } @@ -134,15 +135,6 @@ input[type=number], td.right { padding: 0 0 4px; } -th { - text-align: center; -} -td > input[type=number] { - width: 8em; - max-width: 100%; - box-sizing: border-box; -} - input[type=number] { -moz-appearance: textfield; } diff --git a/site/.vuepress/components/codes/qft/labels.json b/site/.vuepress/components/codes/qft/labels.json index 8751cae..07f7cca 100644 --- a/site/.vuepress/components/codes/qft/labels.json +++ b/site/.vuepress/components/codes/qft/labels.json @@ -13,7 +13,9 @@ "previewNote": "※ x座標の範囲は0~600、y座標の範囲は16~464です\n※ ゲーム内のフォントはプレビューのより幅が広いです", "freeze": { "h3": "一時停止", - "th": ["タイミング", "停止フレーム数", "停止秒数"], + "duration": "長さ:", + "frame": "(フレーム)", + "sec": "(秒)", "rows": { "yellowCoin": "黄コインを取った時", "redCoin": "赤コインを取った時", @@ -40,7 +42,9 @@ "previewNote": "※ x ranges from 0 to 600, and y ranges from 16 to 464.\n※ The font is wider in the game compared to the preview.", "freeze": { "h3": "Freezing the timer", - "th": ["Timing", "Duration(frame)", "Duration(sec)"], + "duration": "Duration: ", + "frame": "(frame)", + "sec": "(sec)", "rows": { "yellowCoin": "When collected a yellow coin", "redCoin": "When collected a red coin",