/*Sprites were created with <CTRL-r>
and can be edited by moving the
cursor on top and pressing <CTRL-r>.

<CTRL-t> to see the num of the sprite
and <CTRL-t> again to get back.  Nums
are assigned by the editor.
*/







                <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 */



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

//See ::/Doc/Credits.DD.



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






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








































































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

RegDefault("ZealOS/BlackDiamond", "I64 best_score=9999;\n");
RegExe("ZealOS/BlackDiamond");

#define MAP_HEIGHT      3000
#define OBJS_NUM        128

I64  x, y, screen_top_y, penalty, chair_lift_num;
I64  obj_x[OBJS_NUM], obj_y[OBJS_NUM], obj_types[OBJS_NUM], obj_saved_x[OBJS_NUM], obj_saved_y[OBJS_NUM];
Bool game_over;

#define T_TREE          0
#define T_LITTLE_ROCK   1
#define T_BIG_ROCK      2
#define T_WOLF          3
#define T_CHAIR_LIFT    4
U8 *imgs[5] = {<3>, <4>, <5>, <6>, <9>};

#define DC_WOLF_WIDTH   48
#define DC_WOLF_HEIGHT  38
U0 DrawRunningWolf(CDC *dc, I64 i)
{//Draw wolf on small DC so bottom gets clipped looking like sunk into snow.
//Then, copy onto main DC.
    U8  *tmps;
    CDC *dc_wolf = DCNew(DC_WOLF_WIDTH, DC_WOLF_HEIGHT);

    DCFill(dc_wolf);
    if (x < obj_x[i])
    {
        dc_wolf->flags |= DCF_SYMMETRY | DCF_TRANSFORMATION | DCF_JUST_MIRROR;
        DCSymmetrySet(dc_wolf, DC_WOLF_WIDTH / 2, 0, DC_WOLF_WIDTH / 2, 1);
    }
    if (tS % 1.0 < 0.5)
        tmps = <6>;
    else
        tmps = <7>;
    Sprite3ZB(dc_wolf, DC_WOLF_WIDTH / 2, 0.85 * DC_WOLF_HEIGHT, 0, tmps, 0.4 * Sin(7 * tS));
    GrBlot(dc, obj_x[i] - DC_WOLF_WIDTH / 2, obj_y[i] - screen_top_y - 0.85 * DC_WOLF_HEIGHT, dc_wolf);
    DCDel(dc_wolf);
    if (0 <= (obj_y[i] - screen_top_y) < GR_HEIGHT)
        obj_x[i] += 3 * SignI64(x - obj_x[i]);
}

U0 DrawMan(CDC *dc)
{
    if (dc->collision_count)
        Sprite3(dc, x, y - screen_top_y, 0, <2>); //Red man
    else
        Sprite3(dc, x, y - screen_top_y, 0, <1>); //Normal man
}

#define WIRE_HEIGHT         595
#define WIRE_WIDTH          121
#define WIRE_DIP            800
#define PULLY_WIDTH         13
U0 DrawUpperChairLift(CDC *dc)
{
    I64 i = chair_lift_num, x, x1, y = obj_y[i] - screen_top_y - WIRE_HEIGHT, y1;

    Sprite3(dc, obj_x[i], y + 13, 0, <8>);
    dc->thick = 2;
    for (x = -WIRE_WIDTH / 2; x < GR_WIDTH + WIRE_WIDTH / 2; x += 2)
    { //Pen width is 2, step 2.
        x1 = x - obj_x[i];
        y1 = y - WIRE_DIP / 2 + Cosh(Ln(WIRE_DIP) + (Abs(x1) - PULLY_WIDTH) / 10000.0) + 0.1 * x1;
        if (!(-PULLY_WIDTH < x1 < PULLY_WIDTH))
        {
            GrPlot3(dc, x - WIRE_WIDTH / 2, y1, 0);
            GrPlot3(dc, x + WIRE_WIDTH / 2, y1, 0);
        }
    }
    dc->thick = 1;
}

U0 DrawIt(CTask *, CDC *dc)
{
    I64  i;
    Bool man_drawn = FALSE;

    for (i = 0; i < OBJS_NUM; i++)
        if (obj_y[i] - 32 <= y <= obj_y[i])
        {
            if (obj_types[i] == T_WOLF && AbsI64(x - obj_x[i]) > 3)
                DrawRunningWolf(dc, i);
            else
                Sprite3(dc, obj_x[i], obj_y[i] - screen_top_y, 0, imgs[obj_types[i]]);
        }

    dc->collision_count = 0;
    dc->color           = ROP_COLLISION;
    dc->bkcolor         = WHITE;
    Sprite3(dc, x, y - screen_top_y, 0, <1>);
    if (!game_over)
    {
        if (dc->collision_count)
        {
            Sound(58);
            penalty++; //Time is irregular. Scoring is imperfect. 60fps more or less.
        }
        else
            Sound;
    }

    dc->color = ROP_EQU;
    for (i = 0; i < OBJS_NUM; i++)
    {
        if (!man_drawn && obj_y[i] >= y)
        {
            DrawMan(dc);
            man_drawn = TRUE;
        }
        if (obj_types[i] == T_WOLF && AbsI64(x - obj_x[i]) > 3)
            DrawRunningWolf(dc, i);
        else
            Sprite3(dc, obj_x[i], obj_y[i] - screen_top_y, 0, imgs[obj_types[i]]);
    }
    if (!man_drawn)
        DrawMan(dc);
    DrawUpperChairLift(dc);

    dc->color = BLACK;
    GrPrint(dc, 0, 0, "Penalty:%d Best:%d", penalty, best_score);
    if (game_over && Blink) {
        dc->color = RED;
        GrPrint(dc, (Fs->pix_width - 9 * FONT_WIDTH) / 2, (Fs->pix_height - FONT_HEIGHT) / 2, "Game Over");
    }
}

