From f1c41539de2dc53e192ff1167a7c87b6dd30d259 Mon Sep 17 00:00:00 2001
From: Randy Heit <rheit@zdoom.fake>
Date: Mon, 22 Jan 2007 23:50:09 +0000
Subject: [PATCH] - Fixed: LocalViewPitch could overflow and wrap around when a
 netgame stalls.

SVN r459 (trunk)
---
 docs/rh-log.txt |  1 +
 src/d_net.cpp   |  5 +++--
 src/g_game.cpp  | 25 +++++++++++++++++++++++--
 src/r_main.cpp  | 29 ++++++++++++++++++++++++++++-
 4 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 3bfff59cf..d0fcefec9 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,4 +1,5 @@
 January 22, 2007
+- Fixed: LocalViewPitch could overflow and wrap around when a netgame stalls.
 - Changed the vertheight and rounding-error-checking code in
   DCanvas::DrawTexture() to calculate off the actual bottom of the image
   instead of the height, improving precision. Now the scaled status bar is
diff --git a/src/d_net.cpp b/src/d_net.cpp
index c66157284..6f5d32064 100644
--- a/src/d_net.cpp
+++ b/src/d_net.cpp
@@ -704,10 +704,11 @@ void GetPackets (void)
 		netnode = doomcom.remotenode;
 		netconsole = playerfornode[netnode] & ~PL_DRONE;
 
-		// [RH] Get "ping" times
+		// [RH] Get "ping" times - totally useless, since it's bound to the frequency
+		// packets go out at.
 		lastrecvtime[netconsole] = currrecvtime[netconsole];
 		currrecvtime[netconsole] = I_MSTime ();
-		
+
 		// check for exiting the game
 		if (netbuffer[0] & NCMD_EXIT)
 		{
diff --git a/src/g_game.cpp b/src/g_game.cpp
index 800c36bde..301cf5927 100644
--- a/src/g_game.cpp
+++ b/src/g_game.cpp
@@ -646,13 +646,34 @@ void G_AddViewPitch (int look)
 	{
 		return;
 	}
+	look <<= 16;
 	if (dmflags & DF_NO_FREELOOK)
 	{
 		LocalViewPitch = 0;
 	}
-	else
+	else if (look > 0)
 	{
-		LocalViewPitch += look << 16;
+		// Avoid overflowing
+		if (LocalViewPitch + look <= LocalViewPitch)
+		{
+			LocalViewPitch = 0x78000000;
+		}
+		else
+		{
+			LocalViewPitch = MIN(LocalViewPitch + look, 0x78000000);
+		}
+	}
+	else if (look < 0)
+	{
+		// Avoid overflowing
+		if (LocalViewPitch + look >= LocalViewPitch)
+		{
+			LocalViewPitch = -0x78000000;
+		}
+		else
+		{
+			LocalViewPitch = MAX(LocalViewPitch + look, -0x78000000);
+		}
 	}
 	if (look != 0)
 	{
diff --git a/src/r_main.cpp b/src/r_main.cpp
index 7c0fbbeff..837f00df7 100644
--- a/src/r_main.cpp
+++ b/src/r_main.cpp
@@ -877,7 +877,34 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
 		!LocalKeyboardTurner)
 	{
 		viewangle = iview->nviewangle + (LocalViewAngle & 0xFFFF0000);
-		viewpitch = clamp<int> (iview->nviewpitch - (LocalViewPitch & 0xFFFF0000), -ANGLE_1*MAX_UP_ANGLE, +ANGLE_1*MAX_DN_ANGLE);
+
+		fixed_t delta = -(signed)(LocalViewPitch & 0xFFFF0000);
+
+		viewpitch = iview->nviewpitch;
+		if (delta > 0)
+		{
+			// Avoid overflowing viewpitch (can happen when a netgame is stalled)
+			if (viewpitch + delta <= viewpitch)
+			{
+				viewpitch = +ANGLE_1*MAX_DN_ANGLE;
+			}
+			else
+			{
+				viewpitch = MIN(viewpitch + delta, +ANGLE_1*MAX_DN_ANGLE);
+			}
+		}
+		else if (delta < 0)
+		{
+			// Avoid overflowing viewpitch (can happen when a netgame is stalled)
+			if (viewpitch + delta >= viewpitch)
+			{
+				viewpitch = -ANGLE_1*MAX_UP_ANGLE;
+			}
+			else
+			{
+				viewpitch = MAX(viewpitch + delta, -ANGLE_1*MAX_UP_ANGLE);
+			}
+		}
 	}
 	else
 	{