← Research

Reversing a Dead Legend: Inside StarCraft Ghost's NOD Engine - PART 1

I wanted to know how StarCraft: Ghost had been built. Not how to finish it, port it, or replace its engine. Just how the thing worked.

The leaked development build offered an unusual starting point: alongside the Xbox prototype was a PC debug executable, Star_d.exe. It did not run correctly out of the box, but its disassembly and decompiled pseudo-code made parts of the engine’s organization visible.

That was enough to keep me coming back for about two years.


The Game Behind the Binary

Ghost was announced in September 2002 as a third-person stealth-action game featuring Nova, a Terran ghost operative. Its original developer, Nihilistic Software, brought forward the NOD engine used in Vampire: The Masquerade - Redemption.

Nihilistic’s work ended in 2004, and development moved to Swingin’ Ape Studios. Blizzard later acquired that studio. The game was indefinitely postponed in 2006 and eventually acknowledged as cancelled.

The build that surfaced in 2020 belongs to the Nihilistic period. It is not a record of everything the later team did. The surviving Xbox prototype and PC executable give us a view of one stage of development, not the final state of the project.

The production history is covered elsewhere, notably in Polygon’s retrospective. My interest here is narrower: what can be learned by reading this particular implementation?


Two Years, in Spare Time

Those two years were not a full-time reverse-engineering job. There was no schedule, milestone plan, or clear destination. I studied the disassembly and pseudo-code in my free time, out of curiosity.

I started over numerous times. Each attempt made some part of the layout easier to recognize, but it was easy to lose direction when every call led into another unfamiliar system.

Eventually I had enough of restarting. I continued in smaller steps instead: map the basic layout, follow the entry point, identify the main loop, and reconstruct the first few layers around it.

That work became Starev. The name describes a reconstruction effort, not a recovered copy of Nihilistic’s source code.

There was a personal reason for choosing Ghost. In 2004, its E3 trailer persuaded me to start saving for a PS2. Some of my early graphics experiments tried to recreate its environments. Years later, I finally had a chance to inspect the real implementation.


What the Debug Build Gave Me

The useful material was not just executable instructions. Function names, diagnostic strings, source paths, and recognizable library calls helped put those instructions into context.

A source path can suggest which module owns a routine. A startup call can reveal a dependency. Repeated references to the same object can help identify who coordinates its lifetime.

Pseudo-code makes these relationships easier to read, but it is still a decompiler’s interpretation. Types, ownership, and control flow need checking against the disassembly. Turning that output into readable C++ is not the same as recovering the original code.

The PC executable was particularly helpful for identifying Win32 entry points and the Direct3D 8 path. Those details describe the PC side of the build; they should not be mistaken for the Xbox platform implementation.


Finding the Outline

Rather than understand every function, I needed a map that told me where to look next.

The broad outline was:

Platform entry and window handling
  -> Application sequence and state
      -> Input, timing, and other foundation services
      -> Rendering and resource interfaces
      -> Menu and UI
      -> Game, simulation, and mission-system boundaries

The important discovery was the role of tSequence. It gave me a place to follow startup and the calls made during a frame. From there, the lower-level services and higher-level game systems stopped looking like unrelated groups of functions.

This was a map of responsibilities, not proof that the whole engine had been reconstructed.


What I Actually Reconstructed

The practical result was a basic engine architecture skeleton: the entry path, main-loop organization, and the first two or three layers of calls around them.

Foundation code and the interfaces between modules gave that skeleton structure. Other files existed to record a boundary or a declaration while their implementation remained incomplete.

I did not deeply reconstruct physics, AI, the game library, or mission scripting. I followed those systems along the surface where the main flow called into them. Knowing where an AI update is dispatched is different from understanding how its behavior works internally.

That distinction matters when reading the rest of the series. Starev was a way to organize and preserve what I understood. It was not a functioning replacement engine or a finished PC version of Ghost.


What Reuse Does, and Does Not, Tell Us

NOD’s earlier use in an RPG explains some of its history. It does not establish that its architecture was unsuitable for an action game.

Rendering, file access, resource lookup, and timing can serve many kinds of games. Player movement and mission behavior are much more specific. The interesting question is where those responsibilities meet, and which assumptions have to change when the game changes.

My surface-level reconstruction was not enough to measure the cost of that adaptation. An inherited filename or an old interface is a trace of history, not evidence that engine reuse caused Ghost’s cancellation.

For someone interested in a genre-agnostic engine, this work offers an example to inspect, not a design recipe. The useful distinction is between shared services and game-specific behavior, rather than between an “RPG engine” and an “action engine.”


The Next Step

Once I had an outline, the next question was how to turn it into a coherent reconstruction without pretending to understand everything below it.

Part 2 follows that work through Starev: the application boundary, staged startup, main-loop dispatch, and the subsystem interfaces left to reconstruct.

Part 3 takes a smaller, testable piece of the problem: reading the custom asset formats in a viewer.

These are accounts of an investigation, not step-by-step tutorials.


References