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