From 5e71585c996ae5d1886c079686eb610816b11e40 Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Fri, 20 May 2016 15:04:00 +0000
Subject: [PATCH] Added, Edit Selection mode: Added "Adjust height" setting. It
 can be used to adjust floor/ceiling height of selected sectors based on the
 sector selection was in and the sector selection was moved into. Removed
 "Adjust heights to match relatively with surrounding sector" option from
 Preferences -> Pasting, because sector height adjustments are now handled by
 Edit Selection mode. Fixed, Sector info panel: in some cases 0 deg.
 floor/ceiling texture rotation was triggering texture offset/scale/rotation
 UI parts to be shown. Fixed even more cases when sidedefs belonging to
 linedefs, which were moved on top of existing linedefs, were incorrectly
 reassigned when applying Edit Selection and Drag Geometry modes. Fixed,
 Bridge mode: in some cases calculated floor/ceiling heights were not applied
 to the sectors created by the mode. Changed, internal: changed program's
 CurrentCulture to InvariantCulture.

---
 Source/Core/Config/PasteOptions.cs            |   5 -
 .../Controls/PasteOptionsControl.Designer.cs  |  32 +--
 Source/Core/Controls/PasteOptionsControl.cs   |  11 +-
 Source/Core/Controls/SectorInfoPanel.cs       |  10 +-
 Source/Core/General/General.cs                |   5 +-
 Source/Core/Geometry/Tools.cs                 |  89 ++++++--
 Source/Core/Map/Linedef.cs                    |   6 +-
 Source/Core/Map/Sidedef.cs                    |  13 +-
 .../Core/Windows/PasteOptionsForm.Designer.cs |  11 +-
 .../BuilderModes/ClassicModes/BridgeMode.cs   |   8 +-
 .../ClassicModes/DragLinedefsMode.cs          |  10 +-
 .../ClassicModes/DragSectorsMode.cs           |  30 ++-
 .../ClassicModes/DragVerticesMode.cs          |  44 ++--
 .../ClassicModes/DrawGeometryMode.cs          |  14 +-
 .../ClassicModes/EditSelectionMode.cs         | 193 ++++++++++++++++--
 .../ResultVertexOverlappingLine.cs            |   4 +
 .../Interface/EditSelectionPanel.Designer.cs  |  54 ++++-
 .../Interface/EditSelectionPanel.cs           |  32 ++-
 .../Interface/EditSelectionPanel.resx         |   9 +
 .../Interface/PreferencesForm.Designer.cs     |  20 +-
 .../BuilderModes/VisualModes/VisualCeiling.cs |   8 +-
 .../BuilderModes/VisualModes/VisualFloor.cs   |   8 +-
 22 files changed, 442 insertions(+), 174 deletions(-)

diff --git a/Source/Core/Config/PasteOptions.cs b/Source/Core/Config/PasteOptions.cs
index b666cf021..f4fd1be23 100644
--- a/Source/Core/Config/PasteOptions.cs
+++ b/Source/Core/Config/PasteOptions.cs
@@ -36,7 +36,6 @@ namespace CodeImp.DoomBuilder.Config
 		
 		private int changetags;				// See TAGS_ constants
 		private bool removeactions;
-		private bool adjustheights;
 		
 		#endregion
 		
@@ -44,7 +43,6 @@ namespace CodeImp.DoomBuilder.Config
 		
 		public int ChangeTags { get { return changetags; } set { changetags = value; } }
 		public bool RemoveActions { get { return removeactions; } set { removeactions = value; } }
-		public bool AdjustHeights { get { return adjustheights; } set { adjustheights = value; } }
 		
 		#endregion
 		
@@ -60,7 +58,6 @@ namespace CodeImp.DoomBuilder.Config
 		{
 			this.changetags = p.changetags;
 			this.removeactions = p.removeactions;
-			this.adjustheights = p.adjustheights;
 		}
 		
 		#endregion
@@ -78,7 +75,6 @@ namespace CodeImp.DoomBuilder.Config
 		{
 			changetags = cfg.ReadSetting(path + ".changetags", 0);
 			removeactions = cfg.ReadSetting(path + ".removeactions", false);
-			adjustheights = cfg.ReadSetting(path + ".adjustheights", true);
 		}
 		
 		// This writes to configuration
@@ -86,7 +82,6 @@ namespace CodeImp.DoomBuilder.Config
 		{
 			cfg.WriteSetting(path + ".changetags", changetags);
 			cfg.WriteSetting(path + ".removeactions", removeactions);
-			cfg.WriteSetting(path + ".adjustheights", adjustheights);
 		}
 		
 		#endregion
diff --git a/Source/Core/Controls/PasteOptionsControl.Designer.cs b/Source/Core/Controls/PasteOptionsControl.Designer.cs
index 0b24a64c5..3d08de55b 100644
--- a/Source/Core/Controls/PasteOptionsControl.Designer.cs
+++ b/Source/Core/Controls/PasteOptionsControl.Designer.cs
@@ -28,39 +28,14 @@ namespace CodeImp.DoomBuilder.Controls
 		/// </summary>
 		private void InitializeComponent()
 		{
-			this.sectorheightsgroup = new System.Windows.Forms.GroupBox();
-			this.adjustheights = new System.Windows.Forms.CheckBox();
 			this.tagsgroup = new System.Windows.Forms.GroupBox();
 			this.removeactions = new System.Windows.Forms.CheckBox();
 			this.removetags = new System.Windows.Forms.RadioButton();
 			this.renumbertags = new System.Windows.Forms.RadioButton();
 			this.keeptags = new System.Windows.Forms.RadioButton();
-			this.sectorheightsgroup.SuspendLayout();
 			this.tagsgroup.SuspendLayout();
 			this.SuspendLayout();
 			// 
-			// sectorheightsgroup
-			// 
-			this.sectorheightsgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-						| System.Windows.Forms.AnchorStyles.Right)));
-			this.sectorheightsgroup.Controls.Add(this.adjustheights);
-			this.sectorheightsgroup.Location = new System.Drawing.Point(0, 138);
-			this.sectorheightsgroup.Name = "sectorheightsgroup";
-			this.sectorheightsgroup.Size = new System.Drawing.Size(443, 50);
-			this.sectorheightsgroup.TabIndex = 3;
-			this.sectorheightsgroup.TabStop = false;
-			this.sectorheightsgroup.Text = " Floor and Ceiling heights ";
-			// 
-			// adjustheights
-			// 
-			this.adjustheights.AutoSize = true;
-			this.adjustheights.Location = new System.Drawing.Point(30, 24);
-			this.adjustheights.Name = "adjustheights";
-			this.adjustheights.Size = new System.Drawing.Size(292, 17);
-			this.adjustheights.TabIndex = 0;
-			this.adjustheights.Text = "Adjust heights to match relatively with surrounding sector";
-			this.adjustheights.UseVisualStyleBackColor = true;
-			// 
 			// tagsgroup
 			// 
 			this.tagsgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
@@ -123,12 +98,9 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
-			this.Controls.Add(this.sectorheightsgroup);
 			this.Controls.Add(this.tagsgroup);
 			this.Name = "PasteOptionsControl";
-			this.Size = new System.Drawing.Size(443, 208);
-			this.sectorheightsgroup.ResumeLayout(false);
-			this.sectorheightsgroup.PerformLayout();
+			this.Size = new System.Drawing.Size(443, 139);
 			this.tagsgroup.ResumeLayout(false);
 			this.tagsgroup.PerformLayout();
 			this.ResumeLayout(false);
