/*
Terry got tricky by not defining a color
right away in these CSprites so they can
work for both players by setting dc->color
before drawing them.  He actually made these
graphics by defining a color in the <CTRL-r>
menu, drawing the unit and deleting the color.

He had to leave a gap between the tank tread
and body because of how it is rendered when rotated.
*/

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

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

//This is an infantry.

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

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


U0 DrawHexes()
{
    F64 dx = 2 * HEX_SIDE + 2 * DCOS, dy = 2 * DSIN, x, y, x1, y1, x2, y2;
    I64 i, j;

    map_dc->color = WHITE;
    GrRect(map_dc, 0, 0, map_dc->width, map_dc->height);
    map_dc->color = BLACK;
    y = 0;
    for (j = 0; j < map_rows; j += 2)
    {
        x = DCOS;
        GrLine(map_dc, x, y, x - DCOS, y + DSIN);
        GrLine(map_dc, x - DCOS, y + DSIN, x, y + 2 * DSIN);
        for (i = 0; i < map_cols; i++)
        {
            x1 = x;
            y1 = y;
            x2 = x1 + HEX_SIDE;
            y2 = y1;
            GrLine(map_dc, x1, y1, x2, y2);
            x1 = x2;
            y1 = y2;
            x2 += DCOS;
            y2 += DSIN;
            GrLine(map_dc, x1, y1, x2, y2);
            GrLine(map_dc, x2, y2, x2 - DCOS, y2 + DSIN);
            x1 = x2;
            y1 = y2;
            x2 += HEX_SIDE;
            GrLine(map_dc, x1, y1, x2, y2);
            GrLine(map_dc, x2, y2, x2 + DCOS, y2 + DSIN);
            x1 = x2;
            y1 = y2;
            x2 += DCOS;
            y2 -= DSIN;
            if (j || i < map_cols - 1)
                GrLine(map_dc, x1, y1, x2, y2);
            x += dx;
        }
        y += dy;
    }
    x = DCOS;
    for (i = 0; i < map_cols; i++)
    {
        x1 = x;
        y1 = y;
        x2 = x1 + HEX_SIDE;
        y2 = y1;
        GrLine(map_dc, x1, y1, x2, y2);
        x1 = x2;
        y1 = y2;
        x2 += DCOS;
        y2 += DSIN;
        GrLine(map_dc, x1, y1, x2, y2);
        x1 = x2;
        y1 = y2;
        x2 += HEX_SIDE;
        GrLine(map_dc, x1, y1, x2, y2);
        x1 = x2;
        y1 = y2;
        x2 += DCOS;
        y2 -= DSIN;
        GrLine(map_dc, x1, y1, x2, y2);
        x += dx;
    }
}

U0 MakeTerrain(U8 color, I64 count, I64 clus_lo, I64 clus_hi)
{
    I64 i, j, l, row, col;

    for (i = 0; i < count; i++)
    {
        col = RandU32 % map_cols;
        row = RandU32 % map_rows;
        l = clus_lo + RandU16 % (clus_hi - clus_lo + 1);
        for (j = 0; j < l; j++)
        {
            terrain[row][col] = color;
            Toward(&row, &col, RandU16 % 6);
            col = ClampI64(col, 0, map_cols - 1);
            row = ClampI64(row, 0, map_rows - 1);
        }
    }
}

U0 MakeRivers()
{
    I64 i, row, col, direction;

    for (i = 0; i < 4; i++)
    {
        row = RandU32 % map_rows;
        col = RandU32 % map_cols;
        direction = RandU16 % 6;
        while (TRUE)
        {
            rivers[row][col] = TRUE;
            Toward(&row, &col, direction);
            if (!(0 <= row < map_rows && 0 <= col < map_cols))
                break;
            if (!(RandU16 & 3))
                direction = (direction + (7 - RandU16 % 3)) % 6;
        }
    }
}

U0 MakeRoads()
{
    I64 i, row, col, direction;

    for (i = 0; i < 5; i++)
    {
        row = RandU32 % map_rows;
        col = RandU32 % map_cols;
        direction = RandU16 % 6;
        while (TRUE)
        {
            roads[row][col] = TRUE;
            Toward(&row, &col, direction);
            if (!(0 <= row < map_rows && 0 <= col < map_cols))
                break;
            if (!(RandU16 % 3))
                direction = (direction + (7 - RandU16 % 3)) % 6;
        }
    }
}

U0 DrawTerrain()
{
    I64 i, j;
    F64 x, y;

    for (j = 0; j < map_rows; j++)
        for (i = 0; i < map_cols; i++)
        {
            map_dc->color = terrain[j][i];
            RowCol2XY(&x, &y, j, i);
            GrFloodFill(map_dc, x, y);
        }
}

