Skip to main content

Phase 4: ROM Injection & Testing

Goals

Inject the converted Nyjah Houston model into the THPS ROM and validate it works correctly.

Step 1: Backup Original ROM

cp "Tony Hawk's Pro Skater (USA) (Rev 1).z64" "THPS_ORIGINAL_BACKUP.z64"

Always keep an unmodified backup.

Step 2: Inject Model Data

Using the ROM offsets documented in Phase 1, write the new binary data.

Python Injection Script

import struct

def inject_model(rom_path, output_path, model_binary, model_offset,
texture_binary, texture_offset):
"""Inject model and texture data into ROM at documented offsets"""
with open(rom_path, 'rb') as f:
rom = bytearray(f.read())

# Inject model (display lists + vertices)
rom[model_offset:model_offset + len(model_binary)] = model_binary

# Inject textures
rom[texture_offset:texture_offset + len(texture_binary)] = texture_binary

# Write modified ROM
with open(output_path, 'wb') as f:
f.write(rom)

print(f"Injected {len(model_binary)} bytes at offset 0x{model_offset:08X}")
print(f"Injected {len(texture_binary)} bytes at offset 0x{texture_offset:08X}")

return output_path

Step 3: Fix Internal Pointers (if needed)

If the container format has size/offset fields that reference the model data:

def fix_pointers(rom, pointer_offsets, old_size, new_size):
"""Update any size fields in the file table/container headers"""
for offset in pointer_offsets:
# Read current value
current = struct.unpack_from('>I', rom, offset)[0]
# Update if it references the old size
if current == old_size:
struct.pack_into('>I', rom, offset, new_size)
print(f"Fixed pointer at 0x{offset:08X}: {old_size} -> {new_size}")

Step 4: Fix ROM Checksum

After modifying the ROM, CRC values in the header must be recalculated.

Using rn64crc (command line)

# Download from romhacking.net utilities section
./rn64crc "THPS_Nyjah.z64"

Python CRC Fix (if tool not available)

def fix_n64_crc(rom_path):
"""
Recalculate CRC1 and CRC2 for N64 ROM header.
CRCs are at offsets 0x10 (CRC1) and 0x14 (CRC2).
Based on the N64 boot code CRC algorithm.
"""
# Use the n64crc algorithm (complex - use a library or tool)
# For now, emulators like Project64 will boot without correct CRC
# Real hardware (EverDrive) requires correct CRC
pass

Alternative: Use a GUI Tool

  • Tool N64 (Windows) — fixes CRC with one click
  • N64 ROM Checksum Fixer — available on romhacking.net

Step 5: Test in Emulator

Initial Testing (Project64 / Mupen64Plus)

  1. Load the modified ROM
  2. Boot test: Does the game reach the title screen?
  3. Menu test: Can you navigate to character select?
  4. Model test: Does Nyjah's model render correctly?
  5. Animation test: Do all animations play without deformation?

Test Checklist

TestPass/FailNotes
Game boots
Title screen renders
Character select works
Model visible on select screen
Model renders in-game
Idle animation plays
Push animation works
Ollie animation works
Kickflip animation works
Grind animation works
Bail animation works
No texture corruption
No vertex explosion
No crashes during gameplay
All levels load

Common Issues & Fixes

SymptomLikely CauseFix
Invisible modelWrong vertex winding orderFlip normals in Blender
Garbled texturesWrong texture format/offsetVerify CI4/CI8 format matches original
Vertex explosionSize mismatch in vertex buffer loadCheck G_VTX command vertex count
T-pose (no animation)Skeleton mismatchVerify bone count and hierarchy
Crash on loadData overflows allocationReduce model size
Wrong colorsPalette offset incorrectFix palette data alignment
Z-fighting/flickerDuplicate overlapping facesRemove internal faces
Partial model missingDisplay list truncatedCheck gsSPEndDisplayList placement

Step 6: Test on Real Hardware (Optional)

If you have an EverDrive 64 or similar flashcart:

  1. Ensure CRC is fixed (real hardware validates checksums)
  2. Copy ROM to SD card
  3. Test on actual N64 hardware
  4. Check for timing issues (emulators are more forgiving)

Step 7: Iterate

Based on testing results:

  1. Fix any rendering issues in Blender
  2. Re-export display lists
  3. Re-convert to binary
  4. Re-inject into ROM
  5. Re-test

This cycle typically takes 3-5 iterations to get right.

Final Output

n64-mods/
├── Tony Hawk's Pro Skater (USA) (Rev 1).z64 # Original (untouched)
├── THPS_Nyjah_Houston.z64 # Modified ROM
├── blender/
│ └── nyjah_houston.blend # Source model
├── textures/
│ ├── face.png
│ ├── torso_front.png
│ ├── torso_back.png
│ └── ...
├── scripts/
│ ├── convert_display_list.py
│ ├── convert_textures.py
│ ├── inject_model.py
│ └── fix_crc.py
└── docs/
├── rom_offsets.md # Documented offsets
└── skeleton_hierarchy.md # Bone structure

Deliverables

After completing this phase:

  1. Working modified ROM with Nyjah Houston as playable character
  2. All source files (Blender, textures, scripts) for future modifications
  3. Documentation of ROM offsets for reproducibility
  4. Test results confirming all animations work