Example #1
0
        /// <summary>
        /// Implements the processes involved in a battle between two armies in the field
        /// </summary>
        /// <returns>bool indicating whether attacking army is victorious</returns>
        /// <remarks>
        /// Predicate: assumes attacker has sufficient days
        /// Predicate: assumes attacker has leader
        /// Predicate: assumes attacker in same fief as defender
        /// Predicate: assumes defender not besieged in keep
        /// Predicate: assumes attacker and defender not same army
        /// </remarks>
        /// <param name="attacker">The attacking army</param>
        /// <param name="defender">The defending army</param>
        /// <param name="circumstance">string indicating circumstance of battle</param>
        public static bool GiveBattle(Army attacker, Army defender, out ProtoBattle battleResults, List <Army> attackerAllies = null, List <Army> defenderAllies = null, string circumstance = "battle")
        {
            Contract.Requires(attacker != null && defender != null && circumstance != null);
            battleResults = new ProtoBattle();
            bool attackerVictorious = false;
            bool battleHasCommenced = false;
            bool attackerLeaderDead = false;
            bool defenderLeaderDead = false;
            // check if losing army has disbanded
            bool attackerDisbanded = false;
            bool defenderDisbanded = false;

            bool siegeRaised = false;

            uint[]   battleValues      = new uint[2];
            double[] casualtyModifiers = new double[2];
            double   statureChange     = 0;

            // if applicable, get siege
            Siege  thisSiege   = null;
            string thisSiegeID = defender.CheckIfBesieger();

            if (!String.IsNullOrWhiteSpace(thisSiegeID))
            {
                // get siege
                thisSiege = Globals_Game.siegeMasterList[thisSiegeID];
            }

            // get starting troop numbers
            uint attackerStartTroops = attacker.CalcArmySize();
            uint defenderStartTroops = defender.CalcArmySize();
            uint attackerCasualties  = 0;
            uint defenderCasualties  = 0;

            if (attackerAllies != null)
            {
                if (attackerAllies.Count > 0)
                {
                    for (int i = 0; i < attackerAllies.Count; i++)
                    {
                        attackerStartTroops += attackerAllies[i].CalcArmySize();
                        battleResults.attackerAllies.Add(attackerAllies[i].GetOwner().familyID);
                    }
                }
            }
            if (defenderAllies != null)
            {
                if (defenderAllies.Count > 0)
                {
                    for (int i = 0; i < defenderAllies.Count; i++)
                    {
                        defenderStartTroops += defenderAllies[i].CalcArmySize();
                        battleResults.defenderAllies.Add(defenderAllies[i].GetOwner().familyID);
                    }
                }
            }
            // get leaders
            Character attackerLeader = attacker.GetLeader();
            Character defenderLeader = defender.GetLeader();


            // if(attackerLeader!=null) {
            battleResults.attackerLeader = attackerLeader.firstName + " " + attackerLeader.familyName;
            //  }
            //  if(defenderLeader!=null) {
            battleResults.defenderLeader = defenderLeader.firstName + " " + defenderLeader.familyName;
            //   }

            battleResults.attackerOwner  = attacker.GetOwner().firstName + "  " + attacker.GetOwner().familyName;
            battleResults.defenderOwner  = defender.GetOwner().firstName + " " + defender.GetOwner().familyName;
            battleResults.battleLocation = attacker.GetLocation().id;
            // introductory text for message
            switch (circumstance)
            {
            case "pillage":
                battleResults.circumstance = 1;
                break;

            case "siege":
                battleResults.circumstance = 2;
                break;

            default:
                battleResults.circumstance = 0;
                break;
            }

            // get battle values for both armies
            switch (circumstance)
            {
            case "pillage":
            {
                battleValues = attacker.CalculateBattleValues(defender, defenderAllies);
                break;
            }

            case "siege":
            {
                battleValues = attacker.CalculateBattleValues(defender, attackerAllies, defenderAllies);
                break;
            }

            default:
            {
                battleValues = attacker.CalculateBattleValues(defender, attackerAllies, defenderAllies);
                break;
            }
            }
            // check if attacker has managed to bring defender to battle
            // case 1: defending army sallies during siege to attack besieger = battle always occurs
            if (circumstance.Equals("siege"))
            {
                battleHasCommenced = true;
            }
            // case 2: defending militia attacks pillaging army during pollage = battle always occurs
            else if (circumstance.Equals("pillage"))
            {
                battleHasCommenced = true;
            }
            // case 3: defender aggression and combatOdds allows battle
            else if (defender.aggression != 0)
            {
                if (defender.aggression == 1)
                {
                    // get odds
                    int battleOdds = Battle.GetBattleOdds(attacker, defender, defenderAllies, attackerAllies);

                    // if odds OK, give battle
                    if (battleOdds <= defender.combatOdds)
                    {
                        battleHasCommenced = true;
                    }

                    // if not, check for battle
                    else
                    {
                        battleHasCommenced = Battle.BringToBattle(battleValues[0], battleValues[1], circumstance);

                        if (!battleHasCommenced)
                        {
                            defender.ProcessRetreat(1);
                        }
                    }
                }

                else
                {
                    battleHasCommenced = true;
                }
            }

            // otherwise, check to see if the attacker can bring the defender to battle
            else
            {
                battleHasCommenced = Battle.BringToBattle(battleValues[0], battleValues[1], circumstance);
                if (!battleHasCommenced)
                {
                    defender.ProcessRetreat(1);
                }
            }
            battleResults.battleTookPlace = battleHasCommenced;
            if (battleHasCommenced)
            {
                List <string> disbandedArmies = new List <string>();
                List <string> retreatedArmies = new List <string>();
                List <string> deadCharacters  = new List <string>();
                // WHO HAS WON?
                // calculate if attacker has won
                attackerVictorious = Battle.DecideBattleVictory(battleValues[0], battleValues[1]);

                // UPDATE STATURE
                if (attackerVictorious)
                {
                    statureChange = 0.8 * (defender.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeAttacker = statureChange;
                    attacker.GetOwner().AdjustStatureModifier(statureChange);
                    attacker.moraleChange(statureChange);
                    if (attackerAllies != null)
                    {
                        if (attackerAllies.Count > 0)
                        {
                            for (int i = 0; i < attackerAllies.Count; i++)
                            {
                                attackerAllies[i].GetOwner().AdjustStatureModifier(statureChange);
                                attackerAllies[i].moraleChange(statureChange);
                            }
                        }
                    }
                    statureChange = -0.5 * (attacker.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeDefender = statureChange;
                    defender.GetOwner().AdjustStatureModifier(statureChange);
                    defender.moraleChange(statureChange);
                    if (defenderAllies != null)
                    {
                        if (defenderAllies.Count > 0)
                        {
                            for (int i = 0; i < defenderAllies.Count; i++)
                            {
                                defenderAllies[i].GetOwner().AdjustStatureModifier(statureChange);
                                defenderAllies[i].moraleChange(statureChange);
                            }
                        }
                    }
                }
                else
                {
                    statureChange = 0.8 * (attacker.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeDefender = statureChange;
                    defender.GetOwner().AdjustStatureModifier(statureChange);
                    defender.moraleChange(statureChange);
                    if (defenderAllies != null)
                    {
                        if (defenderAllies.Count > 0)
                        {
                            for (int i = 0; i < defenderAllies.Count; i++)
                            {
                                defenderAllies[i].GetOwner().AdjustStatureModifier(statureChange);
                                defenderAllies[i].moraleChange(statureChange);
                            }
                        }
                    }
                    statureChange = -0.5 * (defender.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeAttacker = statureChange;
                    attacker.GetOwner().AdjustStatureModifier(statureChange);
                    attacker.moraleChange(statureChange);
                    if (attackerAllies != null)
                    {
                        if (attackerAllies.Count > 0)
                        {
                            for (int i = 0; i < attackerAllies.Count; i++)
                            {
                                attackerAllies[i].GetOwner().AdjustStatureModifier(statureChange);
                                attackerAllies[i].moraleChange(statureChange);
                            }
                        }
                    }
                }

                // CASUALTIES
                // calculate troop casualties for both sides
                casualtyModifiers = Battle.CalculateBattleCasualties(attackerStartTroops, defenderStartTroops, battleValues[0], battleValues[1], attackerVictorious);


                uint totalAttackTroopsLost = 0;
                uint totalDefendTroopsLost = 0;

                // if losing side sustains >= 50% casualties, disbands
                if (attackerVictorious)
                {
                    // either indicate losing army to be disbanded
                    if (casualtyModifiers[1] >= 0.5)
                    {
                        defenderDisbanded = true;
                        disbandedArmies.Add(defender.owner);
                        totalDefendTroopsLost = defender.CalcArmySize();
                        if (defenderAllies != null)
                        {
                            if (defenderAllies.Count > 0)
                            {
                                for (int i = 0; i < defenderAllies.Count; i++)
                                {
                                    disbandedArmies.Add(defenderAllies[i].owner);
                                    totalDefendTroopsLost += defenderAllies[i].CalcArmySize();
                                }
                            }
                        }
                    }
                    // OR apply troop casualties to losing army
                    else
                    {
                        totalDefendTroopsLost = defender.ApplyTroopLosses(casualtyModifiers[1]);
                        if (defenderAllies != null)
                        {
                            if (defenderAllies.Count > 0)
                            {
                                for (int i = 0; i < defenderAllies.Count; i++)
                                {
                                    totalDefendTroopsLost += defenderAllies[i].ApplyTroopLosses(casualtyModifiers[1]);
                                }
                            }
                        }
                    }

                    // apply troop casualties to winning army
                    totalAttackTroopsLost = attacker.ApplyTroopLosses(casualtyModifiers[0]);
                    if (attackerAllies != null)
                    {
                        if (attackerAllies.Count > 0)
                        {
                            for (int i = 0; i < attackerAllies.Count; i++)
                            {
                                totalAttackTroopsLost += attackerAllies[i].ApplyTroopLosses(casualtyModifiers[0]);
                            }
                        }
                    }
                }
                else
                {
                    if (casualtyModifiers[0] >= 0.5)
                    {
                        attackerDisbanded = true;
                        disbandedArmies.Add(attacker.owner);
                        totalAttackTroopsLost = attacker.CalcArmySize();
                        if (attackerAllies != null)
                        {
                            if (attackerAllies.Count > 0)
                            {
                                for (int i = 0; i < attackerAllies.Count; i++)
                                {
                                    disbandedArmies.Add(attackerAllies[i].owner);
                                    totalAttackTroopsLost += attackerAllies[i].CalcArmySize();
                                }
                            }
                        }
                    }
                    else
                    {
                        totalAttackTroopsLost = attacker.ApplyTroopLosses(casualtyModifiers[0]);
                        if (attackerAllies != null)
                        {
                            if (attackerAllies.Count > 0)
                            {
                                for (int i = 0; i < attackerAllies.Count; i++)
                                {
                                    totalAttackTroopsLost += attackerAllies[i].ApplyTroopLosses(casualtyModifiers[0]);
                                }
                            }
                        }
                    }

                    totalDefendTroopsLost = defender.ApplyTroopLosses(casualtyModifiers[1]);
                    if (defenderAllies != null)
                    {
                        if (defenderAllies.Count > 0)
                        {
                            for (int i = 0; i < defenderAllies.Count; i++)
                            {
                                totalDefendTroopsLost += defenderAllies[i].ApplyTroopLosses(casualtyModifiers[1]);
                            }
                        }
                    }
                }
                battleResults.attackerCasualties = totalAttackTroopsLost;
                battleResults.defenderCasualties = totalDefendTroopsLost;
                // UPDATE TOTAL SIEGE LOSSES, if appropriate
                // NOTE: the defender in this battle is the attacker in the siege and v.v.
                if (thisSiege != null)
                {
                    // update total siege attacker (defender in this battle) losses
                    thisSiege.totalCasualtiesAttacker += Convert.ToInt32(totalDefendTroopsLost);

                    // update total siege defender (attacker in this battle) losses
                    if (circumstance.Equals("siege"))
                    {
                        thisSiege.totalCasualtiesDefender += Convert.ToInt32(totalAttackTroopsLost);
                    }
                }

                // get casualty figures (for message)
                if (!attackerDisbanded)
                {
                    // get attacker casualties
                    attackerCasualties = totalAttackTroopsLost;
                }
                if (!defenderDisbanded)
                {
                    // get defender casualties
                    defenderCasualties = totalDefendTroopsLost;
                }

                // DAYS
                // adjust days
                // NOTE: don't adjust days if is a siege (will be deducted elsewhere)
                if (!circumstance.Equals("siege"))
                {
                    if (attackerLeader != null)
                    {
                        attackerLeader.AdjustDays(1);
                    }
                    // need to check for defender having no leader
                    if (defenderLeader != null)
                    {
                        defenderLeader.AdjustDays(1);
                    }
                    else
                    {
                        defender.days -= 1;
                    }
                }

                // RETREATS
                // create array of armies (for easy processing)
                Army[] bothSides = { attacker, defender };

                // check if either army needs to retreat
                int[] retreatDistances = Battle.CheckForRetreat(attacker, defender, casualtyModifiers[0], casualtyModifiers[1], attackerVictorious);

                // if is pillage or siege, attacking army (the fief's army) doesn't retreat
                // if is pillage, the defending army (the pillagers) always retreats if has lost
                if (circumstance.Equals("pillage") || circumstance.Equals("siege"))
                {
                    retreatDistances[0] = 0;
                }

                if (circumstance.Equals("pillage"))
                {
                    if (attackerVictorious)
                    {
                        retreatDistances[1] = 1;
                    }
                }

                // if have retreated, perform it
                for (int i = 0; i < retreatDistances.Length; i++)
                {
                    if (retreatDistances[i] > 0)
                    {
                        bothSides[i].ProcessRetreat(retreatDistances[i]);
                    }
                }

                if (attackerAllies != null)
                {
                    if (attackerAllies.Count > 0)
                    {
                        for (int i = 0; i < attackerAllies.Count; i++)
                        {
                            attackerAllies[i].ProcessRetreat(retreatDistances[0]);
                        }
                    }
                }

                if (defenderAllies != null)
                {
                    if (defenderAllies.Count > 0)
                    {
                        for (int i = 0; i < defenderAllies.Count; i++)
                        {
                            defenderAllies[i].ProcessRetreat(retreatDistances[1]);
                        }
                    }
                }
                // If attacker has retreated add to retreat list
                if (retreatDistances[0] > 0)
                {
                    retreatedArmies.Add(battleResults.attackerOwner);
                    for (int i = 0; i < attackerAllies.Count; i++)
                    {
                        retreatedArmies.Add(attackerAllies[i].owner);
                    }
                }
                // If defender retreated add to retreat list
                if (retreatDistances[1] > 0)
                {
                    retreatedArmies.Add(battleResults.defenderOwner);
                    for (int i = 0; i < defenderAllies.Count; i++)
                    {
                        retreatedArmies.Add(defenderAllies[i].owner);
                    }
                }
                // PC/NPC INJURIES/DEATHS
                // check if any PCs/NPCs have been wounded or killed
                bool characterDead = false;

                // 1. ATTACKER
                uint friendlyBV = battleValues[0];
                uint enemyBV    = battleValues[1];

                // if army leader a PC, check entourage
                if (attackerLeader is PlayerCharacter)
                {
                    for (int i = 0; i < (attackerLeader as PlayerCharacter).myNPCs.Count; i++)
                    {
                        if ((attackerLeader as PlayerCharacter).myNPCs[i].inEntourage)
                        {
                            characterDead = (attackerLeader as PlayerCharacter).myNPCs[i].CalculateCombatInjury(casualtyModifiers[0]);
                        }

                        // process death, if applicable
                        if (characterDead)
                        {
                            (attackerLeader as PlayerCharacter).myNPCs[i].ProcessDeath("injury");
                        }
                    }
                }

                // check army leader
                if (attackerLeader != null)
                {
                    attackerLeaderDead = attackerLeader.CalculateCombatInjury(casualtyModifiers[0]);
                }


                // process death, if applicable
                if (attackerLeaderDead)
                {
                    deadCharacters.Add(attackerLeader.firstName + " " + attackerLeader.familyName);
                    Character newLeader = null;

                    // if is pillage, do NOT elect new leader for attacking army
                    if (!circumstance.Equals("pillage"))
                    {
                        // if possible, elect new leader from entourage
                        if (attackerLeader is PlayerCharacter)
                        {
                            if ((attackerLeader as PlayerCharacter).myNPCs.Count > 0)
                            {
                                // get new leader
                                newLeader = (attackerLeader as PlayerCharacter).ElectNewArmyLeader();
                            }
                        }

                        // assign newLeader (can assign null leader if none found)
                        attacker.AssignNewLeader(newLeader);
                    }
                }
                else
                {
                    // if pillage, if fief's army loses, make sure bailiff always returns to keep
                    if (circumstance.Equals("pillage"))
                    {
                        if (!attackerVictorious)
                        {
                            attackerLeader.inKeep = true;
                        }
                    }
                }

                // 2. DEFENDER

                // need to check if defending army had a leader
                if (defenderLeader != null)
                {
                    // if army leader a PC, check entourage
                    if (defenderLeader is PlayerCharacter)
                    {
                        for (int i = 0; i < (defenderLeader as PlayerCharacter).myNPCs.Count; i++)
                        {
                            if ((defenderLeader as PlayerCharacter).myNPCs[i].inEntourage)
                            {
                                characterDead = (defenderLeader as PlayerCharacter).myNPCs[i].CalculateCombatInjury(casualtyModifiers[1]);
                            }

                            // process death, if applicable
                            if (characterDead)
                            {
                                (defenderLeader as PlayerCharacter).myNPCs[i].ProcessDeath("injury");
                            }
                        }
                    }

                    // check army leader
                    defenderLeaderDead = defenderLeader.CalculateCombatInjury(casualtyModifiers[1]);

                    // process death, if applicable
                    if (defenderLeaderDead)
                    {
                        deadCharacters.Add(defenderLeader.firstName + " " + defenderLeader.familyName);
                        Character newLeader = null;

                        // if possible, elect new leader from entourage
                        if (defenderLeader is PlayerCharacter)
                        {
                            if ((defenderLeader as PlayerCharacter).myNPCs.Count > 0)
                            {
                                // get new leader
                                newLeader = (defenderLeader as PlayerCharacter).ElectNewArmyLeader();
                            }
                        }

                        // assign newLeader (can assign null leader if none found)
                        defender.AssignNewLeader(newLeader);
                    }
                }

                battleResults.deaths          = deadCharacters.ToArray();
                battleResults.retreatedArmies = retreatedArmies.ToArray();

                battleResults.attackerVictorious = attackerVictorious;

                // check for SIEGE RELIEF
                if (thisSiege != null)
                {
                    battleResults.isSiege       = true;
                    battleResults.siegeBesieger = thisSiege.GetBesiegingPlayer().firstName + " " + thisSiege.GetBesiegingPlayer().familyName;
                    battleResults.siegeDefender = thisSiege.GetDefendingPlayer().firstName + " " + thisSiege.GetDefendingPlayer().familyName;
                    // attacker (relieving army) victory or defender (besieging army) retreat = relief
                    if ((attackerVictorious) || (retreatDistances[1] > 0))
                    {
                        // indicate siege raised
                        siegeRaised = true;
                        battleResults.siegeRaised = true;
                    }

                    // check to see if siege raised due to death of siege owner with no heir
                    else if ((defenderLeaderDead) && ((defenderLeader as PlayerCharacter) == thisSiege.GetBesiegingPlayer()))
                    {
                        // get siege owner's heir
                        Character thisHeir = (defenderLeader as PlayerCharacter).GetHeir();

                        if (thisHeir == null)
                        {
                            battleResults.DefenderDeadNoHeir = true;
                            // indicate siege raised
                            siegeRaised = true;
                        }
                    }
                }
            }

            // =================== construct and send JOURNAL ENTRY
            // ID
            uint entryID = Globals_Game.GetNextJournalEntryID();

            // personae
            // personae tags vary depending on circumstance
            string attackOwnTag  = "|attackerOwner";
            string attackLeadTag = "|attackerLeader";
            string defendOwnTag  = "|defenderOwner";
            string defendLeadTag = "|defenderLeader";

            if ((circumstance.Equals("pillage")) || (circumstance.Equals("siege")))
            {
                attackOwnTag  = "|sallyOwner";
                attackLeadTag = "|sallyLeader";
                defendOwnTag  = "|defenderAgainstSallyOwner";
                defendLeadTag = "|defenderAgainstSallyLeader";
            }
            List <string> tempPersonae = new List <string>();

            tempPersonae.Add(defender.GetOwner().charID + defendOwnTag);
            if (attackerLeader != null)
            {
                tempPersonae.Add(attackerLeader.charID + attackLeadTag);
            }
            if (defenderLeader != null)
            {
                tempPersonae.Add(defenderLeader.charID + defendLeadTag);
            }
            tempPersonae.Add(attacker.GetOwner().charID + attackOwnTag);
            tempPersonae.Add(attacker.GetLocation().owner.charID + "|fiefOwner");
            if ((!circumstance.Equals("pillage")) && (!circumstance.Equals("siege")))
            {
                tempPersonae.Add("all|all");
            }
            string[] battlePersonae = tempPersonae.ToArray();

            // location
            string battleLocation = attacker.GetLocation().id;


            // put together new journal entry
            JournalEntry battleResult = new JournalEntry(entryID, Globals_Game.clock.currentYear, Globals_Game.clock.currentSeason, battlePersonae, "battle", battleResults, loc: battleLocation);

            // add new journal entry to pastEvents
            Globals_Game.AddPastEvent(battleResult);

            // display pop-up informational message
            battleResults.ActionType   = Actions.Update;
            battleResults.ResponseType = DisplayMessages.BattleResults;
            if (battleHasCommenced)
            {
                Globals_Game.UpdatePlayer(defender.GetOwner().playerID, DisplayMessages.BattleBringSuccess, new string[] { battleResults.attackerOwner });
            }
            else
            {
                Globals_Game.UpdatePlayer(defender.GetOwner().playerID, DisplayMessages.BattleBringFail, new string[] { battleResults.attackerOwner });
            }

            // end siege if appropriate
            if (siegeRaised)
            {
                //HACK
                thisSiege.SiegeEnd(false, DisplayMessages.BattleResults, new string[] { DisplaySiegeResults(battleResults) });
                thisSiege = null;

                // ensure if siege raised correct value returned to Form1.siegeReductionRound method
                if (circumstance.Equals("siege"))
                {
                    attackerVictorious = true;
                }
            }

            // process leader deaths
            if (defenderLeaderDead)
            {
                defenderLeader.ProcessDeath("injury");
            }
            else if (attackerLeaderDead)
            {
                attackerLeader.ProcessDeath("injury");
            }


            // DISBANDMENT

            // if is pillage, attacking (temporary) army always disbands after battle
            if (circumstance.Equals("pillage"))
            {
                attackerDisbanded = true;
            }

            // process army disbandings (after all other functions completed)
            if (attackerDisbanded)
            {
                attacker.DisbandArmy();
                attacker = null;
            }

            if (defenderDisbanded)
            {
                defender.DisbandArmy();
                defender = null;
            }

            return(attackerVictorious);
        }