From 8bfcb8c939649db0a59a6720039df4ebad934f17 Mon Sep 17 00:00:00 2001
From: Mitchell Richters <mjr4077au@gmail.com>
Date: Tue, 20 Sep 2022 09:54:01 +1000
Subject: [PATCH] - Floatify `InputPacket::fvel` and `InputPacket::svel`.

* Since all velocities are floated, we can now take each game's keymove scaling into its ticker and use a consistent keymove size, making non-mouselook and controller input truly identical across the games without having to try and fudge any values.
---
 source/core/d_protocol.cpp           |   8 +-
 source/core/gameinput.cpp            | 118 +++++++--------------------
 source/core/gamestruct.h             |   1 -
 source/core/inputstate.cpp           |   8 +-
 source/core/packet.h                 |   4 +-
 source/games/blood/src/blood.h       |   1 -
 source/games/blood/src/player.cpp    |  24 +++---
 source/games/duke/src/duke3d.h       |   1 -
 source/games/duke/src/inlines.h      |   4 +-
 source/games/duke/src/input.cpp      |   7 +-
 source/games/duke/src/player_d.cpp   |   4 +-
 source/games/duke/src/player_r.cpp   |   4 +-
 source/games/duke/src/sectors_d.cpp  |   2 +-
 source/games/exhumed/src/exhumed.cpp |   2 +-
 source/games/exhumed/src/exhumed.h   |   1 -
 source/games/sw/src/game.h           |   1 -
 source/games/sw/src/input.cpp        |   5 +-
 source/games/sw/src/player.cpp       |  28 +++----
 18 files changed, 83 insertions(+), 140 deletions(-)

diff --git a/source/core/d_protocol.cpp b/source/core/d_protocol.cpp
index 83e72b9bd..1cc0e5d2d 100644
--- a/source/core/d_protocol.cpp
+++ b/source/core/d_protocol.cpp
@@ -164,9 +164,9 @@ int UnpackUserCmd (InputPacket *ucmd, const InputPacket *basis, uint8_t **stream
 		if (flags & UCMDF_YAW)
 			ucmd->avel = ReadFloat(stream);
 		if (flags & UCMDF_FORWARDMOVE)
-			ucmd->fvel = ReadWord (stream);
+			ucmd->fvel = ReadFloat(stream);
 		if (flags & UCMDF_SIDEMOVE)
-			ucmd->svel = ReadWord (stream);
+			ucmd->svel = ReadFloat(stream);
 	}
 
 	return int(*stream - start);
