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






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


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





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


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


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




#define BORDER          6
#define EAT_TIME        0.5
#define FLAP_TIME       0.5
#define BAT_BOX         10

Bool flap_down, flap_up;
F64  flap_phase, delta_phase, bat_y, bat_x, eat_timeout, flap_time;
F64  frame_x, game_t0, game_tf;

#define BUGS_NUM        32
I32  bug_count, bugs_x[BUGS_NUM], bugs_y[BUGS_NUM];
Bool bugs_dead[BUGS_NUM];

#define GLOW_PERIOD     3.0
F64 bugs_glow_phase[BUGS_NUM];

CDC *limit_flood_fill_dc; //Prevent uncontrolled flood-fill flicker.

U0 DrawIt(CTask *task, CDC *dc)
{
    I64 i, y, x, 
        h = MaxI64(1, task->pix_width  - 2 * BORDER), 
        v = MaxI64(1, task->pix_height - 2 * BORDER);
    U8 *tmps, *tmps2, *tmps3;
    F64 tt = flap_phase * flap_phase * flap_phase, ts = tS;

    bat_x = task->pix_width >> 3;
    Sprite3(dc, (7 * task->pix_width) >> 3, 20, 0, <5>);

    dc->color = DKGRAY;
    GrCircle(dc, bat_x + 5 + 20 * Saw(15 * tS, 2), bat_y, 10 + 20 * Saw(15 * tS, 2), 5, -pi/4, pi/2);

    tmps = SpriteInterpolate(tt, <1>, <2>);
    if (eat_timeout && tS < eat_timeout)
    {
        tmps2 = SpriteInterpolate(tt, <3>, <4>);
        tmps3 = SpriteInterpolate(1.0 - (eat_timeout - tS) / EAT_TIME, tmps2, tmps);
        Free(tmps);
        Free(tmps2);
        tmps = tmps3;
    }

    DCFill(limit_flood_fill_dc);
    Sprite3(limit_flood_fill_dc, 16, 32, 0, tmps);

    if (GrPeek(limit_flood_fill_dc, 0, 0) != TRANSPARENT)
    {//Did FloodFill go crazy?
        limit_flood_fill_dc->color = TRANSPARENT;
        GrFloodFill(limit_flood_fill_dc, 0, 0);
    }
    GrBlot(dc, bat_x - 16, bat_y - 32, limit_flood_fill_dc);

    Free(tmps);

    for (i = 0; i < BUGS_NUM; i++)
        if (!bugs_dead[i])
        {
            x = (bugs_x[i] + frame_x) % h + BORDER;
            y = bugs_y[i] % v + BORDER;
            if (Saw(ts + bugs_glow_phase[i], GLOW_PERIOD) < 0.2)
            {
                if (i & 1)
                    dc->color = YELLOW;
                else
                    dc->color = LTGREEN;
            }
            else
                dc->color = BLACK;
            GrPlot(dc, x, y);
            GrPlot(dc, x + 1, y);
            dc->color = BLACK;
            GrPlot(dc, x, y - 1);
        }
    if (game_tf)
    {
        dc->color = RED;
        GrPrint(dc, (task->pix_width - FONT_WIDTH * 14) / 2, (task->pix_height - FONT_HEIGHT) / 2, "Game Completed");
        tt = game_tf;
    }
    else
    {
        dc->color = BLACK;
        tt = tS;
    }
    GrPrint(dc, 0, 0, "Bugs:%3.1f%% Time:%3.2f Best:%3.2f",
                        100.0 * (BUGS_NUM - bug_count) / BUGS_NUM, tt-game_t0, best_score);
}

U0 CheckBugs(CTask *task)
{
    I64 i, x, y, 
        h = MaxI64(1, task->pix_width  - 2 * BORDER), 
        v = MaxI64(1, task->pix_height - 2 * BORDER);

    if (eat_timeout && eat_timeout - tS < 0.75 * EAT_TIME)
    {
        Suspend(task->song_task, FALSE);
        if (tS >= eat_timeout)
            eat_timeout = 0;
    }
    for (i = 0; i < BUGS_NUM; i++)
        if (!bugs_dead[i])
        {
            x = (bugs_x[i] + frame_x) % h + BORDER;
            y = bugs_y[i] % v + BORDER;
            if (AbsI64(x - bat_x) < BAT_BOX && AbsI64(y - bat_y) < BAT_BOX)
            {
                bugs_dead[i] = TRUE;
                eat_timeout = tS + EAT_TIME;
                Sound(74);
                Suspend(task->song_task);
                bug_count--;
            }
        }
    if (!game_tf && !bug_count)
    {
        game_tf = tS;
        Suspend(task->song_task);
        Sound;
        if (game_tf - game_t0 < best_score)
            best_score = game_tf - game_t0;
    }
    frame_x -= 0.1;
    if (frame_x < 0)
        frame_x += h;
}

