diff --git a/Build/Compilers/ZDoom/acc.exe b/Build/Compilers/ZDoom/acc.exe
index fbdd29fc88b0c6d242e05354a4264c6a6ec16cdb..a295df1d5995775c500cee526358f6410a266d00 100644
Binary files a/Build/Compilers/ZDoom/acc.exe and b/Build/Compilers/ZDoom/acc.exe differ
diff --git a/Build/Compilers/ZDoom/zspecial.acs b/Build/Compilers/ZDoom/zspecial.acs
index 63e1b6fdc6c679c5f117312d0690223c0df717c8..e85ca5586c5890693a0010b8157b25acc216bb85 100644
--- a/Build/Compilers/ZDoom/zspecial.acs
+++ b/Build/Compilers/ZDoom/zspecial.acs
@@ -24,12 +24,12 @@ special
 	 17:Thing_Raise(1),
 	 18:StartConversation(1,2),
 	 19:Thing_Stop(1),
-	 20:Floor_LowerByValue(3),
-	 21:Floor_LowerToLowest(2),
-	 22:Floor_LowerToNearest(2),
-	 23:Floor_RaiseByValue(3),
-	 24:Floor_RaiseToHighest(2),
-	 25:Floor_RaiseToNearest(2),
+	 20:Floor_LowerByValue(3,4),
+	 21:Floor_LowerToLowest(2,3),
+	 22:Floor_LowerToNearest(2,3),
+	 23:Floor_RaiseByValue(3,5),
+	 24:Floor_RaiseToHighest(2,5),
+	 25:Floor_RaiseToNearest(2,4),
 	 26:Stairs_BuildDown(5),
 	 27:Stairs_BuildUp(5),
 	 28:Floor_RaiseAndCrush(3,4),
@@ -39,19 +39,19 @@ special
 	 32:Stairs_BuildUpSync(4),
 	 33:ForceField(0),
 	 34:ClearForceField(1),
-	 35:Floor_RaiseByValueTimes8(3),
-	 36:Floor_LowerByValueTimes8(3),
-	 37:Floor_MoveToValue(3,4),
+	 35:Floor_RaiseByValueTimes8(3,5),
+	 36:Floor_LowerByValueTimes8(3,4),
+	 37:Floor_MoveToValue(3,5),
 	 38:Ceiling_Waggle(5),
 	 39:Teleport_ZombieChanger(2),
-	 40:Ceiling_LowerByValue(3),
-	 41:Ceiling_RaiseByValue(3),
+	 40:Ceiling_LowerByValue(3,4),
+	 41:Ceiling_RaiseByValue(3,4),
 	 42:Ceiling_CrushAndRaise(3,4),
 	 43:Ceiling_LowerAndCrush(3,4),
 	 44:Ceiling_CrushStop(1),
 	 45:Ceiling_CrushRaiseAndStay(3,4),
 	 46:Floor_CrushStop(1),
-	 47:Ceiling_MoveToValue(3,4),
+	 47:Ceiling_MoveToValue(3,5),
 //	 48:Sector_Attach3dMidtex
 	 49:GlassBreak(0,1),
 //	 50:ExtraFloor_LightOnly
@@ -70,10 +70,10 @@ special
 	 63:Plat_DownByValue(4),
 	 64:Plat_UpWaitDownStay(3),
 	 65:Plat_UpByValue(4),
-	 66:Floor_LowerInstant(3),
-	 67:Floor_RaiseInstant(3),
-	 68:Floor_MoveToValueTimes8(4),
-	 69:Ceiling_MoveToValueTimes8(4),
+	 66:Floor_LowerInstant(3,4),
+	 67:Floor_RaiseInstant(3,5),
+	 68:Floor_MoveToValueTimes8(4,5),
+	 69:Ceiling_MoveToValueTimes8(4,5),
 	 70:Teleport(1,3),
 	 71:Teleport_NoFog(1,4),
 	 72:ThrustThing(2,4),
@@ -109,6 +109,9 @@ special
 //	102:Scroll_Texture_Up
 //	103:Scroll_Texture_Down
 	104:Ceiling_CrushAndRaiseSilentDist(4,5),
+	105:Door_WaitRaise(4,5),
+	106:Door_WaitClose(3,4),
+	107:Line_SetPortalTarget(2),
 
 	109:Light_ForceLightning(1),
 	110:Light_RaiseByValue(2),
@@ -177,14 +180,14 @@ special
 	188:Sector_SetCeilingScale(5),
 	189:Sector_SetFloorScale(5),
 	191:SetPlayerProperty(3),
-	192:Ceiling_LowerToHighestFloor(2),
-	193:Ceiling_LowerInstant(3),
-	194:Ceiling_RaiseInstant(3),
+	192:Ceiling_LowerToHighestFloor(2,4),
+	193:Ceiling_LowerInstant(3,5),
+	194:Ceiling_RaiseInstant(3,4),
 	195:Ceiling_CrushRaiseAndStayA(4,5),
 	196:Ceiling_CrushAndRaiseA(4,5),
 	197:Ceiling_CrushAndRaiseSilentA(4,5),
-	198:Ceiling_RaiseByValueTimes8(3),
-	199:Ceiling_LowerByValueTimes8(3),
+	198:Ceiling_RaiseByValueTimes8(3,4),
+	199:Ceiling_LowerByValueTimes8(3,4),
 	200:Generic_Floor(5),
 	201:Generic_Ceiling(5),
 	202:Generic_Door(5),
@@ -223,9 +226,9 @@ special
 	235:Floor_TransferTrigger(1),
 	236:Floor_TransferNumeric(1),
 	237:ChangeCamera(3),
-	238:Floor_RaiseToLowestCeiling(2),
+	238:Floor_RaiseToLowestCeiling(2,4),
 	239:Floor_RaiseByValueTxTy(3),
-	240:Floor_RaiseByTexture(2),
+	240:Floor_RaiseByTexture(2,4),
 	241:Floor_LowerToLowestTxTy(2),
 	242:Floor_LowerToHighest(3,4),
 	243:Exit_Normal(1),
@@ -237,10 +240,31 @@ special
 	249:Door_CloseWaitOpen(3, 4),
 	250:Floor_Donut(3),
 	251:FloorAndCeiling_LowerRaise(3,4),
-	252:Ceiling_RaiseToNearest(2),
-	253:Ceiling_LowerToLowest(2),
-	254:Ceiling_LowerToFloor(2),
+	252:Ceiling_RaiseToNearest(2,3),
+	253:Ceiling_LowerToLowest(2,4),
+	254:Ceiling_LowerToFloor(2,4),
 	255:Ceiling_CrushRaiseAndStaySilA(4,5),
+
+	// These are specialized versions of the Generic_* specials which are defined for EE Extradata.
+	256:Floor_LowerToHighestEE(2, 3),
+	257:Floor_RaiseToLowest(2, 3),
+	258:Floor_LowerToLowestCeiling(2,3),
+	259:Floor_RaiseToCeiling(2, 4),
+	260:Floor_ToCeilingInstant(1, 3),
+	261:Floor_LowerByTexture(2, 3),
+	262:Ceiling_RaiseToHighest(2, 3),
+	263:Ceiling_ToHighestInstant(1, 3),
+	264:Ceiling_LowerToNearest(2, 4),
+	265:Ceiling_RaiseToLowest(2, 3),
+	266:Ceiling_RaiseToHighestFloor(2, 3),
+	267:Ceiling_ToFloorInstant(1, 3),
+	268:Ceiling_RaiseByTexture(2, 3),
+	269:Ceiling_LowerByTexture(2, 4),
+	270:Stairs_BuildDownDoom(5),
+	271:Stairs_BuildUpDoomSync(4),
+	272:Stairs_BuildDownDoomSync(4),
+	
+	
 	
 	// internal functions have negative values
 	-1:GetLineUDMFInt(2),
diff --git a/Build/Configurations/Includes/ZDoom_linedefs.cfg b/Build/Configurations/Includes/ZDoom_linedefs.cfg
index 40a3d95997f6b363e79f334cbf23a81cc1e8ce3a..d3cae5b2abf9b1e816bfdea6f06ef575156bf9c8 100644
--- a/Build/Configurations/Includes/ZDoom_linedefs.cfg
+++ b/Build/Configurations/Includes/ZDoom_linedefs.cfg
@@ -2982,22 +2982,24 @@ zdoom
 				type = 11;
 				enum
 				{
-					1 = "Texture only";
-					2 = "Things only";
-					4 = "Both";
+					0 = "Texture only";
+					1 = "Things only";
+					2 = "Both";
 				}
 			}
 			arg3
 			{
 				title = "Horizontal Speed";
+				default = 128;
 				type = 11;
-				enum = "scroll_speeds";
+				enum = "sector_scroll_speeds_x";
 			}
 			arg4
 			{
 				title = "Vertical Speed";
+				default = 128;
 				type = 11;
-				enum = "scroll_speeds";
+				enum = "sector_scroll_speeds_y";
 			}
 		}
 		224
@@ -3025,14 +3027,16 @@ zdoom
 			arg3
 			{
 				title = "Horizontal Speed";
+				default = 128;
 				type = 11;
-				enum = "scroll_speeds";
+				enum = "sector_scroll_speeds_x";
 			}
 			arg4
 			{
 				title = "Vertical Speed";
+				default = 128;
 				type = 11;
-				enum = "scroll_speeds";
+				enum = "sector_scroll_speeds_y";
 			}
 		}
 		225
diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg
index 50f36d72d1f521274471d74667cd8a22a9969a1f..c1f17c0a99f1fcf8ef6efb5255fdee1897ea90c1 100644
--- a/Build/Configurations/Includes/ZDoom_misc.cfg
+++ b/Build/Configurations/Includes/ZDoom_misc.cfg
@@ -661,6 +661,36 @@ enums
 		128 = "128: Very fast";
 	}
 	
+	sector_scroll_speeds_x
+	{
+		0 = "0: West very fast";
+		16 = "16: West fast";
+		32 = "32: West normal";
+		64 = "64: West slow"; 
+		96 = "96: West very slow";
+		128 = "128: Don't scroll";
+		160 = "144: East very slow";
+		192 = "160: East slow";
+		224 = "176: East normal"; 
+		240 = "192: East fast";
+		256 = "256: East very fast";
+	}
+	
+	sector_scroll_speeds_y
+	{
+		0 = "0: South very fast";
+		16 = "16: South fast";
+		32 = "32: South normal";
+		64 = "64: South slow"; 
+		96 = "96: South very slow";
+		128 = "128: Don't scroll";
+		160 = "144: North very slow";
+		192 = "160: North slow";
+		224 = "176: North normal"; 
+		240 = "192: North fast";
+		256 = "256: North very fast";
+	}
+	
 	stair_speeds
 	{
 		2  = "2: Slow";
diff --git a/Build/Scripting/ZDoom_ACS.cfg b/Build/Scripting/ZDoom_ACS.cfg
index 0c720800c2d726c266cab29463a81fb238fabfa3..2982cfe89d911dd0b2816060cf24ae6e72b4adc6 100644
--- a/Build/Scripting/ZDoom_ACS.cfg
+++ b/Build/Scripting/ZDoom_ACS.cfg
@@ -72,6 +72,7 @@ keywords
 	Ceiling_CrushAndRaiseA = "Ceiling_CrushAndRaiseA(tag, dspeed, uspeed, crush, crushmode)";
 	Ceiling_CrushAndRaiseDist = "Ceiling_CrushAndRaiseDist(tag, dist, speed, damage, crushmode)";
 	Ceiling_CrushAndRaiseSilentA = "Ceiling_CrushAndRaiseSilentA(tag, dspeed, uspeed, crush, crushmode)";
+	Ceiling_CrushAndRaiseSilentDist = "Ceiling_CrushAndRaiseSilentDist(tag, dist, speed, damage[, crushmode])";
 	Ceiling_CrushRaiseAndStay = "Ceiling_CrushRaiseAndStay(tag, speed, crush, crushmode)";
 	Ceiling_CrushRaiseAndStayA = "Ceiling_CrushRaiseAndStayA(tag, dspeed, uspeed, crush, crushmode)";
 	Ceiling_CrushRaiseAndStaySilA = "Ceiling_CrushRaiseAndStaySilA(tag, dspeed, uspeed, crush, crushmode)";
@@ -91,8 +92,8 @@ keywords
 	Ceiling_RaiseInstant = "Ceiling_RaiseInstant(tag, unused, height)";
 	Ceiling_RaiseToNearest = "Ceiling_RaiseToNearest(tag, speed)";
 	Ceiling_Waggle = "Ceiling_Waggle(tag, amp, freq, offset, time)";
-	ChangeActorAngle = "ChangeActorAngle(int tid, fixed angle[, bool interpolate = false])\nSets the angle for the actors with the specified tid.\nIf tid is 0, it sets the angle for the activator of the script.\nangle: a fixed point angle in the range of 0.0 to 1.0 (N = 0.25, W = 0.5, S = 0.75, E = 1.0).";
-	ChangeActorPitch = "ChangeActorPitch(int tid, fixed pitch[, bool interpolate = false])\nSets the pitch for the actors with the specified tid. If tid is 0, it sets the pitch for the activator of the script.\npitch: a fixed point angle in the range of 0.0 to 1.0.";
+	ChangeActorAngle = "void ChangeActorAngle(int tid, fixed angle[, bool interpolate = false])\nSets the angle for the actors with the specified tid.\nIf tid is 0, it sets the angle for the activator of the script.\nangle: a fixed point angle in the range of 0.0 to 1.0 (N = 0.25, W = 0.5, S = 0.75, E = 1.0).";
+	ChangeActorPitch = "void ChangeActorPitch(int tid, fixed pitch[, bool interpolate = false])\nSets the pitch for the actors with the specified tid. If tid is 0, it sets the pitch for the activator of the script.\npitch: a fixed point angle in the range of 0.0 to 1.0.";
 	ChangeActorRoll = "void ChangeActorRoll(int tid, fixed angle[, bool interpolate = false])";
 	ChangeCamera = "ChangeCamera(tid, who, revert)";
 	ChangeCeiling = "void ChangeCeiling(int tag, str flatname)";
diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg
index cb2355642ed0c597c86bc6d05d1882a512a26c8f..194679dc8852f6930ff1dc4cc57b40882fc963e0 100644
--- a/Build/Scripting/ZDoom_DECORATE.cfg
+++ b/Build/Scripting/ZDoom_DECORATE.cfg
@@ -23,7 +23,50 @@ scripttype = 3; //0 = unknown script, 1 = acc, 2 = modeldef, 3 = decorate
 
 keywords
 {
+//Editor special comments
+//These are handled in a different fascion: key is replaced with the value and the caret is placed at [EP] position	
+	$Angled = "$Angled";
+	$NotAngled = "$NotAngled";
+	$Category = "//$Category \"[EP]\"";
+	$Sprite = "//$Sprite \"[EP]\"";
+	$IgnoreRenderstyle = "//$IgnoreRenderstyle";
+	$Title = "//$Title \"[EP]\"";
+	$Arg0 = "//$Arg0 \"[EP]\"";
+	$Arg1 = "//$Arg1 \"[EP]\"";
+	$Arg2 = "//$Arg2 \"[EP]\"";
+	$Arg3 = "//$Arg3 \"[EP]\"";
+	$Arg4 = "//$Arg4 \"[EP]\"";
+	$Arg0Default = "//$Arg0Default ";
+	$Arg1Default = "//$Arg1Default ";
+	$Arg2Default = "//$Arg2Default ";
+	$Arg3Default = "//$Arg3Default ";
+	$Arg4Default = "//$Arg4Default ";
+	$Arg0Tooltip = "//$Arg0Tooltip \"[EP]\"";
+	$Arg1Tooltip = "//$Arg1Tooltip \"[EP]\"";
+	$Arg2Tooltip = "//$Arg2Tooltip \"[EP]\"";
+	$Arg3Tooltip = "//$Arg3Tooltip \"[EP]\"";
+	$Arg4Tooltip = "//$Arg4Tooltip \"[EP]\"";
+	$Arg0Type = "//$Arg0Type ";
+	$Arg1Type = "//$Arg1Type ";
+	$Arg2Type = "//$Arg2Type ";
+	$Arg3Type = "//$Arg3Type ";
+	$Arg4Type = "//$Arg4Type ";
+	$Arg0Enum = "//$Arg0Enum ";
+	$Arg1Enum = "//$Arg1Enum ";
+	$Arg2Enum = "//$Arg2Enum ";
+	$Arg3Enum = "//$Arg3Enum ";
+	$Arg4Enum = "//$Arg4Enum ";
+	$Color = "//$Color ";
+	$Obsolete = "//$Obsolete \"[EP]\"";
+	$GZDB_SKIP = "//$GZDB_SKIP";
+//Preprocessor directives
 	#Include = "#Include";
+	#region = "#region";
+	#endregion = "#endregion";
+//WFDS
+	A_Bool = "return A_Bool(bool result);";
+	A_Int = "return A_Int(int result);";
+	A_State = "return A_State(str state);\nreturn A_State(int offset);";
 //Monster AI
 	A_AlertMonsters = "A_AlertMonsters[(float maxrange = 0.0[, int flags = 0])]";
 	A_Burst = "A_Burst(str chunktype)";
@@ -49,7 +92,7 @@ keywords
 	A_KillTracer = "A_KillTracer[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage.";
 	A_Look = "A_Look";
 	A_Look2 = "A_Look2";
-	A_LookEx = "A_LookEx(int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state seestate)";
+	A_LookEx = "A_LookEx(int flags, float minseedist, float maxseedist, float maxheardist, float fov, state seestate)";
 	A_RaiseChildren = "A_RaiseChildren[(bool copyaffiliation = false)]";
 	A_RaiseMaster = "A_RaiseMaster[(bool copyaffiliation = false)]";
 	A_RaiseSiblings = "A_RaiseSiblings[(bool copyaffiliation = false)]"; 
@@ -64,23 +107,23 @@ keywords
 	A_Srcr2Decide = "A_Srcr2Decide";
 	A_SwapTeleFog = "A_SwapTeleFog";
 	A_TurretLook = "A_TurretLook";
-	A_Teleport = "A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]";
+	A_Teleport = "state A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]\nbool A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]";
 	A_VileChase = "A_VileChase";
 	A_Wander = "A_Wander";
 //Generic monster attacks
 	A_CustomMissile = "A_CustomMissile(str missiletype[, float spawnheight = 0.0[, int spawnofs_horiz = 0[, int angle = 0[, int aimflags = 0[, int pitch = 0[, int target = AAPTR_TARGET]]]]]])";
 	A_CustomBulletAttack = "A_CustomBulletAttack(float horz_spread, float vert_spread, int numbullets, int damageperbullet[, str pufftype = \"BulletPuff\"[, float range = 0.0[, int flags = 0[, int target = AAPTR_TARGET]]]])";
-	A_CustomRailgun = "A_CustomRailgun(int damage[, int offset[, color ringcolor[, color corecolor[, int flags = 0[, bool aim = false[, float maxdiff = 0.0[, str pufftype = \"\"[, float spread_xy = 0.0[, float spread_z = 0.0[, fixed range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass = \"\"[, float spawnofs_z = 0[, int spiraloffset = 270]]]]]]]]]]]]]]]])";
+	A_CustomRailgun = "A_CustomRailgun(int damage[, int offset[, color ringcolor[, color corecolor[, int flags = 0[, bool aim = false[, float maxdiff = 0.0[, str pufftype = \"\"[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass = \"\"[, float spawnofs_z = 0[, int spiraloffset = 270]]]]]]]]]]]]]]]])";
 	A_CustomMeleeAttack = "A_CustomMeleeAttack[(int damage = 0[, str meleesound = \"\"[, str misssound = \"\"[, str damagetype = \"Melee\"[, bool bleed = true]]]])]";
 	A_CustomComboAttack = "A_CustomComboAttack(str missiletype, float spawnheight, int damage, str meleesound[, str damagetype = \"Melee\"[, bool bleed = true]])";
-	A_MonsterRefire = "A_MonsterRefire(int chancecontinue, str abortstate) ";
+	A_MonsterRefire = "state A_MonsterRefire(int chancecontinue, str abortstate)";
 	A_BasicAttack = "A_BasicAttack(int meleedamage, str meleesound, str missiletype, float missileheight)";
 	A_BulletAttack = "A_BulletAttack";
 	A_MonsterRail = "A_MonsterRail";
 	A_Explode = "A_Explode[(int explosiondamage = 128[, int explosionradius = 128[, int flags = XF_HURTSOURCE[, bool alert = false[, int fulldamageradius = 0[, int nails = 0[, int naildamage = 10[, str pufftype = \"BulletPuff\"]]]]]]])]";
 	A_RadiusThrust = "A_RadiusThrust(int force, int distance[, int flags[, int fullthrustdistance]])";
 	A_Detonate = "A_Detonate";
-	A_ThrowGrenade = "A_ThrowGrenade(str spawntype[, float spawnheight[, float throwspeed_horz[, float throwspeed_vert[, bool useammo]]]])";
+	A_ThrowGrenade = "bool A_ThrowGrenade(str spawntype[, float spawnheight[, float throwspeed_horz[, float throwspeed_vert[, bool useammo]]]])";
 	A_WolfAttack = "A_WolfAttack[(int flags = 0[, str soundname = \"weapons/pistol\"[, float snipe = 1.0[, int damage = 64[, int blocksize = 128[, int pointblank = 0[, int longrange = 0[, float runspeed = 160.0[, str pufftype = \"BulletPuff\"]]]]]]]])]"; 
 //Freeze death functions 
 	A_FreezeDeath = "A_FreezeDeath";
@@ -116,45 +159,45 @@ keywords
 	A_CheckTerrain = "A_CheckTerrain";
 	A_SetBlend = "A_SetBlend(str blendcolor, float alpha, int duration[, str fadecolor])";
 	A_CheckPlayerDone = "A_CheckPlayerDone";
-	A_PlayerSkinCheck = "A_PlayerSkinCheck(str state)";
+	A_PlayerSkinCheck = "state A_PlayerSkinCheck(str state)";
 	A_SkullPop = "A_SkullPop[(str type = \"BloodySkull\")]";
 	A_Quake = "A_Quake(int intensity, int duration, int damageradius, int tremorradius[, str sound = \"world/quake\"])";
 	A_QuakeEx = "A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad[, str sound = \"world/quake\"[, int flags = 0[, float mulwavex = 1.0[, float mulwavey = 1.0[, float mulwavez = 1.0]]]]])";
 //Spawn functions
 	A_TossGib = "A_TossGib";
 	A_SpawnDebris = "A_SpawnDebris(str type[, bool translation = false[, float horizontal_vel = 1.0[, float vertical_vel = 1.0]]])";
-	A_SpawnItem = "A_SpawnItem(str type, int distance, float zpos, bool useammo, bool translation)";
-	A_SpawnItemEx = "A_SpawnItemEx(str type[, float xoffset = 0.0[, float yoffset = 0.0[, float zoffset = 0.0[, float xvelocity = 0.0[, float yvelocity = 0.0[, float zvelocity = 0.0[, float angle = 0.0[, int flags = 0[, int skipchance = 0[, int tid = 0]]]]]]]]]])";
+	A_SpawnItem = "bool A_SpawnItem(str type, int distance, float zpos, bool useammo, bool translation)";
+	A_SpawnItemEx = "bool A_SpawnItemEx(str type[, float xoffset = 0.0[, float yoffset = 0.0[, float zoffset = 0.0[, float xvelocity = 0.0[, float yvelocity = 0.0[, float zvelocity = 0.0[, float angle = 0.0[, int flags = 0[, int skipchance = 0[, int tid = 0]]]]]]]]]])";
 	A_SpawnParticle = "A_SpawnParticle(color color[, int flags = 0[, int lifetime = 35[, int size = 1[, float angle = 0.0[, float xoff = 0.0[, float yoff = 0.0[, float zoff = 0.0[, float velx = 0.0[, float vely = 0.0[, float velz = 0.0[, float accelx = 0.0[, float accely = 0.0[, float accelz = 0.0[, float startalpha = 1.0[, float fadestep = -1.0]]]]]]]]]]]]]]])";
 //State jumps
-	A_CheckBlock = "A_CheckBlock(str block[, int flags = 0[, int pointer = AAPTR_TARGET]])";
-	A_CheckCeiling = "A_CheckCeiling(int offset OR str state)";
-	A_CheckFloor = "A_CheckFloor(int offset OR str state)";
-	A_CheckFlag = "A_CheckFlag(str flagname, state label[, int check_pointer = AAPTR_DEFAULT])";
-	A_CheckLOF = "A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT]]]]]]]])";
-	A_CheckProximity = "A_CheckProximity(str jump, str classname, float distance[, int count = 1[, int flags = 0[, int pointer = AAPTR_DEFAULT]]])"; 
-	A_CheckRange = "A_CheckRange(float distance, int offset OR str state[, bool 2d_check = false])";
-	A_CheckSight = "A_CheckSight(int offset OR str state)";
-	A_CheckSightOrRange = "A_CheckSightOrRange(float distance, int offset OR str state[, bool 2d_check = false])";
-	A_CheckSpecies = "A_CheckSpecies(str jump[, str species=\"None\"[, int pointer = AAPTR_DEFAULT]]) ";
-	A_Jump = "A_Jump(int chance, int offset OR str state, ...)";
-	A_JumpIf = "A_JumpIf(expression, int offset OR str state)";
-	A_JumpIfArmorType = "A_JumpIfArmorType(str armortype, str state[, int minimum = 1])";
-	A_JumpIfCloser = "A_JumpIfCloser(int distance, int offset OR str state[, bool noz = false])";
-	A_JumpIfHealthLower = "A_JumpIfHealthLower(int health, int offset OR str state[, int pointer = AAPTR_DEFAULT])";
-	A_JumpIfHigherOrLower = "A_JumpIfHigherOrLower(str high, str low[, float offsethigh = 0.0[, float offsetlow = 0.0[, bool includeHeight = true[, int pointer = AAPTR_TARGET]]]])";
-	A_JumpIfInventory = "A_JumpIfInventory(str inventorytype, int amount, int offset OR str state[, int owner = AAPTR_DEFAULT])";
-	A_JumpIfInTargetInventory = "A_JumpIfInTargetInventory(str item, int count, int offset OR str state[, int forward = AAPTR_DEFAULT])";
-	A_JumpIfInTargetLOS = "A_JumpIfInTargetLOS(int offset OR str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags.";
-	A_JumpIfMasterCloser = "A_JumpIfMasterCloser(int distance, int offset OR str state[, bool noz = false])";
-	A_JumpIfNoAmmo = "A_JumpIfNoAmmo(int offset OR str state)";
-	A_JumpIfTargetInLOS = "A_JumpIfTargetInLOS(int offset OR str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags.";
-	A_JumpIfTargetInsideMeleeRange = "A_JumpIfTargetInsideMeleeRange(int offset OR str state)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is within melee range of the caller.";
-	A_JumpIfTargetOutsideMeleeRange = "A_JumpIfTargetOutsideMeleeRange(int offset OR str state)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is beyond melee range of the caller.";
-	A_JumpIfTracerCloser = "A_JumpIfTracerCloser(int distance, int offset OR str state[, bool noz = false])";
+	A_CheckBlock = "state A_CheckBlock(str block[, int flags = 0[, int pointer = AAPTR_TARGET]])";
+	A_CheckCeiling = "state A_CheckCeiling(str state)\nstate A_CheckCeiling(int offset)";
+	A_CheckFloor = "state A_CheckFloor(str state)\nstate A_CheckFloor(int offset)";
+	A_CheckFlag = "state A_CheckFlag(str flagname, state label[, int check_pointer = AAPTR_DEFAULT])";
+	A_CheckLOF = "state A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT]]]]]]]])";
+	A_CheckProximity = "state A_CheckProximity(str jump, str classname, float distance[, int count = 1[, int flags = 0[, int pointer = AAPTR_DEFAULT]]])"; 
+	A_CheckRange = "state A_CheckRange(float distance, str state[, bool 2d_check = false])\nstate A_CheckRange(float distance, int offset[, bool 2d_check = false])";
+	A_CheckSight = "state A_CheckSight(str state)\nstate A_CheckSight(int offsete)";
+	A_CheckSightOrRange = "state A_CheckSightOrRange(float distance, str state[, bool 2d_check = false])\nstate A_CheckSightOrRange(float distance, int offset[, bool 2d_check = false])";
+	A_CheckSpecies = "state A_CheckSpecies(str jump[, str species=\"None\"[, int pointer = AAPTR_DEFAULT]]) ";
+	A_Jump = "state A_Jump(int chance, str state, ...)\nstate A_Jump(int chance, int offset, ...)";
+	A_JumpIf = "state A_JumpIf(expression, str state)\nstate A_JumpIf(expression, int offset)";
+	A_JumpIfArmorType = "state A_JumpIfArmorType(str armortype, str state[, int minimum = 1])";
+	A_JumpIfCloser = "state A_JumpIfCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfCloser(int distance, int offset[, bool noz = false])";
+	A_JumpIfHealthLower = "state A_JumpIfHealthLower(int health, str state[, int pointer = AAPTR_DEFAULT])\nstate A_JumpIfHealthLower(int health, int offset[, int pointer = AAPTR_DEFAULT])";
+	A_JumpIfHigherOrLower = "state A_JumpIfHigherOrLower(str high, str low[, float offsethigh = 0.0[, float offsetlow = 0.0[, bool includeheight = true[, int pointer = AAPTR_TARGET]]]])";
+	A_JumpIfInventory = "state A_JumpIfInventory(str inventorytype, int amount, str state[, int owner = AAPTR_DEFAULT])\nstate A_JumpIfInventory(str inventorytype, int amount, int offset[, int owner = AAPTR_DEFAULT])";
+	A_JumpIfInTargetInventory = "state A_JumpIfInTargetInventory(str item, int count, str state[, int forward = AAPTR_DEFAULT])\nstate A_JumpIfInTargetInventory(str item, int count, int offset[, int forward = AAPTR_DEFAULT])";
+	A_JumpIfInTargetLOS = "state A_JumpIfInTargetLOS(str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nstate A_JumpIfInTargetLOS(int offset[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags.";
+	A_JumpIfMasterCloser = "state A_JumpIfMasterCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfMasterCloser(int distance, int offset[, bool noz = false])";
+	A_JumpIfNoAmmo = "state A_JumpIfNoAmmo(str state)\nstate A_JumpIfNoAmmo(int offset)";
+	A_JumpIfTargetInLOS = "state A_JumpIfTargetInLOS(str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nstate A_JumpIfTargetInLOS(int offset[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags.";
+	A_JumpIfTargetInsideMeleeRange = "state A_JumpIfTargetInsideMeleeRange(str state)\nstate A_JumpIfTargetInsideMeleeRange(int offset)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is within melee range of the caller.";
+	A_JumpIfTargetOutsideMeleeRange = "state A_JumpIfTargetOutsideMeleeRange(str state)\nstate A_JumpIfTargetOutsideMeleeRange(int offset)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is beyond melee range of the caller.";
+	A_JumpIfTracerCloser = "state A_JumpIfTracerCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfTracerCloser(int distance, int offset[, bool noz = false])";
 //Status changes
 	A_ActiveAndUnblock = "A_ActiveAndUnblock"; 
-	A_CallSpecial = "A_CallSpecial(int special[, int arg1 = 0[, int arg2 = 0[, int arg3 = 0[, int arg4 = 0[, int arg5 = 0]]]]])";
+	A_CallSpecial = "bool A_CallSpecial(int special[, int arg1 = 0[, int arg2 = 0[, int arg3 = 0[, int arg4 = 0[, int arg5 = 0]]]]])";
 	A_ChangeFlag = "A_ChangeFlag(str flagname, bool value)";
 	A_ChangeVelocity = "A_ChangeVelocity[(float x = 0.0[, float y = 0.0[, float z = 0.0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]])]\nflags: CVF flags.";
 	A_ClearShadow = "A_ClearShadow";
@@ -163,7 +206,7 @@ keywords
 	A_FadeIn = "A_FadeIn[(float increase_amount = 0.1[, int flags = 0])]\nflags: FTF flags.";
 	A_FadeOut = "A_FadeOut[(float reduce_amount = 0.1[, int flags = FTF_REMOVE])]\nflags: FTF flags.";
 	A_FadeTo = "A_FadeTo(float target[, float amount = 0.1[, int flags = 0]])\nflags: FTF flags.";
-	A_FaceMovementDirection = "A_FaceMovementDirection([float offset = 0[, float anglelimit = 0[, float pitchlimit = 0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]]])";
+	A_FaceMovementDirection = "state A_FaceMovementDirection[(float offset = 0[, float anglelimit = 0[, float pitchlimit = 0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]])]";
 	A_Fall = "A_Fall";
 	A_Gravity = "A_Gravity";
 	A_HideThing = "A_HideThing";
@@ -178,6 +221,7 @@ keywords
 	A_ScreamAndUnblock = "A_ScreamAndUnblock";
 	A_SetAngle = "A_SetAngle(float angle[, int flags = 0[, int pointer = AAPTR_DEFAULT]])\nangle: the actor's new angle, in degrees.\nflags: SPF flags.";
 	A_SetArg = "A_SetArg(int position, int value)";
+	A_SetChaseThreshold = "A_SetChaseThreshold(int threshold[, bool setdefaultthreshhold = false[, int pointer = AAPTR_DEFAULT]])";
 	A_SetDamageType = "A_SetDamageType(str damagetype)";
 	A_SetFloat = "A_SetFloat";
 	A_SetFloatSpeed = "A_SetFloatSpeed(float speed[, int pointer = AAPTR_DEFAULT])";
@@ -220,23 +264,23 @@ keywords
 	A_FaceTracer = "A_FaceTracer[(float angle = 0.0[, float pitch = 270.0])]\nA_FaceTracer([float max_turn = 0.0[, float max_pitch = 270.0[, float ang_offset = 0.0[, float pitch_offset = 0.0[, int flags = 0[, float z_add = 0.0]]]]]])";
 	A_Fire = "A_Fire[(float height = 0.0)]";
 	A_Weave = "A_Weave(int horzspeed, int vertspeed, float horzdist, float vertdist)";
-	A_Warp = "A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nflags: WARPF flags.";
+	A_Warp = "state A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nbool A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nflags: WARPF flags.";
 	A_Countdown = "A_Countdown";
 	A_CountdownArg = "A_CountdownArg(int arg[, str targetstate])";
 	A_Stop = "A_Stop";
 //Inventory functions
-	A_GiveInventory = "A_GiveInventory(str type[, int count = 0[, int giveto = AAPTR_DEFAULT]])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.\ngiveto: the actor to give the item to";
-	A_GiveToChildren = "A_GiveToChildren(str type[, int count])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.";
-	A_GiveToSiblings = "A_GiveToSiblings(str type[, int count])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.";
-	A_GiveToTarget = "A_GiveToTarget(str type, int count[, int giveto])";
-	A_TakeInventory = "A_TakeInventory(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])";
-	A_TakeFromChildren = "A_TakeFromChildren(str type[, int count])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0.";
-	A_TakeFromSiblings = "A_TakeFromSiblings(str type[, int count])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0.";
-	A_TakeFromTarget = "A_TakeFromTarget(str type, int count[, int flags[, int takefrom]])";
+	A_GiveInventory = "bool A_GiveInventory(str type[, int count = 0[, int giveto = AAPTR_DEFAULT]])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.\ngiveto: the actor to give the item to";
+	A_GiveToChildren = "int A_GiveToChildren(str type[, int count = 0])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.";
+	A_GiveToSiblings = "int A_GiveToSiblings(str type[, int count = 0])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.";
+	A_GiveToTarget = "bool A_GiveToTarget(str type, int count[, int giveto = AAPTR_DEFAULT])";
+	A_TakeInventory = "bool A_TakeInventory(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])";
+	A_TakeFromChildren = "int A_TakeFromChildren(str type[, int count = 0])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0.";
+	A_TakeFromSiblings = "int A_TakeFromSiblings(str type[, int count = 0])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0.";
+	A_TakeFromTarget = "bool A_TakeFromTarget(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])";
 	A_DropInventory = "A_DropInventory(str type)";
 	A_DropItem = "A_DropItem(str item[, int dropamount = -1[, int chance = 256]])\nThe calling actor drops the specified item.\nThis works in a similar way to the DropItem actor property.";
-	A_SelectWeapon = "A_SelectWeapon(str type)";
-	A_RadiusGive = "A_RadiusGive(str item, fixed distance, int flags[, int amount = 0[, str filter = \"None\"[, str species = \"None\"[, fixed mindist = 0]]]])\nflags: RGF flags.";
+	A_SelectWeapon = "bool A_SelectWeapon(str type)";
+	A_RadiusGive = "int A_RadiusGive(str item, float distance, int flags[, int amount = 0[, str filter = \"None\"[, str species = \"None\"[, float mindist = 0]]]])\nflags: RGF flags.";
 //Weapon functions
 	A_WeaponReady = "A_WeaponReady[(int flags = 0)]\nflags: WRF flags.";
 	A_Lower = "A_Lower";
@@ -245,7 +289,7 @@ keywords
 	A_ClearReFire = "A_ClearReFire";
 	A_GunFlash = "A_GunFlash[(str state = \"Flash\"[, int flags = 0])]\nflags: GFF flags.";
 	A_CheckReload = "A_CheckReload";
-	A_CheckForReload = "A_CheckForReload(int counter, str state[, bool dontincrement = false])";
+	A_CheckForReload = "state A_CheckForReload(int counter, str state[, bool dontincrement = false])";
 	A_ResetReloadCounter = "A_ResetReloadCounter";
 	A_Light = "A_Light(int intensity)";
 	A_Light0 = "A_Light0";
@@ -260,8 +304,8 @@ keywords
 	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\"]]]]]]]]]])]";
 	A_CustomPunch = "A_CustomPunch(int damage[, bool norandom = false[, int flags = 0[, str pufftype = \"BulletPuff\"[, float range = 64.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"[, str meleesound[, str misssound]]]]]]]]])";
 	A_FireBullets = "A_FireBullets(int spread_horz, int spread_vert, int numbullets, int damage[, str pufftype = \"\"[, int flags = FBF_USEAMMO[, float range = 0.0]]])";
-	A_FireCustomMissile = "A_FireCustomMissile(str missiletype[, int angle = 0[, bool useammo = false[, int spawnofs_horz = 0[, int spawnheight = 0[, bool aim = false OR int flags = 0[, angle pitch = 0]]]]]])";
-	A_RailAttack = "A_RailAttack(int damage[, int spawnofs_horz[, bool useammo[, str ringcolor[, str corecolor[, int flags[, int maxdiff[, str pufftype[, float spread_xy = 0[, float spread_z = 0.0[, fixed range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass[, float spawnofs_z = 0.0[, int spiraloffset = 270]]]]]]]]]]]]]]]])";
+	A_FireCustomMissile = "A_FireCustomMissile(str missiletype[, int angle = 0[, bool useammo = false[, int spawnofs_horz = 0[, int spawnheight = 0[, int flags = 0[, angle pitch = 0]]]]]])";
+	A_RailAttack = "A_RailAttack(int damage[, int spawnofs_horz[, bool useammo[, str ringcolor[, str corecolor[, int flags[, int maxdiff[, str pufftype[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192.0[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass[, float spawnofs_z = 0.0[, int spiraloffset = 270]]]]]]]]]]]]]]]])";
 	A_FireAssaultGun = "A_FireAssaultGun";
 	A_FireBFG = "A_FireBFG";
 	A_FireOldBFG = "A_FireOldBFG";
@@ -324,7 +368,7 @@ keywords
 	A_BarrelDestroy = "A_BarrelDestroy";
 //Miscellaneous functions not listed in the "Action functions" wiki article
 	A_Bang4Cloud = "A_Bang4Cloud";
-	A_Blast = "A_Blast[(int flags = 0[, int strength = 255[, int radius = 255[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, sound blastsound = \"BlastRadius\"]]]]])]";
+	A_Blast = "A_Blast[(int flags = 0[, int strength = 255[, int radius = 255[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, str blastsound = \"BlastRadius\"]]]]])]\nA_Blast[(int flags = 0[, int strength = 255[, float radius = 255.0[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, str blastsound = \"BlastRadius\"]]]]])]";
 	A_BishopMissileWeave = "A_BishopMissileWeave";
 	A_DropWeaponPieces = "A_DropWeaponPieces(str actorclass1, str actorclass2, str actorclass3)";
 	A_Feathers = "A_Feathers";
@@ -341,28 +385,48 @@ keywords
 	abs = "abs(x)\nReturns the absolute value of x.";
 	sin = "sin(x)\nTrigonometry function, x must be in degrees.";
 	cos = "cos(x)\nTrigonometry function, x must be in degrees.";
+	tan = "tan(x)\nTrigonometry function, x must be in degrees.";
+	asin = "asin(x)\nTrigonometry function, returns an angle in degrees.";
+	acos = "acos(x)\nTrigonometry function, returns an angle in degrees.";
+	atan = "atan(x)\nTrigonometry function, returns an angle in degrees.";
+	sinh = "sinh(x)\nTrigonometry function, x must be in radians.";
+	cosh = "cosh(x)\nTrigonometry function, x must be in radians.";
+	tanh = "tanh(x)\nTrigonometry function, x must be in radians.";
+	exp = "exp(x)\nReturns the base-e exponential function of x, which is e raised to the power x.";
+	log = "log(x)\nReturns the natural logarithm of x - the opposite of exp."; 
+	log10 = "log10(x)\nReturns the common (base-10) logarithm of x.";
+	ceil = "ceil(x)\nRounds the number upward to the next closest integer.";
+	floor = "floor(x)\nRounds the number downward to the next closest integer.";
 	sqrt = "sqrt(x)\nReturns the square root of x.";
-	random = "random[identifier](min, max)\nReturns a random integer value between min and max.";
-	random2 = "random2[identifier](mask)\nReturns a random integer value between -mask and +mask.";
-	frandom = "frandom[identifier](min, max)\nReturns a random floating point value between min and max.";
-	randompick = "randompick[identifier](int, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters.";
-	frandompick = "frandompick[identifier](int, ...)\nSimilar to randompick but for float-point values.";
-//State keywords
-	//Bright = "Bright";
-	CanRaise = "CanRaise";
-	Fast = "Fast";
+	min = "min(x1, ...)\nGets the smallest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
+	max = "max(x1, ...)\nGets the largest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
+	clamp = "clamp(src, min, max)\nReturns src within the range of min and max inclusively. All parameters can be ints or floats.";
+//Randum number functions
+	random = "int random[identifier](min, max)\nReturns a random integer value between min and max.";
+	random2 = "int random2[identifier](mask)\nReturns a random integer value between -mask and +mask.";
+	frandom = "float frandom[identifier](min, max)\nReturns a random floating point value between min and max.";
+	randompick = "int randompick[identifier](int, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters.";
+	frandompick = "float frandompick[identifier](float, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters.";
+//State functions
 	Light = "Light(str lightname)";
-	NoDelay = "NoDelay";
 	Offset = "Offset(int x, int y)";
-	Slow = "Slow";
 //Special functions
 	CheckClass = "bool CheckClass(str classname[, int ptr_select = AAPTR_DEFAULT[, bool match_superclass = false]])";
-	IsPointerEqual = "bool IsPointerEqual(int ptr_select1, int ptr_select2)";
+	IsPointerEqual = "bool IsPointerEqual(int ptr1, int ptr2)";
+	CountInv = "int CountInv(str itemclassname[, int ptr_select = AAPTR_DEFAULT])";
+	GetDistance = "float GetDistance(bool checkz[, int ptr_select = AAPTR_TARGET])";
+	GetSpawnHealth = "int GetSpawnHealth()";
+	GetGibHealth = "int GetGibHealth()";
 }
 
 properties
 {
 	Actor;
+	enum;
+	const;
+	var;
+	int;
+	float;
 //WFDS	
 	if;
 	else;
@@ -373,7 +437,13 @@ properties
 	Wait;
 	Fail;
 	goto;
-//states:
+//State keywords
+	Bright;
+	CanRaise;
+	Fast;
+	Slow;
+	NoDelay;
+//States
 	States;
 	Spawn:;
 	Idle:;
@@ -452,6 +522,8 @@ properties
 	Activation;
 	TeleFogSourceType;
 	TeleFogDestType;
+	Threshold;
+	DefThreshold;
 //Collision and 'Physics'
 	Radius;
 	Height;
@@ -1008,6 +1080,7 @@ constants
 	CBF_SETTRACER;
 	CBF_SETONPTR;
 	CBF_DROPOFF;
+	CBF_NOACTORS;
 	CHF_DONTMOVE;
 	CHF_FASTCHASE;
 	CHF_NIGHTMAREFAST;
diff --git a/Documents/cmdargs.txt b/Documents/cmdargs.txt
index daf8db53ea41228cb03e97d6350a418387dad378..6e490f7218a421bfa4a873dfb6a8768706670fdc 100644
--- a/Documents/cmdargs.txt
+++ b/Documents/cmdargs.txt
@@ -1,55 +1,63 @@
-Doom Builder 2 command-line arguments
+GZDoom Builder command-line arguments
 ==========================================================================================
 
 Usage:
 
-   builder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nopreferences]
-               [-strictpatches] [-resource wad|dir|pk3 [roottextures] [rootflats]
-               [strictpatches] [notest] resourcename]
+   GZBuilder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nopreferences]
+               [-strictpatches] [-portable] [-resource wad|dir|pk3 [roottextures]
+               [rootflats] [strictpatches] [notest] resourcename]
 
 ==========================================================================================
 
 Parameters:
 
-- wadfile
+wadfile
 This is a .WAD file to load immediately after Doom Builder has started up. Unless -map
 and -cfg are used, this will show the map-options dialog.
 
-- map
-Where 'mapname' is the name of the map (map header lump name) such as MAP01 or E1M1. When
+-map "mapname"
+Where "mapname" is the name of the map (map header lump name) such as MAP01 or E1M1. When
 specified, this will indicate the map to load from the specified wad file. Use in
 combination with -cfg to provide the required information to skip the map-options dialog.
 
-- cfg
-Where 'configname' is a game configuration filename, for example, "ZDoom_DoomHexen.cfg".
+-cfg "configname"
+-config "configname"
+Where "configname" is a game configuration filename, for example, "ZDoom_DoomHexen.cfg".
 Do NOT include the path, all game configurations must be in the Configurations subfolder.
 When used in combination with -map this will provide the required information to load a
 map directly and skip the map-options dialog.
 
-- delaywindow
+-delaywindow
 This delays showing the main interface window until the automatic map loading from
 command line parameters is completed, and the program is not terminating yet. This is
 usefull for plugins that can be used to perform batch processes where the showing of the
 main interface window is not desired. If a plugin completes it's actions on map load and
 terminates the application immediately, the main window will not be shown at all.
 
-- nosettings
+-nosettings
 When this parameter is specified, Doom Builder will not load your preferences or game
 configuration settings and will use the default settings instead. You will not lose your
 original settings, but when this parameter is specified your settings will not be saved.
 
-- strictpatches
+-strictpatches
 Specify this parameter to enforce strictly loading texture patches from between P_START
 and P_END marker lumps only. This can solve lump name conflicts, but old WAD files do not
 always adhere to this rule.
 
-- resource
+-portable
+The editor will be launched in portable mode. It will use the "GZBuilder.cfg" located in 
+the program directory instead of the one located in the 
+"%LocalAppData%\Doom Builder\GZBuilder.cfg" to load and save program settings. Log and 
+crash report files will be also created in the program directory.
+
+-resource <resource type> [flags] "path\to\resource"
 When -wadfile is specified, the -resource option can be used to add additional resources
 that must be loaded along with the wad file. Note that these are added to the resources
 which are automatically loaded due to the selection of a game configuration. You can
 repeat this option for any number of resources you wish to add. As always, the last
-specified resource will override any data in earlier specified resource. This parameter
-has the following arguments:
+specified resource will override any data in earlier specified resource.
+
+This parameter has the following arguments:
 
    wad|dir|pk3       Either 'wad', 'dir' or 'pk3' must be specified to indicate how this
                      resource must be loaded. This is the same as selecting the tabs in
@@ -77,16 +85,18 @@ Examples:
 This loads the file "Ubermegawad.wad" after Doom Builder is initialized and shows the
 map-options dialog:
 
-   builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad"
+   GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad"
 
 Same as the example above, but now without showing the map-options dialog and instead
 immediately loads map MAP23 with the game configuration for Doom 2:
 
-   builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom2.cfg"
+   GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom_Doom2Doom.cfg"
 
-Same as the example above, but with added wad file resource and PK3 file resource:
+Same as the example above, but using one of GZDoom game configurations with added wad 
+file resource and PK3 file resources:
 
-   builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom2.cfg"
-               -resource wad strictpatches "C:\Games\Doom\gothtextures.wad"
-               -resource pk3 "C:\Games\Doom\hardmonsters.pk3"
+   GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "GZDoom_DoomUDMF.cfg"
+                 -resource pk3 notest "C:\GZDoom\gzdoom.pk3"
+                 -resource wad strictpatches "C:\Games\Doom\gothtextures.wad"
+                 -resource pk3 "C:\Games\Doom\hardmonsters.pk3"
 
diff --git a/Help/commandlineparams.html b/Help/commandlineparams.html
index e42a407328b1df766f62ae146ea3377ef5478f6f..8e70ff7cc37621f7488fd3824266cc1f4707a631 100644
--- a/Help/commandlineparams.html
+++ b/Help/commandlineparams.html
@@ -7,49 +7,74 @@
 </head>
 <body>
 <object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e">
-  <param name="keyword" value="command line">
-  <param name="keyword" value="arguments">
+	<param name="keyword" value="command line">
+	<param name="keyword" value="arguments">
 </object>
 <div id="gz_title">
-  <h1>Command Line Parameters</h1>
+	<h1>Command Line Parameters</h1>
 </div>
 <div id="contents">
-  <p> All command line parameters are case-insensitive.<br />
-    <br />
-    <b class="fat">-portable</b> - <span class="red">GZDB only.</span><br />
-    The editor will be launched in portable mode. It will use the &quot;GZBuilder.cfg&quot; located in the program directory instead of the one located in the &quot;%LocalAppData%\Doom Builder\GZBuilder.cfg&quot; to load and save program settings. Log and crash report files will be also created in the program directory.<br />
-    <br />
-    <b class="fat">-nosettings</b><br />
-    The editor doesn't load or save program settings.<br />
-    <br />
-    <b class="fat">-delaywindow</b><br />
-    Delays showing of the main window.<br />
-    <br />
-    <b class="fat">-map &quot;path\to\mapfile.wad&quot;</b><br />
-    The editor will automatically load the specified map.<br />
-  <h2>The following parameters are used only in conjunction with the &quot;-map&quot; parameter</h2>
-  They replicate the settings, which can be set in the <a href="w_openmapoptions.html">Open Map Window</a>.<br />
-  <br />
-  <b class="fat">-strictpatches</b><br />
-  Enables strict patches rules.<br />
-  <br />
-  <b class="fat">-cfg &quot;path\to\game configuration.cfg&quot;</b><br />
-  <b class="fat">-config &quot;path\to\game configuration.cfg&quot;</b><br />
-  The editor will use the specified game configuration file when loading the map.<br />
-  <br />
-  <b class="fat">-resource &lt;resource type&gt; [flags] &quot;path\to\resource&quot;</b><br />
-  Adds a map resource.<br />
-  <strong>Resource type</strong> (required): &quot;wad&quot;, &quot;dir&quot; or &quot;pk3&quot;.<br />
-  <strong>Flags</strong> (optional):
-  <ul>
-    <li><strong>ROOTTEXTURES</strong> - load images in the root directory of the resource as textures.</li>
-    <li><strong>ROOTFLATS</strong> - load images in the root directory of the resource as flats.</li>
-    <li><strong>STRICTPATCHES</strong> - use strict rules for patches.</li>
-    <li><strong>NOTEST</strong> - exclude this resource from testing parameters.</li>
-  </ul>
-  <strong>Examples:</strong>
-  <pre>
-  -resource pk3 notest "c:\GZDoom\gzdoom.pk3"
-  -resource WAD "c:\Doom\DOOM.WAD"</pre>
+	<h2>Usage:</h2>
+	All command line parameters are case-insensitive.<br />
+	<br />
+	<b class="fat">GZBuilder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nosettings]
+	[-strictpatches] [-portable] [-resource wad|dir|pk3 [roottextures] [rootflats]
+	[strictpatches] [notest] resourcename]</b>
+	<h2>Parameters:</h2>
+	<br />
+	<b class="fat">wadfile</b><br />
+	This is a .WAD file to load immediately after GZDoom Builder has started up. Unless <strong>-map</strong> and <strong>-cfg</strong> are used, this will show the map-options dialog.<br />
+	<p><b class="fat">-map &quot;mapname&quot;</b><br />
+		Where &quot;mapname&quot; is the name of the map (map header lump name) such as <strong>MAP01</strong> or <strong>E1M1</strong>.<br />
+		When specified, this will indicate the map to load from the specified wad file.<br />
+		Use in combination with <strong>-cfg</strong> to provide the required information to skip the map-options dialog.
+	<p><b class="fat">-delaywindow</b><br />
+		This delays showing the main interface window until the automatic map loading from command line parameters is completed, and the program is not terminating yet.<br />This is usefull for plugins that can be used to perform batch processes where the showing of the main interface window is not desired.<br />If a plugin completes it's actions on map load and terminates the application immediately, the main window will not be shown at all.
+	<p>
+		<b class="fat">-nosettings</b><br />
+		When this parameter is specified, GZDoom Builder will not load your preferences or game	configuration settings and will use the default settings instead.<br />You will not lose your original settings, but when this parameter is specified your settings will not be saved.<br />
+		<br />
+		<b class="fat">-portable</b> - <span class="red">GZDB only.</span><br />
+		The editor will be launched in portable mode. It will use the &quot;GZBuilder.cfg&quot; located in the program directory instead of the one located in the &quot;%LocalAppData%\Doom Builder\GZBuilder.cfg&quot; to load and save program settings. Log and crash report files will be also created in the program directory.<br />
+	<h2>The following parameters are used only when both &quot;wadfile&quot; and &quot;-map&quot; parameters are present</h2>
+	They replicate the settings, which can be set in the <a href="w_openmapoptions.html">Open Map Window</a>.<br />
+	<br />
+	<b class="fat">-strictpatches</b><br />
+	Specify this parameter to enforce strictly loading texture patches from between P_START
+	and P_END marker lumps only. This can solve lump name conflicts, but old WAD files do not
+	always adhere to this rule.<br />
+	<br />
+	<b class="fat">-cfg &quot;game_configuration.cfg&quot;</b><br />
+	<b class="fat">-config &quot;game_configuration.cfg&quot;</b><br />
+	The editor will use the specified game configuration file when loading the map.<br />
+	Do not include the path, all game configurations must be in the &quot;Configurations&quot; subfolder.<br />
+	<br />
+	<b class="fat">-resource &lt;resource type&gt; [flags] &quot;path\to\resource&quot;</b><br />
+	Adds a map resource. Note that these are added to the resources, which are automatically loaded according to selected game configuration.<br />
+	<strong>Resource type</strong> (required): &quot;wad&quot;, &quot;dir&quot; or &quot;pk3&quot;.<br />
+	<strong>Flags</strong> (optional):
+	<ul>
+		<li><strong>ROOTTEXTURES</strong> - load images in the root directory of the resource as textures  (directory/pk3 resources only).</li>
+		<li><strong>ROOTFLATS</strong> - load images in the root directory of the resource as flats (directory/pk3 resources only).</li>
+		<li><strong>STRICTPATCHES</strong> - use strict rules for patches (wad resources only).</li>
+		<li><strong>NOTEST</strong> - exclude this resource from testing parameters.</li>
+	</ul>
+	<h2>Examples:</h2>
+	This loads the file "Ubermegawad.wad" after GZDoom Builder is initialized and shows the
+	map-options dialog:
+	<pre>
+GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad"
+</pre>
+	Same as the example above, but now without showing the map-options dialog and instead immediately loading map MAP23 with the Doom 2 game configuration:
+	<pre>
+GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom_Doom2Doom.cfg"
+</pre>
+	Same as the example above, but using one of GZDoom game configurations with added wad file resource and PK3 file resources:
+	<pre>
+GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "GZDoom_DoomUDMF.cfg"
+               -resource pk3 notest "C:\GZDoom\gzdoom.pk3"
+               -resource wad strictpatches "C:\Games\Doom\gothtextures.wad"
+               -resource pk3 "C:\Games\Doom\hardmonsters.pk3"
+</pre>
 </div>
 </body>
diff --git a/Help/gc_decoratekeys.html b/Help/gc_decoratekeys.html
index 3cc1d5fe2af0653cbfb68a83f08b39703a8d1dda..fdb1dc0d8c45ba4c39bfa65869b9c674da861705 100644
--- a/Help/gc_decoratekeys.html
+++ b/Help/gc_decoratekeys.html
@@ -31,6 +31,9 @@
     <strong>//$Title &lt;title&gt;</strong><br />
     Specifies which name to give to the actor. By default, a custom actor not identified in a configuration file will use the Tag property, and if not present, will default to the class name.<br />
     <br />
+    <strong>//$IgnoreRenderstyle</strong> - <span class="red">GZDB only</span>.<br />
+    "RenderStyle" DECORATE property will be ignored by the editor. Helpful when you want to see the sprite of an invisible actor in Visual mode.<br />
+    <br />
     <strong><a name="argtitle" id="argtitle"></a>//$ArgN &lt;name&gt;</strong> - <span class="red">GZDB only</span>.<br />
     Allows to override default argument names for this actor.<br />
     <br />
@@ -87,6 +90,7 @@ Actor ChexShield : ResistanceRune replaces ResistanceRune 5104
 {
   //$Category &quot;Pickups/Chex Powerups&quot;
   //$Sprite ARMXA0
+  //$IgnoreRenderstyle
   //$Title "Chex Shield"
   //$Color 12
   //$NotAngled
@@ -115,6 +119,7 @@ Actor ChexShield : ResistanceRune replaces ResistanceRune 5104
 
   Height 44
   Radius 26
+  RenderStyle None
   Inventory.PickupMessage "Picked up the energized Chex armor!"
 
   States
diff --git a/Help/gzdb/compilingtheeditor.html b/Help/gzdb/compilingtheeditor.html
index 03ef2e3365449cc4800e757b0b91c11dd809e2fc..a515ea547e620abd72595059aab3fa093fbd433b 100644
--- a/Help/gzdb/compilingtheeditor.html
+++ b/Help/gzdb/compilingtheeditor.html
@@ -28,21 +28,34 @@
     <li>7-zip archiver (<a href="www.7-zip.org">www.7-zip.org</a>).</li>
     <li>Inno Setup 5 or newer (<a href="http://www.jrsoftware.org/isinfo.php">http://www.jrsoftware.org/isinfo.php</a>).</li>
     <li>Microsoft HTML Help compiler (<a href="http://www.microsoft.com/en-us/download/details.aspx?id=21138">http://www.microsoft.com/en-us/download/details.aspx?id=21138</a>).</li>
-    <li>SlimDX Developer SDK. You can download it for free from <a href="http://slimdx.org/download.php">http://slimdx.org/download.php</a>.</li>
+    <li>SlimDX Developer SDK (<a href="http://slimdx.org/download.php">http://slimdx.org/download.php</a>).</li>
+    <li>DirectX SDK (<a href="https://www.microsoft.com/en-us/download/details.aspx?id=6812">https://www.microsoft.com/en-us/download/details.aspx?id=6812</a>).</li>
   </ul>
   
   <h2>Obtaining the source:</h2>
-  The Doom Builder 2 source code is hosted on SourceForge and is available through SVN at the following location:<pre>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</pre>
-  If you don't want to use a SVN client, head to 
-  <a href="https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/">https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/</a>
-  and press &quot;Download Snapshot&quot; button.
+  The GZDoom Builder source code is hosted on SourceForge and is available through SVN at the following location:
+  <pre>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</pre>
+  If you don't want to use a SVN client, head to <a href="https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/">https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/</a> and press &quot;Download Snapshot&quot; button.
+  <h2>Quick start guide:</h2>
+  This guide assumes you are using <strong>Visual Studio 2008</strong> / <strong>Visual C# 2008 Express Edition</strong> and <strong>Tortiose SVN</strong>.
+  <ol>
+    <li>Create an empty folder, right click on it and choose "<strong>SVN Checkout...</strong>" from the context menu.</li>
+    <li>Enter &quot;<strong>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</strong>&quot; in the &quot;<strong>URL of repository</strong>&quot; field and click OK.</li>
+    <li> Open &quot;<strong>Builder.sln</strong>&quot; in the Visual Studio and make sure it compiles and runs (click the green &quot;<strong>Play</strong>&quot; button, or press <strong>F5</strong>).
+      <ul>
+      <li>If the Visual Studio complains about missing <strong>SlimDX</strong> reference in the Builder project, you'll need to re-add it manually. To do so, delete SlimDX from the References in the Solution Explorer, right click on the Builder project and choose &quot;<strong>Add reference</strong>&quot;. On the .NET tab, choose SlimDX (.net 2.0, x86 version).</li>
+      <li>You can ignore the warning about missing <strong>JetBrains.Profiler.Core.Api</strong> reference. Everything should build fine, unless you choose a   profiler-enabled build target (or you can use dotTrace Performance, if   you have access to it).</li>
+      </ul>
+    </li>
+    <li>If you've made some code changes and want to submit them to the main GZDB repository, you can make a diff patch (right-click on the GZDB source folder and choose &quot;<strong>TortioseSVN -&gt; Create patch...</strong>&quot;) and post it at the official GZDB thread at ZDoom.org (<a href="http://forum.zdoom.org/viewtopic.php?f=3&t=32392&start=999999">http://forum.zdoom.org/viewtopic.php?f=3&amp;t=32392&amp;start=999999</a>).</li>
+  </ol>
   <h2>Batch files:</h2>
 GZDB source comes with several batch files, which can be used to automatically compile and package the editor. Before launching a batch file for the first time, make sure to open it and check that variables holding software paths point to the right directories. These variables are always located near the top of the file, after the info block.
 <ul>
-  <li><strong>Clean Rebuild.bat</strong> - removes project cache files, then compiles it in Release mode.<br />Requires Visual C#  Express Edition / Visual Studio.</li><br />
+  <li><strong>Clean Rebuild.bat</strong> - removes project cache files, then compiles it in Release mode.<br />Requires Visual C# Express Edition / Visual Studio.</li><br />
   <li><strong>CompileHelp.bat</strong> - compiles &quot;Build\Refmanual.chm&quot;. Help source files are located in the &quot;Help&quot; directory.<br />Requires Microsoft HTML Help compiler.</li><br />
   <li><strong>MakeRelease.bat</strong> - removes project cache files,  sets project version number to match the latest SVN revision, compiles the project in Release mode, generates &quot;Build\Changelog.txt&quot;, compiles &quot;Build\Refmanual.chm&quot;, creates an installer and places it in the &quot;Release&quot; folder.<br />Requires Subversion command-line client, Visual C#  Express Edition / Visual Studio, Microsoft HTML Help compiler and Inno Setup 5.</li><br />
-  <li><strong>MakeSVNRelease.bat</strong> - removes project cache files,  sets project version number to match the latest SVN revision, compiles the project in Release mode, generates &quot;Build\Changelog.txt&quot;, compiles &quot;Build\Refmanual.chm&quot;, packs the build into 7-zip archive and places it in the &quot;SVN_Build&quot; folder.<br />Requires Subversion command-line client, Visual C#  Express Edition / Visual Studio, Microsoft HTML Help compiler and 7-zip archiver.</li>
+  <li><strong>MakeSVNRelease.bat</strong> - removes project cache files,  sets project version number to match the latest SVN revision, compiles the project in Release mode, generates &quot;Build\Changelog.txt&quot;, compiles &quot;Build\Refmanual.chm&quot;, packs the build into 7-zip archive and places it in the &quot;SVN_Build&quot; folder.<br />Requires Subversion command-line client, Visual C# Express Edition / Visual Studio, Microsoft HTML Help compiler and 7-zip archiver.</li>
 </ul>
 </div>
 </body>
diff --git a/Source/Core/Actions/ActionManager.cs b/Source/Core/Actions/ActionManager.cs
index dbc4ae91f5735365446a077468fd9b0d7fca2a81..ee882570ed81b8227483ab08e5bfcc1fa9583bb4 100644
--- a/Source/Core/Actions/ActionManager.cs
+++ b/Source/Core/Actions/ActionManager.cs
@@ -193,7 +193,7 @@ namespace CodeImp.DoomBuilder.Actions
 			else
 			{
 				// Action already exists!
-				General.ErrorLogger.Add(ErrorType.Warning, "Action '" + name + "' already exists. Action names must be unique.");
+				General.ErrorLogger.Add(ErrorType.Warning, "Action \"" + name + "\" already exists. Action names must be unique.");
 			}
 		}
 
diff --git a/Source/Core/Actions/HintsManager.cs b/Source/Core/Actions/HintsManager.cs
index 942665f2c0cd5f232a5fc22e29f3e79667b130c1..5c4a7fc8ebd68ad7a2586c6608a6fcf0c437ee58 100644
--- a/Source/Core/Actions/HintsManager.cs
+++ b/Source/Core/Actions/HintsManager.cs
@@ -142,7 +142,7 @@ namespace CodeImp.DoomBuilder.Actions
 			{
 				General.Interface.ShowHints(DEFAULT_HINT);
 #if DEBUG
-				Console.WriteLine("WARNING: Unable to get hints for class '" + fullname + "', group '" + groupname + "'");
+				Console.WriteLine("WARNING: Unable to get hints for class \"" + fullname + "\", group \"" + groupname + "\"");
 #endif
 				return;
 			}
diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 4bd3281c50efcdfcc0a860ef62ed7c6ba9b2bc99..b09048e9d0bafb90424d3767e7947b13113ab20d 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -1143,6 +1143,7 @@
     <None Include="Resources\GroupRemove.png" />
     <None Include="Resources\GridDecrease.png" />
     <None Include="Resources\GridIncrease.png" />
+    <None Include="Resources\FixedThingsScale.png" />
     <Content Include="Resources\Light.png" />
     <None Include="Resources\Lightbulb.png" />
     <None Include="Resources\LightDisabled.png" />
diff --git a/Source/Core/Compilers/Compiler.cs b/Source/Core/Compilers/Compiler.cs
index 7289a4f76a58ecb520d2b1ef5b522085868f8ed9..bbc18bfeaca6f0f233a4ef10b352e7e73ed53255 100644
--- a/Source/Core/Compilers/Compiler.cs
+++ b/Source/Core/Compilers/Compiler.cs
@@ -76,9 +76,9 @@ namespace CodeImp.DoomBuilder.Compilers
 			// Initialize
 			this.info = info;
 			this.errors = new List<CompilerError>();
-			this.includes = new HashSet<string>(); //mxd
-			
-			General.WriteLogLine("Creating compiler '" + info.Name + "' on interface '" + this.GetType().Name + "'...");
+			this.includes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd
+
+			General.WriteLogLine("Creating compiler \"" + info.Name + "\" on interface \"" + this.GetType().Name + "\"...");
 			
 			// Create temporary directory
 			tempdir = Directory.CreateDirectory(General.MakeTempDirname());
@@ -146,7 +146,7 @@ namespace CodeImp.DoomBuilder.Compilers
 				string srcfile = Path.Combine(info.Path, f);
 				if(!File.Exists(srcfile)) 
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "The file '" + f + "' required by the '" + info.Name + "' compiler is missing. According to the compiler configuration in '" + info.FileName + "', the was expected to be found in the following path: " + info.Path);
+					General.ErrorLogger.Add(ErrorType.Error, "The file \"" + f + "\" required by the \"" + info.Name + "\" compiler is missing. According to the compiler configuration in \"" + info.FileName + "\", it was expected to be found here: \"" + info.Path + "\"");
 				} 
 				else 
 				{
diff --git a/Source/Core/Config/ArgumentInfo.cs b/Source/Core/Config/ArgumentInfo.cs
index e939553fc241e3da6e8fbd3a5c2869c8be18831a..7187af1c1d36e65ac68d9214a422de7a1d6dcf69 100644
--- a/Source/Core/Config/ArgumentInfo.cs
+++ b/Source/Core/Config/ArgumentInfo.cs
@@ -87,7 +87,7 @@ namespace CodeImp.DoomBuilder.Config
 					}
 					else
 					{
-						General.ErrorLogger.Add(ErrorType.Warning, "'" + argspath + ".arg" + istr + "' references unknown enumeration '" + argdic["enum"] + "'.");
+						General.ErrorLogger.Add(ErrorType.Warning, "\"" + argspath + ".arg" + istr + "\" references unknown enumeration \"" + argdic["enum"] + "\".");
 					}
 				}
 			}
diff --git a/Source/Core/Config/CompilerInfo.cs b/Source/Core/Config/CompilerInfo.cs
index 3cd1c9fbf4c462787c6785528461df68a9587fa3..65b7e9ab9d710deed17b9c7f7f12fe6cf562442f 100644
--- a/Source/Core/Config/CompilerInfo.cs
+++ b/Source/Core/Config/CompilerInfo.cs
@@ -59,7 +59,7 @@ namespace CodeImp.DoomBuilder.Config
 		// Constructor
 		internal CompilerInfo(string filename, string name, string path, Configuration cfg)
 		{
-			General.WriteLogLine("Registered compiler configuration '" + name + "' from '" + filename + "'");
+			General.WriteLogLine("Registered compiler configuration \"" + name + "\" from \"" + filename + "\"");
 			
 			// Initialize
 			this.filename = filename;
@@ -80,7 +80,7 @@ namespace CodeImp.DoomBuilder.Config
 					//mxd
 					string include = de.Value.ToString().Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
 					if(files.Contains(include))
-						General.ErrorLogger.Add(ErrorType.Warning, "Include file '" + de.Value + "' is double-defined in '" + name + "' compiler configuration");
+						General.ErrorLogger.Add(ErrorType.Warning, "Include file \"" + de.Value + "\" is double defined in \"" + name + "\" compiler configuration");
 					else
 						files.Add(include);
 				}
diff --git a/Source/Core/Config/GeneralizedOption.cs b/Source/Core/Config/GeneralizedOption.cs
index 379738839272de16769de8a5dbdac1146dd4a2ed..794292d9213fde345e49fd502029fc0b6a512dd8 100644
--- a/Source/Core/Config/GeneralizedOption.cs
+++ b/Source/Core/Config/GeneralizedOption.cs
@@ -76,7 +76,7 @@ namespace CodeImp.DoomBuilder.Config
 				}
 				else
 				{
-					General.ErrorLogger.Add(ErrorType.Warning, "Structure '" + fullpath + "." + name + "' contains invalid entries. The keys must be numeric.");
+					General.ErrorLogger.Add(ErrorType.Warning, "Structure \"" + fullpath + "." + name + "\" contains invalid entries. The keys must be numeric.");
 				}
 			}
 			
diff --git a/Source/Core/Config/MapLumpInfo.cs b/Source/Core/Config/MapLumpInfo.cs
index efecc10f94249a76fd288367468164097be4c82a..802d36952646229b0716a15bd0075900073732a5 100644
--- a/Source/Core/Config/MapLumpInfo.cs
+++ b/Source/Core/Config/MapLumpInfo.cs
@@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Config
 				}
 				else
 				{
-					General.ErrorLogger.Add(ErrorType.Warning, "Map lump '" + name + "' in the current game configuration specifies an unknown script configuration '" + scriptconfig + "'. Using plain text instead.");
+					General.ErrorLogger.Add(ErrorType.Warning, "Map lump \"" + name + "\" in the current game configuration specifies an unknown script configuration \"" + scriptconfig + "\". Using plain text instead.");
 					this.Script = new ScriptConfiguration();
 				}
 			}
diff --git a/Source/Core/Config/NodebuilderInfo.cs b/Source/Core/Config/NodebuilderInfo.cs
index 8dcb20dfb54a2f9acb17dc7a0ee2da34f34332fd..7649c725ba8e9362054ca94930c0d754f61a2fbf 100644
--- a/Source/Core/Config/NodebuilderInfo.cs
+++ b/Source/Core/Config/NodebuilderInfo.cs
@@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Config
 		// Constructor
 		public NodebuilderInfo(string filename, string name, Configuration cfg)
 		{
-			General.WriteLogLine("Registered nodebuilder configuration '" + name + "' from '" + filename + "'");
+			General.WriteLogLine("Registered nodebuilder configuration \"" + name + "\" from \"" + filename + "\"");
 			
 			// Initialize
 			this.name = name;
@@ -80,7 +80,7 @@ namespace CodeImp.DoomBuilder.Config
 			}
 			
 			// No compiler found?
-			if(this.compiler == null) throw new Exception("No such compiler defined: '" + compilername + "'");
+			if(this.compiler == null) throw new Exception("Compiler \"" + compilername + "\" is not defined");
 		}
 
 		// Constructor for "none" nodebuilder
diff --git a/Source/Core/Config/ProgramConfiguration.cs b/Source/Core/Config/ProgramConfiguration.cs
index e7d1e32e24371d1bf06f1f59ec0da7a858c5eeeb..7d6947c04c482799c51c2b95fbfea66949b7eed3 100644
--- a/Source/Core/Config/ProgramConfiguration.cs
+++ b/Source/Core/Config/ProgramConfiguration.cs
@@ -85,7 +85,8 @@ namespace CodeImp.DoomBuilder.Config
 		private float filteranisotropy;
 		private bool showtexturesizes;
 		private bool locatetexturegroup; //mxd
-        private SplitLineBehavior splitlinebehavior; //mxd
+		private bool keeptexturefilterfocused; //mxd
+		private SplitLineBehavior splitlinebehavior; //mxd
 
         //mxd. Script editor settings
         private string scriptfontname;
@@ -131,7 +132,8 @@ namespace CodeImp.DoomBuilder.Config
 		private bool storeSelectedEditTab;
         private int maxbackups;
         private bool checkforupdates;
-		private bool rendercomments;
+		private bool rendercomments; //mxd
+		private bool fixedthingsscale; //mxd
 		private bool rendergrid;
         private bool rendernightspath;
 		private bool dynamicgridsize;
@@ -194,6 +196,7 @@ namespace CodeImp.DoomBuilder.Config
 		public float FilterAnisotropy { get { return filteranisotropy; } internal set { filteranisotropy = value; } }
 		public bool ShowTextureSizes { get { return showtexturesizes; } internal set { showtexturesizes = value; } }
 		public bool LocateTextureGroup { get { return locatetexturegroup; } internal set { locatetexturegroup = value; } } //mxd
+		public bool KeepTextureFilterFocused { get { return keeptexturefilterfocused; } internal set { keeptexturefilterfocused = value; } } //mxd
 		public SplitLineBehavior SplitLineBehavior { get { return splitlinebehavior; } set { splitlinebehavior = value; } } //mxd
 
         //mxd. Script editor settings
@@ -241,6 +244,7 @@ namespace CodeImp.DoomBuilder.Config
         internal int MaxBackups { get { return maxbackups; } set { maxbackups = value; } }
         internal bool CheckForUpdates { get { return checkforupdates; } set { checkforupdates = value; } } //mxd
 		public bool RenderComments { get { return rendercomments; } internal set { rendercomments = value; } } //mxd
+		public bool FixedThingsScale { get { return fixedthingsscale; } internal set { fixedthingsscale = value; } } //mxd
 		public bool RenderGrid { get { return rendergrid; } internal set { rendergrid = value; } } //mxd
         public bool RenderNiGHTSPath { get { return rendernightspath; } internal set { rendernightspath = value; } }
         public bool DynamicGridSize { get { return dynamicgridsize; } internal set { dynamicgridsize = value; } } //mxd
@@ -326,6 +330,7 @@ namespace CodeImp.DoomBuilder.Config
 				filteranisotropy = cfg.ReadSetting("filteranisotropy", 8.0f);
 				showtexturesizes = cfg.ReadSetting("showtexturesizes", true);
 				locatetexturegroup = cfg.ReadSetting("locatetexturegroup", true); //mxd
+				keeptexturefilterfocused = cfg.ReadSetting("keeptexturefilterfocused", true); //mxd
 				splitlinebehavior = (SplitLineBehavior) General.Clamp(cfg.ReadSetting("splitlinebehavior", 0), 0, 3); //mxd
 
                 //mxd. Script editor
@@ -371,6 +376,7 @@ namespace CodeImp.DoomBuilder.Config
                 maxbackups = cfg.ReadSetting("maxbackups", 3);
                 checkforupdates = false; //No update checking for Zone Builder
 				rendercomments = cfg.ReadSetting("rendercomments", true); //mxd
+				fixedthingsscale = cfg.ReadSetting("fixedthingsscale", false); //mxd
 				rendergrid = cfg.ReadSetting("rendergrid", true); //mxd
                 rendernightspath = cfg.ReadSetting("rendernightspath", true);
                 dynamicgridsize = cfg.ReadSetting("dynamicgridsize", true); //mxd
@@ -438,6 +444,7 @@ namespace CodeImp.DoomBuilder.Config
 			cfg.WriteSetting("filteranisotropy", filteranisotropy);
 			cfg.WriteSetting("showtexturesizes", showtexturesizes);
 			cfg.WriteSetting("locatetexturegroup", locatetexturegroup); //mxd
+			cfg.WriteSetting("keeptexturefilterfocused", keeptexturefilterfocused); //mxd
 			cfg.WriteSetting("splitlinebehavior", (int)splitlinebehavior); //mxd
 
             //mxd. Script editor
@@ -485,6 +492,7 @@ namespace CodeImp.DoomBuilder.Config
             cfg.WriteSetting("maxbackups", maxbackups);
             //cfg.WriteSetting("checkforupdates", checkforupdates); //mxd
 			cfg.WriteSetting("rendercomments", rendercomments); //mxd
+			cfg.WriteSetting("fixedthingsscale", fixedthingsscale); //mxd
 			cfg.WriteSetting("rendergrid", rendergrid); //mxd
             cfg.WriteSetting("rendernightspath", rendernightspath); //mxd
             cfg.WriteSetting("dynamicgridsize", dynamicgridsize); //mxd
@@ -498,7 +506,7 @@ namespace CodeImp.DoomBuilder.Config
 			cfg.WriteSetting("defaultbrightness", defaultbrightness);
 			
 			// Save settings configuration
-			General.WriteLogLine("Saving program configuration to '" + filepathname + "'...");
+			General.WriteLogLine("Saving program configuration to \"" + filepathname + "\"...");
 			cfg.SaveConfiguration(filepathname);
 		}
 		
diff --git a/Source/Core/Config/ScriptConfiguration.cs b/Source/Core/Config/ScriptConfiguration.cs
index f9c5557f2a3b220e6119350ec162465565a784aa..f389cfcfaded5724bcb900fdb66f0d7809366a99 100644
--- a/Source/Core/Config/ScriptConfiguration.cs
+++ b/Source/Core/Config/ScriptConfiguration.cs
@@ -28,12 +28,20 @@ using ScintillaNET;
 namespace CodeImp.DoomBuilder.Config
 {
 	//mxd
-	internal enum ScriptType
+	public enum ScriptType
 	{
 		UNKNOWN = 0,
 		ACS = 1,
 		MODELDEF = 2,
 		DECORATE = 3,
+		GLDEFS = 4,
+		SNDSEQ = 5,
+		MAPINFO = 6,
+		VOXELDEF = 7,
+		TEXTURES = 8,
+		ANIMDEFS = 9,
+		REVERBS = 10,
+		TERRAIN = 11,
 	}
 	
 	internal class ScriptConfiguration : IComparable<ScriptConfiguration>
@@ -214,7 +222,7 @@ namespace CodeImp.DoomBuilder.Config
 				string keyword = de.Key.ToString();
 				if(keywords.ContainsKey(keyword)) //mxd
 				{
-					General.ErrorLogger.Add(ErrorType.Warning, "Keyword \"" + keyword + "\" is double-defined in \"" + description + "\" script configuration.");
+					General.ErrorLogger.Add(ErrorType.Warning, "Keyword \"" + keyword + "\" is double defined in \"" + description + "\" script configuration.");
 					continue;
 				}
 
@@ -226,16 +234,16 @@ namespace CodeImp.DoomBuilder.Config
             //mxd. Sort keywords lookup
             keywordkeyssorted.Sort();
 
-            //mxd. Load properties
-            dic = cfg.ReadSetting("properties", new Hashtable());
-            foreach (DictionaryEntry de in dic)
-            {
-                string property = de.Key.ToString();
-                if (lowerproperties.ContainsValue(property)) //mxd
-                {
-                    General.ErrorLogger.Add(ErrorType.Warning, "Property \"" + property + "\" is double-defined in \"" + description + "\" script configuration.");
-                    continue;
-                }
+			//mxd. Load properties
+			dic = cfg.ReadSetting("properties", new Hashtable());
+			foreach(DictionaryEntry de in dic)
+			{
+				string property = de.Key.ToString();
+				if(lowerproperties.ContainsValue(property)) //mxd
+				{
+					General.ErrorLogger.Add(ErrorType.Warning, "Property \"" + property + "\" is double defined in \"" + description + "\" script configuration.");
+					continue;
+				}
 
                 properties.Add(property);
                 lowerproperties[property.ToLowerInvariant()] = property;
@@ -248,12 +256,12 @@ namespace CodeImp.DoomBuilder.Config
             dic = cfg.ReadSetting("constants", new Hashtable());
 			foreach(DictionaryEntry de in dic)
 			{
-                string constant = de.Key.ToString();
-                if (lowerconstants.ContainsValue(constant)) //mxd
-                {
-                    General.ErrorLogger.Add(ErrorType.Warning, "Constant \"" + constant + "\" is double-defined in \"" + description + "\" script configuration.");
-                    continue;
-                }
+				string constant = de.Key.ToString();
+				if(lowerconstants.ContainsValue(constant)) //mxd
+				{
+					General.ErrorLogger.Add(ErrorType.Warning, "Constant \"" + constant + "\" is double defined in \"" + description + "\" script configuration.");
+					continue;
+				}
 
                 constants.Add(constant);
                 lowerconstants[constant.ToLowerInvariant()] = constant;
@@ -275,10 +283,10 @@ namespace CodeImp.DoomBuilder.Config
                     foreach (string file in files)
 					{
 						string name = Path.GetFileNameWithoutExtension(file);
-                        if (string.IsNullOrEmpty(name))
-                        {
-							General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet '" + file + "' for '" + description + "' script configuration.");
-                        }
+						if(string.IsNullOrEmpty(name))
+						{
+							General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration.");
+						}
 						else
 						{
                             if (name.Contains(" ")) name = name.Replace(' ', '_');
@@ -290,37 +298,36 @@ namespace CodeImp.DoomBuilder.Config
                             }
 							else
 							{
-								General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet '" + file + "' for '" + description + "' script configuration: file is empty!");
+								General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration: file is empty!");
 							}
 						}
 					}
 
-                    //mxd. Sort snippets lookup
-                    sortedkeys.Sort();
-                    snippetkeyssorted = new HashSet<string>(sortedkeys, StringComparer.OrdinalIgnoreCase);
-
-                }
-            }
-
-            // Compiler specified?
-            if (compilername.Length > 0)
-            {
-                // Find compiler
-                foreach (CompilerInfo c in General.Compilers)
-                {
-                    // Compiler name matches?
-                    if (c.Name == compilername)
-                    {
-                        // Apply compiler
-                        this.compiler = c;
-                        break;
-                    }
-                }
-
-                // No compiler found?
-                if (this.compiler == null) throw new Exception("No such compiler defined: '" + compilername + "'");
-            }
-        }
+					//mxd. Sort snippets lookup
+					sortedkeys.Sort();
+					snippetkeyssorted = new HashSet<string>(sortedkeys, StringComparer.OrdinalIgnoreCase);
+				}
+			}
+			
+			// Compiler specified?
+			if(compilername.Length > 0)
+			{
+				// Find compiler
+				foreach(CompilerInfo c in General.Compilers)
+				{
+					// Compiler name matches?
+					if(c.Name == compilername)
+					{
+						// Apply compiler
+						this.compiler = c;
+						break;
+					}
+				}
+				
+				// No compiler found?
+				if(this.compiler == null) throw new Exception("Compiler \"" + compilername + "\" is not defined");
+			}
+		}
 		
 		#endregion
 
diff --git a/Source/Core/Config/ThingCategory.cs b/Source/Core/Config/ThingCategory.cs
index 05cbbabe5ca682e30b1eb79619480f92c50ead04..06db6ac8501228011a303f143ea529866b9c1023 100644
--- a/Source/Core/Config/ThingCategory.cs
+++ b/Source/Core/Config/ThingCategory.cs
@@ -293,7 +293,7 @@ namespace CodeImp.DoomBuilder.Config
 					if(child.IsValid && child.things.Count > 0)
 					{
 						if(cats.ContainsKey(child.title.ToLowerInvariant()))
-							General.ErrorLogger.Add(ErrorType.Warning, "Thing Category '" + child.title + "' is double-defined in " + this.title);
+							General.ErrorLogger.Add(ErrorType.Warning, "Thing Category \"" + child.title + "\" is double defined in " + this.title);
 						cats[child.title.ToLowerInvariant()] = child;
 					}
 				}
diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs
index a15f4bd1668db1f00d100eeb3266944dbe0f39fd..3bd3ec9ab78b94bb920f51a14d53c092bd62a664 100644
--- a/Source/Core/Config/ThingTypeInfo.cs
+++ b/Source/Core/Config/ThingTypeInfo.cs
@@ -559,7 +559,7 @@ namespace CodeImp.DoomBuilder.Config
 			//mxd. Marked as obsolete?
 			if(actor.HasPropertyWithValue("$obsolete"))
 			{
-				obsoletemessage = ZDTextParser.StripQuotes(actor.GetPropertyValueString("$obsolete", 0));
+				obsoletemessage = actor.GetPropertyValueString("$obsolete", 0, true);
 				obsolete = true;
 				color = 4; //red
 			}
@@ -591,7 +591,8 @@ namespace CodeImp.DoomBuilder.Config
 			if(actor.HasPropertyWithValue("height")) height = actor.GetPropertyValueInt("height", 0);
 
 			//mxd. Renderstyle
-			if(actor.HasPropertyWithValue("renderstyle")) renderstyle = actor.GetPropertyValueString("renderstyle", 0).ToLower();
+			if(actor.HasPropertyWithValue("renderstyle") && !actor.HasProperty("$ignorerenderstyle"))
+				renderstyle = actor.GetPropertyValueString("renderstyle", 0, true).ToLower();
 
 			//mxd. Alpha
 			if(actor.HasPropertyWithValue("alpha"))
diff --git a/Source/Core/Config/ThingsFlagsCompare.cs b/Source/Core/Config/ThingsFlagsCompare.cs
index fcbb4a542a2c99c2b482caac4159972b40463006..365c0f858876a24c2fb0fa0e9161f2b73f68a388 100644
--- a/Source/Core/Config/ThingsFlagsCompare.cs
+++ b/Source/Core/Config/ThingsFlagsCompare.cs
@@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Config
 
 				// Duplicate flags check
 				if(Flags.ContainsKey(flag))
-					General.ErrorLogger.Add(ErrorType.Warning, "ThingFlagsCompare flag '" + flag + "' is double-defined in '" + name + "' group");
+					General.ErrorLogger.Add(ErrorType.Warning, "ThingFlagsCompare flag \"" + flag + "\" is double defined in the \"" + name + "\" group");
 
 				Flags[flag] = new ThingFlagsCompare(cfg, name, flag);
 			}
@@ -294,7 +294,7 @@ namespace CodeImp.DoomBuilder.Config
 							result.Add("Thing is not used by any class.");
 							break;
 						default:
-							result.Add("At least one '" + group.Key + "' flag should be set.");
+							result.Add("At least one \"" + group.Key + "\" flag should be set.");
 							break;
 					}
 				}
diff --git a/Source/Core/Controls/ArgumentBox.cs b/Source/Core/Controls/ArgumentBox.cs
index 37e5293eda64de949e320c0d2723484562437a0e..04e9a0390a6a3f096ae1d4b35f844da871d220c2 100644
--- a/Source/Core/Controls/ArgumentBox.cs
+++ b/Source/Core/Controls/ArgumentBox.cs
@@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.Controls
 		//mxd. this sets default value
 		public void SetDefaultValue() 
 		{
-			typehandler.SetDefaultValue();
+			typehandler.ApplyDefaultValue();
 			combobox.SelectedItem = null;
 			combobox.Text = typehandler.GetStringValue();
 			combobox_Validating(this, new CancelEventArgs());
diff --git a/Source/Core/Controls/ArgumentsControl.cs b/Source/Core/Controls/ArgumentsControl.cs
index a511c612e10c846ff8c21a2d5e78a12360d94ab7..fe9b817a38392d8341528c52d439179e481687be 100644
--- a/Source/Core/Controls/ArgumentsControl.cs
+++ b/Source/Core/Controls/ArgumentsControl.cs
@@ -204,15 +204,21 @@ namespace CodeImp.DoomBuilder.Controls
 		{
 			// Update arguments
 			int showaction = 0;
+			ArgumentInfo[] oldarginfo = (arginfo != null ? (ArgumentInfo[])arginfo.Clone() : null); //mxd
 
 			// Only when action type is known
 			if(General.Map.Config.LinedefActions.ContainsKey(action)) showaction = action;
+			
+			// Update argument infos
 			if((showaction == 0) && (info != null)) arginfo = info.Args;
 			else arginfo = General.Map.Config.LinedefActions[showaction].Args;
 
 			// Don't update action args when thing type is changed
 			if(info != null && showaction != 0 && this.action == showaction) return;
 
+			//mxd. Don't update action args when old and new argument infos match
+			if(arginfo != null && oldarginfo != null && ArgumentInfosMatch(arginfo, oldarginfo)) return;
+
 			// Change the argument descriptions
 			this.BeginUpdate();
 
@@ -387,6 +393,24 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 		}
 
+		//mxd
+		private static bool ArgumentInfosMatch(ArgumentInfo[] info1, ArgumentInfo[] info2)
+		{
+			if(info1.Length != info2.Length) return false;
+			bool haveusedargs = false; // Arguments should still be reset if all arguments are unused
+			
+			for(int i = 0; i < info1.Length; i++)
+			{
+				if(info1[i].Used != info1[2].Used || info1[i].Type != info1[2].Type 
+					|| info1[i].Title.ToUpperInvariant() != info2[i].Title.ToUpperInvariant())
+					return false;
+
+				haveusedargs |= (info1[i].Used || info1[2].Used);
+			}
+
+			return haveusedargs;
+		}
+
 		#endregion
 
 		#region ================== Redraw control
diff --git a/Source/Core/Controls/FieldsEditorControl.cs b/Source/Core/Controls/FieldsEditorControl.cs
index 9b4fe135df8c1665b4a6f4489c643b39f88ad61b..dc095c27332753207b77b715c8c522f4f9b70b66 100644
--- a/Source/Core/Controls/FieldsEditorControl.cs
+++ b/Source/Core/Controls/FieldsEditorControl.cs
@@ -61,27 +61,27 @@ namespace CodeImp.DoomBuilder.Controls
 		private string lasteditfieldname;
 		private bool autoinsertuserprefix;
 		private Dictionary<string, UniversalType> uifields;//mxd
-        private bool showfixedfields = true; //mxd
-
-        #endregion
+		private bool showfixedfields = true; //mxd
+		
+		#endregion
 
-        #region ================== Properties
+		#region ================== Properties
 
-        public bool AllowInsert { get { return fieldslist.AllowUserToAddRows; } set { fieldslist.AllowUserToAddRows = value; SetupNewRowStyle(); } }
+		public bool AllowInsert { get { return fieldslist.AllowUserToAddRows; } set { fieldslist.AllowUserToAddRows = value; SetupNewRowStyle(); } }
 		public bool AutoInsertUserPrefix { get { return autoinsertuserprefix; } set { autoinsertuserprefix = value; } }
 		public int PropertyColumnWidth { get { return fieldname.Width; } set { fieldname.Width = value; UpdateValueColumn(); UpdateBrowseButton(); } }
 		public int TypeColumnWidth { get { return fieldtype.Width; } set { fieldtype.Width = value; UpdateValueColumn(); UpdateBrowseButton(); } }
 		public bool PropertyColumnVisible { get { return fieldname.Visible; } set { fieldname.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } }
 		public bool TypeColumnVisible { get { return fieldtype.Visible; } set { fieldtype.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } }
 		public bool ValueColumnVisible { get { return fieldvalue.Visible; } set { fieldvalue.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } }
-        public bool ShowFixedFields { get { return showfixedfields; } set { showfixedfields = value; UpdateFixedFieldsVisibility(); } } //mxd
+		public bool ShowFixedFields {get { return showfixedfields; } set { showfixedfields = value; UpdateFixedFieldsVisibility(); } } //mxd
 
-        #endregion
+		#endregion
 
-        #region ================== Constructor
+		#region ================== Constructor
 
-        // Constructor
-        public FieldsEditorControl()
+		// Constructor
+		public FieldsEditorControl()
 		{
 			InitializeComponent();
 			autoinsertuserprefix = true;
@@ -171,6 +171,7 @@ namespace CodeImp.DoomBuilder.Controls
 				
 				// Go for all rows
 				bool foundrow = false;
+				bool skiprow = false; //mxd
 				foreach(DataGridViewRow row in fieldslist.Rows)
 				{
 					// Row is a field?
@@ -181,11 +182,18 @@ namespace CodeImp.DoomBuilder.Controls
 						// Row name matches with field
 						if(frow.Name == f.Key)
 						{
+							//mxd. User vars are set separately
+							if(frow.RowType == FieldsEditorRowType.USERVAR)
+							{
+								skiprow = true;
+								break;
+							}
+							
 							// First time?
 							if(first)
 							{
 								// Set type when row is not fixed
-								if(!frow.IsFixed) frow.ChangeType(f.Value.Type);
+								if(frow.RowType == FieldsEditorRowType.DYNAMIC) frow.ChangeType(f.Value.Type);
 
 								// Apply value of field to row
 								frow.Define(f.Value.Value);
@@ -207,16 +215,18 @@ namespace CodeImp.DoomBuilder.Controls
 						}
 					}
 				}
+
+				//mxd. User vars are set separately
+				if(skiprow) continue;
 				
 				// Row not found?
 				if(!foundrow)
 				{
 					// Make new row
-					FieldsEditorRow frow = new FieldsEditorRow(fieldslist, f.Key, f.Value.Type, f.Value.Value);
+					FieldsEditorRow frow = new FieldsEditorRow(fieldslist, f.Key, f.Value.Type, f.Value.Value, false);
 					fieldslist.Rows.Insert(fieldslist.Rows.Count - 1, frow);
 					
-					// When not the first, clear the field
-					// because the others did not define this one
+					// When not the first, clear the field because the others did not define this one
 					if(!first) frow.Clear();
 				}
 			}
@@ -245,6 +255,82 @@ namespace CodeImp.DoomBuilder.Controls
 			// Sort fields
 			Sort();
 		}
+
+		//mxd
+		public void SetUserVars(Dictionary<string, UniversalType> vars, UniFields fromfields, bool first)
+		{
+			foreach(KeyValuePair<string, UniversalType> group in vars)
+			{
+				// Go for all rows
+				bool foundrow = false;
+				TypeHandler vartype = General.Types.GetFieldHandler((int)group.Value, 0);
+				object value = fromfields.ContainsKey(group.Key) ? fromfields[group.Key].Value : vartype.GetDefaultValue();
+				
+				foreach(DataGridViewRow row in fieldslist.Rows)
+				{
+					// Row is a field?
+					if(row is FieldsEditorRow)
+					{
+						FieldsEditorRow frow = row as FieldsEditorRow;
+						
+						// Row name matches with user var?
+						if(frow.RowType == FieldsEditorRowType.USERVAR && frow.Name == group.Key)
+						{
+							// First time?
+							if(first)
+							{
+								frow.Define(value);
+							}
+							// Check if the value is different
+							else if(!frow.TypeHandler.GetValue().Equals(value))
+							{
+								// Clear the value in the row
+								frow.Define(value);
+								frow.Clear();
+							}
+							
+							// Done
+							foundrow = true;
+							break;
+						}
+					}
+				}
+				
+				// Row not found?
+				if(!foundrow)
+				{
+					// Make new row
+					object defaultvalue = vartype.GetDefaultValue();
+					FieldsEditorRow frow = new FieldsEditorRow(fieldslist, group.Key, (int)group.Value, defaultvalue, true);
+					if(!value.Equals(defaultvalue)) frow.Define(value);
+					fieldslist.Rows.Insert(fieldslist.Rows.Count - 1, frow);
+				}
+			}
+			
+			// Now check for rows that the givens fields do NOT have
+			foreach(DataGridViewRow row in fieldslist.Rows)
+			{
+				// Row is a field?
+				if(row is FieldsEditorRow)
+				{
+					FieldsEditorRow frow = row as FieldsEditorRow;
+					
+					// Don't undefine user var rows defined by other actor types
+					if(frow.RowType != FieldsEditorRowType.USERVAR || !vars.ContainsKey(frow.Name)) continue;
+
+					// Is this row defined previously?
+					if(frow.IsDefined)
+					{
+						// Check if this row can not be found in the fields at all
+						if(!fromfields.ContainsKey(frow.Name))
+						{
+							// It is not defined in these fields, undefine the value
+							frow.Undefine();
+						}
+					}
+				}
+			}
+		}
 		
 		// This applies the current fields to a UniFields object
 		public void Apply(UniFields tofields)
@@ -259,6 +345,7 @@ namespace CodeImp.DoomBuilder.Controls
 				
 				// Go for all rows
 				bool foundrow = false;
+				bool skiprow = false; //mxd
 				foreach(DataGridViewRow row in fieldslist.Rows)
 				{
 					// Row is a field and matches field name?
@@ -266,6 +353,13 @@ namespace CodeImp.DoomBuilder.Controls
 					{
 						FieldsEditorRow frow = row as FieldsEditorRow;
 
+						//mxd. User vars are stored separately
+						if(frow.RowType == FieldsEditorRowType.USERVAR)
+						{
+							skiprow = true;
+							break;
+						}
+
 						// Field is defined?
 						if(frow.IsDefined)
 						{
@@ -275,6 +369,9 @@ namespace CodeImp.DoomBuilder.Controls
 					}
 				}
 
+				//mxd. User vars are stored separately
+				if(skiprow) continue;
+
 				// No such row?
 				if(!foundrow)
 				{
@@ -292,7 +389,7 @@ namespace CodeImp.DoomBuilder.Controls
 					FieldsEditorRow frow = row as FieldsEditorRow;
 					
 					// Field is defined and not empty?
-					if(frow.IsDefined && !frow.IsEmpty)
+					if(frow.RowType != FieldsEditorRowType.USERVAR && frow.IsDefined && !frow.IsEmpty)
 					{
 						// Apply field
 						object oldvalue = null;
@@ -300,7 +397,7 @@ namespace CodeImp.DoomBuilder.Controls
 						tofields[frow.Name] = new UniValue(frow.TypeHandler.Index, frow.GetResult(oldvalue));
 
 						// Custom row?
-						if(!frow.IsFixed)
+						if(frow.RowType == FieldsEditorRowType.DYNAMIC)
 						{
 							// Write type to map configuration
 							General.Map.Options.SetUniversalFieldType(elementname, frow.Name, frow.TypeHandler.Index);
@@ -310,6 +407,38 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 		}
 
+		//mxd
+		public void ApplyUserVars(Dictionary<string, UniversalType> vars, UniFields tofields)
+		{
+			// Apply user variables when target map element contains user var definition and the value is not default
+			foreach(DataGridViewRow row in fieldslist.Rows)
+			{
+				// Row is a field?
+				if(row is FieldsEditorRow)
+				{
+					FieldsEditorRow frow = row as FieldsEditorRow;
+					if(frow.RowType != FieldsEditorRowType.USERVAR || !vars.ContainsKey(frow.Name)) continue;
+
+					object oldvalue = (tofields.ContainsKey(frow.Name) ? tofields[frow.Name].Value : null);
+					object newvalue = frow.GetResult(oldvalue);
+
+					// Skip field when mixed values
+					if(newvalue == null) continue;
+
+					// Remove field
+					if(newvalue.Equals(frow.TypeHandler.GetDefaultValue()))
+					{
+						if(tofields.ContainsKey(frow.Name)) tofields.Remove(frow.Name);
+					}
+					// Add field
+					else if(!newvalue.Equals(oldvalue))
+					{
+						tofields[frow.Name] = new UniValue(frow.TypeHandler.Index, newvalue);
+					}
+				}
+			}
+		}
+
 		#endregion
 
 		#region ================== Events
@@ -377,16 +506,16 @@ namespace CodeImp.DoomBuilder.Controls
 				// First column?
 				if(e.ColumnIndex == 0)
 				{
-					// Not a fixed field?
-					if((frow != null) && !frow.IsFixed)
+					// Dynamic field?
+					if((frow != null) && frow.RowType == FieldsEditorRowType.DYNAMIC)
 					{
 						lasteditfieldname = frow.Name;
 						fieldslist.CurrentCell = fieldslist.SelectedRows[0].Cells[0];
 						fieldslist.CurrentCell.ReadOnly = false;
 
-						if((e.RowIndex == fieldslist.NewRowIndex) || 
-                            frow.Name.StartsWith(FIELD_PREFIX_SUGGESTION, StringComparison.OrdinalIgnoreCase))
-                            fieldslist.BeginEdit(false);
+						if((e.RowIndex == fieldslist.NewRowIndex) ||
+						   frow.Name.StartsWith(FIELD_PREFIX_SUGGESTION, StringComparison.OrdinalIgnoreCase))
+							fieldslist.BeginEdit(false);
 						else
 							fieldslist.BeginEdit(true);
 					}
@@ -399,21 +528,20 @@ namespace CodeImp.DoomBuilder.Controls
 		{
 			// Get the row
 			FieldsEditorRow row = e.Row as FieldsEditorRow;
+			if(row == null) return;
 			
-			// Fixed field?
-			if(row.IsFixed)
+			// Fixed/uservar field?
+			if(row.RowType == FieldsEditorRowType.FIXED || row.RowType == FieldsEditorRowType.USERVAR)
 			{
 				// Just undefine the field
 				row.Undefine();
 				e.Cancel = true;
 
-				if(OnFieldUndefined != null)
-					OnFieldUndefined(row.Name);
+				if(OnFieldUndefined != null) OnFieldUndefined(row.Name);
 			}
 			else
 			{
-				if(OnFieldDeleted != null)
-					OnFieldDeleted(row.Name);
+				if(OnFieldDeleted != null) OnFieldDeleted(row.Name);
 			}
 		}
 
@@ -428,10 +556,7 @@ namespace CodeImp.DoomBuilder.Controls
 				{
 					// Remove all text
 					fieldslist.Rows[e.RowIndex].Cells[0].Style.ForeColor = SystemColors.WindowText;
-					if(autoinsertuserprefix)
-						fieldslist.Rows[e.RowIndex].Cells[0].Value = FIELD_PREFIX_SUGGESTION;
-					else
-						fieldslist.Rows[e.RowIndex].Cells[0].Value = "";
+					fieldslist.Rows[e.RowIndex].Cells[0].Value = (autoinsertuserprefix ? FIELD_PREFIX_SUGGESTION : string.Empty);
 				}
 			}
 			// Value cell?
@@ -470,13 +595,13 @@ namespace CodeImp.DoomBuilder.Controls
 						// Select the value of this field (for DropDownList style combo)
 						foreach(EnumItem i in enumscombo.Items)
 						{
-                            // Matches?
-                            if (string.Compare(i.Title, frow.TypeHandler.GetStringValue(), StringComparison.OrdinalIgnoreCase) == 0)
-                            {
+							// Matches?
+							if(string.Compare(i.Title, frow.TypeHandler.GetStringValue(), StringComparison.OrdinalIgnoreCase) == 0)
+							{
 								// Select this item
 								enumscombo.SelectedItem = i;
-                                break; //mxd
-                            }
+								break; //mxd
+							}
 						}
 
 						// Put the display text in the text (for DropDown style combo)
@@ -538,12 +663,11 @@ namespace CodeImp.DoomBuilder.Controls
 									int type = General.Map.Options.GetUniversalFieldType(elementname, validname, 0);
 
 									// Make new row
-									frow = new FieldsEditorRow(fieldslist, validname, type, null);
+									frow = new FieldsEditorRow(fieldslist, validname, type, null, false);
 									frow.Visible = false;
 									fieldslist.Rows.Insert(e.RowIndex + 1, frow);
 
-									if(OnFieldInserted != null)
-										OnFieldInserted(validname);
+									if(OnFieldInserted != null) OnFieldInserted(validname);
 								}
 							}
 						}
@@ -587,11 +711,8 @@ namespace CodeImp.DoomBuilder.Controls
 								row.Cells[0].Value = validname;
 								if(type != -1) frow.ChangeType(type);
 
-								if(OnFieldNameChanged != null)
-									OnFieldNameChanged(lasteditfieldname, validname);
-
-								if(OnFieldTypeChanged != null)
-									OnFieldTypeChanged(validname);
+								if(OnFieldNameChanged != null) OnFieldNameChanged(lasteditfieldname, validname);
+								if(OnFieldTypeChanged != null) OnFieldTypeChanged(validname);
 							}
 							else
 							{
@@ -615,8 +736,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// Changing field type?
 			if((e.ColumnIndex == 1) && (frow != null))
 			{
-				if(OnFieldTypeChanged != null)
-					OnFieldTypeChanged(frow.Name);
+				if(OnFieldTypeChanged != null) OnFieldTypeChanged(frow.Name);
 			}
 			// Changing field value?
 			if((e.ColumnIndex == 2) && (frow != null))
@@ -641,18 +761,18 @@ namespace CodeImp.DoomBuilder.Controls
 			// Delete all rows that must be deleted
 			for(int i = fieldslist.Rows.Count - 1; i >= 0; i--)
 			{
-                if (fieldslist.Rows[i].ReadOnly)
-                {
-                    try { fieldslist.Rows.RemoveAt(i); } catch { }
-                }
-                else
-                {
-                    //mxd. Preserve fixed fields visibility setting
-                    FieldsEditorRow frow = (fieldslist.Rows[i] as FieldsEditorRow);
-                    if (frow != null && frow.IsFixed) frow.Visible = showfixedfields;
-                    else fieldslist.Rows[i].Visible = true;
-                }
-            }
+				if(fieldslist.Rows[i].ReadOnly)
+				{
+					try { fieldslist.Rows.RemoveAt(i); } catch { }
+				}
+				else
+				{
+					//mxd. Preserve fixed fields visibility setting
+					FieldsEditorRow frow = (fieldslist.Rows[i] as FieldsEditorRow);
+					if(frow != null && frow.RowType == FieldsEditorRowType.FIXED) frow.Visible = showfixedfields;
+					else fieldslist.Rows[i].Visible = true;
+				}
+			}
 
 			// Update new row
 			SetupNewRowStyle();
@@ -730,17 +850,17 @@ namespace CodeImp.DoomBuilder.Controls
 		private void ApplyValue(FieldsEditorRow frow, object value)
 		{
 			// Defined?
-			if((value != null) && (!frow.IsFixed || !frow.Info.Default.Equals(value)))
+			if((value != null) && (frow.RowType == FieldsEditorRowType.DYNAMIC || frow.RowType == FieldsEditorRowType.USERVAR 
+				|| !frow.Info.Default.Equals(value)))
 			{
 				frow.Define(value);
 			}
-			else if(frow.IsFixed)
+			else if(frow.RowType == FieldsEditorRowType.FIXED)
 			{
 				frow.Undefine();
 			}
 			
-			if(OnFieldValueChanged != null)
-				OnFieldValueChanged(frow.Name);
+			if(OnFieldValueChanged != null) OnFieldValueChanged(frow.Name);
 		}
 		
 		// This applies the contents of the enums combobox and hides (if opened)
@@ -841,16 +961,16 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 		}
 
-        //mxd
-        private void UpdateFixedFieldsVisibility()
-        {
-            foreach (var row in fieldslist.Rows)
-            {
-                FieldsEditorRow frow = (row as FieldsEditorRow);
-                if (frow != null && frow.IsFixed) frow.Visible = showfixedfields;
-            }
-        }
-
-        #endregion
-    }
+		//mxd
+		private void UpdateFixedFieldsVisibility()
+		{
+			foreach(var row in fieldslist.Rows)
+			{
+				FieldsEditorRow frow = (row as FieldsEditorRow);
+				if(frow != null && frow.RowType == FieldsEditorRowType.FIXED) frow.Visible = showfixedfields;
+			}
+		}
+		
+		#endregion
+	}
 }
diff --git a/Source/Core/Controls/FieldsEditorRow.cs b/Source/Core/Controls/FieldsEditorRow.cs
index 6a276301b0303043b1f7bcd2aa9d1752a6514fa7..99f647b287d9e703c7e762b5ab0ce61015191a25 100644
--- a/Source/Core/Controls/FieldsEditorRow.cs
+++ b/Source/Core/Controls/FieldsEditorRow.cs
@@ -26,6 +26,23 @@ using CodeImp.DoomBuilder.Types;
 
 namespace CodeImp.DoomBuilder.Controls
 {
+	internal enum FieldsEditorRowType //mxd
+	{
+		// This is a fixed field defined in the game configuration
+		// The field cannot be deleted (delete will result in a reset)
+		// and cannot change type.
+		FIXED,
+
+		// This is an abstartct variable field enetered by user
+		// The field can be deleted and can change type.
+		DYNAMIC,
+
+		// This is a user variable field defined in actor's DECORATE
+		// The field cannot be deleted (delete will result in a reset)
+		// but can change type.
+		USERVAR,
+	}
+	
 	internal class FieldsEditorRow : DataGridViewRow
 	{
 		#region ================== Constants
@@ -34,13 +51,11 @@ namespace CodeImp.DoomBuilder.Controls
 
 		#region ================== Variables
 		
-		// This is true when for a fixed field as defined in the game configuration
-		// This means that the field cannot be deleted (delete will result in a reset)
-		// and cannot change type.
-		private bool isfixed;
+		//mxd. Row type
+		private readonly FieldsEditorRowType rowtype;
 
 		// Field information (only for fixed fields)
-		private UniversalFieldInfo fieldinfo;
+		private readonly UniversalFieldInfo fieldinfo;
 
 		// This is true when the field is defined. Cannot be false when this field
 		// is not fixed, because non-fixed fields are deleted from the list when undefined.
@@ -53,7 +68,7 @@ namespace CodeImp.DoomBuilder.Controls
 
 		#region ================== Properties
 
-		public bool IsFixed { get { return isfixed; } }
+		public FieldsEditorRowType RowType { get { return rowtype; } } //mxd
 		public bool IsDefined { get { return isdefined; } }
 		public bool IsEmpty { get { return (this.Cells[2].Value == null) || (this.Cells[2].Value.ToString().Length == 0); } }
 		public string Name { get { return this.Cells[0].Value.ToString(); } }
@@ -73,7 +88,7 @@ namespace CodeImp.DoomBuilder.Controls
 			
 			// Fixed
 			this.fieldinfo = fixedfield;
-			isfixed = true;
+			this.rowtype = FieldsEditorRowType.FIXED; //mxd
 			
 			// Type
 			this.fieldtype = General.Types.GetFieldHandler(fixedfield);
@@ -97,31 +112,54 @@ namespace CodeImp.DoomBuilder.Controls
 		}
 
 		// Constructor for a non-fixed, defined field
-		public FieldsEditorRow(DataGridView view, string name, int type, object value)
+		//mxd. Also for a user variable field.
+		public FieldsEditorRow(DataGridView view, string name, int type, object value, bool isuservar)
 		{
-			// Defined
-			this.DefaultCellStyle.ForeColor = SystemColors.WindowText;
-			isdefined = true;
-
-			// Non-fixed
-			isfixed = false;
+			//mxd. Row type
+			this.rowtype = (isuservar ? FieldsEditorRowType.USERVAR : FieldsEditorRowType.DYNAMIC);
 
 			// Type
 			this.fieldtype = General.Types.GetFieldHandler(type, value);
 
 			// Make all cells
 			base.CreateCells(view);
-			
-			// Setup property cell
-			this.Cells[0].Value = name;
-			this.Cells[0].ReadOnly = true;
 
-			// Setup type cell
-			this.Cells[1].Value = fieldtype.GetDisplayType();
-			this.Cells[1].ReadOnly = false;
+			//mxd. Our path splits here...
+			if(isuservar)
+			{
+				// Not defined
+				this.DefaultCellStyle.ForeColor = SystemColors.GrayText;
+				isdefined = false;
+				fieldtype.ApplyDefaultValue();
 
-			// Setup value cell
-			this.Cells[2].Value = fieldtype.GetStringValue();
+				// Setup property cell
+				this.Cells[0].Value = name;
+				this.Cells[0].ReadOnly = true;
+
+				// Setup type cell
+				this.Cells[1].Value = fieldtype.GetDisplayType();
+				this.Cells[1].ReadOnly = true;
+
+				// Setup value cell
+				this.Cells[2].Value = fieldtype.GetStringValue();
+			}
+			else
+			{
+				// Defined
+				this.DefaultCellStyle.ForeColor = SystemColors.WindowText;
+				isdefined = true;
+
+				// Setup property cell
+				this.Cells[0].Value = name;
+				this.Cells[0].ReadOnly = true;
+
+				// Setup type cell
+				this.Cells[1].Value = fieldtype.GetDisplayType();
+				this.Cells[1].ReadOnly = false;
+
+				// Setup value cell
+				this.Cells[2].Value = fieldtype.GetStringValue();
+			}
 
 			// We have no destructor
 			GC.SuppressFinalize(this);
@@ -140,7 +178,7 @@ namespace CodeImp.DoomBuilder.Controls
 				fieldtype.Browse(parent);
 
 				// This is a fixed field?
-				if(isfixed)
+				if(rowtype == FieldsEditorRowType.FIXED)
 				{
 					// Does this match the default setting?
 					if(fieldtype.GetValue().Equals(fieldinfo.Default))
@@ -188,7 +226,7 @@ namespace CodeImp.DoomBuilder.Controls
 				this.Cells[2].Value = fieldtype.GetStringValue();
 
 				// This is a fixed field?
-				if(isfixed)
+				if(rowtype == FieldsEditorRowType.FIXED)
 				{
 					// Does this match the default setting?
 					if(fieldtype.GetValue().Equals(fieldinfo.Default))
@@ -201,15 +239,19 @@ namespace CodeImp.DoomBuilder.Controls
 		}
 		
 		// This undefines the field
-		// ONLY VALID FOR FIXED FIELDS
+		// ONLY VALID FOR FIXED AND USERVAR FIELDS
 		// You should just delete non-fixed fields
 		public void Undefine()
 		{
 			// Must be fixed!
-			if(!isfixed) throw new InvalidOperationException();
+			if(rowtype != FieldsEditorRowType.FIXED && rowtype != FieldsEditorRowType.USERVAR) throw new InvalidOperationException();
 			
 			// Now undefined
-			fieldtype.SetValue(fieldinfo.Default);
+			if(rowtype == FieldsEditorRowType.USERVAR)
+				fieldtype.ApplyDefaultValue();
+			else
+				fieldtype.SetValue(fieldinfo.Default);
+
 			this.Cells[2].Value = fieldtype.GetStringValue();
 			this.DefaultCellStyle.ForeColor = SystemColors.GrayText;
 			isdefined = false;
@@ -218,10 +260,13 @@ namespace CodeImp.DoomBuilder.Controls
 		// This defines the field
 		public void Define(object value)
 		{
+			//mxd. Don't count as defined when default value is passed
+			if(value.ToString() == fieldtype.GetDefaultValue().ToString()) return;
+			
 			// Now defined
 			fieldtype.SetValue(value);
 			this.Cells[2].Value = fieldtype.GetStringValue();
-			this.DefaultCellStyle.ForeColor = SystemColors.WindowText;
+			this.DefaultCellStyle.ForeColor = (rowtype == FieldsEditorRowType.USERVAR ? SystemColors.HotTrack : SystemColors.WindowText);
 			isdefined = true;
 		}
 
@@ -229,13 +274,12 @@ namespace CodeImp.DoomBuilder.Controls
 		public void ChangeType(int typeindex)
 		{
 			// Can't do this for a fixed field!
-			if(isfixed) throw new InvalidOperationException();
+			if(rowtype == FieldsEditorRowType.FIXED) throw new InvalidOperationException();
 			
 			// Different?
 			if(typeindex != fieldtype.Index)
 			{
 				// Change field type!
-				//TypeHandlerAttribute attrib = General.Types.GetAttribute(typeindex); //mxd
 				fieldtype = General.Types.GetFieldHandler(typeindex, this.Cells[2].Value);
 				this.Cells[1].Value = fieldtype.GetDisplayType();
 			}
diff --git a/Source/Core/Controls/FlatSelectorControl.cs b/Source/Core/Controls/FlatSelectorControl.cs
index c466a9a6d097bdd1822dc8f2967e99d735c971d4..3c76acbceb8353351b0ccfc039beb6922da2838a 100644
--- a/Source/Core/Controls/FlatSelectorControl.cs
+++ b/Source/Core/Controls/FlatSelectorControl.cs
@@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.Controls
 				if(usepreviews ? !texture.IsPreviewLoaded : !texture.IsImageLoaded) timer.Start(); //mxd
 				
 				// Set the image
-				return (usepreviews ? texture.GetPreview() : texture.GetBitmap());
+				return new Bitmap(usepreviews ? texture.GetPreview() : texture.GetBitmap());
 			}
 		}
 
diff --git a/Source/Core/Controls/ImageBrowserControl.Designer.cs b/Source/Core/Controls/ImageBrowserControl.Designer.cs
index 567270c5295e0d82e5e008ca80982791bdf36d83..2549132af1c693e769fe85cbf34bcce0a3e06881 100644
--- a/Source/Core/Controls/ImageBrowserControl.Designer.cs
+++ b/Source/Core/Controls/ImageBrowserControl.Designer.cs
@@ -116,6 +116,7 @@ namespace CodeImp.DoomBuilder.Controls
 			this.list.DoubleClick += new System.EventHandler(this.list_DoubleClick);
 			this.list.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.list_ItemSelectionChanged);
 			this.list.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.list_KeyPress);
+			this.list.KeyDown += new System.Windows.Forms.KeyEventHandler(this.list_KeyDown);
 			// 
 			// showsubdirtextures
 			// 
diff --git a/Source/Core/Controls/ImageBrowserControl.cs b/Source/Core/Controls/ImageBrowserControl.cs
index ede2166fa6492d2a9cbe295bac19514200f2c76c..b7b8c2a0bb7a219272c693234d90c2f9e02138ef 100644
--- a/Source/Core/Controls/ImageBrowserControl.cs
+++ b/Source/Core/Controls/ImageBrowserControl.cs
@@ -237,6 +237,20 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 		}
 
+		//mxd. Handle keyboard navigation the same way regardless of list being focused...
+		private void list_KeyDown(object sender, KeyEventArgs e)
+		{
+			// Check what key is pressed
+			switch(e.KeyData)
+			{
+				// Cursor keys
+				case Keys.Left: SelectNextItem(SearchDirectionHint.Left); e.SuppressKeyPress = true; break;
+				case Keys.Right: SelectNextItem(SearchDirectionHint.Right); e.SuppressKeyPress = true; break;
+				case Keys.Up: SelectNextItem(SearchDirectionHint.Up); e.SuppressKeyPress = true; break;
+				case Keys.Down: SelectNextItem(SearchDirectionHint.Down); e.SuppressKeyPress = true; break;
+			}
+		}
+
 		//mxd
 		private void filterSize_WhenTextChanged(object sender, EventArgs e) 
 		{
@@ -277,6 +291,8 @@ namespace CodeImp.DoomBuilder.Controls
 		//mxd. Transfer focus to Filter textbox
 		private void list_KeyPress(object sender, KeyPressEventArgs e)
 		{
+			if(!General.Settings.KeepTextureFilterFocused) return;
+
 			objectname.Focus();
 			if(e.KeyChar == '\b') // Any better way to check for Backspace?..
 			{
@@ -388,36 +404,115 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 			else
 			{
-				// Get selected item
-				ListViewItem lvi = list.SelectedItems[0];
-				Rectangle lvirect = list.GetItemRect(lvi.Index, ItemBoundsPortion.Entire);
-				Point spos = new Point(lvirect.Location.X + lvirect.Width / 2, lvirect.Y + lvirect.Height / 2);
+				//mxd
+				int index = list.SelectedItems[0].Index;
+				int targetindex = -1;
+				ListViewGroup startgroup = list.SelectedItems[0].Group;
+				Rectangle startrect = list.SelectedItems[0].GetBounds(ItemBoundsPortion.Entire);
 				
-				// Try finding 5 times in the given direction
-				for(int i = 0; i < 5; i++)
+				switch(dir)
 				{
-					// Move point in given direction
-					switch(dir)
-					{
-						case SearchDirectionHint.Left: spos.X -= list.TileSize.Width / 2; break;
-						case SearchDirectionHint.Right: spos.X += list.TileSize.Width / 2; break;
-						case SearchDirectionHint.Up: spos.Y -= list.TileSize.Height / 2; break;
-						case SearchDirectionHint.Down: spos.Y += list.TileSize.Height / 2; break;
-					}
-					
-					// Test position
-					lvi = list.GetItemAt(spos.X, spos.Y);
-					if(lvi != null)
-					{
-						// Select item
-						list.SelectedItems.Clear();
-						lvi.Selected = true;
+					// Check previous items untill groups match...
+					case SearchDirectionHint.Left:
+						if(list.SelectedIndices[0] > 0)
+						{
+							while(--index > -1)
+							{
+								if(list.Items[index].Group == startgroup)
+								{
+									targetindex = index;
+									break;
+								}
+							}
+						}
+						break;
+
+					// Same thing, other direction...
+					case SearchDirectionHint.Right:
+						if(list.SelectedIndices[0] < list.Items.Count - 1)
+						{
+							while(++index < list.Items.Count)
+							{
+								if(list.Items[index].Group == startgroup)
+								{
+									targetindex = index;
+									break;
+								}
+							}
+						}
+						break;
+
+					// Check previous items untill X coordinate match and Y coordinate is less than the start ones...
+					case SearchDirectionHint.Up:
+						while(--index > -1)
+						{
+							ListViewItem item = list.Items[index];
+							if(item != null && item.Group == startgroup)
+							{
+								Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire);
+								if(rect.X == startrect.X && rect.Y < startrect.Y)
+								{
+									targetindex = index;
+									break;
+								}
+							}
+						}
 						break;
+
+					// Same thing, other direction...
+					case SearchDirectionHint.Down:
+						if(list.SelectedIndices[0] < list.Items.Count - 1)
+						{
+							while(++index < list.Items.Count)
+							{
+								ListViewItem item = list.Items[index];
+								if(item != null && item.Group == startgroup)
+								{
+									Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire);
+									if(rect.X == startrect.X && rect.Y > startrect.Y)
+									{
+										targetindex = index;
+										break;
+									}
+								}
+							}
+						}
+						break;
+				}
+
+				//mxd. Use the old method for Up/Down keys, becaue it can jump between Groups...
+				if(targetindex == -1 && (dir == SearchDirectionHint.Up || dir == SearchDirectionHint.Down))
+				{
+					Point spos = new Point(startrect.Location.X + startrect.Width / 2, startrect.Y + startrect.Height / 2);
+
+					// Try finding 5 times in the given direction
+					for(int i = 0; i < 5; i++)
+					{
+						// Move point in given direction
+						switch(dir)
+						{
+							case SearchDirectionHint.Up: spos.Y -= list.TileSize.Height / 2; break;
+							case SearchDirectionHint.Down: spos.Y += list.TileSize.Height / 2; break;
+						}
+
+						// Test position
+						ListViewItem lvi = list.GetItemAt(spos.X, spos.Y);
+						if(lvi != null)
+						{
+							targetindex = lvi.Index;
+							break;
+						}
 					}
 				}
-				
-				// Make selection visible
-				if(list.SelectedItems.Count > 0) list.SelectedItems[0].EnsureVisible();
+
+				//mxd. Found something?..
+				if(targetindex != -1)
+				{
+					// Select item
+					list.SelectedItems.Clear();
+					list.Items[targetindex].Selected = true;
+					list.SelectedItems[0].EnsureVisible();
+				}
 			}
 		}
 		
@@ -514,6 +609,15 @@ namespace CodeImp.DoomBuilder.Controls
 		private void RefillList(bool selectfirst)
 		{
 			visibleitems = new List<ImageBrowserItem>();
+
+			//mxd. Store info about currently selected item
+			string selectedname = string.Empty;
+			ListViewGroup selecteditemgroup = null;
+			if(!selectfirst && keepselected == -1 && list.SelectedIndices.Count > 0)
+			{
+				selectedname = list.Items[list.SelectedIndices[0]].Text;
+				selecteditemgroup = list.Items[list.SelectedIndices[0]].Group;
+			}
 			
 			// Begin updating list
 			updating = true;
@@ -569,6 +673,56 @@ namespace CodeImp.DoomBuilder.Controls
 				{
 					SelectFirstItem();
 				}
+				//mxd. Try reselecting the same/next closest item
+				else if(selecteditemgroup != null && !string.IsNullOrEmpty(selectedname))
+				{
+					ListViewItem bestmatch = null;
+					int charsmatched = 1;
+					foreach(ListViewItem item in list.Items)
+					{
+						if(item.Group == selecteditemgroup && item.Text[0] == selectedname[0])
+						{
+							if(item.Text == selectedname)
+							{
+								bestmatch = item;
+								break;
+							}
+
+							for(int i = 1; i < Math.Min(item.Text.Length, selectedname.Length); i++)
+							{
+								if(item.Text[i] != selectedname[i])
+								{
+									if(i > charsmatched)
+									{
+										bestmatch = item;
+										charsmatched = i;
+									}
+									break;
+								}
+							}
+						}
+					}
+
+					// Select the first item from the same group...
+					if(bestmatch == null)
+					{
+						foreach(ListViewItem item in list.Items)
+						{
+							if(item.Group == selecteditemgroup)
+							{
+								bestmatch = item;
+								break;
+							}
+						}
+					}
+
+					// Select found item
+					if(bestmatch != null)
+					{
+						bestmatch.Selected = true;
+						bestmatch.EnsureVisible();
+					}
+				}
 			}
 			
 			// Raise event
@@ -605,7 +759,10 @@ namespace CodeImp.DoomBuilder.Controls
 		// This sends the focus to the textbox
 		public void FocusTextbox()
 		{
-			objectname.Focus();
+			if(General.Settings.KeepTextureFilterFocused) //mxd
+				objectname.Focus();
+			else
+				list.Focus();
 		}
 		
 		#endregion
diff --git a/Source/Core/Controls/ScriptEditorControl.cs b/Source/Core/Controls/ScriptEditorControl.cs
index c001cc5401f8301a3a9bb072033e8c85e36faed6..14bcc86b71c9e931f8b01351799e8dba4a705280 100644
--- a/Source/Core/Controls/ScriptEditorControl.cs
+++ b/Source/Core/Controls/ScriptEditorControl.cs
@@ -35,1417 +35,1425 @@ using ScintillaNET;
 
 namespace CodeImp.DoomBuilder.Controls
 {
-    internal enum ScriptStyleType
-    {
-        PlainText = 0,
-        Keyword = 1,
-        Constant = 2,
-        Comment = 3,
-        Literal = 4,
-        LineNumber = 5,
-        String = 6, //mxd
-        Include = 7, //mxd
-        Property = 8, //mxd
-    }
-
-    internal partial class ScriptEditorControl : UserControl
-    {
-        #region ================== Enums
-
-        // Index for registered images
-        private enum ImageIndex
-        {
-            ScriptConstant = 0,
-            ScriptKeyword = 1,
-            ScriptError = 2,
-            ScriptSnippet = 3, //mxd
-            ScriptProperty = 4, //mxd
-        }
-
-        #endregion
-
-        #region ================== Constants
-
-        private const string LEXERS_RESOURCE = "Lexers.cfg";
-        private const int MAX_BACKTRACK_LENGTH = 200;
-        private const int HIGHLIGHT_INDICATOR = 8; //mxd. Indicators 0-7 could be in use by a lexer so we'll use indicator 8 to highlight words.
-
-        #endregion
-
-        #region ================== Delegates / Events
-
-        public delegate void ExplicitSaveTabDelegate();
-        public delegate void OpenScriptBrowserDelegate();
-        public delegate void OpenFindReplaceDelegate();
-        public delegate void FindNextDelegate();
-        public delegate void FindPreviousDelegate(); //mxd
-
-        public event ExplicitSaveTabDelegate OnExplicitSaveTab;
-        public event OpenScriptBrowserDelegate OnOpenScriptBrowser;
-        public event OpenFindReplaceDelegate OnOpenFindAndReplace;
-        public event FindNextDelegate OnFindNext;
-        public event FindPreviousDelegate OnFindPrevious; //mxd
-        public new event EventHandler OnTextChanged; //mxd
-
-        #endregion
-
-        #region ================== Variables
-
-        // Script configuration
-        private ScriptConfiguration scriptconfig;
-
-        // List of keywords and constants
-        private List<string> autocompletelist;
-
-        // Style translation from Scintilla style to ScriptStyleType
-        private Dictionary<int, ScriptStyleType> stylelookup;
-
-        // Current position information
-        private string curfunctionname = "";
-        private int curargumentindex;
-        private int curfunctionstartpos;
-        private int linenumbercharlength; //mxd. Current max number of chars in the line number
-        private int lastcaretpos; //mxd. Used in brace matching
-        private int caretoffset; //mxd. Used to modify caret position after autogenerating stuff
-        private bool skiptextinsert; //mxd. Gross hacks
-        private bool expandcodeblock; //mxd. More gross hacks
-        private string highlightedword; //mxd
-        private Encoding encoding; //mxd
-
-        #endregion
-
-        #region ================== Properties
-
-        public bool IsChanged { get { return scriptedit.Modified; } }
-        public int SelectionStart { get { return scriptedit.SelectionStart; } set { scriptedit.SelectionStart = value; } }
-        public int SelectionEnd { get { return scriptedit.SelectionEnd; } set { scriptedit.SelectionEnd = value; } }
-        public new string Text { get { return scriptedit.Text; } set { scriptedit.Text = value; } } //mxd
-        public string SelectedText { get { return scriptedit.SelectedText; } } //mxd
-        public bool ShowWhitespace { get { return scriptedit.ViewWhitespace != WhitespaceMode.Invisible; } set { scriptedit.ViewWhitespace = value ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; } }
-        public bool WrapLongLines { get { return scriptedit.WrapMode != WrapMode.None; } set { scriptedit.WrapMode = (value ? WrapMode.Char : WrapMode.None); } }
-        public ComboBox FunctionBar { get { return functionbar; } } //mxd
-        public Scintilla Scintilla { get { return scriptedit; } } //mxd
-
-        #endregion
-
-        #region ================== Contructor / Disposer
-
-        // Constructor
-        public ScriptEditorControl()
-        {
-            // Initialize
-            InitializeComponent();
-
-            //mxd. ASCII with cyrillic support...
-            encoding = Encoding.GetEncoding(1251);
-
-            // Script editor properties
-            //TODO: use ScintillaNET properties instead when they become available
-            scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1));
-            scriptedit.DirectMessage(NativeMethods.SCI_SETMOUSEDOWNCAPTURES, new IntPtr(1));
-            scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1));
-
-            // Symbol margin
-            scriptedit.Margins[0].Type = MarginType.Symbol;
-            scriptedit.Margins[0].Width = 20;
-            scriptedit.Margins[0].Mask = 1 << (int)ImageIndex.ScriptError; // Error marker only
-            scriptedit.Margins[0].Cursor = MarginCursor.Arrow;
-            scriptedit.Margins[0].Sensitive = true;
-
-            // Line numbers margin
-            if (General.Settings.ScriptShowLineNumbers)
-            {
-                scriptedit.Margins[1].Type = MarginType.Number;
-                scriptedit.Margins[1].Width = 16;
-            }
-            scriptedit.Margins[1].Mask = 0; // No markers here
-
-            // Spacing margin
-            scriptedit.Margins[2].Type = MarginType.Symbol;
-            scriptedit.Margins[2].Width = 5;
-            scriptedit.Margins[2].Cursor = MarginCursor.Arrow;
-            scriptedit.Margins[2].Mask = 0; // No markers here
-
-            // Images
-            RegisterAutoCompleteImage(ImageIndex.ScriptConstant, Resources.ScriptConstant);
-            RegisterAutoCompleteImage(ImageIndex.ScriptKeyword, Resources.ScriptKeyword);
-            RegisterAutoCompleteImage(ImageIndex.ScriptSnippet, Resources.ScriptSnippet); //mxd
-            RegisterAutoCompleteImage(ImageIndex.ScriptProperty, Resources.ScriptProperty); //mxd
-            RegisterMarkerImage(ImageIndex.ScriptError, Resources.ScriptError);
-
-            //mxd. These key combinations put odd characters in the script. Let's disable them
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Q, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.W, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.E, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.R, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Y, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.U, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.I, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.P, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.A, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.D, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.G, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.H, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.J, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.K, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.L, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.Z, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.X, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.C, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.V, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.B, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.N, Command.Null);
-            scriptedit.AssignCmdKey(Keys.Control | Keys.M, Command.Null);
-
-            //mxd. These key combinations are used to perform special actions. Let's disable them
-            scriptedit.AssignCmdKey(Keys.F3, Command.Null); // F3 for Find Next
-            scriptedit.AssignCmdKey(Keys.F2, Command.Null); // F2 for Find Previous
-            scriptedit.AssignCmdKey(Keys.Control | Keys.F, Command.Null); // CTRL+F for find & replace
-            scriptedit.AssignCmdKey(Keys.Control | Keys.S, Command.Null); // CTRL+S for save
-            scriptedit.AssignCmdKey(Keys.Control | Keys.O, Command.Null); // CTRL+O for open
-            scriptedit.AssignCmdKey(Keys.Control | Keys.Space, Command.Null); // CTRL+Space to autocomplete <- TODO: this doesn't seem to work...
-        }
-
-        #endregion
-
-        #region ================== Public methods
-
-        // This launches keyword help website
-        public bool LaunchKeywordHelp()
-        {
-            string helpsite = scriptconfig.KeywordHelp;
-            string currentword = GetCurrentWord();
-            if (!string.IsNullOrEmpty(currentword) && (currentword.Length > 1) && !string.IsNullOrEmpty(helpsite))
-            {
-                currentword = scriptconfig.GetKeywordCase(currentword);
-                helpsite = helpsite.Replace("%K", currentword);
-                General.OpenWebsite(helpsite);
-                return true;
-            }
-
-            return !string.IsNullOrEmpty(helpsite); //mxd
-        }
-
-        // This replaces the selection with the given text
-        public void ReplaceSelection(string replacement)
-        {
-            scriptedit.ReplaceSelection(replacement); //mxd TODO: encoding check/conversion?
-        }
-
-        // This moves the caret to a given line and ensures the line is visible
-        public void MoveToLine(int linenumber)
-        {
-            scriptedit.Lines[linenumber].Goto();
-            EnsureLineVisible(linenumber);
-        }
-
-        // This makes sure a line is visible
-        public void EnsureLineVisible(int linenumber)
-        {
-            // Determine target lines range
-            int startline = Math.Max(0, linenumber - 4);
-            int endline = Math.Min(scriptedit.Lines.Count, Math.Max(linenumber, linenumber + scriptedit.LinesOnScreen - 6));
-
-            // Go to target line
-            scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed
-            scriptedit.ShowLines(startline, endline);
-
-            // We may want to do some scrolling...
-            if (scriptedit.FirstVisibleLine >= startline)
-                scriptedit.Lines[startline].Goto();
-            else if (scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline)
-                scriptedit.Lines[endline].Goto();
-        }
-
-        //mxd
-        private void SelectAndShow(int startpos, int endpos)
-        {
-            // Select the result
-            int startline = scriptedit.LineFromPosition(startpos);
-            int endline = scriptedit.LineFromPosition(endpos);
-
-            // Go to target line
-            scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed
-            scriptedit.ShowLines(startline, endline);
-            scriptedit.GotoPosition(startpos);
-
-            // We may want to do some extra scrolling...
-            if (startline > 1 && scriptedit.FirstVisibleLine >= startline - 1)
-                scriptedit.Lines[startline - 1].Goto();
-            else if (endline < scriptedit.Lines.Count - 1 && scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline + 1)
-                scriptedit.Lines[endline + 1].Goto();
-
-            // Update selection
-            scriptedit.SelectionStart = startpos;
-            scriptedit.SelectionEnd = endpos;
-        }
-
-        // This returns the line for a position
-        public int LineFromPosition(int position)
-        {
-            return scriptedit.LineFromPosition(position);
-        }
-
-        // This clears all marks
-        public void ClearMarks()
-        {
-            scriptedit.MarkerDeleteAll((int)ImageIndex.ScriptError);
-        }
-
-        // This adds a mark on the given line
-        public void AddMark(int linenumber)
-        {
-            scriptedit.Lines[linenumber].MarkerAdd((int)ImageIndex.ScriptError);
-        }
-
-        // This refreshes the style setup
-        public void RefreshStyle()
-        {
-            // Re-setup with the same config
-            SetupStyles(scriptconfig);
-        }
-
-        // This sets up the script editor with a script configuration
-        public void SetupStyles(ScriptConfiguration config)
-        {
-            Configuration lexercfg = new Configuration();
-
-            // Make collections
-            stylelookup = new Dictionary<int, ScriptStyleType>();
-            Dictionary<string, string> autocompletedict = new Dictionary<string, string>(StringComparer.Ordinal);
-
-            // Keep script configuration
-            scriptconfig = config;
-
-            // Find a resource named Lexers.cfg
-            string[] resnames = General.ThisAssembly.GetManifestResourceNames();
-            foreach (string rn in resnames)
-            {
-                // Found one?
-                if (rn.EndsWith(LEXERS_RESOURCE, StringComparison.OrdinalIgnoreCase))
-                {
-                    // Get a stream from the resource
-                    Stream lexersdata = General.ThisAssembly.GetManifestResourceStream(rn);
-                    if (lexersdata != null)
-                    {
-                        StreamReader lexersreader = new StreamReader(lexersdata, Encoding.ASCII);
-
-                        // Load configuration from stream
-                        lexercfg.InputConfiguration(lexersreader.ReadToEnd());
-
-                        // Done with the resource
-                        lexersreader.Dispose();
-                        lexersdata.Dispose();
-                    }
-
-                    //mxd. We are done here
-                    break;
-                }
-            }
-
-            //mxd. Reset document slyle
-            scriptedit.ClearDocumentStyle();
-            scriptedit.StyleResetDefault();
-
-            // Check if specified lexer exists and set the lexer to use
-            string lexername = "lexer" + (int)scriptconfig.Lexer;
-            if (!lexercfg.SettingExists(lexername)) throw new InvalidOperationException("Unknown lexer " + scriptconfig.Lexer + " specified in script configuration!");
-            scriptedit.Lexer = scriptconfig.Lexer;
-
-            //mxd. Set word chars
-            scriptedit.SetWordChars(scriptconfig.WordCharacters);
-
-            // Set the default style and settings
-            scriptedit.Styles[Style.Default].Font = General.Settings.ScriptFontName;
-            scriptedit.Styles[Style.Default].Size = General.Settings.ScriptFontSize;
-            scriptedit.Styles[Style.Default].Bold = General.Settings.ScriptFontBold;
-            scriptedit.Styles[Style.Default].Italic = false;
-            scriptedit.Styles[Style.Default].Underline = false;
-            scriptedit.Styles[Style.Default].Case = StyleCase.Mixed;
-            scriptedit.Styles[Style.Default].ForeColor = General.Colors.PlainText.ToColor();
-            scriptedit.Styles[Style.Default].BackColor = General.Colors.ScriptBackground.ToColor();
-            scriptedit.CaretPeriod = SystemInformation.CaretBlinkTime;
-            scriptedit.CaretForeColor = General.Colors.ScriptBackground.Inverse().ToColor();
-
-            // Set tabulation settings
-            scriptedit.UseTabs = General.Settings.ScriptUseTabs;
-            scriptedit.TabWidth = General.Settings.ScriptTabWidth;
-            //scriptedit.IndentWidth = General.Settings.ScriptTabWidth; // Equals to TabWidth by default
-            //TODO: use ScintillaNET properties instead when they become available
-            scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1));
-            scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1));
-
-            // This applies the default style to all styles
-            scriptedit.StyleClearAll();
-
-            // Set the code page to use. [mxd] No longer needed?
-            //scriptedit.CodePage = scriptconfig.CodePage;
-
-            //mxd. We can't change Font or Size here because this will screw displayed tab width (because it's based on character width)...
-            // Set the default to something normal (this is used by the autocomplete list)
-            //scriptedit.Styles[Style.Default].Font = this.Font.Name;
-            scriptedit.Styles[Style.Default].Bold = this.Font.Bold;
-            scriptedit.Styles[Style.Default].Italic = this.Font.Italic;
-            scriptedit.Styles[Style.Default].Underline = this.Font.Underline;
-            //scriptedit.Styles[Style.Default].Size = (int)Math.Round(this.Font.SizeInPoints);
-
-            // Set style for linenumbers and margins
-            scriptedit.Styles[Style.LineNumber].BackColor = General.Colors.ScriptBackground.ToColor();
-            scriptedit.SetFoldMarginColor(true, General.Colors.ScriptFoldBackColor.ToColor());
-            scriptedit.SetFoldMarginHighlightColor(true, General.Colors.ScriptFoldBackColor.ToColor());
-            for (int i = 25; i < 32; i++)
-            {
-                scriptedit.Markers[i].SetForeColor(General.Colors.ScriptFoldBackColor.ToColor());
-                scriptedit.Markers[i].SetBackColor(General.Colors.ScriptFoldForeColor.ToColor());
-            }
-
-            //mxd. Set style for (mis)matching braces
-            scriptedit.Styles[Style.BraceLight].BackColor = General.Colors.ScriptBraceHighlight.ToColor();
-            scriptedit.Styles[Style.BraceBad].BackColor = General.Colors.ScriptBadBraceHighlight.ToColor();
-
-            //mxd. Set whitespace color
-            scriptedit.SetWhitespaceForeColor(true, General.Colors.ScriptWhitespace.ToColor());
-
-            //mxd. Set selection colors
-            scriptedit.SetSelectionForeColor(true, General.Colors.ScriptSelectionForeColor.ToColor());
-            scriptedit.SetSelectionBackColor(true, General.Colors.ScriptSelectionBackColor.ToColor());
-
-            // Clear all keywords
-            for (int i = 0; i < 9; i++) scriptedit.SetKeywords(i, null);
-
-            // Now go for all elements in the lexer configuration
-            // We are looking for the numeric keys, because these are the
-            // style index to set and the value is our ScriptStyleType
-            IDictionary dic = lexercfg.ReadSetting(lexername, new Hashtable());
-            foreach (DictionaryEntry de in dic)
-            {
-                // Check if this is a numeric key
-                int stylenum;
-                if (int.TryParse(de.Key.ToString(), out stylenum))
-                {
-                    // Add style to lookup table
-                    stylelookup.Add(stylenum, (ScriptStyleType)(int)de.Value);
-
-                    // Apply color to style
-                    int colorindex;
-                    ScriptStyleType type = (ScriptStyleType)(int)de.Value;
-                    switch (type)
-                    {
-                        case ScriptStyleType.PlainText: colorindex = ColorCollection.PLAINTEXT; break;
-                        case ScriptStyleType.Comment: colorindex = ColorCollection.COMMENTS; break;
-                        case ScriptStyleType.Constant: colorindex = ColorCollection.CONSTANTS; break;
-                        case ScriptStyleType.Keyword: colorindex = ColorCollection.KEYWORDS; break;
-                        case ScriptStyleType.LineNumber: colorindex = ColorCollection.LINENUMBERS; break;
-                        case ScriptStyleType.Literal: colorindex = ColorCollection.LITERALS; break;
-                        case ScriptStyleType.String: colorindex = ColorCollection.STRINGS; break;
-                        case ScriptStyleType.Include: colorindex = ColorCollection.INCLUDES; break;
-                        case ScriptStyleType.Property: colorindex = ColorCollection.PROPERTIES; break;
-                        default: colorindex = ColorCollection.PLAINTEXT; break;
-                    }
-
-                    scriptedit.Styles[stylenum].ForeColor = General.Colors.Colors[colorindex].ToColor();
-                }
-            }
-
-            // Create the keywords list and apply it
-            string imageindex = ((int)ImageIndex.ScriptKeyword).ToString(CultureInfo.InvariantCulture);
-            int keywordsindex = lexercfg.ReadSetting(lexername + ".keywordsindex", -1);
-            if (keywordsindex > -1)
-            {
-                StringBuilder keywordslist = new StringBuilder("");
-                foreach (string k in scriptconfig.Keywords)
-                {
-                    if (keywordslist.Length > 0) keywordslist.Append(" ");
-                    keywordslist.Append(k);
-
-                    //mxd. Skip adding the keyword if we have a snippet with the same name
-                    if (!scriptconfig.Snippets.Contains(k))
-                        autocompletedict.Add(k.ToUpperInvariant(), k + "?" + imageindex);
-                }
-                string words = keywordslist.ToString();
-                scriptedit.SetKeywords(keywordsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
-            }
-
-            //mxd. Create the properties list and apply it
-            imageindex = ((int)ImageIndex.ScriptProperty).ToString(CultureInfo.InvariantCulture);
-            int propertiesindex = lexercfg.ReadSetting(lexername + ".propertiesindex", -1);
-            if (propertiesindex > -1)
-            {
-                StringBuilder propertieslist = new StringBuilder("");
-                HashSet<string> addedprops = new HashSet<string>();
-                char[] dot = new[] { '.' };
-                foreach (string p in scriptconfig.Properties)
-                {
-                    if (propertieslist.Length > 0) propertieslist.Append(" ");
-
-                    // Scintilla doesn't highlight keywords with '.' or ':', so get rid of those 
-                    if (scriptconfig.ScriptType == ScriptType.DECORATE)
-                    {
-                        string prop = p;
-                        if (prop.Contains(":")) prop = prop.Replace(":", string.Empty);
-                        if (prop.Contains("."))
-                        {
-                            // Split dotted properties into separate entries
-                            string[] parts = prop.Split(dot, StringSplitOptions.RemoveEmptyEntries);
-                            List<string> result = new List<string>();
-                            foreach (string part in parts)
-                            {
-                                if (!addedprops.Contains(part))
-                                {
-                                    result.Add(part);
-                                    addedprops.Add(part);
-                                }
-                            }
-
-                            if (result.Count > 0) propertieslist.Append(string.Join(" ", result.ToArray()));
-                        }
-                        else
-                        {
-                            addedprops.Add(prop);
-                            propertieslist.Append(prop);
-                        }
-                    }
-                    else
-                    {
-                        propertieslist.Append(p);
-                    }
-
-                    // Autocomplete doesn't mind '.' or ':'
-                    autocompletedict[p.ToUpperInvariant()] = p + "?" + imageindex;
-                }
-                string words = propertieslist.ToString();
-                scriptedit.SetKeywords(propertiesindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
-            }
-
-            // Create the constants list and apply it
-            imageindex = ((int)ImageIndex.ScriptConstant).ToString(CultureInfo.InvariantCulture);
-            int constantsindex = lexercfg.ReadSetting(lexername + ".constantsindex", -1);
-            if (constantsindex > -1)
-            {
-                StringBuilder constantslist = new StringBuilder("");
-                foreach (string c in scriptconfig.Constants)
-                {
-                    if (autocompletedict.ContainsKey(c.ToUpperInvariant())) //mxd. This happens when there's a keyword and a constant with the same name...
-                    {
-                        General.ErrorLogger.Add(ErrorType.Error, "Constant '" + c + "' is double-defined in '" + scriptconfig.Description + "' script configuration!");
-                        continue;
-                    }
-
-                    if (constantslist.Length > 0) constantslist.Append(" ");
-                    constantslist.Append(c);
-
-                    //mxd. Skip adding the constant if we have a snippet with the same name
-                    if (!scriptconfig.Snippets.Contains(c))
-                        autocompletedict.Add(c.ToUpperInvariant(), c + "?" + imageindex);
-                }
-                string words = constantslist.ToString();
-                scriptedit.SetKeywords(constantsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
-            }
-
-            //mxd. Create the snippets list and apply it
-            imageindex = ((int)ImageIndex.ScriptSnippet).ToString(CultureInfo.InvariantCulture);
-            int snippetindex = lexercfg.ReadSetting(lexername + ".snippetindex", -1);
-            if (snippetindex > -1 && scriptconfig.Snippets.Count > 0)
-            {
-                StringBuilder snippetslist = new StringBuilder("");
-                foreach (string c in scriptconfig.Snippets)
-                {
-                    if (autocompletedict.ContainsKey(c.ToUpperInvariant())) continue;
-                    if (snippetslist.Length > 0) snippetslist.Append(" ");
-                    snippetslist.Append(c);
-                    autocompletedict.Add(c.ToUpperInvariant(), c + "?" + imageindex);
-                }
-                string words = snippetslist.ToString();
-                scriptedit.SetKeywords(snippetindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
-            }
-
-            // Make autocomplete list
-            autocompletelist = new List<string>(autocompletedict.Values);
-
-            // Setup folding (https://github.com/jacobslusser/ScintillaNET/wiki/Automatic-Code-Folding)
-            if (General.Settings.ScriptShowFolding && (scriptconfig.Lexer == Lexer.Cpp || scriptconfig.Lexer == Lexer.CppNoCase))
-            {
-                // Instruct the lexer to calculate folding
-                scriptedit.SetProperty("fold", "1");
-                scriptedit.SetProperty("fold.compact", "0"); // 1 = folds blank lines
-                scriptedit.SetProperty("fold.comment", "1"); // Enable block comment folding
-                scriptedit.SetProperty("fold.preprocessor", "1"); // Enable #region folding
-                scriptedit.SetFoldFlags(FoldFlags.LineAfterContracted); // Draw line below if not expanded
-
-                // Configure a margin to display folding symbols
-                scriptedit.Margins[2].Type = MarginType.Symbol;
-                scriptedit.Margins[2].Mask = Marker.MaskFolders;
-                scriptedit.Margins[2].Sensitive = true;
-                scriptedit.Margins[2].Width = 12;
-
-                // Configure folding markers with respective symbols
-                scriptedit.Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus;
-                scriptedit.Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus;
-                scriptedit.Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected;
-                scriptedit.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner;
-                scriptedit.Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected;
-                scriptedit.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine;
-                scriptedit.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner;
-
-                // Enable automatic folding
-                scriptedit.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change);
-            }
-            else
-            {
-                // Disable folding
-                scriptedit.SetProperty("fold", "0");
-                scriptedit.SetProperty("fold.compact", "0");
-
-                scriptedit.Margins[2].Type = MarginType.Symbol;
-                scriptedit.Margins[2].Mask = 0; // No markers here
-                scriptedit.Margins[2].Sensitive = false;
-                scriptedit.Margins[2].Width = 5;
-
-                scriptedit.AutomaticFold = AutomaticFold.None;
-            }
-
-            // Rearrange the layout
-            this.PerformLayout();
-        }
-
-        // This returns the current word (where the caret is at)
-        public string GetCurrentWord()
-        {
-            return GetWordAt(scriptedit.CurrentPosition);
-        }
-
-        // This returns the word at the given position
-        public string GetWordAt(int position)
-        {
-            return scriptedit.GetWordFromPosition(position);
-        }
-
-        // Perform undo
-        public void Undo()
-        {
-            scriptedit.Undo();
-        }
-
-        // Perform redo
-        public void Redo()
-        {
-            scriptedit.Redo();
-        }
-
-        // This clears all undo levels
-        public void ClearUndoRedo()
-        {
-            scriptedit.EmptyUndoBuffer();
-        }
-
-        //mxd. This marks the current document as unmodified
-        public void SetSavePoint()
-        {
-            scriptedit.SetSavePoint();
-        }
-
-        // Perform cut
-        public void Cut()
-        {
-            scriptedit.Cut();
-        }
-
-        // Perform copy
-        public void Copy()
-        {
-            scriptedit.Copy();
-        }
-
-        // Perform paste
-        public void Paste()
-        {
-            scriptedit.Paste();
-        }
-
-        // This steals the focus (use with care!)
-        public void GrabFocus()
-        {
-            scriptedit.Focus();
-        }
-
-        public byte[] GetText()
-        {
-            return encoding.GetBytes(scriptedit.Text); //mxd TODO: other encodings?..
-        }
-
-        public void SetText(byte[] text)
-        {
-            scriptedit.Text = encoding.GetString(text); //mxd TODO: other encodings?..
-        }
-
-        //mxd
-        public void InsertSnippet(string[] lines)
-        {
-            // Insert the snippet
-            int curline = scriptedit.LineFromPosition(scriptedit.SelectionStart);
-            int indent = scriptedit.Lines[scriptedit.CurrentLine].Indentation;
-            string tabs = Environment.NewLine + GetIndentationString(indent);
-            string spaces = new String(' ', General.Settings.ScriptTabWidth);
-            int entrypos = -1;
-            int entryline = -1;
-            string[] processedlines = ProcessLineBreaks(lines);
-
-            // Process special chars, try to find entry position marker
-            for (int i = 0; i < lines.Length; i++)
-            {
-                if (!scriptedit.UseTabs) processedlines[i] = processedlines[i].Replace("\t", spaces);
-
-                // Check if we have the [EP] marker
-                if (entrypos == -1)
-                {
-                    int pos = processedlines[i].IndexOf("[EP]", StringComparison.Ordinal);
-                    if (pos != -1)
-                    {
-                        processedlines[i] = processedlines[i].Remove(pos, 4);
-                        entryline = curline + i;
-                        entrypos = processedlines[i].Length - pos;
-                    }
-                }
-            }
-
-            // Replace the text
-            string text = string.Join(tabs, processedlines);
-            scriptedit.SelectionStart = scriptedit.WordStartPosition(scriptedit.CurrentPosition, true);
-            scriptedit.SelectionEnd = scriptedit.WordEndPosition(scriptedit.CurrentPosition, true);
-            scriptedit.ReplaceSelection(text);
-
-            // Move the cursor if we had the [EP] marker
-            if (entrypos != -1)
-            {
-                scriptedit.SetEmptySelection(scriptedit.Lines[entryline].EndPosition - entrypos - 2);
-            }
-        }
-
-        //mxd. Find next result
-        public bool FindNext(FindReplaceOptions options, bool useselectionstart)
-        {
-            int startpos = (useselectionstart ? Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) : Math.Max(scriptedit.SelectionStart, scriptedit.SelectionEnd));
-
-            // Search the document
-            scriptedit.TargetStart = startpos;
-            scriptedit.TargetEnd = scriptedit.TextLength;
-            scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None;
-            if (options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord;
-
-            int result = scriptedit.SearchInTarget(options.FindText);
-
-            // Wrap around?
-            if (result == -1)
-            {
-                scriptedit.TargetStart = 0;
-                scriptedit.TargetEnd = startpos;
-                result = scriptedit.SearchInTarget(options.FindText);
-            }
-
-            // Found something
-            if (result != -1)
-            {
-                // Select the result
-                SelectAndShow(result, result + options.FindText.Length);
-
-                // Update extra highlights
-                HighlightWord(options.FindText);
-
-                // All done
-                return true;
-            }
-
-            // Nothing found...
-            return false;
-        }
-
-        //mxd. Find previous result
-        public bool FindPrevious(FindReplaceOptions options)
-        {
-            int endpos = Math.Max(0, Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) - 1);
-
-            // Search the document
-            scriptedit.TargetStart = endpos;
-            scriptedit.TargetEnd = 0;
-            scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None;
-            if (options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord;
-
-            int result = scriptedit.SearchInTarget(options.FindText);
-
-            // Wrap around?
-            if (result == -1)
-            {
-                scriptedit.TargetStart = scriptedit.TextLength;
-                scriptedit.TargetEnd = endpos;
-                result = scriptedit.SearchInTarget(options.FindText);
-            }
-
-            // Found something
-            if (result != -1)
-            {
-                // Select the result
-                SelectAndShow(result, result + options.FindText.Length);
-
-                // Update extra highlights
-                HighlightWord(options.FindText);
-
-                // All done
-                return true;
-            }
-
-            // Nothing found...
-            return false;
-        }
-
-        //mxd. (Un)indents selection
-        public void IndentSelection(bool indent)
-        {
-            // Get selected range of lines
-            int startline = scriptedit.LineFromPosition(scriptedit.SelectionStart);
-            int endline = scriptedit.LineFromPosition(scriptedit.SelectionEnd);
-
-            for (int i = startline; i < endline + 1; i++)
-            {
-                scriptedit.Lines[i].Indentation += (indent ? General.Settings.ScriptTabWidth : -General.Settings.ScriptTabWidth);
-            }
-        }
-
-        #endregion
-
-        #region ================== Utility methods
-
-        // This returns the ScriptStyleType for a given Scintilla style
-        private ScriptStyleType GetScriptStyle(int scintillastyle)
-        {
-            return (stylelookup.ContainsKey(scintillastyle) ? stylelookup[scintillastyle] : ScriptStyleType.PlainText);
-        }
-
-        // This gathers information about the current caret position
-        private void UpdatePositionInfo()
-        {
-            int bracketlevel = 0;           // bracket level counting
-            int argindex = 0;               // function argument counting
-            int pos = scriptedit.CurrentPosition;
-
-            // Get the text
-            string scripttext = scriptedit.Text;
-
-            // Reset position info
-            curfunctionname = "";
-            curargumentindex = 0;
-            curfunctionstartpos = 0;
-
-            // Determine lowest backtrack position
-            int limitpos = scriptedit.CurrentPosition - MAX_BACKTRACK_LENGTH;
-            if (limitpos < 0) limitpos = 0;
-
-            // We can only do this when we have function syntax information
-            if ((scriptconfig.ArgumentDelimiter.Length == 0) || (scriptconfig.FunctionClose.Length == 0) ||
-               (scriptconfig.FunctionOpen.Length == 0) || (scriptconfig.Terminator.Length == 0)) return;
-
-            // Get int versions of the function syntax informantion
-            int argumentdelimiter = scriptconfig.ArgumentDelimiter[0];
-            int functionclose = scriptconfig.FunctionClose[0];
-            int functionopen = scriptconfig.FunctionOpen[0];
-            int terminator = scriptconfig.Terminator[0];
-
-            // Continue backtracking until we reached the limitpos
-            while (pos >= limitpos)
-            {
-                // Backtrack 1 character
-                pos--;
-
-                // Get the style and character at this position
-                ScriptStyleType curstyle = GetScriptStyle(scriptedit.GetStyleAt(pos));
-                int curchar = scriptedit.GetCharAt(pos);
-
-                // Then meeting ) then increase bracket level
-                // When meeting ( then decrease bracket level
-                // When bracket level goes -1, then the next word should be the function name
-                // Only when at bracket level 0, count the comma's for argument index
-
-                // TODO:
-                // Original code checked for scope character here and breaks if found
-
-                // Check if in plain text or keyword
-                if ((curstyle == ScriptStyleType.PlainText) || (curstyle == ScriptStyleType.Keyword))
-                {
-                    // Closing bracket
-                    if (curchar == functionclose)
-                    {
-                        bracketlevel++;
-                    }
-                    // Opening bracket
-                    else if (curchar == functionopen)
-                    {
-                        bracketlevel--;
-
-                        // Out of the brackets?
-                        if (bracketlevel < 0)
-                        {
-                            // Skip any whitespace before this bracket
-                            do
-                            {
-                                // Backtrack 1 character
-                                curchar = scriptedit.GetCharAt(--pos);
-                            }
-                            while ((pos >= limitpos) && ((curchar == ' ') || (curchar == '\t') ||
-                                                        (curchar == '\r') || (curchar == '\n')));
-
-                            // NOTE: We may need to set onlyWordCharacters argument in the
-                            // following calls to false to get any argument delimiter included,
-                            // but this may also cause a valid keyword to be combined with other
-                            // surrounding characters that do not belong to the keyword.
-
-                            // Find the word before this bracket
-                            int wordstart = scriptedit.WordStartPosition(pos, true);
-                            int wordend = scriptedit.WordEndPosition(pos, true);
-                            string word = scripttext.Substring(wordstart, wordend - wordstart);
-                            if (word.Length > 0)
-                            {
-                                // Check if this is an argument delimiter
-                                // I can't remember why I did this, but I'll probably stumble
-                                // upon the problem if this doesn't work right (see note above)
-                                if (word[0] == argumentdelimiter)
-                                {
-                                    // We are now in the parent function
-                                    bracketlevel++;
-                                    argindex = 0;
-                                }
-                                // Now check if this is a keyword
-                                else if (scriptconfig.IsKeyword(word))
-                                {
-                                    // Found it!
-                                    curfunctionname = scriptconfig.GetKeywordCase(word);
-                                    curargumentindex = argindex;
-                                    curfunctionstartpos = wordstart;
-                                    break;
-                                }
-                                else
-                                {
-                                    // Don't know this word
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                    // Argument delimiter
-                    else if (curchar == argumentdelimiter)
-                    {
-                        // Only count these at brackt level 0
-                        if (bracketlevel == 0) argindex++;
-                    }
-                    // Terminator
-                    else if (curchar == terminator)
-                    {
-                        // Can't find anything, break now
-                        break;
-                    }
-                }
-            }
-        }
-
-        // This registers an image for the autocomplete list
-        private void RegisterAutoCompleteImage(ImageIndex index, Bitmap image)
-        {
-            // Register image
-            scriptedit.RegisterRgbaImage((int)index, image);
-        }
-
-        // This registers an image for the markes list
-        private void RegisterMarkerImage(ImageIndex index, Bitmap image)
-        {
-            // Register image
-            scriptedit.Markers[(int)index].DefineRgbaImage(image);
-            scriptedit.Markers[(int)index].Symbol = MarkerSymbol.RgbaImage;
-        }
-
-        //mxd. This converts [LB] markers to line breaks if necessary
-        private static string[] ProcessLineBreaks(string[] lines)
-        {
-            List<string> result = new List<string>(lines.Length);
-            string[] separator = new[] { "[LB]" };
-
-            foreach (string line in lines)
-            {
-                if (line.IndexOf(separator[0], StringComparison.Ordinal) != -1)
-                {
-                    if (General.Settings.ScriptAllmanStyle)
-                        result.AddRange(line.Split(separator, StringSplitOptions.RemoveEmptyEntries));
-                    else
-                        result.Add(line.Replace(separator[0], " "));
-                }
-                else
-                {
-                    result.Add(line);
-                }
-            }
-
-            return result.ToArray();
-        }
-
-        //mxd. Autocompletion handling (https://github.com/jacobslusser/ScintillaNET/wiki/Basic-Autocompletion)
-        private bool ShowAutoCompletionList()
-        {
-            int currentpos = scriptedit.CurrentPosition;
-            int wordstartpos = scriptedit.WordStartPosition(currentpos, true);
-
-            if (wordstartpos >= currentpos)
-            {
-                // Hide the list
-                scriptedit.AutoCCancel();
-                return false;
-            }
-
-            // Get entered text
-            string start = scriptedit.GetTextRange(wordstartpos, currentpos - wordstartpos);
-            if (string.IsNullOrEmpty(start))
-            {
-                // Hide the list
-                scriptedit.AutoCCancel();
-                return false;
-            }
-
-            // Filter the list
-            List<string> filtered = new List<string>();
-            foreach (string s in autocompletelist)
-                if (s.IndexOf(start, StringComparison.OrdinalIgnoreCase) != -1) filtered.Add(s);
-
-            // Any matches?
-            if (filtered.Count > 0)
-            {
-                // Show the list
-                scriptedit.AutoCShow(currentpos - wordstartpos, string.Join(" ", filtered.ToArray()));
-                return true;
-            }
-
-            // Hide the list
-            scriptedit.AutoCCancel();
-            return false;
-        }
-
-        //mxd
-        private string GetIndentationString(int indent)
-        {
-            if (scriptedit.UseTabs)
-            {
-                string indentstr = string.Empty;
-                int numtabs = indent / scriptedit.TabWidth;
-                if (numtabs > 0) indentstr = new string('\t', numtabs);
-
-                // Mixed padding? Add spaces
-                if (numtabs * scriptedit.TabWidth < indent)
-                {
-                    int numspaces = indent - numtabs * scriptedit.TabWidth;
-                    indentstr += new string(' ', numspaces);
-                }
-
-                return indentstr;
-            }
-            else
-            {
-                return new string(' ', indent);
-            }
-        }
-
-        //mxd. https://github.com/jacobslusser/ScintillaNET/wiki/Find-and-Highlight-Words
-        private void HighlightWord(string text)
-        {
-            // Remove all uses of our indicator
-            scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR;
-            scriptedit.IndicatorClearRange(0, scriptedit.TextLength);
-
-            // Update indicator appearance
-            scriptedit.Indicators[HIGHLIGHT_INDICATOR].Style = IndicatorStyle.RoundBox;
-            scriptedit.Indicators[HIGHLIGHT_INDICATOR].Under = true;
-            scriptedit.Indicators[HIGHLIGHT_INDICATOR].ForeColor = General.Colors.ScriptIndicator.ToColor();
-            scriptedit.Indicators[HIGHLIGHT_INDICATOR].OutlineAlpha = 50;
-            scriptedit.Indicators[HIGHLIGHT_INDICATOR].Alpha = 30;
-
-            // Search the document
-            scriptedit.TargetStart = 0;
-            scriptedit.TargetEnd = scriptedit.TextLength;
-            scriptedit.SearchFlags = SearchFlags.WholeWord;
-
-            while (scriptedit.SearchInTarget(text) != -1)
-            {
-                //mxd. Don't mark currently selected word
-                if (scriptedit.SelectionStart != scriptedit.TargetStart && scriptedit.SelectionEnd != scriptedit.TargetEnd)
-                {
-                    // Mark the search results with the current indicator
-                    scriptedit.IndicatorFillRange(scriptedit.TargetStart, scriptedit.TargetEnd - scriptedit.TargetStart);
-                }
-
-                // Search the remainder of the document
-                scriptedit.TargetStart = scriptedit.TargetEnd;
-                scriptedit.TargetEnd = scriptedit.TextLength;
-            }
-        }
-
-        #endregion
-
-        #region ================== Events
-
-        // Layout needs to be re-organized
-        protected override void OnLayout(LayoutEventArgs e)
-        {
-            base.OnLayout(e);
-
-            // With or without functions bar?
-            if (functionbar.Visible)
-            {
-                scriptpanel.Top = functionbar.Bottom + 6;
-                scriptpanel.Height = this.ClientSize.Height - scriptpanel.Top;
-            }
-            else
-            {
-                scriptpanel.Top = 0;
-                scriptpanel.Height = this.ClientSize.Height;
-            }
-        }
-
-        //mxd. Script text changed
-        private void scriptedit_TextChanged(object sender, EventArgs e)
-        {
-            // Line number margin width needs changing?
-            int curlinenumbercharlength = scriptedit.Lines.Count.ToString().Length;
-
-            // Calculate the width required to display the last line number
-            // and include some padding for good measure.
-            if (curlinenumbercharlength != linenumbercharlength)
-            {
-                const int padding = 2;
-                scriptedit.Margins[1].Width = scriptedit.TextWidth(Style.LineNumber, new string('9', curlinenumbercharlength + 1)) + padding;
-                linenumbercharlength = curlinenumbercharlength;
-            }
-
-            if (OnTextChanged != null) OnTextChanged(this, EventArgs.Empty);
-        }
-
-        //mxd
-        private void scriptedit_CharAdded(object sender, CharAddedEventArgs e)
-        {
-            // Hide call tip if any
-            scriptedit.CallTipCancel();
-
-            // Offset caret if needed
-            if (caretoffset != 0)
-            {
-                scriptedit.SetEmptySelection(scriptedit.SelectionStart + caretoffset);
-                caretoffset = 0;
-                if (!expandcodeblock) return;
-            }
-
-            // Move CodeBlockOpen to the new line?
-            if (expandcodeblock)
-            {
-                if (scriptedit.CurrentLine > 0)
-                {
-                    string linetext = scriptedit.Lines[scriptedit.CurrentLine - 1].Text;
-                    int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, StringComparison.Ordinal));
-                    if (blockopenpos != -1)
-                    {
-                        // Do it only if initial line doesn't start with CodeBlockOpen
-                        string linestart = linetext.Substring(0, blockopenpos).Trim();
-                        if (linestart.Length > 0)
-                        {
-                            scriptedit.InsertText(scriptedit.Lines[scriptedit.CurrentLine - 1].Position + blockopenpos,
-                                Environment.NewLine + GetIndentationString(scriptedit.Lines[scriptedit.CurrentLine - 1].Indentation));
-                        }
-                    }
-                }
-
-                expandcodeblock = false;
-                return;
-            }
-
-            // Auto-match braces
-            if (General.Settings.ScriptAutoCloseBrackets)
-            {
-                //TODO: Auto-match quotes
-                bool endpos = (scriptedit.CurrentPosition == scriptedit.TextLength);
-                if (!string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) && e.Char == scriptconfig.CodeBlockOpen[0] && !string.IsNullOrEmpty(scriptconfig.CodeBlockClose) &&
-                    (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.CodeBlockClose[0]))
-                {
-                    scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.CodeBlockClose);
-                    return;
-                }
-
-                if (!string.IsNullOrEmpty(scriptconfig.FunctionOpen) && e.Char == scriptconfig.FunctionOpen[0] && !string.IsNullOrEmpty(scriptconfig.FunctionClose) &&
-                    (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.FunctionClose[0]))
-                {
-                    scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.FunctionClose);
-                    return;
-                }
-
-                if (!string.IsNullOrEmpty(scriptconfig.ArrayOpen) && e.Char == scriptconfig.ArrayOpen[0] && !string.IsNullOrEmpty(scriptconfig.ArrayClose) &&
-                    (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.ArrayClose[0]))
-                {
-                    scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.ArrayClose);
-                    return;
-                }
-            }
-
-            if (General.Settings.ScriptAutoShowAutocompletion)
-            {
-                // Display the autocompletion list
-                ShowAutoCompletionList();
-            }
-        }
-
-        //mxd
-        private void scriptedit_UpdateUI(object sender, UpdateUIEventArgs e)
-        {
-            // If a word is selected, highlight the same words
-            if (scriptedit.SelectedText != highlightedword)
-            {
-                // Highlight only when whole word is selected
-                if (!string.IsNullOrEmpty(scriptedit.SelectedText) && scriptedit.GetWordFromPosition(scriptedit.SelectionStart) == scriptedit.SelectedText)
-                {
-                    HighlightWord(scriptedit.SelectedText);
-                }
-                else
-                {
-                    // Clear highlight
-                    scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR;
-                    scriptedit.IndicatorClearRange(0, scriptedit.TextLength);
-                }
-
-                highlightedword = scriptedit.SelectedText;
-            }
-
-            // Has the caret changed position?
-            int caretpos = scriptedit.CurrentPosition;
-            if (lastcaretpos != caretpos && scriptconfig.BraceChars.Count > 0)
-            {
-                // Perform brace matching (https://github.com/jacobslusser/ScintillaNET/wiki/Brace-Matching)
-                lastcaretpos = caretpos;
-                int bracepos1 = -1;
-
-                // Is there a brace to the left or right?
-                if (caretpos > 0 && scriptconfig.BraceChars.Contains((char)scriptedit.GetCharAt(caretpos - 1)))
-                    bracepos1 = (caretpos - 1);
-                else if (scriptconfig.BraceChars.Contains((char)(scriptedit.GetCharAt(caretpos))))
-                    bracepos1 = caretpos;
-
-                if (bracepos1 > -1)
-                {
-                    // Find the matching brace
-                    int bracepos2 = scriptedit.BraceMatch(bracepos1);
-                    if (bracepos2 == Scintilla.InvalidPosition)
-                        scriptedit.BraceBadLight(bracepos1);
-                    else
-                        scriptedit.BraceHighlight(bracepos1, bracepos2);
-                }
-                else
-                {
-                    // Turn off brace matching
-                    scriptedit.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition);
-                }
-            }
-        }
-
-        //mxd
-        private void scriptedit_InsertCheck(object sender, InsertCheckEventArgs e)
-        {
-            // Gross hacks...
-            if (skiptextinsert)
-            {
-                e.Text = string.Empty;
-                skiptextinsert = false;
-            }
-            // Do we want auto-indentation?
-            else if (!expandcodeblock && General.Settings.ScriptAutoIndent && e.Text == "\r\n")
-            {
-                // Get current line indentation up to the cursor position
-                string linetext = scriptedit.Lines[scriptedit.CurrentLine].Text;
-                int selectionpos = scriptedit.SelectionStart - scriptedit.Lines[scriptedit.CurrentLine].Position;
-                int indent = 0;
-                for (int i = 0; i < selectionpos; i++)
-                {
-                    switch (linetext[i])
-                    {
-                        case ' ': indent++; break;
-                        case '\t': indent += scriptedit.TabWidth; break;
-                        default: i = selectionpos; break; // break the loop
-                    }
-                }
-
-                // Store initial indentation
-                int initialindent = indent;
-
-                // Need to increase indentation? We do this when:
-                // 1. Line contains '{' and '}' and the cursor is between them
-                // 2. Line either doesn't contain '}', or it's before '{', or the line contains '{' and the cursor is after it 
-                int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, selectionpos, StringComparison.Ordinal));
-                int blockclosepos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.IndexOf(scriptconfig.CodeBlockClose, selectionpos, StringComparison.Ordinal));
-
-                // Add indentation when the cursor is between { and }
-                bool addindent = (blockopenpos != -1 && blockopenpos < selectionpos) && (blockclosepos == -1 || (blockopenpos < blockclosepos && blockclosepos >= selectionpos));
-                if (addindent) indent += scriptedit.TabWidth;
-
-                // Calculate indentation
-                string indentstr = GetIndentationString(indent);
-
-                // Move CodeBlockOpen to the new line? (will be applied in scriptedit_CharAdded)
-                expandcodeblock = General.Settings.ScriptAllmanStyle;
-
-                // Offset closing block char?
-                if (addindent && blockclosepos != -1)
-                {
-                    string initialindentstr = GetIndentationString(initialindent);
-                    indentstr += Environment.NewLine + initialindentstr;
-
-                    // Offset cursor position (will be performed in scriptedit_CharAdded)
-                    caretoffset = -(initialindentstr.Length + Environment.NewLine.Length);
-                }
-
-                // Apply new indentation
-                e.Text += indentstr;
-            }
-        }
-
-        //mxd
-        private void scriptedit_AutoCCompleted(object sender, AutoCSelectionEventArgs e)
-        {
-            // Expand snippet?
-            string[] lines = scriptconfig.GetSnippet(e.Text);
-            if (lines != null) InsertSnippet(lines);
-        }
-
-        // Key pressed down
-        private void scriptedit_KeyDown(object sender, KeyEventArgs e)
-        {
-            // F3 for Find Next
-            if ((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None))
-            {
-                if (OnFindNext != null) OnFindNext();
-            }
-            // F2 for Find Previous (mxd)
-            else if ((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None))
-            {
-                if (OnFindPrevious != null) OnFindPrevious();
-            }
-            // CTRL+F for find & replace
-            else if ((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control))
-            {
-                if (OnOpenFindAndReplace != null) OnOpenFindAndReplace();
-            }
-            // CTRL+S for save
-            else if ((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control))
-            {
-                if (OnExplicitSaveTab != null) OnExplicitSaveTab();
-            }
-            // CTRL+O for open
-            else if ((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control))
-            {
-                if (OnOpenScriptBrowser != null) OnOpenScriptBrowser();
-            }
-            // CTRL+Space to autocomplete
-            else if ((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control))
-            {
-                // Hide call tip if any
-                scriptedit.CallTipCancel();
-
-                // Show autocomplete
-                if (ShowAutoCompletionList()) skiptextinsert = true;
-            }
-            //mxd. Tab to expand code snippet. Do it only when the text cursor is at the end of a keyword.
-            else if (e.KeyCode == Keys.Tab)
-            {
-                if (!scriptedit.AutoCActive)
-                {
-                    string curword = GetCurrentWord().ToLowerInvariant();
-                    if (scriptconfig.Snippets.Contains(curword) && scriptedit.CurrentPosition == scriptedit.WordEndPosition(scriptedit.CurrentPosition, true))
-                    {
-                        InsertSnippet(scriptconfig.GetSnippet(curword));
-                        skiptextinsert = true;
-                    }
-                }
-            }
-            else
-            {
-                //mxd. Skip text insert when "save screenshot" action's keys are pressed
-                Actions.Action[] actions = General.Actions.GetActionsByKey((int)e.KeyData);
-                foreach (Actions.Action action in actions)
-                {
-                    if (action.ShortName == "savescreenshot" || action.ShortName == "saveeditareascreenshot")
-                    {
-                        skiptextinsert = true;
-                        return;
-                    }
-                }
-            }
-        }
-
-        // Key released
-        private void scriptedit_KeyUp(object sender, KeyEventArgs e)
-        {
-            bool showcalltip = false;
-            int highlightstart = 0;
-            int highlightend = 0;
-
-            UpdatePositionInfo();
-
-            // Call tip shown
-            if (scriptedit.CallTipActive)
-            {
-                // Should we hide the call tip?
-                if (curfunctionname.Length == 0)
-                {
-                    // Hide the call tip
-                    scriptedit.CallTipCancel();
-                }
-                else
-                {
-                    // Update the call tip
-                    showcalltip = true;
-                }
-            }
-            // No call tip
-            else
-            {
-                // Should we show a call tip?
-                showcalltip = (curfunctionname.Length > 0) && !scriptedit.AutoCActive;
-            }
-
-            // Show or update call tip
-            if (showcalltip)
-            {
-                string functiondef = scriptconfig.GetFunctionDefinition(curfunctionname);
-                if (functiondef != null)
-                {
-                    // Determine the range to highlight
-                    int argsopenpos = functiondef.IndexOf(scriptconfig.FunctionOpen, StringComparison.Ordinal);
-                    int argsclosepos = functiondef.LastIndexOf(scriptconfig.FunctionClose, StringComparison.Ordinal);
-                    if ((argsopenpos > -1) && (argsclosepos > -1))
-                    {
-                        string argsstr = functiondef.Substring(argsopenpos + 1, argsclosepos - argsopenpos - 1);
-                        string[] args = argsstr.Split(scriptconfig.ArgumentDelimiter[0]);
-                        if ((curargumentindex >= 0) && (curargumentindex < args.Length))
-                        {
-                            int argoffset = 0;
-                            for (int i = 0; i < curargumentindex; i++) argoffset += args[i].Length + 1;
-                            highlightstart = argsopenpos + argoffset + 1;
-                            highlightend = highlightstart + args[curargumentindex].Length;
-                        }
-                    }
-
-                    //mxd. If the tip obscures the view, move it down
-                    int tippos;
-                    int funcline = scriptedit.LineFromPosition(curfunctionstartpos);
-                    if (scriptedit.CurrentLine > funcline)
-                        tippos = scriptedit.Lines[scriptedit.CurrentLine].Position + scriptedit.Lines[scriptedit.CurrentLine].Indentation; //scriptedit.PositionFromLine(curline) /*+ (curfunctionstartpos - scriptedit.PositionFromLine(funcline))*/;
-                    else
-                        tippos = curfunctionstartpos;
-
-                    // Show tip
-                    scriptedit.CallTipShow(tippos, functiondef);
-                    scriptedit.CallTipSetHlt(highlightstart, highlightend);
-                }
-            }
-        }
-
-        #endregion
-    }
-}
\ No newline at end of file
+	internal enum ScriptStyleType
+	{
+		PlainText = 0,
+		Keyword = 1,
+		Constant = 2,
+		Comment = 3,
+		Literal = 4,
+		LineNumber = 5,
+		String = 6, //mxd
+		Include = 7, //mxd
+		Property = 8, //mxd
+	}
+	
+	internal partial class ScriptEditorControl : UserControl
+	{
+		#region ================== Enums
+
+		// Index for registered images
+		private enum ImageIndex
+		{
+			ScriptConstant = 0,
+			ScriptKeyword = 1,
+			ScriptError = 2,
+			ScriptSnippet = 3, //mxd
+			ScriptProperty = 4, //mxd
+		}
+
+		#endregion
+
+		#region ================== Constants
+
+		private const string LEXERS_RESOURCE = "Lexers.cfg";
+		private const int MAX_BACKTRACK_LENGTH = 200;
+		private const int HIGHLIGHT_INDICATOR = 8; //mxd. Indicators 0-7 could be in use by a lexer so we'll use indicator 8 to highlight words.
+		
+		#endregion
+
+		#region ================== Delegates / Events
+
+		public delegate void ExplicitSaveTabDelegate();
+		public delegate void OpenScriptBrowserDelegate();
+		public delegate void OpenFindReplaceDelegate();
+		public delegate void FindNextDelegate();
+		public delegate void FindPreviousDelegate(); //mxd
+
+		public event ExplicitSaveTabDelegate OnExplicitSaveTab;
+		public event OpenScriptBrowserDelegate OnOpenScriptBrowser;
+		public event OpenFindReplaceDelegate OnOpenFindAndReplace;
+		public event FindNextDelegate OnFindNext;
+		public event FindPreviousDelegate OnFindPrevious; //mxd
+		public new event EventHandler OnTextChanged; //mxd
+
+		#endregion
+
+		#region ================== Variables
+		
+		// Script configuration
+		private ScriptConfiguration scriptconfig;
+		
+		// List of keywords and constants
+		private List<string> autocompletelist;
+
+		// Style translation from Scintilla style to ScriptStyleType
+		private Dictionary<int, ScriptStyleType> stylelookup;
+		
+		// Current position information
+		private string curfunctionname = "";
+		private int curargumentindex;
+		private int curfunctionstartpos;
+		private int linenumbercharlength; //mxd. Current max number of chars in the line number
+		private int lastcaretpos; //mxd. Used in brace matching
+		private int caretoffset; //mxd. Used to modify caret position after autogenerating stuff
+		private bool skiptextinsert; //mxd. Gross hacks
+		private bool expandcodeblock; //mxd. More gross hacks
+		private string highlightedword; //mxd
+		private Encoding encoding; //mxd
+		
+		#endregion
+
+		#region ================== Properties
+
+		public bool IsChanged { get { return scriptedit.Modified; } }
+		public int SelectionStart { get { return scriptedit.SelectionStart; } set { scriptedit.SelectionStart = value; } }
+		public int SelectionEnd { get { return scriptedit.SelectionEnd; } set { scriptedit.SelectionEnd = value; } }
+		public new string Text { get { return scriptedit.Text; } set { scriptedit.Text = value; } } //mxd
+		public string SelectedText { get { return scriptedit.SelectedText; } } //mxd
+		public bool ShowWhitespace { get { return scriptedit.ViewWhitespace != WhitespaceMode.Invisible; } set { scriptedit.ViewWhitespace = value ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; } }
+		public bool WrapLongLines { get { return scriptedit.WrapMode != WrapMode.None; } set { scriptedit.WrapMode = (value ? WrapMode.Char : WrapMode.None); } }
+		public ComboBox FunctionBar { get { return functionbar; } } //mxd
+		public Scintilla Scintilla { get { return scriptedit; } } //mxd
+
+		#endregion
+
+		#region ================== Contructor / Disposer
+
+		// Constructor
+		public ScriptEditorControl()
+		{
+			// Initialize
+			InitializeComponent();
+
+			//mxd. ASCII with cyrillic support...
+			encoding = Encoding.GetEncoding(1251);
+			
+			// Script editor properties
+			//TODO: use ScintillaNET properties instead when they become available
+			scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1));
+			scriptedit.DirectMessage(NativeMethods.SCI_SETMOUSEDOWNCAPTURES, new IntPtr(1));
+			scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1));
+
+			// Symbol margin
+			scriptedit.Margins[0].Type = MarginType.Symbol;
+			scriptedit.Margins[0].Width = 20;
+			scriptedit.Margins[0].Mask = 1 << (int)ImageIndex.ScriptError; // Error marker only
+			scriptedit.Margins[0].Cursor = MarginCursor.Arrow;
+			scriptedit.Margins[0].Sensitive = true;
+			
+			// Line numbers margin
+			if(General.Settings.ScriptShowLineNumbers)
+			{
+				scriptedit.Margins[1].Type = MarginType.Number;
+				scriptedit.Margins[1].Width = 16;
+			}
+			scriptedit.Margins[1].Mask = 0; // No markers here
+
+			// Spacing margin
+			scriptedit.Margins[2].Type = MarginType.Symbol;
+			scriptedit.Margins[2].Width = 5;
+			scriptedit.Margins[2].Cursor = MarginCursor.Arrow;
+			scriptedit.Margins[2].Mask = 0; // No markers here
+
+			// Images
+			RegisterAutoCompleteImage(ImageIndex.ScriptConstant, Resources.ScriptConstant);
+			RegisterAutoCompleteImage(ImageIndex.ScriptKeyword, Resources.ScriptKeyword);
+			RegisterAutoCompleteImage(ImageIndex.ScriptSnippet, Resources.ScriptSnippet); //mxd
+			RegisterAutoCompleteImage(ImageIndex.ScriptProperty, Resources.ScriptProperty); //mxd
+			RegisterMarkerImage(ImageIndex.ScriptError, Resources.ScriptError);
+
+			//mxd. These key combinations put odd characters in the script. Let's disable them
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Q, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.W, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.E, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.R, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Y, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.U, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.I, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.P, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.A, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.D, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.G, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.H, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.J, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.K, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.L, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.Z, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.X, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.C, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.V, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.B, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.N, Command.Null);
+			scriptedit.AssignCmdKey(Keys.Control | Keys.M, Command.Null);
+
+			//mxd. These key combinations are used to perform special actions. Let's disable them
+			scriptedit.AssignCmdKey(Keys.F3, Command.Null); // F3 for Find Next
+			scriptedit.AssignCmdKey(Keys.F2, Command.Null); // F2 for Find Previous
+			scriptedit.AssignCmdKey(Keys.Control | Keys.F, Command.Null); // CTRL+F for find & replace
+			scriptedit.AssignCmdKey(Keys.Control | Keys.S, Command.Null); // CTRL+S for save
+			scriptedit.AssignCmdKey(Keys.Control | Keys.O, Command.Null); // CTRL+O for open
+			scriptedit.AssignCmdKey(Keys.Control | Keys.Space, Command.Null); // CTRL+Space to autocomplete <- TODO: this doesn't seem to work...
+		}
+		
+		#endregion
+		
+		#region ================== Public methods
+		
+		// This launches keyword help website
+		public bool LaunchKeywordHelp()
+		{
+			string helpsite = scriptconfig.KeywordHelp;
+			string currentword = GetCurrentWord();
+			if(!string.IsNullOrEmpty(currentword) && (currentword.Length > 1) && !string.IsNullOrEmpty(helpsite))
+			{
+				currentword = scriptconfig.GetKeywordCase(currentword);
+				helpsite = helpsite.Replace("%K", currentword);
+				General.OpenWebsite(helpsite);
+				return true;
+			}
+
+			return !string.IsNullOrEmpty(helpsite); //mxd
+		}
+		
+		// This replaces the selection with the given text
+		public void ReplaceSelection(string replacement)
+		{
+			scriptedit.ReplaceSelection(replacement); //mxd TODO: encoding check/conversion?
+		}
+		
+		// This moves the caret to a given line and ensures the line is visible
+		public void MoveToLine(int linenumber)
+		{
+			scriptedit.Lines[linenumber].Goto();
+			EnsureLineVisible(linenumber);
+		}
+
+		// This makes sure a line is visible
+		public void EnsureLineVisible(int linenumber)
+		{
+			// Determine target lines range
+			int startline = Math.Max(0, linenumber - 4);
+			int endline = Math.Min(scriptedit.Lines.Count, Math.Max(linenumber, linenumber + scriptedit.LinesOnScreen - 6));
+
+			// Go to target line
+			scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed
+			scriptedit.ShowLines(startline, endline);
+
+			// We may want to do some scrolling...
+			if(scriptedit.FirstVisibleLine >= startline)
+				scriptedit.Lines[startline].Goto();
+			else if(scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline)
+				scriptedit.Lines[endline].Goto();
+		}
+
+		//mxd
+		private void SelectAndShow(int startpos, int endpos)
+		{
+			// Select the result
+			int startline = scriptedit.LineFromPosition(startpos);
+			int endline = scriptedit.LineFromPosition(endpos);
+
+			// Go to target line
+			scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed
+			scriptedit.ShowLines(startline, endline);
+			scriptedit.GotoPosition(startpos);
+
+			// We may want to do some extra scrolling...
+			if(startline > 1 && scriptedit.FirstVisibleLine >= startline - 1)
+				scriptedit.Lines[startline - 1].Goto();
+			else if(endline < scriptedit.Lines.Count - 1 && scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline + 1)
+				scriptedit.Lines[endline + 1].Goto();
+
+			// Update selection
+			scriptedit.SelectionStart = startpos;
+			scriptedit.SelectionEnd = endpos;
+		}
+
+		// This returns the line for a position
+		public int LineFromPosition(int position)
+		{
+			return scriptedit.LineFromPosition(position);
+		}
+		
+		// This clears all marks
+		public void ClearMarks()
+		{
+			scriptedit.MarkerDeleteAll((int)ImageIndex.ScriptError);
+		}
+
+		// This adds a mark on the given line
+		public void AddMark(int linenumber)
+		{
+			scriptedit.Lines[linenumber].MarkerAdd((int)ImageIndex.ScriptError);
+		}
+
+		// This refreshes the style setup
+		public void RefreshStyle()
+		{
+			// Re-setup with the same config
+			SetupStyles(scriptconfig);
+		}
+
+		// This sets up the script editor with a script configuration
+		public void SetupStyles(ScriptConfiguration config)
+		{
+			Configuration lexercfg = new Configuration();
+
+			// Make collections
+			stylelookup = new Dictionary<int, ScriptStyleType>();
+			Dictionary<string, string> autocompletedict = new Dictionary<string, string>(StringComparer.Ordinal);
+			
+			// Keep script configuration
+			scriptconfig = config;
+			
+			// Find a resource named Lexers.cfg
+			string[] resnames = General.ThisAssembly.GetManifestResourceNames();
+			foreach(string rn in resnames)
+			{
+				// Found one?
+				if(rn.EndsWith(LEXERS_RESOURCE, StringComparison.OrdinalIgnoreCase))
+				{
+					// Get a stream from the resource
+					Stream lexersdata = General.ThisAssembly.GetManifestResourceStream(rn);
+					if(lexersdata != null)
+					{
+						StreamReader lexersreader = new StreamReader(lexersdata, Encoding.ASCII);
+
+						// Load configuration from stream
+						lexercfg.InputConfiguration(lexersreader.ReadToEnd());
+
+						// Done with the resource
+						lexersreader.Dispose();
+						lexersdata.Dispose();
+					}
+
+					//mxd. We are done here
+					break;
+				}
+			}
+
+			//mxd. Reset document slyle
+			scriptedit.ClearDocumentStyle();
+			scriptedit.StyleResetDefault();
+			
+			// Check if specified lexer exists and set the lexer to use
+			string lexername = "lexer" + (int)scriptconfig.Lexer;
+			if(!lexercfg.SettingExists(lexername)) throw new InvalidOperationException("Unknown lexer " + scriptconfig.Lexer + " specified in script configuration!");
+			scriptedit.Lexer = scriptconfig.Lexer;
+
+			//mxd. Set word chars
+			scriptedit.SetWordChars(scriptconfig.WordCharacters);
+			
+			// Set the default style and settings
+			scriptedit.Styles[Style.Default].Font = General.Settings.ScriptFontName;
+			scriptedit.Styles[Style.Default].Size = General.Settings.ScriptFontSize;
+			scriptedit.Styles[Style.Default].Bold = General.Settings.ScriptFontBold;
+			scriptedit.Styles[Style.Default].Italic = false;
+			scriptedit.Styles[Style.Default].Underline = false;
+			scriptedit.Styles[Style.Default].Case = StyleCase.Mixed;
+			scriptedit.Styles[Style.Default].ForeColor = General.Colors.PlainText.ToColor();
+			scriptedit.Styles[Style.Default].BackColor = General.Colors.ScriptBackground.ToColor();
+			scriptedit.CaretPeriod = SystemInformation.CaretBlinkTime;
+			scriptedit.CaretForeColor = General.Colors.ScriptBackground.Inverse().ToColor();
+			
+			// Set tabulation settings
+			scriptedit.UseTabs = General.Settings.ScriptUseTabs;
+			scriptedit.TabWidth = General.Settings.ScriptTabWidth;
+			//scriptedit.IndentWidth = General.Settings.ScriptTabWidth; // Equals to TabWidth by default
+			//TODO: use ScintillaNET properties instead when they become available
+			scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1));
+			scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1));
+			
+			// This applies the default style to all styles
+			scriptedit.StyleClearAll();
+
+			// Set the code page to use. [mxd] No longer needed?
+			//scriptedit.CodePage = scriptconfig.CodePage;
+
+			//mxd. We can't change Font or Size here because this will screw displayed tab width (because it's based on character width)...
+			// Set the default to something normal (this is used by the autocomplete list)
+			//scriptedit.Styles[Style.Default].Font = this.Font.Name;
+			scriptedit.Styles[Style.Default].Bold = this.Font.Bold;
+			scriptedit.Styles[Style.Default].Italic = this.Font.Italic;
+			scriptedit.Styles[Style.Default].Underline = this.Font.Underline;
+			//scriptedit.Styles[Style.Default].Size = (int)Math.Round(this.Font.SizeInPoints);
+
+			// Set style for linenumbers and margins
+			scriptedit.Styles[Style.LineNumber].BackColor = General.Colors.ScriptBackground.ToColor();
+			scriptedit.SetFoldMarginColor(true, General.Colors.ScriptFoldBackColor.ToColor());
+			scriptedit.SetFoldMarginHighlightColor(true, General.Colors.ScriptFoldBackColor.ToColor());
+			for(int i = 25; i < 32; i++)
+			{
+				scriptedit.Markers[i].SetForeColor(General.Colors.ScriptFoldBackColor.ToColor());
+				scriptedit.Markers[i].SetBackColor(General.Colors.ScriptFoldForeColor.ToColor());
+			}
+ 
+			//mxd. Set style for (mis)matching braces
+			scriptedit.Styles[Style.BraceLight].BackColor = General.Colors.ScriptBraceHighlight.ToColor();
+			scriptedit.Styles[Style.BraceBad].BackColor = General.Colors.ScriptBadBraceHighlight.ToColor();
+
+			//mxd. Set whitespace color
+			scriptedit.SetWhitespaceForeColor(true, General.Colors.ScriptWhitespace.ToColor());
+
+			//mxd. Set selection colors
+			scriptedit.SetSelectionForeColor(true, General.Colors.ScriptSelectionForeColor.ToColor());
+			scriptedit.SetSelectionBackColor(true, General.Colors.ScriptSelectionBackColor.ToColor());
+
+			// Clear all keywords
+			for(int i = 0; i < 9; i++) scriptedit.SetKeywords(i, null);
+			
+			// Now go for all elements in the lexer configuration
+			// We are looking for the numeric keys, because these are the
+			// style index to set and the value is our ScriptStyleType
+			IDictionary dic = lexercfg.ReadSetting(lexername, new Hashtable());
+			foreach(DictionaryEntry de in dic)
+			{
+				// Check if this is a numeric key
+				int stylenum;
+				if(int.TryParse(de.Key.ToString(), out stylenum))
+				{
+					// Add style to lookup table
+					stylelookup.Add(stylenum, (ScriptStyleType)(int)de.Value);
+					
+					// Apply color to style
+					int colorindex;
+					ScriptStyleType type = (ScriptStyleType)(int)de.Value;
+					switch(type)
+					{
+						case ScriptStyleType.PlainText: colorindex = ColorCollection.PLAINTEXT; break;
+						case ScriptStyleType.Comment: colorindex = ColorCollection.COMMENTS; break;
+						case ScriptStyleType.Constant: colorindex = ColorCollection.CONSTANTS; break;
+						case ScriptStyleType.Keyword: colorindex = ColorCollection.KEYWORDS; break;
+						case ScriptStyleType.LineNumber: colorindex = ColorCollection.LINENUMBERS; break;
+						case ScriptStyleType.Literal: colorindex = ColorCollection.LITERALS; break;
+						case ScriptStyleType.String: colorindex = ColorCollection.STRINGS; break;
+						case ScriptStyleType.Include: colorindex = ColorCollection.INCLUDES; break;
+						case ScriptStyleType.Property: colorindex = ColorCollection.PROPERTIES; break;
+						default: colorindex = ColorCollection.PLAINTEXT; break;
+					}
+
+					scriptedit.Styles[stylenum].ForeColor = General.Colors.Colors[colorindex].ToColor();
+				}
+			}
+			
+			// Create the keywords list and apply it
+			string imageindex = ((int)ImageIndex.ScriptKeyword).ToString(CultureInfo.InvariantCulture);
+			int keywordsindex = lexercfg.ReadSetting(lexername + ".keywordsindex", -1);
+			if(keywordsindex > -1)
+			{
+				StringBuilder keywordslist = new StringBuilder();
+				foreach(string k in scriptconfig.Keywords)
+				{
+					if(keywordslist.Length > 0) keywordslist.Append(" ");
+					keywordslist.Append(k);
+
+					//mxd. Skip adding the keyword if we have a snippet with the same name
+					if(!scriptconfig.Snippets.Contains(k))
+						autocompletedict.Add(k, k + "?" + imageindex);
+				}
+				string words = keywordslist.ToString();
+				scriptedit.SetKeywords(keywordsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
+			}
+
+			//mxd. Create the properties list and apply it
+			imageindex = ((int)ImageIndex.ScriptProperty).ToString(CultureInfo.InvariantCulture);
+			int propertiesindex = lexercfg.ReadSetting(lexername + ".propertiesindex", -1);
+			if(propertiesindex > -1)
+			{
+				StringBuilder propertieslist = new StringBuilder();
+				HashSet<string> addedprops = new HashSet<string>();
+				char[] dot = {'.'};
+				foreach(string p in scriptconfig.Properties)
+				{
+					if(propertieslist.Length > 0) propertieslist.Append(" ");
+
+					// Scintilla doesn't highlight keywords with '.' or ':', so get rid of those 
+					if(scriptconfig.ScriptType == ScriptType.DECORATE)
+					{
+						string prop = p;
+						if(prop.Contains(":")) prop = prop.Replace(":", string.Empty);
+						if(prop.Contains("."))
+						{
+							// Split dotted properties into separate entries
+							string[] parts = prop.Split(dot, StringSplitOptions.RemoveEmptyEntries);
+							List<string> result = new List<string>();
+							foreach(string part in parts)
+							{
+								if(!addedprops.Contains(part))
+								{
+									result.Add(part);
+									addedprops.Add(part);
+								}
+							}
+
+							if(result.Count > 0) propertieslist.Append(string.Join(" ", result.ToArray()));
+						}
+						else
+						{
+							addedprops.Add(prop);
+							propertieslist.Append(prop);
+						}
+					}
+					else
+					{
+						propertieslist.Append(p);
+					}
+
+					// Autocomplete doesn't mind '.' or ':'
+					// Skip adding the keyword if we have a snippet with the same name
+					if(!scriptconfig.Snippets.Contains(p))
+						autocompletedict.Add(p, p + "?" + imageindex);
+				}
+				string words = propertieslist.ToString();
+				scriptedit.SetKeywords(propertiesindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
+			}
+
+			// Create the constants list and apply it
+			imageindex = ((int)ImageIndex.ScriptConstant).ToString(CultureInfo.InvariantCulture);
+			int constantsindex = lexercfg.ReadSetting(lexername + ".constantsindex", -1);
+			if(constantsindex > -1)
+			{
+				StringBuilder constantslist = new StringBuilder();
+				foreach(string c in scriptconfig.Constants)
+				{
+					if(autocompletedict.ContainsKey(c)) continue; //mxd. This happens when there's a keyword and a constant with the same name...
+					
+					if(constantslist.Length > 0) constantslist.Append(" ");
+					constantslist.Append(c);
+
+					//mxd. Skip adding the constant if we have a snippet with the same name
+					if(!scriptconfig.Snippets.Contains(c))
+						autocompletedict.Add(c, c + "?" + imageindex);
+				}
+				string words = constantslist.ToString();
+				scriptedit.SetKeywords(constantsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
+			}
+
+			//mxd. Create the snippets list and apply it
+			imageindex = ((int)ImageIndex.ScriptSnippet).ToString(CultureInfo.InvariantCulture);
+			int snippetindex = lexercfg.ReadSetting(lexername + ".snippetindex", -1);
+			if(snippetindex > -1 && scriptconfig.Snippets.Count > 0) 
+			{
+				StringBuilder snippetslist = new StringBuilder();
+				foreach(string s in scriptconfig.Snippets) 
+				{
+					if(snippetslist.Length > 0) snippetslist.Append(" ");
+					snippetslist.Append(s);
+					autocompletedict.Add(s, s + "?" + imageindex);
+				}
+				string words = snippetslist.ToString();
+				scriptedit.SetKeywords(snippetindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant()));
+			}
+			
+			// Make autocomplete list
+			autocompletelist = new List<string>(autocompletedict.Values);
+
+			// Setup folding (https://github.com/jacobslusser/ScintillaNET/wiki/Automatic-Code-Folding)
+			if(General.Settings.ScriptShowFolding && (scriptconfig.Lexer == Lexer.Cpp || scriptconfig.Lexer == Lexer.CppNoCase))
+			{
+				// Instruct the lexer to calculate folding
+				scriptedit.SetProperty("fold", "1");
+				scriptedit.SetProperty("fold.compact", "0"); // 1 = folds blank lines
+				scriptedit.SetProperty("fold.comment", "1"); // Enable block comment folding
+				scriptedit.SetProperty("fold.preprocessor", "1"); // Enable #region folding
+				scriptedit.SetFoldFlags(FoldFlags.LineAfterContracted); // Draw line below if not expanded
+
+				// Configure a margin to display folding symbols
+				scriptedit.Margins[2].Type = MarginType.Symbol;
+				scriptedit.Margins[2].Mask = Marker.MaskFolders;
+				scriptedit.Margins[2].Sensitive = true;
+				scriptedit.Margins[2].Width = 12;
+
+				// Configure folding markers with respective symbols
+				scriptedit.Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus;
+				scriptedit.Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus;
+				scriptedit.Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected;
+				scriptedit.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner;
+				scriptedit.Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected;
+				scriptedit.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine;
+				scriptedit.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner;
+
+				// Enable automatic folding
+				scriptedit.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change);
+			}
+			else
+			{
+				// Disable folding
+				scriptedit.SetProperty("fold", "0");
+				scriptedit.SetProperty("fold.compact", "0");
+
+				scriptedit.Margins[2].Type = MarginType.Symbol;
+				scriptedit.Margins[2].Mask = 0; // No markers here
+				scriptedit.Margins[2].Sensitive = false;
+				scriptedit.Margins[2].Width = 5;
+
+				scriptedit.AutomaticFold = AutomaticFold.None;
+			}
+
+			// Rearrange the layout
+			this.PerformLayout();
+		}
+		
+		// This returns the current word (where the caret is at)
+		public string GetCurrentWord()
+		{
+			return GetWordAt(scriptedit.CurrentPosition);
+		}
+
+		// This returns the word at the given position
+		public string GetWordAt(int position)
+		{
+			return scriptedit.GetWordFromPosition(position);
+		}
+
+		// Perform undo
+		public void Undo()
+		{
+			scriptedit.Undo();
+		}
+
+		// Perform redo
+		public void Redo()
+		{
+			scriptedit.Redo();
+		}
+
+		// This clears all undo levels
+		public void ClearUndoRedo()
+		{
+			scriptedit.EmptyUndoBuffer();
+		}
+
+		//mxd. This marks the current document as unmodified
+		public void SetSavePoint()
+		{
+			scriptedit.SetSavePoint();
+		}
+
+		// Perform cut
+		public void Cut()
+		{
+			scriptedit.Cut();
+		}
+
+		// Perform copy
+		public void Copy()
+		{
+			scriptedit.Copy();
+		}
+
+		// Perform paste
+		public void Paste()
+		{
+			scriptedit.Paste();
+		}
+		
+		// This steals the focus (use with care!)
+		public void GrabFocus()
+		{
+			scriptedit.Focus();
+		}
+
+		public byte[] GetText()
+		{
+			return encoding.GetBytes(scriptedit.Text); //mxd TODO: other encodings?..
+		}
+
+		public void SetText(byte[] text)
+		{
+			scriptedit.Text = encoding.GetString(text); //mxd TODO: other encodings?..
+		}
+
+		//mxd
+		public void InsertSnippet(string[] lines) 
+		{
+			// Insert the snippet
+			int curline = scriptedit.LineFromPosition(scriptedit.SelectionStart);
+			int indent = scriptedit.Lines[scriptedit.CurrentLine].Indentation;
+			string tabs = Environment.NewLine + GetIndentationString(indent);
+			string spaces = new String(' ', General.Settings.ScriptTabWidth);
+			int entrypos = -1;
+			int entryline = -1;
+			string[] processedlines = ProcessLineBreaks(lines);
+
+			// Process special chars, try to find entry position marker
+			for(int i = 0; i < lines.Length; i++) 
+			{
+				if(!scriptedit.UseTabs) processedlines[i] = processedlines[i].Replace("\t", spaces);
+
+				// Check if we have the [EP] marker
+				if(entrypos == -1) 
+				{
+					int pos = processedlines[i].IndexOf("[EP]", StringComparison.Ordinal);
+					if(pos != -1) 
+					{
+						processedlines[i] = processedlines[i].Remove(pos, 4);
+						entryline = curline + i;
+						entrypos = processedlines[i].Length - pos;
+					}
+				}
+			}
+
+			// Replace the text
+			string text = string.Join(tabs, processedlines);
+			scriptedit.SelectionStart = scriptedit.WordStartPosition(scriptedit.CurrentPosition, true);
+			scriptedit.SelectionEnd = scriptedit.WordEndPosition(scriptedit.CurrentPosition, true);
+			scriptedit.ReplaceSelection(text);
+
+			// Move the cursor if we had the [EP] marker
+			if(entrypos != -1) 
+			{
+				scriptedit.SetEmptySelection(scriptedit.Lines[entryline].EndPosition - entrypos - 2);
+			}
+		}
+
+		//mxd. Find next result
+		public bool FindNext(FindReplaceOptions options, bool useselectionstart)
+		{
+			int startpos = (useselectionstart ? Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) : Math.Max(scriptedit.SelectionStart, scriptedit.SelectionEnd));
+
+			// Search the document
+			scriptedit.TargetStart = startpos;
+			scriptedit.TargetEnd = scriptedit.TextLength;
+			scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None;
+			if(options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord;
+
+			int result = scriptedit.SearchInTarget(options.FindText);
+			
+			// Wrap around?
+			if(result == -1)
+			{
+				scriptedit.TargetStart = 0;
+				scriptedit.TargetEnd = startpos;
+				result = scriptedit.SearchInTarget(options.FindText);
+			}
+
+			// Found something
+			if(result != -1)
+			{
+				// Select the result
+				SelectAndShow(result, result + options.FindText.Length);
+
+				// Update extra highlights
+				HighlightWord(options.FindText);
+
+				// All done
+				return true;
+			}
+
+			// Nothing found...
+			return false;
+		}
+
+		//mxd. Find previous result
+		public bool FindPrevious(FindReplaceOptions options)
+		{
+			int endpos = Math.Max(0, Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) - 1);
+
+			// Search the document
+			scriptedit.TargetStart = endpos;
+			scriptedit.TargetEnd = 0;
+			scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None;
+			if(options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord;
+
+			int result = scriptedit.SearchInTarget(options.FindText);
+
+			// Wrap around?
+			if(result == -1)
+			{
+				scriptedit.TargetStart = scriptedit.TextLength;
+				scriptedit.TargetEnd = endpos;
+				result = scriptedit.SearchInTarget(options.FindText);
+			}
+
+			// Found something
+			if(result != -1)
+			{
+				// Select the result
+				SelectAndShow(result, result + options.FindText.Length);
+
+				// Update extra highlights
+				HighlightWord(options.FindText);
+
+				// All done
+				return true;
+			}
+
+			// Nothing found...
+			return false;
+		}
+
+		//mxd. (Un)indents selection
+		public void IndentSelection(bool indent)
+		{
+			// Get selected range of lines
+			int startline = scriptedit.LineFromPosition(scriptedit.SelectionStart);
+			int endline = scriptedit.LineFromPosition(scriptedit.SelectionEnd);
+
+			for(int i = startline; i < endline + 1; i++)
+			{
+				scriptedit.Lines[i].Indentation += (indent ? General.Settings.ScriptTabWidth : -General.Settings.ScriptTabWidth);
+			}
+		}
+
+		#endregion
+
+		#region ================== Utility methods
+
+		// This returns the ScriptStyleType for a given Scintilla style
+		private ScriptStyleType GetScriptStyle(int scintillastyle)
+		{
+			return (stylelookup.ContainsKey(scintillastyle) ? stylelookup[scintillastyle] : ScriptStyleType.PlainText);
+		}
+		
+		// This gathers information about the current caret position
+		private void UpdatePositionInfo()
+		{
+			int bracketlevel = 0;			// bracket level counting
+			int argindex = 0;				// function argument counting
+			int pos = scriptedit.CurrentPosition;
+
+			// Get the text
+			string scripttext = scriptedit.Text;
+
+			// Reset position info
+			curfunctionname = "";
+			curargumentindex = 0;
+			curfunctionstartpos = 0;
+			
+			// Determine lowest backtrack position
+			int limitpos = scriptedit.CurrentPosition - MAX_BACKTRACK_LENGTH;
+			if(limitpos < 0) limitpos = 0;
+			
+			// We can only do this when we have function syntax information
+			if((scriptconfig.ArgumentDelimiter.Length == 0) || (scriptconfig.FunctionClose.Length == 0) ||
+			   (scriptconfig.FunctionOpen.Length == 0) || (scriptconfig.Terminator.Length == 0)) return;
+			
+			// Get int versions of the function syntax informantion
+			int argumentdelimiter = scriptconfig.ArgumentDelimiter[0];
+			int functionclose = scriptconfig.FunctionClose[0];
+			int functionopen = scriptconfig.FunctionOpen[0];
+			int terminator = scriptconfig.Terminator[0];
+			
+			// Continue backtracking until we reached the limitpos
+			while(pos >= limitpos)
+			{
+				// Backtrack 1 character
+				pos--;
+				
+				// Get the style and character at this position
+				ScriptStyleType curstyle = GetScriptStyle(scriptedit.GetStyleAt(pos));
+				int curchar = scriptedit.GetCharAt(pos);
+				
+				// Then meeting ) then increase bracket level
+				// When meeting ( then decrease bracket level
+				// When bracket level goes -1, then the next word should be the function name
+				// Only when at bracket level 0, count the comma's for argument index
+				
+				// TODO:
+				// Original code checked for scope character here and breaks if found
+				
+				// Check if in plain text or keyword
+				if((curstyle == ScriptStyleType.PlainText) || (curstyle == ScriptStyleType.Keyword))
+				{
+					// Closing bracket
+					if(curchar == functionclose)
+					{
+						bracketlevel++;
+					}
+					// Opening bracket
+					else if(curchar == functionopen)
+					{
+						bracketlevel--;
+						
+						// Out of the brackets?
+						if(bracketlevel < 0)
+						{
+							// Skip any whitespace before this bracket
+							do
+							{
+								// Backtrack 1 character
+								curchar = scriptedit.GetCharAt(--pos);
+							}
+							while((pos >= limitpos) && ((curchar == ' ') || (curchar == '\t') ||
+														(curchar == '\r') || (curchar == '\n')));
+							
+							// NOTE: We may need to set onlyWordCharacters argument in the
+							// following calls to false to get any argument delimiter included,
+							// but this may also cause a valid keyword to be combined with other
+							// surrounding characters that do not belong to the keyword.
+							
+							// Find the word before this bracket
+							int wordstart = scriptedit.WordStartPosition(pos, true);
+							int wordend = scriptedit.WordEndPosition(pos, true);
+							string word = scripttext.Substring(wordstart, wordend - wordstart);
+							if(word.Length > 0)
+							{
+								// Check if this is an argument delimiter
+								// I can't remember why I did this, but I'll probably stumble
+								// upon the problem if this doesn't work right (see note above)
+								if(word[0] == argumentdelimiter)
+								{
+									// We are now in the parent function
+									bracketlevel++;
+									argindex = 0;
+								}
+								// Now check if this is a keyword
+								else if(scriptconfig.IsKeyword(word))
+								{
+									// Found it!
+									curfunctionname = scriptconfig.GetKeywordCase(word);
+									curargumentindex = argindex;
+									curfunctionstartpos = wordstart;
+									break;
+								}
+								else
+								{
+									// Don't know this word
+									break;
+								}
+							}
+						}
+					}
+					// Argument delimiter
+					else if(curchar == argumentdelimiter)
+					{
+						// Only count these at brackt level 0
+						if(bracketlevel == 0) argindex++;
+					}
+					// Terminator
+					else if(curchar == terminator)
+					{
+						// Can't find anything, break now
+						break;
+					}
+				}
+			}
+		}
+		
+		// This registers an image for the autocomplete list
+		private void RegisterAutoCompleteImage(ImageIndex index, Bitmap image)
+		{
+			// Register image
+			scriptedit.RegisterRgbaImage((int)index, image);
+		}
+
+		// This registers an image for the markes list
+		private void RegisterMarkerImage(ImageIndex index, Bitmap image)
+		{
+			// Register image
+			scriptedit.Markers[(int)index].DefineRgbaImage(image);
+			scriptedit.Markers[(int)index].Symbol = MarkerSymbol.RgbaImage;
+		}
+
+		//mxd. This converts [LB] markers to line breaks if necessary
+		private static string[] ProcessLineBreaks(string[] lines) 
+		{
+			List<string> result = new List<string>(lines.Length);
+			string[] separator = new[] { "[LB]" };
+
+			foreach(string line in lines) 
+			{
+				if(line.IndexOf(separator[0], StringComparison.Ordinal) != -1) 
+				{
+					if(General.Settings.ScriptAllmanStyle)
+						result.AddRange(line.Split(separator, StringSplitOptions.RemoveEmptyEntries));
+					else
+						result.Add(line.Replace(separator[0], " "));
+				} 
+				else 
+				{
+					result.Add(line);
+				}
+			}
+
+			return result.ToArray();
+		}
+
+		//mxd. Autocompletion handling (https://github.com/jacobslusser/ScintillaNET/wiki/Basic-Autocompletion)
+		private bool ShowAutoCompletionList()
+		{
+			int currentpos = scriptedit.CurrentPosition;
+			int wordstartpos = scriptedit.WordStartPosition(currentpos, true);
+
+			if(wordstartpos >= currentpos)
+			{
+				// Hide the list
+				scriptedit.AutoCCancel();
+				return false;
+			}
+
+			// Get entered text
+			string start = scriptedit.GetTextRange(wordstartpos, currentpos - wordstartpos);
+			if(string.IsNullOrEmpty(start))
+			{
+				// Hide the list
+				scriptedit.AutoCCancel();
+				return false;
+			}
+
+			// Don't show Auto-completion list when editing comment, include or string
+			switch(GetScriptStyle(scriptedit.GetStyleAt(currentpos)))
+			{
+				case ScriptStyleType.Comment:
+				case ScriptStyleType.String:
+				case ScriptStyleType.Include:
+					// Hide the list
+					scriptedit.AutoCCancel();
+					return false;
+			}
+
+			// Filter the list
+			List<string> filtered = new List<string>();
+			foreach(string s in autocompletelist)
+				if(s.IndexOf(start, StringComparison.OrdinalIgnoreCase) != -1) filtered.Add(s);
+
+			// Any matches?
+			if(filtered.Count > 0)
+			{
+				// Show the list
+				scriptedit.AutoCShow(currentpos - wordstartpos, string.Join(" ", filtered.ToArray()));
+				return true;
+			}
+
+			// Hide the list
+			scriptedit.AutoCCancel();
+			return false;
+		}
+
+		//mxd
+		private string GetIndentationString(int indent)
+		{
+			if(scriptedit.UseTabs)
+			{
+				string indentstr = string.Empty;
+				int numtabs = indent / scriptedit.TabWidth;
+				if(numtabs > 0) indentstr = new string('\t', numtabs);
+
+				// Mixed padding? Add spaces
+				if(numtabs * scriptedit.TabWidth < indent)
+				{
+					int numspaces = indent - numtabs * scriptedit.TabWidth;
+					indentstr += new string(' ', numspaces);
+				}
+
+				return indentstr;
+			}
+			else
+			{
+				return new string(' ', indent);
+			}
+		}
+
+		//mxd. https://github.com/jacobslusser/ScintillaNET/wiki/Find-and-Highlight-Words
+		private void HighlightWord(string text)
+		{
+			// Remove all uses of our indicator
+			scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR;
+			scriptedit.IndicatorClearRange(0, scriptedit.TextLength);
+
+			// Update indicator appearance
+			scriptedit.Indicators[HIGHLIGHT_INDICATOR].Style = IndicatorStyle.RoundBox;
+			scriptedit.Indicators[HIGHLIGHT_INDICATOR].Under = true;
+			scriptedit.Indicators[HIGHLIGHT_INDICATOR].ForeColor = General.Colors.ScriptIndicator.ToColor();
+			scriptedit.Indicators[HIGHLIGHT_INDICATOR].OutlineAlpha = 50;
+			scriptedit.Indicators[HIGHLIGHT_INDICATOR].Alpha = 30;
+
+			// Search the document
+			scriptedit.TargetStart = 0;
+			scriptedit.TargetEnd = scriptedit.TextLength;
+			scriptedit.SearchFlags = SearchFlags.WholeWord;
+
+			while(scriptedit.SearchInTarget(text) != -1)
+			{
+				//mxd. Don't mark currently selected word
+				if(scriptedit.SelectionStart != scriptedit.TargetStart && scriptedit.SelectionEnd != scriptedit.TargetEnd)
+				{
+					// Mark the search results with the current indicator
+					scriptedit.IndicatorFillRange(scriptedit.TargetStart, scriptedit.TargetEnd - scriptedit.TargetStart);
+				}
+
+				// Search the remainder of the document
+				scriptedit.TargetStart = scriptedit.TargetEnd;
+				scriptedit.TargetEnd = scriptedit.TextLength;
+			}
+		}
+
+		#endregion
+		
+		#region ================== Events
+		
+		// Layout needs to be re-organized
+		protected override void OnLayout(LayoutEventArgs e)
+		{
+			base.OnLayout(e);
+
+			// With or without functions bar?
+			if(functionbar.Visible)
+			{
+				scriptpanel.Top = functionbar.Bottom + 6;
+				scriptpanel.Height = this.ClientSize.Height - scriptpanel.Top;
+			}
+			else
+			{
+				scriptpanel.Top = 0;
+				scriptpanel.Height = this.ClientSize.Height;
+			}
+		}
+
+		//mxd. Script text changed
+		private void scriptedit_TextChanged(object sender, EventArgs e)
+		{
+			// Line number margin width needs changing?
+			int curlinenumbercharlength = scriptedit.Lines.Count.ToString().Length;
+
+			// Calculate the width required to display the last line number
+			// and include some padding for good measure.
+			if(curlinenumbercharlength != linenumbercharlength)
+			{
+				const int padding = 2;
+				scriptedit.Margins[1].Width = scriptedit.TextWidth(Style.LineNumber, new string('9', curlinenumbercharlength + 1)) + padding;
+				linenumbercharlength = curlinenumbercharlength;
+			}
+			
+			if(OnTextChanged != null) OnTextChanged(this, EventArgs.Empty);
+		}
+
+		//mxd
+		private void scriptedit_CharAdded(object sender, CharAddedEventArgs e)
+		{
+			// Hide call tip if any
+			scriptedit.CallTipCancel();
+
+			// Offset caret if needed
+			if(caretoffset != 0)
+			{
+				scriptedit.SetEmptySelection(scriptedit.SelectionStart + caretoffset);
+				caretoffset = 0;
+				if(!expandcodeblock) return;
+			}
+
+			// Move CodeBlockOpen to the new line?
+			if(expandcodeblock)
+			{
+				if(scriptedit.CurrentLine > 0)
+				{
+					string linetext = scriptedit.Lines[scriptedit.CurrentLine - 1].Text;
+					int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, StringComparison.Ordinal));
+					if(blockopenpos != -1)
+					{
+						// Do it only if initial line doesn't start with CodeBlockOpen
+						string linestart = linetext.Substring(0, blockopenpos).Trim();
+						if(linestart.Length > 0)
+						{
+							scriptedit.InsertText(scriptedit.Lines[scriptedit.CurrentLine - 1].Position + blockopenpos, 
+								Environment.NewLine + GetIndentationString(scriptedit.Lines[scriptedit.CurrentLine - 1].Indentation));
+						}
+					}
+				}
+
+				expandcodeblock = false;
+				return;
+			}
+
+			// Auto-match braces
+			if(General.Settings.ScriptAutoCloseBrackets)
+			{
+				//TODO: Auto-match quotes
+				bool endpos = (scriptedit.CurrentPosition == scriptedit.TextLength);
+				if(!string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) && e.Char == scriptconfig.CodeBlockOpen[0] && !string.IsNullOrEmpty(scriptconfig.CodeBlockClose) &&
+					(endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.CodeBlockClose[0]))
+				{
+					scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.CodeBlockClose);
+					return;
+				}
+				
+				if(!string.IsNullOrEmpty(scriptconfig.FunctionOpen) && e.Char == scriptconfig.FunctionOpen[0] && !string.IsNullOrEmpty(scriptconfig.FunctionClose) &&
+					(endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.FunctionClose[0]))
+				{
+					scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.FunctionClose);
+					return;
+				}
+				
+				if(!string.IsNullOrEmpty(scriptconfig.ArrayOpen) && e.Char == scriptconfig.ArrayOpen[0] && !string.IsNullOrEmpty(scriptconfig.ArrayClose) &&
+					(endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.ArrayClose[0]))
+				{
+					scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.ArrayClose);
+					return;
+				}
+			}
+
+			if(General.Settings.ScriptAutoShowAutocompletion)
+			{
+				// Display the autocompletion list
+				ShowAutoCompletionList();
+			}
+		}
+
+		//mxd
+		private void scriptedit_UpdateUI(object sender, UpdateUIEventArgs e)
+		{
+			// If a word is selected, highlight the same words
+			if(scriptedit.SelectedText != highlightedword)
+			{
+				// Highlight only when whole word is selected
+				if(!string.IsNullOrEmpty(scriptedit.SelectedText) && scriptedit.GetWordFromPosition(scriptedit.SelectionStart) == scriptedit.SelectedText)
+				{
+					HighlightWord(scriptedit.SelectedText);
+				}
+				else
+				{
+					// Clear highlight
+					scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR;
+					scriptedit.IndicatorClearRange(0, scriptedit.TextLength);
+				}
+
+				highlightedword = scriptedit.SelectedText;
+			}
+			
+			// Has the caret changed position?
+			int caretpos = scriptedit.CurrentPosition;
+			if(lastcaretpos != caretpos && scriptconfig.BraceChars.Count > 0)
+			{
+				// Perform brace matching (https://github.com/jacobslusser/ScintillaNET/wiki/Brace-Matching)
+				lastcaretpos = caretpos;
+				int bracepos1 = -1;
+
+				// Is there a brace to the left or right?
+				if(caretpos > 0 && scriptconfig.BraceChars.Contains((char)scriptedit.GetCharAt(caretpos - 1)))
+					bracepos1 = (caretpos - 1);
+				else if(scriptconfig.BraceChars.Contains((char)(scriptedit.GetCharAt(caretpos))))
+					bracepos1 = caretpos;
+
+				if(bracepos1 > -1)
+				{
+					// Find the matching brace
+					int bracepos2 = scriptedit.BraceMatch(bracepos1);
+					if(bracepos2 == Scintilla.InvalidPosition)
+						scriptedit.BraceBadLight(bracepos1);
+					else
+						scriptedit.BraceHighlight(bracepos1, bracepos2);
+				}
+				else
+				{
+					// Turn off brace matching
+					scriptedit.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition);
+				}
+			}
+		}
+
+		//mxd
+		private void scriptedit_InsertCheck(object sender, InsertCheckEventArgs e)
+		{
+			// Gross hacks...
+			if(skiptextinsert)
+			{
+				e.Text = string.Empty;
+				skiptextinsert = false;
+			}
+			// Do we want auto-indentation?
+			else if(!expandcodeblock && General.Settings.ScriptAutoIndent && e.Text == "\r\n")
+			{
+				// Get current line indentation up to the cursor position
+				string linetext = scriptedit.Lines[scriptedit.CurrentLine].Text;
+				int selectionpos = scriptedit.SelectionStart - scriptedit.Lines[scriptedit.CurrentLine].Position;
+				int indent = 0;
+				for(int i = 0; i < selectionpos; i++)
+				{
+					switch(linetext[i])
+					{
+						case  ' ': indent++; break;
+						case '\t': indent += scriptedit.TabWidth; break;
+						default: i = selectionpos; break; // break the loop
+					}
+				}
+
+				// Store initial indentation
+				int initialindent = indent;
+
+				// Need to increase indentation? We do this when:
+				// 1. Line contains '{' and '}' and the cursor is between them
+				// 2. Line either doesn't contain '}', or it's before '{', or the line contains '{' and the cursor is after it 
+				int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, selectionpos, StringComparison.Ordinal));
+				int blockclosepos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.IndexOf(scriptconfig.CodeBlockClose, selectionpos, StringComparison.Ordinal));
+
+				// Add indentation when the cursor is between { and }
+				bool addindent = (blockopenpos != -1 && blockopenpos < selectionpos) && (blockclosepos == -1 || (blockopenpos < blockclosepos && blockclosepos >= selectionpos));
+				if(addindent) indent += scriptedit.TabWidth;
+
+				// Calculate indentation
+				string indentstr = GetIndentationString(indent);
+
+				// Move CodeBlockOpen to the new line? (will be applied in scriptedit_CharAdded)
+				expandcodeblock = General.Settings.ScriptAllmanStyle;
+
+				// Offset closing block char?
+				if(addindent && blockclosepos != -1)
+				{
+					string initialindentstr = GetIndentationString(initialindent);
+					indentstr += Environment.NewLine + initialindentstr;
+					
+					// Offset cursor position (will be performed in scriptedit_CharAdded)
+					caretoffset = -(initialindentstr.Length + Environment.NewLine.Length);
+				}
+
+				// Apply new indentation
+				e.Text += indentstr;
+			}
+		}
+
+		//mxd
+		private void scriptedit_AutoCCompleted(object sender, AutoCSelectionEventArgs e)
+		{
+			// Expand snippet?
+			string[] lines = scriptconfig.GetSnippet(e.Text);
+			if(lines != null) InsertSnippet(lines);
+		}
+		
+		// Key pressed down
+		private void scriptedit_KeyDown(object sender, KeyEventArgs e)
+		{
+			// F3 for Find Next
+			if((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None))
+			{
+				if(OnFindNext != null) OnFindNext();
+			}
+			// F2 for Find Previous (mxd)
+			else if((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None))
+			{
+				if(OnFindPrevious != null) OnFindPrevious();
+			}
+			// CTRL+F for find & replace
+			else if((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control))
+			{
+				if(OnOpenFindAndReplace != null) OnOpenFindAndReplace();
+			}
+			// CTRL+S for save
+			else if((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control))
+			{
+				if(OnExplicitSaveTab != null) OnExplicitSaveTab();
+			}
+			// CTRL+O for open
+			else if((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control))
+			{
+				if(OnOpenScriptBrowser != null) OnOpenScriptBrowser();
+			}
+			// CTRL+Space to autocomplete
+			else if((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control))
+			{
+				// Hide call tip if any
+				scriptedit.CallTipCancel();
+				
+				// Show autocomplete
+				if(ShowAutoCompletionList()) skiptextinsert = true;
+			}
+			//mxd. Tab to expand code snippet. Do it only when the text cursor is at the end of a keyword.
+			else if(e.KeyCode == Keys.Tab)
+			{
+				if(!scriptedit.AutoCActive)
+				{
+					string curword = GetCurrentWord().ToLowerInvariant();
+					if(scriptconfig.Snippets.Contains(curword) && scriptedit.CurrentPosition == scriptedit.WordEndPosition(scriptedit.CurrentPosition, true))
+					{
+						InsertSnippet(scriptconfig.GetSnippet(curword));
+						skiptextinsert = true;
+					}
+				}
+			}
+			else
+			{
+				//mxd. Skip text insert when "save screenshot" action's keys are pressed
+				Actions.Action[] actions = General.Actions.GetActionsByKey((int)e.KeyData);
+				foreach(Actions.Action action in actions)
+				{
+					if(action.ShortName == "savescreenshot" || action.ShortName == "saveeditareascreenshot")
+					{
+						skiptextinsert = true;
+						return;
+					}
+				}
+			}
+		}
+		
+		// Key released
+		private void scriptedit_KeyUp(object sender, KeyEventArgs e)
+		{
+			bool showcalltip = false;
+			int highlightstart = 0;
+			int highlightend = 0;
+			
+			UpdatePositionInfo();
+			
+			// Call tip shown
+			if(scriptedit.CallTipActive)
+			{
+				// Should we hide the call tip?
+				if(curfunctionname.Length == 0)
+				{
+					// Hide the call tip
+					scriptedit.CallTipCancel();
+				}
+				else
+				{
+					// Update the call tip
+					showcalltip = true;
+				}
+			}
+			// No call tip
+			else
+			{
+				// Should we show a call tip?
+				showcalltip = (curfunctionname.Length > 0) && !scriptedit.AutoCActive;
+			}
+			
+			// Show or update call tip
+			if(showcalltip)
+			{
+				string functiondef = scriptconfig.GetFunctionDefinition(curfunctionname);
+				if(functiondef != null)
+				{
+					// Determine the range to highlight
+					int argsopenpos = functiondef.IndexOf(scriptconfig.FunctionOpen, StringComparison.Ordinal);
+					int argsclosepos = functiondef.LastIndexOf(scriptconfig.FunctionClose, StringComparison.Ordinal);
+					if((argsopenpos > -1) && (argsclosepos > -1))
+					{
+						string argsstr = functiondef.Substring(argsopenpos + 1, argsclosepos - argsopenpos - 1);
+						string[] args = argsstr.Split(scriptconfig.ArgumentDelimiter[0]);
+						if((curargumentindex >= 0) && (curargumentindex < args.Length))
+						{
+							int argoffset = 0;
+							for(int i = 0; i < curargumentindex; i++) argoffset += args[i].Length + 1;
+							highlightstart = argsopenpos + argoffset + 1;
+							highlightend = highlightstart + args[curargumentindex].Length;
+						}
+					}
+
+					//mxd. If the tip obscures the view, move it down
+					int tippos;
+					int funcline = scriptedit.LineFromPosition(curfunctionstartpos);
+					if(scriptedit.CurrentLine > funcline)
+						tippos = scriptedit.Lines[scriptedit.CurrentLine].Position + scriptedit.Lines[scriptedit.CurrentLine].Indentation; //scriptedit.PositionFromLine(curline) /*+ (curfunctionstartpos - scriptedit.PositionFromLine(funcline))*/;
+					else
+						tippos = curfunctionstartpos;
+					
+					// Show tip
+					scriptedit.CallTipShow(tippos, functiondef);
+					scriptedit.CallTipSetHlt(highlightstart, highlightend);
+				}
+			}
+		}
+		
+		#endregion
+	}
+}
diff --git a/Source/Core/Controls/ScriptFileDocumentTab.cs b/Source/Core/Controls/ScriptFileDocumentTab.cs
index 98b2cc1dacd69fde325c4210b13004d4e78e2d05..8978b07fc27b89fb3d11570dc035c02aadf94a54 100644
--- a/Source/Core/Controls/ScriptFileDocumentTab.cs
+++ b/Source/Core/Controls/ScriptFileDocumentTab.cs
@@ -61,15 +61,15 @@ namespace CodeImp.DoomBuilder.Controls
 			if(config.Extensions.Length > 0) ext = "." + config.Extensions[0];
 			SetTitle("Untitled" + ext);
 			editor.ClearUndoRedo();
-            editor.FunctionBar.Enabled = (config.ScriptType != ScriptType.UNKNOWN); //mxd
-        }
-
-        #endregion
-
-            #region ================== Methods
-
-            // This compiles the script file
-        public override void Compile()
+			editor.FunctionBar.Enabled = (config.ScriptType != ScriptType.UNKNOWN); //mxd
+		}
+		
+		#endregion
+		
+		#region ================== Methods
+		
+		// This compiles the script file
+		public override void Compile()
 		{
 			//mxd. ACS requires special handling...
 			if(config.ScriptType == ScriptType.ACS)
@@ -126,8 +126,8 @@ namespace CodeImp.DoomBuilder.Controls
 			// Dispose compiler
 			compiler.Dispose();
 
-            //mxd. Update script navigator
-            UpdateNavigator();
+			//mxd. Update script navigator
+			UpdateNavigator();
 			
 			// Feed errors to panel
 			panel.ShowErrors(errors);
@@ -147,7 +147,7 @@ namespace CodeImp.DoomBuilder.Controls
 				// Boilderplate
 				if(!General.CompiledScriptConfigs.ContainsKey(General.Map.Options.ScriptCompiler))
 				{
-					General.ShowErrorMessage("Unable to compile '" + inputfile + "'. Unable to find required script compiler configuration ('" + General.Map.Options.ScriptCompiler + "').", MessageBoxButtons.OK);
+					General.ShowErrorMessage("Unable to compile \"" + inputfile + "\". Unable to find required script compiler configuration (\"" + General.Map.Options.ScriptCompiler + "\").", MessageBoxButtons.OK);
 					return;
 				}
 
@@ -232,7 +232,7 @@ namespace CodeImp.DoomBuilder.Controls
 					{
 						// Fail
 						compiler.Dispose();
-						errors.Add(new CompilerError("Output file '" + outputfile + "' doesn't exist."));
+						errors.Add(new CompilerError("Output file \"" + outputfile + "\" doesn't exist."));
 						panel.ShowErrors(errors);
 						return;
 					}
@@ -247,7 +247,7 @@ namespace CodeImp.DoomBuilder.Controls
 					{
 						// Fail
 						compiler.Dispose();
-						errors.Add(new CompilerError("Unable to create library file '" + targetfilename + "'. " + e.GetType().Name + ": " + e.Message));
+						errors.Add(new CompilerError("Unable to create library file \"" + targetfilename + "\". " + e.GetType().Name + ": " + e.Message));
 						panel.ShowErrors(errors);
 						return;
 					}
@@ -257,8 +257,8 @@ namespace CodeImp.DoomBuilder.Controls
 			// Dispose compiler
 			compiler.Dispose();
 
-            // Update script navigator
-            UpdateNavigator();
+			// Update script navigator
+			UpdateNavigator();
 
 			// Feed errors to panel
 			panel.ShowErrors(errors);
@@ -282,16 +282,16 @@ namespace CodeImp.DoomBuilder.Controls
 			catch(Exception e)
 			{
 				// Failed
-				General.ErrorLogger.Add(ErrorType.Error, "Cannot open file '" + filepathname + "' for writing. Make sure the path exists and that the file is not in use by another application.");
+				General.ErrorLogger.Add(ErrorType.Error, "Cannot open file \"" + filepathname + "\" for writing. Make sure the path exists and that the file is not in use by another application.");
 				General.WriteLogLine(e.GetType().Name + ": " + e.Message);
 				General.ShowErrorMessage("Unable to open file \"" + filepathname + "\" for writing. Make sure the path exists and that the file is not in use by another application.", MessageBoxButtons.OK);
 				return false;
 			}
-
-            // Done
-            editor.SetSavePoint(); //mxd
-            UpdateTitle(); //mxd
-            return true;
+			
+			// Done
+			editor.SetSavePoint(); //mxd
+			UpdateTitle(); //mxd
+			return true;
 		}
 		
 		// This saves the document to a new file
@@ -317,14 +317,13 @@ namespace CodeImp.DoomBuilder.Controls
 		{
 			try
 			{
-                // Read the file
-                editor.Text = File.ReadAllText(filepathname); //mxd
-            }
-
-            catch (Exception e)
+				// Read the file
+				editor.Text = File.ReadAllText(filepathname); //mxd
+			}
+			catch(Exception e)
 			{
 				// Failed
-				General.ErrorLogger.Add(ErrorType.Error, "Cannot open file '" + filepathname + "' for reading. Make sure the path exists and that the file is not in use by another application.");
+				General.ErrorLogger.Add(ErrorType.Error, "Cannot open file \"" + filepathname + "\" for reading. Make sure the path exists and that the file is not in use by another application.");
 				General.WriteLogLine(e.GetType().Name + ": " + e.Message);
 				General.ShowErrorMessage("Unable to open file \"" + filepathname + "\" for reading. Make sure the path exists and that the file is not in use by another application.", MessageBoxButtons.OK);
 				return false;
diff --git a/Source/Core/Controls/StatisticsControl.Designer.cs b/Source/Core/Controls/StatisticsControl.Designer.cs
index 9ade8ee10f3cbf428493e9e3a7d411c3c7f91043..387d1746602d7727aab496e8079f6269c0225db0 100644
--- a/Source/Core/Controls/StatisticsControl.Designer.cs
+++ b/Source/Core/Controls/StatisticsControl.Designer.cs
@@ -45,7 +45,7 @@
 			this.thingscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
 			this.thingscount.Location = new System.Drawing.Point(10, 81);
 			this.thingscount.Name = "thingscount";
-			this.thingscount.Size = new System.Drawing.Size(43, 14);
+			this.thingscount.Size = new System.Drawing.Size(63, 14);
 			this.thingscount.TabIndex = 19;
 			this.thingscount.Text = "0";
 			this.thingscount.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -55,7 +55,7 @@
 			this.sectorscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
 			this.sectorscount.Location = new System.Drawing.Point(10, 62);
 			this.sectorscount.Name = "sectorscount";
-			this.sectorscount.Size = new System.Drawing.Size(43, 14);
+			this.sectorscount.Size = new System.Drawing.Size(63, 14);
 			this.sectorscount.TabIndex = 18;
 			this.sectorscount.Text = "0";
 			this.sectorscount.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -65,7 +65,7 @@
 			this.sidedefscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
 			this.sidedefscount.Location = new System.Drawing.Point(10, 44);
 			this.sidedefscount.Name = "sidedefscount";
-			this.sidedefscount.Size = new System.Drawing.Size(43, 14);
+			this.sidedefscount.Size = new System.Drawing.Size(63, 14);
 			this.sidedefscount.TabIndex = 17;
 			this.sidedefscount.Text = "0";
 			this.sidedefscount.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -75,7 +75,7 @@
 			this.linedefscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
 			this.linedefscount.Location = new System.Drawing.Point(10, 26);
 			this.linedefscount.Name = "linedefscount";
-			this.linedefscount.Size = new System.Drawing.Size(43, 14);
+			this.linedefscount.Size = new System.Drawing.Size(63, 14);
 			this.linedefscount.TabIndex = 16;
 			this.linedefscount.Text = "0";
 			this.linedefscount.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -85,7 +85,7 @@
 			this.verticescount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
 			this.verticescount.Location = new System.Drawing.Point(10, 8);
 			this.verticescount.Name = "verticescount";
-			this.verticescount.Size = new System.Drawing.Size(43, 14);
+			this.verticescount.Size = new System.Drawing.Size(63, 14);
 			this.verticescount.TabIndex = 15;
 			this.verticescount.Text = "0";
 			this.verticescount.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -93,7 +93,7 @@
 			// thingslabel
 			// 
 			this.thingslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
-			this.thingslabel.Location = new System.Drawing.Point(55, 81);
+			this.thingslabel.Location = new System.Drawing.Point(75, 81);
 			this.thingslabel.Name = "thingslabel";
 			this.thingslabel.Size = new System.Drawing.Size(60, 15);
 			this.thingslabel.TabIndex = 14;
@@ -102,7 +102,7 @@
 			// sectorslabel
 			// 
 			this.sectorslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
-			this.sectorslabel.Location = new System.Drawing.Point(55, 62);
+			this.sectorslabel.Location = new System.Drawing.Point(75, 62);
 			this.sectorslabel.Name = "sectorslabel";
 			this.sectorslabel.Size = new System.Drawing.Size(60, 15);
 			this.sectorslabel.TabIndex = 13;
@@ -111,7 +111,7 @@
 			// sidedefslabel
 			// 
 			this.sidedefslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
-			this.sidedefslabel.Location = new System.Drawing.Point(55, 44);
+			this.sidedefslabel.Location = new System.Drawing.Point(75, 44);
 			this.sidedefslabel.Name = "sidedefslabel";
 			this.sidedefslabel.Size = new System.Drawing.Size(60, 15);
 			this.sidedefslabel.TabIndex = 12;
@@ -120,7 +120,7 @@
 			// linedefslabel
 			// 
 			this.linedefslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
-			this.linedefslabel.Location = new System.Drawing.Point(55, 26);
+			this.linedefslabel.Location = new System.Drawing.Point(75, 26);
 			this.linedefslabel.Name = "linedefslabel";
 			this.linedefslabel.Size = new System.Drawing.Size(60, 15);
 			this.linedefslabel.TabIndex = 11;
@@ -129,7 +129,7 @@
 			// verticeslabel
 			// 
 			this.verticeslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
-			this.verticeslabel.Location = new System.Drawing.Point(55, 8);
+			this.verticeslabel.Location = new System.Drawing.Point(75, 8);
 			this.verticeslabel.Name = "verticeslabel";
 			this.verticeslabel.Size = new System.Drawing.Size(60, 15);
 			this.verticeslabel.TabIndex = 10;
@@ -151,7 +151,7 @@
 			this.Controls.Add(this.verticeslabel);
 			this.ForeColor = System.Drawing.SystemColors.GrayText;
 			this.Name = "StatisticsControl";
-			this.Size = new System.Drawing.Size(118, 104);
+			this.Size = new System.Drawing.Size(138, 104);
 			this.ResumeLayout(false);
 
 		}
diff --git a/Source/Core/Controls/TextureSelectorControl.cs b/Source/Core/Controls/TextureSelectorControl.cs
index 0410e3f7b0f0e66eff53c8344d0a15e8ec533af0..4df91dd0be6ca9ee6ea7cf0c794115f0151f3529 100644
--- a/Source/Core/Controls/TextureSelectorControl.cs
+++ b/Source/Core/Controls/TextureSelectorControl.cs
@@ -74,10 +74,12 @@ namespace CodeImp.DoomBuilder.Controls
 
 				if(string.IsNullOrEmpty(texture.FilePathName) || texture is UnknownImage) DisplayImageSize(0, 0); //mxd
 				else DisplayImageSize(texture.ScaledWidth, texture.ScaledHeight); //mxd
-				if(usepreviews ? !texture.IsPreviewLoaded : !texture.IsImageLoaded) timer.Start(); //mxd
-				
+
+				if(usepreviews && !texture.IsPreviewLoaded) timer.Start(); //mxd
+				else if(!texture.IsImageLoaded) texture.LoadImage(); //mxd. In some cases the image may never me loaded by the DataManager
+
 				// Set the image
-				return (usepreviews ? texture.GetPreview() : texture.GetBitmap());
+				return new Bitmap((usepreviews ? texture.GetPreview() : texture.GetBitmap()));
 			}
 		}
 
diff --git a/Source/Core/Controls/ThingBrowserControl.cs b/Source/Core/Controls/ThingBrowserControl.cs
index d010904dfc550dd3a658cb95e446726d92ab8970..be0ffae714ea6200c387b5b49b36cd6c6a1ed12d 100644
--- a/Source/Core/Controls/ThingBrowserControl.cs
+++ b/Source/Core/Controls/ThingBrowserControl.cs
@@ -495,14 +495,25 @@ namespace CodeImp.DoomBuilder.Controls
 				validnodes.Clear();
 
 				string match = tbFilter.Text.ToUpperInvariant();
+				HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+				
+				// First add nodes, which titles start with given text
 				foreach(TreeNode node in nodes)
 				{
-					if(node.Text.ToUpperInvariant().Contains(match)) 
+					if(node.Text.ToUpperInvariant().StartsWith(match))
 					{
 						typelist.Nodes.Add(node);
+						added.Add(node.Text);
 					}
 				}
 
+				// Then add nodes, which titles contain given text
+				foreach(TreeNode node in nodes)
+				{
+					if(!added.Contains(node.Text) && node.Text.ToUpperInvariant().Contains(match)) 
+						typelist.Nodes.Add(node);
+				}
+
 				doupdatenode = true;
 				doupdatetextbox = true;
 			}
diff --git a/Source/Core/Data/ColormapImage.cs b/Source/Core/Data/ColormapImage.cs
index 487c483a045d3e9208527db9106dbbc2c6ee2c21..6f0563814ca8db0af6347d6a0e3d73ece71a9b4c 100644
--- a/Source/Core/Data/ColormapImage.cs
+++ b/Source/Core/Data/ColormapImage.cs
@@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.Data
 					if(reader is UnknownImageReader)
 					{
 						// Data is in an unknown format!
-						General.ErrorLogger.Add(ErrorType.Error, "Colormap lump '" + Name + "' data format could not be read. Does this lump contain valid colormap data at all?");
+						General.ErrorLogger.Add(ErrorType.Error, "Colormap lump \"" + Name + "\" data format could not be read. Does this lump contain valid colormap data at all?");
 						bitmap = null;
 					}
 					else
@@ -97,7 +97,7 @@ namespace CodeImp.DoomBuilder.Data
 				else
 				{
 					// Missing a patch lump!
-					General.ErrorLogger.Add(ErrorType.Error, "Missing colormap lump '" + Name + "'. Did you forget to include required resources?");
+					General.ErrorLogger.Add(ErrorType.Error, "Missing colormap lump \"" + Name + "\". Did you forget to include required resources?");
 					loadfailed = true;
 				}
 
diff --git a/Source/Core/Data/DataLocation.cs b/Source/Core/Data/DataLocation.cs
index c12df73cb0e29ffb66c25458c0b869f39e35efa5..1bc1c4cbdce8176c950ef7ea698a87b51dcf7aa5 100644
--- a/Source/Core/Data/DataLocation.cs
+++ b/Source/Core/Data/DataLocation.cs
@@ -79,8 +79,8 @@ namespace CodeImp.DoomBuilder.Data
                 }
             }
 
-            return name;
-        }
+			return (name ?? string.Empty);
+		}
 
         // This compares two locations
         public int CompareTo(DataLocation other)
diff --git a/Source/Core/Data/FileImage.cs b/Source/Core/Data/FileImage.cs
index adfefe4cfd50677ed3bcbbbb00efa49725747f99..2d99cfa679102e9534261050c4350195dab3aeb4 100644
--- a/Source/Core/Data/FileImage.cs
+++ b/Source/Core/Data/FileImage.cs
@@ -172,7 +172,7 @@ namespace CodeImp.DoomBuilder.Data
 				// Not loaded?
 				if(bitmap == null) 
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "Image file '" + filepathname + "' data format could not be read, while loading image '" + this.Name + "'. Is this a valid picture file at all?");
+					General.ErrorLogger.Add(ErrorType.Error, "Image file \"" + filepathname + "\" data format could not be read, while loading image \"" + this.Name + "\". Is this a valid picture file at all?");
 					loadfailed = true;
 				} 
 				else 
diff --git a/Source/Core/Data/FlatImage.cs b/Source/Core/Data/FlatImage.cs
index 578a6c872419e162c7a0767a3935818ba6971c4e..b098a67c0ed280f47c9486ceeaa56bb6378af690 100644
--- a/Source/Core/Data/FlatImage.cs
+++ b/Source/Core/Data/FlatImage.cs
@@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.Data
 					if(reader is UnknownImageReader)
 					{
 						// Data is in an unknown format!
-						General.ErrorLogger.Add(ErrorType.Error, "Flat lump '" + Name + "' data format could not be read. Does this lump contain valid picture data at all?");
+						General.ErrorLogger.Add(ErrorType.Error, "Flat lump \"" + Name + "\" data format could not be read. Does this lump contain valid picture data at all?");
 						bitmap = null;
 					}
 					else
@@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.Data
 				else
 				{
 					// Missing a patch lump!
-					General.ErrorLogger.Add(ErrorType.Error, "Missing flat lump '" + Name + "'. Did you forget to include required resources?");
+					General.ErrorLogger.Add(ErrorType.Error, "Missing flat lump \"" + Name + "\". Did you forget to include required resources?");
 					loadfailed = true;
 				}
 
diff --git a/Source/Core/Data/HighResImage.cs b/Source/Core/Data/HighResImage.cs
index fb058813f7380972fe43ea708586ff7c8d448fbe..9cb1a82b8d2b6d67c7ca56bd695cdddb940ee56b 100644
--- a/Source/Core/Data/HighResImage.cs
+++ b/Source/Core/Data/HighResImage.cs
@@ -125,17 +125,26 @@ namespace CodeImp.DoomBuilder.Data
 				catch(Exception e)
 				{
 					// Unable to make bitmap
-					General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message);
+					General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message);
 					loadfailed = true;
 				}
 
 				int missingpatches = 0; //mxd
 
-				if(!loadfailed)
+				if(patches.Count == 0) //mxd
+				{
+					// No patches!
+					General.ErrorLogger.Add(ErrorType.Warning, "No patches are defined for texture \"" + this.Name + "\"");
+					loadfailed = true;
+				}
+				else if(!loadfailed)
 				{
 					// Go for all patches
 					foreach(TexturePatch p in patches)
 					{
+						//mxd. Some patches (like "TNT1A0") should be skipped
+						if(p.skip) continue;
+						
 						// Get the patch data stream
 						Stream patchdata = General.Map.Data.GetPatchData(p.lumpname, p.haslongname);
 
@@ -161,7 +170,7 @@ namespace CodeImp.DoomBuilder.Data
 								if(reader is UnknownImageReader) 
 								{
 									// Data is in an unknown format!
-									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'");
+									General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\"");
 									missingpatches++; //mxd
 								}
 							}
@@ -175,7 +184,7 @@ namespace CodeImp.DoomBuilder.Data
 								catch(InvalidDataException)
 								{
 									// Data cannot be read!
-									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'");
+									General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\"");
 									missingpatches++; //mxd
 								}
 
@@ -217,7 +226,7 @@ namespace CodeImp.DoomBuilder.Data
 							}
 							
 							// Missing a patch lump!
-							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'");
+							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\"");
 							missingpatches++; //mxd
 						}
 					}
@@ -243,12 +252,9 @@ namespace CodeImp.DoomBuilder.Data
 			if(p.flipx || p.flipy)
 			{
 				RotateFlipType flip;
-				if(p.flipx && !p.flipy)
-					flip = RotateFlipType.RotateNoneFlipX;
-				else if(!p.flipx && p.flipy)
-					flip = RotateFlipType.RotateNoneFlipY;
-				else
-					flip = RotateFlipType.RotateNoneFlipXY;
+				if(p.flipx && !p.flipy) flip = RotateFlipType.RotateNoneFlipX;
+				else if(!p.flipx && p.flipy) flip = RotateFlipType.RotateNoneFlipY;
+				else flip = RotateFlipType.RotateNoneFlipXY;
 				patchbmp.RotateFlip(flip);
 			}
 
@@ -258,15 +264,9 @@ namespace CodeImp.DoomBuilder.Data
 				RotateFlipType rotate;
 				switch(p.rotate)
 				{
-					case 90:
-						rotate = RotateFlipType.Rotate90FlipNone;
-						break;
-					case 180:
-						rotate = RotateFlipType.Rotate180FlipNone;
-						break;
-					default:
-						rotate = RotateFlipType.Rotate270FlipNone;
-						break;
+					case 90:  rotate = RotateFlipType.Rotate90FlipNone; break;
+					case 180: rotate = RotateFlipType.Rotate180FlipNone; break;
+					default:  rotate = RotateFlipType.Rotate270FlipNone; break;
 				}
 				patchbmp.RotateFlip(rotate);
 			}
@@ -282,7 +282,7 @@ namespace CodeImp.DoomBuilder.Data
 				}
 				catch(Exception e)
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + p.lumpname + "' for alpha adjustment. " + e.GetType().Name + ": " + e.Message);
+					General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + p.lumpname + "\" for alpha adjustment. " + e.GetType().Name + ": " + e.Message);
 				}
 
 				if(bmpdata != null)
@@ -347,7 +347,7 @@ namespace CodeImp.DoomBuilder.Data
 						}
 						catch(Exception e)
 						{
-							General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture '" + this.Name + "' to apply render style. " + e.GetType().Name + ": " + e.Message);
+							General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture \"" + this.Name + "\" to apply render style. " + e.GetType().Name + ": " + e.Message);
 						}
 
 						if(texturebmpdata != null)
diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs
index 8fc961039930a05bb4ea82f724dd032623540b11..fc89ce4c84701da503c25233f9a30f0398a4b1d9 100644
--- a/Source/Core/Data/ImageData.cs
+++ b/Source/Core/Data/ImageData.cs
@@ -277,7 +277,7 @@ namespace CodeImp.DoomBuilder.Data
 						catch(Exception e)
 						{
 							bitmap = oldbitmap;
-							General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message);
+							General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message);
 						}
 					}
 					
@@ -293,7 +293,7 @@ namespace CodeImp.DoomBuilder.Data
 						}
 						catch(Exception e)
 						{
-							General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message);
+							General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message);
 						}
 
 						// Bitmap locked?
@@ -348,7 +348,7 @@ namespace CodeImp.DoomBuilder.Data
 					{
 						BitmapData bmpdata = null;
 						try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); }
-						catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + this.filepathname + "' for glow color calculation. " + e.GetType().Name + ": " + e.Message); }
+						catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for glow color calculation. " + e.GetType().Name + ": " + e.Message); }
 
 						if(bmpdata != null)
 						{
@@ -403,7 +403,7 @@ namespace CodeImp.DoomBuilder.Data
                     {
 						BitmapData bmpdata = null;
 						try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); }
-						catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + this.filepathname + "' for translucency check. " + e.GetType().Name + ": " + e.Message); }
+						catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for translucency check. " + e.GetType().Name + ": " + e.Message); }
 
 						if(bmpdata != null)
 						{
diff --git a/Source/Core/Data/PK3FileImage.cs b/Source/Core/Data/PK3FileImage.cs
index 33da887d71c086e6a4a9c0976017e297d40a7bb3..4546fd2121a186cb6607cd18a18f39b220245a66 100644
--- a/Source/Core/Data/PK3FileImage.cs
+++ b/Source/Core/Data/PK3FileImage.cs
@@ -140,7 +140,7 @@ namespace CodeImp.DoomBuilder.Data
 					// Not loaded?
 					if(bitmap == null)
 					{
-						General.ErrorLogger.Add(ErrorType.Error, "Image file '" + filepathname + "' data format could not be read, while loading texture '" + this.Name + "'");
+						General.ErrorLogger.Add(ErrorType.Error, "Image file \"" + filepathname + "\" data format could not be read, while loading texture \"" + this.Name + "\"");
 						loadfailed = true;
 					}
 					else
diff --git a/Source/Core/Data/SimpleTextureImage.cs b/Source/Core/Data/SimpleTextureImage.cs
index eb79db49af9ac33f81285aa912c0309ec4b9308a..7f74073745aa3be7d96a6cf60eec1c04d092e3f9 100644
--- a/Source/Core/Data/SimpleTextureImage.cs
+++ b/Source/Core/Data/SimpleTextureImage.cs
@@ -17,8 +17,8 @@
 #region ================== Namespaces
 
 using System;
-using CodeImp.DoomBuilder.IO;
 using System.IO;
+using CodeImp.DoomBuilder.IO;
 
 #endregion
 
@@ -32,7 +32,7 @@ namespace CodeImp.DoomBuilder.Data
 
 		#region ================== Variables
 
-		private string lumpname;
+		private readonly string lumpname;
 
 		#endregion
 
@@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Data
 					// Not loaded?
 					if(bitmap == null)
 					{
-						General.ErrorLogger.Add(ErrorType.Error, "Image lump '" + lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?");
+						General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?");
 						loadfailed = true;
 					}
 					else
@@ -108,7 +108,7 @@ namespace CodeImp.DoomBuilder.Data
 				}
 				else
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "Image lump '" + lumpname + "' could not be found, while loading texture '" + this.Name + "'. Did you forget to include required resources?");
+					General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + lumpname + "\" could not be found, while loading texture \"" + this.Name + "\". Did you forget to include required resources?");
 					loadfailed = true;
 				}
 				
diff --git a/Source/Core/Data/SpriteImage.cs b/Source/Core/Data/SpriteImage.cs
index 4c31db5f815c889d8960d9bd0199570a00d96950..9e1e870ff5cba0e8b46a1f32049a21fb485ecc05 100644
--- a/Source/Core/Data/SpriteImage.cs
+++ b/Source/Core/Data/SpriteImage.cs
@@ -95,7 +95,7 @@ namespace CodeImp.DoomBuilder.Data
 					if(reader is UnknownImageReader)
 					{
 						// Data is in an unknown format!
-						General.ErrorLogger.Add(ErrorType.Error, "Sprite lump '" + Name + "' data format could not be read. Does this lump contain valid picture data at all?");
+						General.ErrorLogger.Add(ErrorType.Error, "Sprite lump \"" + Name + "\" data format could not be read. Does this lump contain valid picture data at all?");
 						bitmap = null;
 					}
 					else
@@ -133,7 +133,7 @@ namespace CodeImp.DoomBuilder.Data
 				else
 				{
 					// Missing a patch lump!
-					General.ErrorLogger.Add(ErrorType.Error, "Missing sprite lump '" + Name + "'. Forgot to include required resources?");
+					General.ErrorLogger.Add(ErrorType.Error, "Missing sprite lump \"" + Name + "\". Forgot to include required resources?");
 				}
 
 				// Pass on to base
diff --git a/Source/Core/Data/TextureImage.cs b/Source/Core/Data/TextureImage.cs
index 9ca200b85fe95fb199170f186014559aa56bc90c..768bf7f24a3764254c99f361302a4bb18bd971f0 100644
--- a/Source/Core/Data/TextureImage.cs
+++ b/Source/Core/Data/TextureImage.cs
@@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.Data
 				catch(Exception e)
 				{
 					// Unable to make bitmap
-					General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message);
+					General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message);
 					loadfailed = true;
 				}
 
@@ -124,7 +124,7 @@ namespace CodeImp.DoomBuilder.Data
 								if(reader is UnknownImageReader) 
 								{
 									// Data is in an unknown format!
-									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?");
+									General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?");
 									loadfailed = true;
 									missingpatches++; //mxd
 								}
@@ -138,7 +138,7 @@ namespace CodeImp.DoomBuilder.Data
 								catch(InvalidDataException)
 								{
 									// Data cannot be read!
-									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?");
+									General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?");
 									loadfailed = true;
 									missingpatches++; //mxd
 								}
@@ -150,7 +150,7 @@ namespace CodeImp.DoomBuilder.Data
 						else
 						{
 							// Missing a patch lump!
-							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'. Did you forget to include required resources?");
+							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?");
 							loadfailed = true;
 							missingpatches++; //mxd
 						}
diff --git a/Source/Core/Data/TexturePatch.cs b/Source/Core/Data/TexturePatch.cs
index 7b7c9101c227a761b0615ba030e1a6f2e28abdc9..efec5da6ee244bb19b07faddfe677a6ebb8769c7 100644
--- a/Source/Core/Data/TexturePatch.cs
+++ b/Source/Core/Data/TexturePatch.cs
@@ -59,6 +59,7 @@ namespace CodeImp.DoomBuilder.Data
 		public readonly TexturePathRenderStyle style;
 		public readonly TexturePathBlendStyle blendstyle; //mxd
 		public readonly float tintammount;//mxd
+		public readonly bool skip; //mxd
 		
 		// Constructor for simple patches
 		public TexturePatch(string lumpname, int x, int y)
@@ -76,6 +77,7 @@ namespace CodeImp.DoomBuilder.Data
 			this.blendstyle = TexturePathBlendStyle.None;//mxd
 			this.tintammount = 0; //mxd
 			this.haslongname = false; //mxd
+			this.skip = false; //mxd
 		}
 
 		//mxd. Constructor for hires patches
@@ -94,6 +96,7 @@ namespace CodeImp.DoomBuilder.Data
 			this.blendstyle = patch.BlendStyle;
 			this.tintammount = patch.TintAmmount;
 			this.haslongname = (Path.GetFileNameWithoutExtension(this.lumpname) != this.lumpname);
+			this.skip = patch.Skip;
 
 			//mxd. Check data so we don't perform unneeded operations later on
 			if(this.alpha == 1.0f) 
diff --git a/Source/Core/Editing/ClassicMode.cs b/Source/Core/Editing/ClassicMode.cs
index 3dcedeff54002e06052cdaaf4eaf554bce5c141d..2b38cc965d267625ffb253827d42f29eac3b23e3 100644
--- a/Source/Core/Editing/ClassicMode.cs
+++ b/Source/Core/Editing/ClassicMode.cs
@@ -565,6 +565,10 @@ namespace CodeImp.DoomBuilder.Editing
 			// Save mouse down position
 			mousedownpos = mousepos;
 			mousedownmappos = mousemappos;
+
+			//mxd. Looks like in some cases (very detailed maps / slow CPUs) OnMouseUp is not fired
+			// This is my attempt at fixing this...
+			if(e.Button == mousedragging) mousedragging = MouseButtons.None;
 			
 			// Let the base class know
 			base.OnMouseDown(e);
diff --git a/Source/Core/Editing/CopyPasteManager.cs b/Source/Core/Editing/CopyPasteManager.cs
index 8e72b861a1e949fcd157a73b8ff7a45cd799a1c6..618f0cc0639b2f04f8fb61f070dd6938b665478c 100644
--- a/Source/Core/Editing/CopyPasteManager.cs
+++ b/Source/Core/Editing/CopyPasteManager.cs
@@ -246,7 +246,7 @@ namespace CodeImp.DoomBuilder.Editing
 						// Write data to stream
 						MemoryStream memstream = new MemoryStream();
 						ClipboardStreamWriter writer = new ClipboardStreamWriter(); //mxd
-						writer.Write(copyset, memstream, General.Map.Config.UseLongTextureNames);
+						writer.Write(copyset, memstream);
 
 						// Set on clipboard
 						Clipboard.SetData(CLIPBOARD_DATA_FORMAT, memstream);
@@ -290,37 +290,31 @@ namespace CodeImp.DoomBuilder.Editing
 							// Create undo
 							General.MainWindow.DisplayStatus(StatusType.Action, "Pasted selected elements.");
 							General.Map.UndoRedo.CreateUndo("Paste");
-							
-							// Read from clipboard
-							Stream memstream = (Stream)Clipboard.GetData(CLIPBOARD_DATA_FORMAT);
-							memstream.Seek(0, SeekOrigin.Begin);
 
 							// Mark all current geometry
 							General.Map.Map.ClearAllMarks(true);
 
-							// Read data stream
-							ClipboardStreamReader reader = new ClipboardStreamReader(); //mxd
-							General.Map.Map.BeginAddRemove();
-							reader.Read(General.Map.Map, memstream);
-							General.Map.Map.EndAddRemove();
+							// Read from clipboard
+							using(Stream memstream = (Stream)Clipboard.GetData(CLIPBOARD_DATA_FORMAT))
+							{
+								// Rewind before use
+								memstream.Seek(0, SeekOrigin.Begin);
+								
+								// Read data stream
+								ClipboardStreamReader reader = new ClipboardStreamReader(); //mxd
+								General.Map.Map.BeginAddRemove();
+								bool success = reader.Read(General.Map.Map, memstream);
+								General.Map.Map.EndAddRemove();
+								if(!success) //mxd
+								{
+									General.Map.UndoRedo.WithdrawUndo(); // This will also mess with the marks...
+									General.Map.Map.ClearAllMarks(true); // So re-mark all current geometry...
+								}
+							}
 							
 							// The new geometry is not marked, so invert the marks to get it marked
 							General.Map.Map.InvertAllMarks();
 
-							// Convert UDMF fields back to flags and activations, if needed
-							if(!(General.Map.FormatInterface is UniversalMapSetIO || General.Map.FormatInterface is SRB2MapSetIO)) General.Map.Map.TranslateFromUDMF();
-
-							//mxd. Translate texture names
-							General.Map.Map.TranslateTextureNames(General.Map.Config.UseLongTextureNames, true);
-							
-							// Modify tags and actions if preferred
-							if(options.ChangeTags == PasteOptions.TAGS_REMOVE) Tools.RemoveMarkedTags();
-							if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags();
-							if(options.RemoveActions) Tools.RemoveMarkedActions();
-
-							// Clean up
-							memstream.Dispose();
-
 							// Check if anything was pasted
 							List<Thing> things = General.Map.Map.GetMarkedThings(true); //mxd
 							int totalpasted = things.Count;
@@ -328,14 +322,25 @@ namespace CodeImp.DoomBuilder.Editing
 							totalpasted += General.Map.Map.GetMarkedLinedefs(true).Count;
 							totalpasted += General.Map.Map.GetMarkedSidedefs(true).Count;
 							totalpasted += General.Map.Map.GetMarkedSectors(true).Count;
+							
 							if(totalpasted > 0)
 							{
+								// Convert UDMF fields back to flags and activations, if needed
+								if(!(General.Map.FormatInterface is UniversalMapSetIO || General.Map.FormatInterface is SRB2MapSetIO)) General.Map.Map.TranslateFromUDMF();
+
+								//mxd. Translate texture names
+								General.Map.Map.TranslateTextureNames(General.Map.Config.UseLongTextureNames, true);
+
+								// Modify tags and actions if preferred
+								if(options.ChangeTags == PasteOptions.TAGS_REMOVE) Tools.RemoveMarkedTags();
+								if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags();
+								if(options.RemoveActions) Tools.RemoveMarkedActions();
+								
 								foreach(Thing t in things) t.UpdateConfiguration(); //mxd
 								General.Map.ThingsFilter.Update();
 								General.Editing.Mode.OnPasteEnd(options.Copy());
 								General.Plugins.OnPasteEnd(options);
 							}
-							return;
 						}
 					}
 				}
diff --git a/Source/Core/Editing/GridSetup.cs b/Source/Core/Editing/GridSetup.cs
index a053d69bbfa69eaadf91acd730fd9eaf6e54c8a3..fd0eb749169e6da85d63e7d1ebf44a8d3416b783 100644
--- a/Source/Core/Editing/GridSetup.cs
+++ b/Source/Core/Editing/GridSetup.cs
@@ -246,7 +246,7 @@ namespace CodeImp.DoomBuilder.Editing
 		// This snaps to the nearest grid coordinate
 		public Vector2D SnappedToGrid(Vector2D v)
 		{
-			return GridSetup.SnappedToGrid(v, gridsizef, gridsizefinv);
+			return SnappedToGrid(v, gridsizef, gridsizefinv);
 		}
 
 		// This snaps to the nearest grid coordinate
@@ -291,6 +291,9 @@ namespace CodeImp.DoomBuilder.Editing
 			// Not lower than 1
 			if(gridsize >= 2)
 			{
+				//mxd. Disable automatic grid resizing
+				General.MainWindow.DisableDynamicGridResize();
+				
 				// Change grid
 				SetGridSize(gridsize >> 1);
 				
@@ -307,6 +310,9 @@ namespace CodeImp.DoomBuilder.Editing
 			// Not higher than 1024
 			if(gridsize <= 512)
 			{
+				//mxd. Disable automatic grid resizing
+				General.MainWindow.DisableDynamicGridResize();
+				
 				// Change grid
 				SetGridSize(gridsize << 1);
 
diff --git a/Source/Core/Editing/ThingsFilter.cs b/Source/Core/Editing/ThingsFilter.cs
index 9d58a380ba8e509ae03e3eb68f3ba70f90d6a14d..d93d6450d9cc1ef1b3732debde52aa2122966b84 100644
--- a/Source/Core/Editing/ThingsFilter.cs
+++ b/Source/Core/Editing/ThingsFilter.cs
@@ -272,7 +272,7 @@ namespace CodeImp.DoomBuilder.Editing
 
 			//Integrity check
 			if(!IsValid())
-				General.ErrorLogger.Add(ErrorType.Warning, "Things filter '" + name + "' has invalid properties. Configure the things filter to fix this!");
+				General.ErrorLogger.Add(ErrorType.Warning, "Things filter \"" + name + "\" has invalid properties. Configure the things filter to fix this!");
 		}
 
 		//mxd
diff --git a/Source/Core/Editing/UndoManager.cs b/Source/Core/Editing/UndoManager.cs
index 66f8fea93248449d35aac491c778a65e0fbc1e03..aab46cc098fff645ccf8a06168dc1f61986a9321 100644
--- a/Source/Core/Editing/UndoManager.cs
+++ b/Source/Core/Editing/UndoManager.cs
@@ -1116,8 +1116,12 @@ namespace CodeImp.DoomBuilder.Editing
 			Sidedef sd = (sindex >= 0) ? General.Map.Map.GetSidedefByIndex(sindex) : null;
 			l.AttachFront(sd);
 			l.Marked = true;
-			if (l.Tag != 0) linedeftags.Add(l.Tag);
-			if (sd != null) sd.Marked = true;
+            if (l.Tag != 0) linedeftags.Add(l.Tag);
+            if (sd != null)
+			{
+				sd.Marked = true;
+				if(sd.Sector != null) sd.Sector.UpdateNeeded = true; //mxd. Sector needs to be updated as well...
+			}
 			geometrychanged = true;
 		}
 
@@ -1141,8 +1145,12 @@ namespace CodeImp.DoomBuilder.Editing
 			Sidedef sd = (sindex >= 0) ? General.Map.Map.GetSidedefByIndex(sindex) : null;
 			l.AttachBack(sd);
 			l.Marked = true;
-			if (l.Tag != 0) linedeftags.Add(l.Tag);
-			if (sd != null) sd.Marked = true;
+            if (l.Tag != 0) linedeftags.Add(l.Tag);
+            if (sd != null)
+			{
+				sd.Marked = true;
+				if(sd.Sector != null) sd.Sector.UpdateNeeded = true; //mxd. Sector needs to be updated as well...
+			}
 			geometrychanged = true;
 		}
 
diff --git a/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs b/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs
index be89edfe7a97b44505180c7b876331e2bfa9694b..2e5ea4b709491b7b38ee7737fc65fee4a0ed0faf 100644
--- a/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs
+++ b/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs
@@ -68,8 +68,7 @@
 			this.newTag.Size = new System.Drawing.Size(54, 24);
 			this.newTag.TabIndex = 2;
 			this.newTag.Text = "New";
-			this.tooltip.SetToolTip(this.newTag, "Finds a tag, which is not used as a tag or tag action argument \r\nby any map eleme" +
-					"nt");
+			this.tooltip.SetToolTip(this.newTag, "Find a tag, which is not used as a tag or tag action argument\r\nby any map element");
 			this.newTag.UseVisualStyleBackColor = true;
 			this.newTag.Click += new System.EventHandler(this.newTag_Click);
 			// 
@@ -80,7 +79,7 @@
 			this.unusedTag.Size = new System.Drawing.Size(54, 24);
 			this.unusedTag.TabIndex = 3;
 			this.unusedTag.Text = "Unused";
-			this.tooltip.SetToolTip(this.unusedTag, "Finds a tag, which is not used as a tag \r\nby any map element of this type");
+			this.tooltip.SetToolTip(this.unusedTag, "Find a tag, which is not used as a tag\r\nby any map element of this type");
 			this.unusedTag.UseVisualStyleBackColor = true;
 			this.unusedTag.Click += new System.EventHandler(this.unusedTag_Click);
 			// 
@@ -98,7 +97,7 @@
 			this.clear.Name = "clear";
 			this.clear.Size = new System.Drawing.Size(26, 24);
 			this.clear.TabIndex = 4;
-			this.tooltip.SetToolTip(this.clear, "Sets tag to 0");
+			this.tooltip.SetToolTip(this.clear, "Set tag to 0");
 			this.clear.UseVisualStyleBackColor = true;
 			this.clear.Click += new System.EventHandler(this.clear_Click);
 			// 
diff --git a/Source/Core/GZBuilder/Controls/TagSelector.cs b/Source/Core/GZBuilder/Controls/TagSelector.cs
index b8744433f4437e12f74d7b79bb9eca1b923fdc32..937e0f6564cae1f5cd5065ba087b18d9c091ba39 100644
--- a/Source/Core/GZBuilder/Controls/TagSelector.cs
+++ b/Source/Core/GZBuilder/Controls/TagSelector.cs
@@ -255,9 +255,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
 		private void TagSelector_Resize(object sender, EventArgs e)
 		{
 			clear.Left = this.Width - clear.Width - clear.Margin.Right;
-			unusedTag.Left = clear.Left - clear.Margin.Left - unusedTag.Margin.Right - unusedTag.Width;
-			newTag.Left = unusedTag.Left - unusedTag.Margin.Left - newTag.Margin.Right - newTag.Width;
-			cbTagPicker.Width = newTag.Left - newTag.Margin.Left - cbTagPicker.Margin.Right - cbTagPicker.Left;
+			unusedTag.Left = clear.Left - unusedTag.Margin.Right - unusedTag.Width;
+			newTag.Left = unusedTag.Left - newTag.Margin.Right - newTag.Width;
+			cbTagPicker.Width = newTag.Left - cbTagPicker.Margin.Right - cbTagPicker.Left;
 		}
 
 		#endregion
diff --git a/Source/Core/GZBuilder/Controls/TagsSelector.cs b/Source/Core/GZBuilder/Controls/TagsSelector.cs
index 7168b9b18dd51215e094fc5cc4439b9a148399df..427fb979e05aea5de37e244931b9067b3c7b41e8 100644
--- a/Source/Core/GZBuilder/Controls/TagsSelector.cs
+++ b/Source/Core/GZBuilder/Controls/TagsSelector.cs
@@ -257,6 +257,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
 				if(tagpicker.SelectedIndex == -1) tagpicker.Text = tag.ToString();
 			}
 
+			clear.Enabled = (tagpicker.Text.Trim() != "0");
+
 			blockupdate = false;
 		}
 
@@ -278,6 +280,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
 
 		private void clear_Click(object sender, EventArgs e)
 		{
+			tagpicker.Focus();
 			tagpicker.SelectedIndex = -1;
 			tagpicker.Text = "0";
 		}
@@ -356,6 +359,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
 		{
 			if(blockupdate) return;
 
+			clear.Enabled = (tagpicker.Text.Trim() != "0");
 			if(tagpicker.SelectedItem != null)
 			{
 				TagInfo info = (TagInfo)tagpicker.SelectedItem;
@@ -420,11 +424,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
 		private void TagsSelector_Resize(object sender, EventArgs e)
 		{
 			clear.Left = this.Width - clear.Width - clear.Margin.Right;
-			unusedtag.Left = clear.Left - clear.Margin.Left - unusedtag.Margin.Right - unusedtag.Width;
-			newtag.Left = unusedtag.Left - unusedtag.Margin.Left - newtag.Margin.Right - newtag.Width;
-			tagpicker.Width = newtag.Left - newtag.Margin.Left - tagpicker.Margin.Right - tagpicker.Left;
+			unusedtag.Left = clear.Left - unusedtag.Margin.Right - unusedtag.Width;
+			newtag.Left = unusedtag.Left - newtag.Margin.Right - newtag.Width;
+			tagpicker.Width = newtag.Left - tagpicker.Margin.Right - tagpicker.Left;
 			removetag.Left = clear.Left;
-			addtag.Left = removetag.Left - removetag.Margin.Left - addtag.Margin.Right - addtag.Width;
+			addtag.Left = removetag.Left - addtag.Margin.Right - addtag.Width;
 		}
 
 		#endregion
diff --git a/Source/Core/GZBuilder/Data/EngineInfo.cs b/Source/Core/GZBuilder/Data/EngineInfo.cs
index 55d73a867c17bf77a7285291ec1ca43a5c01e870..de217051c5689406022c1735be3bcfff9be4c5f8 100644
--- a/Source/Core/GZBuilder/Data/EngineInfo.cs
+++ b/Source/Core/GZBuilder/Data/EngineInfo.cs
@@ -45,7 +45,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 		{
 			if(testprogramname == DEFAULT_ENGINE_NAME && !String.IsNullOrEmpty(TestProgram)) 
 			{
-				//get engine name from path
+				// Get engine name from path
 				testprogramname = Path.GetFileNameWithoutExtension(TestProgram);
 			}
 
@@ -59,12 +59,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 			if(File.Exists(TestProgram))
 			{
 				Icon i = Icon.ExtractAssociatedIcon(TestProgram);
-				if(i != null) icon = i.ToBitmap();
+				icon = (i != null ? i.ToBitmap() : new Bitmap(Properties.Resources.Question));
 			}
-			
-			if(icon == null)
+			else
 			{
-				icon = new Bitmap(16, 16);
+				icon = new Bitmap(Properties.Resources.Warning);
 			}
 		}
 
diff --git a/Source/Core/GZBuilder/Geometry/Line3D.cs b/Source/Core/GZBuilder/Geometry/Line3D.cs
index 9cd37036836450d101e70ed44b333732f297907f..f7ed0d9a066e5c0e7210b1be9a530eccbc7bae89 100644
--- a/Source/Core/GZBuilder/Geometry/Line3D.cs
+++ b/Source/Core/GZBuilder/Geometry/Line3D.cs
@@ -22,6 +22,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry
 		{
 			this.Start = start;
 			this.End = end;
+			this.Start2D = start;
+			this.End2D = end;
 			this.Color = General.Colors.InfoLine;
 			this.RenderArrowhead = true;
 		}
@@ -30,6 +32,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry
 		{
 			this.Start = start;
 			this.End = end;
+			this.Start2D = start;
+			this.End2D = end;
 			this.Color = General.Colors.InfoLine;
 			this.RenderArrowhead = renderArrowhead;
 		}
@@ -38,6 +42,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry
 		{
 			this.Start = start;
 			this.End = end;
+			this.Start2D = start;
+			this.End2D = end;
 			this.Color = color;
 			this.RenderArrowhead = true;
 		}
@@ -46,6 +52,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry
 		{
 			this.Start = start;
 			this.End = end;
+			this.Start2D = start;
+			this.End2D = end;
 			this.Color = color;
 			this.RenderArrowhead = renderArrowhead;
 		}
diff --git a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs
index 55d105663dd0c85ec39a55f453454f5d1fc8406c..7773d22f064bed37ac2a3c3d15661a1e10113504 100644
--- a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs
+++ b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs
@@ -130,7 +130,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
 			
 			// Get OS name
 			ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem");
-			foreach(ManagementObject mo in searcher.Get())
+			foreach(ManagementBaseObject mo in searcher.Get())
 			{
 				result += "OS: " + mo["Caption"] + Environment.NewLine;
 				break;
@@ -138,7 +138,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows
 
 			// Get GPU name
 			searcher = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController");
-			foreach(ManagementObject mo in searcher.Get())
+			foreach(ManagementBaseObject mo in searcher.Get())
 			{
 				PropertyData bpp = mo.Properties["CurrentBitsPerPixel"];
 				PropertyData description = mo.Properties["Description"];
diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs
index 7c5e9f782a3742e5bc31cecd2c52cc1d388296d2..bc831fefd4f8a9ee765999053e183c396d013770 100644
--- a/Source/Core/GZBuilder/md3/ModelReader.cs
+++ b/Source/Core/GZBuilder/md3/ModelReader.cs
@@ -102,7 +102,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 				MemoryStream ms = LoadFile(containers, mde.ModelNames[i], true);
 				if(ms == null) 
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': unable to find file.");
+					General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": unable to find file.");
 					continue;
 				}
 
@@ -112,7 +112,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					case ".md3":
 						if(!string.IsNullOrEmpty(mde.FrameNames[i]))
 						{
-							General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': frame names are not supported for MD3 models!");
+							General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": frame names are not supported for MD3 models!");
 							continue;
 						}
 						result = ReadMD3Model(ref bbs, useSkins, ms, device, mde.FrameIndices[i]);
@@ -131,7 +131,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 				//got errors?
 				if(!String.IsNullOrEmpty(result.Errors)) 
 				{
-					General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': " + result.Errors);
+					General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + result.Errors);
 				} 
 				else 
 				{
@@ -164,7 +164,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 							if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1) 
 							{
 								mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
-								errors.Add("image format '" + ext + "' is not supported!");
+								errors.Add("image format \"" + ext + "\" is not supported!");
 								continue;
 							}
 
@@ -177,7 +177,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 							if(t == null) 
 							{
 								mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
-								errors.Add("unable to load skin '" + result.Skins[m] + "'");
+								errors.Add("unable to load skin \"" + result.Skins[m] + "\"");
 								continue;
 							} 
 
@@ -191,7 +191,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 						if(t == null) 
 						{
 							mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
-							errors.Add("unable to load texture '" + mde.TextureNames[i] + "'");
+							errors.Add("unable to load texture \"" + mde.TextureNames[i] + "\"");
 						} 
 						else 
 						{
@@ -203,7 +203,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					if(errors.Count > 0) 
 					{
 						foreach(string e in errors)
-							General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': " + e);
+							General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + e);
 					}
 				}
 			}
@@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 				string magic = ReadString(br, 4);
 				if(magic != "IDP3")
 				{
-					result.Errors = "unknown header: expected 'IDP3', but got '" + magic + "'";
+					result.Errors = "unknown header: expected \"IDP3\", but got \"" + magic + "\"";
 					return result;
 				}
 
@@ -341,7 +341,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			long start = br.BaseStream.Position;
 			
 			string magic = ReadString(br, 4);
-			if(magic != "IDP3") return "error while reading surface. Unknown header: expected 'IDP3', but got '" + magic + "'";
+			if(magic != "IDP3") return "error while reading surface. Unknown header: expected \"IDP3\", but got \"" + magic + "\"";
 
 			string name = ReadString(br, 64);
 			int flags = br.ReadInt32();
@@ -432,8 +432,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			{
 				string magic = ReadString(br, 4);
 				if(magic != "IDP2") //magic number: "IDP2"
-				{  
-					result.Errors = "unknown header: expected 'IDP2', but got '" + magic + "'";
+				{
+					result.Errors = "unknown header: expected \"IDP2\", but got \"" + magic + "\"";
 					return result;
 				}
 
@@ -521,7 +521,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					// No dice? Bail out!
 					if(!framefound)
 					{
-						result.Errors = "unable to find frame '" + framename + "'!";
+						result.Errors = "unable to find frame \"" + framename + "\"!";
 						return result;
 					}
 				}
diff --git a/Source/Core/General/FileLockChecker.cs b/Source/Core/General/FileLockChecker.cs
index 79aa82c0f7599609b0aacb1f4a0662047c20784e..64d0226dead5e8a6e2a639dc25087267d86f5e99 100644
--- a/Source/Core/General/FileLockChecker.cs
+++ b/Source/Core/General/FileLockChecker.cs
@@ -176,8 +176,8 @@ namespace CodeImp.DoomBuilder
 							foreach(Process process in result.Processes)
 							{
 								result.Error += Path.GetFileName(process.MainModule.FileName)
-									+ " ('" + process.MainModule.FileName
-									+ "', started at " + process.StartTime + ")" 
+									+ " (\"" + process.MainModule.FileName
+									+ "\", started at " + process.StartTime + ")" 
 									+ Environment.NewLine + Environment.NewLine;
 							}
 						}
diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs
index a31a12eaf28c23856be5cb0ea7781deeb4dcba35..8307d02ddf1c330d04fd2c6c0a821d70101e9eee 100644
--- a/Source/Core/General/General.cs
+++ b/Source/Core/General/General.cs
@@ -318,7 +318,7 @@ namespace CodeImp.DoomBuilder
 					ConfigurationInfo cfginfo = new ConfigurationInfo(cfg, fullfilename);
 					
 					// Add to lists
-					General.WriteLogLine("Registered game configuration '" + cfginfo.Name + "' from '" + fullfilename + "'");
+					General.WriteLogLine("Registered game configuration \"" + cfginfo.Name + "\" from \"" + fullfilename + "\"");
 					configs.Add(cfginfo);
 				}
 			}
@@ -369,7 +369,7 @@ namespace CodeImp.DoomBuilder
 								catch(Exception e)
 								{
 									// Unable to load configuration
-									errorlogger.Add(ErrorType.Error, "Unable to load the nodebuilder configuration '" + de.Key + "' from \"" + Path.GetFileName(filepath) + "\". Error: " + e.Message);
+									errorlogger.Add(ErrorType.Error, "Unable to load the nodebuilder configuration \"" + de.Key + "\" from \"" + Path.GetFileName(filepath) + "\". Error: " + e.Message);
 								}
 							}
 						}
@@ -677,7 +677,7 @@ namespace CodeImp.DoomBuilder
 				// Show any errors if preferred
 				if(errorlogger.IsErrorAdded)
 				{
-					mainwindow.DisplayStatus(StatusType.Warning, "There were errors during program statup!");
+					mainwindow.DisplayStatus(StatusType.Warning, "There were errors during program startup!");
 					if(!delaymainwindow && General.Settings.ShowErrorsWindow) mainwindow.ShowErrors();
 				}
 
@@ -707,7 +707,7 @@ namespace CodeImp.DoomBuilder
 						if((DateTime.Now - File.GetLastWriteTime(backup)).TotalDays > 30)
 						{
 							File.Delete(backup);
-							WriteLogLine("Removed '" + backup + "' map backup.");
+							WriteLogLine("Removed \"" + backup + "\" map backup.");
 						}
 					}
 				}
@@ -749,7 +749,7 @@ namespace CodeImp.DoomBuilder
 				MessageBoxIcon.Exclamation) == DialogResult.Yes)
 			{
 				// Go to DirectX End-User Runtime Web Installer page (mxd)
-				OpenWebsite("http://www.microsoft.com/en-us/download/details.aspx?id=35");
+				OpenWebsite("https://www.microsoft.com/en-us/download/details.aspx?id=35&44F86079-8679-400C-BFF2-9CA5F2BCBDFC=1");
 			}
 
 			// End program here
@@ -859,7 +859,7 @@ namespace CodeImp.DoomBuilder
 					catch(Exception) { }
 
 					// Warn the user?
-					if(!portablemode) ShowWarningMessage("Failed to enable portable mode.\nMake sure you have write premission for '" + apppath + "' directory.", MessageBoxButtons.OK);
+					if(!portablemode) ShowWarningMessage("Failed to enable portable mode.\nMake sure you have write premission for \"" + apppath + "\" directory.", MessageBoxButtons.OK);
 				}
 				// Resource?
 				else if(string.Compare(curarg, "-RESOURCE", true) == 0)
@@ -1219,8 +1219,8 @@ namespace CodeImp.DoomBuilder
 			if(changemapwindow.ShowDialog(mainwindow) != DialogResult.OK) return;
 
 			// Display status
-			mainwindow.DisplayStatus(StatusType.Busy, "Switching to map '" + changemapwindow.Options.CurrentName + "'...");
-			WriteLogLine("Switching to map '" + changemapwindow.Options.CurrentName + "'...");
+			mainwindow.DisplayStatus(StatusType.Busy, "Switching to map \"" + changemapwindow.Options.CurrentName + "\"...");
+			WriteLogLine("Switching to map \"" + changemapwindow.Options.CurrentName + "\"...");
 			
 			Cursor.Current = Cursors.WaitCursor;
 
@@ -1431,8 +1431,14 @@ namespace CodeImp.DoomBuilder
 					mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!");
 					if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors();
 				}
-				else
+				else if(result)
+				{
 					mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + ".");
+				}
+				else
+				{
+					mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd
+				}
 
 				Cursor.Current = Cursors.Default;
 			}
@@ -1499,10 +1505,16 @@ namespace CodeImp.DoomBuilder
 					{
 						// Show any errors if preferred
 						mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!");
-						if(!delaymainwindow && General.Settings.ShowErrorsWindow) mainwindow.ShowErrors();
+						if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors();
 					}
-					else
+					else if(result)
+					{
 						mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + ".");
+					}
+					else
+					{
+						mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd
+					}
 					
 					Cursor.Current = Cursors.Default;
 				}
@@ -1561,8 +1573,14 @@ namespace CodeImp.DoomBuilder
 					mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!");
 					if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors();
 				}
+				else if(result)
+				{
+					mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + ".");
+				}
 				else
-					mainwindow.DisplayStatus(StatusType.Info, "Map saved into " + map.FileTitle + ".");
+				{
+					mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd
+				}
 
 				Cursor.Current = Cursors.Default;
 			}
diff --git a/Source/Core/General/Launcher.cs b/Source/Core/General/Launcher.cs
index 3f659eb97504e8840685bc08f89787f3f6bc6464..762ff71c51e6f0ec37d1f02768c715b89cdbaaa2 100644
--- a/Source/Core/General/Launcher.cs
+++ b/Source/Core/General/Launcher.cs
@@ -245,7 +245,7 @@ namespace CodeImp.DoomBuilder
 		{
 			if(process != null)
 			{
-				General.ShowWarningMessage("Game engine is already running." + Environment.NewLine + "Please close '" + process.MainModule.FileName + "' first.", MessageBoxButtons.OK);
+				General.ShowWarningMessage("Game engine is already running." + Environment.NewLine + "Please close \"" + process.MainModule.FileName + "\" first.", MessageBoxButtons.OK);
 				return true;
 			}
 
diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs
index 1ca70b56449bc18482a1ad68e2dbd56778871744..6fafb93ff2018374e516c29a5e6ea75cfc0f1ffd 100644
--- a/Source/Core/General/MapManager.cs
+++ b/Source/Core/General/MapManager.cs
@@ -724,7 +724,7 @@ namespace CodeImp.DoomBuilder
         internal bool SaveMap(string newfilepathname, SavePurpose purpose) 
 		{
 			string settingsfile;
-			WAD targetwad;
+			WAD targetwad = null;
 			bool includenodes;
 
 			General.WriteLogLine("Saving map to file: " + newfilepathname);
@@ -773,6 +773,31 @@ namespace CodeImp.DoomBuilder
 				includenodes = VerifyNodebuilderLumps(tempwad, TEMP_MAP_HEADER);
 			}
 
+			//mxd. Target file is read-only?
+			FileInfo info = new FileInfo(newfilepathname);
+			if(info.Exists && info.IsReadOnly)
+			{
+				if(General.ShowWarningMessage("Unable to save the map: target file is read-only.\nRemove read-only flag and save the map anyway?", MessageBoxButtons.YesNo) == DialogResult.Yes)
+				{
+					General.WriteLogLine("Removing read-only flag from the map file...");
+					try
+					{
+						info.IsReadOnly = false;
+					}
+					catch(Exception e)
+					{
+						General.ShowErrorMessage("Failed to remove read-only flag from \"" + filepathname + "\":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK);
+						General.WriteLogLine("Failed to remove read-only flag from \"" + filepathname + "\":" + e.Message);
+						return false;
+					}
+				}
+				else
+				{
+					General.WriteLogLine("Map saving cancelled...");
+					return false;
+				}
+			}
+
 			// Suspend data resources
 			data.Suspend();
 
@@ -916,22 +941,29 @@ namespace CodeImp.DoomBuilder
 					targetwad = new WAD(newfilepathname);
 				}
 			} 
-			catch (IOException) 
+			catch(Exception e) 
 			{
-				General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
-				if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
+				General.ShowErrorMessage("Unable to write the map to target file \"" + newfilepathname + "\":\n" + e.Message, MessageBoxButtons.OK);
+				if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile))
+				{
+					//mxd. Clean-up
+					if(File.Exists(newfilepathname))
+					{
+						//mxd. We MAY've just deleted the map from the target file. Let's pretend this never happened
+						if(targetwad != null) targetwad.Dispose();
+						File.Delete(newfilepathname);
+						File.Move(origwadfile, newfilepathname);
+					}
+					else
+					{
+						File.Delete(origwadfile); 
+					}
+				}
+
 				data.Resume();
-				General.WriteLogLine("Map saving failed");
+				General.WriteLogLine("Map saving failed: " + e.Message);
 				return false;
 			} 
-			catch (UnauthorizedAccessException) 
-			{
-				General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
-				if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
-				data.Resume();
-				General.WriteLogLine("Map saving failed");
-				return false;
-			}
 
 			// Copy map lumps to target file
 			CopyLumpsByType(tempwad, TEMP_MAP_HEADER, targetwad, origmapname, true, true, includenodes, true);
diff --git a/Source/Core/General/UpdateChecker.cs b/Source/Core/General/UpdateChecker.cs
index 26c34fcf91f715eee0b30888910c4d6542838e9c..1bd87f687215490bb8f2ea1c89f65ca82af6e34e 100644
--- a/Source/Core/General/UpdateChecker.cs
+++ b/Source/Core/General/UpdateChecker.cs
@@ -10,8 +10,9 @@ namespace CodeImp.DoomBuilder
 {
 	internal static class UpdateChecker
 	{
+		private const string NO_UPDATE_REQUIRED = "Your version is up to date.";
+		
 		private static BackgroundWorker worker;
-		private static string errordesc;
 		private static bool verbose;
 
 		internal static void PerformCheck(bool verbosemode)
@@ -19,15 +20,7 @@ namespace CodeImp.DoomBuilder
 			// Update check already runing?
 			if(worker != null && worker.IsBusy)
 			{
-				if(verbosemode)
-				{
-					General.ShowWarningMessage("Update check is already running!", MessageBoxButtons.OK);
-				}
-				else
-				{
-					General.ErrorLogger.Add(ErrorType.Warning, "Update check is already running!");
-					General.MainWindow.ShowErrors();
-				}
+				if(verbosemode) General.ShowWarningMessage("Update check is already running!", MessageBoxButtons.OK);
 				return;
 			}
 
@@ -45,7 +38,7 @@ namespace CodeImp.DoomBuilder
 			string updaterpath = Path.Combine(General.AppPath, "Updater.exe");
 			if(!File.Exists(updaterpath))
 			{
-				errordesc = "Update check failed: '" + updaterpath + "' does not exist!";
+				e.Result = "Update check failed: \"" + updaterpath + "\" does not exist!";
 				e.Cancel = true;
 				return;
 			} 
@@ -53,7 +46,7 @@ namespace CodeImp.DoomBuilder
 			string inipath = Path.Combine(General.AppPath, "Updater.ini");
 			if(!File.Exists(inipath))
 			{
-				errordesc = "Update check failed: '" + inipath + "' does not exist!";
+				e.Result = "Update check failed: \"" + inipath + "\" does not exist!";
 				e.Cancel = true;
 				return;
 			}
@@ -61,7 +54,7 @@ namespace CodeImp.DoomBuilder
 			string url = GetDownloadUrl(inipath);
 			if(string.IsNullOrEmpty(url))
 			{
-				errordesc = "Update check failed: failed to get update url from Updater.ini!";
+				e.Result = "Update check failed: failed to get update url from Updater.ini!";
 				e.Cancel = true;
 				return;
 			}
@@ -77,7 +70,7 @@ namespace CodeImp.DoomBuilder
 			{
 				if(stream == null)
 				{
-					errordesc = "Update check failed: failed to retrieve remote revision info.";
+					e.Result = "Update check failed: failed to retrieve remote revision info.";
 					e.Cancel = true;
 					return;
 				}
@@ -90,7 +83,7 @@ namespace CodeImp.DoomBuilder
 
 				if(!int.TryParse(s, out remoterev))
 				{
-					errordesc = "Update check failed: failed to retrieve remote revision number.";
+					e.Result = "Update check failed: failed to retrieve remote revision number.";
 					e.Cancel = true;
 					return;
 				}
@@ -103,7 +96,7 @@ namespace CodeImp.DoomBuilder
 
 				if(string.IsNullOrEmpty(changelog))
 				{
-					errordesc = "Update check failed: failed to retrieve changelog.";
+					e.Result = "Update check failed: failed to retrieve changelog.";
 					e.Cancel = true;
 					return;
 				}
@@ -113,24 +106,20 @@ namespace CodeImp.DoomBuilder
 			}
 			else if(verbose)
 			{
-				errordesc = "Your version is up to date";
+				e.Result = NO_UPDATE_REQUIRED;
 			}
 		}
 
-		private static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
+		private static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
 		{
 			worker = null;
+			string errordesc = (e.Result != null ? e.Result.ToString() : string.Empty);
 			if(!string.IsNullOrEmpty(errordesc))
 			{
 				if(verbose)
-				{
 					General.ShowWarningMessage(errordesc, MessageBoxButtons.OK);
-				}
-				else
-				{
-					General.ErrorLogger.Add(ErrorType.Warning, errordesc);
-					General.MainWindow.ShowErrors();
-				}
+				else if(errordesc != NO_UPDATE_REQUIRED)
+					General.ErrorLogger.Add(ErrorType.Error, errordesc);
 			}
 		}
 
@@ -178,47 +167,42 @@ namespace CodeImp.DoomBuilder
 		private static MemoryStream DownloadWebFile(string url)
 		{
 			// Open a data stream from the supplied URL
-			WebRequest webReq = WebRequest.Create(url);
-			WebResponse webResponse;
+			WebRequest request = WebRequest.Create(url);
+			WebResponse response;
 
 			try
 			{
-				webResponse = webReq.GetResponse();
+				response = request.GetResponse();
 			}
 			catch(WebException)
 			{
 				return null;
 			}
 			
-			Stream dataStream = webResponse.GetResponseStream();
+			Stream source = response.GetResponseStream();
+			if(source == null) return null;
 
 			// Download the data in chuncks
-			byte[] dataBuffer = new byte[1024];
+			byte[] buffer = new byte[1024];
 
 			// Download the data
-			MemoryStream memoryStream = new MemoryStream();
+			MemoryStream result = new MemoryStream();
 			while(!General.MainWindow.IsDisposed)
 			{
 				// Let's try and read the data
-				int bytesFromStream = dataStream.Read(dataBuffer, 0, dataBuffer.Length);
-				if(bytesFromStream == 0)
-				{
-					// Download complete
-					break;
-				}
-				else 
-				{
-					// Write the downloaded data
-					memoryStream.Write(dataBuffer, 0, bytesFromStream);
-				}
+				int numbytes = source.Read(buffer, 0, buffer.Length);
+				if(numbytes == 0) break; // Download complete
+
+				// Write the downloaded data
+				result.Write(buffer, 0, numbytes);
 			}
 
 			// Release resources
-			dataStream.Close();
+			source.Close();
 
 			// Rewind and return the stream
-			memoryStream.Position = 0;
-			return memoryStream;
+			result.Position = 0;
+			return result;
 		}
 
 		private static string GetDownloadUrl(string filename)
diff --git a/Source/Core/Geometry/InterpolationTools.cs b/Source/Core/Geometry/InterpolationTools.cs
index 7ca42aa131217cf4f8777396fcfcdb25b182d4d9..7d8f2fb9cbfd79938f984da92e2afcfba93cf8e3 100644
--- a/Source/Core/Geometry/InterpolationTools.cs
+++ b/Source/Core/Geometry/InterpolationTools.cs
@@ -21,7 +21,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				case Mode.EASE_IN_SINE: return EaseInSine(val1, val2, delta);
 				case Mode.EASE_OUT_SINE: return EaseOutSine(val1, val2, delta);
 				case Mode.EASE_IN_OUT_SINE: return EaseInOutSine(val1, val2, delta);
-				default: throw new NotImplementedException("InterpolationTools.Interpolate: '" + mode + "' mode is not supported!");
+				default: throw new NotImplementedException("InterpolationTools.Interpolate: \"" + mode + "\" mode is not supported!");
 			}
 		}
 		
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index 5d076db369db27ee17aa41e637a232769fd43d41..fa6312187322eac68f1c141c32b0f417ab3533e9 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -1845,7 +1845,7 @@ namespace CodeImp.DoomBuilder.Geometry
 					return GetSidedefBottomOffsetY(side, offset, scaleY, fromNormalized);
 
 				default:
-					throw new NotSupportedException("Tools.GetSidedefOffsetY: '" + part + "' geometry type is not supported!");
+					throw new NotSupportedException("Tools.GetSidedefOffsetY: \"" + part + "\" geometry type is not supported!");
 			}
 		}
 
@@ -2236,7 +2236,7 @@ namespace CodeImp.DoomBuilder.Geometry
 		/// <summary>Flips sector linedefs so they all face either inward or outward.</summary>
 		public static void FlipSectorLinedefs(ICollection<Sector> sectors, bool selectedlinesonly) 
 		{
-			Dictionary<Linedef, bool> processed = new Dictionary<Linedef, bool>();
+			HashSet<Linedef> processed = new HashSet<Linedef>();
 			
 			foreach(Sector s in sectors) 
 			{
@@ -2248,7 +2248,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				//sort lines
 				foreach(Sidedef side in s.Sidedefs) 
 				{
-					if(processed.ContainsKey(side.Line)) continue;
+					if(processed.Contains(side.Line)) continue;
 					if(selectedlinesonly && !side.Line.Selected)
 					{
 						if(side == side.Line.Front) unselectedfrontlines++;
@@ -2261,7 +2261,7 @@ namespace CodeImp.DoomBuilder.Geometry
 					else
 						backlines.Add(side.Line);
 
-					processed.Add(side.Line, false);
+					processed.Add(side.Line);
 				}
 
 				//flip lines
diff --git a/Source/Core/IO/ClipboardStreamReader.cs b/Source/Core/IO/ClipboardStreamReader.cs
index 22fc2652e1784a7ca9880b878687c180f30dc3fa..4580b84938e91b14fdfa8f284181f991bdd2c57a 100644
--- a/Source/Core/IO/ClipboardStreamReader.cs
+++ b/Source/Core/IO/ClipboardStreamReader.cs
@@ -7,6 +7,7 @@ using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Types;
+using CodeImp.DoomBuilder.Windows;
 
 #endregion
 
@@ -29,32 +30,56 @@ namespace CodeImp.DoomBuilder.IO
 			public Dictionary<string, bool> Flags;
 		}
 
-		private bool uselongtexturenames; //mxd
-
 		#endregion 
 
 		#region ================== Properties
 
-		public bool UseLongTextureNames { get { return uselongtexturenames; } } //mxd
-
 		#endregion
 
 		#region ================== Reading
 
 		// This reads from a stream
-		public MapSet Read(MapSet map, Stream stream) 
+		public bool Read(MapSet map, Stream stream) 
 		{
 			BinaryReader reader = new BinaryReader(stream);
 
+			//mxd. Sanity checks
+			int numverts = reader.ReadInt32();
+			if(map.Vertices.Count + numverts >= General.Map.FormatInterface.MaxVertices)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of vertices (" + (map.Vertices.Count + numverts) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxVertices + ").");
+				return false;
+			}
+
+			int numsectors = reader.ReadInt32();
+			if(map.Sectors.Count + numsectors >= General.Map.FormatInterface.MaxSectors)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of sectors (" + (map.Sectors.Count + numsectors) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxSectors + ").");
+				return false;
+			}
+
+			int numlinedefs = reader.ReadInt32();
+			if(map.Linedefs.Count + numlinedefs >= General.Map.FormatInterface.MaxLinedefs)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of linedefs (" + (map.Linedefs.Count + numlinedefs) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxLinedefs + ").");
+				return false;
+			}
+
+			int numthings = reader.ReadInt32();
+			if(map.Things.Count + numthings >= General.Map.FormatInterface.MaxThings)
+			{
+				General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of things (" + (map.Things.Count + numthings) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxThings + ").");
+				return false;
+			}
+
 			// Read the map
-			uselongtexturenames = reader.ReadBoolean(); //mxd
 			Dictionary<int, Vertex> vertexlink = ReadVertices(map, reader);
 			Dictionary<int, Sector> sectorlink = ReadSectors(map, reader);
 			Dictionary<int, SidedefData> sidedeflink = ReadSidedefs(reader);
 			ReadLinedefs(map, reader, vertexlink, sectorlink, sidedeflink);
 			ReadThings(map, reader);
 
-			return map;
+			return true;
 		}
 
 		private static Dictionary<int, Vertex> ReadVertices(MapSet map, BinaryReader reader) 
@@ -388,7 +413,7 @@ namespace CodeImp.DoomBuilder.IO
 						break;
 
 					default: //WOLOLO! ERRORS!
-						throw new Exception("Got unknown value type while reading custom fields from clipboard data! Field '" + name + "', type '" + type + "', primitive type '" + valueType + "'");
+						throw new Exception("Got unknown value type while reading custom fields from clipboard data! Field \"" + name + "\", type \"" + type + "\", primitive type \"" + valueType + "\"");
 				}
 			}
 
diff --git a/Source/Core/IO/ClipboardStreamWriter.cs b/Source/Core/IO/ClipboardStreamWriter.cs
index 28ee6f1bd3c66fc26f40713e81460061f8c0a0e7..7c7bce25361d9375c1dc53c19db39a40dc019712 100644
--- a/Source/Core/IO/ClipboardStreamWriter.cs
+++ b/Source/Core/IO/ClipboardStreamWriter.cs
@@ -22,7 +22,7 @@ namespace CodeImp.DoomBuilder.IO
 		
 		#region ================== Variables
 
-		private Configuration config;
+		private readonly Configuration config;
 
 		#endregion
 
@@ -83,13 +83,13 @@ namespace CodeImp.DoomBuilder.IO
 
 		#region ================== Writing
 
-		public void Write(MapSet map, Stream stream, bool longtexturenames) 
+		public void Write(MapSet map, Stream stream) 
 		{
-			Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream, longtexturenames);
+			Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream);
 		}
 
 		public void Write(ICollection<Vertex> vertices, ICollection<Linedef> linedefs, ICollection<Sidedef> sidedefs, 
-						  ICollection<Sector> sectors, ICollection<Thing> things, Stream stream, bool longtexturenames) 
+						  ICollection<Sector> sectors, ICollection<Thing> things, Stream stream) 
 		{
 			// Create collections
 			Dictionary<Vertex, int> vertexids = new Dictionary<Vertex, int>();
@@ -104,7 +104,10 @@ namespace CodeImp.DoomBuilder.IO
 			BinaryWriter writer = new BinaryWriter(stream);
 			
 			// Write the data structures to stream
-			writer.Write(longtexturenames); //mxd
+			writer.Write(vertices.Count); //mxd
+			writer.Write(sectors.Count); //mxd
+			writer.Write(linedefs.Count); //mxd
+			writer.Write(things.Count); //mxd
 			WriteVertices(vertices, writer);
 			WriteSectors(sectors, writer);
 			WriteSidedefs(sidedefs, writer, sectorids);
@@ -292,8 +295,8 @@ namespace CodeImp.DoomBuilder.IO
 					writer.Write(s.ToCharArray());
 				} 
 				else //WOLOLO! ERRORS!
-				{ 
-					General.ErrorLogger.Add(ErrorType.Error, "Unable to copy Universal Field '" + f.Key + "' to clipboard: unknown value type '" + f.Value.Type + "'!");
+				{
+					General.ErrorLogger.Add(ErrorType.Error, "Unable to copy Universal Field \"" + f.Key + "\" to clipboard: unknown value type \"" + f.Value.Type + "\"!");
 				}
 			}
 		}
diff --git a/Source/Core/IO/Configuration.cs b/Source/Core/IO/Configuration.cs
index d5008d22b3f23a7b5409eab15271a61f09114e22..9eb36e9994c1a85d860af961ed365c67a5e7f5e7 100644
--- a/Source/Core/IO/Configuration.cs
+++ b/Source/Core/IO/Configuration.cs
@@ -804,7 +804,8 @@ namespace CodeImp.DoomBuilder.IO
 							case "true": return true;
 							case "false": return false;
 							case "null": return null;
-							default: RaiseError(file, line, ERROR_KEYWORDUNKNOWN + "\nUnrecognized token: '" + val.Trim().ToLowerInvariant() + "'"); return null;
+							default: RaiseError(file, line, ERROR_KEYWORDUNKNOWN + "\nUnrecognized token: \"" + val.Trim().ToLowerInvariant() + "\"");
+								return null;
 						}
 					}
 				}
@@ -860,7 +861,7 @@ namespace CodeImp.DoomBuilder.IO
 					} 
 					else 
 					{
-						RaiseError(file, line, "Include missing structure '" + args[1] + "' in file '" + includefile + "'");
+						RaiseError(file, line, "Include missing structure \"" + args[1] + "\" in file \"" + includefile + "\"");
 						return;
 					}
 				}
@@ -885,7 +886,7 @@ namespace CodeImp.DoomBuilder.IO
 			}
 			catch(Exception e)
 			{
-				RaiseError(file, line, "Unable to include file '" + includefile + "'. " + e.GetType().Name + ": " + e.Message);
+				RaiseError(file, line, "Unable to include file \"" + includefile + "\". " + e.GetType().Name + ": " + e.Message);
 				return;
 			}
 			
@@ -915,7 +916,7 @@ namespace CodeImp.DoomBuilder.IO
 					}
 					else
 					{
-						RaiseError(file, line, "Include missing structure '" + args[1] + "' in file '" + includefile + "'");
+						RaiseError(file, line, "Include missing structure \"" + args[1] + "\" in file \"" + includefile + "\"");
 						return;
 					}
 				}
diff --git a/Source/Core/IO/UniversalEntry.cs b/Source/Core/IO/UniversalEntry.cs
index a69b9482fda2cf77abad02e50fcb0329492b74d4..d08d1b4d49286b5e24b7ee83d93b3e57c2f610e0 100644
--- a/Source/Core/IO/UniversalEntry.cs
+++ b/Source/Core/IO/UniversalEntry.cs
@@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.IO
 		// Will throw and exception when it is not
 		public void ValidateType(Type t)
 		{
-			if(value.GetType() != t) throw new Exception("The value of entry '" + key + "' is of incompatible type (expected " + t.Name + ")");
+			if(value.GetType() != t) throw new Exception("The value of entry \"" + key + "\" is of incompatible type (expected " + t.Name + ")");
 		}
 
 		//mxd 
diff --git a/Source/Core/IO/UniversalParser.cs b/Source/Core/IO/UniversalParser.cs
index 6a881526d0f11c7dc607ee9c276ce32dd916adde..cd4fa47855e6129eeadb48713ec5fa5837d98ec2 100644
--- a/Source/Core/IO/UniversalParser.cs
+++ b/Source/Core/IO/UniversalParser.cs
@@ -414,13 +414,13 @@ namespace CodeImp.DoomBuilder.IO
 								catch(FormatException)
 								{
 									// ERROR: Invalid value in assignment
-									RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'");
+									RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\"");
 								}
 							}
 							catch(FormatException)
 							{
 								// ERROR: Invalid value in assignment
-								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'");
+								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\"");
 							}
 						}
 						// Floating point?
@@ -434,7 +434,7 @@ namespace CodeImp.DoomBuilder.IO
 							catch(FormatException)
 							{ 
 								// ERROR: Invalid value in assignment
-								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'");
+								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\"");
 							}
 							
 							// Add it to struct
@@ -476,13 +476,13 @@ namespace CodeImp.DoomBuilder.IO
 								catch(FormatException)
 								{ 
 									// ERROR: Invalid value in assignment
-									RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'");
+									RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\"");
 								}
 							}
 							catch(FormatException)
 							{ 
 								// ERROR: Invalid value in assignment
-								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'");
+								RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\"");
 							}
 						}
 						
@@ -533,7 +533,7 @@ namespace CodeImp.DoomBuilder.IO
 									catch(FormatException)
 									{ 
 										// ERROR: Invalid value in assignment
-										RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + v.Trim() + "'");
+										RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\"");
 									}
 									
 									// Convert the number to a char
@@ -541,7 +541,7 @@ namespace CodeImp.DoomBuilder.IO
 									catch(FormatException)
 									{ 
 										// ERROR: Invalid value in assignment
-										RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + v.Trim() + "'");
+										RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\"");
 									}
 									
 									// Add the char
@@ -623,7 +623,7 @@ namespace CodeImp.DoomBuilder.IO
 								
 							default:
 								// Unknown keyword
-								RaiseError(line, ERROR_KEYWORDUNKNOWN + "\n\nUnrecognized token: '" + val.ToString().Trim() + "'");
+								RaiseError(line, ERROR_KEYWORDUNKNOWN + "\n\nUnrecognized token: \"" + val.ToString().Trim() + "\"");
 								break;
 						}
 						
diff --git a/Source/Core/IO/UniversalStreamReader.cs b/Source/Core/IO/UniversalStreamReader.cs
index b506246970aca106cc5b1a801b2304a10f44f21e..c52666a55c70a3420c032e1fa025cdb3624625e3 100644
--- a/Source/Core/IO/UniversalStreamReader.cs
+++ b/Source/Core/IO/UniversalStreamReader.cs
@@ -494,7 +494,7 @@ namespace CodeImp.DoomBuilder.IO
 					} 
 					else if(!e.IsValidType(e.Value.GetType())) 
 					{
-						General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry '" + e.Key + "' is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored.");
+						General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored.");
 						continue;
 					}
 
@@ -522,7 +522,7 @@ namespace CodeImp.DoomBuilder.IO
 							} 
 							else if(!e.IsValidType(e.Value.GetType())) 
 							{
-								General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry '" + e.Key + "' is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored.");
+								General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored.");
 								continue;
 							}
 
@@ -582,7 +582,7 @@ namespace CodeImp.DoomBuilder.IO
 			{
 				// Report error when entry is required!
 				if(required)
-					General.ErrorLogger.Add(ErrorType.Error, "Error while reading UDMF map data: Missing required field '" + entryname + "' at " + where + ".");
+					General.ErrorLogger.Add(ErrorType.Error, "Error while reading UDMF map data: Missing required field \"" + entryname + "\" at " + where + ".");
 
 				// Make default entry
 				result = defaultvalue;
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index ef6300a87a3724ca7b9e95a13e8a5b1e6505a2ef..07a8f3f08a26d76ae8f54fedb15b045de6969b26 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -2721,7 +2721,7 @@ namespace CodeImp.DoomBuilder.Map
 			{
 				float px = t.Position.x;
 				float py = t.Position.y;
-				float ts = ((t.FixedSize && General.Map.Renderer2D.Scale > 1.0f) ? t.Size / General.Map.Renderer2D.Scale : t.Size);
+				float ts = (((t.FixedSize || General.Settings.FixedThingsScale) && General.Map.Renderer2D.Scale > 1.0f) ? t.Size / General.Map.Renderer2D.Scale : t.Size);
 
 				//mxd. Within range?
 				if(px < range.Left - ts || px > range.Right + ts || py < range.Top - ts || py > range.Bottom + ts) continue;
diff --git a/Source/Core/Plugins/Plugin.cs b/Source/Core/Plugins/Plugin.cs
index 3c54801593b2af71d0c548bfb9e10f61013bcfd6..536f6e01747a594389de816a5d4bc8c4eb0a2029 100644
--- a/Source/Core/Plugins/Plugin.cs
+++ b/Source/Core/Plugins/Plugin.cs
@@ -66,7 +66,7 @@ namespace CodeImp.DoomBuilder.Plugins
 			// Initialize
 			string shortfilename = Path.GetFileName(filename);
 			name = Path.GetFileNameWithoutExtension(filename);
-			General.WriteLogLine("Loading plugin '" + name + "' from '" + shortfilename + "'...");
+			General.WriteLogLine("Loading plugin \"" + name + "\" from \"" + shortfilename + "\"...");
 
 			try
 			{
@@ -218,7 +218,7 @@ namespace CodeImp.DoomBuilder.Plugins
 			catch(TargetInvocationException e)
 			{
 				// Error!
-				string error = "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'.";
+				string error = "Failed to create class instance \"" + t.Name + "\" from plugin \"" + name + "\".";
 				General.ShowErrorMessage(error + Environment.NewLine + Environment.NewLine + "See the error log for more details", MessageBoxButtons.OK, false);
 				General.WriteLogLine(error + " " + e.InnerException.GetType().Name + " at target: " 
 					+ e.InnerException.Message + Environment.NewLine + "Stacktrace: " + e.InnerException.StackTrace.Trim());
@@ -227,7 +227,7 @@ namespace CodeImp.DoomBuilder.Plugins
 			catch(Exception e)
 			{
 				// Error!
-				string error = "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'.";
+				string error = "Failed to create class instance \"" + t.Name + "\" from plugin \"" + name + "\".";
 				General.ShowErrorMessage(error + Environment.NewLine + Environment.NewLine + "See the error log for more details", MessageBoxButtons.OK, false);
 				General.WriteLogLine(error + " " + e.GetType().Name + ": " + e.Message + Environment.NewLine
 					+ "Stacktrace: " + e.StackTrace.Trim());
diff --git a/Source/Core/Properties/Resources.Designer.cs b/Source/Core/Properties/Resources.Designer.cs
index 57be92f732755207060702b389a64a6131a29320..a6f6670d6efa772d71326af7ace3616f872e2716 100644
--- a/Source/Core/Properties/Resources.Designer.cs
+++ b/Source/Core/Properties/Resources.Designer.cs
@@ -1,7 +1,7 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
-//     Dieser Code wurde von einem Tool generiert.
-//     Laufzeitversion:4.0.30319.42000
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.5466
 //
 //     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
 //     der Code erneut generiert wird.
@@ -370,9 +370,13 @@ namespace CodeImp.DoomBuilder.Properties {
             }
         }
         
-        /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
-        /// </summary>
+        internal static System.Drawing.Bitmap FixedThingsScale {
+            get {
+                object obj = ResourceManager.GetObject("FixedThingsScale", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         internal static System.Drawing.Bitmap fog {
             get {
                 object obj = ResourceManager.GetObject("fog", resourceCulture);
diff --git a/Source/Core/Properties/Resources.resx b/Source/Core/Properties/Resources.resx
index 7ac990d15f0bcefd46c46fe4f8daee6b45c25048..46ad6a9e28eebea3f3cb9f62f1aaf4de7b3f8108 100644
--- a/Source/Core/Properties/Resources.resx
+++ b/Source/Core/Properties/Resources.resx
@@ -574,4 +574,7 @@
   <data name="ScriptProperty" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ScriptProperty.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="FixedThingsScale" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\FixedThingsScale.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
\ No newline at end of file
diff --git a/Source/Core/Rendering/D3DDevice.cs b/Source/Core/Rendering/D3DDevice.cs
index a4fa7c8381e5a28bc8e2fd15f4215dcfe6b86507..888dfb1e3e991a5c26739e35ee493a22f67ee4e0 100644
--- a/Source/Core/Rendering/D3DDevice.cs
+++ b/Source/Core/Rendering/D3DDevice.cs
@@ -168,8 +168,8 @@ namespace CodeImp.DoomBuilder.Rendering
 			device.SetRenderState(RenderState.NormalizeNormals, false);
 			device.SetRenderState(RenderState.PointSpriteEnable, false);
 			device.SetRenderState(RenderState.RangeFogEnable, false);
-            device.SetRenderState(RenderState.ShadeMode, ShadeMode.Flat); //mxd
-            device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
+			device.SetRenderState(RenderState.ShadeMode, ShadeMode.Gouraud);
+			device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
 			device.SetRenderState(RenderState.SpecularEnable, false);
 			device.SetRenderState(RenderState.StencilEnable, false);
 			device.SetRenderState(RenderState.TextureFactor, -1);
diff --git a/Source/Core/Rendering/IRenderer2D.cs b/Source/Core/Rendering/IRenderer2D.cs
index deae50f17ce3ecc3b398aa6146fb3ba3e06adda1..6ae6863732a9f0185de2afdd21177c623557fa74 100644
--- a/Source/Core/Rendering/IRenderer2D.cs
+++ b/Source/Core/Rendering/IRenderer2D.cs
@@ -74,6 +74,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		void RenderRectangleFilled(RectangleF rect, PixelColor c, bool transformrect, ImageData texture);
 		void RenderLine(Vector2D start, Vector2D end, float thickness, PixelColor c, bool transformcoords);
 		void RenderArrows(ICollection<Line3D> line); //mxd
+		void RenderArrows(ICollection<Line3D> line, bool transformcoords); //mxd
 		void RenderText(TextLabel text);
 		void RenderGeometry(FlatVertex[] vertices, ImageData texture, bool transformcoords);
 		void RenderHighlight(FlatVertex[] vertices, int color); //mxd
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index e92ce23c841c895dfba7d8346a16f6e64cf5f433..e5e5ad815c4c0743ffb9c928dde95f2620cd1412 100644
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -250,7 +250,6 @@ namespace CodeImp.DoomBuilder.Rendering
 						// BACKGROUND
 						case RendererLayer.Background:
 							if((backimageverts == null) || (General.Map.Grid.Background.Texture == null)) break;
-							graphics.Device.SetTexture(0, General.Map.Grid.Background.Texture);
 							graphics.Shaders.Display2D.Texture1 = General.Map.Grid.Background.Texture;
 							graphics.Shaders.Display2D.SetSettings(1f / windowsize.Width, 1f / windowsize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -261,7 +260,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 						// GRID
 						case RendererLayer.Grid:
-							graphics.Device.SetTexture(0, backtex);
 							graphics.Shaders.Display2D.Texture1 = backtex;
 							graphics.Shaders.Display2D.SetSettings(1f / backsize.Width, 1f / backsize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -271,7 +269,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 						// GEOMETRY
 						case RendererLayer.Geometry:
-							graphics.Device.SetTexture(0, plottertex);
 							graphics.Shaders.Display2D.Texture1 = plottertex;
 							graphics.Shaders.Display2D.SetSettings(1f / structsize.Width, 1f / structsize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -281,7 +278,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 						// THINGS
 						case RendererLayer.Things:
-							graphics.Device.SetTexture(0, thingstex);
 							graphics.Shaders.Display2D.Texture1 = thingstex;
 							graphics.Shaders.Display2D.SetSettings(1f / thingssize.Width, 1f / thingssize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -291,7 +287,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 						// OVERLAY
 						case RendererLayer.Overlay:
-							graphics.Device.SetTexture(0, overlaytex);
 							graphics.Shaders.Display2D.Texture1 = overlaytex;
 							graphics.Shaders.Display2D.SetSettings(1f / overlaysize.Width, 1f / overlaysize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -301,7 +296,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 						// SURFACE
 						case RendererLayer.Surface:
-							graphics.Device.SetTexture(0, surfacetex);
 							graphics.Shaders.Display2D.Texture1 = surfacetex;
 							graphics.Shaders.Display2D.SetSettings(1f / overlaysize.Width, 1f / overlaysize.Height, FSAA_FACTOR, layer.alpha, false);
 							graphics.Shaders.Display2D.BeginPass(aapass);
@@ -317,7 +311,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				graphics.Present();
 
 				// Release binds
-				graphics.Device.SetTexture(0, null);
 				graphics.Shaders.Display2D.Texture1 = null;
 				graphics.Device.SetStreamSource(0, null, 0, 0);
 			}
@@ -985,20 +978,22 @@ namespace CodeImp.DoomBuilder.Rendering
 
 		// This makes vertices for a thing
 		// Returns false when not on the screen
-		private bool CreateThingBoxVerts(Thing t, ref FlatVertex[] verts, Dictionary<Thing, Vector2D> thingsByPosition, int offset, PixelColor c)
+		private bool CreateThingBoxVerts(Thing t, ref FlatVertex[] verts, ref List<Line3D> bboxes, Dictionary<Thing, Vector2D> thingsByPosition, int offset, PixelColor c, byte bboxalpha)
 		{
             float thingsize = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : t.Size;
 			if(thingsize * scale < MINIMUM_THING_RADIUS) return false; //mxd. Don't render tiny little things
 
-			// Determine size
-			float circlesize = (t.FixedSize && (scale > 1.0f) ? thingsize /* * THING_CIRCLE_SIZE*/ : thingsize * scale /* * THING_CIRCLE_SIZE*/);
+			// Determine sizes
+			float circlesize = ((t.FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size : t.Size * scale);
+			float bboxsize = ((!t.FixedSize && General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size * scale : -1); //mxd
+			float screensize = Math.Max(circlesize, bboxsize); //mxd
 			
 			// Transform to screen coordinates
 			Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale);
 			
 			// Check if the thing is actually on screen
-			if(((screenpos.x + circlesize) <= 0.0f) || ((screenpos.x - circlesize) >= windowsize.Width) ||
-			   ((screenpos.y + circlesize) <= 0.0f) || ((screenpos.y - circlesize) >= windowsize.Height))
+			if(((screenpos.x + screensize) <= 0.0f) || ((screenpos.x - screensize) >= windowsize.Width) ||
+			   ((screenpos.y + screensize) <= 0.0f) || ((screenpos.y - screensize) >= windowsize.Height))
 				return false;
 
 			// Get integral color
@@ -1036,6 +1031,22 @@ namespace CodeImp.DoomBuilder.Rendering
 			//mxd. Add to list
 			thingsByPosition.Add(t, screenpos);
 
+			//mxd. Add bounding box?
+			if(bboxsize > 0)
+			{
+				PixelColor boxcolor = c.WithAlpha(bboxalpha);
+
+				Vector2D tl = new Vector2D(screenpos.x - bboxsize, screenpos.y - bboxsize);
+				Vector2D tr = new Vector2D(screenpos.x + bboxsize, screenpos.y - bboxsize);
+				Vector2D bl = new Vector2D(screenpos.x - bboxsize, screenpos.y + bboxsize);
+				Vector2D br = new Vector2D(screenpos.x + bboxsize, screenpos.y + bboxsize);
+
+				bboxes.Add(new Line3D(tl, tr, boxcolor, false));
+				bboxes.Add(new Line3D(tr, br, boxcolor, false));
+				bboxes.Add(new Line3D(bl, br, boxcolor, false));
+				bboxes.Add(new Line3D(tl, bl, boxcolor, false));
+			}
+
 			// Done
 			return true;
 		}
@@ -1045,10 +1056,10 @@ namespace CodeImp.DoomBuilder.Rendering
 		{
             // Determine size
             float thingsize = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : t.Size;
-            float arrowsize = (t.FixedSize && (scale > 1.0f) ? thingsize : thingsize * scale) * THING_ARROW_SIZE; //mxd
+            float arrowsize = ((t.FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size : t.Size * scale) * THING_ARROW_SIZE; //mxd
 
-			// Setup rotated rect for arrow
-			float sinarrowsize = (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * arrowsize;
+            // Setup rotated rect for arrow
+            float sinarrowsize = (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * arrowsize;
 			float cosarrowsize = (float)Math.Cos(t.Angle + Angle2D.PI * 0.25f) * arrowsize;
 
 			verts[offset].x = screenpos.x + sinarrowsize;
@@ -1123,6 +1134,7 @@ namespace CodeImp.DoomBuilder.Rendering
 				
 				// Make alpha color
 				Color4 alphacolor = new Color4(alpha, 1.0f, 1.0f, 1.0f);
+				bool isthingsmode = (General.Editing.Mode.GetType().Name == "ThingsMode");
 				
 				// Set renderstates for things rendering
 				graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
@@ -1136,7 +1148,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride);
 				
 				// Set things texture
-				graphics.Device.SetTexture(0, thingtexture.Texture);
 				graphics.Shaders.Things2D.Texture1 = thingtexture.Texture;
 				SetWorldTransformation(false);
 				graphics.Shaders.Things2D.SetSettings(alpha);
@@ -1148,6 +1159,7 @@ namespace CodeImp.DoomBuilder.Rendering
 				// Determine next lock size
 				int locksize = (things.Count > THING_BUFFER_SIZE) ? THING_BUFFER_SIZE : things.Count;
 				FlatVertex[] verts = new FlatVertex[THING_BUFFER_SIZE * 6];
+				List<Line3D> bboxes = new List<Line3D>(locksize); //mxd
 
 				//mxd
 				Dictionary<int, List<Thing>> thingsByType = new Dictionary<int, List<Thing>>();
@@ -1171,7 +1183,8 @@ namespace CodeImp.DoomBuilder.Rendering
 					
 					// Create vertices
 					PixelColor tc = fixedcolor ? c : DetermineThingColor(t);
-					if(CreateThingBoxVerts(t, ref verts, thingsByPosition, buffercount * 6, tc)) 
+					byte bboxalpha = (byte)(alpha * ((!fixedcolor && !t.Selected && isthingsmode) ? 128 : 255));
+					if(CreateThingBoxVerts(t, ref verts, ref bboxes, thingsByPosition, buffercount * 6, tc, bboxalpha))
 					{
 						buffercount++;
 
@@ -1234,8 +1247,8 @@ namespace CodeImp.DoomBuilder.Rendering
 					}
 					if(sprite.Texture == null) sprite.CreateTexture();
 
-					graphics.Device.SetTexture(0, sprite.Texture);
 					graphics.Shaders.Things2D.Texture1 = sprite.Texture;
+					graphics.Shaders.Things2D.ApplySettings();
 
 					// Determine next lock size
 					locksize = (group.Value.Count > THING_BUFFER_SIZE) ? THING_BUFFER_SIZE : group.Value.Count;
@@ -1246,7 +1259,7 @@ namespace CodeImp.DoomBuilder.Rendering
 					totalcount = 0;
 
 					float spriteWidth, spriteHeight;
-					float spriteScale = (group.Value[0].FixedSize && (scale > 1.0f)) ? 1.0f : scale;
+					float spriteScale = ((group.Value[0].FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f)) ? 1.0f : scale;
 
                     float radius = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : info.Radius;
 					if(sprite.Width > sprite.Height) 
@@ -1310,7 +1323,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				graphics.Shaders.Things2D.EndPass();
 
 				//mxd. Render thing arrows
-				graphics.Device.SetTexture(0, thingtexture.Texture);
 				graphics.Shaders.Things2D.Texture1 = thingtexture.Texture;
 				graphics.Shaders.Things2D.BeginPass(0);
 
@@ -1418,6 +1430,9 @@ namespace CodeImp.DoomBuilder.Rendering
 				}
 
 				graphics.Shaders.Things2D.End();
+
+				//mxd. Render thing boxes
+				RenderArrows(bboxes, false);
 			}
 		}
 		
@@ -1625,7 +1640,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
 				graphics.Device.SetRenderState(RenderState.FogEnable, false);
 				graphics.Shaders.Display2D.Texture1 = t;
-				graphics.Device.SetTexture(0, t);
 				SetWorldTransformation(transformcoords);
 				graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 				
@@ -1682,7 +1696,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				graphics.Shaders.Display2D.Texture1 = graphics.FontTexture;
 				SetWorldTransformation(false);
 				graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
-				graphics.Device.SetTexture(0, graphics.FontTexture);
 				graphics.Device.SetStreamSource(0, text.VertexBuffer, 0, FlatVertex.Stride);
 
 				// Draw
@@ -1745,7 +1758,6 @@ namespace CodeImp.DoomBuilder.Rendering
 			graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
 			graphics.Device.SetRenderState(RenderState.FogEnable, false);
 			SetWorldTransformation(false);
-			graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
 			graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
 			graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 			
@@ -1784,7 +1796,6 @@ namespace CodeImp.DoomBuilder.Rendering
 			graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
 			graphics.Device.SetRenderState(RenderState.FogEnable, false);
 			SetWorldTransformation(false);
-			graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
 			graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
 			graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 
@@ -1820,7 +1831,6 @@ namespace CodeImp.DoomBuilder.Rendering
 			graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
 			graphics.Device.SetRenderState(RenderState.FogEnable, false);
 			SetWorldTransformation(false);
-			graphics.Device.SetTexture(0, texture.Texture);
 			graphics.Shaders.Display2D.Texture1 = texture.Texture;
 			graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 
@@ -1833,7 +1843,8 @@ namespace CodeImp.DoomBuilder.Rendering
 		}
 
 		//mxd
-		public void RenderArrows(ICollection<Line3D> lines) 
+		public void RenderArrows(ICollection<Line3D> lines) { RenderArrows(lines, true); }
+		public void RenderArrows(ICollection<Line3D> lines, bool transformcoords) 
 		{
 			if(lines.Count == 0) return;
 			int pointscount = 0;
@@ -1841,9 +1852,12 @@ namespace CodeImp.DoomBuilder.Rendering
 			// Translate to screen coords, determine renderability
 			foreach(Line3D line in lines)
 			{
-				// Calculate screen positions
-				line.Start2D = ((Vector2D)line.Start).GetTransformed(translatex, translatey, scale, -scale); //start
-				line.End2D = ((Vector2D)line.End).GetTransformed(translatex, translatey, scale, -scale); //end
+				// Calculate screen positions?
+				if(transformcoords)
+				{
+					line.Start2D = ((Vector2D)line.Start).GetTransformed(translatex, translatey, scale, -scale); //start
+					line.End2D = ((Vector2D)line.End).GetTransformed(translatex, translatey, scale, -scale); //end
+				}
 
 				float maxx = Math.Max(line.Start2D.x, line.End2D.x);
 				float minx = Math.Min(line.Start2D.x, line.End2D.x);
@@ -1922,7 +1936,6 @@ namespace CodeImp.DoomBuilder.Rendering
 			graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
 			graphics.Device.SetRenderState(RenderState.FogEnable, false);
 			SetWorldTransformation(false);
-			graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
 			graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
 			graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 
@@ -1999,7 +2012,6 @@ namespace CodeImp.DoomBuilder.Rendering
             graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
             graphics.Device.SetRenderState(RenderState.FogEnable, false);
             SetWorldTransformation(false);
-            graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture);
             graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture;
             graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear);
 
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 1cb9e59af17d4ebc0d040e5f9d10d0449f2fab64..2c723f9e932c759a3bd02cc4124f93e8cd0f69e6 100644
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -1874,13 +1874,11 @@ namespace CodeImp.DoomBuilder.Rendering
 			if(crosshairbusy)
 			{
 				if(General.Map.Data.CrosshairBusy3D.Texture == null) General.Map.Data.CrosshairBusy3D.CreateTexture();
-				graphics.Device.SetTexture(0, General.Map.Data.CrosshairBusy3D.Texture);
 				graphics.Shaders.Display2D.Texture1 = General.Map.Data.CrosshairBusy3D.Texture;
 			}
 			else
 			{
 				if(General.Map.Data.Crosshair3D.Texture == null) General.Map.Data.Crosshair3D.CreateTexture();
-				graphics.Device.SetTexture(0, General.Map.Data.Crosshair3D.Texture);
 				graphics.Shaders.Display2D.Texture1 = General.Map.Data.Crosshair3D.Texture;
 			}
 			
diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg
index 5c4bb6df7e658f2d2708e89c4e9057f3fdec516b..61a629ed01236cea93a1bf2f13a846b359927aa7 100644
--- a/Source/Core/Resources/Actions.cfg
+++ b/Source/Core/Resources/Actions.cfg
@@ -1037,6 +1037,16 @@ togglecomments //mxd
 	allowscroll = false;
 }
 
+togglefixedthingsscale //mxd
+{
+	title = "Toggle Fixed Things Scale";
+	category = "view";
+	description = "When enabled, Things will no longer be scaled based on current zoom level in Classic modes.";
+	allowkeys = true;
+	allowmouse = false;
+	allowscroll = false;
+}
+
 togglebrightness //mxd
 {
 	title = "Toggle Full Brightness";
diff --git a/Source/Core/Resources/FixedThingsScale.png b/Source/Core/Resources/FixedThingsScale.png
new file mode 100644
index 0000000000000000000000000000000000000000..b94d1acfa5e05dfa73f72709313f50e6ec602796
Binary files /dev/null and b/Source/Core/Resources/FixedThingsScale.png differ
diff --git a/Source/Core/Types/AngleDegreesFloatHandler.cs b/Source/Core/Types/AngleDegreesFloatHandler.cs
index 82b074a7c6c74f4344e6b26c816c31435ea245cc..47f3588823ee40d84c999be92408d7484ade9b14 100644
--- a/Source/Core/Types/AngleDegreesFloatHandler.cs
+++ b/Source/Core/Types/AngleDegreesFloatHandler.cs
@@ -102,6 +102,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0f;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/AngleDegreesHandler.cs b/Source/Core/Types/AngleDegreesHandler.cs
index ec4e7c9c3a159b3f090b6a90e8cf43cf3378ca73..0120c0ce3e19f7f9d1a81479128d9ef40e55081c 100644
--- a/Source/Core/Types/AngleDegreesHandler.cs
+++ b/Source/Core/Types/AngleDegreesHandler.cs
@@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/AngleRadiansHandler.cs b/Source/Core/Types/AngleRadiansHandler.cs
index 57a9315db3c8594e8a1f92c829e857b8626c27e6..dee4904cafc4d9e8454a22aa87fb3a89dbadf602 100644
--- a/Source/Core/Types/AngleRadiansHandler.cs
+++ b/Source/Core/Types/AngleRadiansHandler.cs
@@ -102,6 +102,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0f;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/BoolHandler.cs b/Source/Core/Types/BoolHandler.cs
index 0b3f369c6e12e3b596adcf05add8875d3c136e68..d70d48e7da89732793ce5b22150cd9103b4fa9f2 100644
--- a/Source/Core/Types/BoolHandler.cs
+++ b/Source/Core/Types/BoolHandler.cs
@@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Types
 
 		public override int GetIntValue()
 		{
-			if(this.value) return 1; else return 0;
+			return (this.value ? 1 : 0);
 		}
 
 		public override string GetStringValue()
@@ -106,6 +106,11 @@ namespace CodeImp.DoomBuilder.Types
 		{
 			return list;
 		}
+
+		public override object GetDefaultValue()
+		{
+			return false;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Core/Types/ColorHandler.cs b/Source/Core/Types/ColorHandler.cs
index 37f7ac9c71d0edc1e04c3c32ed17f4dc8dad7f57..b48c6e714dac270a9f17511810b80b0b8e0e4f8c 100644
--- a/Source/Core/Types/ColorHandler.cs
+++ b/Source/Core/Types/ColorHandler.cs
@@ -113,6 +113,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString("X6");
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/EnumBitsHandler.cs b/Source/Core/Types/EnumBitsHandler.cs
index c392bf532b09ce0df11fbda2bb5c7170ba437efe..267e7ab80d1bc9aa0612dafc40dc8cb62ca3dc4b 100644
--- a/Source/Core/Types/EnumBitsHandler.cs
+++ b/Source/Core/Types/EnumBitsHandler.cs
@@ -38,7 +38,7 @@ namespace CodeImp.DoomBuilder.Types
 
 		private EnumList list;
 		private int value;
-		private int defaultValue; //mxd
+		private int defaultvalue; //mxd
 
 		#endregion
 
@@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Types
 		// When set up for an argument
 		public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo)
 		{
-			defaultValue = (int)arginfo.DefaultValue;//mxd
+			defaultvalue = (int)arginfo.DefaultValue;//mxd
 			base.SetupArgument(attr, arginfo);
 
 			// Keep enum list reference
@@ -100,9 +100,9 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
-			value = defaultValue;
+			value = defaultvalue;
 		}
 
 		public override object GetValue()
@@ -120,6 +120,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/EnumOptionHandler.cs b/Source/Core/Types/EnumOptionHandler.cs
index 30184b1487c0a1b306469873d16482368d4ed3f0..1ce9ce3e477c21885bb917fbce28784d68646e72 100644
--- a/Source/Core/Types/EnumOptionHandler.cs
+++ b/Source/Core/Types/EnumOptionHandler.cs
@@ -140,7 +140,7 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
 			value = defaultvalue;
 		}
@@ -189,6 +189,11 @@ namespace CodeImp.DoomBuilder.Types
 		{
 			return General.Types.GetAttribute((int)UniversalType.Integer);
 		}
+
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Core/Types/EnumStringsHandler.cs b/Source/Core/Types/EnumStringsHandler.cs
index 0ad1d6d4179662744cd56287ecb0646ef34d01ff..750316621eacc24b8ada7a10c18ae4876ab5b2ac 100644
--- a/Source/Core/Types/EnumStringsHandler.cs
+++ b/Source/Core/Types/EnumStringsHandler.cs
@@ -34,7 +34,7 @@ namespace CodeImp.DoomBuilder.Types
 
 		private EnumList list;
 		private EnumItem value;
-		private EnumItem defaultValue; //mxd
+		private EnumItem defaultvalue; //mxd
 
 		#endregion
 
@@ -50,7 +50,7 @@ namespace CodeImp.DoomBuilder.Types
 		// When set up for an argument
 		public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo)
 		{
-			defaultValue = new EnumItem(arginfo.DefaultValue.ToString(), arginfo.DefaultValue.ToString()); //mxd
+			defaultvalue = new EnumItem(arginfo.DefaultValue.ToString(), arginfo.DefaultValue.ToString()); //mxd
 			base.SetupArgument(attr, arginfo);
 
 			// Keep enum list reference
@@ -121,9 +121,9 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
-			value = defaultValue;
+			value = defaultvalue;
 		}
 
 		public override object GetValue()
@@ -171,6 +171,11 @@ namespace CodeImp.DoomBuilder.Types
 			return General.Types.GetAttribute((int)UniversalType.String);
 		}
 
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/FlatHandler.cs b/Source/Core/Types/FlatHandler.cs
index 339ac1f1c9f0dcffa22c9fddbe12947c88d3b451..4aa40363ed69c241c551a13ce3924b6723aa3c00 100644
--- a/Source/Core/Types/FlatHandler.cs
+++ b/Source/Core/Types/FlatHandler.cs
@@ -70,6 +70,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value;
 		}
 
+		public override object GetDefaultValue()
+		{
+			return string.Empty;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/FloatHandler.cs b/Source/Core/Types/FloatHandler.cs
index 4cb05edd1acc57997a36941e14cd242a47c2c4b4..67ab905ce066d6878bbd4b19360a5d3e1b62e6a6 100644
--- a/Source/Core/Types/FloatHandler.cs
+++ b/Source/Core/Types/FloatHandler.cs
@@ -85,6 +85,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0f;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/IntegerHandler.cs b/Source/Core/Types/IntegerHandler.cs
index c6fab35cfeb83b8fe6c6f6a528b78274c0a9c0d3..0760e92d95113f0d08bf448645801b8b9a33dd5f 100644
--- a/Source/Core/Types/IntegerHandler.cs
+++ b/Source/Core/Types/IntegerHandler.cs
@@ -34,7 +34,7 @@ namespace CodeImp.DoomBuilder.Types
 		#region ================== Variables
 
 		private int value;
-		private int defaultValue; //mxd
+		private int defaultvalue; //mxd
 		
 		#endregion
 
@@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Types
 		//mxd
 		public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) 
 		{
-			defaultValue = (int)arginfo.DefaultValue;
+			defaultvalue = (int)arginfo.DefaultValue;
 			base.SetupArgument(attr, arginfo);
 		}
 
@@ -85,9 +85,9 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
-			value = defaultValue;
+			value = defaultvalue;
 		}
 
 		public override object GetValue()
@@ -104,6 +104,11 @@ namespace CodeImp.DoomBuilder.Types
 		{
 			return this.value.ToString();
 		}
+
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Core/Types/LinedefTypeHandler.cs b/Source/Core/Types/LinedefTypeHandler.cs
index db7c5b9721897434f0340529fcafae72a537fad3..ee1cd52234ba9a0c5406698287176d30e52b85c1 100644
--- a/Source/Core/Types/LinedefTypeHandler.cs
+++ b/Source/Core/Types/LinedefTypeHandler.cs
@@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/NullHandler.cs b/Source/Core/Types/NullHandler.cs
index 2de10e8535f7ede222a66fd3ac1bc9585ef6cd80..3e5b87acd89bb07341cd685b97c1381373080ca9 100644
--- a/Source/Core/Types/NullHandler.cs
+++ b/Source/Core/Types/NullHandler.cs
@@ -62,6 +62,11 @@ namespace CodeImp.DoomBuilder.Types
 		{
 			return this.value.ToString();
 		}
+
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Core/Types/RandomFloatHandler.cs b/Source/Core/Types/RandomFloatHandler.cs
index 0d26774c46f4dc159282edf07942343abc52eaec..b3b383265764c4e8e7ced34b1a44dbdfd0661c8e 100644
--- a/Source/Core/Types/RandomFloatHandler.cs
+++ b/Source/Core/Types/RandomFloatHandler.cs
@@ -18,7 +18,7 @@ namespace CodeImp.DoomBuilder.Types
 		#region ================== Variables
 
 		private float value;
-		private bool randomValue;
+		private bool randomvalue;
 		private float min;
 		private float max;
 
@@ -77,7 +77,7 @@ namespace CodeImp.DoomBuilder.Types
 						if(float.TryParse(parts[0], NumberStyles.Float, CultureInfo.CurrentCulture, out min) &&
 						   float.TryParse(parts[1], NumberStyles.Float, CultureInfo.CurrentCulture, out max)) 
 						{
-							randomValue = (min != max);
+							randomvalue = (min != max);
 
 							if(min == max) this.value = min;
 							else if(min > max) General.Swap(ref min, ref max);
@@ -91,22 +91,27 @@ namespace CodeImp.DoomBuilder.Types
 
 		public override object GetValue() 
 		{
-			if(randomValue)	return General.Random(min, max); //mxd
+			if(randomvalue)	return General.Random(min, max); //mxd
 			return this.value;
 		}
 
 		public override int GetIntValue() 
 		{
-			if(randomValue)	return (int)General.Random(min, max); //mxd
+			if(randomvalue)	return (int)General.Random(min, max); //mxd
 			return (int)this.value;
 		}
 
 		public override string GetStringValue() 
 		{
-			if(randomValue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd
+			if(randomvalue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd
 			return this.value.ToString(CultureInfo.InvariantCulture);
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0f;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/RandomIntegerHandler.cs b/Source/Core/Types/RandomIntegerHandler.cs
index 208168d18368d5b23a9fb127bd6613307b8108f9..3b63513d2d26ede2aefb521104a1b31c07297691 100644
--- a/Source/Core/Types/RandomIntegerHandler.cs
+++ b/Source/Core/Types/RandomIntegerHandler.cs
@@ -14,8 +14,8 @@ namespace CodeImp.DoomBuilder.Types
 		#region ================== Variables
 
 		private int value;
-		private int defaultValue; 
-		private bool randomValue; 
+		private int defaultvalue; 
+		private bool randomvalue; 
 		private int min;
 		private int max;
 
@@ -29,7 +29,7 @@ namespace CodeImp.DoomBuilder.Types
 
 		public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) 
 		{
-			defaultValue = (int)arginfo.DefaultValue;
+			defaultvalue = (int)arginfo.DefaultValue;
 			base.SetupArgument(attr, arginfo);
 
 			//mxd. We don't want to store this type
@@ -74,7 +74,7 @@ namespace CodeImp.DoomBuilder.Types
 						if(int.TryParse(parts[0], NumberStyles.Integer, CultureInfo.CurrentCulture, out min) &&
 						   int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.CurrentCulture, out max)) 
 						{
-							randomValue = (min != max);
+							randomvalue = (min != max);
 							if(min == max) this.value = min;
 							else if(min > max) General.Swap(ref min, ref max);
 						}
@@ -89,29 +89,34 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
-			value = defaultValue;
+			value = defaultvalue;
 		}
 
 		public override object GetValue() 
 		{
-			if(randomValue)	return General.Random(min, max); //mxd
+			if(randomvalue)	return General.Random(min, max); //mxd
 			return this.value;
 		}
 
 		public override int GetIntValue() 
 		{
-			if(randomValue)	return General.Random(min, max); //mxd
+			if(randomvalue)	return General.Random(min, max); //mxd
 			return this.value;
 		}
 
 		public override string GetStringValue() 
 		{
-			if(randomValue)	return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd
+			if(randomvalue)	return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd
 			return this.value.ToString(CultureInfo.InvariantCulture);
 		}
 
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/SectorEffectHandler.cs b/Source/Core/Types/SectorEffectHandler.cs
index af18f9bd8de97569c1b1e3eaca6b7258eda7a1ee..dd342eba419c94cee5636c4035da91757827ca1c 100644
--- a/Source/Core/Types/SectorEffectHandler.cs
+++ b/Source/Core/Types/SectorEffectHandler.cs
@@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/SectorTagHandler.cs b/Source/Core/Types/SectorTagHandler.cs
index 3f680fab61403f2ee698b5877604a2ed6c52c662..79eed3198484dcaab5d427beb43a4eb79617b660 100644
--- a/Source/Core/Types/SectorTagHandler.cs
+++ b/Source/Core/Types/SectorTagHandler.cs
@@ -170,7 +170,7 @@ namespace CodeImp.DoomBuilder.Types
 		}
 
 		//mxd
-		public override void SetDefaultValue() 
+		public override void ApplyDefaultValue() 
 		{
 			value = defaultvalue;
 		}
@@ -197,6 +197,11 @@ namespace CodeImp.DoomBuilder.Types
 			return (this.value != null ? this.value.Title : "0: No Tag");
 		}
 
+		public override object GetDefaultValue()
+		{
+			return defaultvalue;
+		}
+
 		// This returns an enum list
 		public override EnumList GetEnumList() 
 		{
diff --git a/Source/Core/Types/StringHandler.cs b/Source/Core/Types/StringHandler.cs
index 9f08dd34a2e394d33ee530f7e5b9b762459ebd1e..e4cee5bcbe37de3f6ab22b94982ba73c1974d865 100644
--- a/Source/Core/Types/StringHandler.cs
+++ b/Source/Core/Types/StringHandler.cs
@@ -68,8 +68,7 @@ namespace CodeImp.DoomBuilder.Types
 		public override int GetIntValue()
 		{
 			int result;
-			if(int.TryParse(this.value, out result)) return result;
-				else return 0;
+			return (int.TryParse(this.value, out result) ? result : 0);
 		}
 
 		public override string GetStringValue()
@@ -77,6 +76,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value;
 		}
 
+		public override object GetDefaultValue()
+		{
+			return string.Empty;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/TextureHandler.cs b/Source/Core/Types/TextureHandler.cs
index 5f338fe4f11ab2f865a89680c4b1dfac450e7ecc..9d89c6a1a2eeffd998ce64017e2bcbf51c731b0d 100644
--- a/Source/Core/Types/TextureHandler.cs
+++ b/Source/Core/Types/TextureHandler.cs
@@ -70,6 +70,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value;
 		}
 
+		public override object GetDefaultValue()
+		{
+			return string.Empty;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/ThingClassHandler.cs b/Source/Core/Types/ThingClassHandler.cs
index 34663f235c1b31afc7d7c7ee8cf499f827aef9b4..6eb96602d9e7e4ef2ec7f4c8f469bb12d99229e6 100644
--- a/Source/Core/Types/ThingClassHandler.cs
+++ b/Source/Core/Types/ThingClassHandler.cs
@@ -91,6 +91,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value;
 		}
 
+		public override object GetDefaultValue()
+		{
+			return string.Empty;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/ThingTypeHandler.cs b/Source/Core/Types/ThingTypeHandler.cs
index 9751c5c0505da072013c1743977094e48259015d..41f5a446debaf8d0705a99aa7aede8d96c089b7c 100644
--- a/Source/Core/Types/ThingTypeHandler.cs
+++ b/Source/Core/Types/ThingTypeHandler.cs
@@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types
 			return this.value.ToString();
 		}
 
+		public override object GetDefaultValue()
+		{
+			return 0;
+		}
+
 		#endregion
 	}
 }
diff --git a/Source/Core/Types/TypeHandler.cs b/Source/Core/Types/TypeHandler.cs
index db6ad473e8c6c16bc387fc6fd5ba04c39160def7..d8f9d50497fe1eebfd7e160b3ba078a25c0048a8 100644
--- a/Source/Core/Types/TypeHandler.cs
+++ b/Source/Core/Types/TypeHandler.cs
@@ -120,11 +120,14 @@ namespace CodeImp.DoomBuilder.Types
 		public abstract void SetValue(object value);
 
 		//mxd. This should replace current value with the default one
-		public virtual void SetDefaultValue() { }
+		public virtual void ApplyDefaultValue() { }
 
 		// This must return the value as one of the primitive data types
 		// supported by UDMF: int, string, float or bool
 		public abstract object GetValue();
+
+		//mxd. This should return the default value
+		public abstract object GetDefaultValue();
 		
 		// This must return the value as integer (for arguments)
 		public virtual int GetIntValue()
@@ -136,9 +139,7 @@ namespace CodeImp.DoomBuilder.Types
 		public abstract string GetStringValue();
 
 		// This is called when the user presses the browse button
-		public virtual void Browse(IWin32Window parent)
-		{
-		}
+		public virtual void Browse(IWin32Window parent) { }
 		
 		// This must returns an enum list when IsEnumerable is true
 		public virtual EnumList GetEnumList()
diff --git a/Source/Core/Windows/AboutForm.cs b/Source/Core/Windows/AboutForm.cs
index d18f72a3f0d66ab44bc8f49cf3ffb2d29006c326..cb631152a94192c7678912dc07c20623115d2121 100644
--- a/Source/Core/Windows/AboutForm.cs
+++ b/Source/Core/Windows/AboutForm.cs
@@ -67,8 +67,7 @@ namespace CodeImp.DoomBuilder.Windows
 		// This copies the version number to clipboard
 		private void copyversion_Click(object sender, EventArgs e)
 		{
-			Clipboard.Clear();
-			Clipboard.SetText(Application.ProductVersion);
+			Clipboard.SetDataObject(Application.ProductVersion, true, 5, 200); //mxd
 		}
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/ActionBrowserForm.cs b/Source/Core/Windows/ActionBrowserForm.cs
index 8ec64585d00e49325b2f7e6f0598626746ce62bd..71a890e228745232163a26c7923e619337e7b7a1 100644
--- a/Source/Core/Windows/ActionBrowserForm.cs
+++ b/Source/Core/Windows/ActionBrowserForm.cs
@@ -36,16 +36,20 @@ namespace CodeImp.DoomBuilder.Windows
 		private readonly ComboBox[] options;
 		private readonly Label[] optionlbls;
 		private readonly TreeNode[] allNodes; //mxd
+		private readonly bool addanyaction; //mxd
 		
 		// Properties
 		public int SelectedAction { get { return selectedaction; } }
 		
 		// Constructor
-		public ActionBrowserForm(int action)
+		public ActionBrowserForm(int action, bool addanyaction)
 		{
 			// Initialize
 			InitializeComponent();
 
+			//mxd. Show "Any action" item?
+			this.addanyaction = addanyaction;
+
 			// Make array references for controls
 			options = new[] { option0, option1, option2, option3, option4, option5, option6, option7 };
 			optionlbls = new[] { option0label, option1label, option2label, option3label, option4label,
@@ -94,12 +98,24 @@ namespace CodeImp.DoomBuilder.Windows
 								foreach(GeneralizedBit ab in sc.Options[i].Bits)
 								{
 									// Select this setting if matches
-									if((actionbits & ab.Index) == ab.Index) options[i].SelectedItem = ab;
+									if((actionbits & ab.Index) == ab.Index)
+									{
+										options[i].SelectedItem = ab;
+										if(ab.Index > 0) break; //mxd
+									}
 								}
 							}
+							else
+							{
+								break; //mxd
+							}
 						}
 					}
 				}
+
+				//mxd. Make sure something is selected
+				if(category.SelectedIndex == -1 && category.Items.Count > 0)
+					category.SelectedIndex = 0;
 			}
 			else
 			{
@@ -110,9 +126,10 @@ namespace CodeImp.DoomBuilder.Windows
 		
 		// This browses for an action
 		// Returns the new action or the same action when cancelled
-		public static int BrowseAction(IWin32Window owner, int action)
+		public static int BrowseAction(IWin32Window owner, int action) { return BrowseAction(owner, action, false); } //mxd
+		public static int BrowseAction(IWin32Window owner, int action, bool addanyaction)
 		{
-			ActionBrowserForm f = new ActionBrowserForm(action);
+			ActionBrowserForm f = new ActionBrowserForm(action, addanyaction);
 			if(f.ShowDialog(owner) == DialogResult.OK) action = f.SelectedAction;
 			f.Dispose();
 			return action;
@@ -123,6 +140,19 @@ namespace CodeImp.DoomBuilder.Windows
 		{
 			actions.BeginUpdate();
 			actions.ShowLines = true;
+
+			// Add "Any action" item?
+			if(addanyaction)
+			{
+				TreeNode aan = actions.Nodes.Add("Any action");
+				aan.Tag = new LinedefActionInfo(-1, "Any action", false, false);
+				if(action == -1)
+				{
+					actions.SelectedNode = aan;
+					aan.EnsureVisible();
+				}
+			}
+
 			foreach(LinedefActionCategory ac in General.Map.Config.ActionCategories)
 			{
 				// Empty category names will not be created
@@ -162,24 +192,40 @@ namespace CodeImp.DoomBuilder.Windows
 		}
 
 		//mxd
-		private void FilterActions(string p) 
+		private void FilterActions(string text) 
 		{
-			List<TreeNode> filteredNodes = new List<TreeNode>();
+			List<TreeNode> filterednodes = new List<TreeNode>();
+			HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 
+			// First add nodes, which titles start with given text
 			foreach(TreeNode n in allNodes) 
 			{
 				foreach(TreeNode cn in n.Nodes) 
 				{
 					LinedefActionInfo ai = cn.Tag as LinedefActionInfo;
-					if(ai.Title.ToLowerInvariant().IndexOf(p) != -1)
-						filteredNodes.Add(cn);
+					if(ai != null && ai.Title.ToUpperInvariant().StartsWith(text))
+					{
+						filterednodes.Add(cn);
+						added.Add(ai.Title);
+					}
+				}
+			}
+
+			// Then add nodes, which titles contain given text
+			foreach(TreeNode n in allNodes)
+			{
+				foreach(TreeNode cn in n.Nodes)
+				{
+					LinedefActionInfo ai = cn.Tag as LinedefActionInfo;
+					if(ai != null && !added.Contains(ai.Title) && ai.Title.ToUpperInvariant().Contains(text))
+						filterednodes.Add(cn);
 				}
 			}
 
 			actions.BeginUpdate();
 			actions.Nodes.Clear();
 			actions.ShowLines = false;
-			actions.Nodes.AddRange(filteredNodes.ToArray());
+			actions.Nodes.AddRange(filterednodes.ToArray());
 			actions.EndUpdate();
 		}
 		
@@ -292,7 +338,7 @@ namespace CodeImp.DoomBuilder.Windows
 		{
 			if(!string.IsNullOrEmpty(tbFilter.Text.Trim()))
 			{
-				FilterActions(tbFilter.Text);
+				FilterActions(tbFilter.Text.ToUpperInvariant());
 			} 
 			else
 			{
diff --git a/Source/Core/Windows/ChangeMapForm.cs b/Source/Core/Windows/ChangeMapForm.cs
index 522c4b694fc4e6ff46427d64f434ed9fd42220e9..bd3a62c7998d378458e6903443c961a3ca00df92 100644
--- a/Source/Core/Windows/ChangeMapForm.cs
+++ b/Source/Core/Windows/ChangeMapForm.cs
@@ -180,7 +180,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// Current map is already loaded
 			if(mapslist.SelectedItems[0].Text == options.LevelName)
 			{
-				MessageBox.Show(this, "Map '" + options.LevelName + "' is already loaded.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+				MessageBox.Show(this, "Map \"" + options.LevelName + "\" is already loaded.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
 				mapslist.Focus();
 				return;
 			}
diff --git a/Source/Core/Windows/ConfigForm.cs b/Source/Core/Windows/ConfigForm.cs
index bc76e8333462d159c2b9679f8131cfe777e5cca0..f1e806cddb4b8194711efb06db7c52e7e7739d57 100644
--- a/Source/Core/Windows/ConfigForm.cs
+++ b/Source/Core/Windows/ConfigForm.cs
@@ -402,7 +402,7 @@ namespace CodeImp.DoomBuilder.Windows
 				ci = listconfigs.Items[i].Tag as ConfigurationInfo;
 				if(!ci.Resources.IsValid())
 				{
-					MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+					MessageBox.Show(this, "At least one resource doesn't exist in \"" + ci.Name + "\" game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
 					tabs.SelectedTab = tabresources;
 					listconfigs.Focus();
 					listconfigs.Items[i].Selected = true;
@@ -871,7 +871,7 @@ namespace CodeImp.DoomBuilder.Windows
 			configinfocopy = current.Clone();
 
 			//display info
-			General.Interface.DisplayStatus(StatusType.Info, "Copied '" + configinfocopy.Name + "' game configuration");
+			General.Interface.DisplayStatus(StatusType.Info, "Copied \"" + configinfocopy.Name + "\" game configuration");
 		}
 
 		private void pasteall_Click(object sender, EventArgs e) 
@@ -885,7 +885,7 @@ namespace CodeImp.DoomBuilder.Windows
 			//update display
 			cbEngineSelector.Text = string.Empty; // Otherwise current text from cbEngineSelector will override the pasted one
 			listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty);
-			General.Interface.DisplayStatus(StatusType.Info, "Pasted game configuration from '" + configinfocopy.Name + "'");
+			General.Interface.DisplayStatus(StatusType.Info, "Pasted game configuration from \"" + configinfocopy.Name + "\"");
 		}
 
 		private void pasteresources_Click(object sender, EventArgs e) 
@@ -898,7 +898,7 @@ namespace CodeImp.DoomBuilder.Windows
 
 			//update display
 			listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty);
-			General.Interface.DisplayStatus(StatusType.Info, "Pasted resources from '" + configinfocopy.Name + "'");
+			General.Interface.DisplayStatus(StatusType.Info, "Pasted resources from \"" + configinfocopy.Name + "\"");
 		}
 
 		private void pasteengines_Click(object sender, EventArgs e) 
@@ -912,7 +912,7 @@ namespace CodeImp.DoomBuilder.Windows
 			//update display
 			cbEngineSelector.Text = string.Empty; // Otherwise current text from cbEngineSelector will override the pasted one
 			listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty);
-			General.Interface.DisplayStatus(StatusType.Info, "Pasted engines list from '" + configinfocopy.Name + "'");
+			General.Interface.DisplayStatus(StatusType.Info, "Pasted engines list from \"" + configinfocopy.Name + "\"");
 		}
 
 		private void pastecolorpresets_Click(object sender, EventArgs e) 
@@ -925,7 +925,7 @@ namespace CodeImp.DoomBuilder.Windows
 
 			//update display
 			listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty);
-			General.Interface.DisplayStatus(StatusType.Info, "Pasted color presets from '" + configinfocopy.Name + "'");
+			General.Interface.DisplayStatus(StatusType.Info, "Pasted color presets from \"" + configinfocopy.Name + "\"");
 		}
 
 		#endregion
diff --git a/Source/Core/Windows/EffectBrowserForm.cs b/Source/Core/Windows/EffectBrowserForm.cs
index 0c8d166165366b0b1588d90dd71ed248bb5faea2..e29d2a53ba374bbcefa949f88224775dde3bc481 100644
--- a/Source/Core/Windows/EffectBrowserForm.cs
+++ b/Source/Core/Windows/EffectBrowserForm.cs
@@ -33,28 +33,31 @@ namespace CodeImp.DoomBuilder.Windows
 		
 		// Variables
 		private int selectedeffect;
-		private ComboBox[] options;
-		private Label[] optionlbls;
-		private ListViewItem[] allItems; //mxd
+		private readonly ComboBox[] options;
+		private readonly ListViewItem[] allitems; //mxd
+		private readonly bool addanyeffect;
 		
 		// Properties
 		public int SelectedEffect { get { return selectedeffect; } }
 		
 		// Constructor
-		public EffectBrowserForm(int effect)
+		public EffectBrowserForm(int effect, bool addanyeffect)
 		{
 			// Initialize
 			InitializeComponent();
 
+			//mxd. Show "Any action" item?
+			this.addanyeffect = addanyeffect;
+
 			// Make array references for controls
 			options = new[] { option0, option1, option2, option3, option4, option5, option6, option7 };
-			optionlbls = new[] { option0label, option1label, option2label, option3label, option4label,
-									   option5label, option6label, option7label };
+			Label[] optionlbls = { option0label, option1label, option2label, option3label, 
+								   option4label, option5label, option6label, option7label };
 			
 			// Go for all predefined effects
 			bool selected = CreateEffects(effect); //mxd
-			allItems = new ListViewItem[effects.Items.Count]; //mxd
-			effects.Items.CopyTo(allItems, 0); //mxd
+			allitems = new ListViewItem[effects.Items.Count]; //mxd
+			effects.Items.CopyTo(allitems, 0); //mxd
 			
 			// Using generalized effects?
 			if(General.Map.Config.GeneralizedEffects)
@@ -82,7 +85,11 @@ namespace CodeImp.DoomBuilder.Windows
 							foreach(GeneralizedBit ab in o.Bits)
 							{
 								// Select this setting if matches
-								if((effect & ab.Index) == ab.Index) options[i].SelectedItem = ab;
+								if((effect & ab.Index) == ab.Index)
+								{
+									options[i].SelectedItem = ab;
+									if(ab.Index > 0) break; //mxd
+								}
 							}
 						}
 					}
@@ -106,9 +113,10 @@ namespace CodeImp.DoomBuilder.Windows
 		
 		// This browses for an effect
 		// Returns the new effect or the same effect when cancelled
-		public static int BrowseEffect(IWin32Window owner, int effect)
+		public static int BrowseEffect(IWin32Window owner, int effect) { return BrowseEffect(owner, effect, false); } //mxd
+		public static int BrowseEffect(IWin32Window owner, int effect, bool addanyeffect)
 		{
-			EffectBrowserForm f = new EffectBrowserForm(effect);
+			EffectBrowserForm f = new EffectBrowserForm(effect, addanyeffect);
 			if(f.ShowDialog(owner) == DialogResult.OK) effect = f.SelectedEffect;
 			f.Dispose();
 			return effect;
@@ -119,6 +127,18 @@ namespace CodeImp.DoomBuilder.Windows
 		{
 			bool selected = false;
 
+			if(addanyeffect)
+			{
+				ListViewItem n = effects.Items.Add("-1");
+				n.SubItems.Add("Any effect");
+				n.Tag = new SectorEffectInfo(-1, "Any effect", false, false);
+				if(effect == -1)
+				{
+					selected = true;
+					n.Selected = true;
+				}
+			}
+
 			foreach(SectorEffectInfo si in General.Map.Config.SortedSectorEffects) 
 			{
 				// Create effect
@@ -135,20 +155,36 @@ namespace CodeImp.DoomBuilder.Windows
 		}
 
 		//mxd
-		private void FilterEffects(string p) 
+		private void FilterEffects(string text) 
 		{
-			List<ListViewItem> filteredItems = new List<ListViewItem>();
+			List<ListViewItem> filtereditems = new List<ListViewItem>();
+			HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 
-			foreach(ListViewItem i in allItems) 
+			// First add nodes, which titles start with given text
+			foreach(ListViewItem i in allitems) 
 			{
 				SectorEffectInfo si = i.Tag as SectorEffectInfo;
-				if(si.Title.ToLowerInvariant().IndexOf(p) != -1)
-					filteredItems.Add(i);
+				if(si != null && si.Title.ToUpperInvariant().StartsWith(text))
+				{
+					filtereditems.Add(i);
+					added.Add(si.Title);
+				}
+			}
+
+			// Then add nodes, which titles contain given text
+			foreach(ListViewItem i in allitems)
+			{
+				SectorEffectInfo si = i.Tag as SectorEffectInfo;
+				if(si != null && !added.Contains(si.Title) && si.Title.ToUpperInvariant().Contains(text))
+				{
+					filtereditems.Add(i);
+					added.Add(si.Title);
+				}
 			}
 
 			effects.BeginUpdate();
 			effects.Items.Clear();
-			effects.Items.AddRange(filteredItems.ToArray());
+			effects.Items.AddRange(filtereditems.ToArray());
 			effects.EndUpdate();
 		}
 		
@@ -181,6 +217,10 @@ namespace CodeImp.DoomBuilder.Windows
 						if(options[i].SelectedIndex > -1)
 							selectedeffect += (options[i].SelectedItem as GeneralizedBit).Index;
 					}
+					else
+					{
+						break; //mxd
+					}
 				}
 			}
 			
@@ -212,7 +252,7 @@ namespace CodeImp.DoomBuilder.Windows
 		{
 			if(!string.IsNullOrEmpty(tbFilter.Text.Trim()))
 			{
-				FilterEffects(tbFilter.Text);
+				FilterEffects(tbFilter.Text.ToUpperInvariant());
 			} 
 			else
 			{
diff --git a/Source/Core/Windows/GridSetupForm.cs b/Source/Core/Windows/GridSetupForm.cs
index a86778c0de15fcb06c2852a4a7d91e1ec485957b..5eecedc04785c08503937efbae275cf35b5e8594 100644
--- a/Source/Core/Windows/GridSetupForm.cs
+++ b/Source/Core/Windows/GridSetupForm.cs
@@ -140,8 +140,18 @@ namespace CodeImp.DoomBuilder.Windows
 		// Apply
 		private void apply_Click(object sender, EventArgs e)
 		{
+			//mxd. Apply
+			int newgridsize = gridsize.GetResult(General.Map.Grid.GridSize);
+			if(newgridsize != General.Map.Grid.GridSize)
+			{
+				//Disable automatic grid resizing
+				General.MainWindow.DisableDynamicGridResize();
+
+				//Apply grid size
+				General.Map.Grid.SetGridSize(newgridsize);
+			}
+			
 			// Apply
-			General.Map.Grid.SetGridSize(gridsize.GetResult(General.Map.Grid.GridSize));
 			General.Map.Grid.SetBackgroundView(backoffsetx.GetResult(General.Map.Grid.BackgroundX),
 											   backoffsety.GetResult(General.Map.Grid.BackgroundY),
 											   backscalex.GetResult((int)(General.Map.Grid.BackgroundScaleX * 100.0f)) / 100.0f,
diff --git a/Source/Core/Windows/IMainForm.cs b/Source/Core/Windows/IMainForm.cs
index 2b6c7a07125a9cf363903d61c7dc2ab3d4c2b4a4..0754b00bcb810ecfec2325cf51399bf650c1c5c8 100644
--- a/Source/Core/Windows/IMainForm.cs
+++ b/Source/Core/Windows/IMainForm.cs
@@ -87,12 +87,24 @@ namespace CodeImp.DoomBuilder.Windows
 		/// </summary>
 		/// <returns>Returns the new action or the same action when cancelled</returns>
 		int BrowseLinedefActions(IWin32Window owner, int initialvalue);
-		
+
+		/// <summary>
+		/// This browses the lindef types
+		/// </summary>
+		/// <returns>Returns the new action or the same action when cancelled</returns>
+		int BrowseLinedefActions(IWin32Window owner, int initialvalue, bool addanyaction);
+
 		/// <summary>
 		/// This browses sector effects
 		/// </summary>
 		/// <returns>Returns the new effect or the same effect when cancelled</returns>
 		int BrowseSectorEffect(IWin32Window owner, int initialvalue);
+		
+		/// <summary>
+		/// This browses sector effects
+		/// </summary>
+		/// <returns>Returns the new effect or the same effect when cancelled</returns>
+		int BrowseSectorEffect(IWin32Window owner, int initialvalue, bool addanyeffect);
 
 		/// <summary>
 		/// This browses for a texture
diff --git a/Source/Core/Windows/LinedefColorPresetsForm.cs b/Source/Core/Windows/LinedefColorPresetsForm.cs
index dd746db42f8782836b3e46f9653693233612a6f9..0eb00147791a73a58afe58786ed309be74046f42 100644
--- a/Source/Core/Windows/LinedefColorPresetsForm.cs
+++ b/Source/Core/Windows/LinedefColorPresetsForm.cs
@@ -180,7 +180,7 @@ namespace CodeImp.DoomBuilder.Windows
 					if(gotmismatch) continue;
 
 					//we have a match
-					warning = "Preset matches '" + other.Preset.Name + "'!";
+					warning = "Preset matches \"" + other.Preset.Name + "\"!";
 					item.ShowWarning = true;
 					break;
 				}
diff --git a/Source/Core/Windows/LinedefEditForm.Designer.cs b/Source/Core/Windows/LinedefEditForm.Designer.cs
index 37f9414b2441b7e96db6f91e738cae3b5a8e510c..c25230ba7fcd1cffed481e17b9ee2af2fd62218d 100644
--- a/Source/Core/Windows/LinedefEditForm.Designer.cs
+++ b/Source/Core/Windows/LinedefEditForm.Designer.cs
@@ -47,6 +47,8 @@ namespace CodeImp.DoomBuilder.Windows
             this.backside = new System.Windows.Forms.CheckBox();
             this.frontside = new System.Windows.Forms.CheckBox();
             this.frontgroup = new System.Windows.Forms.GroupBox();
+            this.replaceunusedfronttextures = new System.Windows.Forms.CheckBox();
+            this.replaceunusedbacktextures = new System.Windows.Forms.CheckBox();
             this.labelFrontTextureOffset = new System.Windows.Forms.Label();
             this.frontsector = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox();
             this.frontlow = new CodeImp.DoomBuilder.Controls.TextureSelectorControl();
@@ -100,6 +102,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // label5
             // 
+            label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
             label5.Location = new System.Drawing.Point(437, 13);
             label5.Name = "label5";
             label5.Size = new System.Drawing.Size(83, 16);
@@ -109,6 +112,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // label4
             // 
+            label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
             label4.Location = new System.Drawing.Point(346, 13);
             label4.Name = "label4";
             label4.Size = new System.Drawing.Size(83, 16);
@@ -118,6 +122,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // label3
             // 
+            label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
             label3.Location = new System.Drawing.Point(255, 13);
             label3.Name = "label3";
             label3.Size = new System.Drawing.Size(83, 16);
@@ -136,6 +141,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // label8
             // 
+            label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
             label8.Location = new System.Drawing.Point(437, 13);
             label8.Name = "label8";
             label8.Size = new System.Drawing.Size(83, 16);
@@ -154,6 +160,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // label10
             // 
+            label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
             label10.Location = new System.Drawing.Point(255, 13);
             label10.Name = "label10";
             label10.Size = new System.Drawing.Size(83, 16);
@@ -257,6 +264,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             this.frontgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
+            this.frontgroup.Controls.Add(this.replaceunusedfronttextures);
             this.frontgroup.Controls.Add(this.labelFrontTextureOffset);
             this.frontgroup.Controls.Add(this.frontsector);
             this.frontgroup.Controls.Add(label11);
@@ -275,6 +283,18 @@ namespace CodeImp.DoomBuilder.Windows
             this.frontgroup.TabStop = false;
             this.frontgroup.Text = "     ";
             // 
+            // replaceunusedfronttextures
+            // 
+            this.replaceunusedfronttextures.AutoSize = true;
+            this.replaceunusedfronttextures.Location = new System.Drawing.Point(90, 121);
+            this.replaceunusedfronttextures.Name = "replaceunusedfronttextures";
+            this.replaceunusedfronttextures.Size = new System.Drawing.Size(144, 17);
+            this.replaceunusedfronttextures.TabIndex = 43;
+            this.replaceunusedfronttextures.Text = "Replace unused textures";
+            this.replaceunusedfronttextures.UseVisualStyleBackColor = true;
+            this.replaceunusedfronttextures.CheckedChanged += new System.EventHandler(this.replaceunusedfronttextures_CheckedChanged);
+            // 
+            // 
             // labelFrontTextureOffset
             // 
             this.labelFrontTextureOffset.Location = new System.Drawing.Point(6, 70);
@@ -354,6 +374,7 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             this.backgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
+            this.backgroup.Controls.Add(this.replaceunusedbacktextures);
             this.backgroup.Controls.Add(this.labelBackTextureOffset);
             this.backgroup.Controls.Add(this.backsector);
             this.backgroup.Controls.Add(label12);
@@ -372,6 +393,18 @@ namespace CodeImp.DoomBuilder.Windows
             this.backgroup.TabStop = false;
             this.backgroup.Text = "     ";
             // 
+            // replaceunusedbacktextures
+            // 
+            this.replaceunusedbacktextures.AutoSize = true;
+            this.replaceunusedbacktextures.Location = new System.Drawing.Point(90, 121);
+            this.replaceunusedbacktextures.Name = "replaceunusedbacktextures";
+            this.replaceunusedbacktextures.Size = new System.Drawing.Size(144, 17);
+            this.replaceunusedbacktextures.TabIndex = 44;
+            this.replaceunusedbacktextures.Text = "Replace unused textures";
+            this.replaceunusedbacktextures.UseVisualStyleBackColor = true;
+            this.replaceunusedbacktextures.CheckedChanged += new System.EventHandler(this.replaceunusedbacktextures_CheckedChanged);
+            // 
+            // 
             // labelBackTextureOffset
             // 
             this.labelBackTextureOffset.Location = new System.Drawing.Point(6, 70);
@@ -625,5 +658,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private System.Windows.Forms.Label labelFrontTextureOffset;
 		private System.Windows.Forms.Label labelBackTextureOffset;
 		private CodeImp.DoomBuilder.Controls.ArgumentsControl argscontrol;
+		private System.Windows.Forms.CheckBox replaceunusedfronttextures;
+		private System.Windows.Forms.CheckBox replaceunusedbacktextures;
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/LinedefEditForm.cs b/Source/Core/Windows/LinedefEditForm.cs
index dcf617ab74453d9c91a2b149223ddec0e532da1d..2a09b16f8cc96d662fcd117ef275b477611fb15d 100644
--- a/Source/Core/Windows/LinedefEditForm.cs
+++ b/Source/Core/Windows/LinedefEditForm.cs
@@ -65,20 +65,20 @@ namespace CodeImp.DoomBuilder.Windows
 			public readonly int OffsetX;
 			public readonly int OffsetY;
 
-			public readonly string TextureTop;
-			public readonly string TextureMid;
-			public readonly string TextureLow;
+			public readonly string HighTexture;
+			public readonly string MiddleTexture;
+			public readonly string LowTexture;
 
 			public SidedefProperties(Sidedef side) 
 			{
-				//offset
+				// Offset
 				OffsetX = side.OffsetX;
 				OffsetY = side.OffsetY;
 
-				//textures
-				TextureTop = side.HighTexture;
-				TextureMid = side.MiddleTexture;
-				TextureLow = side.LowTexture;
+				// Textures
+				HighTexture = side.HighTexture;
+				MiddleTexture = side.MiddleTexture;
+				LowTexture = side.LowTexture;
 			}
 		}
 
@@ -149,6 +149,12 @@ namespace CodeImp.DoomBuilder.Windows
 			apply.Top = panel.Bottom + panel.Margin.Bottom + apply.Margin.Top;
 			cancel.Top = apply.Top;
 
+			//mxd. Apply texture replacement settings
+			preventchanges = true;
+			replaceunusedfronttextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedfronttextures", true);
+			replaceunusedbacktextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedbacktextures", true);
+			preventchanges = false;
+
 			// Update window height
 			this.Height = apply.Bottom + apply.Margin.Bottom * 2 + (this.Height - this.ClientRectangle.Height) + 1;
 		}
@@ -285,22 +291,22 @@ namespace CodeImp.DoomBuilder.Windows
 				if(l.Front != null)
 				{
 					//mxd
-					if(fronthigh.TextureName != l.Front.HighTexture) 
+					if(!string.IsNullOrEmpty(fronthigh.TextureName) && fronthigh.TextureName != l.Front.HighTexture) 
 					{
 						if(!fronthigh.Required && l.Front.HighRequired()) fronthigh.Required = true;
-						fronthigh.MultipleTextures = true; //mxd
+						fronthigh.MultipleTextures = true;
 						fronthigh.TextureName = string.Empty;
 					}
-					if(frontmid.TextureName != l.Front.MiddleTexture) 
+					if(!string.IsNullOrEmpty(frontmid.TextureName) && frontmid.TextureName != l.Front.MiddleTexture) 
 					{
 						if(!frontmid.Required && l.Front.MiddleRequired()) frontmid.Required = true;
-						frontmid.MultipleTextures = true; //mxd
+						frontmid.MultipleTextures = true;
 						frontmid.TextureName = string.Empty;
 					}
-					if(frontlow.TextureName != l.Front.LowTexture) 
+					if(!string.IsNullOrEmpty(frontlow.TextureName) && frontlow.TextureName != l.Front.LowTexture) 
 					{
 						if(!frontlow.Required && l.Front.LowRequired()) frontlow.Required = true;
-						frontlow.MultipleTextures = true; //mxd
+						frontlow.MultipleTextures = true;
 						frontlow.TextureName = string.Empty;
 					}
 					if(frontsector.Text != l.Front.Sector.Index.ToString()) frontsector.Text = string.Empty;
@@ -312,22 +318,22 @@ namespace CodeImp.DoomBuilder.Windows
 				if(l.Back != null)
 				{
 					//mxd
-					if(backhigh.TextureName != l.Back.HighTexture) 
+					if(!string.IsNullOrEmpty(backhigh.TextureName) && backhigh.TextureName != l.Back.HighTexture) 
 					{
 						if(!backhigh.Required && l.Back.HighRequired()) backhigh.Required = true;
-						backhigh.MultipleTextures = true; //mxd
+						backhigh.MultipleTextures = true;
 						backhigh.TextureName = string.Empty;
 					}
-					if(backmid.TextureName != l.Back.MiddleTexture) 
+					if(!string.IsNullOrEmpty(backmid.TextureName) && backmid.TextureName != l.Back.MiddleTexture) 
 					{
 						if(!backmid.Required && l.Back.MiddleRequired()) backmid.Required = true;
-						backmid.MultipleTextures = true; //mxd
+						backmid.MultipleTextures = true;
 						backmid.TextureName = string.Empty;
 					}
-					if(backlow.TextureName != l.Back.LowTexture) 
+					if(!string.IsNullOrEmpty(backlow.TextureName) && backlow.TextureName != l.Back.LowTexture) 
 					{
 						if(!backlow.Required && l.Back.LowRequired()) backlow.Required = true;
-						backlow.MultipleTextures = true; //mxd
+						backlow.MultipleTextures = true;
 						backlow.TextureName = string.Empty;
 					}
 					if(backsector.Text != l.Back.Sector.Index.ToString()) backsector.Text = string.Empty;
@@ -593,7 +599,12 @@ namespace CodeImp.DoomBuilder.Windows
 		//mxd. Store window location
 		private void LinedefEditForm_FormClosing(object sender, FormClosingEventArgs e) 
 		{
+			// Save location
 			location = this.Location;
+			
+			// Save persistent settings
+			General.Settings.WriteSetting("editlinedefswindow.replaceunusedfronttextures", replaceunusedfronttextures.Checked);
+			General.Settings.WriteSetting("editlinedefswindow.replaceunusedbacktextures", replaceunusedbacktextures.Checked);
 		}
 
 		// Help!
@@ -659,24 +670,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void fronthigh_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(fronthigh.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.TextureTop : "-");
+					if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
-				foreach(Linedef l in lines) 
-					if(l.Front != null)	l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+				int i = 0;
+				foreach(Linedef l in lines)
+				{
+					if(l.Front != null
+						&& (replaceunusedfronttextures.Checked
+						|| (l.Front.HighRequired()
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.HighTexture != "-"))))
+						l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -689,24 +707,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void frontmid_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(frontmid.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.TextureMid : "-");
+					if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
-				foreach(Linedef l in lines) 
-					if(l.Front != null)	l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+				int i = 0;
+				foreach(Linedef l in lines)
+				{
+					if(l.Front != null 
+						&& (replaceunusedfronttextures.Checked 
+						|| (l.Front.MiddleRequired() 
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.MiddleTexture != "-"))))
+						l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -719,24 +744,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void frontlow_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(frontlow.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.TextureLow : "-");
+					if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Front != null) l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+				{
+					if(l.Front != null
+						&& (replaceunusedfronttextures.Checked
+						|| (l.Front.LowRequired()
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.LowTexture != "-"))))
+						l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -749,24 +781,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backhigh_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backhigh.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.TextureTop : "-");
+					if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.HighRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.HighTexture != "-"))))
+						l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -779,24 +818,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backmid_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backmid.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.TextureMid : "-");
+					if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values
+			}
+			// Update values
+			else 
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.MiddleRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.MiddleTexture != "-"))))
+						l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -809,24 +855,111 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backlow_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backlow.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.TextureLow : "-");
+					if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-");
 					i++;
 				}
-			
-			} 
-			else //update values 
+			}
+			// Update values
+			else
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.LowRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.LowTexture != "-"))))
+						l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+					i++;
+				}
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		private void replaceunusedfronttextures_CheckedChanged(object sender, EventArgs e)
+		{
+			//Re-apply front textures
+			if(preventchanges) return;
+			MakeUndo();
+
+			// Set values
+			int i = 0;
+			foreach(Linedef l in lines)
+			{
+				if(l.Front == null) continue;
+
+				// Update top texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(fronthigh.TextureName))
+					l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-");
+				else
+					l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+
+				// Update middle texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontmid.TextureName))
+					l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-");
+				else
+					l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+
+				// Update bottom texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontlow.TextureName))
+					l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-");
+				else
+					l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+
+				i++;
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		private void replaceunusedbacktextures_CheckedChanged(object sender, EventArgs e)
+		{
+			//Re-apply back textures
+			if(preventchanges) return;
+			MakeUndo();
+
+			// Set values
+			int i = 0;
+			foreach(Linedef l in lines)
+			{
+				if(l.Back == null) continue;
+
+				// Update top texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backhigh.TextureName))
+					l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-");
+				else
+					l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+
+				// Update middle texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backmid.TextureName))
+					l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-");
+				else
+					l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+
+				// Update bottom texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backlow.TextureName))
+					l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-");
+				else
+					l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+
+				i++;
 			}
 
 			// Update the used textures
diff --git a/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs b/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs
index ee764311f1ca0c08e24d87c8a41ed44bba863516..902e5c6e3fd71308225fd402827499fb1582fb58 100644
--- a/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs
+++ b/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs
@@ -60,6 +60,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.tabfront = new System.Windows.Forms.TabPage();
 			this.frontside = new System.Windows.Forms.CheckBox();
 			this.frontgroup = new System.Windows.Forms.GroupBox();
+			this.replaceunusedfronttextures = new System.Windows.Forms.CheckBox();
 			this.frontflagsgroup = new System.Windows.Forms.GroupBox();
 			this.flagsFront = new CodeImp.DoomBuilder.Controls.CheckboxArrayControl();
 			this.frontscalegroup = new System.Windows.Forms.GroupBox();
@@ -90,6 +91,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.tabback = new System.Windows.Forms.TabPage();
 			this.backside = new System.Windows.Forms.CheckBox();
 			this.backgroup = new System.Windows.Forms.GroupBox();
+			this.replaceunusedbacktextures = new System.Windows.Forms.CheckBox();
 			this.groupBox4 = new System.Windows.Forms.GroupBox();
 			this.resetbacklight = new System.Windows.Forms.Button();
 			this.backsector = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox();
@@ -496,6 +498,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.frontgroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
 						| System.Windows.Forms.AnchorStyles.Left)
 						| System.Windows.Forms.AnchorStyles.Right)));
+			this.frontgroup.Controls.Add(this.replaceunusedfronttextures);
 			this.frontgroup.Controls.Add(this.frontflagsgroup);
 			this.frontgroup.Controls.Add(this.frontscalegroup);
 			this.frontgroup.Controls.Add(this.groupBox6);
@@ -511,6 +514,17 @@ namespace CodeImp.DoomBuilder.Windows
 			this.frontgroup.TabStop = false;
 			this.frontgroup.Text = "     ";
 			// 
+			// replaceunusedfronttextures
+			// 
+			this.replaceunusedfronttextures.AutoSize = true;
+			this.replaceunusedfronttextures.Location = new System.Drawing.Point(312, 15);
+			this.replaceunusedfronttextures.Name = "replaceunusedfronttextures";
+			this.replaceunusedfronttextures.Size = new System.Drawing.Size(144, 17);
+			this.replaceunusedfronttextures.TabIndex = 46;
+			this.replaceunusedfronttextures.Text = "Replace unused textures";
+			this.replaceunusedfronttextures.UseVisualStyleBackColor = true;
+			this.replaceunusedfronttextures.CheckedChanged += new System.EventHandler(this.replaceunusedfronttextures_CheckedChanged);
+			// 
 			// frontflagsgroup
 			// 
 			this.frontflagsgroup.Controls.Add(this.flagsFront);
@@ -862,7 +876,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// frontmid
 			// 
-			this.frontmid.Location = new System.Drawing.Point(309, 217);
+			this.frontmid.Location = new System.Drawing.Point(309, 225);
 			this.frontmid.MultipleTextures = false;
 			this.frontmid.Name = "frontmid";
 			this.frontmid.Required = false;
@@ -874,7 +888,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// fronthigh
 			// 
-			this.fronthigh.Location = new System.Drawing.Point(309, 19);
+			this.fronthigh.Location = new System.Drawing.Point(309, 35);
 			this.fronthigh.MultipleTextures = false;
 			this.fronthigh.Name = "fronthigh";
 			this.fronthigh.Required = false;
@@ -914,6 +928,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.backgroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
 						| System.Windows.Forms.AnchorStyles.Left)
 						| System.Windows.Forms.AnchorStyles.Right)));
+			this.backgroup.Controls.Add(this.replaceunusedbacktextures);
 			this.backgroup.Controls.Add(this.groupBox4);
 			this.backgroup.Controls.Add(this.backflagsgroup);
 			this.backgroup.Controls.Add(this.backscalegroup);
@@ -929,6 +944,17 @@ namespace CodeImp.DoomBuilder.Windows
 			this.backgroup.TabStop = false;
 			this.backgroup.Text = "     ";
 			// 
+			// replaceunusedbacktextures
+			// 
+			this.replaceunusedbacktextures.AutoSize = true;
+			this.replaceunusedbacktextures.Location = new System.Drawing.Point(312, 15);
+			this.replaceunusedbacktextures.Name = "replaceunusedbacktextures";
+			this.replaceunusedbacktextures.Size = new System.Drawing.Size(144, 17);
+			this.replaceunusedbacktextures.TabIndex = 47;
+			this.replaceunusedbacktextures.Text = "Replace unused textures";
+			this.replaceunusedbacktextures.UseVisualStyleBackColor = true;
+			this.replaceunusedbacktextures.CheckedChanged += new System.EventHandler(this.replaceunusedbacktextures_CheckedChanged);
+			// 
 			// groupBox4
 			// 
 			this.groupBox4.Controls.Add(this.resetbacklight);
@@ -1290,7 +1316,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// backmid
 			// 
-			this.backmid.Location = new System.Drawing.Point(309, 217);
+			this.backmid.Location = new System.Drawing.Point(309, 225);
 			this.backmid.MultipleTextures = false;
 			this.backmid.Name = "backmid";
 			this.backmid.Required = false;
@@ -1302,7 +1328,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// backhigh
 			// 
-			this.backhigh.Location = new System.Drawing.Point(309, 19);
+			this.backhigh.Location = new System.Drawing.Point(309, 35);
 			this.backhigh.MultipleTextures = false;
 			this.backhigh.Name = "backhigh";
 			this.backhigh.Required = false;
@@ -1359,6 +1385,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.fieldslist.Name = "fieldslist";
 			this.fieldslist.PropertyColumnVisible = true;
 			this.fieldslist.PropertyColumnWidth = 150;
+			this.fieldslist.ShowFixedFields = true;
 			this.fieldslist.Size = new System.Drawing.Size(527, 602);
 			this.fieldslist.TabIndex = 0;
 			this.fieldslist.TypeColumnVisible = true;
@@ -1406,6 +1433,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.tabfront.ResumeLayout(false);
 			this.tabfront.PerformLayout();
 			this.frontgroup.ResumeLayout(false);
+			this.frontgroup.PerformLayout();
 			this.frontflagsgroup.ResumeLayout(false);
 			this.frontscalegroup.ResumeLayout(false);
 			this.groupBox6.ResumeLayout(false);
@@ -1414,6 +1442,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.tabback.ResumeLayout(false);
 			this.tabback.PerformLayout();
 			this.backgroup.ResumeLayout(false);
+			this.backgroup.PerformLayout();
 			this.groupBox4.ResumeLayout(false);
 			this.groupBox4.PerformLayout();
 			this.backflagsgroup.ResumeLayout(false);
@@ -1517,5 +1546,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private CodeImp.DoomBuilder.GZBuilder.Controls.TagsSelector tagsselector;
 		private System.Windows.Forms.Button resetfrontlight;
 		private System.Windows.Forms.Button resetbacklight;
+		private System.Windows.Forms.CheckBox replaceunusedfronttextures;
+		private System.Windows.Forms.CheckBox replaceunusedbacktextures;
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/LinedefEditFormUDMF.cs b/Source/Core/Windows/LinedefEditFormUDMF.cs
index 8098c5da7c09e087952e97549f4bdd1dbd787d17..35069bfb8b764c5408a5882bb3f98a602c04d01c 100644
--- a/Source/Core/Windows/LinedefEditFormUDMF.cs
+++ b/Source/Core/Windows/LinedefEditFormUDMF.cs
@@ -102,22 +102,22 @@ namespace CodeImp.DoomBuilder.Windows
 			public readonly int Brightness;
 			public readonly bool AbsoluteBrightness;
 
-			public readonly string TextureTop;
-			public readonly string TextureMid;
-			public readonly string TextureLow;
+			public readonly string HighTexture;
+			public readonly string MiddleTexture;
+			public readonly string LowTexture;
 
 			public SidedefProperties(Sidedef side) 
 			{
 				Flags = side.GetFlags();
 
-				//offset
+				// Offset
 				OffsetX = side.OffsetX;
 				OffsetY = side.OffsetY;
 
 				Brightness = UniFields.GetInteger(side.Fields, "light", 0);
 				AbsoluteBrightness = side.Fields.GetValue("lightabsolute", false);
 
-				//scales
+				// Scale
 				ScaleTopX = UniFields.GetFloat(side.Fields, "scalex_top", 1.0f);
 				ScaleTopY = UniFields.GetFloat(side.Fields, "scaley_top", 1.0f);
 				ScaleMidX = UniFields.GetFloat(side.Fields, "scalex_mid", 1.0f);
@@ -125,7 +125,7 @@ namespace CodeImp.DoomBuilder.Windows
 				ScaleBottomX = UniFields.GetFloat(side.Fields, "scalex_bottom", 1.0f);
 				ScaleBottomY = UniFields.GetFloat(side.Fields, "scaley_bottom", 1.0f);
 
-				//offsets
+				// Local offsets
 				OffsetTopX = UniFields.GetFloat(side.Fields, "offsetx_top", 0f);
 				OffsetTopY = UniFields.GetFloat(side.Fields, "offsety_top", 0f);
 				OffsetMidX = UniFields.GetFloat(side.Fields, "offsetx_mid", 0f);
@@ -133,10 +133,10 @@ namespace CodeImp.DoomBuilder.Windows
 				OffsetBottomX = UniFields.GetFloat(side.Fields, "offsetx_bottom", 0f);
 				OffsetBottomY = UniFields.GetFloat(side.Fields, "offsety_bottom", 0f);
 
-				//textures
-				TextureTop = side.HighTexture;
-				TextureMid = side.MiddleTexture;
-				TextureLow = side.LowTexture;
+				// Textures
+				HighTexture = side.HighTexture;
+				MiddleTexture = side.MiddleTexture;
+				LowTexture = side.LowTexture;
 			}
 		}
 
@@ -149,7 +149,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// Initialize
 			InitializeComponent();
 
-			//mxd. Widow setup
+			// Widow setup
 			if(location != Point.Empty) 
 			{
 				this.StartPosition = FormStartPosition.Manual;
@@ -169,7 +169,7 @@ namespace CodeImp.DoomBuilder.Windows
 				flags.Add(lf.Value, lf.Key);
 			flags.Enabled = General.Map.Config.LinedefFlags.Count > 0;
 
-			//mxd
+			// Fill sidedef flags lists
 			foreach(KeyValuePair<string, string> lf in General.Map.Config.SidedefFlags) 
 			{
 				flagsFront.Add(lf.Value, lf.Key);
@@ -184,7 +184,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// Fill activations list
 			foreach(LinedefActivateInfo ai in General.Map.Config.LinedefActivates) udmfactivates.Add(ai.Title, ai);
 
-			//mxd. Fill keys list
+			// Fill keys list
 			keynumbers = new List<int>();
 			if(General.Map.Config.Enums.ContainsKey("keys"))
 			{
@@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.Windows
 			// Fill universal fields list
 			fieldslist.ListFixedFields(General.Map.Config.LinedefFields);
 
-			//initialize controls
+			// Initialize controls
 			frontUdmfControls = new List<PairedFieldsControl> { pfcFrontOffsetTop, pfcFrontOffsetMid, pfcFrontOffsetBottom, pfcFrontScaleTop, pfcFrontScaleMid, pfcFrontScaleBottom };
 			backUdmfControls = new List<PairedFieldsControl> { pfcBackOffsetTop, pfcBackOffsetMid, pfcBackOffsetBottom, pfcBackScaleTop, pfcBackScaleMid, pfcBackScaleBottom };
 
@@ -225,13 +225,19 @@ namespace CodeImp.DoomBuilder.Windows
 			foreach(KeyValuePair<string, string> lf in General.Map.Config.LinedefRenderStyles)
 				renderStyle.Items.Add(lf.Value);
 
-			//Restore value linking
+			// Restore value linking
 			pfcFrontScaleTop.LinkValues = linkFrontTopScale;
 			pfcFrontScaleMid.LinkValues = linkFrontMidScale;
 			pfcFrontScaleBottom.LinkValues = linkFrontBottomScale;
 			pfcBackScaleTop.LinkValues = linkBackTopScale;
 			pfcBackScaleMid.LinkValues = linkBackMidScale;
 			pfcBackScaleBottom.LinkValues = linkBackBottomScale;
+
+			// Apply texture replacement settings
+			preventchanges = true;
+			replaceunusedfronttextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedfronttextures", true);
+			replaceunusedbacktextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedbacktextures", true);
+			preventchanges = false;
 		}
 
 		#endregion
@@ -301,11 +307,11 @@ namespace CodeImp.DoomBuilder.Windows
 				frontlow.Required = fl.Front.LowRequired();
 				frontsector.Text = fl.Front.Sector.Index.ToString();
 
-				//flags
+				// Flags
 				foreach(CheckBox c in flagsFront.Checkboxes)
 					if(fl.Front.Flags.ContainsKey(c.Tag.ToString())) c.Checked = fl.Front.Flags[c.Tag.ToString()];
 
-				//front settings
+				// Front settings
 				foreach(PairedFieldsControl pfc in frontUdmfControls)
 					pfc.SetValuesFrom(fl.Front.Fields, true);
 
@@ -326,11 +332,11 @@ namespace CodeImp.DoomBuilder.Windows
 				backlow.Required = fl.Back.LowRequired();
 				backsector.Text = fl.Back.Sector.Index.ToString();
 
-				//flags
+				// Flags
 				foreach(CheckBox c in flagsBack.Checkboxes)
 					if(fl.Back.Flags.ContainsKey(c.Tag.ToString())) c.Checked = fl.Back.Flags[c.Tag.ToString()];
 
-				//back settings
+				// Back settings
 				foreach(PairedFieldsControl pfc in backUdmfControls)
 					pfc.SetValuesFrom(fl.Back.Fields, true);
 
@@ -432,19 +438,19 @@ namespace CodeImp.DoomBuilder.Windows
 				if(l.Front != null)
 				{
 					//mxd
-					if(fronthigh.TextureName != l.Front.HighTexture) 
+					if(!string.IsNullOrEmpty(fronthigh.TextureName) && fronthigh.TextureName != l.Front.HighTexture) 
 					{
 						if(!fronthigh.Required && l.Front.HighRequired()) fronthigh.Required = true;
-						fronthigh.MultipleTextures = true; //mxd
+						fronthigh.MultipleTextures = true;
 						fronthigh.TextureName = string.Empty;
 					}
-					if(frontmid.TextureName != l.Front.MiddleTexture) 
+					if(!string.IsNullOrEmpty(frontmid.TextureName) && frontmid.TextureName != l.Front.MiddleTexture) 
 					{
 						if(!frontmid.Required && l.Front.MiddleRequired()) frontmid.Required = true;
-						frontmid.MultipleTextures = true; //mxd
+						frontmid.MultipleTextures = true;
 						frontmid.TextureName = string.Empty;
 					}
-					if(frontlow.TextureName != l.Front.LowTexture) 
+					if(!string.IsNullOrEmpty(frontlow.TextureName) && frontlow.TextureName != l.Front.LowTexture) 
 					{
 						if(!frontlow.Required && l.Front.LowRequired()) frontlow.Required = true;
 						frontlow.MultipleTextures = true; //mxd
@@ -486,22 +492,22 @@ namespace CodeImp.DoomBuilder.Windows
 				if(l.Back != null)
 				{
 					//mxd
-					if(backhigh.TextureName != l.Back.HighTexture) 
+					if(!string.IsNullOrEmpty(backhigh.TextureName) && backhigh.TextureName != l.Back.HighTexture) 
 					{
 						if(!backhigh.Required && l.Back.HighRequired()) backhigh.Required = true;
-						backhigh.MultipleTextures = true; //mxd
+						backhigh.MultipleTextures = true;
 						backhigh.TextureName = string.Empty;
 					}
-					if(backmid.TextureName != l.Back.MiddleTexture) 
+					if(!string.IsNullOrEmpty(backmid.TextureName) && backmid.TextureName != l.Back.MiddleTexture) 
 					{
 						if(!backmid.Required && l.Back.MiddleRequired()) backmid.Required = true;
-						backmid.MultipleTextures = true; //mxd
+						backmid.MultipleTextures = true;
 						backmid.TextureName = string.Empty;
 					}
-					if(backlow.TextureName != l.Back.LowTexture) 
+					if(!string.IsNullOrEmpty(backlow.TextureName) && backlow.TextureName != l.Back.LowTexture) 
 					{
 						if(!backlow.Required && l.Back.LowRequired()) backlow.Required = true;
-						backlow.MultipleTextures = true; //mxd
+						backlow.MultipleTextures = true;
 						backlow.TextureName = string.Empty;
 					}
 					if(backsector.Text != l.Back.Sector.Index.ToString()) backsector.Text = string.Empty;
@@ -829,11 +835,16 @@ namespace CodeImp.DoomBuilder.Windows
 			fieldslist.Focus();
 		}
 
-		//mxd. Store window location
+		//mxd. Store window settings
 		private void LinedefEditForm_FormClosing(object sender, FormClosingEventArgs e) 
 		{
+			// Save location and active tab
 			location = this.Location;
 			activetab = tabs.SelectedIndex;
+
+			// Save persistent settings
+			General.Settings.WriteSetting("editlinedefswindow.replaceunusedfronttextures", replaceunusedfronttextures.Checked);
+			General.Settings.WriteSetting("editlinedefswindow.replaceunusedbacktextures", replaceunusedbacktextures.Checked);
 		}
 
 		// Help!
@@ -1055,23 +1066,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void fronthigh_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(fronthigh.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.TextureTop : "-");
+					if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else 
 			{
-				foreach(Linedef l in lines) 
-					if(l.Front != null)	l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+				int i = 0;
+				foreach(Linedef l in lines)
+				{
+					if(l.Front != null
+						&& (replaceunusedfronttextures.Checked
+						|| (l.Front.HighRequired()
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.HighTexture != "-"))))
+						l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -1084,23 +1103,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void frontmid_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(frontmid.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.TextureMid : "-");
+					if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else 
 			{
-				foreach(Linedef l in lines) 
-					if(l.Front != null)	l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+				int i = 0;
+				foreach(Linedef l in lines)
+				{
+					if(l.Front != null
+						&& (replaceunusedfronttextures.Checked
+						|| (l.Front.MiddleRequired()
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.MiddleTexture != "-"))))
+						l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -1113,23 +1140,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void frontlow_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(frontlow.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.TextureLow : "-");
+					if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Front != null) l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+				{
+					if(l.Front != null
+						&& (replaceunusedfronttextures.Checked
+						|| (l.Front.LowRequired()
+						|| (linedefprops[i].Front != null && linedefprops[i].Front.LowTexture != "-"))))
+						l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -1142,23 +1177,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backhigh_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backhigh.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.TextureTop : "-");
+					if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else 
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.HighRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.HighTexture != "-"))))
+						l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -1171,23 +1214,31 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backmid_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backmid.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.TextureMid : "-");
+					if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.MiddleRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.MiddleTexture != "-"))))
+						l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+					i++;
+				}
 			}
 
 			// Update the used textures
@@ -1200,23 +1251,111 @@ namespace CodeImp.DoomBuilder.Windows
 		private void backlow_OnValueChanged(object sender, EventArgs e) 
 		{
 			if(preventchanges) return;
-			MakeUndo(); //mxd
+			MakeUndo();
 
-			//restore values
+			// Restore values
 			if(string.IsNullOrEmpty(backlow.TextureName)) 
 			{
 				int i = 0;
-
 				foreach(Linedef l in lines) 
 				{
-					if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.TextureLow : "-");
+					if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-");
 					i++;
 				}
-			} 
-			else //update values
+			}
+			// Update values
+			else 
 			{
+				int i = 0;
 				foreach(Linedef l in lines)
-					if(l.Back != null) l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+				{
+					if(l.Back != null
+						&& (replaceunusedbacktextures.Checked
+						|| (l.Back.LowRequired()
+						|| (linedefprops[i].Back != null && linedefprops[i].Back.LowTexture != "-"))))
+						l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+					i++;
+				}
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		private void replaceunusedfronttextures_CheckedChanged(object sender, EventArgs e)
+		{
+			//Re-apply front textures
+			if(preventchanges) return;
+			MakeUndo();
+
+			// Set values
+			int i = 0;
+			foreach(Linedef l in lines)
+			{
+				if(l.Front == null) continue;
+
+				// Update top texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(fronthigh.TextureName))
+					l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-");
+				else
+					l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture));
+
+				// Update middle texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontmid.TextureName))
+					l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-");
+				else
+					l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture));
+
+				// Update bottom texture
+				if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontlow.TextureName))
+					l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-");
+				else
+					l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture));
+
+				i++;
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		private void replaceunusedbacktextures_CheckedChanged(object sender, EventArgs e)
+		{
+			//Re-apply back textures
+			if(preventchanges) return;
+			MakeUndo();
+
+			// Set values
+			int i = 0;
+			foreach(Linedef l in lines)
+			{
+				if(l.Back == null) continue;
+
+				// Update top texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backhigh.TextureName))
+					l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-");
+				else
+					l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture));
+
+				// Update middle texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backmid.TextureName))
+					l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-");
+				else
+					l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture));
+
+				// Update bottom texture
+				if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backlow.TextureName))
+					l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-");
+				else
+					l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture));
+
+				i++;
 			}
 
 			// Update the used textures
diff --git a/Source/Core/Windows/LinedefEditFormUDMF.resx b/Source/Core/Windows/LinedefEditFormUDMF.resx
index d572a5b76a7701bbfde350c0bece45467dc73b51..e3a990b4748e58197abef9cb6947f2b5ea887144 100644
--- a/Source/Core/Windows/LinedefEditFormUDMF.resx
+++ b/Source/Core/Windows/LinedefEditFormUDMF.resx
@@ -146,7 +146,7 @@
         AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w
         LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
         ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADM
-        CAAAAk1TRnQBSQFMAgEBAgEAAcABAAHAAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
+        CAAAAk1TRnQBSQFMAgEBAgEAAcgBAAHIAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
         AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
         AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
         AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs
index ef555c39287455d68f5c9ec4d6a3ed46925ff761..ed08300990810875b6490ee4609e27d7778eb36f 100644
--- a/Source/Core/Windows/MainForm.Designer.cs
+++ b/Source/Core/Windows/MainForm.Designer.cs
@@ -182,6 +182,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.buttonviewceilings = new System.Windows.Forms.ToolStripButton();
 			this.seperatorviews = new System.Windows.Forms.ToolStripSeparator();
 			this.buttontogglecomments = new System.Windows.Forms.ToolStripButton();
+			this.buttontogglefixedthingsscale = new System.Windows.Forms.ToolStripButton();
 			this.buttonsnaptogrid = new System.Windows.Forms.ToolStripButton();
 			this.buttonautomerge = new System.Windows.Forms.ToolStripButton();
 			this.buttonautoclearsidetextures = new System.Windows.Forms.ToolStripButton();
@@ -256,6 +257,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.flowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel();
 			this.modecontrolsloolbar = new System.Windows.Forms.ToolStrip();
 			this.itemtogglecomments = new System.Windows.Forms.ToolStripMenuItem();
+			this.itemtogglefixedthingsscale = new System.Windows.Forms.ToolStripMenuItem();
 			this.itemdynamicgridsize = new System.Windows.Forms.ToolStripMenuItem();
             this.itemrendernightspath = new System.Windows.Forms.ToolStripMenuItem();
             toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
@@ -741,6 +743,7 @@ namespace CodeImp.DoomBuilder.Windows
             this.itemtogglegrid,
             this.itemrendernightspath,
             this.itemtogglecomments,
+			this.itemtogglefixedthingsscale,
             this.toolStripSeparator4,
             this.menuzoom,
             this.itemgotocoords,
@@ -1247,6 +1250,7 @@ namespace CodeImp.DoomBuilder.Windows
             this.buttonfullbrightness,
             this.buttontogglegrid,
             this.buttontogglecomments,
+			this.buttontogglefixedthingsscale,
             this.separatorfullbrightness,
             this.buttonviewnormal,
             this.buttonviewbrightness,
@@ -1677,6 +1681,19 @@ namespace CodeImp.DoomBuilder.Windows
 			this.buttontogglecomments.Text = "Show Comments";
 			this.buttontogglecomments.Click += new System.EventHandler(this.InvokeTaggedAction);
 			// 
+			// buttontogglefixedthingsscale
+			// 
+			this.buttontogglefixedthingsscale.Checked = true;
+			this.buttontogglefixedthingsscale.CheckState = System.Windows.Forms.CheckState.Checked;
+			this.buttontogglefixedthingsscale.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+			this.buttontogglefixedthingsscale.Image = global::CodeImp.DoomBuilder.Properties.Resources.FixedThingsScale;
+			this.buttontogglefixedthingsscale.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.buttontogglefixedthingsscale.Name = "buttontogglefixedthingsscale";
+			this.buttontogglefixedthingsscale.Size = new System.Drawing.Size(23, 22);
+			this.buttontogglefixedthingsscale.Tag = "builder_togglefixedthingsscale";
+			this.buttontogglefixedthingsscale.Text = "Fixed Things Scale";
+			this.buttontogglefixedthingsscale.Click += new System.EventHandler(this.InvokeTaggedAction);
+			// 
 			// buttonsnaptogrid
 			// 
 			this.buttonsnaptogrid.Checked = true;
@@ -2234,9 +2251,9 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			this.statistics.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
 			this.statistics.ForeColor = System.Drawing.SystemColors.GrayText;
-			this.statistics.Location = new System.Drawing.Point(869, 2);
+			this.statistics.Location = new System.Drawing.Point(849, 2);
 			this.statistics.Name = "statistics";
-			this.statistics.Size = new System.Drawing.Size(118, 102);
+			this.statistics.Size = new System.Drawing.Size(138, 102);
 			this.statistics.TabIndex = 9;
 			this.statistics.Visible = false;
 			// 
@@ -2448,6 +2465,18 @@ namespace CodeImp.DoomBuilder.Windows
 			this.itemtogglecomments.Text = "Show Comments";
 			this.itemtogglecomments.Click += new System.EventHandler(this.InvokeTaggedAction);
 			// 
+			// itemtogglefixedthingsscale
+			// 
+			this.itemtogglefixedthingsscale.Checked = true;
+			this.itemtogglefixedthingsscale.CheckOnClick = true;
+			this.itemtogglefixedthingsscale.CheckState = System.Windows.Forms.CheckState.Checked;
+			this.itemtogglefixedthingsscale.Image = global::CodeImp.DoomBuilder.Properties.Resources.FixedThingsScale;
+			this.itemtogglefixedthingsscale.Name = "itemtogglefixedthingsscale";
+			this.itemtogglefixedthingsscale.Size = new System.Drawing.Size(215, 22);
+			this.itemtogglefixedthingsscale.Tag = "builder_togglefixedthingsscale";
+			this.itemtogglefixedthingsscale.Text = "Fixed Things Scale";
+			this.itemtogglefixedthingsscale.Click += new System.EventHandler(this.InvokeTaggedAction);
+			// 
 			// itemdynamicgridsize
 			// 
 			this.itemdynamicgridsize.Checked = true;
@@ -2725,6 +2754,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private ToolStripMenuItem item2zoom800;
 		private ToolStripMenuItem itemzoom800;
 		private ToolStripButton buttontogglecomments;
+		private ToolStripButton buttontogglefixedthingsscale;
 		private ToolStripMenuItem itemlinedefcolors;
 		private ToolStripSeparator separatorlinecolors;
 		private ToolStripButton buttonlinededfcolors;
@@ -2737,5 +2767,6 @@ namespace CodeImp.DoomBuilder.Windows
         private ToolStripMenuItem itemdynamicgridsize;
         private ToolStripMenuItem itemrendernightspath;
 		private ToolStripMenuItem itemtogglecomments;
+		private ToolStripMenuItem itemtogglefixedthingsscale;
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index cdde40ad2f81e0ea55a600da7c64e2def5db4486..64fd4c7b5e21ac9c029fe1dabb5b50ac782dae36 100644
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -734,14 +734,14 @@ namespace CodeImp.DoomBuilder.Windows
 
 				if(!File.Exists(filePaths[0])) 
 				{
-					General.Interface.DisplayStatus(StatusType.Warning, "Cannot open '" + filePaths[0] + "': file does not exist!");
+					General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filePaths[0] + "\": file does not exist!");
 					return;
 				}
 
 				string ext = Path.GetExtension(filePaths[0]);
 				if(string.IsNullOrEmpty(ext) || ext.ToLower() != ".wad") 
 				{
-					General.Interface.DisplayStatus(StatusType.Warning, "Cannot open '" + filePaths[0] + "': only WAD files can be loaded this way!");
+					General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filePaths[0] + "\": only WAD files can be loaded this way!");
 					return;
 				}
 
@@ -970,6 +970,9 @@ namespace CodeImp.DoomBuilder.Windows
 					// Get integral zoom level
 					int size = int.Parse((sender as ToolStripMenuItem).Tag.ToString(), CultureInfo.InvariantCulture);
 
+					//mxd. Disable automatic grid resizing
+					DisableDynamicGridResize();
+
 					// Change grid size
 					General.Map.Grid.SetGridSize(size);
 					
@@ -1493,8 +1496,7 @@ namespace CodeImp.DoomBuilder.Windows
 			if(General.Map != null)
 			{
 				// Make the new items list
-				ToolStripItem[] items = new ToolStripItem[(General.Map.Config.Skills.Count * 2) + General.Map.ConfigSettings.TestEngines.Count + 2]; //mxd
-				int addindex = 0;
+				List<ToolStripItem> items = new List<ToolStripItem>(General.Map.Config.Skills.Count * 2 + General.Map.ConfigSettings.TestEngines.Count + 2);
 				
 				// Positive skills are with monsters
 				foreach(SkillInfo si in General.Map.Config.Skills)
@@ -1504,12 +1506,11 @@ namespace CodeImp.DoomBuilder.Windows
 					menuitem.Click += TestSkill_Click;
 					menuitem.Tag = si.Index;
 					menuitem.Checked = (General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
-					items[addindex++] = menuitem;
+					items.Add(menuitem);
 				}
 
 				// Add seperator
-				items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) };
-				addindex++;
+				items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) });
 
 				// Negative skills are without monsters
 				foreach(SkillInfo si in General.Map.Config.Skills)
@@ -1519,26 +1520,37 @@ namespace CodeImp.DoomBuilder.Windows
 					menuitem.Click += TestSkill_Click;
 					menuitem.Tag = -si.Index;
 					menuitem.Checked = (!General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
-					items[addindex++] = menuitem;
+					items.Add(menuitem);
 				}
 
 				//mxd. Add seperator
-				items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) };
-				addindex++;
+				items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) });
 
 				//mxd. Add test engines
 				for(int i = 0; i < General.Map.ConfigSettings.TestEngines.Count; i++)
 				{
+					if(General.Map.ConfigSettings.TestEngines[i].TestProgramName == EngineInfo.DEFAULT_ENGINE_NAME) continue;
 					ToolStripMenuItem menuitem = new ToolStripMenuItem(General.Map.ConfigSettings.TestEngines[i].TestProgramName);
 					menuitem.Image = General.Map.ConfigSettings.TestEngines[i].TestProgramIcon;
 					menuitem.Click += TestEngine_Click;
 					menuitem.Tag = i;
 					menuitem.Checked = (i == General.Map.ConfigSettings.CurrentEngineIndex);
-					items[addindex++] = menuitem;
+					items.Add(menuitem);
 				}
 				
 				// Add to list
-				buttontest.DropDownItems.AddRange(items);
+				buttontest.DropDownItems.AddRange(items.ToArray());
+			}
+		}
+
+		//mxd
+		internal void DisableDynamicGridResize()
+		{
+			if(General.Settings.DynamicGridSize)
+			{
+				General.Settings.DynamicGridSize = false;
+				itemdynamicgridsize.Checked = false;
+				buttontoggledynamicgrid.Checked = false;
 			}
 		}
 
@@ -2027,6 +2039,8 @@ namespace CodeImp.DoomBuilder.Windows
             itemrendernightspath.Checked = General.Settings.RenderNiGHTSPath;
             buttontogglecomments.Visible = General.Settings.ToolbarViewModes && maploaded && General.Map.UDMF; //mxd
 			buttontogglecomments.Checked = General.Settings.RenderComments; //mxd
+			buttontogglefixedthingsscale.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
+			buttontogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd
 			separatorfullbrightness.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd
 			buttonviewbrightness.Visible = General.Settings.ToolbarViewModes && maploaded;
 			buttonviewceilings.Visible = General.Settings.ToolbarViewModes && maploaded;
@@ -2048,7 +2062,7 @@ namespace CodeImp.DoomBuilder.Windows
 			buttontogglefog.Visible = General.Settings.GZToolbarGZDoom && maploaded;
             buttontogglesky.Visible = maploaded && (General.Settings.GZToolbarGZDoom || General.Map.SRB2);
             buttontoggleeventlines.Visible = General.Settings.GZToolbarGZDoom && maploaded;
-			buttontogglevisualvertices.Visible = General.Settings.GZToolbarGZDoom && maploaded;
+			buttontogglevisualvertices.Visible = General.Settings.GZToolbarGZDoom && maploaded && General.Map.UDMF;
 			separatorgzmodes.Visible = General.Settings.GZToolbarGZDoom && maploaded;
 
 			//mxd. Show/hide additional panels
@@ -2776,6 +2790,19 @@ namespace CodeImp.DoomBuilder.Windows
 			RedrawDisplay();
 		}
 
+		//mxd. Action to toggle fixed things scale
+		[BeginAction("togglefixedthingsscale")]
+		internal void ToggleFixedThingsScale()
+		{
+			buttontogglefixedthingsscale.Checked = !buttontogglefixedthingsscale.Checked;
+			itemtogglefixedthingsscale.Checked = buttontogglefixedthingsscale.Checked;
+			General.Settings.FixedThingsScale = buttontogglefixedthingsscale.Checked;
+			DisplayStatus(StatusType.Action, "Fixed things scale is " + (buttontogglefixedthingsscale.Checked ? "ENABLED" : "DISABLED"));
+
+			// Redraw display to show changes
+			RedrawDisplay();
+		}
+
 		// Action to toggle snap to grid
 		[BeginAction("togglesnap")]
 		internal void ToggleSnapToGrid()
@@ -2888,6 +2915,8 @@ namespace CodeImp.DoomBuilder.Windows
 			itemtoggleinfo.Checked = IsInfoPanelExpanded;
 			itemtogglecomments.Visible = (General.Map != null && General.Map.UDMF); //mxd
 			itemtogglecomments.Checked = General.Settings.RenderComments; //mxd
+			itemtogglefixedthingsscale.Visible = (General.Map != null); //mxd
+			itemtogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd
 			
 			// View mode items
 			if(General.Map != null)
@@ -3059,7 +3088,7 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 
 			//open file
-			DisplayStatus(StatusType.Info, "Shortcut reference saved to '" + path + "'");
+			DisplayStatus(StatusType.Info, "Shortcut reference saved to \"" + path + "\"");
 			Process.Start(path);
 		}
 
@@ -3067,8 +3096,8 @@ namespace CodeImp.DoomBuilder.Windows
 		private void itemopenconfigfolder_Click(object sender, EventArgs e)
 		{
 			if(Directory.Exists(General.SettingsPath)) Process.Start(General.SettingsPath);
-			else General.ShowErrorMessage("Huh? Where did Settings folder go?.." + Environment.NewLine 
-				+ "I swear it was here: '" + General.SettingsPath + "'!", MessageBoxButtons.OK); // I don't think this will ever happen
+			else General.ShowErrorMessage("Huh? Where did Settings folder go?.." + Environment.NewLine
+				+ "I swear it was here: \"" + General.SettingsPath + "\"!", MessageBoxButtons.OK); // I don't think this will ever happen
 		}
 		
 		#endregion
@@ -3195,11 +3224,11 @@ namespace CodeImp.DoomBuilder.Windows
 			string folder = General.Settings.ScreenshotsPath;
 			if(!Directory.Exists(folder)) 
 			{
-				if(folder != General.DefaultScreenshotsPath 
-					&& General.ShowErrorMessage("Screenshots save path '" + folder 
-					+ "' does not exist!\nPress OK to save to the default folder ('" 
-					+ General.DefaultScreenshotsPath 
-					+ "').\nPress Cancel to abort.", MessageBoxButtons.OKCancel) == DialogResult.Cancel) return;
+				if(folder != General.DefaultScreenshotsPath
+					&& General.ShowErrorMessage("Screenshots save path \"" + folder
+					+ "\" does not exist!\nPress OK to save to the default folder (\"" 
+					+ General.DefaultScreenshotsPath
+					+ "\").\nPress Cancel to abort.", MessageBoxButtons.OKCancel) == DialogResult.Cancel) return;
 
 
 				folder = General.DefaultScreenshotsPath;
@@ -3332,7 +3361,7 @@ namespace CodeImp.DoomBuilder.Windows
                     {
                         bitmap.Save(path, ImageFormat.Png);
                     }
-                    DisplayStatus(StatusType.Info, "Screenshot saved to '" + path + "'");
+                    DisplayStatus(StatusType.Info, "Screenshot saved to \"" + path + "\"");
 				} 
 				catch(ExternalException e) 
 				{
@@ -3690,14 +3719,28 @@ namespace CodeImp.DoomBuilder.Windows
 		// Returns the new action or the same action when cancelled
 		public int BrowseLinedefActions(IWin32Window owner, int initialvalue)
 		{
-			return ActionBrowserForm.BrowseAction(owner, initialvalue);
+			return ActionBrowserForm.BrowseAction(owner, initialvalue, false);
+		}
+		
+		//mxd. This browses the lindef types
+		// Returns the new action or the same action when cancelled
+		public int BrowseLinedefActions(IWin32Window owner, int initialvalue, bool addanyaction)
+		{
+			return ActionBrowserForm.BrowseAction(owner, initialvalue, addanyaction);
 		}
 
 		// This browses sector effects
 		// Returns the new effect or the same effect when cancelled
 		public int BrowseSectorEffect(IWin32Window owner, int initialvalue)
 		{
-			return EffectBrowserForm.BrowseEffect(owner, initialvalue);
+			return EffectBrowserForm.BrowseEffect(owner, initialvalue, false);
+		}
+
+		//mxd. This browses sector effects
+		// Returns the new effect or the same effect when cancelled
+		public int BrowseSectorEffect(IWin32Window owner, int initialvalue, bool addanyeffect)
+		{
+			return EffectBrowserForm.BrowseEffect(owner, initialvalue, addanyeffect);
 		}
 
 		// This browses thing types
diff --git a/Source/Core/Windows/OpenMapOptionsForm.Designer.cs b/Source/Core/Windows/OpenMapOptionsForm.Designer.cs
index e6db65578fe345b5270d5663d15a940d1c3a6b11..93442de0a7d7399971038019d65555c377656028 100644
--- a/Source/Core/Windows/OpenMapOptionsForm.Designer.cs
+++ b/Source/Core/Windows/OpenMapOptionsForm.Designer.cs
@@ -225,7 +225,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.MaximizeBox = false;
 			this.MinimizeBox = false;
 			this.Name = "OpenMapOptionsForm";
-			this.Opacity = 1;
+			this.Opacity = 0;
 			this.ShowIcon = false;
 			this.ShowInTaskbar = false;
 			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
diff --git a/Source/Core/Windows/OpenMapOptionsForm.cs b/Source/Core/Windows/OpenMapOptionsForm.cs
index cfcfe6fffe037cb77a4d19aeded50a1d22efe7bf..d6dfd94d2e4a6748d18fcf105a31280ed2cfe0d7 100644
--- a/Source/Core/Windows/OpenMapOptionsForm.cs
+++ b/Source/Core/Windows/OpenMapOptionsForm.cs
@@ -30,7 +30,7 @@ using CodeImp.DoomBuilder.Config;
 
 namespace CodeImp.DoomBuilder.Windows
 {
-	internal partial class OpenMapOptionsForm : DelayedForm
+	internal partial class OpenMapOptionsForm : Form
 	{
 		// Variables
 		private Configuration mapsettings;
@@ -126,72 +126,103 @@ namespace CodeImp.DoomBuilder.Windows
 				scriptcompiler.Items.Add(group.Value);
 			}
 
-			//mxd. Go for all enabled configurations
-			for(int i = 0; i < General.Configs.Count; i++) 
+			// Go for all configurations
+			foreach(ConfigurationInfo info in General.Configs)
 			{
-				if(!General.Configs[i].Enabled) continue;
-				
 				// Add config name to list
-				index = config.Items.Add(General.Configs[i]);
+				index = config.Items.Add(info);
 
 				// Select this item
-				if(General.Configs[i].Filename == gameconfig) config.SelectedIndex = index;
+				if(info.Filename == gameconfig) config.SelectedIndex = index;
 			}
 
-			//mxd. No dice? Try disabled ones
+			// Still no configuration selected?
 			if(config.SelectedIndex == -1) 
 			{
-				for(int i = 0; i < General.Configs.Count; i++) 
+				//mxd. Then go for all ENABLED configurations with resources to find a suitable one
+				foreach(ConfigurationInfo info in General.Configs)
 				{
-					if(General.Configs[i].Enabled) continue;
-					if(General.Configs[i].Filename == gameconfig) 
+					// Check if a resource location is set for this configuration, if so, match the wad against this configuration
+					if(info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile))
 					{
-						//add and Select this item
-						config.SelectedIndex = config.Items.Add(General.Configs[i]);
+						//mxd. Already added?
+						index = config.Items.IndexOf(info);
+
+						// Select or add and select this item
+						config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); 
 						break;
 					}
 				}
 			}
 
-			// Still no configuration selected?
-			if(config.SelectedIndex == -1) 
+			//mxd. Still no configuration selected?
+			if(config.SelectedIndex == -1)
 			{
-				// Then go for all configurations with resources to find a suitable one
-				for(int i = 0; i < General.Configs.Count; i++)
+				// Then go for all DISABLED configurations with resources to find a suitable one
+				foreach(ConfigurationInfo info in General.Configs)
 				{
 					// Check if a resource location is set for this configuration, if so, match the wad against this configuration
-					if(General.Configs[i].Resources.Count > 0 && MatchConfiguration(General.Configs[i].Configuration, wadfile))
+					if(!info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile))
 					{
-						index = config.Items.IndexOf(General.Configs[i]); //mxd. Already added?
-						config.SelectedIndex = (index != -1 ? index : config.Items.Add(General.Configs[i])); // Select or add and select this item
+						//mxd. Already added?
+						index = config.Items.IndexOf(info);
+
+						// Select or add and select this item
+						config.SelectedIndex = (index != -1 ? index : config.Items.Add(info));
 						break;
 					}
 				}
 			}
 
 			//mxd. Still no configuration selected?
-			if(config.SelectedIndex == -1) 
+			if(config.SelectedIndex == -1)
+			{
+				//mxd. Then go for all ENABLED configurations without resources to find a suitable one
+				foreach(ConfigurationInfo info in General.Configs)
+				{
+					// Check if a resource location is not set for this configuration, if so, match the wad against this configuration
+					if(info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile))
+					{
+						//mxd. Already added?
+						index = config.Items.IndexOf(info);
+
+						// Select or add and select this item
+						config.SelectedIndex = (index != -1 ? index : config.Items.Add(info));
+						break;
+					}
+				}
+			}
+
+			//mxd. Still no configuration selected?
+			if(config.SelectedIndex == -1)
 			{
-				// Then go for all configurations without resources to find a suitable one
-				for(int i = 0; i < General.Configs.Count; i++) 
+				// Then go for all DISABLED configurations without resources to find a suitable one
+				foreach(ConfigurationInfo info in General.Configs)
 				{
 					// Check if a resource location is not set for this configuration, if so, match the wad against this configuration
-					if(General.Configs[i].Resources.Count == 0 && MatchConfiguration(General.Configs[i].Configuration, wadfile)) 
+					if(!info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile))
 					{
-						index = config.Items.IndexOf(General.Configs[i]); //mxd. Already added?
-						config.SelectedIndex = (index != -1 ? index : config.Items.Add(General.Configs[i])); // Select or add and select this item
+						//mxd. Already added?
+						index = config.Items.IndexOf(info);
+
+						// Select or add and select this item
+						config.SelectedIndex = (index != -1 ? index : config.Items.Add(info));
 						break;
 					}
 				}
 			}
 			
 			//mxd. Bail out if still no dice...
-			if(config.SelectedIndex == -1)
+			if(config.SelectedIndex == -1 || mapslist.Items.Count == 0)
 			{
-				this.Visible = false;
 				General.ShowWarningMessage("Unable to find maps using any game configuration.\nDoes this wad contain any maps at all?..", MessageBoxButtons.OK);
 				cancel_Click(this, EventArgs.Empty);
 			}
+			else
+			{
+				// Show the window
+				this.Opacity = 1;
+			}
 
 			// Done
 			Cursor.Current = Cursors.Default;
diff --git a/Source/Core/Windows/PreferencesForm.Designer.cs b/Source/Core/Windows/PreferencesForm.Designer.cs
index b9fafc3143f914a0b9032c245c0bb44520943659..4871b4d380ee5ba587a0dd0d2c537cdafc192ab9 100644
--- a/Source/Core/Windows/PreferencesForm.Designer.cs
+++ b/Source/Core/Windows/PreferencesForm.Designer.cs
@@ -40,10 +40,10 @@ namespace CodeImp.DoomBuilder.Windows
             System.Windows.Forms.Label label21;
             System.Windows.Forms.Label label29;
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PreferencesForm));
+            this.keepfilterfocused = new System.Windows.Forms.CheckBox();
             this.maxBackups = new System.Windows.Forms.TrackBar();
             this.labelBackups = new System.Windows.Forms.Label();
             this.label27 = new System.Windows.Forms.Label();
-            this.checkforupdates = new System.Windows.Forms.CheckBox();
             this.cbStoreEditTab = new System.Windows.Forms.CheckBox();
             this.locatetexturegroup = new System.Windows.Forms.CheckBox();
             this.recentFiles = new System.Windows.Forms.TrackBar();
@@ -215,7 +215,6 @@ namespace CodeImp.DoomBuilder.Windows
             this.colorliterals = new CodeImp.DoomBuilder.Controls.ColorControl();
             this.colorconstants = new CodeImp.DoomBuilder.Controls.ColorControl();
             this.previewgroup = new System.Windows.Forms.GroupBox();
-            this.scriptedit = new CodeImp.DoomBuilder.Controls.ScriptEditorPreviewControl();
             this.tabpasting = new System.Windows.Forms.TabPage();
             this.label16 = new System.Windows.Forms.Label();
             this.pasteoptions = new CodeImp.DoomBuilder.Controls.PasteOptionsControl();
@@ -266,7 +265,6 @@ namespace CodeImp.DoomBuilder.Windows
             this.groupBox8.SuspendLayout();
             this.groupBox7.SuspendLayout();
             this.groupBox6.SuspendLayout();
-            this.previewgroup.SuspendLayout();
             this.tabpasting.SuspendLayout();
             this.SuspendLayout();
             // 
@@ -299,10 +297,10 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             // groupBox1
             // 
+            groupBox1.Controls.Add(this.keepfilterfocused);
             groupBox1.Controls.Add(this.maxBackups);
             groupBox1.Controls.Add(this.labelBackups);
             groupBox1.Controls.Add(this.label27);
-            groupBox1.Controls.Add(this.checkforupdates);
             groupBox1.Controls.Add(this.cbStoreEditTab);
             groupBox1.Controls.Add(this.locatetexturegroup);
             groupBox1.Controls.Add(this.recentFiles);
@@ -332,6 +330,18 @@ namespace CodeImp.DoomBuilder.Windows
             groupBox1.TabStop = false;
             groupBox1.Text = " Options ";
             // 
+            // keepfilterfocused
+            // 
+            this.keepfilterfocused.AutoSize = true;
+            this.keepfilterfocused.Location = new System.Drawing.Point(32, 356);
+            this.keepfilterfocused.Name = "keepfilterfocused";
+            this.keepfilterfocused.Size = new System.Drawing.Size(280, 17);
+            this.keepfilterfocused.TabIndex = 52;
+            this.keepfilterfocused.Text = "Keep Filter input focused when image browser is open";
+            this.toolTip1.SetToolTip(this.keepfilterfocused, "When enabled, all key presses in \r\nimage browsers will be redirected \r\nto the Fil" +
+        "ter textbox.");
+            this.keepfilterfocused.UseVisualStyleBackColor = true;
+            // 
             // maxBackups
             // 
             this.maxBackups.BackColor = System.Drawing.SystemColors.Window;
@@ -364,21 +374,10 @@ namespace CodeImp.DoomBuilder.Windows
             this.label27.Text = "Max. backups:";
             this.toolTip1.SetToolTip(this.label27, "Controls how many backups \r\nare made when a map is saved.");
             // 
-            // checkforupdates
-            // 
-            this.checkforupdates.AutoSize = true;
-            this.checkforupdates.Location = new System.Drawing.Point(32, 440);
-            this.checkforupdates.Name = "checkforupdates";
-            this.checkforupdates.Size = new System.Drawing.Size(160, 17);
-            this.checkforupdates.TabIndex = 51;
-            this.checkforupdates.Text = "Check for updates at startup";
-            this.checkforupdates.UseVisualStyleBackColor = true;
-            this.checkforupdates.Visible = false;
-            // 
             // cbStoreEditTab
             // 
             this.cbStoreEditTab.AutoSize = true;
-            this.cbStoreEditTab.Location = new System.Drawing.Point(32, 419);
+            this.cbStoreEditTab.Location = new System.Drawing.Point(32, 440);
             this.cbStoreEditTab.Name = "cbStoreEditTab";
             this.cbStoreEditTab.Size = new System.Drawing.Size(203, 17);
             this.cbStoreEditTab.TabIndex = 50;
@@ -388,7 +387,7 @@ namespace CodeImp.DoomBuilder.Windows
             // locatetexturegroup
             // 
             this.locatetexturegroup.AutoSize = true;
-            this.locatetexturegroup.Location = new System.Drawing.Point(32, 377);
+            this.locatetexturegroup.Location = new System.Drawing.Point(32, 398);
             this.locatetexturegroup.Name = "locatetexturegroup";
             this.locatetexturegroup.Size = new System.Drawing.Size(267, 17);
             this.locatetexturegroup.TabIndex = 49;
@@ -465,7 +464,7 @@ namespace CodeImp.DoomBuilder.Windows
             // cbSynchCameras
             // 
             this.cbSynchCameras.AutoSize = true;
-            this.cbSynchCameras.Location = new System.Drawing.Point(32, 398);
+            this.cbSynchCameras.Location = new System.Drawing.Point(32, 419);
             this.cbSynchCameras.Name = "cbSynchCameras";
             this.cbSynchCameras.Size = new System.Drawing.Size(260, 17);
             this.cbSynchCameras.TabIndex = 42;
@@ -475,7 +474,7 @@ namespace CodeImp.DoomBuilder.Windows
             // showtexturesizes
             // 
             this.showtexturesizes.AutoSize = true;
-            this.showtexturesizes.Location = new System.Drawing.Point(32, 356);
+            this.showtexturesizes.Location = new System.Drawing.Point(32, 377);
             this.showtexturesizes.Name = "showtexturesizes";
             this.showtexturesizes.Size = new System.Drawing.Size(208, 17);
             this.showtexturesizes.TabIndex = 41;
@@ -612,7 +611,7 @@ namespace CodeImp.DoomBuilder.Windows
             label1.AutoSize = true;
             label1.Location = new System.Drawing.Point(28, 29);
             label1.Name = "label1";
-            label1.Size = new System.Drawing.Size(143, 13);
+            label1.Size = new System.Drawing.Size(135, 13);
             label1.TabIndex = 20;
             label1.Text = "Texture and flat brightness:";
             label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
@@ -2100,6 +2099,7 @@ namespace CodeImp.DoomBuilder.Windows
             this.scripttabwidth.ButtonStepsUseModifierKeys = false;
             this.scripttabwidth.ButtonStepsWrapAround = false;
             this.scripttabwidth.Location = new System.Drawing.Point(181, 22);
+            this.scripttabwidth.MaximumValue = 2147483647;
             this.scripttabwidth.Name = "scripttabwidth";
             this.scripttabwidth.Size = new System.Drawing.Size(71, 24);
             this.scripttabwidth.StepValues = null;
@@ -2464,7 +2464,6 @@ namespace CodeImp.DoomBuilder.Windows
             // 
             this.previewgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-            this.previewgroup.Controls.Add(this.scriptedit);
             this.previewgroup.Location = new System.Drawing.Point(217, 344);
             this.previewgroup.Name = "previewgroup";
             this.previewgroup.Size = new System.Drawing.Size(457, 157);
@@ -2472,13 +2471,6 @@ namespace CodeImp.DoomBuilder.Windows
             this.previewgroup.TabStop = false;
             this.previewgroup.Text = " Preview ";
             // 
-            // scriptedit
-            // 
-            this.scriptedit.Location = new System.Drawing.Point(6, 19);
-            this.scriptedit.Name = "scriptedit";
-            this.scriptedit.Size = new System.Drawing.Size(445, 132);
-            this.scriptedit.TabIndex = 0;
-            // 
             // tabpasting
             // 
             this.tabpasting.Controls.Add(this.label16);
@@ -2589,7 +2581,6 @@ namespace CodeImp.DoomBuilder.Windows
             this.groupBox7.PerformLayout();
             this.groupBox6.ResumeLayout(false);
             this.groupBox6.PerformLayout();
-            this.previewgroup.ResumeLayout(false);
             this.tabpasting.ResumeLayout(false);
             this.ResumeLayout(false);
 
@@ -2715,7 +2706,6 @@ namespace CodeImp.DoomBuilder.Windows
 		private System.Windows.Forms.Label label26;
 		private System.Windows.Forms.CheckBox locatetexturegroup;
 		private System.Windows.Forms.CheckBox cbStoreEditTab;
-		private System.Windows.Forms.CheckBox checkforupdates;
         private System.Windows.Forms.TrackBar maxBackups;
         private System.Windows.Forms.Label labelBackups;
         private System.Windows.Forms.Label label27;
@@ -2778,5 +2768,6 @@ namespace CodeImp.DoomBuilder.Windows
         private System.Windows.Forms.CheckBox cbDrawThingsFixedSize;
         private System.Windows.Forms.Label labelDefaultThingSize;
         private System.Windows.Forms.TrackBar tbDefaultThingSize;
+        private System.Windows.Forms.CheckBox keepfilterfocused;
     }
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/PreferencesForm.cs b/Source/Core/Windows/PreferencesForm.cs
index 6e0aab3e641dff87c31bab77a883850944eea814..7c8b7421d56ff9b45e81c5cfbf6c1c249f45e31b 100644
--- a/Source/Core/Windows/PreferencesForm.cs
+++ b/Source/Core/Windows/PreferencesForm.cs
@@ -39,8 +39,8 @@ namespace CodeImp.DoomBuilder.Windows
 		private bool allowapplycontrol;
 		private bool disregardshift;
 		private bool disregardcontrol;
-		private readonly List<ListViewItem> actionListItems; //mxd
-		private readonly List<int> actionListItemsGroupIndices; //mxd
+		private readonly List<ListViewItem> allactionitems; //mxd
+		private readonly List<int> allactionitemsgroups; //mxd
 
 		private bool reloadresources;
 		
@@ -90,8 +90,8 @@ namespace CodeImp.DoomBuilder.Windows
 
 			//mxd
 			locatetexturegroup.Checked = General.Settings.LocateTextureGroup;
+			keepfilterfocused.Checked = General.Settings.KeepTextureFilterFocused;
 			cbStoreEditTab.Checked = General.Settings.StoreSelectedEditTab;
-            checkforupdates.Checked = General.Settings.CheckForUpdates;
 			toolbar_gzdoom.Checked = General.Settings.GZToolbarGZDoom;
 			cbSynchCameras.Checked = General.Settings.GZSynchCameras;
 			tbDynLightCount.Value = General.Clamp(General.Settings.GZMaxDynamicLights, tbDynLightCount.Minimum, tbDynLightCount.Maximum);
@@ -154,8 +154,10 @@ namespace CodeImp.DoomBuilder.Windows
 			
 			// Fill list of actions
 			Action[] actions = General.Actions.GetAllActions();
-			actionListItems = new List<ListViewItem>(); //mxd
-			actionListItemsGroupIndices = new List<int>(); //mxd
+			allactionitems = new List<ListViewItem>(); //mxd
+			allactionitemsgroups = new List<int>(); //mxd
+
+			listactions.BeginUpdate(); //mxd
 			foreach(Action a in actions)
 			{
 				// Create item
@@ -167,15 +169,16 @@ namespace CodeImp.DoomBuilder.Windows
 				if(General.Actions.Categories.ContainsKey(a.Category)) 
 				{
 					item.Group = listactions.Groups[a.Category];
-					actionListItemsGroupIndices.Add(listactions.Groups.IndexOf(item.Group));
+					allactionitemsgroups.Add(listactions.Groups.IndexOf(item.Group)); //mxd
 				}
 				else //mxd
 				{ 
-					actionListItemsGroupIndices.Add(-1);
+					allactionitemsgroups.Add(-1);
 				}
 
-				actionListItems.Add(item); //mxd
+				allactionitems.Add(item); //mxd
 			}
+			listactions.EndUpdate(); //mxd
 
 			// Set the colors
 			// TODO: Make this automated by using the collection
@@ -298,8 +301,8 @@ namespace CodeImp.DoomBuilder.Windows
 			General.Settings.GZToolbarGZDoom = toolbar_gzdoom.Checked; //mxd
 			General.Settings.ShowTextureSizes = showtexturesizes.Checked;
 			General.Settings.StoreSelectedEditTab = cbStoreEditTab.Checked; //mxd
-            General.Settings.CheckForUpdates = checkforupdates.Checked; //mxd
 			General.Settings.LocateTextureGroup = locatetexturegroup.Checked; //mxd
+			General.Settings.KeepTextureFilterFocused = keepfilterfocused.Checked; //mxd
 			General.Settings.MaxRecentFiles = recentFiles.Value; //mxd
             General.Settings.MaxBackups = maxBackups.Value;
             General.Settings.ScreenshotsPath = screenshotsfolderpath.Text.Trim(); //mxd
@@ -323,7 +326,7 @@ namespace CodeImp.DoomBuilder.Windows
 			General.Settings.ScriptFontSize = fontsize;
 			
 			// Apply control keys to actions
-			foreach(ListViewItem item in actionListItems) //mxd
+			foreach(ListViewItem item in allactionitems) //mxd
 				General.Actions[item.Name].SetShortcutKey((int)item.SubItems[1].Tag);
 
 			// Apply the colors
@@ -540,7 +543,7 @@ namespace CodeImp.DoomBuilder.Windows
 				if(thiskey != 0)
 				{
 					// Find actions with same key
-					foreach(ListViewItem item in actionListItems)
+					foreach(ListViewItem item in allactionitems)
 					{
 						// Don't count the selected action
 						if(item != listactions.SelectedItems[0])
@@ -702,6 +705,9 @@ namespace CodeImp.DoomBuilder.Windows
 		// Item selected
 		private void listactions_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
 		{
+			//mxd. Leave when not allowed to update
+			if(!allowapplycontrol) return;
+
 			string disregardkeys = "";
 
 			// Anything selected?
@@ -886,51 +892,61 @@ namespace CodeImp.DoomBuilder.Windows
 		}
 
 		//mxd
-		private void tbFilterActions_TextChanged(object sender, EventArgs e) 
+		private void tbFilterActions_TextChanged(object sender, EventArgs e)
 		{
+			ListViewItem curselection = (listactions.SelectedItems.Count > 0 ? listactions.SelectedItems[0] : null);
+			ListViewItem toselect = null;
+
+			allowapplycontrol = false;
 			listactions.BeginUpdate();
+			listactions.Items.Clear();
 			
-			//restore everything
-			if(string.IsNullOrEmpty(tbFilterActions.Text)) 
+			// Restore everything
+			if(string.IsNullOrEmpty(tbFilterActions.Text))
 			{
-				//restore items
-				listactions.Items.Clear();
-				listactions.Items.AddRange(actionListItems.ToArray());
-
-				//restore groups
-				for(int i = 0; i < actionListItems.Count; i++) 
+				// Restore items and groups
+				for(int i = 0; i < allactionitems.Count; i++)
 				{
-					if(actionListItemsGroupIndices[i] != -1)
-						actionListItems[i].Group = listactions.Groups[actionListItemsGroupIndices[i]];
+					if(allactionitemsgroups[i] != -1)
+						allactionitems[i].Group = listactions.Groups[allactionitemsgroups[i]];
+
+					// Item sould be added AFTER restoring it's group, otherwise item sorting will be screwed!
+					listactions.Items.Add(allactionitems[i]);
+
+					// Restore selection?
+					if(allactionitems[i] == curselection) toselect = curselection;
 				}
-			} 
-			else //apply filtering
-			{ 
+			}
+			// Apply filtering
+			else
+			{
 				string match = tbFilterActions.Text.ToUpperInvariant();
-				for(int i = 0; i < actionListItems.Count; i++) 
+				for(int i = 0; i < allactionitems.Count; i++) 
 				{
-					if(actionListItems[i].Text.ToUpperInvariant().Contains(match)) 
+					if(allactionitems[i].Text.ToUpperInvariant().Contains(match))
 					{
-						//ensure visible
-						if(!listactions.Items.Contains(actionListItems[i])) 
-						{
-							listactions.Items.Add(actionListItems[i]);
+						// Restore group
+						if(allactionitemsgroups[i] != -1)
+							allactionitems[i].Group = listactions.Groups[allactionitemsgroups[i]];
 
-							//restore group
-							if(actionListItemsGroupIndices[i] != -1)
-								actionListItems[i].Group = listactions.Groups[actionListItemsGroupIndices[i]];
-						}
+						// Add item
+						listactions.Items.Add(allactionitems[i]);
+
+						// Restore selection?
+						if(allactionitems[i] == curselection) toselect = curselection;
 					} 
-					else if(listactions.Items.Contains(actionListItems[i])) 
-					{
-						//ensure invisible
-						listactions.Items.Remove(actionListItems[i]);
-					}
 				}
 			}
 
-			listactions.Sort();
+			// Restore selection?
+			if(toselect != null)
+			{
+				toselect.Selected = true;
+				listactions.EnsureVisible(toselect.Index);
+			}
+
 			listactions.EndUpdate();
+			allowapplycontrol = true;
 		}
 
 		#endregion
diff --git a/Source/Core/Windows/SectorEditForm.Designer.cs b/Source/Core/Windows/SectorEditForm.Designer.cs
index dc8df19cb8981a387fb96ac376e8462d45f133ad..0717ce2da7a9585ca91d1e63cd2d72bf410b332f 100644
--- a/Source/Core/Windows/SectorEditForm.Designer.cs
+++ b/Source/Core/Windows/SectorEditForm.Designer.cs
@@ -265,7 +265,8 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// label2
 			// 
-			label2.Location = new System.Drawing.Point(193, 16);
+			label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+			label2.Location = new System.Drawing.Point(196, 16);
 			label2.Name = "label2";
 			label2.Size = new System.Drawing.Size(114, 16);
 			label2.TabIndex = 15;
@@ -283,7 +284,8 @@ namespace CodeImp.DoomBuilder.Windows
 			// 
 			// label4
 			// 
-			label4.Location = new System.Drawing.Point(313, 16);
+			label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
+			label4.Location = new System.Drawing.Point(316, 16);
 			label4.Name = "label4";
 			label4.Size = new System.Drawing.Size(114, 16);
 			label4.TabIndex = 14;
diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs
index 80a4dfd34e484b422760b834a750111aba40a317..0b8c11933baf7bdf4d8fc2fbade7041c6a34bfb1 100644
--- a/Source/Core/Windows/ThingEditForm.cs
+++ b/Source/Core/Windows/ThingEditForm.cs
@@ -391,7 +391,7 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 
 			// Verify the type
-			if(((thingtype.GetFullType(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetFullType(0) > General.Map.FormatInterface.MaxThingType)))
+			if(!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetFullType(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetFullType(0) > General.Map.FormatInterface.MaxThingType)))
 			{
 				General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK);
 				return;
@@ -621,12 +621,14 @@ namespace CodeImp.DoomBuilder.Windows
 			action_ValueChanges(this, EventArgs.Empty);
 
 			//mxd. Update things
-			if(preventchanges) return;
-			MakeUndo(); //mxd
-
-			if(((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)))
+			if(preventchanges ||
+					(!string.IsNullOrEmpty(thingtype.TypeStringValue) &&
+					thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType
+					|| thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))
 				return;
 
+			MakeUndo(); //mxd
+
 			foreach(Thing t in things) 
 			{
 				//Set type
diff --git a/Source/Core/Windows/ThingEditFormUDMF.cs b/Source/Core/Windows/ThingEditFormUDMF.cs
index dfc1ca432b93a19d59d8952f9381c73483f67566..73f89f9d81d1d90522dafb9433f88dc750c3ab34 100644
--- a/Source/Core/Windows/ThingEditFormUDMF.cs
+++ b/Source/Core/Windows/ThingEditFormUDMF.cs
@@ -131,11 +131,11 @@ namespace CodeImp.DoomBuilder.Windows
 			// Fill universal fields list
 			fieldslist.ListFixedFields(General.Map.Config.ThingFields);
 
-            //mxd. Show fixed fields?
-            hidefixedfields.Checked = !General.Settings.ReadSetting("customfieldsshowfixed", true);
+			//mxd. Show fixed fields?
+			hidefixedfields.Checked = !General.Settings.ReadSetting("customfieldsshowfixed", true);
 
-            // Thing height?
-            posZ.Visible = General.Map.FormatInterface.HasThingHeight;
+			// Thing height?
+			posZ.Visible = General.Map.FormatInterface.HasThingHeight;
 			zlabel.Visible = General.Map.FormatInterface.HasThingHeight;
 			cbAbsoluteHeight.Visible = General.Map.FormatInterface.HasThingHeight; //mxd
 
@@ -177,7 +177,7 @@ namespace CodeImp.DoomBuilder.Windows
 			Thing ft = General.GetByIndex(things, 0);
 
 			// Set type
-			thingtype.SelectType(ft.FullType);
+			thingtype.SelectType(ft.SRB2Type);
 
 			// Flags
 			foreach(CheckBox c in flags.Checkboxes) 
@@ -199,6 +199,11 @@ namespace CodeImp.DoomBuilder.Windows
 			posY.ButtonStep = General.Map.Grid.GridSize;
 			posZ.ButtonStep = General.Map.Grid.GridSize;
 
+			//mxd. User vars. Should be done before adding regular fields
+			ThingTypeInfo fti = General.Map.Data.GetThingInfoEx(ft.SRB2Type);
+			if(fti != null && fti.Actor != null && fti.Actor.UserVars.Count > 0)
+				fieldslist.SetUserVars(fti.Actor.UserVars, ft.Fields, true);
+
 			// Custom fields
 			fieldslist.SetValues(ft.Fields, true);
 			commenteditor.SetValues(ft.Fields, true);
@@ -236,7 +241,7 @@ namespace CodeImp.DoomBuilder.Windows
 
 				// Type does not match?
 				ThingTypeInfo info = thingtype.GetSelectedInfo(); //mxd
-				if(info != null && info.Index != t.FullType) thingtype.ClearSelectedType();
+				if(info != null && info.Index != t.SRB2Type) thingtype.ClearSelectedType();
 
 				// Flags
 				foreach(CheckBox c in flags.Checkboxes) 
@@ -272,6 +277,11 @@ namespace CodeImp.DoomBuilder.Windows
 				//mxd. Arguments
 				argscontrol.SetValue(t, false);
 
+				//mxd. User vars. Should be done before adding regular fields
+				ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.SRB2Type);
+				if(ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0)
+					fieldslist.SetUserVars(ti.Actor.UserVars, t.Fields, false);
+
 				//mxd. Custom fields
 				fieldslist.SetValues(t.Fields, false);
 				commenteditor.SetValues(t.Fields, false); //mxd. Comments
@@ -294,16 +304,6 @@ namespace CodeImp.DoomBuilder.Windows
 
 				//mxd. Store initial properties
 				thingprops.Add(new ThingProperties(t));
-
-				//mxd. add user vars
-				/*if(info != null && info.Actor != null && info.Actor.UserVars.Count > 0) 
-				 {
-					foreach(string s in info.Actor.UserVars) 
-					{
-						if(!t.Fields.ContainsKey(s))
-							fieldslist.SetValue(s, 0, CodeImp.DoomBuilder.Types.UniversalType.Integer);
-					}
-				}*/
 			}
 
 			preventchanges = false;
@@ -442,7 +442,7 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 
 			// Verify the type
-			if(((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) 
+			if(!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) 
 			{
 				General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK);
 				return;
@@ -490,6 +490,11 @@ namespace CodeImp.DoomBuilder.Windows
 				if(!string.IsNullOrEmpty(score.Text))
 					UniFields.SetInteger(t.Fields, "score", score.GetResult(t.Fields.GetValue("score", 0)), 0);
 
+				//mxd. User vars. Should be called after fieldslist.Apply()
+				ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.SRB2Type);
+				if(ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0)
+					fieldslist.ApplyUserVars(ti.Actor.UserVars, t.Fields);
+
 				color.ApplyTo(t.Fields, t.Fields.GetValue("fillcolor", 0));
 
 				//mxd. Comments
@@ -505,7 +510,7 @@ namespace CodeImp.DoomBuilder.Windows
 				if(c.CheckState == CheckState.Checked) defaultflags.Add(c.Tag.ToString());
 			}
 			General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType);
-			General.Settings.DefaultThingAngle = angle.GetResult(General.Settings.DefaultThingAngle);
+			General.Settings.DefaultThingAngle = (int)Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90);
 			General.Settings.SetDefaultThingFlags(defaultflags);
 
 			// Store value linking
@@ -581,8 +586,8 @@ namespace CodeImp.DoomBuilder.Windows
 		{
 			location = this.Location;
 			activetab = tabs.SelectedIndex;
-            General.Settings.WriteSetting("customfieldsshowfixed", !hidefixedfields.Checked);
-        }
+			General.Settings.WriteSetting("customfieldsshowfixed", !hidefixedfields.Checked);
+		}
 
 		// Help
 		private void ThingEditForm_HelpRequested(object sender, HelpEventArgs hlpevent) 
@@ -679,9 +684,10 @@ namespace CodeImp.DoomBuilder.Windows
 			action_ValueChanges(this, EventArgs.Empty);
 
 			//mxd. Update things
-			if(preventchanges 
-					|| (thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) 
-					|| (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))
+			if(preventchanges ||
+					(!string.IsNullOrEmpty(thingtype.TypeStringValue) && 
+					thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType 
+					|| thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))
 				return;
 
 			MakeUndo(); //mxd
@@ -689,7 +695,7 @@ namespace CodeImp.DoomBuilder.Windows
 			foreach(Thing t in things) 
 			{
 				//Set type
-				t.FullType = thingtype.GetResult(t.FullType);
+				t.SRB2Type = thingtype.GetResult(t.SRB2Type);
 
 				// Update settings
 				t.UpdateConfiguration();
@@ -871,12 +877,12 @@ namespace CodeImp.DoomBuilder.Windows
 			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
 
-        private void hidefixedfields_CheckedChanged(object sender, EventArgs e)
-        {
-            fieldslist.ShowFixedFields = !hidefixedfields.Checked;
-        }
+		private void hidefixedfields_CheckedChanged(object sender, EventArgs e)
+		{
+			fieldslist.ShowFixedFields = !hidefixedfields.Checked;
+		}
 
-        #endregion
+		#endregion
 
-    }
+	}
 }
\ No newline at end of file
diff --git a/Source/Core/ZDoom/ActorStructure.cs b/Source/Core/ZDoom/ActorStructure.cs
index fc99f25b506a4798b67305064410fb9bc3c3483a..544f814cdca09e254ac055ff8562a57193087c51 100644
--- a/Source/Core/ZDoom/ActorStructure.cs
+++ b/Source/Core/ZDoom/ActorStructure.cs
@@ -21,6 +21,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Data;
+using CodeImp.DoomBuilder.Types;
 
 #endregion
 
@@ -52,7 +53,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		
 		// Properties
 		private Dictionary<string, List<string>> props;
-		private readonly List<string> userVars; //mxd
+		private readonly Dictionary<string, UniversalType> uservars; //mxd
 		
 		// States
 		private Dictionary<string, StateStructure> states;
@@ -68,7 +69,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		public string ReplacesClass { get { return replaceclass; } }
 		public ActorStructure BaseClass { get { return baseclass; } }
 		internal int DoomEdNum { get { return doomednum; } set { doomednum = value; } }
-		public List<string> UserVars { get { return userVars; } } //mxd
+		public Dictionary<string, UniversalType> UserVars { get { return uservars; } } //mxd
 		
 		#endregion
 		
@@ -78,10 +79,10 @@ namespace CodeImp.DoomBuilder.ZDoom
 		internal ActorStructure(DecorateParser parser)
 		{
 			// Initialize
-			flags = new Dictionary<string, bool>(StringComparer.Ordinal);
-			props = new Dictionary<string, List<string>>(StringComparer.Ordinal);
-			states = new Dictionary<string, StateStructure>(StringComparer.Ordinal);
-			userVars = new List<string>();//mxd
+			flags = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
+			props = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
+			states = new Dictionary<string, StateStructure>(StringComparer.OrdinalIgnoreCase);
+			uservars = new Dictionary<string, UniversalType>(StringComparer.OrdinalIgnoreCase);//mxd
 			bool done = false; //mxd
 			
 			// Always define a game property, but default to 0 values
@@ -163,7 +164,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 							else if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out doomednum)) // Check if numeric
 							{
 								// Not numeric!
-								parser.ReportError("Expected editor thing number or start of actor scope while parsing '" + classname + "'");
+								parser.ReportError("Expected editor thing number or start of actor scope while parsing \"" + classname + "\"");
 								return;
 							}
 							break;
@@ -271,18 +272,87 @@ namespace CodeImp.DoomBuilder.ZDoom
 						break;
 
 					case "var": //mxd
-						while(parser.SkipWhitespace(true)) 
+						// Type
+						parser.SkipWhitespace(true);
+						string typestr = parser.ReadToken().ToUpperInvariant();
+						UniversalType type = UniversalType.EnumOption; // There is no Unknown type, so let's use something impossiburu...
+						switch(typestr)
 						{
-							string t = parser.ReadToken();
-							if(string.IsNullOrEmpty(t) || t == ";") break;
-							if(t.StartsWith("user_") && !userVars.Contains(t))
-								userVars.Add(t);
+							case "INT":
+								type = UniversalType.Integer;
+								break;
+
+							default:
+								parser.LogWarning("Unknown user variable type");
+								break;
+						}
+
+						// Name
+						parser.SkipWhitespace(true);
+						string name = parser.ReadToken();
+						if(string.IsNullOrEmpty(name))
+						{
+							parser.ReportError("Expected User Variable name");
+							return;
+						}
+						if(!name.StartsWith("user_", StringComparison.OrdinalIgnoreCase))
+						{
+							parser.ReportError("User Variable name must start with \"user_\" prefix");
+							return;
+						}
+						if(uservars.ContainsKey(name))
+						{
+							parser.ReportError("User Variable \"" + name + "\" is double-defined");
+							return;
+						}
+						if(!skipsuper && baseclass != null && baseclass.uservars.ContainsKey(name))
+						{
+							parser.ReportError("User variable \"" + name + "\" is already defined in one of the parent classes");
+							return;
+						}
+
+						// Rest
+						parser.SkipWhitespace(true);
+						string next = parser.ReadToken();
+						if(next == "[") // that's User Array. Let's skip it...
+						{
+							int arrlen = -1;
+							if(!parser.ReadSignedInt(ref arrlen))
+							{
+								parser.ReportError("Expected User Array length, but got \"" + next + "\"");
+								return;
+							}
+							if(arrlen < 1)
+							{
+								parser.ReportError("User Array length must be a positive value");
+								return;
+							}
+							if(!parser.NextTokenIs("]") || !parser.NextTokenIs(";"))
+							{
+								return;
+							}
+						}
+						else if(next != ";")
+						{
+							parser.ReportError("Expected \";\", but got \"" + next + "\"");
+							return;
+						}
+						else
+						{
+							// Add to collection
+							uservars.Add(name, type);
 						}
 						break;
 
 					case "}":
-						// Actor scope ends here,
-						// break out of this parse loop
+						//mxd. Get user vars from the BaseClass, if we have one
+						if(!skipsuper && baseclass != null && baseclass.uservars.Count > 0)
+						{
+							foreach(var group in baseclass.uservars)
+								uservars.Add(group.Key, group.Value);
+						}
+
+						// Actor scope ends here, break out of this parse loop
 						done = true;
 						break;
 
@@ -414,7 +484,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 					}
 				}
 
-				parser.LogWarning("Unable to find '" + inheritclass + "' class to inherit from, while parsing '" + classname + ":" + doomednum + "'");
+				parser.LogWarning("Unable to find \"" + inheritclass + "\" class to inherit from, while parsing \"" + classname + ":" + doomednum + "\"");
 			}
 		}
 		
@@ -466,12 +536,13 @@ namespace CodeImp.DoomBuilder.ZDoom
 		/// <summary>
 		/// This returns a specific value of a specific property as a string. Returns an empty string when the propery does not have the specified value.
 		/// </summary>
-		public string GetPropertyValueString(string propname, int valueindex)
+		public string GetPropertyValueString(string propname, int valueindex) { return GetPropertyValueString(propname, valueindex, true); } //mxd. Added "stripquotes" parameter
+		public string GetPropertyValueString(string propname, int valueindex, bool stripquotes)
 		{
 			if(props.ContainsKey(propname) && (props[propname].Count > valueindex))
-				return props[propname][valueindex];
+				return (stripquotes ? ZDTextParser.StripQuotes(props[propname][valueindex]) : props[propname][valueindex]);
 			if(!skipsuper && (baseclass != null))
-				return baseclass.GetPropertyValueString(propname, valueindex);
+				return baseclass.GetPropertyValueString(propname, valueindex, stripquotes);
 			return "";
 		}
 		
@@ -480,11 +551,11 @@ namespace CodeImp.DoomBuilder.ZDoom
 		/// </summary>
 		public int GetPropertyValueInt(string propname, int valueindex)
 		{
-			string str = GetPropertyValueString(propname, valueindex);
+			string str = GetPropertyValueString(propname, valueindex, false);
 
 			//mxd. It can be negative...
-			if(str == "-" && props.Count > valueindex + 1) 
-				str += GetPropertyValueString(propname, valueindex + 1);
+			if(str == "-" && props.Count > valueindex + 1)
+				str += GetPropertyValueString(propname, valueindex + 1, false);
 			
 			int intvalue;
 			if(int.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out intvalue))
@@ -497,11 +568,11 @@ namespace CodeImp.DoomBuilder.ZDoom
 		/// </summary>
 		public float GetPropertyValueFloat(string propname, int valueindex)
 		{
-			string str = GetPropertyValueString(propname, valueindex);
+			string str = GetPropertyValueString(propname, valueindex, false);
 
 			//mxd. It can be negative...
 			if(str == "-" && props.Count > valueindex + 1)
-				str += GetPropertyValueString(propname, valueindex + 1);
+				str += GetPropertyValueString(propname, valueindex + 1, false);
 
 			float fvalue;
 			if(float.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out fvalue))
@@ -554,7 +625,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		/// </summary>
 		public Dictionary<string, StateStructure> GetAllStates()
 		{
-			Dictionary<string, StateStructure> list = new Dictionary<string, StateStructure>(states);
+			Dictionary<string, StateStructure> list = new Dictionary<string, StateStructure>(states, StringComparer.OrdinalIgnoreCase);
 			
 			if(!skipsuper && (baseclass != null))
 			{
@@ -590,75 +661,75 @@ namespace CodeImp.DoomBuilder.ZDoom
 			// Sprite forced?
 			if(HasPropertyWithValue("$sprite"))
 			{
-                string sprite = GetPropertyValueString("$sprite", 0); //mxd
-                if ((sprite.Length > DataManager.INTERNAL_PREFIX.Length) &&
-                   sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX)) return sprite; //mxd
-                if (General.Map.Data.GetSpriteExists(sprite)) return sprite; //mxd. Added availability check
-
-                //mxd. Bitch and moan
-                General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in " + classname + ":" + doomednum + ". The sprite \"" + sprite + "\" assigned by the \"$sprite\" property does not exist.");
-            }
-
-            // Try the idle state
-            if (HasState("idle"))
-            {
-                StateStructure s = GetState("idle");
-                string spritename = s.GetSprite(0);
-                if (!string.IsNullOrEmpty(spritename))
-                    result = spritename;
-            }
-
-            // Try the see state
-            if (string.IsNullOrEmpty(result) && HasState("see"))
-            {
-                StateStructure s = GetState("see");
-                string spritename = s.GetSprite(0);
-                if (!string.IsNullOrEmpty(spritename))
-                    result = spritename;
-            }
-
-            // Try the inactive state
-            if (string.IsNullOrEmpty(result) && HasState("inactive"))
-            {
-                StateStructure s = GetState("inactive");
-                string spritename = s.GetSprite(0);
-                if (!string.IsNullOrEmpty(spritename))
-                    result = spritename;
-            }
-
-            // Try the spawn state
-            if (string.IsNullOrEmpty(result) && HasState("spawn"))
-            {
-                StateStructure s = GetState("spawn");
-                string spritename = s.GetSprite(0);
-                if (!string.IsNullOrEmpty(spritename))
-                    result = spritename;
-            }
-
-            // Still no sprite found? then just pick the first we can find
-            if (string.IsNullOrEmpty(result))
-            {
-                Dictionary<string, StateStructure> list = GetAllStates();
-                foreach (StateStructure s in list.Values)
-                {
-                    string spritename = s.GetSprite(0);
-                    if (!string.IsNullOrEmpty(spritename))
-                    {
-                        result = spritename;
-                        break;
-                    }
-                }
-            }
-
-            if (!string.IsNullOrEmpty(result))
-            {
-                // The sprite name is not actually complete, we still have to append
-                // the direction characters to it. Find an existing sprite with direction.
-                foreach (string postfix in SPRITE_POSTFIXES)
-                {
-                    if (General.Map.Data.GetSpriteExists(result + postfix))
-                        return result + postfix;
-                }
+				string sprite = GetPropertyValueString("$sprite", 0, true); //mxd
+				if((sprite.Length > DataManager.INTERNAL_PREFIX.Length) && 
+					sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX)) return sprite; //mxd
+				if(General.Map.Data.GetSpriteExists(sprite)) return sprite; //mxd. Added availability check
+
+				//mxd. Bitch and moan
+				General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in " + classname + ":" + doomednum + ". The sprite \"" + sprite + "\" assigned by the \"$sprite\" property does not exist.");
+			}
+
+			// Try the idle state
+			if(HasState("idle"))
+			{
+				StateStructure s = GetState("idle");
+				string spritename = s.GetSprite(0);
+				if(!string.IsNullOrEmpty(spritename))
+					result = spritename;
+			}
+			
+			// Try the see state
+			if(string.IsNullOrEmpty(result) && HasState("see"))
+			{
+				StateStructure s = GetState("see");
+				string spritename = s.GetSprite(0);
+				if(!string.IsNullOrEmpty(spritename))
+					result = spritename;
+			}
+			
+			// Try the inactive state
+			if(string.IsNullOrEmpty(result) && HasState("inactive"))
+			{
+				StateStructure s = GetState("inactive");
+				string spritename = s.GetSprite(0);
+				if(!string.IsNullOrEmpty(spritename))
+					result = spritename;
+			}
+			
+			// Try the spawn state
+			if(string.IsNullOrEmpty(result) && HasState("spawn"))
+			{
+				StateStructure s = GetState("spawn");
+				string spritename = s.GetSprite(0);
+				if(!string.IsNullOrEmpty(spritename))
+					result = spritename;
+			}
+			
+			// Still no sprite found? then just pick the first we can find
+			if(string.IsNullOrEmpty(result))
+			{
+				Dictionary<string, StateStructure> list = GetAllStates();
+				foreach(StateStructure s in list.Values)
+				{
+					string spritename = s.GetSprite(0);
+					if(!string.IsNullOrEmpty(spritename))
+					{
+						result = spritename;
+						break;
+					}
+				}
+			}
+			
+			if(!string.IsNullOrEmpty(result))
+			{
+				// The sprite name is not actually complete, we still have to append
+				// the direction characters to it. Find an existing sprite with direction.
+				foreach(string postfix in SPRITE_POSTFIXES)
+				{
+					if(General.Map.Data.GetSpriteExists(result + postfix))
+						return result + postfix;
+				}
 			}
 			
 			// No sprite found
diff --git a/Source/Core/ZDoom/AnimdefsParser.cs b/Source/Core/ZDoom/AnimdefsParser.cs
index d48cc9bddf5bf583b1c1f7b89b88029d3e6f974e..65d0208598e04cbbe1459b5d1b5ae7436e68ac32 100644
--- a/Source/Core/ZDoom/AnimdefsParser.cs
+++ b/Source/Core/ZDoom/AnimdefsParser.cs
@@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 				// Check results
 				if(cameratextures.ContainsKey(texturename.ToUpperInvariant()))
 				{
-					ReportError("Camera texture '" + texturename + "' is defined more than once");
+					ReportError("Camera texture \"" + texturename + "\" is defined more than once");
 					return false;
 				}
 
diff --git a/Source/Core/ZDoom/DecorateParser.cs b/Source/Core/ZDoom/DecorateParser.cs
index 1475b3598fddc1d25cbbbee59b66110ebad3a5cf..2529e955189e313b229b6ec5207a91a8b50f61da 100644
--- a/Source/Core/ZDoom/DecorateParser.cs
+++ b/Source/Core/ZDoom/DecorateParser.cs
@@ -86,12 +86,12 @@ namespace CodeImp.DoomBuilder.ZDoom
 		{
 			// Syntax
 			whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :)
-			specialtokens = ":{}+-\n;,";
-
-            // Initialize
-            actors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase);
-            archivedactors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase);
-            parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd
+			specialtokens = ":{}[]+-\n;,";
+			
+			// Initialize
+			actors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase);
+			archivedactors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase);
+			parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd
 		}
 
         // Disposer
diff --git a/Source/Core/ZDoom/PatchStructure.cs b/Source/Core/ZDoom/PatchStructure.cs
index 17fb6093c0c30c57094aa30f3063856a44330965..1eea528ef229123ac9fd011de57f6e3a3cbfb8db 100644
--- a/Source/Core/ZDoom/PatchStructure.cs
+++ b/Source/Core/ZDoom/PatchStructure.cs
@@ -30,23 +30,27 @@ namespace CodeImp.DoomBuilder.ZDoom
 	{
 		#region ================== Constants
 
+		// Some odd things in ZDoom
+		private const string IGNORE_SPRITE = "TNT1A0";
+
 		#endregion
 
 		#region ================== Variables
 
 		// Declaration
-		private string name;
-		private int offsetx;
-		private int offsety;
-		private bool flipx;
-		private bool flipy;
-		private float alpha;
-		private int rotation; //mxd
-		private TexturePathRenderStyle renderStyle; //mxd
-		private PixelColor blendColor; //mxd
-		private TexturePathBlendStyle blendStyle; //mxd
-		private float tintAmmount; //mxd
-		private static string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd
+		private readonly string name;
+		private readonly int offsetx;
+		private readonly int offsety;
+		private readonly bool flipx;
+		private readonly bool flipy;
+		private readonly float alpha;
+		private readonly int rotation; //mxd
+		private readonly TexturePathRenderStyle renderStyle; //mxd
+		private readonly PixelColor blendColor; //mxd
+		private readonly TexturePathBlendStyle blendStyle; //mxd
+		private readonly float tintAmmount; //mxd
+		private static readonly string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd
+		private readonly bool skip; //mxd
 
 		#endregion
 
@@ -63,6 +67,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		public TexturePathBlendStyle BlendStyle { get { return blendStyle; } }
 		public float TintAmmount { get { return tintAmmount; } }
 		public PixelColor BlendColor { get { return blendColor; } }//mxd
+		public bool Skip { get { return skip; } } //mxd
 
 		#endregion
 
@@ -88,6 +93,9 @@ namespace CodeImp.DoomBuilder.ZDoom
 				return;
 			}
 
+			//mxd. Skip what must be skipped
+			skip = (name.ToUpperInvariant() == IGNORE_SPRITE);
+
 			//mxd
 			name = name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
 
@@ -147,7 +155,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 
 						if(rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) 
 						{
-							parser.LogWarning("Unsupported rotation (" + rotation + ") in patch '" + name + "'");
+							parser.LogWarning("Unsupported rotation (" + rotation + ") in patch \"" + name + "\"");
 							rotation = 0;
 						}
 						break;
@@ -206,7 +214,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 				// Try parsing as value
 				if(!float.TryParse(strvalue, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
 				{
-					parser.ReportError("Expected numeric value for property '" + propertyname + "'");
+					parser.ReportError("Expected numeric value for property \"" + propertyname + "\"");
 					return false;
 				}
 				// Success
@@ -214,7 +222,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			}
 
 			// Can't find the property value!
-			parser.ReportError("Expected a value for property '" + propertyname + "'");
+			parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 			value = 0.0f;
 			return false;
 		}
@@ -230,7 +238,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 				// Try parsing as value
 				if(!int.TryParse(strvalue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
 				{
-					parser.ReportError("Expected integral value for property '" + propertyname + "'");
+					parser.ReportError("Expected integral value for property \"" + propertyname + "\"");
 					return false;
 				}
 
@@ -239,7 +247,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			}
 
 			// Can't find the property value!
-			parser.ReportError("Expected a value for property '" + propertyname + "'");
+			parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 			value = 0;
 			return false;
 		}
@@ -253,7 +261,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			if(string.IsNullOrEmpty(value)) 
 			{
 				// Can't find the property value!
-				parser.ReportError("Expected a value for property '" + propertyname + "'");
+				parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 				return false;
 			}
 
@@ -270,20 +278,20 @@ namespace CodeImp.DoomBuilder.ZDoom
 			if(string.IsNullOrEmpty(strvalue)) 
 			{
 				// Can't find the property value!
-				parser.ReportError("Expected a value for property '" + propertyname + "'");
+				parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 				return false;
 			}
 
 			if(strvalue[0] != '#') 
 			{
-				parser.ReportError("Expected color value for property '" + propertyname + "'");
+				parser.ReportError("Expected color value for property \"" + propertyname + "\"");
 				return false;
 			}
 
 			// Try parsing as value
 			if(!int.TryParse(strvalue.Remove(0, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value)) 
 			{
-				parser.ReportError("Expected color value for property '" + propertyname + "'");
+				parser.ReportError("Expected color value for property \"" + propertyname + "\"");
 				return false;
 			}
 
diff --git a/Source/Core/ZDoom/TextureStructure.cs b/Source/Core/ZDoom/TextureStructure.cs
index 0650c93db6bda253da5c9f90c1b9a96e4bce6f21..47eda03b4f1bd57390c88b2f5a60fc869cf94915 100644
--- a/Source/Core/ZDoom/TextureStructure.cs
+++ b/Source/Core/ZDoom/TextureStructure.cs
@@ -28,9 +28,6 @@ namespace CodeImp.DoomBuilder.ZDoom
 	{
 		#region ================== Constants
 
-		// Some odd thing in ZDoom
-		private const string IGNORE_SPRITE = "TNT1A0";
-
 		#endregion
 
 		#region ================== Variables
@@ -169,9 +166,6 @@ namespace CodeImp.DoomBuilder.ZDoom
 						PatchStructure pt = new PatchStructure(parser);
 						if(parser.HasError) break;
 
-						//mxd. Let's ignore TNT1A0
-						if(pt.Name == IGNORE_SPRITE) break;
-
 						// Add the patch
 						patches.Add(pt);
 						break;
@@ -200,7 +194,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 				// Try parsing as value
 				if(!float.TryParse(strvalue, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
 				{
-					parser.ReportError("Expected numeric value for property '" + propertyname + "'");
+					parser.ReportError("Expected numeric value for property \"" + propertyname + "\"");
 					return false;
 				}
 
@@ -209,7 +203,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			}
 
 			// Can't find the property value!
-			parser.ReportError("Expected a value for property '" + propertyname + "'");
+			parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 			value = 0.0f;
 			return false;
 		}
@@ -225,7 +219,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 				// Try parsing as value
 				if(!int.TryParse(strvalue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
 				{
-					parser.ReportError("Expected integral value for property '" + propertyname + "'");
+					parser.ReportError("Expected integral value for property \"" + propertyname + "\"");
 					return false;
 				}
 
@@ -234,7 +228,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			}
 
 			// Can't find the property value!
-			parser.ReportError("Expected a value for property '" + propertyname + "'");
+			parser.ReportError("Expected a value for property \"" + propertyname + "\"");
 			value = 0;
 			return false;
 		}
diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs
index d9df88fa22f1e3138d0709987f5c679700310438..e76247d3a204f2dcda0ea468f589a5b270dccd8a 100644
--- a/Source/Core/ZDoom/ZDTextParser.cs
+++ b/Source/Core/ZDoom/ZDTextParser.cs
@@ -201,7 +201,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 							if(datastream.Position == datastream.Length) //mxd
 							{
 								// ZDoom doesn't give even a warning message about this, so we shouldn't report error or fail parsing.
-								General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in '" + sourcename + "', line " + GetCurrentLineNumber() + ". Block comment is not closed.");
+								General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in \"" + sourcename + "\", line " + GetCurrentLineNumber() + ". Block comment is not closed.");
 								return false;
 							}
 
@@ -441,7 +441,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 
 			if(string.Compare(token, expectedtoken, true) != 0)
 			{
-				if(reporterror) ReportError("Expected '" + expectedtoken + "', but got '" + token + "'");
+				if(reporterror) ReportError("Expected \"" + expectedtoken + "\", but got \"" + token + "\"");
 
 				// Rewind so this structure can be read again
 				DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
@@ -529,18 +529,18 @@ namespace CodeImp.DoomBuilder.ZDoom
 		//mxd. This adds a warning to the ErrorLogger
 		protected internal void LogWarning(string message)
 		{
-            // Add a warning
-            int errline = (datastream != null ? GetCurrentLineNumber() : CompilerError.NO_LINE_NUMBER);
-            General.ErrorLogger.Add(ErrorType.Warning, GetLanguageType() + " warning in '" + sourcename
-								+ (errline != CompilerError.NO_LINE_NUMBER ? "', line " + (errline + 1) : "'") + ". " 
+			// Add a warning
+			int errline = (datastream != null ? GetCurrentLineNumber() : CompilerError.NO_LINE_NUMBER);
+			General.ErrorLogger.Add(ErrorType.Warning, GetLanguageType() + " warning in \"" + sourcename
+								+ (errline != CompilerError.NO_LINE_NUMBER ? "\", line " + (errline + 1) : "\"") + ". " 
 								+ message + ".");
 		}
 
 		//mxd. This adds an error to the ErrorLogger
 		public void LogError()
 		{
-			General.ErrorLogger.Add(ErrorType.Error, GetLanguageType() + " error in '" + errorsource
-								+ (errorline != CompilerError.NO_LINE_NUMBER ? "', line " + (errorline + 1) : "'") + ". "
+			General.ErrorLogger.Add(ErrorType.Error, GetLanguageType() + " error in \"" + errorsource
+								+ (errorline != CompilerError.NO_LINE_NUMBER ? "\", line " + (errorline + 1) : "\"") + ". "
 								+ errordesc + ".");
 		}
 
@@ -611,7 +611,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 					// includefilename references something above the root?
 					if(index-- < 0)
 					{
-						ReportError("Unable to construct rooted path from '" + includefilename + "'");
+						ReportError("Unable to construct rooted path from \"" + includefilename + "\"");
 						return string.Empty;
 					}
 
diff --git a/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs b/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs
index 9abf7d6095ab879e1d6ed4dc50d1f546ba417f72..902a0953962541448cf61713cc86c19f2df892e6 100644
--- a/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs
+++ b/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs
@@ -238,7 +238,7 @@
 			// 
 			this.floorHeightAmmount.AllowNegative = false;
 			this.floorHeightAmmount.ExtendedLimits = false;
-			this.floorHeightAmmount.Label = "Floor height:";
+			this.floorHeightAmmount.Label = "Height:";
 			this.floorHeightAmmount.Location = new System.Drawing.Point(6, 19);
 			this.floorHeightAmmount.Maximum = 100;
 			this.floorHeightAmmount.Minimum = 0;
diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj
index ac6d2a70679e66919768c19d2423cab85fb15c3b..accc5ae31e03976ad2a3d338d63ddb99e186b32e 100644
--- a/Source/Plugins/BuilderModes/BuilderModes.csproj
+++ b/Source/Plugins/BuilderModes/BuilderModes.csproj
@@ -361,6 +361,12 @@
     <Compile Include="Interface\DrawGridOptionsPanel.Designer.cs">
       <DependentUpon>DrawGridOptionsPanel.cs</DependentUpon>
     </Compile>
+    <Compile Include="Interface\DrawLineOptionsPanel.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Interface\DrawLineOptionsPanel.Designer.cs">
+      <DependentUpon>DrawLineOptionsPanel.cs</DependentUpon>
+    </Compile>
     <Compile Include="Interface\DrawRectangleOptionsPanel.cs">
       <SubType>UserControl</SubType>
     </Compile>
@@ -563,6 +569,9 @@
     <EmbeddedResource Include="Resources\DrawGeometryMode.png" />
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="Interface\DrawLineOptionsPanel.resx">
+      <DependentUpon>DrawLineOptionsPanel.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="Interface\FilterSelectedThingsForm.resx">
       <DependentUpon>FilterSelectedThingsForm.cs</DependentUpon>
     </EmbeddedResource>
@@ -635,6 +644,9 @@
   <ItemGroup>
     <EmbeddedResource Include="Resources\InsertThingsRadiallyMode.png" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Repeat.png" />
+  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
index e367f659cecc50d5f19835afbc9cb35c442d6741..2808e59a70011b3d2cbeb1fa8b1c897ebdd705f6 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
@@ -737,7 +737,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
 					return InterpolationTools.EaseInOutSine(val1, val2, delta);
 
 				default:
-					throw new Exception("DrawBezierPathMode.IntepolateValue: '" + mode + "' mode is not supported!");
+					throw new Exception("DrawBezierPathMode.IntepolateValue: \"" + mode + "\" mode is not supported!");
 			}
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
index 06872feaa628e5ad1a5e2335527d764785f05134..3dfd7e81314b5ceb28a83040ddfd694c7f0c35e8 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs
@@ -31,12 +31,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		private readonly HintLabel hintlabel;
 		private Curve curve;
-		private static int segmentLength = 32;
-		private const int MIN_SEGMENT_LENGTH = 1;
+		private int segmentlength;
+		private const int MIN_SEGMENT_LENGTH = 16;
 		private const int MAX_SEGMENT_LENGTH = 4096; //just some arbitrary number
 
-		//interface
-		private readonly DrawCurveOptionsPanel panel;
+		// Interface
+		private DrawCurveOptionsPanel panel;
 
 		#endregion
 
@@ -46,10 +46,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			hintlabel = new HintLabel(General.Colors.InfoLine);
 			labeluseoffset = false;
-
-			//Options docker
-			panel = new DrawCurveOptionsPanel(MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH);
-			panel.OnValueChanged += OptionsPanelOnValueChanged;
 		}
 
 		public override void Dispose() 
@@ -102,7 +98,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					List<Vector2D> verts = new List<Vector2D>();
 					for(int i = 0; i < points.Count; i++) verts.Add(points[i].pos);
 					if(curp.pos != verts[verts.Count-1]) verts.Add(curp.pos);
-					curve = CurveTools.CurveThroughPoints(verts, 0.5f, 0.75f, segmentLength);
+					curve = CurveTools.CurveThroughPoints(verts, 0.5f, 0.75f, segmentlength);
 
 					// Render lines
 					for(int i = 1; i < curve.Shape.Count; i++) 
@@ -151,7 +147,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				Vector2D start = new Vector2D(mousemappos.x + (32 / renderer.Scale), mousemappos.y - (16 / renderer.Scale));
 				Vector2D end = new Vector2D(mousemappos.x + (96 / renderer.Scale), mousemappos.y);
 				hintlabel.Move(start, end);
-				hintlabel.Text = "SEG LEN: " + segmentLength;
+				hintlabel.Text = "SEG LEN: " + segmentlength;
 				renderer.RenderText(hintlabel.TextLabel);
 
 				// Done
@@ -171,7 +167,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			base.OnEngage();
 
 			//setup settings panel
-			panel.SegmentLength = segmentLength;
+			panel.SegmentLength = segmentlength;
 			panel.Register();
 		}
 
@@ -245,55 +241,62 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 
 				// Make the drawing
-				if(!Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
+				if(Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
 				{
-					// Drawing failed
-					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
-					General.Map.UndoRedo.WithdrawUndo();
-					General.Map.UndoRedo.WithdrawUndo();
-					return;
-				}
-
-				// Snap to map format accuracy
-				General.Map.Map.SnapAllToAccuracy();
+					// Snap to map format accuracy
+					General.Map.Map.SnapAllToAccuracy();
 
-				// Clear selection
-				General.Map.Map.ClearAllSelected();
+					// Clear selection
+					General.Map.Map.ClearAllSelected();
 
-				// Update cached values
-				General.Map.Map.Update();
+					// Update cached values
+					General.Map.Map.Update();
 
-				// Edit new sectors?
-				List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
-				if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
-					General.Interface.ShowEditSectors(newsectors);
+					// Edit new sectors?
+					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
+					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
+						General.Interface.ShowEditSectors(newsectors);
 
-				// Update the used textures
-				General.Map.Data.UpdateUsedTextures();
+					// Update the used textures
+					General.Map.Data.UpdateUsedTextures();
 
-				//mxd
-				General.Map.Renderer2D.UpdateExtraFloorFlag();
+					//mxd
+					General.Map.Renderer2D.UpdateExtraFloorFlag();
 
-				// Map is changed
-				General.Map.IsChanged = true;
+					// Map is changed
+					General.Map.IsChanged = true;
+				}
+				else
+				{
+					// Drawing failed
+					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
+					General.Map.UndoRedo.WithdrawUndo();
+					General.Map.UndoRedo.WithdrawUndo();
+				}
 			}
 
 			// Done
 			Cursor.Current = Cursors.Default;
 
-			// Return to original mode
-			General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
-		}
+			if(continuousdrawing)
+			{
+				// Reset settings
+				points.Clear();
+				labels.Clear();
 
-		public override void OnDisengage() 
-		{
-			base.OnDisengage();
-			panel.Unregister();
+				// Redraw display
+				General.Interface.RedrawDisplay();
+			}
+			else
+			{
+				// Return to original mode
+				General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			}
 		}
 
 		private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) 
 		{
-			segmentLength = panel.SegmentLength;
+			segmentlength = panel.SegmentLength;
 			Update();
 		}
 
@@ -304,18 +307,52 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#endregion
 
+		#region ================== mxd. Settings panel
+
+		protected override void SetupInterface()
+		{
+			// Load stored settings
+			segmentlength = General.Clamp(General.Settings.ReadPluginSetting("drawcurvemode.segmentlength", 32), MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH);
+			
+			// Add options docker
+			panel = new DrawCurveOptionsPanel(MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH);
+			panel.SegmentLength = segmentlength;
+			panel.OnValueChanged += OptionsPanelOnValueChanged;
+			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
+
+			// Needs to be set after adding the OnContinuousDrawingChanged event...
+			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawcurvemode.continuousdrawing", false);
+		}
+
+		protected override void AddInterface()
+		{
+			panel.Register();
+		}
+
+		protected override void RemoveInterface()
+		{
+			// Store settings
+			General.Settings.WritePluginSetting("drawcurvemode.segmentlength", segmentlength);
+			General.Settings.WritePluginSetting("drawcurvemode.continuousdrawing", panel.ContinuousDrawing);
+
+			// Remove the buttons
+			panel.Unregister();
+		}
+
+		#endregion
+
 		#region ================== Actions
 
 		[BeginAction("increasesubdivlevel")]
 		protected virtual void IncreaseSubdivLevel() 
 		{
-			if(segmentLength < MAX_SEGMENT_LENGTH) 
+			if(segmentlength < MAX_SEGMENT_LENGTH) 
 			{
-				int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentLength / 32 * 16);
-				segmentLength += increment;
+				int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
+				segmentlength += increment;
 
-				if(segmentLength > MAX_SEGMENT_LENGTH) segmentLength = MAX_SEGMENT_LENGTH;
-				panel.SegmentLength = segmentLength;
+				if(segmentlength > MAX_SEGMENT_LENGTH) segmentlength = MAX_SEGMENT_LENGTH;
+				panel.SegmentLength = segmentlength;
 				Update();
 			}
 		}
@@ -323,13 +360,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("decreasesubdivlevel")]
 		protected virtual void DecreaseSubdivLevel() 
 		{
-			if(segmentLength > MIN_SEGMENT_LENGTH) 
+			if(segmentlength > MIN_SEGMENT_LENGTH) 
 			{
-				int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentLength / 32 * 16);
-				segmentLength -= increment;
+				int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16);
+				segmentlength -= increment;
 
-				if(segmentLength < MIN_SEGMENT_LENGTH) segmentLength = MIN_SEGMENT_LENGTH;
-				panel.SegmentLength = segmentLength;
+				if(segmentlength < MIN_SEGMENT_LENGTH) segmentlength = MIN_SEGMENT_LENGTH;
+				panel.SegmentLength = segmentlength;
 				Update();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs
index acbba493568d926396be2aa93bdbf010adc118e2..c14e5f1a620084d5c16d09bf87d7036239a624f4 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs
@@ -21,47 +21,64 @@ namespace CodeImp.DoomBuilder.BuilderModes
 	{
 		#region ================== Variables
 
-		//interface
+		// Drawing
+		private float angle; // in radians
+		
+		// Interface
 		private DrawEllipseOptionsPanel panel;
 
 		#endregion
 
 		#region ================== Constructor
 
-		public DrawEllipseMode() 
-		{
-			undoName = "Ellipse draw";
-			shapeName = "ellipse";
-			usefourcardinaldirections = true;
-		}
-
 		#endregion
 
 		#region ================== Settings panel
 
 		override protected void SetupInterface() 
 		{
-			maxSubdivisions = 512;
-			minSubdivisions = 6;
+			maxsubdivisions = 512;
+			minsubdivisions = 3;
+			minpointscount = 3;
+			alwaysrendershapehints = true;
+
+			// Load stored settings
+			subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawellipsemode.subdivisions", 8), minsubdivisions, maxsubdivisions);
+			bevelwidth = General.Settings.ReadPluginSetting("drawellipsemode.bevelwidth", 0);
+			int angledeg = General.Settings.ReadPluginSetting("drawellipsemode.angle", 0);
+			angle = Angle2D.DegToRad(angledeg);
+			currentbevelwidth = bevelwidth;
 
 			//Add options docker
 			panel = new DrawEllipseOptionsPanel();
-			panel.MaxSubdivisions = maxSubdivisions;
-			panel.MinSubdivisions = minSubdivisions;
+			panel.MaxSubdivisions = maxsubdivisions;
+			panel.MinSubdivisions = minsubdivisions;
 			panel.MinSpikiness = (int)General.Map.FormatInterface.MinCoordinate;
 			panel.MaxSpikiness = (int)General.Map.FormatInterface.MaxCoordinate;
+			panel.Spikiness = bevelwidth;
+			panel.Angle = angledeg;
+			panel.Subdivisions = subdivisions;
 			panel.OnValueChanged += OptionsPanelOnValueChanged;
+			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
+
+			// Needs to be set after adding the OnContinuousDrawingChanged event...
+			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawellipsemode.continuousdrawing", false);
 		}
 
 		override protected void AddInterface() 
 		{
 			panel.Register();
-			bevelWidth = panel.Spikiness;
-			subdivisions = panel.Subdivisions;
 		}
 
 		override protected void RemoveInterface() 
 		{
+			// Store settings
+			General.Settings.WritePluginSetting("drawellipsemode.subdivisions", subdivisions);
+			General.Settings.WritePluginSetting("drawellipsemode.bevelwidth", bevelwidth);
+			General.Settings.WritePluginSetting("drawellipsemode.angle", panel.Angle);
+			General.Settings.WritePluginSetting("drawellipsemode.continuousdrawing", panel.ContinuousDrawing);
+
+			// Remove the buttons
 			panel.Unregister();
 		}
 
@@ -71,21 +88,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		override protected Vector2D[] GetShape(Vector2D pStart, Vector2D pEnd) 
 		{
-			//no shape
+			// No shape
 			if(pEnd.x == pStart.x && pEnd.y == pStart.y) return new Vector2D[0];
 
-			//line
+			// Line
 			if(pEnd.x == pStart.x || pEnd.y == pStart.y) return new[] { pStart, pEnd };
 
-			//got shape
-			if(bevelWidth < 0) 
-			{
-				currentBevelWidth = -Math.Min(Math.Abs(bevelWidth), Math.Min(width, height) / 2) + 1;
-			} 
+			// Got shape
+			if(subdivisions < 6)
+				currentbevelwidth = 0; // Works strange otherwise
+			else if(bevelwidth < 0) 
+				currentbevelwidth = -Math.Min(Math.Abs(bevelwidth), Math.Min(width, height) / 2) + 1;
 			else 
-			{
-				currentBevelWidth = bevelWidth;
-			}
+				currentbevelwidth = bevelwidth;
 
 			Vector2D[] shape = new Vector2D[subdivisions + 1];
 
@@ -94,7 +109,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			int hh = height / 2;
 
 			Vector2D center = new Vector2D(pStart.x + hw, pStart.y + hh);
-			float curAngle = 0;
+			float curAngle = angle;
 			float angleStep = -Angle2D.PI / subdivisions * 2;
 
 			for(int i = 0; i < subdivisions; i++) 
@@ -102,8 +117,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				int px, py;
 				if(doBevel) 
 				{
-					px = (int)(center.x - (float)Math.Sin(curAngle) * (hw + currentBevelWidth));
-					py = (int)(center.y - (float)Math.Cos(curAngle) * (hh + currentBevelWidth));
+					px = (int)(center.x - (float)Math.Sin(curAngle) * (hw + currentbevelwidth));
+					py = (int)(center.y - (float)Math.Cos(curAngle) * (hh + currentbevelwidth));
 				} 
 				else 
 				{
@@ -114,24 +129,54 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				shape[i] = new Vector2D(px, py);
 				curAngle += angleStep;
 			}
-			//add final point
+
+			// Add final point
 			shape[subdivisions] = shape[0];
 			return shape;
 		}
 
 		protected override string GetHintText() 
 		{
-			return "BVL: " + bevelWidth + "; VERTS: " + subdivisions;
+			return "BVL: " + bevelwidth + "; VERTS: " + subdivisions;
 		}
 
 		#endregion
 
 		#region ================== Events
 
+		public override void OnAccept()
+		{
+			switch(points.Count - 1) // Last point matches the first one
+			{
+				case 3:  undoname = "Triangle draw"; shapename = "triangle"; break;
+				case 4:  undoname = "Rhombus draw"; shapename = "rhombus"; break;
+				case 5:  undoname = "Pentagon draw"; shapename = "pentagon"; break;
+				case 6:  undoname = "Hexagon draw"; shapename = "hexagon"; break;
+				case 7:  undoname = "Heptagon draw"; shapename = "heptagon"; break;
+				case 8:  undoname = "Octagon draw"; shapename = "octagon"; break;
+				case 9:  undoname = "Enneagon draw"; shapename = "enneagon"; break;
+				case 10: undoname = "Decagon draw"; shapename = "decagon"; break;
+				case 11: undoname = "Hendecagon draw"; shapename = "hendecagon"; break;
+				case 12: undoname = "Dodecagon draw"; shapename = "dodecagon"; break;
+				case 13: undoname = "Tridecagon draw"; shapename = "tridecagon"; break;
+				case 14: undoname = "Tetradecagon draw"; shapename = "tetradecagon"; break;
+				case 15: undoname = "Pentadecagon draw"; shapename = "pentadecagon"; break;
+				case 16: undoname = "Hexadecagon draw"; shapename = "hexadecagon"; break;
+				case 17: undoname = "Heptadecagon draw"; shapename = "heptadecagon"; break;
+				case 18: undoname = "Octadecagon draw"; shapename = "octadecagon"; break;
+				case 19: undoname = "Enneadecagon draw"; shapename = "enneadecagon"; break;
+				case 20: undoname = "Icosagon draw"; shapename = "icosagon"; break;
+				default: undoname = "Ellipse draw"; shapename = "ellipse"; break;
+			}
+			
+			base.OnAccept();
+		}
+
 		private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) 
 		{
-			bevelWidth = panel.Spikiness;
-			subdivisions = Math.Min(maxSubdivisions, panel.Subdivisions);
+			bevelwidth = panel.Spikiness;
+			subdivisions = Math.Min(maxsubdivisions, panel.Subdivisions);
+			angle = Angle2D.DegToRad(panel.Angle);
 			Update();
 		}
 
@@ -146,9 +191,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		override protected void IncreaseSubdivLevel() 
 		{
-			if(maxSubdivisions - subdivisions > 1) 
+			if(maxsubdivisions - subdivisions > 1) 
 			{
-				subdivisions += 2;
+				subdivisions += (subdivisions % 2 != 0 ? 1 : 2);
 				panel.Subdivisions = subdivisions;
 				Update();
 			}
@@ -156,9 +201,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		override protected void DecreaseSubdivLevel() 
 		{
-			if(subdivisions - minSubdivisions > 1) 
+			if(subdivisions - minsubdivisions > 1) 
 			{
-				subdivisions -= 2;
+				subdivisions -= (subdivisions % 2 != 0 ? 1 : 2);
 				panel.Subdivisions = subdivisions;
 				Update();
 			}
@@ -166,20 +211,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		protected override void IncreaseBevel() 
 		{
-			if(points.Count < 2 || currentBevelWidth == bevelWidth || bevelWidth < 0) 
+			if(points.Count < 2 || currentbevelwidth == bevelwidth || bevelwidth < 0) 
 			{
-				bevelWidth = Math.Min(bevelWidth + General.Map.Grid.GridSize, panel.MaxSpikiness);
-				panel.Spikiness = bevelWidth;
+				bevelwidth = Math.Min(bevelwidth + General.Map.Grid.GridSize, panel.MaxSpikiness);
+				panel.Spikiness = bevelwidth;
 				Update();
 			}
 		}
 
 		protected override void DecreaseBevel() 
 		{
-			if(bevelWidth > 0 || currentBevelWidth <= bevelWidth + 1) 
+			if(bevelwidth > 0 || currentbevelwidth <= bevelwidth + 1) 
 			{
-				bevelWidth = Math.Max(bevelWidth - General.Map.Grid.GridSize, panel.MinSpikiness);
-				panel.Spikiness = bevelWidth;
+				bevelwidth = Math.Max(bevelwidth - General.Map.Grid.GridSize, panel.MinSpikiness);
+				panel.Spikiness = bevelwidth;
 				Update();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index ca2c2baa05b4ae7a1b9b9dbfb031da1d956071be..31fce87d431a6fcbca0f065d0a1e252dccadd810 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -18,14 +18,14 @@
 
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Windows.Forms;
-using CodeImp.DoomBuilder.Windows;
+using CodeImp.DoomBuilder.Actions;
+using CodeImp.DoomBuilder.Editing;
+using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Rendering;
-using CodeImp.DoomBuilder.Geometry;
-using System.Drawing;
-using CodeImp.DoomBuilder.Editing;
-using CodeImp.DoomBuilder.Actions;
+using CodeImp.DoomBuilder.Windows;
 
 #endregion
 
@@ -65,10 +65,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		protected bool snaptonearest;	// CTRL to enable
 		protected bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable
 		protected static bool usefourcardinaldirections;
+		protected bool continuousdrawing; //mxd. Restart after finishing drawing?
 
 		//mxd. Labels display style
 		protected bool labelshowangle = true;
 		protected bool labeluseoffset = true;
+
+		//mxd. Interface
+		private DrawLineOptionsPanel panel;
 		
 		#endregion
 
@@ -88,6 +92,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// No selection in this mode
 			General.Map.Map.ClearAllSelected();
 			General.Map.Map.ClearAllMarks(false);
+
+			//mxd
+			SetupInterface();
 			
 			// We have no destructor
 			GC.SuppressFinalize(this);
@@ -446,6 +453,31 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		
 		#endregion
 
+		#region ================== mxd. Settings panel
+
+		protected virtual void SetupInterface()
+		{
+			//Add options docker
+			panel = new DrawLineOptionsPanel();
+			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
+
+			// Needs to be set after adding the OnContinuousDrawingChanged event...
+			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawlinesmode.continuousdrawing", false);
+		}
+
+		protected virtual void AddInterface()
+		{
+			panel.Register();
+		}
+
+		protected virtual void RemoveInterface()
+		{
+			General.Settings.WritePluginSetting("drawlinesmode.continuousdrawing", panel.ContinuousDrawing);
+			panel.Unregister();
+		}
+
+		#endregion
+
 		#region ================== Events
 
 		public override void OnHelp()
@@ -458,6 +490,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			base.OnEngage();
 			EnableAutoPanning();
+			AddInterface(); //mxd
 			renderer.SetPresentation(Presentation.Standard);
 			
 			// Set cursor
@@ -467,6 +500,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Disengaging
 		public override void OnDisengage()
 		{
+			RemoveInterface(); //mxd
 			base.OnDisengage();
 			DisableAutoPanning();
 		}
@@ -474,6 +508,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Cancelled
 		public override void OnCancel()
 		{
+			//mxd. Cannot leave this way when continuous drawing is enabled
+			if(continuousdrawing) return;
+			
 			// Cancel base class
 			base.OnCancel();
 			
@@ -505,44 +542,57 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing.");
 				
 				// Make the drawing
-				if(!Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
+				if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd
+				{
+					// Snap to map format accuracy
+					General.Map.Map.SnapAllToAccuracy();
+
+					// Clear selection
+					General.Map.Map.ClearAllSelected();
+
+					// Update cached values
+					General.Map.Map.Update();
+
+					// Edit new sectors?
+					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
+					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
+						General.Interface.ShowEditSectors(newsectors);
+
+					// Update the used textures
+					General.Map.Data.UpdateUsedTextures();
+
+					//mxd
+					General.Map.Renderer2D.UpdateExtraFloorFlag();
+
+					// Map is changed
+					General.Map.IsChanged = true;
+				}
+				else
 				{
 					// Drawing failed
 					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
 					General.Map.UndoRedo.WithdrawUndo();
 					General.Map.UndoRedo.WithdrawUndo();
-					return;
 				}
-
-				// Snap to map format accuracy
-				General.Map.Map.SnapAllToAccuracy();
-				
-				// Clear selection
-				General.Map.Map.ClearAllSelected();
-				
-				// Update cached values
-				General.Map.Map.Update();
-
-				// Edit new sectors?
-				List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
-				if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
-					General.Interface.ShowEditSectors(newsectors);
-				
-				// Update the used textures
-				General.Map.Data.UpdateUsedTextures();
-
-				//mxd
-				General.Map.Renderer2D.UpdateExtraFloorFlag();
-				
-				// Map is changed
-				General.Map.IsChanged = true;
 			}
 
 			// Done
 			Cursor.Current = Cursors.Default;
-			
-			// Return to original mode
-			General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+
+			if(continuousdrawing)
+			{
+				//mxd. Reset settings
+				points.Clear();
+				labels.Clear();
+
+				//mxd. Redraw display
+				General.Interface.RedrawDisplay();
+			}
+			else
+			{
+				// Return to original mode
+				General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			}
 		}
 
 		// This redraws the display
@@ -595,6 +645,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			   (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) ||
 			   (snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
 		}
+
+		//mxd
+		protected void OnContinuousDrawingChanged(object value, EventArgs e)
+		{
+			continuousdrawing = (bool)value;
+		}
 		
 		#endregion
 		
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
index 1261e048ca33809ce99b632d3021b04be21c56cb..3ce2499348c86f355539acd6cbb616c369347f74 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
@@ -27,15 +27,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 	public class DrawGridMode : DrawGeometryMode
 	{
+		#region ================== Enums
+
+		public enum GridLockMode
+		{
+			NONE,
+			HORIZONTAL,
+			VERTICAL,
+			BOTH,
+		}
+
+		#endregion
+
 		#region ================== Variables
 
-		private static int horizontalSlices = 3;
-		private static int verticalSlices = 3;
-		private static bool triangulate;
-		private static bool gridlock;
-		private static InterpolationTools.Mode horizontalinterpolation = InterpolationTools.Mode.LINEAR;
-		private static InterpolationTools.Mode verticalinterpolation = InterpolationTools.Mode.LINEAR;
+		// Settings
+		private int horizontalslices;
+		private int verticalslices;
+		private bool triangulate;
+		private GridLockMode gridlockmode;
+		private InterpolationTools.Mode horizontalinterpolation;
+		private InterpolationTools.Mode verticalinterpolation;
 
+		// Drawing
 		private readonly List<DrawnVertex[]> gridpoints;
 		private HintLabel hintlabel;
 		
@@ -46,7 +60,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private Vector2D start;
 		private Vector2D end;
 
-		//interface
+		// Interface
 		private DrawGridOptionsPanel panel;
 		private Docker docker;
 
@@ -65,40 +79,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Events
 
-		public override void OnEngage() 
-		{
-			base.OnEngage();
-
-			// Create and setup settings panel
-			panel = new DrawGridOptionsPanel();
-			panel.MaxHorizontalSlices = (int)General.Map.FormatInterface.MaxCoordinate;
-			panel.MaxVerticalSlices = (int) General.Map.FormatInterface.MaxCoordinate;
-			panel.Triangulate = triangulate;
-			panel.LockToGrid = gridlock;
-			panel.HorizontalSlices = horizontalSlices - 1;
-			panel.VerticalSlices = verticalSlices - 1;
-			panel.HorizontalInterpolationMode = horizontalinterpolation;
-			panel.VerticalInterpolationMode = verticalinterpolation;
-
-			panel.OnValueChanged += OptionsPanelOnValueChanged;
-			panel.OnGridLockChanged += OptionsPanelOnOnGridLockChanged;
-
-			// Add docker
-			docker = new Docker("drawgrid", "Draw Grid", panel);
-			General.Interface.AddDocker(docker);
-			General.Interface.SelectDocker(docker);
-		}
-
-		public override void OnDisengage() 
-		{
-			base.OnDisengage();
-
-			// Remove docker
-			General.Interface.RemoveDocker(docker);
-			panel.Dispose();
-			panel = null;
-		}
-
 		override public void OnAccept() 
 		{
 			Cursor.Current = Cursors.AppStarting;
@@ -120,62 +100,75 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				List<Sector> newsectors = new List<Sector>();
 				foreach(DrawnVertex[] shape in gridpoints) 
 				{
-					if(!Tools.DrawLines(shape, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) 
+					if(Tools.DrawLines(shape, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate))
 					{
-						// Drawing failed
-						// NOTE: I have to call this twice, because the first time only cancels this volatile mode
-						General.Map.UndoRedo.WithdrawUndo();
-						General.Map.UndoRedo.WithdrawUndo();
-						return;
-					}
+						// Update cached values after each step...
+						General.Map.Map.Update();
 
-					// Update cached values after each step...
-					General.Map.Map.Update();
-
-					newsectors.AddRange(General.Map.Map.GetMarkedSectors(true));
-				}
+						newsectors.AddRange(General.Map.Map.GetMarkedSectors(true));
 
-				// Snap to map format accuracy
-				General.Map.Map.SnapAllToAccuracy();
+						// Snap to map format accuracy
+						General.Map.Map.SnapAllToAccuracy();
 
-				// Clear selection
-				General.Map.Map.ClearAllSelected();
+						// Clear selection
+						General.Map.Map.ClearAllSelected();
 
-				// Edit new sectors?
-				if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
-					General.Interface.ShowEditSectors(newsectors);
+						// Edit new sectors?
+						if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
+							General.Interface.ShowEditSectors(newsectors);
 
-				// Update the used textures
-				General.Map.Data.UpdateUsedTextures();
+						// Update the used textures
+						General.Map.Data.UpdateUsedTextures();
 
-				//mxd
-				General.Map.Renderer2D.UpdateExtraFloorFlag();
+						//mxd
+						General.Map.Renderer2D.UpdateExtraFloorFlag();
 
-				// Map is changed
-				General.Map.IsChanged = true;
+						// Map is changed
+						General.Map.IsChanged = true;
+					}
+					else
+					{
+						// Drawing failed
+						// NOTE: I have to call this twice, because the first time only cancels this volatile mode
+						General.Map.UndoRedo.WithdrawUndo();
+						General.Map.UndoRedo.WithdrawUndo();
+					}
+				}
 			}
 
 			// Done
 			Cursor.Current = Cursors.Default;
 
-			// Return to original mode
-			General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			if(continuousdrawing)
+			{
+				// Reset settings
+				points.Clear();
+				labels.Clear();
+
+				// Redraw display
+				General.Interface.RedrawDisplay();
+			}
+			else
+			{
+				// Return to original mode
+				General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			}
 		}
 
 		private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) 
 		{
 			triangulate = panel.Triangulate;
-			horizontalSlices = panel.HorizontalSlices + 1;
-			verticalSlices = panel.VerticalSlices + 1;
+			horizontalslices = panel.HorizontalSlices + 1;
+			verticalslices = panel.VerticalSlices + 1;
 			horizontalinterpolation = panel.HorizontalInterpolationMode;
 			verticalinterpolation = panel.VerticalInterpolationMode;
 			Update();
 		}
 
-		private void OptionsPanelOnOnGridLockChanged(object sender, EventArgs eventArgs) 
+		private void OptionsPanelOnGridLockChanged(object sender, EventArgs eventArgs) 
 		{
-			gridlock = panel.LockToGrid;
-			General.Hints.ShowHints(this.GetType(), (gridlock ? "gridlockhelp" : "general"));
+			gridlockmode = panel.GridLockMode;
+			General.Hints.ShowHints(this.GetType(), ((gridlockmode != GridLockMode.NONE) ? "gridlockhelp" : "general"));
 			Update();
 		}
 
@@ -195,8 +188,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			// We WANT snaptogrid and DON'T WANT snaptonearest when lock to grid is enabled
 			snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState; //mxd
-			snaptogrid = (snaptocardinaldirection || gridlock || (General.Interface.ShiftState ^ General.Interface.SnapToGrid));
-			snaptonearest = (!gridlock && (General.Interface.CtrlState ^ General.Interface.AutoMerge));
+			snaptogrid = (snaptocardinaldirection || gridlockmode != GridLockMode.NONE || (General.Interface.ShiftState ^ General.Interface.SnapToGrid));
+			snaptonearest = (gridlockmode == GridLockMode.NONE && (General.Interface.CtrlState ^ General.Interface.AutoMerge));
 
 			DrawnVertex curp;
 			if(points.Count == 1)
@@ -246,7 +239,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					}
 
 					//render hint
-					if(horizontalSlices > 1 || verticalSlices > 1) 
+					if(horizontalslices > 1 || verticalslices > 1) 
 					{
 						hintlabel.Text = "H: " + (slicesH - 1) + "; V: " + (slicesV - 1);
 						if(width > hintlabel.Text.Length * vsize && height > 16 * vsize) 
@@ -277,10 +270,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
 				return false;
 
-			DrawnVertex newpoint = new DrawnVertex();
-			newpoint.pos = pos;
-			newpoint.stitch = true;
-			newpoint.stitchline = stitchline;
+			DrawnVertex newpoint = new DrawnVertex { pos = pos, stitch = true, stitchline = stitchline };
 			points.Add(newpoint);
 
 			if(points.Count == 1) 
@@ -311,10 +301,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					DrawnVertex[] verts = new DrawnVertex[shape.Length];
 					for(int i = 0; i < shape.Length; i++) 
 					{
-						newpoint = new DrawnVertex();
-						newpoint.pos = shape[i];
-						newpoint.stitch = true;
-						newpoint.stitchline = stitchline;
+						newpoint = new DrawnVertex { pos = shape[i], stitch = true, stitchline = stitchline };
 						verts[i] = newpoint;
 					}
 
@@ -328,22 +315,34 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		private List<Vector2D[]> GetShapes(Vector2D s, Vector2D e) 
 		{
-			//no shape
+			// No shape
 			if(s == e) return new List<Vector2D[]>();
 
-			//setup slices
-			if(gridlock) 
-			{
-				slicesH = width / General.Map.Grid.GridSize;
-				slicesV = height / General.Map.Grid.GridSize;
-			} 
-			else 
+			// Setup slices
+			switch(gridlockmode)
 			{
-				slicesH = horizontalSlices;
-				slicesV = verticalSlices;
+				case GridLockMode.NONE:
+					slicesH = horizontalslices;
+					slicesV = verticalslices;
+					break;
+
+				case GridLockMode.HORIZONTAL:
+					slicesH = width / General.Map.Grid.GridSize;
+					slicesV = verticalslices;
+					break;
+
+				case GridLockMode.VERTICAL:
+					slicesH = horizontalslices;
+					slicesV = height / General.Map.Grid.GridSize;
+					break;
+
+				case GridLockMode.BOTH:
+					slicesH = width / General.Map.Grid.GridSize;
+					slicesV = height / General.Map.Grid.GridSize;
+					break;
 			}
 
-			//create a segmented line
+			// Create a segmented line
 			List<Vector2D[]> shapes;
 			if(width == 0 || height == 0)
 			{
@@ -369,19 +368,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					return shapes;
 				}
 
-				//create a line
+				// Create a line
 				return new List<Vector2D[]> {new[] {s, e}};
 			}
 
-			//create shape
+			// Create shape
 			List<Vector2D> rect = new List<Vector2D> { s, new Vector2D((int)s.x, (int)e.y), e, new Vector2D((int)e.x, (int)s.y), s };
-			if(!gridlock && slicesH == 1 && slicesV == 1) 
+			if(slicesH == 1 && slicesV == 1) 
 			{
 				if(triangulate) rect.AddRange(new[] { s, e });
 				return new List<Vector2D[]> { rect.ToArray() };
 			}
 
-			//create blocks
+			// Create blocks
 			shapes = new List<Vector2D[]> { rect.ToArray() };
 			RectangleF[,] blocks = new RectangleF[slicesH, slicesV];
 			for(int w = 0; w < slicesH; w++) 
@@ -396,7 +395,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 			}
 
-			//add subdivisions
+			// Add subdivisions
 			if(slicesH > 1) 
 			{
 				for(int w = 1; w < slicesH; w++) 
@@ -414,7 +413,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 			}
 
-			//triangulate?
+			// Triangulate?
 			if(triangulate) 
 			{
 				bool startflip = ((int)Math.Round(((s.x + e.y) / General.Map.Grid.GridSize) % 2) == 0);
@@ -440,7 +439,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return shapes;
 		}
 
-		//update bottom-left and top-right points, which define drawing shape
+		// Update bottom-left and top-right points, which define drawing shape
 		private void UpdateReferencePoints(DrawnVertex p1, DrawnVertex p2) 
 		{
 			if(!p1.pos.IsFinite() || !p2.pos.IsFinite()) return;
@@ -473,15 +472,75 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#endregion
 
+		#region ================== Settings panel
+
+		protected override void SetupInterface()
+		{
+			// Load stored settings
+			triangulate = General.Settings.ReadPluginSetting("drawgridmode.triangulate", false);
+			gridlockmode = (GridLockMode)General.Settings.ReadPluginSetting("drawgridmode.gridlockmode", 0);
+			horizontalslices = Math.Max(General.Settings.ReadPluginSetting("drawgridmode.horizontalslices", 3), 3);
+			verticalslices = Math.Max(General.Settings.ReadPluginSetting("drawgridmode.verticalslices", 3), 3);
+			horizontalinterpolation = (InterpolationTools.Mode)General.Settings.ReadPluginSetting("drawgridmode.horizontalinterpolation", 0);
+			verticalinterpolation = (InterpolationTools.Mode)General.Settings.ReadPluginSetting("drawgridmode.verticalinterpolation", 0);
+			
+			// Create and setup settings panel
+			panel = new DrawGridOptionsPanel();
+			panel.MaxHorizontalSlices = (int)General.Map.FormatInterface.MaxCoordinate;
+			panel.MaxVerticalSlices = (int)General.Map.FormatInterface.MaxCoordinate;
+			panel.Triangulate = triangulate;
+			panel.GridLockMode = gridlockmode;
+			panel.HorizontalSlices = horizontalslices - 1;
+			panel.VerticalSlices = verticalslices - 1;
+			panel.HorizontalInterpolationMode = horizontalinterpolation;
+			panel.VerticalInterpolationMode = verticalinterpolation;
+
+			panel.OnValueChanged += OptionsPanelOnValueChanged;
+			panel.OnGridLockModeChanged += OptionsPanelOnGridLockChanged;
+			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
+
+			// Needs to be set after adding the OnContinuousDrawingChanged event...
+			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawgridmode.continuousdrawing", false);
+		}
+
+		protected override void AddInterface()
+		{
+			// Add docker
+			docker = new Docker("drawgrid", "Draw Grid", panel);
+			General.Interface.AddDocker(docker);
+			General.Interface.SelectDocker(docker);
+		}
+
+		protected override void RemoveInterface()
+		{
+			// Store settings
+			General.Settings.WritePluginSetting("drawgridmode.triangulate", triangulate);
+			General.Settings.WritePluginSetting("drawgridmode.gridlockmode", (int)gridlockmode);
+			General.Settings.WritePluginSetting("drawgridmode.horizontalslices", horizontalslices);
+			General.Settings.WritePluginSetting("drawgridmode.verticalslices", verticalslices);
+			General.Settings.WritePluginSetting("drawgridmode.horizontalinterpolation", (int)horizontalinterpolation);
+			General.Settings.WritePluginSetting("drawgridmode.verticalinterpolation", (int)verticalinterpolation);
+			General.Settings.WritePluginSetting("drawgridmode.continuousdrawing", panel.ContinuousDrawing);
+
+			// Remove docker
+			General.Interface.RemoveDocker(docker);
+			panel.Dispose();
+			panel = null;
+		}
+
+		#endregion
+
 		#region ================== Actions
 
 		[BeginAction("increasebevel")]
 		protected void IncreaseBevel()
 		{
-			if(!gridlock && (points.Count < 2 || horizontalSlices < width - 2) && horizontalSlices - 1 < panel.MaxHorizontalSlices) 
+			if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.VERTICAL) 
+				&& (points.Count < 2 || horizontalslices < width - 2) 
+				&& horizontalslices - 1 < panel.MaxHorizontalSlices) 
 			{
-				horizontalSlices++;
-				panel.HorizontalSlices = horizontalSlices - 1;
+				horizontalslices++;
+				panel.HorizontalSlices = horizontalslices - 1;
 				Update();
 			}
 		}
@@ -489,10 +548,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("decreasebevel")]
 		protected void DecreaseBevel()
 		{
-			if(!gridlock && horizontalSlices > 1) 
+			if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.VERTICAL) && horizontalslices > 1) 
 			{
-				horizontalSlices--;
-				panel.HorizontalSlices = horizontalSlices - 1;
+				horizontalslices--;
+				panel.HorizontalSlices = horizontalslices - 1;
 				Update();
 			}
 		}
@@ -500,10 +559,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("increasesubdivlevel")]
 		protected void IncreaseSubdivLevel()
 		{
-			if(!gridlock && (points.Count < 2 || verticalSlices < height - 2) && verticalSlices - 1 < panel.MaxVerticalSlices) 
+			if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.HORIZONTAL) 
+				&& (points.Count < 2 || verticalslices < height - 2) 
+				&& verticalslices - 1 < panel.MaxVerticalSlices) 
 			{
-				verticalSlices++;
-				panel.VerticalSlices = verticalSlices - 1;
+				verticalslices++;
+				panel.VerticalSlices = verticalslices - 1;
 				Update();
 			}
 		}
@@ -511,10 +572,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("decreasesubdivlevel")]
 		protected void DecreaseSubdivLevel()
 		{
-			if(!gridlock && verticalSlices > 1) 
+			if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.HORIZONTAL) && verticalslices > 1) 
 			{
-				verticalSlices--;
-				panel.VerticalSlices = verticalSlices - 1;
+				verticalslices--;
+				panel.VerticalSlices = verticalslices - 1;
 				Update();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
index 5269ad90fa892761b7c871abb88a6f88d3d5f771..688508f59e560af4cdc32f49399949db9e50dbb1 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs
@@ -30,22 +30,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		#region ================== Variables
 
 		protected HintLabel hintlabel;
-		protected int bevelWidth;
-		protected int currentBevelWidth;
+		protected int bevelwidth;
+		protected int currentbevelwidth;
 		protected int subdivisions;
 
-		protected int maxSubdivisions;
-		protected int minSubdivisions;
+		protected int maxsubdivisions;
+		protected int minsubdivisions;
 
-		protected string undoName = "Rectangle draw";
-		protected string shapeName = "rectangle";
+		protected string undoname = "Rectangle draw";
+		protected string shapename = "rectangle";
 
 		protected Vector2D start;
 		protected Vector2D end;
 		protected int width;
 		protected int height;
+		protected int minpointscount;
+		protected bool alwaysrendershapehints;
 
-		//interface
+		// Interface
 		private DrawRectangleOptionsPanel panel;
 
 		#endregion
@@ -56,7 +58,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			snaptogrid = true;
 			usefourcardinaldirections = true;
-			SetupInterface();
 		}
 
 		public override void Dispose() 
@@ -76,28 +77,44 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Settings panel
 
-		protected virtual void SetupInterface() 
+		protected override void SetupInterface() 
 		{
-			maxSubdivisions = 16;
+			maxsubdivisions = 16;
+			minpointscount = 4;
+
+			// Load stored settings
+			subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawrectanglemode.subdivisions", 0), minsubdivisions, maxsubdivisions);
+			bevelwidth = General.Settings.ReadPluginSetting("drawrectanglemode.bevelwidth", 0);
+			currentbevelwidth = bevelwidth;
 
 			//Add options docker
 			panel = new DrawRectangleOptionsPanel();
-			panel.MaxSubdivisions = maxSubdivisions;
-			panel.MinSubdivisions = minSubdivisions;
+			panel.MaxSubdivisions = maxsubdivisions;
+			panel.MinSubdivisions = minsubdivisions;
 			panel.MaxBevelWidth = (int)General.Map.FormatInterface.MaxCoordinate;
 			panel.MinBevelWidth = (int)General.Map.FormatInterface.MinCoordinate;
+			panel.BevelWidth = bevelwidth;
+			panel.Subdivisions = subdivisions;
 			panel.OnValueChanged += OptionsPanelOnValueChanged;
+			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
+
+			// Needs to be set after adding the OnContinuousDrawingChanged event...
+			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawrectanglemode.continuousdrawing", false);
 		}
 
-		protected virtual void AddInterface() 
+		protected override void AddInterface() 
 		{
 			panel.Register();
-			bevelWidth = panel.BevelWidth;
-			subdivisions = panel.Subdivisions;
 		}
 
-		protected virtual void RemoveInterface() 
+		protected override void RemoveInterface()
 		{
+			// Store settings
+			General.Settings.WritePluginSetting("drawrectanglemode.subdivisions", subdivisions);
+			General.Settings.WritePluginSetting("drawrectanglemode.bevelwidth", bevelwidth);
+			General.Settings.WritePluginSetting("drawrectanglemode.continuousdrawing", panel.ContinuousDrawing);
+
+			// Remove the buttons
 			panel.Unregister();
 		}
 
@@ -144,7 +161,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					}
 
 					//got beveled corners? 
-					if(shape.Length > 5) 
+					if(alwaysrendershapehints || shape.Length > minpointscount + 1) 
 					{
 						//render hint
 						if(width > 64 * vsize && height > 16 * vsize) 
@@ -178,47 +195,47 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//no shape
 			if(pStart == pEnd) 
 			{
-				currentBevelWidth = 0;
+				currentbevelwidth = 0;
 				return new Vector2D[0];
 			}
 
 			//line
 			if(pEnd.x == pStart.x || pEnd.y == pStart.y) 
 			{
-				currentBevelWidth = 0;
+				currentbevelwidth = 0;
 				return new[] { pStart, pEnd };
 			}
 
 			//no corners
-			if(bevelWidth == 0) 
+			if(bevelwidth == 0) 
 			{
-				currentBevelWidth = 0;
+				currentbevelwidth = 0;
 				return new[] { pStart, new Vector2D((int)pStart.x, (int)pEnd.y), pEnd, new Vector2D((int)pEnd.x, (int)pStart.y), pStart };
 			}
 
 			//got corners. TODO: check point order
 			bool reverse = false;
-			currentBevelWidth = Math.Min(Math.Abs(bevelWidth), Math.Min(width, height) / 2);
+			currentbevelwidth = Math.Min(Math.Abs(bevelwidth), Math.Min(width, height) / 2);
 			
-			if(bevelWidth < 0) 
+			if(bevelwidth < 0) 
 			{
-				currentBevelWidth *= -1;
+				currentbevelwidth *= -1;
 				reverse = true;
 			}
 
 			List<Vector2D> shape = new List<Vector2D>();
 
 			//top-left corner
-			shape.AddRange(GetCornerPoints(pStart, currentBevelWidth, currentBevelWidth, !reverse));
+			shape.AddRange(GetCornerPoints(pStart, currentbevelwidth, currentbevelwidth, !reverse));
 
 			//top-right corner
-			shape.AddRange(GetCornerPoints(new Vector2D(pEnd.x, pStart.y), -currentBevelWidth, currentBevelWidth, reverse));
+			shape.AddRange(GetCornerPoints(new Vector2D(pEnd.x, pStart.y), -currentbevelwidth, currentbevelwidth, reverse));
 
 			//bottom-right corner
-			shape.AddRange(GetCornerPoints(pEnd, -currentBevelWidth, -currentBevelWidth, !reverse));
+			shape.AddRange(GetCornerPoints(pEnd, -currentbevelwidth, -currentbevelwidth, !reverse));
 
 			//bottom-left corner
-			shape.AddRange(GetCornerPoints(new Vector2D(pStart.x, pEnd.y), currentBevelWidth, -currentBevelWidth, reverse));
+			shape.AddRange(GetCornerPoints(new Vector2D(pStart.x, pEnd.y), currentbevelwidth, -currentbevelwidth, reverse));
 
 			//closing point
 			shape.Add(shape[0]);
@@ -229,7 +246,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private Vector2D[] GetCornerPoints(Vector2D startPoint, int bevel_width, int bevel_height, bool reverse) 
 		{
 			Vector2D[] points;
-			Vector2D center = (bevelWidth > 0 ? new Vector2D(startPoint.x + bevel_width, startPoint.y + bevel_height) : startPoint);
+			Vector2D center = (bevelwidth > 0 ? new Vector2D(startPoint.x + bevel_width, startPoint.y + bevel_height) : startPoint);
 			float curAngle = Angle2D.PI;
 
 			int steps = subdivisions + 2;
@@ -248,14 +265,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		protected virtual string GetHintText() 
 		{
-			return "BVL: " + bevelWidth + "; SUB: " + subdivisions;
+			return "BVL: " + bevelwidth + "; SUB: " + subdivisions;
 		}
 
-		//update top-left and bottom-right points, which define drawing shape
+		// Update top-left and bottom-right points, which define drawing shape
 		private void UpdateReferencePoints(DrawnVertex p1, DrawnVertex p2) 
 		{
 			if(!p1.pos.IsFinite() || !p2.pos.IsFinite()) return;
 
+			// Make sure start always stays at left and up from the end
 			if(p1.pos.x < p2.pos.x) 
 			{
 				start.x = p1.pos.x;
@@ -278,6 +296,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				end.y = p1.pos.y;
 			}
 
+			// Update size
 			width = (int)(end.x - start.x);
 			height = (int)(end.y - start.y);
 		}
@@ -330,18 +349,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		#endregion
 
 		#region ================== Events
-
-		public override void OnEngage() 
-		{
-			base.OnEngage();
-			AddInterface();
-		}
-
-		public override void OnDisengage() 
-		{
-			RemoveInterface();
-			base.OnDisengage();
-		}
 		
 		override public void OnAccept() 
 		{
@@ -349,57 +356,70 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Settings.FindDefaultDrawSettings();
 
 			// When we have a rectangle or a line
-			if(points.Count > 4 || points.Count == 2) 
+			if(points.Count > minpointscount || points.Count == 2) 
 			{
 				// Make undo for the draw
-				General.Map.UndoRedo.CreateUndo(undoName);
+				General.Map.UndoRedo.CreateUndo(undoname);
 
 				// 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 word = adjectives[new Random().Next(adjectives.Length - 1)];
 				string a = (word[0] == 'u' ? "an " : "a ");
 
-				General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " " + shapeName + ".");
+				General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " " + shapename + ".");
 
 				// Make the drawing
-				if(!Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) 
+				if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate))
 				{
-					// Drawing failed
-					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
-					General.Map.UndoRedo.WithdrawUndo();
-					General.Map.UndoRedo.WithdrawUndo();
-					return;
-				}
-
-				// Snap to map format accuracy
-				General.Map.Map.SnapAllToAccuracy();
+					// Snap to map format accuracy
+					General.Map.Map.SnapAllToAccuracy();
 
-				// Clear selection
-				General.Map.Map.ClearAllSelected();
+					// Clear selection
+					General.Map.Map.ClearAllSelected();
 
-				// Update cached values
-				General.Map.Map.Update();
+					// Update cached values
+					General.Map.Map.Update();
 
-				// Edit new sectors?
-				List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
-				if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
-					General.Interface.ShowEditSectors(newsectors);
+					// Edit new sectors?
+					List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true);
+					if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0))
+						General.Interface.ShowEditSectors(newsectors);
 
-				// Update the used textures
-				General.Map.Data.UpdateUsedTextures();
+					// Update the used textures
+					General.Map.Data.UpdateUsedTextures();
 
-				//mxd
-				General.Map.Renderer2D.UpdateExtraFloorFlag();
+					//mxd
+					General.Map.Renderer2D.UpdateExtraFloorFlag();
 
-				// Map is changed
-				General.Map.IsChanged = true;
+					// Map is changed
+					General.Map.IsChanged = true;
+				}
+				else
+				{
+					// Drawing failed
+					// NOTE: I have to call this twice, because the first time only cancels this volatile mode
+					General.Map.UndoRedo.WithdrawUndo();
+					General.Map.UndoRedo.WithdrawUndo();
+				}
 			}
 
 			// Done
 			Cursor.Current = Cursors.Default;
 
-			// Return to original mode
-			General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			if(continuousdrawing)
+			{
+				// Reset settings
+				points.Clear();
+				labels.Clear();
+
+				// Redraw display
+				General.Interface.RedrawDisplay();
+			}
+			else
+			{
+				// Return to original mode
+				General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
+			}
 		}
 
 		public override void OnHelp() 
@@ -409,7 +429,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) 
 		{
-			bevelWidth = panel.BevelWidth;
+			bevelwidth = panel.BevelWidth;
 			subdivisions = panel.Subdivisions;
 			Update();
 		}
@@ -421,7 +441,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("increasesubdivlevel")]
 		protected virtual void IncreaseSubdivLevel() 
 		{
-			if(subdivisions < maxSubdivisions) 
+			if(subdivisions < maxsubdivisions) 
 			{
 				subdivisions++;
 				panel.Subdivisions = subdivisions;
@@ -432,7 +452,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("decreasesubdivlevel")]
 		protected virtual void DecreaseSubdivLevel() 
 		{
-			if(subdivisions > minSubdivisions) 
+			if(subdivisions > minsubdivisions) 
 			{
 				subdivisions--;
 				panel.Subdivisions = subdivisions;
@@ -443,10 +463,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("increasebevel")]
 		protected virtual void IncreaseBevel() 
 		{
-			if(points.Count < 2 || currentBevelWidth == bevelWidth || bevelWidth < 0) 
+			if(points.Count < 2 || currentbevelwidth == bevelwidth || bevelwidth < 0) 
 			{
-				bevelWidth = Math.Min(bevelWidth + General.Map.Grid.GridSize, panel.MaxBevelWidth);
-				panel.BevelWidth = bevelWidth;
+				bevelwidth = Math.Min(bevelwidth + General.Map.Grid.GridSize, panel.MaxBevelWidth);
+				panel.BevelWidth = bevelwidth;
 				Update();
 			}
 		}
@@ -454,10 +474,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		[BeginAction("decreasebevel")]
 		protected virtual void DecreaseBevel() 
 		{
-			if(currentBevelWidth == bevelWidth || bevelWidth > 0) 
+			if(currentbevelwidth == bevelwidth || bevelwidth > 0) 
 			{
-				bevelWidth = Math.Max(bevelWidth - General.Map.Grid.GridSize, panel.MinBevelWidth);
-				panel.BevelWidth = bevelWidth;
+				bevelwidth = Math.Max(bevelwidth - General.Map.Grid.GridSize, panel.MinBevelWidth);
+				panel.BevelWidth = bevelwidth;
 				Update();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index 9f564195ebfbb531fdb7567f39edae997299585d..baa5386733a50e647d8ae0760f03614bdf99fd38 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -2004,7 +2004,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(!start.Fields.ContainsKey(key) && !end.Fields.ContainsKey(key)) 
 			{
-				General.Interface.DisplayStatus(StatusType.Warning, "First or last selected sector must have the '" + key + "' property!");
+				General.Interface.DisplayStatus(StatusType.Warning, "First or last selected sector must have the \"" + key + "\" property!");
 			} 
 			else 
 			{
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index b8e20965b621717f43365b651112b2982427bbb8..64fecd3c5a0d94d97e3f13dc1b8fbf477d2f7406 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -761,7 +761,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(t.Fields.ContainsKey("comment"))
 			{
-				float size = ((t.FixedSize && renderer.Scale > 1.0f) ? t.Size / renderer.Scale : t.Size);
+				float size = (((t.FixedSize || General.Settings.FixedThingsScale) && renderer.Scale > 1.0f) ? t.Size / renderer.Scale : t.Size);
 				if(size * renderer.Scale < 1.5f) return; // Thing is too small to render
 
 				int iconindex = 0;
@@ -1141,7 +1141,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if(excludedLines.Count == thingsCount) 
 						{
 							ThingTypeInfo tti = General.Map.Data.GetThingInfo(t.SRB2Type);
-							General.ErrorLogger.Add(ErrorType.Warning, "Unable to align Thing �" + t.Index + " (" + tti.Title + ") to any linedef in a map!");
+							General.ErrorLogger.Add(ErrorType.Warning, "Unable to align " + tti.Title + " (index " + t.Index + ") to any linedef!");
 							aligned = true;
 						}
 					}
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs
index 1a8e2801a1ee2772b9d86d19f6bcb180f0d57afe..1f424aef9e0a1ddc9b3763035d1398953f38624f 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs
@@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This must return the string that is displayed in the listbox
 		public override string ToString()
 		{
-			return "Texture '" + texturename + "' is not aligned on linedefs " + side1.Line.Index + " (" + (side1.IsFront ? "front" : "back") 
+			return "Texture \"" + texturename + "\" is not aligned on linedefs " + side1.Line.Index + " (" + (side1.IsFront ? "front" : "back") 
 				+ ") and " + side2.Line.Index + " (" + (side2.IsFront ? "front" : "back") + ")";
 		}
 		
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs
index ecaad6e49abb8150d4869c837e9024c8180f5e6b..224ee01ae6cb5f1c6b0b22dbd92bfd28c104d82d 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs
@@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					string f = flag.Trim();
 					if(!General.Map.Config.LinedefFlags.ContainsKey(f))
 					{
-						MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
+						MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
 						return objs.ToArray();
 					}
 					replaceflagslist.Add(f);
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs b/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs
index 52fcca576f29144c4f741cd9fcf76112b8ee541c..27ebc3874d0189b54100bf49ac863891f305c4fc 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs
@@ -38,8 +38,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Variables
 
-		private List<int> generalizedbits;
-
 		#endregion
 
 		#region ================== Properties
@@ -50,31 +48,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Constructor / Destructor
 
-		//mxd
-		public FindLinedefTypes() 
-		{
-			if(!General.Map.Config.GeneralizedActions) return;
-
-			// Get all them generalized bits
-			generalizedbits = new List<int>();
-			foreach(GeneralizedCategory cat in General.Map.Config.GenActionCategories) 
-			{
-				foreach(GeneralizedOption option in cat.Options) 
-				{
-					foreach(GeneralizedBit bit in option.Bits) 
-					{
-						if(bit.Index > 0) generalizedbits.Add(bit.Index);
-					}
-				}
-			}
-		}
-
 		#endregion
 
 		#region ================== Methods
 
 		// This is called when the browse button is pressed
 		public override string Browse(string initialvalue)
+		{
+			int num;
+			int.TryParse(initialvalue, out num);
+			return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, num, true).ToString();
+		}
+
+		//mxd. This is called when the browse replace button is pressed
+		public override string BrowseReplace(string initialvalue)
 		{
 			int num;
 			int.TryParse(initialvalue, out num);
@@ -178,7 +165,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 
 				//mxd
-				List<int> expectedbits = GetGeneralizedBits(action);
+				HashSet<int> expectedbits = GetGeneralizedBits(action);
 
 				// Where to search?
 				ICollection<Linedef> list = withinselection ? General.Map.Map.GetSelectedLinedefs(true) : General.Map.Map.Linedefs;
@@ -186,8 +173,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Go for all linedefs
 				foreach(Linedef l in list)
 				{
-					// Action matches?
-					if(l.Action != action && !BitsMatch(l.Action, expectedbits)) continue;
+					// Action matches? -1 means any action (mxd)
+					if((action == -1 && l.Action == 0) || (action > -1 && (l.Action != action && !BitsMatch(l.Action, expectedbits)))) continue;
 
 					bool match = true;
 					string argtext = "";
@@ -260,18 +247,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 
 		//mxd
-		private static List<int> GetGeneralizedBits(int effect) 
+		private static HashSet<int> GetGeneralizedBits(int action) 
 		{
-			if(!General.Map.Config.GeneralizedActions) return new List<int>();
-			List<int> bits = new List<int>();
+			if(!General.Map.Config.GeneralizedActions) return new HashSet<int>();
+			HashSet<int> bits = new HashSet<int>();
 
 			foreach(GeneralizedCategory cat in General.Map.Config.GenActionCategories) 
 			{
+				if((action < cat.Offset) || (action >= (cat.Offset + cat.Length))) continue;
+				int actionbits = action - cat.Offset;
 				foreach(GeneralizedOption option in cat.Options) 
 				{
 					foreach(GeneralizedBit bit in option.Bits) 
 					{
-						if(bit.Index > 0 && (effect & bit.Index) == bit.Index)
+						if(bit.Index > 0 && (actionbits & bit.Index) == bit.Index)
 							bits.Add(bit.Index);
 					}
 				}
@@ -281,16 +270,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 
 		//mxd
-		private static bool BitsMatch(int action, List<int> expectedbits) 
+		private static bool BitsMatch(int action, HashSet<int> expectedbits) 
 		{
-			if(!General.Map.Config.GeneralizedActions) return false;
+			if(!General.Map.Config.GeneralizedActions || expectedbits.Count == 0) return false;
+
+			HashSet<int> bits = GetGeneralizedBits(action);
+			if(bits.Count == 0) return false;
 
 			foreach(int bit in expectedbits) 
 			{
-				if((action & bit) != bit) return false;
+				if(bits.Contains(bit)) return true;
 			}
 
-			return true;
+			return false;
 		}
 		
 		#endregion
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs b/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs
index 26885b2df15ff8a546c01a92a8608b39d4f218fb..ebad855238339cbe99bbfc61f6da120b25dbc6c8 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs
@@ -80,6 +80,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			return string.Empty;
 		}
+
+		//mxd. This is called when the replace browse button is pressed
+		public virtual string BrowseReplace(string initialvalue)
+		{
+			return Browse(initialvalue);
+		}
 		
 		// This is called to perform a search (and replace)
 		// Must return a list of items to show in the results list
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs b/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs
index cd9370690be45252aee351d70b99b7cf2fe4038c..e21791c7e2ca3ded70e6930165ac387546fa32fd 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs
@@ -18,10 +18,10 @@
 
 using System;
 using System.Collections.Generic;
-using System.Windows.Forms;
-using CodeImp.DoomBuilder.Map;
 using System.Drawing;
+using System.Windows.Forms;
 using CodeImp.DoomBuilder.Config;
+using CodeImp.DoomBuilder.Map;
 
 #endregion
 
@@ -36,8 +36,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Variables
 
-		private List<int> generalizedbits;
-
 		#endregion
 
 		#region ================== Properties
@@ -48,22 +46,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Constructor / Destructor
 
-		//mxd
-		public FindSectorEffect() 
-		{
-			if(!General.Map.Config.GeneralizedEffects) return;
-
-			// Get all them generalized bits
-			generalizedbits = new List<int>();
-			foreach(GeneralizedOption option in General.Map.Config.GenEffectOptions) 
-			{
-				foreach(GeneralizedBit bit in option.Bits) 
-				{
-					if(bit.Index > 0) generalizedbits.Add(bit.Index);
-				}
-			}
-		}
-
 		#endregion
 
 		#region ================== Methods
@@ -73,10 +55,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			int effect;
 			int.TryParse(initialvalue, out effect);
-			effect = General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect);
-			return effect.ToString();
+			return General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect, true).ToString();
 		}
 
+		//mxd. This is called when the browse replace button is pressed
+		public override string BrowseReplace(string initialvalue)
+		{
+			int effect;
+			int.TryParse(initialvalue, out effect);
+			return General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect).ToString();
+		}
 
 		// This is called to perform a search (and replace)
 		// Returns a list of items to show in the results list
@@ -113,8 +101,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Go for all sectors
 				foreach(Sector s in list)
 				{
-					// Effect matches?
-					if(s.Effect == effect || BitsMatch(s.Effect, expectedbits))
+					// Effect matches? -1 means any effect (mxd)
+					if((effect == -1 && s.Effect > 0) || (effect > -1 && (s.Effect == effect || BitsMatch(s.Effect, expectedbits))))
 					{
 						// Replace
 						if(replace) s.Effect = replaceeffect;
@@ -150,7 +138,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 
 		//mxd
-		private static bool BitsMatch(int effect, List<int> expectedbits) 
+		private static bool BitsMatch(int effect, IEnumerable<int> expectedbits) 
 		{
 			if(!General.Map.Config.GeneralizedEffects) return false;
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs
index eef28388bf3ae8c5079b5dde0c87d778ae6bbb2c..560ac22de3d892eed65aae65315d2912cf5aac01 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs
@@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					string f = flag.Trim();
 					if(!General.Map.Config.SectorFlags.ContainsKey(f))
 					{
-						MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
+						MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
 						return objs.ToArray();
 					}
 					replaceflagslist.Add(f);
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs
index 4409719b39fcc87d51d32f9c3a53ba42eddf7ebe..39caa40b8e21d53c1f0f27bde03d27d9cd0510e1 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs
@@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					string f = flag.Trim();
 					if(!General.Map.Config.SidedefFlags.ContainsKey(f))
 					{
-						MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
+						MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
 						return objs.ToArray();
 					}
 					replaceflagslist.Add(f);
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs b/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs
index 5ae4c805fda04965b39d29eea4c871ac066247ee..e1bc042a4d4dda1077171ad31914077e1559f1eb 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs
@@ -60,16 +60,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return General.Map.FormatInterface.HasThingAction;
 		}
 
-
 		// This is called when the browse button is pressed
 		public override string Browse(string initialvalue)
 		{
 			int action;
 			int.TryParse(initialvalue, out action);
-			action = General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action);
-			return action.ToString();
+			return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action, true).ToString();
 		}
 
+		// This is called when the browse replace button is pressed
+		public override string BrowseReplace(string initialvalue)
+		{
+			int action;
+			int.TryParse(initialvalue, out action);
+			return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action).ToString();
+		}
 
 		// This is called to perform a search (and replace)
 		// Returns a list of items to show in the results list
@@ -172,8 +177,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Go for all things
 				foreach(Thing t in list) 
 				{
-					// Action matches?
-					if(t.Action != action) continue;
+					// Action matches? -1 means any action (mxd)
+					if((action == -1 && t.Action == 0) || (action > -1 && t.Action != action)) continue;
 
 					bool match = true;
 					string argtext = "";
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs
index cfe3efe4fcf18ddb720c1c157e5e33a1882c2c12..cb70f0eeb4790cb2aa563cf6b911191b84434766 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs
@@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					string f = flag.Trim();
 					if(!General.Map.Config.ThingFlags.ContainsKey(f))
 					{
-						MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
+						MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error);
 						return objs.ToArray();
 					}
 					replaceflagslist.Add(f);
diff --git a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs
index 1b0038ee0b0b6f879ea3d1921fb30bd761b8f2ff..0cf67208ef06bb62c17e840892e9bcaf86e3d182 100644
--- a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs
+++ b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs
@@ -164,7 +164,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					break;
 
 				default:
-					throw new NotImplementedException("GetSidedefPartSize: got unsupported geometry type: '" + type + "'");
+					throw new NotImplementedException("GetSidedefPartSize: got unsupported geometry type: \"" + type + "\"");
 			}
 
 			return rect;
diff --git a/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs b/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs
index d67b22271af8d9c2961878198b79bb0a8832fc21..f9b7dc47f3bddcf05fc17c4752963d86fd889ce6 100644
--- a/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs
+++ b/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs
@@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
 							ImageData id = General.Map.Data.GetTextureImage(s);
 							if(id.Width == 0 || id.Height == 0) 
 							{
-								General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture '" + s + "' has invalid size (" + id.Width + "x" + id.Height + ")!");
+								General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
 								continue;
 							}
 
@@ -100,7 +100,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
 						} 
 						else 
 						{
-							General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture '" + s + "' does not exist!");
+							General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" does not exist!");
 						}
 					}
 				}
@@ -115,7 +115,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
 							ImageData id = General.Map.Data.GetFlatImage(s);
 							if(id.Width == 0 || id.Height == 0) 
 							{
-								General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' has invalid size (" + id.Width + "x" + id.Height + ")!");
+								General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
 								continue;
 							}
 
@@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
 						} 
 						else 
 						{
-							General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' does not exist!");
+							General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" does not exist!");
 						}
 					}
 				}
@@ -185,7 +185,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
 				sw.Write(mtl.ToString());
 
 			//done
-			General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to '" + savePath + ".obj'");
+			General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to \"" + savePath + ".obj\"");
 		}
 
 		#endregion
diff --git a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs
index f590468ca9bb10cc56dff6824bae520855b528d4..2f0810b31a54e66a9e283d899c5aab0d434ba448 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs
@@ -32,26 +32,29 @@
 			this.seglabel = new System.Windows.Forms.ToolStripLabel();
 			this.seglen = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
 			this.reset = new System.Windows.Forms.ToolStripButton();
+			this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+			this.continuousdrawing = new System.Windows.Forms.ToolStripButton();
 			this.toolstrip.SuspendLayout();
 			this.SuspendLayout();
 			// 
 			// toolstrip
 			// 
 			this.toolstrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.continuousdrawing,
+            this.toolStripSeparator1,
             this.seglabel,
             this.seglen,
             this.reset});
 			this.toolstrip.Location = new System.Drawing.Point(0, 0);
 			this.toolstrip.Name = "toolstrip";
-			this.toolstrip.Size = new System.Drawing.Size(249, 25);
+			this.toolstrip.Size = new System.Drawing.Size(320, 25);
 			this.toolstrip.TabIndex = 7;
 			this.toolstrip.Text = "toolStrip1";
 			// 
 			// seglabel
 			// 
-			this.seglabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear;
 			this.seglabel.Name = "seglabel";
-			this.seglabel.Size = new System.Drawing.Size(113, 22);
+			this.seglabel.Size = new System.Drawing.Size(97, 22);
 			this.seglabel.Text = "Segment Length:";
 			// 
 			// seglen
@@ -69,7 +72,7 @@
             0,
             0});
 			this.seglen.Name = "seglen";
-			this.seglen.Size = new System.Drawing.Size(56, 20);
+			this.seglen.Size = new System.Drawing.Size(56, 23);
 			this.seglen.Text = "0";
 			this.seglen.Value = new decimal(new int[] {
             0,
@@ -84,17 +87,32 @@
 			this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
 			this.reset.ImageTransparentColor = System.Drawing.Color.Magenta;
 			this.reset.Name = "reset";
-			this.reset.Size = new System.Drawing.Size(23, 22);
+			this.reset.Size = new System.Drawing.Size(23, 20);
 			this.reset.Text = "Reset";
 			this.reset.Click += new System.EventHandler(this.reset_Click);
 			// 
+			// toolStripSeparator1
+			// 
+			this.toolStripSeparator1.Name = "toolStripSeparator1";
+			this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
+			// 
+			// continuousdrawing
+			// 
+			this.continuousdrawing.CheckOnClick = true;
+			this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat;
+			this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.continuousdrawing.Name = "continuousdrawing";
+			this.continuousdrawing.Size = new System.Drawing.Size(135, 22);
+			this.continuousdrawing.Text = "Continuous drawing";
+			this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged);
+			// 
 			// DrawCurveOptionsPanel
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
 			this.Controls.Add(this.toolstrip);
 			this.Name = "DrawCurveOptionsPanel";
-			this.Size = new System.Drawing.Size(249, 60);
+			this.Size = new System.Drawing.Size(320, 60);
 			this.toolstrip.ResumeLayout(false);
 			this.toolstrip.PerformLayout();
 			this.ResumeLayout(false);
@@ -108,6 +126,8 @@
 		internal CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown seglen;
 		private System.Windows.Forms.ToolStrip toolstrip;
 		private System.Windows.Forms.ToolStripButton reset;
+		private System.Windows.Forms.ToolStripButton continuousdrawing;
+		private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
 
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs
index d97ba896ca895c0ee26373c2fb1ca4386f29ce70..f3cd053814622959294fb6ca0f046edf8d6ffbc9 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs
@@ -6,9 +6,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 	internal partial class DrawCurveOptionsPanel : UserControl
 	{
 		public event EventHandler OnValueChanged;
-		private bool blockEvents;
+		public event EventHandler OnContinuousDrawingChanged;
+		private bool blockevents;
 
-		public int SegmentLength { get { return (int)seglen.Value; } set { blockEvents = true; seglen.Value = value; blockEvents = false; } }
+		public int SegmentLength { get { return (int)seglen.Value; } set { blockevents = true; seglen.Value = value; blockevents = false; } }
+		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
 
 		public DrawCurveOptionsPanel(int minLength, int maxLength) 
 		{
@@ -22,6 +24,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		public void Register() 
 		{
+			General.Interface.AddButton(continuousdrawing);
+			General.Interface.AddButton(toolStripSeparator1);
 			General.Interface.AddButton(seglabel);
 			General.Interface.AddButton(seglen);
 			General.Interface.AddButton(reset);
@@ -32,16 +36,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Interface.RemoveButton(reset);
 			General.Interface.RemoveButton(seglen);
 			General.Interface.RemoveButton(seglabel);
+			General.Interface.RemoveButton(toolStripSeparator1);
+			General.Interface.RemoveButton(continuousdrawing);
 		}
 
 		private void seglen_ValueChanged(object sender, EventArgs e) 
 		{
-			if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
+			if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
 		}
 
 		private void reset_Click(object sender, EventArgs e) 
 		{
 			seglen.Value = seglen.Minimum;
 		}
+
+		private void continuousdrawing_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty);
+		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs
index bb88abb86687ee2a85c9ce7c5468f2bfd94104d9..b95825fe62023c0146cb8da8905e45c24081d1e8 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs
@@ -29,10 +29,14 @@
 		private void InitializeComponent() 
 		{
 			this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+			this.continuousdrawing = new System.Windows.Forms.ToolStripButton();
+			this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
 			this.subdivslabel = new System.Windows.Forms.ToolStripLabel();
 			this.subdivs = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
 			this.spikinesslabel = new System.Windows.Forms.ToolStripLabel();
 			this.spikiness = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
+			this.anglelabel = new System.Windows.Forms.ToolStripLabel();
+			this.angle = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
 			this.reset = new System.Windows.Forms.ToolStripButton();
 			this.toolStrip1.SuspendLayout();
 			this.SuspendLayout();
@@ -40,22 +44,40 @@
 			// toolStrip1
 			// 
 			this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.continuousdrawing,
+            this.toolStripSeparator1,
             this.subdivslabel,
             this.subdivs,
             this.spikinesslabel,
             this.spikiness,
+            this.anglelabel,
+            this.angle,
             this.reset});
 			this.toolStrip1.Location = new System.Drawing.Point(0, 0);
 			this.toolStrip1.Name = "toolStrip1";
-			this.toolStrip1.Size = new System.Drawing.Size(348, 25);
+			this.toolStrip1.Size = new System.Drawing.Size(582, 25);
 			this.toolStrip1.TabIndex = 6;
 			this.toolStrip1.Text = "toolStrip1";
 			// 
+			// continuousdrawing
+			// 
+			this.continuousdrawing.CheckOnClick = true;
+			this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat;
+			this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.continuousdrawing.Name = "continuousdrawing";
+			this.continuousdrawing.Size = new System.Drawing.Size(135, 22);
+			this.continuousdrawing.Text = "Continuous drawing";
+			this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged);
+			// 
+			// toolStripSeparator1
+			// 
+			this.toolStripSeparator1.Name = "toolStripSeparator1";
+			this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
+			// 
 			// subdivslabel
 			// 
-			this.subdivslabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear;
 			this.subdivslabel.Name = "subdivslabel";
-			this.subdivslabel.Size = new System.Drawing.Size(53, 22);
+			this.subdivslabel.Size = new System.Drawing.Size(37, 22);
 			this.subdivslabel.Text = "Sides:";
 			// 
 			// subdivs
@@ -102,12 +124,41 @@
             0,
             0});
 			this.spikiness.Name = "spikiness";
-			this.spikiness.Size = new System.Drawing.Size(56, 20);
+			this.spikiness.Size = new System.Drawing.Size(56, 23);
 			this.spikiness.Text = "0";
 			this.spikiness.Value = new decimal(new int[] {
             0,
             0,
             0,
+            0});
+			// 
+			// anglelabel
+			// 
+			this.anglelabel.Name = "anglelabel";
+			this.anglelabel.Size = new System.Drawing.Size(41, 22);
+			this.anglelabel.Text = "Angle:";
+			// 
+			// angle
+			// 
+			this.angle.AutoSize = false;
+			this.angle.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0);
+			this.angle.Maximum = new decimal(new int[] {
+            360,
+            0,
+            0,
+            0});
+			this.angle.Minimum = new decimal(new int[] {
+            360,
+            0,
+            0,
+            -2147483648});
+			this.angle.Name = "angle";
+			this.angle.Size = new System.Drawing.Size(56, 23);
+			this.angle.Text = "0";
+			this.angle.Value = new decimal(new int[] {
+            0,
+            0,
+            0,
             0});
 			// 
 			// reset
@@ -126,7 +177,7 @@
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
 			this.Controls.Add(this.toolStrip1);
 			this.Name = "DrawEllipseOptionsPanel";
-			this.Size = new System.Drawing.Size(348, 60);
+			this.Size = new System.Drawing.Size(582, 60);
 			this.toolStrip1.ResumeLayout(false);
 			this.toolStrip1.PerformLayout();
 			this.ResumeLayout(false);
@@ -142,5 +193,9 @@
 		private System.Windows.Forms.ToolStripLabel spikinesslabel;
 		private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown spikiness;
 		private System.Windows.Forms.ToolStripButton reset;
+		private System.Windows.Forms.ToolStripButton continuousdrawing;
+		private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+		private System.Windows.Forms.ToolStripLabel anglelabel;
+		private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown angle;
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs
index d2fcb94566a5243d835e8518f42597eaedc0effd..eee4b7e6a02adf3df084ca4bf65440e7a3918a77 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs
@@ -6,17 +6,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 	internal partial class DrawEllipseOptionsPanel : UserControl
 	{
 		public event EventHandler OnValueChanged;
-		private bool blockEvents;
+		public event EventHandler OnContinuousDrawingChanged;
+		private bool blockevents;
 
-		private static int aquityValue;
-		private static int subdivsValue = 8;
-
-		public int Spikiness { get { return (int)spikiness.Value; } set { blockEvents = true; spikiness.Value = value; blockEvents = false; } }
-		public int Subdivisions { get { return (int)subdivs.Value; } set { blockEvents = true; subdivs.Value = value; blockEvents = false; } }
+		public int Spikiness { get { return (int)spikiness.Value; } set { blockevents = true; spikiness.Value = value; blockevents = false; } }
+		public int Subdivisions { get { return (int)subdivs.Value; } set { blockevents = true; subdivs.Value = value; blockevents = false; } }
+		public int Angle { get { return (int)angle.Value; } set { blockevents = true; angle.Value = value; blockevents = false; } }
 		public int MaxSubdivisions { get { return (int)subdivs.Maximum; } set { subdivs.Maximum = value; } }
 		public int MinSubdivisions { get { return (int)subdivs.Minimum;  } set { subdivs.Minimum = value; } }
 		public int MaxSpikiness { get { return (int)spikiness.Maximum; } set { spikiness.Maximum = value; } }
 		public int MinSpikiness { get { return (int)spikiness.Minimum; } set { spikiness.Minimum = value; } }
+		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
 		
 		public DrawEllipseOptionsPanel() 
 		{
@@ -25,40 +25,55 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		public void Register() 
 		{
-			spikiness.Value = aquityValue;
-			subdivs.Value = subdivsValue;
 			spikiness.ValueChanged += ValueChanged;
 			subdivs.ValueChanged += ValueChanged;
+			angle.ValueChanged += ValueChanged;
 
+			General.Interface.AddButton(continuousdrawing);
+			General.Interface.AddButton(toolStripSeparator1);
 			General.Interface.AddButton(subdivslabel);
 			General.Interface.AddButton(subdivs);
 			General.Interface.AddButton(spikinesslabel);
 			General.Interface.AddButton(spikiness);
+			General.Interface.AddButton(anglelabel);
+			General.Interface.AddButton(angle);
 			General.Interface.AddButton(reset);
 		}
 
 		public void Unregister() 
 		{
 			General.Interface.RemoveButton(reset);
+			General.Interface.RemoveButton(angle);
+			General.Interface.RemoveButton(anglelabel);
 			General.Interface.RemoveButton(spikiness);
 			General.Interface.RemoveButton(spikinesslabel);
 			General.Interface.RemoveButton(subdivs);
 			General.Interface.RemoveButton(subdivslabel);
+			General.Interface.RemoveButton(toolStripSeparator1);
+			General.Interface.RemoveButton(continuousdrawing);
 		}
 
 		private void ValueChanged(object sender, EventArgs e) 
 		{
-			aquityValue = (int)spikiness.Value;
-			subdivsValue = (int)subdivs.Value;
-			if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
+			if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
 		}
 
 		private void reset_Click(object sender, EventArgs e) 
 		{
-			blockEvents = true;
+			// Reset values
+			blockevents = true;
 			spikiness.Value = 0;
-			blockEvents = false;
-			subdivs.Value = subdivs.Minimum;
+			angle.Value = 0;
+			subdivs.Value = 6;
+			blockevents = false;
+
+			// Dispatch event
+			OnValueChanged(this, EventArgs.Empty);
+		}
+
+		private void continuousdrawing_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty);
 		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs
index 368897f699393f69dc7dd81879151483b8da2ac6..ad2e5fd57cf72d4878b2f074b8cba52c9b0b896a 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs
@@ -29,8 +29,9 @@
 		private void InitializeComponent() 
 		{
 			this.groupBox1 = new System.Windows.Forms.GroupBox();
+			this.gridlockmode = new System.Windows.Forms.ComboBox();
+			this.label5 = new System.Windows.Forms.Label();
 			this.triangulate = new System.Windows.Forms.CheckBox();
-			this.gridlock = new System.Windows.Forms.CheckBox();
 			this.reset = new System.Windows.Forms.Button();
 			this.slicesV = new System.Windows.Forms.NumericUpDown();
 			this.slicesH = new System.Windows.Forms.NumericUpDown();
@@ -41,18 +42,22 @@
 			this.interphmode = new System.Windows.Forms.ComboBox();
 			this.label3 = new System.Windows.Forms.Label();
 			this.label4 = new System.Windows.Forms.Label();
+			this.groupBox3 = new System.Windows.Forms.GroupBox();
+			this.continuousdrawing = new System.Windows.Forms.CheckBox();
 			this.groupBox1.SuspendLayout();
 			((System.ComponentModel.ISupportInitialize)(this.slicesV)).BeginInit();
 			((System.ComponentModel.ISupportInitialize)(this.slicesH)).BeginInit();
 			this.groupBox2.SuspendLayout();
+			this.groupBox3.SuspendLayout();
 			this.SuspendLayout();
 			// 
 			// groupBox1
 			// 
 			this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
 						| System.Windows.Forms.AnchorStyles.Right)));
+			this.groupBox1.Controls.Add(this.gridlockmode);
+			this.groupBox1.Controls.Add(this.label5);
 			this.groupBox1.Controls.Add(this.triangulate);
-			this.groupBox1.Controls.Add(this.gridlock);
 			this.groupBox1.Controls.Add(this.reset);
 			this.groupBox1.Controls.Add(this.slicesV);
 			this.groupBox1.Controls.Add(this.slicesH);
@@ -65,6 +70,32 @@
 			this.groupBox1.TabStop = false;
 			this.groupBox1.Text = " Number of slices: ";
 			// 
+			// gridlockmode
+			// 
+			this.gridlockmode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+						| System.Windows.Forms.AnchorStyles.Right)));
+			this.gridlockmode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+			this.gridlockmode.FormattingEnabled = true;
+			this.gridlockmode.Items.AddRange(new object[] {
+            "None",
+            "Horizontal",
+            "Vertical",
+            "Both"});
+			this.gridlockmode.Location = new System.Drawing.Point(118, 77);
+			this.gridlockmode.Name = "gridlockmode";
+			this.gridlockmode.Size = new System.Drawing.Size(76, 21);
+			this.gridlockmode.TabIndex = 16;
+			this.gridlockmode.SelectedIndexChanged += new System.EventHandler(this.gridlockmode_SelectedIndexChanged);
+			// 
+			// label5
+			// 
+			this.label5.AutoSize = true;
+			this.label5.Location = new System.Drawing.Point(17, 80);
+			this.label5.Name = "label5";
+			this.label5.Size = new System.Drawing.Size(95, 13);
+			this.label5.TabIndex = 15;
+			this.label5.Text = "Lock slices to grid:";
+			// 
 			// triangulate
 			// 
 			this.triangulate.AutoSize = true;
@@ -76,17 +107,6 @@
 			this.triangulate.UseVisualStyleBackColor = true;
 			this.triangulate.CheckedChanged += new System.EventHandler(this.ValueChanged);
 			// 
-			// gridlock
-			// 
-			this.gridlock.AutoSize = true;
-			this.gridlock.Location = new System.Drawing.Point(20, 80);
-			this.gridlock.Name = "gridlock";
-			this.gridlock.Size = new System.Drawing.Size(111, 17);
-			this.gridlock.TabIndex = 13;
-			this.gridlock.Text = "Lock slices to grid";
-			this.gridlock.UseVisualStyleBackColor = true;
-			this.gridlock.CheckedChanged += new System.EventHandler(this.gridlock_CheckedChanged);
-			// 
 			// reset
 			// 
 			this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset;
@@ -190,20 +210,46 @@
 			this.label4.TabIndex = 15;
 			this.label4.Text = "Horizontal";
 			// 
+			// groupBox3
+			// 
+			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.continuousdrawing);
+			this.groupBox3.Location = new System.Drawing.Point(3, 225);
+			this.groupBox3.Name = "groupBox3";
+			this.groupBox3.Size = new System.Drawing.Size(200, 55);
+			this.groupBox3.TabIndex = 11;
+			this.groupBox3.TabStop = false;
+			this.groupBox3.Text = "Additional options";
+			// 
+			// continuousdrawing
+			// 
+			this.continuousdrawing.AutoSize = true;
+			this.continuousdrawing.Location = new System.Drawing.Point(20, 24);
+			this.continuousdrawing.Name = "continuousdrawing";
+			this.continuousdrawing.Size = new System.Drawing.Size(119, 17);
+			this.continuousdrawing.TabIndex = 15;
+			this.continuousdrawing.Text = "Continuous drawing";
+			this.continuousdrawing.UseVisualStyleBackColor = true;
+			this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged);
+			// 
 			// DrawGridOptionsPanel
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+			this.Controls.Add(this.groupBox3);
 			this.Controls.Add(this.groupBox2);
 			this.Controls.Add(this.groupBox1);
 			this.Name = "DrawGridOptionsPanel";
-			this.Size = new System.Drawing.Size(206, 299);
+			this.Size = new System.Drawing.Size(206, 426);
 			this.groupBox1.ResumeLayout(false);
 			this.groupBox1.PerformLayout();
 			((System.ComponentModel.ISupportInitialize)(this.slicesV)).EndInit();
 			((System.ComponentModel.ISupportInitialize)(this.slicesH)).EndInit();
 			this.groupBox2.ResumeLayout(false);
 			this.groupBox2.PerformLayout();
+			this.groupBox3.ResumeLayout(false);
+			this.groupBox3.PerformLayout();
 			this.ResumeLayout(false);
 
 		}
@@ -212,7 +258,6 @@
 
 		private System.Windows.Forms.GroupBox groupBox1;
 		private System.Windows.Forms.CheckBox triangulate;
-		private System.Windows.Forms.CheckBox gridlock;
 		private System.Windows.Forms.Button reset;
 		private System.Windows.Forms.NumericUpDown slicesV;
 		private System.Windows.Forms.NumericUpDown slicesH;
@@ -223,5 +268,9 @@
 		private System.Windows.Forms.ComboBox interphmode;
 		private System.Windows.Forms.Label label3;
 		private System.Windows.Forms.Label label4;
+		private System.Windows.Forms.GroupBox groupBox3;
+		private System.Windows.Forms.CheckBox continuousdrawing;
+		private System.Windows.Forms.ComboBox gridlockmode;
+		private System.Windows.Forms.Label label5;
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs
index a9d2f72e3c1f435389523190d32dfa63e7d5c899..f9476fc7835e457b0c786dc31147f64482ee6f13 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs
@@ -1,29 +1,42 @@
 using System;
 using System.Windows.Forms;
-using CodeImp.DoomBuilder.Geometry;
+using InterpolationMode = CodeImp.DoomBuilder.Geometry.InterpolationTools.Mode;
+using GridLockMode = CodeImp.DoomBuilder.BuilderModes.DrawGridMode.GridLockMode;
 
 namespace CodeImp.DoomBuilder.BuilderModes
 {
 	internal partial class DrawGridOptionsPanel : UserControl
 	{
 		public event EventHandler OnValueChanged;
-		public event EventHandler OnGridLockChanged;
+		public event EventHandler OnGridLockModeChanged;
+		public event EventHandler OnContinuousDrawingChanged;
 		private bool blockevents;
 
 		public bool Triangulate { get { return triangulate.Checked; } set { blockevents = true; triangulate.Checked = value; blockevents = false; } }
-		public bool LockToGrid { get { return gridlock.Checked; } set { blockevents = true; gridlock.Checked = value; blockevents = false; } }
+		public GridLockMode GridLockMode { get { return (GridLockMode)gridlockmode.SelectedIndex; } set { blockevents = true; gridlockmode.SelectedIndex = (int)value; blockevents = false; } }
 		public int HorizontalSlices { get { return (int)slicesH.Value; } set { blockevents = true; slicesH.Value = value; blockevents = false; } }
 		public int MaxHorizontalSlices { get { return (int)slicesH.Maximum; } set { slicesH.Maximum = value; } }
 		public int VerticalSlices { get { return (int)slicesV.Value; } set { blockevents = true; slicesV.Value = value; blockevents = false; } }
 		public int MaxVerticalSlices { get { return (int)slicesV.Maximum; } set { slicesV.Maximum = value; } }
-		public InterpolationTools.Mode HorizontalInterpolationMode 
+		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
+		public InterpolationMode HorizontalInterpolationMode 
 		{
-			get { return gridlock.Checked ? InterpolationTools.Mode.LINEAR : (InterpolationTools.Mode)interphmode.SelectedIndex; }
+			get
+			{
+				GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex;
+				return (mode == GridLockMode.BOTH || mode == GridLockMode.HORIZONTAL) 
+					? InterpolationMode.LINEAR : (InterpolationMode)interphmode.SelectedIndex;
+			}
 			set { interphmode.SelectedIndex = (int)value; }
 		}
-		public InterpolationTools.Mode VerticalInterpolationMode 
+		public InterpolationMode VerticalInterpolationMode 
 		{
-			get { return gridlock.Checked ? InterpolationTools.Mode.LINEAR : (InterpolationTools.Mode)interpvmode.SelectedIndex; }
+			get
+			{
+				GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex;
+				return (mode == GridLockMode.BOTH || mode == GridLockMode.VERTICAL) 
+					? InterpolationMode.LINEAR : (InterpolationMode)interpvmode.SelectedIndex;
+			}
 			set { interpvmode.SelectedIndex = (int)value; }
 		}
 
@@ -43,15 +56,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
 		}
 
-		private void gridlock_CheckedChanged(object sender, EventArgs e)
+		private void gridlockmode_SelectedIndexChanged(object sender, EventArgs e)
 		{
-			slicesH.Enabled = !gridlock.Checked;
-			slicesV.Enabled = !gridlock.Checked;
-			interpvmode.Enabled = !gridlock.Checked;
-			interphmode.Enabled = !gridlock.Checked;
-			reset.Enabled = !gridlock.Checked;
-
-			if(!blockevents && OnGridLockChanged != null) OnGridLockChanged(this, EventArgs.Empty);
+			GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex;
+			slicesH.Enabled = (mode == GridLockMode.NONE || mode == GridLockMode.VERTICAL);
+			slicesV.Enabled = (mode == GridLockMode.NONE || mode == GridLockMode.HORIZONTAL);
+			interphmode.Enabled = slicesH.Enabled;
+			interpvmode.Enabled = slicesV.Enabled;
+			reset.Enabled = (mode != GridLockMode.BOTH);
+			
+			if(!blockevents && OnGridLockModeChanged != null) OnGridLockModeChanged(this, EventArgs.Empty);
 		}
 
 		private void interpmode_DropDownClosed(object sender, EventArgs e) 
@@ -61,12 +75,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		private void reset_Click(object sender, EventArgs e)
 		{
+			GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex;
+			
 			blockevents = true;
-			slicesH.Value = 3;
-			slicesV.Value = 3;
+			if((mode == GridLockMode.NONE || mode == GridLockMode.VERTICAL)) slicesH.Value = 3;
+			if(mode == GridLockMode.NONE || mode == GridLockMode.HORIZONTAL) slicesV.Value = 3;
 			blockevents = false;
 
 			if(OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
 		}
+
+		private void continuousdrawing_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty);
+		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af61aca311e5b07ea8b810d3f9afb9df4a254465
--- /dev/null
+++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs
@@ -0,0 +1,75 @@
+namespace CodeImp.DoomBuilder.BuilderModes
+{
+	partial class DrawLineOptionsPanel
+	{
+		/// <summary> 
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.IContainer components = null;
+
+		/// <summary> 
+		/// Clean up any resources being used.
+		/// </summary>
+		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+		protected override void Dispose(bool disposing)
+		{
+			if(disposing && (components != null))
+			{
+				components.Dispose();
+			}
+			base.Dispose(disposing);
+		}
+
+		#region Component Designer generated code
+
+		/// <summary> 
+		/// Required method for Designer support - do not modify 
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+			this.continuousdrawing = new System.Windows.Forms.ToolStripButton();
+			this.toolStrip1.SuspendLayout();
+			this.SuspendLayout();
+			// 
+			// toolStrip1
+			// 
+			this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.continuousdrawing});
+			this.toolStrip1.Location = new System.Drawing.Point(0, 0);
+			this.toolStrip1.Name = "toolStrip1";
+			this.toolStrip1.Size = new System.Drawing.Size(200, 25);
+			this.toolStrip1.TabIndex = 8;
+			this.toolStrip1.Text = "toolStrip1";
+			// 
+			// continuousdrawing
+			// 
+			this.continuousdrawing.CheckOnClick = true;
+			this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat;
+			this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.continuousdrawing.Name = "continuousdrawing";
+			this.continuousdrawing.Size = new System.Drawing.Size(135, 22);
+			this.continuousdrawing.Text = "Continuous drawing";
+			this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged);
+			// 
+			// DrawLineOptionsPanel
+			// 
+			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.Controls.Add(this.toolStrip1);
+			this.Name = "DrawLineOptionsPanel";
+			this.Size = new System.Drawing.Size(200, 60);
+			this.toolStrip1.ResumeLayout(false);
+			this.toolStrip1.PerformLayout();
+			this.ResumeLayout(false);
+			this.PerformLayout();
+
+		}
+
+		#endregion
+
+		private System.Windows.Forms.ToolStrip toolStrip1;
+		private System.Windows.Forms.ToolStripButton continuousdrawing;
+	}
+}
diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fbc34259572874728f491ffcfb9bb3564282c11f
--- /dev/null
+++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Windows.Forms;
+
+namespace CodeImp.DoomBuilder.BuilderModes
+{
+	internal partial class DrawLineOptionsPanel : UserControl
+	{
+		public event EventHandler OnContinuousDrawingChanged;
+
+		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
+		
+		public DrawLineOptionsPanel()
+		{
+			InitializeComponent();
+		}
+
+		public void Register()
+		{
+			General.Interface.AddButton(continuousdrawing);
+		}
+
+		public void Unregister()
+		{
+			General.Interface.RemoveButton(continuousdrawing);
+		}
+
+		private void continuousdrawing_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty);
+		}
+	}
+}
diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx
new file mode 100644
index 0000000000000000000000000000000000000000..36f2967b5c1d4c3261b1fba7d66b0b0a4e3033a7
--- /dev/null
+++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
\ No newline at end of file
diff --git a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs
index a86a0f0135c49d79aeffee255cca43adda695cd3..edfc1649d47fae246ca72d5f7dd31d3fd7cd1240 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs
@@ -29,10 +29,12 @@
 		private void InitializeComponent() 
 		{
 			this.toolStrip1 = new System.Windows.Forms.ToolStrip();
+			this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
 			this.radiuslabel = new System.Windows.Forms.ToolStripLabel();
 			this.radius = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
 			this.subdivslabel = new System.Windows.Forms.ToolStripLabel();
 			this.subdivs = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown();
+			this.continuousdrawing = new System.Windows.Forms.ToolStripButton();
 			this.reset = new System.Windows.Forms.ToolStripButton();
 			this.toolStrip1.SuspendLayout();
 			this.SuspendLayout();
@@ -40,6 +42,8 @@
 			// toolStrip1
 			// 
 			this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.continuousdrawing,
+            this.toolStripSeparator1,
             this.radiuslabel,
             this.radius,
             this.subdivslabel,
@@ -47,15 +51,19 @@
             this.reset});
 			this.toolStrip1.Location = new System.Drawing.Point(0, 0);
 			this.toolStrip1.Name = "toolStrip1";
-			this.toolStrip1.Size = new System.Drawing.Size(380, 25);
+			this.toolStrip1.Size = new System.Drawing.Size(488, 25);
 			this.toolStrip1.TabIndex = 7;
 			this.toolStrip1.Text = "toolStrip1";
 			// 
+			// toolStripSeparator1
+			// 
+			this.toolStripSeparator1.Name = "toolStripSeparator1";
+			this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
+			// 
 			// radiuslabel
 			// 
-			this.radiuslabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear;
 			this.radiuslabel.Name = "radiuslabel";
-			this.radiuslabel.Size = new System.Drawing.Size(92, 22);
+			this.radiuslabel.Size = new System.Drawing.Size(76, 22);
 			this.radiuslabel.Text = "Bevel Radius:";
 			// 
 			// radius
@@ -112,6 +120,16 @@
             0});
 			this.subdivs.ValueChanged += new System.EventHandler(this.ValueChanged);
 			// 
+			// continuousdrawing
+			// 
+			this.continuousdrawing.CheckOnClick = true;
+			this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat;
+			this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.continuousdrawing.Name = "continuousdrawing";
+			this.continuousdrawing.Size = new System.Drawing.Size(135, 22);
+			this.continuousdrawing.Text = "Continuous drawing";
+			this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged);
+			// 
 			// reset
 			// 
 			this.reset.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
@@ -128,7 +146,7 @@
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
 			this.Controls.Add(this.toolStrip1);
 			this.Name = "DrawRectangleOptionsPanel";
-			this.Size = new System.Drawing.Size(380, 60);
+			this.Size = new System.Drawing.Size(488, 60);
 			this.toolStrip1.ResumeLayout(false);
 			this.toolStrip1.PerformLayout();
 			this.ResumeLayout(false);
@@ -144,5 +162,7 @@
 		private System.Windows.Forms.ToolStripLabel subdivslabel;
 		private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown subdivs;
 		private System.Windows.Forms.ToolStripButton reset;
+		private System.Windows.Forms.ToolStripButton continuousdrawing;
+		private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs
index c885ea33804790aab8783a1071dbcc7cfbfe96ad..bb4f638729c2f670329da6ed3a401fd80a7ad8fe 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs
@@ -6,17 +6,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 	internal partial class DrawRectangleOptionsPanel : UserControl
 	{
 		public event EventHandler OnValueChanged;
-		private bool blockEvents;
+		public event EventHandler OnContinuousDrawingChanged;
+		private bool blockevents;
 
-		private static int radiusValue;
-		private static int subdivsValue;
-
-		public int BevelWidth { get { return (int)radius.Value; } set { blockEvents = true; radius.Value = value; blockEvents = false; } }
+		public int BevelWidth { get { return (int)radius.Value; } set { blockevents = true; radius.Value = value; blockevents = false; } }
 		public int MaxBevelWidth { get { return (int)radius.Maximum; } set { radius.Maximum = value; } }
 		public int MinBevelWidth { get { return (int)radius.Minimum; } set { radius.Minimum = value; } }
-		public int Subdivisions { get { return (int)subdivs.Value; } set { blockEvents = true; subdivs.Value = value; blockEvents = false; } }
+		public int Subdivisions { get { return (int)subdivs.Value; } set { blockevents = true; subdivs.Value = value; blockevents = false; } }
 		public int MaxSubdivisions { get { return (int)subdivs.Maximum; } set { subdivs.Maximum = value; } }
 		public int MinSubdivisions { get { return (int)subdivs.Minimum; } set { subdivs.Minimum = value; } }
+		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
 
 		public DrawRectangleOptionsPanel() 
 		{
@@ -25,11 +24,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		public void Register() 
 		{
-			radius.Value = radiusValue;
-			subdivs.Value = subdivsValue;
 			radius.ValueChanged += ValueChanged;
 			subdivs.ValueChanged += ValueChanged;
 
+			General.Interface.AddButton(continuousdrawing);
+			General.Interface.AddButton(toolStripSeparator1);
 			General.Interface.AddButton(radiuslabel);
 			General.Interface.AddButton(radius);
 			General.Interface.AddButton(subdivslabel);
@@ -44,22 +43,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Interface.RemoveButton(subdivslabel);
 			General.Interface.RemoveButton(radius);
 			General.Interface.RemoveButton(radiuslabel);
+			General.Interface.RemoveButton(toolStripSeparator1);
+			General.Interface.RemoveButton(continuousdrawing);
 		}
 
 		private void ValueChanged(object sender, EventArgs e) 
 		{
-			radiusValue = (int)radius.Value;
-			subdivsValue = (int)subdivs.Value;
-			if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
+			if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty);
 		}
 
 		private void reset_Click(object sender, EventArgs e) 
 		{
-			blockEvents = true;
+			// Reset values
+			blockevents = true;
 			radius.Value = 0;
-			blockEvents = false;
 			subdivs.Value = 0;
+			blockevents = false;
+
+			// Dispatch event
+			OnValueChanged(this, EventArgs.Empty);
 		}
 
+		private void continuousdrawing_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty);
+		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs b/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs
index a782ef92c5ca5a5e0894af6ac4a5813bb6906c35..f0dabd2aef2cace61766e8dfe188db1fc80977e4 100644
--- a/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs
+++ b/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs
@@ -330,16 +330,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					catch(TargetInvocationException ex)
 					{
 						// Error!
-						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'");
+						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\"");
 						General.WriteLogLine(ex.InnerException.GetType().Name + ": " + ex.InnerException.Message);
-						throw ex;
+						throw;
 					}
 					catch(Exception ex)
 					{
 						// Error!
-						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'");
+						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\"");
 						General.WriteLogLine(ex.GetType().Name + ": " + ex.Message);
-						throw ex;
+						throw;
 					}
 					
 					// Add to list
@@ -749,7 +749,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			foreach(ErrorResult result in results.SelectedItems) sb.AppendLine(result.ToString());
 
 			// Set on clipboard
-			Clipboard.SetText(sb.ToString());
+			Clipboard.SetDataObject(sb.ToString(), true, 5, 200); //mxd
 
 			// Inform the user
 			General.Interface.DisplayStatus(StatusType.Info, "Analysis results copied to clipboard.");
diff --git a/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs b/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs
index 83c7d8418752b65c4075b65634b3102e7f5ce645..789112fa47269c5515c061af3576a19282e5b36e 100644
--- a/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs
+++ b/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs
@@ -80,14 +80,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					catch(TargetInvocationException ex)
 					{
 						// Error!
-						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'");
+						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\"");
 						General.WriteLogLine(ex.InnerException.GetType().Name + ": " + ex.InnerException.Message);
 						throw;
 					}
 					catch(Exception ex)
 					{
 						// Error!
-						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'");
+						General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\"");
 						General.WriteLogLine(ex.GetType().Name + ": " + ex.Message);
 						throw;
 					}
@@ -151,7 +151,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Browse replacement clicked
 		private void browsereplace_Click(object sender, EventArgs e)
 		{
-			replaceinput.Text = newfinder.Browse(replaceinput.Text);
+			replaceinput.Text = newfinder.BrowseReplace(replaceinput.Text);
 		}
 
 		//mxd
diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
index c61aee09f6101f0a1ebe27604ae0ad4951218b39..2b1741aa02f41bd0732493f29eb0cc7946338d5c 100644
--- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
@@ -263,9 +263,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.autodrawonedit.AutoSize = true;
 			this.autodrawonedit.Location = new System.Drawing.Point(13, 24);
 			this.autodrawonedit.Name = "autodrawonedit";
-			this.autodrawonedit.Size = new System.Drawing.Size(346, 17);
+			this.autodrawonedit.Size = new System.Drawing.Size(353, 30);
 			this.autodrawonedit.TabIndex = 11;
-			this.autodrawonedit.Text = "Start drawing when Edit pressed over empty space in Classic modes";
+			this.autodrawonedit.Text = "Start drawing when Edit pressed over empty space in Classic modes\r\nInsert new thi" +
+				"ng when Edit pressed over empty space in Things mode";
 			this.autodrawonedit.UseVisualStyleBackColor = true;
 			// 
 			// syncSelection
@@ -331,7 +332,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// editnewthing
 			// 
 			this.editnewthing.AutoSize = true;
-			this.editnewthing.Location = new System.Drawing.Point(13, 49);
+			this.editnewthing.Location = new System.Drawing.Point(13, 62);
 			this.editnewthing.Name = "editnewthing";
 			this.editnewthing.Size = new System.Drawing.Size(248, 17);
 			this.editnewthing.TabIndex = 1;
@@ -341,7 +342,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// editnewsector
 			// 
 			this.editnewsector.AutoSize = true;
-			this.editnewsector.Location = new System.Drawing.Point(13, 74);
+			this.editnewsector.Location = new System.Drawing.Point(13, 87);
 			this.editnewsector.Name = "editnewsector";
 			this.editnewsector.Size = new System.Drawing.Size(258, 17);
 			this.editnewsector.TabIndex = 2;
@@ -351,7 +352,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// additiveselect
 			// 
 			this.additiveselect.AutoSize = true;
-			this.additiveselect.Location = new System.Drawing.Point(13, 99);
+			this.additiveselect.Location = new System.Drawing.Point(13, 112);
 			this.additiveselect.Name = "additiveselect";
 			this.additiveselect.Size = new System.Drawing.Size(205, 17);
 			this.additiveselect.TabIndex = 3;
diff --git a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
index aa41c515c659b607e67c57009f21eb55648df8da..b86a96466bb45f8c2d9ff5ba4998741678d1444c 100644
--- a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
+++ b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
@@ -1,10 +1,10 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
-//     Dieser Code wurde von einem Tool generiert.
-//     Laufzeitversion:4.0.30319.42000
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
 //
-//     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
-//     der Code erneut generiert wird.
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
 // </auto-generated>
 //------------------------------------------------------------------------------
 
@@ -13,13 +13,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
     
     
     /// <summary>
-    ///   Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
     /// </summary>
-    // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
-    // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
-    // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
-    // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     internal class Resources {
@@ -33,7 +33,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+        ///   Returns the cached ResourceManager instance used by this class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
         internal static global::System.Resources.ResourceManager ResourceManager {
@@ -47,8 +47,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
-        ///   Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
         internal static global::System.Globalization.CultureInfo Culture {
@@ -61,7 +61,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap AlignThings {
             get {
@@ -71,7 +71,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Angle {
             get {
@@ -81,7 +81,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap BrightnessGradient {
             get {
@@ -91,7 +91,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap CeilingAlign {
             get {
@@ -101,7 +101,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap CeilsGradient {
             get {
@@ -111,7 +111,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap ColorPick {
             get {
@@ -121,7 +121,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Copy {
             get {
@@ -131,7 +131,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap CopyProperties {
             get {
@@ -141,7 +141,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap CurveLines {
             get {
@@ -151,7 +151,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Door {
             get {
@@ -161,7 +161,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap DrawCurveMode {
             get {
@@ -171,7 +171,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap DrawEllipseMode {
             get {
@@ -181,7 +181,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap DrawGeometryMode {
             get {
@@ -191,7 +191,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap DrawGridMode {
             get {
@@ -201,7 +201,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap DrawRectangleMode {
             get {
@@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap FilterThings {
             get {
@@ -221,7 +221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Flip {
             get {
@@ -231,7 +231,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap FlipSelectionH {
             get {
@@ -241,7 +241,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap FlipSelectionV {
             get {
@@ -251,7 +251,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap FloorAlign {
             get {
@@ -261,7 +261,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap FloorsGradient {
             get {
@@ -271,7 +271,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Folder {
             get {
@@ -281,7 +281,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Gear {
             get {
@@ -291,7 +291,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Hide {
             get {
@@ -301,7 +301,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap HideAll {
             get {
@@ -311,7 +311,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap InsertThingsRadiallyMode {
             get {
@@ -321,7 +321,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Join {
             get {
@@ -331,7 +331,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap List {
             get {
@@ -341,7 +341,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap List_Images {
             get {
@@ -351,7 +351,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Merge {
             get {
@@ -361,7 +361,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap PasteProperties {
             get {
@@ -371,7 +371,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap PastePropertiesOptions {
             get {
@@ -381,7 +381,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap PlaceThings {
             get {
@@ -391,7 +391,17 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap Repeat {
+            get {
+                object obj = ResourceManager.GetObject("Repeat", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Reset {
             get {
@@ -401,7 +411,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Save {
             get {
@@ -411,7 +421,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap SelectThingsInSectors {
             get {
@@ -421,7 +431,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap SelectTouching {
             get {
@@ -431,7 +441,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Show {
             get {
@@ -441,7 +451,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Show2 {
             get {
@@ -451,7 +461,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Show3 {
             get {
@@ -461,7 +471,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Similar {
             get {
@@ -471,7 +481,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap Text {
             get {
@@ -481,7 +491,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap TextureLock {
             get {
@@ -491,7 +501,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap ThingPointAtCursor {
             get {
@@ -501,7 +511,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap treeview {
             get {
@@ -511,7 +521,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap ViewSelectionEffects {
             get {
@@ -521,7 +531,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap ViewSelectionIndex {
             get {
@@ -531,7 +541,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
         }
         
         /// <summary>
-        ///   Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
         internal static System.Drawing.Bitmap VisualModeGZ {
             get {
diff --git a/Source/Plugins/BuilderModes/Properties/Resources.resx b/Source/Plugins/BuilderModes/Properties/Resources.resx
index 5ee3b44dece846c6553bd7eb63dfc37a8b0ba6b6..5d591af10daa23c3e4c7dd9d76bbf8552a2d34b1 100644
--- a/Source/Plugins/BuilderModes/Properties/Resources.resx
+++ b/Source/Plugins/BuilderModes/Properties/Resources.resx
@@ -118,9 +118,6 @@
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
-  <data name="Join" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Join.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
-  </data>
   <data name="FloorAlign" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\FloorAlign.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -139,9 +136,6 @@
   <data name="ViewSelectionEffects" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ViewSelectionEffects.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Gear" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Gear.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
-  </data>
   <data name="HideAll" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\HideAll.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -196,12 +190,12 @@
   <data name="ThingPointAtCursor" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ThingPointAtCursor.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
-  </data>
   <data name="Text" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Text.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="Show" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Show.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
   <data name="BrightnessGradient" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\BrightnessGradient.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -217,8 +211,8 @@
   <data name="Reset" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Reset.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Show" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Show.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="Join" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Join.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="ViewSelectionIndex" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ViewSelectionIndex.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -229,6 +223,9 @@
   <data name="Show2" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Show2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
   <data name="ColorPick" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ColorPick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -238,8 +235,8 @@
   <data name="FlipSelectionH" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\FlipSelectionH.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="Angle" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Angle.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -262,4 +259,10 @@
   <data name="InsertThingsRadiallyMode" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\InsertThingsRadiallyMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="Gear" type="System.Resources.ResXFileRef, System.Windows.Forms">
+	<value>..\Resources\Gear.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="Repeat" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Repeat.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
\ No newline at end of file
diff --git a/Source/Plugins/BuilderModes/Resources/Repeat.png b/Source/Plugins/BuilderModes/Resources/Repeat.png
new file mode 100644
index 0000000000000000000000000000000000000000..48350331c3025d345424a05147edaa22ea0ad025
Binary files /dev/null and b/Source/Plugins/BuilderModes/Resources/Repeat.png differ
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
index bdd272784e2bdcbc149b9e87b5c05d46a91f709e..3d33932b666bef31548da483175d457c7579f48d 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
@@ -801,7 +801,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Apply Texture
 		public virtual void ApplyTexture(string texture)
 		{
-			mode.CreateUndo("Change flat '" + texture + "'");
+			mode.CreateUndo("Change flat \"" + texture + "\"");
 			SetTexture(texture);
 			OnTextureChanged(); //mxd
 		}
@@ -813,7 +813,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			string texturename = ((General.Map.Options.UseLongTextureNames && Texture != null && Texture.UsedInMap) ? Texture.Name : GetTextureName());
 			BuilderPlug.Me.CopiedFlat = texturename;
 			if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedTexture = texturename;
-			mode.SetActionResult("Copied flat '" + texturename + "'.");
+			mode.SetActionResult("Copied flat \"" + texturename + "\".");
 		}
 		
 		public virtual void OnPasteTexture() { }
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
index 6ae07697a7ce65113eb399082718a6920ad78f57..2b72450032aa237b8dee42662cb7abbe7228ab22 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
@@ -1186,10 +1186,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(BuilderPlug.Me.CopiedTexture != null)
 			{
-				mode.CreateUndo("Paste texture '" + BuilderPlug.Me.CopiedTexture + "'");
-				mode.SetActionResult("Pasted texture '" + BuilderPlug.Me.CopiedTexture + "'.");
+				mode.CreateUndo("Paste texture \"" + BuilderPlug.Me.CopiedTexture + "\"");
+				mode.SetActionResult("Pasted texture \"" + BuilderPlug.Me.CopiedTexture + "\".");
 				SetTexture(BuilderPlug.Me.CopiedTexture);
-				OnTextureChanged();//mxd
+				OnTextureChanged(); //mxd
 			}
 		}
 		
@@ -1221,7 +1221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			string texturename = ((General.Map.Options.UseLongTextureNames && Texture != null && Texture.UsedInMap) ? Texture.Name : GetTextureName());
 			BuilderPlug.Me.CopiedTexture = texturename;
 			if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedFlat = texturename;
-			mode.SetActionResult("Copied texture '" + texturename + "'.");
+			mode.SetActionResult("Copied texture \"" + texturename + "\".");
 		}
 		
 		// Copy texture offsets
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index a1ebc44259b70bb7cb9b51e974cbe92a06b8afab..b9db85e16f0159adee8cbe60c3adf9f77eb1507b 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -517,6 +517,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This updates the VisualSectors and VisualThings that have their Changed property set
 		private void UpdateChangedObjects()
 		{
+			//mxd
+			SectorData[] toupdate = new SectorData[sectordata.Values.Count];
+			sectordata.Values.CopyTo(toupdate, 0);
+			foreach(SectorData data in toupdate) data.Update();
+			
 			foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
 			{
 				if(vs.Value != null)
@@ -1538,8 +1543,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// and uses the marks to check what needs to be reloaded.
 		protected override void ResourcesReloadedPartial()
 		{
-			bool sectorsmarked = false;
-			
 			if(General.Map.UndoRedo.GeometryChanged)
 			{
 				// Let the core do this (it will just dispose the sectors that were changed)
@@ -1547,6 +1550,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			}
 			else
 			{
+				bool sectorsmarked = false;
+				
 				// Neighbour sectors must be updated as well
 				foreach(Sector s in General.Map.Map.Sectors)
 				{
@@ -1578,7 +1583,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if(s.Marked)
 					{
 						SectorData sd = GetSectorData(s);
-						sd.Reset();
+						sd.Reset(false); //mxd (changed Reset implementation)
 						
 						// UpdateSectorGeometry for associated sectors (sd.UpdateAlso) as well!
 						foreach(KeyValuePair<Sector, bool> us in sd.UpdateAlso)
@@ -1603,8 +1608,22 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					// No sectors or geometry changed. So we only have
 					// to update things when they have changed.
+					HashSet<Thing> toremove = new HashSet<Thing>(); //mxd
 					foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
-						if((vt.Value != null) && vt.Key.Marked) (vt.Value as BaseVisualThing).Rebuild();
+					{
+						if((vt.Value != null) && vt.Key.Marked)
+						{
+							if(vt.Key.IsDisposed) toremove.Add(vt.Key); //mxd. Disposed things will cause problems
+							else (vt.Value as BaseVisualThing).Rebuild();
+						}
+					}
+
+					//mxd. Remove disposed things
+					foreach(Thing t in toremove)
+					{
+						if(allthings[t] != null) allthings[t].Dispose();
+						allthings.Remove(t);
+					}
 				}
 				else
 				{
@@ -3011,7 +3030,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			renderer.SetCrosshairBusy(true);
 			General.Interface.RedrawDisplay();
 			GetTargetEventReceiver(false).OnSelectTexture();
-			UpdateChangedObjects();
 			RebuildElementData(); //mxd. Extrafloors or Glow effects may've been changed
 			renderer.SetCrosshairBusy(false);
 			PostAction();
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
index d28640a66af42c8c63b4b4df92f1194e02097c9b..cc06ba6703b405c3f4b244b390a1a9687df32a0c 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
@@ -35,14 +35,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Variables
 		
-		private BaseVisualMode mode;
+		private readonly BaseVisualMode mode;
 
 		private VisualFloor floor;
 		private VisualCeiling ceiling;
 		private List<VisualFloor> extrafloors;
 		private List<VisualCeiling> extraceilings;
-		private List<VisualFloor> extrabackfloors; //mxd
-		private List<VisualCeiling> extrabackceilings; //mxd
+		private readonly List<VisualFloor> extrabackfloors; //mxd
+		private readonly List<VisualCeiling> extrabackceilings; //mxd
 		private Dictionary<Sidedef, VisualSidedefParts> sides;
 		
 		// If this is set to true, the sector will be rebuilt after the action is performed.
@@ -121,16 +121,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			changed = true;
 			
 			// Not sure what from this part we need, so commented out for now
-			SectorData data = GetSectorData();
-			data.Reset();
-			
-			// Update sectors that rely on this sector
-			foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso)
+			SectorData data = mode.GetSectorDataEx(this.Sector); //mxd
+			if(data != null) //mxd
 			{
-				if(mode.VisualSectorExists(s.Key))
+				data.Reset(includeneighbours);
+
+				// Update sectors that rely on this sector
+				foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso)
 				{
-					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
-					vs.UpdateSectorGeometry(s.Value);
+					if(mode.VisualSectorExists(s.Key))
+					{
+						BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
+						vs.Changed = true;
+					}
 				}
 			}
 			
diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
index 22349e7f98546037ae25dd45833ad2f094747637..03ea37e64b99ee146508747871cf0a92ab8df228 100644
--- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
@@ -113,6 +113,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			Effect3DFloor e = new Effect3DFloor(this, sourcelinedef);
 			extrafloors.Add(e);
 			alleffects.Add(e);
+
+			//mxd. Extrafloor neighbours should be updated when extrafloor is changed
+			foreach(Sidedef sd in this.Sector.Sidedefs)
+			{
+				if(sd.Other != null && sd.Other.Sector != null)
+					AddUpdateSector(sd.Other.Sector, false);
+			}
 		}
 		
 		// Brightness level effect
@@ -214,7 +221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 		
 		// This resets this sector data and all sectors that require updating after me
-		public void Reset()
+		/*public void Reset()
 		{
 			if(isupdating) return;
 			isupdating = true;
@@ -236,6 +243,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				sd.Reset();
 			}
 
+			isupdating = false;
+		}*/
+
+		//mxd. This marks this sector data and all sector datas that require updating as not updated
+		public void Reset(bool resetneighbours)
+		{
+			if(isupdating) return;
+			isupdating = true;
+
+			// This is set to false so that this sector is rebuilt the next time it is needed!
+			updated = false;
+
+			// The visual sector associated is now outdated
+			if(mode.VisualSectorExists(sector))
+			{
+				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector);
+				vs.Changed = true;
+			}
+
+			// Reset the sectors that depend on this sector
+			if(resetneighbours)
+			{
+				foreach(KeyValuePair<Sector, bool> s in updatesectors)
+				{
+					SectorData sd = mode.GetSectorDataEx(s.Key);
+					if(sd != null) sd.Reset(s.Value);
+				}
+			}
+
 			isupdating = false;
 		}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
index f8e206c3fcb00a11bddc8fea5e70ffcc298f8dc9..efb5a88e800e6b1ea6e21d4d7ec4abf756acf615 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
@@ -369,27 +369,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(BuilderPlug.Me.CopiedFlat != null)
 			{
-				mode.CreateUndo("Paste ceiling '" + BuilderPlug.Me.CopiedFlat + "'");
-				mode.SetActionResult("Pasted flat '" + BuilderPlug.Me.CopiedFlat + "' on ceiling.");
-
-				//mxd. Glow effect may require SectorData and geometry update
-				bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture);
+				mode.CreateUndo("Paste ceiling \"" + BuilderPlug.Me.CopiedFlat + "\"");
+				mode.SetActionResult("Pasted flat \"" + BuilderPlug.Me.CopiedFlat + "\" on ceiling.");
 
 				SetTexture(BuilderPlug.Me.CopiedFlat);
 
-				//mxd. Glow effect may require SectorData and geometry update
-				if(prevtextureglows && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture))
-				{
-					SectorData sd = mode.GetSectorData(level.sector);
-					sd.UpdateForced();
-
-					if(mode.VisualSectorExists(level.sector))
-					{
-						BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
-						vs.UpdateSectorGeometry(false);
-					}
-				}
-
 				//mxd. 3D floors may need updating...
 				OnTextureChanged();
 			}
@@ -591,7 +575,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This changes the texture
 		protected override void SetTexture(string texturename)
 		{
+			//mxd. Glow effect may require SectorData and geometry update
+			bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture);
+
+			// Set new texture
 			level.sector.SetCeilTexture(texturename);
+
+			//mxd. Glow effect may require SectorData and geometry update
+			if(prevtextureglows 
+				&& !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture)
+				&& mode.VisualSectorExists(level.sector))
+			{
+				((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true;
+			}
+			
 			General.Map.Data.UpdateUsedTextures();
 		}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
index cd0986355ce63f19a34c81fe8a25c469c8835c82..c0125c0d7838dd31e3072586fcfa3dd971684e30 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
@@ -368,27 +368,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(BuilderPlug.Me.CopiedFlat != null)
 			{
-				mode.CreateUndo("Paste floor '" + BuilderPlug.Me.CopiedFlat + "'");
-				mode.SetActionResult("Pasted flat '" + BuilderPlug.Me.CopiedFlat + "' on floor.");
-
-				//mxd. Glow effect may require SectorData and geometry update
-				bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture);
+				mode.CreateUndo("Paste floor \"" + BuilderPlug.Me.CopiedFlat + "\"");
+				mode.SetActionResult("Pasted flat \"" + BuilderPlug.Me.CopiedFlat + "\" on floor.");
 				
 				SetTexture(BuilderPlug.Me.CopiedFlat);
 
-				//mxd. Glow effect may require SectorData and geometry update
-				if(prevtextureglows && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture))
-				{
-					SectorData sd = mode.GetSectorData(level.sector);
-					sd.UpdateForced();
-
-					if(mode.VisualSectorExists(level.sector))
-					{
-						BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
-						vs.UpdateSectorGeometry(false);
-					}
-				}
-
 				//mxd. 3D floors may need updating...
 				OnTextureChanged();
 			}
@@ -464,12 +448,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				// This floor is part of 3D-floor
 				if(level.sector != Sector.Sector)
-					((BaseVisualSector)mode.GetVisualSector(level.sector)).Floor.OnChangeTargetBrightness(up);
+				{
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+					vs.Floor.OnChangeTargetBrightness(up);
+					vs.UpdateSectorGeometry(true);
+				}
 				// This is actual floor of a sector with extrafloors
 				else if(Sector.ExtraFloors.Count > 0 && !Sector.ExtraFloors[0].ExtraFloor.Floor.restrictlighting && !Sector.ExtraFloors[0].ExtraFloor.Floor.disablelighting)
+				{
 					Sector.ExtraFloors[0].OnChangeTargetBrightness(up);
+				}
 				else
+				{
 					base.OnChangeTargetBrightness(up);
+				}
 			} 
 			else 
 			{
@@ -554,7 +546,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This changes the texture
 		protected override void SetTexture(string texturename)
 		{
+			//mxd. Glow effect may require SectorData and geometry update
+			bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture);
+			
+			// Set new texture
 			level.sector.SetFloorTexture(texturename);
+
+			//mxd. Glow effect may require SectorData and geometry update
+			if(prevtextureglows 
+				&& !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture)
+				&& mode.VisualSectorExists(level.sector))
+			{
+				((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true;
+			}
+
 			General.Map.Data.UpdateUsedTextures();
 		}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs
index d2a2793144aafb2ad4900b80bc2dec69ae1738d2..63f841778b2218a3bb36810005d6af9906c3a701 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs
@@ -240,7 +240,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(polygons.Count > 0)
 			{
 				// Keep top and bottom planes for intersection testing
-				top = osd.Floor.plane;
+				Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's ceiling can be lower than the other sector's floor!
+				top = (osd.Floor.plane.GetZ(linecenter) < sd.Ceiling.plane.GetZ(linecenter) ? osd.Floor.plane : sd.Ceiling.plane);
 				bottom = sd.Floor.plane;
 				
 				// Process the polygon and create vertices
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs
index 5bb646357537f96122723fbe2b03fb9589281108..a281d5f48cac29efbccb486a0145f9ca5e5c24ba 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs
@@ -235,8 +235,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(polygons.Count > 0)
 			{
 				// Keep top and bottom planes for intersection testing
+				Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's floor can be higher than the other sector's ceiling!
 				top = sd.Ceiling.plane;
-				bottom = osd.Ceiling.plane;
+				bottom = (osd.Ceiling.plane.GetZ(linecenter) > sd.Floor.plane.GetZ(linecenter) ? osd.Ceiling.plane : sd.Floor.plane);
 				
 				// Process the polygon and create vertices
 				List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
diff --git a/Source/Plugins/NodesViewer/NodesViewerMode.cs b/Source/Plugins/NodesViewer/NodesViewerMode.cs
index 1552d97a8064b515f94cba5c1ae3c0089ba0067d..45f89e50737206e3ee1d103ce02ca1b1d8d5041a 100644
--- a/Source/Plugins/NodesViewer/NodesViewerMode.cs
+++ b/Source/Plugins/NodesViewer/NodesViewerMode.cs
@@ -244,7 +244,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 					nodesformat = new string(reader.ReadChars(4));
 					if(!supportedFormats.Contains(nodesformat)) 
 					{
-						MessageBox.Show("'" + nodesformat + "' node format is not supported.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
+						MessageBox.Show("\"" + nodesformat + "\" node format is not supported.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
 						return false;
 					}
 
diff --git a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs
index 8ccaab4d07e2dcc32ff326ca4740c3c142d11350..db2b9e84f08c35c193b3c87dc2b0b8f96d809388 100644
--- a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs
+++ b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs
@@ -655,7 +655,7 @@ namespace CodeImp.DoomBuilder.TagExplorer
 					break;
 
 				default:
-					throw new NotImplementedException("Tag Explorer: Sort mode '" + sortMode + "' is not implemented!");
+					throw new NotImplementedException("Tag Explorer: Sort mode \"" + sortMode + "\" is not implemented!");
 			}
 		}
 
diff --git a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
index 783d25a3326e3d0467607afe7e7769a754e521cf..b379f2d594eb00ff8245ccd50345d9d8e970653e 100644
--- a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
+++ b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
@@ -260,7 +260,14 @@ namespace CodeImp.DoomBuilder.Plugins.VisplaneExplorer
 
 			// Export the current map to a temporary WAD file
 			tempfile = BuilderPlug.MakeTempFilename(".wad");
-			General.Map.ExportToFile(tempfile);
+			if(!General.Map.ExportToFile(tempfile))
+			{
+				//mxd. Abort on export fail
+				Cursor.Current = Cursors.Default;
+				General.Interface.DisplayStatus(StatusType.Warning, "Unable to set test environment...");
+				OnCancel();
+				return;
+			}
 
 			// Load the map in VPO_DLL
 			BuilderPlug.VPO.Start(tempfile, General.Map.Options.LevelName);