diff --git a/src/deh_soc.c b/src/deh_soc.c
index 3759cc9c7552987029edcc8f6c1e76322ef61ed3..03711ed6a7f649bd3e56ff49aef0b9430c58b0a0 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -1750,6 +1750,8 @@ void readlevelheader(MYFILE *f, INT32 num)
 				mapheaderinfo[num-1]->levelflags = (UINT16)i;
 			else if (fastcmp(word, "MENUFLAGS"))
 				mapheaderinfo[num-1]->menuflags = (UINT8)i;
+			else if (fastcmp(word, "MOBJSCALE"))
+				mapheaderinfo[num-1]->mobj_scale = get_number(word2);
 
 			// Individual triggers for level flags, for ease of use (and 2.0 compatibility)
 			else if (fastcmp(word, "SCRIPTISFILE"))
diff --git a/src/doomstat.h b/src/doomstat.h
index bde2bacc72890d47b61a6085a26c5cda33dcfad0..4f05d9349bda7ec653d3d670e797af96c113a00b 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -349,6 +349,9 @@ typedef struct
 	// NiGHTS stuff.
 	UINT8 numGradedMares;       ///< Internal. For grade support.
 	nightsgrades_t *grades;     ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful.
+	
+	// mapobjectscale
+	fixed_t mobj_scale; 		///< Replacement for TOL_ERZ3
 
 	// Music stuff.
 	UINT32 musinterfadeout;     ///< Fade out level music on intermission screen in milliseconds
@@ -558,6 +561,7 @@ extern UINT32 countdown;
 extern UINT32 countdown2;
 
 extern fixed_t gravity;
+extern fixed_t mapobjectscale;
 
 //for CTF balancing
 extern INT16 autobalance;
diff --git a/src/g_game.c b/src/g_game.c
index 5d6954b9b7cef3c6e5b34a1c2a5115fde61fdfb8..8dd68ab882a6b0e02ae2441ef2bf732610b7ae51 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -234,6 +234,7 @@ mobj_t *hunt3;
 UINT32 countdown, countdown2; // for racing
 
 fixed_t gravity;
+fixed_t mapobjectscale;
 
 INT16 autobalance; //for CTF team balance
 INT16 teamscramble; //for CTF team scramble
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index f395a83905de4ecd65bef7017c41cfb8cef8f2f0..7783b85372a8890d973d6907e495c08bc2893ba4 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -4262,8 +4262,8 @@ static void HWR_AddSprites(sector_t *sec)
 
 	// Handle all things in sector.
 	// If a limit exists, handle things a tiny bit different.
-	limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
-	hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
+	limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale;
+	hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) * mapobjectscale;
 	for (thing = sec->thinglist; thing; thing = thing->snext)
 	{
 		if (R_ThingWithinDist(thing, limit_dist, hoop_limit_dist))
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 9985e5631201752eddf1ba2abc71aa7304da8f62..a614442dbec6b440804bc3c7978b6ca2bb353e37 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -2835,6 +2835,7 @@ enum mapheaderinfo_e
 	mapheaderinfo_maxbonuslives,
 	mapheaderinfo_levelflags,
 	mapheaderinfo_menuflags,
+	mapheaderinfo_mobj_scale,
 	mapheaderinfo_selectheading,
 	mapheaderinfo_startrings,
 	mapheaderinfo_sstimer,
@@ -2883,6 +2884,7 @@ static const char *const mapheaderinfo_opt[] = {
 	"maxbonuslives",
 	"levelflags",
 	"menuflags",
+	"mobjscale",
 	"selectheading",
 	"startrings",
 	"sstimer",
@@ -3024,6 +3026,9 @@ static int mapheaderinfo_get(lua_State *L)
 	case mapheaderinfo_menuflags:
 		lua_pushinteger(L, header->menuflags);
 		break;
+	case mapheaderinfo_mobj_scale:
+		lua_pushinteger(L, header->mobj_scale);
+		break;
 	case mapheaderinfo_selectheading:
 		lua_pushstring(L, header->selectheading);
 		break;
diff --git a/src/lua_script.c b/src/lua_script.c
index 057899555480383611652c552e41bf41398b0e2b..a36f1e099458415f72db29a0e2d96382b779a0fe 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -400,6 +400,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
 	} else if (fastcmp(word,"gravity")) {
 		lua_pushinteger(L, gravity);
 		return 1;
+	} else if (fastcmp(word,"mapobjectscale")) {
+		lua_pushinteger(L, mapobjectscale);
+		return 1;
 	} else if (fastcmp(word,"VERSION")) {
 		lua_pushinteger(L, VERSION);
 		return 1;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index e1b21e295bf4226a632112a4b66fe3d4b849c485..be4e2ab9e1b98dabaf904f2bbd8586676e67c2d3 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -10921,6 +10921,8 @@ void A_SetScale(mobj_t *actor)
 			CONS_Printf("A_SetScale: No target!\n");
 		return;
 	}
+	
+	locvar1 = FixedMul(locvar1, mapobjectscale);
 
 	if ((locvar2 & 65535) == 0)
 		P_SetScale(target, locvar1, true); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 over time
diff --git a/src/p_floor.c b/src/p_floor.c
index 118b4bdbc7c11f7030380dd0472bcf74ecba5b5b..9191d514ee102675a244210709816b30905be863 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1862,8 +1862,8 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
 	}
 
 	leftmostvertex = rightmostvertex = topmostvertex = bottommostvertex = 0;
