U0 AttackHeader(Unit *tmpu, U8 *st, Unit *target)
{
        I64 i = 9 + StrLen(st);

        if (target)
        {
                i += 9;
                if (target->armor)
                        i += 8;
                else
                        i += 10;
        }
        '\n\n';
        "$BLACK$%h*c$FG$\n", i, '-';
        if (tmpu->player)
                "$PURPLE$Player 2$FG$ ";
        else
                "$CYAN$Player 1$FG$ ";
        "%s", st;
        if (target)
        {
                if (target->player)
                        " $PURPLE$Player 2";
                else
                        " $CYAN$Player 1";
                if (target->armor)
                        " Armored";
                else
                        " Unarmored";
                '$FG$';
        }
        '\n';
        "$BLACK$%h*c$FG$\n", i, '-';
}

F64 HitDamage(Unit *tmpu, Unit *target, I64 facing=1, F64 range_factor=0)
{
        F64 d, res = 200.0 * Rand;

        "\nRoll Out of 200\t\t:%6.2f Damage\n", res;
        if (target->armor)
        {
                d = target->armor / 100.0 * (5 - facing) / 5.0;
                if (d >= 0)
                {
                        "Armor Attack\t\t:%6.2f\n", ToF64(tmpu->armored_attack);
                        res *= (tmpu->armored_attack / 100.0) / d;
                }
                else
                        res = 0;
                "Armor(%z) Defense\t:%6.2f\n", facing, 
                "Front\0FrontSide\0RearSide\0Rear\0", 100 * d;
        }
        else
        {
                d = 1.0 - range_factor;
                if (d > 0)
                {
                        "Unarmored Attack\t:%6.2f\n", ToF64(tmpu->unarmored_attack);
                        "Range Adjust\t\t:%6.2f%%\n", 100 * d;
                        res *= (tmpu->unarmored_attack / 100.0) * d;
                }
                else
                        res = 0;
        }
        "Attack/Defense Adjusted\t:%6.2f Damage\n", res;

        return Round(res);
}

Bool DamageDo(Unit *target, F64 damage)
{
        if (damage > 0)
        {
                if (target->armor)
                        "Armor Hit Score %6.2f\t:", damage;
                else
                        "%3d Life - %3f Damage\t=", target->life, damage;
                if (damage >= target->life)
                {
                        "$RED$Killed$FG$\n";
                        Noise(1000 * animation_delay, 74, 98);
                        Sleep(1000 * animation_delay);
                        target->life = 0;
                        VisRecalc(VR_FRIENDLY_UNIT_DIED, target);
                        alive_count[target->player]--;
                        return TRUE;
                }
                else
                {
                        if (target->armor)
                        {
                                if (damage > 0.6 * target->life)
                                {
                                        target->movement = 0;
                                        "$RED$Immobilized$FG$\n";
                                }
                                else
                                        "$GREEN$No Penetration$FG$\n";
                        }
                        else
                        {
                                target->life -= damage;
                                "$RED$%6.2f Life$FG$\n", ToF64(target->life);
                        }
                        return FALSE;
                }
        }
        else
                return FALSE;
}

U0 IndirectAdd(Unit *tmpu, I64 row, I64 col)
{
        IndirectOrders *tmpi;

        if (tmpu->life <= 0 || tmpu->range <= 0)
                return;
        tmpu->fired = TRUE;
        tmpi=CAlloc(sizeof(IndirectOrders));
        tmpi->attacker = tmpu;
        tmpi->row = row;
        tmpi->col = col;
        QueueInsert(tmpi, indirect_head.last);
}

Bool BulletPlot(U0, I64 x, I64 y, I64)
{
        fire_x = x;
        fire_y = y;
        firing = TRUE;
        Sleep(3 * animation_delay);
        return TRUE;
}

U0 UnitDirectFire(Unit *tmpu, Unit *target)
{
        I64 r, c, facing, t1 = terrain[tmpu->row][tmpu->col], t2 = terrain[target->row][target->col];
        F64 x1, y1, x2, y2, d, a, range_factor;

        if (tmpu->life <= 0 || target->life <= 0 || tmpu->range <= 0)
                return;
        AttackHeader(tmpu, "DirectFire", target);
        RowCol2XY(&x1, &y1, tmpu->row, tmpu->col);
        RowCol2XY(&x2, &y2, target->row, target->col);
        d = 100 * Rand;
        "+%5.2f  Roll\n", d;
        d += tmpu->accuracy;
        "+%2d.00  Accuracy\n", tmpu->accuracy;

        range_factor = Sqrt(Sqr(x2 - x1) + Sqr(y2 - y1)) / (tmpu->range * 2 * DSIN);
        "-%5.2f%% of Range\n", 100 * range_factor;
        d -= 100 * range_factor;
        if (t2 == TREES)
        {
                "-30.00  Target in Trees Penalty\n";
                d -= 30;
        }
        if (t1 == MOUNTAINS && t2 != MOUNTAINS)
        {
                "+30.00  High Ground Bonus\n";
                d += 30;
        }
        "_______\n";
        target_unit=target;
        if (d >= 0)
        {
                "+%5.2f  Hit\n", d;
                target_hit = TRUE;
                Noise(500 * animation_delay, 34, 41);
                Sleep(500 * animation_delay);
                Line(NULL, x1, y1, 0, x2, y2, 0, &BulletPlot);
        }
        else
        {
                "-%5.2f  Miss\n", -d;
                target_hit = FALSE;
                Noise(1000 * animation_delay, 69, 74);
                Sleep(1000 * animation_delay);
                a = pi * 2 * Rand;
                d = (0.5 - d / 100) * HEX_SIDE;
                Line(NULL, x1, y1, 0, x2 + d * Cos(a), y2 + d * Sin(a), 0, &BulletPlot);
        }
        firing = FALSE;
        tmpu->fired = TRUE;
        if (target_hit)
        {
                r = target->row;
                c = target->col;
                if ((facing = HexMoveOne(&r, &c, x1, y1)) >= 0)
                        facing = FacingChange(facing, target->facing);
                else
                        facing = 0;
                DamageDo(target, HitDamage(tmpu, target, facing, range_factor));
        }
        while (screencast.ona) //see Sound()
                Yield;
        target_unit = NULL;
}

