예제 #1
0
        public ObjectData(ObjectPrototypeData proto) : this()
        {
            Level            = proto.Level;
            Name             = proto.Name;
            ShortDescription = proto.ShortDescription;
            Description      = proto.Description;
            Material         = proto.Material;
            ObjectType       = proto.ObjectType;
            ExtraFlags       = proto.ExtraFlags;
            WearFlags        = proto.WearFlags;
            Values           = proto.Values;
            Weight           = proto.Weight;
            Cost             = proto.Cost;
            Prototype        = proto;

            if (ObjectType == Enums.ItemClass.Light && (int)Values[2] == 999)
            {
                Values[2] = -1;
            }

            foreach (AffectData aff in Affected)
            {
                if (aff.Location == Enums.ApplyType.SpellAffect)
                {
                    ApplyAffect(aff);
                }
            }
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Wand or Staff
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetOtherItemTypeValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // All segments should be parsed as ints
            SetValue_Int(splitLine[0], ref outObj.Values[0], "other type", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[1], ref outObj.Values[1], "other type", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[2], ref outObj.Values[2], "other type", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[3], ref outObj.Values[3], "other type", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[4], ref outObj.Values[4], "other type", areaFile, lineNum, outObj.VNUM);

            return(true);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Wand or Staff
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetWandAndStaffValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // Segment 1 - Level, should be an integer
            SetValue_Int(splitLine[0], ref outObj.Values[0], "staff or wand", areaFile, lineNum, outObj.VNUM);

            // Segment 2 - Current charges, should be an integer
            SetValue_Int(splitLine[1], ref outObj.Values[1], "staff or wand", areaFile, lineNum, outObj.VNUM);

            // Segment 3 - Max charges, should be an integer
            SetValue_Int(splitLine[2], ref outObj.Values[2], "staff or wand", areaFile, lineNum, outObj.VNUM);

            // Segment 4 - Skill for wielding
            SetValue_Skill(splitLine[3], ref outObj.Values[3], "staff or wand", areaFile, lineNum, outObj.VNUM);

            // Segment 5 - Appears to be unused, but should be an integer
            SetValue_Int(splitLine[4], ref outObj.Values[4], "staff or wand", areaFile, lineNum, outObj.VNUM);

            return(true);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Wand or Staff
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetPotionPillScrollValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // Segment 1 - Level, should be an integer
            SetValue_Int(splitLine[0], ref outObj.Values[0], "potion, pill, or scroll", areaFile, lineNum, outObj.VNUM);

            // Segment 2 - Spell #1, should be a skill
            SetValue_Skill(splitLine[1], ref outObj.Values[1], "potion, pill, or scroll", areaFile, lineNum, outObj.VNUM);

            // Segment 3 - Spell #2, should be a skill
            SetValue_Skill(splitLine[2], ref outObj.Values[2], "potion, pill, or scroll", areaFile, lineNum, outObj.VNUM);

            // Segment 4 - Spell #3, should be a skill
            SetValue_Skill(splitLine[3], ref outObj.Values[3], "potion, pill, or scroll", areaFile, lineNum, outObj.VNUM);

            // Segment 5 - Spell #4, should be a skill
            SetValue_Skill(splitLine[4], ref outObj.Values[4], "potion, pill, or scroll", areaFile, lineNum, outObj.VNUM);

            return(true);
        }
        private static string[] ParseValuesLine(string lineData, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            string[] splitInput = lineData.Split(' ');
            string[] output     = new string[5];
            bool     inQuoted   = false;
            int      count      = 0;
            string   buf        = String.Empty;

            foreach (string val in splitInput)
            {
                // If we're not in a quoted string and either the value doesn't start with a quote or is fully quoted...
                if (!inQuoted && (!val.StartsWith("'") || (val.StartsWith("'") && val.EndsWith("'"))))
                {
                    // Add the value to the output, removing all quotes
                    output[count] = val.Trim('\'');
                    count++;
                }
                // If we're in a quoted string and the value contains the ending quote...
                else if (inQuoted && val.EndsWith("'"))
                {
                    // Add the buffer and this value to the output, stripping the end quote
                    output[count] = buf + " " + val.Trim('\'');

                    count++;
                    inQuoted = false;
                }
                // If we're in a quoted string and the value does not contain the end quote...
                else if (inQuoted && !val.EndsWith("'"))
                {
                    // Add it to the buffer
                    buf += " " + val;
                }
                // If (implied) we're not in a quoted string and the value starts with a quote but doesn't end with a quote...
                else if (val.StartsWith("'") && !val.EndsWith("'"))
                {
                    // Add the value to the buffer, stripping the quote, and note that we're in a quoted string
                    buf      = val.Trim('\'');
                    inQuoted = true;
                }
            }

            return(output);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Wand or Staff
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetFurnitureValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // All segments should be parsed as ints
            SetValue_Int(splitLine[0], ref outObj.Values[0], "furniture", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[1], ref outObj.Values[1], "furniture", areaFile, lineNum, outObj.VNUM);

            // Segment 3, wear flag
            try
            {
                FurnitureFlag furnFlags = (FurnitureFlag)AlphaConversions.ConvertROMAlphaToInt32(splitLine[2]);
                outObj.Values[2] = furnFlags;
            }
            catch (ArgumentException e)
            {
                // Invalid extra flags
                throw new ObjectParsingException(String.Format("Error parsing furniture flags for object {0} in area {1}: invalid furniture flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum), e);
            }

            SetValue_Int(splitLine[3], ref outObj.Values[3], "furniture", areaFile, lineNum, outObj.VNUM);
            SetValue_Int(splitLine[4], ref outObj.Values[4], "furniture", areaFile, lineNum, outObj.VNUM);

            return(true);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Weapon
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetWeaponValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // Segment 1 - Weapon Type, should be a string matching the Name of a WeaponClass in the WeaponTable
            WeaponClass weapClass = Consts.WeaponClass.WeaponTable.SingleOrDefault(w => w.Name.ToLower().Equals(splitLine[0].ToLower()));

            if (weapClass == null)
            {
                // Invalid weapon class
                throw new ObjectParsingException(String.Format("Error parsing weapon class for object {0} in area {1}: unknown weapon class \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
            }
            else
            {
                // Store the weapon class
                outObj.Values[0] = weapClass;
            }

            // Segment 2 - Damage dice number, should be an integer
            int damDiceNum;

            if (!Int32.TryParse(splitLine[1], out damDiceNum))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing weapon damage dice number for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[1] = damDiceNum;
            }

            // Segment 3 - Damage dice type, should be an integer
            int damDiceType;

            if (!Int32.TryParse(splitLine[2], out damDiceType))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing weapon damage dice type for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[2] = damDiceType;
            }

            // Segment 4 - Attack Type, should be a string matching the Abreviation of a DamageType in the AttackTable
            DamageType damType = Consts.DamageTypes.AttackTable.SingleOrDefault(w => w.Abbreviation.ToLower().Equals(splitLine[3].ToLower()));

            if (weapClass == null)
            {
                // Invalid weapon class
                throw new ObjectParsingException(String.Format("Error parsing attack type for object {0} in area {1}: unknown attachk type \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[3], lineNum));
            }
            else
            {
                // Store the weapon class
                outObj.Values[3] = damType;
            }

            // Segment 5 - Weapon Flags
            try
            {
                WeaponFlag weapFlags = AlphaConversions.ConvertROMAlphaToWeaponFlag(splitLine[4]);
                outObj.Values[4] = weapFlags;
            }
            catch (ArgumentException e)
            {
                // Invalid extra flags
                throw new ObjectParsingException(String.Format("Error parsing weapon flags for object {0} in area {1}: invalid weapon flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[4], lineNum), e);
            }

            return(true);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is Container
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetContainerValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // Segment 1 - Capacity, should be an integer
            int capacity = 0;

            if (!Int32.TryParse(splitLine[0], out capacity))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing capacity for container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[0] = capacity;
            }

            // Segment 2 - Flags, should be a string matching Container flags
            try
            {
                ContainerFlag conFlags = AlphaConversions.ConvertROMAlphaToContainerFlag(splitLine[1]);
                outObj.Values[1] = conFlags;
            }
            catch (ArgumentException e)
            {
                // Invalid extra flags
                throw new ObjectParsingException(String.Format("Error parsing container flags for object {0} in area {1}: invalid weapon flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum), e);
            }

            // Segment 3 - Appears to be unused, but should be an integer
            int unknown = 0;

            if (!Int32.TryParse(splitLine[2], out unknown))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing unknown value (value #3) for container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[2] = unknown;
            }

            // Segment 4 - Maximum weight, should be an integer
            int maxWeight = 0;

            if (!Int32.TryParse(splitLine[3], out maxWeight))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing maximum weight for container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[3], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[3] = maxWeight;
            }

            // Segment 5 - Weight multiplier, should be an integer
            int weightMult = 0;

            if (!Int32.TryParse(splitLine[4], out weightMult))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing weight multiplier for container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[4], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[4] = weightMult;
            }

            return(true);
        }
        /// <summary>
        /// Sets the Values array of <paramref name="outObj"/> based on input values from <paramref name="splitLine"/> appropriate where object type is DrinkContainer or Fountain
        /// </summary>
        /// <returns><c>true</c> if values were set without errors, <c>false</c> otherwise. Errors are logged within this method.</returns>
        /// <param name="splitLine">Array of values to parse</param>
        /// <param name="outObj">Object whose Values property should be set</param>
        /// <param name="areaFile">Filename of the area file being parsed, used for error messages</param>
        /// <param name="lineNum">Line number the values came from, used for error messages</param>
        private static bool SetFountainAndDrinkContainerValues(string[] splitLine, ObjectPrototypeData outObj, string areaFile, int lineNum)
        {
            // Segment 1 - Container capacity, should be an integer
            int capacity = 0;

            if (!Int32.TryParse(splitLine[0], out capacity))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing capacity for fountain/drink container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[0] = capacity;
            }

            // Segment 2 - Container fill level, should be an integer
            int fillLevel = 0;

            if (!Int32.TryParse(splitLine[1], out fillLevel))
            {
                // Invalid damage dice number
                throw new ObjectParsingException(String.Format("Error parsing fill level for fountain/drink container object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
            }
            else
            {
                // Store the damage dice number
                outObj.Values[1] = fillLevel;
            }


            // Segment 3 - Liquid Type, should be a string matching the Name of a LiquidType in the LiquidTable
            string liqType = String.Empty;

            if (splitLine[2].StartsWith("'"))
            {
                int    i = 2;
                string nextElem;

                do
                {
                    nextElem = splitLine[i++];
                    liqType += " " + nextElem;
                }while (!nextElem.EndsWith("'"));

                liqType = liqType.Trim().Trim('\'');
            }
            else
            {
                liqType = splitLine[2];
            }

            LiquidType liqiudType = Consts.Liquids.LiquidTable.SingleOrDefault(l => l.Name.ToLower().Equals(liqType.ToLower()));

            if (liqiudType == null)
            {
                // Invalid weapon class
                throw new ObjectParsingException(String.Format("Error parsing liquid type for fountain/drink container object {0} in area {1}: unknown liquid type \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum));
            }
            else
            {
                // Store the weapon class
                outObj.Values[2] = liqiudType;
            }

            return(true);
        }
        internal static ObjectPrototypeData ParseObjectData(ref StringReader sr, string areaFile, ref int lineNum, string firstLine, bool log = true)
        {
            if (log)
            {
                Logging.Log.Debug(String.Format("ParseObjectData() called for area {0} starting on line {1}", areaFile, lineNum));
            }

            // Instantiate variables for the method
            ObjectPrototypeData outObj = new ObjectPrototypeData();
            string lineData            = firstLine;

            // First, pull the VNUM, then set it if it's valid
            int vnum = Data.ParseVNUM(lineData);

            if (!vnum.Equals(0))
            {
                outObj.VNUM = vnum;
            }
            else
            {
                return(null);
            }

            if (log)
            {
                Logging.Log.Debug(String.Format("Found object definition for vnum {0} beginning on line {1}", outObj.VNUM, lineNum));
            }

            // Set NewFormat to true - old format objects will be parsed from another method
            outObj.NewFormat = true;

            // Set reset number to zero
            outObj.ResetNum = 0;

            // Read the name
            outObj.Name = Data.ReadLongText(sr, ref lineNum, areaFile, outObj.VNUM);

            // Read the short description
            outObj.ShortDescription = Data.ReadLongText(sr, ref lineNum, areaFile, outObj.VNUM);

            // Read the long description
            outObj.Description = Data.ReadLongText(sr, ref lineNum, areaFile, outObj.VNUM);

            // Read the material - it may be oldstyle, but the original ROM code doesn't do anything with that either
            outObj.Material = Data.ReadLongText(sr, ref lineNum, areaFile, outObj.VNUM);

            // Read the next line and split, expect 3 segments
            lineData = sr.ReadLine();
            lineNum++;
            string[] splitLine = lineData.Split(' ');

            if (splitLine.Length != 3)
            {
                throw new ObjectParsingException(String.Format("Error parsing object {0} in area {1}: invalid type/extra flag/wear flag line, expected 3 segments but got {2} - value {3} on line {4}", outObj.VNUM, areaFile, splitLine.Length, lineData, lineNum));
            }

            // Segment 1, item type - attempt to pull a match from the ItemTypeTable
            ItemType objType = Consts.ItemTypes.ItemTypeTable.SingleOrDefault(it => it.Name.ToLower().Equals(splitLine[0].ToLower()));

            if (objType == null)
            {
                // Invalid item type
                throw new ObjectParsingException(String.Format("Error parsing item type for object {0} in area {1}: unknown item type \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
            }
            else
            {
                outObj.ObjectType = objType.Type;
            }

            // Segment 2, extra flag
            try
            {
                ItemExtraFlag extraFlags = AlphaConversions.ConvertROMAlphaToItemExtraFlag(splitLine[1]);
                outObj.ExtraFlags = extraFlags;
            }
            catch (ArgumentException e)
            {
                // Invalid extra flags
                throw new ObjectParsingException(String.Format("Error parsing extra flags for object {0} in area {1}: invalid extra flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum), e);
            }

            // Segment 3, wear flag
            try
            {
                WearFlag wearFlags = AlphaConversions.ConvertROMAlphaToWearFlag(splitLine[2]);
                outObj.WearFlags = wearFlags;
            }
            catch (ArgumentException e)
            {
                // Invalid extra flags
                throw new ObjectParsingException(String.Format("Error parsing wear flags for object {0} in area {1}: invalid extra flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum), e);
            }

            // Read the next line and split, expect 5 segments
            lineData = sr.ReadLine();
            lineNum++;

            string[] splitValues = ParseValuesLine(lineData, outObj, areaFile, lineNum);

            if (splitValues.Length != 5)
            {
                throw new ObjectParsingException(String.Format("Error parsing object {0} in area {1}: invalid values line, expected 5 segments but got {2} - value {3} on line {4}", outObj.VNUM, areaFile, splitLine.Length, lineData, lineNum));
            }

            // The meaning and data type of each of the 5 values changes depending on the item type
            // TODO: Finish implementing with Regex
            switch (outObj.ObjectType)
            {
            case ItemClass.Weapon:
                // Parse and set values
                if (!SetWeaponValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            case ItemClass.Container:
                // Parse and set values
                if (!SetContainerValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            case ItemClass.DrinkContainer:
            case ItemClass.Fountain:
                // Parse and set values
                if (!SetFountainAndDrinkContainerValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            case ItemClass.Wand:
            case ItemClass.Staff:
                // Parse and set values
                if (!SetWandAndStaffValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            case ItemClass.Potion:
            case ItemClass.Pill:
            case ItemClass.Scroll:
                // Parse and set values
                if (!SetPotionPillScrollValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            case ItemClass.Furniture:
                // Parse and set values
                if (!SetFurnitureValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;

            default:
                // Parse and set values
                if (!SetOtherItemTypeValues(splitValues, outObj, areaFile, lineNum))
                {
                    // An error was encountered, return a null object
                    return(null);
                }

                break;
            }

            // Read the next line and split, expect 4 segments
            lineData = sr.ReadLine();
            lineNum++;
            splitLine = lineData.Split(' ');

            if (splitLine.Length != 4)
            {
                throw new ObjectParsingException(String.Format("Error parsing object {0} in area {1}: invalid level/weight/cost/condition line, expected 4 segments but got {2} - value {3} on line {4}", outObj.VNUM, areaFile, splitLine.Length, lineData, lineNum));
            }

            // Segment 1 - Level
            int lvl = 0;

            if (!Int32.TryParse(splitLine[0], out lvl))
            {
                throw new ObjectParsingException(String.Format("Error parsing level for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
            }
            else
            {
                outObj.Level = lvl;
            }

            // Segment 2 - Weight
            int weight = 0;

            if (!Int32.TryParse(splitLine[1], out weight))
            {
                throw new ObjectParsingException(String.Format("Error parsing weight for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
            }
            else
            {
                outObj.Weight = weight;
            }

            // Segment 3 - Cost
            int cost = 0;

            if (!Int32.TryParse(splitLine[2], out cost))
            {
                throw new ObjectParsingException(String.Format("Error parsing cost for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum));
            }
            else
            {
                outObj.Cost = cost;
            }

            // Segment 4 - Condition
            switch (splitLine[3].ToLower())
            {
            case "p":
                outObj.Condition = 100;
                break;

            case "g":
                outObj.Condition = 90;
                break;

            case "a":
                outObj.Condition = 75;
                break;

            case "w":
                outObj.Condition = 50;
                break;

            case "d":
                outObj.Condition = 25;
                break;

            case "b":
                outObj.Condition = 10;
                break;

            case "r":
                outObj.Condition = 0;
                break;

            default:
                outObj.Condition = 100;
                break;
            }

            bool readingAffects = true;

            while (readingAffects)
            {
                // Peek at the start of the next line
                char nextLineStart = (char)sr.Peek();

                // If the next line does not start with a #, we have more to do
                if (!nextLineStart.Equals('#'))
                {
                    AffectData aff = new AffectData();

                    // Read the full line (more just to advance the cursor than anything; we've already read all the data)
                    lineData = sr.ReadLine();
                    lineNum++;

                    // Different behavior for different characters
                    switch (lineData.Trim().ToLower())
                    {
                    // Permanent affect
                    case "a":
                        // Read and split the next line for location and modifier
                        lineData = sr.ReadLine();
                        lineNum++;
                        splitLine = lineData.Split(' ');

                        // Should be two elements
                        if (splitLine.Length != 2)
                        {
                            throw new ObjectParsingException(String.Format("Error parsing object {0} in area {1}: invalid affect line, expected 2 segments but got {2} - value {3} on line {4}", outObj.VNUM, areaFile, splitLine.Length, lineData, lineNum));
                        }

                        // Set up properties of the affect
                        aff.Where     = ToWhere.Object;
                        aff.Type      = null;
                        aff.Level     = outObj.Level;
                        aff.Duration  = -1;
                        aff.BitVector = AffectedByFlag.None;

                        // Segment 1 - Location
                        int location = 0;
                        if (!Int32.TryParse(splitLine[0], out location))
                        {
                            throw new ObjectParsingException(String.Format("Error parsing location for object {0} affect in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[0], lineNum));
                        }
                        else
                        {
                            aff.Location = (ApplyType)location;
                        }

                        // Segment 2 - Modifier
                        int modifier = 0;
                        if (!Int32.TryParse(splitLine[1], out modifier))
                        {
                            throw new ObjectParsingException(String.Format("Error parsing modifier for object {0} affect in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
                        }
                        else
                        {
                            aff.Modifier = modifier;
                        }

                        if (log)
                        {
                            Logging.Log.Debug(String.Format("Object affect to {0} with modifier {1} added to object {2}", aff.Location.ToString(), aff.Modifier, outObj.VNUM));
                        }

                        // Add the affect to the object
                        outObj.Affected.Add(aff);

                        break;

                    case "f":
                        // Read and split the next line for location and modifier
                        lineData = sr.ReadLine();
                        lineNum++;
                        splitLine = lineData.Split(' ');

                        // Should be two elements
                        if (splitLine.Length != 4)
                        {
                            throw new ObjectParsingException(String.Format("Error parsing object {0} in area {1}: invalid affect line, expected 4 segments but got {2} - value {3} on line {4}", outObj.VNUM, areaFile, splitLine.Length, lineData, lineNum));
                        }

                        // Set up properties of the affect
                        aff.Type     = null;
                        aff.Level    = outObj.Level;
                        aff.Duration = -1;

                        // Segment 1 - Flag type (A, I, R, or V)
                        switch (splitLine[0].ToLower())
                        {
                        case "a":
                            aff.Where = ToWhere.Affects;
                            break;

                        case "i":
                            aff.Where = ToWhere.Immune;
                            break;

                        case "r":
                            aff.Where = ToWhere.Resist;
                            break;

                        case "v":
                            aff.Where = ToWhere.Vuln;
                            break;

                        default:
                            throw new ObjectParsingException(String.Format("Error parsing affect flags for object {0} in area {1}: invalid flag location type \"{2}\" encountered, expected A, I, R, or V on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
                        }

                        // Segment 2 - Location
                        int flagLocation = 0;
                        if (!Int32.TryParse(splitLine[1], out flagLocation))
                        {
                            throw new ObjectParsingException(String.Format("Error parsing affect flags location for object {0} in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[1], lineNum));
                        }
                        else
                        {
                            aff.Location = (ApplyType)flagLocation;
                        }

                        // Segment 3 - Modifier
                        int flagMod = 0;
                        if (!Int32.TryParse(splitLine[2], out flagMod))
                        {
                            throw new ObjectParsingException(String.Format("Error parsing affect flags modifier for object {0} affect in area {1}: expected an integer but found \"{2}\" on line {3}", outObj.VNUM, areaFile, splitLine[2], lineNum));
                        }
                        else
                        {
                            aff.Modifier = flagMod;
                        }

                        // Segment 4 - Bitvector (value of the flag to apply)
                        try
                        {
                            int bitvector = AlphaConversions.ConvertROMAlphaToInt32(splitLine[3]);
                            aff.BitVector = (AffectedByFlag)bitvector;
                        }
                        catch (ArgumentException e)
                        {
                            // Invalid extra flags
                            throw new ObjectParsingException(String.Format("Error parsing affect flags bitvector for object {0} in area {1}: invalid flag value \"{2}\" found on line {3}", outObj.VNUM, areaFile, splitLine[3], lineNum), e);
                        }

                        if (log)
                        {
                            Logging.Log.Debug(String.Format("Object affect flag loaded to {0} modifying {1} with modifier {2} and bitvector {3} on object {4} in area {5}", aff.Where.ToString(), aff.Location.ToString(), aff.Modifier, aff.BitVector, outObj.VNUM, areaFile));
                        }

                        // Add the affect
                        outObj.Affected.Add(aff);
                        break;

                    case "e":
                        // Object extra descriptions
                        // TODO: This is an almost straight copy of extra description loading in rooms, should be made its own method
                        ExtraDescription desc = new ExtraDescription();

                        // Read the next line
                        lineData = sr.ReadLine();
                        lineNum++;

                        // Store the value as the description's keyowrds
                        desc.Keywords = lineData.TrimEnd('~');

                        // Pull the extra description's data
                        desc.Description = Data.ReadLongText(sr, ref lineNum, areaFile, outObj.VNUM);

                        if (log)
                        {
                            Logging.Log.Debug(String.Format("Extra description loaded for object {0} in area {1} with keywords {2}", outObj.VNUM, areaFile, desc.Keywords));
                        }

                        // Append the ExtraDescription to the object
                        outObj.ExtraDescriptions.Add(desc);
                        break;

                    default:
                        if (log)
                        {
                            Logging.Log.Warn(String.Format("Invalid object modifier \"{0}\" found in object {1} in area {2} on line {3}", lineData.Trim(), outObj.VNUM, areaFile, lineNum));
                        }
                        break;
                    }
                }
                else
                {
                    // We're done with this object
                    readingAffects = false;
                }
            }


            return(outObj);
        }
예제 #11
0
 public ObjectData(ObjectPrototypeData proto, int level) : this(proto)
 {
     Level = (level > 0) ? level : 0;
 }
예제 #12
0
        public static AreaData LoadFromFile(string areaPath)
        {
            // Check that the file exists
            //try
            //{
            int              lineNum = 0;
            string           lineData;
            string           areaFile      = Path.GetFileName(areaPath);
            AreaReadingState state         = AreaReadingState.WaitingForSection;
            AreaData         areaOut       = new AreaData();
            int              errors        = 0;
            int              loaded        = 0;
            bool             backFromError = false;

            if (!File.Exists(areaPath))
            {
                // Log an error and return null
                Logging.Log.Error(String.Format("Unable to load requested area file {0}", areaPath));
                return(null);
            }

            // Instantiate a StreamReader and read the entire file
            StreamReader sr       = new StreamReader(areaPath);
            string       fileData = sr.ReadToEnd();

            sr.Dispose();

            // Instantiate a StreamReader for the file
            StringReader strRdr = new StringReader(fileData);

            // Parse the file, one line at a time.
            while ((lineData = strRdr.ReadLine()) != null)
            {
                // Increment lineNum
                lineNum++;

                switch (state)
                {
                case AreaReadingState.WaitingForSection:
                    // Skip blank lines while in this state
                    if (lineData.Trim().Equals(String.Empty))
                    {
                        Logging.Log.Debug(String.Format("Skipping empty line at {0}:{1}", areaFile, lineNum));
                        continue;
                    }

                    // Expect the first data line we come across to start with #
                    if (!lineData.StartsWith("#", StringComparison.InvariantCulture))
                    {
                        // Log an error and return null
                        Logging.Log.Error(String.Format("Error parsing {0} line {1}: Expected a section identifier, instead got {2}", areaFile, lineNum, lineData));
                        return(null);
                    }

                    // We've encountered a section heading; which one?
                    switch (lineData.Trim().ToUpper())
                    {
                        #region #$
                    // End-of-File Heading
                    case "#$":
                        // Log
                        Logging.Log.Debug(String.Format("Found #$ EOF marker in file {0} on line {1}, finishing up", areaFile, lineNum));

                        // Set state to finished
                        state = AreaReadingState.Finished;

                        break;
                        #endregion

                        #region #OBJECTS
                    case "#OBJECTS":
                        Logging.Log.Debug(String.Format("Found #OBJECTS heading in file {0} on line {1}", areaFile, lineNum));

                        // Continue reading until we hit a #0
                        bool readingObjects = true;
                        backFromError = false;
                        errors        = 0;
                        loaded        = 0;

                        while (readingObjects)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            // If we've recently come back from failing to load a mob, we need to ignore some lines
                            // until we get to the start of the next mob definition
                            if (backFromError)
                            {
                                // If the line is not the section terminator but it does begin with #, it is
                                // (should be) a new mob definition, so un-set the backFromError flag
                                if (!lineData.Trim().Equals("#0") && lineData.Trim().Length > 0 && lineData.Trim()[0].Equals('#'))
                                {
                                    // Un-set the backFromError flag; it's time to resume loading
                                    backFromError = false;

                                    Logging.Log.Debug(String.Format("Resuming loading of #OBJECTS section in area {0} on line {1} with mob {2}", areaFile, lineNum, lineData.Trim()));
                                }
                                // Otherwise, just move on to the next iteration of the loop
                                else
                                {
                                    continue;
                                }
                            }

                            if (lineData == null)
                            {
                                readingObjects = false;
                            }
                            else if (lineData.Trim().Equals("#0"))
                            {
                                readingObjects = false;
                            }
                            else if (!lineData.Trim().Equals("#0") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                try
                                {
                                    ObjectPrototypeData newObj = ObjectPrototypeData.ParseObjectData(ref strRdr, areaFile, ref lineNum, lineData);

                                    // If we have a loaded room, add it to the world
                                    if (newObj != null)
                                    {
                                        Program.World.Objects.Add(newObj);
                                        loaded++;
                                    }
                                    else
                                    {
                                        // Record a failed mob load, and set the indicator that we're back because of an error and should keep reading
                                        // but do nothing until we find a new mob
                                        errors++;
                                        backFromError = true;
                                    }
                                }
                                catch (ObjectParsingException ex)
                                {
                                    Logging.Log.Error(String.Format("Error parsing object: {0}", ex.Message));
                                }
                            }
                        }

                        Logging.Log.Debug(String.Format("Finished reading #OBJECTS section of file {0} on line {1} - loaded {2} objects, failed loading {3} mobs", areaFile, lineNum, loaded, errors));

                        break;
                        #endregion

                        #region #RESETS
                    case "#RESETS":
                        Logging.Log.Debug(String.Format("Found #RESETS heading in file {0} on line {1}", areaFile, lineNum));

                        // Continue reading until we hit a #0
                        bool readingResets = true;
                        backFromError = false;
                        errors        = 0;
                        loaded        = 0;
                        ResetData lastMob = null;

                        while (readingResets)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            if (lineData == null)
                            {
                                readingResets = false;
                            }
                            else if (lineData.Trim().Equals("S"))
                            {
                                readingResets = false;
                            }
                            else if (!lineData.Trim().Equals("S") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                try
                                {
                                    // Parse the reset
                                    ResetData newReset = ResetData.ParseResetData(areaFile, ref lineNum, lineData, lastMob);

                                    // Check that the reset parsed
                                    if (newReset != null)
                                    {
                                        // Special handling if the new reset is an E(quip) or G(ive)
                                        if (newReset.Command == ResetCommand.EquipObjectOnMob || newReset.Command == ResetCommand.GiveObjectToMob)
                                        {
                                            // Nest in the mob reset it relates to
                                            lastMob.Inner.Add(newReset);
                                        }
                                        else
                                        {
                                            // Otherwise, add the reset to the area
                                            areaOut.Resets.Add(newReset);
                                        }

                                        // If the reset was to spawn a M(ob), reset lastMob
                                        if (newReset.Command == ResetCommand.SpawnMobile)
                                        {
                                            lastMob = newReset;
                                        }

                                        // Finally, increment the loaded count
                                        loaded++;
                                    }
                                    else
                                    {
                                        // Record a failed mob load, and set the indicator that we're back because of an error and should keep reading
                                        // but do nothing until we find a new mob
                                        errors++;
                                        backFromError = true;
                                    }
                                }
                                catch (ObjectParsingException ex)
                                {
                                    Logging.Log.Error(String.Format("Error parsing object: {0}", ex.Message));
                                }
                            }
                        }

                        break;
                        #endregion

                        #region #SHOPS
                    case "#SHOPS":
                        Logging.Log.Debug(String.Format("Found #SHOPS heading in file {0} on line {1}", areaFile, lineNum));

                        // Continue reading until we hit a #0
                        bool readingShops = true;
                        backFromError = false;
                        errors        = 0;
                        loaded        = 0;

                        while (readingShops)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            // If we've recently come back from failing to load a mob, we need to ignore some lines
                            // until we get to the start of the next mob definition
                            if (backFromError)
                            {
                                // If the line is not the section terminator but it does begin with #, it is
                                // (should be) a new mob definition, so un-set the backFromError flag
                                if (!lineData.Trim().Equals("#0") && lineData.Trim().Length > 0 && lineData.Trim()[0].Equals('#'))
                                {
                                    // Un-set the backFromError flag; it's time to resume loading
                                    backFromError = false;

                                    Logging.Log.Debug(String.Format("Resuming loading of #SHOPS section in area {0} on line {1} with mob {2}", areaFile, lineNum, lineData.Trim()));
                                }
                                // Otherwise, just move on to the next iteration of the loop
                                else
                                {
                                    continue;
                                }
                            }

                            if (lineData == null)
                            {
                                readingShops = false;
                            }
                            else if (lineData.Trim().Equals("#0"))
                            {
                                readingShops = false;
                            }
                            else if (!lineData.Trim().Equals("#0") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                // TODO: Implement #SHOPS parsing
                            }
                        }

                        break;
                        #endregion

                        #region #SPECIALS
                    case "#SPECIALS":
                        Logging.Log.Debug(String.Format("Found #SPECIALS heading in file {0} on line {1}", areaFile, lineNum));

                        // Continue reading until we hit a #0
                        bool readingSpecials = true;
                        backFromError = false;
                        errors        = 0;
                        loaded        = 0;

                        while (readingSpecials)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            // If we've recently come back from failing to load a mob, we need to ignore some lines
                            // until we get to the start of the next mob definition
                            if (backFromError)
                            {
                                // If the line is not the section terminator but it does begin with #, it is
                                // (should be) a new mob definition, so un-set the backFromError flag
                                if (!lineData.Trim().Equals("#0") && lineData.Trim().Length > 0 && lineData.Trim()[0].Equals('#'))
                                {
                                    // Un-set the backFromError flag; it's time to resume loading
                                    backFromError = false;

                                    Logging.Log.Debug(String.Format("Resuming loading of #SPECIALS section in area {0} on line {1} with mob {2}", areaFile, lineNum, lineData.Trim()));
                                }
                                // Otherwise, just move on to the next iteration of the loop
                                else
                                {
                                    continue;
                                }
                            }

                            if (lineData == null)
                            {
                                readingSpecials = false;
                            }
                            else if (lineData.Trim().Equals("#0"))
                            {
                                readingSpecials = false;
                            }
                            else if (!lineData.Trim().Equals("#0") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                // TODO: Implement #SPECIALS parsing
                            }
                        }

                        break;
                        #endregion

                        #region #MOBILES
                    case "#MOBILES":
                        Logging.Log.Debug(String.Format("Found #MOBILES heading in file {0} on line {1}", areaFile, lineNum));

                        errors        = 0;
                        loaded        = 0;
                        backFromError = false;

                        // Continue reading until we hit a #0
                        bool readingMobs = true;
                        while (readingMobs)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            // If we've recently come back from failing to load a mob, we need to ignore some lines
                            // until we get to the start of the next mob definition
                            if (backFromError)
                            {
                                // If the line is not the section terminator but it does begin with #, it is
                                // (should be) a new mob definition, so un-set the backFromError flag
                                if (!lineData.Trim().Equals("#0") && lineData.Trim().Length > 0 && lineData.Trim()[0].Equals('#'))
                                {
                                    // Un-set the backFromError flag; it's time to resume loading
                                    backFromError = false;

                                    Logging.Log.Debug(String.Format("Resuming loading of #MOBILES section in area {0} on line {1} with mob {2}", areaFile, lineNum, lineData.Trim()));
                                }
                                // Otherwise, just move on to the next iteration of the loop
                                else
                                {
                                    continue;
                                }
                            }

                            if (lineData == null)
                            {
                                readingMobs = false;
                            }
                            else if (lineData.Trim().Equals("#0"))
                            {
                                readingMobs = false;
                            }
                            else if (!lineData.Trim().Equals("#0") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                MobPrototypeData newMob = MobPrototypeData.ParseMobData(ref strRdr, areaFile, ref lineNum, lineData);

                                // If we have a loaded room, add it to the world
                                if (newMob != null)
                                {
                                    Program.World.Mobs.Add(newMob);
                                    loaded++;
                                }
                                else
                                {
                                    // Record a failed mob load, and set the indicator that we're back because of an error and should keep reading
                                    // but do nothing until we find a new mob
                                    errors++;
                                    backFromError = true;
                                }
                            }
                        }

                        Logging.Log.Debug(String.Format("Finished reading #MOBILES section of file {0} on line {1} - loaded {2} mobs, failed loading {3} mobs", areaFile, lineNum, loaded, errors));

                        break;
                        #endregion

                        #region #ROOMS
                    case "#ROOMS":
                        Logging.Log.Debug(String.Format("Found #ROOMS heading in file {0} on line {1}", areaFile, lineNum));

                        // Continue reading until we hit a #0
                        bool readingRooms = true;
                        backFromError = false;
                        errors        = 0;
                        loaded        = 0;

                        while (readingRooms)
                        {
                            // Read a line
                            lineData = strRdr.ReadLine();
                            lineNum++;

                            // If we've recently come back from failing to load a mob, we need to ignore some lines
                            // until we get to the start of the next mob definition
                            if (backFromError)
                            {
                                // If the line is not the section terminator but it does begin with #, it is
                                // (should be) a new mob definition, so un-set the backFromError flag
                                if (!lineData.Trim().Equals("#0") && lineData.Trim().Length > 0 && lineData.Trim()[0].Equals('#'))
                                {
                                    // Un-set the backFromError flag; it's time to resume loading
                                    backFromError = false;

                                    Logging.Log.Debug(String.Format("Resuming loading of #ROOMS section in area {0} on line {1} with mob {2}", areaFile, lineNum, lineData.Trim()));
                                }
                                // Otherwise, just move on to the next iteration of the loop
                                else
                                {
                                    continue;
                                }
                            }

                            if (lineData == null)
                            {
                                readingRooms = false;
                            }
                            else if (lineData.Trim().Equals("#0"))
                            {
                                readingRooms = false;
                            }
                            else if (!lineData.Trim().Equals("#0") && !lineData.Trim().Equals("#$") && !lineData.Trim().Equals(""))
                            {
                                RoomIndexData newRoom = RoomIndexData.ParseRoomData(ref strRdr, areaFile, ref lineNum, lineData);

                                // If we have a loaded room, add it to the world
                                if (newRoom != null)
                                {
                                    loaded++;
                                    Program.World.Rooms.Add(newRoom);
                                }
                                else
                                {
                                    errors++;
                                    backFromError = true;
                                }
                            }
                        }

                        Logging.Log.Debug(String.Format("Finished reading #ROOMS section of file {0} on line {1} - loaded {2} rooms, failed loading {3} rooms", areaFile, lineNum, loaded, errors));

                        break;

                    default:
                        break;
                        #endregion

                        #region #AREA
                    // AREA Heading
                    case "#AREA":
                        Logging.Log.Debug(String.Format("Found #AREA heading in file {0} on line {1}", areaFile, lineNum));

                        #region Filename
                        // Read the next line - will be the area filename
                        lineData = strRdr.ReadLine();
                        lineNum++;

                        // Trim the trailing tilde
                        lineData = lineData.Substring(0, lineData.Trim().Length - 1);

                        // Set filename
                        areaOut.Filename = lineData;

                        Logging.Log.Debug(String.Format("Read area filename in file {0} on line {1}", areaFile, lineNum));
                        #endregion

                        #region Name
                        // Read the next line - will be the area name
                        lineData = strRdr.ReadLine();
                        lineNum++;

                        // Trim the trailing tilde
                        lineData = lineData.Substring(0, lineData.Trim().Length - 1);

                        // Set name
                        areaOut.Name = lineData;

                        Logging.Log.Debug(String.Format("Read area name in file {0} on line {1}", areaFile, lineNum));
                        #endregion

                        #region Credits
                        // Read the next line - will be the credits
                        lineData = strRdr.ReadLine();
                        lineNum++;

                        // Trim the trailing tilde
                        lineData = lineData.Substring(0, lineData.Trim().Length - 1);

                        // Set credits
                        areaOut.Credits = lineData;

                        Logging.Log.Debug(String.Format("Read credits information in file {0} on line {1}", areaFile, lineNum));
                        #endregion

                        #region MinVNUM and MaxVNUM
                        // Read the next line - will be the VNUM values
                        lineData = strRdr.ReadLine();
                        lineNum++;

                        // Split the line on space
                        string[] vnumData = lineData.Trim().Split(' ');

                        // Should be two values
                        if (!vnumData.Length.Equals(2))
                        {
                            // Log an error and return null
                            Logging.Log.Error(String.Format("Error parsing {0} line {1}: Expected two numbers separated by space for VNUM limits, instead found {2}", areaFile, lineNum, lineData));
                            return(null);
                        }

                        // Tracks which of the two numbers we're on
                        bool firstNum = true;

                        // Loop over the two values, each should convert to an integer
                        foreach (string vnum in vnumData)
                        {
                            int intVal;

                            // Try to parse the value as a 32-bit integer
                            if (!Int32.TryParse(vnum, out intVal))
                            {
                                // Log an error and return null
                                Logging.Log.Error(String.Format("Error parsing {0} line {1}: Error converting VNUM value {2} to an integer", areaFile, lineNum, vnum));
                                return(null);
                            }
                            else
                            {
                                if (firstNum)
                                {
                                    areaOut.MinVNum = intVal;
                                    firstNum        = false;
                                }
                                else
                                {
                                    areaOut.MaxVNum = intVal;
                                }
                            }
                        }

                        Logging.Log.Debug(String.Format("Finished processing #AREA section of file {0} at line {1}", areaFile, lineNum));
                        #endregion

                        break;
                        #endregion
                    }
                    break;

                default:
                    break;
                }
            }

            strRdr.Dispose();

            // Return the output area
            return(areaOut);
            //}
            //catch (Exception e)
            //{
            //    // Log the exception and rethrow
            //    Logging.Log.Fatal(String.Format("Unhandled exception caught: {0}: {1}\n{2}", e.GetType(), e.Message, e.StackTrace));
            //    throw (e);
            //}
        }