5.8 KiB
HMagic Reference Documentation
Consolidated: 2025-12-08 Purpose: Reference notes and regression checklist for porting HMagic data to yaze
Overview
HMagic is a legacy ALTTP ROM editor. This document consolidates extraction notes and regression testing requirements to ensure yaze parsers/editors avoid known HMagic bugs while reusing valuable data knowledge.
Part 1: Extraction Notes
Goal: reuse hmagic's data knowledge (not its unsafe plumbing) to improve yaze parsers/editors.
Offsets and Structures to Port
structs.hcontainsoffsets_tywithdungeon_offsets_ty,overworld_offsets_ty,text_offsets_ty/text_codes_ty.z3ed.c::LoadOffsets(currently US-only, hardcoded): torches (0x2736a), torch_count (0x88c1); text dictionary/regions (bank=0x0e, dictionary=0x74703..0x748D9, param_counts=0x7536b, region1=0xe0000..0xe8000, region2=0x75f40..0x77400, codes bounds).- Action: lift into a region table (US/EU/JP) with file-size validation before use.
- Status: US offsets added at
src/zelda3/formats/offsets.{h,cc}with basic bounds validation; EU/JP remain TODO.
Text Decode/Encode Logic (TextLogic.c)
- Decoder: walks monologue stream until
abs_terminator; handlesregion_switch, zchars< zchar_bound, dictionary entries (dict_base..),msg_terminator, and commands with params viaparam_countstable. Appends toZTextMessagebuffers. - Encoder: rebuilds messages, searches dictionary for matches (linear search), writes params per
param_counts, respectsmax_message_length. - Bugs/risks: heavy global reliance on
offsets, no ROM bounds checks, dictionary search inline and naive. Port by reimplementing with span/bounds checks and unit tests.
Tile/Palette Rendering Math
Files: DungeonLogic.c, TileMapLogic.c, GraphicsLogic.c
- Helpers like
fill4x2,drawXx3/4, bitplane copies - Data: tile stride = 64 words per row in buffer; SNES bitplane packing assumed
- Bugs:
draw3x2doesn't advance pointers; many helpers assume globals (dm_rd,dm_wr,dm_buf,dm_l) - If reusing math, reimplement with explicit buffer sizes and tests
Data Tables/Enums Worth Reusing
sprname.dat(sprite names) - standard format parsed and ported tosrc/zelda3/sprite/sprite_names.h(284 entries, length-prefixed, limit 15 chars)- Enum headers:
DungeonEnum.h,OverworldEnum.h,HMagicEnum.h,TextEnum.h,SampleEnum.h, etc. - UI labels (entrance names, dungeon names) via
HM_TextResource entrance_names
Known Bugs/Behavior to Test Against
From z3ed.c header:
- Overworld: editing items/exits/whirlpools can corrupt pointers; "remove all exits" nukes ending white dots and Ganon->Triforce entrance; global grid editing inserts entrances/crashes
- Dungeon: pointer calc fails with too much data (space issues)
- BG1/BG2: sprite handling fixed in later epochs; still verify
- Monologue: storage corruption fixed once; still regression-test text save/load
Part 2: Regression Checklist
Goal: ensure yaze parsers/editors don't reproduce known hmagic bugs.
Test Scenarios
1. Overworld Exits/Items/Whirlpools Pointer Integrity
- Edit exits/whirlpools/items, save, reload ROM
- Verify ending white dots (credits) and Ganon->Triforce entrance remain intact
- Validate pointer tables (no mass repoint to empty room)
2. "Remove All Overworld Exits" Safety
- Invoke bulk-delete; ensure credits dots and special entrances remain
- Verify no unintended entrance insertion/crash when editing global grid
3. Dungeon Room Pointer Overflow
- Add room data until near limit
- Ensure pointer calc stays valid and refuses to corrupt or overrun
- Should emit error instead of silent corruption
4. BG1/BG2 Sprite Handling
- Move BG2 markers (red dots) and confirm BG flag persists across save/reload
5. Monologue Storage
- Round-trip text: decode -> modify -> encode
- Ensure no bank overflow, region switch honored, abs terminator respected
- Dictionary bounds enforced
6. Sprite Names
- Decode
sprname.datstandard format (flag=0, LE size, 0x11c length-prefixed entries) - Ensure names load
- If alt format (flag!=0) appears, validate 256x9-byte table
Implementation Plan
Add gtest cases using a US ROM fixture (vanilla.sfc):
- Text: round-trip known messages and synthetic long messages; check max length enforcement
- Sprite names: decode standard/alt format blobs; compare to reference array
- Pointer safety: build synthetic overworld/dungeon tables and assert parsers reject OOB offsets
Add CLI fixtures for bulk operations (remove exits/items) and assert postconditions via serializers.
Porting Approach for yaze
-
Add a
formats/zelda3_offsets.{h,cc}with a region table (US/EU/JP) + validation (file size, bounds on dictionary/regions/param tables). Expose typed structs matching hmagic but without globals. -
Text: implement a safe decoder/encoder following hmagic's logic, with tests using a known US ROM fixture; include dictionary search as a reusable function. Add CLI or unit tests to compare round-trip.
-
Tile/metatile: reimplement only the packing math you need; avoid copying
dm_*globals. Add tests with sample tile data to verify blits. -
Data tables: convert
sprname.datand enums into constexpr arrays/enum classes; include provenance comments. -
Regression checklist: create a test list based on the "Remaining things Puzzledude claims are borked" to ensure yaze doesn't repeat those bugs.
References to Harvest
structs.hfor offsets structsz3ed.c::LoadOffsetsfor US constantsTextLogic.cfor monologue decode/encode flowDungeonLogic.c/TileMapLogic.c/GraphicsLogic.cfor tile/bitplane math (reimplement safely)sprname.datfor sprite names- Header comments in
z3ed.cfor bug/regression notes