示例#1
0
        /// <summary>
        /// Processes functions involved in lodging a new ownership (and kingship) challenge
        /// Returns ProtoMessage in case of error
        /// </summary>
        public ProtoMessage LodgeOwnershipChallenge(PlayerCharacter challenger)
        {
            bool         proceed = true;
            ProtoMessage result  = null;

            // ensure aren't current owner
            if (challenger == this.owner)
            {
                result = new ProtoMessage();
                result.ResponseType = DisplayMessages.KingdomAlreadyKing;
            }

            else
            {
                // create and send new OwnershipChallenge
                OwnershipChallenge newChallenge = new OwnershipChallenge(Globals_Game.GetNextOwnChallengeID(), challenger.charID, "kingdom", this.id);
                proceed = Globals_Game.AddOwnershipChallenge(newChallenge, out result);
            }

            if (proceed)
            {
                // create and send journal entry
                // get interested parties
                PlayerCharacter currentOwner = this.owner;

                // ID
                uint entryID = Globals_Game.GetNextJournalEntryID();

                // date
                uint year   = Globals_Game.clock.currentYear;
                byte season = Globals_Game.clock.currentSeason;

                // location
                string entryLoc = this.id;

                // journal entry personae
                string   allEntry          = "all|all";
                string   currentOwnerEntry = currentOwner.charID + "|king";
                string   challengerEntry   = challenger.charID + "|pretender";
                string[] entryPersonae     = new string[] { currentOwnerEntry, challengerEntry, allEntry };

                // entry type
                string entryType = "depose_new";

                // journal entry description
                string[] fields = new string[4];
                fields[0] = this.name;
                fields[1] = this.id;
                fields[2] = challenger.firstName + " " + challenger.familyName;
                fields[3] = currentOwner.firstName + " " + currentOwner.familyName;

                ProtoMessage ownershipChallenge = new ProtoMessage();
                ownershipChallenge.MessageFields = fields;
                ownershipChallenge.ResponseType  = DisplayMessages.KingdomOwnershipChallenge;
                // create and send a proposal (journal entry)
                JournalEntry myEntry = new JournalEntry(entryID, year, season, entryPersonae, entryType, ownershipChallenge, loc: entryLoc);
                Globals_Game.AddPastEvent(myEntry);
            }
            return(result);
        }
示例#2
0
        /// <summary>
        /// Inserts the supplied PlayerCharacter's ID into the Position's officeHolder variable
        /// </summary>
        /// <param name="newPositionHolder">PlayerCharacter being assigned to the Position</param>
        public void BestowPosition(PlayerCharacter newPositionHolder)
        {
            PlayerCharacter oldPositionHolder = null;

            // remove existing holder if necessary
            if (!String.IsNullOrWhiteSpace(this.officeHolder))
            {
                // get current holder
                if (Globals_Game.pcMasterList.ContainsKey(this.officeHolder))
                {
                    oldPositionHolder = Globals_Game.pcMasterList[this.officeHolder];
                }

                // remove from position
                this.RemoveFromOffice(oldPositionHolder);
            }

            // assign position
            this.officeHolder = newPositionHolder.charID;

            // update stature
            newPositionHolder.AdjustStatureModifier(this.stature);

            // CREATE JOURNAL ENTRY
            // get interested parties
            bool            success = true;
            PlayerCharacter king    = this.GetKingdom().owner;

            // ID
            uint entryID = Globals_Game.GetNextJournalEntryID();

            // date
            uint year   = Globals_Game.clock.currentYear;
            byte season = Globals_Game.clock.currentSeason;

            // personae
            List <string> tempPersonae = new List <string>();

            tempPersonae.Add("all|all");
            tempPersonae.Add(king.charID + "|king");
            tempPersonae.Add(newPositionHolder.charID + "|newPositionHolder");
            if (oldPositionHolder != null)
            {
                tempPersonae.Add(oldPositionHolder.charID + "|oldPositionHolder");
            }
            string[] thisPersonae = tempPersonae.ToArray();

            // type
            string type = "grantPosition";

            // description

            String[] fields = new string[] { this.title[0].name, king.firstName + " " + king.familyName, newPositionHolder.firstName + " " + newPositionHolder.familyName, "" };
            if (oldPositionHolder != null)
            {
                fields[3] = "; This has necessitated the removal of " + oldPositionHolder.firstName + " " + oldPositionHolder.familyName + " from the position";
            }

            ProtoMessage bestowPosition = new ProtoMessage();

            bestowPosition.MessageFields = fields;
            bestowPosition.ResponseType  = DisplayMessages.RankTitleTransfer;
            // create and add a journal entry to the pastEvents journal
            JournalEntry thisEntry = new JournalEntry(entryID, year, season, thisPersonae, type, bestowPosition);

            success = Globals_Game.AddPastEvent(thisEntry);
        }
