diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index a4c378f7d..45dab9708 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,20 @@
+April 4, 2008 (Changes by Graf Zahl)
+- Fixed: P_CheckSwitchRange accessed invalid memory when testing a one-sided
+  line.
+- Fixed: P_SpawnPuff assumed that all melee attacks have the same range
+  (MELEERANGE) and didn't set the puff to its melee state if the range
+  was different. Even worse, it checked a global variable for this so
+  the behavior was undefined when P_SpawnPuff was called from anywhere
+  else but P_LineAttack. To reduce the amount of parameters I combined
+  this information with the hitthing and temporary parameters into one
+  flags parameter. Also changed P_LineAttack so that it gets passed
+  an additional parameter that specifies whether the attack is a melee
+  attack or not and set this to true in all calls that are to be considered
+  melee attacks. I couldn't use the damage type because A_CustomPunch
+  and A_CustomMeleeAttack allow passing any damage type they want.
+- Added a sprite option as an alternative of particles for FX_ROCKET 
+  and FX_GRENADE.
+
 April 3, 2008
 - Changed the Makefiles that are used by both Linux and MinGW so that msys
   detection occurs only if $OS is Windows_NT. Otherwise, spurious nul files
diff --git a/src/actor.h b/src/actor.h
index 5623be939..92f9a4685 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -701,6 +701,7 @@ public:
 	//Added by MC:
 	SDWORD id;						// Player ID (for items, # in list.)
 
+	BYTE smokecounter;
 	BYTE FloatBobPhase;
 	BYTE FriendPlayer;				// [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
 	DWORD Translation;
diff --git a/src/am_map.cpp b/src/am_map.cpp
index 5c9009818..132b281e7 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -123,7 +123,6 @@ CVAR (Bool,  am_showitems,			false,		CVAR_ARCHIVE);
 CVAR (Bool,  am_showtime,			true,		CVAR_ARCHIVE);
 CVAR (Bool,  am_showtotaltime,		false,		CVAR_ARCHIVE);
 CVAR (Bool,  am_usecustomcolors,	true,		CVAR_ARCHIVE);
-CVAR (Float, am_ovtrans,			1.f,		CVAR_ARCHIVE);
 CVAR (Color, am_backcolor,			0x6c5440,	CVAR_ARCHIVE);
 CVAR (Color, am_yourcolor,			0xfce8d8,	CVAR_ARCHIVE);
 CVAR (Color, am_wallcolor,			0x2c1808,	CVAR_ARCHIVE);
diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp
index 0cfc408ab..0d343eda0 100644
--- a/src/g_doom/a_doomweaps.cpp
+++ b/src/g_doom/a_doomweaps.cpp
@@ -48,7 +48,7 @@ void A_Punch (AActor *actor)
 
 	angle += pr_punch.Random2() << 18;
 	pitch = P_AimLineAttack (actor, angle, MELEERANGE);
-	P_LineAttack (actor, angle, MELEERANGE, pitch, damage, NAME_None, NAME_BulletPuff);
+	P_LineAttack (actor, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
 
 	// turn to face target
 	if (linetarget)
diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp
index 83aa31312..2126285b4 100644
--- a/src/g_doom/a_scriptedmarine.cpp
+++ b/src/g_doom/a_scriptedmarine.cpp
@@ -456,7 +456,7 @@ void A_M_Punch (AActor *self)
 	A_FaceTarget (self);
 	angle = self->angle + (pr_m_punch.Random2() << 18);
 	pitch = P_AimLineAttack (self, angle, MELEERANGE);
-	P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff);
+	P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
 
 	// turn to face target
 	if (linetarget)
@@ -486,7 +486,7 @@ void A_M_BerserkPunch (AActor *self)
 	A_FaceTarget (self);
 	angle = self->angle + (pr_m_punch.Random2() << 18);
 	pitch = P_AimLineAttack (self, angle, MELEERANGE);
-	P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff);
+	P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true);
 
 	// turn to face target
 	if (linetarget)
diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp
index a9bb7bd24..46243b6da 100644
--- a/src/g_heretic/a_chicken.cpp
+++ b/src/g_heretic/a_chicken.cpp
@@ -412,7 +412,7 @@ void A_BeakAttackPL1 (AActor *actor)
 	damage = 1 + (pr_beakatkpl1()&3);
 	angle = player->mo->angle;
 	slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
