Example #1
0
        private void Attack(OrderType attackDirection)
        {
            // Logic from "The Complete Civilization II Combat Guide v1.1"

            IUnit attacker = _activeUnit;

            // Determine direction of attack and all units on that square
            int[] deltaXY = new int[] { 0, 0 };
            switch (attackDirection)
            {
            case OrderType.MoveSW: deltaXY = new int[] { -1, 1 }; break;

            case OrderType.MoveS: deltaXY = new int[] { 0, 2 }; break;

            case OrderType.MoveSE: deltaXY = new int[] { 1, 1 }; break;

            case OrderType.MoveE: deltaXY = new int[] { 2, 0 }; break;

            case OrderType.MoveNE: deltaXY = new int[] { 1, 1 }; break;

            case OrderType.MoveN: deltaXY = new int[] { 0, -2 }; break;

            case OrderType.MoveNW: deltaXY = new int[] { -1, -1 }; break;

            case OrderType.MoveW: deltaXY = new int[] { -2, 0 }; break;
            }
            int[] newXY = { attacker.X + deltaXY[0], attacker.Y + deltaXY[1] };
            var   unitsOnTargetSquare = _units.Where(unit => unit.X == newXY[0] && unit.Y == newXY[1]).ToList();

            // Primary defender is the unit with largest defense factor
            IUnit defender = unitsOnTargetSquare.OrderBy(u => u.DefenseFactor(attacker)).First();

            // Calculate odds of attacker winning combat (a round of battle)
            double A    = attacker.AttackFactor(defender);
            double D    = defender.DefenseFactor(attacker);
            double FP_A = attacker.Firepower(true, defender);
            double FP_D = defender.Firepower(false, attacker);
            double probAttackerWins;

            if (D >= A)
            {
                probAttackerWins = (A * 8 - 1) / (2 * D * 8);
            }
            else
            {
                probAttackerWins = 1 - ((D * 8 + 1) / (2 * A * 8));
            }

            // Battle -> Loop through combat rounds until a unit loses its HP
            Random      random = new Random();
            double      rand;
            bool        attackerWinsRound;
            List <bool> combatRoundsAttackerWins = new List <bool>(); // Register combat outcomes
            List <int>  attackerHitpoints        = new List <int>();  // Register attacker hitpoints in each round
            List <int>  defenderHitpoints        = new List <int>();  // Register defender hitpoints in each round

            do
            {
                rand = random.Next(0, 1000) / 1000.0;   // Generate a random number between 0 and 1 to determine who won
                attackerWinsRound = probAttackerWins > rand;
                attackerHitpoints.Add(attacker.HitPoints);
                defenderHitpoints.Add(defender.HitPoints);
                if (attackerWinsRound)
                {
                    defender.HitPointsLost += (int)FP_A;
                    combatRoundsAttackerWins.Add(true);
                }
                else
                {
                    attacker.HitPointsLost += (int)FP_D;
                    combatRoundsAttackerWins.Add(false);
                }
            } while (attacker.HitPoints > 0 && defender.HitPoints > 0);

            bool attackerWinsBattle = defender.HitPoints <= 0;

            if (attackerWinsBattle)
            {
                // Defender loses - kill all units on the tile (except if on city & if in fortress/airbase)
                if (defender.IsInCity || Map.TileC2(defender.X, defender.Y).Fortress || Map.TileC2(defender.X, defender.Y).Airbase)
                {
                    defender.Dead = true;
                    //_casualties.Add(defender);
                    //_units.Remove(defender);
                }
                else
                {
                    foreach (IUnit unit in unitsOnTargetSquare)
                    {
                        unit.Dead = true;
                        //_casualties.Add(unit);
                        //_units.Remove(unit);
                    }
                }
            }
            else
            {
                attacker.Dead = true;
                //_casualties.Add(attacker);
                //_units.Remove(attacker);
            }

            OnUnitEvent?.Invoke(null, new UnitEventArgs(UnitEventType.Attack, attacker, defender, combatRoundsAttackerWins, attackerHitpoints, defenderHitpoints));
        }