示例#3
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);
        }
示例#4
0
        /// <summary>
        /// Allows an attacking army to lay siege to an enemy fief
        /// </summary>
        /// <param name="attacker">The attacking army</param>
        /// <param name="target">The fief to be besieged</param>
        public static Siege SiegeStart(Army attacker, Fief target)
        {
            Army defenderGarrison   = null;
            Army defenderAdditional = null;

            // check for existence of army in keep
            for (int i = 0; i < target.armies.Count; i++)
            {
                // get army
                Army armyInFief = Globals_Game.armyMasterList[target.armies[i]];

                // check is in keep
                Character armyLeader = armyInFief.GetLeader();
                if (armyLeader != null)
                {
                    if (armyLeader.inKeep)
                    {
                        // check owner is same as that of fief (i.e. can help in siege)
                        if (armyInFief.GetOwner() == target.owner)
                        {
                            defenderAdditional = armyInFief;
                            break;
                        }
                    }
                }
            }

            // create defending force
            defenderGarrison = target.CreateDefendingArmy();

            // get the minumum days of all army objects involved
            double minDays = Math.Min(attacker.days, defenderGarrison.days);

            if (defenderAdditional != null)
            {
                minDays = Math.Min(minDays, defenderAdditional.days);
            }

            // get defenderAdditional ID, or null if no defenderAdditional
            string defAddID = null;

            if (defenderAdditional != null)
            {
                defAddID = defenderAdditional.armyID;
            }

            // create siege object
            Siege mySiege = new Siege(Globals_Game.GetNextSiegeID(), Globals_Game.clock.currentYear, Globals_Game.clock.currentSeason, attacker.GetOwner().charID, target.owner.charID, attacker.armyID, defenderGarrison.armyID, target.id, minDays, target.keepLevel, defAdd: defAddID);

            // add to master list
            Globals_Game.siegeMasterList.Add(mySiege.siegeID, mySiege);

            // add to siege owners
            mySiege.GetBesiegingPlayer().mySieges.Add(mySiege.siegeID);
            mySiege.GetDefendingPlayer().mySieges.Add(mySiege.siegeID);

            // add to fief
            target.siege = mySiege.siegeID;

            // reduce expenditures in fief, except for garrison
            target.infrastructureSpendNext = 0;
            target.keepSpendNext           = 0;
            target.officialsSpendNext      = 0;

            // update days (NOTE: siege.days will be updated in syncDays)
            mySiege.totalDays++;

            // sychronise days
            mySiege.SyncSiegeDays(mySiege.days - 1);

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

            // personae
            List <string> tempPersonae = new List <string>();

            tempPersonae.Add("all|all");
            tempPersonae.Add(mySiege.GetDefendingPlayer().charID + "|fiefOwner");
            tempPersonae.Add(mySiege.GetBesiegingPlayer().charID + "|attackerOwner");
            tempPersonae.Add(attacker.GetLeader().charID + "|attackerLeader");
            // get defenderLeader
            Character defenderLeader = defenderGarrison.GetLeader();

            if (defenderLeader != null)
            {
                tempPersonae.Add(defenderLeader.charID + "|defenderGarrisonLeader");
            }
            // get additional defending leader
            Character addDefendLeader = null;

            if (defenderAdditional != null)
            {
                addDefendLeader = defenderAdditional.GetLeader();
                if (addDefendLeader != null)
                {
                    tempPersonae.Add(addDefendLeader.charID + "|defenderAdditionalLeader");
                }
            }
            string[] siegePersonae = tempPersonae.ToArray();

            // location
            string siegeLocation = mySiege.GetFief().id;

            // description
            string[] fields = new string[6];
            fields[0] = mySiege.GetBesiegingPlayer().firstName + " " + mySiege.GetBesiegingPlayer().familyName;
            fields[1] = attacker.GetLeader().firstName + " " + attacker.GetLeader().familyName;
            fields[2] = mySiege.GetFief().name;
            fields[3] = mySiege.GetDefendingPlayer().firstName + " " + mySiege.GetDefendingPlayer().familyName;
            fields[4] = fields[5] = "";
            if (defenderLeader != null)
            {
                fields[4] = "The defending garrison is led by " + defenderLeader.firstName + " " + defenderLeader.familyName + ".";
            }
            if (addDefendLeader != null)
            {
                fields[5] = "Additional defending forces are led by " + addDefendLeader.firstName + " " + addDefendLeader.familyName + ".";
            }

            ProtoMessage siege = new ProtoMessage();

            siege.MessageFields = fields;
            siege.ResponseType  = DisplayMessages.PillageInitiateSiege;
            // put together new journal entry
            JournalEntry siegeResult = new JournalEntry(entryID, Globals_Game.clock.currentYear, Globals_Game.clock.currentSeason, siegePersonae, "siege", siege, loc: siegeLocation);

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

            return(mySiege);
        }