@@ -137,8 +109,6 @@ namespace CodeImp.DoomBuilder.Controls
 
 		#endregion
 
-		private System.Windows.Forms.GroupBox sectorheightsgroup;
-		private System.Windows.Forms.CheckBox adjustheights;
 		private System.Windows.Forms.GroupBox tagsgroup;
 		private System.Windows.Forms.CheckBox removeactions;
 		private System.Windows.Forms.RadioButton removetags;
diff --git a/Source/Core/Controls/PasteOptionsControl.cs b/Source/Core/Controls/PasteOptionsControl.cs
index d82666b2d..c339ca438 100644
--- a/Source/Core/Controls/PasteOptionsControl.cs
+++ b/Source/Core/Controls/PasteOptionsControl.cs
@@ -53,7 +53,6 @@ namespace CodeImp.DoomBuilder.Controls
 			renumbertags.Checked = (options.ChangeTags == 1);
 			removetags.Checked = (options.ChangeTags == 2);
 			removeactions.Checked = options.RemoveActions;
-			adjustheights.Checked = options.AdjustHeights;
 		}
 		
 		// This returns the options as set by the user
@@ -62,14 +61,10 @@ namespace CodeImp.DoomBuilder.Controls
 			PasteOptions options = new PasteOptions();
 			
 			// Collect settings
-			if(keeptags.Checked)
-				options.ChangeTags = 0;
-			else if(renumbertags.Checked)
-				options.ChangeTags = 1;
-			else if(removetags.Checked)
-				options.ChangeTags = 2;
+			if(keeptags.Checked) options.ChangeTags = 0;
+			else if(renumbertags.Checked) options.ChangeTags = 1;
+			else if(removetags.Checked) options.ChangeTags = 2;
 			options.RemoveActions = removeactions.Checked;
-			options.AdjustHeights = adjustheights.Checked;
 			
 			return options;
 		}
diff --git a/Source/Core/Controls/SectorInfoPanel.cs b/Source/Core/Controls/SectorInfoPanel.cs
index a151b7995..bc0780376 100644
--- a/Source/Core/Controls/SectorInfoPanel.cs
+++ b/Source/Core/Controls/SectorInfoPanel.cs
@@ -268,12 +268,13 @@ namespace CodeImp.DoomBuilder.Controls
 					}
 
 					//rotation
-					if(s.Fields.ContainsKey("rotationceiling")) 
+					float ceilangle = s.Fields.GetValue("rotationceiling", 0f);
+					if(ceilangle != 0f) 
 					{
 						showExtededCeilingInfo = true;
 						ceilingAngle.Enabled = true;
 						ceilingAngleLabel.Enabled = true;
-						ceilingAngle.Text = s.Fields["rotationceiling"].Value + "\u00B0";
+						ceilingAngle.Text = ceilangle + "\u00B0";
 					} 
 					else 
 					{
@@ -282,12 +283,13 @@ namespace CodeImp.DoomBuilder.Controls
 						ceilingAngleLabel.Enabled = false;
 					}
 
-					if(s.Fields.ContainsKey("rotationfloor")) 
+					float floorangle = s.Fields.GetValue("rotationfloor", 0f);
+					if(floorangle != 0f) 
 					{
 						showExtededFloorInfo = true;
 						floorAngle.Enabled = true;
 						floorAngleLabel.Enabled = true;
-						floorAngle.Text = s.Fields["rotationfloor"].Value + "\u00B0";
+						floorAngle.Text = floorangle + "\u00B0";
 					} 
 					else 
 					{
diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs
index 9435a8f86..5d7b4d061 100644
--- a/Source/Core/General/General.cs
+++ b/Source/Core/General/General.cs
@@ -21,6 +21,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Drawing;
+using System.Globalization;
 using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
@@ -538,7 +539,9 @@ namespace CodeImp.DoomBuilder
 			Application.EnableVisualStyles();
 			Application.SetCompatibleTextRenderingDefault(false); //mxd
 			//Application.DoEvents();		// This must be here to work around a .NET bug
-			//ToolStripManager.Renderer = new ToolStripProfessionalRenderer(new TanColorTable());
+
+			//mxd. Set CultureInfo
+			Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
 			
 			// Hook to DLL loading failure event
 			AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index 706a8bec3..0eaefea3b 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -2166,13 +2166,13 @@ namespace CodeImp.DoomBuilder.Geometry
 			// Create drawn lines per sector collection
 			foreach(Linedef l in drawnlines)
 			{
-				if(l.Front != null && l.Front.Sector != null)
+				if(l.Front != null && (l.Front.Sector != null && !SectorWasInvalid(l.Front.Sector)))
 				{
 					if(!sectorsidesref.ContainsKey(l.Front.Sector)) sectorsidesref.Add(l.Front.Sector, new HashSet<Sidedef>());
 					sectorsidesref[l.Front.Sector].Add(l.Front);
 				}
 
-				if(l.Back != null && l.Back.Sector != null)
+				if(l.Back != null && (l.Back.Sector != null && !SectorWasInvalid(l.Back.Sector)))
 				{
 					if(!sectorsidesref.ContainsKey(l.Back.Sector)) sectorsidesref.Add(l.Back.Sector, new HashSet<Sidedef>());
 					sectorsidesref[l.Back.Sector].Add(l.Back);
@@ -2207,11 +2207,43 @@ namespace CodeImp.DoomBuilder.Geometry
 							newsector.UpdateCache();
 							group.Key.UpdateCache();
 						}
+
+						// Existing sector may've become invalid
+						SectorWasInvalid(group.Key);
 					}
 				}
 			}
 		}
 
+		//mxd
+		private static bool SectorWasInvalid(Sector s)
+		{
+			if(s.Sidedefs.Count < 3 || s.FlatVertices.Length < 3)
+			{
+				// Collect changed lines
+				HashSet<Linedef> changedlines = new HashSet<Linedef>();
+				foreach(Sidedef side in s.Sidedefs) changedlines.Add(side.Line);
+
+				// Delete sector
+				s.Dispose();
+
+				// Correct lines
+				foreach(Linedef l in changedlines)
+				{
+					l.ApplySidedFlags();
+					if(l.Front == null)
+					{
+						l.FlipVertices();
+						l.FlipSidedefs();
+					}
+				}
+
+				return true;
+			}
+
+			return false;
+		}
+
 		#endregion
 
 		#region ================== Linedefs (mxd)
@@ -2313,13 +2345,15 @@ namespace CodeImp.DoomBuilder.Geometry
 		}
 
 		//mxd. Try to create/remove/reassign outer sidedefs. Selected linedefs and verts are marked