U0 DrawRivers()
{
    I64 i, j, k, r, c;
    F64 x1, y1, x2, y2;

    for (j = 0; j < map_rows; j++)
        for (i = 0; i < map_cols; i++)
        {
            if (rivers[j][i])
            {
                RowCol2XY(&x1, &y1, j, i);
                for (k = 0; k < 6; k++)
                {
                    r = j;
                    c = i;
                    Toward(&r, &c, k);
                    if (0 <= r < map_rows && 0 <= c < map_cols && rivers[r][c])
                    {
                        RowCol2XY(&x2, &y2, r, c);
                        map_dc->color = LTBLUE;
                        map_dc->thick = 4;
                        GrLine3(map_dc, x1, y1, 0, x2, y2, 0);
                        map_dc->color = BLUE;
                        map_dc->thick = 2;
                        GrLine3(map_dc, x1, y1, 0, x2, y2, 0);
                    }
                }
            }
        }
}

U0 DrawRoads()
{
    I64 i, j, k, r, c;
    F64 x1, y1, x2, y2;

    map_dc->color = RED;
    map_dc->thick = 3;
    for (j = 0; j < map_rows; j++)
        for (i = 0; i < map_cols; i++)
        {
            if (roads[j][i])
            {
                RowCol2XY(&x1, &y1, j, i);
                for (k = 0; k < 6; k++)
                {
                    r = j;
                    c = i;
                    Toward(&r, &c, k);
                    if (0 <= r < map_rows && 0 <= c < map_cols && roads[r][c])
                    {
                        RowCol2XY(&x2, &y2, r, c);
                        GrLine3(map_dc, x1, y1, 0, x2, y2, 0);
                    }
                }
            }
        }
}

U0 DrawDots()
{
    I64 i, j;
    F64 x, y;

    map_dc->color = BLACK;
    for (j = 0; j < map_rows; j++)
        for (i = 0; i < map_cols; i++)
        {
            RowCol2XY(&x, &y, j, i);
            GrPlot(map_dc, x, y);
        }
}

U0 HexCentersCalc()
{
    I64 i, j;
    F64 x, y;

    for (j = 0; j < map_rows; j++)
        for (i = 0; i < map_cols; i++)
        {
            x = (2 * HEX_SIDE + 2 * DCOS) * i + HEX_SIDE / 2 + DCOS;
            if (j & 1)
                x += HEX_SIDE + DCOS;
            y = DSIN * (j + 1);
            hex_centers[j][i].x = x;
            hex_centers[j][i].y = y;
        }
}

U0 InitMap()
{
    HexCentersCalc;
    DrawHexes;
    MemSet(terrain, PLAINS, sizeof(terrain));
    MemSet(roads, FALSE, sizeof(roads));
    MemSet(rivers, FALSE, sizeof(rivers));
    MemSet(vis_map, FALSE, sizeof(vis_map));
    MakeTerrain(MOUNTAINS, 0.03 * map_cols * map_cols, 5, 35);
    MakeTerrain(TREES, 0.03 * map_cols * map_cols, 5, 35);
    DrawTerrain;
    MakeRivers;
    DrawRivers;
    MakeRoads;
    DrawRoads;
    DrawDots;
}

U0 InitUnits()
{
    I64   i, j, row, col, type;
    Unit *tmpu;

    MemSet(units, 0, sizeof(units));
    alive_count[0] = alive_count[1]=UNITS_NUM;
    for (j = 0; j < 2; j++)
        for (i = 0; i < alive_count[j]; i++)
        {
            tmpu = &units[j][i];
            tmpu->player    = j;
            tmpu->num       = i;
            tmpu->life      = 100;
            tmpu->facing    = RandU16 % 6;
            if (!j)
            {
                if (i >= UNITS_NUM / 2)
                {
                    if (i >= 15 * UNITS_NUM / 16)
                        type = UT_ARTILLERY;
                    else
                        type = UT_INFANTRY;
                }
                else
                {
                    if (i >= UNITS_NUM / 4)
                        type = UT_MD_TANK;
                    else
                        type = UT_LT_TANK;
                }
            }
            else
            {
                if (i >= UNITS_NUM / 2)
                {
                    if (i >= 15 * UNITS_NUM / 16)
                        type = UT_ARTILLERY;
                    else
                        type = UT_INFANTRY;
                }
                else
                {
                    if (i >= UNITS_NUM / 4)
                        type=UT_MD_TANK;
                    else
                        type=UT_LT_TANK;
                }
            }
            tmpu->type=type;
            switch (type)
            {
                case UT_INFANTRY:
                    tmpu->infantry          = TRUE;
                    tmpu->indirect_fire     = FALSE;
                    tmpu->armor             = 0;
                    tmpu->armored_attack    = 15;
                    tmpu->unarmored_attack  = 180;
                    tmpu->accuracy          = 45;
                    tmpu->range             = 5;
                    tmpu->movement          = 4;
                    tmpu->img               = <1>;
                    break;

                case UT_ARTILLERY:
                    tmpu->infantry          = TRUE;
                    tmpu->indirect_fire     = TRUE;
                    tmpu->armor             = 0;
                    tmpu->armored_attack    = 60;
                    tmpu->unarmored_attack  = 180;
                    tmpu->accuracy          = 25;
                    tmpu->range             = 20;
                    tmpu->movement          = 2;
                    tmpu->img               = <2>;
                    break;

                case UT_LT_TANK:
                    tmpu->infantry          = FALSE;
                    tmpu->indirect_fire     = FALSE;
                    tmpu->armor             = 30;
                    tmpu->armored_attack    = 40;
                    tmpu->unarmored_attack  = 60;
                    tmpu->accuracy          = 25;
                    tmpu->range             = 8;
                    tmpu->movement          = 24;
                    tmpu->img               = <3>;
                    break;

                case UT_MD_TANK:
                    tmpu->infantry          = FALSE;
                    tmpu->indirect_fire     = FALSE;
                    tmpu->armor             = 60;
                    tmpu->armored_attack    = 60;
                    tmpu->unarmored_attack  = 80;
                    tmpu->accuracy          = 25;
                    tmpu->range             = 12;
                    tmpu->movement          = 16;
                    tmpu->img               = <4>;
                    break;
            }
            do
            {
                row = RandU32 % map_rows;
                col = RandU32 % (map_cols / 3);
                if (j)
                    col += 2 * map_cols / 3;
            }
            while (UnitFind(row, col));

            tmpu->row = row;
            tmpu->col = col;
            LBts(&tmpu->vis[cur_player], 0);
        }
}

