#define ROAD_NUM        512
#define ROAD_WIDTH_BY_2 200
#define CAR_WIDTH_BY_2  100

I64  road_x[ROAD_NUM], road_trend;
F64  speed, distance;
I64  road_ptr = 0, car_x;
F64  t_last;
Bool crash;

U0 DrawIt(CTask *task, CDC *dc)
{
    I64 w = task->pix_width, h = task->pix_height;
    I64 i, x, y, xx;

    xx = w >> 1 - car_x + road_x[road_ptr & (ROAD_NUM - 1)];

    dc->color = LTGRAY;
    for (i = 0; i < ROAD_NUM; i++)
    {
        x = w >> 1 - car_x + road_x[(i + road_ptr) & (ROAD_NUM - 1)];
        y = h - 0.5 * i;
        if (y < (h + FONT_HEIGHT) >> 1)
            break;
        GrPlot(dc, x + ROAD_WIDTH_BY_2 - 0.4 * i, y);
        GrPlot(dc, x - ROAD_WIDTH_BY_2 + 0.4 * i, y);
    }
    dc->color = WHITE;

    x = w >> 1 - CAR_WIDTH_BY_2;
    if (x < xx - ROAD_WIDTH_BY_2)
        crash = TRUE;
    GrLine(dc, x - 10, h, x - 40, h - 100);
    GrLine(dc, x + 10, h, x + 40, h - 100);

    x = w >> 1 + CAR_WIDTH_BY_2;
    if (x > xx + ROAD_WIDTH_BY_2)
        crash = TRUE;
    GrLine(dc, x - 10, h, x - 40, h - 100);
    GrLine(dc, x + 10, h, x + 40, h - 100);

    dc->color = YELLOW;
    if (crash)
        GrPrint(dc, w >> 1 - FONT_WIDTH * 4, (h - FONT_HEIGHT) >> 1, "Game Over");
}

U0 UpdateRoad()
{
    F64 t0 = tS;

    distance += speed * (t0 - t_last);
    t_last = t0;
    while (distance > 1.0)
    {
        road_trend = ClampI64(road_trend + SignI64(RandU16 % 3 - 1), -5, 5);
        road_x[road_ptr & (ROAD_NUM - 1)] = road_x[(road_ptr - 1) & (ROAD_NUM - 1)] += road_trend / 3;
        road_ptr++;
        distance -= 1.0;
    }
}

U0 Init()
{
    I64 i, x = 0;

    DocClear;
    "$BG,DKGRAY$%h*c", (TEXT_ROWS - 1) / 2, '\n';
    speed = 0;
    distance = 0;
    road_trend = 0;
    road_ptr = 0;
    car_x = 0;
    for (i = 0; i < ROAD_NUM; i++)
    {
        road_x[i] = x;
        road_trend = ClampI64(road_trend + SignI64(RandU16 % 3 - 1), -5, 5);
        x += road_trend / 3;
    }
    t_last = tS;
    crash = FALSE;
}

U0 Halogen()
{
    I64 arg1, arg2, ch=0, sc=0;
    SettingsPush; //See SettingsPush
    Fs->text_attr = BLACK << 4 + WHITE;
    MenuPush(   "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Restart(,'\n');"
                "  Accelerate(,,SC_CURSOR_UP);"
                "  Deccellerate(,,SC_CURSOR_DOWN);"
                "  Left(,,SC_CURSOR_LEFT);"
                "  Right(,,SC_CURSOR_RIGHT);"
                "}"
                );
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    Init;
    Fs->draw_it = &DrawIt;
    try
    {
        while (TRUE)
        {
            switch (MessageScan(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_KEY_UP))
            {
                case MESSAGE_KEY_DOWN:
                    ch = arg1;
                    sc = arg2;
                    switch (ch)
                    {
                        case '\n':
                            Init;
                            break;

                        case CH_ESC:
                        case CH_SHIFT_ESC:
                            goto ha_done;
                    }
                    break;
                case MESSAGE_KEY_UP:
                    ch = arg1;
                    sc = arg2;
                    if (!ch)
                        switch (sc.u8[0])
                        {
                            case SC_CURSOR_RIGHT:
                            case SC_CURSOR_LEFT:
                            case SC_CURSOR_UP:
                            case SC_CURSOR_DOWN:
                                sc = 0;
                                break;
                        }
                    break;
            }
            switch (sc.u8[0])
            {
                case SC_CURSOR_RIGHT:
                    car_x++;
                    break;

                case SC_CURSOR_LEFT:
                    car_x--;
                    break;

                case SC_CURSOR_UP:
                    if (++speed > 200)
                        speed = 200;
                    break;

                case SC_CURSOR_DOWN:
                    if (--speed < 0)
                        speed = 0;
                    break;
            }
            if (crash)
                Sound;
            else
            {
                if (speed)
                    Sound(Freq2Ona(speed + 10));
                else
                    Sound;
                UpdateRoad;
            }
            Sleep(10);
        }
ha_done:
        MessageGet(,, 1 << MESSAGE_KEY_UP);
    }
    catch
        PutExcept;
    MenuPop;
    DocClear;
    SettingsPop;
}

Halogen;