-		public static void AdjustOuterSidedefs(HashSet<Sector> selectedsectors, HashSet<Linedef> selectedlines)
+		public static HashSet<Sidedef> AdjustOuterSidedefs(HashSet<Sector> selectedsectors, HashSet<Linedef> selectedlines)
 		{
+			HashSet<Sidedef> adjustedsides = new HashSet<Sidedef>();
 			HashSet<Sidedef> outersides = new HashSet<Sidedef>();
+			HashSet<Sidedef> innersides = new HashSet<Sidedef>();
 			HashSet<Linedef> singlesidedlines = new HashSet<Linedef>();
 			HashSet<Linedef> lineswithoutsides = new HashSet<Linedef>();
 
-			// Collect lines without sidedefs and lines, which don't reference selected sectors
+			// Collect lines without sidedefs and inner and outer sides
 			foreach(Linedef line in selectedlines)
 			{
 				if(line.Front == null && line.Back == null)
@@ -2328,20 +2362,28 @@ namespace CodeImp.DoomBuilder.Geometry
 				}
 				else
 				{
-					if(line.Back != null && line.Back.Sector != null && !selectedsectors.Contains(line.Back.Sector))
-						outersides.Add(line.Back);
-					if(line.Front != null && line.Front.Sector != null && !selectedsectors.Contains(line.Front.Sector))
-						outersides.Add(line.Front);
+					if(line.Back != null && line.Back.Sector != null)
+					{
+						if(!selectedsectors.Contains(line.Back.Sector)) outersides.Add(line.Back);
+						else innersides.Add(line.Back);
+					}
+
+					if(line.Front != null && line.Front.Sector != null)
+					{
+						if(!selectedsectors.Contains(line.Front.Sector)) outersides.Add(line.Front);
+						else innersides.Add(line.Front);
+					}
 				}
 			}
 
-			// Collect outer sides and single-sided lines
+			// Collect inner and outer sides and single-sided lines
 			foreach(Sector sector in selectedsectors)
 			{
 				foreach(Sidedef side in sector.Sidedefs)
 				{
 					if(side.Other == null) singlesidedlines.Add(side.Line);
 					else if(!selectedsectors.Contains(side.Other.Sector)) outersides.Add(side.Other);
+					innersides.Add(side);
 				}
 			}
 
@@ -2363,7 +2405,9 @@ namespace CodeImp.DoomBuilder.Geometry
 
 						// Copy props from the other side
 						ns.CopyPropertiesTo(newside);
-						newside.RemoveUnneededTextures(true, true, true);
+
+						// Store
+						adjustedsides.Add(newside);
 
 						sideschanged = true;
 					}
@@ -2382,7 +2426,9 @@ namespace CodeImp.DoomBuilder.Geometry
 
 						// Copy props from the other side
 						ns.CopyPropertiesTo(newside);
-						newside.RemoveUnneededTextures(true, true, true);
+						
+						// Store
+						adjustedsides.Add(newside);
 
 						sideschanged = true;
 					}
@@ -2447,8 +2493,9 @@ namespace CodeImp.DoomBuilder.Geometry
 				// Copy props from the other side
 				Sidedef propssource = (line.Front ?? line.Back);
 				propssource.CopyPropertiesTo(newside);
-				newside.RemoveUnneededTextures(true, true, true);
-				newside.Other.RemoveUnneededTextures(true, true, true);
+
+				// Store
+				adjustedsides.Add(newside);
 
 				// Correct the linedef
 				if((line.Front == null) && (line.Back != null))
@@ -2467,6 +2514,9 @@ namespace CodeImp.DoomBuilder.Geometry
 			{
 				if(group.Value == null)
 				{
+					// Other side textures may require updating...
+					if(group.Key.Other != null) adjustedsides.Add(group.Key.Other);
+					
 					// Side points nowhere. Remove it
 					Linedef l = group.Key.Line;
 					group.Key.Dispose();
@@ -2485,12 +2535,23 @@ namespace CodeImp.DoomBuilder.Geometry
 				{
 					// Reattach side
 					group.Key.SetSector(group.Value);
-					group.Key.RemoveUnneededTextures(true, true, true);
+
+					// Store
+					adjustedsides.Add(group.Key);
 				}
 			}
 
+			// Inner side textures may need updating
+			foreach(Sidedef s in innersides)
+			{
+				if(!s.IsDisposed) s.RemoveUnneededTextures(s.Other != null, false, true);
+			}
+
 			// Update map geometry
 			General.Map.Map.Update();
+
+			// Done
+			return adjustedsides;
 		}
 
 		//mxd
diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs
index 1b24de054..560755dc0 100644
--- a/Source/Core/Map/Linedef.cs
+++ b/Source/Core/Map/Linedef.cs
@@ -1074,7 +1074,7 @@ namespace CodeImp.DoomBuilder.Map
 		{
 			// Check which lines were 2 sided
 			bool otherwas2s = ((other.Front != null) && (other.Back != null));
-			bool thiswas2s = ((this.Front != null) && (this.Back != null));
+			//bool thiswas2s = ((this.Front != null) && (this.Back != null));
 			
 			// Get sector references
 			Sector otherfs = (other.front != null ? other.front.Sector : null);
@@ -1262,8 +1262,8 @@ namespace CodeImp.DoomBuilder.Map
 					other.ApplySidedFlags();
 				
 				// Remove unneeded textures
-				if(other.front != null) other.front.RemoveUnneededTextures(!(otherwas2s && thiswas2s));
-				if(other.back != null) other.back.RemoveUnneededTextures(!(otherwas2s && thiswas2s));
+				//if(other.front != null) other.front.RemoveUnneededTextures(!(otherwas2s && thiswas2s));
+				//if(other.back != null) other.back.RemoveUnneededTextures(!(otherwas2s && thiswas2s));
 			}
 			
 			// If either of the two lines was selected, keep the other selected
diff --git a/Source/Core/Map/Sidedef.cs b/Source/Core/Map/Sidedef.cs
index e6d1a7831..07e9bf234 100644
--- a/Source/Core/Map/Sidedef.cs
+++ b/Source/Core/Map/Sidedef.cs
@@ -331,18 +331,7 @@ namespace CodeImp.DoomBuilder.Map
 		}
 		
 		// This removes textures that are not required
-		public void RemoveUnneededTextures(bool removemiddle)
-		{
-			RemoveUnneededTextures(removemiddle, false, false);
-		}
-
-		// This removes textures that are not required
-		public void RemoveUnneededTextures(bool removemiddle, bool force) 
-		{
-			RemoveUnneededTextures(removemiddle, force, false);
-		}
-		
-		// This removes textures that are not required
+		public void RemoveUnneededTextures(bool removemiddle) { RemoveUnneededTextures(removemiddle, false, false); }
 		public void RemoveUnneededTextures(bool removemiddle, bool force, bool shiftmiddle)
 		{
 			bool changed = false; //mxd
diff --git a/Source/Core/Windows/PasteOptionsForm.Designer.cs b/Source/Core/Windows/PasteOptionsForm.Designer.cs
index 0173c29c8..20752f5c2 100644
--- a/Source/Core/Windows/PasteOptionsForm.Designer.cs
+++ b/Source/Core/Windows/PasteOptionsForm.Designer.cs
@@ -36,7 +36,7 @@
 			// paste
 			// 
 			this.paste.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-			this.paste.Location = new System.Drawing.Point(142, 214);
+			this.paste.Location = new System.Drawing.Point(142, 152);
 			this.paste.Name = "paste";
 			this.paste.Size = new System.Drawing.Size(112, 25);
 			this.paste.TabIndex = 3;
@@ -48,7 +48,7 @@
 			// 
 			this.cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
 			this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-			this.cancel.Location = new System.Drawing.Point(260, 214);
+			this.cancel.Location = new System.Drawing.Point(260, 152);
 			this.cancel.Name = "cancel";
 			this.cancel.Size = new System.Drawing.Size(112, 25);
 			this.cancel.TabIndex = 4;
@@ -58,12 +58,11 @@
 			// 
 			// pasteoptions
 			// 
-			this.pasteoptions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-						| System.Windows.Forms.AnchorStyles.Left)
+			this.pasteoptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
 						| System.Windows.Forms.AnchorStyles.Right)));
 			this.pasteoptions.Location = new System.Drawing.Point(12, 12);
 			this.pasteoptions.Name = "pasteoptions";
