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;
    }
}