public GiveResetData(ResetData data) : base() { this.Arg1 = data.Arg1; this.Arg2 = data.Arg2; this.Arg3 = data.Arg3; this.Arg4 = data.Arg4; this.Command = data.Command; this.Inner = data.Inner; }
public MobileResetData(ResetData data) { this.Arg1 = data.Arg1; this.Arg2 = data.Arg2; this.Arg3 = data.Arg3; this.Arg4 = data.Arg4; this.Command = data.Command; this.Inner = data.Inner; }
internal static ResetData ParseResetData(string areaFile, ref int lineNum, string firstLine, ResetData lastMob) { //if (log) //Logging.Log.Debug(String.Format("ParseResetData() called for area {0} starting on line {1}", areaFile, lineNum)); // Instantiate variables for the method ResetData outReset = new ResetData(); string lineData = firstLine; // Regex to parse reset lines Regex lineRegex = new Regex(@"^(\w){1}\s+(\d+)\s+(\d+)\s+(-*\d+)\s*(\d+)*\s*(\d+)*(\s*\*(.*))*\s*$"); // Attempt to parse the line Match match = lineRegex.Match(lineData); // Ensure we have at least one match so we can check the command if (match.Success) { string value = match.Groups[1].ToString(); outReset.Arg1 = Convert.ToInt32(match.Groups[3].ToString()); outReset.Arg2 = Convert.ToInt32(match.Groups[4].ToString()); outReset.Arg3 = (value.Equals("G") || value.Equals("R")) ? 0 : Convert.ToInt32(match.Groups[5].ToString()); outReset.Arg4 = (value.Equals("P") || value.Equals("M")) ? 0 : (match.Groups[6].Success) ? Convert.ToInt32(match.Groups[6].ToString()) : 0; switch (value) { case "M": // Mob reset outReset.Command = ResetCommand.SpawnMobile; // Validate the mob and room VNUMs if (!Program.World.Mobs.Exists(m => m.VNUM == outReset.Arg1)) { Logging.Log.Error(String.Format("Encountered unknown mobile VNUM {0} in reset data on line {1} of area {2}", outReset.Arg1, lineNum, areaFile)); return(null); } else if (!Program.World.Rooms.Exists(r => r.VNUM == outReset.Arg3)) { Logging.Log.Error(String.Format("Encountered unknown room VNUM {0} in reset data on line {1} of area {2}", outReset.Arg3, lineNum, areaFile)); return(null); } else { Logging.Log.Debug(String.Format("Loaded mobile reset for mobile {0} in room {1} with maximum occupancy {2} for area {3}", outReset.Arg1, outReset.Arg3, outReset.Arg2, areaFile)); // Return the reset return(outReset); } case "E": // Equip reset outReset.Command = ResetCommand.EquipObjectOnMob; // Ensure we have a mob if (lastMob == null || lastMob.Command != ResetCommand.SpawnMobile) { Logging.Log.Error(String.Format("Encountered equip reset command in an invalid location, no previous mob to apply to - line {0} of area {1}", lineNum, areaFile)); return(null); } // Validate the object VNUM if (!Program.World.Objects.Exists(o => o.VNUM == outReset.Arg1)) { Logging.Log.Error(String.Format("Encountered unknown object VNUM {0} in equip reset data on line {1} of area {2}", outReset.Arg1, lineNum, areaFile)); return(null); } // Validate the wear location else if (!Enum.TryParse <Enums.WearFlag>(outReset.Arg3.ToString(), out _)) { Logging.Log.Error(String.Format("Encountered invalid wear location {0} in equip reset data on line {1} of area {2}", outReset.Arg3, lineNum, areaFile)); return(null); } // Reset Arg2 based on the old limit rules if (outReset.Arg2 > 50) { outReset.Arg2 = 6; } else if (outReset.Arg2 == -1) { outReset.Arg2 = 999; } Logging.Log.Debug(String.Format("Loaded equip reset for mobile {0} with item {1} in wear location {2} with limit of {3} on line {4} of area {5}", outReset.Arg4, outReset.Arg1, outReset.Arg3, outReset.Arg2, lineNum, areaFile)); return(outReset); case "G": // Give reset outReset.Command = ResetCommand.GiveObjectToMob; // Ensure we have a mob if (lastMob == null || lastMob.Command != ResetCommand.SpawnMobile) { Logging.Log.Error(String.Format("Encountered give reset command in an invalid location, no previous mob to apply to - line {0} of area {1}", lineNum, areaFile)); return(null); } // Validate the object VNUM if (!Program.World.Objects.Exists(o => o.VNUM == outReset.Arg1)) { Logging.Log.Error(String.Format("Encountered unknown object VNUM {0} in equip reset data on line {1} of area {2}", outReset.Arg1, lineNum, areaFile)); return(null); } // Reset Arg2 based on the old limit rules if (outReset.Arg2 > 50) { outReset.Arg2 = 6; } else if (outReset.Arg2 == -1) { outReset.Arg2 = 999; } Logging.Log.Debug(String.Format("Loaded give reset for mobile {0} with item {1} with limit of {2} on line {3} of area {4}", outReset.Arg4, outReset.Arg1, outReset.Arg2, lineNum, areaFile)); return(outReset); case "O": // Object reset return(null); case "P": // Put reset return(null); case "R": // Randomize reset return(null); case "D": // Door reset return(null); default: Logging.Log.Warn(String.Format("Encountered unknown reset type {0} on line {1} in file {2}", value, lineNum, areaFile)); return(null); } } else { Logging.Log.Warn(String.Format("Encountered invalid reset data ({0}) on line {1} of file {2}", lineData, lineNum, areaFile)); return(null); } }
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); //} }