From 988ef7de3cb4ee724b9c9cb511b8ced0e3f1d40a Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Fri, 15 Jul 2016 14:07:30 +0000
Subject: [PATCH] Added "flagsrename" Game configurations property. It allows
 to override Thing flag names for specific things. Added, Automap mode: added
 "Show locks" button (available in Hexen and UDMF map formats only). Updated
 documentation.

---
 Build/Configurations/Includes/ZDoom_misc.cfg  |  25 +
 .../Configurations/Includes/ZDoom_things.cfg  |   5 +
 Help/gc_thingsettings.html                    |  85 ++-
 Help/gzdb/text_lumps.html                     |  11 +-
 Source/Core/Config/ThingTypeInfo.cs           |  32 +-
 Source/Core/Controls/ThingInfoPanel.cs        |  13 +-
 Source/Core/Data/DataManager.cs               |  22 +-
 Source/Core/Windows/ThingEditForm.cs          |  55 ++
 Source/Core/Windows/ThingEditFormUDMF.cs      |  56 +-
 Source/Core/ZDoom/LockDefsParser.cs           |  73 ++-
 Source/Plugins/AutomapMode/AutomapMode.cs     | 542 ++++++++++--------
 Source/Plugins/AutomapMode/AutomapMode.csproj |   3 +
 .../Interface/MenusForm.Designer.cs           |  58 +-
 .../AutomapMode/Interface/MenusForm.cs        |   9 +
 .../Properties/Resources.Designer.cs          |   9 +-
 .../AutomapMode/Properties/Resources.resx     |   7 +-
 .../AutomapMode/Resources/ShowLocks.png       | Bin 0 -> 1267 bytes
 17 files changed, 685 insertions(+), 320 deletions(-)
 create mode 100644 Source/Plugins/AutomapMode/Resources/ShowLocks.png

diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg
index 676295848..7e8b65744 100644
--- a/Build/Configurations/Includes/ZDoom_misc.cfg
+++ b/Build/Configurations/Includes/ZDoom_misc.cfg
@@ -175,6 +175,31 @@ thingflagscompare_udmf
 	}
 }
 
+//mxd. SectorAction flags renaming
+secact_flagsrename
+{
+	DoomMapSetIO
+	{
+		8 = "Monsters activate";
+	}
+	
+	HexenMapSetIO
+	{
+		8 = "Monsters activate";
+		16 = "Projectiles activate";
+		8192 = "Players can't activate";
+		16384 = "Activate once only";
+	}
+	
+	UniversalMapSetIO
+	{
+		ambush = "Monsters activate";
+		dormant = "Projectiles activate";
+		strifeally = "Players can't activate";
+		standing = "Activate once only";
+	}
+}
+
 // Default sector brightness levels
 sectorbrightness
 {
diff --git a/Build/Configurations/Includes/ZDoom_things.cfg b/Build/Configurations/Includes/ZDoom_things.cfg
index 13740cdc1..cbf355d44 100644
--- a/Build/Configurations/Includes/ZDoom_things.cfg
+++ b/Build/Configurations/Includes/ZDoom_things.cfg
@@ -757,30 +757,35 @@ zdoom
 		{
 			title = "Actor enters sector";
 			class = "SecActEnter";
+			flagsrename { include("ZDoom_misc.cfg", "secact_flagsrename") }
 		} 
 		
 		9989
 		{
 			title = "Actor hits fake floor";
 			class = "SecActHitFakeFloor";
+			flagsrename { include("ZDoom_misc.cfg", "secact_flagsrename") }
 		}
 		
 		9996
 		{
 			title = "Actor hits ceiling";
 			class = "SecActHitCeil";
+			flagsrename { include("ZDoom_misc.cfg", "secact_flagsrename") }
 		}
 		
 		9999
 		{
 			title = "Actor hits floor";
 			class = "SecActHitFloor";
+			flagsrename { include("ZDoom_misc.cfg", "secact_flagsrename") }
 		} 
 		
 		9997
 		{
 			title = "Actor leaves sector";
 			class = "SecActExit";
+			flagsrename { include("ZDoom_misc.cfg", "secact_flagsrename") }
 		}
 		
 		9982
diff --git a/Help/gc_thingsettings.html b/Help/gc_thingsettings.html
index 3df49c819..db75c8a26 100644
--- a/Help/gc_thingsettings.html
+++ b/Help/gc_thingsettings.html
@@ -22,25 +22,23 @@
     This defines what the default flags should be first the first new thing when inserted. In map formats that use numeric thing flags, the settings in this structure should be the numeric flags to set. In map formats that use named flags, the settings must be the names of the flags to set. The value of the settings is optional and is ignored by Doom Builder.<br />
     <br />
     Example for numeric flags:
-  <pre>
-defaultthingflags
+  <pre>defaultthingflags
 {
-	1;
-	2;
-	4;
-	32;
+  1;
+  2;
+  4;
+  32;
 }
 </pre>
   <br />
   Example for named flags:
-  <pre>
-defaultthingflags
+  <pre>defaultthingflags
 {
-	skill1;
-	skill2;
-	skill3;
-	single;
-	coop;
+  skill1;
+  skill2;
+  skill3;
+  single;
+  coop;
 }
 </pre>
   <br />
@@ -51,16 +49,16 @@ defaultthingflags
   <pre>        
 thingrenderstyles
 {
-	normal = "Normal";
-	translucent = "Translucent";
-	soultrans = "Translucent (Lost Soul)";
-	translucentstencil = "Translucent (stencil)";
-	add = "Additive";
-	subtract = "Subtractive";
-	stencil = "Stencil";
-	fuzzy = "Fuzzy";
-	optfuzzy = "Fuzzy/Shadow (uses r_drawfuzz CVAR)";
-	none = "None";
+  normal = "Normal";
+  translucent = "Translucent";
+  soultrans = "Translucent (Lost Soul)";
+  translucentstencil = "Translucent (stencil)";
+  add = "Additive";
+  subtract = "Subtractive";
+  stencil = "Stencil";
+  fuzzy = "Fuzzy";
+  optfuzzy = "Fuzzy/Shadow (uses r_drawfuzz CVAR)";
+  none = "None";
 }
 </pre>
   <br />
@@ -166,13 +164,46 @@ thingrenderstyles
   When set to true, the sprite set in the Game Configuration will be used even if a DECORATE actor definition of this thing contains a different sprite.<br />
   <br />
   <b class="fat">class</b> (string) - <span class="red">GZDB only</span>.<br />
-  Sets  DECORATE class name, which corresponds to this thing. Used internally to attach models and dynamic lights to given thing and when looking for an actor class to inherit from in DECORATE parser.<br />
+  Sets DECORATE class name, which corresponds to this thing. Used internally to attach models and dynamic lights to given thing and when looking for an actor class to inherit from in DECORATE parser.<br />
   <strong>Example:</strong>
   <pre>3001
 {
-    title = "Imp";
-    sprite = "TROOA2A8";
-    <span class="blue">class = "DoomImp";</span>
+  title = "Imp";
+  sprite = "TROOA2A8";
+  <span class="blue">class = "DoomImp";</span>
+}</pre>
+<br />
+  <b class="fat">locksprite</b> (boolean) - <span class="red">GZDB only</span>.<br />
+  When set to true, the sprite set in the Game Configuration will be used even if a DECORATE actor definition of this thing contains a different sprite.<br />
+  <br />
+  <b class="fat">flagsrename</b> (structure) - <span class="red">GZDB only</span>.<br />
+  Allows to specify custom flag names for specific Things for every supported map format.<br />
+  <strong>Example:</strong>
+  <pre>9998
+{
+  title = "Actor enters sector";
+  class = "SecActEnter";
+  <span class="blue">flagsrename
+  {
+    DoomMapSetIO
+    {
+      8 = "Monsters activate";
+    }
+    HexenMapSetIO
+    {
+      8 = "Monsters activate";
+      16 = "Projectiles activate";
+      8192 = "Players can't activate";
+      16384 = "Activate once only";
+    }
+    UniversalMapSetIO
+    {
+      ambush = "Monsters activate";
+      dormant = "Projectiles activate";
+      strifeally = "Players can't activate";
+      standing = "Activate once only";
+    }
+  }</span>
 }</pre>
 <br />
 <span class="big">Thing argument definitions:</span><br />
diff --git a/Help/gzdb/text_lumps.html b/Help/gzdb/text_lumps.html
index 0d75e11f5..8f8a50131 100644
--- a/Help/gzdb/text_lumps.html
+++ b/Help/gzdb/text_lumps.html
@@ -63,7 +63,8 @@
     Sound Sequence and Sound Sequence Group definitions are loaded and can be selected in the "Sound sequence" drop-down of the Edit Sector window (UDMF only). 
     
     <h2>LOCKDEFS:</h2>
-    Lock definitions are loaded. The values are used to  populate &quot;<strong>keys</strong>&quot; Game Configuration enum.
+    Lock definitions are loaded. The values are used to  populate &quot;<strong>keys</strong>&quot; Game Configuration enum.<br />
+    You can specify a lock title by adding &quot;<strong>//$Title</strong>&quot; special comment inside a lock's definition body.
     <h2>TERRAIN:</h2>
     Terrain names are loaded and used in the floor and ceiling "Terrain" drop-downs of the Edit Sector window (UDMF only).
     
@@ -91,12 +92,12 @@
     <p>If you are creating maps for Doom or Doom 2, you probably don't need to read this, since required information is already added for those games.<br />
       <br />
 	  <b>To load models or dynamic lights defined in GLDEFS for things defined in configuration files:</b><br />
-	  To display a model instead of a thing sprite, or to attach a light defined in GLDEFS, GZDB needs to know a thing's class name (because that's how overrides are defined in MODELDEF and GLDEFS). Things defined in Doom Builder configuration files don't have this value. So, if you aren't using configs, which came with GZDoom Builder, or you are creating maps for games other than Doom and Doom 2, you'll need to add a new value named "class" to thing definition in game configuration:<br />
+	  To display a model instead of a thing sprite, or to attach a light defined in GLDEFS, GZDB needs to know a thing's class name (because that's how overrides are defined in MODELDEF and GLDEFS). Things defined in Doom Builder configuration files don't have this value. So, if you aren't using configs, which came with GZDoom Builder, or you are creating maps for games other than Doom and Doom 2, you'll need to add a new value named "class" to thing definition in game configuration:
 <pre>3001
 {
-    title = "Imp";
-    sprite = "TROOA2A8";
-    <span class="blue">class = "DoomImp";</span> // <- you'll need to add this value
+  title = "Imp";
+  sprite = "TROOA2A8";
+  <span class="blue">class = "DoomImp";</span> // <- you'll need to add this value
 }</pre>
  <br>
  You can find all thing class names at <a href="http://www.zdoom.org/wiki/Classes">http://www.zdoom.org/wiki/Classes</a>.</p>
diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs
index 23d8b8133..4081155aa 100644
--- a/Source/Core/Config/ThingTypeInfo.cs
+++ b/Source/Core/Config/ThingTypeInfo.cs
@@ -17,6 +17,7 @@
 #region ================== Namespaces
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Drawing;
 using System.Globalization;
@@ -85,6 +86,7 @@ namespace CodeImp.DoomBuilder.Config
 		private readonly bool locksprite; //mxd
 		private bool obsolete; //mxd
 		private string obsoletemessage; //mxd
+		private Dictionary<string, Dictionary<string, string>> flagsrename; //mxd. <MapSetIOName, <flag, title>>
 
 		//mxd. GZDoom rendering properties
 		private ThingRenderMode rendermode;
@@ -126,6 +128,7 @@ namespace CodeImp.DoomBuilder.Config
 		public SizeF SpriteScale { get { return spritescale; } }
 		public string ClassName { get { return classname; } } //mxd. Need this to add model overrides for things defined in configs
 		public string LightName { get { return lightname; } } //mxd
+		public Dictionary<string, string> FlagsRename { get { return flagsrename.ContainsKey(General.Map.Config.FormatInterface) ? flagsrename[General.Map.Config.FormatInterface] : null ; } } //mxd
 
 		//mxd. GZDoom rendering properties
 		public ThingRenderMode RenderMode { get { return rendermode; } }
@@ -168,6 +171,7 @@ namespace CodeImp.DoomBuilder.Config
 			this.absolutez = false;
 			this.xybillboard = false;
 			this.locksprite = false; //mxd
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); //mxd
 			
 			// We have no destructor
 			GC.SuppressFinalize(this);
@@ -207,6 +211,28 @@ namespace CodeImp.DoomBuilder.Config
 			this.spritescale = new SizeF(sscale, sscale);
 			this.locksprite = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".locksprite", false); //mxd
 			this.classname = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".class", String.Empty); //mxd
+
+			//mxd. Read flagsrename
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
+			IDictionary maindic = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".flagsrename", new Hashtable());
+			foreach(DictionaryEntry de in maindic)
+			{
+				string ioname = de.Key.ToString().ToLowerInvariant();
+				switch(ioname)
+				{
+					case "doommapsetio":
+					case "hexenmapsetio":
+					case "universalmapsetio":
+						IDictionary flagdic = de.Value as IDictionary;
+						if(flagdic == null) continue;
+						flagsrename.Add(ioname, new Dictionary<string, string>());
+						foreach(DictionaryEntry fe in flagdic)
+							flagsrename[ioname].Add(fe.Key.ToString(), fe.Value.ToString());
+						break;
+
+					default: throw new NotImplementedException("Unsupported MapSetIO");
+				}
+			}
 			
 			// Read the args
 			for(int i = 0; i < Linedef.NUM_ARGS; i++)
@@ -254,7 +280,8 @@ namespace CodeImp.DoomBuilder.Config
 			this.fixedrotation = cat.FixedRotation; //mxd
 			this.absolutez = cat.AbsoluteZ;
 			this.spritescale = new SizeF(cat.SpriteScale, cat.SpriteScale);
-			this.locksprite = false;
+			this.locksprite = false; //mxd
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); //mxd
 
 			// Safety
 			if(this.radius < 4f || this.fixedsize) this.radius = THING_FIXED_SIZE;
@@ -298,6 +325,7 @@ namespace CodeImp.DoomBuilder.Config
 			this.fixedrotation = cat.FixedRotation; //mxd
 			this.absolutez = cat.AbsoluteZ;
 			this.spritescale = new SizeF(cat.SpriteScale, cat.SpriteScale);
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); //mxd
 
 			// Safety
 			if(this.hangs && this.absolutez) this.hangs = false; //mxd
@@ -344,6 +372,7 @@ namespace CodeImp.DoomBuilder.Config
 			this.fixedrotation = cat.FixedRotation; //mxd
 			this.absolutez = cat.AbsoluteZ;
 			this.spritescale = new SizeF(cat.SpriteScale, cat.SpriteScale);
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); //mxd
 
 			// Safety
 			if(this.hangs && this.absolutez) this.hangs = false; //mxd
@@ -393,6 +422,7 @@ namespace CodeImp.DoomBuilder.Config
 			this.absolutez = other.absolutez;
 			this.xybillboard = other.xybillboard; //mxd
 			this.spritescale = new SizeF(other.spritescale.Width, other.spritescale.Height);
+			this.flagsrename = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); //mxd
 
 			//mxd. Copy GZDoom rendering properties
 			this.rendermode = other.rendermode;
diff --git a/Source/Core/Controls/ThingInfoPanel.cs b/Source/Core/Controls/ThingInfoPanel.cs
index 3a5f993ad..6d469d3e6 100644
--- a/Source/Core/Controls/ThingInfoPanel.cs
+++ b/Source/Core/Controls/ThingInfoPanel.cs
@@ -153,8 +153,8 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 
 			// Apply script args?