U0 Init()
{
    I64 i;

    limit_flood_fill_dc = DCNew(32, 40);
    flap_down = flap_up = FALSE;
    flap_phase = 0;
    bat_x = Fs->pix_width >> 3;
    bat_y = 0;
    frame_x = 0;
    bug_count = BUGS_NUM;

    for (i = 0; i < BUGS_NUM; i++)
    {
        bugs_dead[i] = FALSE;
        bugs_x[i] = RandU16;
        bugs_y[i] = RandU16;
        bugs_glow_phase[i] = GLOW_PERIOD * Rand;
    }

    Suspend(Fs->song_task, FALSE);
    flap_time = eat_timeout = 0;
    delta_phase = game_tf = 0;
    game_t0 = tS;
}

U0 SongTask(I64)
{//Song by Terry A. Davis
    Fs->task_end_cb = &SoundTaskEndCB;
    MusicSettingsReset;
    while (TRUE)
    {
        Play("4eB5E4B5C4B5EsEFqE4eB5E4B5C4B5EsEF");
        Play("5qE4eA5D4ABA5DsDCqD4eB5E4B5C4B");
        Play("5EsEDqE");
    }
}

U0 AnimateTask(I64)
{
    while (TRUE)
    {
        if (flap_down)
        {
            flap_down = FALSE;
            delta_phase = -0.005 * Min(1.0, (tS - flap_time) / FLAP_TIME);
            flap_time = tS;
        }
        else if (flap_up)
        {
            flap_up = FALSE;
            delta_phase = 0.005;
        }
        if (delta_phase < 0)
        {
            bat_y += 75 * delta_phase;
            delta_phase += 0.000015;
        }
        else
            bat_y += 0.15;
        bat_y = Clamp(bat_y, BORDER, Fs->parent_task->pix_height - BORDER);
        flap_phase = Clamp(flap_phase + delta_phase, 0.0, 1.0);
        CheckBugs(Fs->parent_task);
        Sleep(1);
    }
}

U0 CleanUp()
{
    DCDel(limit_flood_fill_dc);
}

U0 FlapBat()
{
    Bool reset_space = TRUE;
    I64  arg1, arg2;

    MenuPush(   "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Restart(,'\n');"
                "  Flap(,CH_SPACE);"
                "}"
                );

    PopUpOk("Use $GREEN$<SPACE>$FG$ to flap.\nHold down to glide.");

    SettingsPush; //See SettingsPush
    Fs->text_attr = LTGRAY << 4 + WHITE;
    WinBorder(ON);
    WinHorz(1, TEXT_COLS / 2);
    WinVert(2, TEXT_ROWS / 2);
    DocCursor;
    DocClear;
    Fs->song_task = Spawn(&SongTask, NULL, "Song",, Fs);
    Init;
    Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs);
    Fs->draw_it = &DrawIt;
    try
    {
        while (TRUE)
        {
            switch (MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN + 1 << MESSAGE_KEY_UP))
            {
                case MESSAGE_KEY_DOWN:
                    switch (arg1)
                    {
                        case CH_SPACE:
                            if (reset_space)
                            {
                                flap_down = TRUE;
                                reset_space = FALSE;
                            }
                            break;

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

                        case CH_SHIFT_ESC:
                        case CH_ESC:
                            goto bl_done;
                    }
                    break;

                case MESSAGE_KEY_UP:
                    switch (arg1)
                    {
                        case CH_SPACE:
                            flap_up = TRUE;
                            reset_space = TRUE;
                            break;
                    }
                    break;
            }
        }
bl_done:
        MessageGet(,, 1 << MESSAGE_KEY_UP);
    }
    catch
        PutExcept;
    SettingsPop;
    CleanUp;
    MenuPop;
    RegWrite("ZealOS/FlapBat", "F64 best_score=%5.4f;\n", best_score);
}

FlapBat;