diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index aa2f803be3fe8070e10e340d00f3ff9122ac4be7..db6ed72285eff52cb18f458c837054c7525be311 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -2789,7 +2789,7 @@ static void HWR_LinkDrawHackFinish(void)
 	linkdrawcount = 0;
 }
 
-static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
+static void HWR_DrawDropShadow(mobj_t *thing, gl_vissprite_t *spr, fixed_t scale)
 {
 	patch_t *gpatch;
 	FOutVector shadowVerts[4];
@@ -2807,7 +2807,6 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 	UINT16 alpha;
 	fixed_t floordiff;
 	fixed_t groundz;
-	fixed_t slopez;
 	pslope_t *groundslope;
 
 	// uncapped/interpolation
@@ -2848,7 +2847,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 	if (alpha >= 255) return;
 	alpha = 255 - alpha;
 
-	gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE);
+	gpatch = (cv_shadow.value == 2) ? spr->gpatch : (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE);
 	if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return;
 	HWR_GetPatch(gpatch);
 
@@ -2874,19 +2873,62 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 	shadowVerts[1].z = shadowVerts[2].z = fy - offset;
 	shadowVerts[0].z = shadowVerts[3].z = fy + offset;
 
+	if (cv_shadow.value == 2)
+	{
+		shadowVerts[0].x = shadowVerts[3].x = spr->x1;
+		shadowVerts[2].x = shadowVerts[1].x = spr->x2;
+		shadowVerts[0].z = shadowVerts[3].z = spr->z1;
+		shadowVerts[2].z = shadowVerts[1].z = spr->z2;
+
+		// Always a pixel above the floor, perfectly flat.
+		for (i = 0; i < 4; i++)
+		{
+			if (groundslope)
+			{
+				fixed_t slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
+				shadowVerts[i].y = FIXED_TO_FLOAT(slopez)/2 + flip * 0.05f;
+			}
+			else
+			{
+				shadowVerts[i].y = FIXED_TO_FLOAT(groundz)/2 + flip * 0.05f;
+			}
+		}
+
+		if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
+		{
+
+			// Now transform the TOP vertices along the floor in the direction of the camera
+			shadowVerts[3].x = spr->x1 + (gpatch->height + fscale + offset) * gl_viewcos;
+			shadowVerts[2].x = spr->x2 + (gpatch->height + fscale + offset) * gl_viewcos;
+			shadowVerts[3].z = spr->z1 + (gpatch->height + fscale + offset) * gl_viewsin;
+			shadowVerts[2].z = spr->z2 + (gpatch->height + fscale + offset) * gl_viewsin;
+		}
+		else
+		{
+			// Now transform the TOP vertices along the floor in the direction of the camera
+			shadowVerts[3].x = spr->x1 + (gpatch->height + offset) * gl_viewcos;
+			shadowVerts[2].x = spr->x2 + (gpatch->height + offset) * gl_viewcos;
+			shadowVerts[3].z = spr->z1 + (gpatch->height + offset) * gl_viewsin;
+			shadowVerts[2].z = spr->z2 + (gpatch->height + offset) * gl_viewsin;
+		}
+	}
+
 	for (i = 0; i < 4; i++)
 	{
 		float oldx = shadowVerts[i].x;
 		float oldy = shadowVerts[i].z;
-		shadowVerts[i].x = fx + ((oldx - fx) * gl_viewcos) - ((oldy - fy) * gl_viewsin);
-		shadowVerts[i].z = fy + ((oldx - fx) * gl_viewsin) + ((oldy - fy) * gl_viewcos);
+		if(!(cv_shadow.value == 2))
+		{
+			shadowVerts[i].x = fx + ((oldx - fx) * gl_viewcos) - ((oldy - fy) * gl_viewsin);
+			shadowVerts[i].z = fy + ((oldx - fx) * gl_viewsin) + ((oldy - fy) * gl_viewcos);
+		}
 	}
 
 	if (groundslope)
 	{
 		for (i = 0; i < 4; i++)
 		{
-			slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
+			fixed_t slopez = P_GetSlopeZAt(groundslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
 			shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + flip * 0.05f;
 		}
 	}
@@ -2902,6 +2944,21 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 	shadowVerts[3].t = shadowVerts[2].t = 0;
 	shadowVerts[0].t = shadowVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t;
 
+
+	if (cv_shadow.value == 2)
+	{
+		if (spr->flip)
+		{
+			shadowVerts[0].s = shadowVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s;
+			shadowVerts[2].s = shadowVerts[1].s = 0;
+		}
+		else
+		{
+			shadowVerts[0].s = shadowVerts[3].s = 0;
+			shadowVerts[2].s = shadowVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s;
+		}
+	}
+
 	if (!(thing->renderflags & RF_NOCOLORMAPS))
 	{
 		if (thing->subsector->sector->numlights)
@@ -2925,6 +2982,13 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
 		blendmode |= PF_ColorMapped;
 	}
 
+	if (cv_shadow.value == 2)
+	{
+		sSurf.PolyColor.s.red = 0x00;
+		sSurf.PolyColor.s.blue = 0x00;
+		sSurf.PolyColor.s.green = 0x00;
+	}
+
 	HWR_ProcessPolygon(&sSurf, shadowVerts, 4, blendmode, shader, false);
 }
 