示例#5
0
        /// <summary>
        /// Calculates the outcome of the pillage of a fief by an army
        /// </summary>
        /// <param name="f">The fief being pillaged</param>
        /// <param name="a">The pillaging army</param>
        /// <param name="circumstance">The circumstance under which the fief is being pillaged</param>
        public static ProtoPillageResult ProcessPillage(Fief f, Army a, string circumstance = "pillage")
        {
            ProtoPillageResult pillageResult      = new ProtoPillageResult();
            double             thisLoss           = 0;
            double             moneyPillagedTotal = 0;
            double             moneyPillagedOwner = 0;
            double             pillageMultiplier  = 0;
            // get army leader
            Character armyLeader = a.GetLeader();

            // get pillaging army owner (receives a proportion of total spoils)
            PlayerCharacter armyOwner = a.GetOwner();

            pillageResult.fiefID = f.id;
            // get garrison leader (to add to journal entry)
            Character defenderLeader = null;

            if (f.bailiff != null)
            {
                defenderLeader = f.bailiff;
            }

            // calculate pillageMultiplier (based on no. pillagers per 1000 population)
            pillageMultiplier = a.CalcArmySize() / (f.population / 1000);

            // calculate days taken for pillage
            double daysTaken = Globals_Game.myRand.Next(7, 16);

            if (daysTaken > a.days)
            {
                daysTaken = a.days;
            }

            // update army days
            armyLeader.AdjustDays(daysTaken);
            pillageResult.daysTaken = daysTaken;

            // % population loss
            thisLoss = (0.007 * pillageMultiplier);
            // ensure is between 1%-20%
            if (thisLoss < 1)
            {
                thisLoss = 1;
            }
            else if (thisLoss > 20)
            {
                thisLoss = 20;
            }
            // apply population loss
            pillageResult.populationLoss = Convert.ToInt32((f.population * (thisLoss / 100)));
            f.population -= Convert.ToInt32((f.population * (thisLoss / 100)));

            // % treasury loss
            if (!circumstance.Equals("quellRebellion"))
            {
                thisLoss = (0.2 * pillageMultiplier);
                // ensure is between 1%-80%
                if (thisLoss < 1)
                {
                    thisLoss = 1;
                }
                else if (thisLoss > 80)
                {
                    thisLoss = 80;
                }
                // apply treasury loss
                if (f.Treasury > 0)
                {
                    pillageResult.treasuryLoss = Convert.ToInt32((f.Treasury * (thisLoss / 100)));
                    f.AdjustTreasury(-Convert.ToInt32((f.Treasury * (thisLoss / 100))));
                }
            }

            // % loyalty loss
            thisLoss = (0.33 * pillageMultiplier);
            // ensure is between 1%-20%
            if (thisLoss < 1)
            {
                thisLoss = 1;
            }
            else if (thisLoss > 20)
            {
                thisLoss = 20;
            }
            // apply loyalty loss
            pillageResult.loyaltyLoss = (f.loyalty * (thisLoss / 100));

            f.loyalty -= (f.loyalty * (thisLoss / 100));

            // % fields loss
            thisLoss = (0.01 * pillageMultiplier);
            // ensure is between 1%-20%
            if (thisLoss < 1)
            {
                thisLoss = 1;
            }
            else if (thisLoss > 20)
            {
                thisLoss = 20;
            }
            // apply fields loss
            pillageResult.fieldsLoss = (f.fields * (thisLoss / 100));
            f.fields -= (f.fields * (thisLoss / 100));

            // % industry loss
            thisLoss = (0.01 * pillageMultiplier);
            // ensure is between 1%-20%
            if (thisLoss < 1)
            {
                thisLoss = 1;
            }
            else if (thisLoss > 20)
            {
                thisLoss = 20;
            }
            // apply industry loss
            pillageResult.industryLoss = (f.industry * (thisLoss / Convert.ToDouble(100)));
            f.industry -= (f.industry * (thisLoss / 100));

            // money pillaged (based on GDP)
            thisLoss = (0.032 * pillageMultiplier);
            // ensure is between 1%-50%
            if (thisLoss < 1)
            {
                thisLoss = 1;
            }
            else if (thisLoss > 50)
            {
                thisLoss = 50;
            }
            // calculate base amount pillaged based on fief GDP
            double baseMoneyPillaged = (f.keyStatsCurrent[1] * (thisLoss / 100));

            moneyPillagedTotal = baseMoneyPillaged;
            pillageResult.baseMoneyPillaged = baseMoneyPillaged;

            // factor in no. days spent pillaging (get extra 5% per day > 7)
            int daysOver7 = Convert.ToInt32(daysTaken) - 7;

            if (daysOver7 > 0)
            {
                for (int i = 0; i < daysOver7; i++)
                {
                    moneyPillagedTotal += (baseMoneyPillaged * 0.05);
                }
                pillageResult.bonusMoneyPillaged = moneyPillagedTotal - baseMoneyPillaged;
                pillageResult.daysTaken          = daysOver7;
            }

            // check for jackpot
            // generate randomPercentage to see if hit the jackpot
            int myRandomPercent = Globals_Game.myRand.Next(101);

            if (myRandomPercent <= 30)
            {
                // generate random int to multiply amount pillaged
                int myRandomMultiplier = Globals_Game.myRand.Next(3, 11);
                pillageResult.jackpot = moneyPillagedTotal * myRandomMultiplier - moneyPillagedTotal;
                moneyPillagedTotal    = moneyPillagedTotal * myRandomMultiplier;
            }

            // check proportion of money pillaged goes to army owner (based on stature)
            double proportionForOwner = 0.05 * armyOwner.CalculateStature();

            moneyPillagedOwner = (moneyPillagedTotal * proportionForOwner);
            pillageResult.moneyPillagedOwner = moneyPillagedOwner;

            // apply to army owner's home fief treasury
            armyOwner.GetHomeFief().AdjustTreasury(Convert.ToInt32(moneyPillagedOwner));

            // apply loss of stature to army owner if fief has same language
            if (armyOwner.language.id == f.language.id)
            {
                armyOwner.AdjustStatureModifier(-0.3);
                pillageResult.statureModifier = (-0.3);
            }
            else if (armyOwner.language.baseLanguage.id == f.language.baseLanguage.id)
            {
                armyOwner.AdjustStatureModifier(-0.2);
                pillageResult.statureModifier = (-0.2);
            }

            // set isPillaged for fief
            f.isPillaged = true;

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

            // personae
            List <string> tempPersonae = new List <string>();

            tempPersonae.Add(f.owner.charID + "|fiefOwner");
            tempPersonae.Add(armyOwner.charID + "|attackerOwner");
            if (armyLeader != null)
            {
                tempPersonae.Add(armyLeader.charID + "|attackerLeader");
            }
            if ((defenderLeader != null) && (!circumstance.Equals("quellRebellion")))
            {
                tempPersonae.Add(defenderLeader.charID + "|defenderLeader");
            }
            if (circumstance.Equals("quellRebellion"))
            {
                tempPersonae.Add("all|all");
            }
            string[] pillagePersonae = tempPersonae.ToArray();

            // location
            string pillageLocation = f.id;

            // type
            string type = "";

            if (circumstance.Equals("pillage"))
            {
                type += "pillage";
            }
            else if (circumstance.Equals("quellRebellion"))
            {
                type += "rebellionQuelled";
            }

            if (circumstance.Equals("pillage"))
            {
                pillageResult.isPillage = true;
            }
            else if (circumstance.Equals("quellRebellion"))
            {
                pillageResult.isPillage = false;
            }
            pillageResult.fiefName  = f.name;
            pillageResult.fiefOwner = f.owner.firstName + " " + f.owner.familyName;

            if ((circumstance.Equals("pillage")) && (defenderLeader != null))
            {
                if (f.owner != defenderLeader)
                {
                    pillageResult.defenderLeader = defenderLeader.firstName + " " + defenderLeader.familyName;
                }
            }

            pillageResult.armyOwner = armyOwner.firstName + " " + armyOwner.familyName;
            if (armyLeader != null)
            {
                pillageResult.armyLeader = armyLeader.firstName + " " + armyLeader.familyName;
            }

            // put together new journal entry
            JournalEntry pillageEntry = new JournalEntry(pillageResult, entryID, Globals_Game.clock.currentYear, Globals_Game.clock.currentSeason, pillagePersonae, type, loc: pillageLocation);

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

            return(pillageResult);
        }
