Skip to content

feat(banim): Extract battle animation assets from baserom into source files#735

Open
laqieer wants to merge 40 commits intoFireEmblemUniverse:masterfrom
laqieer:banim-assets-source
Open

feat(banim): Extract battle animation assets from baserom into source files#735
laqieer wants to merge 40 commits intoFireEmblemUniverse:masterfrom
laqieer:banim-assets-source

Conversation

@laqieer
Copy link
Copy Markdown
Contributor

@laqieer laqieer commented Mar 1, 2026

Summary

This PR extracts battle animation (banim) graphical assets from raw baserom.gba .incbin directives in data/data_banim.s into individual, trackable source files. It also decompiles two animation script binaries into human-readable assembly source using animscr.inc macros.

Motivation

The original data/data_banim.s contained hundreds of .incbin "baserom.gba", offset, size directives that embedded raw ROM data directly. This made the graphical assets opaque, untrackable, and impossible to modify without hex editing the base ROM.

Changes

Asset Extraction (~1500 files)

  • 651 PNG source images (graphics/banim/assets/img/) — 4bpp tile graphics converted to editable PNGs
  • 120 palette files (graphics/banim/assets/pal/) — .pal (text) and .agbpal (binary, for edge-case high-bit palettes)
  • 617 TSA tilemap files (graphics/banim/assets/tsa/) — binary tile arrangement data preserved as-is (see rationale below)

Animation Script Decompilation

  • Decompiled 007219FC_AnimScr_NaglfarBG4.bin and 00723208_AnimScr_DarkBreath_Far.bin into data/banim/animscr_naglfarbg4_darkbreath.s
  • Translated raw hex into standard animscr.inc macros (anim_sprite, ANIMSCR_FORCE_SPRITE, animscr_loop, etc.)
  • Combined into a single .s file because DarkBreath_Far references OAM arrays stored inside the NaglfarBG4 binary block
  • Replaced .incbin directives with .include in data/data_banim.s
  • Deleted the original .bin files

Build System Integration

  • graphics/banim/assets/img/banim_img_rules.mk — auto-generated Makefile rules for PNG → 4bpp conversion with correct width constraints
  • graphics/banim/assets/pal/banim_pal_rules.mk — palette conversion rules (.pal.gbapal)
  • Makefile — includes the new .mk rule files and adds pattern rules for .tsa.tsa.lz compression

Build Artifact Cleanup

  • Removed .lz intermediate files that were accidentally committed (they are auto-generated by the Makefile %.lz: % rule and already covered by .gitignore)

Documentation

  • docs/banim_asset_extraction.md — extraction workflow, conversion rules, and edge cases
  • docs/Banim_TSA_Preservation_Report.md — rationale for keeping TSA files as binary (multi-frame shared tilesets prevent lossless PNG round-tripping)
  • docs/Banim_AnimScr_Decompilation_Report.md — animation script decompilation process and arm_compressing_linker.py pipeline analysis

Utility Scripts

  • scripts/generate_anim_script.py — disassembles animation script binaries into labeled .s files using animscr.inc macros

Design Decisions

Why TSA files remain binary

Multiple animation frames share a single large tileset (.4bpp), but each frame has its own .tsa mapping into that tileset. Converting a TSA+tileset to PNG and back through tsa_generator.py discards the shared tile indices and reorders them, breaking byte-for-byte reproduction. This is consistent with how pokeemerald handles its tilemaps (raw .bin files). See docs/Banim_TSA_Preservation_Report.md for the full investigation.

Why AnimScr files use .include instead of arm_compressing_linker.py

The Naglfar/DarkBreath animation scripts were not LZ-compressed in the original ROM (included via plain .incbin without .lz suffix). The arm_compressing_linker.py pipeline is only needed for assets requiring LZ compression. Direct .include lets the standard GNU assembler resolve label relocations natively via R_ARM_ABS32.

Build Verification

  • make clean && make fireemblem8.gba completes successfully
  • sha1sum -c checksum.sha1 confirms byte-for-byte match with the original ROM

Internal Review Notes

During development, the following review feedback from the human developer (@laqieer) was addressed:

  • Documentation language: All docs translated to English for international reviewers
  • Intermediate artifacts: Removed accidentally committed .tsa.lz and .4bpp.lz build products
  • Preview PNGs: Removed 799 .tsa.png preview files (4MB) that served no build purpose
  • Temporary scripts: Cleaned up intermediate script versions (generate_animscr_s_v2.py, v3.py)
  • Documentation consolidation: Merged redundant AnimScr_Disassembly_Report.md into the decompilation report
  • Workflow preference: Documentation and exploration findings are now committed alongside code changes

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25

Agent: OpenClaw Assistant | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: OpenClaw Assistant | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: OpenClaw Assistant | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: OpenClaw Assistant | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: banim-scribe | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: banim-scribe | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: banim-migrator | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
Agent: banim-migrator | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
… Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
…odel: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
… Nightfall | Model: github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
…github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
…ub-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
… github-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
…ub-copilot/gpt-5.1-codex | OpenClaw: 2026.2.25
…github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.26
…tes to actual 4bpp image data\n- Split 006792A4_Pal_086792A4 into palette and TSA components\n- Rebuilt and verified with checksum\n\nAgent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.26
Records the exploration, batch testing, and root-cause analysis revealing that Banim TSAs rely on multi-to-one shared image tilesets, making them incompatible with the current 1-to-1 png tsa_generator toolchain. Concludes that these binaries must be preserved.

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
These PNGs are strictly for visual reference and preview purposes.
As documented in Banim_TSA_Preservation_Report.md, the original .tsa
and .4bpp files are non-regeneratable due to multi-frame shared tileset
architecture, so these PNGs are NOT used in the build process.

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
Added a section detailing the investigation into the pret/pokeemerald
repository. It confirms that retaining raw binary tilemaps (.bin/TSA)
is the standard practice in GBA decompilations, as their gbagfx tool
also lacks the ability to generate tilemaps from PNGs (only decoding
is supported).

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
Reverse-engineered the two animscr binary files into labeled assembly
source. Key findings:

