diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg
index aafc65fcd78ae3558c57ae8bb5d4e83e4ad7d9bd..d0dea09b2c60763665601dd8c99ca4fe21b8abe9 100644
--- a/Build/Scripting/ZDoom_DECORATE.cfg
+++ b/Build/Scripting/ZDoom_DECORATE.cfg
@@ -308,6 +308,7 @@ keywords
 	A_Recoil = "A_Recoil(float force)";
 	A_ZoomFactor = "A_ZoomFactor[(float zoom = 1.0[, int flags = 0])]\nflags: ZOOM flags.";
 	A_SetCrosshair = "A_SetCrosshair(int number)";
+	A_WeaponOffset = "A_WeaponOffset[(float x = 0[, float y = 32[, int flags = 0])]\nflags: WOF flags.";
 //Weapon attack functions
 	A_Punch = "A_Punch";
 	A_Saw = "A_Saw[(str fullsound = \"weapons/sawfull\"[, str hitsound = \"weapons/sawhit\"[, int damage = 0[, str pufftype = \"BulletPuff\"[, int flags = 0[, float range = 65.0[, float spread_xy = 2.8125[, float spread_z = 0.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"]]]]]]]]]])]";
@@ -1343,4 +1344,8 @@ constants
 	GZF_3DRESTRICT;
 	GZF_NOPORTALS;
 	GZF_NO3DFLOOR;
+//A_WeaponOffset flags
+	WOF_KEEPX;
+	WOF_KEEPY;
+	WOF_ADD;
 }
diff --git a/Help/gzdb/text_lumps.html b/Help/gzdb/text_lumps.html
index 767349f461060e80bd1a0bb631afface6984813f..25817d507775628330f563fd8959b0867e8388db 100644
--- a/Help/gzdb/text_lumps.html
+++ b/Help/gzdb/text_lumps.html
@@ -22,7 +22,11 @@
 	</div>
 	
 	<div id="contents">
-    <p>GZDoom Builder will automatically load data from the following lumps if they are present in the map's resources.</p>
+    <p>GZDoom Builder will automatically load data from the following lumps if they are present in the map's resources:</p>
+    <h2>DECORATE:</h2>
+    Actor definitions are loaded and used to poulate Things list. Extra parameters can be assigned using <a href="../gc_decoratekeys.html">special comments</a>.<br />
+    DamageTypes are loaded and used in the "Damage Type" drop-down of the Edit Sector window (UDMF only).
+    
     <a name="textures" id="textures"></a><h2>TEXTURES:</h2>
     You can use "<strong>//$GZDB_SKIP</strong>" special comment to abort parsing of the current file. Useful if you don't want textures from certain files or parts of files to show up in the <a href="w_imagesbrowser.html">Image Browser</a> or want to increase resource loading speed.<br /><br />
     GZDoom Builder adds support for the following TEXTURES parameters:
@@ -53,6 +57,15 @@
     
     <h2>SNDSEQ:</h2>
     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>TERRAIN:</h2>
+    Terrain names are loaded and used in the floor and ceiling "Terrain" drop-downs of the Edit Sector window (UDMF only).
+    
+    <h2>X11R6RGB:</h2>
+    Colors are loaded and used by other text parsers where appropriate.
+    
+    <h2>CVARINFO:</h2>
+    CVARs are loaded. Currently the editor uses them only for "DistanceCheck" DECORATE property support.
          
     <a name="modeldef" id="modeldef"></a>
     <h2>MODELDEF:</h2>
diff --git a/Source/Core/Geometry/LinedefSide.cs b/Source/Core/Geometry/LinedefSide.cs
index 58d6281b8c689645d59aa098496644b951df8790..030379e8d45e73c110afae76b91eede18a770747 100644
--- a/Source/Core/Geometry/LinedefSide.cs
+++ b/Source/Core/Geometry/LinedefSide.cs
@@ -107,7 +107,9 @@ namespace CodeImp.DoomBuilder.Geometry
 		//mxd. Useful when debugging...
 		public override string ToString()
 		{
-			return line  + " (" + (front ? "front" : "back") + ")";
+			Sidedef side = (front ? line.Front : line.Back);
+			Sector sector = (side != null ? side.Sector : null);
+			return line + " (" + (front ? "front" : "back") + ")" + (sector != null ? ", Sector " + sector.Index : "");
 		}
 #endif
 
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index 9ed03cc8e9ea6d2b1a45cbfb6dfd4433dbbca1ba..706a8bec37e7e3c51e66f8b0b9fc1f2ebabdb80b 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -2157,6 +2157,63 @@ namespace CodeImp.DoomBuilder.Geometry
 
 		#endregion
 