-			this.pasteoptions.Size = new System.Drawing.Size(360, 188);
+			this.pasteoptions.Size = new System.Drawing.Size(360, 138);
 			this.pasteoptions.TabIndex = 5;
 			// 
 			// PasteOptionsForm
@@ -72,7 +71,7 @@
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
 			this.CancelButton = this.cancel;
-			this.ClientSize = new System.Drawing.Size(384, 246);
+			this.ClientSize = new System.Drawing.Size(384, 184);
 			this.Controls.Add(this.pasteoptions);
 			this.Controls.Add(this.cancel);
 			this.Controls.Add(this.paste);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
index b223c482c..807edbdcd 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
@@ -212,7 +212,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
 				General.Map.UndoRedo.CreateUndo("Bridge ("+form.Subdivisions+" subdivisions)");
 
 				List<List<SectorProperties>> sectorProps = new List<List<SectorProperties>>();
-				List<List<List<Sector>>> newSectors = new List<List<List<Sector>>>();
+				List<List<HashSet<Sector>>> newSectors = new List<List<HashSet<Sector>>>();
 				
 				//create sector properties collection
 				//sector row
@@ -229,7 +229,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
 				//sector row
 				for(int i = 0; i < drawShapes.Count; i++) 
 				{
-					newSectors.Add(new List<List<Sector>>());
+					newSectors.Add(new List<HashSet<Sector>>());
 
 					//sector in row
 					for(int c = 0; c < drawShapes[i].Count; c++) 
@@ -244,11 +244,11 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
 							return;
 						}
 
-						List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
+						HashSet<Sector> newsectors = General.Map.Map.GetUnselectedSectorsFromLinedefs(General.Map.Map.GetMarkedLinedefs(true));
 						newSectors[i].Add(newsectors);
 
 						//set floor/ceiling heights and brightness
-						foreach(Sector s in newsectors) 
+						foreach(Sector s in newsectors)
 						{
 							SectorProperties sp = sectorProps[i][c];
 							s.Brightness = sp.Brightness;
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
index 3f2b1fbe1..95d20f33e 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
@@ -121,12 +121,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				//mxd. Marked lines were created during linedef splitting
 				HashSet<Linedef> changedlines = new HashSet<Linedef>(selectedlines);
 				changedlines.UnionWith(newlines);
+				foreach(Linedef l in unstablelines) if(!l.IsDisposed) changedlines.Add(l);
 
 				//mxd. Add sectors, which have all their linedefs selected (otherwise those would be destroyed after moving the selection)
 				HashSet<Sector> toadjust = General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines);
 
 				//mxd. Reattach/add/remove outer sidedefs
-				Tools.AdjustOuterSidedefs(toadjust, changedlines);
+				HashSet<Sidedef> adjustedsides = Tools.AdjustOuterSidedefs(toadjust, changedlines);
+
+				//mxd. Remove unneeded textures
+				foreach(Sidedef side in adjustedsides)
+				{
+					side.RemoveUnneededTextures(true, true, true);
+					if(side.Other != null) side.Other.RemoveUnneededTextures(true, true, true);
+				}
 
 				//mxd. Split outer sectors
 				Tools.SplitOuterSectors(changedlines);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
index e23c506ed..c59549381 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
@@ -118,22 +118,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// When not cancelled
 			if(!cancelled)
 			{
-				//mxd. Reattach/add/remove sidedefs only when there are no unstable lines in selection
-				if(unstablelines.Count == 0)
-				{
-					HashSet<Sector> toadjust = new HashSet<Sector>(selectedsectors);
+				//mxd. Collect changed lines
+				HashSet<Linedef> changedlines = new HashSet<Linedef>(selectedlines);
+				foreach(Linedef l in unstablelines) if(!l.IsDisposed) changedlines.Add(l);
+
+				//mxd. Collect changed sectors
+				HashSet<Sector> toadjust = new HashSet<Sector>(selectedsectors);
 
-					// Add sectors, which are not selected, but have all their linedefs selected
-					// (otherwise those would be destroyed after moving the selection)
-					toadjust.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(selectedlines));
+				//mxd. Add sectors, which are not selected, but have all their linedefs selected
+				// (otherwise those would be destroyed after moving the selection)
+				toadjust.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines));
 
-					// Process outer sidedefs
-					Tools.AdjustOuterSidedefs(toadjust, new HashSet<Linedef>(selectedlines));
+				//mxd. Process outer sidedefs
+				HashSet<Sidedef> adjustedsides = Tools.AdjustOuterSidedefs(toadjust, changedlines);
 
-					// Split outer sectors
-					Tools.SplitOuterSectors(selectedlines);
+				//mxd. Remove unneeded textures
+				foreach(Sidedef side in adjustedsides)
+				{
+					side.RemoveUnneededTextures(true, true, true);
+					if(side.Other != null) side.Other.RemoveUnneededTextures(true, true, true);
 				}
 
