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

//Set snap to 4 and width to 4
//if you edit this map.

//Don't forget to change the
//starting pos.


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

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

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

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

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


//These are indexed by color #.
//See COLORS.

U8 *tiles1[16]={NULL, <7> , <5> , NULL, NULL, NULL, NULL, NULL, <6> , NULL, NULL, NULL, NULL, NULL, NULL, NULL};

U8 *tiles2[16]={NULL, <8> , <5> , NULL, NULL, NULL, NULL, NULL, <6> , NULL, NULL, NULL, NULL, NULL, NULL, NULL};

#define SCREEN_SCALE        24
#define SCREEN_WIDTH        24
#define SCREEN_HEIGHT       24
I64 screen_x, screen_y;

#define MAP_SCALE           4
I64 map_width, map_height;
U8 *map = NULL;

I64  man_x, man_y, man_dx, man_dy;
Bool man_attack;
F64  man_attack_t0;

#define MONSTERS_NUM        10
I64 monsters_left;
class Monster
{
    I64  x, y, dx, dy;
    Bool dead, pad[7];

} monsters[MONSTERS_NUM];

F64 t0, tf;

#define LOS_SCALE           4

Bool LOSPlot(U8 *, I64 x, I64 y, I64)
{
    if (!map[(y / LOS_SCALE) * map_width + (x / LOS_SCALE)])
        return FALSE;
    else
        return TRUE;
}

Bool LOS(I64 x1, I64 y1, I64 x2, I64 y2)
{//Line of sight
    return Line(NULL, x1 * LOS_SCALE + LOS_SCALE / 2, y1 * LOS_SCALE + LOS_SCALE / 2, 0, 
                      x2 * LOS_SCALE + LOS_SCALE / 2, y2 * LOS_SCALE + LOS_SCALE / 2, 0, &LOSPlot);
}