+		#region ================== Sectors (mxd)
+
+		public static void SplitOuterSectors(IEnumerable<Linedef> drawnlines)
+		{
+			Dictionary<Sector, HashSet<Sidedef>> sectorsidesref = new Dictionary<Sector, HashSet<Sidedef>>();
+
+			// Create drawn lines per sector collection
+			foreach(Linedef l in drawnlines)
+			{
+				if(l.Front != null && l.Front.Sector != null)
+				{
+					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(!sectorsidesref.ContainsKey(l.Back.Sector)) sectorsidesref.Add(l.Back.Sector, new HashSet<Sidedef>());
+					sectorsidesref[l.Back.Sector].Add(l.Back);
+				}
+			}
+
+			// Split sectors
+			foreach(KeyValuePair<Sector, HashSet<Sidedef>> group in sectorsidesref)
+			{
+				// Sector has all sides selected?
+				if(group.Key.Sidedefs.Count == group.Value.Count)
+				{
+					group.Key.Marked = true; // Sometimes those are not marked...
+					continue;
+				}
+
+				// Process all sides
+				foreach(Sidedef side in group.Value)
+				{
+					// Sector was already split?
+					if(side.Sector != group.Key) continue;
+
+					// Find drawing interior
+					List<LinedefSide> sides = FindPotentialSectorAt(side.Line, side.IsFront);
+
+					// Number of potential sides fewer than the sector has?
+					if(sides != null && sides.Count > 0 && sides.Count < group.Key.Sidedefs.Count)
+					{
+						Sector newsector = MakeSector(sides, null, false);
+						if(newsector != null)
+						{
+							newsector.UpdateCache();
+							group.Key.UpdateCache();
+						}
+					}
+				}
+			}
+		}
+
+		#endregion
+
 		#region ================== Linedefs (mxd)
 
 		/// <summary>Flips sector linedefs so they all face either inward or outward.</summary>
@@ -2349,91 +2406,46 @@ namespace CodeImp.DoomBuilder.Geometry
 			// These steps must be done in 2 phases, otherwise we'll end up getting sidedefs modified in a previous adjustment loop step
 
 			// Find sidedefs to join singlesided lines
-			Dictionary<Linedef, Sidedef> linenearestsideref = new Dictionary<Linedef, Sidedef>();
+			Dictionary<Linedef, Sector> linesectorref = new Dictionary<Linedef, Sector>();
 			foreach(Linedef line in singlesidedlines)
 			{
-				// Line is now inside a sector?
-				Vector2D testpoint = line.GetSidePoint(line.Front == null);
-				Sector nearest = General.Map.Map.GetSectorByCoordinates(testpoint, selectedsectors);
+				// Line is now inside a sector? (check from the missing side!)
+				Sector nearest = FindPotentialSector(line, (line.Front == null), outersides);
 
-				if(nearest != null)
-				{
-					Linedef nl = null;
-					float distance = float.MaxValue;
-
-					// Find nearest linedef
-					foreach(Sidedef ns in nearest.Sidedefs)
-					{
-						float d = ns.Line.SafeDistanceToSq(testpoint, true);
-						if(d < distance)
-						{
-							// This one is closer
-							nl = ns.Line;
-							distance = d;
-						}
-					}
-
-					// Find nearest sidedef
-					if(nl != null)
-					{
-						Sidedef ns = (nl.SideOfLine(testpoint) <= 0 ? nl.Front : nl.Back);
-						if(ns != null) linenearestsideref[line] = ns;
-					}
-				}
+				// We can reattach our line!
+				if(nearest != null) linesectorref[line] = nearest;
 			}
 
 			// Find sidedefs to join outer sides
-			Dictionary<Sidedef, Sidedef> sidenearestsideref = new Dictionary<Sidedef, Sidedef>();
+			Dictionary<Sidedef, Sector> sidesectorref = new Dictionary<Sidedef, Sector>();
 			foreach(Sidedef side in outersides)
 			{
 				// Side is inside a sector?
-				Vector2D testpoint = side.Line.GetSidePoint(side.IsFront);
-				Sector nearest = General.Map.Map.GetSectorByCoordinates(testpoint, selectedsectors);
-				sidenearestsideref[side] = null; // This side will be removed in phase 2
+				Sector nearest = FindPotentialSector(side.Line, side.IsFront, outersides);
 
+				// We can reattach our side!
 				if(nearest != null)
 				{
-					Linedef nl = null;
-					float distance = float.MaxValue;
-
-					// Find nearest linedef
-					foreach(Sidedef ns in nearest.Sidedefs)
-					{
-						float d = ns.Line.SafeDistanceToSq(testpoint, true);
-						if(d < distance)
-						{
-							// This one is closer
-							nl = ns.Line;
-							distance = d;
-						}
-					}
-
-					// Find nearest sidedef
-					if(nl != null)
-					{
-						Sidedef ns = (nl.SideOfLine(testpoint) <= 0 ? nl.Front : nl.Back);
-						if(ns != null && ns.Sector != null)
-						{
-							if(side.Sector != ns.Sector) 
-								sidenearestsideref[side] = ns; // This side will be reattached in phase 2 
-							else
-								sidenearestsideref.Remove(side); // This side is already attached where it needs to be
-						}
-					}
+					if(side.Sector != nearest) sidesectorref[side] = nearest;  // This side will be reattached in phase 2
+					else sidesectorref.Remove(side); // This side is already attached where it needs to be
+				}
+				else
+				{
+					sidesectorref[side] = null; // This side will be removed in phase 2
 				}
 			}
 
 			// Check single-sided lines. Add new sidedefs if necessary
