/// <summary> /// Rolls attacks for either attackers or defenders /// </summary> /// <param name="units">Unit stacks making attacks</param> /// <param name="results">List storing attack roll results</param> private void RollAttacks(List <UnitStack> units, List <AttackRollResultsCollection> results) { for (int i = 0; i < units.Count; i++) { if (!units[i].IsAffectedBy("Confusion")) { List <Attack> phaseAttacks = units[i].GetUnitType().GetAttacksForPhase(_currentPhase); if (phaseAttacks.Count > 0) { AttackRollResultsCollection unitStackAttackRolls = new AttackRollResultsCollection(); for (int j = 0; j < units[i].GetTotalQty(); j++) { for (int k = 0; k < phaseAttacks.Count; k++) { for (int l = 0; l < phaseAttacks[k].GetNumberOfAttacks(); l++) { AttackRollResult result = CombatHelper.Instance.CreateAnAttackRollResult(units[i], phaseAttacks[k]); unitStackAttackRolls.AddAttackRollResult(result); } } } results.Add(unitStackAttackRolls); } } } results.Sort((x, y) => x.GetAt(0).AttackSkill.CompareTo(y.GetAt(0).AttackSkill)); }
/// <summary> /// Get an attack roll result colleciton to resolve /// </summary> /// <returns>Attack roll result colleciton to resolve</returns> public AttackRollResultsCollection SelectAttackRollResultsCollection() { if (_currentAttacks != null && _currentAttacks.Count > 0) { return(_currentAttacks); } AttackRollResultsCollection result = GetAnAttackRollResultsCollection(); _currentAttacks = result; return(result); }
/// <summary> /// Handles defender selection and related animations. /// </summary> private void ProcessPhaseWithAttacks() { FileLogger.Trace("COMBAT VIEW", "ProcessPhaseWithAttacks"); // unit stacks could be created or destroyed - update the stack views UpdateUnitStackViews(); if (!_model.AreThereUnresolvedAttacks()) { _skipPhase = false; ProcessCombatTurn(); } else { // show all attacks UpdateAttackViews(); AttackRollResultsCollection currentAttackBatch = _model.SelectAttackRollResultsCollection(); if (currentAttackBatch != null) { FileLogger.Trace("COMBAT", "Selected attacks by " + currentAttackBatch.GetUnitStack().GetUnitType().GetName()); if (currentAttackBatch.GetUnitStack() != _currentAttacker) { SetNewStackForCurrentAttackView(currentAttackBatch.GetUnitStack()); // a new defender will be selected against a new attack _currentDefender = null; _skipStack = false; FileLogger.Trace("COMBAT VIEW", "ProcessPhaseWithAttacks: Setting skip stack to false"); } if (!_model.IsPlayerTurn()) { SelectAnNPCStackAsTarget(); } else { // if it's the player's turn // and he already selected a defending stack, resolve the attack if (_currentDefender != null && _currentDefender.GetTotalQty() > 0) { FileLogger.Trace("COMBAT", "Resolving an attack against " + _currentDefender.GetUnitType().GetName()); _model.ResolveCurrentAttack(false); } // else wait until the player will click on a stack view } } // else panic - there should be no case when there are unresolved attacks // but the model can't return an attack collection } }
/// <summary> /// Get an attack roll result collection /// </summary> /// <returns>An attack roll result collection selected</returns> private AttackRollResultsCollection GetAnAttackRollResultsCollection() { if (_isCombatOver) { return(null); } if (!_isDefenderPC || _defenderRollResults.Count == 0) { AttackRollResultsCollection result = GetFirstNonEmptyCollection(_attackerRollResults); if (result != null) { return(result); } } return(GetFirstNonEmptyCollection(_defenderRollResults)); }
/// <summary> /// Resolve current attack /// </summary> /// <param name="useEstimates">Whether estimated results will be used or honest rolls will be made</param> public void ResolveCurrentAttack(bool useEstimates) { bool ok = false; if (_currentTarget != null && _currentAttacks != null && _currentAttacks.Count > 0) { ok = ResolveAnAttackAgainstTarget(_currentTarget, _currentAttacks.GetAt(_currentAttacks.Count - 1), useEstimates); } if (!ok || _currentAttacks == null || _currentAttacks.Count == 0 || _currentTarget == null || _currentTarget.GetTotalQty() == 0) { _currentTarget = null; _currentAttacks = null; FileLogger.Trace("COMBAT", "ResolveCurrentAttack: reset current target."); } else { FileLogger.Trace("COMBAT", "ResolveCurrentAttack: " + _currentAttacks.Count + " attacks and " + _currentTarget.GetTotalQty() + " targets left."); } }
/// <summary> /// Resolve combat /// Used by the game to resolve NPC-to-NPC battles /// and by Strategos to plan invasions /// </summary> /// <param name="useEstimates">Whether estimated results will be used or honest rolls will be made</param> public void ResolveCombat(bool useEstimates = false) { while (!IsCombatOver()) { PerformPhaseActions(); AttackRollResultsCollection currentAttackBatch = SelectAttackRollResultsCollection(); if (currentAttackBatch != null) { FileLogger.Trace("COMBAT", "Selected attacks by " + currentAttackBatch.GetUnitStack().GetUnitType().GetName()); UnitStack target = SelectDefendingStack(); if (target != null) { FileLogger.Trace("COMBAT", "Selected " + target.GetUnitType().GetName() + " as a target"); ResolveCurrentAttack(useEstimates); } else { PerformEndOfCombatCheck(); } } } }
/// <summary> /// Class constructor /// </summary> /// <param name="attacks">Collection of attack roll results</param> public UnitStackAttackedEvent(AttackRollResultsCollection attacks) { _attacks = attacks; }