-	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff));
+	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff), true);
 	if (linetarget)
 	{
 		player->mo->angle = R_PointToAngle2 (player->mo->x,
@@ -444,7 +444,7 @@ void A_BeakAttackPL2 (AActor *actor)
 	damage = pr_beakatkpl2.HitDice (4);
 	angle = player->mo->angle;
 	slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
-	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff));
+	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ABeakPuff), true);
 	if (linetarget)
 	{
 		player->mo->angle = R_PointToAngle2 (player->mo->x,
diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp
index 0acff0794..b6113dd6d 100644
--- a/src/g_heretic/a_hereticweaps.cpp
+++ b/src/g_heretic/a_hereticweaps.cpp
@@ -217,7 +217,7 @@ void A_StaffAttackPL1 (AActor *actor)
 	angle = player->mo->angle;
 	angle += pr_sap.Random2() << 18;
 	slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
-	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff));
+	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff), true);
 	if (linetarget)
 	{
 		//S_StartSound(player->mo, sfx_stfhit);
@@ -256,7 +256,7 @@ void A_StaffAttackPL2 (AActor *actor)
 	angle = player->mo->angle;
 	angle += pr_sap2.Random2() << 18;
 	slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
-	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff2));
+	P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AStaffPuff2), true);
 	if (linetarget)
 	{
 		//S_StartSound(player->mo, sfx_stfpow);
diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp
index 3cfc0441d..8fe893135 100644
--- a/src/g_hexen/a_clericmace.cpp
+++ b/src/g_hexen/a_clericmace.cpp
@@ -94,7 +94,7 @@ void A_CMaceAttack (AActor *actor)
 		slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE);
 		if (linetarget)
 		{
-			P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
+			P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
 			AdjustPlayerAngle (player->mo);
 //			player->mo->angle = R_PointToAngle2(player->mo->x,
 //				player->mo->y, linetarget->x, linetarget->y);
@@ -104,7 +104,7 @@ void A_CMaceAttack (AActor *actor)
 		slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE);
 		if (linetarget)
 		{
-			P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
+			P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
 			AdjustPlayerAngle (player->mo);
 //			player->mo->angle = R_PointToAngle2(player->mo->x,
 //				player->mo->y, linetarget->x, linetarget->y);
diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp
index b8d0cff6e..b2aec98ed 100644
--- a/src/g_hexen/a_fighteraxe.cpp
+++ b/src/g_hexen/a_fighteraxe.cpp
@@ -352,7 +352,7 @@ void A_FAxeAttack (AActor *actor)
 		slope = P_AimLineAttack (pmo, angle, AXERANGE);
 		if (linetarget)
 		{
-			P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype);
+			P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true);
 			if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
 			{
 				P_ThrustMobj (linetarget, angle, power);
@@ -365,7 +365,7 @@ void A_FAxeAttack (AActor *actor)
 		slope = P_AimLineAttack (pmo, angle, AXERANGE);
 		if (linetarget)
 		{
-			P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype);
+			P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true);
 			if (linetarget->flags3&MF3_ISMONSTER)
 			{
 				P_ThrustMobj (linetarget, angle, power);
@@ -380,7 +380,7 @@ void A_FAxeAttack (AActor *actor)
 
 	angle = pmo->angle;
 	slope = P_AimLineAttack (pmo, angle, MELEERANGE);
-	P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype);
+	P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
 
 axedone:
 	if (useMana == 2)
diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp
index b6ea2097f..5b8b4583d 100644
--- a/src/g_hexen/a_fighterhammer.cpp
+++ b/src/g_hexen/a_fighterhammer.cpp
@@ -194,7 +194,7 @@ void A_FHammerAttack (AActor *actor)
 		slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
 		if (linetarget)
 		{
-			P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
+			P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
 			AdjustPlayerAngle(pmo);
 			if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
 			{
@@ -207,7 +207,7 @@ void A_FHammerAttack (AActor *actor)
 		slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
 		if(linetarget)
 		{
-			P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff));
+			P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true);
 			AdjustPlayerAngle(pmo);
 			if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
 			{
@@ -220,7 +220,7 @@ void A_FHammerAttack (AActor *actor)
 	// didn't find any targets in meleerange, so set to throw out a hammer
 	angle = pmo->angle;
 	slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE);