示例#6
0
        /// <summary>
        /// Processes the actions involved with a marriage
        /// </summary>
        /// <returns>bool indicating whether engagement was processed successfully</returns>
        public bool ProcessMarriage()
        {
            bool success = false;

            // get interested parties
            PlayerCharacter headOfFamilyBride = null;
            PlayerCharacter headOfFamilyGroom = null;
            Character       bride             = null;
            Character       groom             = null;

            for (int i = 0; i < this.personae.Length; i++)
            {
                string   thisPersonae      = this.personae[i];
                string[] thisPersonaeSplit = thisPersonae.Split('|');

                switch (thisPersonaeSplit[1])
                {
                case "headOfFamilyGroom":
                    headOfFamilyGroom = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    break;

                case "headOfFamilyBride":
                    headOfFamilyBride = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    break;

                case "bride":
                    bride = Globals_Game.npcMasterList[thisPersonaeSplit[0]];
                    break;

                case "groom":
                    if (Globals_Game.pcMasterList.ContainsKey(thisPersonaeSplit[0]))
                    {
                        groom = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    }
                    else if (Globals_Game.npcMasterList.ContainsKey(thisPersonaeSplit[0]))
                    {
                        groom = Globals_Game.npcMasterList[thisPersonaeSplit[0]];
                    }
                    break;

                default:
                    break;
                }
            }

            // ID
            uint marriageID = Globals_Game.GetNextJournalEntryID();

            // date
            uint year   = Globals_Game.clock.currentYear;
            byte season = Globals_Game.clock.currentSeason;

            // personae
            string headOfFamilyBrideEntry = headOfFamilyBride.charID + "|headOfFamilyBride";
            string headOfFamilyGroomEntry = headOfFamilyGroom.charID + "|headOfFamilyGroom";
            string thisBrideEntry         = bride.charID + "|bride";
            string thisGroomEntry         = groom.charID + "|groom";
            string allEntry = "all|all";

            string[] marriagePersonae = new string[] { headOfFamilyGroomEntry, headOfFamilyBrideEntry, thisBrideEntry, thisGroomEntry, allEntry };

            // type
            string type = "marriage";

            string[] fields = new string[3];
            fields[0] = groom.firstName + " " + groom.familyName;
            fields[1] = bride.firstName + " " + groom.familyName;
            fields[2] = bride.familyName;
            // description

            ProtoMessage marriage = new ProtoMessage();

            marriage.MessageFields = fields;
            marriage.ResponseType  = DisplayMessages.JournalMarriage;
            // create and add a marriage entry to the pastEvents journal
            JournalEntry marriageEntry = new JournalEntry(marriageID, year, season, marriagePersonae, type, marriage, null);

            success = Globals_Game.AddPastEvent(marriageEntry);

            if (success)
            {
                // remove fiancees
                bride.fiancee = null;
                groom.fiancee = null;

                // add spouses
                bride.spouse = groom.charID;
                groom.spouse = bride.charID;

                // change wife's family
                bride.familyID   = groom.familyID;
                bride.familyName = groom.familyName;

                // switch myNPCs
                headOfFamilyBride.myNPCs.Remove(bride as NonPlayerCharacter);
                headOfFamilyGroom.myNPCs.Add(bride as NonPlayerCharacter);

                // move wife to groom's location
                bride.location = groom.location;

                // check to see if headOfFamilyBride should receive increase in stature
                // get highest rank for headOfFamilyBride and headOfFamilyGroom
                Rank brideHighestRank = headOfFamilyBride.GetHighestRank();
                Rank groomHighestRank = headOfFamilyGroom.GetHighestRank();

                // compare ranks
                if ((brideHighestRank != null) && (groomHighestRank != null))
                {
                    if (groomHighestRank.id < brideHighestRank.id)
                    {
                        headOfFamilyBride.AdjustStatureModifier((brideHighestRank.id - groomHighestRank.id) * 0.4);
                    }
                }
            }

            return(success);
        }