-			// Key is dragged single-sided line, value is the nearset side of a sector dragged line ended up in.
-			foreach(KeyValuePair<Linedef, Sidedef> group in linenearestsideref)
+			// Key is dragged single-sided line, value is a sector dragged line ended up in.
+			foreach(KeyValuePair<Linedef, Sector> group in linesectorref)
 			{
 				Linedef line = group.Key;
 
 				// Create new sidedef
-				Sidedef newside = General.Map.Map.CreateSidedef(line, line.Front == null, group.Value.Sector);
+				Sidedef newside = General.Map.Map.CreateSidedef(line, line.Front == null, group.Value);
 
 				// Copy props from the other side
-				Sidedef propssource = ((line.Front ?? line.Back) ?? group.Value);
+				Sidedef propssource = (line.Front ?? line.Back);
 				propssource.CopyPropertiesTo(newside);
 				newside.RemoveUnneededTextures(true, true, true);
 				newside.Other.RemoveUnneededTextures(true, true, true);
@@ -2450,8 +2462,8 @@ namespace CodeImp.DoomBuilder.Geometry
 			}
 
 			// Check outer sidedefs. Remove/change sector if necessary
-			// Key is outer sidedef of dragged geometry, value is nearset side of a sector dragged side ended up in.
-			foreach(KeyValuePair<Sidedef, Sidedef> group in sidenearestsideref)
+			// Key is outer sidedef of dragged geometry, value is a sector dragged side ended up in.
+			foreach(KeyValuePair<Sidedef, Sector> group in sidesectorref)
 			{
 				if(group.Value == null)
 				{
@@ -2472,7 +2484,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				else
 				{
 					// Reattach side
-					group.Key.SetSector(group.Value.Sector);
+					group.Key.SetSector(group.Value);
 					group.Key.RemoveUnneededTextures(true, true, true);
 				}
 			}
@@ -2481,6 +2493,27 @@ namespace CodeImp.DoomBuilder.Geometry
 			General.Map.Map.Update();
 		}
 
+		//mxd
+		private static Sector FindPotentialSector(Linedef line, bool front, HashSet<Sidedef> sidestoexclude)
+		{
+			List<LinedefSide> sectorsides = FindPotentialSectorAt(line, front);
+			if(sectorsides == null) return null;
+
+			// Filter outersides from the list, proceed only if all sectorsides reference the same sector
+			Sector result = null;
+			foreach(LinedefSide sectorside in sectorsides)
+			{
+				Sidedef target = (sectorside.Front ? sectorside.Line.Front : sectorside.Line.Back);
+				if(target != null && !sidestoexclude.Contains(target))
+				{
+					if(result == null) result = target.Sector;
+					else if(result != target.Sector) return null; // Fial...
+				}
+			}
+
+			return result;
+		}
+
 		#endregion
 
 		#region ================== Misc Exported Functions
diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs
index abbf3caa280ac4c5d2b2d8c3ad2bf22aff350a05..1b24de054adfdd9ffe8c3ecba6221152c4bcec16 100644
--- a/Source/Core/Map/Linedef.cs
+++ b/Source/Core/Map/Linedef.cs
@@ -1073,23 +1073,23 @@ namespace CodeImp.DoomBuilder.Map
 		public bool Join(Linedef other)
 		{
 			// Check which lines were 2 sided
-			bool l1was2s = ((other.Front != null) && (other.Back != null));
-			bool l2was2s = ((this.Front != null) && (this.Back != null));
+			bool otherwas2s = ((other.Front != null) && (other.Back != null));
+			bool thiswas2s = ((this.Front != null) && (this.Back != null));
 			
 			// Get sector references
-			Sector l1fs = other.front != null ? other.front.Sector : null;
-			Sector l1bs = other.back != null ? other.back.Sector : null;
-			Sector l2fs = this.front != null ? this.front.Sector : null;
-			Sector l2bs = this.back != null ? this.back.Sector : null;
+			Sector otherfs = (other.front != null ? other.front.Sector : null);
+			Sector otherbs = (other.back != null ? other.back.Sector : null);
+			Sector thisfs = (this.front != null ? this.front.Sector : null);
+			Sector thisbs = (this.back != null ? this.back.Sector : null);
 
 			// This line has no sidedefs?
-			if((l2fs == null) && (l2bs == null))
+			if((thisfs == null) && (thisbs == null))
 			{
 				// We have no sidedefs, so we have no influence
 				// Nothing to change on the other line
 			}
 			// Other line has no sidedefs?
-			else if((l1fs == null) && (l1bs == null))
+			else if((otherfs == null) && (otherbs == null))
 			{
 				// The other has no sidedefs, so it has no influence
 				// Copy my sidedefs to the other
@@ -1110,44 +1110,44 @@ namespace CodeImp.DoomBuilder.Map
 			else
 			{
 				// Compare front sectors
-				if((l1fs != null) && (l1fs == l2fs))
+				if((otherfs != null) && (otherfs == thisfs))
 				{
 					// Copy textures
 					if(other.front != null) other.front.AddTexturesTo(this.back);
 					if(this.front != null) this.front.AddTexturesTo(other.back);
 
-					// Change sidedefs
-					if(!JoinChangeSidedefs(other, true, back)) return false;
+					// Change sidedefs?
+					if(back != null && !JoinChangeSidedefs(other, true, back)) return false;
 				}
 				// Compare back sectors
-				else if((l1bs != null) && (l1bs == l2bs))
+				else if((otherbs != null) && (otherbs == thisbs))
 				{
 					// Copy textures
 					if(other.back != null) other.back.AddTexturesTo(this.front);
 					if(this.back != null) this.back.AddTexturesTo(other.front);
 
-					// Change sidedefs
-					if(!JoinChangeSidedefs(other, false, front)) return false;
+					// Change sidedefs?
+					if(front != null && !JoinChangeSidedefs(other, false, front)) return false;
 				}
 				// Compare front and back
-				else if((l1fs != null) && (l1fs == l2bs))
+				else if((otherfs != null) && (otherfs == thisbs))
 				{
 					// Copy textures
 					if(other.front != null) other.front.AddTexturesTo(this.front);
 					if(this.back != null) this.back.AddTexturesTo(other.back);
 
-					// Change sidedefs
-					if(!JoinChangeSidedefs(other, true, front)) return false;
+					// Change sidedefs?
+					if(front != null && !JoinChangeSidedefs(other, true, front)) return false;
 				}
 				// Compare back and front
-				else if((l1bs != null) && (l1bs == l2fs))
+				else if((otherbs != null) && (otherbs == thisfs))
 				{
 					// Copy textures
 					if(other.back != null) other.back.AddTexturesTo(this.back);
 					if(this.front != null) this.front.AddTexturesTo(other.front);
 
-					// Change sidedefs
-					if(!JoinChangeSidedefs(other, false, back)) return false;
+					// Change sidedefs?
+					if(back != null && !JoinChangeSidedefs(other, false, back)) return false;
 				}
 				else
 				{
@@ -1158,20 +1158,18 @@ namespace CodeImp.DoomBuilder.Map
 						if(this.start == other.end)
 						{
 							// Copy textures
-							if(other.back != null) other.back.AddTexturesTo(this.front);
 							if(this.back != null) this.back.AddTexturesTo(other.front);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, false, front)) return false;
+							// Change sidedefs?
+							if(front != null && !JoinChangeSidedefs(other, false, front)) return false;
 						}
 						else
 						{
 							// Copy textures
-							if(other.back != null) other.back.AddTexturesTo(this.back);
 							if(this.front != null) this.front.AddTexturesTo(other.front);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, false, back)) return false;
+							// Change sidedefs?
+							if(back != null && !JoinChangeSidedefs(other, false, back)) return false;
 						}
 					}
 					// This line single sided?
@@ -1180,21 +1178,27 @@ namespace CodeImp.DoomBuilder.Map
 						// Other line with its back to this?
 						if(other.start == this.end)
 						{
-							// Copy textures
-							if(other.back != null) other.back.AddTexturesTo(this.front);
-							if(this.back != null) this.back.AddTexturesTo(other.front);
+							//mxd. Marked sector means other side belongs to a sector being moved...
+							if(otherbs == null || !otherbs.Marked)
+							{
+								// Copy textures
+								if(other.back != null) other.back.AddTexturesTo(this.front);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, false, front)) return false;
+								// Change sidedefs
+								if(!JoinChangeSidedefs(other, false, front)) return false;
+							}
 						}
 						else
 						{
-							// Copy textures
-							if(other.front != null) other.front.AddTexturesTo(this.front);
-							if(this.back != null) this.back.AddTexturesTo(other.back);
+							//mxd. Marked sector means other side belongs to a sector being moved...
+							if(otherfs == null || !otherfs.Marked)
+							{
+								// Copy textures
+								if(other.front != null) other.front.AddTexturesTo(this.front);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, true, front)) return false;
+								// Change sidedefs
+								if(!JoinChangeSidedefs(other, true, front)) return false;
+							}
 						}
 					}
 					else
@@ -1202,33 +1206,64 @@ namespace CodeImp.DoomBuilder.Map
 						// This line with its back to the other?
 						if(this.start == other.end)
 						{
-							// Copy textures
-							if(other.back != null) other.back.AddTexturesTo(this.front);
-							if(this.back != null) this.back.AddTexturesTo(other.front);
+							//mxd. Marked sector means other side belongs to a sector being moved...
+							//mxd. Attach our front to other back?
+							if(otherbs == null || !otherbs.Marked)
+							{
+								// Copy textures
+								if(other.back != null) other.back.AddTexturesTo(this.front);
+								if(this.back != null) this.back.AddTexturesTo(other.front);
+
+								// Change sidedefs (replace other back with our front)
+								if(front != null && !JoinChangeSidedefs(other, false, front)) return false;
+							}
+							//mxd. Attach our back to other front?
+							else if(otherfs == null || !otherfs.Marked)
+							{
+								// Copy textures
+								if(other.front != null) other.front.AddTexturesTo(this.back);
+								if(this.front != null) this.front.AddTexturesTo(other.back);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, false, front)) return false;
+								// Change sidedefs (replace other back with our front)
+								if(back != null && !JoinChangeSidedefs(other, true, back)) return false;
+							}
 						}