-	if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff)) != NULL)
+	if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(AHammerPuff), true) != NULL)
 	{
 		pmo->special1 = false;
 	}
diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp
index c42f7d2dc..8a2e07b6f 100644
--- a/src/g_hexen/a_fighterplayer.cpp
+++ b/src/g_hexen/a_fighterplayer.cpp
@@ -258,7 +258,7 @@ void A_FPunchAttack (AActor *actor)
 				power = 6*FRACUNIT;
 				pufftype = RUNTIME_CLASS(AHammerPuff);
 			}
-			P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype);
+			P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
 			if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
 			{
 				P_ThrustMobj (linetarget, angle, power);
@@ -277,7 +277,7 @@ void A_FPunchAttack (AActor *actor)
 				power = 6*FRACUNIT;
 				pufftype = RUNTIME_CLASS(AHammerPuff);
 			}
-			P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype);
+			P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
 			if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
 			{
 				P_ThrustMobj (linetarget, angle, power);
@@ -291,7 +291,7 @@ void A_FPunchAttack (AActor *actor)
 
 	angle = pmo->angle;
 	slope = P_AimLineAttack (pmo, angle, MELEERANGE);
-	P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype);
+	P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
 
 punchdone:
 	if (pmo->special1 == 3)
diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp
index 095d6a62b..76f948a0d 100644
--- a/src/g_hexen/a_pig.cpp
+++ b/src/g_hexen/a_pig.cpp
@@ -269,7 +269,7 @@ void A_SnoutAttack (AActor *actor)
 	damage = 3+(pr_snoutattack()&3);
 	angle = player->mo->angle;
 	slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
-	puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ASnoutPuff));
+	puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, RUNTIME_CLASS(ASnoutPuff), true);
 	S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
 	if(linetarget)
 	{
diff --git a/src/g_level.cpp b/src/g_level.cpp
index abf1a9fc5..1537e854d 100644
--- a/src/g_level.cpp
+++ b/src/g_level.cpp
@@ -2304,9 +2304,7 @@ void G_FinishTravel ()
 
 			// The player being spawned here is a short lived dummy and
 			// must not start any ENTER script or big problems will happen.
-			P_SpawnPlayer (&playerstarts[pawn->player - players], true);
-
-			pawndup = pawn->player->mo;
+			pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], true);
 			if (!startkeepfacing)
 			{
 				pawn->angle = pawndup->angle;
diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp
index 7f3f4d20a..0198a6c2c 100644
--- a/src/g_strife/a_strifeweapons.cpp
+++ b/src/g_strife/a_strifeweapons.cpp
@@ -210,7 +210,7 @@ void A_JabDagger (AActor *actor)
 
 	angle = actor->angle + (pr_jabdagger.Random2() << 18);
 	pitch = P_AimLineAttack (actor, angle, 80*FRACUNIT);
-	P_LineAttack (actor, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, RUNTIME_CLASS(AStrifeSpark));
+	P_LineAttack (actor, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, RUNTIME_CLASS(AStrifeSpark), true);
 
 	// turn to face target
 	if (linetarget)
@@ -934,7 +934,7 @@ void A_RocketInFlight (AActor *self)
 	AActor *trail;
 
 	S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM);
