RegDefault("ZealOS/ZoneOut", "F64 best_score=9999;\n");
RegExe("ZealOS/ZoneOut");










                                <1>/* Graphics Not Rendered in HTML */
























                                <2>/* Graphics Not Rendered in HTML */













                                     <3>/* Graphics Not Rendered in HTML */

/* Graphics Not Rendered in HTML */










#define THEM_NUM                10

class Obj
{
    Obj *next, *last;
    F64  t0, theta;
    I64  x, y, z;
    Bool hit, pad[7];

} us, them[THEM_NUM], shots;

I64 num_them;
F64 t0, tf;

#define SCREEN_SCALE        512
#define TANK_HEIGHT         32

U0 ZOTransform(CDC *dc, I64 *x, I64 *y, I64 *z)
{
    I64 zz;

    Mat4x4MulXYZ(dc->r, x, y, z);
    zz = *z;
    if (zz < 1)
        zz = 1;
    *x = SCREEN_SCALE / 2 * *x / zz;
    *y = SCREEN_SCALE / 2 * (*y + TANK_HEIGHT) / zz;
    *x += dc->x;
    *y += dc->y;
    *z += dc->z;
}

U0 DrawIt(CTask *task, CDC *dc)
{
    Obj *tmpo;
    I64  i, dd, y, w = task->pix_width, h = task->pix_height, cx = w >> 1, cy = h >> 1;
    U8  *img;
    F64  tt, theta;

    theta = 640 * Wrap(2 * us.theta) / pi;
    Sprite3(dc, theta - 1280, 90, 0, <4>);
    Sprite3(dc, theta,    90, 0, <4>);
    Sprite3(dc, theta + 1280, 90, 0, <4>);

    DCDepthBufAlloc(dc);
    dc->transform   = &ZOTransform;
    dc->x           = cx;
    dc->y           = cy;
    Mat4x4TranslationEqu(dc->r, -us.x, -us.y, -us.z);
    Mat4x4RotY(dc->r, us.theta - pi / 2);
    Mat4x4RotX(dc->r, pi / 16);

    dc->flags |= DCF_TRANSFORMATION;
    for (i = 0; i < THEM_NUM; i++)
    {
        y = them[i].y;
        tmpo = shots.next;
        while (tmpo != &shots)
        {
            dd = SqrI64(them[i].x - tmpo->x) + SqrI64(them[i].z - tmpo->z);
            if (dd < SCREEN_SCALE / 2 * SCREEN_SCALE / 2)
            {
                y -= Sqrt(dd);
                if (!them[i].hit)
                {
                    them[i].hit = TRUE;
                    if (!--num_them)
                    {
                        tf = tS;
                        if (tf - t0 < best_score)
                            best_score = tf - t0;
                    }
                }
            }
            tmpo = tmpo->next;
        }
        if (them[i].hit)
            img = <2>;
        else
            img = <1>;
        Sprite3YB(dc, them[i].x, y, them[i].z, img, -them[i].theta);
    }
    tmpo = shots.next;
    while (tmpo != &shots)
    {
        Sprite3YB(dc, tmpo->x, tmpo->y, tmpo->z, <3>, -tmpo->theta);
        tmpo = tmpo->next;
    }
    dc->flags &= ~DCF_TRANSFORMATION;
    dc->color = LTGREEN;
    GrLine(dc, cx - 5, cy, cx + 5, cy);
    GrLine(dc, cx, cy - 5, cx, cy + 5);
    if (tf)
    {
        dc->color = RED;
        if (Blink)
            GrPrint(dc, cx - (FONT_WIDTH * 14) / 2, cy - FONT_HEIGHT / 2, "Game Completed");
        tt = tf;
    }
    else
    {
        dc->color = BLACK;
        GrLine(dc, cx - 5, cy, cx + 5, cy);
        GrLine(dc, cx, cy - 5, cx, cy + 5);
        tt = tS;
    }
    dc->color = BLACK;
    GrPrint(dc, 0, 0, "Enemy:%d Time:%3.2f Best:%3.2f", num_them, tt - t0, best_score);
}

U0 Fire()
{
    Obj *tmpo = MAlloc(sizeof(Obj));

    tmpo->x  = us.x;
    tmpo->y  = TANK_HEIGHT;
    tmpo->z  = us.z;
    tmpo->theta  = us.theta;
    tmpo->t0 = tS;
    QueueInsert(tmpo, shots.last);
}