-			Label[] arglabels = new[] { arglbl1, arglbl2, arglbl3, arglbl4, arglbl5 };
-			Label[] args = new[] { arg1, arg2, arg3, arg4, arg5 };
+			Label[] arglabels = { arglbl1, arglbl2, arglbl3, arglbl4, arglbl5 };
+			Label[] args = { arg1, arg2, arg3, arg4, arg5 };
 
 			if(scriptitem != null)
 			{
@@ -195,10 +195,17 @@ namespace CodeImp.DoomBuilder.Controls
 
 			//mxd. Flags
 			flags.Items.Clear();
+			Dictionary<string, string> flagsrename = ti.FlagsRename;
 			foreach(KeyValuePair<string, string> group in General.Map.Config.ThingFlags)
 			{
 				if(t.Flags.ContainsKey(group.Key) && t.Flags[group.Key])
-					flags.Items.Add(new ListViewItem(group.Value) { Checked = true });
+				{
+					ListViewItem lvi = (flagsrename != null && flagsrename.ContainsKey(group.Key)) 
+						? new ListViewItem(flagsrename[group.Key]) { ForeColor = SystemColors.HotTrack } 
+						: new ListViewItem(group.Value);
+					lvi.Checked = true;
+					flags.Items.Add(lvi);
+				}
 			}
 
 			//mxd. Flags panel visibility and size
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index 93fb5aab4..6f26d7122 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -105,6 +105,8 @@ namespace CodeImp.DoomBuilder.Data
 		private string[] damagetypes;
 		private Dictionary<string, PixelColor> knowncolors; // Colors parsed from X11R6RGB lump. Color names are lowercase without spaces
 		private CvarsCollection cvars; // Variables parsed from CVARINFO
+		private Dictionary<int, PixelColor> lockcolors; // Lock colors defined in LOCKDEFS
+		private Dictionary<int, int> lockableactions; // <Action number, arg referenceing "keys" enum number>
 
 		//mxd. Text resources
 		private Dictionary<ScriptType, HashSet<TextResource>> textresources; 
@@ -168,6 +170,8 @@ namespace CodeImp.DoomBuilder.Data
 		public Dictionary<string, PixelColor> KnownColors { get { return knowncolors; } }
 		internal Dictionary<ScriptType, HashSet<TextResource>> TextResources { get { return textresources; } }
 		internal CvarsCollection CVars { get { return cvars; } }
+		public Dictionary<int, PixelColor> LockColors { get { return lockcolors; } }
+		public Dictionary<int, int> LockableActions { get { return lockableactions; } }
 
 		//mxd
 		internal IEnumerable<DataReader> Containers { get { return containers; } }
@@ -2798,6 +2802,7 @@ namespace CodeImp.DoomBuilder.Data
 
 			// Apply to the enums list?
 			EnumList keys = parser.GetLockDefs();
+			lockableactions = new Dictionary<int, int>();
 			if(keys.Count > 0)
 			{
 				keys.Insert(0, new EnumItem("0", "None"));
@@ -2812,9 +2817,22 @@ namespace CodeImp.DoomBuilder.Data
 
 				foreach(LinedefActionInfo info in General.Map.Config.LinedefActions.Values)
 				{
-					foreach(ArgumentInfo ai in info.Args)
-						if(ai.Enum.Name == "keys") ai.Enum = General.Map.Config.Enums["keys"];
+					for(int i = 0; i < info.Args.Length; i++)
+					{
+						if(info.Args[i].Enum.Name == "keys")
+						{
+							info.Args[i].Enum = General.Map.Config.Enums["keys"];
+							lockableactions[info.Index] = i;
+						}
+					}
 				}
+
+				// Also store lock colors
+				lockcolors = parser.MapColors;
+			}
+			else
+			{
+				lockcolors = new Dictionary<int, PixelColor>();
 			}
 		}
 
diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs
index 76dc045fc..5a18300cf 100644
--- a/Source/Core/Windows/ThingEditForm.cs
+++ b/Source/Core/Windows/ThingEditForm.cs
@@ -50,6 +50,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private bool undocreated; //mxd
 		private static bool useabsoluteheight; //mxd
 		private List<ThingProperties> thingprops; //mxd
+		private Dictionary<string, string> flagsrename; //mxd
 
 		//mxd. Window setup stuff
 		private static Point location = Point.Empty;
@@ -186,6 +187,9 @@ namespace CodeImp.DoomBuilder.Windows
 			posY.ButtonStep = General.Map.Grid.GridSize;
 			posZ.ButtonStep = General.Map.Grid.GridSize;
 
+			//mxd
+			thinginfo = General.Map.Data.GetThingInfoEx(ft.Type);
+
 			// Action/tags
 			action.Value = ft.Action;
 			if(General.Map.FormatInterface.HasThingTag) //mxd
@@ -213,7 +217,10 @@ namespace CodeImp.DoomBuilder.Windows
 				ThingTypeInfo info = thingtype.GetSelectedInfo(); //mxd
 
 				if(info != null && info.Index != t.Type)
+				{
 					thingtype.ClearSelectedType();
+					thinginfo = null; //mxd
+				}
 				
 				// Flags
 				foreach(CheckBox c in flags.Checkboxes)
@@ -263,6 +270,7 @@ namespace CodeImp.DoomBuilder.Windows
 
 			argscontrol.UpdateScriptControls(); //mxd
 			actionhelp.UpdateAction(action.GetValue()); //mxd
+			UpdateFlagNames(); //mxd
 		}
 
 		//mxd
@@ -274,6 +282,51 @@ namespace CodeImp.DoomBuilder.Windows
 			//mxd. Make undo
 			General.Map.UndoRedo.CreateUndo("Edit " + (things.Count > 1 ? things.Count + " things" : "thing"));
 		}
+
+		//mxd
+		private void UpdateFlagNames()
+		{
+			Dictionary<string, string> newflagsrename = (thinginfo != null ? thinginfo.FlagsRename : null);
+
+			// Update flag names?
+			if(flagsrename != null || newflagsrename != null)
+			{
+				flags.SuspendLayout();
+
+				// Restore default flags?
+				if(flagsrename != null)
+				{
+					foreach(CheckBox cb in flags.Checkboxes)
+					{
+						string flag = cb.Tag.ToString();
+						if(flagsrename.ContainsKey(flag))
+						{
+							cb.Text = General.Map.Config.ThingFlags[flag];
+							cb.ForeColor = SystemColors.WindowText;
+						}
+					}
+				}
+
+				// Apply new renaming?
+				if(newflagsrename != null)
+				{
+					foreach(CheckBox cb in flags.Checkboxes)
+					{
+						string flag = cb.Tag.ToString();
+						if(newflagsrename.ContainsKey(flag))
+						{
+							cb.Text = newflagsrename[flag];
+							cb.ForeColor = SystemColors.HotTrack;
+						}
+					}
+				}
+
+				flags.ResumeLayout();
+			}
+
+			// Store current flag names
+			flagsrename = newflagsrename;
+		}
 		
 		#endregion
 
@@ -569,6 +622,8 @@ namespace CodeImp.DoomBuilder.Windows
 				t.UpdateConfiguration();
 			}
 
+			UpdateFlagNames(); //mxd
+
 			General.Map.IsChanged = true;
 			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
diff --git a/Source/Core/Windows/ThingEditFormUDMF.cs b/Source/Core/Windows/ThingEditFormUDMF.cs
index 8f3350aa9..df08d4509 100644
--- a/Source/Core/Windows/ThingEditFormUDMF.cs
+++ b/Source/Core/Windows/ThingEditFormUDMF.cs
@@ -51,6 +51,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private static bool useabsoluteheight; //mxd
 		private List<ThingProperties> thingprops; //mxd
 		private readonly string[] renderstyles; //mxd
+		private Dictionary<string, string> flagsrename; //mxd
 
 		//mxd. Window setup stuff
 		private static Point location = Point.Empty;
@@ -207,6 +208,7 @@ namespace CodeImp.DoomBuilder.Windows
 			ThingTypeInfo fti = General.Map.Data.GetThingInfoEx(ft.Type);
 			if(fti != null && fti.Actor != null && fti.Actor.UserVars.Count > 0)
 				fieldslist.SetUserVars(fti.Actor.UserVars, ft.Fields, true);
+			thinginfo = fti; //mxd
 
 			// Custom fields
 			fieldslist.SetValues(ft.Fields, true);
@@ -245,7 +247,11 @@ namespace CodeImp.DoomBuilder.Windows
 
 				// Type does not match?
 				ThingTypeInfo info = thingtype.GetSelectedInfo(); //mxd
-				if(info != null && info.Index != t.Type) thingtype.ClearSelectedType();
+				if(info != null && info.Index != t.Type)
+				{
+					thingtype.ClearSelectedType();
+					thinginfo = null; //mxd
+				}
 
 				// Flags
 				foreach(CheckBox c in flags.Checkboxes) 