示例#7
0
        // TODO I suspect there may be issues with this if any of the characters die. Test.
        /// <summary>
        /// Allows a character to reply to a marriage proposal
        /// </summary>
        /// <returns>bool indicating whether reply was processed successfully</returns>
        /// <param name="proposalAccepted">bool indicating whether proposal accepted</param>
        public bool ReplyToProposal(bool proposalAccepted)
        {
            bool success = true;

            string[] replyFields = new string[4];
            // get interested parties
            PlayerCharacter headOfFamilyBride = null;
            PlayerCharacter headOfFamilyGroom = null;
            Character       bride             = null;
            Character       groom             = null;

            for (int i = 0; i < this.personae.Length; i++)
            {
                string   thisPersonae      = this.personae[i];
                string[] thisPersonaeSplit = thisPersonae.Split('|');

                switch (thisPersonaeSplit[1])
                {
                case "headOfFamilyBride":
                    headOfFamilyBride = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    break;

                case "headOfFamilyGroom":
                    headOfFamilyGroom = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    break;

                case "bride":
                    bride = Globals_Game.npcMasterList[thisPersonaeSplit[0]];
                    break;

                case "groom":
                    if (Globals_Game.pcMasterList.ContainsKey(thisPersonaeSplit[0]))
                    {
                        groom = Globals_Game.pcMasterList[thisPersonaeSplit[0]];
                    }
                    else if (Globals_Game.npcMasterList.ContainsKey(thisPersonaeSplit[0]))
                    {
                        groom = Globals_Game.npcMasterList[thisPersonaeSplit[0]];
                    }
                    break;

                default:
                    break;
                }
            }

            // ID
            uint replyID = Globals_Game.GetNextJournalEntryID();

            // date
            uint year   = Globals_Game.clock.currentYear;
            byte season = Globals_Game.clock.currentSeason;

            // personae
            List <string> tempPersonae = new List <string>();

            tempPersonae.Add(headOfFamilyBride.charID + "|headOfFamilyBride");
            tempPersonae.Add(headOfFamilyGroom.charID + "|headOfFamilyGroom");
            tempPersonae.Add(bride.charID + "|bride");
            tempPersonae.Add(groom.charID + "|groom");
            if (proposalAccepted)
            {
                tempPersonae.Add("all|all");
            }
            string[] myReplyPersonae = tempPersonae.ToArray();

            // type
            string type = "";

            if (proposalAccepted)
            {
                type = "proposalAccepted";
            }
            else
            {
                type = "proposalRejected";
            }

            // description
            replyFields[0] = groom.firstName + " " + groom.familyName;
            replyFields[1] = bride.firstName + " " + bride.familyName;

            if (proposalAccepted)
            {
                replyFields[2] = "ACCEPTED";
            }
            else
            {
                replyFields[2] = "REJECTED";
            }
            replyFields[3] = headOfFamilyBride.firstName + " " + headOfFamilyBride.familyName;

            ProtoMessage proposalReply = new ProtoMessage();

            proposalReply.MessageFields = replyFields;
            proposalReply.ResponseType  = DisplayMessages.JournalProposalReply;
            // create and send a proposal reply (journal entry)
            JournalEntry myProposalReply = new JournalEntry(replyID, year, season, myReplyPersonae, type, proposalReply, null);

            success = Globals_Game.AddPastEvent(myProposalReply);

            if (success)
            {
                string[] newFields = new string[this.entryDetails.MessageFields.Length + 2];
                Array.Copy(this.entryDetails.MessageFields, newFields, this.entryDetails.MessageFields.Length);
                newFields[newFields.Length - 1] = Globals_Game.clock.seasons[season] + ", " + year;
                this.entryDetails.MessageFields = newFields;
                this.replied = true;
                // mark proposal as replied
                if (proposalAccepted)
                {
                    this.entryDetails.MessageFields[this.entryDetails.MessageFields.Length - 2] = "ACCEPTED";
                }
                else
                {
                    this.entryDetails.MessageFields[this.entryDetails.MessageFields.Length - 2] = "REJECTED";
                }

                // if accepted, process engagement
                if (proposalAccepted)
                {
                    myProposalReply.ProcessEngagement();
                }
            }

            return(success);
        }
示例#8
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);
     }
 }