diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index c8c9a007aa03c17d75d3b525138f6c4e6157c33f..7960c1a37f3dfadeedf158ad0c2cab57699cbee5 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -1639,25 +1639,49 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 
 		//mxd
-		internal List<IVisualEventReceiver> RemoveDuplicateSidedefs(List<IVisualEventReceiver> objs) 
+		private static IEnumerable<IVisualEventReceiver> RemoveDuplicateSidedefs(IEnumerable<IVisualEventReceiver> objs) 
 		{
 			HashSet<Sidedef> processed = new HashSet<Sidedef>();
 			List<IVisualEventReceiver> result = new List<IVisualEventReceiver>();
 
-			foreach(IVisualEventReceiver i in objs)
+			if(General.Map.UDMF)
 			{
-				BaseVisualGeometrySidedef sidedef = i as BaseVisualGeometrySidedef;
-				if(sidedef != null)
+				// For UDMF maps, we only need to remove duplicate extrafloor sidedefs
+				foreach(IVisualEventReceiver i in objs)
 				{
-					if(!processed.Contains(sidedef.Sidedef))
+					if(i is VisualMiddle3D)
+					{
+						VisualMiddle3D vm = i as VisualMiddle3D;
+						if(!processed.Contains(vm.Sidedef))
+						{
+							processed.Add(vm.Sidedef);
+							result.Add(i);
+						}
+					}
+					else
 					{
-						processed.Add(sidedef.Sidedef);
 						result.Add(i);
 					}
 				}
-				else
+			}
+			else
+			{
+				// For Doom/Hexen maps, we need to remove all duplicates
+				foreach(IVisualEventReceiver i in objs)
 				{
-					result.Add(i);
+					BaseVisualGeometrySidedef sidedef = i as BaseVisualGeometrySidedef;
+					if(sidedef != null)
+					{
+						if(!processed.Contains(sidedef.Sidedef))
+						{
+							processed.Add(sidedef.Sidedef);
+							result.Add(i);
+						}
+					}
+					else
+					{
+						result.Add(i);
+					}
 				}
 			}
 
@@ -2598,8 +2622,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private void MoveTextureByOffset(int ox, int oy)
 		{
 			PreAction(UndoGroup.TextureOffsetChange);
-			List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
-			if(!General.Map.UDMF) objs = RemoveDuplicateSidedefs(objs);
+			IEnumerable<IVisualEventReceiver> objs = RemoveDuplicateSidedefs(GetSelectedObjects(true, true, false, false));
 			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(ox, oy, true);
 			PostAction();
 		}
diff --git a/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs b/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
index a89b5ca2e19640d8ae9a1417f584be11d53fc38e..80497f8e68da57fc812962ade23f33399cd58259 100644
--- a/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
@@ -1,5 +1,6 @@
 #region === Copyright (c) 2010 Pascal van der Heiden ===
 
+using System.Collections.Generic;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Map;
 
@@ -114,14 +115,46 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//mxd. Update outer sidedef geometry
 			if(updatesides)
 			{
-				foreach(Sidedef side in data.Sector.Sidedefs)
+				UpdateSectorSides(data.Sector);
+
+				// Update sectors with PlaneCopySlope Effect...
+				List<SectorData> toupdate = new List<SectorData>();
+				foreach(Sector s in data.UpdateAlso.Keys)
 				{
-					if(side.Other != null && side.Other.Sector != null && data.Mode.VisualSectorExists(side.Other.Sector))
+					SectorData osd = data.Mode.GetSectorDataEx(s);
+					if(osd == null) continue;
+					foreach(SectorEffect e in osd.Effects)
 					{
-						BaseVisualSector vs = (BaseVisualSector)data.Mode.GetVisualSector(side.Other.Sector);
-						vs.GetSidedefParts(side.Other).SetupAllParts();
+						if(e is EffectPlaneCopySlope)
+						{
+							toupdate.Add(osd);
+							break;
+						}
 					}
 				}
+
+				// Do it in 2 steps, because SectorData.Reset() may change SectorData.UpdateAlso collection...
+				foreach(SectorData sd in toupdate)
+				{
+					// Update PlaneCopySlope Effect...
+					sd.Reset(false);
+
+					// Update outer sides...
+					UpdateSectorSides(sd.Sector);
+				}
+			}
+		}
+
+		//mxd
+		private void UpdateSectorSides(Sector s)
+		{
+			foreach(Sidedef side in s.Sidedefs)
+			{
+				if(side.Other != null && side.Other.Sector != null && data.Mode.VisualSectorExists(side.Other.Sector))
+				{
+					BaseVisualSector vs = (BaseVisualSector)data.Mode.GetVisualSector(side.Other.Sector);
+					vs.GetSidedefParts(side.Other).SetupAllParts();
+				}
 			}
 		}
 	}