@@ -324,6 +330,7 @@ namespace CodeImp.DoomBuilder.Windows
 			actionhelp.UpdateAction(action.GetValue()); //mxd
 			labelScale.Enabled = scale.NonDefaultValue; //mxd
 			commenteditor.FinishSetup(); //mxd
+			UpdateFlagNames(); //mxd
 		}
 
 		//mxd
@@ -337,6 +344,51 @@ namespace CodeImp.DoomBuilder.Windows
 			foreach(Thing t in things) t.Fields.BeforeFieldsChange();
 		}
 
+		//mxd
+		private void UpdateFlagNames()
+		{
+			Dictionary<string, string> newflagsrename = (thinginfo != null ? thinginfo.FlagsRename : null);
+			
+			// Update flag names?
+			if(flagsrename != null || newflagsrename != null)
+			{
+				flags.SuspendLayout();
+
+				// Restore default flags?
+				if(flagsrename != null)
+				{
+					foreach(CheckBox cb in flags.Checkboxes)
+					{
+						string flag = cb.Tag.ToString();
+						if(flagsrename.ContainsKey(flag))
+						{
+							cb.Text = General.Map.Config.ThingFlags[flag];
+							cb.ForeColor = SystemColors.WindowText;
+						}
+					}
+				}
+
+				// Apply new renaming?
+				if(newflagsrename != null)
+				{
+					foreach(CheckBox cb in flags.Checkboxes)
+					{
+						string flag = cb.Tag.ToString();
+						if(newflagsrename.ContainsKey(flag))
+						{
+							cb.Text = newflagsrename[flag];
+							cb.ForeColor = SystemColors.HotTrack;
+						}
+					}
+				}
+
+				flags.ResumeLayout();
+			}
+
+			// Store current flag names
+			flagsrename = newflagsrename;
+		}
+
 		#endregion
 
 		#region ================== Events
@@ -710,6 +762,8 @@ namespace CodeImp.DoomBuilder.Windows
 				t.UpdateConfiguration();
 			}
 
+			UpdateFlagNames(); //mxd
+
 			General.Map.IsChanged = true;
 			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
diff --git a/Source/Core/ZDoom/LockDefsParser.cs b/Source/Core/ZDoom/LockDefsParser.cs
index 4ff8cf603..ef50e2360 100644
--- a/Source/Core/ZDoom/LockDefsParser.cs
+++ b/Source/Core/ZDoom/LockDefsParser.cs
@@ -1,6 +1,7 @@
 using System.Collections.Generic;
 using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Data;
+using CodeImp.DoomBuilder.Rendering;
 
 namespace CodeImp.DoomBuilder.ZDoom
 {
@@ -9,10 +10,14 @@ namespace CodeImp.DoomBuilder.ZDoom
 		internal override ScriptType ScriptType { get { return ScriptType.LOCKDEFS; } }
 
 		private Dictionary<int, string> locks;
+		private Dictionary<int, PixelColor> mapcolors;
+
+		public Dictionary<int, PixelColor> MapColors { get { return mapcolors; } }
 
 		public LockDefsParser()
 		{
 			locks = new Dictionary<int, string>();
+			mapcolors = new Dictionary<int, PixelColor>();
 		}
 
 		public override bool Parse(TextResourceData data, bool clearerrors)
@@ -32,6 +37,8 @@ namespace CodeImp.DoomBuilder.ZDoom
 			string locktitle = string.Empty;
 			string game = string.Empty;
 			int bracelevel = 0;
+			long lockstartpos = -1;
+			PixelColor mapcolor = new PixelColor();
 
 			while(SkipWhitespace(true))
 			{
@@ -64,10 +71,13 @@ namespace CodeImp.DoomBuilder.ZDoom
 						//wiki: The locknumber must be in the 1-to-255 range
 						if(locknum < 1 || locknum > 255)
 						{
-							ReportError("The locknumber must be in the 1-to-255 range, but is " + locknum);
+							ReportError("The locknumber must be in the [1 .. 255] range, but is " + locknum);
 							return false;
 						}
 
+						// Store position
+						lockstartpos = datastream.Position;
+
 						SkipWhitespace(true);
 						token = ReadToken().ToLowerInvariant();
 						if(!string.IsNullOrEmpty(token))
@@ -93,6 +103,51 @@ namespace CodeImp.DoomBuilder.ZDoom
 						locktitle = StripQuotes(ReadToken(false));
 						break;
 
+					// Mapcolor r g b
+					case "mapcolor":
+						int r = 0;
+						int g = 0;
+						int b = 0;
+
+						SkipWhitespace(false);
+						if(!ReadSignedInt(ref r))
+						{
+							ReportError("Expected Mapcolor Red value");
+							return false;
+						}
+						if(r < 0 || r > 255)
+						{
+							ReportError("Mapcolor Red value must be in [0 .. 255] range, but is " + r);
+							return false;
+						}
+
+						SkipWhitespace(false);
+						if(!ReadSignedInt(ref g))
+						{
+							ReportError("Expected Mapcolor Green value");
+							return false;
+						}
+						if(g < 0 || g > 255)
+						{
+							ReportError("Mapcolor Green value must be in [0 .. 255] range, but is " + g);
+							return false;
+						}
+
+						SkipWhitespace(false);
+						if(!ReadSignedInt(ref b))
+						{
+							ReportError("Expected Mapcolor Blue value");
+							return false;
+						}
+						if(b < 0 || b > 255)
+						{
+							ReportError("Mapcolor Blue value must be in [0 .. 255] range, but is " + b);
+							return false;
+						}
+
+						mapcolor = new PixelColor(255, (byte)r, (byte)g, (byte)b);
+						break;
+
 					case "{":
 						bracelevel++;
 						break;
@@ -104,18 +159,32 @@ namespace CodeImp.DoomBuilder.ZDoom
 						if(locknum > 0 && (string.IsNullOrEmpty(game) || General.Map.Config.BaseGame == game))
 						{
 							// No custom title given?
-							if(string.IsNullOrEmpty(locktitle)) locktitle = "Lock " + locknum;
+							if(string.IsNullOrEmpty(locktitle))
+							{
+								locktitle = "Lock " + locknum;
+							}
 
+							// Lock already defined?
 							if(locks.ContainsKey(locknum))
+							{
+								// Do some stream poition hacking to make the warning point to the correct line
+								long curpos = datastream.Position;
+								if(lockstartpos != -1) datastream.Position = lockstartpos;
 								LogWarning("Lock " + locknum + " is double-defined as \"" + locks[locknum] + "\" and \"" + locktitle + "\"");
+								datastream.Position = curpos;
+							}
 
+							// Add to collections
 							locks[locknum] = locktitle;
+							if(mapcolor.a == 255) mapcolors[locknum] = mapcolor;
 						}
 
 						// Reset values
 						locknum = -1;
 						locktitle = string.Empty;
 						game = string.Empty;
+						mapcolor = new PixelColor();
+						lockstartpos = -1;
 						break;
 				}
 			}
diff --git a/Source/Plugins/AutomapMode/AutomapMode.cs b/Source/Plugins/AutomapMode/AutomapMode.cs
index 69fe1f141..1077b856a 100644
--- a/Source/Plugins/AutomapMode/AutomapMode.cs
+++ b/Source/Plugins/AutomapMode/AutomapMode.cs
@@ -1,15 +1,15 @@
 
 #region ================== Copyright (c) 2016 Boris Iwanski
 
-/*
- * Copyright (c) 2016 Boris Iwanski https://github.com/biwa/automapmode
- * This program is released under GNU General Public License
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
+/*
+ * Copyright (c) 2016 Boris Iwanski https://github.com/biwa/automapmode
+ * This program is released under GNU General Public License
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
  */
 
 #endregion
@@ -21,21 +21,21 @@ using System.Collections.Generic;
 using System.Drawing;
 using System.Windows.Forms;
 using CodeImp.DoomBuilder.Config;