+						// Both lines face the same way
 						else
 						{
-							// Copy textures
-							if(other.back != null) other.back.AddTexturesTo(this.back);
-							if(this.front != null) this.front.AddTexturesTo(other.front);
+							//mxd. Marked sector means other side belongs to a sector being moved...
+							//mxd. Attach our back to other back?
+							if(otherbs == null || !otherbs.Marked)
+							{
+								// Copy textures
+								if(other.back != null) other.back.AddTexturesTo(this.back);
+								if(this.front != null) this.front.AddTexturesTo(other.front);
+
+								// Change sidedefs
+								if(back != null && !JoinChangeSidedefs(other, false, back)) return false;
+							}
+							//mxd. Attach our front to other front?
+							else if(otherfs == null || !otherfs.Marked)
+							{
+								// Copy textures
+								if(other.front != null) other.front.AddTexturesTo(this.front);
+								if(this.back != null) this.back.AddTexturesTo(other.back);
 
-							// Change sidedefs
-							if(!JoinChangeSidedefs(other, false, back)) return false;
+								// Change sidedefs
+								if(front != null && !JoinChangeSidedefs(other, true, front)) return false;
+							}
 						}
 					}
 				}
 				
 				// Apply single/double sided flags if the double-sided-ness changed
-				if( (!l1was2s && ((other.Front != null) && (other.Back != null))) ||
-					(l1was2s && ((other.Front == null) || (other.Back == null))) )
+				if( (!otherwas2s && (other.Front != null && other.Back != null)) ||
+					 (otherwas2s && (other.Front == null || other.Back == null)) )
 					other.ApplySidedFlags();
 				
 				// Remove unneeded textures
-				if(other.front != null) other.front.RemoveUnneededTextures(!(l1was2s && l2was2s));
-				if(other.back != null) other.back.RemoveUnneededTextures(!(l1was2s && l2was2s));
+				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
@@ -1287,7 +1322,13 @@ namespace CodeImp.DoomBuilder.Map
 		// String representation
 		public override string ToString()
 		{
+#if DEBUG
+			string starttext = (start != null ? " (" + start : string.Empty);
+			string endtext = (end != null ? ", " + end + ")" : string.Empty);
+			return "Linedef " + listindex + (marked ? " (marked)" : "") + starttext + endtext; //mxd
+#else
 			return "Linedef " + listindex;
+#endif
 		}
 		
 		#endregion
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index 3963225469cc0bb08a01f0000883dc98b2b180a7..f6b51dfb7af94340b131c0934656d8e6b5c180dd 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -2167,8 +2167,7 @@ namespace CodeImp.DoomBuilder.Map
 						if(l1.Index == l2.Index) continue;
 						
 						// Sharing vertices?
