141 lines
5.5 KiB
C
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
|