static public CombatResult GenerateForCombat(ICombat combat, Func <Guid, IEnumerable <UInt32> > randomNumberGenerator) { CombatResult result = new CombatResult(combat.CombatId); result.m_StartingArmies = combat.InvolvedArmies; result.m_SurvivingArmies = (from army in combat.InvolvedArmies select new CombatArmy(army)).ToList(); // Remove any armies with no troops (e.g. spoils of war, the defender is just here so we know what region's at stake!) result.m_SurvivingArmies.RemoveAll(army => army.NumberOfTroops == 0); while (result.m_SurvivingArmies.GroupBy(army => army.OwnerUserId).Count() > 1) { CombatRoundResult combatRound = CombatRoundResult.GenerateForCombat(combat.ResolutionType, result.m_SurvivingArmies, randomNumberGenerator); result.m_Rounds.Add(combatRound); // Remove armies with no troops left result.m_SurvivingArmies.RemoveAll(army => army.NumberOfTroops == 0); // Mass invasion has an early out when the defenders are all dead. Otherwise, fight to the last army standing! if (combat.ResolutionType == CombatType.MassInvasion) { if (result.m_SurvivingArmies.Where(army => army.ArmyMode == CombatArmyMode.Defending).Count() == 0) { break; } } } return(result); }
static public CombatRoundResult GenerateForCombat(CombatType resolutionMode, List <CombatArmy> armies, Func <Guid, IEnumerable <UInt32> > randomNumberGenerator) { CombatRoundResult roundResult = new CombatRoundResult(); // Generate the results for each army foreach (CombatArmy army in armies) { roundResult.m_ArmyResults.Add(CombatArmyRoundResult.GenerateForCombat(army, randomNumberGenerator(army.OriginRegionId))); } switch (resolutionMode) { case CombatType.BorderClash: case CombatType.SpoilsOfWar: { for (int counter = 0; counter < 3; ++counter) { var attackingDiceQuery = from armyResult in roundResult.m_ArmyResults where armyResult.RolledResults.Count() > counter join army in armies on armyResult.OriginRegionId equals army.OriginRegionId let armyDiceRoll = armyResult.RolledResults.ElementAt(counter) orderby armyDiceRoll descending, army.NumberOfTroops ascending select new { Army = army, Results = armyResult, AttackerRoll = armyDiceRoll }; var attackers = attackingDiceQuery.ToList(); for (int attackerIndex = 0; attackerIndex < attackers.Count; ++attackerIndex) { var attacker = attackers[attackerIndex]; // Compare against all remaining attackers (or until we run out of troops) for (int defenderIndex = attackerIndex + 1; attacker.Results.TroopsLost < attacker.Army.NumberOfTroops && defenderIndex < attackers.Count; ++defenderIndex) { var defender = attackers[defenderIndex]; // Ensure defender has troops left and this wouldn't be friendly fire if (defender.Army.OwnerUserId != attacker.Army.OwnerUserId && defender.Results.TroopsLost < defender.Army.NumberOfTroops) { // We've sorted out players by dice roll, so anyone in a lower index must either draw or be worse if (attacker.AttackerRoll == defender.AttackerRoll) { if (resolutionMode == CombatType.SpoilsOfWar) { // For a spoils of war, don't deduct troops on a draw. We don't want to be left with no one able to take the territory over continue; } attacker.Results.TroopsLost += 1; } defender.Results.TroopsLost += 1; } } } } break; } case CombatType.MassInvasion: case CombatType.Invasion: { // Calculate troop loses. On a tie, the defenders lose var defendingDiceQuery = from armyResult in roundResult.m_ArmyResults join army in armies on armyResult.OriginRegionId equals army.OriginRegionId where army.ArmyMode == CombatArmyMode.Defending select new { Army = army, Results = armyResult, DefenderRolls = armyResult.RolledResults.OrderByDescending(diceRoll => diceRoll).ToList() }; var attackingDiceQuery = from armyResult in roundResult.m_ArmyResults join army in armies on armyResult.OriginRegionId equals army.OriginRegionId where army.ArmyMode == CombatArmyMode.Attacking orderby army.NumberOfTroops ascending select new { Army = army, Results = armyResult, AttackerRolls = armyResult.RolledResults.OrderByDescending(diceRoll => diceRoll).ToList() }; var defender = defendingDiceQuery.FirstOrDefault(); for (int counter = 0; counter < defender.DefenderRolls.Count; ++counter) { UInt32 defenderRoll = defender.DefenderRolls[counter]; foreach (var attacker in attackingDiceQuery) { // Check this attacker still has any dice left and both sides still have troops if (counter < attacker.AttackerRolls.Count && attacker.Results.TroopsLost < attacker.Army.NumberOfTroops && defender.Results.TroopsLost < defender.Army.NumberOfTroops) { UInt32 attackerRoll = attacker.AttackerRolls[counter]; if (attackerRoll >= defenderRoll) { defender.Results.TroopsLost += 1; } else { attacker.Results.TroopsLost += 1; } } } } break; } } // Apply troop loses to the armies var armyQuery = from armyResult in roundResult.m_ArmyResults join army in armies on armyResult.OriginRegionId equals army.OriginRegionId select new { Army = army, TroopsLost = armyResult.TroopsLost }; foreach (var army in armyQuery) { army.Army.NumberOfTroops -= army.TroopsLost; } return(roundResult); }