diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..765b22f6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*.cs] +indent_style = tab \ No newline at end of file diff --git a/Build/Compilers/BCC/bcc.cfg b/Build/Compilers/BCC/bcc.cfg index ccac4682..5d1d733b 100755 --- a/Build/Compilers/BCC/bcc.cfg +++ b/Build/Compilers/BCC/bcc.cfg @@ -7,7 +7,7 @@ compilers // All others are the required files (the setting names do not matter) bcc { - interface = "AccCompiler"; + interface = "BccCompiler"; program = "bcc.exe"; zcommon = "zcommon.bcs"; std = "std.acs"; diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg index b8ea86e0..bb6165f1 100755 --- a/Build/Configurations/Includes/ZDoom_misc.cfg +++ b/Build/Configurations/Includes/ZDoom_misc.cfg @@ -648,6 +648,138 @@ universalfields default = 0.0; managed = false; } + + nogradient_top + { + type = 3; + default = false; + managed = false; + } + + flipgradient_top + { + type = 3; + default = false; + managed = false; + } + + clampgradient_top + { + type = 3; + default = false; + managed = false; + + } + + useowncolors_top + { + type = 3; + default = false; + managed = false; + + } + + uppercolor_top + { + type = 10; + default = 16777215; + managed = false; + } + + lowercolor_top + { + type = 10; + default = 16777215; + managed = false; + } + + nogradient_mid + { + type = 3; + default = false; + managed = false; + } + + flipgradient_mid + { + type = 3; + default = false; + managed = false; + } + + clampgradient_mid + { + type = 3; + default = false; + managed = false; + + } + + useowncolors_mid + { + type = 3; + default = false; + managed = false; + + } + + uppercolor_mid + { + type = 10; + default = 16777215; + managed = false; + } + + lowercolor_mid + { + type = 10; + default = 16777215; + managed = false; + } + + nogradient_bottom + { + type = 3; + default = false; + managed = false; + } + + flipgradient_bottom + { + type = 3; + default = false; + managed = false; + } + + clampgradient_bottom + { + type = 3; + default = false; + managed = false; + + } + + useowncolors_bottom + { + type = 3; + default = false; + managed = false; + + } + + uppercolor_bottom + { + type = 10; + default = 16777215; + managed = false; + } + + lowercolor_bottom + { + type = 10; + default = 16777215; + managed = false; + } } thing diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 1b0796d8..31415763 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -141,6 +141,7 @@ --> + diff --git a/Source/Core/BuilderMono.csproj b/Source/Core/BuilderMono.csproj index 3c32dbca..de92d607 100644 --- a/Source/Core/BuilderMono.csproj +++ b/Source/Core/BuilderMono.csproj @@ -138,6 +138,7 @@ --> + diff --git a/Source/Core/Compilers/AccCompiler.cs b/Source/Core/Compilers/AccCompiler.cs index 867d1a47..4230babf 100755 --- a/Source/Core/Compilers/AccCompiler.cs +++ b/Source/Core/Compilers/AccCompiler.cs @@ -30,18 +30,24 @@ using CodeImp.DoomBuilder.ZDoom.Scripting; namespace CodeImp.DoomBuilder.Compilers { - internal sealed class AccCompiler : Compiler + internal class AccCompiler : Compiler { - #region ================== Constants - - private const string ACS_ERROR_FILE = "acs.err"; - + #region ================== Internal classes + + protected class CompileContext { } + #endregion - + + #region ================== Constants + + private const string ACS_ERROR_FILE = "acs.err"; + + #endregion + #region ================== Variables private AcsParserSE parser; //mxd - + #endregion #region ================== Properties @@ -52,7 +58,7 @@ namespace CodeImp.DoomBuilder.Compilers #endregion #region ================== Constructor - + // Constructor public AccCompiler(CompilerInfo info) : base(info, false) { @@ -62,7 +68,7 @@ namespace CodeImp.DoomBuilder.Compilers public override void Dispose() { // Not already disposed? - if(!isdisposed) + if (!isdisposed) { // Clean up @@ -70,26 +76,116 @@ namespace CodeImp.DoomBuilder.Compilers base.Dispose(); } } - + #endregion - + #region ================== Methods - + + protected virtual CompileContext OnBeforeProcessStart(ProcessStartInfo info) + { + return new CompileContext(); + } + + protected virtual void OnCheckError(HashSet includes, ProcessStartInfo processinfo, Process process, CompileContext context) + { + int line = 0; + + // Now find the error file + string errfile = Path.Combine(this.workingdir, ACS_ERROR_FILE); + if (File.Exists(errfile)) + { + try + { + // Regex to find error lines + Regex errlinematcher = new Regex(":[0-9]+: ", RegexOptions.Compiled | RegexOptions.CultureInvariant); + + // Read all lines + bool erroradded = false; //mxd + string[] errlines = File.ReadAllLines(errfile); + string temppath = this.tempdir.FullName + Path.DirectorySeparatorChar.ToString(); //mxd. Need trailing slash.. + while (line < errlines.Length) + { + // Check line + string linestr = errlines[line]; + Match match = errlinematcher.Match(linestr); + if (match.Success && (match.Index > 0)) + { + CompilerError err = new CompilerError(); + + // The match without spaces and semicolon is the line number + string linenr = match.Value.Replace(":", "").Trim(); + if (!int.TryParse(linenr, out err.linenumber)) + err.linenumber = CompilerError.NO_LINE_NUMBER; + else + err.linenumber--; + + // Everything before the match is the filename + err.filename = linestr.Substring(0, match.Index).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + + //mxd. Get rid of temp directory path + if (err.filename.StartsWith(temppath)) err.filename = err.filename.Replace(temppath, string.Empty); + + if (!Path.IsPathRooted(err.filename)) + { + //mxd. If the error is in an include file, try to find it in loaded resources + if (includes.Contains(err.filename)) + { + foreach (DataReader dr in General.Map.Data.Containers) + { + if (dr is DirectoryReader && dr.FileExists(err.filename)) + { + err.filename = Path.Combine(dr.Location.location, err.filename); + break; + } + } + } + else + { + // Add working directory to filename, so it could be recognized as map namespace lump in MapManager.CompileLump() + err.filename = Path.Combine(processinfo.WorkingDirectory, err.filename); + } + } + + // Everything after the match is the description + err.description = linestr.Substring(match.Index + match.Length).Trim(); + + // Report the error + ReportError(err); + erroradded = true; //mxd + } + + // Next line + line++; + } + + //mxd. Some ACC errors are not properly formatted. If that's the case, threat the whole acs.err as an error... + if (!erroradded && errlines.Length > 0) + { + ReportError(new CompilerError(string.Join(Environment.NewLine, errlines))); + } + } + catch (Exception e) + { + // Error reading errors (ironic, isn't it) + ReportError(new CompilerError("Failed to retrieve compiler error report. " + e.GetType().Name + ": " + e.Message)); + } + } + } + // This runs the compiler public override bool Run() { Process process; - int line = 0; string sourcedir = Path.GetDirectoryName(sourcefile); // Preprocess the file parser = new AcsParserSE { IsMapScriptsLump = SourceIsMapScriptsLump, - OnInclude = delegate(AcsParserSE se, string includefile, AcsParserSE.IncludeType includetype) + OnInclude = delegate (AcsParserSE se, string includefile, AcsParserSE.IncludeType includetype) { TextResourceData data = General.Map.Data.GetTextResourceData(includefile); - if(data == null) + if (data == null) { se.ReportError("Unable to find include file \"" + includefile + "\"."); return false; // Fial @@ -100,31 +196,31 @@ namespace CodeImp.DoomBuilder.Compilers }; string inputfilepath = Path.Combine(this.tempdir.FullName, inputfile); - using(FileStream stream = File.OpenRead(inputfilepath)) + using (FileStream stream = File.OpenRead(inputfilepath)) { // Map SCRIPTS lump is empty. Abort the process without generating any warnings or errors. - if(SourceIsMapScriptsLump && stream.Length == 0) return false; + if (SourceIsMapScriptsLump && stream.Length == 0) return false; DataLocation dl = new DataLocation(DataLocation.RESOURCE_DIRECTORY, Path.GetDirectoryName(inputfilepath), false, false, false, null); //mxd. TextResourceData must point to temp path when compiling WAD lumps for lump to be recognized as map lump when reporting errors... TextResourceData data = new TextResourceData(stream, dl, (SourceIsMapScriptsLump ? inputfile : sourcefile)); - if(!parser.Parse(data, info.Files, true, AcsParserSE.IncludeType.NONE, false)) + if (!parser.Parse(data, info.Files, true, AcsParserSE.IncludeType.NONE, false)) { // Check for errors - if(parser.HasError) ReportError(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine)); + if (parser.HasError) ReportError(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine)); return true; } } //mxd. External lumps should be libraries - if(!SourceIsMapScriptsLump && !parser.IsLibrary) + if (!SourceIsMapScriptsLump && !parser.IsLibrary) { ReportError(new CompilerError("External ACS files can only be compiled as libraries.", sourcefile)); return true; } //mxd. Update script names if we are compiling the map SCRIPTS lump - if(SourceIsMapScriptsLump) + if (SourceIsMapScriptsLump) { General.Map.UpdateScriptNames(parser); } @@ -132,22 +228,22 @@ namespace CodeImp.DoomBuilder.Compilers //xabis // Copy includes from the resources into the compiler's folder, preserving relative pathing and naming HashSet includes = parser.GetIncludes(); //mxd - foreach(string include in includes) + foreach (string include in includes) { // Grab the script text from the resources TextResourceData data = General.Map.Data.GetTextResourceData(include); - if(data != null && data.Stream != null) + if (data != null && data.Stream != null) { // Pull the pk3 or directory sub folder out if applicable FileInfo fi = new FileInfo(Path.Combine(this.tempdir.FullName, include)); // Do not allow files to be overwritten, either accidentally or maliciously - if(!fi.Exists) + if (!fi.Exists) { General.WriteLogLine("Copying script include: " + include); // Create the directory path as needed - if(!string.IsNullOrEmpty(fi.DirectoryName)) Directory.CreateDirectory(fi.DirectoryName); + if (!string.IsNullOrEmpty(fi.DirectoryName)) Directory.CreateDirectory(fi.DirectoryName); // Dump the script into the target file BinaryReader reader = new BinaryReader(data.Stream); @@ -164,7 +260,7 @@ namespace CodeImp.DoomBuilder.Compilers args = args.Replace("%PT", this.tempdir.FullName); args = args.Replace("%PS", sourcedir); args = args.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); //mxd. This fixes include path when the map is in a root directory - + // Setup process info ProcessStartInfo processinfo = new ProcessStartInfo(); processinfo.Arguments = args; @@ -174,114 +270,37 @@ namespace CodeImp.DoomBuilder.Compilers processinfo.UseShellExecute = true; processinfo.WindowStyle = ProcessWindowStyle.Hidden; processinfo.WorkingDirectory = this.workingdir; - + + CompileContext context = OnBeforeProcessStart(processinfo); + // Output info General.WriteLogLine("Running compiler..."); General.WriteLogLine("Program: " + processinfo.FileName); General.WriteLogLine("Arguments: " + processinfo.Arguments); - + try { // Start the compiler process = Process.Start(processinfo); } - catch(Exception e) + catch (Exception e) { // Unable to start the compiler General.ShowErrorMessage("Unable to start the compiler (" + info.Name + "). " + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } - + // Wait for compiler to complete process.WaitForExit(); TimeSpan deltatime = TimeSpan.FromTicks(process.ExitTime.Ticks - process.StartTime.Ticks); General.WriteLogLine("Compiler process has finished."); General.WriteLogLine("Compile time: " + deltatime.TotalSeconds.ToString("########0.00") + " seconds"); - - // Now find the error file - string errfile = Path.Combine(this.workingdir, ACS_ERROR_FILE); - if(File.Exists(errfile)) - { - try - { - // Regex to find error lines - Regex errlinematcher = new Regex(":[0-9]+: ", RegexOptions.Compiled | RegexOptions.CultureInvariant); - - // Read all lines - bool erroradded = false; //mxd - string[] errlines = File.ReadAllLines(errfile); - string temppath = this.tempdir.FullName + Path.DirectorySeparatorChar.ToString(); //mxd. Need trailing slash.. - while(line < errlines.Length) - { - // Check line - string linestr = errlines[line]; - Match match = errlinematcher.Match(linestr); - if(match.Success && (match.Index > 0)) - { - CompilerError err = new CompilerError(); - - // The match without spaces and semicolon is the line number - string linenr = match.Value.Replace(":", "").Trim(); - if(!int.TryParse(linenr, out err.linenumber)) - err.linenumber = CompilerError.NO_LINE_NUMBER; - else - err.linenumber--; - - // Everything before the match is the filename - err.filename = linestr.Substring(0, match.Index).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - //mxd. Get rid of temp directory path - if(err.filename.StartsWith(temppath)) err.filename = err.filename.Replace(temppath, string.Empty); - - if(!Path.IsPathRooted(err.filename)) - { - //mxd. If the error is in an include file, try to find it in loaded resources - if(includes.Contains(err.filename)) - { - foreach(DataReader dr in General.Map.Data.Containers) - { - if(dr is DirectoryReader && dr.FileExists(err.filename)) - { - err.filename = Path.Combine(dr.Location.location, err.filename); - break; - } - } - } - else - { - // Add working directory to filename, so it could be recognized as map namespace lump in MapManager.CompileLump() - err.filename = Path.Combine(processinfo.WorkingDirectory, err.filename); - } - } - - // Everything after the match is the description - err.description = linestr.Substring(match.Index + match.Length).Trim(); - - // Report the error - ReportError(err); - erroradded = true; //mxd - } - - // Next line - line++; - } + OnCheckError(includes, processinfo, process, context); - //mxd. Some ACC errors are not properly formatted. If that's the case, threat the whole acs.err as an error... - if(!erroradded && errlines.Length > 0) - { - ReportError(new CompilerError(string.Join(Environment.NewLine, errlines))); - } - } - catch(Exception e) - { - // Error reading errors (ironic, isn't it) - ReportError(new CompilerError("Failed to retrieve compiler error report. " + e.GetType().Name + ": " + e.Message)); - } - } - return true; } - + #endregion } } \ No newline at end of file diff --git a/Source/Core/Compilers/BccCompiler.cs b/Source/Core/Compilers/BccCompiler.cs new file mode 100644 index 00000000..3a5a2f70 --- /dev/null +++ b/Source/Core/Compilers/BccCompiler.cs @@ -0,0 +1,83 @@ +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace CodeImp.DoomBuilder.Compilers +{ + internal class BccCompiler : AccCompiler + { + public BccCompiler(CompilerInfo info) : base(info) { } + + protected override CompileContext OnBeforeProcessStart(ProcessStartInfo info) + { + info.UseShellExecute = false; + info.CreateNoWindow = true; + info.RedirectStandardError = true; + info.RedirectStandardOutput = true; + return new CompileContext(); + } + + protected override void OnCheckError(HashSet includes, ProcessStartInfo processinfo, Process process, CompileContext context) + { + if (process.ExitCode != 0) + { + bool foundAnyErrors = false; + string[] errorLines = process.StandardOutput.ReadToEnd().Split('\n'); + + foreach (string rawErrorLine in errorLines) + { + string[] rawError = rawErrorLine.Split(new char[] { ':' }, 4); + if (rawError.Length != 4) + continue; + string errorFile = rawError[0]; + int errorLine; + if (!int.TryParse(rawError[1], out errorLine)) + continue; + errorLine--; + // rawError[2] is ignored. in BCC, this contains the column at which the error happened. not supported in error viewer. + string errorContent = rawError[3].Trim(); + + // logic copied from AccCompiler + string temppath = this.tempdir.FullName + Path.DirectorySeparatorChar.ToString(); //mxd. Need trailing slash.. + if (errorFile.StartsWith(temppath)) errorFile = errorFile.Replace(temppath, string.Empty); + + if (!Path.IsPathRooted(errorFile)) + { + //mxd. If the error is in an include file, try to find it in loaded resources + if (includes.Contains(errorFile)) + { + foreach (DataReader dr in General.Map.Data.Containers) + { + if (dr is DirectoryReader && dr.FileExists(errorFile)) + { + errorFile = Path.Combine(dr.Location.location, errorFile); + break; + } + } + } + else + { + // Add working directory to filename, so it could be recognized as map namespace lump in MapManager.CompileLump() + errorFile = Path.Combine(processinfo.WorkingDirectory, errorFile); + } + } + // end logic copied from AccCompiler + + CompilerError err = new CompilerError(); + err.linenumber = errorLine; + err.filename = errorFile; + err.description = errorContent; + + ReportError(err); + foundAnyErrors = true; + } + + if (!foundAnyErrors) + ReportError(new CompilerError(string.Join(Environment.NewLine, errorLines))); + } + } + } +} diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs index 4017cb4c..e492ea4a 100755 --- a/Source/Core/Config/ThingTypeInfo.cs +++ b/Source/Core/Config/ThingTypeInfo.cs @@ -640,23 +640,30 @@ namespace CodeImp.DoomBuilder.Config if (renderradius == 0) renderradius = radius; - //mxd. DistanceCheck. The value is CVAR. Also we'll need squared value - if(actor.HasPropertyWithValue("distancecheck")) + // DistanceCheck. The value is CVAR. Also we'll need squared value + if (actor.HasPropertyWithValue("distancecheck")) { string cvarname = actor.GetPropertyValueString("distancecheck", 0); - if(!General.Map.Data.CVars.Integers.ContainsKey(cvarname)) + if (General.Map.Data.CVars.AllNames.Contains(cvarname)) { - General.ErrorLogger.Add(ErrorType.Error, "Error in actor \"" + title + "\":" + index + ". DistanceCheck property references undefined cvar \"" + cvarname + "\""); - distancechecksq = double.MaxValue; + if (!General.Map.Data.CVars.Integers.ContainsKey(cvarname)) + { + General.ErrorLogger.Add(ErrorType.Error, "Error in actor \"" + title + "\":" + index + ". DistanceCheck property references cvar \"" + cvarname + "\" which has to be of type int, but is not"); + distancechecksq = double.MaxValue; + } + else + { + distancechecksq = Math.Pow(General.Map.Data.CVars.Integers[cvarname], 2); + } } else { - distancechecksq = Math.Pow(General.Map.Data.CVars.Integers[cvarname], 2); + General.ErrorLogger.Add(ErrorType.Error, "Error in actor \"" + title + "\":" + index + ". DistanceCheck property references undefined cvar \"" + cvarname + "\""); } } //mxd. Renderstyle - if(actor.HasPropertyWithValue("renderstyle") && !actor.HasProperty("$ignorerenderstyle")) + if (actor.HasPropertyWithValue("renderstyle") && !actor.HasProperty("$ignorerenderstyle")) renderstyle = actor.GetPropertyValueString("renderstyle", 0, true).ToLower(); //mxd. Alpha diff --git a/Source/Core/Controls/PairedFieldsControl.cs b/Source/Core/Controls/PairedFieldsControl.cs index 723bdb53..15e967be 100755 --- a/Source/Core/Controls/PairedFieldsControl.cs +++ b/Source/Core/Controls/PairedFieldsControl.cs @@ -69,8 +69,8 @@ namespace CodeImp.DoomBuilder.Controls if(AllowDecimal) { - newValue1 = Math.Round(UniFields.GetFloat(fields, field1, defaultValue), 2).ToString(); - newValue2 = Math.Round(UniFields.GetFloat(fields, field2, defaultValue), 2).ToString(); + newValue1 = UniFields.GetFloat(fields, field1, defaultValue).ToString(); + newValue2 = UniFields.GetFloat(fields, field2, defaultValue).ToString(); } else { diff --git a/Source/Core/Data/CvarsCollection.cs b/Source/Core/Data/CvarsCollection.cs index 5b236f19..655f92dd 100755 --- a/Source/Core/Data/CvarsCollection.cs +++ b/Source/Core/Data/CvarsCollection.cs @@ -17,7 +17,7 @@ namespace CodeImp.DoomBuilder.Data internal readonly Dictionary Colors; internal readonly Dictionary Booleans; internal readonly Dictionary Strings; - private readonly HashSet allnames; + internal readonly HashSet AllNames; #endregion @@ -30,7 +30,7 @@ namespace CodeImp.DoomBuilder.Data Colors = new Dictionary(StringComparer.OrdinalIgnoreCase); Booleans = new Dictionary(StringComparer.OrdinalIgnoreCase); Strings = new Dictionary(StringComparer.OrdinalIgnoreCase); - allnames = new HashSet(StringComparer.OrdinalIgnoreCase); + AllNames = new HashSet(StringComparer.OrdinalIgnoreCase); } #endregion @@ -39,40 +39,40 @@ namespace CodeImp.DoomBuilder.Data public bool AddValue(string name, int value) { - if(allnames.Contains(name)) return false; - allnames.Add(name); + if(AllNames.Contains(name)) return false; + AllNames.Add(name); Integers.Add(name, value); return true; } public bool AddValue(string name, float value) { - if(allnames.Contains(name)) return false; - allnames.Add(name); + if(AllNames.Contains(name)) return false; + AllNames.Add(name); Floats.Add(name, value); return true; } public bool AddValue(string name, PixelColor value) { - if(allnames.Contains(name)) return false; - allnames.Add(name); + if(AllNames.Contains(name)) return false; + AllNames.Add(name); Colors.Add(name, value); return true; } public bool AddValue(string name, bool value) { - if(allnames.Contains(name)) return false; - allnames.Add(name); + if(AllNames.Contains(name)) return false; + AllNames.Add(name); Booleans.Add(name, value); return true; } public bool AddValue(string name, string value) { - if(allnames.Contains(name)) return false; - allnames.Add(name); + if(AllNames.Contains(name)) return false; + AllNames.Add(name); Strings.Add(name, value); return true; } diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs index 636ea624..1fef165f 100755 --- a/Source/Core/General/General.cs +++ b/Source/Core/General/General.cs @@ -23,6 +23,7 @@ using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Security.AccessControl; @@ -293,6 +294,13 @@ namespace CodeImp.DoomBuilder #region ================== Configurations + /// + /// Checks if a given game configuration file exists. + /// + /// The file name of the game configuration file. + /// true if the game configuration exists, false if it doesn't + internal static bool ConfigurationInfoExist(string filename) => configs.Any(ci => string.Compare(Path.GetFileNameWithoutExtension(ci.Filename), Path.GetFileNameWithoutExtension(filename), true) == 0); + // This returns the game configuration info by filename internal static ConfigurationInfo GetConfigurationInfo(string filename) { diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index 47cc4ba6..37086126 100755 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -421,7 +421,16 @@ namespace CodeImp.DoomBuilder // Copy the map lumps to the temp file General.WriteLogLine("Copying map lumps to temporary file..."); - CopyLumpsByType(mapwad, options.CurrentName, tempwadreader.WadFile, TEMP_MAP_HEADER, true, true, true, true); + if (!CopyLumpsByType(mapwad, options.CurrentName, tempwadreader.WadFile, TEMP_MAP_HEADER, true, true, true, true)) + { + // Ooops, the map doesn't exit. This should only happend when run from the command line using the "-map" parameter + General.ErrorLogger.Add(ErrorType.Error, $"Map \"{options.CurrentName}\" does not exist in file \"{filepathname}\"."); + + // Close the map file + mapwad.Dispose(); + + return false; + } // Close the map file mapwad.Dispose(); @@ -1660,7 +1669,7 @@ namespace CodeImp.DoomBuilder } // This copies specific map lumps from one WAD to another - private void CopyLumpsByType(WAD source, string sourcemapname, + private bool CopyLumpsByType(WAD source, string sourcemapname, WAD target, string targetmapname, bool copyrequired, bool copyblindcopy, bool copynodebuild, bool copyscript, @@ -1734,7 +1743,11 @@ namespace CodeImp.DoomBuilder target.WriteHeaders(); //mxd target.Compress(); // [ZZ] + + return true; } + + return false; } // This finds a lump within the range of known lump names diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs index a528114d..c9ace672 100755 --- a/Source/Core/Map/Linedef.cs +++ b/Source/Core/Map/Linedef.cs @@ -620,7 +620,7 @@ namespace CodeImp.DoomBuilder.Map if(args[0] > General.Map.FormatInterface.MaxArgument) // Split sector tag? { int hitag = args[0] / 256; - int lotag = args[0] - hitag; + int lotag = args[0] % 256; args[0] = lotag; args[4] = hitag; @@ -652,7 +652,7 @@ namespace CodeImp.DoomBuilder.Map break; default: // Convert tag to Line_SetIdentification? - if(tags[0] > General.Map.FormatInterface.MinArgument) + if(tags[0] > General.Map.FormatInterface.MaxArgument) { if(action != 0) { @@ -662,7 +662,7 @@ namespace CodeImp.DoomBuilder.Map else // Convert to Line_SetIdentification { int hiid = tags[0] / 256; - int loid = tags[0] - hiid; + int loid = tags[0] % 256; action = 121; args[0] = loid; diff --git a/Source/Core/Rendering/SurfaceManager.cs b/Source/Core/Rendering/SurfaceManager.cs index 55853710..fd4f2333 100755 --- a/Source/Core/Rendering/SurfaceManager.cs +++ b/Source/Core/Rendering/SurfaceManager.cs @@ -617,7 +617,7 @@ namespace CodeImp.DoomBuilder.Rendering { if(!resourcesunloaded) { - ShaderName pass = Renderer.FullBrightness ? ShaderName.display2d_fullbright : ShaderName.display2d_normal; //mxd + ShaderName pass = (Renderer.FullBrightness && General.Map.Renderer2D.ViewMode != ViewMode.Brightness) ? ShaderName.display2d_fullbright : ShaderName.display2d_normal; //mxd foreach(KeyValuePair> imgsurfaces in surfaces) { graphics.SetShader(pass); diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs index d729383c..14e47c81 100755 --- a/Source/Core/Windows/MainForm.cs +++ b/Source/Core/Windows/MainForm.cs @@ -565,7 +565,7 @@ namespace CodeImp.DoomBuilder.Windows configfile = General.AutoLoadConfig; if (string.IsNullOrEmpty(configfile)) configfile = mapsettings.ReadSetting("gameconfig", ""); - if(configfile.Trim().Length == 0) + if(configfile.Trim().Length == 0 || !General.ConfigurationInfoExist(configfile)) { showdialog = true; } diff --git a/Source/Core/ZDoom/DecorateActorStructure.cs b/Source/Core/ZDoom/DecorateActorStructure.cs index e73b07d8..3954751a 100755 --- a/Source/Core/ZDoom/DecorateActorStructure.cs +++ b/Source/Core/ZDoom/DecorateActorStructure.cs @@ -14,11 +14,13 @@ namespace CodeImp.DoomBuilder.ZDoom { #region ================== DECORATE Actor Structure parsing + private DecorateParser parser; + internal DecorateActorStructure(ZDTextParser zdparser, DecorateCategoryInfo catinfo) { this.catinfo = catinfo; //mxd - DecorateParser parser = (DecorateParser)zdparser; + parser = (DecorateParser)zdparser; bool done = false; //mxd // First next token is the class name @@ -170,6 +172,10 @@ namespace CodeImp.DoomBuilder.ZDoom break; case "states": + // Skip cast type if there is one + if (!SkipCastTypes()) + return; + if (!parser.NextTokenIs("{", true)) return; @@ -456,6 +462,59 @@ namespace CodeImp.DoomBuilder.ZDoom } } - #endregion - } + /// + /// Skips state cast type, it one exists. + /// + /// true if there was nothing to skip or if skippen succeeded, false if it failed + private bool SkipCastTypes() + { + // Alloed casts, see https://zdoom.org/wiki/Converting_DECORATE_code_to_ZScript#Cast_types + string[] allowedcasts = { "actor", "overlay", "weapon", "item" }; + + // Skip cast types, which can be defined like this: + // States(Actor, Item) + // See https://github.com/UltimateDoomBuilder/UltimateDoomBuilder/issues/977 + if (parser.NextTokenIs("(", false)) + { + while (parser.SkipWhitespace(true)) + { + string token = parser.ReadToken().ToLowerInvariant(); + + if(!allowedcasts.Contains(token)) + { + parser.ReportError($"Unexpected cast type \"{token}\", expected one of: " + string.Join(", ", allowedcasts)); + return false; + } + + parser.SkipWhitespace(true); + + // Get next token + token = parser.ReadToken(); + + // End of cast type? + if(token == ")") + return true; + + // More cast types coming? + if (token == ",") + continue; + + // No comma or brace after a cast type, so report an error and return + parser.ReportError($"Expected \",\", or \")\", got {token}"); + return false; + } + } + else + { + // We get here if there was no cast type + return true; + } + + // We should never get here, since we'll return in the parsing loop, + // but we need to make the compiler happy + return false; + } + + #endregion + } } diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs index 919d5629..cd5bb819 100755 --- a/Source/Core/ZDoom/ZDTextParser.cs +++ b/Source/Core/ZDoom/ZDTextParser.cs @@ -549,6 +549,8 @@ namespace CodeImp.DoomBuilder.ZDoom return false; } + long prevstreamposition = DataStream.Position; + string token = ReadToken(); if(string.Compare(token, expectedtoken, true) != 0) @@ -556,7 +558,7 @@ namespace CodeImp.DoomBuilder.ZDoom if(reporterror) ReportError("Expected \"" + expectedtoken + "\", but got \"" + token + "\""); // Rewind so this structure can be read again - DataStream.Seek(-token.Length - 1, SeekOrigin.Current); + DataStream.Seek(prevstreamposition, SeekOrigin.Begin); return false; } diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs index 72e06db5..36cd0bd1 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs @@ -284,8 +284,8 @@ namespace CodeImp.DoomBuilder.BuilderModes offset.y %= texture.Height / s.Fields.GetValue((alignFloors ? "yscalefloor" : "yscaleceiling"), 1.0); } - UniFields.SetFloat(s.Fields, (alignFloors ? "xpanningfloor" : "xpanningceiling"), Math.Round(-offset.x), 0.0); - UniFields.SetFloat(s.Fields, (alignFloors ? "ypanningfloor" : "ypanningceiling"), Math.Round(offset.y), 0.0); + UniFields.SetFloat(s.Fields, (alignFloors ? "xpanningfloor" : "xpanningceiling"), Math.Round(-offset.x, 6), 0.0); + UniFields.SetFloat(s.Fields, (alignFloors ? "ypanningfloor" : "ypanningceiling"), Math.Round(offset.y, 6), 0.0); //update s.UpdateNeeded = true;