diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 37d77b467306b823cd36a9a1bdcb57500723cc2e..68c5dd14dd1e041c964d9676c7e7dff9fd24a94b 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -84,7 +84,7 @@ typedef struct gl_vissprite_s
 
 	//Hurdler: 25/04/2000: now support colormap in hardware mode
 	UINT8 *colormap;
-	INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
+	INT32 dispoffset; // copy of mobj->dispoffset, affects ordering but not drawing
 
 	patch_t *gpatch;
 	mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out.
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index d2982afe44eb1df1812e82a79eab25de87f0b31e..ab2b7cae299fa3bad183a2886d058b46581d52fa 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5052,7 +5052,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
 			return;
 	}
 
-	dispoffset = thing->info->dispoffset;
+	dispoffset = thing->dispoffset;
 
 	this_scale = FIXED_TO_FLOAT(thing->scale);
 	spritexscale = FIXED_TO_FLOAT(thing->spritexscale);
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index cf8ccab2cec113df3e7038c5657a0be395b1f7ea..ffdfe999d58e6e7f48906d589dffdc0aa5ff4448 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -96,7 +96,8 @@ enum mobj_e {
 	mobj_standingslope,
 	mobj_colorized,
 	mobj_mirrored,
-	mobj_shadowscale
+	mobj_shadowscale,
+	mobj_dispoffset
 };
 
 static const char *const mobj_opt[] = {
@@ -173,6 +174,7 @@ static const char *const mobj_opt[] = {
 	"colorized",
 	"mirrored",
 	"shadowscale",
+	"dispoffset",
 	NULL};
 
 #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@@ -439,6 +441,9 @@ static int mobj_get(lua_State *L)
 	case mobj_shadowscale:
 		lua_pushfixed(L, mo->shadowscale);
 		break;
+	case mobj_dispoffset:
+		lua_pushinteger(L, mo->dispoffset);
+		break;
 	default: // extra custom variables in Lua memory
 		lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
 		I_Assert(lua_istable(L, -1));
@@ -803,6 +808,9 @@ static int mobj_set(lua_State *L)
 	case mobj_shadowscale:
 		mo->shadowscale = luaL_checkfixed(L, 3);
 		break;
+	case mobj_dispoffset:
+		mo->dispoffset = luaL_checkinteger(L, 3);
+		break;
 	default:
 		lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
 		I_Assert(lua_istable(L, -1));
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 87e20fd4ac5c9135394ed15ba238fad8ed262f85..10a01dbaa35b140c9e5c0f5e9f3b5377cc47c07c 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -10499,6 +10499,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 
 	mobj->reactiontime = info->reactiontime;
 
+	mobj->dispoffset = info->dispoffset;
+
 	mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer
 
 	// do not set the state with P_SetMobjState,
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 2d096385bd1689f2fb3402a5ca1489cbfd7bca40..d078137d88632e9fc19e93922f0470bfdf6938b6 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -390,6 +390,7 @@ typedef struct mobj_s
 	boolean colorized; // Whether the mobj uses the rainbow colormap
 	boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left
 	fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius
+	INT32 dispoffset; // copy of info->dispoffset, so mobjs can be sorted independently of their type
 
 	// WARNING: New fields must be added separately to savegame and Lua.
 } mobj_t;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 722340f41f6c4fe86f2a70ebfd597bb0a142c290..17c47c7a17ed87aef1f84407234db0732ff1c22b 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1486,6 +1486,7 @@ typedef enum
 	MD2_SPRITEXOFFSET = 1<<20,
 	MD2_SPRITEYOFFSET = 1<<21,
 	MD2_FLOORSPRITESLOPE = 1<<22,
+	MD2_DISPOFFSET = 1<<23
 } mobj_diff2_t;
 
 typedef enum
@@ -1720,6 +1721,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 		|| (slope->normal.z != FRACUNIT))
 			diff2 |= MD2_FLOORSPRITESLOPE;
 	}
+	if (mobj->dispoffset != mobj->info->dispoffset)
+		diff2 |= MD2_DISPOFFSET;
 
 	if (diff2 != 0)
 		diff |= MD_MORE;
@@ -1895,6 +1898,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 		WRITEFIXED(save_p, slope->normal.y);
 		WRITEFIXED(save_p, slope->normal.z);
 	}
+	if (diff2 & MD2_DISPOFFSET)
+		WRITEINT32(save_p, mobj->dispoffset);
 
 	WRITEUINT32(save_p, mobj->mobjnum);
 }
@@ -2942,6 +2947,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 		slope->normal.y = READFIXED(save_p);
 		slope->normal.z = READFIXED(save_p);
 	}
+	if (diff2 & MD2_DISPOFFSET)
+		mobj->dispoffset = READINT32(save_p);
+	else
+		mobj->dispoffset = mobj->info->dispoffset;
 
 	if (diff & MD_REDFLAG)
 	{
diff --git a/src/r_things.c b/src/r_things.c
index accd1e2b3cd16795a27700d23f128d25e3c99fbb..1dee17356767c8d6442bfcaab60215c7dd52bb1d 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1437,7 +1437,7 @@ static void R_ProjectSprite(mobj_t *thing)
 	fixed_t paperoffset = 0, paperdistance = 0;
 	angle_t centerangle = 0;
 
-	INT32 dispoffset = thing->info->dispoffset;
+	INT32 dispoffset = thing->dispoffset;
 
 	//SoM: 3/17/2000
 	fixed_t gz = 0, gzt = 0;
diff --git a/src/r_things.h b/src/r_things.h
index b1ff32b1ee4a3e723bb020f27a397c71e3f91297..6a6ff3042aac453d3fef3a961aabb1a71c142c8d 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -209,7 +209,7 @@ typedef struct vissprite_s
 
 	INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH];
 
-	INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
+	INT32 dispoffset; // copy of mobj->dispoffset, affects ordering but not drawing
 } vissprite_t;
 
 extern UINT32 visspritecount;