-	P_SpawnPuff (RUNTIME_CLASS(AMiniMissilePuff), self->x, self->y, self->z, self->angle - ANGLE_180, 2, true);
+	P_SpawnPuff (RUNTIME_CLASS(AMiniMissilePuff), self->x, self->y, self->z, self->angle - ANGLE_180, 2, PF_HITTHING);
 	trail = Spawn<ARocketTrail> (self->x - self->momx, self->y - self->momy, self->z, ALLOW_REPLACE);
 	if (trail != NULL)
 	{
diff --git a/src/m_options.cpp b/src/m_options.cpp
index f2a4b930a..db93d6484 100644
--- a/src/m_options.cpp
+++ b/src/m_options.cpp
@@ -477,6 +477,13 @@ static value_t ColumnMethods[] = {
 	{ 1.0, "Optimized" }
 };
 
+static value_t RocketTrailTypes[] = {
+	{ 0.0, "Off" },
+	{ 1.0, "Particles" },
+	{ 2.0, "Sprites" },
+	{ 3.0, "Sprites & Particles" }
+};
+
 static value_t BloodTypes[] = {
 	{ 0.0, "Sprites" },
 	{ 1.0, "Sprites & Particles" },
@@ -522,7 +529,7 @@ static menuitem_t VideoItems[] = {
 #endif
 	{ redtext,	" ",					{NULL},					{0.0}, {0.0},	{0.0}, {NULL} },
 	{ discrete, "Use fuzz effect",		{&r_drawfuzz},			{2.0}, {0.0},	{0.0}, {YesNo} },
-	{ discrete, "Rocket Trails",		{&cl_rockettrails},		{2.0}, {0.0},	{0.0}, {OnOff} },
+	{ discrete, "Rocket Trails",		{&cl_rockettrails},		{4.0}, {0.0},	{0.0}, {RocketTrailTypes} },
 	{ discrete, "Blood Type",			{&cl_bloodtype},	   	{3.0}, {0.0},	{0.0}, {BloodTypes} },
 	{ discrete, "Bullet Puff Type",		{&cl_pufftype},			{2.0}, {0.0},	{0.0}, {PuffTypes} },
 };
diff --git a/src/p_effect.cpp b/src/p_effect.cpp
index 67a6270c2..66dea8240 100644
--- a/src/p_effect.cpp
+++ b/src/p_effect.cpp
@@ -228,7 +228,7 @@ void P_RunEffect (AActor *actor, int effects)
 	particle_t *particle;
 	int i;
 
-	if ((effects & FX_ROCKET) && cl_rockettrails)
+	if ((effects & FX_ROCKET) && (cl_rockettrails & 1))
 	{
 		// Rocket trail
 
@@ -274,7 +274,7 @@ void P_RunEffect (AActor *actor, int effects)
 				break;
 		}
 	}
-	if ((effects & FX_GRENADE) && (cl_rockettrails))
+	if ((effects & FX_GRENADE) && (cl_rockettrails & 1))
 	{
 		// Grenade trail
 
diff --git a/src/p_local.h b/src/p_local.h
index 04146959a..0f2d1ec6a 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -90,13 +90,20 @@ void	P_UnPredictPlayer ();
 extern fixed_t FloatBobOffsets[64];
 extern AActor *MissileActor;
 
-void P_SpawnPlayer (mapthing2_t* mthing, bool tempplayer=false);
+APlayerPawn *P_SpawnPlayer (mapthing2_t* mthing, bool tempplayer=false);
 
 void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move);
 int P_FaceMobj (AActor *source, AActor *target, angle_t *delta);
 bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax);
 
-AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, bool hit=false, bool temporary=false);
+enum EPuffFlags
+{
+	PF_HITTHING = 1,
+	PF_MELEERANGE = 2,
+	PF_TEMPORARY = 4
+};
+
+AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0);
 void	P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator);
 void	P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
 void	P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator);
@@ -307,8 +314,8 @@ bool	P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, boo
 extern	AActor*	linetarget; 	// who got hit (or NULL)
 
 fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange=0, bool forcenosmart=false);
-AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype);
-AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype);
+AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, bool ismelee = false);
+AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false);
 void	P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch);
 void	P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch);
 void	P_TraceBleed (int damage, AActor *target, AActor *missile);		// missile version
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 3b571c477..f02da328f 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -2809,7 +2809,7 @@ static bool CheckForSpectral (FTraceResults &res)
 }
 
 AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
-				   int pitch, int damage, FName damageType, const PClass *pufftype)
+				   int pitch, int damage, FName damageType, const PClass *pufftype, bool ismeleeattack)
 {
 	fixed_t vx, vy, vz, shootz;
 	FTraceResults trace;
@@ -2818,6 +2818,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 	bool hitGhosts;
 	bool killPuff = false;
 	AActor *puff = NULL;
+	int flags = ismeleeattack? PF_MELEERANGE : 0;
 
 	angle >>= ANGLETOFINESHIFT;
 	pitch = (angle_t)(pitch) >> ANGLETOFINESHIFT;
@@ -2853,7 +2854,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 		}
 		if (puffDefaults->flags3 & MF3_ALWAYSPUFF)
 		{ // Spawn the puff anyway
-			puff = P_SpawnPuff (pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2);
+			puff = P_SpawnPuff (pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, flags);
 		}
 		else
 		{
@@ -2872,7 +2873,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 				fixed_t closer = trace.Distance - 4*FRACUNIT;
 				puff = P_SpawnPuff (pufftype, t1->x + FixedMul (vx, closer),
 					t1->y + FixedMul (vy, closer),
-					shootz + FixedMul (vz, closer), angle - ANG90, 0);
+					shootz + FixedMul (vz, closer), angle - ANG90, 0, flags);
 			}
 
 			// [RH] Spawn a decal