-using CodeImp.DoomBuilder.Map;
+using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Rendering;
-using CodeImp.DoomBuilder.Editing;
-
-#endregion
-
-namespace CodeImp.DoomBuilder.AutomapMode
-{
-	[EditMode(DisplayName = "Automap Mode",
-			  SwitchAction = "automapmode",	// Action name used to switch to this mode
-			  ButtonImage = "automap.png",	// Image resource name for the button
-			  ButtonOrder = int.MinValue + 503,	// Position of the button (lower is more to the bottom)
-			  ButtonGroup = "000_editing",
-			  UseByDefault = true)]
-
+using CodeImp.DoomBuilder.Editing;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.AutomapMode
+{
+	[EditMode(DisplayName = "Automap Mode",
+			  SwitchAction = "automapmode",	// Action name used to switch to this mode
+			  ButtonImage = "automap.png",	// Image resource name for the button
+			  ButtonOrder = int.MinValue + 503,	// Position of the button (lower is more to the bottom)
+			  ButtonGroup = "000_editing",
+			  UseByDefault = true)]
+
 	public class AutomapMode : ClassicMode
 	{
 		#region ================== Enums
@@ -51,22 +51,22 @@ namespace CodeImp.DoomBuilder.AutomapMode
 
 		#region ================== Constants
 
-		private const float LINE_LENGTH_SCALER = 0.001f; //mxd
-
-		#endregion
-
-		#region ================== Variables
-
-		private CustomPresentation automappresentation;
+		private const float LINE_LENGTH_SCALER = 0.001f; //mxd
+
+		#endregion
+
+		#region ================== Variables
+
+		private CustomPresentation automappresentation;
 		private List<Linedef> validlinedefs;
 		private HashSet<Sector> secretsectors; //mxd
-
-		// Highlighted item
+
+		// Highlighted item
 		private Linedef highlighted;
 
 		//mxd. UI
-		private MenusForm menusform;
-
+		private MenusForm menusform;
+
 		//mxd. Colors
 		private PixelColor ColorSingleSided;
 		private PixelColor ColorSecret;
@@ -75,25 +75,26 @@ namespace CodeImp.DoomBuilder.AutomapMode
 		private PixelColor ColorMatchingHeight;
 		private PixelColor ColorHiddenFlag;
 		private PixelColor ColorInvisible;
-		private PixelColor ColorBackground;
-		
-		#endregion
-
-		#region ================== Properties
-
-		public override object HighlightedObject { get { return highlighted; } }
-		
-		#endregion
-
-		#region ================== Constructor / Disposer
-
-		//mxd
+		private PixelColor ColorBackground;
+		
+		#endregion
+
+		#region ================== Properties
+
+		public override object HighlightedObject { get { return highlighted; } }
+		
+		#endregion
+
+		#region ================== Constructor / Disposer
+
+		//mxd
 		public AutomapMode()
 		{
 			// Create and setup menu
 			menusform = new MenusForm();
 			menusform.ShowHiddenLines = General.Settings.ReadPluginSetting("automapmode.showhiddenlines", false);
 			menusform.ShowSecretSectors = General.Settings.ReadPluginSetting("automapmode.showsecretsectors", false);
+			menusform.ShowLocks = General.Settings.ReadPluginSetting("automapmode.showlocks", true);
 			menusform.ColorPreset = (ColorPreset)General.Settings.ReadPluginSetting("automapmode.colorpreset", (int)ColorPreset.DOOM);
 
 			// Handle events
@@ -103,10 +104,8 @@ namespace CodeImp.DoomBuilder.AutomapMode
 				General.Interface.RedrawDisplay();
 			};
 
-			menusform.OnShowSecretSectorsChanged += delegate
-			{
-				General.Interface.RedrawDisplay();
-			};
+			menusform.OnShowSecretSectorsChanged += delegate { General.Interface.RedrawDisplay(); };
+			menusform.OnShowLocksChanged += delegate { General.Interface.RedrawDisplay(); };
 
 			menusform.OnColorPresetChanged += delegate
 			{
@@ -117,51 +116,51 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			// Apply color preset
 			ApplyColorPreset(menusform.ColorPreset);
 		}
-
-		#endregion
-
-		#region ================== Methods
-
+
+		#endregion
+
+		#region ================== Methods
+
 		// This highlights a new item
 		private void Highlight(Linedef l)
 		{
-			// Update display
-			if(renderer.StartPlotter(false))
-			{
-				// Undraw previous highlight
-				if((highlighted != null) && !highlighted.IsDisposed)
+			// Update display
+			if(renderer.StartPlotter(false))
+			{
+				// Undraw previous highlight
+				if((highlighted != null) && !highlighted.IsDisposed)
 				{
-					PixelColor c = LinedefIsValid(highlighted) ? DetermineLinedefColor(highlighted) : PixelColor.Transparent;
-					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, c, LINE_LENGTH_SCALER);
-				}
-
-				// Set new highlight
-				highlighted = l;
-
-				// Render highlighted item
-				if((highlighted != null) && !highlighted.IsDisposed && LinedefIsValid(highlighted))
+					PixelColor c = LinedefIsValid(highlighted) ? DetermineLinedefColor(highlighted) : PixelColor.Transparent;
+					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, c, LINE_LENGTH_SCALER);
+				}
+
+				// Set new highlight
+				highlighted = l;
+
+				// Render highlighted item
+				if((highlighted != null) && !highlighted.IsDisposed && LinedefIsValid(highlighted))
 				{
-					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, General.Colors.InfoLine, LINE_LENGTH_SCALER);
-				}
-
-				// Done
-				renderer.Finish();
-				renderer.Present();
-			}
-
-			// Show highlight info
-			if((highlighted != null) && !highlighted.IsDisposed)
-				General.Interface.ShowLinedefInfo(highlighted);
-			else
-				General.Interface.HideInfo();
-		}
-
-		//mxd
-		internal void UpdateValidLinedefs()
-		{
-			validlinedefs = new List<Linedef>();
+					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, General.Colors.InfoLine, LINE_LENGTH_SCALER);
+				}
+
+				// Done
+				renderer.Finish();
+				renderer.Present();
+			}
+
+			// Show highlight info
+			if((highlighted != null) && !highlighted.IsDisposed)
+				General.Interface.ShowLinedefInfo(highlighted);
+			else
+				General.Interface.HideInfo();
+		}
+
+		//mxd
+		internal void UpdateValidLinedefs()
+		{
+			validlinedefs = new List<Linedef>();
 			foreach(Linedef ld in General.Map.Map.Linedefs)
-				if(LinedefIsValid(ld)) validlinedefs.Add(ld);
+				if(LinedefIsValid(ld)) validlinedefs.Add(ld);
 		}
 
 		//mxd
@@ -170,10 +169,17 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			secretsectors = new HashSet<Sector>();
 			foreach(Sector s in General.Map.Map.Sectors)
 				if(SectorIsSecret(s)) secretsectors.Add(s);
-		}
-
-		private PixelColor DetermineLinedefColor(Linedef ld)
+		}
+
+		private PixelColor DetermineLinedefColor(Linedef ld)
 		{
+			//mxd
+			if(menusform.ShowLocks)
+			{
+				PixelColor lockcolor = new PixelColor();
+				if(GetLockColor(ld, ref lockcolor)) return lockcolor;
+			}
+			
 			//mxd
 			if(menusform.ShowSecretSectors &&
 			   (ld.Front != null && secretsectors.Contains(ld.Front.Sector) || ld.Back != null && secretsectors.Contains(ld.Back.Sector)))
@@ -187,22 +193,22 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			if(ld.Front.Sector.CeilHeight == ld.Back.Sector.CeilHeight && ld.Front.Sector.FloorHeight == ld.Back.Sector.FloorHeight)
 				return ColorMatchingHeight;
 
-			if(menusform.ShowHiddenLines ^ General.Interface.CtrlState) return ColorInvisible; 
-
-			return new PixelColor(255, 255, 255, 255);
-		}
-
-		private bool LinedefIsValid(Linedef ld)
-		{
-			if(menusform.ShowHiddenLines ^ General.Interface.CtrlState) return true;
-			if(ld.IsFlagSet(BuilderPlug.Me.HiddenFlag)) return false;
-			if(ld.Back == null || ld.Front == null || ld.IsFlagSet(BuilderPlug.Me.SecretFlag)) return true;
-			if(ld.Back != null && ld.Front != null && (ld.Front.Sector.FloorHeight != ld.Back.Sector.FloorHeight || ld.Front.Sector.CeilHeight != ld.Back.Sector.CeilHeight)) return true;
-
-			return false;
-		}
-
-		//mxd
+			if(menusform.ShowHiddenLines ^ General.Interface.CtrlState) return ColorInvisible; 
+
+			return new PixelColor(255, 255, 255, 255);
+		}
+
+		private bool LinedefIsValid(Linedef ld)
+		{
+			if(menusform.ShowHiddenLines ^ General.Interface.CtrlState) return true;
+			if(ld.IsFlagSet(BuilderPlug.Me.HiddenFlag)) return false;
+			if(ld.Back == null || ld.Front == null || ld.IsFlagSet(BuilderPlug.Me.SecretFlag)) return true;
+			if(ld.Back != null && ld.Front != null && (ld.Front.Sector.FloorHeight != ld.Back.Sector.FloorHeight || ld.Front.Sector.CeilHeight != ld.Back.Sector.CeilHeight)) return true;
+
+			return false;
+		}
+
+		//mxd
 		private static bool SectorIsSecret(Sector s)
 		{
 			SectorEffectData data = General.Map.Config.GetSectorEffectData(s.Effect);
@@ -221,6 +227,33 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			return false;
 		}
 
