// FS2 wind system port (chunk2 `ComputeWindComponents` and `ApplyWind`). // // FS2 splits the sky into four altitude bands; each band carries a // 4-byte record `[magnitude, turbByte, reserved, directionByteAngle]`. // `windCompute` (called every other frame in the original) selects the // active band, resolves the record into a signed 16-bit (X, Z) wind // vector, and caches `WindLayerByte1` for the turbulence kick. // `windApply` (called every frame) returns the per-frame world-position // delta and updates the bank-accumulator + turbulence-kick state that // downstream FS2 routines consume. // // Default state is all zeros, matching the FS2 ROM image's // uninitialised wind tables; that yields no wind until layers are // configured. #ifndef WIND_H #define WIND_H #include #include typedef struct WindLayerT { int8_t magnitude; // record byte 0 (signed) uint8_t turbByte; // record byte 1 (bit 0 enables turbulence) uint8_t reserved; // record byte 2 (ignored by `resolve`) uint8_t direction; // record byte 3 (byte angle) } WindLayerT; typedef struct WindStateT { // Configuration: altitude thresholds (FS2 cells `WindAlt1/2/3`) // and the four layer records. Ordering: surface < layer1 < // layer2 < layer3 by altitude. uint16_t altThreshold1; uint16_t altThreshold2; uint16_t altThreshold3; WindLayerT surface; WindLayerT layer1; WindLayerT layer2; WindLayerT layer3; // Auxiliary FS2 state cells. uint8_t yokeOffset1; // $0847 (added to direction always) uint8_t yokeOffset2; // $0849 (added on the surface band) uint8_t scaleByteLo; // $09DE (turbulence scale low) uint8_t scaleByteHi; // $09DF (turbulence scale hi + L180C scale) uint8_t updateCounter; // mirrors FS2 `UpdateCounter` // Computed by windCompute. int16_t componentX; // $09A2/$09A3 (signed 16-bit wind X) int16_t componentZ; // $09A4/$09A5 (signed 16-bit wind Z) uint8_t layerByte1; // `WindLayerByte1` cache uint8_t surfaceFlag; // $09A6 (1 when the surface band was picked) // Computed by windApply. int16_t bankAccum; // $09AF/$09B0 (downstream bank derivation) int16_t turbKick; // $08A1/$08A2 (turbulence kick output) } WindStateT; void windInit(WindStateT *w); // Pick the active layer based on `altitude16` and resolve its (X, Z) // components. Direct port of `ComputeWindComponents` (chunk2 L483). // The original is called every other frame; we leave the cadence to // the caller. void windCompute(WindStateT *w, uint16_t altitude16); // Per-frame wind step. Direct port of `ApplyWind` (chunk2 L397). On // the ground, returns zero delta. Off the ground, advances the // bank-accumulator and turbulence-kick state and returns the // world-position delta for this frame in (deltaX, deltaZ) as a Q16.16 // world-unit value (matching the FS2 32-bit position cell convention // and aircraft.h's `AC_POS_FRACT_BITS`). void windApply(WindStateT *w, bool onGround, int32_t *deltaX_q1616, int32_t *deltaZ_q1616); #endif