-						if((l1.End == l2.End) ||
-						   (l1.End == l2.Start))
+						if(l1.End == l2.End || l1.End == l2.Start)
 						{
 							bool oppositedirection = (l1.End == l2.Start);
 							bool l2marked = l2.Marked;
@@ -2183,8 +2182,8 @@ namespace CodeImp.DoomBuilder.Map
 							{
 								l1.FrontInterior = l2.FrontInterior ^ oppositedirection;
 							}
-								// If l1 is marked as new geometry, we may need to flip it to preserve
-								// orientation of the original geometry, and update its FrontInterior
+							// If l1 is marked as new geometry, we may need to flip it to preserve
+							// orientation of the original geometry, and update its FrontInterior
 							else if(l1.Marked) 
 							{
 								if(oppositedirection) 
@@ -2209,8 +2208,7 @@ namespace CodeImp.DoomBuilder.Map
 						if(l1.Index == l2.Index) continue;
 						
 						// Sharing vertices?
-						if((l1.Start == l2.End) ||
-						   (l1.Start == l2.Start))
+						if(l1.Start == l2.End || l1.Start == l2.Start)
 						{
 							bool oppositedirection = (l1.Start == l2.End);
 							bool l2marked = l2.Marked;
@@ -2225,8 +2223,8 @@ namespace CodeImp.DoomBuilder.Map
 							{
 								l1.FrontInterior = l2.FrontInterior ^ oppositedirection;
 							}
-								// If l1 is marked as new geometry, we may need to flip it to preserve
-								// orientation of the original geometry, and update its FrontInterior
+							// If l1 is marked as new geometry, we may need to flip it to preserve
+							// orientation of the original geometry, and update its FrontInterior
 							else if(l1.Marked) 
 							{
 								if(oppositedirection) 
@@ -3098,17 +3096,6 @@ namespace CodeImp.DoomBuilder.Map
 			return null;
 		}
 
-		//mxd
-		/// <summary>This returns a sector if given coordinates are inside one.</summary>
-		public Sector GetSectorByCoordinates(Vector2D pos, HashSet<Sector> sectorsToExclude)
-		{
-			foreach(Sector s in sectors)
-			{
-				if(!sectorsToExclude.Contains(s) && s.Intersect(pos)) return s;
-			}
-			return null;
-		}
-
 		//mxd
 		/// <summary>This returns a sector if given coordinates are inside one.</summary>
 		public Sector GetSectorByCoordinates(Vector2D pos, VisualBlockMap blockmap) 
diff --git a/Source/Core/Map/Sector.cs b/Source/Core/Map/Sector.cs
index 8591a75d7df1c1c3a36f6b6c7a4e9bcef9266c88..53f9f89a4ad36de2fa88dac323dfbcc5a81e7a20 100644
--- a/Source/Core/Map/Sector.cs
+++ b/Source/Core/Map/Sector.cs
@@ -568,7 +568,7 @@ namespace CodeImp.DoomBuilder.Map
 		// This requires the sector triangulation to be up-to-date!
 		private RectangleF CreateBBox()
 		{
-			if(sidedefs.Count == 0) return  new RectangleF(); //mxd
+			if(sidedefs.Count == 0) return new RectangleF(); //mxd
 			
 			// Setup
 			float left = float.MaxValue;
@@ -576,29 +576,29 @@ namespace CodeImp.DoomBuilder.Map
 			float right = float.MinValue;
 			float bottom = float.MinValue;
 
-			Dictionary<Vertex, bool> processed = new Dictionary<Vertex, bool>(); //mxd
+			HashSet<Vertex> processed = new HashSet<Vertex>(); //mxd
 
 			//mxd. This way bbox will be created even if triangulation failed (sector with 2 or less sidedefs and 2 vertices)
 			foreach(Sidedef s in sidedefs) 
 			{
 				//start...
-				if(!processed.ContainsKey(s.Line.Start)) 
+				if(!processed.Contains(s.Line.Start)) 
 				{
 					if(s.Line.Start.Position.x < left) left = s.Line.Start.Position.x;
 					if(s.Line.Start.Position.x > right) right = s.Line.Start.Position.x;
 					if(s.Line.Start.Position.y < top) top = s.Line.Start.Position.y;
 					if(s.Line.Start.Position.y > bottom) bottom = s.Line.Start.Position.y;
-					processed.Add(s.Line.Start, false);
+					processed.Add(s.Line.Start);
 				}
 
 				//end...
-				if(!processed.ContainsKey(s.Line.End)) 
+				if(!processed.Contains(s.Line.End)) 
 				{
 					if(s.Line.End.Position.x < left) left = s.Line.End.Position.x;
 					if(s.Line.End.Position.x > right) right = s.Line.End.Position.x;
 					if(s.Line.End.Position.y < top) top = s.Line.End.Position.y;
 					if(s.Line.End.Position.y > bottom) bottom = s.Line.End.Position.y;
-					processed.Add(s.Line.End, false);
+					processed.Add(s.Line.End);
 				}
 			}
 			
@@ -791,7 +791,11 @@ namespace CodeImp.DoomBuilder.Map
 		// String representation
 		public override string ToString()
 		{
+#if DEBUG
+			return "Sector " + listindex + (marked ? " (marked)" : ""); //mxd
+#else
 			return "Sector " + listindex;
+#endif
 		}
 		
 		#endregion
diff --git a/Source/Core/Map/Sidedef.cs b/Source/Core/Map/Sidedef.cs
index cc24717a8afbd4afa8b5f77dbfa593dbd293eab4..c3bafcbaac88ea0602646248e7ae129e1d7fc307 100644
--- a/Source/Core/Map/Sidedef.cs
+++ b/Source/Core/Map/Sidedef.cs
@@ -633,6 +633,17 @@ namespace CodeImp.DoomBuilder.Map
 
 			General.Map.IsChanged = true;
 		}
+
+		//mxd. String representation
+		public override string ToString()
+		{
+#if DEBUG
+			return "Sidedef " + listindex + (marked ? " (marked)" : "") + " (Line " + linedef.Index + (linedef.Marked ? " (marked)" : "") + ", Sector " + sector.Index + (sector.Marked ? " (marked)" : "") + ")";
+#else
+			return "Sidedef " + listindex;
+#endif
+		}
+
 		
 		#endregion
 
diff --git a/Source/Core/Map/Vertex.cs b/Source/Core/Map/Vertex.cs
index 44e25dbce8ff291ae8d37a6cabd9a7d3757512db..d0c80fab10a441ef1173de2e6dd8f85be6dd9b35 100644
--- a/Source/Core/Map/Vertex.cs
+++ b/Source/Core/Map/Vertex.cs
@@ -329,7 +329,11 @@ namespace CodeImp.DoomBuilder.Map
 		// String representation
 		public override string ToString()
 		{
+#if DEBUG
+			return "Vertex (" + pos + (marked ? "; marked" : "") + ")";
+#else
 			return "Vertex (" + pos + ")";
+#endif
 		}
 
 		#endregion
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
index b84e25beb0035f2939e1e8716db4980a75cef70d..dca8e83423371231838c9061b74dde3cc67a234d 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
@@ -419,8 +419,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Move selected geometry to final position
 				MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptogridincrement, snaptonearest, snaptocardinaldirection);
 
+				//mxd. Used in Linedef.Join()...
+				General.Map.Map.MarkSelectedSectors(true, true);
+
 				// Stitch geometry
-				if(snaptonearest) General.Map.Map.StitchGeometry();
+				General.Map.Map.StitchGeometry();
 
 				// Make corrections for backward linedefs
 				MapSet.FlipBackwardLinedefs(General.Map.Map.Linedefs);
@@ -516,17 +519,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							s.CeilSlopeOffset = -Vector3D.DotProduct(s.CeilSlope, new Vector3D(center + offset, ceiling.GetZ(center)));
 						}
 					}