@@ -2925,7 +2926,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 				(trace.Actor->flags & MF_NOBLOOD) ||
 				(trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT)))
 			{
-				puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true);
+				puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING);
 			}
 			if (!(GetDefaultByType(pufftype)->flags3&MF3_BLOODLESSIMPACT))
 			{
@@ -2972,7 +2973,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 				{ 
 					// Since the puff is the damage inflictor we need it here 
 					// regardless of whether it is displayed or not.
-					puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true, true);
+					puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY);
 					killPuff = true;
 				}
 				P_DamageMobj (trace.Actor, puff ? puff : t1, t1, damage, damageType, flags);
@@ -2983,7 +2984,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 
 			if (puff == NULL)
 			{ // Spawn puff just to get a mass for the splash
-				puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, true, true);
+				puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY);
 				killPuff = true;
 			}
 			SpawnDeepSplash (t1, trace, puff, vx, vy, vz);
@@ -2998,7 +2999,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 }
 
 AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
-				   int pitch, int damage, FName damageType, FName pufftype)
+				   int pitch, int damage, FName damageType, FName pufftype, bool ismeleeattack)
 {
 	const PClass * type = PClass::FindClass(pufftype);
 	if (type == NULL)
@@ -3007,7 +3008,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
 	}
 	else
 	{
-		return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type);
+		return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, ismeleeattack);
 	}
 	return NULL;
 }
@@ -3273,7 +3274,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
 		if ((RailHits[i].HitActor->flags & MF_NOBLOOD) ||
 			(RailHits[i].HitActor->flags2 & (MF2_DORMANT|MF2_INVULNERABLE)))
 		{
-			if (puffclass != NULL) P_SpawnPuff (puffclass, x, y, z, source->angle - ANG180, 1, true);
+			if (puffclass != NULL) P_SpawnPuff (puffclass, x, y, z, source->angle - ANG180, 1, PF_HITTHING);
 		}
 		else
 		{
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 1df118ffb..101226f68 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -77,9 +77,8 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
 extern cycle_t BotSupportCycles;
 extern cycle_t BotWTG;
 extern fixed_t attackrange;
-extern int tmfloorpic;
-extern sector_t *tmfloorsector;
 EXTERN_CVAR (Bool, r_drawfuzz);
+EXTERN_CVAR (Int,  cl_rockettrails)
 
 // PRIVATE DATA DEFINITIONS ------------------------------------------------
 
@@ -102,6 +101,7 @@ static FRandom pr_spawnmissile ("SpawnMissile");
 static FRandom pr_missiledamage ("MissileDamage");
  FRandom pr_slam ("SkullSlam");
 static FRandom pr_multiclasschoice ("MultiClassChoice");
+static FRandom pr_rockettrail("RocketTrail");
 
 // PUBLIC DATA DEFINITIONS -------------------------------------------------
 
@@ -321,7 +321,8 @@ void AActor::Serialize (FArchive &arc)
 		<< DamageType
 		<< gravity
 		<< FastChaseStrafeCount
-		<< master;
+		<< master
+		<< smokecounter;
 
 	if (arc.IsStoring ())
 	{
@@ -2584,12 +2585,46 @@ void AActor::Tick ()
 			return;
 		}
 
+		if (cl_rockettrails & 2)
+		{
+			if (effects & FX_ROCKET) 
+			{
+				if (++smokecounter==4)
+				{
+					// add some smoke behind the rocket 
+					smokecounter = 0;
+					AActor * th = Spawn("RocketSmokeTrail", x-momx, y-momy, z-momz, ALLOW_REPLACE);
+					if (th)
+					{
+						th->tics -= pr_rockettrail()&3;
+						if (th->tics < 1) th->tics = 1;
+					}
+				}
+			}
+			else if (effects & FX_GRENADE) 
+			{
+				if (++smokecounter==8)
+				{
+					smokecounter = 0;
+					angle_t moveangle = R_PointToAngle2(0,0,momx,momy);
+					AActor * th = Spawn("GrenadeSmokeTrail", 
+						x - FixedMul (finecosine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10),
+						y - FixedMul (finesine[(moveangle)>>ANGLETOFINESHIFT], radius*2) + (pr_rockettrail()<<10),
+						z - (height>>3) * (momz>>16) + (2*height)/3, ALLOW_REPLACE);
+					if (th)
+					{
+						th->tics -= pr_rockettrail()&3;
+						if (th->tics < 1) th->tics = 1;
+					}
+				}
+			}
+		}
 
 		fixed_t oldz = z;
 
 		// [RH] Give the pain elemental vertical friction
 		// This used to be in APainElemental::Tick but in order to use
-		// A_PainAttack with other monsters it has to be here!
+		// A_PainAttack with other monsters it has to be here
 		if (flags4 & MF4_VFRICTION)
 		{
 			if (health >0)
@@ -3481,7 +3516,7 @@ EXTERN_CVAR (Bool, chasedemo)
 
 extern bool demonew;
 
-void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
+APlayerPawn *P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
 {
 	int		  playernum;
 	player_t *p;
@@ -3508,7 +3543,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
 
 	// not playing?
 	if (playernum >= MAXPLAYERS || !playeringame[playernum])
-		return;
+		return NULL;
 
 	p = &players[playernum];
 
@@ -3705,6 +3740,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
 			FBehavior::StaticStartTypedScripts (SCRIPT_Respawn, p->mo, true);
 		}
 	}
+	return mobj;
 }
 
 
