public override bool Equals(object obj) { MobPrototypeData other = (MobPrototypeData)obj; return(other.VNUM.Equals(other.VNUM) && other.Killed.Equals(Killed) && other.Name.Equals(Name) && other.ShortDescription.Equals(ShortDescription) && other.LongDescription.Equals(LongDescription) && other.Description.Equals(Description) && other.Race.Equals(Race) && other.Resistance.Equals(Resistance) && other.Vulnerability.Equals(Vulnerability) && other.Form.Equals(Form) && other.Parts.Equals(Parts) && other.Actions.Equals(Actions) && other.AffectedBy.Equals(AffectedBy) && other.Alignment.Equals(Alignment) && other.Group.Equals(Group) && other.Level.Equals(Level) && other.HitRoll.Equals(HitRoll) && other.Health.Equals(Health) && other.Mana.Equals(Mana) && other.Damage.Equals(Damage) && other.DamageType.Equals(DamageType) && other.ArmorRating.Equals(ArmorRating) && other.Offense.Equals(Offense) && other.Immunity.Equals(Immunity) && other.Resistance.Equals(Resistance) && other.StartingPosition.Equals(StartingPosition) && other.DefaultPosition.Equals(DefaultPosition) && other.Gender.Equals(Gender) && other.Wealth.Equals(Wealth) && other.Size.Equals(Size)); }
public CharacterData(MobPrototypeData prototype) : this() { // Simple assignments Prototype = prototype; Name = prototype.Name; ShortDescription = prototype.ShortDescription; LongDescription = prototype.LongDescription; Description = prototype.Description; SpecialFunction = prototype.SpecialFunction; Prompt = null; Group = prototype.Group; Action = prototype.Actions; Communication = CommunicationFlag.NoChannels | CommunicationFlag.NoShout | CommunicationFlag.NoTell; AffectedBy = prototype.AffectedBy; Alignment = prototype.Alignment; Level = prototype.Level; HitRoll = prototype.HitRoll; DamRoll = prototype.Damage.Bonus; Damage = prototype.Damage; Armor = prototype.ArmorRating; Offense = prototype.Offense; Immunity = prototype.Immunity; Resist = prototype.Resistance; Vulnerability = prototype.Vulnerability; StartPosition = prototype.StartingPosition; DefaultPosition = prototype.DefaultPosition; Race = prototype.Race; Form = prototype.Form; Parts = prototype.Parts; Size = prototype.Size; Material = prototype.Material; Affects = new List <AffectData>(); PermanentStats = new Stats(); ModifiedStats = new Stats(); // Calculated assignments if (prototype.Wealth == 0) { Gold = 0; Silver = 0; } else { Random rand = new Random(); // Calculate the randomized wealth of the mob (0.5x - 1.5x the mob's wealth value) long actualWealth = rand.Next(prototype.Wealth / 2, 3 * prototype.Wealth / 2); // Set gold based on actual wealth Gold = rand.Next((int)actualWealth / 200, (int)actualWealth / 100); Silver = actualWealth - (Gold * 100); } // Roll the hit dice to determine max health; set current to the max. MaxHealth = prototype.Health.RollDice(); Health = MaxHealth; // Roll the mana dice to determine max mana; set current to the max MaxMana = prototype.Mana.RollDice(); Mana = MaxMana; // If no damage class is set, choose from slash, pound, and pierce if (prototype.DamageType.DamageClass == DamageClass.None) { Random rand = new Random(); DamageType = Consts.DamageTypes.AttackTable[rand.Next(3)]; } else { DamageType = prototype.DamageType; } // If the prototype gender is random, choose one now; otherwise, set if (prototype.Gender.GenderCode == Sex.Random) { Random rng = new Random(); Gender = Consts.Gender.GenderTable[rng.Next(2)]; } else { Gender = prototype.Gender; } // Set stats - first, set a base across all stats PermanentStats = new Stats(Helpers.Miscellaneous.LowestOf(new int[] { 25, 11 + (Level / 4) })); // Next, adjust stats based on action flags (classes, mostly) if (Action.HasFlag(ActionFlag.Warrior)) { PermanentStats.Strength += 3; PermanentStats.Intelligence -= 1; PermanentStats.Constitution += 2; } if (Action.HasFlag(ActionFlag.Thief)) { PermanentStats.Dexterity += 3; PermanentStats.Intelligence += 1; PermanentStats.Wisdom -= 1; } if (Action.HasFlag(ActionFlag.Cleric)) { PermanentStats.Wisdom += 3; PermanentStats.Dexterity -= 1; PermanentStats.Strength += 1; } if (Action.HasFlag(ActionFlag.Mage)) { PermanentStats.Intelligence += 3; PermanentStats.Strength -= 1; PermanentStats.Dexterity += 1; } // 2 point dexterity bonus for Fast if (Offense.HasFlag(OffensiveFlag.Offense_Fast)) { PermanentStats.Dexterity += 2; } // Size modifiers to strength and constitution - increase when size > medium PermanentStats.Strength += (int)Size.SizeCode - (int)Enums.Size.Medium; PermanentStats.Constitution += ((int)Size.SizeCode - (int)Enums.Size.Medium) / 2; // Permanent spells // Sanctuary if (AffectedBy.HasFlag(AffectedByFlag.Sanctuary)) { SkillType skill = Consts.Skills.SkillTable.SingleOrDefault(s => s.Name.ToLower().Equals("sanctuary")); AffectData affect = new AffectData() { Where = ToWhere.Affects, Type = skill, Level = Level, Duration = -1, Location = ApplyType.None, Modifier = 0, BitVector = AffectedByFlag.Sanctuary }; ApplyAffect(affect); } // Haste - also applies a dexterity modifier based on level if (AffectedBy.HasFlag(AffectedByFlag.Haste)) { SkillType skill = Consts.Skills.SkillTable.Single(s => s.Name.ToLower().Equals("haste")); AffectData affect = new AffectData() { Where = ToWhere.Affects, Type = skill, Level = Level, Duration = -1, Location = ApplyType.Dexterity, Modifier = (Level >= 32) ? 4 : (Level >= 25) ? 3 : (Level >= 18) ? 2 : 1, BitVector = AffectedByFlag.Haste }; ApplyAffect(affect); } // Protection from Evil if (AffectedBy.HasFlag(AffectedByFlag.ProtectEvil)) { SkillType skill = Consts.Skills.SkillTable.Single(s => s.Name.ToLower().Equals("protection evil")); AffectData affect = new AffectData() { Where = ToWhere.Affects, Type = skill, Level = Level, Duration = -1, Location = ApplyType.Saves, Modifier = -1, BitVector = AffectedByFlag.ProtectEvil }; ApplyAffect(affect); } // Protection from Good if (AffectedBy.HasFlag(AffectedByFlag.ProtectGood)) { SkillType skill = Consts.Skills.SkillTable.Single(s => s.Name.ToLower().Equals("protection good")); AffectData affect = new AffectData() { Where = ToWhere.Affects, Type = skill, Level = Level, Duration = -1, Location = ApplyType.Saves, Modifier = -1, BitVector = AffectedByFlag.ProtectGood }; ApplyAffect(affect); } }
internal static MobPrototypeData ParseMobData(ref StringReader sr, string areaFile, ref int lineNum, string firstLine) { Logging.Log.Debug(String.Format("ParseMobData() called for area {0} starting on line {1}", areaFile, lineNum)); // Instantiate variables for the method MobPrototypeData outMob = new MobPrototypeData(); string lineData = firstLine; // First, pull the VNUM, then set it if it's valid int vnum = Data.ParseVNUM(lineData); if (!vnum.Equals(0)) { outMob.VNUM = vnum; } else { return(null); } Logging.Log.Debug(String.Format("Found mob definition for vnum {0} beginning on line {1}", outMob.VNUM, lineNum)); // Read the mob name - technically we should just read 'til we get a tilde, but it looks like they're always on one line anyway... outMob.Name = sr.ReadLine().TrimEnd('~'); lineNum++; // Next, read the short description; again, a single line outMob.ShortDescription = sr.ReadLine().TrimEnd('~'); lineNum++; // Then, read the long description outMob.LongDescription = Data.ReadLongText(sr, ref lineNum, areaFile, outMob.VNUM); // Finally, read yet another description outMob.Description = Data.ReadLongText(sr, ref lineNum, areaFile, outMob.VNUM); // TODO: Capitalize the first letter of LongDescription and Description. Or don't, I'm not your dad. // Next, parse the race string mobRaceName = sr.ReadLine().TrimEnd('~'); lineNum++; Race mobRace = Consts.Races.RaceTable.SingleOrDefault(r => r.Name.ToLower().Equals(mobRaceName.ToLower())); // If we can't find the race, log a warning and return null if (mobRace == null) { Logging.Log.Error(String.Format("Encountered unknown race {0} for mob {1} of area {2} on line {3}", mobRaceName, outMob.VNUM, areaFile, lineNum)); return(null); } else { // Otherwise, store the race outMob.Race = mobRace; // Race defaults a number of flags; set these now outMob.Form = outMob.Race.Form; outMob.Parts = outMob.Race.Parts; outMob.Actions = outMob.Race.Actions; outMob.AffectedBy = outMob.Race.Affects; outMob.Immunity = outMob.Race.Immunities; outMob.Resistance = outMob.Race.Resistances; outMob.Vulnerability = outMob.Race.Vulnerabilities; } // Split the next line into an array that should have four elements lineData = sr.ReadLine(); lineNum++; string[] splitLine = lineData.Split(' '); // Expect four segments if (splitLine.Length != 4) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid act/aff/align/group line, expected 4 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } int parsedValue = 0; // First segment, action flags - also add IsNPC to all mobs outMob.Actions |= AlphaConversions.ConvertROMAlphaToActionFlag(splitLine[0]) | ActionFlag.IsNPC; // Second segment, affected by flags outMob.AffectedBy = AlphaConversions.ConvertROMAlphaToAffectedByFlag(splitLine[1]); // Third segment, alignment if (!Int32.TryParse(splitLine[2], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing alignment for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[2], lineNum)); return(null); } else { outMob.Alignment = Convert.ToInt32(splitLine[2]); } // Fourth segment, group if (!Int32.TryParse(splitLine[3], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing group number for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[3], lineNum)); return(null); } else { outMob.Group = Convert.ToInt32(splitLine[3]); } // Read the next line and split - expect six segments lineData = sr.ReadLine(); lineNum++; splitLine = lineData.Split(' '); if (splitLine.Length != 6) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid level/hit/health/mana/damage/dtype line, expected 6 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment, level if (!Int32.TryParse(splitLine[0], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing level for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[0], lineNum)); return(null); } else { outMob.Level = Convert.ToInt32(splitLine[0]); } // Second segment, hitroll if (!Int32.TryParse(splitLine[1], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing hitroll for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[1], lineNum)); return(null); } else { outMob.HitRoll = Convert.ToInt32(splitLine[1]); } // Third segment, hit dice DiceRoll dice; if (!DiceRoll.TryParse(splitLine[2], out dice)) { Logging.Log.Error(String.Format("Error parsing hit dice for mobile {0} in area {1}: invalid dice roll string ({2}) encountered on line {3}", outMob.VNUM, areaFile, splitLine[2], lineNum)); return(null); } else { outMob.Health = dice; } // Fourth segment, mana dice if (!DiceRoll.TryParse(splitLine[3], out dice)) { Logging.Log.Error(String.Format("Error parsing mana dice for mobile {0} in area {1}: invalid dice roll string ({2}) encountered on line {3}", outMob.VNUM, areaFile, splitLine[3], lineNum)); return(null); } else { outMob.Mana = dice; } // Fifth segment, damage dice if (!DiceRoll.TryParse(splitLine[4], out dice)) { Logging.Log.Error(String.Format("Error parsing damage dice for mobile {0} in area {1}: invalid dice roll string ({2}) encountered on line {3}", outMob.VNUM, areaFile, splitLine[4], lineNum)); return(null); } else { outMob.Damage = dice; } // Sixth segment, damage type - check that we have a matching damage type with the given abbreviation DamageType dtype = Consts.DamageTypes.AttackTable.SingleOrDefault(d => d.Abbreviation.Equals(splitLine[5].Trim())); if (dtype == null) { Logging.Log.Error(String.Format("Error parsing damage type for mobile {0} in area {1}: unknown damage type {2} specified on line {4}", outMob.VNUM, areaFile, splitLine[5], lineNum)); return(null); } else { outMob.DamageType = dtype; } // Read the next line and split again, armor classes - expect four segments lineData = sr.ReadLine(); lineNum++; splitLine = lineData.Split(' '); if (splitLine.Length != 4) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid level/hit/health/mana/damage/dtype line, expected 4 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment, piercing AC if (!Int32.TryParse(splitLine[0], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing piercing AC for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[0], lineNum)); return(null); } else { outMob.ArmorRating.Pierce = Convert.ToInt32(splitLine[0]); } // Second segment, bashing AC if (!Int32.TryParse(splitLine[1], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing bashing AC for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[1], lineNum)); return(null); } else { outMob.ArmorRating.Bash = Convert.ToInt32(splitLine[1]); } // Third segment, slashing AC if (!Int32.TryParse(splitLine[2], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing slashing AC for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[2], lineNum)); return(null); } else { outMob.ArmorRating.Slash = Convert.ToInt32(splitLine[2]); } // Fourth segment, exotic AC if (!Int32.TryParse(splitLine[3], out parsedValue)) { Logging.Log.Error(String.Format("Error parsing exotic AC for mobile {0} in area {1}: non-numeric value {2} encountered on line {3}", outMob.VNUM, areaFile, splitLine[3], lineNum)); return(null); } else { outMob.ArmorRating.Exotic = Convert.ToInt32(splitLine[3]); } // Read the next line and split again, offense/imm/res/vuln flags - expect four segments lineData = sr.ReadLine(); lineNum++; splitLine = lineData.Split(' '); if (splitLine.Length != 4) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid offense/imm/res/vuln line, expected 4 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment, offense flags outMob.Offense |= AlphaConversions.ConvertROMAlphaToOffensiveFlag(splitLine[0]); // Second segment, immunity flags outMob.Immunity |= AlphaConversions.ConvertROMAlphaToImmunitylag(splitLine[1]); // Third segment, resistance flags outMob.Resistance |= AlphaConversions.ConvertROMAlphaToResistanceFlag(splitLine[2]); // Fourth segment, vulnerability flags outMob.Vulnerability |= AlphaConversions.ConvertROMAlphaToVulnerabilityFlag(splitLine[3]); // Read the next line and split again, start pos/default pos/sex/wealth - epect four segments lineData = sr.ReadLine(); lineNum++; splitLine = lineData.Split(' '); if (splitLine.Length != 4) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid start pos/default pos/sex/wealth line, expected 4 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment, start position Position startPos = Consts.Positions.PositionTable.SingleOrDefault(p => p.ShortName.Equals(splitLine[0])); if (startPos == null) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid start position \"{2}\" found on line {3}", outMob.VNUM, areaFile, splitLine[0], lineNum)); return(null); } else { outMob.StartingPosition = startPos; } // Second segment, default position Position defPos = Consts.Positions.PositionTable.SingleOrDefault(p => p.ShortName.Equals(splitLine[1])); if (startPos == null) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid default position \"{2}\" found on line {3}", outMob.VNUM, areaFile, splitLine[1], lineNum)); return(null); } else { outMob.DefaultPosition = defPos; } // Third segment, gender Gender mobGender = Consts.Gender.GenderTable.SingleOrDefault(g => g.Name.Equals(splitLine[2])); if (mobGender == null) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid gender \"{2}\" found on line {3}", outMob.VNUM, areaFile, splitLine[2], lineNum)); return(null); } else { outMob.Gender = mobGender; } // Fourth segment, wealth int wealth = 0; if (!Int32.TryParse(splitLine[3], out wealth)) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid wealth \"{2}\" found on line {3}, expected an integer", outMob.VNUM, areaFile, splitLine[3], lineNum)); return(null); } else { outMob.Wealth = wealth; } // Read the next line and split again, form/parts/size/material - epect four segments lineData = sr.ReadLine(); lineNum++; splitLine = lineData.Split(' '); if (splitLine.Length != 4) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid start pos/default pos/sex/wealth line, expected 4 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment, form outMob.Form |= AlphaConversions.ConvertROMAlphaToFormFlag(splitLine[0]); // Second segment, parts outMob.Parts |= AlphaConversions.ConvertROMAlphaToPartFlag(splitLine[1]); // Third segment, size Models.Size mobSize = Consts.Size.SizeTable.SingleOrDefault(s => s.Name.Equals(splitLine[2])); if (mobSize == null) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid size \"{2}\" found on line {3}", outMob.VNUM, areaFile, splitLine[2], lineNum)); return(null); } else { outMob.Size = mobSize; } // Fourth segment, material outMob.Material = splitLine[3]; // Peek ahead to the next line, see if it starts with F, which tells us to un-set some flags while ((char)sr.Peek() == 'F') { // Read the line lineData = sr.ReadLine(); lineNum++; // Split the line, expect 3 segments splitLine = lineData.Split(' '); if (splitLine.Length != 3) { Logging.Log.Error(String.Format("Error parsing mobile {0} in area {1}: invalid flag modification line, expected 3 segments but got {2} - value {3} on line {4}", outMob.VNUM, areaFile, splitLine.Length, lineData, lineNum)); return(null); } // First segment is line identifier, ignore it. Second segment is which flag to modify, third segment is flag(s) to remove. switch (splitLine[1]) { case "act": // Actions Logging.Log.Debug(String.Format("Removing action flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Actions &= ~AlphaConversions.ConvertROMAlphaToActionFlag(splitLine[2]); break; case "aff": // AffectedBy Logging.Log.Debug(String.Format("Removing affected by flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.AffectedBy &= ~AlphaConversions.ConvertROMAlphaToAffectedByFlag(splitLine[2]); break; case "off": // Offense Logging.Log.Debug(String.Format("Removing offense flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Offense &= ~AlphaConversions.ConvertROMAlphaToOffensiveFlag(splitLine[2]); break; case "imm": // Immunities Logging.Log.Debug(String.Format("Removing immunity flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Immunity &= ~AlphaConversions.ConvertROMAlphaToImmunitylag(splitLine[2]); break; case "res": // Resistances Logging.Log.Debug(String.Format("Removing restistance flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Resistance &= ~AlphaConversions.ConvertROMAlphaToResistanceFlag(splitLine[2]); break; case "vul": // Vulnerabilities Logging.Log.Debug(String.Format("Removing vulnerability flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Vulnerability &= ~AlphaConversions.ConvertROMAlphaToVulnerabilityFlag(splitLine[2]); break; case "for": // Form Logging.Log.Debug(String.Format("Removing form flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Form &= ~AlphaConversions.ConvertROMAlphaToFormFlag(splitLine[2]); break; case "par": // Parts Logging.Log.Debug(String.Format("Removing parts flags {0} from mob {1} in area {2} on line {3}", splitLine[2], outMob.VNUM, areaFile, lineNum)); // Remove flags outMob.Parts &= ~AlphaConversions.ConvertROMAlphaToPartFlag(splitLine[2]); break; default: Logging.Log.Warn(String.Format("Encountered unexpected mob flag modifier type {0} for mob {1} in file {2} on line {3}", splitLine[1], outMob.VNUM, areaFile, lineNum)); break; } } Logging.Log.Debug(String.Format("Mobile {0} in area {1} loaded", outMob.VNUM, areaFile)); return(outMob); }
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); //} }