public ObjectPrototypeData()
 {
     Affected          = new List <AffectData>();
     ExtraDescriptions = new List <ExtraDescription>();
     ExtraFlags        = new ItemExtraFlag();
     WearFlags         = new WearFlag();
     Values            = new object[5];
     Values[0]         = 0;
     Values[1]         = 0;
     Values[2]         = 0;
     Values[3]         = 0;
     Values[4]         = 0;
 }
        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);
        }