+		//mxd
+		private static bool GetLockColor(Linedef l, ref PixelColor lockcolor)
+		{
+			int locknum = 0;
+
+			// Check locknumber property
+			if(General.Map.UDMF)
+			{
+				locknum = UniFields.GetInteger(l.Fields, "locknumber");
+			}
+
+			// Check action
+			if(locknum == 0 && l.Action != 0 && General.Map.Data.LockableActions.ContainsKey(l.Action))
+			{
+				locknum = l.Args[General.Map.Data.LockableActions[l.Action]];
+			}
+
+			if(locknum != 0 && General.Map.Data.LockColors.ContainsKey(locknum))
+			{
+				lockcolor = General.Map.Data.LockColors[locknum];
+				return true;
+			}
+
+			// No dice
+			return false;
+		}
+
 		//mxd
 		private void ApplyColorPreset(ColorPreset preset)
 		{
@@ -259,63 +292,64 @@ namespace CodeImp.DoomBuilder.AutomapMode
 					ColorBackground = new PixelColor(255, 0, 0, 0);
 					break;
 			}
-		}
-
-		#endregion
-		
-		#region ================== Events
-
-		public override void OnHelp()
+		}
+
+		#endregion
+		
+		#region ================== Events
+
+		public override void OnHelp()
 		{
-			General.ShowHelp("/gzdb/features/classic_modes/mode_automap.html");
-		}
-
-		// Cancel mode
-		public override void OnCancel()
-		{
-			base.OnCancel();
-
-			// Return to this mode
-			General.Editing.ChangeMode(new AutomapMode());
-		}
-
-		// Mode engages
-		public override void OnEngage()
-		{
-			base.OnEngage();
+			General.ShowHelp("/gzdb/features/classic_modes/mode_automap.html");
+		}
+
+		// Cancel mode
+		public override void OnCancel()
+		{
+			base.OnCancel();
+
+			// Return to this mode
+			General.Editing.ChangeMode(new AutomapMode());
+		}
+
+		// Mode engages
+		public override void OnEngage()
+		{
+			base.OnEngage();
 			renderer.DrawMapCenter = false; //mxd
-
-			// Automap presentation without the surfaces
-			automappresentation = new CustomPresentation();
-			automappresentation.AddLayer(new PresentLayer(RendererLayer.Overlay, BlendingMode.Mask));
-			automappresentation.AddLayer(new PresentLayer(RendererLayer.Grid, BlendingMode.Mask));
-			automappresentation.AddLayer(new PresentLayer(RendererLayer.Geometry, BlendingMode.Alpha, 1f, true));
-			renderer.SetPresentation(automappresentation);
+
+			// Automap presentation without the surfaces
+			automappresentation = new CustomPresentation();
+			automappresentation.AddLayer(new PresentLayer(RendererLayer.Overlay, BlendingMode.Mask));
+			automappresentation.AddLayer(new PresentLayer(RendererLayer.Grid, BlendingMode.Mask));
+			automappresentation.AddLayer(new PresentLayer(RendererLayer.Geometry, BlendingMode.Alpha, 1f, true));
+			renderer.SetPresentation(automappresentation);
 
 			UpdateValidLinedefs();
 			UpdateSecretSectors(); //mxd
 
 			//mxd. Show UI
 			menusform.Register();
-		}
-		
-		// Mode disengages
-		public override void OnDisengage()
-		{
+		}
+		
+		// Mode disengages
+		public override void OnDisengage()
+		{
 			base.OnDisengage();
 
 			//mxd. Store settings
 			General.Settings.WritePluginSetting("automapmode.showhiddenlines", menusform.ShowHiddenLines);
 			General.Settings.WritePluginSetting("automapmode.showsecretsectors", menusform.ShowSecretSectors);
+			General.Settings.WritePluginSetting("automapmode.showlocks", menusform.ShowLocks);
 			General.Settings.WritePluginSetting("automapmode.colorpreset", (int)menusform.ColorPreset);
 
 			//mxd. Hide UI
 			menusform.Unregister();
-
-			// Hide highlight info
-			General.Interface.HideInfo();
-		}
-
+
+			// Hide highlight info
+			General.Interface.HideInfo();
+		}
+
 		//mxd
 		public override void OnUndoEnd()
 		{
@@ -323,8 +357,8 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			UpdateSecretSectors();
 
 			base.OnUndoEnd();
-		}
-
+		}
+
 		//mxd
 		public override void OnRedoEnd()
 		{
@@ -332,119 +366,119 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			UpdateSecretSectors();
 
 			base.OnRedoEnd();
-		}
-
-		// This redraws the display
-		public override void OnRedrawDisplay()
-		{
-			renderer.RedrawSurface();
-			
-			// Render lines
-			if(renderer.StartPlotter(true))
+		}
+
+		// This redraws the display
+		public override void OnRedrawDisplay()
+		{
+			renderer.RedrawSurface();
+			
+			// Render lines
+			if(renderer.StartPlotter(true))
 			{
-				foreach(Linedef ld in General.Map.Map.Linedefs)
-				{
-					if(LinedefIsValid(ld))
-						renderer.PlotLine(ld.Start.Position, ld.End.Position, DetermineLinedefColor(ld), LINE_LENGTH_SCALER);
-				}
-
-				if((highlighted != null) && !highlighted.IsDisposed && LinedefIsValid(highlighted))
+				foreach(Linedef ld in General.Map.Map.Linedefs)
 				{
-					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, General.Colors.InfoLine, LINE_LENGTH_SCALER);
-				}
-
-				renderer.Finish();
-			}
-
-			//mxd. Render background
+					if(LinedefIsValid(ld))
+						renderer.PlotLine(ld.Start.Position, ld.End.Position, DetermineLinedefColor(ld), LINE_LENGTH_SCALER);
+				}
+
+				if((highlighted != null) && !highlighted.IsDisposed && LinedefIsValid(highlighted))
+				{
+					renderer.PlotLine(highlighted.Start.Position, highlighted.End.Position, General.Colors.InfoLine, LINE_LENGTH_SCALER);
+				}
+
+				renderer.Finish();
+			}
+
+			//mxd. Render background
 			if(renderer.StartOverlay(true))
 			{
 				RectangleF screenrect = new RectangleF(0, 0, General.Interface.Display.Width, General.Interface.Display.Height);
 				renderer.RenderRectangleFilled(screenrect, ColorBackground, false);
 				renderer.Finish();
-			}
-
-			renderer.Present();
-		}
-
-		protected override void OnSelectEnd()
-		{
-			// Item highlighted?
-			if((highlighted != null) && !highlighted.IsDisposed)
+			}
+
+			renderer.Present();
+		}
+
+		protected override void OnSelectEnd()
+		{
+			// Item highlighted?
+			if((highlighted != null) && !highlighted.IsDisposed)
 			{
-				General.Map.UndoRedo.CreateUndo("Toggle \"Shown as 1-sided on automap\" linedef flag");
-
-				// Toggle flag
+				General.Map.UndoRedo.CreateUndo("Toggle \"Shown as 1-sided on automap\" linedef flag");
+
+				// Toggle flag
 				highlighted.SetFlag(BuilderPlug.Me.SecretFlag, !highlighted.IsFlagSet(BuilderPlug.Me.SecretFlag));
-				UpdateValidLinedefs();
-			}
-
-			base.OnSelectEnd();
-		}
-		
-		protected override void OnEditEnd()
-		{
-			// Item highlighted?
-			if((highlighted != null) && !highlighted.IsDisposed)
+				UpdateValidLinedefs();
+			}
+
+			base.OnSelectEnd();
+		}
+		
+		protected override void OnEditEnd()
+		{
+			// Item highlighted?
+			if((highlighted != null) && !highlighted.IsDisposed)
 			{
-				General.Map.UndoRedo.CreateUndo("Toggle \"Not shown on automap\" linedef flag");
-
-				// Toggle flag
+				General.Map.UndoRedo.CreateUndo("Toggle \"Not shown on automap\" linedef flag");
+
+				// Toggle flag
 				highlighted.SetFlag(BuilderPlug.Me.HiddenFlag, !highlighted.IsFlagSet(BuilderPlug.Me.HiddenFlag));
-				UpdateValidLinedefs();
-				General.Interface.RedrawDisplay();
-			}
-
-			base.OnEditEnd();
-		}
-		
-		// Mouse moves
-		public override void OnMouseMove(MouseEventArgs e)
-		{
-			base.OnMouseMove(e);
-
-			// Not holding any buttons?
-			if(e.Button == MouseButtons.None)
-			{
-				// Find the nearest linedef within highlight range
-				Linedef l = MapSet.NearestLinedefRange(validlinedefs, mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale);
-
-				// Highlight if not the same
-				if(l != highlighted) Highlight(l);
-			}
-		}
-
-		// Mouse leaves
-		public override void OnMouseLeave(EventArgs e)
-		{
-			base.OnMouseLeave(e);
-
-			// Highlight nothing
-			Highlight(null);
-		}
-
-		public override void OnKeyDown(KeyEventArgs e)
-		{
-			base.OnKeyDown(e);
-
-			if(e.Control)
+				UpdateValidLinedefs();
+				General.Interface.RedrawDisplay();
+			}
+
+			base.OnEditEnd();
+		}
+		
+		// Mouse moves
+		public override void OnMouseMove(MouseEventArgs e)
+		{
+			base.OnMouseMove(e);
+
+			// Not holding any buttons?
+			if(e.Button == MouseButtons.None)
+			{
+				// Find the nearest linedef within highlight range
+				Linedef l = MapSet.NearestLinedefRange(validlinedefs, mousemappos, BuilderPlug.Me.HighlightRange / renderer.Scale);
+
+				// Highlight if not the same
+				if(l != highlighted) Highlight(l);
+			}
+		}
+
+		// Mouse leaves
+		public override void OnMouseLeave(EventArgs e)
+		{
+			base.OnMouseLeave(e);
+
+			// Highlight nothing
+			Highlight(null);
+		}
+
+		public override void OnKeyDown(KeyEventArgs e)
+		{
+			base.OnKeyDown(e);
+
+			if(e.Control)
 			{
-				UpdateValidLinedefs();
-				General.Interface.RedrawDisplay();
-			}
-		}
-
-		public override void OnKeyUp(KeyEventArgs e)
-		{
-			base.OnKeyUp(e);
-
-			if(!e.Control)
+				UpdateValidLinedefs();
+				General.Interface.RedrawDisplay();
+			}
+		}
+
+		public override void OnKeyUp(KeyEventArgs e)
+		{
+			base.OnKeyUp(e);
+
+			if(!e.Control)
 			{
-				UpdateValidLinedefs();
-				General.Interface.RedrawDisplay();
-			}
-		}
-
-		#endregion
-	}
-}
+				UpdateValidLinedefs();
+				General.Interface.RedrawDisplay();
+			}
+		}
+
+		#endregion
+	}
+}
diff --git a/Source/Plugins/AutomapMode/AutomapMode.csproj b/Source/Plugins/AutomapMode/AutomapMode.csproj
index 5b4bcf188..ce64f2935 100644
--- a/Source/Plugins/AutomapMode/AutomapMode.csproj
+++ b/Source/Plugins/AutomapMode/AutomapMode.csproj
@@ -94,4 +94,7 @@
   <ItemGroup>
     <None Include="Resources\ShowSecrets.png" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\ShowLocks.png" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs b/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
