#include "game_types.h"

/* Coroutine dispatcher, extended skeleton (InitThree shape, 3 args): frame
   setup with null-guard, Resolve/Swap rounds, mid dispatch, FreeObject3
   rounds. Threads x[] = {b, B98, ...} then {?, B80, c}. Block live-ins on
   the first pass are (a, fr); scheduler re-entry supplies resume state. */
/* Collision_CircleTest @ 0x08016BC0 (real 448B) -- circle-test dispatch threading (b, c). Mirrors src/matched/Collision_CircleTest.c. */
extern int *Mem_GetStackFrame(void);
extern int *Mem_GetStackFrame_08015DC8(void);
extern int Collision_Resolve(int *a, int b);
extern void Mem_Swap(int *a, int *b);
extern void Mem_PopStack(void);
extern void Mem_PushStack(void);
extern void Mem_FreeObject3(int a, int b);

typedef struct {
    int link;
    int zero;
    int *self;
    int resume;
    int *sp;
} Frame;

void Collision_CircleTest(int *a, int *b, int c)
{
    int *fr = Mem_GetStackFrame();
    Frame blk;
    int *fr2;
    int *x = a, *y = fr; /* block-3 live-ins on the first pass */
    /* block 0, resumes at 0x08016BF4 */
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016BF4;
    blk.sp = (int *)&blk;
    fr[1] = (int)&blk;
    fr[1] = *(int *)fr[1];
    /* block 1 (second frame), resumes at 0x08016C24 */
    fr2 = Mem_GetStackFrame_08015DC8();
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016C24;
    blk.sp = (int *)&blk;
    fr[1] = (int)&blk + 24;
    {
        int slot[6];
        slot[0] = (int)&blk + 48;
        Collision_Resolve(slot, 0);
    }
    /* block 2, resumes at 0x08016C50 */
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016C50;
    blk.sp = (int *)&blk;
    fr[1] = (int)&blk + 48;
    Mem_Swap(fr2, fr + 1);
    fr[1] = *(int *)fr[1];
    Mem_PopStack();
    Mem_PushStack();
    if (a == 0)
        return;
    /* block 3: data word + b through (x, y), resumes at 0x08016CA4 */
    x[1] = 0x02000BE0;
    x[0] = (int)b;
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016CA4;
    blk.sp = (int *)&blk;
    y[1] = (int)&blk;
    fr2[1] = 0x02000B98;
    fr[1] = *(int *)fr[1];
    /* block 4, resumes at 0x08016CD8 */
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016CD8;
    blk.sp = (int *)&blk;
    fr[1] = (int)&blk + 120;
    Mem_FreeObject3((int)x, 0);
    fr[1] = *(int *)fr[1];
    Mem_PopStack();
    Mem_PushStack();
    /* block 5 (do-block of the 0x08016D18 descriptor): thread and exit */
    x[1] = 0x02000B80;
    x[2] = c;
    fr[1] = *(int *)fr[1];
    /* block 6, resumes at 0x08016D58: frees x once more, then exits */
    blk.link = fr[1];
    blk.zero = 0;
    blk.self = (int *)&blk;
    blk.resume = 0x08016D58;
    blk.sp = (int *)&blk;
    fr[1] = (int)&blk + 144;
    Mem_FreeObject3((int)x, 0);
    fr[1] = *(int *)fr[1];
    Mem_PopStack();
    Mem_PushStack();
}
