/// <summary>
        /// Checks that an OwnershipChallenge id is in the correct format
        /// </summary>
        /// <returns>bool indicating whether the id is valid</returns>
        /// <param name="id">The id to be validated</param>
        public static bool ValidateChallengeID(string id)
        {
            bool isValid = true;

            // split and ensure has correct format
            string[] idSplit = id.Split('_');
            if (idSplit.Length != 2)
            {
                isValid = false;
            }

            // must start with 'Challenge'
            else if (!idSplit[0].Equals("Challenge"))
            {
                isValid = false;
            }

            // must end with numbers
            else if (!Utility_Methods.CheckStringValid("numbers", idSplit[1]))
            {
                isValid = false;
            }

            return(isValid);
        }
Example #2
0
        /// <summary>
        /// Generates a trait set for a Character, based on parent traits
        /// </summary>
        /// <returns>Array containing trait set</returns>
        /// <param name="mummyTraits">The mother's traits</param>
        /// <param name="daddyTraits">The father's traits</param>
        /// <param name="isMale">Whether character is a male</param>
        public static Tuple <Trait, int>[] GenerateTraitSetFromParents(Tuple <Trait, int>[] mummyTraits, Tuple <Trait, int>[] daddyTraits, bool isMale)
        {
            // store all unique traitKeys from both parents
            List <string> uniqueTraitKeys = new List <string>();

            // mummy's traits
            for (int i = 0; i < mummyTraits.Length; i++)
            {
                uniqueTraitKeys.Add(mummyTraits[i].Item1.id);
            }

            // daddy's traits
            for (int i = 0; i < daddyTraits.Length; i++)
            {
                if (!uniqueTraitKeys.Contains(daddyTraits[i].Item1.id))
                {
                    uniqueTraitKeys.Add(daddyTraits[i].Item1.id);
                }
            }

            // create new traits using uniqueTraitKeys
            Tuple <Trait, int>[] newTraits = Utility_Methods.GenerateTraitSet(uniqueTraitKeys);

            return(newTraits);
        }