-	widthfactor = heightfactor = FRACUNIT;
-	spacing = (32<<FRACBITS);
+	widthfactor = heightfactor = mapobjectscale;
+	spacing = (32*mapobjectscale);
 	type = MT_ROCKCRUMBLE1;
 	lifetime = 3*TICRATE;
 	fromcenter = false;
diff --git a/src/p_map.c b/src/p_map.c
index b79f9d45c77ea069f079e1d2a50d6b45bfa1e646..be9f4738f6a9d3ad4fcf0482562fdccec76ff5d3 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -156,6 +156,8 @@ boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
 
 boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 {
+	const fixed_t hscale = mapobjectscale + (mapobjectscale - object->scale);
+	const fixed_t vscale = mapobjectscale + (object->scale - mapobjectscale);
 	fixed_t vertispeed = spring->info->mass;
 	fixed_t horizspeed = spring->info->damage;
 	boolean final = false;
@@ -377,10 +379,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 	}
 
 	if (vertispeed)
-		object->momz = FixedMul(vertispeed,FixedSqrt(FixedMul(object->scale, spring->scale)));
+		object->momz = FixedMul(vertispeed,FixedSqrt(FixedMul(vscale, spring->scale)));
 
 	if (horizspeed)
-		P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(object->scale, spring->scale))));
+		P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(hscale, spring->scale))));
 
 	// Re-solidify
 	spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL));
@@ -2965,7 +2967,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
 
 		if (!(thing->flags & MF_NOCLIP))
 		{
-			const fixed_t maxstep = MAXSTEPMOVE;
+			const fixed_t maxstep = FixedMul(MAXSTEPMOVE, mapobjectscale);
 
 			if (tmceilingz - tmfloorz < thing->height)
 				return false; // doesn't fit
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 1ec09ab8582adea2716db0d817b670bf4aba0d2c..2fd4c8136d787f57180bad985d323e135283ffe3 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -10684,9 +10684,15 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 	mobj->destscale = mobj->scale;
 	mobj->scalespeed = FRACUNIT/12;
 
+	if (mapobjectscale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN)
+	{
+		mobj->destscale = mapobjectscale;
+		mobj->scalespeed = mapobjectscale/12;
+	}
+	
 	// TODO: Make this a special map header
 	if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN))
-		mobj->destscale = FRACUNIT/2;
+		mobj->destscale /= 2;
 
 	// Sprite rendering
 	mobj->blendmode = AST_TRANSLUCENT;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index da73dd8a0e1470a1fafd4f5285923ea29c70b7fb..a32da1c34559c2b8b2718366bf0a16ab3d9a4611 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1974,7 +1974,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 		diff |= MD_SCALE;
 	if (mobj->destscale != mobj->scale)
 		diff |= MD_DSCALE;
-	if (mobj->scalespeed != FRACUNIT/12)
+	if (mobj->scalespeed != mapobjectscale/12)
 		diff2 |= MD2_SCALESPEED;
 
 	if (mobj == redflag)
@@ -3219,7 +3219,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 	if (diff2 & MD2_SCALESPEED)
 		mobj->scalespeed = READFIXED(save_p);
 	else
-		mobj->scalespeed = FRACUNIT/12;
+		mobj->scalespeed = mapobjectscale/12;
 	if (diff2 & MD2_CUSVAL)
 		mobj->cusval = READINT32(save_p);
 	if (diff2 & MD2_CVMEM)
@@ -4600,6 +4600,7 @@ static void P_NetArchiveMisc(boolean resending)
 	WRITEUINT32(save_p, countdown2);
 
 	WRITEFIXED(save_p, gravity);
+	WRITEFIXED(save_p, mapobjectscale);
 
 	WRITEUINT32(save_p, countdowntimer);
 	WRITEUINT8(save_p, countdowntimeup);
@@ -4698,6 +4699,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
 	countdown2 = READUINT32(save_p);
 
 	gravity = READFIXED(save_p);
+	mapobjectscale = READFIXED(save_p);
 
 	countdowntimer = (tic_t)READUINT32(save_p);
 	countdowntimeup = (boolean)READUINT8(save_p);
diff --git a/src/p_setup.c b/src/p_setup.c
index b5ed485d8a7df9512ce24a4b78f61e950280b280..1c74ea4ad25830c010d7e14df5c17ec6ed9534b6 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -14,6 +14,7 @@
 #include "doomdef.h"
 #include "d_main.h"
 #include "byteptr.h"
+#include "doomstat.h"
 #include "g_game.h"
 
 #include "p_local.h"
