diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index d0fda96..d47a359 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -182,6 +182,7 @@ + diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 081e918..77f8919 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -22,6 +22,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Threading; using System.Windows.Forms; using CodeImp.DoomBuilder.Config; @@ -32,6 +33,7 @@ using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.SRB2; using CodeImp.DoomBuilder.Windows; using CodeImp.DoomBuilder.ZDoom; using SlimDX; @@ -2092,43 +2094,81 @@ namespace CodeImp.DoomBuilder.Data //mxd. This loads (Z)MAPINFO private void LoadMapInfo(out Dictionary spawnnums, out Dictionary doomednums) { - MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation }; - - // Parse mapinfo - foreach (DataReader dr in containers) + if (General.Map.SRB2) { - currentreader = dr; + SOCParser parser = new SOCParser { OnInclude = ParseFromLocation }; - Dictionary streams = dr.GetMapinfoData(); - foreach (KeyValuePair group in streams) + // Parse mapinfo + foreach (DataReader dr in containers) { - // Parse the data - parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false); + currentreader = dr; - //MAPINFO lumps are interdependable. Can't carry on... - if (parser.HasError) + Dictionary streams1 = dr.GetObjctcfgData(); + Dictionary streams2 = dr.GetMaincfgData(); + Dictionary streams3 = dr.GetSOCData(); + Dictionary streams = streams1.Concat(streams2).Concat(streams3).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + + foreach (KeyValuePair group in streams) { - parser.LogError(); - break; + // Parse the data + parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false); + + //MAPINFO lumps are interdependable. Can't carry on... + if (parser.HasError) + { + parser.LogError(); + break; + } } } - } - if (!parser.HasError) - { - // Store parsed data - spawnnums = parser.SpawnNums; - doomednums = parser.DoomEdNums; - mapinfo = parser.MapInfo; + if (!parser.HasError) + mapinfo = parser.MapInfo; + else + mapinfo = new MapInfo(); + + spawnnums = new Dictionary(); + doomednums = new Dictionary(); } else { - // No nulls allowed! - spawnnums = new Dictionary(); - doomednums = new Dictionary(); - mapinfo = new MapInfo(); - } + MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation }; + // Parse mapinfo + foreach (DataReader dr in containers) + { + currentreader = dr; + + Dictionary streams = dr.GetMapinfoData(); + foreach (KeyValuePair group in streams) + { + // Parse the data + parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false); + + //MAPINFO lumps are interdependable. Can't carry on... + if (parser.HasError) + { + parser.LogError(); + break; + } + } + } + + if (!parser.HasError) + { + // Store parsed data + spawnnums = parser.SpawnNums; + doomednums = parser.DoomEdNums; + mapinfo = parser.MapInfo; + } + else + { + // No nulls allowed! + spawnnums = new Dictionary(); + doomednums = new Dictionary(); + mapinfo = new MapInfo(); + } + } currentreader = null; } diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs index 98b97cc..7194598 100644 --- a/Source/Core/Data/DataReader.cs +++ b/Source/Core/Data/DataReader.cs @@ -161,8 +161,17 @@ namespace CodeImp.DoomBuilder.Data //mxd. When implemented, this returns the MAPINFO lump public abstract Dictionary GetMapinfoData(); // { return new Dictionary(); } - //mxd. When implemented, this returns the GLDEFS lump - public abstract Dictionary GetGldefsData(GameType gametype); // { return new Dictionary(); } + //mxd. When implemented, this returns the MAINCFG lump + public virtual Dictionary GetMaincfgData() { return new Dictionary(); } + + //mxd. When implemented, this returns the OBJCTCFG lump + public virtual Dictionary GetObjctcfgData() { return new Dictionary(); } + + //mxd. When implemented, this returns the SOC_ lumps + public virtual Dictionary GetSOCData() { return new Dictionary(); } + + //mxd. When implemented, this returns the GLDEFS lump + public abstract Dictionary GetGldefsData(GameType gametype); // { return new Dictionary(); } //mxd. When implemented, this returns the REVERBS lump public abstract Dictionary GetReverbsData(); // { return new Dictionary(); } diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs index ef1382f..434d01c 100644 --- a/Source/Core/Data/WADReader.cs +++ b/Source/Core/Data/WADReader.cs @@ -835,8 +835,53 @@ namespace CodeImp.DoomBuilder.Data return streams; } - //mxd - public override Dictionary GetGldefsData(GameType gameType) + public override Dictionary GetMaincfgData() + { + if (issuspended) throw new Exception("Data reader is suspended"); + + Dictionary streams = new Dictionary(StringComparer.Ordinal); + string src = "MAINCFG"; + + //should be only one entry per wad + int lumpindex = file.FindLumpIndex(src); + + if (lumpindex != -1) streams.Add(src, file.Lumps[lumpindex].Stream); + return streams; + } + + public override Dictionary GetObjctcfgData() + { + if (issuspended) throw new Exception("Data reader is suspended"); + + Dictionary streams = new Dictionary(StringComparer.Ordinal); + string src = "OBJCTCFG"; + + //should be only one entry per wad + int lumpindex = file.FindLumpIndex(src); + + if (lumpindex != -1) streams.Add(src, file.Lumps[lumpindex].Stream); + return streams; + } + + public override Dictionary GetSOCData() + { + if (issuspended) throw new Exception("Data reader is suspended"); + + Dictionary streams = new Dictionary(StringComparer.Ordinal); + string prefix = "SOC_"; + + foreach (Lump lump in file.Lumps) + { + if (lump.Name.StartsWith(prefix)) + { + streams.Add(lump.Name, lump.Stream); + } + } + return streams; + } + + //mxd + public override Dictionary GetGldefsData(GameType gameType) { if(issuspended) throw new Exception("Data reader is suspended"); diff --git a/Source/Core/SRB2/SOCParser.cs b/Source/Core/SRB2/SOCParser.cs new file mode 100644 index 0000000..2a597b8 --- /dev/null +++ b/Source/Core/SRB2/SOCParser.cs @@ -0,0 +1,190 @@ +#region ================== Namespaces + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using CodeImp.DoomBuilder.ZDoom; +using CodeImp.DoomBuilder.GZBuilder.Data; + +#endregion + +namespace CodeImp.DoomBuilder.SRB2 +{ + internal sealed class SOCParser : ZDTextParser + { + #region ================== Delegates + + public delegate void IncludeDelegate(SOCParser parser, string includefile, bool clearerror); + public IncludeDelegate OnInclude; + + #endregion + + #region ================== Variables + + private MapInfo mapinfo; + private string mapname; + private readonly HashSet parsedlumps; + private StreamReader streamreader; + + #endregion + + #region ================== Properties + + public MapInfo MapInfo { get { return mapinfo; } } + + #endregion + + #region ================== Constructor + + public SOCParser() + { + // Syntax + whitespace = "\n \t\r\u00A0"; + specialtokens = "=\n"; + + mapinfo = new MapInfo(); + parsedlumps = new HashSet(StringComparer.OrdinalIgnoreCase); + } + + #endregion + + #region ================== Parsing + + override public bool Parse(Stream stream, string sourcefilename, bool clearerrors) + { + if (string.IsNullOrEmpty(mapname)) throw new NotSupportedException("Map name required!"); + return Parse(stream, sourcefilename, mapname, clearerrors); + } + + public bool Parse(Stream stream, string sourcefilename, string mapname, bool clearerrors) + { + this.mapname = mapname.ToUpperInvariant(); + if (!base.Parse(stream, sourcefilename, clearerrors)) return false; + + // Keep local data + streamreader = new StreamReader(stream, Encoding.ASCII); + + while (!streamreader.EndOfStream) + { + string line = streamreader.ReadLine(); + if (String.IsNullOrEmpty(line) || line.StartsWith("\n") || line.StartsWith("#")) continue; + string[] tokens = line.Split(new char[] { ' ' }); + switch (tokens[0].ToUpperInvariant()) + { + case "LEVEL": + if (tokens.Length < 2 || String.IsNullOrEmpty(tokens[1])) + { + ReportError("Level block is missing a level number."); + break; + } + if (GetMapName(tokens[1].ToUpperInvariant()) != mapname) break; + if (!ParseLevelHeader(mapname)) return false; + break; + } + } + + // All done + return !this.HasError; + } + + #endregion + + #region ================== Map block parsing + + private bool ParseLevelHeader(string mapname) + { + if (mapname == null) return false; + string levelname = ""; + int act = 0; + bool zone = true; + while (!streamreader.EndOfStream) + { + string line = streamreader.ReadLine(); + if (String.IsNullOrEmpty(line) || line.StartsWith("\n")) break; + if (line.StartsWith("#")) continue; + string[] tokens = line.Split(new char[] { '=' }); + if (tokens.Length != 2) + { + ReportError("Invalid line."); + return false; + } + tokens[0] = tokens[0].Trim().ToUpperInvariant(); + tokens[1] = tokens[1].Trim().ToUpperInvariant(); + switch(tokens[0]) + { + case "LEVELNAME": + levelname = tokens[1]; + break; + + case "ACT": + if (!int.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out act) || act < 0 || act >= 20) + { + ReportError("Invalid act number."); + return false; + } + break; + + case "NOZONE": + zone = tokens[1][0] == 'T' || tokens[1][0] == 'Y'; + break; + + case "SKYNUM": + int skyn; + if (!int.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out skyn)) + { + ReportError("Invalid sky number."); + return false; + } + mapinfo.Sky1 = "SKY" + skyn; + break; + } + } + mapinfo.Title = levelname + (zone ? " ZONE" : "") + (act > 0 ? " " + act : ""); + + return true; + } + + private static string GetMapName(string number) + { + int n; + if (int.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) + return ConvertToExtendedMapNum(n); + else + { + if (number.Length != 2 || number[0] < 'A' || number[0] > 'Z' || number[1] < '0' || number[1] > '9') return null; + return "MAP" + number; + } + + } + + private static string ConvertToExtendedMapNum(int n) + { + if (n <= 0 || n > 1035) + return null; + if (n < 10) + return "MAP0" + n; + if (n < 100) + return "MAP" + n.ToString(); + + int x = n - 100; + int p = x / 36; + int q = x % 36; + char a = (char)('A' + p); + char b = (q < 10) ? (char)('0' + q) : (char)('A' + q - 10); + return "MAP" + String.Concat(a, b); + } + + #endregion + + #region ================== Methods + + protected override string GetLanguageType() + { + return "SOC"; + } + + #endregion + } +}