//Uses fixed-point.



<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 FRAMES 6

U8 *imgs[FRAMES] = {<1>, <2>, <3>, <4>, <3>, <2>};

F64 fire_end_time;

class Trooper
{
        I64              x, y, dx, dy, att, def, rng, player;
        F64              animate_time_base, fire_end_time;
        Trooper *target;
};

#define TROOPERS_NUM    100
Trooper tr[2][TROOPERS_NUM];

Bool time_lapse = FALSE;

#define TAP_MODE_RADIUS 50
Bool tap_mode;

#define AI_NOTHING 0
#define AI_TARGET  1
#define AI_RANDOM  2
#define AI_AI_NUM  3
I64 ai_mode;

I64 ai_targets[10];

U0 DrawTrooper(CTask *, CDC *dc, Trooper *tmpt)
{
        U8 *tmps;
        I64 x, y, gx, gy;
        F64 speed, tt;

        if (tmpt->def > 0)
        {
                x = tmpt->dx >> 28;
                y = tmpt->dy >> 28;
                speed = 0.5 * Sqrt(x * x + y * y);

                tt = tmpt->animate_time_base + tS * speed;
                if (time_lapse)
                {
                        x = (tmpt->x + 500 * tmpt->dx) >> 32;
                        y = (tmpt->y + 500 * tmpt->dy) >> 32;
                }
                else
                {
                        x = tmpt->x.i32[1];
                        y = tmpt->y.i32[1];
                }
                if (tmpt->target)
                {
                        gx = x;
                        gy = y;
                        if (tmpt->dx < 0)
                        {
                                dc->flags |= DCF_SYMMETRY | DCF_JUST_MIRROR;
                                DCSymmetrySet(dc, x, y, x, y + 1);
                                gx -= 13;
                                gy -= 7;
                        }
                        else
                        {
                                dc->flags &= ~DCF_SYMMETRY | DCF_JUST_MIRROR;
                                gx += 13;
                                gy -= 7;
                        }

                        dc->color = BLACK;
                        Sprite3(dc, x + 1, y, 0, <5>);

                        if (!tmpt->player)
                                dc->color = LTCYAN;
                        else
                                dc->color = LTPURPLE;
                        Sprite3(dc, x, y, 0, <5>);

                        dc->flags &= ~(DCF_SYMMETRY | DCF_JUST_MIRROR);
                        if (!tmpt->player)
                                dc->color = WHITE;
                        else
                                dc->color = LTBLUE;
                        GrLine3(dc, gx, gy, 0, tmpt->target->x.i32[1], tmpt->target->y.i32[1], 0);
                }
                else
                {
                        if (tmpt->dx < 0)
                        {
                                dc->flags |= DCF_SYMMETRY | DCF_JUST_MIRROR;
                                DCSymmetrySet(dc, x, y, x, y + 1);
                        }
                        else
                                dc->flags &= ~DCF_SYMMETRY | DCF_JUST_MIRROR;
                        tmps = SpriteInterpolate(tt % 1.0, imgs[tt % FRAMES], imgs[(tt + 1.0) % FRAMES]);

                        dc->color = BLACK;
                        Sprite3(dc, x + 1, y, 0, tmps);

                        if (!tmpt->player)
                                dc->color = LTCYAN;
                        else
                                dc->color = LTPURPLE;
                        Sprite3(dc, x, y, 0, tmps);

                        Free(tmps);
                        dc->flags &= ~(DCF_SYMMETRY | DCF_JUST_MIRROR);
                }
        }
}

U0 DrawIt(CTask *task, CDC *dc)
{
        Trooper *tmpt=tr;
        I64              i, j, count[2], 
                         x = mouse.pos.x - task->pix_left - task->scroll_x, 
                         y = mouse.pos.y - task->pix_top  - task->scroll_y;
        Bool     repulsive = mouse.pos.z > 0 ^^ mouse.rb, 
                         active = !winmgr.grab_scroll && (mouse.lb || mouse.rb);

        for (j = 0; j < 2; j++)
        {
                count[j] = 0;
                for (i = 0; i < TROOPERS_NUM; i++, tmpt++)
                {
                        if (tmpt->def > 0)
                        {
                                DrawTrooper(task, dc, tmpt);
                                count[j]++;
                        }
                }
        }
        if (tap_mode)
        {
                dc->color = YELLOW;
                GrCircle(dc, x, y, TAP_MODE_RADIUS);
        }
        else
        {
                if (repulsive)
                {
                        if (active)
                                dc->color = LTRED;
                        else
                                dc->color = RED;
                }
                else
                {
                        if (active)
                                dc->color = LTBLUE;
                        else
                                dc->color = BLUE;
                }
                GrCircle(dc, x, y, AbsI64(mouse.pos.z));
        }
        dc->color = LTCYAN;
        GrPrint(dc, (task->win_right - 8) * FONT_WIDTH, 0, "%03d", count[0]);
        dc->color = LTPURPLE;
        GrPrint(dc, (task->win_right - 4) * FONT_WIDTH, 0, "%03d", count[1]);
}