+				//mxd. Split outer sectors
+				Tools.SplitOuterSectors(changedlines);
+
 				// If only a single sector was selected, deselect it now
 				if(selectedsectors.Count == 1)
 				{
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
index e67e465be..07b948246 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
@@ -106,31 +106,39 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// When not cancelled
 			if(!cancelled)
 			{
-				//mxd. If linedefs were dragged, reattach/add/remove sidedefs
-				if(stablelines.Count > 0)
-				{
-					// Get new lines from linedef marks...
-					HashSet<Linedef> newlines = new HashSet<Linedef>(General.Map.Map.GetMarkedLinedefs(true));
+				//mxd. Get new lines from linedef marks...
+				HashSet<Linedef> newlines = new HashSet<Linedef>(General.Map.Map.GetMarkedLinedefs(true));
 
-					// Marked lines were created during linedef splitting
-					HashSet<Linedef> changedlines = new HashSet<Linedef>(stablelines);
-					changedlines.UnionWith(newlines);
+				//mxd. Marked lines were created during linedef splitting
+				HashSet<Linedef> changedlines = new HashSet<Linedef>(stablelines);
+				changedlines.UnionWith(newlines);
+				foreach(Linedef l in unstablelines) if(!l.IsDisposed) changedlines.Add(l);
 
-					// Get sectors, which have all their linedefs selected (otherwise those would be destroyed after moving the selection)
-					HashSet<Sector> toadjust = General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines);
+				//mxd. Get sectors, which have all their linedefs selected (otherwise those would be destroyed after moving the selection)
+				HashSet<Sector> toadjust = General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines);
+				
+				//mxd. If linedefs were dragged, reattach/add/remove sidedefs
+				if(changedlines.Count > 0)
+				{
+					// Reattach/add/remove outer sidedefs
+					HashSet<Sidedef> adjustedsides = Tools.AdjustOuterSidedefs(toadjust, changedlines);
 
-					if(changedlines.Count > 0)
+					// Remove unneeded textures
+					foreach(Sidedef side in adjustedsides)
 					{
-						// Reattach/add/remove outer sidedefs
-						Tools.AdjustOuterSidedefs(toadjust, changedlines);
+						side.RemoveUnneededTextures(true, true, true);
+						if(side.Other != null) side.Other.RemoveUnneededTextures(true, true, true);
+					}
 
-						// Split outer sectors
-						Tools.SplitOuterSectors(changedlines);
+					// Split outer sectors
+					Tools.SplitOuterSectors(changedlines);
 
-						// Additional verts may've been created
-						if(selectedverts.Count > 1)
+					// Additional verts may've been created
+					if(selectedverts.Count > 1)
+					{
+						foreach(Linedef l in changedlines)
 						{
-							foreach(Linedef l in changedlines)
+							if(!unstablelines.Contains(l))
 							{
 								l.Start.Selected = true;
 								l.End.Selected = true;
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 04907c298..21f77f343 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -176,6 +176,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if(showguidelines)
 					{
 						Vector2D prevp = points[points.Count - 1].pos;
+						PixelColor c = General.Colors.InfoLine.WithAlpha(80);
 						if(curp.pos.x != prevp.x && curp.pos.y != prevp.y)
 						{
 							renderguidelabels = true;
@@ -184,7 +185,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							Vector2D bl = new Vector2D(Math.Min(curp.pos.x, prevp.x), Math.Min(curp.pos.y, prevp.y));
 							
 							// Create guidelines
-							PixelColor c = General.Colors.InfoLine.WithAlpha(80);
 							Line3D[] lines = new Line3D[5];
 							lines[0] = new Line3D(new Vector2D(tr.x, General.Map.Config.TopBoundary), new Vector2D(tr.x, General.Map.Config.BottomBoundary), c, false);
 							lines[1] = new Line3D(new Vector2D(bl.x, General.Map.Config.TopBoundary), new Vector2D(bl.x, General.Map.Config.BottomBoundary), c, false);
@@ -227,6 +227,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							guidelabels[2].Move(new Vector2D(tr.x, bl.y), bl);
 							guidelabels[3].Move(bl, new Vector2D(bl.x, tr.y));
 						}
+						// Render horizontal line
+						else if(curp.pos.x != prevp.x)
+						{
+							Line3D l = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, curp.pos.y), new Vector2D(General.Map.Config.RightBoundary, curp.pos.y), c, false);
+							renderer.RenderArrows(new List<Line3D>{ l });
+						}
+						// Render vertical line
+						else if(curp.pos.y != prevp.y)
+						{
+							Line3D l = new Line3D(new Vector2D(curp.pos.x, General.Map.Config.TopBoundary), new Vector2D(curp.pos.x, General.Map.Config.BottomBoundary), c, false);
+							renderer.RenderArrows(new List<Line3D> { l });
+						}
 					}
 					
 					// Render lines
diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
index 235fd65fd..a1320f30d 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
@@ -71,6 +71,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			RotateLB
 		}
 
+		internal enum HeightAdjustMode
+		{
+			NONE,
+			ADJUST_FLOORS,
+			ADJUST_CEILINGS,
+			ADJUST_BOTH,
+		}
+
 		#endregion
 
 		#region ================== Structs (mxd)
@@ -141,6 +149,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private bool pasting;
 		private bool autodrag; //mxd
 		private PasteOptions pasteoptions;
+		private HeightAdjustMode heightadjustmode; //mxd
 		
 		// Docker
 		private EditSelectionPanel panel;
@@ -226,6 +235,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		internal bool ScaleFloorOffsets { get { return scaleflooroffsets; } set { scaleflooroffsets = value; UpdateAllChanges(); } }
 		internal bool ScaleCeilingOffsets { get { return scaleceiloffsets; } set { scaleceiloffsets = value; UpdateAllChanges(); } }
 
+		//mxd. Height offset mode
+		internal HeightAdjustMode SectorHeightAdjustMode { get { return heightadjustmode; } set { heightadjustmode = value; } }
+
 		#endregion
 
 		#region ================== Constructor / Disposer
@@ -1018,8 +1030,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private void FlipLinedefs()
 		{
 			// Flip linedefs
-			foreach(Linedef ld in selectedlines)
-				ld.FlipVertices();
+			foreach(Linedef ld in selectedlines) ld.FlipVertices();
 			
 			// Done
 			linesflipped = !linesflipped;
@@ -1027,6 +1038,125 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		
 		#endregion
 
+		#region ================== Sector height adjust methods (mxd)
+
+		private static Sector GetOutsideSector(IEnumerable<Sector> sectors)
+		{
+			Sector result = null;
+			foreach(Sector s in sectors)
+			{
+				foreach(Sidedef side in s.Sidedefs)
+				{
+					if(side.Other == null || side.Other.Sector == null) continue;
+					if(result == null) result = side.Other.Sector;
+					else if(result != side.Other.Sector) return null;
+				}
+			}
+
+			return result;
+		}
+
+		private static void AdjustSectorsHeight(ICollection<Sector> toadjust, HeightAdjustMode adjustmode, int oldfloorheight, int oldceilheight)
+		{
+			// Adjust only when selection is inside a single sector
+			if(adjustmode == HeightAdjustMode.NONE || oldfloorheight == int.MinValue || oldceilheight == int.MinValue) return;
+			Sector outsidesector = GetOutsideSector(toadjust);
+			if(outsidesector == null) return;
+
+			// Height differences
+			int floorheightdiff = outsidesector.FloorHeight - oldfloorheight;
+			int ceilheightdiff = outsidesector.CeilHeight - oldceilheight;
+
+			switch(adjustmode)
+			{
+				case HeightAdjustMode.ADJUST_FLOORS:
+					foreach(Sector s in toadjust) AdjustSectorHeight(s, floorheightdiff, int.MinValue);
+					break;
+
+				case HeightAdjustMode.ADJUST_CEILINGS:
+					foreach(Sector s in toadjust) AdjustSectorHeight(s, int.MinValue, ceilheightdiff);
+					break;
+
+				case HeightAdjustMode.ADJUST_BOTH:
+					foreach(Sector s in toadjust) AdjustSectorHeight(s, floorheightdiff, ceilheightdiff);
+					break;
+
+				default:
+					throw new NotImplementedException("Unknown HeightAdjustMode: " + adjustmode);
+			}
+		}
+
+		private static void AdjustSectorHeight(Sector s, int flooroffset, int ceiloffset)
+		{
+			// Adjust floor height
+			if(flooroffset != int.MinValue)
+			{
+				// Adjust regular height
+				s.FloorHeight += flooroffset;
+
+				if(General.Map.UDMF)
+				{
+					// Adjust slope height?
+					if(s.FloorSlope.GetLengthSq() > 0 && !float.IsNaN(s.FloorSlopeOffset / s.FloorSlope.z))
+					{
+						s.FloorSlopeOffset -= flooroffset * (float)Math.Sin(s.FloorSlope.GetAngleZ());
+					}
+					// Adjust vertex height?
+					else if(s.Sidedefs.Count == 3)
+					{
+						// Collect verts
+						HashSet<Vertex> verts = new HashSet<Vertex>();
+						foreach(Sidedef side in s.Sidedefs)
+						{
+							verts.Add(side.Line.Start);
+							verts.Add(side.Line.End);
+						}
+
+						// Offset verts
+						foreach(Vertex v in verts)
+						{
+							if(!float.IsNaN(v.ZFloor)) v.ZFloor += flooroffset;
+						}
+					}
+				}
+			}
+
+			// Adjust ceiling height
+			if(ceiloffset != int.MinValue)
+			{
+				// Adjust regular height
+				s.CeilHeight += ceiloffset;
+
+				if(General.Map.UDMF)
+				{
+					// Adjust slope height?
+					if(s.CeilSlope.GetLengthSq() > 0 && !float.IsNaN(s.CeilSlopeOffset / s.CeilSlope.z))
+					{
+						s.CeilSlopeOffset -= ceiloffset * (float)Math.Sin(s.CeilSlope.GetAngleZ());
+					}
+					// Adjust vertex height?
+					else if(s.Sidedefs.Count == 3)
+					{
+						// Collect verts
+						HashSet<Vertex> verts = new HashSet<Vertex>();
+						foreach(Sidedef side in s.Sidedefs)
+						{
+							verts.Add(side.Line.Start);
+							verts.Add(side.Line.End);
+						}
+
+						// Offset verts
+						foreach(Vertex v in verts)
+						{
+							if(!float.IsNaN(v.ZCeiling)) v.ZCeiling += ceiloffset;
+						}
+					}
+				}
+			}
+		}
+
+		#endregion
+
 		#region ================== Events
 
 		public override void OnHelp()
@@ -1047,7 +1177,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Interface.AddButton(BuilderPlug.Me.MenusForm.FlipSelectionV);
 
 			//mxd. Get EditPanel-related settings
-			usepreciseposition = General.Settings.ReadPluginSetting("editselectionusespreciseposition", true);
+			usepreciseposition = General.Settings.ReadPluginSetting("editselectionmode.usepreciseposition", true);
+			heightadjustmode = (HeightAdjustMode)General.Settings.ReadPluginSetting("editselectionmode.heightadjustmode", (int)HeightAdjustMode.NONE);
 			
 			// Add docker
 			panel = new EditSelectionPanel(this);
@@ -1128,7 +1259,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if((t.Position.x + t.Size) > right.x) right.x = t.Position.x + t.Size;
 					if((t.Position.y + t.Size) > right.y) right.y = t.Position.y + t.Size;
 
-					
 					if(!fixedrotationthingtypes.Contains(t.Type)) //mxd
 					{
 						ThingTypeInfo tti = General.Map.Data.GetThingInfoEx(t.Type);
@@ -1192,6 +1322,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Update
 				panel.ShowOriginalValues(baseoffset, basesize);
 				panel.SetTextureTransformSettings(General.Map.UDMF); //mxd
+				panel.SetHeightAdjustMode(heightadjustmode, selectedsectors.Count > 0); //mxd
 				UpdateRectangleComponents();
 				UpdatePanel();
 				Update();
@@ -1392,6 +1523,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				
 				General.Map.Map.Update(true, true);
 				
+				//mxd
+				int oldoutsidefloorheight = int.MinValue;
+				int oldoutsideceilingheight = int.MinValue;
+
 				// When pasting, we want to join with the parent sector
 				// where the sidedefs are referencing a virtual sector
 				if(pasting)
@@ -1463,21 +1598,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Do we have a virtual and parent sector?
 					if((vsector != null) && (parent != null))
 					{
-						// Adjust the floor and ceiling heights of all new sectors
-						if(pasteoptions.AdjustHeights)
-						{
-							ICollection<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
-							foreach(Sector s in newsectors)
-							{
-								s.CeilHeight += parent.CeilHeight - vsector.CeilHeight;
-								s.FloorHeight += parent.FloorHeight - vsector.FloorHeight;
-							}
-						}
+						//mxd. Apply HeightAdjustMode
+						AdjustSectorsHeight(General.Map.Map.GetMarkedSectors(true), heightadjustmode, vsector.FloorHeight, vsector.CeilHeight);
 					}
 					
 					// Remove any virtual sectors
 					General.Map.Map.RemoveVirtualSectors();
 				}
+				else
+				{
+					//mxd. Get floor/ceiling height from outside sector
+					if(unstablelines.Count == 0 && heightadjustmode != HeightAdjustMode.NONE)
+					{
+						// Get affected sectors
+						HashSet<Sector> affectedsectors = new HashSet<Sector>(General.Map.Map.GetSelectedSectors(true));
+						
+						Sector curoutsidesector = GetOutsideSector(affectedsectors);
+						if(curoutsidesector != null)
+						{
+							oldoutsidefloorheight = curoutsidesector.FloorHeight;
+							oldoutsideceilingheight = curoutsidesector.CeilHeight;
+						}
+					}
+				}
 
 				// Stitch geometry
 				General.Map.Map.StitchGeometry();
@@ -1491,12 +1634,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				//mxd. Update cached values
 				General.Map.Map.Update();
 
-				//mxd.  Get new lines from linedef marks...
+				//mxd. Get new lines from linedef marks...
 				HashSet<Linedef> newlines = new HashSet<Linedef>(General.Map.Map.GetMarkedLinedefs(true));
 
-				//mxd.  Marked lines were created during linedef splitting
+				//mxd. Marked lines were created during linedef splitting
 				HashSet<Linedef> changedlines = new HashSet<Linedef>(selectedlines);
 				changedlines.UnionWith(newlines);
+				foreach(Linedef l in unstablelines) if(!l.IsDisposed) changedlines.Add(l);
 
 				//mxd. Update outer sides of the selection
 				if(changedlines.Count > 0)
@@ -1506,7 +1650,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					affectedsectors.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines));
 
 					// Reattach/add/remove outer sidedefs
-					Tools.AdjustOuterSidedefs(affectedsectors, new HashSet<Linedef>(changedlines));
+					HashSet<Sidedef> adjustedsides = Tools.AdjustOuterSidedefs(affectedsectors, changedlines);
+
+					// Change floor/ceiling height?
+					if(!pasting) AdjustSectorsHeight(affectedsectors, heightadjustmode, oldoutsidefloorheight, oldoutsideceilingheight);
+
+					// Remove unneeded textures (needs to be done AFTER adjusting floor/ceiling height)
+					foreach(Sidedef side in adjustedsides)
+					{
+						side.RemoveUnneededTextures(true, true, true);
+						if(side.Other != null) side.Other.RemoveUnneededTextures(true, true, true);
+					}
 
 					// Split outer sectors
 					Tools.SplitOuterSectors(changedlines);
@@ -1552,8 +1706,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.FlipSelectionV);
 
 			//mxd. Save EditPanel-related settings 
