/**
 * game_types.h - bit Generations: Orbital (GBA) - Decompiled Type Definitions
 *
 * Reverse-engineered struct layouts and function prototypes.
 * Fixed-point format: Q4.12 (shifted left by 12) unless noted otherwise.
 *
 * Key constants:
 *   0xf0 = 240 = SCREEN_WIDTH
 *   0xa0 = 160 = SCREEN_HEIGHT
 *   0x1000 = 1.0 in Q12 fixed-point
 *   0x78000 = 120.0 pixels (screen center X)
 *   0x50000 = 80.0 pixels (screen center Y)
 */

#ifndef GAME_TYPES_H
#define GAME_TYPES_H

#include <stdint.h>
#include <stddef.h>

/* GBA ARM target: 4-byte natural alignment */
#if defined(__GNUC__)
  #define PACKED __attribute__((packed))
  #define ALIGNED(n) __attribute__((aligned(n)))
#else
  #define PACKED
  #define ALIGNED(n)
#endif

/* ========================================================================
 *  Primitive Types (matching Ghidra decompilation conventions)
 * ======================================================================== */

typedef int8_t     s8;
typedef uint8_t    u8;
typedef int16_t    s16;
typedef uint16_t   u16;
typedef int32_t    s32;
typedef uint32_t   u32;
typedef int64_t    s64;
typedef uint64_t   u64;

/* ========================================================================
 *  GBA Display Constants
 * ======================================================================== */

#define SCREEN_WIDTH        240     /* 0xf0 pixels */
#define SCREEN_HEIGHT       160     /* 0xa0 pixels */
#define GBA_TILE_SIZE       8       /* 8x8 pixels per tile */
#define GBA_OAM_COUNT       128     /* max hardware sprites */
#define GBA_BG_MAP_WIDTH    32      /* tiles per BG map row */
#define GBA_BG_MAP_HEIGHT   32      /* tiles per BG map column */

/* ========================================================================
 *  Fixed-Point Q12 Helpers
 *
 *   0x1000 = 1.0
 *   0x78000 = 120.0 (screen center X)
 *   0x50000 = 80.0  (screen center Y)
 * ======================================================================== */

#define FP_SHIFT            12
#define FP_ONE              (1 << FP_SHIFT)              /* 0x1000 = 1.0 */
#define FP_FROM_INT(n)      ((s32)(n) << FP_SHIFT)       /* int -> Q12    */
#define FP_TO_INT(n)        ((n) >> FP_SHIFT)            /* Q12 -> int    */
#define FP_MUL(a, b)        ((s32)(((s64)(a) * (b)) >> FP_SHIFT))
#define FP_DIV(a, b)        ((s32)(((s64)(a) << FP_SHIFT) / (b)))

#define INIT_POS_X          0x78000  /* 120.0 pixels in Q12 */
#define INIT_POS_Y          0x50000  /* 80.0 pixels in Q12  */

/* ========================================================================
 *  OAM Attribute Masks
 * ======================================================================== */

#define OAM_ATTR0_Y_MASK     0x00FF
#define OAM_ATTR0_MODE_MASK  0x0C00
#define OAM_ATTR0_SHAPE_MASK 0xC000
#define OAM_ATTR1_X_MASK     0x01FF
#define OAM_ATTR1_HFLIP      0x1000
#define OAM_ATTR1_VFLIP      0x2000
#define OAM_ATTR1_SIZE_MASK  0xC000
#define OAM_ATTR2_TILE_MASK  0x03FF
#define OAM_ATTR2_PAL_MASK   0xF000

/* ========================================================================
 *  GBA Video Modes
 * ======================================================================== */

#define GBA_VIDEO_MODE_0     0
#define GBA_VIDEO_MODE_1     1
#define GBA_VIDEO_MODE_2     2

/* ========================================================================
 *  Input Register Bits (KEYINPUT at 0x04000130, active-low)
 * ======================================================================== */

#define KEY_A        0x0001
#define KEY_B        0x0002
#define KEY_SELECT   0x0004
#define KEY_START    0x0008
#define KEY_RIGHT    0x0010
#define KEY_LEFT     0x0020
#define KEY_UP       0x0040
#define KEY_DOWN     0x0080
#define KEY_R        0x0100
#define KEY_L        0x0200

/* ========================================================================
 *  Animation Constants
 * ======================================================================== */

#define ENTITY_COUNT            32      /* 0x20: entity pool size */
#define ENTITY_SIZE             0x104   /* 260 bytes per entity */
#define ENTITY_POOL_OFFSET      0x204   /* byte offset in GameState */
#define PAL_ANIM_SLOT_COUNT     5       /* palette animation slots */
#define PAL_ANIM_SLOT_SIZE      0x20    /* 32 bytes per palette slot */
#define LEVEL_PARAM_COUNT       12      /* difficulty levels per type */
#define ANIM_TABLE_STRIDE       0x30    /* 48 bytes per type (4B * 12) */
#define ANIM_TABLE_STRIDE2      0x60    /* 96 bytes per type (8B * 12) */
#define LEVEL_DATA_STRIDE       0x2c    /* 44 bytes per level entry */
#define CAMERA_SIZE             0x64    /* 100 bytes */
#define PLAYER_STRUCT_SIZE      0x100   /* estimated */
#define RENDER_CTRL_SIZE        0x110   /* estimated */

/* ========================================================================
 *  Camera / Viewport Object  (100 bytes = 0x64)
 *
 *  Initialized by GameState_Init, updated by Object_UpdateScreenPosition.
 *  Manages the screen view into the world, tracks the player planet's
 *  position and wraps it around world boundaries.
 *
 *  Accessed as s32[] in decompiled code (word-indexed offsets).
 *  Lives at GameState + 0x1a0.
 * ======================================================================== */

typedef struct Camera {
    /* 0x00 */ s32 x;                /* position X (Q12 fixed point) */
    /* 0x04 */ s32 y;                /* position Y (Q12 fixed point) */
    /* 0x08 */ s32 prev_x;           /* previous frame X position */
    /* 0x0c */ s32 prev_y;           /* previous frame Y position */
    /* 0x10 */ s32 world_width;      /* world boundary width (pixels) */
    /* 0x14 */ s32 world_height;     /* world boundary height (pixels) */

    /* Attached object (satellite) velocity accumulators.
     * These accumulate frame-to-frame motion deltas so that satellites
     * orbit or trail the player planet with inertia. */
    /* 0x18 */ s32 sat0_dx;          /* satellite 0: accumulated X offset */
    /* 0x1c */ s32 sat0_dy;          /* satellite 0: accumulated Y offset */
    /* 0x20 */ s32 sat1_dx;          /* satellite 1: accumulated X offset */
    /* 0x24 */ s32 sat1_dy;          /* satellite 1: accumulated Y offset */

    /* Attached object (satellite) screen positions in Q12 fixed point.
     * Written to OAM each frame by camera_update(). */
    /* 0x28 */ s32 sat0_x;           /* satellite 0: world position X */
    /* 0x2c */ s32 sat0_y;           /* satellite 0: world position Y */
    /* 0x30 */ s32 sat1_x;           /* satellite 1: world position X */
    /* 0x34 */ s32 sat1_y;           /* satellite 1: world position Y */

    /* Per-satellite influence factors.
     * 0 = static (fixed on screen), nonzero = moves proportionally
     * to the player's frame-to-frame displacement. */
    /* 0x38 */ s32 sat0_influence;   /* satellite 0: inertia multiplier */
    /* 0x3c */ s32 sat1_influence;   /* satellite 1: inertia multiplier */

    /* 0x40 */ s32 num_attached;     /* count of active satellites (0-2) */
    /* 0x44 */ s32 field_0x44;       /* unknown / padding */
    /* 0x48 */ s32 field_0x48;       /* unknown / padding */

    /* Display dimensions (typically 240x160, matching GBA screen). */
    /* 0x4c */ s32 display_width;    /* viewport width in pixels (240) */
    /* 0x50 */ s32 display_height;   /* viewport height in pixels (160) */

    /* Computed screen-space position of the camera (top-left corner).
     * screen_x = FP_TO_INT(x) - display_width / 2
     * screen_y = FP_TO_INT(y) - display_height / 2 */
    /* 0x54 */ s32 screen_x;         /* screen-space X of viewport origin */
    /* 0x58 */ s32 screen_y;         /* screen-space Y of viewport origin */

    /* Camera dimensions (usually mirrors display_width/height). */
    /* 0x5c */ s32 camera_width;     /* camera region width */
    /* 0x60 */ s32 camera_height;    /* camera region height */
} Camera;