U0 DoAiTarget()
{
        I64              i, j;
        Trooper *tmpt1, *tmpt0;

        for (i = 0; i < 10; i++)
        {
                tmpt0 = &tr[0][ai_targets[i]];
                for (j = 0; j < 10; j++)
                {
                        tmpt1 = &tr[1][i * 10 + j];
                        tmpt1->dx = (tmpt0->x - tmpt1->x) >> 11;
                        tmpt1->dy = (tmpt0->y - tmpt1->y) >> 11;
                }
        }
}

U0 UpdatePos()
{
        I64              i, j;
        Trooper *tmpt = tr;

        for (j = 0; j < 2; j++)
                for (i = 0; i < TROOPERS_NUM; i++, tmpt++)
                {
                        tmpt->x += tmpt->dx;
                        if (tmpt->x >= GR_WIDTH << 32)
                                tmpt->x -= GR_WIDTH << 32;

                        if (tmpt->x < 0)
                                tmpt->x += GR_WIDTH << 32;

                        tmpt->y += tmpt->dy;
                        if (tmpt->y >= GR_HEIGHT << 32)
                                tmpt->y -= GR_HEIGHT << 32;

                        if (tmpt->y < 0)
                                tmpt->y += GR_HEIGHT << 32;
                }
}

U0 ResolveFiring()
{
        I64              i, j, dd, dx, dy;
        Trooper *tmpt = tr, *tmpt0, *tmpt1;

        for (j = 0; j < 2; j++)
                for (i = 0; i < TROOPERS_NUM; i++, tmpt++)
                {
                        if (tmpt->target && tmpt->fire_end_time < tS)
                        {
                                tmpt->target->def  -= tmpt->att;
                                tmpt->fire_end_time = 0;
                                tmpt->target            = NULL;
                        }
                }

        for (i = 0; i < TROOPERS_NUM; i++)
        {
                tmpt0 = &tr[0][i];
                for (j = 0; j < TROOPERS_NUM; j++)
                {
                        tmpt1 = &tr[1][j];
                        if (tmpt0->def > 0 && tmpt1->def > 0)
                        {
                                dx = (tmpt0->x - tmpt1->x) >> 32;
                                dy = (tmpt0->y - tmpt1->y) >> 32;
                                dd = dx * dx + dy * dy;
                                if (dd < tmpt0->rng && !tmpt0->target)
                                {
                                        fire_end_time = tmpt0->fire_end_time = tS + 0.125;
                                        Sound(86);
                                        tmpt0->target = tmpt1;
                                }
                                if (dd < tmpt1->rng && !tmpt1->target)
                                {
                                        fire_end_time = tmpt1->fire_end_time = tS + 0.125;
                                        Sound(86);
                                        tmpt1->target = tmpt0;
                                }
                        }
                }
        }

        if (tS >= fire_end_time)
                Sound;
}

U0 UpdateHumanVelocities()
{
        F64              intensity;
        I64              i, j, dx, dy, d, 
                         x = mouse.pos.x - Fs->pix_left - Fs->scroll_x, 
                         y = mouse.pos.y - Fs->pix_top  - Fs->scroll_y;
        Bool     active = !winmgr.grab_scroll && (mouse.lb || mouse.rb);
        Trooper *tmpt = &tr[0][0];

        if (tap_mode)
        {
                for (i = 0; i < TROOPERS_NUM; i++, tmpt++)
                {
                        dx = x - tmpt->x.i32[1];
                        dy = y - tmpt->y.i32[1];
                        if ((d = dx * dx + dy * dy) && d < TAP_MODE_RADIUS * TAP_MODE_RADIUS)
                        {
                                intensity = SqrI64(SqrI64(SqrI64(TAP_MODE_RADIUS) - d));
                                dx = intensity * dx / d;
                                dy = intensity * dy / d;
                                tmpt->dx = tmpt->dx - dx;
                                tmpt->dy = tmpt->dy - dy;
                        }
                        else
                        {
                                tmpt->dx -= 0.2 * tmpt->dx;
                                tmpt->dy -= 0.2 * tmpt->dy;
                        }
                }
        }
        else if (active)
        {
                j = 400000000 * mouse.pos.z;
                if (mouse.rb)
                        j =-j;
                for (i = 0; i < TROOPERS_NUM; i++, tmpt++)
                {
                        dx = x - tmpt->x.i32[1];
                        dy = y - tmpt->y.i32[1];
                        if (d = dx * dx + dy * dy)
                        {
                                dx = j * dx / d;
                                dy = j * dy / d;
                                tmpt->dx = tmpt->dx - dx;
                                tmpt->dy = tmpt->dy - dy;
                        }
                }
        }
}

