Native game flow, rendering and simulation
This is the first code-level map of TFX 2.05. Links open the relevant routine in the native disassembly browser. Names describe observed responsibilities; original source symbols have not been recovered. File offsets identify the September 1994 executable, as explained in executable-format.md.
From presentation to flight
The game flow is driven by saved parser graphs. The nine decoded .par resources contain 41 functions and 1,173 statements. Menus, campaign variables, conditions, briefings, scenes and gameplay launches inhabit the same graph. The presentation browser plays contiguous visual groups; programs.json retains all other statements and their raw settings.
The graph executor dispatches statement types while servicing input and presentation/audio work. A type-5 statement reaches the launch bridge, which builds and tokenises its argument string, then calls launch_game. That routine parses options, sets up resources and mission state, starts the selected music path, calls the flight session, then stops music and tears the session down. It returns to the graph rather than owning all campaign progression itself.
flowchart TD
A[Saved presentation graph] --> B[Menus, variables and conditions]
B --> C[Briefing and presentation scenes]
C --> D[Type 5: launch game]
D --> E[Mission and resource setup]
E --> F[Flight session loop]
F --> G[Result and session cleanup]
G --> B
The executable also retains authoring, diagnostic and utility paths. Their presence in the call graph is not evidence that all of them are reached during ordinary campaign play.
The in-flight configuration menu persists preferences in TFX.CFG; its seven-value REALISM record and HUD intensity keys are mapped in configuration and graphics settings.
The flight session loop
The session loop begins at file 0x72018; its repeated body runs from approximately 0x72045 to 0x723df. The loop continues while data-object word 0x593a is zero. It services audio, player/control work, other actors, collision responses, projectiles, camera preparation, terrain and moving-object drawing, HUD work and frame presentation.
The elapsed-step word at data offset 0x13476 is shared by these subsystems. The projectile wrapper at 0x71fd4 explicitly divides a longer elapsed interval into chunks of at most 10 before running the update and collision passes. Scenery animation has a separate accumulated-step flag. The launcher's fast timer supplies approximately 54.6204 ticks/s; the animation gate subtracts 7 timer ticks per eligible update, giving a nominal 7.8029 actor animation ticks/s. It permits only one such update per displayed frame, so low frame rates can slow animation. Native timing notes and captures explain the timer, authored holds and the distinct rendering cadence of procedural vertex jitter. These are derived rates from isolated native handlers; full-mission timing still needs a traced run.
One important indirect call is the player update. 0x7d550 installs 0x8f56c in data-object slot 0x12bcc, and the control path invokes it at file 0x8697e. Keeping this assignment/call relationship matters: following direct calls alone misses much of the flight model.
The active projectiles similarly carry update callbacks. The recovered weapon-stage tables now identify their normal timed callback sequences and have been verified through the native selector. Actor-dependent contacts, responses and event-driven changes still need live tracing.
Player flight dynamics
The player model uses x87 floating point, including 64-bit fields. It maintains floating positions and other flight state, then converts results for the fixed-point rendering and entity systems. The geometry engine's integer matrices do not imply that the aerodynamics are integer-only.
A mission's plane command chooses:
| Script value | Player craft | Internal index | Flight preset initialiser |
|---|---|---|---|
| 1 | Eurofighter | 0 | 0x98234 |
| 2 | F-117 | 1 | 0x97598 |
| 3 | F-22 | 2 | 0x96918 |
The plane command handler selects the efa, f_117a and f_22 names from the native table, then subtracts one for the internal index. Flight-state initialisation dispatches to the corresponding preset. Each preset writes a substantial set of different coefficients and initial values; these are genuine numerical differences, rather than cockpit/model changes alone.
The three initialisers have been executed in an isolated, relocated LE image. A CSV comparison and exact-byte capture expose 95 floating-field locations written by one or more presets. Blank CSV cells mean that a field was not completely written by that isolated initialiser, not that its native value is necessarily zero. Values are deliberately labelled by data offset until their physical meanings and units are established.
The player updater branches on landed/airborne and special state, and on the flight-control mode. Its paths include 0x8dc50, 0x8e280, 0x8e5a8 and 0x9feb4. More detailed calculation passes at 0x9fe14 and 0x9fe50 call several distinct numerical stages. Those entry points are mapped; assigning every stage a lift, drag, torque or engine label requires more work than counting floating-point operations.
The pose handoff at 0x75114 copies converted XYZ values, angle words and shifted speed into the moving-entity representation. This gives a concrete boundary for subsequent renderer and simulation analysis.
Other aircraft and entities
The previously unnamed resource with identifier a32646b8 resolves to WAYBIN/CRAFTYPE.CFG, using the explicit filename at the native loader. The entity browser exposes all 47 authored profiles.
The loader stores two header words, then scans variable-sized records. The record-size helper masks the type byte with 0x7f and returns 74, 58, 46 or 34 bytes for kinds 14–17. The supplied configuration has 29 kind-14 aircraft records and 18 kind-16 surface/entity records, followed by a 34-byte zero terminator. Its second header word is 47 and agrees with the parsed record count.
Every record begins with a type byte, a 20-byte display-name field, a 10-byte model/definition name, one flag byte and a 16-bit numeric ID at offset 0x20. The ID lookup confirms that last field. Remaining numeric operands are preserved in the browser by byte offset; their units and flag meanings are not yet fully identified.
The profiles include repeated aircraft models with names ending in e, a and n, two refuellers, Hercules variants, SAM sites, fleets, convoys and individual ships. The naming suffixes alone are insufficient to prove a difficulty mapping. These spawned-entity settings are separate from the player's more extensive flight-preset initialisers.
Projectiles, damage and collision
The projectile update pass walks a linked list, copies current XYZ into previous-position fields, then calls the projectile's update callback. A second pass tests trajectories against scenery, using both endpoints through the collision routine at 0xb752c. It then applies projectile-specific responses and effects. This is evidence for a swept path test, rather than only asking whether the projectile's new endpoint happens to be inside a target.
Player collision/damage handling queries scenery, invokes SSD event handlers and updates landing, damaged/dead and mission-exit state. SSDs supply their own conditional damage and collision programs. The assembled-definition browser retains those programs and exposes their rectangular tests.
This first pass does not establish a complete weapon damage or target-health chart. The projectile callback, collision response, SSD damage entry and mission permission rules must be joined before deriving hit counts. The presence of a collision box by itself is not proof that a target is destructible by every weapon.
Renderer
The session prepares camera state through 0x73cd0, renders the terrain neighbourhood through 0xb0ba8, and draws moving objects through 0x7cf34. The world lookup uses 2,048 units per terrain cell and the stored grid index X * 200 + (199 - Z).
Models are executable drawing programs. Loading converts big-endian disk words into handler offsets and 32-byte vertex-slot offsets. Vertex transformation/projection, facing tests, authored ordering, flat/shaded polygons, textures, sized point effects and bound external models are separate native paths. Rotated components use a 1,024-sample sine table and a fixed-point matrix generator.
The renderer contains self-modifying code and placeholder operands that are filled during setup. A naïve linear disassembly or an uninitialised call into those paths can therefore mislead. The viewers currently reproduce geometry, native component matrices and validated branch predicates, and now resolve native atlas bindings and affine UV sampling. Recovered Gouraud attributes, nine special raster modes and native HUD/MFD captures are now available. Live scene lighting, embedded 3D MFD camera views and complete clipped integer rasterisation remain separate runtime work. See textures and cockpits for the new captures and viewer scope.
Palette transitions are also code-driven. 0x72b24 interpolates 224 RGB triples, uses a divisor of 50 and masks each DAC component to six bits. This demonstrates that an environment's palette file alone does not describe every colour seen in flight.
See model-format.md, terrain-and-scenery.md and media-and-presentations.md for the corresponding data formats and native comparison checks.
Mission rules
The catalogue now recognises 201 mission scripts, including scripts preceded by extensive authoring comments and retained examples. They are not 201 independently confirmed playable campaign missions. The text includes INIT, FINISH and END sections, initial conditions and expressions involving targets, scores, plane counts and parser variables.
The archived missions/planes.mis is especially useful: its authoring comments explicitly list alive(targ#N), dead(targ#N), eplanes_down, fplanes_down, personal/enemy/friendly air scores, completion conditions and setpar operations. Its worked example asks for four enemy kills and returns a result based on that count. This is direct evidence for the script language, without reconstructing all of its rules from briefing text.
The mission browser overlays decoded starts, target cells, flak regions and textual waypoint routes. The parser graphs then consume mission results and campaign variables to choose subsequent scenes and branches. Executing those expressions, compiled waypoint commands and all campaign transitions is the next stage; current map overlays do not simulate them.
Recovered executable and resource relationships
The compiled-program investigation now connects the native actor dispatcher and air waypoint VM to all 192 programs, including initial aircraft groups, ground attackers and player routes. Eighteen CBN files supply timed AI inputs. These data are distinct from the player flight coefficients and SSD part-animation streams.
Environment captures recover palette banks and distance fields through the original parser. HUD captures execute original readout layout with declared synthetic inputs and expose the embedded font and 29 viewport records. Presentation research now includes native font pixels, discrete DAC fade steps and separate BIOS/retrace timing fields.
Audio dispatch is also corrected: 0xb4000/0xb40c8 play/stop CD audio, while 0xa5d68/0xa5b64 select/start resident synthesised resources. Native checks and scene associations verify the distinction; the CD opening graphics still explicitly request synthesised intro music.
Verified campaign flow and store physics
The campaign viewer now follows the retail and PC Plus parser branches, gosub returns, numeric assignments and decoded menu choices. Native branch and assignment checks cover every recovered record. Node 8 runs an options menu; node 9 invokes the waypoint planner. Flight results remain explicit external inputs to the inspection runner.
The weapon viewer extracts all 27 weapon records and 92 timed projectile stages. Native checks cover every stage selector entry and 29 carried-store loadouts. Weapons and dynamics identifies mass, drag, load-dependent moments, fuel capacity and the projectile's current/previous position fields. Full guidance and damage outcomes still require joining the callbacks to live actors and SSD events.