/* ========================================================================
 *  Animation State  (24 bytes = 0x18)
 *
 *  Used by the sprite frame animation system.
 *  Managed by LoadLevelData (clear), InitSubPositions (select frame).
 * ======================================================================== */

typedef struct AnimState {
    /* 0x00 */ s32   data_ptr;       /* pointer to animation data table */
    /* 0x04 */ s32   frame_ptr;      /* pointer to current frame set */
    /* 0x08 */ s32   palette_src;    /* source palette for blending */
    /* 0x0c */ s32   palette_dst;    /* destination palette / current */
    /* 0x10 */ s32   timer;          /* playback timer / frame counter */
    /* 0x14 */ s32   speed;          /* playback speed / step */
} AnimState;

/* ========================================================================
 *  Palette Animation Slot  (32 bytes = 0x20)
 *
 *  5 slots starting at byte 0x3c in the RenderController.
 *  Managed by func_0x080023f4 (update), func_0x080022b4 (blend),
 *  func_0x080023a0 (fade).
 *
 *  Each slot blends between two RGB555 palette sources or animates
 *  through frames. The blend_t factor interpolates between palette_a
 *  and palette_b; dest_* fields control OAM sprite output.
 * ======================================================================== */

typedef struct PalAnimSlot {
    /* 0x00 */ u8    active;         /* 0 = inactive, 1 = blending, 2 = fading */
    /* 0x01 */ u8    pad[3];
    /* 0x04 */ s32   data_ptr;       /* pointer to animation data table */
    /* 0x08 */ s32   palette_a;      /* palette source A (16-bit entries) */
    /* 0x0c */ s32   palette_b;      /* palette source B (16-bit entries) */
    /* 0x10 */ s16   blend_t;        /* blend factor (0x000 = A, 0x1000 = B) */
    /* 0x12 */ s16   blend_step;     /* blend speed per frame */
    /* 0x14 */ s16   blend_max;      /* blend endpoint */
    /* 0x16 */ s16   frame_shift;    /* animation frame bit-shift */
    /* 0x18 */ s16   dest_x;         /* OAM destination X */
    /* 0x1a */ s16   dest_y;         /* OAM destination Y */
    /* 0x1c */ s16   dest_tile;      /* OAM tile index */
    /* 0x1e */ s16   dest_size;      /* OAM sprite size */
} PalAnimSlot;

/* ========================================================================
 *  UI Bar Element
 *
 *  Part of the level-select / progress bar display.
 *  5 elements, managed by Collectible_Init / func_0x08001198.
 *  Positions start off-screen (x >= 240) and slide in.
 * ======================================================================== */

#define UI_BAR_ELEMENT_COUNT  5

typedef struct UIBarState {
    /* 0x00 */ s32 interp[UI_BAR_ELEMENT_COUNT];    /* interpolation t (0x1000 = 1.0) */
    /* 0x14 */ s32 target_x[UI_BAR_ELEMENT_COUNT];  /* target X positions */
    /* 0x28 */ s32 start_x[UI_BAR_ELEMENT_COUNT];   /* start X positions */
    /* 0x3c */ s32 current_x[UI_BAR_ELEMENT_COUNT]; /* current X positions */
    /* 0x50 */ u8   dirty;            /* non-zero when positions need update */
    /* 0x51 */ u8   pad[3];
    /* 0x54 */ s32  level_number;     /* current level index */
} UIBarState;

/* ========================================================================
 *  Entity / Planet Object  (0x104 bytes = 260)
 *
 *  Used by the player planet and all orbital entities.
 *  Pool of 32 entities starts at GameState + 0x204.
 *  Entity[0] is typically the player-controlled planet.
 *
 *  Accessible via: gameState + ENTITY_POOL_OFFSET + index * ENTITY_SIZE
 *
 *  Word-indexed accesses in decompiled code:
 *    param_1[0]   = x (Q12)
 *    param_1[1]   = y (Q12)
 *    param_1[0xf] = state (jump table index, 0-4)
 *    param_1[0x22] = level_index (s16 at byte 0x88)
 *    param_1[0x23] = linked_entity (void* at byte 0x8c)
 * ======================================================================== */