-			General.Settings.WritePluginSetting("editselectionusespreciseposition", usepreciseposition);
-			
+			General.Settings.WritePluginSetting("editselectionmode.usepreciseposition", usepreciseposition);
+			General.Settings.WritePluginSetting("editselectionmode.heightadjustmode", (int)heightadjustmode);
+
 			// Remove docker
 			General.Interface.RemoveDocker(docker);
 			panel.Dispose();
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultVertexOverlappingLine.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultVertexOverlappingLine.cs
index 8d4ef1d37..2ecf114da 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultVertexOverlappingLine.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultVertexOverlappingLine.cs
@@ -93,6 +93,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						(lines[i].Start == lines[c].End && lines[i].End == lines[c].Start)) 
 					{
 						lines[c].Join(lines[i]);
+
+						//mxd. Textures may've become unused
+						if(lines[c].Front != null) lines[c].Front.RemoveUnneededTextures(lines[c].Back != null, false, true);
+						if(lines[c].Back != null) lines[c].Back.RemoveUnneededTextures(lines[c].Front != null, false, true);
 					}
 				}
 			}
diff --git a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.Designer.cs
index 2b5b18e8d..16652a30a 100644
--- a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.Designer.cs
@@ -29,6 +29,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private void InitializeComponent()
 		{
 			this.components = new System.ComponentModel.Container();
+			System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditSelectionPanel));
 			this.groupBox1 = new System.Windows.Forms.GroupBox();
 			this.preciseposition = new System.Windows.Forms.CheckBox();
 			this.orgposy = new System.Windows.Forms.Button();
