From 86e2fefcacec985ff8f5c20ea8428f96f61d4518 Mon Sep 17 00:00:00 2001
From: MascaraSnake <jonassauer27@gmail.com>
Date: Thu, 30 Dec 2021 18:19:42 +0100
Subject: [PATCH] Add sector gravity field for UDMF

---
 src/lua_maplib.c |  8 ++++++++
 src/p_enemy.c    | 15 +++------------
 src/p_mobj.c     | 14 ++++++--------
 src/p_saveg.c    |  8 +++++++-
 src/p_setup.c    |  8 +++++++-
 src/p_spec.c     | 10 +++++++++-
 src/p_spec.h     |  1 +
 src/r_defs.h     |  4 ++--
 8 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index a74c6fc973..0a147acbb3 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -51,6 +51,7 @@ enum sector_e {
 	sector_cslope,
 	sector_flags,
 	sector_friction,
+	sector_gravity,
 };
 
 static const char *const sector_opt[] = {
@@ -76,6 +77,7 @@ static const char *const sector_opt[] = {
 	"c_slope",
 	"flags",
 	"friction",
+	"gravity",
 	NULL};
 
 enum subsector_e {
@@ -659,6 +661,9 @@ static int sector_get(lua_State *L)
 	case sector_friction: // friction
 		lua_pushinteger(L, sector->friction);
 		return 1;
+	case sector_gravity: // gravity
+		lua_pushfixed(L, sector->gravity);
+		return 1;
 	}
 	return 0;
 }
@@ -749,6 +754,9 @@ static int sector_set(lua_State *L)
 	case sector_flags:
 		sector->flags = luaL_checkinteger(L, 3);
 		break;
+	case sector_gravity:
+		sector->gravity = luaL_checkfixed(L, 3);
+		break;
 	}
 	return 0;
 }
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 5c92bdc060..9cf5687e70 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -11461,10 +11461,7 @@ void A_BrakLobShot(mobj_t *actor)
 		return; // Don't even bother if we've got nothing to aim at.
 
 	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
+	g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector));
 
 	// Look up distance between actor and its target
 	x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y);
@@ -11576,10 +11573,7 @@ void A_NapalmScatter(mobj_t *actor)
 		airtime = 16<<FRACBITS;
 
 	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
+	g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector));
 
 	// vy = (g*(airtime-1))/2
 	vy = FixedMul(g,(airtime-(1<<FRACBITS)))>>1;
@@ -12289,10 +12283,7 @@ void A_Boss5Jump(mobj_t *actor)
 		return; // Don't even bother if we've got nothing to aim at.
 
 	// Look up actor's current gravity situation