typedef struct PACKED Entity {
    /* 0x00 */ s32   x;              /* position X (Q12 fixed point) */
    /* 0x04 */ s32   y;              /* position Y (Q12 fixed point) */
    /* 0x08 */ s32   prev_x;         /* previous X (Q12) */
    /* 0x0c */ s32   prev_y;         /* previous Y (Q12) */
    /* 0x10 */ s32   vel_x;          /* velocity X (Q12) */
    /* 0x14 */ s32   vel_y;          /* velocity Y (Q12) */
    /* 0x18 */ s32   accel_x;        /* acceleration X */
    /* 0x1c */ s32   accel_y;        /* acceleration Y */
    /* 0x20 */ s32   orbit_angle;    /* orbital angle (fixed point) */
    /* 0x24 */ s32   flags_a;        /* flags (set to 1 on init) */
    /* 0x28 */ u32   flags_b;        /* bitfield: 0x10=in-orbit, 0x04=absorbing,
                                              0x02=highlighted, 0x01=hidden */
    /* 0x2c */ s32   timer;          /* state timer / counter */
    /* 0x30 */ s32   field_0x30;     /* unused / padding */
    /* 0x34 */ u8    flag_0x34;      /* single-byte flag (set on transition) */
    /* 0x35 */ u8    pad_35[3];

    /* 0x38 */ u32   vtable;         /* type / vtable pointer (GBA: 32-bit) */
    /* 0x3c */ s32   state;          /* state machine index (0-4), used for
                                              jump table dispatch */

    /* 0x40 */ u32   sprite_flags;   /* sprite rendering flags */
    /* 0x44 */ u32   script_ptr;     /* script/command pointer (GBA: 32-bit) */

    /* Position in integer pixels (converted from Q12 by >> 12).
     * Used for screen-space rendering and camera offset calculations.
     * PlaceObject sets these directly; camera reads them for viewport. */
    /* 0x48 */ s32   pos_x;          /* position X (integer pixels) */
    /* 0x4c */ s32   pos_y;          /* position Y (integer pixels) */
    /* 0x50 */ s32   prev_pos_x;     /* previous position X (pixels) */
    /* 0x54 */ s32   prev_pos_y;     /* previous position Y (pixels) */

    /* Velocity in integer pixels per frame.
     * Added to pos_x/pos_y each frame; used for rendering trail/orbit. */
    /* 0x58 */ s32   vel_x_px;       /* velocity X (pixels/frame) */
    /* 0x5c */ s32   vel_y_px;       /* velocity Y (pixels/frame) */

    /* 0x60 */ s32   mode;           /* behavior mode (0=idle, 1=launch,
                                              2=flight, 3=landing) */
    /* 0x64 */ s32   rotation;       /* rotation angle (used for OAM rotation) */

    /* Alternate velocity (used when entity is in orbit / attached). */
    /* 0x68 */ s32   alt_vel_x;      /* alternate velocity X */
    /* 0x6c */ s32   alt_vel_y;      /* alternate velocity Y */

    /* Screen-space positions for rendering (integer pixels).
     * Computed from pos_x/pos_y minus camera viewport origin.
     * 0x70/0x74 used for "primary" position, 0x78/0x7c for "secondary". */
    /* 0x70 */ s32   screen_x;       /* screen X (primary) */
    /* 0x74 */ s32   screen_y;       /* screen Y (primary) */
    /* 0x78 */ s32   screen_x2;      /* screen X (secondary / timer display) */
    /* 0x7c */ s32   screen_y2;      /* screen Y (secondary / timer display) */

    /* Level / scoring metadata (s16 fields packed without padding). */
    /* 0x80 */ s16   field_0x80;     /* unknown / padding */
    /* 0x82 */ s16   direction;      /* facing direction / angle index */
    /* 0x84 */ s16   direction2;     /* secondary direction (prev/target) */
    /* 0x86 */ s16   score;          /* entity's associated score value */
    /* 0x88 */ s16   level_index;    /* difficulty/level index (0-11),
                                              used as table lookup key */
    /* 0x8a */ u16   pad_8a;         /* alignment padding */

    /* Linked list: entities can form chains (e.g., orbit chains).
     * 0x8c points to the next entity in the chain, or NULL.
     * 0xb0 is used as a secondary chain head (e.g., for absorbed entities). */
    /* 0x8c */ u32   linked_entity;  /* next entity in chain (GBA: 32-bit) */

    /* Orbital mechanics parameters (used when flags_b & 0x10). */
    /* 0x90 */ s32   orbit_param;    /* orbit angle or parameter */
    /* 0x94 */ s32   orbit_speed;    /* orbit angular speed */
    /* 0x98 */ s32   orbit_radius;   /* orbit radius (Q12) */
    /* 0x9c */ s16   orbit_scale;    /* orbit scaling factor */
    /* 0x9e */ u16   pad_9e;

    /* Score comparison / absorption state.
     * comparison_type encodes direction: 1=less, 2=equal, 3=greater.
     * palette_timer drives the visual absorption effect. */
    /* 0xa0 */ s32   comparison_raw;  /* comparison data (accessed as both s32 and u16) */
    /* 0xa4 */ s16   palette_timer;    /* palette blend timer */
    /* 0xa6 */ s16   palette_dir;      /* palette blend direction (-1,0,+1) */
    /* 0xa8 */ s16   pause_flag;       /* non-zero to pause entity behavior */
    /* 0xaa */ u16   pad_aa;
    /* 0xac */ s32   chain_head_pad; /* padding to align chain_head */
    /* 0xb0 */ u32   chain_head;     /* secondary chain head (GBA: 32-bit) */
    /* 0xb4 */ u8    extra[0x50];    /* type-specific data, pads to 0x104 total */
} Entity;

/* ========================================================================
 *  Level Data Table Entry  (0x2c bytes = 44)
 *
 *  Indexed by current_level. Table base is stored in a DAT_ constant.
 *  Each entry contains difficulty thresholds and parameters for
 *  the current level. Stride confirmed by:
 *    iVar2 = *(int *)(iVar8 + 0x198) * 0x2c + table_base;
 * ======================================================================== */

typedef struct LevelDataEntry {
    /* 0x00 */ s32   param_0;        /* difficulty threshold A */
    /* 0x04 */ s32   param_4;        /* difficulty threshold B */
    /* 0x08 */ s32   param_8;        /* gravity constant */
    /* 0x0c */ s32   param_c;        /* attraction radius */
    /* 0x10 */ s32   param_10;       /* spawn delay */
    /* 0x14 */ s32   param_14;       /* score multiplier */
    /* 0x18 */ s32   param_18;       /* palette index */
    /* 0x1c */ s32   param_1c;       /* sprite group */
    /* 0x20 */ s32   param_20;       /* OAM attribute base */
    /* 0x24 */ s32   param_24;       /* sound effect ID */
    /* 0x28 */ s32   param_28;       /* flags / mode */
} LevelDataEntry;

/* ========================================================================
 *  Animation Data Table Entry
 *
 *  Two table formats, both indexed by [type][level_index]:
 *
 *  Format A: type * 0x30 + level_index * 4
 *    Each type has 12 entries of 4 bytes (s32 values).
 *    Used for: *(short *)(entity + 0x88) * 4 +
 *              *(int *)(entity + 0x3c) * 0x30 + table_base
 *
 *  Format B: type * 0x60 + level_index * 8
 *    Each type has 12 entries of 8 bytes (two s32 values).
 *    Used for: *(short *)(entity + 0x88) * 8 +
 *              *(int *)(entity + 0x3c) * 0x60 + table_base
 * ======================================================================== */

typedef struct AnimDataEntryA {
    s32 value;          /* single parameter per difficulty level */
} AnimDataEntryA;

typedef struct AnimDataEntryB {
    s32 value_a;        /* first parameter */
    s32 value_b;        /* second parameter (e.g., size or speed) */
} AnimDataEntryB;

/* ========================================================================
 *  Player State Object
 *
 *  Manages the player-controlled planet's rendering, input handling,
 *  and mode transitions (idle, launch, flight, landing).
 *
 *  Mode values: 0 = idle/aim, 1 = launch, 2 = flight, 3 = landing
 *
 *  The player has a dual-buffered script system: script_ptr_A (0x0c) is
 *  the primary callback, script_ptr_B (0x14) is queued for the next
 *  mode transition.
 * ======================================================================== */