@@ -74,6 +75,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.floortexall = new System.Windows.Forms.CheckBox();
 			this.floortexgroup = new System.Windows.Forms.GroupBox();
 			this.tooltip = new System.Windows.Forms.ToolTip(this.components);
+			this.label10 = new System.Windows.Forms.Label();
+			this.heightmode = new System.Windows.Forms.ComboBox();
 			this.groupBox1.SuspendLayout();
 			this.groupBox2.SuspendLayout();
 			this.groupBox3.SuspendLayout();
@@ -464,6 +467,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// 
 			this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
 						| System.Windows.Forms.AnchorStyles.Right)));
+			this.groupBox3.Controls.Add(this.heightmode);
+			this.groupBox3.Controls.Add(this.label10);
 			this.groupBox3.Controls.Add(this.label14);
 			this.groupBox3.Controls.Add(this.flipv);
 			this.groupBox3.Controls.Add(this.fliph);
@@ -472,7 +477,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.groupBox3.Controls.Add(this.absrot);
 			this.groupBox3.Location = new System.Drawing.Point(3, 272);
 			this.groupBox3.Name = "groupBox3";
-			this.groupBox3.Size = new System.Drawing.Size(243, 91);
+			this.groupBox3.Size = new System.Drawing.Size(243, 122);
 			this.groupBox3.TabIndex = 2;
 			this.groupBox3.TabStop = false;
 			this.groupBox3.Text = "Transform:";
@@ -480,7 +485,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// label14
 			// 
 			this.label14.AutoSize = true;
-			this.label14.Location = new System.Drawing.Point(9, 61);
+			this.label14.Location = new System.Drawing.Point(9, 88);
 			this.label14.Name = "label14";
 			this.label14.Size = new System.Drawing.Size(46, 13);
 			this.label14.TabIndex = 27;
@@ -490,7 +495,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// 
 			this.flipv.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
 			this.flipv.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.FlipSelectionV;
-			this.flipv.Location = new System.Drawing.Point(94, 53);
+			this.flipv.Location = new System.Drawing.Point(94, 80);
 			this.flipv.Name = "flipv";
 			this.flipv.Size = new System.Drawing.Size(30, 30);
 			this.flipv.TabIndex = 2;
@@ -501,7 +506,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// 
 			this.fliph.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
 			this.fliph.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.FlipSelectionH;
-			this.fliph.Location = new System.Drawing.Point(58, 53);
+			this.fliph.Location = new System.Drawing.Point(58, 80);
 			this.fliph.Name = "fliph";
 			this.fliph.Size = new System.Drawing.Size(30, 30);
 			this.fliph.TabIndex = 1;
@@ -522,9 +527,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.label11.AutoSize = true;
 			this.label11.Location = new System.Drawing.Point(146, 28);
 			this.label11.Name = "label11";
-			this.label11.Size = new System.Drawing.Size(13, 13);
+			this.label11.Size = new System.Drawing.Size(28, 13);
 			this.label11.TabIndex = 22;
-			this.label11.Text = "ยบ";
+			this.label11.Text = "deg.";
 			// 
 			// absrot
 			// 
@@ -554,7 +559,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.ceiltexgroup.Controls.Add(this.ceiltexoffset);
 			this.ceiltexgroup.Controls.Add(this.ceiltexrotation);
 			this.ceiltexgroup.Controls.Add(this.ceiltexscale);
-			this.ceiltexgroup.Location = new System.Drawing.Point(3, 369);
+			this.ceiltexgroup.Location = new System.Drawing.Point(3, 401);
 			this.ceiltexgroup.Name = "ceiltexgroup";
 			this.ceiltexgroup.Size = new System.Drawing.Size(243, 58);
 			this.ceiltexgroup.TabIndex = 3;
@@ -597,7 +602,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// ceiltexall
 			// 
 			this.ceiltexall.AutoSize = true;
-			this.ceiltexall.Location = new System.Drawing.Point(14, 368);
+			this.ceiltexall.Location = new System.Drawing.Point(14, 400);
 			this.ceiltexall.Name = "ceiltexall";
 			this.ceiltexall.Size = new System.Drawing.Size(154, 17);
 			this.ceiltexall.TabIndex = 0;
@@ -641,7 +646,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// floortexall
 			// 
 			this.floortexall.AutoSize = true;
-			this.floortexall.Location = new System.Drawing.Point(14, 432);
+			this.floortexall.Location = new System.Drawing.Point(14, 464);
 			this.floortexall.Name = "floortexall";
 			this.floortexall.Size = new System.Drawing.Size(146, 17);
 			this.floortexall.TabIndex = 1;
@@ -656,13 +661,40 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.floortexgroup.Controls.Add(this.floortexoffset);
 			this.floortexgroup.Controls.Add(this.floortexrotation);
 			this.floortexgroup.Controls.Add(this.floortexscale);
-			this.floortexgroup.Location = new System.Drawing.Point(3, 433);
+			this.floortexgroup.Location = new System.Drawing.Point(3, 465);
 			this.floortexgroup.Name = "floortexgroup";
 			this.floortexgroup.Size = new System.Drawing.Size(243, 58);
 			this.floortexgroup.TabIndex = 38;
 			this.floortexgroup.TabStop = false;
 			this.floortexgroup.Text = "  ";
 			// 
+			// label10
+			// 
+			this.label10.AutoSize = true;
+			this.label10.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+			this.label10.ForeColor = System.Drawing.SystemColors.HotTrack;
+			this.label10.Location = new System.Drawing.Point(14, 56);
+			this.label10.Name = "label10";
+			this.label10.Size = new System.Drawing.Size(41, 13);
+			this.label10.TabIndex = 28;
+			this.label10.Text = "Height:";
+			this.tooltip.SetToolTip(this.label10, resources.GetString("label10.ToolTip"));
+			// 
+			// heightmode
+			// 
+			this.heightmode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+			this.heightmode.FormattingEnabled = true;
+			this.heightmode.Items.AddRange(new object[] {
+            "Don\'t adjust height",
+            "Adjust floor height",
+            "Adjust ceiling height",
+            "Adjust floor and ceiling heights"});
+			this.heightmode.Location = new System.Drawing.Point(58, 53);
+			this.heightmode.Name = "heightmode";
+			this.heightmode.Size = new System.Drawing.Size(171, 21);
+			this.heightmode.TabIndex = 29;
+			this.heightmode.SelectedIndexChanged += new System.EventHandler(this.heightmode_SelectedIndexChanged);
+			// 
 			// EditSelectionPanel
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -738,5 +770,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private System.Windows.Forms.GroupBox floortexgroup;
 		private System.Windows.Forms.CheckBox preciseposition;
 		private System.Windows.Forms.ToolTip tooltip;
+		private System.Windows.Forms.ComboBox heightmode;
+		private System.Windows.Forms.Label label10;
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.cs b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.cs
index 7c1339560..24f9a1ffb 100644
--- a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.cs
@@ -33,20 +33,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		#region ================== Variables
 		
 		// Editing mode
