Example #1
0
        public bool ExecuteTurn()
        {
            lock (battleLock)
            {
                battleRandom.UpdateSeed(Round, Turn);

                ICombatList offensiveCombatList;
                ICombatList defensiveCombatList;
                BattleSide  sideAttacking;


                // This will finalize any reports already started.
                BattleReport.CompleteReport(ReportState.Staying);

                #region Battle Start

                if (!BattleStarted)
                {
                    // Makes sure battle is valid before even starting it
                    // This shouldnt really happen but I remember it happening in the past
                    // so until we can make sure that we dont even start invalid battles, it's better to leave it
                    if (!IsBattleValid())
                    {
                        BattleEnded(false);
                        return(false);
                    }

                    BringWaitingTroopsIntoBattle();

                    BattleStarted = true;
                    BattleReport.CreateBattleReport();
                    EnterBattle(this, Attackers, Defenders);
                }

                #endregion

                #region Targeting

                List <CombatList.Target> currentDefenders;
                ICombatGroup             attackerGroup;
                ICombatObject            attackerObject;

                do
                {
                    #region Find Attacker

                    var newRound =
                        !battleOrder.NextObject(Round,
                                                Attackers,
                                                Defenders,
                                                out attackerObject,
                                                out attackerGroup,
                                                out sideAttacking);

                    // Save the offensive/defensive side relative to the attacker to make it easier in this function to know
                    // which side is attacking.
                    defensiveCombatList = sideAttacking == BattleSide.Attack ? Defenders : Attackers;
                    offensiveCombatList = sideAttacking == BattleSide.Attack ? Attackers : Defenders;

                    if (newRound)
                    {
                        ++Round;
                        Turn = 0;

                        BringWaitingTroopsIntoBattle();

                        EnterRound(this, Attackers, Defenders, Round);

                        // Since the EventEnterRound can remove the object from battle, we need to make sure he's still in the battle
                        // If they aren't, then we just find a new attacker
                        if (attackerObject != null && !offensiveCombatList.AllCombatObjects().Contains(attackerObject))
                        {
                            continue;
                        }
                    }

                    // Verify battle is still good to go
                    if (attackerObject == null || !IsBattleValid())
                    {
                        BattleEnded(true);
                        return(false);
                    }

                    #endregion

                    #region Find Target(s)

                    var targetResult = defensiveCombatList.GetBestTargets(BattleId,
                                                                          attackerObject,
                                                                          out currentDefenders,
                                                                          battleFormulas.GetNumberOfHits(attackerObject, defensiveCombatList),
                                                                          Round);

                    if (currentDefenders.Count == 0 || attackerObject.Stats.Atk == 0)
                    {
                        attackerObject.ParticipatedInRound(Round);
                        dbManager.Save(attackerObject);
                        SkippedAttacker(this, sideAttacking, attackerGroup, attackerObject);

                        // If the attacker can't attack because it has no one in range, then we skip him and find another target right away.
                        if (targetResult == CombatList.BestTargetResult.NoneInRange)
                        {
                            continue;
                        }

                        return(true);
                    }

                    #endregion

                    break;
                }while (true);

                #endregion

                for (int attackIndex = 0; attackIndex < currentDefenders.Count; attackIndex++)
                {
                    var defender = currentDefenders[attackIndex];

                    // Make sure the target is still in the battle (they can leave if someone else in the group took dmg and caused the entire group to leave)
                    // We just skip incase they left while we were attacking
                    // which means if the attacker is dealing splash they may deal less hits in this fringe case
                    if (!defensiveCombatList.AllCombatObjects().Contains(defender.CombatObject))
                    {
                        continue;
                    }

                    // Target is still in battle, attack it
                    decimal carryOverDmg;
                    AttackTarget(offensiveCombatList,
                                 defensiveCombatList,
                                 attackerGroup,
                                 attackerObject,
                                 sideAttacking,
                                 defender,
                                 attackIndex,
                                 Round,
                                 out carryOverDmg);

                    // Add another target if we have to carry over some dmg and our current hit isnt from a carry over already
                    if (carryOverDmg > 0m && !defender.DamageCarryOverPercentage.HasValue)
                    {
                        List <CombatList.Target> carryOverDefender;
                        defensiveCombatList.GetBestTargets(BattleId,
                                                           attackerObject,
                                                           out carryOverDefender,
                                                           1,
                                                           Round);

                        if (carryOverDefender.Count > 0)
                        {
                            var target = carryOverDefender.First();
                            target.DamageCarryOverPercentage = carryOverDmg;
                            currentDefenders.Insert(attackIndex + 1, target);
                        }
                    }
                }

                // Just a safety check
                if (attackerObject.Disposed)
                {
                    throw new Exception("Attacker has been improperly disposed");
                }

                attackerObject.ParticipatedInRound(Round);

                dbManager.Save(attackerObject);

                ExitTurn(this, Attackers, Defenders, Turn++);

                if (!IsBattleValid())
                {
                    BattleEnded(true);
                    return(false);
                }

                // Remove any attackers that don't have anyone in range
                var groupsWithoutAnyoneInRange = Attackers.Where(attacker => attacker.All(combatObjects => !Defenders.HasInRange(combatObjects))).ToList();
                foreach (var group in groupsWithoutAnyoneInRange)
                {
                    Remove(group, BattleSide.Attack, ReportState.Exiting);
                }

                return(true);
            }
        }