Bool HexOccupy(Bool overrun, Unit *tmpu, Unit *target)
{
        I64 t2 = terrain[target->row][target->col];
        F64 damage;

        if (tmpu->life <= 0 || target->life <= 0)
                return FALSE;
        if (overrun)
                AttackHeader(tmpu, "OverRun", target);
        else
                AttackHeader(tmpu, "CloseAssault", target);
        Noise(500 * animation_delay, 34, 41);
        Sleep(500 * animation_delay);
        tmpu->fired = TRUE;
        target->fired = TRUE;
        damage=HitDamage(tmpu, target);
        if (overrun)
        {
                damage *= 2.0;
                "x2 OverRun Bonus\t=%6.2f Damage\n", damage;
                if (t2 != PLAINS)
                {
                        damage /= 2.0;
                        "/2 Terrain Penalty\t=%6.2f Damage\n", damage;
                }
        }
        else
        {
                damage *= 3.0;
                "x3 CloseAssault Bonus\t=%6.2f Damage\n", damage;
        }
        if (DamageDo(target, Round(damage)))
        {
                "$RED$Success$FG$\n";
                while (screencast.ona) //see Sound()
                        Yield;
                return TRUE;
        }
        else
        {
                tmpu->life = 0;
                VisRecalc(VR_FRIENDLY_UNIT_DIED, tmpu);
                alive_count[tmpu->player]--;
                "$RED$Failure$FG$\n";
                while (screencast.ona) //see Sound()
                        Yield;
                return FALSE;
        }
}

U0 IndirectResolveAll()
{
        I64                              i, r, c;
        F64                              x1, y1, x2, y2, d, range_factor;
        Unit                    *tmpu, *target;
        IndirectOrders  *tmpi = indirect_head.next, *tmpi1;

        while (tmpi != *indirect_head)
        {
                tmpi1 = tmpi->next;
                tmpu = tmpi->attacker;
                AttackHeader(tmpu, "IndirectFire", NULL);
                RowCol2XY(&x1, &y1, tmpu->row, tmpu->col);
                RowCol2XY(&x2, &y2, tmpi->row, tmpi->col);
                d = 100 * Rand;
                "+%5.2f  Roll\n", d;
                d += tmpu->accuracy;
                "+%2d.00  Accuracy\n", tmpu->accuracy;
                range_factor = Sqrt(Sqr(x2 - x1) + Sqr(y2 - y1)) / (tmpu->range * 2 * DSIN);
                "-%5.2f%% of Range\n", 100 * range_factor;
                d -= 100 * range_factor;
                '_______\n';


                if (d >= 0)
                {
                        "+%5.2f  Hit\n", d;
                        Noise(500 * animation_delay, 34, 41);
                        Sleep(500 * animation_delay);
                }
                else
                {
                        "-%5.2f  Miss\n", -d;
                        Noise(1000 * animation_delay, 69, 74);
                        Sleep(1000 * animation_delay);
                        i = RandU16 % 6;
                        if (tmpi->row & 1)
                                tmpi->col += col_offsets_odd[i];
                        else
                                tmpi->col += col_offsets_even[i];
                        tmpi->row += row_offsets[i];
                        RowCol2XY(&x2, &y2, tmpi->row, tmpi->col);
                }

                Line(NULL, x1, y1, 0, x2, y2, 0, &BulletPlot);
                firing = FALSE;
                tmpu->fired = TRUE;
                indirect_row = tmpi->row;
                indirect_col = tmpi->col;
                indirect_explosion = TRUE;
                for (i = 0; i < 7; i++)
                {
                        if (tmpi->row & 1)
                                c = tmpi->col + col_offsets_odd[i];
                        else
                                c = tmpi->col + col_offsets_even[i];
                        r = tmpi->row + row_offsets[i];
                        if (0 <= r < map_rows && 0 <= c < map_cols && (target = UnitFind(r, c)))
                        {
                                AttackHeader(tmpu, "IndirectFire", target);
                                DamageDo(target, HitDamage(tmpu, target));
                        }
                }
                Noise(2000 * animation_delay, 70, 74);
                Sleep(2000 * animation_delay);
                while (screencast.ona) //see Sound()
                        Yield;
                indirect_explosion = FALSE;

                QueueRemove(tmpi);
                Free(tmpi);
                tmpi = tmpi1;
        }
}