243 lines
12 KiB
Markdown
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.
|