fs2port/port/include/ww1ace.h
2026-05-13 21:32:05 -05:00

141 lines
5.5 KiB
C

// FS2 "World War 1 Ace" combat mode (chunk3 / chunk4 / chunk5).
//
// FS2 spawns six enemy aircraft, each with a status code:
// 0 = shot down, 1 = returning / home, 2 = attacking.
// The player's score (`WW1AceScore`) and bomb count (`WW1AceBombsStr`)
// drive the panel HUD overlay; the "War Report" screen (chunk3 L2455)
// summarises the campaign so far.
//
// This port keeps the same six-enemy slot table and status semantics,
// adds minimal AI (attacking enemies drift toward the player, returning
// enemies head home), and renders each enemy as a small line sprite in
// the world view. Hit detection / damage tracking are stubbed pending
// the full chunk5 fire-control routines.
#ifndef WW1ACE_H
#define WW1ACE_H
#include <stdbool.h>
#include <stdint.h>
#include "camera.h"
#include "framebuffer.h"
#include "renderer.h"
#define WW1_ENEMY_COUNT 6
#define WW1_BULLET_COUNT 12 // pool: 6 enemy + 6 player rounds
#define WW1_BOMB_COUNT 4 // pool of bombs in flight
typedef enum WW1EnemyStatusE {
WW1_ENEMY_SHOT_DOWN = 0,
WW1_ENEMY_RETURNING = 1,
WW1_ENEMY_ATTACKING = 2
} WW1EnemyStatusE;
typedef struct WW1EnemyT {
WW1EnemyStatusE status;
int32_t worldX; // Q16.16, matches AircraftT/CameraT
int32_t worldY;
int32_t worldZ;
// Q8.8 velocity components in metres/frame. Drives the
// maneuvering AI: enemies bank, climb, and turn rather than
// sliding straight toward the player.
int16_t velX;
int16_t velY;
int16_t velZ;
uint8_t heading; // byte angle
uint8_t maneuverPhase; // 0..255, drives sinusoidal jink
uint8_t fireCooldown; // frames until next shot at player
} WW1EnemyT;
typedef struct WW1BulletT {
bool active;
bool fromEnemy; // true = enemy round, false = player
int32_t worldX; // Q16.16
int32_t worldY;
int32_t worldZ;
int16_t velX; // Q8.8 metres / frame
int16_t velY;
int16_t velZ;
uint8_t framesLeft; // self-expiry counter
} WW1BulletT;
typedef struct WW1BombT {
bool active;
int32_t worldX; // Q16.16
int32_t worldY; // descending under gravity
int32_t worldZ;
int16_t velX; // Q8.8 metres / frame (inherited from player)
int16_t velY; // negative (falling), accelerates
int16_t velZ;
} WW1BombT;
typedef struct WW1AceStateT {
bool enabled;
bool showWarReport;
uint16_t score; // mirrors `WW1AceScore` (16-bit)
uint8_t bombs; // mirrors `WW1AceBombsStr` countdown
uint16_t damageByEnemy; // mirrors $08A4
uint16_t bombHits; // mirrors $A81B
uint8_t playerFireCooldown; // throttles repeat gun fire to a burst rate
WW1EnemyT enemies[WW1_ENEMY_COUNT];
WW1BulletT bullets[WW1_BULLET_COUNT];
WW1BombT bombsInFlight[WW1_BOMB_COUNT];
// Internal: next bomb impact frame, RNG seed for AI jitter.
uint16_t rngState;
} WW1AceStateT;
void ww1aceInit(WW1AceStateT *s);
// Toggle WW1 Ace mode. Spawns / despawns enemies and resets the
// score/bomb counters. Player coords are Q16.16 world-units.
void ww1aceToggle(WW1AceStateT *s, int32_t playerX, int32_t playerZ);
// Legacy bomb-drop entry that just decrements the bomb count. Prefer
// `ww1aceDropBombAt` so the bomb is added to the in-flight pool with
// the player's actual position + velocity.
void ww1aceDropBomb(WW1AceStateT *s);
// Drop a bomb at the player's current world position with the player's
// horizontal velocity (Q8.8 metres/frame). The bomb then falls under
// gravity in `ww1aceUpdate` and tries to score a hit on a ground
// enemy at impact.
void ww1aceDropBombAt(WW1AceStateT *s, int32_t playerX, int32_t playerY, int32_t playerZ,
int16_t playerVelX_q88, int16_t playerVelZ_q88);
// Fire the machine gun at any enemy in front. The closest attacking
// enemy within `aimConeDeg` of the nose gets shot down. Player coords
// are Q16.16 world-units.
void ww1aceFireGun(WW1AceStateT *s, int32_t playerX, int32_t playerY, int32_t playerZ, uint8_t playerYaw);
// Per-frame AI + projectile update. Attacking enemies maneuver toward
// the player and fire bursts when aimed; returning enemies head home;
// shot-down enemies stay down. Bullets and bombs in flight advance,
// expire, and check hits. Player damage accumulates via
// `damageByEnemy`; when it hits AC_FAIL_BY_DAMAGE the caller can
// trigger a player crash. Returns true if a player-fatal hit occurred
// this frame.
bool ww1aceUpdate(WW1AceStateT *s, int32_t playerX, int32_t playerY, int32_t playerZ, uint8_t playerYaw);
// Render bullets and bombs in flight as small dots through the camera
// projection. Called alongside ww1aceRender.
void ww1aceRenderProjectiles(const WW1AceStateT *s, const CameraT *cam, RenderStateT *renderer);
// Render the enemies into the 3D viewport using the supplied camera.
void ww1aceRender(const WW1AceStateT *s, const CameraT *cam, RenderStateT *renderer);
// Draw the score / bomb overlay near the top of the panel.
void ww1aceHudDraw(const WW1AceStateT *s, FramebufferT *fb);
// Draw the full "War Report" screen. Caller is responsible for
// freezing the simulation while the screen is shown.
void ww1aceDrawWarReport(const WW1AceStateT *s, FramebufferT *fb);
#endif