@@ -3714,7 +3750,7 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool tempplayer)
 // already be in host byte order.
 //
 // [RH] position is used to weed out unwanted start spots
-void P_SpawnMapThing (mapthing2_t *mthing, int position)
+AActor *P_SpawnMapThing (mapthing2_t *mthing, int position)
 {
 	const PClass *i;
 	int mask;
@@ -3722,13 +3758,13 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 	fixed_t x, y, z;
 
 	if (mthing->type == 0 || mthing->type == -1)
-		return;
+		return NULL;
 
 	// count deathmatch start positions
 	if (mthing->type == 11)
 	{
 		deathmatchstarts.Push (*mthing);
-		return;
+		return NULL;
 	}
 
 	// Convert Strife starts to Hexen-style starts
@@ -3769,7 +3805,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 		polyspawns = polyspawn;
 		if (mthing->type != PO_ANCHOR_TYPE)
 			po_NumPolyobjs++;
-		return;
+		return NULL;
 	}
 
 	// check for players specially
@@ -3807,13 +3843,13 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 		}
 		if (!(mthing->flags & mask))
 		{
-			return;
+			return NULL;
 		}
 
 		mask = G_SkillProperty(SKILLP_SpawnFilter);
 		if (!(mthing->flags & mask))
 		{
-			return;
+			return NULL;
 		}
 
 		// Check class spawn masks. Now with player classes available
@@ -3823,7 +3859,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 			int spawnmask = players[consoleplayer].GetSpawnClass();
 			if (spawnmask != 0 && (mthing->flags & spawnmask) == 0)
 			{ // Not for current class
-				return;
+				return NULL;
 			}
 		}
 		else if (!deathmatch)
@@ -3842,7 +3878,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 			}
 			if (mask != -1 && (mthing->flags & mask) == 0)
 			{
-				return;
+				return NULL;
 			}
 		}
 	}
@@ -3851,14 +3887,14 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 	{
 		// [RH] Only spawn spots that match position.
 		if (mthing->args[0] != position)
-			return;
+			return NULL;
 
 		// save spots for respawning in network games
 		playerstarts[pnum] = *mthing;
 		if (!deathmatch)
-			P_SpawnPlayer (mthing);
+			return P_SpawnPlayer (mthing);
 
-		return;
+		return NULL;
 	}
 
 	// [RH] sound sequence overriders
@@ -3866,7 +3902,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 	{
 		P_PointInSector (mthing->x<<FRACBITS,
 			mthing->y<<FRACBITS)->seqType = mthing->type - 1400;
-		return;
+		return NULL;
 	}
 	else if (mthing->type == 1411)
 	{
@@ -3886,7 +3922,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 			P_PointInSector (mthing->x << FRACBITS,
 				mthing->y << FRACBITS)->seqType = type;
 		}
-		return;
+		return NULL;
 	}
 
 	// [RH] Determine if it is an old ambient thing, and if so,
