# Zapper Mario - patching instructions

`ZapperMario.ips` turns the unmodified *Super Mario Bros. + Duck Hunt (USA)* ROM into
the *Zapper Mario* ROM (controller 1 drives both players; the Zapper in port 2 shoots
enemies during Super Mario Bros., each hit counting as a fireball hit and each shot
costing a coin; Duck Hunt gains
Game D "3 Ducks", Game E "Random" and a dog that can be shot while he laughs; the
multicart menu can be operated with the Zapper). The original ROM is not included; you
must supply your own copy. (The project README carries the same instructions.)

## 1. Check that you have the right original ROM

The patch only works on this exact file (iNES header included, 81,936 bytes):

| | |
|---|---|
| File | `Super Mario Bros. + Duck Hunt (USA).nes` |
| Size | 81,936 bytes (16-byte iNES header + 64 KB PRG + 16 KB CHR, mapper 66) |
| **MD5** | `1306a0286248a0851005464d7ec8d785` |
| SHA-1 | `663ddef71cc808c5382a3426ef6d03b5499a51c8` |
| CRC32 | `666ee28e` |

Verify before patching, for example:

```
md5sum "Super Mario Bros. + Duck Hunt (USA).nes"        # Linux / macOS
certutil -hashfile "Super Mario Bros. + Duck Hunt (USA).nes" MD5   # Windows
```

If the MD5 differs (different dump, headerless ROM, trained or overdumped copy), do
not apply the patch; the result will not work.

## 2. Apply the patch

Use any IPS patcher:

* **Floating IPS / Lunar IPS (Windows)**: open the patcher, choose `ZapperMario.ips`,
  then choose the original ROM. Keep a copy of the original: Lunar IPS patches in place.
* **Online**: an IPS web patcher (for example "ROM Patcher JS") run in the browser,
  select the ROM and the IPS file, download the result.
* **Included script (any OS with Python 3, no other tools):**

  ```
  python3 tools/ips.py apply "Super Mario Bros. + Duck Hunt (USA).nes" patch/ZapperMario.ips "Super Mario Bros. + Duck Hunt (Zapper Mario).nes"
  ```

## 3. Check the result

| | |
|---|---|
| Patched ROM size | 98,320 bytes (header + 64 KB PRG + 32 KB CHR) |
| Patched ROM **MD5** | `055e4b5461be8e9a5b5c7ac50f4da70b` |
| Patched ROM SHA-1 | `646419c775d60729b35a1e0ff49b2d3997a4100c` |
| Patch file MD5 | `00d2373da03411e73f12e174f399cdac` (21,272 bytes) |

The patched ROM is 16 KB larger than the original: the CHR ROM grows from two to four
8 KB banks (header byte 5 changes from 2 to 4) because the hurt-dog face needed a free
sprite tile. Every IPS patcher handles this (the patch writes the whole appended area),
but the result must be exactly 98,320 bytes. Play it with the Zapper plugged into
controller port 2 (CRT television, or an emulator with Zapper support such as Mesen,
FCEUX or Nestopia; the Zapper does not work on LCD screens).

## What the patch changes (for the curious)

47 records, about 21,000 bytes in total (file offsets include the 16-byte header):

| File offsets | CPU address | Bytes | Purpose |
|---|---|---|---|
| `0x002EFA`, `0x0072DA`, `0x00800A` | bank 0 `$AEEA`, `$F2CA`, `$FFFA` | 10 | SMB: `ldx CurrentPlayer` -> `ldx #0`; NMI stub `lda #$10 / sta $800D` in an unused hole; NMI vector -> `$F2CA` |
| `0x00A190`-`0x00A851` | bank 1 `$A180`-`$A841` | 1,730 | Zapper code for SMB (bank-0 return sequences in front of an RTI/RTS, shot logic, coin cost) |
| `0x00A870`-`0x00B690` | bank 1 `$A860`-`$B680` | 3,617 | Duck Hunt extension code and data (`src/duckhunt.asm`): Game D / Game E flight logic, third duck object, shootable dog, three-duck catch pose, random scenes, new title and scene streams |
| `0x008072` | bank 1 `$8062` | 2 | menu: the controller read becomes a call that also reads the Zapper (off-screen shot = Select, on-screen shot = Start) |
| 34 places in `0x00C064`-`0x00D4F1` | bank 1 `$C054`-`$D4E1` | 161 | Hooks into the menu and Duck Hunt code (five-game title, top-score table at `$05D0`, flight init, "all ducks done" test, shot entry, dog state table, catch animation, sprite set table, CHR bank select), each a `jsr`/`jmp` into the new code with `nop` padding; the original bytes are verified before patching |
| `0x00F2DF` | bank 1 `$F2CF` | 3 | `jmp` to the Zapper code (continuation of the NMI stub) |
| `0x000005` | header | 1 | CHR size 2 -> 4 banks |
| `0x014010`-`0x01800F` | CHR banks 2 and 3 | 16,384 | Duck Hunt tiles with the hurt-dog eye tile at `$EB` and flat-shaded dog body tiles at `$EC`-`$F1` and the duckless paw and arm at `$F2`-`$F3` (bank 2) and a copy (bank 3) |

Bank 0 is Super Mario Bros., bank 1 holds the menu and Duck Hunt; the new code sits in
areas that were unused (`$FF`) in the original. The patch was generated and round-trip
verified with `tools/ips.py`; the sources are `src/zapper.asm` and `src/duckhunt.asm`,
rebuilt with `python3 build.py`.
