Пример #1
0
        /// <summary>
        /// Implements the processes involved in the pillage of a fief by an army
        /// </summary>
        /// <param name="a">The pillaging army</param>
        /// <param name="f">The fief being pillaged</param>
        public static ProtoMessage PillageFief(Army a, Fief f)
        {
            ProtoMessage result           = new ProtoMessage();
            bool         pillageCancelled = false;
            bool         bailiffPresent   = false;
            Army         fiefArmy         = null;

            // check if bailiff present in fief (he'll lead the army)
            if (f.bailiff != null)
            {
                for (int i = 0; i < f.charactersInFief.Count; i++)
                {
                    if (f.charactersInFief[i] == f.bailiff)
                    {
                        bailiffPresent = true;
                        break;
                    }
                }
            }

            // if bailiff is present, create an army and attempt to give battle
            // no bailiff = no leader = pillage is unopposed by defending forces
            if (bailiffPresent)
            {
                // create temporary army for battle
                fiefArmy = f.CreateDefendingArmy();

                // give battle and get result
                ProtoBattle battleResults;
                pillageCancelled = Battle.GiveBattle(fiefArmy, a, out battleResults, circumstance: "pillage");

                if (pillageCancelled)
                {
                    string toDisplay = "The pillaging force has been forced to retreat by the fief's defenders!";
                    result.ResponseType = DisplayMessages.PillageRetreat;
                    // Let owner know that pillage attempt has been thwarted
                    Globals_Game.UpdatePlayer(f.owner.playerID, DisplayMessages.PillageRetreat);
                    return(result);
                }

                else
                {
                    // check still have enough days left
                    if (a.days < 7)
                    {
                        // Inform fief owner pillage attempt thwarted
                        Globals_Game.UpdatePlayer(f.owner.playerID, DisplayMessages.PillageDays);
                        result.ResponseType = DisplayMessages.PillageDays;
                        pillageCancelled    = true;
                        return(result);
                    }
                }
            }

            if (!pillageCancelled)
            {
                // process pillage
                return(Pillage_Siege.ProcessPillage(f, a));
            }
            result.ResponseType = DisplayMessages.Success;
            result.Message      = "The pillage was successful";
            return(result);
        }