typedef struct PlayerState {
    /* 0x00 */ s32   x;              /* position X (Q12) */
    /* 0x04 */ s32   y;              /* position Y (Q12) */
    /* 0x08 */ u32   self;           /* self-referencing pointer (GBA: 32-bit) */
    /* 0x0c */ u32   script_ptr_a;   /* primary script/callback pointer */
    /* 0x10 */ s32   script_arg_a;   /* script argument */
    /* 0x14 */ u32   script_ptr_b;   /* queued script for next transition */
    /* 0x18 */ s32   script_arg_b;   /* queued script argument */
    /* 0x1c */ s32   field_0x1c;
    /* 0x20 */ s32   field_0x20;
    /* 0x24 */ s32   field_0x24;
    /* 0x28 */ u32   flags;          /* bitfield flags */
    /* 0x2c */ s32   timer;          /* frame counter / state timer */
    /* 0x30 */ s32   field_0x30;
    /* 0x34 */ s32   field_0x34;
    /* 0x38 */ u32   vtable;         /* type / vtable pointer (GBA: 32-bit) */
    /* 0x3c */ s32   world_x;        /* world position X (Q12, relative) */
    /* 0x40 */ s32   world_y;        /* world position Y (Q12, relative) */
    /* 0x44 */ u32   callback_a;     /* callback function pointer */
    /* 0x48 */ s32   callback_data;  /* callback user data */
    /* 0x4c */ u32   callback_b;     /* second callback function pointer */
    /* 0x50 */ s32   callback_self;  /* callback self pointer */
    /* 0x54 */ s32   screen_x;       /* screen-space X (integer pixels) */
    /* 0x58 */ s32   screen_y;       /* screen-space Y (integer pixels) */
    /* 0x5c */ s32   state_value;    /* mode-specific value (e.g., launch timer) */
    /* 0x60 */ s32   mode;           /* current mode: 0=aim, 1=launch, 2=flight, 3=landing */
    /* 0x64 */ s32   rotation;       /* rotation angle (Q12) */
    /* 0x68 */ u8    active;         /* non-zero when player is active */
    /* 0x69 */ u8    pad_69[3];
    /* 0x6c */ u32   linked_entity;  /* entity this player is attached to (GBA: 32-bit) */
    /* ... additional fields extend beyond this point ... */
} PlayerState;

/* ========================================================================
 *  Render Controller Object
 *
 *  Manages sprite rendering, palette animation, and OAM output.
 *  Contains 5 palette animation slots, 2 animation states, and
 *  per-entity rendering parameters.
 *
 *  Palette slots at byte 0x3c, each 0x20 bytes (5 * 0x20 = 0xa0).
 *  AnimStates at bytes 0xd4 and 0xec, each 24 bytes.
 * ======================================================================== */

typedef struct RenderController {
    /* 0x00 */ s32   field_0x00;
    /* 0x04 */ s32   field_0x04;
    /* 0x08 */ void  *self;          /* self-referencing pointer */
    /* 0x0c */ s32   field_0x0c;
    /* 0x10 */ s32   field_0x10;
    /* 0x14 */ s32   field_0x14;
    /* 0x18 */ s32   field_0x18;
    /* 0x1c */ s32   field_0x1c;
    /* 0x20 */ s32   field_0x20;
    /* 0x24 */ s32   field_0x24;
    /* 0x28 */ s32   field_0x28;
    /* 0x2c */ s32   field_0x2c;
    /* 0x30 */ s32   field_0x30;
    /* 0x34 */ u8    flag_0x34;      /* single-byte flag */
    /* 0x35 */ u8    pad_35[3];
    /* 0x38 */ void  *vtable;        /* type / vtable pointer */

    /* Palette animation slots (5 slots, 0x20 bytes each).
     * Processed by func_0x080023f4, which iterates all 5. */
    /* 0x3c */ PalAnimSlot pal_slots[PAL_ANIM_SLOT_COUNT];  /* 5 * 0x20 = 0xa0 */

    /* 0xfc */ u32   sprite_ptr;     /* pointer to current sprite data (GBA: 32-bit) */
    /* 0x100 */ u32  anim_table_ptr; /* pointer to animation data table (GBA: 32-bit) */
    /* 0x104 */ s32  anim_counter_x; /* animation frame counter (X axis) */
    /* 0x108 */ s32  anim_counter_y; /* animation frame counter (Y axis) */

    /* Sprite animation states (2 states, 0x18 bytes each).
     * Used for entity sprite frame selection via FUN_08000ae4. */
    /* 0x10c */ u8    anim_buf[0x30]; /* local sprite animation buffer */
    /* 0xd4 (within pal_slots overlap) AnimState anim_a; */
    /* 0xec (within pal_slots overlap) AnimState anim_b; */
} RenderController;

/* ========================================================================
 *  Global Game State
 *
 *  Pointer stored at *DAT_080043a4 (accessed frequently as iVar8).
 *  Contains the camera, entity pool, player, render controller,
 *  level state, and global counters.
 *
 *  Major sub-structures and their offsets:
 *    0x08c: Linked list node array (16 nodes * 16 bytes)
 *    0x18c: World dimensions (Q12)
 *    0x198: Current level index
 *    0x1a0: Camera (0x64 bytes)
 *    0x204: Entity pool (32 * 0x104 bytes)
 *    0x1684+: Player, RenderController, LevelState
 *
 *  Entity[0] (at 0x204) is the player-controlled planet.
 *  Entity[0].pos_x is at GameState + 0x24c.
 *  Entity[0].pos_y is at GameState + 0x250.
 * ======================================================================== */

typedef struct GameState {
    /* 0x000 */ s32   flags_a;
    /* 0x004 */ s32   flags_b;           /* initialized to -1 */
    /* 0x008 */ s32   flags_c;
    /* 0x00c */ s32   flags_d;           /* initialized to -1 */
    /* 0x010 */ s32   flags_e;

    /* ... field_0x14 through field_0x54 ... */
    /* 0x014 */ s32   field_0x14[17];

    /* Linked list system (sorted by priority for update order). */
    /* 0x058 */ u32   list1_head;       /* primary linked list head (GBA: 32-bit) */
    /* 0x05c */ s32   list1_pad;
    /* 0x060 */ s32   list1_count;       /* primary list entry count */
    /* 0x064 */ s32   list1_pad2;

    /* 0x068 */ s32   field_0x68;
    /* 0x06c */ s32   field_0x6c;

    /* 0x070 */ u32   list2_head;       /* secondary linked list head (GBA: 32-bit) */
    /* 0x074 */ s32   list2_pad;
    /* 0x078 */ s32   list2_count;
    /* 0x07c */ s32   field_0x7c;
    /* 0x080 */ s32   field_0x80;
    /* 0x084 */ s32   field_0x84;
    /* 0x088 */ s32   field_0x88;

    /* Linked list nodes: 16 entries, each 4 words (16 bytes).
     * Used for priority-sorted update/render queues. */
    /* 0x08c */ s32   list_nodes[64];    /* 16 * 4 words = 0x100 bytes */

    /* 0x18c */ s32   world_width;       /* world boundary width (Q12) */
    /* 0x190 */ s32   world_height;      /* world boundary height (Q12) */
    /* 0x194 */ s32   field_0x194;
    /* 0x198 */ s32   current_level;     /* current level index (0-11) */
    /* 0x19c */ s32   level_data_index;  /* used with LEVEL_DATA_STRIDE */

    /* Camera / Viewport (100 bytes = 0x64).
     * Initialized by GameState_Init (FUN_080001cc).
     * Updated by Object_UpdateScreenPosition (FUN_08000250). */
    /* 0x1a0 */ Camera camera;

    /* Entity pool: 32 entities, each 0x104 bytes.
     * Entity[0] is the player-controlled planet.
     * Indexed as: entities[index] for i in 0..31
     * Total: 32 * 0x104 = 0x1480 bytes. */
    /* 0x204 */ Entity entities[ENTITY_COUNT];

    /* Player entity position shortcuts (same as entities[0].pos_x/y).
     * Convenience: GameState + 0x24c = entities[0].pos_x
     *              GameState + 0x250 = entities[0].pos_y */

    /* ... fields between entities and player/controller ... */
    /* 0x1684 */ s32   field_0x1684[0x1fc]; /* gap / sub-structures */

    /* Player State (estimated offset, size ~0x100 bytes).
     * Managed by Player_InitState, Player_SetMode, etc. */
    /* ~0x1684 */ PlayerState player;

    /* ... additional sub-structures ... */

    /* Render Controller (estimated offset).
     * Manages palette animation, sprite rendering, OAM output. */
    /* RenderController render_ctrl; */

    /* Level State (at byte 0x2480).
     * Initialized by Boundary_Init (FUN_08000e78).
     * Contains animation state, UI bar, level metadata. */
    /* 0x2480 */ s32   level_state_base[4]; /* start of LevelState */

    /* ... LevelState fields continue ... */

    /* 0x2540 */ s32   field_0x2540;
    /* 0x2544 */ s32   field_0x2544;
    /* 0x2550 */ s32   field_0x2550;       /* initialized to 0x100 */
    /* 0x2558 */ s32   field_0x2558;       /* initialized to 0x40 */
    /* 0x2560 */ s32   field_0x2560;
    /* 0x256c */ s32   field_0x256c;
    /* 0x2574 */ s32   field_0x2574;

    /* Gameplay state flag.
     * Non-zero during active gameplay; checked before processing input. */
    /* 0x1c20 */ u8    gameplay_active;

    /* ... additional fields ... */
} GameState;

/* ========================================================================
 *  Level State  (large struct, starts at GameState + 0x2480)
 *
 *  Initialized by Boundary_Init (FUN_08000e78).
 *  Contains animation state, UI bar elements, and level metadata.
 * ======================================================================== */

typedef struct PACKED LevelState {
    /* 0x00 */ s32   x;              /* world position X (Q12) */
    /* 0x04 */ s32   y;              /* world position Y (Q12) */
    /* 0x08 */ u32   self;           /* self-referencing pointer (GBA: 32-bit) */
    /* 0x0c */ s32   field_0x0c;
    /* 0x10 */ s32   field_0x10;
    /* 0x14 */ s32   field_0x14;
    /* 0x18 */ u32   self2;          /* second self pointer (GBA: 32-bit) */
    /* 0x1c */ s32   field_0x1c;
    /* 0x20 */ s32   field_0x20;
    /* 0x24 */ s32   field_0x24;
    /* 0x28 */ s32   field_0x28;
    /* 0x2c */ s32   field_0x2c;
    /* 0x30 */ s32   field_0x30;
    /* 0x34 */ u8    field_0x34;     /* single byte flag */
    /* 0x35 */ u8    pad_35[3];
    /* 0x38 */ u32   vtable;         /* type / vtable pointer (GBA: 32-bit) */
    /* 0x3c */ AnimState anim;

    /* UI bar: 5 animated elements for level progress display.
     * Byte offsets 0x54-0xa7. */
    /* 0x54 */ s32   bar_interp[UI_BAR_ELEMENT_COUNT];     /* byte 0x54 */
    /* 0x68 */ s32   bar_target_x[UI_BAR_ELEMENT_COUNT];  /* byte 0x68 */
    /* 0x7c */ s32   bar_start_x[UI_BAR_ELEMENT_COUNT];   /* byte 0x7c */
    /* 0x90 */ s32   bar_current_x[UI_BAR_ELEMENT_COUNT]; /* byte 0x90 */
    /* 0xa4 */ u8    bar_dirty;      /* non-zero = UI needs redraw */
    /* 0xa5 */ u8    pad_a5[3];
    /* 0xa8 */ s32   level_number;   /* current level index */

    /* ... additional fields extend beyond this point ... */
} LevelState;

/* ========================================================================
 *  Sprite / OAM Helper Structures
 * ======================================================================== */

/* OAM entry indices for attached object sprites */
typedef struct OamIndices {
    u16 attr0_index;    /* index into OAM buffer for ATTR0 */
    u16 attr1_index;    /* index into OAM buffer for ATTR1 */
} OamIndices;

/* ========================================================================
 *  Collision Bounding Box
 * ======================================================================== */

typedef struct BBox {
    s32 x;              /* center X (Q12 fixed point) */
    s32 y;              /* center Y (Q12 fixed point) */
    s32 half_w;         /* half-width (Q12 fixed point) */
    s32 half_h;         /* half-height (Q12 fixed point) */
} BBox;

/* ========================================================================
 *  Motion Vector (6 words = 24 bytes)
 * ======================================================================== */

typedef struct MotionVec {
    s32 pos_x;          /* position X (Q12) */
    s32 pos_y;          /* position Y (Q12) */
    s32 vel_x;          /* velocity X (Q12) */
    s32 vel_y;          /* velocity Y (Q12) */
    s32 accel_x;        /* acceleration X */
    s32 accel_y;        /* acceleration Y */
} MotionVec;

/* ========================================================================
 *  Function Prototypes
 * ======================================================================== */

/* --- Camera / Viewport (0x08000xxx) --- */

/**
 * GameState_Init @ 0x080001cc
 * Initialize camera centered on screen.
 * Sets position to (120.0, 80.0) in Q12, display to 240x160.
 * param_1[0x11]=0, param_1[0x12]=0, param_1[0x13]=0xf0, param_1[0x14]=0xa0
 */
Camera *camera_init(Camera *cam);

/**
 * ObjectArray_ClearWithFree @ 0x08000210
 * Cleanup camera and optionally free memory.
 * Iterates through sub-objects in reverse and frees if flag set.
 */
void camera_cleanup(int base, u32 flags);

/**
 * Object_UpdateScreenPosition @ 0x08000250
 * Update camera screen position and render satellites.
 * Computes screen_x/y = FP_TO_INT(pos) - display_dim / 2.
 * Updates attached object positions using influence factors.
 * Writes OAM sprite attrs for each satellite.
 */
void camera_update(Camera *cam);

/**
 * SetObjectSize @ 0x08000440
 * Set camera/world dimensions.
 */
void camera_set_dimensions(int base, s32 width, s32 height);

/**
 * Object_SetPositionWrapped @ 0x08000448
 * Set camera position with world-boundary wrapping.
 * Wraps position within [0, world_width) and [0, world_height).
 */
void camera_set_position(Camera *cam, s32 new_x, s32 new_y, s8 snap);

/**
 * Object_BounceOffWalls @ 0x08000688
 * Check if a rectangle intersects the visible viewport,
 * accounting for world-wrap boundaries. Returns 1 if collision occurs.
 * Used for camera viewport culling.
 */
s32 camera_check_viewport_collision(int base, s32 *x_ptr, s32 *y_ptr,
                                    s32 rect_w, s32 rect_h);

/**
 * FreeIfFlagSet @ 0x080008a4
 * Free memory if bit 0 of flags is set.
 */
void free_if_flag_set(int ptr, u32 flags);

/* --- Physics / Math (0x080008xx - 0x08001xxx) --- */

/**
 * Object_ApplyFriction @ 0x080008d0
 * Apply spring damping to a value.
 * Moves param[1] toward param[0] with damping factor param[2].
 * 3-word array: [target, current, damping_factor].
 */
void apply_spring_damping(s32 *spring);

/**
 * func_0x08000934 @ 0x08000934
 * Update hardware OAM attributes for a special object (e.g., arrow/indicator).
 * Handles type 0 (clear), 1 (dual-axis), 2/3 (single-axis) modes.
 */
void update_oam_indicator(s32 *anim);

/**
 * LoadLevelData @ 0x08000abc
 * Clear a 6-word animation/motion state to zero.
 * 6 words = 24 bytes (AnimState size).
 */
void anim_state_clear(AnimState *anim);

/**
 * UpdateSubPositions @ 0x08000acc
 * Free animation state if bit 0 of flags is set.
 */
void anim_state_free(AnimState *anim, u32 flags);

/**
 * InitSubPositions @ 0x08000ae4
 * Select an animation frame from a time-based keyframe table.
 * Walks a lookup table and selects the frame corresponding to the
 * given time value, updating the AnimState pointers.
 */
void anim_select_frame(AnimState *anim, s32 group, u32 time);

/**
 * func_0x08000ba4 @ 0x08000ba4
 * Free animation state if bit 0 of flags is set (alternate).
 */
void anim_state_free2(int ptr, u32 flags);

/* --- Level State / UI Bar (0x08000e78 - 0x08001xxx) --- */

/**
 * Boundary_Init @ 0x08000e78
 * Initialize the game level state.
 * Sets up animation system, UI bar elements, and level metadata.
 * UI bar: 5 elements with interp=0x1000, target_x starting at 0xf0.
 */
LevelState *level_state_init(LevelState *state);

/**
 * Collectible_Animate @ 0x08000f68
 * Cleanup level state and optionally free memory.
 */
void level_state_cleanup(LevelState *state, u32 flags);

/**
 * Collectible_Init @ 0x08000f9c
 * Initialize the UI bar element positions.
 * Calculates target_x based on level_number (< 6, or >= 6).
 * Sets bar_dirty = 1 when complete.
 */
void level_bar_init(LevelState *state);

/**
 * Physics_ApplyGravity @ 0x08001080
 * Render a numeric digit/score display to OAM.
 * Creates OAM entries for 1 or 2 digit numbers at given coords.
 * Handles multi-digit values by splitting into individual digits.
 */
void render_digit_to_oam(LevelState *state, u16 x, u16 y, s32 value);

/**
 * func_0x08001198 @ 0x08001198
 * Update the level bar when level changes.
 * Interpolates bar positions from old to new level.
 * Triggers digit rendering when all interpolations reach 0x1000.
 */
void level_bar_update(LevelState *state);

/* --- Physics / Distance (0x08001ddc - 0x08001xxx) --- */

/**
 * Physics_DistanceSquared @ 0x08001ddc
 * Compute squared distance from a point to a clamped line segment.
 * Clamps point to the segment's bounding region, returns squared
 * distance in Q12 fixed point (left-shifted by 12).
 */
s32 compute_clamped_distance_sq(s32 *radii, s32 *point_a, s32 *point_b);

/**
 * Physics_CalcDistanceClamped @ 0x08001ed8
 * Compute difference vector between two points,
 * clamped by the radius in radii[0..1].
 * Output written to out[0..1].
 */
void compute_clamped_diff(s32 *radii, s32 *out, s32 *point_a, s32 *point_b);

/**
 * func_0x08001fd0 @ 0x08001fd0
 * Check bounded collision between a point and a rectangle.
 * Tests if a point (with bounding radii) overlaps a rectangle region.
 * Returns 1 if collision, 0 otherwise.
 */
s32 check_bounded_collision(s32 *radii, s32 *center, s32 rad_a,
                            s32 *rect_pos, s32 rad_b);

/* --- RenderController / Sprite System (0x080020xx - 0x080025xx) --- */

/**
 * Render_LoadSpriteSheet @ 0x080020e8
 * Initialize the render controller / sprite sheet manager.
 * Sets up vtable, linked list pointers, clears animation states.
 */
RenderController *render_ctrl_init(RenderController *ctrl);

/**
 * Render_DrawSpriteAt @ 0x0800216c
 * Cleanup render controller and optionally free memory.
 */
void render_ctrl_cleanup(RenderController *ctrl, u32 flags);

/**
 * Render_DrawSpriteScaled @ 0x0800218c
 * Configure render controller for scaled sprite rendering.
 * Sets up 5 palette animation slots with sprite data pointers.
 * Slot layout: active(1), pad(3), data_ptr(4), pal_a(4), pal_b(4),
 *              blend_t(2), blend_step(2), blend_max(2), frame_shift(2),
 *              dest_x(2), dest_y(2), dest_tile(2), dest_size(2)
 */
void render_ctrl_setup_scaled(RenderController *ctrl, int sprite_data, u32 param_3);

/**
 * Render_DrawFrame @ 0x080022b4
 * Animate palette blending between two RGB555 sources.
 * Linearly interpolates 16 palette entries based on blend factor.
 * Writes blended palette via DMA to VRAM.
 */
void palette_blend_animate(int base, PalAnimSlot *slot);

/**
 * Render_UpdateAll @ 0x080023a0
 * Animate palette fade with frame offset.
 * Selects palette frame based on animated timer, DMA to VRAM.
 */
void palette_fade_animate(int base, PalAnimSlot *slot);

/**
 * func_0x080023f4 @ 0x080023f4
 * Update all palette animation slots and sprite animation.
 * Iterates 5 PalAnimSlots, calling blend or fade as appropriate.
 * Also updates sprite animation counter from anim_table_ptr.
 */
void palette_anim_update(RenderController *ctrl);

/**
 * func_0x08002510 @ 0x08002510
 * Start a palette animation on a given slot.
 * Sets active=1, blend_t=0, blend_step, and computes frame_shift.
 */
void palette_anim_start(RenderController *ctrl, s32 slot, u16 speed, s32 type);

/* --- Entity Pool (0x080025xx - 0x08002xxx) --- */

/**
 * Render_DrawBox @ 0x08002558
 * Initialize the entity pool / object manager.
 * Clears entity slots and animation states.
 * Also initializes 2 AnimState blocks at offset 0xd4.
 */
void *entity_pool_init(void *state);

/**
 * Render_DrawUI @ 0x080025d8
 * Destroy entity pool and free sub-allocations.
 * Iterates through entity slots and animation states.
 */
void entity_pool_destroy(int base, u32 flags);

/**
 * Render_DrawText @ 0x0800263c
 * Configure an entity from level data script.
 * Sets up position, velocity, direction, and state machine.
 * Calls entity_set_type, entity_set_velocity, entity_set_direction.
 */
void entity_setup_from_script(Entity *entity, s32 *script_data);

/**
 * func_0x080027ec @ 0x080027ec
 * Process entity interaction / orbital mechanics.
 * Handles the player absorbing another entity, applying gravity
 * and orbital attachment. Returns 64-bit result.
 */
s64 entity_process_interaction(Entity *player, void *target);

/**
 * func_0x08002958 @ 0x08002958
 * Compare entity score against global score.
 * Sets comparison_result (-1, 0, +1) and comparison_type.
 */
void entity_compare_score(Entity *entity);

/**
 * func_0x080029bc @ 0x080029bc
 * Apply gravitational attraction between entities.
 * Computes gravity vector and updates entity acceleration.
 * Uses entity's velocity and orbit parameters.
 */
