diff --git a/src/dehacked.c b/src/dehacked.c
index daf5780072ef914572feb9fb80e14e7528e5f2c3..32339fe87ebea4364abec7c9906bde2997293726 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -3027,6 +3027,7 @@ static actionpointer_t actionpointers[] =
 	{{A_DragonbomberSpawn},      "A_DRAGONBOMERSPAWN"},
 	{{A_DragonWing},             "A_DRAGONWING"},
 	{{A_DragonSegment},          "A_DRAGONSEGMENT"},
+	{{A_ChangeHeight},           "A_CHANGEHEIGHT"},
 	{{NULL},                     "NONE"},
 
 	// This NULL entry must be the last in the list
@@ -6224,10 +6225,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	"S_ROCKET",
 
-	"S_LASER1",
+	"S_LASER",
 	"S_LASER2",
 	"S_LASERFLASH",
-	"S_LASERSPARK",
+
+	"S_LASERFLAME1",
+	"S_LASERFLAME2",
+	"S_LASERFLAME3",
+	"S_LASERFLAME4",
+	"S_LASERFLAME5",
 
 	"S_TORPEDO",
 
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index c5af8d6d336a8c8b29d9ce492402c323bb964b13..3d1316a2f199508e866dc983265ff0da9de27f99 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -298,6 +298,8 @@ light_t *t_lspr[NUMSPRITES] =
 
 	// Projectiles
 	&lspr[NOLIGHT],     // SPR_MISL
+	&lspr[SMALLREDBALL_L], // SPR_LASR
+	&lspr[REDSHINE_L],  // SPR_LASF
 	&lspr[NOLIGHT],     // SPR_TORP
 	&lspr[NOLIGHT],     // SPR_ENRG
 	&lspr[NOLIGHT],     // SPR_MINE
diff --git a/src/info.c b/src/info.c
index 2944c53b1c584f4c3bdc35dc1f7437e6971582b3..ccb03ab1a9893e9919f5ee3bf23f11296e262d5b 100644
--- a/src/info.c
+++ b/src/info.c
@@ -187,6 +187,8 @@ char sprnames[NUMSPRITES + 1][5] =
 
 	// Projectiles
 	"MISL",
+	"LASR", // GFZ3 laser
+	"LASF", // GFZ3 laser flames
 	"TORP", // Torpedo
 	"ENRG", // Energy ball
 	"MINE", // Skim mine
@@ -2058,10 +2060,15 @@ state_t states[NUMSTATES] =
 
 	{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET}, // S_ROCKET
 