U0 MoveUs(F64 theta)
{
    us.x += 0.1 * SCREEN_SCALE * Cos(theta);
    us.z += 0.1 * SCREEN_SCALE * Sin(theta);
}

U0 AnimateTask(I64)
{
    I64  i;
    Obj *tmpo, *tmpo1;

    while (TRUE)
    {
        for (i = 0; i < THEM_NUM; i++)
        {
            them[i].x += SCREEN_SCALE / 32 * Cos(them[i].theta);
            them[i].z += SCREEN_SCALE / 32 * Sin(them[i].theta);
            them[i].theta += Rand / 100.0;
        }
        tmpo = shots.next;
        while (tmpo != &shots)
        {
            tmpo1 = tmpo->next;
            if (tS - tmpo->t0 > 1.0)
            {
                QueueRemove(tmpo);
                Free(tmpo);
            }
            else
            {
                tmpo->x += 0.25 * SCREEN_SCALE  *Cos(tmpo->theta);
                tmpo->z += 0.25 * SCREEN_SCALE * Sin(tmpo->theta);
            }
            tmpo = tmpo1;
        }
        Sleep(20);
    }
}

U0 Init()
{
    I64 i;

    DocClear;
    "$BG, LTCYAN$%h12c", '\n';
    QueueInit(&shots);
    MemSet(&us, 0, sizeof(us));
    MemSet(them, 0, sizeof(them));
    num_them = THEM_NUM;
    for (i = 0; i < THEM_NUM; i++)
    {
        them[i].x   = 10000 * Rand - 5000;
        them[i].z   = 10000 * Rand - 5000;
        them[i].theta   = 2 * pi * Rand;
        them[i].hit = FALSE;
    }
    tf = 0;
    t0 = tS;
}

U0 CleanUp()
{
    QueueDel(&shots, TRUE);
}

U0 SongTask(I64)
{//Randomly generate (by God :-)
    Fs->task_end_cb = &SoundTaskEndCB;
    MusicSettingsReset;
    while (TRUE)
    {
        Play("5sD4B5D4B5qEsG4B5G4B5eD4GsB5F4B5FeD4A5qFG");
        Play("5sD4B5D4B5qEsG4B5G4B5eD4GsB5F4B5FeD4A5qFG");
        Play("5eGDsFGFGqDE4eB5E4sG5D4G5DqF4sGAGA");
        Play("5eGDsFGFGqDE4eB5E4sG5D4G5DqF4sGAGA");
    }
}

U0 ZoneOut()
{
    I64 sc;

    PopUpOk(    "Terry refused to rip-off the original\n"
                "so this is intentionally crappy\n"
                "and included for demonstration\n"
                "purposes.\n\n"
                "Write games, don't play them.\n");

    MenuPush(   "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Restart(,'\n');"
                "  Fwd(,,SC_CURSOR_UP);"
                "  Bwd(,,SC_CURSOR_DOWN);"
                "  Left(,,SC_CURSOR_LEFT);"
                "  Right(,,SC_CURSOR_RIGHT);"
                "  Fire(,CH_SPACE);"
                "}"
                );

    SettingsPush; //See SettingsPush
    Fs->text_attr = YELLOW << 4 + WHITE;
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    Init;
    Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs);
    Fs->song_task    = Spawn(&SongTask, NULL, "Song",, Fs);
    Fs->draw_it      = &DrawIt;
    try
    {
        while (TRUE)
        {
            switch (KeyGet(&sc))
            {
                case CH_SPACE:
                    Fire;
                    break;

                case '\n':
                    CleanUp;
                    Init;
                    break;

                case CH_ESC:
                case CH_SHIFT_ESC:
                    goto zo_done;

                case 0:
                    switch (sc.u8[0])
                    {
                        case SC_CURSOR_RIGHT:
                            us.theta -= pi / 256;
                            break;

                        case SC_CURSOR_LEFT:
                            us.theta += pi / 256;
                            break;

                        case SC_CURSOR_UP:
                            MoveUs(us.theta);
                            break;

                        case SC_CURSOR_DOWN:
                            MoveUs(us.theta + pi);
                            break;
                    }
                    break;
            }
        }
zo_done:
    }
    catch
        PutExcept;
    CleanUp;
    DocClear;
    SettingsPop;
    MenuPop;
    RegWrite("ZealOS/ZoneOut", "F64 best_score=%5.4f;\n", best_score);
}

ZoneOut;