@@ -394,6 +395,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
 	mapheaderinfo[num]->maxbonuslives = -1;
 	mapheaderinfo[num]->levelflags = 0;
 	mapheaderinfo[num]->menuflags = 0;
+	mapheaderinfo[num]->mobj_scale = FRACUNIT;
 #if 1 // equivalent to "FlickyList = DEMO"
 	P_SetDemoFlickies(num);
 #else // equivalent to "FlickyList = NONE"
@@ -1539,7 +1541,7 @@ static void P_LoadThings(UINT8 *data)
 		mt->options = READUINT16(data);
 		mt->extrainfo = (UINT8)(mt->type >> 12);
 		Tag_FSet(&mt->tags, 0);
-		mt->scale = FRACUNIT;
+		mt->scale = mapobjectscale;
 		mt->spritexscale = mt->spriteyscale = FRACUNIT;
 		memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
 		memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
@@ -3162,7 +3164,7 @@ static void P_LoadTextmap(void)
 		mt->z = 0;
 		mt->extrainfo = 0;
 		Tag_FSet(&mt->tags, 0);
-		mt->scale = FRACUNIT;
+		mt->scale = mapobjectscale;
 		mt->spritexscale = mt->spriteyscale = FRACUNIT;
 		memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
 		memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
@@ -7226,6 +7228,9 @@ static void P_InitLevelSettings(void)
 
 	modulothing = 0;
 
+	// map object scale
+	mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale;
+	
 	// special stage tokens, emeralds, and ring total
 	tokenbits = 0;
 	runemeraldmanager = false;
diff --git a/src/p_user.c b/src/p_user.c
index 3ee13aca96989a4c7f5b94a64c8e525f275f9882..bdc0a7b5a5e3e4b40110795a33426317f6b1f2f4 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -6342,9 +6342,9 @@ static void P_SpectatorMovement(player_t *player)
 		ticmiss++;
 
 	if (cmd->buttons & BT_JUMP)
-		player->mo->z += FRACUNIT*16;
+		player->mo->z += mapobjectscale*16;
 	else if (cmd->buttons & BT_SPIN)
-		player->mo->z -= FRACUNIT*16;
+		player->mo->z -= mapobjectscale*16;
 
 	if (player->mo->z > player->mo->ceilingz - player->mo->height)
 		player->mo->z = player->mo->ceilingz - player->mo->height;
@@ -6358,14 +6358,14 @@ static void P_SpectatorMovement(player_t *player)
 	player->mo->momx = player->mo->momy = player->mo->momz = 0;
 	if (cmd->forwardmove != 0)
 	{
-		P_Thrust(player->mo, player->mo->angle, cmd->forwardmove*(FRACUNIT/2));
+		P_Thrust(player->mo, player->mo->angle, cmd->forwardmove*(mapobjectscale/2));
 
 		// Quake-style flying spectators :D
-		player->mo->momz += FixedMul(cmd->forwardmove*(FRACUNIT/2), AIMINGTOSLOPE(player->aiming));
+		player->mo->momz += FixedMul(cmd->forwardmove*(mapobjectscale/2), AIMINGTOSLOPE(player->aiming));
 	}
 	if (cmd->sidemove != 0)
 	{
-		P_Thrust(player->mo, player->mo->angle-ANGLE_90, cmd->sidemove*(FRACUNIT/2));
+		P_Thrust(player->mo, player->mo->angle-ANGLE_90, cmd->sidemove*(mapobjectscale/2));
 	}
 }
 
@@ -9142,12 +9142,14 @@ static void P_NukeAllPlayers(player_t *player)
 //
 void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
 {
-	const fixed_t ns = 60 << FRACBITS;
+	const fixed_t ns = 60 * mapobjectscale;
 	mobj_t *mo;
 	angle_t fa;
 	thinker_t *think;
 	INT32 i;
 
+	radius = FixedMul(radius, mapobjectscale);
+	
 	for (i = 0; i < 16; i++)
 	{
 		fa = (i*(FINEANGLES/16));
@@ -10013,8 +10015,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		return true;
 	}
 
-	thiscam->radius = FixedMul(20*FRACUNIT, mo->scale);
-	thiscam->height = FixedMul(16*FRACUNIT, mo->scale);
+	thiscam->radius = FixedMul(20*mapobjectscale, mo->scale);
+	thiscam->height = FixedMul(16*mapobjectscale, mo->scale);
 
 	// Don't run while respawning from a starpost
 	// Inu 4/8/13 Why not?!
diff --git a/src/s_sound.c b/src/s_sound.c
index 32353a59c2d590dd8ea1f74b47399de0886684d0..b2e51735f56b4d79acfb3f49e6931ad7afa16381 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -1081,7 +1081,7 @@ fixed_t S_CalculateSoundDistance(fixed_t sx1, fixed_t sy1, fixed_t sz1, fixed_t
 
 	approx_dist <<= FRACBITS;
 
-	return approx_dist;
+	return FixedDiv(approx_dist, mapobjectscale); // approx_dist
 }
 
 //