index e4a3d5cc4..28bcf0947 100644
--- a/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
+++ b/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
@@ -29,11 +29,12 @@
 		private void InitializeComponent()
 		{
 			this.toolStrip1 = new System.Windows.Forms.ToolStrip();
-			this.showhiddenlines = new System.Windows.Forms.ToolStripButton();
-			this.showsecretsectors = new System.Windows.Forms.ToolStripButton();
 			this.colorpresetseparator = new System.Windows.Forms.ToolStripSeparator();
 			this.colorpresetlabel = new System.Windows.Forms.ToolStripLabel();
 			this.colorpreset = new System.Windows.Forms.ToolStripComboBox();
+			this.showhiddenlines = new System.Windows.Forms.ToolStripButton();
+			this.showsecretsectors = new System.Windows.Forms.ToolStripButton();
+			this.showlocks = new System.Windows.Forms.ToolStripButton();
 			this.toolStrip1.SuspendLayout();
 			this.SuspendLayout();
 			// 
@@ -42,6 +43,7 @@
 			this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.showhiddenlines,
             this.showsecretsectors,
+            this.showlocks,
             this.colorpresetseparator,
             this.colorpresetlabel,
             this.colorpreset});
@@ -51,26 +53,6 @@
 			this.toolStrip1.TabIndex = 0;
 			this.toolStrip1.Text = "toolStrip1";
 			// 
-			// showhiddenlines
-			// 
-			this.showhiddenlines.CheckOnClick = true;
-			this.showhiddenlines.Image = global::CodeImp.DoomBuilder.AutomapMode.Properties.Resources.ShowHiddenLines;
-			this.showhiddenlines.ImageTransparentColor = System.Drawing.Color.Magenta;
-			this.showhiddenlines.Margin = new System.Windows.Forms.Padding(0, 1, 2, 2);
-			this.showhiddenlines.Name = "showhiddenlines";
-			this.showhiddenlines.Size = new System.Drawing.Size(123, 22);
-			this.showhiddenlines.Text = "Show hidden lines";
-			this.showhiddenlines.CheckedChanged += new System.EventHandler(this.showhiddenlines_CheckedChanged);
-			// 
-			// showsecretsectors
-			// 
-			this.showsecretsectors.CheckOnClick = true;
-			this.showsecretsectors.Image = global::CodeImp.DoomBuilder.AutomapMode.Properties.Resources.ShowSecrets;
-			this.showsecretsectors.Name = "showsecretsectors";
-			this.showsecretsectors.Size = new System.Drawing.Size(95, 22);
-			this.showsecretsectors.Text = "Show secrets";
-			this.showsecretsectors.CheckedChanged += new System.EventHandler(this.showsecretsectors_CheckedChanged);
-			// 
 			// colorpresetseparator
 			// 
 			this.colorpresetseparator.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
@@ -94,6 +76,37 @@
 			this.colorpreset.Size = new System.Drawing.Size(75, 25);
 			this.colorpreset.SelectedIndexChanged += new System.EventHandler(this.colorpreset_SelectedIndexChanged);
 			// 