+				}
 
-					// Update cached values
-					General.Map.Map.Update();
+				// Update cached values
+				General.Map.Map.Update();
 
-					//mxd. Let the plugins know
-					General.Editing.AcceptMode();
+				//mxd. Let the plugins know
+				General.Editing.AcceptMode();
 
-					// Done
-					Cursor.Current = Cursors.Default;
-					General.Map.IsChanged = true;
-				}
+				// Done
+				Cursor.Current = Cursors.Default;
+				General.Map.IsChanged = true;
 			}
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
index 1670d26e28bad370350a51539a1818e22f7410f6..ebd9dce6e5ad9f96fca145f8d50ce74a3ebe38ff 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragLinedefsMode.cs
@@ -102,6 +102,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			ICollection<Vertex> verts = General.Map.Map.GetVerticesFromLinesMarks(true);
 			foreach(Vertex v in verts) v.Selected = true;
 
+			//mxd. Mark moved sectors (used in Linedef.Join())
+			HashSet<Sector> draggeddsectors = General.Map.Map.GetUnselectedSectorsFromLinedefs(selectedlines);
+			foreach(Sector s in draggeddsectors) s.Marked = true;
+
 			// Perform normal disengage
 			base.OnDisengage();
 
@@ -114,12 +118,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				//mxd. Reattach/add/remove sidedefs only when there are no unstable lines in selection
 				if(unstablelines.Count == 0)
 				{
-					// Add sectors, which have all their linedefs selected
-					// (otherwise those would be destroyed after moving the selection)
-					HashSet<Sector> toadjust = General.Map.Map.GetUnselectedSectorsFromLinedefs(selectedlines);
+					// 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>(selectedlines);
+					changedlines.UnionWith(newlines);
+					
+					// 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);
 
 					// Process outer sidedefs
-					Tools.AdjustOuterSidedefs(toadjust, new HashSet<Linedef>(selectedlines));
+					Tools.AdjustOuterSidedefs(toadjust, changedlines);
+
+					// Split outer sectors
+					Tools.SplitOuterSectors(changedlines);
 				}
 
 				// If only a single linedef was selected, deselect it now
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
index 4235b5f8b92b205f7eddff85b8b53983aaeaeaf1..e23c506ed709ebc30876ba31bfa1ee6afb9af088 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragSectorsMode.cs
@@ -129,6 +129,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 					// Process outer sidedefs
 					Tools.AdjustOuterSidedefs(toadjust, new HashSet<Linedef>(selectedlines));
+
+					// Split outer sectors
+					Tools.SplitOuterSectors(selectedlines);
 				}
 
 				// If only a single sector was selected, deselect it now
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
index 59f6a963b39bb005d84b1e7987a5888d531a91e0..70c466fb37f72908247a024904e98f7f3d738c8e 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragVerticesMode.cs
@@ -91,7 +91,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Select vertices from marks
 			General.Map.Map.ClearSelectedVertices();
 			General.Map.Map.SelectMarkedVertices(true, true);
-			
+
+			//mxd. Mark stable lines now (marks will be carried to split lines by MapSet.StitchGeometry())
+			HashSet<Linedef> stablelines = (!cancelled ? new HashSet<Linedef>(General.Map.Map.LinedefsFromMarkedVertices(false, true, false)) : new HashSet<Linedef>());
+			foreach(Linedef l in stablelines) l.Marked = true;
+
+			//mxd. Mark moved sectors (used in Linedef.Join())
+			HashSet<Sector> draggeddsectors = (!cancelled ? General.Map.Map.GetUnselectedSectorsFromLinedefs(stablelines) : new HashSet<Sector>());
+			foreach(Sector s in draggeddsectors) s.Marked = true;
+
 			// Perform normal disengage
 			base.OnDisengage();
 			
