//These are the coordinates of the player.
I64 x = 0, y = GR_HEIGHT / 2;

/*This is a FIFO (first-in first-out) data structure
which keeps track of bullets.  When a new bullet is
fired, the bullets_in val is increased by one.
When a bullet expires, the bullets_out value is increased
by one.  The in and out values loop-around, back to
the start of the arrays.    It is known as a ring-buffer.
*/
#define BULLETS_NUM 32
I64 bullets_in = 0, bullets_out = 0, bx[BULLETS_NUM], by[BULLETS_NUM];

//This is a fifo which keeps track of the bad guys.
#define DEAD_NUM 32
I64  dead_in = 0, dead_out = 0, gx[DEAD_NUM], gy[DEAD_NUM];
Bool g_dead[DEAD_NUM];

/*This is a sprite created and edited by pressing
<CTRL-r>.  When created, they are assigned
a num.  Press <CTRL-t>, to see the hidden DolDoc
place holder for the sprite.    The text in quotes
can be set to whatever you want or nothing,
but the ending num can't be changed.    It
is controled by the editor.
*/
<1>/* Graphics Not Rendered in HTML */



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


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




//Called by the Window Mgr system task 60fps.
//The task arg is the task owning the window.
U0 DrawIt(CTask *task, CDC *dc)
{
    I64 i, j;
    //<CTRL-t> now to see the DolDoc place holder
    //where the sprite num is encoded. $IB...$ stands
    //for "insert pointer to binary object".
    Sprite3(dc, x, y, 0, <1>);

    i = bullets_out;
    while (i != bullets_in)
    {
        j = i++ & (BULLETS_NUM - 1);
        GrLine(dc, bx[j], by[j], bx[j] - 2, by[j]);
    }
    i = dead_out;
    while (i != dead_in)
    {
        j = i++ & (BULLETS_NUM - 1);
        if (!g_dead[j])
        {
            if (gx[j] % 10 > 4)
                Sprite3(dc, gx[j], gy[j], 0, <2>);
            else
                Sprite3(dc, gx[j], gy[j], 0, <3>);
        }
    }
    dc->color = BLACK;
    GrPrint(dc, 0, 0,           "If you aspire to making games,");
    GrPrint(dc, 0, FONT_HEIGHT, "you must learn to make-up rules.");
}

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

U0 TheDead()
{
    I64  i, j, i1, j1, k = 0, sc = 0, ch = 0, message_code, arg1, arg2;
    Bool gun_on = FALSE;

    MenuPush(   "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Fire(,CH_SPACE);"
                "  Up(,,SC_CURSOR_UP);"
                "  Down(,,SC_CURSOR_DOWN);"
                "}"
                );
    SettingsPush; //See SettingsPush
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    DocClear;
    Fs->song_task   = Spawn(&SongTask, NULL, "Song",, Fs);
    Fs->draw_it     = &DrawIt;

    try
    {
        do
        {
            if (message_code = MessageScan(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_KEY_UP))
            {
                //With keyboard messages, the two message args
                //are the scan code and ascii value for the key.
                sc = arg2;
                ch = arg1;

                if (message_code == MESSAGE_KEY_DOWN)
                {
                    //The low byte of the scan code identifies the key.
                    if (sc.u8[0] == SC_CURSOR_DOWN)
                    {
                        y += 10;
                        if (y > GR_HEIGHT - 30)
                            y = GR_HEIGHT - 30;
                    }
                    else if (sc.u8[0] == SC_CURSOR_UP)
                    {
                        y -= 10;
                        if (y < 0)
                            y = 0;
                    }
                    else if (sc.u8[0] == SC_CURSOR_RIGHT || ch == CH_SPACE)
                        gun_on = TRUE;
                }
                else if (message_code == MESSAGE_KEY_UP)
                {
                    if (sc.u8[0] == SC_CURSOR_RIGHT || ch == CH_SPACE)
                        gun_on = FALSE;
                }
            }

            i = bullets_out;
            while (i != bullets_in)
            {
                j = i++ & (BULLETS_NUM - 1);
                bx[j] += 5;
                if (bx[j] > GR_WIDTH)
                    bullets_out++;
                else
                {
                    i1 = dead_out;
                    while (i1 != dead_in)
                    {
                        j1 = i1++ & (DEAD_NUM - 1);
                        if (gy[j1] <= by[j] <= gy[j1] + 38 && gx[j1] <= bx[j] <= gx[j1] + 40)
                            g_dead[j1] = TRUE;
                    }
                }
            }

            if (gun_on)
            {
                j = bullets_in & (BULLETS_NUM - 1);
                bx[j] = x + 32;
                by[j] = y + 14;
                bullets_in++;
            }

            //Runs one out of four passes through this loop.
            if (!(k % 4))
            {
                i = dead_out;
                while (i != dead_in)
                {
                    j = i++ &(DEAD_NUM - 1);
                    gx[j] -= 1;
                    if (gx[j] < 25)
                        dead_out++;
                }
            }

            //Runs one out of 150 passes through this loop.
            if (!(k % 150))
            {
                j = dead_in & (DEAD_NUM - 1);
                gx[j] = GR_WIDTH - 30;
                gy[j] = RandU32 % (GR_HEIGHT - 50) + 25;
                g_dead[j] = FALSE;
                dead_in++;
            }
            k++;

            Sleep(10); //Swap this task out for 10 miliseconds.
        }
        while (ch != CH_ESC && ch != CH_SHIFT_ESC);

    }
    catch
        PutExcept;
    SettingsPop;
    MenuPop;
}

TheDead; //Run program when #included