- NaglfarBG4.bin (6156 bytes) contains interleaved data: 26 OAM sprite
  arrays for NaglfarBG4, an AnimScr script, then 26 more OAM sprite
  arrays for DarkBreath_Far. DarkBreath_Far.bin (108 bytes) is just
  the DarkBreath script referencing OAM data inside NaglfarBG4.

- OAM entries use both ANIM_SPRITE and ANIM_SPRITE_AFFIN formats
  (12 bytes each, distinguished by oam1 == 0xFFFF).

- All OAM data verified byte-for-byte identical. Script sections
  require arm_compressing_linker.py for final label resolution.

- Created 52 new AnimSprite labels (AnimSpr_NaglfarOBJ_0..24,
  AnimSpr_DarkBreathOBJ_0..25) for previously unlabeled OAM arrays.

- Full exploration documented in docs/AnimScr_Disassembly_Report.md.

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
- Deleted 007219FC_AnimScr_NaglfarBG4.bin and 00723208_AnimScr_DarkBreath_Far.bin
- Replaced their .incbin references in data_banim.s with an .include of the decompiled animscr_naglfarbg4_darkbreath.s
- Verified byte-for-byte identical build (sha1sum OK)

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
laqieer added 10 commits March 1, 2026 11:52
Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
Removed the following files as they are generated dynamically during build:
- graphics/banim/assets/img/006671B0_Img_EfxMagdhisEffectBG_LayerB.4bpp.lz
- graphics/banim/assets/tsa/005DDAF4_Tsa_085DDAF4.tsa.lz
- graphics/banim/assets/tsa/00603F00_Tsa_EfxElfireBG_Clear.tsa.lz

Verified standard 'make' regenerates them natively and sha1sum passes.

Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
Deleted banim_asset_process_log.md as it contained Feishu chat logs not relevant to the PR.
Translated banim_asset_extraction.md to English.

Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
Agent: Rennac | Model: github-copilot/gemini-3.1-pro-preview | OpenClaw: 2026.2.25
- Removed 799 .tsa.png preview files (4MB, not needed for build)
- Removed redundant AnimScr_Disassembly_Report.md (content consolidated
  in Banim_AnimScr_Decompilation_Report.md)

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
Resolved conflicts in data_banim.s by keeping the extracted asset paths.
This ensures the branch stays in sync with upstream changes while maintaining
the extracted banim assets.

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
…merge

The upstream master reverted a previous banim sourcing PR, which deleted
banim_img_rules.mk (with -num_tiles rules), update_banim_img_rules.py,
and the reports directory. Without banim_img_rules.mk, the generic
%.4bpp: %.png rule produces incorrect tile counts, causing sha1 mismatch.

Build verified: sha1sum OK (c25b145e37456171ada4b0d440bf88a19f4d509f)

Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25
@laqieer
Copy link
Copy Markdown
Contributor Author

laqieer commented Mar 1, 2026

Build Verification Log

Branch: banim-assets-source (commit 5a1c626)
Build: make clean && make fireemblem8.gba -j$(nproc)
Result: ✅ SUCCESS

SHA1 Verification

c25b145e37456171ada4b0d440bf88a19f4d509f  fireemblem8.gba: OK

Build Summary

  • Full clean build completed successfully (12,334 lines of build output)
  • All banim assets compiled from extracted source files (.4bpp, .tsa, .agbpal)
  • PNG→4bpp conversion uses correct -num_tiles parameters via banim_img_rules.mk
  • LZ compression applied to .4bpp.lz and .tsa.lz intermediates
  • Final ROM binary matches expected checksum byte-for-byte
Last 20 lines of build log (sanitized)
arm-none-eabi-ld -T ldscript.txt -Map fireemblem8.map @objects.lst -R data/banim/data_banim.o.sym.o -L tools/agbcc/lib -o fireemblem8.elf -lc -lgcc
arm-none-eabi-strip -N .gcc2_compiled. fireemblem8.elf
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_gameending lma 0x2000000 adjusted to 0x201f19c
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_bmstart lma 0x2000000 adjusted to 0x20219d4
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_gamestartsave lma 0x2000000 adjusted to 0x20231d4
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_sio lma 0x2000000 adjusted to 0x20331d4
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_worldmap lma 0x2000000 adjusted to 0x203435c
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_gamestart lma 0x2000000 adjusted to 0x20331d4
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_sio lma 0x20331d4 adjusted to 0x2052cfc
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_worldmap lma 0x203435c adjusted to 0x2053e84
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_banim lma 0x2000000 adjusted to 0x2052cfc
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_sio lma 0x2052cfc adjusted to 0x2072e84
arm-none-eabi-strip: stEX0UjE: section ewram_overlay_worldmap lma 0x2053e84 adjusted to 0x207400c
arm-none-eabi-strip: stEX0UjE: section ewram_data lma 0x2000000 adjusted to 0x20905e0
arm-none-eabi-objcopy --strip-debug -O binary --pad-to 0x9000000 --gap-fill=0xff fireemblem8.elf fireemblem8.gba

=== SHA1 Verification ===
c25b145e37456171ada4b0d440bf88a19f4d509f  fireemblem8.gba
Expected: c25b145e37456171ada4b0d440bf88a19f4d509f  fireemblem8.gba
Result: OK

Full sanitized build log (12,334 lines) available on request.


Agent: Rennac | Model: github-copilot/claude-opus-4.6 | OpenClaw: 2026.2.25

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant