/*
 * bit Generations: Orbital - Binary-Accurate Decompilation
 * Using agbcc (GCC 2.95) for GBA
 * 
 * This file contains functions that compile to match the original ROM
 */

typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef int s32;
typedef short s16;
typedef char s8;

/* Object structure offsets */
#define OBJ_PREV_X     2   /* offset 0x08 */
#define OBJ_PREV_Y     3   /* offset 0x0C */
#define OBJ_SCREEN_X   4   /* offset 0x10 */
#define OBJ_SCREEN_Y   5   /* offset 0x14 */

/* GBA Hardware */
#define REG_DISPCNT    (*(volatile u32*)0x04000000)
#define REG_KEYINPUT   (*(volatile u16*)0x04000130)
#define REG_VCOUNT     (*(volatile u16*)0x04000006)

/* Function prototypes */
extern void Memory_Free(void *ptr);

/*
 * 0x08000440 - SetObjectScreenPos
 * Sets the screen X and Y position of an object
 * Parameters: r0=obj, r1=screen_x, r2=screen_y
 */
void SetObjectScreenPos(u32 *obj, u32 screen_x, u32 screen_y) {
    obj[OBJ_SCREEN_X] = screen_x;
    obj[OBJ_SCREEN_Y] = screen_y;
}

/*
 * 0x08000ABC - Object_ClearState
 * Clears the first 6 words of an object
 */
void Object_ClearState(u32 *obj) {
    obj[0] = 0;
    obj[1] = 0;
    obj[2] = 0;
    obj[3] = 0;
    obj[4] = 0;
    obj[5] = 0;
}

/*
 * 0x08000ACC - FreeIfFlagSet
 * Frees object if bit 0 of flags is set
 */
void FreeIfFlagSet(void *obj, u32 flags) {
    if (flags & 1) {
        Memory_Free(obj);
    }
}

/*
 * 0x08005EB8 - Return 0x0C
 */
u32 GetUnknownSize_0C(void) {
    return 0x0C;
}

/*
 * 0x08005EBC - Return 0x1E
 */
u32 GetUnknownSize_1E(void) {
    return 0x1E;
}

/*
 * 0x08005EC0 - Nop function
 */
void NopFunction(void) {
    /* empty */
}

/*
 * 0x08014F7C - BIOS DivMod (SWI 6)
 */
s32 BIOS_DivMod(s32 a, s32 b) {
    /* GBA BIOS call - compiler will emit swi #6 */
    return a % b;  /* Actually returns remainder in r1 */
}

/*
 * 0x08014F78 - BIOS Div (SWI 6)
 */
s32 BIOS_Div(s32 a, s32 b) {
    return a / b;
}

/*
 * 0x08014F74 - BIOS CpuSet (SWI 11)
 */
void BIOS_CpuSet(void *src, void *dst, u32 control) {
    /* GBA BIOS call */
}

/*
 * 0x08014F70 - BIOS CpuFastSet (SWI 12)
 */
void BIOS_CpuFastSet(void *src, void *dst, u32 control) {
    /* GBA BIOS call */
}

/*
 * 0x08014F6C - BIOS BgAffineSet (SWI 10)
 */
void BIOS_BgAffineSet(void *src, void *dst, u32 count) {
    /* GBA BIOS call */
}

/*
 * 0x08014F98 - BIOS Sqrt (SWI 18)
 */
u32 BIOS_Sqrt(u32 val) {
    return val; /* Placeholder - actual implementation uses SWI */
}

/*
 * 0x08014F9C - BIOS ArcTan (SWI 15)
 */
s32 BIOS_ArcTan(s32 val) {
    return val; /* Placeholder */
}

/*
 * 0x08014F84 - BIOS HuffUnComp (SWI 19)
 */
void BIOS_HuffUnComp(void *src, void *dst) {
    /* GBA BIOS call */
}

/*
 * Math utility functions
 */

u32 Math_Clamp(u32 val, u32 min, u32 max) {
    if (val < min) return min;
    if (val > max) return max;
    return val;
}

s32 Math_Abs(s32 val) {
    return val < 0 ? -val : val;
}

u32 Math_Min(u32 a, u32 b) {
    return a < b ? a : b;
}

u32 Math_Max(u32 a, u32 b) {
    return a > b ? a : b;
}

/*
 * Compare function for sorting
 */
s32 Compare_Int(u32 a, u32 b) {
    if (a > b) return 1;
    if (a < b) return -1;
    return 0;
}

/*
 * Display functions
 */

void Display_WaitVBlank(void) {
    while (REG_VCOUNT < 160);
}

void Display_SetMode(u32 mode) {
    REG_DISPCNT = mode;
}

/*
 * Input
 */
u32 Input_Read(void) {
    return REG_KEYINPUT;
}

/*
 * Timer
 */
u32 Timer_Get(void) {
    return *(volatile u32*)0x04000100;
}

/*
 * DMA Transfer
 */
void DMA_Transfer(void *src, void *dst, u32 count) {
    *(volatile u32*)0x040000D4 = (u32)src;
    *(volatile u32*)0x040000D8 = (u32)dst;
    *(volatile u32*)0x040000DC = count;
}

/*
 * Palette
 */
void Palette_SetColor(u32 index, u16 color) {
    *(volatile u16*)(0x05000000 + index * 2) = color;
}

/*
 * Sound stubs
 */
void Sound_Play(void) {
    /* stub */
}

void Sound_StopAll(void) {
    /* stub */
}

/*
 * Random number generator
 */
static u32 rng_seed = 0x12345678;

u32 Random_Get(void) {
    rng_seed = rng_seed * 1103515245 + 12345;
    return rng_seed >> 16;
}

/*
 * Memory functions
 */
void Memory_Set(u8 *dst, u8 val, u32 count) {
    u32 i;
    for (i = 0; i < count; i++) {
        dst[i] = val;
    }
}

void Memory_Copy(u8 *dst, u8 *src, u32 count) {
    u32 i;
    for (i = 0; i < count; i++) {
        dst[i] = src[i];
    }
}