U0 DrawIt(CTask *task, CDC *dc)
{
    CDC     *dc_t = DCAlias(gr.dc2, task);
    I64      i, x, y, xx, yy, x1, y1, z1, color, 
             cx = task->pix_width  / 2, 
             cy = task->pix_height / 2;
    CD3I32   poly[4];
    U8     **_tiles;
    F64      tt;
    Monster *tmpm;

    if (Blink(5))
        _tiles = tiles1;
    else
        _tiles = tiles2;

    Mat4x4RotX(dc_t->r, 60 * 2 * pi / 360);
    Mat4x4RotZ(dc_t->r, 15 * 2 * pi / 360);
    DCMat4x4Set(dc_t, dc_t->r);
    dc_t->x = task->pix_width  / 2;
    dc_t->y = task->pix_height / 2;
    dc_t->flags |= DCF_TRANSFORMATION;

    //You could make it much more efficient
    //if you did it like ::/Demo/Games/BigGuns.ZC
    //with a CDC.

    for (y = -SCREEN_HEIGHT / 2; y < SCREEN_HEIGHT / 2; y++)
    {
        yy = y + screen_y;
        if (0 <= yy < map_height)
            for (x = -SCREEN_WIDTH / 2; x < SCREEN_WIDTH / 2; x++)
            {
                xx = x + screen_x;
                if (0 <= xx < map_width)
                {
                    if ((color = map[yy * map_width + xx]) && LOS(xx, yy, man_x, man_y))
                    {
                        if (_tiles[color])
                        {
                            x1 = x * SCREEN_SCALE;
                            y1 = y * SCREEN_SCALE;
                            z1 = 0;
                            DCTransform(dc_t, &x1, &y1, &z1);
                            Sprite3(dc, x1, y1, z1, _tiles[color]);
                        }
                        else
                        {//If no tile defined, do solid color.
                            poly[0].x = x * SCREEN_SCALE;
                            poly[0].y = y * SCREEN_SCALE;
                            poly[0].z = 0;
                            poly[1].x = (x + 1) * SCREEN_SCALE - 1;
                            poly[1].y = y * SCREEN_SCALE;
                            poly[1].z = 0;
                            poly[2].x = (x + 1) * SCREEN_SCALE;
                            poly[2].y = (y + 1) * SCREEN_SCALE - 1;
                            poly[2].z = 0;
                            poly[3].x = x * SCREEN_SCALE - 1;
                            poly[3].y = (y + 1) * SCREEN_SCALE - 1;
                            poly[3].z = 0;
                            dc_t->color = color;
                            GrFillPoly3(dc_t, 4, poly);
                        }
                    }
                }
            }
    }

    for (y = -SCREEN_HEIGHT / 2; y < SCREEN_HEIGHT / 2; y++)
    {
        yy = y + screen_y;
        if (0 <= yy < map_height)
            for (x = -SCREEN_WIDTH / 2; x < SCREEN_WIDTH / 2; x++)
            {
                xx = x + screen_x;
                if (0 <= xx < map_width)
                {
                    if (!map[yy * map_width + xx])
                    {
                        if (yy + 1 < map_height && LOS(xx, yy + 1, man_x, man_y))
                        {
                            x1 = x * SCREEN_SCALE;
                            y1 = y * SCREEN_SCALE;
                            z1 = 0;
                            DCTransform(dc_t, &x1, &y1, &z1);
                            Sprite3(dc, x1, y1, z1, <9>);
                        }
                        if (xx + 1 < map_width && LOS(xx + 1, yy, man_x, man_y))
                        {
                            x1 = x * SCREEN_SCALE;
                            y1 = y * SCREEN_SCALE;
                            z1 = 0;
                            DCTransform(dc_t, &x1, &y1, &z1);
                            Sprite3(dc, x1, y1, z1, <10>);
                        }
                    }
                }
            }
    }

    for (i = 0, tmpm = monsters; i < MONSTERS_NUM; i++, tmpm++)
        if (!tmpm->dead && LOS(tmpm->x, tmpm->y, man_x, man_y))
        {
            x1 = (tmpm->x - screen_x) * SCREEN_SCALE + SCREEN_SCALE / 2;
            y1 = (tmpm->y - screen_y) * SCREEN_SCALE + SCREEN_SCALE / 2;
            z1 = 0;
            DCTransform(dc_t, &x1, &y1, &z1);
            if (tmpm->dx < 0) {
                dc->flags |= DCF_SYMMETRY|DCF_JUST_MIRROR;
                DCSymmetrySet(dc, x1, y1, x1, y1 + 1);
            }
            else
                dc->flags &= ~(DCF_SYMMETRY | DCF_JUST_MIRROR);
            Sprite3(dc, x1, y1, z1, <4>);
        }

    x1 = (man_x - screen_x) * SCREEN_SCALE + SCREEN_SCALE / 2;
    y1 = (man_y - screen_y) * SCREEN_SCALE + SCREEN_SCALE / 2;
    z1 = 0;
    if (tS - man_attack_t0 < 0.2)
    {
        x1 += Tri(tS - man_attack_t0, 0.2) * SCREEN_SCALE * man_dx;
        y1 += Tri(tS - man_attack_t0, 0.2) * SCREEN_SCALE * man_dy;
        if (man_dy != 1)
            y1 -= Saw(tS - man_attack_t0, 0.2) * SCREEN_SCALE;
    }
    DCTransform(dc_t, &x1, &y1, &z1);
    if (man_dx < 0)
    {
        dc->flags |= DCF_SYMMETRY | DCF_JUST_MIRROR;
        DCSymmetrySet(dc, x1, y1, x1, y1 + 1);
    }
    else
        dc->flags &= ~(DCF_SYMMETRY | DCF_JUST_MIRROR);

    if (tS - man_attack_t0 < 0.2)
        Sprite3(dc, x1, y1, z1, <3>);
    else
        Sprite3(dc, x1, y1, z1, <2>);

    DCDel(dc_t);

    if (tf)
    {
        dc->color = LTRED;
        if (Blink)
            GrPrint(dc, cx - (FONT_WIDTH * 14) / 2, cy - FONT_HEIGHT / 2, "Game Completed");
        tt = tf;
    }
    else
    {
        dc->color = LTGREEN;
        tt = tS;
    }
    GrPrint(dc, 0, 0, "Enemy:%d Time:%3.2f Best:%3.2f", monsters_left, tt - t0, best_score);
}