void entity_apply_gravity(Entity *entity, void *attractor);

/* --- Entity Rendering (0x08002xxx) --- */

/**
 * Render_DrawProgressBar @ 0x08002abc
 * Update entity rendering based on progress/score.
 * Handles interpolation toward target, palette direction changes.
 * Calls PlaceObject with interpolated position.
 */
void entity_render_progress(Entity *entity);

/**
 * func_0x08002c34 @ 0x08002c34
 * Update entity screen position with velocity offset.
 * Applies orbit-based position calculation using sin/cos table.
 */
void entity_update_screen_with_orbit(Entity *entity);

/**
 * Render_DrawTimerDisplay @ 0x08002d20
 * Render entity timer display and linked list management.
 * Handles viewport culling, linked list insertion for render queue.
 */
void entity_render_timer(Entity *entity);

/**
 * Render_DrawScoreDisplay @ 0x08002ff0
 * Update entity score display rendering.
 * Copies position data for score indicator display.
 */
void entity_render_score(Entity *entity);

/* --- Gameplay / Level Management (0x08003xxx - 0x08004xxx) --- */

/**
 * func_0x080037ac @ 0x080037ac
 * Load level assets from ROM.
 * Copies level data to VRAM using DMA.
 */
void level_load_assets(Entity *entity);

/**
 * Level_LoadFromROM @ 0x0800380c
 * Set entity behavior type via jump table dispatch.
 * Writes type to entity + 0x3c, then dispatches.
 */
void entity_set_type(Entity *entity, s32 type);

/**
 * Level_SpawnObjects @ 0x080039d4
 * Set entity direction/orientation.
 * Updates direction and direction2 fields, calls FUN_08004574
 * to map direction to level index.
 */
void entity_set_direction(Entity *entity, s32 dir, s32 flag);

/**
 * Level_CreateWalls @ 0x08003ac4
 * Link entity to an attractor / orbit parent.
 * Sets orbit parameters and calls PlaceObject for position.
 */
void entity_set_orbit(Entity *entity, void *parent, s32 angle,
                      s32 speed, s32 radius);

/**
 * Level_InitGravitySources @ 0x08003bec
 * Initialize gravity source for an entity.
 * Copies velocity, sets up gravity parameters.
 */
void entity_init_gravity(Entity *entity);

/**
 * func_0x08003c38 @ 0x08003c38
 * Compute orbit speed factor from distance and velocity.
 * Uses division and lookup tables for gravity calculation.
 */
void entity_compute_orbit_speed(Entity *entity);

/**
 * Level_PlaceObject @ 0x08003ce0
 * Set entity position with world-boundary wrapping.
 * Updates pos_x/pos_y and computes wrapped distance to prev_pos.
 */
void entity_set_position(Entity *entity, s32 x, s32 y, s8 snap);

/**
 * Level_SetupComplete @ 0x08003e04
 * Finalize entity setup: clamp velocity to max, normalize if needed.
 * Uses lookup tables for velocity magnitude calculation.
 */
void entity_finalize_setup(Entity *entity);

/**
 * func_0x08003fd0 @ 0x08003fd0
 * Handle entity input processing (debug/director mode).
 * Processes button input for entity position/direction adjustment.
 */
void entity_handle_input(Entity *entity);

/**
 * func_0x080041c4 @ 0x080041c4
 * Update entity palette blending over time.
 * Handles directional palette transitions (absorption effect).
 * Uses level_data_index to select palette source.
 */
void entity_update_palette_blend(Entity *entity);

/**
 * func_0x0800431c @ 0x0800431c
 * Check absorption condition and trigger effects.
 * Tests score thresholds against global_score, activates visual feedback.
 * Manages absorption animation state.
 */
void entity_check_absorption(Entity *entity);

/**
 * func_0x08004494 @ 0x08004494
 * Update entity comparison state against global score.
 * Determines directional indicator (higher/lower/equal).
 * Triggers palette animation on state change.
 */
void entity_update_comparison(Entity *entity);

/**
 * func_0x08004574 @ 0x08004574
 * Map a score value to a difficulty/level index (0-11).
 * Walks a 12-entry threshold table to find the appropriate index.
 */
s32 score_to_level_index(s32 score);

/* --- Entity Velocity / Rendering (0x08004xxx - 0x08005xxx) --- */

/**
 * func_0x08004718 @ 0x08004718
 * Check if entity has non-zero velocity.
 * Returns 1 if vel_x != 0 or vel_y != 0.
 */
s32 entity_has_velocity(Entity *entity);

/**
 * func_0x080049dc @ 0x080049dc
 * Update entity rendering (progress bar + score + timer).
 * Calls render_progress, render_score, render_timer.
 */
void entity_update_render(Entity *entity);

/**
 * func_0x08004c34 @ 0x08004c34
 * Render entity sprite with score-based animation index.
 * Uses score comparison result as OAM animation frame.
 */
void entity_render_with_score_anim(Entity *entity);

/**
 * func_0x08004ca4 @ 0x08004ca4
 * Render entity sprite with neutral animation (no score effect).
 */
void entity_render_neutral(Entity *entity);

/**
 * func_0x08004d18 @ 0x08004d18
 * Render entity sprite with animation index 4 (special effect).
 */
void entity_render_special(Entity *entity);

/**
 * func_0x08004d8c @ 0x08004d8c
 * Render entity with scale-based animation parameters.
 */
void entity_render_scaled(Entity *entity);

/**
 * func_0x08004e14 @ 0x08004e14
 * Render entity with rotation-based animation parameters.
 */
void entity_render_rotated(Entity *entity);

/**
 * Camera_RenderObject @ 0x08004e98
 * Render entity as camera-attached object (secondary animation state).
 */
void entity_render_attached(Entity *entity);

/**
 * Camera_RenderLevelObject @ 0x08004f08
 * Render entity as level object with frame animation.
 * Uses sprite_flags to select between two animation sets.
 */
void entity_render_level_object(Entity *entity);

/**
 * Camera_RenderAtOffset @ 0x0800504c
 * Render entity with static offset (animation index 4).
 */
void entity_render_offset(Entity *entity);

/* --- Player State (0x080050xx - 0x080056xx) --- */

/**
 * Player_InitState @ 0x080050c8
 * Initialize the player state.
 * Clears all fields, sets vtable, active=1.
 */
PlayerState *player_init(PlayerState *player);

/**
 * Player_FreeState @ 0x0800513c
 * Free player state and optionally release memory.
 */
void player_free(PlayerState *player, u32 flags);

/**
 * Player_SetMode @ 0x0800515c
 * Set player behavior mode (0=aim, 1=launch, 2=flight, 3=landing).
 * Sets up script callback and calls mode-specific init function.
 * Computes world_x/y from game state dimensions.
 */
void player_set_mode(PlayerState *player, s32 mode);

/**
 * Player_UpdateIdle @ 0x08005214
 * Register player idle-mode callback in render update queue.
 * Selects callback based on current mode.
 */
void player_update_idle(PlayerState *player);

/**
 * Player_UpdateAiming @ 0x0800528c
 * Initialize aiming mode (setup camera and input handlers).
 */
void player_update_aiming(void);

/**
 * Player_UpdateLaunch @ 0x080052cc
 * Initialize launch mode.
 * Sets launch timer to 0x78, resets secondary timer.
 */