Example #3
0
        /// <summary>
        /// Constructor for TitleName
        /// </summary>
        /// <param name="lang">string holding Language ID</param>
        /// <param name="nam">string holding title name associated with specific language</param>
        public TitleName(string lang, string nam)
        {
            // VALIDATION

            // LANG
            // trim
            lang = lang.Trim();

            if ((!Utility_Methods.ValidateLanguageID(lang)) && (!lang.Equals("generic")))
            {
                throw new InvalidDataException("TitleName langID must either be 'generic' or have the format 'lang_' followed by 1-2 letters, ending in 1-2 numbers");
            }

            // NAM
            // trim and ensure 1st is uppercase
            nam = Utility_Methods.FirstCharToUpper(nam.Trim());

            if (!Utility_Methods.ValidateName(nam))
            {
                throw new InvalidDataException("TitleName name must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            this.langID = lang;
            this.name   = nam;
        }
Example #4
0
        /// <summary>
        /// Constructor for BaseLanguage
        /// </summary>
        /// <param name="id">String holding language ID</param>
        /// <param name="nam">String holding language name</param>
        public BaseLanguage(String id, String nam)
        {
            // VALIDATION

            // ID
            // trim
            id = id.Trim();

            if (!Utility_Methods.ValidateLanguageID(id, "baseLang"))
            {
                throw new InvalidDataException("BaseLanguage ID must have the format 'lang_' followed by 1-2 letters");
            }

            // NAM
            // trim and ensure 1st is uppercase
            nam = Utility_Methods.FirstCharToUpper(nam.Trim());

            if (!Utility_Methods.ValidateName(nam))
            {
                throw new InvalidDataException("BaseLanguage name must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            this.id   = id;
            this.name = nam;
        }
        /// <summary>
        /// Checks that a JournalEntry personae entry is in the correct format
        /// </summary>
        /// <returns>bool indicating whether the personae entry is valid</returns>
        /// <param name="personae">The personae entry to be validated</param>
        public static bool ValidateJentryPersonae(string personae)
        {
            bool isValid = true;

            // split using'|'
            string[] persSplit = personae.Split('|');
            if (persSplit.Length != 2)
            {
                isValid = false;
            }

            // 1st section must be valid character ID or 'all'
            else if ((!persSplit[0].Equals("all")) && (!Utility_Methods.ValidateCharacterID(persSplit[0])))
            {
                isValid = false;
            }

            // 2nd section must be all letters
            else if (!Utility_Methods.CheckStringValid("letters", persSplit[1]))
            {
                isValid = false;
            }

            return(isValid);
        }
Example #6
0
        /// <summary>
        /// Constructor for Language_Serialised taking seperate values.
        /// For creating Language_Serialised from CSV file.
        /// </summary>
        /// <param name="id">string holding Language ID</param>
        /// <param name="bLang">string holding BaseLanguage (ID)</param>
        /// <param name="dial">int holding language dialect code</param>
        public Language_Serialised(string id, string bLang, int dial)
        {
            // VALIDATION

            // ID
            // trim id and bLang
            id    = id.Trim();
            bLang = bLang.Trim();

            if (!id.Contains(bLang))
            {
                throw new InvalidDataException("Language_Serialised ID be based on its BaseLanguage ID");
            }

            else if (!Utility_Methods.ValidateLanguageID(id))
            {
                throw new InvalidDataException("Language_Serialised ID must have the format 'lang_' followed by 1-2 letters, ending in 1-2 numbers");
            }

            // BLANG
            if (!Utility_Methods.ValidateLanguageID(bLang, "baseLang"))
            {
                throw new InvalidDataException("Language_Serialised BaseLanguage ID must have the format 'lang_' followed by 1-2 letters");
            }

            // DIALECT
            if (dial < 1)
            {
                throw new InvalidDataException("Language dialect code must be an integer >= 0");
            }

            this.id           = id;
            this.baseLanguage = bLang;
            this.dialect      = dial;
        }
Example #7
0
        /// <summary>
        /// Constructor for Terrain
        /// </summary>
        /// <param name="id">String holding terrain code</param>
        /// <param name="desc">String holding terrain description</param>
        /// <param name="tc">double holding terrain travel cost</param>
        public Terrain(String id, string desc, double tc, double[] combatMods)
        {
            // VALIDATION

            // ID
            // trim
            id = id.Trim();

            if (!Utility_Methods.ValidateTerrainID(id))
            {
                throw new InvalidDataException("Terrain ID must have the format 'terr_' followed by some letters");
            }

            // DESC
            // trim and ensure 1st is uppercase
            desc = Utility_Methods.FirstCharToUpper(desc.Trim());

            if (!Utility_Methods.ValidateName(desc))
            {
                throw new InvalidDataException("Terrain description must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            // TC
            if (tc < 1)
            {
                throw new InvalidDataException("Terrain travelCost must be a double >= 1");
            }

            this.id          = id;
            this.description = desc;
            this.travelCost  = tc;
            this.combatMods  = combatMods;
        }
Example #8
0
        /// <summary>
        /// Generates a characteristic stat for a Character, based on parent stats
        /// </summary>
        /// <returns>Double containing characteristic stat</returns>
        /// <param name="mummyStat">The mother's characteristic stat</param>
        /// <param name="daddyStat">The father's characteristic stat</param>
        public static Double GenerateKeyCharacteristics(Double mummyStat, Double daddyStat)
        {
            Double newStat = 0;

            // get average of parents' stats
            Double parentalAverage = (mummyStat + daddyStat) / 2;

            // generate random (0 - 100) to determine relationship of new stat to parentalAverage
            double randPercentage = Utility_Methods.GetRandomDouble(100);

            // calculate new stat
            if (randPercentage <= 35)
            {
                newStat = parentalAverage;
            }
            else if (randPercentage <= 52.5)
            {
                newStat = parentalAverage - 1;
            }
            else if (randPercentage <= 70)
            {
                newStat = parentalAverage + 1;
            }
            else if (randPercentage <= 80)
            {
                newStat = parentalAverage - 2;
            }
            else if (randPercentage <= 90)
            {
                newStat = parentalAverage + 2;
            }
            else if (randPercentage <= 95)
            {
                newStat = parentalAverage - 3;
            }
            else
            {
                newStat = parentalAverage + 3;
            }

            // make sure new stat falls within acceptable range
            if (newStat < 1)
            {
                newStat = 1;
            }
            else if (newStat > 9)
            {
                newStat = 9;
            }

            return(newStat);
        }
Example #9
0
        /// <summary>
        /// Constructor for Place_Serialised taking seperate values.
        /// For creating Place_Serialised from CSV file.
        /// </summary>
        /// <param name="id">String holding place ID</param>
        /// <param name="nam">String holding place name</param>
        /// <param name="own">String holding Place owner (ID)</param>
        /// <param name="tiHo">String holding place title holder (charID)</param>
        /// <param name="rnk">String holding Place rank (ID)</param>
        public Place_Serialised(String id, String nam, byte r, String tiHo = null, string own = null)
        {
            // VALIDATION

            // ID
            // trim and ensure is uppercase
            id = id.Trim().ToUpper();

            if (!Utility_Methods.ValidatePlaceID(id))
            {
                throw new InvalidDataException("Place_Serialised id must be 5 characters long, start with a letter, and end in at least 2 numbers");
            }

            // NAM
            // trim and ensure 1st is uppercase
            nam = Utility_Methods.FirstCharToUpper(nam.Trim());

            if (!Utility_Methods.ValidateName(nam))
            {
                throw new InvalidDataException("Place_Serialised name must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            // TIHO
            if (!String.IsNullOrWhiteSpace(tiHo))
            {
                // trim and ensure 1st is uppercase
                tiHo = Utility_Methods.FirstCharToUpper(tiHo.Trim());

                if (!Utility_Methods.ValidateCharacterID(tiHo))
                {
                    throw new InvalidDataException("Place_Serialised titleHolder must have the format 'Char_' followed by some numbers");
                }
            }

            // OWNER
            if (!String.IsNullOrWhiteSpace(owner))
            {
                // trim and ensure 1st is uppercase
                owner = Utility_Methods.FirstCharToUpper(owner.Trim());

                if (!Utility_Methods.ValidateCharacterID(owner))
                {
                    throw new InvalidDataException("Place_Serialised owner must have the format 'Char_' followed by some numbers");
                }
            }

            this.id          = id;
            this.name        = nam;
            this.owner       = own;
            this.titleHolder = tiHo;
            this.rank        = r;
        }
Example #10
0
        /// <summary>
        /// Constructor for Province
        /// </summary>
        /// <param name="otax">Double holding province tax rate</param>
        /// <param name="king">Province's Kingdom object</param>
        public Province(String id, String nam, Double otax, String tiHo = null, PlayerCharacter own = null, Kingdom king = null, Rank r = null)
            : base(id, nam, tiHo, own, r)
        {
            // VALIDATION

            // OTAX
            if (!Utility_Methods.ValidatePercentage(otax))
            {
                throw new InvalidDataException("Province taxrate must be a double between 0 and 100");
            }

            this.taxRate = otax;
            this.kingdom = king;
        }
Example #11
0
        /// <summary>
        /// Constructor for Kingdom_Serialised taking seperate values.
        /// For creating Kingdom_Serialised from CSV file.
        /// </summary>
        /// <param name="nat">Kingdom's Nationality object</param>
        public Kingdom_Serialised(String id, String nam, byte r, string nat, String tiHo = null, string own = null)
            : base(id, nam, r, own: own, tiHo: tiHo)
        {
            // VALIDATION

            // NAT
            // trim and ensure 1st is uppercase
            nat = Utility_Methods.FirstCharToUpper(nat.Trim());

            if (!Utility_Methods.ValidateNationalityID(nat))
            {
                throw new InvalidDataException("Kingdom_Serialised nationality ID must be 1-3 characters long, and consist entirely of letters");
            }

            this.nationality = nat;
        }
        /// <summary>
        /// Checks that a nationality id is in the correct format
        /// </summary>
        /// <returns>bool indicating whether the id is valid</returns>
        /// <param name="nat">The id to be validated</param>
        public static bool ValidateNationalityID(string nat)
        {
            bool isValid = true;

            // 1-3 in length
            if ((nat.Length < 1) || (nat.Length > 3))
            {
                isValid = false;
            }

            // letters only
            if (!Utility_Methods.CheckStringValid("letters", nat))
            {
                isValid = false;
            }

            return(isValid);
        }
        /// <summary>
        /// Checks that a Language id is in the correct format
        /// </summary>
        /// <returns>bool indicating whether the id is valid</returns>
        /// <param name="id">The id to be validated</param>
        /// <param name="langType">The type of id to be validated (lang, baseLang)</param>
        public static bool ValidateLanguageID(string id, string langType = "lang")
        {
            bool isValid = true;

            // split and ensure has correct format
            string[] idSplit = id.Split('_');
            if (idSplit.Length != 2)
            {
                isValid = false;
            }

            // must start with 'lang'
            else if (!idSplit[0].ToLower().Equals("lang"))
            {
                isValid = false;
            }

            else if (langType.Equals("baseLang"))
            {
                // 2nd section must be letters
                if (!Utility_Methods.CheckStringValid("letters", idSplit[1]))
                {
                    isValid = false;
                }
            }

            else
            {
                // 1st character of 2nd section must be letter
                if (!Utility_Methods.CheckStringValid("letters", idSplit[1].Substring(0, 1)))
                {
                    isValid = false;
                }

                // last character of 2nd section must be number
                else if (!Utility_Methods.CheckStringValid("numbers", idSplit[1].Substring(idSplit[1].Length - 1, 1)))
                {
                    isValid = false;
                }
            }

            return(isValid);
        }
Example #14
0
        /// <summary>
        /// Constructor for Position
        /// </summary>
        /// <param name="holder">string holding ID of the office holder</param>
        /// <param name="nat">Nationality associated with the position</param>
        public Position(byte id, TitleName[] ti, byte stat, string holder, Nationality nat)
            : base(id, ti, stat)
        {
            // VALIDATION

            // HOLDER
            if (!String.IsNullOrWhiteSpace(holder))
            {
                // trim and ensure 1st is uppercase
                holder = Utility_Methods.FirstCharToUpper(holder.Trim());

                if (!Utility_Methods.ValidateCharacterID(holder))
                {
                    throw new InvalidDataException("Position officeHolder id must have the format 'Char_' followed by some numbers");
                }
            }

            this.officeHolder = holder;
            this.nationality  = nat;
        }
Example #15
0
        /// <summary>
        /// Constructor for Position_Serialised taking seperate values.
        /// For creating Position_Serialised from CSV file.
        /// </summary>
        /// <param name="id">byte holding Position ID</param>
        /// <param name="ti">title name in various languages</param>
        /// <param name="stat">byte holding stature for this position</param>
        /// <param name="holder">string ID of the office holder</param>
        /// <param name="nat">string holding ID of Nationality associated with the position</param>
        public Position_Serialised(byte id, TitleName[] ti, byte stat, string holder, string nat)
        {
            // VALIDATION

            // STAT
            if (stat < 1)
            {
                stat = 1;
            }
            else if (stat > 3)
            {
                stat = 3;
            }

            // HOLDER
            if (!String.IsNullOrWhiteSpace(holder))
            {
                // trim and ensure 1st is uppercase
                holder = Utility_Methods.FirstCharToUpper(holder.Trim());

                if (!Utility_Methods.ValidateCharacterID(holder))
                {
                    throw new InvalidDataException("Position_Serialised officeHolder id must have the format 'Char_' followed by some numbers");
                }
            }

            // NAT
            // trim and ensure 1st is uppercase
            nat = Utility_Methods.FirstCharToUpper(nat.Trim());

            if (!Utility_Methods.ValidateNationalityID(nat))
            {
                throw new InvalidDataException("Position_Serialised nationality ID must be 1-3 characters long, and consist entirely of letters");
            }

            this.id           = id;
            this.title        = ti;
            this.stature      = stat;
            this.officeHolder = holder;
            this.nationality  = nat;
        }
Example #16
0
        /// <summary>
        /// Constructor for Trait
        /// </summary>
        /// <param name="id">String holding trait ID</param>
        /// <param name="nam">String holding trait name</param>
        /// <param name="effs">Dictionary(string, double) holding trait effects</param>
        public Trait(String id, String nam, Dictionary <Globals_Game.Stats, double> effs)
        {
            // VALIDATION

            // ID
            // trim
            id = id.Trim();

            if (!Utility_Methods.ValidateTraitID(id))
            {
                throw new InvalidDataException("Trait ID must have the format 'trait_' followed by some numbers");
            }

            // NAM
            // trim and ensure 1st is uppercase
            nam = Utility_Methods.FirstCharToUpper(nam.Trim());

            if (!Utility_Methods.ValidateName(nam))
            {
                throw new InvalidDataException("Trait name must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            // effect values
            double[] effVals = new double[effs.Count];
            effs.Values.CopyTo(effVals, 0);

            for (int i = 0; i < effVals.Length; i++)
            {
                if ((effVals[i] < -0.99) || (effVals[i] > 0.99))
                {
                    throw new InvalidDataException("All Trait effect values must be doubles between -0.99 and 0.99");
                }
            }

            this.id      = id;
            this.name    = nam;
            this.effects = effs;
        }
Example #17
0
        /// <summary>
        /// Constructor for Province_Serialised taking seperate values.
        /// For creating Province_Serialised from CSV file.
        /// </summary>
        /// <param name="otax">Double holding province tax rate</param>
        /// <param name="king">string holding Province's Kingdom (id)</param>
        public Province_Serialised(String id, String nam, byte r, Double otax, String tiHo = null, string own = null, string king = null)
            : base(id, nam, r, own: own, tiHo: tiHo)
        {
            // VALIDATION

            // OTAX
            if (!Utility_Methods.ValidatePercentage(otax))
            {
                throw new InvalidDataException("Province_Serialised taxrate must be a double between 0 and 100");
            }

            // KING
            // trim and ensure is uppercase
            king = king.Trim().ToUpper();

            if (!Utility_Methods.ValidatePlaceID(king))
            {
                throw new InvalidDataException("Province_Serialised kingdom ID must be 5 characters long, start with a letter, and end in at least 2 numbers");
            }

            this.taxRate = otax;
            this.kingdom = king;
        }
        /// <summary>
        /// Checks that a Place id is in the correct format
        /// </summary>
        /// <returns>bool indicating whether the id is valid</returns>
        /// <param name="id">The id to be validated</param>
        public static bool ValidatePlaceID(string id)
        {
            bool isValid = true;

            // ensure is 5 in length
            if (id.Length != 5)
            {
                isValid = false;
            }

            // ensure 1st is letter
            else if (!Utility_Methods.CheckStringValid("letters", id.Substring(0, 1)))
            {
                isValid = false;
            }

            // ensure ends in 2 numbers
            else if (!Utility_Methods.CheckStringValid("numbers", id.Substring(3)))
            {
                isValid = false;
            }

            return(isValid);
        }
Example #19
0
        /// <summary>
        /// Calculates casualties from a battle for both sides
        /// </summary>
        /// <returns>double[] containing percentage loss modifier for each side</returns>
        /// <param name="attackerTroops">uint containing attacking army troop numbers</param>
        /// <param name="defenderTroops">uint containing defending army troop numbers</param>
        /// <param name="attackerValue">uint containing attacking army battle value</param>
        /// <param name="defenderValue">uint containing defending army battle value</param>
        /// <param name="attackerVictorious">bool indicating whether attacking army was victorious</param>
        public static double[] CalculateBattleCasualties(uint attackerTroops, uint defenderTroops, uint attackerValue, uint defenderValue, bool attackerVictorious)
        {
            double[] battleCasualties  = new double[2];
            double   largeArmyModifier = 0;
            bool     largestWon        = true;

            // determine highest/lowest battle value
            double maxBV = Math.Max(attackerValue, defenderValue);
            double minBV = Math.Min(attackerValue, defenderValue);

            // use BVs to determine high mark for base casualty rate of army with smallest battle value (see below)
            double highCasualtyRate = maxBV / (maxBV + minBV);

            // determine base casualty rate for army with smallest battle value
            double smallestModifier = Utility_Methods.GetRandomDouble(highCasualtyRate, min: 0.1);

            // determine if army with largest battle value won
            if (maxBV == attackerValue)
            {
                if (!attackerVictorious)
                {
                    largestWon = false;
                }
            }
            else
            {
                if (attackerVictorious)
                {
                    largestWon = false;
                }
            }

            // if army with largest battle value won
            if (largestWon)
            {
                // calculate casualty modifier for army with largest battle value
                // (based on adapted version of Lanchester's Square Law - i.e. largest army loses less troops than smallest)
                largeArmyModifier = (1 + ((minBV * minBV) / (maxBV * maxBV))) / 2;

                // attacker is large army
                if (attackerVictorious)
                {
                    battleCasualties[1] = smallestModifier;
                    // determine actual troop losses for largest army based on smallest army losses,
                    // modified by largeArmyModifier
                    uint largeArmyLosses = Convert.ToUInt32((defenderTroops * battleCasualties[1]) * largeArmyModifier);
                    // derive final casualty modifier for largest army
                    battleCasualties[0] = largeArmyLosses / (double)attackerTroops;
                }
                // defender is large army
                else
                {
                    battleCasualties[0] = smallestModifier;
                    uint largeArmyLosses = Convert.ToUInt32((attackerTroops * battleCasualties[0]) * largeArmyModifier);
                    battleCasualties[1] = largeArmyLosses / (double)defenderTroops;
                }
            }

            // if army with smallest battle value won
            else
            {
                // calculate casualty modifier for army with largest battle value
                // this ensures its losses will be roughly the same as the smallest army (because it lost)
                largeArmyModifier = Utility_Methods.GetRandomDouble(1.20, min: 0.8);

                // defender is large army
                if (attackerVictorious)
                {
                    // smallest army losses reduced because they won
                    battleCasualties[0] = smallestModifier / 2;
                    // determine actual troop losses for largest army based on smallest army losses,
                    // modified by largeArmyModifier
                    uint largeArmyLosses = Convert.ToUInt32((attackerTroops * battleCasualties[0]) * largeArmyModifier);
                    // derive final casualty modifier for largest army
                    battleCasualties[1] = largeArmyLosses / (double)defenderTroops;
                }
                // attacker is large army
                else
                {
                    battleCasualties[1] = smallestModifier / 2;
                    uint largeArmyLosses = Convert.ToUInt32((defenderTroops * battleCasualties[1]) * largeArmyModifier);
                    battleCasualties[0] = largeArmyLosses / (double)attackerTroops;
                }
            }


            return(battleCasualties);
        }
Example #20
0
        /// <summary>
        /// Constructor for Ailment
        /// </summary>
        /// <param name="id">String holding ailment ID</param>
        /// <param name="descr">string holding ailment description</param>
        /// <param name="wh">string holding ailment date</param>
        /// <param name="eff">uint holding current ailment effect</param>
        /// <param name="minEff">uint holding minimum ailment effect</param>
        public Ailment(String id, string descr, string wh, uint eff, uint minEff)
        {
            // VALIDATION

            // ID
            // trim and ensure 1st is uppercase
            id = Utility_Methods.FirstCharToUpper(id.Trim());

            if (!Utility_Methods.ValidateAilmentID(id))
            {
                throw new InvalidDataException("Ailment ID must have the format 'Ail_' followed by some numbers");
            }

            // DESCR
            // trim and ensure 1st is uppercase
            descr = Utility_Methods.FirstCharToUpper(descr.Trim());

            if (!Utility_Methods.ValidateName(descr))
            {
                throw new InvalidDataException("Ailment description must be 1-40 characters long and contain only valid characters (a-z and ') or spaces");
            }

            // WHEN
            // trim and ensure 1st is uppercase
            wh = Utility_Methods.FirstCharToUpper(wh.Trim());

            // check contains season
            if (!wh.Contains("Spring"))
            {
                if (!wh.Contains("Summer"))
                {
                    if (!wh.Contains("Autumn"))
                    {
                        if (!wh.Contains("Winter"))
                        {
                            throw new InvalidDataException("Ailment 'when' must specify the season and year in which the ailment occurred");
                        }
                    }
                }
            }

            // EFF
            // check must be 1-5
            if ((eff < 1) || (eff > 5))
            {
                throw new InvalidDataException("Ailment effect must be a uint between 1-5");
            }

            // MINEFF
            // check not > 1
            if (minEff > 1)
            {
                throw new InvalidDataException("Ailment minimumEffect must be a uint less than 2");
            }

            this.ailmentID     = id;
            this.description   = descr;
            this.when          = wh;
            this.effect        = eff;
            this.minimumEffect = minEff;
        }