diff --git a/Source/Plugins/BuilderModes/VisualModes/EffectPlaneCopySlope.cs b/Source/Plugins/BuilderModes/VisualModes/EffectPlaneCopySlope.cs
index 946380c32420b023e42363aaefb6b206ce77ed6d..a158ff4b0308bce7e932b14ff109fe39a0e9843c 100644
--- a/Source/Plugins/BuilderModes/VisualModes/EffectPlaneCopySlope.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/EffectPlaneCopySlope.cs
@@ -1,4 +1,5 @@
-using CodeImp.DoomBuilder.Map;
+using System.Collections.Generic;
+using CodeImp.DoomBuilder.Map;
 
 namespace CodeImp.DoomBuilder.BuilderModes
 {
@@ -26,6 +27,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			Sector sourcesector = null;
 			SectorData sourcesectordata = null;
+			bool updatesides = false;
 
 			// Copy slopes from tagged sectors
 			//check which arguments we must use
@@ -51,6 +53,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 					data.Floor.plane = sourcesectordata.Floor.plane;
 					sourcesectordata.AddUpdateSector(data.Sector, true);
+
+					updatesides = true;
 				}
 			}
 
@@ -77,6 +81,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 						data.Ceiling.plane = sourcesectordata.Ceiling.plane;
 						sourcesectordata.AddUpdateSector(data.Sector, true);
+
+						updatesides = true;
 					}
 
 				} 
@@ -105,26 +111,73 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			}
 
 			// Copy slope across the line
-			if(!copyFloor && !copyCeiling) return;
+			if((copyFloor || copyCeiling) && linedef.Front != null && linedef.Back != null)
+			{
+				// Get appropriate source sector data
+				sourcesectordata = data.Mode.GetSectorData(front ? linedef.Back.Sector : linedef.Front.Sector);
+				if(!sourcesectordata.Updated) sourcesectordata.Update();
 
-			//get appropriate source sector data
-			sourcesectordata = data.Mode.GetSectorData(front ? linedef.Back.Sector : linedef.Front.Sector);
-			if(!sourcesectordata.Updated) sourcesectordata.Update();
+				//copy floor slope?
+				if(copyFloor)
+				{
+					data.Floor.plane = sourcesectordata.Floor.plane;
+					sourcesectordata.AddUpdateSector(data.Sector, true);
+				}
 
-			//copy floor slope?
-			if(copyFloor) 
+				//copy ceiling slope?
+				if(copyCeiling)
+				{
+					data.Ceiling.plane = sourcesectordata.Ceiling.plane;
+					sourcesectordata.AddUpdateSector(data.Sector, true);
+				}
+
+				updatesides = true;
+			}
+
+			// Update outer sidedef geometry
+			if(updatesides)
 			{
-				data.Floor.plane = sourcesectordata.Floor.plane;
-				sourcesectordata.AddUpdateSector(data.Sector, true);
+				UpdateSectorSides(data.Sector);
+
+				// Update sectors with PlaneCopySlope Effect...
+				List<SectorData> toupdate = new List<SectorData>();
+				foreach(Sector s in data.UpdateAlso.Keys)
+				{
+					SectorData osd = data.Mode.GetSectorDataEx(s);
+					if(osd == null) continue;
+					foreach(SectorEffect e in osd.Effects)
+					{
+						if(e is EffectPlaneCopySlope)
+						{
+							toupdate.Add(osd);
+							break;
+						}
+					}
+				}
+
+				// Do it in 2 steps, because SectorData.Reset() may change SectorData.UpdateAlso collection...
+				foreach(SectorData sd in toupdate)
+				{
+					// Update PlaneCopySlope Effect...
+					sd.Reset(false);
+
+					// Update outer sides...
+					UpdateSectorSides(sd.Sector);
+				}
 			}
+		}
 
-			//copy ceiling slope?
-			if(copyCeiling) 
+		//mxd
+		private void UpdateSectorSides(Sector s)
+		{
+			foreach(Sidedef side in s.Sidedefs)
 			{
-				data.Ceiling.plane = sourcesectordata.Ceiling.plane;
-				sourcesectordata.AddUpdateSector(data.Sector, true);
+				if(side.Other != null && side.Other.Sector != null && data.Mode.VisualSectorExists(side.Other.Sector))
+				{
+					BaseVisualSector vs = (BaseVisualSector)data.Mode.GetVisualSector(side.Other.Sector);
+					vs.GetSidedefParts(side.Other).SetupAllParts();
+				}
 			}
-			
 		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
index bf49f892c653d60d632051697f5de0971be82586..b156b2d45b28bf5a6ee4a601d636e2a5edb6b293 100644
--- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
@@ -66,6 +66,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public bool CeilingChanged { get { return ceilingchanged; } set { ceilingchanged |= value; } }
 		public List<SectorLevel> LightLevels { get { return lightlevels; } }
 		public List<Effect3DFloor> ExtraFloors { get { return extrafloors; } }
+		public List<SectorEffect> Effects { get { return alleffects; } } //mxd
 		public SectorLevel Floor { get { return floor; } }
 		public SectorLevel Ceiling { get { return ceiling; } }
 		public BaseVisualMode Mode { get { return mode; } }