-	if (actor->subsector->sector->gravity)
-		g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000)));
-	else
-		g = gravity;
+	g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector));
 
 	// Look up distance between actor and its tracer
 	x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 428274679e..aea7964bef 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1446,6 +1446,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 	if (mo->subsector->sector->ffloors) // Check for 3D floor gravity too.
 	{
 		ffloor_t *rover;
+		fixed_t gravfactor;
 
 		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
 		{
@@ -1455,11 +1456,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 			if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
 				goopgravity = true;
 
-			if (!(rover->master->frontsector->gravity))
+			gravfactor = P_GetSectorGravityFactor(mo->subsector->sector);
+
+			if (gravfactor == FRACUNIT)
 				continue;
 
-			gravityadd = -FixedMul(gravity,
-				(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+			gravityadd = -FixedMul(gravity, gravfactor);
 
 			if (rover->master->frontsector->verticalflip && gravityadd > 0)
 				mo->eflags |= MFE_VERTICALFLIP;
@@ -1471,11 +1473,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 
 	if (no3dfloorgrav)
 	{
-		if (mo->subsector->sector->gravity)
-			gravityadd = -FixedMul(gravity,
-				(FixedDiv(*mo->subsector->sector->gravity>>FRACBITS, 1000)));
-		else
-			gravityadd = -gravity;
+		gravityadd = -FixedMul(gravity, P_GetSectorGravityFactor(mo->subsector->sector));
 
 		if (mo->subsector->sector->verticalflip && gravityadd > 0)
 			mo->eflags |= MFE_VERTICALFLIP;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 0f56799409..66df83603b 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -853,6 +853,7 @@ static void P_NetUnArchiveWaypoints(void)
 #define SD_FLOORLIGHT 0x08
 #define SD_CEILLIGHT 0x10
 #define SD_FLAG      0x20
+#define SD_GRAVITY   0x40
 
 #define LD_FLAG     0x01
 #define LD_SPECIAL  0x02
@@ -1040,6 +1041,8 @@ static void ArchiveSectors(void)
 			diff3 |= SD_CEILLIGHT;
 		if (ss->flags != spawnss->flags)
 			diff3 |= SD_FLAG;
+		if (ss->gravity != spawnss->gravity)
+			diff3 |= SD_GRAVITY;
 
 		if (ss->ffloors && CheckFFloorDiff(ss))
 			diff |= SD_FFLOORS;
@@ -1106,6 +1109,8 @@ static void ArchiveSectors(void)
 			}
 			if (diff3 & SD_FLAG)
 				WRITEUINT32(save_p, ss->flags);
+			if (diff3 & SD_GRAVITY)
+				WRITEFIXED(save_p, ss->gravity);
 			if (diff & SD_FFLOORS)
 				ArchiveFFloors(ss);
 		}
@@ -1209,7 +1214,8 @@ static void UnArchiveSectors(void)
 		}
 		if (diff3 & SD_FLAG)
 			sectors[i].flags = READUINT32(save_p);
-
+		if (diff3 & SD_GRAVITY)
+			sectors[i].gravity = READFIXED(save_p);
 
 		if (diff & SD_FFLOORS)
 			UnArchiveFFloors(&sectors[i]);
diff --git a/src/p_setup.c b/src/p_setup.c
index 85d4ee5dce..2bcde2b92f 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -999,7 +999,7 @@ static void P_InitializeSector(sector_t *ss)
 
 	ss->extra_colormap = NULL;
 
-	ss->gravity = NULL;
+	ss->gravityptr = NULL;
 	ss->verticalflip = false;
 
 	ss->cullheight = NULL;
@@ -1047,6 +1047,8 @@ static void P_LoadSectors(UINT8 *data)
 
 		ss->colormap_protected = false;
 
+		ss->gravity = FRACUNIT;
+
 		ss->flags = MSF_FLIPSPECIAL_FLOOR;
 
 		P_InitializeSector(ss);
@@ -1676,6 +1678,8 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val)
 		sectors[i].flags |= MSF_HEATWAVE;
 	else if (fastcmp(param, "friction"))
 		sectors[i].friction = atol(val);
+	else if (fastcmp(param, "gravity"))
+		sectors[i].gravity = FLOAT_TO_FIXED(atof(val));
 }
 
 static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val)
@@ -1952,6 +1956,8 @@ static void P_LoadTextmap(void)
 
 		sc->colormap_protected = false;
 
+		sc->gravity = FRACUNIT;
+
 		sc->flags = MSF_FLIPSPECIAL_FLOOR;
 
 		textmap_colormap.used = false;
diff --git a/src/p_spec.c b/src/p_spec.c
index 69b76aee75..846ce93769 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -5958,6 +5958,14 @@ static boolean P_CheckGametypeRules(INT32 checktype, UINT32 target)
 	}
 }
 
+fixed_t P_GetSectorGravityFactor(sector_t *sec)
+{
+	if (sec->gravityptr)
+		return FixedDiv(*sec->gravityptr >> FRACBITS, 1000);
+	else
+		return sec->gravity;
+}
+
 /** After the map has loaded, scans for specials that spawn 3Dfloors and
   * thinkers.
   *
@@ -6105,7 +6113,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 				sec = sides[*lines[i].sidenum].sector - sectors;
 				TAG_ITER_SECTORS(tag, s)
 				{
-					sectors[s].gravity = &sectors[sec].floorheight; // This allows it to change in realtime!
+					sectors[s].gravityptr = &sectors[sec].floorheight; // This allows it to change in realtime!
 
 					if (lines[i].flags & ML_NOCLIMB)
 						sectors[s].verticalflip = true;
diff --git a/src/p_spec.h b/src/p_spec.h
index 6b1db7faf4..82f858a059 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -467,6 +467,7 @@ void P_SetupLevelFlatAnims(void);
 // at map load
 void P_InitSpecials(void);
 void P_ApplyFlatAlignment(sector_t* sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling);
+fixed_t P_GetSectorGravityFactor(sector_t *sec);
 void P_SpawnSpecials(boolean fromnetsave);
 
 // every tic
diff --git a/src/r_defs.h b/src/r_defs.h
index 105494bd70..0fd13b7077 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -366,8 +366,8 @@ typedef struct sector_s
 	extracolormap_t *extra_colormap;
 	boolean colormap_protected;
 
-	// This points to the master's floorheight, so it can be changed in realtime!
-	fixed_t *gravity; // per-sector gravity
+	fixed_t gravity; // per-sector gravity factor
+	fixed_t *gravityptr; // For binary format: Read gravity from floor height of master sector
 	boolean verticalflip; // If gravity < 0, then allow flipped physics
 	sectorflags_t flags;
 
-- 
GitLab