Giants: Citizen Kabuto demo
Planet Moon's 2001 action game (Interplay), the "Reaper" demo. Direct3D 7.
Registered as giants_demo.
Payload and licence
test/candidate-corpus/manifest.json, id giants-demo: archive.org
giantsreaperdemoinstall/giantsreaperdemoinstall.exe (105.8 MB, SHA-1
9647ca57...). The outer exe is a CAB 7z opens (Disk1\); inside is an
**InstallShield 6** set (data1.hdr, data1.cab, data2.cab, ikernel.ex_).
IS6 setups need their out-of-process engine, so the installer is not run;
the fetcher unpacks it with unshield, one file group at a time, into the
layout the game expects:
| File group | Installed to |
|---|---|
| Main Files (exe, gg_dx7r.dll, gs_ds.dll, Eaxman.dll, license, readme) | \ |
Game Files Bin, WAbx, GData, GZP (.gzp archives, GameObj.bin) |
Bin\ |
| Stream Files, Music Files | Stream\ |
257 files, 123 MB. The game probes Bin\Override\*.*, Bin\*.gzp, Bin\*.*,
StreamEnglish\*.* and Stream\*.* at start; with everything in one flat
directory (what tools/is-cab.js --extract writes) it stops with
"Failed to open GameObj.bin".
Licence: license.txt -- personal noncommercial home use; no decompiling,
reverse engineering or disassembly; no copying or distribution. localOnly;
API traces only.
DXErr 887600FF (fixed)
The first run ended at the game's own "Game Error Screen" with
DXErr 887600FF (DDERR_NOTFOUND). The game creates its Z-buffer
(DDSCAPS_ZBUFFER), attaches it to the back buffer with AddAttachedSurface,
and later asks the render target (IDirect3DDevice7::GetRenderTarget) for
GetAttachedSurface(DDSCAPS_ZBUFFER). Our GetAttachedSurface only looked at
the flip-chain link (misc0), while AddAttachedSurface records the
relationship on the child (DX_SURF_META +4). It now also scans the explicit
children by caps ($dx_surface_explicit_child);
test/test-directdraw-get-attached-explicit.js. Found with
--trace-api-mem=IDirectDraw_CreateSurface:1:124,IDirectDrawSurface_GetAttachedSurface:1:16.
Route (CLI, --batch-size=100000, --headless-gl)
Mount the tree at C:\ (--exe-guest-path=C:\GiantsReaperDemo.exe --cwd=C:\).
| Batch | Action | Screen |
|---|---|---|
| ~500 | "Select Player ID", 3D island and logo | |
| 1000 | click (320,437) "Enter New ID" | "Enter New Player ID" |
| 1100 | keypress W, 6 (WM_CHAR; keydown letters are ignored) |
name "W6" |
| 1140 | Enter | main menu (Start New Single Player Game ...) |
| 1300 | mousedown/up IN PLACE (no move) | loading "Delphi's Story 1: Yan, the Samurai Smartie" |
| ~2400 | intro cutscene with subtitles | |
| ~2900 | Mission Objectives over the HUD |
The menu cursor is the game's own, driven by DirectInput deltas. It moves
1:1 with the deltas (GetDeviceState, a 20-byte mouse state, every frame),
but the game puts it on "Start New Single Player Game" by itself when the menu
opens, while the host pointer is still where the last click was (320,437).
So any absolute move aimed at the item's screen position is applied as a
delta from the wrong origin and pins the cursor at the edge; clicking without
moving selects the highlighted item. Not an emulator bug -- a real mouse
user only ever moves relative to the cursor they see. On a phone this is
why the layout uses trackpad (relative) touch.
| 2950 | mousedown/up | dismisses Mission Objectives: gameplay |
Rendering: the flat green world (fixed)
The green was fog colour (FOGCOLOR 0x2D654E, matched to the pixel),
not a texture. The renderer is D3D7 vertex buffers: ProcessVertices from
untransformed sources into XYZRHW buffers, then DrawIndexedPrimitiveVB.
Per-object FVFs, from --trace-dx (PVtx records): models 0x112
(XYZ|NORMAL|TEX1) -> 0x1C4, sprites/foliage 0x142 -> 0x144, and the
terrain 0x42 (XYZ|DIFFUSE, no texture coordinates) -> 0x144. Fog is
FOGENABLE with FOGVERTEXMODE LINEAR, FOGTABLEMODE NONE, start 0, end
1536 (later 6000).
- Buildings and statues (0x112): the pipeline wrote specular alpha 0 = 100%
fog. Fixed in ba9eac483 (
$d3dim_vertex_fog_alpha). - Terrain, cliffs, player: stage 0 is
TEXCOORDINDEX= 0x20000 (TCI_CAMERASPACEPOSITION) withTEXTURETRANSFORMFLAGS= COUNT2 and a planarSetTransform(TEXTURE0)before every terrainProcessVertices(Xform Set 16in--trace-dx). Nothing generated the coordinates, and TEXTURE0 went to matrix slot 3 -- the composite worldviewprojection scratch. Fixed by generating stage-0 coordinates in$d3dim_prepare_draw_vertex($d3dim_texgen) and storing TEXTURE0..7 and TTFF in a per-device block ($d3dim_tex_block);test/test-d3dim-texgen-camera-position.js.
Still open after the fix: the ground and the far cliffs render very dark (ground texels 0x010100..0x080E00, cliff silhouettes 0x000000). Uniform texture is present, so the next suspects are the terrain's multi-pass blend (stage 0 alternates SELECTARG1 / MODULATE textures with ALPHAOP MODULATE) and the reflection-vector texgen mode (TCI 3), which is not generated yet. Untested in the browser.
Evidence: scratch/runs/20261011T1840Z-giants-demo-w6,
scratch/runs/20261011T1950Z-giants-di-cursor-w6 (m1-p0..p3 measure the
cursor; m2/m3 the route into the mission),
scratch/runs/20261011T2040Z-giants-untextured-w6 (fog: gl3100 before,
fix-g3100 after ba9eac483), scratch/runs/20261012T0000Z-giants-texgen-w6
(texgen: texgen-g3100/g3200).