-		readonly EditSelectionMode mode;
+		private readonly EditSelectionMode mode;
 		
 		// Input
 		private bool userinput;
 		private bool preventchanges; //mxd
 		
 		// Values
-		Vector2D orgpos;
-		Vector2D orgsize;
-		Vector2D abspos;
-		Vector2D relpos;
-		Vector2D abssize;
-		Vector2D relsize;
-		float absrotate;
+		private Vector2D orgpos;
+		private Vector2D orgsize;
+		private Vector2D abspos;
+		private Vector2D relpos;
+		private Vector2D abssize;
+		private Vector2D relsize;
+		private float absrotate;
 		
 		#endregion
 		
@@ -146,6 +146,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			preventchanges = false;
 		}
 
+		//mxd
+		internal void SetHeightAdjustMode(EditSelectionMode.HeightAdjustMode adjustmode, bool enable)
+		{
+			preventchanges = true;
+			heightmode.SelectedIndex = (int)adjustmode;
+			heightmode.Enabled = enable;
+			preventchanges = false;
+		}
+
 		//mxd
 		private void UpdateAllFloorTransformsCheckbox()
 		{
@@ -371,6 +380,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			mode.UsePrecisePosition = preciseposition.Checked;
 			General.Interface.FocusDisplay();
 		}
+
+		//mxd
+		private void heightmode_SelectedIndexChanged(object sender, EventArgs e)
+		{
+			if(preventchanges || heightmode.SelectedIndex == -1) return;
+			mode.SectorHeightAdjustMode = (EditSelectionMode.HeightAdjustMode)heightmode.SelectedIndex;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.resx b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.resx
index d53e092a1..e02189afe 100644
--- a/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.resx
+++ b/Source/Plugins/BuilderModes/Interface/EditSelectionPanel.resx
@@ -120,6 +120,15 @@
   <metadata name="tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
+  <data name="label10.ToolTip" xml:space="preserve">
+    <value>Allows to adjust floor/ceiling heights of the selection
+based on floor/ceiling heights difference between 
+sectors outside selected sectors.
+
+Applied only when selected sectors were inside a single 
+sector when the mode was enabled, and are inside a 
+single sector when the mode is applied.</value>
+  </data>
   <metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
index ee0bc2946..e4cea1172 100644
--- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
@@ -283,9 +283,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.autodragonpaste.AutoSize = true;
 			this.autodragonpaste.Location = new System.Drawing.Point(13, 187);
 			this.autodragonpaste.Name = "autodragonpaste";
-			this.autodragonpaste.Size = new System.Drawing.Size(202, 17);
+			this.autodragonpaste.Size = new System.Drawing.Size(201, 17);
 			this.autodragonpaste.TabIndex = 6;
-			this.autodragonpaste.Text = "Drag selection automatically on paste";
+			this.autodragonpaste.Text = "Automatically drag selection on paste";
 			this.autodragonpaste.UseVisualStyleBackColor = true;
 			// 
 			// visualmodeclearselection
@@ -293,9 +293,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.visualmodeclearselection.AutoSize = true;
 			this.visualmodeclearselection.Location = new System.Drawing.Point(13, 162);
 			this.visualmodeclearselection.Name = "visualmodeclearselection";
-			this.visualmodeclearselection.Size = new System.Drawing.Size(216, 17);
+			this.visualmodeclearselection.Size = new System.Drawing.Size(231, 17);
 			this.visualmodeclearselection.TabIndex = 5;
-			this.visualmodeclearselection.Text = "Automatic clear selection in Visual Mode";
+			this.visualmodeclearselection.Text = "Automatically clear selection in Visual Mode";
 			this.visualmodeclearselection.UseVisualStyleBackColor = true;
 			// 
 			// autoclearselection
@@ -303,9 +303,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.autoclearselection.AutoSize = true;
 			this.autoclearselection.Location = new System.Drawing.Point(13, 137);
 			this.autoclearselection.Name = "autoclearselection";
-			this.autoclearselection.Size = new System.Drawing.Size(226, 17);
+			this.autoclearselection.Size = new System.Drawing.Size(241, 17);
 			this.autoclearselection.TabIndex = 4;
-			this.autoclearselection.Text = "Automatic clear selection in Classic Modes";
+			this.autoclearselection.Text = "Automatically clear selection in Classic Modes";
 			this.autoclearselection.UseVisualStyleBackColor = true;
 			// 
 			// editnewthing
@@ -323,9 +323,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.editnewsector.AutoSize = true;
 			this.editnewsector.Location = new System.Drawing.Point(13, 87);
 			this.editnewsector.Name = "editnewsector";
-			this.editnewsector.Size = new System.Drawing.Size(258, 17);
+			this.editnewsector.Size = new System.Drawing.Size(253, 17);
 			this.editnewsector.TabIndex = 2;
-			this.editnewsector.Text = "Edit sector properties when drawing a new sector";
+			this.editnewsector.Text = "Edit sector properties after drawing a new sector";
 			this.editnewsector.UseVisualStyleBackColor = true;
 			// 
 			// additiveselect
@@ -333,9 +333,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.additiveselect.AutoSize = true;
 			this.additiveselect.Location = new System.Drawing.Point(13, 112);
 			this.additiveselect.Name = "additiveselect";
-			this.additiveselect.Size = new System.Drawing.Size(205, 17);
+			this.additiveselect.Size = new System.Drawing.Size(207, 17);
 			this.additiveselect.TabIndex = 3;
-			this.additiveselect.Text = "Additive selecting without holding shift";
+			this.additiveselect.Text = "Additive selecting without holding Shift";
 			this.additiveselect.UseVisualStyleBackColor = true;
 			// 
 			// groupBox2
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
index fc0135ff2..94ad16b19 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
@@ -386,14 +386,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd
 		private void ChangeVertexHeight(int amount) 
 		{
-			List<Vertex> verts = new List<Vertex>(3);
+			HashSet<Vertex> verts = new HashSet<Vertex>();
 
-			//do this only if all 3 verts have offsets
+			// Do this only if all 3 verts have offsets
 			foreach(Sidedef side in level.sector.Sidedefs) 
 			{
 				if(float.IsNaN(side.Line.Start.ZCeiling) || float.IsNaN(side.Line.End.ZCeiling)) return;
-				if(!verts.Contains(side.Line.Start)) verts.Add(side.Line.Start);
-				if(!verts.Contains(side.Line.End)) verts.Add(side.Line.End);
+				verts.Add(side.Line.Start);
+				verts.Add(side.Line.End);
 			}
 
 			foreach(Vertex v in verts) 
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
index 8693c5f36..d410774f8 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
@@ -357,14 +357,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd
 		private void ChangeVertexHeight(int amount) 
 		{
-			List<Vertex> verts = new List<Vertex>(3);
+			HashSet<Vertex> verts = new HashSet<Vertex>();
 
-			//do this only if all 3 verts have offsets
+			// Do this only if all 3 verts have offsets
 			foreach(Sidedef side in level.sector.Sidedefs) 
 			{
 				if(float.IsNaN(side.Line.Start.ZFloor) || float.IsNaN(side.Line.End.ZFloor)) return;
-				if(!verts.Contains(side.Line.Start)) verts.Add(side.Line.Start);
-				if(!verts.Contains(side.Line.End)) verts.Add(side.Line.End);
+				verts.Add(side.Line.Start);
+				verts.Add(side.Line.End);
 			}
 
 			foreach(Vertex v in verts) 
-- 
GitLab