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;