I64 Compare(I64 e1, I64 e2)
{
    return e1 - e2;
}

U0 Init()
{
    I64 i, j;

    for (i = 0; i < OBJS_NUM; i++)
    {
        obj_saved_y[i] = RandU32 % MAP_HEIGHT;
        obj_saved_x[i] = RandU32 % GR_WIDTH;
        j = RandU16;
        if (j & 7)
            obj_types[i] = T_TREE;
        else if (j & 31)
            obj_types[i] = T_LITTLE_ROCK;
        else if (j & 63)
            obj_types[i] = T_BIG_ROCK;
        else
            obj_types[i] = T_WOLF;
    }
    QuickSortI64(obj_saved_y, OBJS_NUM, &Compare); //Break associations. Doesn't matter.

    chair_lift_num = RandU16 % OBJS_NUM;
    obj_types[chair_lift_num] = T_CHAIR_LIFT;
}

U0 BlackDiamond()
{
    I64 ch, sc;

    MenuPush(
                "File {"
                "  New(,'\n');"
                "  Restart(,CH_SPACE);"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Up(,,SC_CURSOR_UP);"
                "  Down(,,SC_CURSOR_DOWN);"
                "  Left(,,SC_CURSOR_LEFT);"
                "  Right(,,SC_CURSOR_RIGHT);"
                "}"
                );
    SettingsPush; //See SettingsPush
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    DocClear;
    Fs->draw_it = &DrawIt;

    Init;
    try
    {
        while (TRUE)
        {
bd_restart:
            MemCopy(obj_x, obj_saved_x, sizeof(obj_x)); //Wolves move. We must reset the
            MemCopy(obj_y, obj_saved_y, sizeof(obj_y)); //wolves if running same game.

            game_over = FALSE;
            screen_top_y = 0;
            x = Fs->pix_width >> 1;
            y = 0;
            penalty = 0;
            while (TRUE)
            {
                if (KeyScan(&ch, &sc))
                {
                    switch (ch)
                    {
                        case 0:
                            if (!game_over)
                                switch (sc.u8[0])
                                {
                                    case SC_CURSOR_RIGHT:
                                        x += 10;
                                        if (x >= Fs->pix_width)
                                            x -= Fs->pix_width;
                                        break;

                                    case SC_CURSOR_LEFT:
                                        x -= 10;
                                        if (x < 0)
                                            x += Fs->pix_width;
                                        break;

                                    case SC_CURSOR_UP:
                                        y -= 10;
                                        break;

                                    case SC_CURSOR_DOWN:
                                        y += 10;
                                        break;
                                }
                            break;

                        case CH_ESC:
                        case CH_SHIFT_ESC:
                            goto bd_done;

                        case '\n':
                            Init;
                            goto bd_restart;

                        case CH_SPACE:
                            game_over = TRUE;
                            while (screen_top_y > 0 || y > 0)
                            {//Animate going back to top.
                                screen_top_y = MaxI64(0, screen_top_y - 4);
                                y = MaxI64(0, y - 4);
                                x += SignI64(Fs->pix_width >> 1 - x);
                                Sleep(1);
                            }
                            Sound;
                            goto bd_restart;
                    }
//Don't want keystrokes building-up in the buf.
                    FlushMessages;
                }
                if (!game_over)
                {
                    y += 2;
                    screen_top_y++;
                    if (y - screen_top_y > Fs->pix_height)
                    {//Animate scrolling screen.
                        while (y - screen_top_y > Fs->pix_height >> 1)
                        {
                            screen_top_y += 2;
                            Sleep(1);
                        }
                    }
                    if (y >= MAP_HEIGHT)
                    {
                        game_over = TRUE;
                        Beep;
                        if (penalty <= best_score)
                        {
                            best_score = penalty;
                            Beep;
                        }
                    }
                }
                Sleep(10);
            }
        }
bd_done:
    }
    catch
        PutExcept;
    SettingsPop;
    MenuPop;
    RegWrite("ZealOS/BlackDiamond", "I64 best_score=%d;\n", best_score);
}

BlackDiamond; //Start game when #included.