fs2port/port/PORT_STATUS.md
2026-05-14 10:13:07 -05:00

243 lines
12 KiB
Markdown

# FS2 C Port - Status vs Original
Comparison of the original Apple II FS2 (disassembled in `src/chunk*.s`)
against the C port in `port/`. Updated 2026-05-14.
Legend: ok = done; partial = approximation or limited; missing = not implemented
---
## Flight model
| Feature | Original | Port |
|---|---|---|
| Position integrator (24-bit XYZ) | `IntegratePhysicsStep` | ok `aircraftStep` (Q16.16) |
| Pitch / bank / yaw rates | `UpdateAutoTrimAndYaw` etc | ok `stepFlight` |
| Auto-coordination (bank to yaw) | `ApplyAutoCoordination` | ok `stepFlight` |
| Wind / turbulence | chunk2 `ApplyWind` (64K) | ok `windCompute` / `windApply` |
| Stall detection and break | per-instrument check | ok `stalled` flag |
| Spin entry from stall | implicit in stall handling | ok yawRate-driven `spinning` state |
| Spin recovery | opposite rudder + nose-down | ok 30-frame recovery condition |
| High-G / VNE damage | `CheckFlightEnvelope` | ok `loadFactor_q88` + `airframeDamage` accumulator |
| Flap speed drag | `RefreshElevatorIndicator` | ok `forwardSpeed *= (256 - flaps>>3) / 256` |
| Mixture too-lean = engine cut | implicit | partial audio penalty, no full model |
| Carb heat icing | chunk5 `CarbHeat` | partial audio penalty, no icing model |
| Magneto on/off effect on engine | `UpdateEngineWithMagneto` | partial audio penalty |
| Engine fault dispatch | `FailureProcTable` | ok reality-mode dispatch |
| Engine knock audio | per-fault sound | ok `audioUpdate` wobble |
| Crash detection (ground) | `HandleCrashOrSplash` | ok |
| Splash detection (water) | `CheckSplash` | ok via `worldZ` water range |
| Building / mountain crash | `crash_msg_table` | partial type set, no scenery-aware test |
## Modes
| Feature | Original | Port |
|---|---|---|
| Free flight | default | ok |
| Slew mode | `SlewMode` (chunk5) | ok `aircraftToggleSlew` |
| Slew digit overlay | `DrawSlewOverlays` | ok |
| Demo mode | `DemoMode64K` | ok `autopilotDemo` with 4-waypoint sequence |
| Edit mode | `EditModeFlag` | ok F7 toggle, full field editor (`editor.c`) |
| Reality mode | `RealityMode` | ok instrument and engine failures |
| Radar view | `RadarView` | ok `worldRenderRadar` |
| WW1 ace combat | `WW1AceMode` | ok bullets, bombs, AI fire, damage |
| Course Plotter | chunk2 `CoursePlottingMenu` | ok `coursePlotter.c` (record/display) |
| Pause | `TogglePause` | ok P key |
| Title / config screen | boot menu sequence | ok `title.c` (MODE/REGION/DISPLAY/TIME/REALITY/START/QUIT) |
| Boot DOS | `BootDOS` | missing (no DOS to boot) |
## Instruments
| Feature | Original | Port |
|---|---|---|
| Airspeed needle | `UpdateAirspeedIndicator` | ok |
| Altimeter main hand | `UpdateAltimeterIndicator` | ok |
| Altimeter 10K hand | `UpdateAltimeter10K` (64K) | ok |
| Attitude indicator | tilted disc | ok `drawHorizonDisc` |
| Heading bug | `DrawHeading` | ok digit readout |
| Magnetic compass | `DrawMagCompass` | partial digit only |
| Vertical speed | `UpdateVerticalSpeedIndicator` | ok |
| Turn coordinator | `UpdateTurnCoordinator` | ok |
| Slip/skid ball | `PLSlipSkidIndicator` | ok reads `sideslip_q88` |
| Throttle position | `UpdateThrottleIndicator` | ok bar indicator |
| Mixture position | `UpdateMixtureControlIndicator` | ok bar indicator |
| Flap position | `UpdateFlapsIndicator` | ok bar indicator |
| Trim position | implicit in auto-trim | ok HOME/END keys + indicator |
| Fuel tank L/R | `UpdateFuelTankGauges` | ok per-frame burn, alternating tanks |
| Oil temp/pressure | `UpdateOilTempAndPressureGauges` | missing |
| RPM display | `DrawRPM` | ok digit |
| Magneto state visual | `DrawMagnetoState` | ok MAG OFF/L/R/START indicator |
| Carb heat state | switch position | ok "C.H." / "HEAT" indicator |
| Lights state | switch position | ok "1" / "O" indicator |
| Failure indicator (X over gauge) | `DrawX` per gauge | ok `drawFailX` |
| Stall / VNE warning | `STALL` / `VNE` text | ok |
| VOR2 / ADF gauge mode-gating | chunk4 ADFMode flag | ok `ac->adfMode` switches needle/digits |
## Radios / Navigation
| Feature | Original | Port |
|---|---|---|
| NAV1 frequency | `NAV1` ($08F7) | ok `radios.c` |
| NAV2 frequency | `NAV2` ($08F5) | ok |
| ADF frequency | `ADFFreq*` | ok |
| COM1 frequency | `str_com1` | ok |
| Station database (deduped) | per-region | ok 695 entries from extractstations |
| BCD frequency increment | step keys | ok shift+digit / digit |
| BCD per-digit entry | `KeyDecreasePatch` | ok Ctrl+1..4 arms input, digit keys append |
| OBS course knob | OBS-related | ok `,` `.` keys |
| VOR CDI needle | `DrawVOR1IndicatorChanges` | ok |
| VOR TO/FROM flag | `msg_vor_flags` | ok "TO" / "FR" / "OFF" |
| ILS glide slope | not in original | missing |
| DME readout | `DrawATISMessage` ATIS bound | ok |
| ADF needle | `DrawADFPanel` | ok gated on `ac->adfMode` |
| ADF heading digits | `DrawADFHeadingDigits` | ok |
| ATIS chunked text | `UpdateCOMMessageChunks` | ok 8-char scrolling window |
| Tune-to-nearest button | not in original | ok T key (port-only) |
## Scenery system
| Feature | Original | Port |
|---|---|---|
| Disk loader (`SceneryReadUntilC0`) | chunk3 `SceneryLoaderEntry1` | ok RAM dump + .SD demand-load (default-on) |
| Block-list indirection | chunk4 `ComputeBlockFromSector` | ok `doHeader` correct mapping |
| Nibble decode | `SceneryNibbleDecode` | missing (only used by Entry4 path) |
| HEADER opcode ($0D) | `SceneryOpHeader` + `LA63A` | ok `doHeader` with cache, default-on demand-load |
| L631D section base | `L631D` | ok `sceneryComputeBaseL631D` |
| EnterLocalFrame ($07) | `SceneryOpEnterLocalFrame` | partial simplified passthrough |
| Vertex emit + transform ($00-$02, $40-$42) | `SceneryOpEmitV*` | ok |
| Cull ($20/$21/$22) | `SceneryOpCullIfOutside*` | ok `doCullN` |
| Cull by outcode list ($04) | `SceneryOpCullByOutcodeList` | partial walks list, no actual cull |
| Jump-if-beyond-XY/XYZ ($13/$14) | `SceneryOpJumpIfBeyondXY*` | ok |
| REL_JUMP ($0B) | `SceneryOpJumpRelative` | ok |
| SUB_INVOKE ($18) / RETURN ($19) | `SceneryOpSubInvoke` | ok |
| RESET_STATE ($2F) | `SceneryOpResetState` | ok |
| MODE_WHITE ($1B) | line-kernel patch | ok semantic equivalent |
| DAY_ONLY ($1C) | line-kernel patch | ok skip-on-night flag |
| WriteWord ($1A) / StoreImmWord ($25) | self-mod patches | ok |
| Curve emit ($2B) | `SceneryOpEmitCurve` | ok via 6502 interpreter on MAME-patched RAM |
| Vertex-cache ops ($31/$32/$33/$35/$42) | cached vertex pool at $0140 | ok pool reads |
| ADF/NAV/COM record ($05/$1D/$1E) | station records | ok |
| SET_COLOR ($12) | `SceneryOpSetColor` | ok |
| Polygon edge emit | `EmitClippedLine` | partial line draw only, no polygon close |
| Polygon scanline fill | `DrawColorSpan` etc | partial 2D scanline edge-intercept; not chunk5's 3D-clipped emitter (FS2 boot Meigs is line-only) |
| Polygon 4-pass 3D clipper | `PolygonScanFillSetup` | ok `sceneryClipPolygon3D` (Sutherland-Hodgman against Z-X / Z-Y / X+Z / Y+Z) |
| Sky/ground tilted fill | `FlipPagesFillViewport` | ok `rendererFillTiltedSkyGround` |
| Frustum line clip (5-plane) | `ClipBothVerticesToFrustum` | ok full-frustum clipper, plane-snap via `chunk5ScaleC2ByC4`; 36/36 pixel-exact vs MAME |
| Vertex pool / EmitPrimaryVertex | $0AB8 column array | partial small pool, no polygon closure |
## Display
| Feature | Original | Port |
|---|---|---|
| 280x192 framebuffer | hires page 1/2 | ok |
| Page flip | `FlipPagesFillViewport` | partial single buffer |
| Color/B&W mode | `ColorModePatch` / `BWModePatch` | partial always color |
| Dotted-pattern night | `SceneryOpDayOnly` etc | ok DAY_ONLY skip |
| Panel bitmap | hires loaded from disk | ok `res/loading_panel.bin` |
| Panel lights overlay (64K) | `UpdateInstrumentLights` | partial state shown as text |
| Message text (`DrawMultiMessage`) | string blit | ok `font.c` + `fontDrawStringCentered` |
| Crash message overlay | `crash_msg_table` | ok MOUNTAIN / BUILDING / SPLASH / CRASH |
| Wing/tail overlays in side views | `DrawWingsOrTailOverlays` | ok `rendererDrawWingOverlay` (right/left strut, back fin, down well) |
| Bomb sight | WW1 bombsight pixels | ok `ww1aceHudDraw` |
| Gunsight | WW1 only | ok `ww1aceHudDraw` |
| NTSC fringing (HIRES decode) | true HIRES pair-merge | partial palette buffer by default; `SCENERY_NTSC=1` reverts to HIRES decode |
## Audio
| Feature | Original | Port |
|---|---|---|
| Engine sound | speaker click | ok sawtooth + throttle modulation |
| Engine fault wobble | not present in original | ok phase-modulated wobble |
| Magneto-off engine cut | engine flag | ok amp = 0 when MAG OFF |
| Stall horn | beeper trill | ok 800 Hz square wave |
| Crash impact | speaker noise | ok noise burst |
| Gun fire (WW1) | not in original | ok rapid sawtooth burst |
| Bomb drop (WW1) | not in original | ok pitch sweep |
| Wind hiss | not in original | ok speed-scaled noise (LCG-driven) |
## Input
| Feature | Original | Port |
|---|---|---|
| Yoke (arrows / WASD) | arrow + paddle | ok |
| Rudder | `/` and Ctrl | ok Q/E |
| Throttle | `[` `]` Ctrl+H | ok Up/PgUp/Dn/PgDn |
| Brake | space | ok space cuts throttle |
| Slew controls | 8/9, 0/-, ,/. , +/= | partial W/A/S/D in slew mode |
| View directions (F1-F5) | 1-5 keys | ok F1-F5 |
| Magneto select | 1-3 keys | ok Shift+M cycles |
| Lights toggle | L key | ok L |
| Carb heat | H key | ok H |
| Pause | Ctrl-P | ok P |
| Edit mode | Ctrl+[ | ok F7 (full field editor) |
| Demo mode | Ctrl+D | ok F10 |
| Slew toggle | Ctrl+S | ok F12 |
| Reality mode | Ctrl+R | ok Tab |
| Radar view | F | ok ` (backquote) |
| Course plotter menu | Ctrl+C | ok C/V/B/N (record/precision/display/off) |
| BCD digit entry arm | KeyDecreasePatch | ok Ctrl+1..4 (NAV1/NAV2/COM1/ADF) |
| Joystick | game port | ok SDL_Joystick (button 0 = gun, 1 = bomb, 2 = view, 3 = radar, 4 = throttle cut) |
## Persisted state
| Feature | Original | Port |
|---|---|---|
| Edit-mode instrument save buffer | $FC00+ | ok `editSavedState` snapshot on toggle |
| Crash recovery snapshot | yes | ok `aircraftArmRecovery` / `aircraftRestoreRecovery` (Space when crashed) |
---
## Multi-region scenery
The FS2.1 base disk's four region variants (Chicago / LA / Seattle / NY)
all share the same `FS2.1` .SD file as their demand-load source.
`port/include/sceneryData.h` exposes the per-region enums; the
`sceneryDataRegionFromName()` table lookup maps `SCENERY_REGION` env var
strings (e.g. "FS2.1_chicago", "SD3", "SDS1") back to enum values for the
`--screenshot` path.
| Region | Source | Default start |
|---|---|---|
| `SCENERY_FS2_1` | `FS2.1` | WW1 ace training field |
| `SCENERY_FS2_1_CHICAGO` | `FS2.1` | KCGX / Meigs Field `(96, 268)` |
| `SCENERY_FS2_1_LA` | `FS2.1` | KLAX `(200, 0)` |
| `SCENERY_FS2_1_SEATTLE` | `FS2.1` | KSEA `(970, 0)` |
| `SCENERY_FS2_1_NY` | `FS2.1` | KJFK `(400, 0)` |
| `SCENERY_SD1..SDS1` | `A2.SD<n>` | per-disk default |
`SCENERY_DEMAND_TRACE=1` logs every fired demand-load. Boot Meigs fires
sid $44 (6 sub-blocks @ $A887) and sid $4E (1 sub-block @ $BA3D).
## Still missing
- **Polygon scanline fill** for non-boot scenes (FS2 boot Meigs is
line-only so this is mostly cosmetic until other regions surface
real polygons).
- **Stuck-key magneto auto-alternation** - chunk5
`MagnetosLeft/Right` handle key-held edge cases.
- **Day-side detailed runway striping** - chunk5 has runway-specific
colour-only details we don't replicate.
- **Oil temp/pressure gauges** - chunk5
`UpdateOilTempAndPressureGauges`.
- **Section anchor / $07 EnterLocalFrame** for real bytecode in
unsurfaced sections. The simplified passthrough is correct for boot
Meigs but full multi-section navigation may need anchor-coord reads
from each section's preamble.
- **ILS glide slope** - FS2 doesn't have it either, but port could add it.
## Recent code-cleanup pass (2026-05-14)
- Dead code removed: `ww1aceDropBomb()` (legacy stub), `Coord16T` /
`VertexT` (unused), `DEG2RAD` (unused macro), `rendererSwapFillColors()`
(uncalled).
- Shared helpers consolidated:
- `camera.h`: `metresFromQ1616`, `q1616FromMetres`, `byteAngleToDegrees`
- `font.h`: `fontDrawStringCentered`
- `fs2math.h`: `fs2ClampInt`, `fs2StepClamp`
- `sceneryDataRegionFromName()` replaces the 19-branch SCENERY_REGION
strcmp chain in main.c.
- `AC_MAX_FORWARD_SPEED_Q88` promoted to `aircraft.h` (audio.c was
redefining the same literal).
- Recovery flag tracked via `ac->hasRecoverySnapshot` only (removed the
`recoveryValid` file-static second-source-of-truth).
- Net change: 16104 -> 16018 lines.