U0 ViewPlayerSet(I8 p)
{
    CMenuEntry *tmpse;

    view_player = p;
    if (tmpse = MenuEntryFind(Fs->cur_menu, "View/Player1"))
        tmpse->checked = view_player == 0;
    if (tmpse = MenuEntryFind(Fs->cur_menu, "View/Player2"))
        tmpse->checked = view_player == 1;
}

U0 Init()
{
    DocClear;
    "GameSeed(0x%X)\n", Seed(PopUpI64Get("GameSeed(0x%X):", Seed));
    moving_unit = NULL;
    InitMap;
    ViewPlayerSet(cur_player = 0);
    enemy_player = 1;
    if (map_width < GR_WIDTH)
    {
        x0 = (MAP_WIDTH  - map_width)  >> 1;
        y0 = (MAP_HEIGHT - map_height) >> 1 + FONT_HEIGHT;
    }
    else
    {
        x0 = 0;
        y0 = FONT_HEIGHT;
    }
    InitUnits;
    QueueInit(&indirect_head);
    turn = 0;
    fire_radius = 0;
    show_vis_row = -1;
    show_vis_col = -1;
    *message_buf = 0;
    message_off_timeout = 0;
    phase = PHASE_END;
}

U0 CleanUp()
{
    QueueDel(&indirect_head, TRUE);
}

U0 PlayerPick(U8 *dirname, I64 player)
{
    I64          i = 0;
    U8          *st;
    CDirEntry   *tmpde, *tmpde1, *tmpde2;
    CDoc        *doc = DocNew;
    Bool        *old_silent = Silent;

    st = MStrPrint("%s/*.ZC*", dirname);
    tmpde = FilesFind(st);
    Free(st);
    tmpde2 = FilesFind("~/ToTheFront/*.ZC*");
    tmpde1 = tmpde;
    Silent(old_silent);

    DocPrint(doc, "Player %d Type\n\n$LTBLUE$", player + 1);
    while (tmpde1)
    {
        if (!(i++ & 3))
            DocPrint(doc, "\n");
        st = StrNew(tmpde1->name);
        FileExtRemove(st);
        tmpde1->user_data = DocPrint(doc, "$MU-UL,\"%-10ts\",LE=%d$ ", st, tmpde1);
        Free(st);
        tmpde1 = tmpde1->next;
    }
    tmpde1 = tmpde2;
    while (tmpde1)
    {
        if (!(i++ & 3))
            DocPrint(doc, "\n");
        st = StrNew(tmpde1->name);
        FileExtRemove(st);
        tmpde1->user_data = DocPrint(doc, "$MU-UL,\"%-10ts\",LE=%d$ ", st, tmpde1);
        Free(st);
        tmpde1 = tmpde1->next;
    }
    DocPrint(doc, "\n\n\n$FG$Create your own AI in ~/ToTheFront.");
    while ((tmpde1 = PopUpMenu(doc)) <= 0);
    ExeFile(tmpde1->full_name);
    DocDel(doc);
    DirTreeDel(tmpde);
    DirTreeDel(tmpde2);
    ExePrint("player_indirect[%d]=&PlayerIndirect;"
             "player_move[%d]=&PlayerMove;"
             "player_direct[%d]=&PlayerDirect;", 
             player, player, player);
}