@@ -3933,7 +3969,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 
 	// don't spawn keycards and players in deathmatch
 	if (deathmatch && info->flags & MF_NOTDMATCH)
-		return;
+		return NULL;
 
 	// [RH] don't spawn extra weapons in coop if so desired
 	if (multiplayer && !deathmatch && (dmflags & DF_NO_COOP_WEAPON_SPAWN))
@@ -3941,14 +3977,14 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 		if (i->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
 		{
 			if ((mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH)
-				return;
+				return NULL;
 		}
 	}
 
 	// don't spawn any monsters if -nomonsters
 	if (((level.flags & LEVEL_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) && info->flags3 & MF3_ISMONSTER )
 	{
-		return;
+		return NULL;
 	}
 	
 	// [RH] Other things that shouldn't be spawned depending on dmflags
@@ -3957,13 +3993,11 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 		if (dmflags & DF_NO_HEALTH)
 		{
 			if (i->IsDescendantOf (RUNTIME_CLASS(AHealth)))
-				return;
+				return NULL;
 			if (i->TypeName == NAME_Berserk)
-				return;
-			if (i->TypeName == NAME_Soulsphere)
-				return;
+				return NULL;
 			if (i->TypeName == NAME_Megasphere)
-				return;
+				return NULL;
 		}
 		if (dmflags & DF_NO_ITEMS)
 		{
@@ -3973,9 +4007,9 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 		if (dmflags & DF_NO_ARMOR)
 		{
 			if (i->IsDescendantOf (RUNTIME_CLASS(AArmor)))
-				return;
+				return NULL;
 			if (i->TypeName == NAME_Megasphere)
-				return;
+				return NULL;
 		}
 	}
 
@@ -4020,9 +4054,10 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 	mobj->BeginPlay ();
 	if (mobj->ObjectFlags & OF_EuthanizeMe)
 	{
-		return;
+		return NULL;
 	}
 	mobj->LevelSpawned ();
+	return mobj;
 }
 
 
@@ -4036,7 +4071,7 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
 // P_SpawnPuff
 //
 
-AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, bool hitthing, bool temporary)
+AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags)
 {
 	AActor *puff;
 
@@ -4048,26 +4083,26 @@ AActor *P_SpawnPuff (const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, an
 	// it will enter the crash state. This is used by the StrifeSpark
 	// and BlasterPuff.
 	FState *crashstate;
-	if (hitthing == false && (crashstate = puff->FindState(NAME_Crash)) != NULL)
+	if (!(flags & PF_HITTHING) && (crashstate = puff->FindState(NAME_Crash)) != NULL)
 	{
 		puff->SetState (crashstate);
 	}
-	else if (attackrange == MELEERANGE && puff->MeleeState != NULL)
+	else if ((flags & PF_MELEERANGE) && puff->MeleeState != NULL)
 	{
 		// handle the hard coded state jump of Doom's bullet puff
 		// in a more flexible manner.
 		puff->SetState (puff->MeleeState);
 	}
 
-	if (cl_pufftype && updown != 3 && !temporary && (puff->flags4 & MF4_ALLOWPARTICLES))
+	if (!(flags & PF_TEMPORARY))
 	{
-		P_DrawSplash2 (32, x, y, z, dir, updown, 1);
-		puff->renderflags |= RF_INVISIBLE;
-	}
+		if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES))
+		{
+			P_DrawSplash2 (32, x, y, z, dir, updown, 1);
+			puff->renderflags |= RF_INVISIBLE;
+		}
 