@@ -99,15 +107,36 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(!cancelled)
 			{
 				//mxd. Reattach/add/remove sidedefs only when there are no unstable lines in selection
-				if(selectedverts.Count > 1 && unstablelines.Count == 0)
+				if(stablelines.Count > 0 && unstablelines.Count == 0)
 				{
-					// Add sectors, which have all their linedefs selected
-					// (otherwise those would be destroyed after moving the selection)
-					HashSet<Linedef> selectedlines = new HashSet<Linedef>(General.Map.Map.LinedefsFromMarkedVertices(false, true, false));
-					HashSet<Sector> toadjust = General.Map.Map.GetUnselectedSectorsFromLinedefs(selectedlines);
-
-					// Process outer sidedefs
-					Tools.AdjustOuterSidedefs(toadjust, selectedlines);
+					// 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);
+
+					// 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);
+
+					if(changedlines.Count > 0)
+					{
+						// Process outer sidedefs
+						Tools.AdjustOuterSidedefs(toadjust, changedlines);
+
+						// Split outer sectors
+						Tools.SplitOuterSectors(changedlines);
+
+						// Additional verts may've been created
+						if(selectedverts.Count > 1)
+						{
+							foreach(Linedef l in changedlines)
+							{
+								l.Start.Selected = true;
+								l.End.Selected = true;
+							}
+						}
+					}
 				}
 				
 				// If only a single vertex was selected, deselect it now
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
index b755212326309b3bd8677906c9aae73be70d4c11..81c77308ef48e6888a0fdf67f9e06b26c09097fc 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
@@ -248,6 +248,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update cached values
 					General.Map.Map.Update();
 
+					//mxd. Outer sectors may require some splittin...
+					Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
+
 					// Edit new sectors?
 					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
 					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 0814572763e0f39c2656b1d22350a6e782209457..04907c298a8ac73ae13dcde9ad090272d961913f 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -767,6 +767,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update cached values
 					General.Map.Map.Update();
 
+					//mxd. Outer sectors may require some splittin...
+					Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
+
 					// Edit new sectors?
 					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
 					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
index 04726c9515890645b5d346ec88c1cbf89881ef8b..b9ac6b774e10825ee5518654e26af038b0f09733 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
@@ -92,7 +92,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				General.Map.UndoRedo.CreateUndo("Grid draw");
 
 				// Make an analysis and show info
-				string[] adjectives = new[] { "gloomy", "sad", "unhappy", "lonely", "troubled", "depressed", "heartsick", "glum", "pessimistic", "bitter", "downcast" }; // aaand my english vocabulary ends here :)
+				string[] adjectives = { "gloomy", "sad", "unhappy", "lonely", "troubled", "depressed", "heartsick", "glum", "pessimistic", "bitter", "downcast" }; // aaand my english vocabulary ends here :)
 				string word = adjectives[new Random().Next(adjectives.Length - 1)];
 				string a = (word[0] == 'u' ? "an " : "a ");
 
@@ -114,6 +114,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						// Clear selection
 						General.Map.Map.ClearAllSelected();
 
+						//mxd. Outer sectors may require some splittin...
+						Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
+
 						// Edit new sectors?
 						if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
 							General.Interface.ShowEditSectors(newsectors);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
index efdc401fbf17fb1b72537bb762d45df43a6db32f..0f07350c7770fff46c4f9f4f6ff758cf1713c635 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
@@ -385,6 +385,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update cached values
 					General.Map.Map.Update();
 
+					//mxd. Outer sectors may require some splittin...
+					Tools.SplitOuterSectors(General.Map.Map.GetMarkedLinedefs(true));
+
 					// Edit new sectors?
 					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
 					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
index 83ca893dca00b445f48be52cfcc38db7b30f77e4..924257e669fe268d04c125f223ea10f5f30508e7 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
@@ -1480,23 +1480,42 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 
 				// Stitch geometry
-				if(snaptonearest) General.Map.Map.StitchGeometry();
+				General.Map.Map.StitchGeometry();
 
 				// Make corrections for backward linedefs
 				MapSet.FlipBackwardLinedefs(General.Map.Map.Linedefs);
 
+				// Snap to map format accuracy
+				General.Map.Map.SnapAllToAccuracy(General.Map.UDMF && usepreciseposition);
+
 				//mxd. Reattach/add/remove sidedefs only when there are no unstable lines in selection
 				if(unstablelines.Count == 0)
 				{
+					// Update cached values
+					General.Map.Map.Update();
+					
+					// 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>(selectedlines);
+					changedlines.UnionWith(newlines);
+
 					// Update outer sides of the selection
-					HashSet<Sector> affectedsectors = new HashSet<Sector>(General.Map.Map.GetSelectedSectors(true));
-					affectedsectors.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(selectedlines));
-					Tools.AdjustOuterSidedefs(affectedsectors, new HashSet<Linedef>(selectedlines));
+					if(changedlines.Count > 0)
+					{
+						// Get affected sectors
+						HashSet<Sector> affectedsectors = new HashSet<Sector>(General.Map.Map.GetSelectedSectors(true));
+						affectedsectors.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(changedlines));
+
+						// Process outer sidedefs
+						Tools.AdjustOuterSidedefs(affectedsectors, new HashSet<Linedef>(changedlines));
+
+						// Split outer sectors
+						Tools.SplitOuterSectors(changedlines);
+					}
 				}
 				
-				// Snap to map format accuracy
-				General.Map.Map.SnapAllToAccuracy(General.Map.UDMF && usepreciseposition);
-				
 				// Update cached values
 				General.Map.Data.UpdateUsedTextures();
 				General.Map.Map.Update();