@@ -206,12 +206,12 @@ int PackUserCmd (const InputPacket *ucmd, const InputPacket *basis, uint8_t **st
 	if (ucmd->fvel != basis->fvel)
 	{
 		flags |= UCMDF_FORWARDMOVE;
-		WriteWord (ucmd->fvel, stream);
+		WriteFloat (ucmd->fvel, stream);
 	}
 	if (ucmd->svel != basis->svel)
 	{
 		flags |= UCMDF_SIDEMOVE;
-		WriteWord (ucmd->svel, stream);
+		WriteFloat (ucmd->svel, stream);
 	}
 
 	// Write the packing bits
diff --git a/source/core/gameinput.cpp b/source/core/gameinput.cpp
index bc7a960cd..891a47a5f 100644
--- a/source/core/gameinput.cpp
+++ b/source/core/gameinput.cpp
@@ -143,104 +143,48 @@ SW:   3 * 1.40625 * 40 = 168.75; // Precisely, ((((3 * 12) + ((3 * 12) / 4)) * 3
 Average: 234.375;
 */
 
-static constexpr double RUNNINGTURNBASE = 1548.75;
-static constexpr double NORMALTURNBASE = 890.625;
-static constexpr double PREAMBLEBASE = 234.375;
-static constexpr double PREAMBLESCALE = PREAMBLEBASE / NORMALTURNBASE;
+static constexpr double TURNSPEEDS[3] = { 234.375, 890.625, 1548.75 };
+static constexpr double PREAMBLESCALE = TURNSPEEDS[0] / TURNSPEEDS[1];
 
 void processMovement(InputPacket* const currInput, InputPacket* const inputBuffer, ControlInfo* const hidInput, double const scaleAdjust, int const drink_amt, bool const allowstrafe, double const turnscale)
 {
-	// set up variables
-	int const running = !!(inputBuffer->actions & SB_RUN);
-	int const keymove = gi->playerKeyMove() << running;
-	bool const strafing = buttonMap.ButtonDown(gamefunc_Strafe) && allowstrafe;
-	float const mousevelscale = keymove * (1.f / 160.f);
-	double const hidprescale = g_gameType & GAMEFLAG_PSEXHUMED ? 5. : 1.;
-	double const hidspeed = getTicrateScale(RUNNINGTURNBASE) * turnscale * BAngToDegree;
+	// set up variables.
+	int const keymove = 1 << int(!!(inputBuffer->actions & SB_RUN));
+	float const hidspeed = float(getTicrateScale(TURNSPEEDS[2]) * turnscale * BAngToDegree);
+	float const scaleAdjustf = float(scaleAdjust);
 
-	// process mouse and initial controller input.
-	if (!strafing)
-		currInput->avel += float(hidInput->mouseturnx + (scaleAdjust * hidInput->dyaw * hidspeed));
+	// determine player input.
+	auto const turning = buttonMap.ButtonDown(gamefunc_Turn_Right) - buttonMap.ButtonDown(gamefunc_Turn_Left);
+	auto const moving = buttonMap.ButtonDown(gamefunc_Move_Forward) - buttonMap.ButtonDown(gamefunc_Move_Backward) + hidInput->dz * scaleAdjustf;
+	auto const strafing = buttonMap.ButtonDown(gamefunc_Strafe_Right) - buttonMap.ButtonDown(gamefunc_Strafe_Left) - hidInput->dx * scaleAdjustf;
+
+	// process player angle input.
+	if (!(buttonMap.ButtonDown(gamefunc_Strafe) && allowstrafe))
+	{
+		float const turndir = clamp(turning + strafing * !allowstrafe, -1.f, 1.f);
+		float const turnspeed = float(getTicrateScale(TURNSPEEDS[keymove]) * turnscale * BAngToDegree * (isTurboTurnTime() ? 1. : PREAMBLESCALE));
+		currInput->avel += hidInput->mouseturnx + (hidInput->dyaw * hidspeed + turndir * turnspeed) * scaleAdjustf;
+		if (turndir) updateTurnHeldAmt(scaleAdjust); else resetTurnHeldAmt();
+	}
 	else
-		currInput->svel += int16_t(((hidInput->mousemovex * mousevelscale) + (scaleAdjust * hidInput->dyaw * keymove)) * hidprescale);
+	{
+		currInput->svel += hidInput->mousemovex + (hidInput->dyaw + turning) * keymove * scaleAdjustf;
+	}
 
+	// process player pitch input.
 	if (!(inputBuffer->actions & SB_AIMMODE))
-		currInput->horz -= hidInput->mouseturny;
+		currInput->horz -= hidInput->mouseturny + hidInput->dpitch * hidspeed * scaleAdjustf;
 	else
-		currInput->fvel -= int16_t(hidInput->mousemovey * mousevelscale * hidprescale);
+		currInput->fvel -= hidInput->mousemovey + hidInput->dpitch * keymove * scaleAdjustf;
 
-	// process remaining controller input.
-	currInput->horz -= float(scaleAdjust * hidInput->dpitch * hidspeed);
-	currInput->svel -= int16_t(scaleAdjust * hidInput->dx * keymove * hidprescale);
-	currInput->fvel += int16_t(scaleAdjust * hidInput->dz * keymove * hidprescale);
-
-	// process keyboard turning keys.
-	if (!strafing)
-	{
-		bool const turnleft = buttonMap.ButtonDown(gamefunc_Turn_Left) || (buttonMap.ButtonDown(gamefunc_Strafe_Left) && !allowstrafe);
-		bool const turnright = buttonMap.ButtonDown(gamefunc_Turn_Right) || (buttonMap.ButtonDown(gamefunc_Strafe_Right) && !allowstrafe);
-
-		if (turnleft || turnright)
-		{
-			double const turnspeed = getTicrateScale(running ? RUNNINGTURNBASE : NORMALTURNBASE) * turnscale * BAngToDegree;
-			float const turnamount = float(scaleAdjust * turnspeed * (isTurboTurnTime() ? 1. : PREAMBLESCALE));
-
-			if (turnleft)
-				currInput->avel -= turnamount;
-
-			if (turnright)
-				currInput->avel += turnamount;
-
-			updateTurnHeldAmt(scaleAdjust);
-		}
-		else
-		{
-			resetTurnHeldAmt();
-		}
-	}
-	else
-	{
-		if (buttonMap.ButtonDown(gamefunc_Turn_Left))
-			currInput->svel -= keymove;
-
-		if (buttonMap.ButtonDown(gamefunc_Turn_Right))
-			currInput->svel += keymove;
-	}
-
-	// process keyboard side velocity keys.
-	if (buttonMap.ButtonDown(gamefunc_Strafe_Left) && allowstrafe)
-		currInput->svel -= keymove;
-
-	if (buttonMap.ButtonDown(gamefunc_Strafe_Right) && allowstrafe)
-		currInput->svel += keymove;
-
-	// process keyboard forward velocity keys.
-	if (!(isRR() && drink_amt >= 66 && drink_amt <= 87))
-	{
-		if (buttonMap.ButtonDown(gamefunc_Move_Forward))
-			currInput->fvel += keymove;
-
-		if (buttonMap.ButtonDown(gamefunc_Move_Backward))
-			currInput->fvel -= keymove;
-	}
-	else
-	{
-		if (buttonMap.ButtonDown(gamefunc_Move_Forward))
-		{
-			currInput->fvel += keymove;
-			currInput->svel -= drink_amt & 1 ? keymove : -keymove;
-		}
-
-		if (buttonMap.ButtonDown(gamefunc_Move_Backward))
-		{
-			currInput->fvel -= keymove;
-			currInput->svel += drink_amt & 1 ? keymove : -keymove;
-		}
-	}
+	// process movement input.
+	currInput->fvel += moving * keymove;
+	currInput->svel += strafing * keymove * allowstrafe;
+	if (isRR() && drink_amt >= 66 && drink_amt <= 87) currInput->svel += drink_amt & 1 ? -currInput->fvel : currInput->fvel;
 
 	// add collected input to game's local input accumulation packet.
-	inputBuffer->fvel = clamp(inputBuffer->fvel + currInput->fvel, -keymove, keymove);
-	inputBuffer->svel = clamp(inputBuffer->svel + currInput->svel, -keymove, keymove);
+	inputBuffer->fvel = clamp<float>(inputBuffer->fvel + currInput->fvel, -keymove, keymove);
+	inputBuffer->svel = clamp<float>(inputBuffer->svel + currInput->svel, -keymove, keymove);
 	inputBuffer->avel += currInput->avel;
 	inputBuffer->horz += currInput->horz;
 }
diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h
index 0d53ad5e4..1678672f3 100644
--- a/source/core/gamestruct.h
+++ b/source/core/gamestruct.h
@@ -111,7 +111,6 @@ struct GameInterface
 	virtual void SetTileProps(int tile, int surf, int vox, int shade) {}
 	virtual fixed_t playerHorizMin() { return IntToFixed(-200); }
 	virtual fixed_t playerHorizMax() { return IntToFixed(200); }
-	virtual int playerKeyMove() { return 0; }
 	virtual void WarpToCoords(double x, double y, double z, DAngle a, int h) {}
 	virtual void ToggleThirdPerson() { }
 	virtual void SwitchCoopView() { Printf("Unsupported command\n"); }
diff --git a/source/core/inputstate.cpp b/source/core/inputstate.cpp
index b14002e9c..82de77d64 100644
--- a/source/core/inputstate.cpp
+++ b/source/core/inputstate.cpp
@@ -67,8 +67,10 @@ CVARD(Bool, invertmouse, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "invert vertic
 
 void InputState::GetMouseDelta(ControlInfo * hidInput)
 {
-	hidInput->mouseturnx = g_mousePos.X * m_yaw * backendinputscale();
-	hidInput->mouseturny = g_mousePos.Y * m_pitch * backendinputscale();
+	g_mousePos *= backendinputscale();
+
+	hidInput->mouseturnx = g_mousePos.X * m_yaw;
+	hidInput->mouseturny = g_mousePos.Y * m_pitch;
 	hidInput->mousemovex = g_mousePos.X * m_side;
 	hidInput->mousemovey = g_mousePos.Y * m_forward;
 
@@ -84,7 +86,7 @@ void InputState::GetMouseDelta(ControlInfo * hidInput)
 		hidInput->mousemovey = -hidInput->mousemovey;
 	}
 
-	g_mousePos = {};
+	g_mousePos.Zero();
 }
 
 //==========================================================================
diff --git a/source/core/packet.h b/source/core/packet.h
index 55afc9f33..9c33dd899 100644
--- a/source/core/packet.h
+++ b/source/core/packet.h
@@ -69,8 +69,8 @@ enum
 
 struct InputPacket
 {
-    int16_t svel;
-    int16_t fvel;
+    float svel;
+    float fvel;
     float avel;
     float horz;
     ESyncBits actions;
diff --git a/source/games/blood/src/blood.h b/source/games/blood/src/blood.h
index 89ed3f35c..fe4c427e4 100644
--- a/source/games/blood/src/blood.h
+++ b/source/games/blood/src/blood.h
@@ -135,7 +135,6 @@ struct GameInterface : public ::GameInterface
 	void SetTileProps(int til, int surf, int vox, int shade) override;
 	fixed_t playerHorizMin() override { return IntToFixed(-180); }
 	fixed_t playerHorizMax() override { return IntToFixed(120); }
-	int playerKeyMove() override { return 1024; }
 	void WarpToCoords(double x, double y, double z, DAngle a, int h) override;
 	void ToggleThirdPerson() override;
 	void SwitchCoopView() override;
diff --git a/source/games/blood/src/player.cpp b/source/games/blood/src/player.cpp
index 1e2b94314..c91beb10c 100644
--- a/source/games/blood/src/player.cpp
+++ b/source/games/blood/src/player.cpp
@@ -102,30 +102,30 @@ POSTURE gPostureDefaults[kModeMax][kPostureMax] = {
 
 	// normal human
 	{
-		{ FixedToFloat<24>(0x4000), FixedToFloat<24>(0x4000), FixedToFloat<24>(0x4000), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(0xbaaaa), -FixedToFloat(0x175555) },
-		{ FixedToFloat<24>(0x1200), FixedToFloat<24>(0x1200), FixedToFloat<24>(0x1200), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
-		{ FixedToFloat<24>(0x2000), FixedToFloat<24>(0x2000), FixedToFloat<24>(0x2000), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
+		{ FixedToFloat<14>(0x4000), FixedToFloat<14>(0x4000), FixedToFloat<14>(0x4000), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(0xbaaaa), -FixedToFloat(0x175555) },
+		{ FixedToFloat<14>(0x1200), FixedToFloat<14>(0x1200), FixedToFloat<14>(0x1200), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
+		{ FixedToFloat<14>(0x2000), FixedToFloat<14>(0x2000), FixedToFloat<14>(0x2000), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
 	},
 
 	// normal beast
 	{
-		{ FixedToFloat<24>(0x4000), FixedToFloat<24>(0x4000), FixedToFloat<24>(0x4000), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(0xbaaaa), -FixedToFloat(0x175555) },
-		{ FixedToFloat<24>(0x1200), FixedToFloat<24>(0x1200), FixedToFloat<24>(0x1200), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
-		{ FixedToFloat<24>(0x2000), FixedToFloat<24>(0x2000), FixedToFloat<24>(0x2000), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
+		{ FixedToFloat<14>(0x4000), FixedToFloat<14>(0x4000), FixedToFloat<14>(0x4000), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(0xbaaaa), -FixedToFloat(0x175555) },
+		{ FixedToFloat<14>(0x1200), FixedToFloat<14>(0x1200), FixedToFloat<14>(0x1200), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
+		{ FixedToFloat<14>(0x2000), FixedToFloat<14>(0x2000), FixedToFloat<14>(0x2000), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
 	},
 
 	// shrink human
 	{
-		{ FixedToFloat<24>(10384), FixedToFloat<24>(10384), FixedToFloat<24>(10384), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(564586), -FixedToFloat(1329173) },
-		{ FixedToFloat<24>(2108), FixedToFloat<24>(2108), FixedToFloat<24>(2108), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
-		{ FixedToFloat<24>(2192), FixedToFloat<24>(2192), FixedToFloat<24>(2192), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
+		{ FixedToFloat<14>(10384), FixedToFloat<14>(10384), FixedToFloat<14>(10384), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(564586), -FixedToFloat(1329173) },
+		{ FixedToFloat<14>(2108), FixedToFloat<14>(2108), FixedToFloat<14>(2108), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
+		{ FixedToFloat<14>(2192), FixedToFloat<14>(2192), FixedToFloat<14>(2192), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
 	},
 
 	// grown human
 	{
-		{ FixedToFloat<24>(19384), FixedToFloat<24>(19384), FixedToFloat<24>(19384), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(1014586), -FixedToFloat(1779173) },
-		{ FixedToFloat<24>(5608), FixedToFloat<24>(5608), FixedToFloat<24>(5608), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
-		{ FixedToFloat<24>(11192), FixedToFloat<24>(11192), FixedToFloat<24>(11192), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
+		{ FixedToFloat<14>(19384), FixedToFloat<14>(19384), FixedToFloat<14>(19384), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 22, 18, 36, 12, -FixedToFloat(1014586), -FixedToFloat(1779173) },
+		{ FixedToFloat<14>(5608), FixedToFloat<14>(5608), FixedToFloat<14>(5608), 14, 17, 0.09375, 0.0625, 0.125, 0.3125, 20, 16, 44, -6, FixedToFloat(0x5b05), 0 },
+		{ FixedToFloat<14>(11192), FixedToFloat<14>(11192), FixedToFloat<14>(11192), 22, 28, 0.09375, 0.0625, 0.0625, 0.15625, 8, 6, 44, -6, 0, 0 },
 	},
 };
 
diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h
index 4fe4b95ce..43dac3257 100644
--- a/source/games/duke/src/duke3d.h
+++ b/source/games/duke/src/duke3d.h
@@ -51,7 +51,6 @@ struct GameInterface : public ::GameInterface
 	void NewGame(MapRecord* map, int skill, bool) override;
 	void LevelCompleted(MapRecord* map, int skill) override;
 	bool DrawAutomapPlayer(const DVector2& mxy, const DVector2& cpos, const DAngle cang, const DVector2& xydim, const double czoom, double const interpfrac) override;
-	int playerKeyMove() override { return 40; }
 	void WarpToCoords(double x, double y, double z, DAngle ang, int horz) override;
 	void ToggleThirdPerson() override;
 	void SwitchCoopView() override;
diff --git a/source/games/duke/src/inlines.h b/source/games/duke/src/inlines.h
index 683ce6daf..2a706d9c0 100644
--- a/source/games/duke/src/inlines.h
+++ b/source/games/duke/src/inlines.h
@@ -167,12 +167,12 @@ inline bool PlayerUseItem(int pl, int num)
 	return ps[pl].sync.isItemUsed(num - 1);
 }
 
-inline int PlayerInputSideVel(int pl)
+inline float PlayerInputSideVel(int pl)
 {
 	return ps[pl].sync.svel;
 }
 
-inline int PlayerInputForwardVel(int pl)
+inline float PlayerInputForwardVel(int pl)
 {
 	return ps[pl].sync.fvel;
 }
diff --git a/source/games/duke/src/input.cpp b/source/games/duke/src/input.cpp
index c4fd9b84f..2453b13fb 100644
--- a/source/games/duke/src/input.cpp
+++ b/source/games/duke/src/input.cpp
@@ -762,7 +762,7 @@ static void processVehicleInput(player_struct *p, ControlInfo* const hidInput, I
 		input.avel = (float)boatApplyTurn(p, hidInput, kbdLeft, kbdRight, scaleAdjust);
 	}
 
-	loc.fvel = clamp<int16_t>(p->MotoSpeed, -(MAXVELMOTO >> 3), MAXVELMOTO);
+	loc.fvel = clamp<float>(p->MotoSpeed, -(MAXVELMOTO >> 3), MAXVELMOTO) * (1.f / 40.f);
 	input.avel *= BAngToDegree;
 	loc.avel += input.avel;
 }
@@ -852,8 +852,9 @@ void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdju
 	if (packet)
 	{
 		*packet = loc;
-		packet->fvel = MulScale(loc.fvel, p->angle.ang.Cos() * (1 << 14), 9) - MulScale(loc.svel, p->angle.ang.Sin() * (1 << 14), 9) + p->fric.X * 512.;
-		packet->svel = MulScale(loc.fvel, p->angle.ang.Sin() * (1 << 14), 9) + MulScale(loc.svel, p->angle.ang.Cos() * (1 << 14), 9) + p->fric.Y * 512.;
+		auto velvect = DVector2(loc.fvel, loc.svel).Rotated(p->angle.ang) + p->fric;
+		packet->fvel = velvect.X;
+		packet->svel = velvect.Y;
 		loc = {};
 	}
 }
diff --git a/source/games/duke/src/player_d.cpp b/source/games/duke/src/player_d.cpp
index 26a34664a..1c5c5349d 100644
--- a/source/games/duke/src/player_d.cpp
+++ b/source/games/duke/src/player_d.cpp
@@ -2988,8 +2988,8 @@ void processinput_d(int snum)
 		if (p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400)
 			doubvel <<= 1;
 
-		p->vel.X += (sb_fvel * doubvel) / 4096.;
-		p->vel.Y += (sb_svel * doubvel) / 4096.;
+		p->vel.X += sb_fvel * doubvel * (5. / 16.);
+		p->vel.Y += sb_svel * doubvel * (5. / 16.);
 
 		bool check;
 
diff --git a/source/games/duke/src/player_r.cpp b/source/games/duke/src/player_r.cpp
index d342acd31..a29ec75d7 100644
--- a/source/games/duke/src/player_r.cpp
+++ b/source/games/duke/src/player_r.cpp
@@ -3700,8 +3700,8 @@ void processinput_r(int snum)
 		if (p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400)
 			doubvel <<= 1;
 
-		p->vel.X += (sb_fvel * doubvel) / 4096.;
-		p->vel.Y += (sb_svel * doubvel) / 4096.;
+		p->vel.X += sb_fvel * doubvel * (5. / 16.);
+		p->vel.Y += sb_svel * doubvel * (5. / 16.);
 
 		if (!isRRRA() && ((p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && p->on_ground) || (p->on_ground && (actions & SB_CROUCH))))
 		{
diff --git a/source/games/duke/src/sectors_d.cpp b/source/games/duke/src/sectors_d.cpp
index eefe11286..3bc9597bf 100644
--- a/source/games/duke/src/sectors_d.cpp
+++ b/source/games/duke/src/sectors_d.cpp
@@ -1539,7 +1539,7 @@ void checksectors_d(int snum)
 
 	if (p->newOwner != nullptr)
 	{
-		if (abs(PlayerInputSideVel(snum)) > 768 || abs(PlayerInputForwardVel(snum)) > 768)
+		if (abs(PlayerInputSideVel(snum)) > 1.5 || abs(PlayerInputForwardVel(snum)) > 1.5)
 		{
 			clearcameras(-1, p);
 			return;
diff --git a/source/games/exhumed/src/exhumed.cpp b/source/games/exhumed/src/exhumed.cpp
index 30d0ca6dd..38f47eb01 100644
--- a/source/games/exhumed/src/exhumed.cpp
+++ b/source/games/exhumed/src/exhumed.cpp
@@ -373,7 +373,7 @@ void GameInterface::Ticker()
 
         auto& lPlayerVel = sPlayerInput[nLocalPlayer].vel;
 
-        auto inputvect = DVector2(localInput.fvel, localInput.svel).Rotated(inita) * (1. / 16.);
+        auto inputvect = DVector2(localInput.fvel, localInput.svel).Rotated(inita) * 0.375;
 
         for (int i = 0; i < 4; i++)
         {
diff --git a/source/games/exhumed/src/exhumed.h b/source/games/exhumed/src/exhumed.h
index abaa146e5..174326da1 100644
--- a/source/games/exhumed/src/exhumed.h
+++ b/source/games/exhumed/src/exhumed.h
@@ -233,7 +233,6 @@ struct GameInterface : public ::GameInterface
     bool DrawAutomapPlayer(const DVector2& mxy, const DVector2& cpos, const DAngle cang, const DVector2& xydim, const double czoom, double const interpfrac) override;
     fixed_t playerHorizMin() override { return IntToFixed(-150); }
     fixed_t playerHorizMax() override { return IntToFixed(150); }
-    int playerKeyMove() override { return 6; }
     void WarpToCoords(double x, double y, double z, DAngle ang, int horz) override;
     void ToggleThirdPerson() override;
     DVector3 chaseCamPos(DAngle ang, fixedhoriz horiz) { return DVector3(-ang.ToVector() * 96., horiz.asbuildf() * 0.75); }
diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h
index 9a7476dd9..5bfb6cd75 100644
--- a/source/games/sw/src/game.h
+++ b/source/games/sw/src/game.h
@@ -1898,7 +1898,6 @@ struct GameInterface : public ::GameInterface
 	void NextLevel(MapRecord *map, int skill) override;
 	void NewGame(MapRecord *map, int skill, bool) override;
     bool DrawAutomapPlayer(const DVector2& mxy, const DVector2& cpos, const DAngle cang, const DVector2& xydim, const double czoom, double const interpfrac) override;
-    int playerKeyMove() override { return 35; }
     void WarpToCoords(double x, double y, double z, DAngle ang, int horz) override;
     void ToggleThirdPerson() override;
     void SwitchCoopView() override;
diff --git a/source/games/sw/src/input.cpp b/source/games/sw/src/input.cpp
index 2d4f3405b..8502cf733 100644
--- a/source/games/sw/src/input.cpp
+++ b/source/games/sw/src/input.cpp
@@ -207,8 +207,9 @@ void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdju
     if (packet)
     {
         *packet = loc;
-        packet->fvel = MulScale(loc.fvel, pp->angle.ang.Cos() * (1 << 14), 9) - MulScale(loc.svel, pp->angle.ang.Sin() * (1 << 14), 9);
-        packet->svel = MulScale(loc.fvel, pp->angle.ang.Sin() * (1 << 14), 9) + MulScale(loc.svel, pp->angle.ang.Cos() * (1 << 14), 9);
+        auto velvect = DVector2(loc.fvel, loc.svel).Rotated(pp->angle.ang);
+        packet->fvel = velvect.X;
+        packet->svel = velvect.Y;
         loc = {};
     }
 }
diff --git a/source/games/sw/src/player.cpp b/source/games/sw/src/player.cpp
index ddfeed674..a7853de2e 100644
--- a/source/games/sw/src/player.cpp
+++ b/source/games/sw/src/player.cpp
@@ -79,7 +79,7 @@ USERSAVE puser[MAX_SW_PLAYERS_REG];
 bool NightVision = false;
 extern int FinishAnim;
 
-constexpr double INPUT_SCALE = 1. / (1 << 12); // Old code used << 6 to get a Q14.18 value
+constexpr double INPUT_SCALE = (105. / 64.); // Old code used << 6 to get a Q14.18 value
 
 // the smaller the number the slower the going
 #define PLAYER_RUN_FRICTION (50000L)
@@ -2131,8 +2131,8 @@ void DoPlayerMove(PLAYER* pp)
 
     pp->ovect = pp->vect;
 
-    pp->vect.X += (pp->input.fvel*synctics*2) * INPUT_SCALE;
-    pp->vect.Y += (pp->input.svel*synctics*2) * INPUT_SCALE;
+    pp->vect.X += pp->input.fvel * INPUT_SCALE;
+    pp->vect.Y += pp->input.svel * INPUT_SCALE;
 
     friction = pp->friction;
     if (!(pp->Flags & PF_SWIMMING) && pp->WadeDepth)
@@ -2650,9 +2650,9 @@ void DoPlayerMoveVehicle(PLAYER* pp)
 
     if (!Prediction)
     {
-        if (abs(pp->input.fvel|pp->input.svel) && !abs(pp->lastinput.fvel| pp->lastinput.svel))
+        if (abs(pp->input.fvel + pp->input.svel) && !abs(pp->lastinput.fvel + pp->lastinput.svel))
             PlaySOsound(pp->sop->mid_sector,SO_DRIVE_SOUND);
-        else if (!abs(pp->input.fvel|pp->input.svel) && abs(pp->lastinput.fvel| pp->lastinput.svel))
+        else if (!abs(pp->input.fvel + pp->input.svel) && abs(pp->lastinput.fvel + pp->lastinput.svel))
             PlaySOsound(pp->sop->mid_sector,SO_IDLE_SOUND);
     }
 
@@ -2668,16 +2668,16 @@ void DoPlayerMoveVehicle(PLAYER* pp)
 
     if (sop->drive_speed)
     {
-        pp->vect.X = MulScaleF(pp->input.fvel, sop->drive_speed, 24);
-        pp->vect.Y = MulScaleF(pp->input.svel, sop->drive_speed, 24);
+        pp->vect.X = pp->input.fvel * sop->drive_speed * (70. / 1048576.);
+        pp->vect.Y = pp->input.svel * sop->drive_speed * (70. / 1048576.);
 
         // does sliding/momentum
         pp->vect = (pp->vect + (pp->ovect * (sop->drive_slide-1)))/sop->drive_slide;
     }
     else
     {
-		pp->vect.X += (pp->input.fvel*synctics*2) * INPUT_SCALE;
-		pp->vect.Y += (pp->input.svel*synctics*2) * INPUT_SCALE;
+		pp->vect.X += pp->input.fvel * INPUT_SCALE;
+		pp->vect.Y += pp->input.svel * INPUT_SCALE;
 		pp->vect *= TANK_FRICTION;
 
         pp->vect = (pp->vect + (pp->ovect*1))/2;
@@ -3330,8 +3330,8 @@ void DoPlayerClimb(PLAYER* pp)
     if (Prediction)
         return;
 
-	pp->vect.X += (pp->input.fvel*synctics*2) * INPUT_SCALE;
-	pp->vect.Y += (pp->input.svel*synctics*2) * INPUT_SCALE;
+	pp->vect.X += pp->input.fvel * INPUT_SCALE;
+	pp->vect.Y += pp->input.svel * INPUT_SCALE;
 	pp->vect *= PLAYER_CLIMB_FRICTION;
     if (abs(pp->vect.X) < 0.05 && abs(pp->vect.Y) < 0.05)
         pp->vect.X = pp->vect.Y = 0;
@@ -5270,7 +5270,7 @@ void DoPlayerBeginOperate(PLAYER* pp)
     switch (sop->track)
     {
     case SO_VEHICLE:
-        if (pp->input.fvel|pp->input.svel)
+        if (pp->input.fvel || pp->input.svel)
             PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
         else
             PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
@@ -5288,7 +5288,7 @@ void DoPlayerBeginOperate(PLAYER* pp)
         break;
 #if 0
     case SO_SPEED_BOAT:
-        if (pp->input.fvel|pp->input.svel)
+        if (pp->input.fvel || pp->input.svel)
             PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
         else
             PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);
@@ -5363,7 +5363,7 @@ void DoPlayerBeginRemoteOperate(PLAYER* pp, SECTOR_OBJECT* sop)
     switch (sop->track)
     {
     case SO_VEHICLE:
-        if (pp->input.fvel|pp->input.svel)
+        if (pp->input.fvel || pp->input.svel)
             PlaySOsound(pp->sop->mid_sector, SO_DRIVE_SOUND);
         else
             PlaySOsound(pp->sop->mid_sector, SO_IDLE_SOUND);