diff --git a/Build/Configurations/Includes/GZDoom_things.cfg b/Build/Configurations/Includes/GZDoom_things.cfg index 0f19902c..91e84b4d 100644 --- a/Build/Configurations/Includes/GZDoom_things.cfg +++ b/Build/Configurations/Includes/GZDoom_things.cfg @@ -19,18 +19,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Intensity"; + default = 64; } } 9801 @@ -39,22 +43,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Start intensity"; + default = 64; } arg4 { title = "End intensity"; + default = 32; } } 9802 @@ -63,22 +72,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Primary intensity"; + default = 64; } arg4 { title = "Secondary intensity"; + default = 32; } } 9803 @@ -87,18 +101,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Intensity scale"; + default = 4; } } 9804 @@ -107,22 +125,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Minimal intensity"; + default = 32; } arg4 { title = "Maximal intensity"; + default = 64; } } 9810 @@ -131,18 +154,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Intensity"; + default = 64; } } 9811 @@ -151,22 +178,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Start intensity"; + default = 32; } arg4 { title = "End intensity"; + default = 64; } } 9812 @@ -175,22 +207,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Primary intensity"; + default = 64; } arg4 { title = "Secondary intensity"; + default = 32; } } 9813 @@ -199,18 +236,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Intensity scale"; + default = 4; } } 9814 @@ -219,22 +260,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Minimal intensity"; + default = 32; } arg4 { title = "Maximal intensity"; + default = 64; } } 9820 @@ -243,18 +289,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Radius"; + default = 64; } } 9821 @@ -263,22 +313,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Start intensity"; + default = 32; } arg4 { title = "End intensity"; + default = 64; } } 9822 @@ -287,22 +342,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Primary intensity"; + default = 32; } arg4 { title = "Secondary intensity"; + default = 64; } } 9823 @@ -311,18 +371,22 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Intensity scale"; + default = 4; } } 9824 @@ -331,22 +395,27 @@ gzdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { title = "Minimal intensity"; + default = 32; } arg4 { title = "Maximal intensity"; + default = 64; } } 9825 = "Vavoom Light"; @@ -356,6 +425,7 @@ gzdoom arg0 { title = "Radius"; + default = 16; } } 1503 @@ -364,18 +434,22 @@ gzdoom arg0 { title = "Radius"; + default = 16; } arg1 { title = "Red"; + default = 255; } arg2 { title = "Green"; + default = 255; } arg3 { title = "Blue"; + default = 255; } } } diff --git a/Build/Configurations/Includes/ZDoom_common.cfg b/Build/Configurations/Includes/ZDoom_common.cfg index 0913a18e..d8cf825c 100644 --- a/Build/Configurations/Includes/ZDoom_common.cfg +++ b/Build/Configurations/Includes/ZDoom_common.cfg @@ -59,12 +59,6 @@ common include("Boom_misc.cfg", "colormaps"); } - // DEFAULT SECTOR BRIGHTNESS LEVELS - sectorbrightness - { - include("Doom_misc.cfg", "sectorbrightness"); - } - // Generalized sector types gen_sectortypes { @@ -112,6 +106,12 @@ mapformat_doom { include("Boom_generalized.cfg", "gen_linedeftypes"); } + + // DEFAULT SECTOR BRIGHTNESS LEVELS + sectorbrightness + { + include("Doom_misc.cfg", "sectorbrightness"); + } // SECTOR TYPES sectortypes @@ -204,6 +204,12 @@ mapformat_hexen // Generalized actions generalizedlinedefs = false; + + // DEFAULT SECTOR BRIGHTNESS LEVELS + sectorbrightness + { + include("ZDoom_misc.cfg", "sectorbrightness"); + } // SECTOR TYPES sectortypes @@ -318,6 +324,12 @@ mapformat_udmf // Generalized actions generalizedlinedefs = false; + + // DEFAULT SECTOR BRIGHTNESS LEVELS + sectorbrightness + { + include("ZDoom_misc.cfg", "sectorbrightness"); + } // SECTOR TYPES sectortypes diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg index 2ac84a59..b8bd01e3 100644 --- a/Build/Configurations/Includes/ZDoom_misc.cfg +++ b/Build/Configurations/Includes/ZDoom_misc.cfg @@ -206,6 +206,11 @@ universalfields add = "Additive"; } } + arg0str + { + type = 2; + default = ""; + } } sidedef @@ -343,6 +348,11 @@ universalfields type = 0; default = 0; } + arg0str + { + type = 2; + default = ""; + } } sector diff --git a/Build/Configurations/Includes/ZDoom_things.cfg b/Build/Configurations/Includes/ZDoom_things.cfg index b22de3da..2964435a 100644 --- a/Build/Configurations/Includes/ZDoom_things.cfg +++ b/Build/Configurations/Includes/ZDoom_things.cfg @@ -540,14 +540,17 @@ zdoom arg0 { title = "Red"; + default = 255; } arg1 { title = "Green"; + default = 255; } arg2 { title = "Blue"; + default = 255; } arg3 { @@ -560,14 +563,17 @@ zdoom arg0 { title = "Red"; + default = 128; } arg1 { title = "Green"; + default = 128; } arg2 { title = "Blue"; + default = 128; } } 9041 @@ -759,10 +765,12 @@ zdoom arg2 { title = "X Scale (64=100%)"; + default = 64; } arg3 { title = "Y Scale (64=100%) "; + default = 64; } arg4 { @@ -798,6 +806,7 @@ zdoom arg0 { title = "Flat Transparency"; + default = 128; } } @@ -807,6 +816,7 @@ zdoom arg0 { title = "Flat Transparency"; + default = 128; } } } diff --git a/Help/Contents.hhc b/Help/Contents.hhc index 5faf4dc9..c1e39dad 100644 --- a/Help/Contents.hhc +++ b/Help/Contents.hhc @@ -233,9 +233,13 @@
  • + +
  • + + +
  • diff --git a/Help/gz_acsex.html b/Help/gz_acsex.html new file mode 100644 index 00000000..f0ccc6cc --- /dev/null +++ b/Help/gz_acsex.html @@ -0,0 +1,39 @@ + + + + + GZDoom Builder features + + + + + + + + + + +

    Enhanced scripting workflow

    + +
    +

    GZDoom Builder includes several features to help you edit and assign scripts easier.

    +Script editor now has "Script names" drop down, which allows you to view and select individual scripts faster.
    +

    Pseudo-named scripts

    +If you add a comment after script opening brace like so:
    +script 1 (void)
    +{ //My Pseudo-named script
    +...
    +}
    +it will be used as script name in "Script names" drop down and in Thing and Linedef Edit windows drop downs (example script will be named as "[1] My Pseudo-named script").

    +Notice: "Script names" drop down items are updated when you compile script successfully. +

    +
    +
    +

    Thing and Linedef scripts can now be set much easier.

    +Notice: to remove named or regular script, clear script selector text box

    +
    +
    +

    If a Thing or Linedef has named script, it will be shown in info panel.

    +
    + + diff --git a/Help/gz_cfg_settings.html b/Help/gz_cfg_settings.html index c72bcd37..d5479d81 100644 --- a/Help/gz_cfg_settings.html +++ b/Help/gz_cfg_settings.html @@ -18,8 +18,18 @@
    -

    basegame - indicates on which game current configuration is based. Used to load game-specific GLDEFS lumps (DOOMDEFS, HTICDEFS, HEXNDEFS or STRFDEFS)
    + +

    General settings:


    basegame - indicates on which game current configuration is based. Used to load game-specific GLDEFS lumps (DOOMDEFS, HTICDEFS, HEXNDEFS or STRFDEFS)
    Possile values: 0 (DOOM), 1 (HERETIC), 2 (HEXEN) or 3 (STRIFE).
    Example: basegame = 0;

    + +

    Thing and linedef definition:

    +Default values can be set in Thing and Linedef argument definitions.
    +Example:
    +arg1
    +{
    +title = "Speed";
    +default = 100;
    +}

    diff --git a/Help/gz_features.html b/Help/gz_features.html index c1ed692a..2a8473de 100644 --- a/Help/gz_features.html +++ b/Help/gz_features.html @@ -22,6 +22,7 @@
  • Dynamic lights (all types) are rendered in Visual modes.
  • Dynamic lights defined in GLDEFS are rendered in Visual modes.
  • Animated lights.
  • +
  • Enhanced scripting workflow.
  • Partial GLDEFS and (Z)MAPINFO support.
  • Fog rendering (including colored fog in maps in UDMF format).
  • MD2 and MD3 models rendering in 2D and 3D modes.
  • @@ -30,6 +31,7 @@
  • "Test Map from current position" feature.
  • "Sync camera position between 2D and 3D modes" feature.
  • "Place Things at cursor position in Visual Modes" feature.
  • +
  • PNG image format support.
  • Color Picker plugin.
  • UDMF Controls plugin.
  • diff --git a/Help/gz_infoex.jpg b/Help/gz_infoex.jpg new file mode 100644 index 00000000..db05040c Binary files /dev/null and b/Help/gz_infoex.jpg differ diff --git a/Help/gz_scripteditor.jpg b/Help/gz_scripteditor.jpg new file mode 100644 index 00000000..b0503c29 Binary files /dev/null and b/Help/gz_scripteditor.jpg differ diff --git a/Help/gz_thing1.jpg b/Help/gz_thing1.jpg new file mode 100644 index 00000000..abef9dcd Binary files /dev/null and b/Help/gz_thing1.jpg differ diff --git a/Help/gz_thing2.jpg b/Help/gz_thing2.jpg new file mode 100644 index 00000000..619b9aa7 Binary files /dev/null and b/Help/gz_thing2.jpg differ diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 97a537b1..becb6f14 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -718,6 +718,7 @@ + @@ -727,6 +728,7 @@ + diff --git a/Source/Core/Builder.sln b/Source/Core/Builder.sln index 41e6d77c..ed3d7843 100644 --- a/Source/Core/Builder.sln +++ b/Source/Core/Builder.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagExplorer", "..\Plugins\T EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UDMFControls", "..\Plugins\UMDFControls\UDMFControls.csproj", "{2D11C828-295C-463A-8545-CA1AD6D51518}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPicker", "..\Plugins\ColorPicker\ColorPicker.csproj", "{A4761900-0EA3-4FE4-A919-847FD5080EFC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -71,6 +73,16 @@ Global {2D11C828-295C-463A-8545-CA1AD6D51518}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {2D11C828-295C-463A-8545-CA1AD6D51518}.Release|Mixed Platforms.Build.0 = Release|Any CPU {2D11C828-295C-463A-8545-CA1AD6D51518}.Release|x86.ActiveCfg = Release|Any CPU + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Any CPU.ActiveCfg = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.ActiveCfg = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Debug|x86.Build.0 = Debug|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Any CPU.ActiveCfg = Release|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|Mixed Platforms.Build.0 = Release|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.ActiveCfg = Release|x86 + {A4761900-0EA3-4FE4-A919-847FD5080EFC}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Core/Compilers/NodesCompiler.cs b/Source/Core/Compilers/NodesCompiler.cs index 6ab73156..e19d30fe 100644 --- a/Source/Core/Compilers/NodesCompiler.cs +++ b/Source/Core/Compilers/NodesCompiler.cs @@ -89,11 +89,15 @@ namespace CodeImp.DoomBuilder.Compilers processinfo = new ProcessStartInfo(); processinfo.Arguments = args; processinfo.FileName = Path.Combine(this.tempdir.FullName, info.ProgramFile); - processinfo.CreateNoWindow = false; + processinfo.CreateNoWindow = true; //mxd. was false processinfo.ErrorDialog = false; - processinfo.UseShellExecute = true; + processinfo.UseShellExecute = false; //mxd. was true processinfo.WindowStyle = ProcessWindowStyle.Hidden; processinfo.WorkingDirectory = this.workingdir; + + //mxd + processinfo.RedirectStandardError = true; + processinfo.RedirectStandardOutput = true; // Output info General.WriteLogLine("Running compiler..."); @@ -111,12 +115,37 @@ namespace CodeImp.DoomBuilder.Compilers General.ShowErrorMessage("Unable to start the compiler (" + info.Name + "). " + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } + + //mxd + string outErr = process.StandardError.ReadToEnd(); + string outMsg = process.StandardOutput.ReadToEnd(); // Wait for compiler to complete process.WaitForExit(); + + //mxd + bool errorsInNormalOurput = (outMsg.Length > 0 && outMsg.ToLowerInvariant().IndexOf("error") != -1); + //zdbsp actually writes building process here, not error info + bool errorsInErrorOutput = (outErr.Length > 0 && outErr.ToLowerInvariant().IndexOf("error") != -1); + deltatime = TimeSpan.FromTicks(process.ExitTime.Ticks - process.StartTime.Ticks); - General.WriteLogLine("Compiler process has finished."); + General.WriteLogLine("Compiler process has finished " + (errorsInNormalOurput || errorsInErrorOutput ? "with errors." : ".")); //mxd General.WriteLogLine("Compile time: " + deltatime.TotalSeconds.ToString("########0.00") + " seconds"); + + //mxd + if (process.ExitCode > 0 || errorsInNormalOurput || errorsInErrorOutput) { + if (errorsInNormalOurput) { + ReportError(new CompilerError(outMsg)); + General.WriteLogLine("Normal output: " + outMsg); + } + + if (errorsInErrorOutput) { + ReportError(new CompilerError(outErr)); + General.WriteLogLine("Error output: " + outErr); + } + return false; + } + return true; } diff --git a/Source/Core/Config/ArgumentInfo.cs b/Source/Core/Config/ArgumentInfo.cs index 039bf5e0..e9915551 100644 --- a/Source/Core/Config/ArgumentInfo.cs +++ b/Source/Core/Config/ArgumentInfo.cs @@ -42,6 +42,8 @@ namespace CodeImp.DoomBuilder.Config private bool used; private int type; private EnumList enumlist; + //mxd + private object defaultValue; #endregion @@ -51,6 +53,8 @@ namespace CodeImp.DoomBuilder.Config public bool Used { get { return used; } } public int Type { get { return type; } } public EnumList Enum { get { return enumlist; } } + //mxd + public object DefaultValue { get { return defaultValue; } } #endregion @@ -65,6 +69,9 @@ namespace CodeImp.DoomBuilder.Config this.title = cfg.ReadSetting(argspath + ".arg" + istr + ".title", "Argument " + (argindex + 1)); this.type = cfg.ReadSetting(argspath + ".arg" + istr + ".type", 0); + //mxd + this.defaultValue = cfg.ReadSetting(argspath + ".arg" + istr + ".default", 0); + // Determine enum type EnumList enumlist = null; IDictionary argdic = cfg.ReadSetting(argspath + ".arg" + istr, new Hashtable()); diff --git a/Source/Core/Controls/ArgumentBox.cs b/Source/Core/Controls/ArgumentBox.cs index b9ba7c62..84e85e1c 100644 --- a/Source/Core/Controls/ArgumentBox.cs +++ b/Source/Core/Controls/ArgumentBox.cs @@ -41,6 +41,8 @@ namespace CodeImp.DoomBuilder.Controls private TypeHandler typehandler; private bool ignorebuttonchange = false; + //mxd + private ArgumentInfo arginfo; #endregion @@ -171,7 +173,9 @@ namespace CodeImp.DoomBuilder.Controls // This sets up the control for a specific argument public void Setup(ArgumentInfo arginfo) { - int oldvalue = 0; + this.arginfo = arginfo; //mxd + + int oldvalue = 0; // Get the original value if(typehandler != null) oldvalue = typehandler.GetIntValue(); @@ -225,6 +229,14 @@ namespace CodeImp.DoomBuilder.Controls combobox_Validating(this, new CancelEventArgs()); } + //mxd. this sets default value + public void SetDefaultValue() { + typehandler.SetDefaultValue(); + combobox.SelectedItem = null; + combobox.Text = typehandler.GetStringValue(); + combobox_Validating(this, new CancelEventArgs()); + } + // This clears the value public void ClearValue() { diff --git a/Source/Core/Controls/FieldsEditorControl.cs b/Source/Core/Controls/FieldsEditorControl.cs index c4c3c26b..9ff8c60f 100644 --- a/Source/Core/Controls/FieldsEditorControl.cs +++ b/Source/Core/Controls/FieldsEditorControl.cs @@ -33,6 +33,7 @@ using System.Drawing.Imaging; using System.Drawing.Drawing2D; using CodeImp.DoomBuilder.Map; using System.Globalization; +using CodeImp.DoomBuilder.Types; #endregion @@ -237,6 +238,48 @@ namespace CodeImp.DoomBuilder.Controls // Sort fields Sort(); } + + //mxd + public object GetValue(string name) { + //have required row? + foreach (DataGridViewRow row in fieldslist.Rows) { + // Row is a field? + if (row is FieldsEditorRow) { + FieldsEditorRow frow = row as FieldsEditorRow; + // Row name matches with field + if (frow.Name == name) { + // Apply value of field to row + if (frow.IsDefined && !frow.IsEmpty) + return frow.GetResult(null); + return null; + } + } + } + + return null; + } + + //mxd + public void SetValue(string name, object value, UniversalType type) { + //have required row? + foreach (DataGridViewRow row in fieldslist.Rows) { + // Row is a field? + if (row is FieldsEditorRow) { + FieldsEditorRow frow = row as FieldsEditorRow; + // Row name matches with field + if (frow.Name == name) { + // Apply value of field to row + frow.Define(value); + return; + } + } + } + + //no such row... let's add it + FieldsEditorRow newfrow = new FieldsEditorRow(fieldslist, name, (int)type, value); + fieldslist.Rows.Insert(fieldslist.Rows.Count - 1, newfrow); + } + // This applies the current fields to a UniFields object public void Apply(UniFields tofields) diff --git a/Source/Core/Controls/LinedefInfoPanel.cs b/Source/Core/Controls/LinedefInfoPanel.cs index d24708fe..9436083d 100644 --- a/Source/Core/Controls/LinedefInfoPanel.cs +++ b/Source/Core/Controls/LinedefInfoPanel.cs @@ -29,6 +29,7 @@ using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.GZBuilder; #endregion @@ -113,9 +114,12 @@ namespace CodeImp.DoomBuilder.Controls angle.Text = l.AngleDeg.ToString() + "\u00B0"; tag.Text = l.Tag.ToString(); unpegged.Text = peggedness; + + //mxd + bool hasArg0Str = General.Map.UDMF && Array.IndexOf(GZGeneral.ACS_SPECIALS, l.Action) != -1 && l.Fields.ContainsKey("arg0str"); // Arguments - arglbl1.Text = act.Args[0].Title + ":"; + arglbl1.Text = hasArg0Str ? "Script name:" : act.Args[0].Title + ":"; //mxd arglbl2.Text = act.Args[1].Title + ":"; arglbl3.Text = act.Args[2].Title + ":"; arglbl4.Text = act.Args[3].Title + ":"; @@ -130,8 +134,14 @@ namespace CodeImp.DoomBuilder.Controls arg3.Enabled = act.Args[2].Used; arg4.Enabled = act.Args[3].Used; arg5.Enabled = act.Args[4].Used; - th = General.Types.GetArgumentHandler(act.Args[0]); - th.SetValue(l.Args[0]); arg1.Text = th.GetStringValue(); + + //mxd + if (hasArg0Str) { + arg1.Text = '"' + l.Fields["arg0str"].Value.ToString() + '"'; + } else { + th = General.Types.GetArgumentHandler(act.Args[0]); + th.SetValue(l.Args[0]); arg1.Text = th.GetStringValue(); + } th = General.Types.GetArgumentHandler(act.Args[1]); th.SetValue(l.Args[1]); arg2.Text = th.GetStringValue(); th = General.Types.GetArgumentHandler(act.Args[2]); diff --git a/Source/Core/Controls/ScriptDocumentTab.cs b/Source/Core/Controls/ScriptDocumentTab.cs index 04da4f55..c687cb1f 100644 --- a/Source/Core/Controls/ScriptDocumentTab.cs +++ b/Source/Core/Controls/ScriptDocumentTab.cs @@ -39,8 +39,9 @@ namespace CodeImp.DoomBuilder.Controls internal abstract class ScriptDocumentTab : TabPage { #region ================== Constants - - private const int EDITOR_BORDER_TOP = 8; + + private const int NAVIGATOR_BORDER_TOP = 8; //mxd + private const int EDITOR_BORDER_TOP = 33; private const int EDITOR_BORDER_BOTTOM = 4; private const int EDITOR_BORDER_LEFT = 4; private const int EDITOR_BORDER_RIGHT = 4; @@ -51,6 +52,8 @@ namespace CodeImp.DoomBuilder.Controls // The script edit control protected ScriptEditorControl editor; + //mxd + protected ComboBox navigator; // Derived classes must set this! protected ScriptConfiguration config; @@ -82,6 +85,17 @@ namespace CodeImp.DoomBuilder.Controls { // Keep panel this.panel = panel; + + //mxd + navigator = new ComboBox(); + navigator.Location = new Point(EDITOR_BORDER_LEFT, NAVIGATOR_BORDER_TOP); + navigator.Width = this.ClientSize.Width - EDITOR_BORDER_LEFT - EDITOR_BORDER_RIGHT; + navigator.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + navigator.DropDownStyle = ComboBoxStyle.DropDownList; + navigator.Name = "navigator"; + navigator.TabStop = true; + navigator.TabIndex = 0; + this.Controls.Add(navigator); // Make the script control editor = new ScriptEditorControl(); @@ -91,7 +105,7 @@ namespace CodeImp.DoomBuilder.Controls editor.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; editor.Name = "editor"; editor.TabStop = true; - editor.TabIndex = 0; + editor.TabIndex = 1; this.Controls.Add(editor); // Bind events diff --git a/Source/Core/Controls/ScriptEditorPanel.cs b/Source/Core/Controls/ScriptEditorPanel.cs index c1ae0438..82bf9b97 100644 --- a/Source/Core/Controls/ScriptEditorPanel.cs +++ b/Source/Core/Controls/ScriptEditorPanel.cs @@ -137,7 +137,18 @@ namespace CodeImp.DoomBuilder.Controls } // Select the first tab - if(tabs.TabPages.Count > 0) tabs.SelectedIndex = 0; + //if(tabs.TabPages.Count > 0) tabs.SelectedIndex = 0; + + //mxd. Select "Scripts" tab, because that's what user will want 99% of time + if (tabs.TabPages.Count > 0) { + foreach (TabPage p in tabs.TabPages) { + if (p.Text == "SCRIPTS") { + tabs.SelectedTab = p; + break; + } + } + if (tabs.SelectedIndex == -1) tabs.SelectedIndex = 0; + } // If the map has remembered any compile errors, then show them ShowErrors(General.Map.Errors); diff --git a/Source/Core/Controls/ScriptLumpDocumentTab.cs b/Source/Core/Controls/ScriptLumpDocumentTab.cs index dc417419..78a881ae 100644 --- a/Source/Core/Controls/ScriptLumpDocumentTab.cs +++ b/Source/Core/Controls/ScriptLumpDocumentTab.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.Globalization; using System.Text; using System.Windows.Forms; using Microsoft.Win32; @@ -31,6 +32,8 @@ using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.IO; using System.IO; using CodeImp.DoomBuilder.Compilers; +//mxd +using CodeImp.DoomBuilder.GZBuilder.Data; #endregion @@ -91,6 +94,14 @@ namespace CodeImp.DoomBuilder.Controls SetTitle(General.Map.Options.CurrentName); else SetTitle(this.lumpname.ToUpper()); + + //mxd + if (this.Text == "SCRIPTS") { + updateNavigator(); + navigator.SelectedIndexChanged += new EventHandler(navigator_SelectedIndexChanged); + }else{ + navigator.Enabled = false; + } } // Disposer @@ -102,6 +113,37 @@ namespace CodeImp.DoomBuilder.Controls #endregion #region ================== Methods + + //mxd + private void updateNavigator() { + string selectedItem = ""; + int selectedIndex = 0; + if (navigator.SelectedIndex != -1) selectedItem = navigator.Text; + + navigator.Items.Clear(); + + //add named scripts + int i = 0; + if (General.Map.UDMF) { + ScriptItem[] namedScripts = new ScriptItem[General.Map.NamedScripts.Count]; + foreach (ScriptItem si in General.Map.NamedScripts) { + namedScripts[i++] = si; + if (si.Name == selectedItem) selectedIndex = i - 1; + } + navigator.Items.AddRange(namedScripts); + } + + //add numbered scripts + ScriptItem[] numberedScripts = new ScriptItem[General.Map.NumberedScripts.Count]; + int c = 0; + foreach (ScriptItem si in General.Map.NumberedScripts) { + numberedScripts[c++] = si; + if (si.Name == selectedItem) selectedIndex = i - 1 + c; + } + navigator.Items.AddRange(numberedScripts); + + if (navigator.Items.Count > 0) navigator.SelectedIndex = selectedIndex; + } // Compile script public override void Compile() @@ -114,6 +156,14 @@ namespace CodeImp.DoomBuilder.Controls // Feed errors to panel panel.ShowErrors(General.Map.Errors); + + //mxd + if (General.Map.Errors.Count == 0) { + General.Map.UpdateScriptNames(); + navigator.SelectedIndexChanged -= navigator_SelectedIndexChanged; + updateNavigator(); + navigator.SelectedIndexChanged += new EventHandler(navigator_SelectedIndexChanged); + } } // Implicit save @@ -135,7 +185,17 @@ namespace CodeImp.DoomBuilder.Controls #endregion #region ================== Events - + + //mxd + private void navigator_SelectedIndexChanged(object sender, EventArgs e) { + if (navigator.SelectedItem is ScriptItem) { + ScriptItem si = navigator.SelectedItem as ScriptItem; + editor.EnsureLineVisible(editor.LineFromPosition(si.SelectionStart)); + editor.SelectionStart = si.SelectionStart; + editor.SelectionEnd = si.SelectionEnd; + } + } + #endregion } } diff --git a/Source/Core/Controls/ThingInfoPanel.cs b/Source/Core/Controls/ThingInfoPanel.cs index 39193d03..e004c4e4 100644 --- a/Source/Core/Controls/ThingInfoPanel.cs +++ b/Source/Core/Controls/ThingInfoPanel.cs @@ -30,6 +30,9 @@ using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.IO; +//mxd +using CodeImp.DoomBuilder.GZBuilder.Data; +using CodeImp.DoomBuilder.GZBuilder; #endregion @@ -166,7 +169,10 @@ namespace CodeImp.DoomBuilder.Controls // Arguments if(act != null) { - arglbl1.Text = act.Args[0].Title + ":"; + //mxd + bool hasArg0Str = General.Map.UDMF && Array.IndexOf(GZGeneral.ACS_SPECIALS, t.Action) != -1 && t.Fields.ContainsKey("arg0str"); + + arglbl1.Text = hasArg0Str ? "Script name:" : act.Args[0].Title + ":"; //mxd arglbl2.Text = act.Args[1].Title + ":"; arglbl3.Text = act.Args[2].Title + ":"; arglbl4.Text = act.Args[3].Title + ":"; @@ -181,8 +187,14 @@ namespace CodeImp.DoomBuilder.Controls arg3.Enabled = act.Args[2].Used; arg4.Enabled = act.Args[3].Used; arg5.Enabled = act.Args[4].Used; - th = General.Types.GetArgumentHandler(act.Args[0]); - th.SetValue(t.Args[0]); arg1.Text = th.GetStringValue(); + + //mxd + if (hasArg0Str) { + arg1.Text = '"' + t.Fields["arg0str"].Value.ToString() + '"'; + } else { + th = General.Types.GetArgumentHandler(act.Args[0]); + th.SetValue(t.Args[0]); arg1.Text = th.GetStringValue(); + } th = General.Types.GetArgumentHandler(act.Args[1]); th.SetValue(t.Args[1]); arg2.Text = th.GetStringValue(); th = General.Types.GetArgumentHandler(act.Args[2]); diff --git a/Source/Core/GZBuilder/Data/GZDoomLight.cs b/Source/Core/GZBuilder/Data/GZDoomLight.cs index 9457554f..98742995 100644 --- a/Source/Core/GZBuilder/Data/GZDoomLight.cs +++ b/Source/Core/GZBuilder/Data/GZDoomLight.cs @@ -17,47 +17,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data Color = new Color3(); Offset = new Vector3(); } - - public static int[] GetDefaultLightSettings(int type) { - int light_id = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, type); - if (light_id != -1) { - int[] args = new int[5]; - - if (light_id == (int)GZDoomLightType.VAVOOM_COLORED) { - args[0] = 16; - args[1] = 255; - args[2] = 255; - args[3] = 255; - } else if (light_id == (int)GZDoomLightType.VAVOOM) { - args[0] = 16; - } else { - int n; - if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) { - n = 0; - } else if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) { - n = 10; - } else { - n = 20; - } - light_id = type - 9800 - n; - - args[0] = 255; - args[1] = 255; - args[2] = 255; - - if (light_id == (int)GZDoomLightType.SECTOR) - args[3] = 4; - else - args[3] = 64; - - if (Array.IndexOf(GZBuilder.GZGeneral.GZ_ANIMATED_LIGHT_TYPES, light_id) != -1) { - args[4] = 32; - } - } - return args; - } - return null; - } } public enum GZDoomLightType : int diff --git a/Source/Core/GZBuilder/Data/ScriptItem.cs b/Source/Core/GZBuilder/Data/ScriptItem.cs new file mode 100644 index 00000000..12da8f38 --- /dev/null +++ b/Source/Core/GZBuilder/Data/ScriptItem.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CodeImp.DoomBuilder.GZBuilder.Data { + public sealed class ScriptItem : Object { + private string name; + private int index; + private int selectionStart; + private int selectionEnd; + + public string Name { get { return name; } } + public int Index { get { return index; } } + public int SelectionStart { get { return selectionStart; } } + public int SelectionEnd { get { return selectionEnd; } } + + public ScriptItem(int index, string name, int selectionStart, int selectionEnd) { + this.name = name; + this.index = index; + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + } + + public ScriptItem(int index, string name) { + this.name = name; + this.index = index; + } + + public override string ToString() { + return name; + } + } +} diff --git a/Source/Core/GZBuilder/GZGeneral.cs b/Source/Core/GZBuilder/GZGeneral.cs index ef7f8688..2ddb65ed 100644 --- a/Source/Core/GZBuilder/GZGeneral.cs +++ b/Source/Core/GZBuilder/GZGeneral.cs @@ -27,10 +27,12 @@ namespace CodeImp.DoomBuilder.GZBuilder private static int[] gzAnimatedLightTypes = { (int)GZDoomLightType.FLICKER, (int)GZDoomLightType.RANDOM, (int)GZDoomLightType.PULSE }; public static int[] GZ_ANIMATED_LIGHT_TYPES { get { return gzAnimatedLightTypes; } } - public static bool UDMF; + //asc script action specials + private static int[] acsSpecials = { 80, 81, 82, 83, 84, 85, 226 }; + public static int[] ACS_SPECIALS { get { return acsSpecials; } } //version - public const float Version = 1.10f; + public const float Version = 1.11f; //debug console #if DEBUG @@ -52,14 +54,6 @@ namespace CodeImp.DoomBuilder.GZBuilder #endif } - public static void OnMapOpenEnd() { - UDMF = (General.Map.Config.FormatInterface == "UniversalMapSetIO"); - General.MainWindow.UpdateGZDoomPannel(); - - //dbg - //GZBuilder.GZGeneral.Trace("GameConfiguration: loaded gametype " + General.Map.Config.GameType); - } - public static void OnReloadResources() { #if DEBUG ((ConsoleDocker)console.Control).Clear(); @@ -174,4 +168,4 @@ namespace CodeImp.DoomBuilder.GZBuilder General.Map.Data.ReloadMapInfo(); } } -} +} \ No newline at end of file diff --git a/Source/Core/GZBuilder/ZDoom/AcsParser.cs b/Source/Core/GZBuilder/ZDoom/AcsParser.cs new file mode 100644 index 00000000..784ad53d --- /dev/null +++ b/Source/Core/GZBuilder/ZDoom/AcsParser.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +using CodeImp.DoomBuilder.ZDoom; +using CodeImp.DoomBuilder.GZBuilder.Data; + +namespace CodeImp.DoomBuilder.GZBuilder.ZDoom +{ + public class AcsParser : ZDTextParser + { + private List namedScripts; + private List numberedScripts; + + public List NamedScripts { get { return namedScripts; } } + public List NumberedScripts { get { return numberedScripts; } } + + public AcsParser() { + namedScripts = new List(); + numberedScripts = new List(); + } + + public override bool Parse(Stream stream, string sourcefilename) { + base.Parse(stream, sourcefilename); + + // Continue until at the end of the stream + while (SkipWhitespace(true)) { + string token = ReadToken(); + + if (!string.IsNullOrEmpty(token)) { + token = token.ToLowerInvariant(); + + if (token == "script") { + int startPos = (int)stream.Position - 7; + SkipWhitespace(true); + token = ReadToken(); + + //is it named script? + if (token.IndexOf('"') != -1) { + token = StripTokenQuotes(token); + ScriptItem i = new ScriptItem(0, token, startPos, (int)stream.Position-1); + namedScripts.Add(i); + } else { //should be numbered script + int n = 0; + if (int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) { + int endPos = (int)stream.Position - 1; + + //now find opening brace + do { + SkipWhitespace(true); + token = ReadToken(); + } while (token != "{"); + + token = ReadLine(); + string name = ""; + + if (token.Length > 0) { + int commentStart = token.IndexOf("//"); + if (commentStart != -1) { //found comment + commentStart += 2; + name = token.Substring(commentStart, token.Length - commentStart); + } + } + + name = (name != "" ? "[" + n + "] " + name : "Script " + n); + ScriptItem i = new ScriptItem(n, name, startPos, endPos); + numberedScripts.Add(i); + } + } + + } + } + } + return true; + } + } +} diff --git a/Source/Core/General/Clock.cs b/Source/Core/General/Clock.cs index 16212473..3bcf71f0 100644 --- a/Source/Core/General/Clock.cs +++ b/Source/Core/General/Clock.cs @@ -14,126 +14,36 @@ #endregion -#region ================== Namespaces - using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -#endregion +using SlimDX; namespace CodeImp.DoomBuilder { public class Clock { - #region ================== Declarations - - //#if !LINUX - - [DllImport("kernel32.dll")] - private static extern short QueryPerformanceCounter(out long x); - - [DllImport("kernel32.dll")] - private static extern short QueryPerformanceFrequency(out long x); - - //#endif - - #endregion - - #region ================== Constants - - #endregion - - #region ================== Variables - - // Settings - private double currenttime; - // Disposing private bool isdisposed = false; - #endregion - - #region ================== Properties - - // Settings - public double CurrentTime { get { return currenttime; } } - // Disposing public bool IsDisposed { get { return isdisposed; } } - #endregion - - #region ================== Constructor / Disposer - // Constructor - public Clock() - { + public Clock(){ // We have no destructor GC.SuppressFinalize(this); } // Disposer - public void Dispose() - { + public void Dispose(){ // Not already disposed? - if(!isdisposed) - { - // Clean up - - // Done + if(!isdisposed) { isdisposed = true; } } - #endregion - - #region ================== Methods - // This queries the system for the current time - public double GetCurrentTime() - { - // Only windows has QPC - //#if !LINUX - - long timefrequency; - - // Get the high resolution clock frequency - if(QueryPerformanceFrequency(out timefrequency) == 0) - { - // No high resolution clock available - currenttime = (double)Environment.TickCount; - } - else - { - long timecount; - - // Get the high resolution count - QueryPerformanceCounter(out timecount); - - // Calculate high resolution time in milliseconds - // TODO: It seems there is a loss of precision here when the - // result of this math is assigned to currenttime, WHY?! - currenttime = (double)timecount / (double)timefrequency * (double)1000.0; - } - - /* - #else - - // In LINUX always use standard clock - currenttime = (double)Environment.TickCount; - - #endif - */ - - // Return the current time - return currenttime; + public double GetCurrentTime(){ + return SlimDX.Configuration.Timer.ElapsedMilliseconds; } - - #endregion } } diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs index 7f62e08f..690ff20e 100644 --- a/Source/Core/General/General.cs +++ b/Source/Core/General/General.cs @@ -671,7 +671,7 @@ namespace CodeImp.DoomBuilder General.WriteLogLine("Creating types manager..."); types = new TypesManager(); - //mxd. init gzdoombuilder + //mxd. init gzdoom builder GZBuilder.GZGeneral.Init(); // Do auto map loading when window is delayed @@ -1019,6 +1019,8 @@ namespace CodeImp.DoomBuilder mainwindow.RedrawDisplay(); mainwindow.UpdateThingsFilters(); mainwindow.UpdateInterface(); + //mxd + mainwindow.UpdateGZDoomPannel(); mainwindow.HideInfo(); if(errorlogger.IsErrorAdded) @@ -1068,6 +1070,8 @@ namespace CodeImp.DoomBuilder mainwindow.RedrawDisplay(); mainwindow.HideInfo(); mainwindow.UpdateThingsFilters(); + //mxd + mainwindow.UpdateGZDoomPannel(); mainwindow.UpdateInterface(); mainwindow.DisplayReady(); General.WriteLogLine("Map unload done"); @@ -1104,6 +1108,9 @@ namespace CodeImp.DoomBuilder // Open map file OpenMapFile(openfile.FileName, null); + + //mxd + mainwindow.UpdateGZDoomPannel(); } openfile.Dispose(); diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index 3a2e7d6f..66d06cbe 100644 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -39,354 +39,365 @@ using CodeImp.DoomBuilder.VisualModes; //mxd using CodeImp.DoomBuilder.GZBuilder; +using CodeImp.DoomBuilder.GZBuilder.Data; +using CodeImp.DoomBuilder.GZBuilder.ZDoom; #endregion -namespace CodeImp.DoomBuilder -{ - public sealed class MapManager - { - #region ================== Constants +namespace CodeImp.DoomBuilder { + public sealed class MapManager { + #region ================== Constants - // Map header name in temporary file - internal const string TEMP_MAP_HEADER = "TEMPMAP"; - internal const string BUILD_MAP_HEADER = "MAP01"; - public const string CONFIG_MAP_HEADER = "~MAP"; + // Map header name in temporary file + internal const string TEMP_MAP_HEADER = "TEMPMAP"; + internal const string BUILD_MAP_HEADER = "MAP01"; + public const string CONFIG_MAP_HEADER = "~MAP"; - #endregion + #endregion - #region ================== Variables + #region ================== Variables - // Status - private bool changed; - private bool scriptschanged; - - // Map information - private string filetitle; - private string filepathname; - private string temppath; + // Status + private bool changed; + private bool scriptschanged; - // Main objects - private MapSet map; - private MapSetIO io; - private MapOptions options; - private ConfigurationInfo configinfo; - private GameConfiguration config; - private DataManager data; - private D3DDevice graphics; - private Renderer2D renderer2d; - private Renderer3D renderer3d; - private WAD tempwad; - private GridSetup grid; - private UndoManager undoredo; - private CopyPasteManager copypaste; - private Launcher launcher; - private ThingsFilter thingsfilter; - private ScriptEditorForm scriptwindow; - private List errors; - private VisualCamera visualcamera; - - // Disposing - private bool isdisposed = false; + // Map information + private string filetitle; + private string filepathname; + private string temppath; - #endregion + // Main objects + private MapSet map; + private MapSetIO io; + private MapOptions options; + private ConfigurationInfo configinfo; + private GameConfiguration config; + private DataManager data; + private D3DDevice graphics; + private Renderer2D renderer2d; + private Renderer3D renderer3d; + private WAD tempwad; + private GridSetup grid; + private UndoManager undoredo; + private CopyPasteManager copypaste; + private Launcher launcher; + private ThingsFilter thingsfilter; + private ScriptEditorForm scriptwindow; + private List errors; + private VisualCamera visualcamera; - #region ================== Properties + //mxd + private List namedScripts; + private List numberedScripts; - public string FilePathName { get { return filepathname; } } - public string FileTitle { get { return filetitle; } } - public string TempPath { get { return temppath; } } - public MapOptions Options { get { return options; } } - public MapSet Map { get { return map; } } - public DataManager Data { get { return data; } } - public bool IsChanged { get { return changed | CheckScriptChanged(); } set { changed |= value; } } - public bool IsDisposed { get { return isdisposed; } } - internal D3DDevice Graphics { get { return graphics; } } - public IRenderer2D Renderer2D { get { return renderer2d; } } - public IRenderer3D Renderer3D { get { return renderer3d; } } - internal Renderer2D CRenderer2D { get { return renderer2d; } } - internal Renderer3D CRenderer3D { get { return renderer3d; } } - public GameConfiguration Config { get { return config; } } - public ConfigurationInfo ConfigSettings { get { return configinfo; } } - public GridSetup Grid { get { return grid; } } - public UndoManager UndoRedo { get { return undoredo; } } - internal CopyPasteManager CopyPaste { get { return copypaste; } } - public IMapSetIO FormatInterface { get { return io; } } - internal Launcher Launcher { get { return launcher; } } - public ThingsFilter ThingsFilter { get { return thingsfilter; } } - internal List Errors { get { return errors; } } - internal ScriptEditorForm ScriptEditor { get { return scriptwindow; } } - public VisualCamera VisualCamera { get { return visualcamera; } set { visualcamera = value; } } - public bool IsScriptsWindowOpen { get { return (scriptwindow != null) && !scriptwindow.IsDisposed; } } - - #endregion + // Disposing + private bool isdisposed = false; - #region ================== Constructor / Disposer + #endregion - // Constructor - internal MapManager() - { - // We have no destructor - GC.SuppressFinalize(this); + #region ================== Properties - // Create temporary path - temppath = General.MakeTempDirname(); - Directory.CreateDirectory(temppath); - General.WriteLogLine("Temporary directory: " + temppath); + public string FilePathName { get { return filepathname; } } + public string FileTitle { get { return filetitle; } } + public string TempPath { get { return temppath; } } + public MapOptions Options { get { return options; } } + public MapSet Map { get { return map; } } + public DataManager Data { get { return data; } } + public bool IsChanged { get { return changed | CheckScriptChanged(); } set { changed |= value; } } + public bool IsDisposed { get { return isdisposed; } } + internal D3DDevice Graphics { get { return graphics; } } + public IRenderer2D Renderer2D { get { return renderer2d; } } + public IRenderer3D Renderer3D { get { return renderer3d; } } + internal Renderer2D CRenderer2D { get { return renderer2d; } } + internal Renderer3D CRenderer3D { get { return renderer3d; } } + public GameConfiguration Config { get { return config; } } + public ConfigurationInfo ConfigSettings { get { return configinfo; } } + public GridSetup Grid { get { return grid; } } + public UndoManager UndoRedo { get { return undoredo; } } + internal CopyPasteManager CopyPaste { get { return copypaste; } } + public IMapSetIO FormatInterface { get { return io; } } + internal Launcher Launcher { get { return launcher; } } + public ThingsFilter ThingsFilter { get { return thingsfilter; } } + internal List Errors { get { return errors; } } + internal ScriptEditorForm ScriptEditor { get { return scriptwindow; } } + public VisualCamera VisualCamera { get { return visualcamera; } set { visualcamera = value; } } + public bool IsScriptsWindowOpen { get { return (scriptwindow != null) && !scriptwindow.IsDisposed; } } - // Basic objects - grid = new GridSetup(); - undoredo = new UndoManager(); - copypaste = new CopyPasteManager(); - launcher = new Launcher(this); - thingsfilter = new NullThingsFilter(); - errors = new List(); - } - - // Disposer - internal bool Dispose() - { - // Not already disposed? - if(!isdisposed) - { - // Let the plugins know - General.Plugins.OnMapCloseBegin(); - - // Stop processing - General.MainWindow.StopProcessing(); - - // Close script editor - CloseScriptEditor(false); - - // Change to no mode - General.Editing.ChangeMode((EditMode)null); - - // Unbind any methods - General.Actions.UnbindMethods(this); - - // Dispose - if(grid != null) grid.Dispose(); - if(launcher != null) launcher.Dispose(); - if(copypaste != null) copypaste.Dispose(); - if(undoredo != null) undoredo.Dispose(); - General.WriteLogLine("Unloading data resources..."); - if(data != null) data.Dispose(); - General.WriteLogLine("Closing temporary file..."); - if(tempwad != null) tempwad.Dispose(); - General.WriteLogLine("Unloading map data..."); - if(map != null) map.Dispose(); - General.WriteLogLine("Stopping graphics device..."); - if(renderer2d != null) renderer2d.Dispose(); - if(renderer3d != null) renderer3d.Dispose(); - if(graphics != null) graphics.Dispose(); - visualcamera = null; - grid = null; - launcher = null; - copypaste = null; - undoredo = null; - data = null; - tempwad = null; - map = null; - renderer2d = null; - renderer3d = null; - graphics = null; - - // We may spend some time to clean things up here - GC.Collect(); - - // Remove temp file - General.WriteLogLine("Removing temporary directory..."); - try { Directory.Delete(temppath, true); } catch(Exception e) - { - General.WriteLogLine(e.GetType().Name + ": " + e.Message); - General.WriteLogLine("Failed to remove temporary directory!"); - } - - // Let the plugins know - General.Plugins.OnMapCloseEnd(); - - // Done - isdisposed = true; - return true; - } - else - { - // Already closed - return true; - } - } + //mxd + public bool UDMF { get { return config.FormatInterface == "UniversalMapSetIO"; } } + public List NamedScripts { + get { + if (!UDMF) throw new Exception("ScriptNames cannot be used in '" + config.FormatInterface + "' format!"); + return namedScripts; + } + } + public List NumberedScripts { get { return numberedScripts; } } - #endregion + #endregion - #region ================== New / Open - - // Initializes for a new map - internal bool InitializeNewMap(MapOptions options) - { - string tempfile; - - // Apply settings - this.filetitle = "unnamed.wad"; - this.filepathname = ""; - this.changed = false; - this.options = options; + #region ================== Constructor / Disposer - General.WriteLogLine("Creating new map '" + options.CurrentName + "' with configuration '" + options.ConfigFile + "'"); + // Constructor + internal MapManager() { + // We have no destructor + GC.SuppressFinalize(this); - // Initiate graphics - General.WriteLogLine("Initializing graphics device..."); - graphics = new D3DDevice(General.MainWindow.Display); - if(!graphics.Initialize()) return false; - - // Create renderers - renderer2d = new Renderer2D(graphics); - renderer3d = new Renderer3D(graphics); - - // Load game configuration - General.WriteLogLine("Loading game configuration..."); - configinfo = General.GetConfigurationInfo(options.ConfigFile); - config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); - configinfo.ApplyDefaults(config); - General.Editing.UpdateCurrentEditModes(); - - // Create map data - map = new MapSet(); - - // Create temp wadfile - tempfile = General.MakeTempFilename(temppath); - General.WriteLogLine("Creating temporary file: " + tempfile); - #if DEBUG - tempwad = new WAD(tempfile); - #else + // Create temporary path + temppath = General.MakeTempDirname(); + Directory.CreateDirectory(temppath); + General.WriteLogLine("Temporary directory: " + temppath); + + // Basic objects + grid = new GridSetup(); + undoredo = new UndoManager(); + copypaste = new CopyPasteManager(); + launcher = new Launcher(this); + thingsfilter = new NullThingsFilter(); + errors = new List(); + + //mxd + numberedScripts = new List(); + namedScripts = new List(); + } + + // Disposer + internal bool Dispose() { + // Not already disposed? + if (!isdisposed) { + // Let the plugins know + General.Plugins.OnMapCloseBegin(); + + // Stop processing + General.MainWindow.StopProcessing(); + + // Close script editor + CloseScriptEditor(false); + + // Change to no mode + General.Editing.ChangeMode((EditMode)null); + + // Unbind any methods + General.Actions.UnbindMethods(this); + + // Dispose + if (grid != null) grid.Dispose(); + if (launcher != null) launcher.Dispose(); + if (copypaste != null) copypaste.Dispose(); + if (undoredo != null) undoredo.Dispose(); + General.WriteLogLine("Unloading data resources..."); + if (data != null) data.Dispose(); + General.WriteLogLine("Closing temporary file..."); + if (tempwad != null) tempwad.Dispose(); + General.WriteLogLine("Unloading map data..."); + if (map != null) map.Dispose(); + General.WriteLogLine("Stopping graphics device..."); + if (renderer2d != null) renderer2d.Dispose(); + if (renderer3d != null) renderer3d.Dispose(); + if (graphics != null) graphics.Dispose(); + visualcamera = null; + grid = null; + launcher = null; + copypaste = null; + undoredo = null; + data = null; + tempwad = null; + map = null; + renderer2d = null; + renderer3d = null; + graphics = null; + + // We may spend some time to clean things up here + GC.Collect(); + + // Remove temp file + General.WriteLogLine("Removing temporary directory..."); + try { Directory.Delete(temppath, true); } catch (Exception e) { + General.WriteLogLine(e.GetType().Name + ": " + e.Message); + General.WriteLogLine("Failed to remove temporary directory!"); + } + + // Let the plugins know + General.Plugins.OnMapCloseEnd(); + + // Done + isdisposed = true; + return true; + } + else { + // Already closed + return true; + } + } + + #endregion + + #region ================== New / Open + + // Initializes for a new map + internal bool InitializeNewMap(MapOptions options) { + string tempfile; + + // Apply settings + this.filetitle = "unnamed.wad"; + this.filepathname = ""; + this.changed = false; + this.options = options; + + General.WriteLogLine("Creating new map '" + options.CurrentName + "' with configuration '" + options.ConfigFile + "'"); + + // Initiate graphics + General.WriteLogLine("Initializing graphics device..."); + graphics = new D3DDevice(General.MainWindow.Display); + if (!graphics.Initialize()) return false; + + // Create renderers + renderer2d = new Renderer2D(graphics); + renderer3d = new Renderer3D(graphics); + + // Load game configuration + General.WriteLogLine("Loading game configuration..."); + configinfo = General.GetConfigurationInfo(options.ConfigFile); + config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); + configinfo.ApplyDefaults(config); + General.Editing.UpdateCurrentEditModes(); + + // Create map data + map = new MapSet(); + + // Create temp wadfile + tempfile = General.MakeTempFilename(temppath); + General.WriteLogLine("Creating temporary file: " + tempfile); +#if DEBUG + tempwad = new WAD(tempfile); +#else try { tempwad = new WAD(tempfile); } catch(Exception e) { General.ShowErrorMessage("Error while creating a temporary wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } - #endif - - // Read the map from temp file - General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); - io = MapSetIO.Create(config.FormatInterface, tempwad, this); +#endif - // Create required lumps - General.WriteLogLine("Creating map data structures..."); - tempwad.Insert(TEMP_MAP_HEADER, 0, 0); - io.Write(map, TEMP_MAP_HEADER, 1); - CreateRequiredLumps(tempwad, TEMP_MAP_HEADER); - - // Load data manager - General.WriteLogLine("Loading data resources..."); - data = new DataManager(); - data.Load(configinfo.Resources, options.Resources); - - // Update structures - options.ApplyGridSettings(); - map.UpdateConfiguration(); - map.Update(); - thingsfilter.Update(); + // Read the map from temp file + General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); + io = MapSetIO.Create(config.FormatInterface, tempwad, this); + + // Create required lumps + General.WriteLogLine("Creating map data structures..."); + tempwad.Insert(TEMP_MAP_HEADER, 0, 0); + io.Write(map, TEMP_MAP_HEADER, 1); + CreateRequiredLumps(tempwad, TEMP_MAP_HEADER); + + // Load data manager + General.WriteLogLine("Loading data resources..."); + data = new DataManager(); + data.Load(configinfo.Resources, options.Resources); + + // Update structures + options.ApplyGridSettings(); + map.UpdateConfiguration(); + map.Update(); + thingsfilter.Update(); //mxd. load models data.LoadModels(); - - // Bind any methods - General.Actions.BindMethods(this); - - // Set defaults - this.visualcamera = new VisualCamera(); - General.Editing.ChangeMode(configinfo.StartMode); - ClassicMode cmode = (General.Editing.Mode as ClassicMode); - if(cmode != null) cmode.SetZoom(0.5f); - renderer2d.SetViewMode((ViewMode)General.Settings.DefaultViewMode); - General.Settings.SetDefaultThingFlags(config.DefaultThingFlags); - //mxd - GZBuilder.GZGeneral.OnMapOpenEnd(); - - // Success - this.changed = false; - General.WriteLogLine("Map creation done"); - return true; - } + namedScripts = new List(); + numberedScripts = new List(); - // Initializes for an existing map - internal bool InitializeOpenMap(string filepathname, MapOptions options) - { - WAD mapwad; - string tempfile; - DataLocation maplocation; - - // Apply settings - this.filetitle = Path.GetFileName(filepathname); - this.filepathname = filepathname; - this.changed = false; - this.options = options; - - General.WriteLogLine("Opening map '" + options.CurrentName + "' with configuration '" + options.ConfigFile + "'"); + // Bind any methods + General.Actions.BindMethods(this); - // Initiate graphics - General.WriteLogLine("Initializing graphics device..."); - graphics = new D3DDevice(General.MainWindow.Display); - if(!graphics.Initialize()) return false; + // Set defaults + this.visualcamera = new VisualCamera(); + General.Editing.ChangeMode(configinfo.StartMode); + ClassicMode cmode = (General.Editing.Mode as ClassicMode); + if (cmode != null) cmode.SetZoom(0.5f); + renderer2d.SetViewMode((ViewMode)General.Settings.DefaultViewMode); + General.Settings.SetDefaultThingFlags(config.DefaultThingFlags); - // Create renderers - renderer2d = new Renderer2D(graphics); - renderer3d = new Renderer3D(graphics); + // Success + this.changed = false; + General.WriteLogLine("Map creation done"); + return true; + } - // Load game configuration - General.WriteLogLine("Loading game configuration..."); - configinfo = General.GetConfigurationInfo(options.ConfigFile); - config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); - configinfo.ApplyDefaults(config); - General.Editing.UpdateCurrentEditModes(); - - // Create map data - map = new MapSet(); - - // Create temp wadfile - tempfile = General.MakeTempFilename(temppath); - General.WriteLogLine("Creating temporary file: " + tempfile); - #if DEBUG - tempwad = new WAD(tempfile); - #else + // Initializes for an existing map + internal bool InitializeOpenMap(string filepathname, MapOptions options) { + WAD mapwad; + string tempfile; + DataLocation maplocation; + + // Apply settings + this.filetitle = Path.GetFileName(filepathname); + this.filepathname = filepathname; + this.changed = false; + this.options = options; + + General.WriteLogLine("Opening map '" + options.CurrentName + "' with configuration '" + options.ConfigFile + "'"); + + // Initiate graphics + General.WriteLogLine("Initializing graphics device..."); + graphics = new D3DDevice(General.MainWindow.Display); + if (!graphics.Initialize()) return false; + + // Create renderers + renderer2d = new Renderer2D(graphics); + renderer3d = new Renderer3D(graphics); + + // Load game configuration + General.WriteLogLine("Loading game configuration..."); + configinfo = General.GetConfigurationInfo(options.ConfigFile); + config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); + configinfo.ApplyDefaults(config); + General.Editing.UpdateCurrentEditModes(); + + // Create map data + map = new MapSet(); + + // Create temp wadfile + tempfile = General.MakeTempFilename(temppath); + General.WriteLogLine("Creating temporary file: " + tempfile); +#if DEBUG + tempwad = new WAD(tempfile); +#else try { tempwad = new WAD(tempfile); } catch(Exception e) { General.ShowErrorMessage("Error while creating a temporary wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } - #endif - - // Now open the map file - General.WriteLogLine("Opening source file: " + filepathname); - #if DEBUG - mapwad = new WAD(filepathname, true); - #else +#endif + + // Now open the map file + General.WriteLogLine("Opening source file: " + filepathname); +#if DEBUG + mapwad = new WAD(filepathname, true); +#else try { mapwad = new WAD(filepathname, true); } catch(Exception e) { General.ShowErrorMessage("Error while opening source wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } - #endif - - // Copy the map lumps to the temp file - General.WriteLogLine("Copying map lumps to temporary file..."); - CopyLumpsByType(mapwad, options.CurrentName, tempwad, TEMP_MAP_HEADER, - true, true, true, true); - - // Close the map file - mapwad.Dispose(); - - // Read the map from temp file - map.BeginAddRemove(); - General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); - io = MapSetIO.Create(config.FormatInterface, tempwad, this); - General.WriteLogLine("Reading map data structures from file..."); - #if DEBUG - map = io.Read(map, TEMP_MAP_HEADER); - #else +#endif + + // Copy the map lumps to the temp file + General.WriteLogLine("Copying map lumps to temporary file..."); + CopyLumpsByType(mapwad, options.CurrentName, tempwad, TEMP_MAP_HEADER, + true, true, true, true); + + // Close the map file + mapwad.Dispose(); + + // Read the map from temp file + map.BeginAddRemove(); + General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); + io = MapSetIO.Create(config.FormatInterface, tempwad, this); + General.WriteLogLine("Reading map data structures from file..."); +#if DEBUG + map = io.Read(map, TEMP_MAP_HEADER); +#else try { map = io.Read(map, TEMP_MAP_HEADER); } catch(Exception e) { @@ -394,1286 +405,1208 @@ namespace CodeImp.DoomBuilder General.ShowErrorMessage("Unable to read the map data structures with the specified configuration.", MessageBoxButtons.OK); return false; } - #endif - map.EndAddRemove(); - - // Load data manager - General.WriteLogLine("Loading data resources..."); - data = new DataManager(); - maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, options.StrictPatches, false, false); - data.Load(configinfo.Resources, options.Resources, maplocation); +#endif + map.EndAddRemove(); - // Remove unused sectors - map.RemoveUnusedSectors(true); - - // Update structures - options.ApplyGridSettings(); - map.UpdateConfiguration(); - map.SnapAllToAccuracy(); - map.Update(); - thingsfilter.Update(); + // Load data manager + General.WriteLogLine("Loading data resources..."); + data = new DataManager(); + maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, options.StrictPatches, false, false); + data.Load(configinfo.Resources, options.Resources, maplocation); + + // Remove unused sectors + map.RemoveUnusedSectors(true); + + // Update structures + options.ApplyGridSettings(); + map.UpdateConfiguration(); + map.SnapAllToAccuracy(); + map.Update(); + thingsfilter.Update(); //mxd. load models data.LoadModels(); - - // Bind any methods - General.Actions.BindMethods(this); + //mxd. check script names + UpdateScriptNames(); - // Set defaults - this.visualcamera = new VisualCamera(); - General.Editing.ChangeMode(configinfo.StartMode); - renderer2d.SetViewMode((ViewMode)General.Settings.DefaultViewMode); - General.Settings.SetDefaultThingFlags(config.DefaultThingFlags); + // Bind any methods + General.Actions.BindMethods(this); - // Center map in screen - if(General.Editing.Mode is ClassicMode) (General.Editing.Mode as ClassicMode).CenterInScreen(); + // Set defaults + this.visualcamera = new VisualCamera(); + General.Editing.ChangeMode(configinfo.StartMode); + renderer2d.SetViewMode((ViewMode)General.Settings.DefaultViewMode); + General.Settings.SetDefaultThingFlags(config.DefaultThingFlags); - //mxd - GZBuilder.GZGeneral.OnMapOpenEnd(); + // Center map in screen + if (General.Editing.Mode is ClassicMode) (General.Editing.Mode as ClassicMode).CenterInScreen(); - // Success - this.changed = false; - General.WriteLogLine("Map loading done"); - return true; - } - - #endregion + // Success + this.changed = false; + General.WriteLogLine("Map loading done"); + return true; + } - #region ================== Save + #endregion - /// - /// This exports the structures from memory into a WAD file with the current map format. - /// - public bool ExportToFile(string filepathname) - { - return SaveMap(filepathname, SavePurpose.Testing); - } + #region ================== Save - // Initializes for an existing map - internal bool SaveMap(string newfilepathname, SavePurpose purpose) - { - MapSet outputset; - string nodebuildername, settingsfile; - StatusInfo oldstatus; - WAD targetwad; - int index; - bool includenodes = false; - string origmapname; - bool success = true; - - General.WriteLogLine("Saving map to file: " + newfilepathname); - - // Scripts changed? - bool localscriptschanged = CheckScriptChanged(); - - // If the scripts window is open, save the scripts first - if(IsScriptsWindowOpen) scriptwindow.Editor.ImplicitSave(); - - // Only recompile scripts when the scripts have changed - // (not when only the map changed) - if(localscriptschanged) - { - if(!CompileScriptLumps()) - { - // Compiler failure - if(errors.Count > 0) - General.ShowErrorMessage("Error while compiling scripts: " + errors[0].description, MessageBoxButtons.OK); - else - General.ShowErrorMessage("Unknown compiler error while compiling scripts!", MessageBoxButtons.OK); - } - } + /// + /// This exports the structures from memory into a WAD file with the current map format. + /// + public bool ExportToFile(string filepathname) { + return SaveMap(filepathname, SavePurpose.Testing); + } - // Show script window if there are any errors and we are going to test the map - // and always update the errors on the scripts window. - if((errors.Count > 0) && (scriptwindow == null) && (purpose == SavePurpose.Testing)) ShowScriptEditor(); - if(scriptwindow != null) scriptwindow.Editor.ShowErrors(errors); - - // Only write the map and rebuild nodes when the actual map has changed - // (not when only scripts have changed) - if(changed) - { - // Make a copy of the map data - outputset = map.Clone(); + // Initializes for an existing map + internal bool SaveMap(string newfilepathname, SavePurpose purpose) { + MapSet outputset; + string nodebuildername, settingsfile; + StatusInfo oldstatus; + WAD targetwad; + int index; + bool includenodes = false; + string origmapname; + bool success = true; - // Remove all flags from all 3D Start things - foreach(Thing t in outputset.Things) - { - if(t.Type == config.Start3DModeThingType) - { - // We're not using SetFlag here, this doesn't have to be undone. - // Please note that this is totally exceptional! - List flagkeys = new List(t.Flags.Keys); - foreach(string k in flagkeys) t.Flags[k] = false; - } - } + General.WriteLogLine("Saving map to file: " + newfilepathname); - // Do we need sidedefs compression? - if(map.Sidedefs.Count > io.MaxSidedefs) - { - // Compress sidedefs - oldstatus = General.MainWindow.Status; - General.MainWindow.DisplayStatus(StatusType.Busy, "Compressing sidedefs..."); - outputset.CompressSidedefs(); - General.MainWindow.DisplayStatus(oldstatus); - - // Check if it still doesnt fit - if(outputset.Sidedefs.Count > io.MaxSidedefs) - { - // Problem! Can't save the map like this! - General.ShowErrorMessage("Unable to save the map: There are too many unique sidedefs!", MessageBoxButtons.OK); - return false; - } - } + // Scripts changed? + bool localscriptschanged = CheckScriptChanged(); - // Check things - if(map.Things.Count > io.MaxThings) - { - General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK); - return false; - } + // If the scripts window is open, save the scripts first + if (IsScriptsWindowOpen) scriptwindow.Editor.ImplicitSave(); - // Check sectors - if(map.Sectors.Count > io.MaxSectors) - { - General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK); - return false; - } + // Only recompile scripts when the scripts have changed + // (not when only the map changed) + if (localscriptschanged) { + if (!CompileScriptLumps()) { + // Compiler failure + if (errors.Count > 0) + General.ShowErrorMessage("Error while compiling scripts: " + errors[0].description, MessageBoxButtons.OK); + else + General.ShowErrorMessage("Unknown compiler error while compiling scripts!", MessageBoxButtons.OK); + } + } - // Check linedefs - if(map.Linedefs.Count > io.MaxLinedefs) - { - General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK); - return false; - } + // Show script window if there are any errors and we are going to test the map + // and always update the errors on the scripts window. + if ((errors.Count > 0) && (scriptwindow == null) && (purpose == SavePurpose.Testing)) ShowScriptEditor(); + if (scriptwindow != null) scriptwindow.Editor.ShowErrors(errors); - // Check vertices - if(map.Vertices.Count > io.MaxVertices) - { - General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK); - return false; - } - - // TODO: Check for more limitations - - // Write to temporary file - General.WriteLogLine("Writing map data structures to file..."); - index = tempwad.FindLumpIndex(TEMP_MAP_HEADER); - if(index == -1) index = 0; - io.Write(outputset, TEMP_MAP_HEADER, index); - outputset.Dispose(); - - // Get the corresponding nodebuilder - nodebuildername = (purpose == SavePurpose.Testing) ? configinfo.NodebuilderTest : configinfo.NodebuilderSave; + // Only write the map and rebuild nodes when the actual map has changed + // (not when only scripts have changed) + if (changed) { + // Make a copy of the map data + outputset = map.Clone(); - // Build the nodes - oldstatus = General.MainWindow.Status; - General.MainWindow.DisplayStatus(StatusType.Busy, "Building map nodes..."); - if(!string.IsNullOrEmpty(nodebuildername)) - includenodes = BuildNodes(nodebuildername, true); - else - includenodes = false; - General.MainWindow.DisplayStatus(oldstatus); - } - else - { - // Check if we have nodebuilder lumps - includenodes = VerifyNodebuilderLumps(tempwad, TEMP_MAP_HEADER); - } - - // Suspend data resources - data.Suspend(); + // Remove all flags from all 3D Start things + foreach (Thing t in outputset.Things) { + if (t.Type == config.Start3DModeThingType) { + // We're not using SetFlag here, this doesn't have to be undone. + // Please note that this is totally exceptional! + List flagkeys = new List(t.Flags.Keys); + foreach (string k in flagkeys) t.Flags[k] = false; + } + } - // Determine original map name - origmapname = (options.PreviousName != "") ? options.PreviousName : options.CurrentName; - - try - { - // Backup existing file, if any - if(File.Exists(newfilepathname)) - { - if(File.Exists(newfilepathname + ".backup3")) File.Delete(newfilepathname + ".backup3"); - if(File.Exists(newfilepathname + ".backup2")) File.Move(newfilepathname + ".backup2", newfilepathname + ".backup3"); - if(File.Exists(newfilepathname + ".backup1")) File.Move(newfilepathname + ".backup1", newfilepathname + ".backup2"); - File.Copy(newfilepathname, newfilepathname + ".backup1"); - } - - // Except when saving INTO another file, - // kill the target file if it is different from source file - if((purpose != SavePurpose.IntoFile) && (newfilepathname != filepathname)) - { - // Kill target file - if(File.Exists(newfilepathname)) File.Delete(newfilepathname); + // Do we need sidedefs compression? + if (map.Sidedefs.Count > io.MaxSidedefs) { + // Compress sidedefs + oldstatus = General.MainWindow.Status; + General.MainWindow.DisplayStatus(StatusType.Busy, "Compressing sidedefs..."); + outputset.CompressSidedefs(); + General.MainWindow.DisplayStatus(oldstatus); - // Kill .dbs settings file - settingsfile = newfilepathname.Substring(0, newfilepathname.Length - 4) + ".dbs"; - if(File.Exists(settingsfile)) File.Delete(settingsfile); - } + // Check if it still doesnt fit + if (outputset.Sidedefs.Count > io.MaxSidedefs) { + // Problem! Can't save the map like this! + General.ShowErrorMessage("Unable to save the map: There are too many unique sidedefs!", MessageBoxButtons.OK); + return false; + } + } - // On Save AS we have to copy the previous file to the new file - if((purpose == SavePurpose.AsNewFile) && (filepathname != "")) - { - // Copy if original file still exists - if(File.Exists(filepathname)) File.Copy(filepathname, newfilepathname, true); - } - - // If the target file exists, we need to rebuild it - if(File.Exists(newfilepathname)) - { - // Move the target file aside - string origwadfile = newfilepathname + ".temp"; - File.Move(newfilepathname, origwadfile); + // Check things + if (map.Things.Count > io.MaxThings) { + General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK); + return false; + } - // Open original file - WAD origwad = new WAD(origwadfile, true); - - // Create new target file - targetwad = new WAD(newfilepathname); + // Check sectors + if (map.Sectors.Count > io.MaxSectors) { + General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK); + return false; + } - // Copy all lumps, except the original map - CopyAllLumpsExceptMap(origwad, targetwad, origmapname); - - // Close original file and delete it - origwad.Dispose(); - File.Delete(origwadfile); - } - else - { - // Create new target file - targetwad = new WAD(newfilepathname); - } - } - catch(IOException) - { - General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); - data.Resume(); - General.WriteLogLine("Map saving failed"); - return false; - } - catch(UnauthorizedAccessException) - { - General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); - data.Resume(); - General.WriteLogLine("Map saving failed"); - return false; - } - - // Copy map lumps to target file - CopyLumpsByType(tempwad, TEMP_MAP_HEADER, targetwad, origmapname, true, true, includenodes, true); + // Check linedefs + if (map.Linedefs.Count > io.MaxLinedefs) { + General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK); + return false; + } - // Was the map lump name renamed? - if((options.PreviousName != options.CurrentName) && - (options.PreviousName != "")) - { - General.WriteLogLine("Renaming map lump name from " + options.PreviousName + " to " + options.CurrentName); - - // Find the map header in target - index = targetwad.FindLumpIndex(options.PreviousName); - if(index > -1) - { - // Rename the map lump name - targetwad.Lumps[index].Rename(options.CurrentName); - options.PreviousName = ""; - } - else - { - // Houston, we've got a problem! - General.ShowErrorMessage("Error renaming map lump name: the original map lump could not be found!", MessageBoxButtons.OK); - options.CurrentName = options.PreviousName; - options.PreviousName = ""; - } - } + // Check vertices + if (map.Vertices.Count > io.MaxVertices) { + General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK); + return false; + } - // Done with the target file - targetwad.Dispose(); + // TODO: Check for more limitations - // Resume data resources - data.Resume(); - - // Not saved for testing purpose? - if(purpose != SavePurpose.Testing) - { - // Saved in a different file? - if(newfilepathname != filepathname) - { - // Keep new filename - filepathname = newfilepathname; - filetitle = Path.GetFileName(filepathname); + // Write to temporary file + General.WriteLogLine("Writing map data structures to file..."); + index = tempwad.FindLumpIndex(TEMP_MAP_HEADER); + if (index == -1) index = 0; + io.Write(outputset, TEMP_MAP_HEADER, index); + outputset.Dispose(); - // Reload resources - ReloadResources(); - } + // Get the corresponding nodebuilder + nodebuildername = (purpose == SavePurpose.Testing) ? configinfo.NodebuilderTest : configinfo.NodebuilderSave; - try - { - // Open or create the map settings - settingsfile = newfilepathname.Substring(0, newfilepathname.Length - 4) + ".dbs"; - options.WriteConfiguration(settingsfile); - } - catch(Exception e) - { - // Warning only - General.ErrorLogger.Add(ErrorType.Warning, "Could not write the map settings configuration file. " + e.GetType().Name + ": " + e.Message); - } - - // Changes saved - changed = false; - scriptschanged = false; - } - - // Success! - General.WriteLogLine("Map saving done"); - return success; - } - - #endregion + // Build the nodes + oldstatus = General.MainWindow.Status; + General.MainWindow.DisplayStatus(StatusType.Busy, "Building map nodes..."); + if (!string.IsNullOrEmpty(nodebuildername)) + includenodes = BuildNodes(nodebuildername, true); + else + includenodes = false; + General.MainWindow.DisplayStatus(oldstatus); + } + else { + // Check if we have nodebuilder lumps + includenodes = VerifyNodebuilderLumps(tempwad, TEMP_MAP_HEADER); + } - #region ================== Nodebuild + // Suspend data resources + data.Suspend(); - // This builds the nodes in the temproary file with the given configuration name - private bool BuildNodes(string nodebuildername, bool failaswarning) - { - NodebuilderInfo nodebuilder; - string tempfile1, tempfile2, sourcefile; - bool lumpscomplete = false; - WAD buildwad; + // Determine original map name + origmapname = (options.PreviousName != "") ? options.PreviousName : options.CurrentName; - // Find the nodebuilder - nodebuilder = General.GetNodebuilderByName(nodebuildername); - if(nodebuilder == null) - { - // Problem! Can't find that nodebuilder! - General.ShowWarningMessage("Unable to build the nodes: The configured nodebuilder cannot be found.\nPlease check your game configuration settings!", MessageBoxButtons.OK); - return false; - } - else - { - // Create the compiler interface that will run the nodebuilder - // This automatically creates a temporary directory for us - Compiler compiler = nodebuilder.CreateCompiler(); - - // Make temporary filename - tempfile1 = General.MakeTempFilename(compiler.Location); + try { + // Backup existing file, if any + if (File.Exists(newfilepathname)) { + if (File.Exists(newfilepathname + ".backup3")) File.Delete(newfilepathname + ".backup3"); + if (File.Exists(newfilepathname + ".backup2")) File.Move(newfilepathname + ".backup2", newfilepathname + ".backup3"); + if (File.Exists(newfilepathname + ".backup1")) File.Move(newfilepathname + ".backup1", newfilepathname + ".backup2"); + File.Copy(newfilepathname, newfilepathname + ".backup1"); + } - // Make the temporary WAD file - General.WriteLogLine("Creating temporary build file: " + tempfile1); - #if DEBUG - buildwad = new WAD(tempfile1); - #else + // Except when saving INTO another file, + // kill the target file if it is different from source file + if ((purpose != SavePurpose.IntoFile) && (newfilepathname != filepathname)) { + // Kill target file + if (File.Exists(newfilepathname)) File.Delete(newfilepathname); + + // Kill .dbs settings file + settingsfile = newfilepathname.Substring(0, newfilepathname.Length - 4) + ".dbs"; + if (File.Exists(settingsfile)) File.Delete(settingsfile); + } + + // On Save AS we have to copy the previous file to the new file + if ((purpose == SavePurpose.AsNewFile) && (filepathname != "")) { + // Copy if original file still exists + if (File.Exists(filepathname)) File.Copy(filepathname, newfilepathname, true); + } + + // If the target file exists, we need to rebuild it + if (File.Exists(newfilepathname)) { + // Move the target file aside + string origwadfile = newfilepathname + ".temp"; + File.Move(newfilepathname, origwadfile); + + // Open original file + WAD origwad = new WAD(origwadfile, true); + + // Create new target file + targetwad = new WAD(newfilepathname); + + // Copy all lumps, except the original map + CopyAllLumpsExceptMap(origwad, targetwad, origmapname); + + // Close original file and delete it + origwad.Dispose(); + File.Delete(origwadfile); + } + else { + // Create new target file + targetwad = new WAD(newfilepathname); + } + } catch (IOException) { + General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); + data.Resume(); + General.WriteLogLine("Map saving failed"); + return false; + } catch (UnauthorizedAccessException) { + General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); + data.Resume(); + General.WriteLogLine("Map saving failed"); + return false; + } + + // Copy map lumps to target file + CopyLumpsByType(tempwad, TEMP_MAP_HEADER, targetwad, origmapname, true, true, includenodes, true); + + // Was the map lump name renamed? + if ((options.PreviousName != options.CurrentName) && + (options.PreviousName != "")) { + General.WriteLogLine("Renaming map lump name from " + options.PreviousName + " to " + options.CurrentName); + + // Find the map header in target + index = targetwad.FindLumpIndex(options.PreviousName); + if (index > -1) { + // Rename the map lump name + targetwad.Lumps[index].Rename(options.CurrentName); + options.PreviousName = ""; + } + else { + // Houston, we've got a problem! + General.ShowErrorMessage("Error renaming map lump name: the original map lump could not be found!", MessageBoxButtons.OK); + options.CurrentName = options.PreviousName; + options.PreviousName = ""; + } + } + + // Done with the target file + targetwad.Dispose(); + + // Resume data resources + data.Resume(); + + // Not saved for testing purpose? + if (purpose != SavePurpose.Testing) { + // Saved in a different file? + if (newfilepathname != filepathname) { + // Keep new filename + filepathname = newfilepathname; + filetitle = Path.GetFileName(filepathname); + + // Reload resources + ReloadResources(); + } + + try { + // Open or create the map settings + settingsfile = newfilepathname.Substring(0, newfilepathname.Length - 4) + ".dbs"; + options.WriteConfiguration(settingsfile); + } catch (Exception e) { + // Warning only + General.ErrorLogger.Add(ErrorType.Warning, "Could not write the map settings configuration file. " + e.GetType().Name + ": " + e.Message); + } + + // Changes saved + changed = false; + scriptschanged = false; + } + + // Success! + General.WriteLogLine("Map saving done"); + return success; + } + + #endregion + + #region ================== Nodebuild + + // This builds the nodes in the temproary file with the given configuration name + private bool BuildNodes(string nodebuildername, bool failaswarning) { + NodebuilderInfo nodebuilder; + string tempfile1, tempfile2, sourcefile; + bool lumpscomplete = false; + WAD buildwad; + + // Find the nodebuilder + nodebuilder = General.GetNodebuilderByName(nodebuildername); + if (nodebuilder == null) { + // Problem! Can't find that nodebuilder! + General.ShowWarningMessage("Unable to build the nodes: The configured nodebuilder cannot be found.\nPlease check your game configuration settings!", MessageBoxButtons.OK); + return false; + } + else { + // Create the compiler interface that will run the nodebuilder + // This automatically creates a temporary directory for us + Compiler compiler = nodebuilder.CreateCompiler(); + + // Make temporary filename + tempfile1 = General.MakeTempFilename(compiler.Location); + + // Make the temporary WAD file + General.WriteLogLine("Creating temporary build file: " + tempfile1); +#if DEBUG + buildwad = new WAD(tempfile1); +#else try { buildwad = new WAD(tempfile1); } catch(Exception e) { General.ShowErrorMessage("Error while creating a temporary wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK); return false; } - #endif - - // Determine source file - if(filepathname.Length > 0) - sourcefile = filepathname; - else - sourcefile = tempwad.Filename; +#endif - // Copy lumps to buildwad - General.WriteLogLine("Copying map lumps to temporary build file..."); - CopyLumpsByType(tempwad, TEMP_MAP_HEADER, buildwad, BUILD_MAP_HEADER, true, false, false, true); - - // Close buildwad - buildwad.Dispose(); - - // Does the nodebuilder require an output file? - if(nodebuilder.HasSpecialOutputFile) - { - // Make a temporary output file for the nodebuilder - tempfile2 = General.MakeTempFilename(compiler.Location); - General.WriteLogLine("Temporary output file: " + tempfile2); - } - else - { - // Output file is same as input file - tempfile2 = tempfile1; - } - - // Run the nodebuilder - compiler.Parameters = nodebuilder.Parameters; - compiler.InputFile = Path.GetFileName(tempfile1); - compiler.OutputFile = Path.GetFileName(tempfile2); - compiler.SourceFile = sourcefile; - compiler.WorkingDirectory = Path.GetDirectoryName(tempfile1); - if(compiler.Run()) - { - // Open the output file - try { buildwad = new WAD(tempfile2); } - catch(Exception e) - { - General.WriteLogLine(e.GetType().Name + " while reading build wad file: " + e.Message); - buildwad = null; - } - - if(buildwad != null) - { - // Output lumps complete? - lumpscomplete = VerifyNodebuilderLumps(buildwad, BUILD_MAP_HEADER); - } - - if(lumpscomplete) - { - // Copy nodebuilder lumps to temp file - General.WriteLogLine("Copying nodebuilder lumps to temporary file..."); - CopyLumpsByType(buildwad, BUILD_MAP_HEADER, tempwad, TEMP_MAP_HEADER, false, false, true, false); - } - else - { - // Nodebuilder did not build the lumps! - if(failaswarning) - General.ShowWarningMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures.\nThe map will be saved without the nodes.", MessageBoxButtons.OK); - else - General.ShowErrorMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures.", MessageBoxButtons.OK); - } - - // Done with the build wad - if(buildwad != null) buildwad.Dispose(); - } - - // Clean up - compiler.Dispose(); - - // Return result - return lumpscomplete; - } - } + // Determine source file + if (filepathname.Length > 0) + sourcefile = filepathname; + else + sourcefile = tempwad.Filename; - // This verifies if the nodebuilder lumps exist in a WAD file - private bool VerifyNodebuilderLumps(WAD wad, string mapheader) - { - bool lumpscomplete = false; - - // Find the map header in source - int srcindex = wad.FindLumpIndex(mapheader); - if(srcindex > -1) - { - // Go for all the map lump names - lumpscomplete = true; - foreach(DictionaryEntry ml in config.MapLumpNames) - { - // Read lump settings from map config - bool lumpnodebuild = config.ReadSetting("maplumpnames." + ml.Key + ".nodebuild", false); - bool lumpallowempty = config.ReadSetting("maplumpnames." + ml.Key + ".allowempty", false); + // Copy lumps to buildwad + General.WriteLogLine("Copying map lumps to temporary build file..."); + CopyLumpsByType(tempwad, TEMP_MAP_HEADER, buildwad, BUILD_MAP_HEADER, true, false, false, true); - // Check if this lump should exist - if(lumpnodebuild && !lumpallowempty) - { - // Find the lump in the source - if(wad.FindLump(ml.Key.ToString(), srcindex, srcindex + config.MapLumpNames.Count + 2) == null) - { - // Missing a lump! - lumpscomplete = false; - break; - } - } - } - } + // Close buildwad + buildwad.Dispose(); - return lumpscomplete; - } - - #endregion + // Does the nodebuilder require an output file? + if (nodebuilder.HasSpecialOutputFile) { + // Make a temporary output file for the nodebuilder + tempfile2 = General.MakeTempFilename(compiler.Location); + General.WriteLogLine("Temporary output file: " + tempfile2); + } + else { + // Output file is same as input file + tempfile2 = tempfile1; + } - #region ================== Lumps - - // This returns a copy of the requested lump stream data - // This is copied from the temp wad file and returns null when the lump is not found - public MemoryStream GetLumpData(string lumpname) - { - Lump l = tempwad.FindLump(lumpname); - if(l != null) - { - l.Stream.Seek(0, SeekOrigin.Begin); - return new MemoryStream(l.Stream.ReadAllBytes()); - } - else - { - return null; - } - } - - // This writes a copy of the data to a lump in the temp file - public void SetLumpData(string lumpname, MemoryStream data) - { - int insertindex = tempwad.Lumps.Count; - - // Remove the lump if it already exists - int li = tempwad.FindLumpIndex(lumpname); - if(li > -1) - { - insertindex = li; - tempwad.RemoveAt(li); - } - - // Insert new lump - Lump l = tempwad.Insert(lumpname, insertindex, (int)data.Length); - l.Stream.Seek(0, SeekOrigin.Begin); - data.WriteTo(l.Stream); - } - - // This checks if the specified lump exists in the temp file - public bool LumpExists(string lumpname) - { - return (tempwad.FindLumpIndex(lumpname) > -1); - } - - // This creates empty lumps for those required - private void CreateRequiredLumps(WAD target, string mapname) - { - int headerindex, insertindex, targetindex; - string lumpname; - bool lumprequired; - - // Find the map header in target - headerindex = target.FindLumpIndex(mapname); - if(headerindex == -1) - { - // If this header doesnt exists in the target - // then insert at the end of the target - headerindex = target.Lumps.Count; - } + // Run the nodebuilder + compiler.Parameters = nodebuilder.Parameters; + compiler.InputFile = Path.GetFileName(tempfile1); + compiler.OutputFile = Path.GetFileName(tempfile2); + compiler.SourceFile = sourcefile; + compiler.WorkingDirectory = Path.GetDirectoryName(tempfile1); + if (compiler.Run()) { + // Open the output file + try { buildwad = new WAD(tempfile2); } catch (Exception e) { + General.WriteLogLine(e.GetType().Name + " while reading build wad file: " + e.Message); + buildwad = null; + } - // Begin inserting at target header index - insertindex = headerindex; + if (buildwad != null) { + // Output lumps complete? + lumpscomplete = VerifyNodebuilderLumps(buildwad, BUILD_MAP_HEADER); + } - // Go for all the map lump names - foreach(DictionaryEntry ml in config.MapLumpNames) - { - // Read lump settings from map config - lumprequired = config.ReadSetting("maplumpnames." + ml.Key + ".required", false); + if (lumpscomplete) { + // Copy nodebuilder lumps to temp file + General.WriteLogLine("Copying nodebuilder lumps to temporary file..."); + CopyLumpsByType(buildwad, BUILD_MAP_HEADER, tempwad, TEMP_MAP_HEADER, false, false, true, false); + } + else { + //mxd. collect errors + string errors = ""; + foreach (CompilerError e in compiler.Errors) + errors += "Error: " + Environment.NewLine + e.description; - // Check if this lump is required - if(lumprequired) - { - // Get the lump name - lumpname = ml.Key.ToString(); - if(lumpname == CONFIG_MAP_HEADER) lumpname = mapname; + // Nodebuilder did not build the lumps! + if (failaswarning) + General.ShowWarningMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures.\nThe map will be saved without the nodes." + (compiler.Errors.Length > 0 ? Environment.NewLine + errors : ""), MessageBoxButtons.OK); + else + General.ShowErrorMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures." + (compiler.Errors.Length > 0 ? Environment.NewLine + errors : ""), MessageBoxButtons.OK); + } - // Check if the lump is missing at the target - targetindex = FindSpecificLump(target, lumpname, headerindex, mapname, config.MapLumpNames); - if(targetindex == -1) - { - // Determine target index - insertindex++; - if(insertindex > target.Lumps.Count) insertindex = target.Lumps.Count; + // Done with the build wad + if (buildwad != null) buildwad.Dispose(); + } + else { //mxd + //collect errors + string errors = ""; + foreach (CompilerError e in compiler.Errors) + errors += "Error: " + Environment.NewLine + e.description; - // Create new, emtpy lump - General.WriteLogLine(lumpname + " is required! Created empty lump."); - target.Insert(lumpname, insertindex, 0); - } - else - { - // Move insert index - insertindex = targetindex; - } - } - } - } - - // This copies all lumps, except those of a specific map - private void CopyAllLumpsExceptMap(WAD source, WAD target, string sourcemapname) - { - // Go for all lumps - bool skipping = false; - foreach(Lump srclump in source.Lumps) - { - // Check if we should stop skipping lumps here - if(skipping && !config.MapLumpNames.Contains(srclump.Name)) - { - // Stop skipping - skipping = false; - } - - // Check if we should start skipping lumps here - if(!skipping && (srclump.Name == sourcemapname)) - { - // We have encountered the map header, start skipping! - skipping = true; - } + // Nodebuilder did not build the lumps! + General.ShowErrorMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures" + (compiler.Errors.Length > 0 ? ":" + Environment.NewLine + errors : "."), MessageBoxButtons.OK); + } - // Not skipping this lump? - if(!skipping) - { - // Copy lump over! - Lump tgtlump = target.Insert(srclump.Name, target.Lumps.Count, srclump.Length); - srclump.CopyTo(tgtlump); - } - } - } - - // This copies specific map lumps from one WAD to another - private void CopyLumpsByType(WAD source, string sourcemapname, - WAD target, string targetmapname, - bool copyrequired, bool copyblindcopy, - bool copynodebuild, bool copyscript) - { - bool lumprequired, lumpblindcopy, lumpnodebuild; - string lumpscript, srclumpname, tgtlumpname; - int srcheaderindex, tgtheaderindex, targetindex, sourceindex, lumpindex; - Lump lump, newlump; - - // Find the map header in target - tgtheaderindex = target.FindLumpIndex(targetmapname); - if(tgtheaderindex == -1) - { - // If this header doesnt exists in the target - // then insert at the end of the target - tgtheaderindex = target.Lumps.Count; - } + // Clean up + compiler.Dispose(); - // Begin inserting at target header index - targetindex = tgtheaderindex; - - // Find the map header in source - srcheaderindex = source.FindLumpIndex(sourcemapname); - if(srcheaderindex > -1) - { - // Copy the map header from source to target - //newlump = target.Insert(targetmapname, tgtindex++, source.Lumps[srcindex].Length); - //source.Lumps[srcindex].CopyTo(newlump); - - // Go for all the map lump names - foreach(DictionaryEntry ml in config.MapLumpNames) - { - // Read lump settings from map config - lumprequired = config.ReadSetting("maplumpnames." + ml.Key + ".required", false); - lumpblindcopy = config.ReadSetting("maplumpnames." + ml.Key + ".blindcopy", false); - lumpnodebuild = config.ReadSetting("maplumpnames." + ml.Key + ".nodebuild", false); - lumpscript = config.ReadSetting("maplumpnames." + ml.Key + ".script", ""); + // Return result + return lumpscomplete; + } + } - // Check if this lump should be copied - if((lumprequired && copyrequired) || (lumpblindcopy && copyblindcopy) || - (lumpnodebuild && copynodebuild) || ((lumpscript.Length != 0) && copyscript)) - { - // Get the lump name - srclumpname = ml.Key.ToString(); - tgtlumpname = ml.Key.ToString(); - if(srclumpname == CONFIG_MAP_HEADER) srclumpname = sourcemapname; - if(tgtlumpname == CONFIG_MAP_HEADER) tgtlumpname = targetmapname; - - // Find the lump in the source - sourceindex = FindSpecificLump(source, srclumpname, srcheaderindex, sourcemapname, config.MapLumpNames); - if(sourceindex > -1) - { - // Remove lump at target - lumpindex = RemoveSpecificLump(target, tgtlumpname, tgtheaderindex, targetmapname, config.MapLumpNames); + // This verifies if the nodebuilder lumps exist in a WAD file + private bool VerifyNodebuilderLumps(WAD wad, string mapheader) { + bool lumpscomplete = false; - // Determine target index - // When original lump was found and removed then insert at that position - // otherwise insert after last insertion position - if(lumpindex > -1) targetindex = lumpindex; else targetindex++; - if(targetindex > target.Lumps.Count) targetindex = target.Lumps.Count; - - // Copy the lump to the target - //General.WriteLogLine(srclumpname + " copying as " + tgtlumpname); - lump = source.Lumps[sourceindex]; - newlump = target.Insert(tgtlumpname, targetindex, lump.Length); - lump.CopyTo(newlump); - } - else - { - // We don't want to bother the user with this. There are a lot of lumps in - // the game configs that are trivial and don't need to be found. - if(lumprequired) - { - General.ErrorLogger.Add(ErrorType.Warning, ml.Key.ToString() + " (required lump) should be read but was not found in the WAD file."); - } - } - } - } - } - } - - // This finds a lump within the range of known lump names - // Returns -1 when the lump cannot be found - internal static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, IDictionary maplumps) - { - // Use the configured map lump names to find the specific lump within range, - // because when an unknown lump is met, this search must stop. + // Find the map header in source + int srcindex = wad.FindLumpIndex(mapheader); + if (srcindex > -1) { + // Go for all the map lump names + lumpscomplete = true; + foreach (DictionaryEntry ml in config.MapLumpNames) { + // Read lump settings from map config + bool lumpnodebuild = config.ReadSetting("maplumpnames." + ml.Key + ".nodebuild", false); + bool lumpallowempty = config.ReadSetting("maplumpnames." + ml.Key + ".allowempty", false); - // Go for all lumps in order to find the specified lump - for(int i = 0; i < maplumps.Count + 1; i++) - { - // Still within bounds? - if((mapheaderindex + i) < source.Lumps.Count) - { - // Check if this is a known lump name - if(maplumps.Contains(source.Lumps[mapheaderindex + i].Name) || - (maplumps.Contains(CONFIG_MAP_HEADER) && (source.Lumps[mapheaderindex + i].Name == mapheadername))) - { - // Is this the lump we are looking for? - if(source.Lumps[mapheaderindex + i].Name == lumpname) - { - // Return this index - return mapheaderindex + i; - } - } - else - { - // Unknown lump hit, abort search - break; - } - } - } - - // Nothing found - return -1; - } - - // This removes a specific lump and returns the position where the lump was removed - // Returns -1 when the lump could not be found - internal static int RemoveSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, IDictionary maplumps) - { - int lumpindex; - - // Find the specific lump index - lumpindex = FindSpecificLump(source, lumpname, mapheaderindex, mapheadername, maplumps); - if(lumpindex > -1) - { - // Remove this lump - //General.WriteLogLine(lumpname + " removed"); - source.RemoveAt(lumpindex); - } - else - { - // Lump not found - //General.ErrorLogger.Add(ErrorType.Warning, lumpname + " should be removed but was not found!"); - } - - // Return result - return lumpindex; - } - - #endregion + // Check if this lump should exist + if (lumpnodebuild && !lumpallowempty) { + // Find the lump in the source + if (wad.FindLump(ml.Key.ToString(), srcindex, srcindex + config.MapLumpNames.Count + 2) == null) { + // Missing a lump! + lumpscomplete = false; + break; + } + } + } + } - #region ================== Selection Groups - - // This adds selection to a group - private void AddSelectionToGroup(int groupindex) - { - General.Interface.SetCursor(Cursors.WaitCursor); - - // Make undo - undoredo.CreateUndo("Assign to group " + groupindex); - - // Make selection - map.AddSelectionToGroup(0x01 << groupindex); - - General.Interface.DisplayStatus(StatusType.Action, "Assigned selection to group " + groupindex); - General.Interface.SetCursor(Cursors.Default); - } - - // This selects a group - private void SelectGroup(int groupindex) - { - // Select - int groupmask = 0x01 << groupindex; - map.SelectVerticesByGroup(groupmask); - map.SelectLinedefsByGroup(groupmask); - map.SelectSectorsByGroup(groupmask); - map.SelectThingsByGroup(groupmask); - - // Redraw to show selection - General.Interface.DisplayStatus(StatusType.Action, "Selected group " + groupindex); - General.Interface.RedrawDisplay(); - } - - // Select actions - [BeginAction("selectgroup1")] internal void SelectGroup1() { SelectGroup(0); } - [BeginAction("selectgroup2")] internal void SelectGroup2() { SelectGroup(1); } - [BeginAction("selectgroup3")] internal void SelectGroup3() { SelectGroup(2); } - [BeginAction("selectgroup4")] internal void SelectGroup4() { SelectGroup(3); } - [BeginAction("selectgroup5")] internal void SelectGroup5() { SelectGroup(4); } - [BeginAction("selectgroup6")] internal void SelectGroup6() { SelectGroup(5); } - [BeginAction("selectgroup7")] internal void SelectGroup7() { SelectGroup(6); } - [BeginAction("selectgroup8")] internal void SelectGroup8() { SelectGroup(7); } - [BeginAction("selectgroup9")] internal void SelectGroup9() { SelectGroup(8); } - [BeginAction("selectgroup10")] internal void SelectGroup10() { SelectGroup(9); } - - // Assign actions - [BeginAction("assigngroup1")] internal void AssignGroup1() { AddSelectionToGroup(0); } - [BeginAction("assigngroup2")] internal void AssignGroup2() { AddSelectionToGroup(1); } - [BeginAction("assigngroup3")] internal void AssignGroup3() { AddSelectionToGroup(2); } - [BeginAction("assigngroup4")] internal void AssignGroup4() { AddSelectionToGroup(3); } - [BeginAction("assigngroup5")] internal void AssignGroup5() { AddSelectionToGroup(4); } - [BeginAction("assigngroup6")] internal void AssignGroup6() { AddSelectionToGroup(5); } - [BeginAction("assigngroup7")] internal void AssignGroup7() { AddSelectionToGroup(6); } - [BeginAction("assigngroup8")] internal void AssignGroup8() { AddSelectionToGroup(7); } - [BeginAction("assigngroup9")] internal void AssignGroup9() { AddSelectionToGroup(8); } - [BeginAction("assigngroup10")] internal void AssignGroup10() { AddSelectionToGroup(9); } - - #endregion - - #region ================== Script Editing - - // Show the script editor - [BeginAction("openscripteditor")] - internal void ShowScriptEditor() - { - Cursor.Current = Cursors.WaitCursor; - - if(scriptwindow == null) - { - // Load the window - scriptwindow = new ScriptEditorForm(); - } - - // Window not yet visible? - if(!scriptwindow.Visible) - { - // Show the window - if(General.Settings.ScriptOnTop) - { - if(scriptwindow.Visible && (scriptwindow.Owner == null)) scriptwindow.Hide(); - scriptwindow.Show(General.MainWindow); - } - else - { - if(scriptwindow.Visible && (scriptwindow.Owner != null)) scriptwindow.Hide(); - scriptwindow.Show(); - } - } - scriptwindow.Activate(); - scriptwindow.Focus(); - Cursor.Current = Cursors.Default; - } - - // This asks the user to save changes in script files - // Returns false when cancelled by the user - internal bool AskSaveScriptChanges() - { - // Window open? - if(scriptwindow != null) - { - // Ask to save changes - // This also saves implicitly - return scriptwindow.AskSaveAll(); - } - else - { - // No problems - return true; - } - } + return lumpscomplete; + } - // This applies the changed status for internal scripts - internal void ApplyScriptChanged() - { - // Remember if lumps are changed - scriptschanged |= scriptwindow.Editor.CheckImplicitChanges(); - } - - // Close the script editor - // Specify true for the closing parameter when - // the window is already in the closing process - internal void CloseScriptEditor(bool closing) - { - if(scriptwindow != null) - { - if(!scriptwindow.IsDisposed) - { - // Remember what files were open - scriptwindow.Editor.WriteOpenFilesToConfiguration(); - - // Close now - if(!closing) scriptwindow.Close(); - } - - // Done - scriptwindow = null; - } - } - - // This checks if the scripts are changed - internal bool CheckScriptChanged() - { - if(scriptwindow != null) - { - // Check if scripts are changed - return scriptschanged || scriptwindow.Editor.CheckImplicitChanges(); - } - else - { - // Check if scripts are changed - return scriptschanged; - } - } + #endregion - // This compiles all lumps that require compiling and stores the results - // Returns true when our code worked properly (even when the compiler returned errors) - private bool CompileScriptLumps() - { - bool success = true; - errors.Clear(); - - // Go for all the map lumps - foreach(MapLumpInfo lumpinfo in config.MapLumps.Values) - { - // Is this a script lump? - if(lumpinfo.script != null) - { - // Compile it now - success &= CompileLump(lumpinfo.name, false); - } - } - return success; - } - - // This compiles a script lump and returns any errors that may have occurred - // Returns true when our code worked properly (even when the compiler returned errors) - internal bool CompileLump(string lumpname, bool clearerrors) - { - string inputfile, outputfile, sourcefile; - Compiler compiler; - byte[] filedata; - string reallumpname = lumpname; - - // Find the lump - if(lumpname == CONFIG_MAP_HEADER) reallumpname = TEMP_MAP_HEADER; - Lump lump = tempwad.FindLump(reallumpname); - if(lump == null) throw new Exception("No such lump in temporary wad file '" + reallumpname + "'."); - - // Determine source file - if(filepathname.Length > 0) - sourcefile = filepathname; - else - sourcefile = tempwad.Filename; - - // New list of errors - if(clearerrors) errors.Clear(); - - // Determine the script configuration to use - ScriptConfiguration scriptconfig = config.MapLumps[lumpname].script; - if(scriptconfig.Compiler != null) - { - try - { - // Initialize compiler - compiler = scriptconfig.Compiler.Create(); - } - catch(Exception e) - { - // Fail - errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message)); - return false; - } + #region ================== Lumps - try - { - // Write lump data to temp script file in compiler's temp directory - inputfile = General.MakeTempFilename(compiler.Location, "tmp"); - lump.Stream.Seek(0, SeekOrigin.Begin); - BinaryReader reader = new BinaryReader(lump.Stream); - File.WriteAllBytes(inputfile, reader.ReadBytes((int)lump.Stream.Length)); - } - catch(Exception e) - { - // Fail - compiler.Dispose(); - errors.Add(new CompilerError("Unable to write script to working file. " + e.GetType().Name + ": " + e.Message)); - return false; - } - - // Make random output filename - outputfile = General.MakeTempFilename(compiler.Location, "tmp"); - - // Run compiler - compiler.Parameters = scriptconfig.Parameters; - compiler.InputFile = Path.GetFileName(inputfile); - compiler.OutputFile = Path.GetFileName(outputfile); - compiler.SourceFile = sourcefile; - compiler.WorkingDirectory = Path.GetDirectoryName(inputfile); - if(compiler.Run()) - { - // Process errors - foreach(CompilerError e in compiler.Errors) - { - CompilerError newerror = e; + // This returns a copy of the requested lump stream data + // This is copied from the temp wad file and returns null when the lump is not found + public MemoryStream GetLumpData(string lumpname) { + Lump l = tempwad.FindLump(lumpname); + if (l != null) { + l.Stream.Seek(0, SeekOrigin.Begin); + return new MemoryStream(l.Stream.ReadAllBytes()); + } + else { + return null; + } + } - // If the error's filename equals our temporary file, - // use the lump name instead and prefix it with ? - if(string.Compare(e.filename, inputfile, true) == 0) - newerror.filename = "?" + reallumpname; + // This writes a copy of the data to a lump in the temp file + public void SetLumpData(string lumpname, MemoryStream data) { + int insertindex = tempwad.Lumps.Count; - errors.Add(newerror); - } + // Remove the lump if it already exists + int li = tempwad.FindLumpIndex(lumpname); + if (li > -1) { + insertindex = li; + tempwad.RemoveAt(li); + } - // No errors? - if(compiler.Errors.Length == 0) - { - // Output file exists? - if(File.Exists(outputfile)) - { - // Copy output file data into a lump? - if(!string.IsNullOrEmpty(scriptconfig.ResultLump)) - { - // Do that now then - try - { - filedata = File.ReadAllBytes(outputfile); - } - catch(Exception e) - { - // Fail - compiler.Dispose(); - errors.Add(new CompilerError("Unable to read compiler output file. " + e.GetType().Name + ": " + e.Message)); - return false; - } + // Insert new lump + Lump l = tempwad.Insert(lumpname, insertindex, (int)data.Length); + l.Stream.Seek(0, SeekOrigin.Begin); + data.WriteTo(l.Stream); + } - // Store data - MemoryStream stream = new MemoryStream(filedata); - SetLumpData(scriptconfig.ResultLump, stream); - } - } - } + // This checks if the specified lump exists in the temp file + public bool LumpExists(string lumpname) { + return (tempwad.FindLumpIndex(lumpname) > -1); + } - // Clean up - compiler.Dispose(); - - // Done - return true; - } - else - { - // Fail - compiler.Dispose(); - errors = null; - return false; - } - } - else - { - // No compiler to run for this script type - return true; - } - } - - // This clears all compiler errors - internal void ClearCompilerErrors() - { - errors.Clear(); - } - - #endregion - - #region ================== Methods + // This creates empty lumps for those required + private void CreateRequiredLumps(WAD target, string mapname) { + int headerindex, insertindex, targetindex; + string lumpname; + bool lumprequired; - // This updates everything after the configuration or settings have been changed - internal void UpdateConfiguration() - { - // Update map - map.UpdateConfiguration(); + // Find the map header in target + headerindex = target.FindLumpIndex(mapname); + if (headerindex == -1) { + // If this header doesnt exists in the target + // then insert at the end of the target + headerindex = target.Lumps.Count; + } - // Update settings - renderer3d.CreateProjection(); + // Begin inserting at target header index + insertindex = headerindex; - // Things filters - General.MainWindow.UpdateThingsFilters(); - } - - // This changes thing filter - public void ChangeThingFilter(ThingsFilter newfilter) - { - // We have a special filter for null - if(newfilter == null) newfilter = new NullThingsFilter(); - - // Deactivate old filter - if(thingsfilter != null) thingsfilter.Deactivate(); + // Go for all the map lump names + foreach (DictionaryEntry ml in config.MapLumpNames) { + // Read lump settings from map config + lumprequired = config.ReadSetting("maplumpnames." + ml.Key + ".required", false); - // Change - thingsfilter = newfilter; + // Check if this lump is required + if (lumprequired) { + // Get the lump name + lumpname = ml.Key.ToString(); + if (lumpname == CONFIG_MAP_HEADER) lumpname = mapname; - // Activate filter - thingsfilter.Activate(); + // Check if the lump is missing at the target + targetindex = FindSpecificLump(target, lumpname, headerindex, mapname, config.MapLumpNames); + if (targetindex == -1) { + // Determine target index + insertindex++; + if (insertindex > target.Lumps.Count) insertindex = target.Lumps.Count; - // Update interface - General.MainWindow.ReflectThingsFilter(); + // Create new, emtpy lump + General.WriteLogLine(lumpname + " is required! Created empty lump."); + target.Insert(lumpname, insertindex, 0); + } + else { + // Move insert index + insertindex = targetindex; + } + } + } + } - // Redraw - General.MainWindow.RedrawDisplay(); - } - - // This sets a new mapset for editing - internal void ChangeMapSet(MapSet newmap) - { - // Let the plugin and editing mode know - General.Plugins.OnMapSetChangeBegin(); - if(General.Editing.Mode != null) General.Editing.Mode.OnMapSetChangeBegin(); - this.visualcamera.Sector = null; + // This copies all lumps, except those of a specific map + private void CopyAllLumpsExceptMap(WAD source, WAD target, string sourcemapname) { + // Go for all lumps + bool skipping = false; + foreach (Lump srclump in source.Lumps) { + // Check if we should stop skipping lumps here + if (skipping && !config.MapLumpNames.Contains(srclump.Name)) { + // Stop skipping + skipping = false; + } - // Can't have a selection in an old map set - map.ClearAllSelected(); + // Check if we should start skipping lumps here + if (!skipping && (srclump.Name == sourcemapname)) { + // We have encountered the map header, start skipping! + skipping = true; + } - // Reset surfaces - renderer2d.Surfaces.Reset(); - - // Apply - map.Dispose(); - map = newmap; - map.UpdateConfiguration(); - map.SnapAllToAccuracy(); - map.Update(); - thingsfilter.Update(); - - // Let the plugin and editing mode know - General.Plugins.OnMapSetChangeEnd(); - if(General.Editing.Mode != null) General.Editing.Mode.OnMapSetChangeEnd(); - } - - // This reloads resources - [BeginAction("reloadresources")] - internal void DoReloadResource() - { - // Set this to false so we can see if errors are added - General.ErrorLogger.IsErrorAdded = false; + // Not skipping this lump? + if (!skipping) { + // Copy lump over! + Lump tgtlump = target.Insert(srclump.Name, target.Lumps.Count, srclump.Length); + srclump.CopyTo(tgtlump); + } + } + } - ReloadResources(); + // This copies specific map lumps from one WAD to another + private void CopyLumpsByType(WAD source, string sourcemapname, + WAD target, string targetmapname, + bool copyrequired, bool copyblindcopy, + bool copynodebuild, bool copyscript) { + bool lumprequired, lumpblindcopy, lumpnodebuild; + string lumpscript, srclumpname, tgtlumpname; + int srcheaderindex, tgtheaderindex, targetindex, sourceindex, lumpindex; + Lump lump, newlump; - if(General.ErrorLogger.IsErrorAdded) - { - // Show any errors if preferred - General.MainWindow.DisplayStatus(StatusType.Warning, "There were errors during resources loading!"); - if(General.Settings.ShowErrorsWindow) General.MainWindow.ShowErrors(); - } - else - General.MainWindow.DisplayReady(); + // Find the map header in target + tgtheaderindex = target.FindLumpIndex(targetmapname); + if (tgtheaderindex == -1) { + // If this header doesnt exists in the target + // then insert at the end of the target + tgtheaderindex = target.Lumps.Count; + } - } - internal void ReloadResources() - { - DataLocation maplocation; - StatusInfo oldstatus; - Cursor oldcursor; - - // Keep old display info - oldstatus = General.MainWindow.Status; - oldcursor = Cursor.Current; - - // Show status - General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading data resources..."); - Cursor.Current = Cursors.WaitCursor; - - // Clean up - data.Dispose(); - data = null; - config = null; - configinfo = null; - GC.Collect(); - GC.WaitForPendingFinalizers(); - - // Reload game configuration - General.WriteLogLine("Reloading game configuration..."); - configinfo = General.GetConfigurationInfo(options.ConfigFile); - config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); - General.Editing.UpdateCurrentEditModes(); - - // Reload data resources - General.WriteLogLine("Reloading data resources..."); - data = new DataManager(); - if(!string.IsNullOrEmpty(filepathname)) - { - maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, false, false, false); - data.Load(configinfo.Resources, options.Resources, maplocation); - } - else - { - data.Load(configinfo.Resources, options.Resources); - } - - // Apply new settings to map elements - map.UpdateConfiguration(); + // Begin inserting at target header index + targetindex = tgtheaderindex; - // Re-link the background image - grid.LinkBackground(); - - // Inform all plugins that the resources are reloaded - General.Plugins.ReloadResources(); - - // Inform editing mode that the resources are reloaded - if(General.Editing.Mode != null) General.Editing.Mode.OnReloadResources(); - - // Reset status - General.MainWindow.DisplayStatus(oldstatus); - Cursor.Current = oldcursor; + // Find the map header in source + srcheaderindex = source.FindLumpIndex(sourcemapname); + if (srcheaderindex > -1) { + // Copy the map header from source to target + //newlump = target.Insert(targetmapname, tgtindex++, source.Lumps[srcindex].Length); + //source.Lumps[srcindex].CopyTo(newlump); + + // Go for all the map lump names + foreach (DictionaryEntry ml in config.MapLumpNames) { + // Read lump settings from map config + lumprequired = config.ReadSetting("maplumpnames." + ml.Key + ".required", false); + lumpblindcopy = config.ReadSetting("maplumpnames." + ml.Key + ".blindcopy", false); + lumpnodebuild = config.ReadSetting("maplumpnames." + ml.Key + ".nodebuild", false); + lumpscript = config.ReadSetting("maplumpnames." + ml.Key + ".script", ""); + + // Check if this lump should be copied + if ((lumprequired && copyrequired) || (lumpblindcopy && copyblindcopy) || + (lumpnodebuild && copynodebuild) || ((lumpscript.Length != 0) && copyscript)) { + // Get the lump name + srclumpname = ml.Key.ToString(); + tgtlumpname = ml.Key.ToString(); + if (srclumpname == CONFIG_MAP_HEADER) srclumpname = sourcemapname; + if (tgtlumpname == CONFIG_MAP_HEADER) tgtlumpname = targetmapname; + + // Find the lump in the source + sourceindex = FindSpecificLump(source, srclumpname, srcheaderindex, sourcemapname, config.MapLumpNames); + if (sourceindex > -1) { + // Remove lump at target + lumpindex = RemoveSpecificLump(target, tgtlumpname, tgtheaderindex, targetmapname, config.MapLumpNames); + + // Determine target index + // When original lump was found and removed then insert at that position + // otherwise insert after last insertion position + if (lumpindex > -1) targetindex = lumpindex; else targetindex++; + if (targetindex > target.Lumps.Count) targetindex = target.Lumps.Count; + + // Copy the lump to the target + //General.WriteLogLine(srclumpname + " copying as " + tgtlumpname); + lump = source.Lumps[sourceindex]; + newlump = target.Insert(tgtlumpname, targetindex, lump.Length); + lump.CopyTo(newlump); + } + else { + // We don't want to bother the user with this. There are a lot of lumps in + // the game configs that are trivial and don't need to be found. + if (lumprequired) { + General.ErrorLogger.Add(ErrorType.Warning, ml.Key.ToString() + " (required lump) should be read but was not found in the WAD file."); + } + } + } + } + } + } + + // This finds a lump within the range of known lump names + // Returns -1 when the lump cannot be found + internal static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, IDictionary maplumps) { + // Use the configured map lump names to find the specific lump within range, + // because when an unknown lump is met, this search must stop. + + // Go for all lumps in order to find the specified lump + for (int i = 0; i < maplumps.Count + 1; i++) { + // Still within bounds? + if ((mapheaderindex + i) < source.Lumps.Count) { + // Check if this is a known lump name + if (maplumps.Contains(source.Lumps[mapheaderindex + i].Name) || + (maplumps.Contains(CONFIG_MAP_HEADER) && (source.Lumps[mapheaderindex + i].Name == mapheadername))) { + // Is this the lump we are looking for? + if (source.Lumps[mapheaderindex + i].Name == lumpname) { + // Return this index + return mapheaderindex + i; + } + } + else { + // Unknown lump hit, abort search + break; + } + } + } + + // Nothing found + return -1; + } + + // This removes a specific lump and returns the position where the lump was removed + // Returns -1 when the lump could not be found + internal static int RemoveSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, IDictionary maplumps) { + int lumpindex; + + // Find the specific lump index + lumpindex = FindSpecificLump(source, lumpname, mapheaderindex, mapheadername, maplumps); + if (lumpindex > -1) { + // Remove this lump + //General.WriteLogLine(lumpname + " removed"); + source.RemoveAt(lumpindex); + } + else { + // Lump not found + //General.ErrorLogger.Add(ErrorType.Warning, lumpname + " should be removed but was not found!"); + } + + // Return result + return lumpindex; + } + + #endregion + + #region ================== Selection Groups + + // This adds selection to a group + private void AddSelectionToGroup(int groupindex) { + General.Interface.SetCursor(Cursors.WaitCursor); + + // Make undo + undoredo.CreateUndo("Assign to group " + groupindex); + + // Make selection + map.AddSelectionToGroup(0x01 << groupindex); + + General.Interface.DisplayStatus(StatusType.Action, "Assigned selection to group " + groupindex); + General.Interface.SetCursor(Cursors.Default); + } + + // This selects a group + private void SelectGroup(int groupindex) { + // Select + int groupmask = 0x01 << groupindex; + map.SelectVerticesByGroup(groupmask); + map.SelectLinedefsByGroup(groupmask); + map.SelectSectorsByGroup(groupmask); + map.SelectThingsByGroup(groupmask); + + // Redraw to show selection + General.Interface.DisplayStatus(StatusType.Action, "Selected group " + groupindex); + General.Interface.RedrawDisplay(); + } + + // Select actions + [BeginAction("selectgroup1")] + internal void SelectGroup1() { SelectGroup(0); } + [BeginAction("selectgroup2")] + internal void SelectGroup2() { SelectGroup(1); } + [BeginAction("selectgroup3")] + internal void SelectGroup3() { SelectGroup(2); } + [BeginAction("selectgroup4")] + internal void SelectGroup4() { SelectGroup(3); } + [BeginAction("selectgroup5")] + internal void SelectGroup5() { SelectGroup(4); } + [BeginAction("selectgroup6")] + internal void SelectGroup6() { SelectGroup(5); } + [BeginAction("selectgroup7")] + internal void SelectGroup7() { SelectGroup(6); } + [BeginAction("selectgroup8")] + internal void SelectGroup8() { SelectGroup(7); } + [BeginAction("selectgroup9")] + internal void SelectGroup9() { SelectGroup(8); } + [BeginAction("selectgroup10")] + internal void SelectGroup10() { SelectGroup(9); } + + // Assign actions + [BeginAction("assigngroup1")] + internal void AssignGroup1() { AddSelectionToGroup(0); } + [BeginAction("assigngroup2")] + internal void AssignGroup2() { AddSelectionToGroup(1); } + [BeginAction("assigngroup3")] + internal void AssignGroup3() { AddSelectionToGroup(2); } + [BeginAction("assigngroup4")] + internal void AssignGroup4() { AddSelectionToGroup(3); } + [BeginAction("assigngroup5")] + internal void AssignGroup5() { AddSelectionToGroup(4); } + [BeginAction("assigngroup6")] + internal void AssignGroup6() { AddSelectionToGroup(5); } + [BeginAction("assigngroup7")] + internal void AssignGroup7() { AddSelectionToGroup(6); } + [BeginAction("assigngroup8")] + internal void AssignGroup8() { AddSelectionToGroup(7); } + [BeginAction("assigngroup9")] + internal void AssignGroup9() { AddSelectionToGroup(8); } + [BeginAction("assigngroup10")] + internal void AssignGroup10() { AddSelectionToGroup(9); } + + #endregion + + #region ================== Script Editing + + // Show the script editor + [BeginAction("openscripteditor")] + internal void ShowScriptEditor() { + Cursor.Current = Cursors.WaitCursor; + + if (scriptwindow == null) { + // Load the window + scriptwindow = new ScriptEditorForm(); + } + + // Window not yet visible? + if (!scriptwindow.Visible) { + // Show the window + if (General.Settings.ScriptOnTop) { + if (scriptwindow.Visible && (scriptwindow.Owner == null)) scriptwindow.Hide(); + scriptwindow.Show(General.MainWindow); + } + else { + if (scriptwindow.Visible && (scriptwindow.Owner != null)) scriptwindow.Hide(); + scriptwindow.Show(); + } + } + scriptwindow.Activate(); + scriptwindow.Focus(); + Cursor.Current = Cursors.Default; + } + + // This asks the user to save changes in script files + // Returns false when cancelled by the user + internal bool AskSaveScriptChanges() { + // Window open? + if (scriptwindow != null) { + // Ask to save changes + // This also saves implicitly + return scriptwindow.AskSaveAll(); + } + else { + // No problems + return true; + } + } + + // This applies the changed status for internal scripts + internal void ApplyScriptChanged() { + // Remember if lumps are changed + scriptschanged |= scriptwindow.Editor.CheckImplicitChanges(); + } + + // Close the script editor + // Specify true for the closing parameter when + // the window is already in the closing process + internal void CloseScriptEditor(bool closing) { + if (scriptwindow != null) { + if (!scriptwindow.IsDisposed) { + // Remember what files were open + scriptwindow.Editor.WriteOpenFilesToConfiguration(); + + // Close now + if (!closing) scriptwindow.Close(); + } + + // Done + scriptwindow = null; + } + } + + // This checks if the scripts are changed + internal bool CheckScriptChanged() { + if (scriptwindow != null) { + // Check if scripts are changed + return scriptschanged || scriptwindow.Editor.CheckImplicitChanges(); + } + else { + // Check if scripts are changed + return scriptschanged; + } + } + + // This compiles all lumps that require compiling and stores the results + // Returns true when our code worked properly (even when the compiler returned errors) + private bool CompileScriptLumps() { + bool success = true; + errors.Clear(); + + // Go for all the map lumps + foreach (MapLumpInfo lumpinfo in config.MapLumps.Values) { + // Is this a script lump? + if (lumpinfo.script != null) { + // Compile it now + success &= CompileLump(lumpinfo.name, false); + } + } + + return success; + } + + // This compiles a script lump and returns any errors that may have occurred + // Returns true when our code worked properly (even when the compiler returned errors) + internal bool CompileLump(string lumpname, bool clearerrors) { + string inputfile, outputfile, sourcefile; + Compiler compiler; + byte[] filedata; + string reallumpname = lumpname; + + // Find the lump + if (lumpname == CONFIG_MAP_HEADER) reallumpname = TEMP_MAP_HEADER; + Lump lump = tempwad.FindLump(reallumpname); + if (lump == null) throw new Exception("No such lump in temporary wad file '" + reallumpname + "'."); + + // Determine source file + if (filepathname.Length > 0) + sourcefile = filepathname; + else + sourcefile = tempwad.Filename; + + // New list of errors + if (clearerrors) errors.Clear(); + + // Determine the script configuration to use + ScriptConfiguration scriptconfig = config.MapLumps[lumpname].script; + if (scriptconfig.Compiler != null) { + try { + // Initialize compiler + compiler = scriptconfig.Compiler.Create(); + } catch (Exception e) { + // Fail + errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message)); + return false; + } + + try { + // Write lump data to temp script file in compiler's temp directory + inputfile = General.MakeTempFilename(compiler.Location, "tmp"); + lump.Stream.Seek(0, SeekOrigin.Begin); + BinaryReader reader = new BinaryReader(lump.Stream); + File.WriteAllBytes(inputfile, reader.ReadBytes((int)lump.Stream.Length)); + } catch (Exception e) { + // Fail + compiler.Dispose(); + errors.Add(new CompilerError("Unable to write script to working file. " + e.GetType().Name + ": " + e.Message)); + return false; + } + + // Make random output filename + outputfile = General.MakeTempFilename(compiler.Location, "tmp"); + + // Run compiler + compiler.Parameters = scriptconfig.Parameters; + compiler.InputFile = Path.GetFileName(inputfile); + compiler.OutputFile = Path.GetFileName(outputfile); + compiler.SourceFile = sourcefile; + compiler.WorkingDirectory = Path.GetDirectoryName(inputfile); + if (compiler.Run()) { + // Process errors + foreach (CompilerError e in compiler.Errors) { + CompilerError newerror = e; + + // If the error's filename equals our temporary file, + // use the lump name instead and prefix it with ? + if (string.Compare(e.filename, inputfile, true) == 0) + newerror.filename = "?" + reallumpname; + + errors.Add(newerror); + } + + // No errors? + if (compiler.Errors.Length == 0) { + // Output file exists? + if (File.Exists(outputfile)) { + // Copy output file data into a lump? + if (!string.IsNullOrEmpty(scriptconfig.ResultLump)) { + // Do that now then + try { + filedata = File.ReadAllBytes(outputfile); + } catch (Exception e) { + // Fail + compiler.Dispose(); + errors.Add(new CompilerError("Unable to read compiler output file. " + e.GetType().Name + ": " + e.Message)); + return false; + } + + // Store data + MemoryStream stream = new MemoryStream(filedata); + SetLumpData(scriptconfig.ResultLump, stream); + } + } + } + + // Clean up + compiler.Dispose(); + + // Done + return true; + } + else { + // Fail + compiler.Dispose(); + errors = null; + return false; + } + } + else { + // No compiler to run for this script type + return true; + } + } + + // This clears all compiler errors + internal void ClearCompilerErrors() { + errors.Clear(); + } + + //mxd + internal void UpdateScriptNames() { + namedScripts = new List(); + numberedScripts = new List(); + + // Load the script lumps + foreach (MapLumpInfo maplumpinfo in config.MapLumps.Values) { + // Is this a script lump? + if (maplumpinfo.script != null && maplumpinfo.name == "SCRIPTS") { + // Load the lump data + MemoryStream stream = GetLumpData(maplumpinfo.name); + if (stream != null) { + AcsParser parser = new AcsParser(); + parser.Parse(stream, "SCRIPTS"); + namedScripts.AddRange(parser.NamedScripts); + numberedScripts.AddRange(parser.NumberedScripts); + } + } + } + } + + #endregion + + #region ================== Methods + + // This updates everything after the configuration or settings have been changed + internal void UpdateConfiguration() { + // Update map + map.UpdateConfiguration(); + + // Update settings + renderer3d.CreateProjection(); + + // Things filters + General.MainWindow.UpdateThingsFilters(); + } + + // This changes thing filter + public void ChangeThingFilter(ThingsFilter newfilter) { + // We have a special filter for null + if (newfilter == null) newfilter = new NullThingsFilter(); + + // Deactivate old filter + if (thingsfilter != null) thingsfilter.Deactivate(); + + // Change + thingsfilter = newfilter; + + // Activate filter + thingsfilter.Activate(); + + // Update interface + General.MainWindow.ReflectThingsFilter(); + + // Redraw + General.MainWindow.RedrawDisplay(); + } + + // This sets a new mapset for editing + internal void ChangeMapSet(MapSet newmap) { + // Let the plugin and editing mode know + General.Plugins.OnMapSetChangeBegin(); + if (General.Editing.Mode != null) General.Editing.Mode.OnMapSetChangeBegin(); + this.visualcamera.Sector = null; + + // Can't have a selection in an old map set + map.ClearAllSelected(); + + // Reset surfaces + renderer2d.Surfaces.Reset(); + + // Apply + map.Dispose(); + map = newmap; + map.UpdateConfiguration(); + map.SnapAllToAccuracy(); + map.Update(); + thingsfilter.Update(); + + // Let the plugin and editing mode know + General.Plugins.OnMapSetChangeEnd(); + if (General.Editing.Mode != null) General.Editing.Mode.OnMapSetChangeEnd(); + } + + // This reloads resources + [BeginAction("reloadresources")] + internal void DoReloadResource() { + // Set this to false so we can see if errors are added + General.ErrorLogger.IsErrorAdded = false; + + ReloadResources(); + + if (General.ErrorLogger.IsErrorAdded) { + // Show any errors if preferred + General.MainWindow.DisplayStatus(StatusType.Warning, "There were errors during resources loading!"); + if (General.Settings.ShowErrorsWindow) General.MainWindow.ShowErrors(); + } + else + General.MainWindow.DisplayReady(); + + } + internal void ReloadResources() { + DataLocation maplocation; + StatusInfo oldstatus; + Cursor oldcursor; + + // Keep old display info + oldstatus = General.MainWindow.Status; + oldcursor = Cursor.Current; + + // Show status + General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading data resources..."); + Cursor.Current = Cursors.WaitCursor; + + // Clean up + data.Dispose(); + data = null; + config = null; + configinfo = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + + // Reload game configuration + General.WriteLogLine("Reloading game configuration..."); + configinfo = General.GetConfigurationInfo(options.ConfigFile); + config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); + General.Editing.UpdateCurrentEditModes(); + + // Reload data resources + General.WriteLogLine("Reloading data resources..."); + data = new DataManager(); + if (!string.IsNullOrEmpty(filepathname)) { + maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, false, false, false); + data.Load(configinfo.Resources, options.Resources, maplocation); + } + else { + data.Load(configinfo.Resources, options.Resources); + } + + // Apply new settings to map elements + map.UpdateConfiguration(); + + // Re-link the background image + grid.LinkBackground(); + + // Inform all plugins that the resources are reloaded + General.Plugins.ReloadResources(); + + // Inform editing mode that the resources are reloaded + if (General.Editing.Mode != null) General.Editing.Mode.OnReloadResources(); + + // Reset status + General.MainWindow.DisplayStatus(oldstatus); + Cursor.Current = oldcursor; //mxd GZBuilder.GZGeneral.OnReloadResources(); - } + } - // Game Configuration action - [BeginAction("mapoptions")] - internal void ShowMapOptions() - { - // Cancel volatile mode, if any - General.Editing.DisengageVolatileMode(); - - // Show map options dialog - MapOptionsForm optionsform = new MapOptionsForm(options); - if(optionsform.ShowDialog(General.MainWindow) == DialogResult.OK) - { - // Update interface - General.MainWindow.UpdateInterface(); + // Game Configuration action + [BeginAction("mapoptions")] + internal void ShowMapOptions() { + // Cancel volatile mode, if any + General.Editing.DisengageVolatileMode(); - // Stop data manager - data.Dispose(); - - // Apply new options - this.options = optionsform.Options; + // Show map options dialog + MapOptionsForm optionsform = new MapOptionsForm(options); + if (optionsform.ShowDialog(General.MainWindow) == DialogResult.OK) { + // Update interface + General.MainWindow.UpdateInterface(); - // Load new game configuration - General.WriteLogLine("Loading game configuration..."); - configinfo = General.GetConfigurationInfo(options.ConfigFile); - config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); - configinfo.ApplyDefaults(config); - General.Editing.UpdateCurrentEditModes(); - - // Setup new map format IO - General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); - io = MapSetIO.Create(config.FormatInterface, tempwad, this); + // Stop data manager + data.Dispose(); - // Create required lumps if they don't exist yet - CreateRequiredLumps(tempwad, TEMP_MAP_HEADER); + // Apply new options + this.options = optionsform.Options; - // Let the plugins know - General.Plugins.MapReconfigure(); - - // Update interface - General.MainWindow.SetupInterface(); - General.MainWindow.UpdateThingsFilters(); - General.MainWindow.UpdateInterface(); - - // Reload resources - ReloadResources(); - - // Done - General.MainWindow.DisplayReady(); - } + // Load new game configuration + General.WriteLogLine("Loading game configuration..."); + configinfo = General.GetConfigurationInfo(options.ConfigFile); + config = new GameConfiguration(General.LoadGameConfiguration(options.ConfigFile)); + configinfo.ApplyDefaults(config); + General.Editing.UpdateCurrentEditModes(); - // Done - optionsform.Dispose(); - } + // Setup new map format IO + General.WriteLogLine("Initializing map format interface " + config.FormatInterface + "..."); + io = MapSetIO.Create(config.FormatInterface, tempwad, this); - // This shows the things filters setup - [BeginAction("thingsfilterssetup")] - internal void ShowThingsFiltersSetup() - { - // Show things filter dialog - ThingsFiltersForm f = new ThingsFiltersForm(); - f.ShowDialog(General.MainWindow); - f.Dispose(); - General.MainWindow.UpdateThingsFilters(); - } - - // This returns true is the given type matches - public bool IsType(Type t) - { - return io.GetType().Equals(t); - } + // Create required lumps if they don't exist yet + CreateRequiredLumps(tempwad, TEMP_MAP_HEADER); - #endregion - } -} + // Let the plugins know + General.Plugins.MapReconfigure(); + + // Update interface + General.MainWindow.SetupInterface(); + General.MainWindow.UpdateThingsFilters(); + General.MainWindow.UpdateInterface(); + + // Reload resources + ReloadResources(); + + // Done + General.MainWindow.DisplayReady(); + } + + // Done + optionsform.Dispose(); + } + + // This shows the things filters setup + [BeginAction("thingsfilterssetup")] + internal void ShowThingsFiltersSetup() { + // Show things filter dialog + ThingsFiltersForm f = new ThingsFiltersForm(); + f.ShowDialog(General.MainWindow); + f.Dispose(); + General.MainWindow.UpdateThingsFilters(); + } + + // This returns true is the given type matches + public bool IsType(Type t) { + return io.GetType().Equals(t); + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Core/Plugins/Plug.cs b/Source/Core/Plugins/Plug.cs index 0e7aa054..ed4de874 100644 --- a/Source/Core/Plugins/Plug.cs +++ b/Source/Core/Plugins/Plug.cs @@ -188,13 +188,13 @@ namespace CodeImp.DoomBuilder.Plugins /// /// Occurs before test map is launched. Return false if map launch is not desired. /// - public virtual bool OnMapTestBegin() { return true; } + //public virtual bool OnMapTestBegin() { return true; } //mxd /// /// Occurs after game engine is closed. /// - public virtual void OnMapTestEnd() { } + //public virtual void OnMapTestEnd() { } /// /// Occurs before the MapSet is changed. This means that the active MapSet will be disposed and changed to a new one. diff --git a/Source/Core/Plugins/PluginManager.cs b/Source/Core/Plugins/PluginManager.cs index 48e89a9d..3f61e306 100644 --- a/Source/Core/Plugins/PluginManager.cs +++ b/Source/Core/Plugins/PluginManager.cs @@ -303,7 +303,7 @@ namespace CodeImp.DoomBuilder.Plugins public void OnPresentDisplayBegin() { foreach(Plugin p in plugins) p.Plug.OnPresentDisplayBegin(); } //mxd. test map events - public bool OnMapTestBegin() { + /*public bool OnMapTestBegin() { bool canLaunch; foreach (Plugin p in plugins) { canLaunch = p.Plug.OnMapTestBegin(); @@ -311,7 +311,7 @@ namespace CodeImp.DoomBuilder.Plugins } return true; } - public void OnMapTestEnd() { foreach (Plugin p in plugins) p.Plug.OnMapTestEnd(); } + public void OnMapTestEnd() { foreach (Plugin p in plugins) p.Plug.OnMapTestEnd(); }*/ #endregion } diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 24af1e83..d4d23bd3 100644 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -1097,10 +1097,7 @@ namespace CodeImp.DoomBuilder.Rendering //mxd. returns true if sector has fog color private bool getFogColor(Sector sector, out Color4 color) { - /*if(sector.Fields == null){ - color = new Color4(); //black - return false; - } else*/ if (GZBuilder.GZGeneral.UDMF && sector.Fields.ContainsKey("fadecolor")) { + if (General.Map.UDMF && sector.Fields.ContainsKey("fadecolor")) { color = new Color4((int)sector.Fields["fadecolor"].Value); return true; } else if (General.Map.Data.MapInfo.HasOutsideFogColor && sector.CeilTexture == General.Map.Config.SkyFlatName) { diff --git a/Source/Core/Resources/Splash3_trans.png b/Source/Core/Resources/Splash3_trans.png index 0ea847a8..60864c69 100644 Binary files a/Source/Core/Resources/Splash3_trans.png and b/Source/Core/Resources/Splash3_trans.png differ diff --git a/Source/Core/Types/IntegerHandler.cs b/Source/Core/Types/IntegerHandler.cs index 3aa7d8bf..1eb67e96 100644 --- a/Source/Core/Types/IntegerHandler.cs +++ b/Source/Core/Types/IntegerHandler.cs @@ -25,6 +25,7 @@ using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Data; using System.IO; using System.Diagnostics; +using CodeImp.DoomBuilder.Config; #endregion @@ -40,6 +41,7 @@ namespace CodeImp.DoomBuilder.Types #region ================== Variables private int value; + private int defaultValue; //mxd #endregion @@ -49,6 +51,12 @@ namespace CodeImp.DoomBuilder.Types #region ================== Methods + //mxd + public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) { + defaultValue = (int)arginfo.DefaultValue; + base.SetupArgument(attr, arginfo); + } + public override void SetValue(object value) { int result; @@ -83,6 +91,10 @@ namespace CodeImp.DoomBuilder.Types } } + public override void SetDefaultValue() { + value = defaultValue; + } + public override object GetValue() { return this.value; @@ -90,7 +102,7 @@ namespace CodeImp.DoomBuilder.Types public override int GetIntValue() { - return this.value; + return this.value; } public override string GetStringValue() diff --git a/Source/Core/Types/StringHandler.cs b/Source/Core/Types/StringHandler.cs index 110b2904..1703e898 100644 --- a/Source/Core/Types/StringHandler.cs +++ b/Source/Core/Types/StringHandler.cs @@ -64,7 +64,7 @@ namespace CodeImp.DoomBuilder.Types public override void SetValue(object value) { if(value != null) - this.value = value.ToString(); + this.value = value.ToString().Replace("\"", ""); //mxd else this.value = ""; } diff --git a/Source/Core/Types/TypeHandler.cs b/Source/Core/Types/TypeHandler.cs index 0c0551ac..98ed968a 100644 --- a/Source/Core/Types/TypeHandler.cs +++ b/Source/Core/Types/TypeHandler.cs @@ -133,6 +133,11 @@ namespace CodeImp.DoomBuilder.Types // How the value is actually validated and stored is up to the implementation public abstract void SetValue(object value); + //mxd. this should replace current value with default one + public virtual void SetDefaultValue() { + throw new NotSupportedException("Override this method to support default value for this type"); + } + // This must return the value as one of the primitive data types // supported by UDMF: int, string, float or bool public abstract object GetValue(); diff --git a/Source/Core/Windows/LinedefEditForm.Designer.cs b/Source/Core/Windows/LinedefEditForm.Designer.cs index 9df7f386..b5e73f3a 100644 --- a/Source/Core/Windows/LinedefEditForm.Designer.cs +++ b/Source/Core/Windows/LinedefEditForm.Designer.cs @@ -45,6 +45,8 @@ namespace CodeImp.DoomBuilder.Windows this.apply = new System.Windows.Forms.Button(); this.actiongroup = new System.Windows.Forms.GroupBox(); this.argspanel = new System.Windows.Forms.Panel(); + this.arg0str = new System.Windows.Forms.ComboBox(); + this.cbArgStr = new System.Windows.Forms.CheckBox(); this.arg2 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); this.arg1 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); this.arg0 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); @@ -282,26 +284,47 @@ namespace CodeImp.DoomBuilder.Windows // // argspanel // + this.argspanel.Controls.Add(this.arg0str); this.argspanel.Controls.Add(this.arg2); this.argspanel.Controls.Add(this.arg1); this.argspanel.Controls.Add(this.arg0); this.argspanel.Controls.Add(this.arg3); this.argspanel.Controls.Add(this.arg4); this.argspanel.Controls.Add(this.arg1label); - this.argspanel.Controls.Add(this.arg0label); this.argspanel.Controls.Add(this.arg3label); this.argspanel.Controls.Add(this.arg2label); this.argspanel.Controls.Add(this.arg4label); + this.argspanel.Controls.Add(this.cbArgStr); + this.argspanel.Controls.Add(this.arg0label); this.argspanel.Location = new System.Drawing.Point(6, 54); this.argspanel.Name = "argspanel"; this.argspanel.Size = new System.Drawing.Size(521, 83); this.argspanel.TabIndex = 2; this.argspanel.Visible = false; // + // arg0str + // + this.arg0str.FormattingEnabled = true; + this.arg0str.Location = new System.Drawing.Point(272, 55); + this.arg0str.Name = "arg0str"; + this.arg0str.Size = new System.Drawing.Size(125, 22); + this.arg0str.TabIndex = 38; + this.arg0str.Leave += new System.EventHandler(this.arg0str_Leave); + // + // cbArgStr + // + this.cbArgStr.Location = new System.Drawing.Point(8, -4); + this.cbArgStr.Name = "cbArgStr"; + this.cbArgStr.Size = new System.Drawing.Size(63, 40); + this.cbArgStr.TabIndex = 37; + this.cbArgStr.Text = "Named script"; + this.cbArgStr.UseVisualStyleBackColor = true; + this.cbArgStr.CheckedChanged += new System.EventHandler(this.cbArgStr_CheckedChanged); + // // arg2 // this.arg2.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arg2.Location = new System.Drawing.Point(123, 55); + this.arg2.Location = new System.Drawing.Point(157, 55); this.arg2.Name = "arg2"; this.arg2.Size = new System.Drawing.Size(93, 24); this.arg2.TabIndex = 2; @@ -309,7 +332,7 @@ namespace CodeImp.DoomBuilder.Windows // arg1 // this.arg1.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arg1.Location = new System.Drawing.Point(123, 29); + this.arg1.Location = new System.Drawing.Point(157, 29); this.arg1.Name = "arg1"; this.arg1.Size = new System.Drawing.Size(93, 24); this.arg1.TabIndex = 1; @@ -317,7 +340,7 @@ namespace CodeImp.DoomBuilder.Windows // arg0 // this.arg0.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arg0.Location = new System.Drawing.Point(123, 3); + this.arg0.Location = new System.Drawing.Point(157, 3); this.arg0.Name = "arg0"; this.arg0.Size = new System.Drawing.Size(93, 24); this.arg0.TabIndex = 0; @@ -325,7 +348,7 @@ namespace CodeImp.DoomBuilder.Windows // arg3 // this.arg3.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arg3.Location = new System.Drawing.Point(364, 3); + this.arg3.Location = new System.Drawing.Point(398, 3); this.arg3.Name = "arg3"; this.arg3.Size = new System.Drawing.Size(93, 24); this.arg3.TabIndex = 3; @@ -333,14 +356,14 @@ namespace CodeImp.DoomBuilder.Windows // arg4 // this.arg4.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.arg4.Location = new System.Drawing.Point(364, 29); + this.arg4.Location = new System.Drawing.Point(398, 29); this.arg4.Name = "arg4"; this.arg4.Size = new System.Drawing.Size(93, 24); this.arg4.TabIndex = 4; // // arg1label // - this.arg1label.Location = new System.Drawing.Point(-62, 34); + this.arg1label.Location = new System.Drawing.Point(-28, 34); this.arg1label.Name = "arg1label"; this.arg1label.Size = new System.Drawing.Size(179, 14); this.arg1label.TabIndex = 33; @@ -350,7 +373,7 @@ namespace CodeImp.DoomBuilder.Windows // // arg0label // - this.arg0label.Location = new System.Drawing.Point(-62, 8); + this.arg0label.Location = new System.Drawing.Point(-28, 8); this.arg0label.Name = "arg0label"; this.arg0label.Size = new System.Drawing.Size(179, 14); this.arg0label.TabIndex = 32; @@ -360,7 +383,7 @@ namespace CodeImp.DoomBuilder.Windows // // arg3label // - this.arg3label.Location = new System.Drawing.Point(179, 8); + this.arg3label.Location = new System.Drawing.Point(213, 8); this.arg3label.Name = "arg3label"; this.arg3label.Size = new System.Drawing.Size(179, 14); this.arg3label.TabIndex = 36; @@ -370,7 +393,7 @@ namespace CodeImp.DoomBuilder.Windows // // arg2label // - this.arg2label.Location = new System.Drawing.Point(-62, 60); + this.arg2label.Location = new System.Drawing.Point(-28, 60); this.arg2label.Name = "arg2label"; this.arg2label.Size = new System.Drawing.Size(179, 14); this.arg2label.TabIndex = 35; @@ -380,7 +403,7 @@ namespace CodeImp.DoomBuilder.Windows // // arg4label // - this.arg4label.Location = new System.Drawing.Point(179, 34); + this.arg4label.Location = new System.Drawing.Point(213, 34); this.arg4label.Name = "arg4label"; this.arg4label.Size = new System.Drawing.Size(179, 14); this.arg4label.TabIndex = 34; @@ -838,6 +861,7 @@ namespace CodeImp.DoomBuilder.Windows this.fieldslist.TypeColumnVisible = true; this.fieldslist.TypeColumnWidth = 100; this.fieldslist.ValueColumnVisible = true; + this.fieldslist.OnFieldValueChanged += new CodeImp.DoomBuilder.Controls.FieldsEditorControl.SingleFieldNameEvent(this.fieldslist_OnFieldValueChanged); // // heightpanel1 // @@ -960,5 +984,7 @@ namespace CodeImp.DoomBuilder.Windows private CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox backoffsety; private CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox backoffsetx; private CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox backsector; + private System.Windows.Forms.CheckBox cbArgStr; + private System.Windows.Forms.ComboBox arg0str; } } \ No newline at end of file diff --git a/Source/Core/Windows/LinedefEditForm.cs b/Source/Core/Windows/LinedefEditForm.cs index 86d327ae..95914e14 100644 --- a/Source/Core/Windows/LinedefEditForm.cs +++ b/Source/Core/Windows/LinedefEditForm.cs @@ -29,6 +29,8 @@ using System.IO; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Editing; using CodeImp.DoomBuilder.Controls; +//mxd +using CodeImp.DoomBuilder.GZBuilder.Data; #endregion @@ -150,6 +152,12 @@ namespace CodeImp.DoomBuilder.Windows if(fl.Flags.ContainsKey(ai.Key)) c.Checked = fl.Flags[ai.Key]; } + //mxd. setup arg0str + arg0str.Location = arg0.Location; + + // Custom fields + fieldslist.SetValues(fl.Fields, true); + // Action/tags action.Value = fl.Action; tag.Text = fl.Tag.ToString(); @@ -191,9 +199,6 @@ namespace CodeImp.DoomBuilder.Windows backoffsety.Text = fl.Back.OffsetY.ToString(); } - // Custom fields - fieldslist.SetValues(fl.Fields, true); - //////////////////////////////////////////////////////////////////////// // Now go for all lines and change the options when a setting is different //////////////////////////////////////////////////////////////////////// @@ -305,6 +310,58 @@ namespace CodeImp.DoomBuilder.Windows preventchanges = false; } + + //mxd + private void setNumberedScripts(Linedef l) { + arg0str.Items.Clear(); + + if (General.Map.NumberedScripts.Count > 0) { + foreach (ScriptItem si in General.Map.NumberedScripts) { + arg0str.Items.Add(si); + if (si.Index == l.Args[0]) + arg0str.SelectedIndex = arg0str.Items.Count - 1; + } + + //script number is not among known scripts... + if (arg0str.SelectedIndex == -1 && l.Args[0] > 0) { + arg0str.Items.Add(new ScriptItem(l.Args[0], "Script " + l.Args[0])); + arg0str.SelectedIndex = arg0str.Items.Count - 1; + } + + } else if (l.Args[0] > 0) { + arg0str.Items.Add(new ScriptItem(l.Args[0], "Script " + l.Args[0])); + arg0str.SelectedIndex = 0; + } + } + + //mxd + private void setNamedScripts(string selectedValue) { + arg0str.Items.Clear(); + + //update arg0str items + if (General.Map.NamedScripts.Count > 0) { + //dbg + GZBuilder.GZGeneral.Trace("Got " + General.Map.NamedScripts.Count + " script names"); + + ScriptItem[] sn = new ScriptItem[General.Map.NamedScripts.Count]; + General.Map.NamedScripts.CopyTo(sn, 0); + arg0str.Items.AddRange(sn); + + for (int i = 0; i < sn.Length; i++) { + if (sn[i].Name == selectedValue) { + arg0str.SelectedIndex = i; + break; + } + } + + //int index = General.Map.NamedScripts.IndexOf(selectedValue); + //if (index != -1) + // arg0str.SelectedIndex = index; + } + else { + arg0str.Text = selectedValue; + } + } // Front side (un)checked private void frontside_CheckStateChanged(object sender, EventArgs e) @@ -362,6 +419,10 @@ namespace CodeImp.DoomBuilder.Windows // Make undo if(lines.Count > 1) undodesc = lines.Count + " linedefs"; General.Map.UndoRedo.CreateUndo("Edit " + undodesc); + + //nxd + bool hasAcs = Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, action.Value) != -1; + bool hasArg0str = General.Map.UDMF && !action.Empty && hasAcs && arg0str.Text.Length > 0; // Go for all the lines foreach(Linedef l in lines) @@ -388,7 +449,16 @@ namespace CodeImp.DoomBuilder.Windows // Action/tags l.Tag = General.Clamp(tag.GetResult(l.Tag), General.Map.FormatInterface.MinTag, General.Map.FormatInterface.MaxTag); if(!action.Empty) l.Action = action.Value; - l.Args[0] = arg0.GetResult(l.Args[0]); + + //mxd + if (hasAcs && !cbArgStr.Checked) { + if (arg0str.SelectedItem != null) + l.Args[0] = ((ScriptItem)arg0str.SelectedItem).Index; + else if (!int.TryParse(arg0str.Text.Trim(), out l.Args[0])) + l.Args[0] = 0; + } else { + l.Args[0] = arg0.GetResult(l.Args[0]); + } l.Args[1] = arg1.GetResult(l.Args[1]); l.Args[2] = arg2.GetResult(l.Args[2]); l.Args[3] = arg3.GetResult(l.Args[3]); @@ -466,6 +536,17 @@ namespace CodeImp.DoomBuilder.Windows // Custom fields fieldslist.Apply(l.Fields); + + //mxd. apply arg0str + if (hasArg0str && cbArgStr.Checked) { + if (l.Fields.ContainsKey("arg0str")) + l.Fields["arg0str"].Value = arg0str.Text; + else + l.Fields.Add("arg0str", new UniValue(2, arg0str.Text)); + } + else if (l.Fields.ContainsKey("arg0str")) { + l.Fields.Remove("arg0str"); + } } // Update the used textures @@ -524,12 +605,38 @@ namespace CodeImp.DoomBuilder.Windows // Zero all arguments when linedef action 0 (normal) is chosen if(!preventchanges && (showaction == 0)) { - arg0.SetValue(0); + //mxd + arg0.SetDefaultValue(); + arg1.SetDefaultValue(); + arg2.SetDefaultValue(); + arg3.SetDefaultValue(); + arg4.SetDefaultValue(); + /*arg0.SetValue(0); arg1.SetValue(0); arg2.SetValue(0); arg3.SetValue(0); - arg4.SetValue(0); + arg4.SetValue(0);*/ } + + //mxd. update arg0str + if (Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, showaction) != -1) { + arg0str.Visible = true; + + if (General.Map.UDMF && fieldslist.GetValue("arg0str") != null) { + cbArgStr.Visible = true; + cbArgStr.Checked = true; + setNamedScripts((string)fieldslist.GetValue("arg0str")); + } else { //use script numbers + cbArgStr.Visible = General.Map.UDMF; + cbArgStr.Checked = false; + Linedef l = General.GetByIndex(lines, 0); + setNumberedScripts(l); + } + } else { + cbArgStr.Checked = false; + cbArgStr.Visible = false; + arg0str.Visible = false; + } } // Browse Action clicked @@ -572,6 +679,31 @@ namespace CodeImp.DoomBuilder.Windows General.Map.UndoRedo.WithdrawUndo(); } + //mxd + private void cbArgStr_CheckedChanged(object sender, EventArgs e) { + arg0str.Text = ""; + + if (cbArgStr.Checked) { + setNamedScripts((string)fieldslist.GetValue("arg0str")); + } + else if (!cbArgStr.Checked) { + setNumberedScripts(General.GetByIndex(lines, 0)); + } + + arg0label.Text = cbArgStr.Checked ? "Script name:" : "Script number:"; + } + + //mxd + private void arg0str_Leave(object sender, EventArgs e) { + if (cbArgStr.Checked) fieldslist.SetValue("arg0str", arg0str.Text, CodeImp.DoomBuilder.Types.UniversalType.String); + } + + //mxd + private void fieldslist_OnFieldValueChanged(string fieldname) { + if (cbArgStr.Checked && fieldname == "arg0str") + arg0str.Text = (string)fieldslist.GetValue(fieldname); + } + // Help! private void LinedefEditForm_HelpRequested(object sender, HelpEventArgs hlpevent) { diff --git a/Source/Core/Windows/LinedefEditForm.resx b/Source/Core/Windows/LinedefEditForm.resx index d853157a..3f7723c1 100644 --- a/Source/Core/Windows/LinedefEditForm.resx +++ b/Source/Core/Windows/LinedefEditForm.resx @@ -204,36 +204,6 @@ True - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - True - True diff --git a/Source/Core/Windows/MapOptionsForm.cs b/Source/Core/Windows/MapOptionsForm.cs index 066303c2..8ea4fdf4 100644 --- a/Source/Core/Windows/MapOptionsForm.cs +++ b/Source/Core/Windows/MapOptionsForm.cs @@ -68,8 +68,12 @@ namespace CodeImp.DoomBuilder.Windows } } + //mxd. Still better than nothing :) + if (config.SelectedIndex == -1 && General.Configs.Count > 0) config.SelectedIndex = 0; + // Set the level name - levelname.Text = options.CurrentName; + if (options.CurrentName.Length > 0) //mxd + levelname.Text = options.CurrentName; // Set strict patches loading strictpatches.Checked = options.StrictPatches; @@ -213,11 +217,11 @@ namespace CodeImp.DoomBuilder.Windows ci = (ConfigurationInfo)config.SelectedItem; // No lump name in the name field? - if(levelname.Text.Trim().Length == 0) - { - // Get default lump name from configuration - levelname.Text = ci.DefaultLumpName; - } + if (levelname.Text.Trim().Length == 0) + { + // Get default lump name from configuration + levelname.Text = ci.DefaultLumpName; + } // Show resources datalocations.FixedResourceLocationList(ci.Resources); diff --git a/Source/Core/Windows/ScriptEditorForm.Designer.cs b/Source/Core/Windows/ScriptEditorForm.Designer.cs index 2f119bf8..02ec88b4 100644 --- a/Source/Core/Windows/ScriptEditorForm.Designer.cs +++ b/Source/Core/Windows/ScriptEditorForm.Designer.cs @@ -28,39 +28,39 @@ namespace CodeImp.DoomBuilder.Windows /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ScriptEditorForm)); - this.editor = new CodeImp.DoomBuilder.Controls.ScriptEditorPanel(); - this.SuspendLayout(); - // - // editor - // - this.editor.BackColor = System.Drawing.SystemColors.Control; - this.editor.Dock = System.Windows.Forms.DockStyle.Fill; - this.editor.Location = new System.Drawing.Point(0, 0); - this.editor.Name = "editor"; - this.editor.Size = new System.Drawing.Size(729, 578); - this.editor.TabIndex = 0; - this.editor.TabStop = false; - // - // ScriptEditorForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(729, 578); - this.Controls.Add(this.editor); - this.DoubleBuffered = true; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.KeyPreview = true; - this.Name = "ScriptEditorForm"; - this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; - this.Text = "Doom Builder Script Editor"; - this.Load += new System.EventHandler(this.ScriptEditorForm_Load); - this.Shown += new System.EventHandler(this.ScriptEditorForm_Shown); - this.Move += new System.EventHandler(this.ScriptEditorForm_Move); - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ScriptEditorForm_FormClosing); - this.HelpRequested += new System.Windows.Forms.HelpEventHandler(this.ScriptEditorForm_HelpRequested); - this.ResizeEnd += new System.EventHandler(this.ScriptEditorForm_ResizeEnd); - this.ResumeLayout(false); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ScriptEditorForm)); + this.editor = new CodeImp.DoomBuilder.Controls.ScriptEditorPanel(); + this.SuspendLayout(); + // + // editor + // + this.editor.BackColor = System.Drawing.SystemColors.Control; + this.editor.Dock = System.Windows.Forms.DockStyle.Fill; + this.editor.Location = new System.Drawing.Point(0, 0); + this.editor.Name = "editor"; + this.editor.Size = new System.Drawing.Size(729, 578); + this.editor.TabIndex = 0; + this.editor.TabStop = false; + // + // ScriptEditorForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(729, 578); + this.Controls.Add(this.editor); + this.DoubleBuffered = true; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.Name = "ScriptEditorForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "GZDoom Builder Script Editor"; + this.Load += new System.EventHandler(this.ScriptEditorForm_Load); + this.Shown += new System.EventHandler(this.ScriptEditorForm_Shown); + this.Move += new System.EventHandler(this.ScriptEditorForm_Move); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ScriptEditorForm_FormClosing); + this.HelpRequested += new System.Windows.Forms.HelpEventHandler(this.ScriptEditorForm_HelpRequested); + this.ResizeEnd += new System.EventHandler(this.ScriptEditorForm_ResizeEnd); + this.ResumeLayout(false); } diff --git a/Source/Core/Windows/ThingEditForm.Designer.cs b/Source/Core/Windows/ThingEditForm.Designer.cs index 383b5703..0513fa3d 100644 --- a/Source/Core/Windows/ThingEditForm.Designer.cs +++ b/Source/Core/Windows/ThingEditForm.Designer.cs @@ -50,6 +50,8 @@ namespace CodeImp.DoomBuilder.Windows this.tabeffects = new System.Windows.Forms.TabPage(); this.actiongroup = new System.Windows.Forms.GroupBox(); this.hexenpanel = new System.Windows.Forms.Panel(); + this.arg0str = new System.Windows.Forms.ComboBox(); + this.cbArgStr = new System.Windows.Forms.CheckBox(); this.arg2 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); this.arg1 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); this.arg0 = new CodeImp.DoomBuilder.Controls.ArgumentBox(); @@ -351,6 +353,8 @@ namespace CodeImp.DoomBuilder.Windows this.hexenpanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.hexenpanel.Controls.Add(this.arg0str); + this.hexenpanel.Controls.Add(this.cbArgStr); this.hexenpanel.Controls.Add(this.arg2); this.hexenpanel.Controls.Add(this.arg1); this.hexenpanel.Controls.Add(this.arg0); @@ -366,6 +370,25 @@ namespace CodeImp.DoomBuilder.Windows this.hexenpanel.Size = new System.Drawing.Size(628, 221); this.hexenpanel.TabIndex = 13; // + // arg0str + // + this.arg0str.FormattingEnabled = true; + this.arg0str.Location = new System.Drawing.Point(179, 93); + this.arg0str.Name = "arg0str"; + this.arg0str.Size = new System.Drawing.Size(125, 22); + this.arg0str.TabIndex = 22; + this.arg0str.Leave += new System.EventHandler(this.arg0str_Leave); + // + // cbArgStr + // + this.cbArgStr.Location = new System.Drawing.Point(14, 3); + this.cbArgStr.Name = "cbArgStr"; + this.cbArgStr.Size = new System.Drawing.Size(63, 40); + this.cbArgStr.TabIndex = 21; + this.cbArgStr.Text = "Named script"; + this.cbArgStr.UseVisualStyleBackColor = true; + this.cbArgStr.CheckedChanged += new System.EventHandler(this.cbArgStr_CheckedChanged); + // // arg2 // this.arg2.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -556,6 +579,7 @@ namespace CodeImp.DoomBuilder.Windows this.fieldslist.TypeColumnVisible = true; this.fieldslist.TypeColumnWidth = 100; this.fieldslist.ValueColumnVisible = true; + this.fieldslist.OnFieldValueChanged += new CodeImp.DoomBuilder.Controls.FieldsEditorControl.SingleFieldNameEvent(this.fieldslist_OnFieldValueChanged); // // cancel // @@ -657,5 +681,7 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox posX; + private System.Windows.Forms.CheckBox cbArgStr; + private System.Windows.Forms.ComboBox arg0str; } } \ No newline at end of file diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs index 99e4932e..ef76db11 100644 --- a/Source/Core/Windows/ThingEditForm.cs +++ b/Source/Core/Windows/ThingEditForm.cs @@ -44,10 +44,8 @@ namespace CodeImp.DoomBuilder.Windows #region ================== Variables private ICollection things; - private List nodes; private ThingTypeInfo thinginfo; private bool preventchanges = false; - //mxd private Vector2D initialPosition; //initial position of a thing used to fill posX and posY fields @@ -129,7 +127,13 @@ namespace CodeImp.DoomBuilder.Windows posY.Text = ((int)ft.Position.y).ToString(); posX.ButtonStep = General.Map.Grid.GridSize; posY.ButtonStep = General.Map.Grid.GridSize; - + + //mxd. setup arg0str + arg0str.Location = arg0.Location; + + // Custom fields + fieldslist.SetValues(ft.Fields, true); + // Action/tags action.Value = ft.Action; tag.Text = ft.Tag.ToString(); @@ -139,9 +143,6 @@ namespace CodeImp.DoomBuilder.Windows arg3.SetValue(ft.Args[3]); arg4.SetValue(ft.Args[4]); - // Custom fields - fieldslist.SetValues(ft.Fields, true); - //////////////////////////////////////////////////////////////////////// // Now go for all lines and change the options when a setting is different //////////////////////////////////////////////////////////////////////// @@ -186,6 +187,55 @@ namespace CodeImp.DoomBuilder.Windows preventchanges = false; } + + //mxd + private void setNumberedScripts(Thing t) { + arg0str.Items.Clear(); + + if (General.Map.NumberedScripts.Count > 0) { + foreach (ScriptItem si in General.Map.NumberedScripts) { + arg0str.Items.Add(si); + if (si.Index == t.Args[0]) + arg0str.SelectedIndex = arg0str.Items.Count - 1; + } + + //script number is not among known scripts... + if (arg0str.SelectedIndex == -1 && t.Args[0] > 0) { + arg0str.Items.Add(new ScriptItem(t.Args[0], "Script " + t.Args[0])); + arg0str.SelectedIndex = arg0str.Items.Count - 1; + } + + } else if (t.Args[0] > 0) { + arg0str.Items.Add(new ScriptItem(t.Args[0], "Script " + t.Args[0])); + arg0str.SelectedIndex = 0; + } + } + //mxd + private void setNamedScripts(string selectedValue) { + arg0str.Items.Clear(); + + //update arg0str items + if (General.Map.NamedScripts.Count > 0) { + //dbg + GZBuilder.GZGeneral.Trace("Got " + General.Map.NamedScripts.Count + " script names"); + + ScriptItem[] sn = new ScriptItem[General.Map.NamedScripts.Count]; + General.Map.NamedScripts.CopyTo(sn, 0); + arg0str.Items.AddRange(sn); + + for(int i = 0; i < sn.Length; i++){ + if (sn[i].Name == selectedValue) { + arg0str.SelectedIndex = i; + break; + } + } + //int index = General.Map.NamedScripts.IndexOf(selectedValue); + //if (index != -1) + //arg0str.SelectedIndex = index; + } else { + arg0str.Text = selectedValue; + } + } #endregion @@ -264,22 +314,33 @@ namespace CodeImp.DoomBuilder.Windows // Zero all arguments when linedef action 0 (normal) is chosen if(!preventchanges && (showaction == 0)) { - //mxd. If thing is light, set default light settings - int[] args = GZDoomLight.GetDefaultLightSettings(thingtype.GetResult(1)); - if (args != null) { - arg0.SetValue(args[0]); - arg1.SetValue(args[1]); - arg2.SetValue(args[2]); - arg3.SetValue(args[3]); - arg4.SetValue(args[4]); - } else { - arg0.SetValue(0); - arg1.SetValue(0); - arg2.SetValue(0); - arg3.SetValue(0); - arg4.SetValue(0); - } + //mxd + arg0.SetDefaultValue(); + arg1.SetDefaultValue(); + arg2.SetDefaultValue(); + arg3.SetDefaultValue(); + arg4.SetDefaultValue(); } + + //update arg0str + if (Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, showaction) != -1) { + arg0str.Visible = true; + + if (General.Map.UDMF && fieldslist.GetValue("arg0str") != null) { + cbArgStr.Visible = true; + cbArgStr.Checked = true; + setNamedScripts((string)fieldslist.GetValue("arg0str")); + } else { //use script numbers + cbArgStr.Visible = General.Map.UDMF; + cbArgStr.Checked = false; + Thing t = General.GetByIndex(things, 0); + setNumberedScripts(t); + } + } else { + cbArgStr.Checked = false; + cbArgStr.Visible = false; + arg0str.Visible = false; + } } // Browse Action clicked @@ -333,7 +394,9 @@ namespace CodeImp.DoomBuilder.Windows //mxd Vector2D delta = new Vector2D((float)posX.GetResult((int)initialPosition.x) - initialPosition.x, (float)posY.GetResult((int)initialPosition.y) - initialPosition.y); - + bool hasAcs = Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, action.Value) != -1; + bool hasArg0str = General.Map.UDMF && !action.Empty && hasAcs && arg0str.Text.Length > 0; + // Go for all the things foreach(Thing t in things) { @@ -356,7 +419,16 @@ namespace CodeImp.DoomBuilder.Windows // Action/tags t.Tag = tag.GetResult(t.Tag); if(!action.Empty) t.Action = action.Value; - t.Args[0] = arg0.GetResult(t.Args[0]); + + //mxd + if (hasAcs && !cbArgStr.Checked) { + if(arg0str.SelectedItem != null) + t.Args[0] = ((ScriptItem)arg0str.SelectedItem).Index; + else if(!int.TryParse(arg0str.Text.Trim(), out t.Args[0])) + t.Args[0] = 0; + } else { + t.Args[0] = arg0.GetResult(t.Args[0]); + } t.Args[1] = arg1.GetResult(t.Args[1]); t.Args[2] = arg2.GetResult(t.Args[2]); t.Args[3] = arg3.GetResult(t.Args[3]); @@ -364,6 +436,16 @@ namespace CodeImp.DoomBuilder.Windows // Custom fields fieldslist.Apply(t.Fields); + + //mxd. apply arg0str + if (hasArg0str && cbArgStr.Checked) { + if (t.Fields.ContainsKey("arg0str")) + t.Fields["arg0str"].Value = arg0str.Text; + else + t.Fields.Add("arg0str", new UniValue(2, arg0str.Text)); + } else if (t.Fields.ContainsKey("arg0str")) { + t.Fields.Remove("arg0str"); + } // Update settings t.UpdateConfiguration(); @@ -390,6 +472,30 @@ namespace CodeImp.DoomBuilder.Windows this.Close(); } + //mxd + private void cbArgStr_CheckedChanged(object sender, EventArgs e) { + arg0str.Text = ""; + + if (cbArgStr.Checked){ + setNamedScripts((string)fieldslist.GetValue("arg0str")); + } else if (!cbArgStr.Checked) { + setNumberedScripts(General.GetByIndex(things, 0)); + } + + arg0label.Text = cbArgStr.Checked ? "Script name:" : "Script number:"; + } + + //mxd + private void arg0str_Leave(object sender, EventArgs e) { + if(cbArgStr.Checked) fieldslist.SetValue("arg0str", arg0str.Text, CodeImp.DoomBuilder.Types.UniversalType.String); + } + + //mxd + private void fieldslist_OnFieldValueChanged(string fieldname) { + if (cbArgStr.Checked && fieldname == "arg0str") + arg0str.Text = (string)fieldslist.GetValue(fieldname); + } + // Help private void ThingEditForm_HelpRequested(object sender, HelpEventArgs hlpevent) { diff --git a/Source/Core/Windows/ThingEditForm.resx b/Source/Core/Windows/ThingEditForm.resx index e3212e91..557ae868 100644 --- a/Source/Core/Windows/ThingEditForm.resx +++ b/Source/Core/Windows/ThingEditForm.resx @@ -126,12 +126,18 @@ True + + True + False False + + False + True @@ -210,6 +216,15 @@ True + + True + + + True + + + True + True diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index b00dc81f..4e1f34ab 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -561,10 +561,10 @@ namespace CodeImp.DoomBuilder.BuilderModes } // Time to pick a new target? - if(General.Clock.CurrentTime > (lastpicktime + PICK_INTERVAL)) + if(General.Clock.GetCurrentTime() > (lastpicktime + PICK_INTERVAL)) { PickTargetUnlocked(); - lastpicktime = General.Clock.CurrentTime; + lastpicktime = General.Clock.GetCurrentTime(); } // The mouse is always in motion diff --git a/Source/Plugins/ColorPicker/BuilderPlug.cs b/Source/Plugins/ColorPicker/BuilderPlug.cs index a30d7972..5841cf5d 100644 --- a/Source/Plugins/ColorPicker/BuilderPlug.cs +++ b/Source/Plugins/ColorPicker/BuilderPlug.cs @@ -29,8 +29,8 @@ namespace CodeImp.DoomBuilder.ColorPicker private Point formLocation; //used to keep form's location constant public override void OnInitialize() { - if (GZBuilder.GZGeneral.Version < 1.06f) { - General.ErrorLogger.Add(ErrorType.Error, "ColorPicker plugin: GZDoomBuilder 1.06 or later required!"); + if (GZBuilder.GZGeneral.Version < 1.11f) { + General.ErrorLogger.Add(ErrorType.Error, "ColorPicker plugin: GZDoomBuilder 1.11 or later required!"); return; } @@ -76,7 +76,7 @@ namespace CodeImp.DoomBuilder.ColorPicker form = new LightColorPicker(); } else if (currentModeName == "SectorsMode") { - if (GZBuilder.GZGeneral.UDMF) { + if (General.Map.UDMF) { if (General.Map.Map.SelectedSectorsCount == 0) { General.Interface.DisplayStatus(StatusType.Warning, "Select some sectors first!"); return; @@ -92,17 +92,17 @@ namespace CodeImp.DoomBuilder.ColorPicker if ( ((VisualMode)General.Editing.Mode).GetSelectedVisualThings(true).Count == 0 ) { //check sectors int selectedSectorsCount = ((VisualMode)General.Editing.Mode).GetSelectedVisualSectors(true).Count; - if (GZBuilder.GZGeneral.UDMF && (selectedSectorsCount > 0 || General.Map.Map.SelectedSectorsCount > 0)) { + if (General.Map.UDMF && (selectedSectorsCount > 0 || General.Map.Map.SelectedSectorsCount > 0)) { form = new SectorColorPicker(); } else { - General.Interface.DisplayStatus(StatusType.Warning, "Select some lights " + (GZBuilder.GZGeneral.UDMF ? ", sectors or surfaces " : "") + "first!"); + General.Interface.DisplayStatus(StatusType.Warning, "Select some lights " + (General.Map.UDMF ? ", sectors or surfaces " : "") + "first!"); return; } } else { form = new LightColorPicker(); } } else { //wrong mode - General.Interface.DisplayStatus(StatusType.Warning, "Switch to" + (GZBuilder.GZGeneral.UDMF ? " Sectors," : "") + " Things or GZDoom Visual Mode first!"); + General.Interface.DisplayStatus(StatusType.Warning, "Switch to" + (General.Map.UDMF ? " Sectors," : "") + " Things or GZDoom Visual Mode first!"); return; } diff --git a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs index d79a0b77..c21956dc 100644 --- a/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/GZDoomEditing/VisualModes/BaseVisualMode.cs @@ -767,10 +767,10 @@ namespace CodeImp.DoomBuilder.GZDoomEditing } // Time to pick a new target? - if(General.Clock.CurrentTime > (lastpicktime + PICK_INTERVAL)) + if(General.Clock.GetCurrentTime() > (lastpicktime + PICK_INTERVAL)) { PickTargetUnlocked(); - lastpicktime = General.Clock.CurrentTime; + lastpicktime = General.Clock.GetCurrentTime(); } // The mouse is always in motion diff --git a/Source/Plugins/TagExplorer/BuilderPlug.cs b/Source/Plugins/TagExplorer/BuilderPlug.cs index 403c79cc..1b41d779 100644 --- a/Source/Plugins/TagExplorer/BuilderPlug.cs +++ b/Source/Plugins/TagExplorer/BuilderPlug.cs @@ -44,9 +44,10 @@ namespace CodeImp.DoomBuilder.TagExplorer } // This is called after a map has been closed - public override void OnMapCloseEnd() { + public override void OnMapCloseBegin() { // If we have a Tag Explorer panel, remove it if (tagExplorer != null) { + tagExplorer.Terminate(); General.Interface.RemoveDocker(docker); docker = null; tagExplorer.Dispose(); @@ -57,24 +58,24 @@ namespace CodeImp.DoomBuilder.TagExplorer // Geometry pasted public override void OnPasteEnd(PasteOptions options) { if (tagExplorer != null) - tagExplorer.UpdateTree(); + tagExplorer.UpdateTree(true); } // Undo performed public override void OnUndoEnd() { if (tagExplorer != null) - tagExplorer.UpdateTree(); + tagExplorer.UpdateTree(true); } // Redo performed public override void OnRedoEnd() { if (tagExplorer != null) - tagExplorer.UpdateTree(); + tagExplorer.UpdateTree(true); } public override void OnActionEnd(CodeImp.DoomBuilder.Actions.Action action) { if (tagExplorer != null && action.Name == "builder_deleteitem") - tagExplorer.UpdateTree(); + tagExplorer.UpdateTree(true); } } } diff --git a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs index 1ab1dbe4..ebd3ced1 100644 --- a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs +++ b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs @@ -68,7 +68,6 @@ namespace CodeImp.DoomBuilder.TagExplorer // Disposer protected override void Dispose(bool disposing) { - if (this.ParentForm != null) this.ParentForm.Activated -= ParentForm_Activated; General.Settings.WritePluginSetting("sortmode", cbSortMode.SelectedIndex); General.Settings.WritePluginSetting("displaymode", cbDisplayMode.SelectedIndex); General.Settings.WritePluginSetting("centeronselected", cbCenterOnSelected.Checked); @@ -81,12 +80,14 @@ namespace CodeImp.DoomBuilder.TagExplorer public void Setup() { if (this.ParentForm != null) this.ParentForm.Activated += ParentForm_Activated; - UpdateTree(); + UpdateTree(true); } - public void UpdateTree() { - treeView.Nodes.Clear(); + public void Terminate() { + if (this.ParentForm != null) this.ParentForm.Activated -= ParentForm_Activated; + } + public void UpdateTree(bool focusDisplay) { bool showTags = (currentDisplayMode == DISPLAY_TAGS || currentDisplayMode == DISPLAY_TAGS_AND_ACTIONS); bool showActions = (currentDisplayMode == DISPLAY_ACTIONS || currentDisplayMode == DISPLAY_TAGS_AND_ACTIONS); bool hasComment = false; @@ -101,295 +102,314 @@ namespace CodeImp.DoomBuilder.TagExplorer TreeNode selectedNode = null; + this.SuspendLayout(); + treeView.Nodes.Clear(); + //add things List nodes = new List(); - ICollection things = General.Map.Map.Things; - foreach (Thing t in things) { - if ((showTags && t.Tag > 0) || (showActions && t.Action > 0)) { - if (filteredTag != -1 && t.Tag != filteredTag) - continue; - if (filteredAction != -1 && t.Action != filteredAction) - continue; - - NodeInfo info = new NodeInfo(t); - string name = info.GetName(ref comment, currentSortMode); - hasComment = comment.Length > 0; - if (!hasComment && cbCommentsOnly.Checked) - continue; - - if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { - TreeNode node = new TreeNode(name, 1, 1); - node.Tag = info; - if (hasComment) node.ForeColor = commentColor; - nodes.Add(node); - - if (info.Index == selection.Index && info.Type == selection.Type) - selectedNode = node; - } - } - } - - //sort nodes - sort(ref nodes, currentSortMode); - - //add "things" category - if (nodes.Count > 0) { - if (currentSortMode == SortMode.SORT_BY_ACTION) { //create action categories - Dictionary categories = new Dictionary(); - TreeNode noAction = new TreeNode("No Action", 0, 0); - - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; - - if (nodeInfo.Action == 0) { - noAction.Nodes.Add(node); + if (!(things is MapElementCollection)) { //don't want to enumerate when array is locked + foreach (Thing t in things) { + if ((showTags && t.Tag > 0) || (showActions && t.Action > 0)) { + if (filteredTag != -1 && t.Tag != filteredTag) continue; + if (filteredAction != -1 && t.Action != filteredAction) + continue; + + NodeInfo info = new NodeInfo(t); + string name = info.GetName(ref comment, currentSortMode); + hasComment = comment.Length > 0; + + if (!hasComment && cbCommentsOnly.Checked) + continue; + + if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { + TreeNode node = new TreeNode(name, 1, 1); + node.Tag = info; + if (hasComment) node.ForeColor = commentColor; + nodes.Add(node); + + if (info.Index == selection.Index && info.Type == selection.Type) + selectedNode = node; + } + } + } + + //sort nodes + sort(ref nodes, currentSortMode); + + //add "things" category + if (nodes.Count > 0) { + if (currentSortMode == SortMode.SORT_BY_ACTION) { //create action categories + Dictionary categories = new Dictionary(); + TreeNode noAction = new TreeNode("No Action", 0, 0); + + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; + + if (nodeInfo.Action == 0) { + noAction.Nodes.Add(node); + continue; + } + + LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(nodeInfo.Action); + + if (!categories.ContainsKey(lai.Index)) + categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Name, 0, 0, new TreeNode[] { node })); + else + categories[lai.Index].Nodes.Add(node); } - LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(nodeInfo.Action); + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); + + TreeNode category = new TreeNode(CAT_THINGS, 0, 0, catNodes); + if (noAction.Nodes.Count > 0) + category.Nodes.Add(noAction); + + treeView.Nodes.Add(category); + + } else if (currentSortMode == SortMode.SORT_BY_INDEX) { //create thing categories + Dictionary categories = new Dictionary(); + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; + ThingTypeInfo tti = General.Map.Data.GetThingInfoEx(General.Map.Map.GetThingByIndex(nodeInfo.Index).Type); + + if (tti != null) { + if (!categories.ContainsKey(tti.Category.Title)) + categories.Add(tti.Category.Title, new TreeNode(tti.Category.Title, 0, 0, new TreeNode[] { node })); + else + categories[tti.Category.Title].Nodes.Add(node); + } else { + if (!categories.ContainsKey("UNKNOWN")) + categories.Add("UNKNOWN", new TreeNode("UNKNOWN", 0, 0, new TreeNode[] { node })); + else + categories["UNKNOWN"].Nodes.Add(node); + } + } + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); + + treeView.Nodes.Add(new TreeNode(CAT_THINGS, 0, 0, catNodes)); - if (!categories.ContainsKey(lai.Index)) - categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Name, 0, 0, new TreeNode[] { node })); - else - categories[lai.Index].Nodes.Add(node); } + else { //sort by tag + Dictionary categories = new Dictionary(); + TreeNode noTag = new TreeNode("No Tag", 0, 0); - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; - TreeNode category = new TreeNode(CAT_THINGS, 0, 0, catNodes); - if (noAction.Nodes.Count > 0) - category.Nodes.Add(noAction); + if (nodeInfo.Tag == 0) { + noTag.Nodes.Add(node); + continue; + } - treeView.Nodes.Add(category); - - } else if (currentSortMode == SortMode.SORT_BY_INDEX) { //create thing categories - Dictionary categories = new Dictionary(); - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; - ThingTypeInfo tti = General.Map.Data.GetThingInfoEx(General.Map.Map.GetThingByIndex(nodeInfo.Index).Type); - - if (!categories.ContainsKey(tti.Category.Title)) - categories.Add(tti.Category.Title, new TreeNode(tti.Category.Title, 0, 0, new TreeNode[] { node })); - else - categories[tti.Category.Title].Nodes.Add(node); - } - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); - - treeView.Nodes.Add(new TreeNode(CAT_THINGS, 0, 0, catNodes)); - - } else { //sort by tag - Dictionary categories = new Dictionary(); - TreeNode noTag = new TreeNode("No Tag", 0, 0); - - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; - - if (nodeInfo.Tag == 0) { - noTag.Nodes.Add(node); - continue; + if (!categories.ContainsKey(nodeInfo.Tag)) + categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 0, 0, new TreeNode[] { node })); + else + categories[nodeInfo.Tag].Nodes.Add(node); } - if (!categories.ContainsKey(nodeInfo.Tag)) - categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 0, 0, new TreeNode[] { node })); - else - categories[nodeInfo.Tag].Nodes.Add(node); + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); + + TreeNode category = new TreeNode(CAT_THINGS, 0, 0, catNodes); + if (noTag.Nodes.Count > 0) + category.Nodes.Add(noTag); + + treeView.Nodes.Add(category); } - - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); - - TreeNode category = new TreeNode(CAT_THINGS, 0, 0, catNodes); - if (noTag.Nodes.Count > 0) - category.Nodes.Add(noTag); - - treeView.Nodes.Add(category); } } //add sectors nodes = new List(); ICollection sectors = General.Map.Map.Sectors; - foreach (Sector s in sectors) { - if ((showTags && s.Tag > 0) || (showActions && s.Effect > 0)) { - if (filteredTag != -1 && s.Tag != filteredTag) - continue; - if (filteredAction != -1 && s.Effect != filteredAction) - continue; - - NodeInfo info = new NodeInfo(s); - string name = info.GetName(ref comment, currentSortMode); - hasComment = comment.Length > 0; - if (!hasComment && cbCommentsOnly.Checked) - continue; + if (!(sectors is MapElementCollection)) { //don't want to enumerate when array is locked + foreach (Sector s in sectors) { + if ((showTags && s.Tag > 0) || (showActions && s.Effect > 0)) { + if (filteredTag != -1 && s.Tag != filteredTag) + continue; + if (filteredAction != -1 && s.Effect != filteredAction) + continue; - if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { - TreeNode node = new TreeNode(name, 3, 3); - node.Tag = info; - if (hasComment) node.ForeColor = commentColor; - nodes.Add(node); + NodeInfo info = new NodeInfo(s); + string name = info.GetName(ref comment, currentSortMode); + hasComment = comment.Length > 0; - if (info.Index == selection.Index && info.Type == selection.Type) - selectedNode = node; + if (!hasComment && cbCommentsOnly.Checked) + continue; + + if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { + TreeNode node = new TreeNode(name, 3, 3); + node.Tag = info; + if (hasComment) node.ForeColor = commentColor; + nodes.Add(node); + + if (info.Index == selection.Index && info.Type == selection.Type) + selectedNode = node; + } } } - } - //sort nodes - sort(ref nodes, currentSortMode); + //sort nodes + sort(ref nodes, currentSortMode); - //add category - if (nodes.Count > 0) { - if (currentSortMode == SortMode.SORT_BY_ACTION) { - Dictionary categories = new Dictionary(); - TreeNode noAction = new TreeNode("No Effect", 2, 2); + //add category + if (nodes.Count > 0) { + if (currentSortMode == SortMode.SORT_BY_ACTION) { + Dictionary categories = new Dictionary(); + TreeNode noAction = new TreeNode("No Effect", 2, 2); - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; - if (nodeInfo.Action == 0) { - noAction.Nodes.Add(node); - continue; + if (nodeInfo.Action == 0) { + noAction.Nodes.Add(node); + continue; + } + + SectorEffectInfo sei = General.Map.Config.GetSectorEffectInfo(nodeInfo.Action); + + if (!categories.ContainsKey(sei.Index)) + categories.Add(sei.Index, new TreeNode(sei.Index + " - " + sei.Title, 2, 2, new TreeNode[] { node })); + else + categories[sei.Index].Nodes.Add(node); } + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); - SectorEffectInfo sei = General.Map.Config.GetSectorEffectInfo(nodeInfo.Action); + TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catNodes); + if (noAction.Nodes.Count > 0) + category.Nodes.Add(noAction); - if (!categories.ContainsKey(sei.Index)) - categories.Add(sei.Index, new TreeNode(sei.Index + " - " + sei.Title, 2, 2, new TreeNode[] { node })); - else - categories[sei.Index].Nodes.Add(node); - } - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); + treeView.Nodes.Add(category); + } else if (currentSortMode == SortMode.SORT_BY_TAG) { + Dictionary categories = new Dictionary(); + TreeNode noTag = new TreeNode("No Tag", 2, 2); - TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catNodes); - if (noAction.Nodes.Count > 0) - category.Nodes.Add(noAction); + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; - treeView.Nodes.Add(category); - } else if (currentSortMode == SortMode.SORT_BY_TAG) { - Dictionary categories = new Dictionary(); - TreeNode noTag = new TreeNode("No Tag", 2, 2); + if (nodeInfo.Tag == 0) { + noTag.Nodes.Add(node); + continue; + } - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; - - if (nodeInfo.Tag == 0) { - noTag.Nodes.Add(node); - continue; + if (!categories.ContainsKey(nodeInfo.Tag)) + categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 2, 2, new TreeNode[] { node })); + else + categories[nodeInfo.Tag].Nodes.Add(node); } + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); - if (!categories.ContainsKey(nodeInfo.Tag)) - categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 2, 2, new TreeNode[] { node })); - else - categories[nodeInfo.Tag].Nodes.Add(node); + TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catNodes); + if (noTag.Nodes.Count > 0) + category.Nodes.Add(noTag); + + treeView.Nodes.Add(category); + } else {//just add them as they are + treeView.Nodes.Add(new TreeNode(CAT_SECTORS, 2, 2, nodes.ToArray())); } - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); - - TreeNode category = new TreeNode(CAT_SECTORS, 2, 2, catNodes); - if (noTag.Nodes.Count > 0) - category.Nodes.Add(noTag); - - treeView.Nodes.Add(category); - } else {//just add them as they are - treeView.Nodes.Add(new TreeNode(CAT_SECTORS, 2, 2, nodes.ToArray())); } } //add linedefs nodes = new List(); ICollection linedefs = General.Map.Map.Linedefs; - foreach (Linedef l in linedefs) { - if ((showTags && l.Tag > 0) || (showActions && l.Action > 0)) { - if (filteredTag != -1 && l.Tag != filteredTag) - continue; - if (filteredAction != -1 && l.Action != filteredAction) - continue; - - NodeInfo info = new NodeInfo(l); - string name = info.GetName(ref comment, currentSortMode); - hasComment = comment.Length > 0; - if (!hasComment && cbCommentsOnly.Checked) - continue; + if (!(linedefs is MapElementCollection)) { //don't want to enumerate when array is locked + foreach (Linedef l in linedefs) { + if ((showTags && l.Tag > 0) || (showActions && l.Action > 0)) { + if (filteredTag != -1 && l.Tag != filteredTag) + continue; + if (filteredAction != -1 && l.Action != filteredAction) + continue; - if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { - TreeNode node = new TreeNode(name, 5, 5); - node.Tag = info; - if (hasComment) node.ForeColor = commentColor; - nodes.Add(node); + NodeInfo info = new NodeInfo(l); + string name = info.GetName(ref comment, currentSortMode); + hasComment = comment.Length > 0; - if (info.Index == selection.Index && info.Type == selection.Type) - selectedNode = node; + if (!hasComment && cbCommentsOnly.Checked) + continue; + + if (!udmf || serachStr.Length == 0 || (hasComment && comment.ToLowerInvariant().IndexOf(serachStr) != -1)) { + TreeNode node = new TreeNode(name, 5, 5); + node.Tag = info; + if (hasComment) node.ForeColor = commentColor; + nodes.Add(node); + + if (info.Index == selection.Index && info.Type == selection.Type) + selectedNode = node; + } } } - } - //sort nodes - sort(ref nodes, currentSortMode); + //sort nodes + sort(ref nodes, currentSortMode); - //add category - if (nodes.Count > 0) { - if (currentSortMode == SortMode.SORT_BY_ACTION) { - Dictionary categories = new Dictionary(); - TreeNode noAction = new TreeNode("No Action", 4, 4); + //add category + if (nodes.Count > 0) { + if (currentSortMode == SortMode.SORT_BY_ACTION) { + Dictionary categories = new Dictionary(); + TreeNode noAction = new TreeNode("No Action", 4, 4); - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; - if (nodeInfo.Action == 0) { - noAction.Nodes.Add(node); - continue; + if (nodeInfo.Action == 0) { + noAction.Nodes.Add(node); + continue; + } + + LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(nodeInfo.Action); + + if (!categories.ContainsKey(lai.Index)) + categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Name, 4, 4, new TreeNode[] { node })); + else + categories[lai.Index].Nodes.Add(node); } + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); - LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(nodeInfo.Action); + TreeNode category = new TreeNode(CAT_LINEDEFS, 4, 4, catNodes); + if (noAction.Nodes.Count > 0) + category.Nodes.Add(noAction); - if (!categories.ContainsKey(lai.Index)) - categories.Add(lai.Index, new TreeNode(lai.Index + " - " + lai.Name, 4, 4, new TreeNode[] { node })); - else - categories[lai.Index].Nodes.Add(node); - } - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); + treeView.Nodes.Add(category); - TreeNode category = new TreeNode(CAT_LINEDEFS, 4, 4, catNodes); - if (noAction.Nodes.Count > 0) - category.Nodes.Add(noAction); + } else if (currentSortMode == SortMode.SORT_BY_TAG) { + Dictionary categories = new Dictionary(); + TreeNode noTag = new TreeNode("No Tag", 4, 4); - treeView.Nodes.Add(category); + foreach (TreeNode node in nodes) { + NodeInfo nodeInfo = node.Tag as NodeInfo; - } else if (currentSortMode == SortMode.SORT_BY_TAG) { - Dictionary categories = new Dictionary(); - TreeNode noTag = new TreeNode("No Tag", 4, 4); + if (nodeInfo.Tag == 0) { + noTag.Nodes.Add(node); + continue; + } - foreach (TreeNode node in nodes) { - NodeInfo nodeInfo = node.Tag as NodeInfo; - - if (nodeInfo.Tag == 0) { - noTag.Nodes.Add(node); - continue; + if (!categories.ContainsKey(nodeInfo.Tag)) + categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 4, 4, new TreeNode[] { node })); + else + categories[nodeInfo.Tag].Nodes.Add(node); } + TreeNode[] catNodes = new TreeNode[categories.Values.Count]; + categories.Values.CopyTo(catNodes, 0); - if (!categories.ContainsKey(nodeInfo.Tag)) - categories.Add(nodeInfo.Tag, new TreeNode("Tag " + nodeInfo.Tag, 4, 4, new TreeNode[] { node })); - else - categories[nodeInfo.Tag].Nodes.Add(node); + TreeNode category = new TreeNode(CAT_LINEDEFS, 4, 4, catNodes); + if (noTag.Nodes.Count > 0) + category.Nodes.Add(noTag); + + treeView.Nodes.Add(category); + } else { //just add them as they are + treeView.Nodes.Add(new TreeNode(CAT_LINEDEFS, 4, 4, nodes.ToArray())); } - TreeNode[] catNodes = new TreeNode[categories.Values.Count]; - categories.Values.CopyTo(catNodes, 0); - - TreeNode category = new TreeNode(CAT_LINEDEFS, 4, 4, catNodes); - if (noTag.Nodes.Count > 0) - category.Nodes.Add(noTag); - - treeView.Nodes.Add(category); - } else { //just add them as they are - treeView.Nodes.Add(new TreeNode(CAT_LINEDEFS, 4, 4, nodes.ToArray())); } } @@ -399,9 +419,13 @@ namespace CodeImp.DoomBuilder.TagExplorer if (selectedNode != null) treeView.SelectedNode = selectedNode; + else if (treeView.Nodes.Count > 0) + treeView.SelectedNode = treeView.Nodes[0]; + + this.ResumeLayout(); //loose focus - General.Interface.FocusDisplay(); + if(focusDisplay) General.Interface.FocusDisplay(); } //tag/action search @@ -479,12 +503,12 @@ namespace CodeImp.DoomBuilder.TagExplorer //EVENTS private void cbDisplayMode_SelectedIndexChanged(object sender, EventArgs e) { currentDisplayMode = cbDisplayMode.SelectedItem.ToString(); - UpdateTree(); + UpdateTree(true); } private void cbSortMode_SelectedIndexChanged(object sender, EventArgs e) { currentSortMode = cbSortMode.SelectedItem.ToString(); - UpdateTree(); + UpdateTree(true); } private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { @@ -518,7 +542,7 @@ namespace CodeImp.DoomBuilder.TagExplorer } General.Map.Map.Update(); - UpdateTree(); + UpdateTree(true); } else { //select element? @@ -646,9 +670,9 @@ namespace CodeImp.DoomBuilder.TagExplorer General.Interface.FocusDisplay(); } - //it is called every time a dialog window closes. + //It is called every time a dialog window closes. private void ParentForm_Activated(object sender, EventArgs e){ - UpdateTree(); + UpdateTree(true); } private void btnClearSearch_Click(object sender, EventArgs e) { @@ -657,11 +681,11 @@ namespace CodeImp.DoomBuilder.TagExplorer } private void tbSearch_TextChanged(object sender, EventArgs e) { - if (tbSearch.Text.Length > 1 || tbSearch.Text.Length == 0) UpdateTree(); + if (tbSearch.Text.Length > 1 || tbSearch.Text.Length == 0) UpdateTree(false); } private void cbCommentsOnly_CheckedChanged(object sender, EventArgs e) { - UpdateTree(); + UpdateTree(true); } } diff --git a/Source/Plugins/TagExplorer/NodeInfo.cs b/Source/Plugins/TagExplorer/NodeInfo.cs index 4405466d..68c20e36 100644 --- a/Source/Plugins/TagExplorer/NodeInfo.cs +++ b/Source/Plugins/TagExplorer/NodeInfo.cs @@ -186,7 +186,7 @@ namespace CodeImp.DoomBuilder.TagExplorer string combinedName = ""; switch (sortMode) { case SortMode.SORT_BY_ACTION: - combinedName = (action > 0 ? "Action:" + action + "; " : "") + (tag > 0 ? "Tag:" + tag + "; " : "") + name + (isDefaultName ? " " + index : ""); + combinedName = (tag > 0 ? "Tag:" + tag + "; " : "") + name + (isDefaultName ? " " + index : ""); break; case SortMode.SORT_BY_INDEX: @@ -194,7 +194,7 @@ namespace CodeImp.DoomBuilder.TagExplorer break; case SortMode.SORT_BY_TAG: - combinedName = (tag > 0 ? "Tag:" + tag + "; " : "") + (action > 0 ? "Action:" + action + "; " : "") + name + (isDefaultName ? " " + index : ""); + combinedName = (action > 0 ? "Action:" + action + "; " : "") + name + (isDefaultName ? " " + index : ""); break; default: diff --git a/Source/Plugins/UMDFControls/BuilderPlug.cs b/Source/Plugins/UMDFControls/BuilderPlug.cs index d70fbc45..5ec1ea6c 100644 --- a/Source/Plugins/UMDFControls/BuilderPlug.cs +++ b/Source/Plugins/UMDFControls/BuilderPlug.cs @@ -22,8 +22,8 @@ namespace CodeImp.DoomBuilder.UDMFControls private Point formLocation; //used to keep form's location constant public override void OnInitialize() { - if (GZBuilder.GZGeneral.Version < 1.09f) { - General.ErrorLogger.Add(ErrorType.Error, "UDMFControls plugin: GZDoomBuilder 1.09 or later required!"); + if (GZBuilder.GZGeneral.Version < 1.11f) { + General.ErrorLogger.Add(ErrorType.Error, "UDMFControls plugin: GZDoomBuilder 1.11 or later required!"); return; } @@ -65,7 +65,7 @@ namespace CodeImp.DoomBuilder.UDMFControls if (General.Editing.Mode == null) return; - if (!GZBuilder.GZGeneral.UDMF) { + if (!General.Map.UDMF) { General.Interface.DisplayStatus(StatusType.Warning, "Map in UDMF format required!"); return; } @@ -102,4 +102,4 @@ namespace CodeImp.DoomBuilder.UDMFControls form = null; } } -} +} \ No newline at end of file