U0 Attack()
{
    I64      i;
    Monster *tmpm;

    man_attack_t0 = tS;
    Noise(100, 53, 74);
    for (i = 0, tmpm = monsters; i < MONSTERS_NUM; i++, tmpm++)
    {
        if (!tmpm->dead && man_x + man_dx == tmpm->x && man_y + man_dy == tmpm->y)
        {
            tmpm->dead = TRUE;
            if (!--monsters_left)
            {
                tf = tS;
                if (tf - t0 < best_score)
                    best_score = tf - t0;
            }
        }
    }
}

U0 Init()
{
    I64      i, x, y;
    CDC     *dc;
    Monster *tmpm;

    dc = Sprite2DC(<1>);
    map_width  = dc->width  / MAP_SCALE;
    map_height = dc->height / MAP_SCALE;
    Free(map);
    map = MAlloc(map_width * map_height * sizeof(U8));
    for (y = 0; y < map_height; y++)
        for (x = 0; x < map_width; x++)
            map[y * map_width + x] = GrPeek(dc, x * MAP_SCALE, y * MAP_SCALE);
    DCDel(dc);

    man_attack_t0 = 0;
    man_attack = FALSE;
    man_x = 0;
    man_y = 4;
    man_dx = 0;
    man_dy = 0;
    screen_x = 0;
    screen_y = 0;
    for (i = 0, tmpm = monsters; i < MONSTERS_NUM; i++, tmpm++)
    {
        tmpm->dead  = FALSE;
        tmpm->dx    = 0;
        tmpm->dy    = 0;
        do
        {
            tmpm->x = RandU64 % (map_width  - 2) + 1;
            tmpm->y = RandU64 % (map_height - 2) + 1;
        }
        while (!map[(tmpm->y) * map_width + tmpm->x]);
    }
    monsters_left = MONSTERS_NUM;
    tf = 0;
    t0 = tS;
}

U0 CleanUp()
{
    Free(map);
    map = NULL;
}

U0 AnimateTask(I64)
{
    I64      i, x, y, dx, dy;
    Monster *tmpm;

    while (TRUE)
    {
        for (i = 0, tmpm = monsters; i < MONSTERS_NUM; i++, tmpm++)
            if (!tmpm->dead)
            {
                dx = RandU16 % 3 - 1;
                dy = RandU16 % 3 - 1;
                x = tmpm->x + dx;
                y = tmpm->y + dy;
                if (0 <= x < map_width && 0 <= y < map_height && map[y * map_width + x])
                {
                    tmpm->x  = x;
                    tmpm->y  = y;
                    tmpm->dx = dx;
                    tmpm->dy = dy;
                }
            }
        Sleep(1000);
    }
}