+			// showhiddenlines
+			// 
+			this.showhiddenlines.CheckOnClick = true;
+			this.showhiddenlines.Image = global::CodeImp.DoomBuilder.AutomapMode.Properties.Resources.ShowHiddenLines;
+			this.showhiddenlines.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.showhiddenlines.Margin = new System.Windows.Forms.Padding(0, 1, 2, 2);
+			this.showhiddenlines.Name = "showhiddenlines";
+			this.showhiddenlines.Size = new System.Drawing.Size(123, 22);
+			this.showhiddenlines.Text = "Show hidden lines";
+			this.showhiddenlines.CheckedChanged += new System.EventHandler(this.showhiddenlines_CheckedChanged);
+			// 
+			// showsecretsectors
+			// 
+			this.showsecretsectors.CheckOnClick = true;
+			this.showsecretsectors.Image = global::CodeImp.DoomBuilder.AutomapMode.Properties.Resources.ShowSecrets;
+			this.showsecretsectors.Margin = new System.Windows.Forms.Padding(0, 1, 2, 2);
+			this.showsecretsectors.Name = "showsecretsectors";
+			this.showsecretsectors.Size = new System.Drawing.Size(95, 22);
+			this.showsecretsectors.Text = "Show secrets";
+			this.showsecretsectors.CheckedChanged += new System.EventHandler(this.showsecretsectors_CheckedChanged);
+			// 
+			// showlocks
+			// 
+			this.showlocks.CheckOnClick = true;
+			this.showlocks.Image = global::CodeImp.DoomBuilder.AutomapMode.Properties.Resources.ShowLocks;
+			this.showlocks.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.showlocks.Name = "showlocks";
+			this.showlocks.Size = new System.Drawing.Size(86, 22);
+			this.showlocks.Text = "Show locks";
+			this.showlocks.CheckedChanged += new System.EventHandler(this.showlocks_CheckedChanged);
+			// 
 			// MenusForm
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -116,5 +129,6 @@
 		private System.Windows.Forms.ToolStripSeparator colorpresetseparator;
 		private System.Windows.Forms.ToolStripLabel colorpresetlabel;
 		private System.Windows.Forms.ToolStripComboBox colorpreset;
+		private System.Windows.Forms.ToolStripButton showlocks;
 	}
 }
diff --git a/Source/Plugins/AutomapMode/Interface/MenusForm.cs b/Source/Plugins/AutomapMode/Interface/MenusForm.cs
index 859f5290a..77d49da6c 100644
--- a/Source/Plugins/AutomapMode/Interface/MenusForm.cs
+++ b/Source/Plugins/AutomapMode/Interface/MenusForm.cs
@@ -7,10 +7,12 @@ namespace CodeImp.DoomBuilder.AutomapMode
 	{
 		public event EventHandler OnShowHiddenLinesChanged;
 		public event EventHandler OnShowSecretSectorsChanged;
+		public event EventHandler OnShowLocksChanged;
 		internal event EventHandler OnColorPresetChanged;
 
 		public bool ShowHiddenLines { get { return showhiddenlines.Checked; } set { showhiddenlines.Checked = value; } }
 		public bool ShowSecretSectors { get { return showsecretsectors.Checked; } set { showsecretsectors.Checked = value; } }
+		public bool ShowLocks { get { return showlocks.Checked; } set { showlocks.Checked = value; } }
 		internal AutomapMode.ColorPreset ColorPreset { get { return (AutomapMode.ColorPreset)colorpreset.SelectedIndex; } set { colorpreset.SelectedIndex = (int)value; } }
 		
 		public MenusForm()
@@ -22,6 +24,7 @@ namespace CodeImp.DoomBuilder.AutomapMode
 		{
 			General.Interface.AddButton(showhiddenlines);
 			General.Interface.AddButton(showsecretsectors);
+			if(!General.Map.DOOM) General.Interface.AddButton(showlocks);
 			General.Interface.AddButton(colorpresetseparator);
 			General.Interface.AddButton(colorpresetlabel);
 			General.Interface.AddButton(colorpreset);
@@ -32,6 +35,7 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			General.Interface.RemoveButton(colorpreset);
 			General.Interface.RemoveButton(colorpresetlabel);
 			General.Interface.RemoveButton(colorpresetseparator);
+			if(!General.Map.DOOM) General.Interface.RemoveButton(showlocks);
 			General.Interface.RemoveButton(showsecretsectors);
 			General.Interface.RemoveButton(showhiddenlines);
 		}
@@ -46,6 +50,11 @@ namespace CodeImp.DoomBuilder.AutomapMode
 			if(OnShowSecretSectorsChanged != null) OnShowSecretSectorsChanged(showsecretsectors.Checked, EventArgs.Empty);
 		}
 
+		private void showlocks_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnShowLocksChanged != null) OnShowLocksChanged(showlocks.Checked, EventArgs.Empty);
+		}
+
 		private void colorpreset_SelectedIndexChanged(object sender, EventArgs e)
 		{
 			if(OnColorPresetChanged != null) OnColorPresetChanged(colorpreset.SelectedIndex, EventArgs.Empty);
diff --git a/Source/Plugins/AutomapMode/Properties/Resources.Designer.cs b/Source/Plugins/AutomapMode/Properties/Resources.Designer.cs
index 493c26216..b58d68343 100644
--- a/Source/Plugins/AutomapMode/Properties/Resources.Designer.cs
+++ b/Source/Plugins/AutomapMode/Properties/Resources.Designer.cs
@@ -1,7 +1,7 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:2.0.50727.5485
+//     Runtime Version:2.0.50727.5466
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
 //     the code is regenerated.
@@ -67,6 +67,13 @@ namespace CodeImp.DoomBuilder.AutomapMode.Properties {
             }
         }
         
+        internal static System.Drawing.Bitmap ShowLocks {
+            get {
+                object obj = ResourceManager.GetObject("ShowLocks", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         internal static System.Drawing.Bitmap ShowSecrets {
             get {
                 object obj = ResourceManager.GetObject("ShowSecrets", resourceCulture);
diff --git a/Source/Plugins/AutomapMode/Properties/Resources.resx b/Source/Plugins/AutomapMode/Properties/Resources.resx
index 4fa11f4c7..80e0c05eb 100644
--- a/Source/Plugins/AutomapMode/Properties/Resources.resx
+++ b/Source/Plugins/AutomapMode/Properties/Resources.resx
@@ -118,10 +118,13 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="ShowSecrets" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\ShowSecrets.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
   <data name="ShowHiddenLines" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ShowHiddenLines.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="ShowSecrets" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\ShowSecrets.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="ShowLocks" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\ShowLocks.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
 </root>
\ No newline at end of file
diff --git a/Source/Plugins/AutomapMode/Resources/ShowLocks.png b/Source/Plugins/AutomapMode/Resources/ShowLocks.png
new file mode 100644
index 0000000000000000000000000000000000000000..3df4ffc3fb29609f2b2332d98c88e71a36fd255d
GIT binary patch
literal 1267
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+*
zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn
zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T
z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj
z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5
zFD<cE0=g99h1>$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;Np<V
zf>iyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$IMft0!ZY(y
z^2>`g!FqgstvvIJOA_;vQ$1a5m4K$`WoD*Wxwx1bn;TddnK)V+85+8pIhvcexLR5`
zn!1@d8JQY6!t}c2Czs}?=9R$orXchh<J1dE4!H$Dn_W_iGRsm^+=}vZ6~NxM%Eav!
z1DxhT^`_u<iy=<E`as9%gCZ9xvSC8N6a-?zlP-`0PyDHQz!YBuOxkx3^cFHOFeZDt
zIEGZ*Dw(v_k2z4Fb^qOW+gi6NGCH&7iE=qM-85gZ_P~P*4mpNK7X?9;8@JRd1XL7$
zF<2bA_WAnKyVGuNp1W*<!AzfL_o~mGnLA&B<?<|(Nn016Wa66Pd3NUOV<syc46iKR
z*vDbmDzopY$fZda1XgfLUs}e|$Rzzscwd6jEuX*}Ex9+EYb~0>{d0dU@vgols1vln
z;F7;i89Q462d9m*yxXpvwY8<5865>&;)g;vY2OZfvrPCD-_<>Alf_jx@*MvZ_+x*|
zh21Gd)4$#-;G3RsPD1WsT>OgFY|QSf6=!_eec0vP)HjV8*Ok_|iEL79Uh{o{m%x=%
z72)$PY}Kh+_)d&T_3px(#vZb>D!yuSYJb_HW%YWg)14pFj}>vv_wihDL0I<EyA82R
zC&`}dGyODkeei~*$0GOp{|L`}=$oB%X2H|u?4No^SLMH(nLFJsrTDJS^!0jC$+@gz
hanb*()9YCz7?d_7{+iSA<rSzH@^tlcS?83{1OP0#!3Y2V

literal 0
HcmV?d00001

-- 
GitLab