-	{SPR_MISL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_LASER1
-	{SPR_MISL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL}, // S_LASER2
-	{SPR_MISL, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_NULL}, // S_LASERFLASH
-	{SPR_MISL, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_LASERSPARK}, // S_LASERSPARK
+	{SPR_LASR, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_NULL}, // S_LASER
+	{SPR_LASR, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_LASER2
+	{SPR_LASR, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_NULL}, // S_LASERFLASH
+
+	{SPR_LASF,                           FF_FULLBRIGHT|0,       2,           {NULL}, 0, 0, S_LASERFLAME2}, // S_LASERFLAME1
+	{SPR_LASF,                           FF_FULLBRIGHT|1,       1, {A_ChangeHeight}, 52*FRACUNIT, 3, S_LASERFLAME3}, // S_LASERFLAME2
+	{SPR_LASF,                           FF_FULLBRIGHT|2,       0, {A_ChangeHeight}, 12*FRACUNIT, 3, S_LASERFLAME4}, // S_LASERFLAME3
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|2,       4,           {NULL}, 1, 2, S_LASERFLAME5}, // S_LASERFLAME4
+	{SPR_LASF, FF_ANIMATE|FF_PAPERSPRITE|FF_FULLBRIGHT|4,      28,           {NULL}, 2, 2, S_NULL}, // S_LASERFLAME5
 
 	{SPR_TORP, 0, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_TORPEDO}, // S_TORPEDO
 
@@ -5668,15 +5675,15 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_EGGMOBILE_FIRE
 		-1,             // doomednum
-		S_SPINFIRE1,    // spawnstate
+		S_LASERFLAME1,  // spawnstate
 		1,              // spawnhealth
 		S_NULL,         // seestate
-		sfx_None,       // seesound
+		sfx_s3kc2s,     // seesound
 		8,              // reactiontime
 		sfx_None,       // attacksound
 		S_NULL,         // painstate
 		0,              // painchance
-		sfx_None,       // painsound
+		sfx_s3k8d,      // painsound
 		S_NULL,         // meleestate
 		S_NULL,         // missilestate
 		S_NULL,         // deathstate
@@ -5684,7 +5691,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		sfx_None,       // deathsound
 		0,              // speed
 		8*FRACUNIT,     // radius
-		14*FRACUNIT,    // height
+		28*FRACUNIT,    // height
 		0,              // display offset
 		DMG_FIRE,       // mass
 		1,              // damage
@@ -9631,13 +9638,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_LASER
 		-1,             // doomednum
-		S_LASER1,       // spawnstate
+		S_LASER,        // spawnstate
 		1000,           // spawnhealth
 		S_NULL,         // seestate
 		sfx_rlaunc,     // seesound
 		8,              // reactiontime
 		sfx_None,       // attacksound
-		S_LASERSPARK,   // painstate
+		S_NULL,         // painstate
 		0,              // painchance
 		sfx_None,       // painsound
 		S_LASERFLASH,   // meleestate
diff --git a/src/info.h b/src/info.h
index 1d1400aba76671207d09d19593edd22900e83b5f..79af9bbbb8ae444fa3e9aee46cc17ca922bf9d68 100644
--- a/src/info.h
+++ b/src/info.h
@@ -284,6 +284,7 @@ void A_RolloutRock();
 void A_DragonbomberSpawn();
 void A_DragonWing();
 void A_DragonSegment();
+void A_ChangeHeight();
 
 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
 #define NUMMOBJFREESLOTS 512
@@ -451,6 +452,8 @@ typedef enum sprite
 
 	// Projectiles
 	SPR_MISL,
+	SPR_LASR, // GFZ3 laser
+	SPR_LASF, // GFZ3 laser flames
 	SPR_TORP, // Torpedo
 	SPR_ENRG, // Energy ball
 	SPR_MINE, // Skim mine
@@ -2219,10 +2222,15 @@ typedef enum state
 
 	S_ROCKET,
 
-	S_LASER1,
+	S_LASER,
 	S_LASER2,
 	S_LASERFLASH,
-	S_LASERSPARK,
+
+	S_LASERFLAME1,
+	S_LASERFLAME2,
+	S_LASERFLAME3,
+	S_LASERFLAME4,
+	S_LASERFLAME5,
 
 	S_TORPEDO,
 
diff --git a/src/p_enemy.c b/src/p_enemy.c
index ec7445f9fb74c956d076c9b3250b07ea71d3e4e2..9fc7734d6cd4dc74a02b3872977a4f808e757418 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -312,6 +312,7 @@ void A_RolloutRock(mobj_t *actor);
 void A_DragonbomberSpawn(mobj_t *actor);
 void A_DragonWing(mobj_t *actor);
 void A_DragonSegment(mobj_t *actor);
+void A_ChangeHeight(mobj_t *actor);
 
 //for p_enemy.c
 
@@ -3086,24 +3087,24 @@ void A_Boss1Laser(mobj_t *actor)
 	{
 		mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type);
 		mo->angle = point->angle;
-		mo->color = LASERCOLORS[((UINT8)(i - 3*leveltime) >> 2) % sizeof(LASERCOLORS)]; // codeing
+		mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing
 		P_UnsetThingPosition(mo);
 		mo->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY;
 		P_SetThingPosition(mo);
 
-		if (leveltime & 1 && mo->info->missilestate)
+		if (dur & 1 && mo->info->missilestate)
 		{
 			P_SetMobjState(mo, mo->info->missilestate);
 			if (mo->info->meleestate)
 			{
-				mobk_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE);
+				mobj_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE);
 				mo2->flags2 |= MF2_LINKDRAW;
 				P_SetTarget(&mo2->tracer, actor);
 				P_SetMobjState(mo2, mo->info->meleestate);
 			}
 		}
 
-		if (leveltime % 4 == 0)
+		if (dur == 1)
 			P_SpawnGhostMobj(mo);
 
 		x = point->x, y = point->y, z = point->z;
@@ -3111,28 +3112,32 @@ void A_Boss1Laser(mobj_t *actor)
 			break;
 	}
 
+	x += point->momx;
+	y += point->momy;
 	floorz = P_FloorzAtPos(x, y, z, mobjinfo[MT_EGGMOBILE_FIRE].height);