Пример #2
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, 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;

            // 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
            battleValues = attacker.CalculateBattleValues(defender);

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

                    // 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);
                    statureChange = -0.5 * (attacker.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeDefender = statureChange;
                    defender.GetOwner().AdjustStatureModifier(statureChange);
                }
                else
                {
                    statureChange = 0.8 * (attacker.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeDefender = statureChange;
                    defender.GetOwner().AdjustStatureModifier(statureChange);
                    statureChange = -0.5 * (defender.CalcArmySize() / Convert.ToDouble(10000));
                    battleResults.statureChangeAttacker = statureChange;
                    attacker.GetOwner().AdjustStatureModifier(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();
                    }
                    // OR apply troop casualties to losing army
                    else
                    {
                        totalDefendTroopsLost = defender.ApplyTroopLosses(casualtyModifiers[1]);
                    }

                    // apply troop casualties to winning army
                    totalAttackTroopsLost = attacker.ApplyTroopLosses(casualtyModifiers[0]);
                }
                else
                {
                    if (casualtyModifiers[0] >= 0.5)
                    {
                        attackerDisbanded = true;
                        disbandedArmies.Add(attacker.owner);
                        totalAttackTroopsLost = attacker.CalcArmySize();
                    }
                    else
                    {
                        totalAttackTroopsLost = attacker.ApplyTroopLosses(casualtyModifiers[0]);
                    }

                    totalDefendTroopsLost = defender.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 attacker has retreated add to retreat list
                if (retreatDistances[0] > 0)
                {
                    retreatedArmies.Add(battleResults.attackerOwner);
                }
                // If defender retreated add to retreat list
                if (retreatDistances[1] > 0)
                {
                    retreatedArmies.Add(battleResults.defenderOwner);
                }
                // 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);
        }
Пример #3
0
 /// <summary>
 /// Respond to ransom demands
 /// </summary>
 /// <param name="paid">Whether or not ransom is to be paid</param>
 /// <returns>Bool indicating success</returns>
 public bool RansomResponse(bool paid, out ProtoMessage error)
 {
     error = null;
     // Check if type is ransom
     if (this.type.Equals("ransom"))
     {
         // Check if already replied
         if (replied)
         {
             // Already replied
             error = new ProtoMessage();
             error.ResponseType = DisplayMessages.RansomRepliedAlready;
             return(false);
         }
         Character       captive = null;
         PlayerCharacter captor;
         PlayerCharacter captiveHeadOfHousehold;
         // Confirm captive is still alive and being held
         foreach (string persona in personae)
         {
             string[] split = persona.Split(new char[] { '|' });
             if (split[1].Equals("Captive"))
             {
                 captive = Globals_Game.getCharFromID(split[0]);
             }
         }
         if (captive == null)
         {
             // Captive does not exist- error
             error = new ProtoMessage();
             error.ResponseType = DisplayMessages.ErrorGenericCharacterUnidentified;
             Globals_Server.logError("Captive unidentified in JEntry: " + this.jEntryID);
             return(false);
         }
         else if (!captive.isAlive)
         {
             // Captive is dead
             error = new ProtoMessage();
             error.ResponseType = DisplayMessages.RansomCaptiveDead;
             return(false);
         }
         captor = Globals_Game.getCharFromID(captive.captorID) as PlayerCharacter;
         if (captor == null)
         {
             // Captive does not have a captor
             error = new ProtoMessage();
             error.ResponseType = DisplayMessages.NotCaptive;
             return(false);
         }
         captiveHeadOfHousehold = captive.GetPlayerCharacter();
         if (captiveHeadOfHousehold == null)
         {
             // Captive is not an employee, family member or player character
             Globals_Server.logError("Captive has no PlayerCharacter: " + captive.charID);
             error = new ProtoMessage();
             error.ResponseType = DisplayMessages.ErrorGenericCharacterUnidentified;
             return(false);
         }
         if (paid)
         {
             // Get ransom amount
             uint ransom = 0;
             if (!UInt32.TryParse(entryDetails.MessageFields[1], out ransom))
             {
                 // Error parsing to int
                 Globals_Server.logError("Could not parse ransom to uint in JEntry: " + jEntryID);
                 error = new ProtoMessage();
                 error.ResponseType = DisplayMessages.ErrorGenericMessageInvalid;
                 return(false);
             }
             else
             {
                 // Check captive's head of household has the funds to release
                 if (captiveHeadOfHousehold.GetHomeFief().GetAvailableTreasury(false) >= ransom)
                 {
                     if (!captiveHeadOfHousehold.GetHomeFief().TreasuryTransfer(captor.GetHomeFief(), (Int32)ransom, out error))
                     {
                         return(false);
                     }
                     else
                     {
                         // Release captive
                         captor.ReleaseCaptive(captive);
                         replied = true;
                         Globals_Game.UpdatePlayer(captor.playerID, DisplayMessages.RansomPaid, new string[] { captive.firstName + " " + captive.familyName });
                         return(true);
                     }
                 }
                 else
                 {
                     // Insufficient funds
                     error = new ProtoMessage();
                     error.ResponseType = DisplayMessages.ErrorGenericInsufficientFunds;
                     return(false);
                 }
             }
         }
         // If not paying ransom, inform captor
         else
         {
             // Create journal entry and update captor
             string[]     newPersonae   = new string[] { captive.charID + "|Captive", captor.charID + "|Captor", captiveHeadOfHousehold.charID + "|HeadOfCaptiveFamily" };
             ProtoMessage deniedMessage = new ProtoMessage();
             deniedMessage.ResponseType  = DisplayMessages.RansonDenied;
             deniedMessage.MessageFields = new string[] { captive.firstName + " " + captive.familyName, captor.firstName + " " + captor.familyName, captiveHeadOfHousehold.firstName + " " + captiveHeadOfHousehold.familyName };
             Globals_Game.UpdatePlayer(captor.playerID, deniedMessage);
             JournalEntry ransomDenied = new JournalEntry(Globals_Game.GetNextJournalEntryID(), Globals_Game.clock.currentYear, Globals_Game.clock.currentSeason, newPersonae, "ransomDenied", deniedMessage);
             Globals_Game.AddPastEvent(ransomDenied);
             replied = true;
             return(true);
         }
     }
     else
     {
         // Not a ransom
         error = new ProtoMessage();
         error.ResponseType = DisplayMessages.EntryNotRansom;
         return(false);
     }
 }