# Sources and reconstruction notes

## Reference material

- The two screenshots supplied with the request: 640×350 forest and ocean, with
  the original yellow character and 1989 credits.
- [DOS Games Archive: original release](https://www.dosgamesarchive.com/file/cd-man/cdman89)
  and [original shareware archive](https://image.dosgamesarchive.com/games/cdman89.zip).
  Preserved locally as `research/cdman89.zip`.
- [DOSGames.com: CD-Man](https://dosgames.com/game/cd-man): additional screenshot,
  version information, and an emulated copy observed during research.
- [Best Old Games screenshot gallery](https://www.bestoldgames.net/cd-man):
  additional forest/ocean and version references. The gallery mixes releases.
- [Ancient DOS Games video reference](https://www.youtube.com/watch?v=oKn2II_h94o).
- The actual included `research/original/CD-MAN.HLP`: primary documentation for
  collecting dots, temporary power pills, bonus items, gate/key, three rounds per
  world, Escape/Continue, and the original F1 endless-lives feature.

The 1992 Snoofer character and the remaining worlds are outside this remake.
Original art and game © Creative Dimensions, Attila Biro and Anders Moree.
This is a personal reconstruction, not an official release. The newly written
JavaScript is separate from the original copyrighted artwork.

## What was extracted and verified

### Version check, 15 September 2026

Pieter confirmed the target is version 1, the yellow-character release with land,
sea and space worlds. Only its land and sea worlds are included here.
The retained June 1989 executable was compared against the later international
shareware package distributed by Creative Dimensions. That package's README
advertises version 2.0 separately; its `CD-MAN.EXE` is a launcher and its
`CD-MAN.CDM` contains the game. The latter is **byte-for-byte identical** to our
33948-byte original executable, SHA-256
`418fd475902add10b1887881287657f9110b7e8bf685e134f08cc46aaa1fcbbf`.
Both land/sea graphics files are also byte-for-byte identical. This verifies the
sound-table source is from the original version-1 family, not version 2.

Comparison package: [international shareware re-release](https://www.dosgamesarchive.com/file/cd-man/cd-man),
retained under `research/international/`. The current build uses the original
PC-speaker routines; the earliest browser build used invented placeholder effects.
An already-open page keeps its old JavaScript until reloaded. Build identifiers
are now included in diagnostic snapshots to make that distinction explicit.

The EXE is a DOS MZ program with a 512-byte header, initial CS `03ec`, IP `0007`.
Its data segment starts at file offset `0400`. The disassembly is retained in
`research/code.disasm.txt`; `scripts/disassemble.py` recreates it. The original
author's source code, comments, names, and build files were not present.

| Evidence | Finding used in the remake |
| --- | --- |
| EXE file `0c73`, DS `0873` | First 21×13 ASCII grid, including the border. The second begins 273 bytes later. Runtime interior is 19×11. |
| CS `1ef2–1f39`, `1faf–200b` | Floor tile rendering and path adjacency from the ASCII maps; 19 columns, 11 rows, 21-byte row stride. |
| `SCREEN1/2.CDM`, `GRAPHIC1/2.CDM` | RLE literal/run encoding, 112000 decoded image bytes, four 28000-byte bitplanes. Each plane is stored by byte column, then row. |
| DS `03f7`, palette records at `10c6` / `10d7` | Original EGA palette registers. Reverse the four source plane bits to obtain the hardware palette index. |
| CS `2104–224d` | Enemy direction ordering: random permutation below a threshold, otherwise coordinate-based pursuit/flight. Avoid immediate reversal except at a dead end. No modern Pac-Man scatter/ambush mode. |
| DS `0ed9`, actor templates at `0ee3` / `0f3f` | Player start `(9,8)`, enemy home `(9,4)`, the four pill cells, and the entry/exit cells and directions for the paired tunnels. |
| CS `2ad8–2b8c` | Tunnel entry checks and exit state restoration. Forest: `(5,6)` right ↔ `(13,5)` up. Ocean: `(1,1)` up ↔ `(14,10)` down. |
| CS `2843–2906` | Key appears temporarily on a randomly chosen eligible cell. It is not a permanently placed item at the start. |
| CS `294d–2a58`, DS `0593`, `059d` | Key ownership enables gate animation. Approach and departure cells open/close it; occupancy checks keep enemies from being caught in the gate. |
| CS `23d9–2570`, DS `0519–053b` | Source/destination rectangles and strips for fountain, waterfall, river, foam, Pacific net, volcano, and island animation. |
| CS `0425–045b` and original help | Three rounds before changing world. The new ending after world two is intentional. |
| CS `06f5–0737`, `3113` | Eight substeps per tile. Normal enemies take an extra substep every 15 ticks; vulnerable enemies skip every eighth tick. Thus rates are 16/15 and 7/8 of the player's rate. |
| Actor templates DS `0ee3/0f3f` + `002d`; CS `3113–3226`, `355f–360f` | Initial enemy countdowns 70, 120, 150, 210, decremented on enemy movement calls. Movement starts at 23 remaining, down from `(9,4)` through `(9,5)` to `(9,6)`. First eight substeps are revealed below y=178. |
| CS `2571–25fe`; DS `0048–004c` | Shared cage/net door: 32×24 frames from `(0,168)` to `(256,168)`, drawn at `(304,178)`. Opening follows odd release counts in 8..46; closing follows the exit. |
| CS `2725–275b`, `27de–280f`; DS `1053/1059/105f` | Each enemy gets its own 235..362 tick vulnerability. At 50 ticks remaining, switch to the warning sprite strip. At zero, become dangerous. These are states, not separate personality types. |
| CS `3437–355e`, DS `0587` | Captures clear only that enemy's vulnerability and set its return countdown to 100..355 movement calls. Awards are 100, 200, 300, 400; capturing all four ends remaining vulnerability. Score labels last 50 ticks. |
| CS `2843–2906`, DS `003d` | Key first appears after 60 ticks; stays still for 168..231 ticks, then disappears for 30..61 ticks before choosing an eligible floor cell. The previous cell is not excluded. Cleared floor is eligible; walls and live pills are not. Each tick decrements the timer before checking pickup, so expiry wins. Pickup compares the logical destination cell from the first movement substep, including a stationary player on the key. A newly spawned key is not picked up until the next tick. Ownership survives loss of life and stops further appearances for that round. |
| CS `294d–2a58` | Gate advances one of eight opening/closing steps every two ticks. An animation completes before another begins. Pending closure waits for enemy occupancy to clear. |
| CS `2e0d–2e48`, `2f5b–2fc7`, DS `1065` | Eight rendered mouth substeps per tile: alternate 32px regular frames with 40px hand-aligned horizontal frames at y=288, or vertical alternates at y=24. Keep the final eating frame on the arrival tick. Resting sprites are used on cleared paths. |
| CS `355f–3611`, DS `1053–1064` | Enemy horizontal substeps alternate regular 32px sprites with 40px aligned strips at y=288/312, selected by danger/vulnerability/warning state. |
| CS `200c–2052`, `207a–209f`; DS `05ac–064d` | Original single-channel PC-speaker effect sequences. Dot divisors `[0,0,0,0,0,20000,21000,0]`; power, key/bonus, death and capture sequences extracted into `original-data.js`. Frequency = 1193182 / divisor; zero disables the speaker. |
| CS `25ff–2724`, DS `053d–057b` | Bonus appearance, sprite/score tables and lifetimes. First appears after 60 ticks; visible 168..231, absent 336..463, with a 50-tick score display after collection. |
| CS `237a–2570` | Scenery generally advances every two ticks; the Pacific island every six. The volcano uses all 20 frames. |

`scripts/extract_assets.py` reads the original palettes and maps directly. It
does not approximate the scenery by redrawing the screenshots. The HUD labels
were cropped from the user-supplied reference; numeric glyphs come from the
original sheet.

## Fidelity limits and intentional changes

This is a new engine, **not a cycle-exact translation** of every assembly routine.
The maze data, palette, sprites, animation rectangles, and tunnel pairing are
extracted. Enemy direction ordering, speed schedules, release countdowns,
individual vulnerability/warning states, return countdowns, key/gate timing,
bonus tables, and speaker note sequences now follow the recovered routines.
Random bytes still come from JavaScript rather than the original DOS generator.

The original busy-wait loop depended on hardware: 34 base ticks/second is the
remake's chosen calibration, not a recovered universal DOS frame rate. The speed
slider scales that common clock. Collision thresholds, some interactions within
one substep and exact tunnel clipping masks still differ. The hand-aligned sprite
frames are now used; Canvas transparency replaces DOS background-restoration blits.
The 27-step tunnel duration is recovered; Canvas rectangle clipping approximates
the original masks. Death notes use the recovered 100 ms waits, scaled by speed.
PC-speaker sound is synthesized from the original divisors and sequence order,
not sampled from a physical speaker; Web Audio's filtering and the output device
affect its timbre. It is not yet verified frame-for-frame against original play.

The default 50% speed and 20–150% slider are intentional, per the user's request.
Timing is independent of CPU speed. Direct world selection, WASD/touch controls,
fullscreen, browser score persistence, and pause-on-background are additions.
Only forest and Pacific are playable; the original archive is kept as research
material and is never executed or loaded by the shipped browser game.

`tests/key.test.js` exercises the complete visible/hidden intervals, minimum and
maximum durations, same-cell relocation, placement eligibility, stationary and
entering-cell pickup, expiry precedence, pause, ownership and round reset.

## HD artwork provenance — 15 September 2026

Build `reference-hd-2026-09-15` adds an optional presentation layer based on the
two images supplied by Pieter. Unchanged source copies, cleanup candidates and
original-sheet-derived SVGs live in `assets/hd/`. The background uses original
reference pixels outside explicit object removal masks. Logical maps, sound
tables and enemy decisions remain independent of this art. SVG smoothing and
frame blending are visual adaptations, not recovered DOS rendering behavior.
See `research/hd-references/GENERATION.md` and the interactive layer inspector.

## User-requested changes after Reference HD

smooth-bite-2026-09-15 uses hand-authored curves and small cached frame bitmaps
instead of tracing each original pixel. These interpret the original designs.
Power-up contact radii are a deliberate 20/18 logical-pixel ellipse: contact
reveals the ordinary dot, centre arrival scores ten. Pieter also requested
respawning at the exact death position. These are documented behaviour choices,
not claims that the DOS executable used those same constants or respawn rule.

## Fidelity polish

`fidelity-polish-2026-09-15` compares the original spider poses directly with
the revised smooth silhouettes (`tests/sprite-reference.html` and
`tests/polish-visual.html`). Vertical shark fins stay upright; movement direction
changes the wake, not a vertical flip. The first eight forest objects in the
original sheet are cherries, apple, banana, grapes, watermelon, pear, orange and
coconut. The earlier strawberry/plum/pineapple interpretations were incorrect.
Transparent HUD letters and forest gate leaves come from Pieter's reference;
cleanup rectangles extend nine pixels into their surroundings for feathering.
Forest portal paths/clipping and the new celebration are presentation choices,
not recovered original rendering routines. Gameplay is unchanged in this build.


## Original cadence corrections (15 September)

Retained v1 EXE disassembly CS:20e8 reads DS:0190 (player destination cell) before
the shared CS:2104–224d random/directed chase-or-flight routine. DS:022a, 022b,
022c initially contain 200. CS:0494–049b and 04f8–04ff decrement the per-player
threshold by 20 after loss of life; the earlier world/round formula was an
inference and has been removed. This routine supplies no evidence of team
coordination or distinct shark/spider personalities.

CS:2a59–2ad7 selects source row 240 for the 16-pose grin/wink; CS:3328 selects
row 216 for the 16-pose flattening/RIP sequence. `tests/original-poses.html`
enlarges the retained original frames. The HD reconstruction uses the same pose
order; exact original busy-loop wall-clock timing is not established. Smooth HD
curves, painted tunnel clipping and net gathering remain presentation adaptations.
The original eight dot-note divisors now use the same recorded mouth phase,
including the final arrival phase, and Web Audio queues all notes in a slow frame.


Enemy audit follow-up: CS:21af/21c1 use enemy-minus-player subtraction and swap
only when negative. On an exactly aligned axis, secondary pursuit therefore
retains left/up, reversed for flight. `enemy-audit-2026-09-15` fixes the former
JS >= comparison. `tests/enemy-source-order.test.js` independently transcribes
the original register swaps and checks12000 directed-choice cases. The warning
continues state M until CS:274d sets G at expiry; both relative speed and flight
remain active throughout warning. The absolute-speed limitation above remains.


## Widescreen and collection feedback choices

Pieter requested the dot sound only after actual collection, overriding the
previous approach-slot timing. `audio.js` schedules the recovered two audible
divisors on the confirmed dot event, including final-dot collection. This is an
intentional feedback adaptation. Collision checking within each enemy substep
follows CS:3283–32ce; the remake still uses a pixel-space19×14 contact rectangle
rather than the original EGA video-offset intervals. Tests distinguish per-enemy
vulnerability through warning/expiry and verify same-step orb activation wins.
Widescreen artwork provenance is in `research/hd-references/WIDESCREEN.md`.