-	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
-	{
-		for (i = 0; point->info->painstate && i < 3; i++)
-		{
-			mobj_t *spark = P_SpawnMobj(x, y, floorz+1, MT_PARTICLE);
-			spark->flags &= ~MF_NOGRAVITY;
-			spark->angle = FixedAngle(P_RandomKey(360)*FRACUNIT);
-			spark->rollangle = FixedAngle(P_RandomKey(360)*FRACUNIT);
-			spark->color = LASERCOLORS[P_RandomKey(sizeof(LASERCOLORS)/sizeof(UINT8))];
-			spark->colorized = true;
-			spark->fuse = 12;
-			spark->destscale = point->scale >> 3;
-			P_SetObjectMomZ(spark, 8*FRACUNIT, true);
-			P_InstaThrust(spark, spark->angle, 6*FRACUNIT);
-			P_SetMobjState(spark, point->info->painstate);
-		}
+	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1)
+	{
 		point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
+		point->angle = actor->angle;
+		point->destscale = actor->scale*3;
+		P_SetScale(point, point->destscale);
 		P_SetTarget(&point->target, actor);
-		point->destscale = 3*FRACUNIT;
-		point->scalespeed = FRACUNIT>>2;
-		point->fuse = TICRATE;
+		P_MobjCheckWater(point);
+		if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
+		{
+			for (i = 0; i < 2; i++)
+			{
+				UINT8 size = 3;
+				mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST);
+				P_SetScale(steam, size*actor->scale);
+				P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true);
+				P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed());
+				if (point->info->painsound)
+					S_StartSound(steam, point->info->painsound);
+			}
+		}
+		else if (point->info->seesound)
+			S_StartSound(point, point->info->seesound);
 	}
 
 	if (dur > 1)
@@ -14452,3 +14457,43 @@ void A_DragonSegment(mobj_t *actor)
 	actor->angle = hangle;
 	P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
 }
+
+// Function: A_ChangeHeight
+//
+// Description: Changes the actor's height by var1
+//
+// var1 = height
+// var2 =
+//     &1: height is absolute
+//     &2: scale with actor's scale
+//
+void A_ChangeHeight(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	fixed_t height = locvar1;
+	boolean reverse;
+
+	if (LUA_CallAction("A_ChangeHeight", actor))
+		return;
+
+	reverse = (actor->eflags & MFE_VERTICALFLIP) || (actor->flags2 & MF2_OBJECTFLIP);
+
+	if (locvar2 & 2)
+		height = FixedMul(height, actor->scale);
+
+	P_UnsetThingPosition(actor);
+	if (locvar2 & 1)
+	{
+		if (reverse)
+			actor->z += actor->height - locvar1;
+		actor->height = locvar1;
+	}
+	else
+	{
+		if (reverse)
+			actor->z -= locvar1;
+		actor->height += locvar1;
+	}
+	P_SetThingPosition(actor);
+}
\ No newline at end of file
diff --git a/src/p_mobj.c b/src/p_mobj.c
index c78ec4a53941bfff0cc2787bd5dd0bd75f9eb281..02be9dcef3975e0b9bb62df1b194e96d534f62e1 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -7056,8 +7056,7 @@ static void P_MobjScaleThink(mobj_t *mobj)
 	fixed_t oldheight = mobj->height;
 	UINT8 correctionType = 0; // Don't correct Z position, just gain height
 
-	if ((mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz))
-		&& mobj->type != MT_EGGMOBILE_FIRE)
+	if (mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz))
 		correctionType = 1; // Correct Z position by centering
 	else if (mobj->eflags & MFE_VERTICALFLIP)
 		correctionType = 2; // Correct Z position by moving down
@@ -7078,10 +7077,6 @@ static void P_MobjScaleThink(mobj_t *mobj)
 		/// \todo Lua hook for "reached destscale"?
 		switch (mobj->type)
 		{
-		case MT_EGGMOBILE_FIRE:
-			mobj->destscale = FRACUNIT;
-			mobj->scalespeed = FRACUNIT>>4;
-			break;
 		default:
 			break;
 		}
diff --git a/src/sounds.c b/src/sounds.c
index ca943c2d06f0fd9d86e0a3616a86c84b857f65e3..9894fd13ecb2509be3118b48dfa53eda04db8467 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -527,7 +527,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"s3k8a",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Boing"},
   {"s3k8b",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Powerful hit"},
   {"s3k8c",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Humming power"},
-  {"s3k8d",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, ""},
+  {"s3k8d",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "/"},
   {"s3k8e",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Accelerating"},
   {"s3k8f",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Opening"},
   {"s3k90",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Impact"},