@@ -4174,7 +4238,7 @@ static void HWR_DrawSprites(void)
 		{
 			if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow)
 			{
-				HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
+				HWR_DrawDropShadow(spr->mobj, spr, spr->mobj->shadowscale);
 			}
 
 			if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
@@ -4184,10 +4248,11 @@ static void HWR_DrawSprites(void)
 				// the linkdraw sprite because the linkdraw sprite does not modify the z-buffer.
 				// The !skipshadow check is there in case there are multiple linkdraw sprites connected
 				// to the same tracer, so the tracer's shadow only gets drawn once.
-				if (cv_shadow.value && !skipshadow && spr->dispoffset < 0 && spr->mobj->tracer->shadowscale)
+				if (cv_shadow.value && !skipshadow && (spr->dispoffset < 0 || cv_shadow.value == 2) && spr->mobj->tracer->shadowscale)
 				{
-					HWR_DrawDropShadow(spr->mobj->tracer, spr->mobj->tracer->shadowscale);
-					skipshadow = true;
+					HWR_DrawDropShadow(spr->mobj->tracer, spr, spr->mobj->tracer->shadowscale);
+					if (cv_shadow.value == 1)
+						skipshadow = true;
 					// The next sprite in this loop should be either another linkdraw sprite or the tracer.
 					// When the tracer is inevitably encountered, skipshadow will cause it's shadow
 					// to get skipped and skipshadow will get set to false by the 'else' clause below.
diff --git a/src/r_main.c b/src/r_main.c
index 2d19c7303c1d579ebcde838bc4a3214ce435ad15..819dcce761109e30bb0f5dcb3dc0c1cd54032557 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -134,6 +134,7 @@ static CV_PossibleValue_t fov_cons_t[] = {{MINFOV, "MIN"}, {MAXFOV, "MAX"}, {0,
 static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
 static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card
 static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}};
+static CV_PossibleValue_t shadow_cons_t[] = {{0, "Off"}, {1, "Drop"}, {2, "Sprite"}};
 
 static void R_SetFov(fixed_t playerfov);
 
@@ -151,7 +152,7 @@ consvar_t cv_chasecam2 = CVAR_INIT ("chasecam2", "On", NULL, CV_CALL, CV_OnOff,
 consvar_t cv_flipcam = CVAR_INIT ("flipcam", "No", NULL, CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange);
 consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", NULL, CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange);
 
-consvar_t cv_shadow = CVAR_INIT ("shadow", "On", NULL, CV_SAVE, CV_OnOff, NULL);
+consvar_t cv_shadow = CVAR_INIT ("shadow", "Drop", NULL, CV_SAVE, shadow_cons_t, NULL);
 consvar_t cv_skybox = CVAR_INIT ("skybox", "On", NULL, CV_SAVE, CV_OnOff, NULL);
 consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", NULL, CV_NETVAR|CV_ALLOWLUA, CV_YesNo, NULL);
 consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", NULL, CV_CALL|CV_ALLOWLUA,  CV_YesNo, R_SetViewSize);
diff --git a/src/r_things.c b/src/r_things.c
index e0ed15706184f45f5679454f3c6962fe89c23cd0..fa2c54e6e9aa2fa655e67d7c224567690a45dc48 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1556,7 +1556,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
 
 	scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
 
-	patch = W_CachePatchName("DSHADOW", PU_SPRITE);
+	patch = (cv_shadow.value == 2) ? vis->patch : W_CachePatchName("DSHADOW", PU_SPRITE);
 	xscale = FixedDiv(projection, tz);
 	yscale = FixedDiv(projectiony, tz);
 	shadowxscale = FixedMul(interp.radius*2, scalemul);
@@ -1593,7 +1593,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
 	shadow->gy = interp.y;
 	shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + patch->height * shadowyscale / 2;
 	shadow->gz = shadow->gzt - patch->height * shadowyscale;
-	shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
+	shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale * (cv_shadow.value == 2 ? 1.15 : 1)));
 	if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
 		shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale);
 	shadow->scalestep = 0;