-	if (!temporary)
-	{
-		if (hitthing && puff->SeeSound)
+		if ((flags & PF_HITTHING) && puff->SeeSound)
 		{ // Hit thing sound
 			S_SoundID (puff, CHAN_BODY, puff->SeeSound, 1, ATTN_NORM);
 		}
diff --git a/src/p_setup.cpp b/src/p_setup.cpp
index 4268d9062..e33bebac3 100644
--- a/src/p_setup.cpp
+++ b/src/p_setup.cpp
@@ -60,7 +60,7 @@
 #include "p_setup.h"
 #include "r_translate.h"
 
-extern void P_SpawnMapThing (mapthing2_t *mthing, int position);
+extern AActor *P_SpawnMapThing (mapthing2_t *mthing, int position);
 extern bool P_LoadBuildMap (BYTE *mapdata, size_t len, mapthing2_t **things, int *numthings);
 
 extern void P_LoadTranslator(const char *lump);
diff --git a/src/p_switch.cpp b/src/p_switch.cpp
index 150a38b74..fdc27114c 100644
--- a/src/p_switch.cpp
+++ b/src/p_switch.cpp
@@ -475,6 +475,9 @@ static int TryFindSwitch (side_t *side, int Where)
 //
 bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
 {
+	// if this line is one sided this function must always return success.
+	if (line->sidenum[0] == NO_SIDE || line->sidenum[1] == NO_SIDE) return true;
+
 	fixed_t checktop;
 	fixed_t checkbot;
 	side_t *side = &sides[line->sidenum[sideno]];
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 99f6f5cf1..36215d536 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1145,7 +1145,7 @@ void A_CustomPunch (AActor *self)
 	PuffType = PClass::FindClass(PuffTypeName);
 	if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff);
 
-	P_LineAttack (self, angle, Range, pitch, Damage, GetDefaultByType(PuffType)->DamageType, PuffType);
+	P_LineAttack (self, angle, Range, pitch, Damage, GetDefaultByType(PuffType)->DamageType, PuffType, true);
 
 	// turn to face target
 	if (linetarget)
diff --git a/wadsrc/decorate/shared/splashes.txt b/wadsrc/decorate/shared/splashes.txt
index f82cc80f0..64bb14909 100644
--- a/wadsrc/decorate/shared/splashes.txt
+++ b/wadsrc/decorate/shared/splashes.txt
@@ -197,3 +197,41 @@ ACTOR SlimeSplash
 	}
 }
 
+// Smoke trail for rocket -----------------------------------
+
+ACTOR RocketSmokeTrail
+{
+	RenderStyle Translucent
+	Alpha 0.4
+	VSpeed 1
+	+NOBLOCKMAP 
+	+NOCLIP 
+	+NOGRAVITY 
+	+DONTSPLASH
+	+NOTELEPORT
+	States
+	{
+	Spawn:
+		RSMK ABCDE 5
+		Stop
+	}
+}
+
+ACTOR GrenadeSmokeTrail
+{
+	RenderStyle Translucent
+	Alpha 0.4
+	+NOBLOCKMAP 
+	+NOCLIP 
+	+DONTSPLASH
+	+NOTELEPORT
+	Gravity 0.1
+	VSpeed 0.5
+	Scale 0.6
+	States
+	{
+	Spawn:
+		RSMK ABCDE 4
+		Stop
+	}
+}
diff --git a/wadsrc/rsmka0.png b/wadsrc/rsmka0.png
new file mode 100644
index 000000000..5e2f4de85
Binary files /dev/null and b/wadsrc/rsmka0.png differ
diff --git a/wadsrc/rsmkb0.png b/wadsrc/rsmkb0.png
new file mode 100644
index 000000000..fab531acf
Binary files /dev/null and b/wadsrc/rsmkb0.png differ
diff --git a/wadsrc/rsmkc0.png b/wadsrc/rsmkc0.png
new file mode 100644
index 000000000..2811d6243
Binary files /dev/null and b/wadsrc/rsmkc0.png differ
diff --git a/wadsrc/rsmkd0.png b/wadsrc/rsmkd0.png
new file mode 100644
index 000000000..659ddd817
Binary files /dev/null and b/wadsrc/rsmkd0.png differ
diff --git a/wadsrc/rsmke0.png b/wadsrc/rsmke0.png
new file mode 100644
index 000000000..930b30a58
Binary files /dev/null and b/wadsrc/rsmke0.png differ
diff --git a/wadsrc/zdoom.lst b/wadsrc/zdoom.lst
index 81e82cdd8..a48633d1d 100644
--- a/wadsrc/zdoom.lst
+++ b/wadsrc/zdoom.lst
@@ -149,6 +149,11 @@ sprites/icecc0.png		    icecc0.png
 sprites/icecd0.png		    icecd0.png
 sprites/amrka0.png			amrka0.png
 sprites/pista0.png			pista0.png
+sprites/rsmka0.png			rsmka0.png
+sprites/rsmkb0.png			rsmkb0.png
+sprites/rsmkc0.png			rsmkc0.png
+sprites/rsmkd0.png			rsmkd0.png
+sprites/rsmke0.png			rsmke0.png
 
 # crouching DoomPlayer
 sprites/plyca1.lmp  		crouch/plyca1.lmp