U0 Init()
{
        I64              i, j, dx, dy;
        Trooper *tmpt;

        MouseSet(,, 25);
        tap_mode = FALSE;
        time_lapse = FALSE;
        fire_end_time = 0;
        MemSet(tr, 0, sizeof(tr));
        for (i = 0; i < 10; i++)
        {
                ai_targets[i] = RandU16 % TROOPERS_NUM;
                dx = RandI32;
                dy = RandI32;
                for (j = 0; j < 10; j++)
                {
                        tmpt = &tr[0][i * 10 + j];
                        tmpt->x                                 = (GR_WIDTH - 100 - i * 10) << 32;
                        tmpt->y                                 = (GR_HEIGHT >> 1 - 50 + j * 10) << 32;
                        tmpt->att                               = 3;
                        tmpt->def                               = 10;
                        tmpt->rng                               = 50 * 50;
                        tmpt->animate_time_base = 10 * Rand;
                        tmpt->player                    = 0;

                        tmpt = &tr[1][i * 10 + j];
                        tmpt->x                                 = (100 + i * 10) << 32;
                        tmpt->y                                 = (GR_HEIGHT >> 1 - 50 + j * 10) << 32;
                        if (ai_mode == AI_RANDOM)
                        {
                                tmpt->dx                        = dx;
                                tmpt->dy                        = dy;
                        }
                        tmpt->att                               = 3;
                        tmpt->def                               = 10;
                        tmpt->rng                               = 50 * 50;
                        tmpt->animate_time_base = 10 * Rand;
                        tmpt->player                    = 1;
                }
        }
        ai_mode = RandU16 % AI_AI_NUM;
}

U0 BattleLines()
{
        CMenuEntry *tmpse;

        MenuPush(       "File {"
                                "  Abort(,CH_SHIFT_ESC);"
                                "  Exit(,CH_ESC);"
                                "}"
                                "Play {"
                                "  Restart(,'\n');"
                                "  TimeLapse(,'1');"
                                "  TapMode(,'2');"
                                "}"
                                );

        SettingsPush; //See SettingsPush
        Fs->text_attr = GREEN << 4 + WHITE;
        AutoComplete;
        WinBorder;
        WinMax;
        DocCursor;
        DocClear;
        Init;
        Fs->draw_it = &DrawIt;
        PopUpOk("The mouse wheel controls\n"
                                "the command force.\n"
                                "Attract or repel with\n"
                                "left or right bttn.\n\n");

        Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER - WIF_FOCUS_TASK_MENU;
        try
        {
                while (TRUE)
                {
                        switch (CharScan)
                        {
                                case '1':
                                        time_lapse = !time_lapse;
                                        tmpse = MenuEntryFind(Fs->cur_menu, "Play/TimeLapse");
                                        tmpse->checked = time_lapse;
                                        break;

                                case '2':
                                        tap_mode = !tap_mode;
                                        tmpse = MenuEntryFind(Fs->cur_menu, "Play/TapMode");
                                        tmpse->checked = tap_mode;
                                        break;

                                case CH_ESC:
                                case CH_SHIFT_ESC:
                                        goto wg_done;

                                case '\n':
                                        Init;
                                        break;
                        }
                        Sleep(40);
                        if (ai_mode == AI_TARGET)
                                DoAiTarget;
                        UpdateHumanVelocities;
                        UpdatePos;
                        ResolveFiring;
                }
wg_done:
        }
        catch
                PutExcept;
        SettingsPop;
        MenuPop;
}

BattleLines;