U0 DunGen()
{
    I64 ch, sc;

    MenuPush(
                "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Play {"
                "  Restart(,'\n');"
                "  Up(,,SC_CURSOR_UP);"
                "  Down(,,SC_CURSOR_DOWN);"
                "  Left(,,SC_CURSOR_LEFT);"
                "  Right(,,SC_CURSOR_RIGHT);"
                "  Attack(,CH_SPACE);"
                "}"
                );

    SettingsPush; //See SettingsPush
    Fs->text_attr = BLACK << 4 + WHITE;
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    DocClear;
    Init;
    PaletteSetLight(FALSE);
    Fs->animate_task = Spawn(&AnimateTask, NULL, "Animate",, Fs);
    Fs->draw_it      = &DrawIt;

    try
    {
        while (TRUE)
        {
            switch (MessageGet(&ch, &sc, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_KEY_UP))
            {
                case MESSAGE_KEY_DOWN:
                    switch (ch)
                    {
                        case '\n':
                            Init;
                            break;

                        case CH_SPACE:
                            man_attack = TRUE;
                            break;

                        case CH_ESC:
                        case CH_SHIFT_ESC:
                            goto dg_done;

                        case 0:
                            switch (sc.u8[0])
                            {
                                case SC_CURSOR_RIGHT:
                                    if (man_attack)
                                    {
                                        man_dx = 1;
                                        man_dy = 0;
                                        Attack;
                                    }
                                    else
                                        if (man_x + 1 < map_width && map[man_y * map_width + (man_x + 1)] == DKGRAY)
                                        {
                                            man_x++;
                                            if (man_x - screen_x > SCREEN_WIDTH / 2 - 3)
                                            {
                                                screen_x += SCREEN_WIDTH / 2;
                                                if (screen_x + SCREEN_WIDTH / 2 > map_width)
                                                    screen_x = map_width - SCREEN_WIDTH / 2;
                                            }
                                        }
                                    break;

                                case SC_CURSOR_LEFT:
                                    if (man_attack)
                                    {
                                        man_dx = -1;
                                        man_dy = 0;
                                        Attack;
                                    }
                                    else
                                        if (man_x - 1 >= 0 && map[man_y * map_width + (man_x - 1)] == DKGRAY)
                                        {
                                            man_x--;
                                            if (man_x - screen_x < -SCREEN_WIDTH / 2 + 3)
                                            {
                                                screen_x -= SCREEN_WIDTH / 2;
                                                if (screen_x - SCREEN_WIDTH / 2 < 0)
                                                    screen_x = SCREEN_WIDTH / 2;
                                            }
                                        }
                                    break;

                                case SC_CURSOR_UP:
                                    if (man_attack)
                                    {
                                        man_dx = 0;
                                        man_dy = -1;
                                        Attack;
                                    }
                                    else
                                        if (man_y - 1 >= 0 && map[(man_y - 1) * map_width + man_x] == DKGRAY)
                                        {
                                            man_y--;
                                            if (man_y - screen_y < -SCREEN_HEIGHT / 2 + 3)
                                            {
                                                screen_y -= SCREEN_HEIGHT / 2;
                                                if (screen_y - SCREEN_HEIGHT / 2 < 0)
                                                    screen_y = SCREEN_HEIGHT / 2;
                                            }
                                        }
                                    break;

                                case SC_CURSOR_DOWN:
                                    if (man_attack)
                                    {
                                        man_dx = 0;
                                        man_dy = 1;
                                        Attack;
                                    }
                                    else
                                        if (man_y + 1 < map_height && map[(man_y + 1) * map_width + man_x] == DKGRAY)
                                        {
                                            man_y++;
                                            if (man_y - screen_y > SCREEN_HEIGHT / 2 - 3)
                                            {
                                                screen_y += SCREEN_HEIGHT / 2;
                                                if (screen_y + SCREEN_HEIGHT / 2 > map_height)
                                                    screen_y = map_height - SCREEN_HEIGHT / 2;
                                            }
                                        }
                                    break;
                            }
                    }
                    break;

                case MESSAGE_KEY_UP:
                    if (ch == CH_SPACE)
                        man_attack = FALSE;
                    break;
            }
        }
dg_done:
        MessageGet(,, 1 << MESSAGE_KEY_UP);
    }
    catch
        PutExcept;
    SettingsPop;
    CleanUp;
    MenuPop;
    RegWrite("ZealOS/DunGen", "F64 best_score=%5.4f;\n", best_score);
}

DunGen;