void player_update_launch(PlayerState *player);

/**
 * Player_UpdateFlight @ 0x08005314
 * Initialize flight mode.
 * Sets flight timer to 600.
 */
void player_update_flight(PlayerState *player);

/**
 * Player_UpdateLanding @ 0x0800535c
 * Initialize landing mode.
 * Sets landing timer to 1.
 */
void player_update_landing(PlayerState *player);

/**
 * func_0x080053a0 @ 0x080053a0
 * Compute player rotation from velocity direction.
 * Uses atan2 lookup table to convert velocity to angle.
 * Applies smoothing with threshold-based snap.
 */
s32 player_compute_rotation(PlayerState *player, s32 *velocity);

/**
 * func_0x080055b8 @ 0x080055b8
 * Check if player is within camera viewport bounds.
 * Converts Q12 world position to screen coordinates, tests collision.
 * Returns viewport size (8, 0x10) or 0 if out of bounds.
 */
s32 player_check_viewport(PlayerState *player);

/**
 * func_0x08005620 @ 0x08005620
 * Auto-transition player mode based on timer expiry.
 * When timer >= 0x12d and viewport check passes, transitions mode.
 */
void player_auto_transition(PlayerState *player);

/**
 * func_0x08005684 @ 0x08005684
 * Update player to follow linked entity position.
 * Copies linked entity's position, checks viewport.
 */
void player_follow_entity(PlayerState *player);

/* --- Player Rendering (0x08005xxx) --- */

/**
 * func_0x08005bd0 @ 0x08005bd0
 * Render player ship with rotation-based OAM attributes.
 * Writes OAM ATTR0/ATTR1/ATTR2 with position, rotation, tile info.
 * Uses camera offset for screen-space conversion.
 */
void player_render_rotated(PlayerState *player);

/**
 * func_0x08005d10 @ 0x08005d10
 * Render player as simple sprite (no rotation).
 * Writes OAM attributes with basic position and tile.
 */
void player_render_simple(PlayerState *player);

/**
 * func_0x08005d98 @ 0x08005d98
 * Render player with double-size sprite and rotation.
 * Uses scale factor 0x300 for larger display.
 */
void player_render_large(PlayerState *player);

/* --- Gameplay Systems (0x08005xxx - 0x08009xxx) --- */

/**
 * func_0x08005f08 @ 0x08005f08
 * Process sound/music state changes.
 * Checks sound enable flags and triggers sound effects.
 */
void sound_process_state(char *state);

/**
 * GameLoop_Update @ 0x08005f84
 * Check if a game loop entry is ready for update.
 * Compares timing data and returns 1 if ready.
 */
s32 gameloop_check_ready(u32 param_1, s32 param_2);

/**
 * func_0x080071f8 @ 0x080071f8
 * Initialize the complete game state.
 * Sets up linked lists, camera, entity pool (32 entities),
 * player state, render controller, and level state.
 * Entities initialized at offset 0x204, stride 0x104.
 */
GameState *game_state_init(GameState *gs);

/**
 * GameState_Setup @ 0x08007290
 * Cleanup and reinitialize game state.
 * Destroys all sub-systems in reverse order, optionally frees memory.
 */
void game_state_cleanup(GameState *gs, u32 flags);

/**
 * Menu_Init @ 0x08007330
 * Initialize menu/game state with linked list sorting.
 * Sets up entity priority queues and render ordering.
 */
void menu_init(GameState *gs);

/* --- Score / Level Select (0x08008xxx - 0x08009xxx) --- */

/**
 * LevelSelect_DrawStars @ 0x08008f04
 * Render and process level select star entities.
 * Handles entity collision, gravity, and absorption.
 * Updates level progress and triggers score display.
 */
void levelselect_update_stars(GameState *gs);

/**
 * Score_UpdateDisplay @ 0x08009228
 * Update score display when entities collide.
 * Handles absorption, score comparison, and visual effects.
 */
void score_update_collision(GameState *gs, Entity *a, Entity *b);

/**
 * func_0x08009378 @ 0x08009378
 * Process entity-to-entity gravitational interaction.
 * Computes attraction force, applies velocity changes.
 */
void entity_gravity_interaction(GameState *gs, Entity *a, Entity *b);

/**
 * func_0x080097d0 @ 0x080097d0
 * Process entity collision response.
 * Handles bounce, absorption, scoring, and state transitions.
 * Uses cross product for direction determination.
 */
void entity_collision_response(GameState *gs, Entity *target, Entity *source);

/**
 * func_0x08009c3c @ 0x08009c3c
 * Compute and apply gravitational force between entities.
 * Uses distance-based force calculation with velocity projection.
 * Updates entity positions and triggers visual feedback.
 */
void entity_apply_gravitational_force(GameState *gs, int *force_out,
                                     Entity *target, Entity *source, s32 param_5);

/**
 * Title_HandleInput @ 0x0800950c
 * Handle title screen input and entity updates.
 * Processes camera-relative position updates and entity physics.
 */
void title_handle_input(GameState *gs, void *camera, Entity *entity);

/* --- GBA Hardware / I/O --- */

/**
 * FUN_08011498 - Copy tile/sprite data to VRAM via DMA.
 */
void vram_copy_tiles(s32 dest_bg, s32 offset, s32 tile, void *src, s32 count);

/**
 * FUN_08012084 - Trigger an error handler / exception display.
 */
void error_display(s32 msg_id, s32 detail, s32 code);

/**
 * FUN_08015440 - Integer division (signed, 64-bit dividend).
 */
s32 int_div64(s32 num_hi, s32 num_lo, s32 denom);

/**
 * FUN_08015448 - Compute absolute value components of a vector.
 */
void vec_abs(s32 *out_x, s32 in_x, s32 *out_y);

/**
 * FUN_08015474 - Fixed-point multiply then shift.
 */
s32 fp_mul_shift(s32 a, s32 b);

/**
 * FUN_080156a4 - Free allocated memory block.
 */
void free_block(void *ptr);

/**
 * FUN_08014f7c - Wrap/clamp a value within [0, max).
 */
s32 wrap_value(s32 val);

/**
 * FUN_08014f74 - Copy data to VRAM (DMA transfer).
 */
void dma_copy(void *src, void *dest, s32 size);

/**
 * FUN_08014f9c - Compute OAM matrix attributes from angle.
 * Generates 4 OAM affine matrix entries from rotation angle.
 */
void compute_oam_matrix(u32 *params, u16 *output, s32 scale_x, s32 scale_y);

/**
 * FUN_08015780 - Initialize memory allocator.
 */
void mem_init(s32 heap_size);

/**
 * FUN_08012974 - Generate pseudo-random number.
 */
u32 random_next(u32 seed);

/**
 * FUN_0801ee4c - Initialize a doubly-linked list.
 */
void list_init(void *list);

/**
 * FUN_0801ee64 - Cleanup a doubly-linked list.
 */
void list_cleanup(void *list, u32 flags);

/**
 * FUN_08013884 - Play a sound effect.
 */
void sound_play(s32 effect_id);

/**
 * FUN_08013950 - Stop a sound effect.
 */
void sound_stop(s32 effect_id);

/**
 * FUN_080139b8 - Stop all sound effects.
 */
void sound_stop_all(void);

#endif /* GAME_TYPES_H */
