diff --git a/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua b/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
index 51f2e32b29..95cfc776e2 100644
--- a/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
+++ b/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
@@ -283,7 +283,13 @@ if CLIENT then
local client = LocalPlayer()
- if not enable_crosshair:GetBool() or not IsValid(client) or client:GetSprintingPredicted() and not GetGlobalBool("ttt2_sprint_crosshair", false) then return end
+ if
+ not enable_crosshair:GetBool()
+ or not IsValid(client)
+ or SPRINT:IsSprinting(client) and not SPRINT.convars.showCrosshair:GetBool()
+ then
+ return
+ end
local sights = not self.NoSights and self:GetIronsights()
local x = math.floor(ScrW() * 0.5)
diff --git a/gamemodes/terrortown/gamemode/client/cl_keys.lua b/gamemodes/terrortown/gamemode/client/cl_keys.lua
index 093cb1270b..8f158c9a0e 100644
--- a/gamemodes/terrortown/gamemode/client/cl_keys.lua
+++ b/gamemodes/terrortown/gamemode/client/cl_keys.lua
@@ -3,7 +3,6 @@
-- @section key_manager
local IsValid = IsValid
-local UpdateInputSprint = UpdateInputSprint
local cv_sv_cheats = GetConVar("sv_cheats")
local function SendWeaponDrop()
@@ -132,43 +131,3 @@ function GM:PlayerBindPress(ply, bindName, pressed)
RunConsoleCommand("ttt_quickslot", "5")
end
end
-
----
--- Called whenever a @{Player} pressed a key included within the IN keys.
--- For a more general purpose function that handles all kinds of input, see @{GM:PlayerButtonDown}.
--- @warning Due to this being a predicted hook, ParticleEffects
--- created only serverside from this hook will not be networked to the client, so make sure to do that on both realms
--- @predicted
--- @param Player ply The @{Player} pressing the key. If running client-side, this will always be LocalPlayer
--- @param number key The key that the player pressed using IN_Enums.
--- @note Note that for some reason KeyPress and KeyRelease are called multiple times
--- for the same key event in multiplayer.
--- @hook
--- @realm client
--- @ref https://wiki.facepunch.com/gmod/GM:KeyPress
--- @local
-function GM:KeyPress(ply, key)
- if not IsFirstTimePredicted() or not IsValid(ply) or ply ~= LocalPlayer() then return end
-
- if key == IN_FORWARD or key == IN_BACK or key == IN_MOVERIGHT or key == IN_MOVELEFT then
- UpdateInputSprint(ply, key, true)
- end
-end
-
----
--- Runs when a IN key was released by a player.
--- For a more general purpose function that handles all kinds of input, see @{GM:PlayerButtonUp}.
--- @param Player ply The @{Player} releasing the key. If running client-side, this will always be LocalPlayer
--- @param number key The key that the player released using IN_Enums.
--- @predicted
--- @hook
--- @realm client
--- @ref https://wiki.facepunch.com/gmod/GM:KeyRelease
--- @local
-function GM:KeyRelease(ply, key)
- if not IsFirstTimePredicted() or not IsValid(ply) or ply ~= LocalPlayer() then return end
-
- if key == IN_FORWARD or key == IN_BACK or key == IN_MOVERIGHT or key == IN_MOVELEFT then
- UpdateInputSprint(ply, key, false)
- end
-end
diff --git a/gamemodes/terrortown/gamemode/client/cl_main.lua b/gamemodes/terrortown/gamemode/client/cl_main.lua
index 2c81c5bd90..73cc880a32 100644
--- a/gamemodes/terrortown/gamemode/client/cl_main.lua
+++ b/gamemodes/terrortown/gamemode/client/cl_main.lua
@@ -551,7 +551,6 @@ function GM:ClearClientState()
client.last_id = nil
client.radio = nil
client.called_corpses = {}
- client.sprintProgress = 1
client:SetTargetPlayer(nil)
diff --git a/gamemodes/terrortown/gamemode/server/sv_player.lua b/gamemodes/terrortown/gamemode/server/sv_player.lua
index 02c7ab5161..14988e1926 100644
--- a/gamemodes/terrortown/gamemode/server/sv_player.lua
+++ b/gamemodes/terrortown/gamemode/server/sv_player.lua
@@ -102,6 +102,8 @@ end
-- @ref https://wiki.facepunch.com/gmod/GM:PlayerSpawn
-- @local
function GM:PlayerSpawn(ply)
+ player_manager.SetPlayerClass(ply, "player_ttt")
+
-- reset any cached weapons
ply:ResetCachedWeapons()
diff --git a/gamemodes/terrortown/gamemode/server/sv_player_ext.lua b/gamemodes/terrortown/gamemode/server/sv_player_ext.lua
index 7dec0c4d32..19c8b8aa48 100644
--- a/gamemodes/terrortown/gamemode/server/sv_player_ext.lua
+++ b/gamemodes/terrortown/gamemode/server/sv_player_ext.lua
@@ -664,9 +664,6 @@ function plymeta:InitialSpawn()
self:ResetStatus()
- -- Always reset sprint
- self.sprintProgress = 1
-
-- Start off with clean, full karma (unless it can and should be loaded)
self:InitKarma()
diff --git a/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/old_ttt_info.lua b/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/old_ttt_info.lua
index 379e055508..f32be5820c 100644
--- a/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/old_ttt_info.lua
+++ b/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/old_ttt_info.lua
@@ -119,8 +119,8 @@ if CLIENT then
-- sprint bar
local sbh = 8 -- spring bar height
- if GetGlobalBool("ttt2_sprint_enabled", true) then
- self:PaintBar(x + margin, ammo_y + bar_height + 5, bar_width, sbh, self.sprint_colors, client.sprintProgress)
+ if SPRINT.convars.enabled:GetBool() then
+ self:PaintBar(x + margin, ammo_y + bar_height + 5, bar_width, sbh, self.sprint_colors, client:GetSprintStamina())
end
local hastewidth = self.hastewidth
diff --git a/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/pure_skin_playerinfo.lua b/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/pure_skin_playerinfo.lua
index 610dcb1b5a..78cf6f8eba 100644
--- a/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/pure_skin_playerinfo.lua
+++ b/gamemodes/terrortown/gamemode/shared/hud_elements/tttinfopanel/pure_skin_playerinfo.lua
@@ -262,8 +262,8 @@ if CLIENT then
-- sprint bar
ty = ty + bh + spc
- if GetGlobalBool("ttt2_sprint_enabled", true) then
- self:DrawBar(nx, ty, bw, sbh, color_sprint, client.sprintProgress, t_scale, "")
+ if SPRINT.convars.enabled:GetBool() then
+ self:DrawBar(nx, ty, bw, sbh, color_sprint, client:GetSprintStamina(), t_scale, "")
end
-- coin info
diff --git a/gamemodes/terrortown/gamemode/shared/sh_include.lua b/gamemodes/terrortown/gamemode/shared/sh_include.lua
index 95cc42d4f1..a4c5d60aae 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_include.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_include.lua
@@ -53,6 +53,7 @@ TTTFiles = {
sh_main = {file = "sh_main.lua", on = "shared"},
sh_network_sync = {file = "sh_network_sync.lua", on = "shared"},
sh_player_ext = {file = "sh_player_ext.lua", on = "shared"},
+ sh_playerclass = { file = "sh_playerclass.lua", on = "shared" },
sh_printmessage_override = {file = "sh_printmessage_override.lua", on = "shared"},
sh_cvar_handler = {file = "sh_cvar_handler.lua", on = "shared"},
sh_role_module = {file = "sh_role_module.lua", on = "shared"},
diff --git a/gamemodes/terrortown/gamemode/shared/sh_init.lua b/gamemodes/terrortown/gamemode/shared/sh_init.lua
index e8e8b27f60..fe9b75c406 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_init.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_init.lua
@@ -579,6 +579,7 @@ ttt_include("sh_hudelement_module")
ttt_include("sh_equip_items")
ttt_include("sh_role_module")
ttt_include("sh_item_module")
+ttt_include("sh_playerclass")
---
-- Returns the equipment's file name
diff --git a/gamemodes/terrortown/gamemode/shared/sh_main.lua b/gamemodes/terrortown/gamemode/shared/sh_main.lua
index c95abcdfb0..93436a8997 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_main.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_main.lua
@@ -4,7 +4,6 @@
local IsValid = IsValid
local hook = hook
local team = team
-local UpdateSprint = UpdateSprint
local MAX_DROWN_TIME = 8
@@ -243,10 +242,22 @@ function GM:Move(ply, moveData)
local mul = ply:GetSpeedMultiplier()
+ mul = mul * SPRINT:HandleSpeedMultiplierCalculation(ply)
+
moveData:SetMaxClientSpeed(moveData:GetMaxClientSpeed() * mul)
moveData:SetMaxSpeed(moveData:GetMaxSpeed() * mul)
end
+-- @param Player ply The player
+-- @param MoveData moveData Movement information
+-- @predicted
+-- @hook
+-- @realm shared
+-- @ref https://wiki.facepunch.com/gmod/GM:FinishMove
+function GM:FinishMove(ply, moveData)
+ SPRINT:HandleStaminaCalculation(ply)
+end
+
local ttt_playercolors = {
all = {
COLOR_WHITE,
@@ -308,8 +319,6 @@ end
-- @realm shared
-- @ref https://wiki.facepunch.com/gmod/GM:Think
function GM:Think()
- UpdateSprint()
-
if CLIENT then
EPOP:Think()
end
@@ -321,10 +330,8 @@ end
-- @param Player ply The player whose sprint speed should be changed
-- @param table sprintMultiplierModifier The modieable table with the sprint speed multiplier
-- @hook
--- @realm server
-function GM:TTT2PlayerSprintMultiplier(ply, sprintMultiplierModifier)
-
-end
+-- @realm shared
+function GM:TTT2PlayerSprintMultiplier(ply, sprintMultiplierModifier) end
---
-- A hook that is called whenever the gamemode needs to check if the player is in the superadmin usergroup.
diff --git a/gamemodes/terrortown/gamemode/shared/sh_player_ext.lua b/gamemodes/terrortown/gamemode/shared/sh_player_ext.lua
index cb4c15e26a..1a66f0ff70 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_player_ext.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_player_ext.lua
@@ -9,6 +9,7 @@ local IsValid = IsValid
local hook = hook
local math = math
+---@class Player
local plymeta = FindMetaTable("Player")
if not plymeta then
Error("FAILED TO FIND PLAYER TABLE")
@@ -16,27 +17,10 @@ if not plymeta then
return
end
----
--- Dummy functions that will be replaced when SetupDataTables runs. These are
--- here for when that does not happen (due to e.g. stacking base classes)
--- @return[default=false] boolean
--- @realm shared
-function plymeta:GetSprintingPredicted()
- return false
-end
-
----
--- Dummy functions that will be replaced when SetupDataTables runs. These are
--- here for when that does not happen (due to e.g. stacking base classes)
--- @realm shared
-function plymeta:SetSprintingPredicted()
-
-end
-
function plymeta:SetupDataTables()
- self:NetworkVar("Bool", 3, "SprintingPredicted")
-
- plymeta.SetupDataTables(self)
+ -- This has to be transferred, because we need the value when predicting the player movement
+ -- It turned out that this is the only reliable way to fix all prediction errors.
+ self:NetworkVar("Float", 0, "SprintStamina")
end
---
diff --git a/gamemodes/terrortown/gamemode/shared/sh_playerclass.lua b/gamemodes/terrortown/gamemode/shared/sh_playerclass.lua
new file mode 100644
index 0000000000..fffd1a0b24
--- /dev/null
+++ b/gamemodes/terrortown/gamemode/shared/sh_playerclass.lua
@@ -0,0 +1,16 @@
+DEFINE_BASECLASS("player_default")
+
+local PLAYER = {}
+
+PLAYER.WalkSpeed = 220
+PLAYER.RunSpeed = 220
+PLAYER.JumpPower = 160
+PLAYER.CrouchedWalkSpeed = 0.3
+
+-- This is needed to allow adding custom networked variables to the player entity
+-- Can be useful for e.g. variables necessary for prediction like the stamina.
+function PLAYER:SetupDataTables()
+ self.Player:SetupDataTables()
+end
+
+player_manager.RegisterClass("player_ttt", PLAYER, "player_default")
diff --git a/gamemodes/terrortown/gamemode/shared/sh_speed.lua b/gamemodes/terrortown/gamemode/shared/sh_speed.lua
index 50f9aeee12..95e55ed2a6 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_speed.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_speed.lua
@@ -1,18 +1,19 @@
---
--- @class SPEED
+---@class SPEED
-local plymeta = assert(FindMetaTable("Player"), "FAILED TO FIND ENTITY TABLE")
-
-SPEED = SPEED or {}
+SPEED = {}
---
--- Handles the speed calculation based on the @{GM:TTTPlayerSpeedModifier} hook
--- @param Player ply The player whose speed should be changed
--- @param MoveData moveData The move data
--- @internal
--- @realm shared
+--- Handles the speed calculation based on the @{GM:TTTPlayerSpeedModifier} hook
+--- Note: Does not handle the sprinting speed calculation, to not show sprinting as a status.
+---@param ply Player The player whose speed should be changed
+---@param moveData MoveData The move data
+---@internal
+---@realm shared
function SPEED:HandleSpeedCalculation(ply, moveData)
- if not ply:IsTerror() then return end
+ if not ply:IsTerror() then
+ return
+ end
local baseMultiplier = 1
local isSlowed = false
@@ -23,17 +24,9 @@ function SPEED:HandleSpeedCalculation(ply, moveData)
if IsValid(wep) and wep.GetIronsights and wep:GetIronsights() then
baseMultiplier = 120 / 220
isSlowed = true
- elseif ply:GetSprintingPredicted() and (ply.sprintProgress or 0) > 0 then
- local sprintMultiplierModifier = {1}
-
- ---
- -- @realm shared
- hook.Run("TTT2PlayerSprintMultiplier", ply, sprintMultiplierModifier)
-
- baseMultiplier = (1 + GetGlobalFloat("ttt2_sprint_max", 0)) * sprintMultiplierModifier[1]
end
- local speedMultiplierModifier = {1}
+ local speedMultiplierModifier = { 1 }
---
-- @realm shared
@@ -42,7 +35,9 @@ function SPEED:HandleSpeedCalculation(ply, moveData)
local oldval = ply:GetSpeedMultiplier()
ply.speedModifier = baseMultiplier * returnMultiplier * speedMultiplierModifier[1]
- if SERVER then return end
+ if SERVER then
+ return
+ end
local newval = math.Round(ply.speedModifier, 1)
@@ -68,9 +63,7 @@ end
-- @return[deprecated] number The deprecated way of changing the player speed
-- @hook
-- @realm shared
-function GM:TTTPlayerSpeedModifier(ply, isSlowed, moveData, speedMultiplierModifier)
-
-end
+function GM:TTTPlayerSpeedModifier(ply, isSlowed, moveData, speedMultiplierModifier) end
if CLIENT then
---
@@ -80,28 +73,29 @@ if CLIENT then
function SPEED:Initialize()
STATUS:RegisterStatus("ttt_speed_status_good", {
hud = {
- Material("vgui/ttt/perks/hud_speedrun.png")
+ Material("vgui/ttt/perks/hud_speedrun.png"),
},
type = "good",
DrawInfo = function()
return math.Round(LocalPlayer():GetSpeedMultiplier(), 1)
- end
+ end,
})
STATUS:RegisterStatus("ttt_speed_status_bad", {
hud = {
- Material("vgui/ttt/perks/hud_speedrun.png")
+ Material("vgui/ttt/perks/hud_speedrun.png"),
},
type = "bad",
DrawInfo = function()
return math.Round(LocalPlayer():GetSpeedMultiplier(), 1)
- end
+ end,
})
end
end
---
--- @class Player
+---@class Player
+local plymeta = assert(FindMetaTable("Player"), "FAILED TO FIND ENTITY TABLE")
---
-- Returns the current player speed modifier
diff --git a/gamemodes/terrortown/gamemode/shared/sh_sprint.lua b/gamemodes/terrortown/gamemode/shared/sh_sprint.lua
index 45a6fcb412..13721de6df 100644
--- a/gamemodes/terrortown/gamemode/shared/sh_sprint.lua
+++ b/gamemodes/terrortown/gamemode/shared/sh_sprint.lua
@@ -1,169 +1,122 @@
-local function PlayerSprint(trySprinting, moveKey)
- if SERVER then return end
-
- local client = LocalPlayer()
- local isSprinting = client:GetSprintingPredicted()
-
- if not GetGlobalBool("ttt2_sprint_enabled", true) then return end
- if not trySprinting and not isSprinting or trySprinting and isSprinting then return end
- if isSprinting and (client.moveKey and not moveKey or not client.moveKey and moveKey) then return end
+---
+---@class SPRINT
+SPRINT = {
+ -- Set up ConVars
+ convars = {
+ -- @realm shared
+ enabled = CreateConVar(
+ "ttt2_sprint_enabled",
+ "1",
+ { FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED },
+ "Toggle Sprint (Def: 1)"
+ ),
+ -- @realm shared
+ multiplier = CreateConVar(
+ "ttt2_sprint_max",
+ "0.5",
+ { FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED },
+ "The speed modifier the player will receive. Will be added on top of 1, so 0.5 => 1.5 speed. (Def: 0.5)"
+ ),
+ -- @realm shared
+ consumption = CreateConVar(
+ "ttt2_sprint_stamina_consumption",
+ "0.6",
+ { FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED },
+ "The speed of the stamina consumption (per second; Def: 0.6)"
+ ),
+ -- @realm shared
+ regeneration = CreateConVar(
+ "ttt2_sprint_stamina_regeneration",
+ "0.3",
+ { FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED },
+ "The regeneration time of the stamina (per second; Def: 0.3)"
+ ),
+ -- @realm shared
+ showCrosshair = CreateConVar(
+ "ttt2_sprint_crosshair",
+ "0",
+ { FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED },
+ "Should the Crosshair be visible while sprinting? (Def: 0)"
+ ),
+ },
+}
- client:SetSprintingPredicted(trySprinting)
- client.moveKey = moveKey
+---
+-- Checks if the player is pressing any movement keys and the sprint key at the same time.
+-- @param Player ply
+-- @return boolean
+-- @realm shared
+function SPRINT:PlayerWantsToSprint(ply)
+ local isSprinting = ply:KeyDown(IN_SPEED)
+ local inMovement = ply:KeyDown(IN_FORWARD)
+ or ply:KeyDown(IN_BACK)
+ or ply:KeyDown(IN_MOVERIGHT)
+ or ply:KeyDown(IN_MOVELEFT)
+
+ return isSprinting and inMovement
end
-if SERVER then
- -- Set ConVars
-
- ---
- -- @realm server
- local sprintEnabled = CreateConVar("ttt2_sprint_enabled", "1", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "Toggle Sprint (Def: 1)")
-
- ---
- -- @realm server
- local maxSprintMul = CreateConVar("ttt2_sprint_max", "0.5", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "The maximum speed modifier the player will receive (Def: 0.5)")
-
- ---
- -- @realm server
- local consumption = CreateConVar("ttt2_sprint_stamina_consumption", "0.6", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "The speed of the stamina consumption (per second; Def: 0.6)")
-
- ---
- -- @realm server
- local stamreg = CreateConVar("ttt2_sprint_stamina_regeneration", "0.3", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "The regeneration time of the stamina (per second; Def: 0.3)")
-
- ---
- -- @realm server
- local showCrosshair = CreateConVar("ttt2_sprint_crosshair", "0", {FCVAR_ARCHIVE, FCVAR_NOTIFY}, "Should the Crosshair be visible while sprinting? (Def: 0)")
-
- hook.Add("TTT2SyncGlobals", "AddSprintGlobals", function()
- SetGlobalBool(sprintEnabled:GetName(), sprintEnabled:GetBool())
- SetGlobalFloat(maxSprintMul:GetName(), maxSprintMul:GetFloat())
- SetGlobalFloat(consumption:GetName(), consumption:GetFloat())
- SetGlobalFloat(stamreg:GetName(), stamreg:GetFloat())
- SetGlobalBool(showCrosshair:GetName(), showCrosshair:GetBool())
- end)
-
- cvars.AddChangeCallback(sprintEnabled:GetName(), function(name, old, new)
- SetGlobalBool(name, tobool(new))
- end, "TTT2SprintENChange")
-
- cvars.AddChangeCallback(maxSprintMul:GetName(), function(name, old, new)
- SetGlobalFloat(name, new)
- end, "TTT2SprintSMulChange")
-
- cvars.AddChangeCallback(consumption:GetName(), function(name, old, new)
- SetGlobalFloat(name, new)
- end, "TTT2SprintSCChange")
-
- cvars.AddChangeCallback(stamreg:GetName(), function(name, old, new)
- SetGlobalFloat(name, new)
- end, "TTT2SprintSRChange")
-
- cvars.AddChangeCallback(showCrosshair:GetName(), function(name, old, new)
- SetGlobalBool(name, tobool(new))
- end, "TTT2SprintCHChange")
-else -- CLIENT
- ---
- -- @realm client
- local enable_doubletap_sprint = CreateConVar("ttt2_enable_doubletap_sprint", "1", {FCVAR_ARCHIVE})
-
- ---
- -- @realm client
- local doubletap_sprint_anykey = CreateConVar("ttt2_doubletap_sprint_anykey", "1", {FCVAR_ARCHIVE})
-
- local lastPress = 0
- local lastPressedMoveKey = nil
+---
+-- Checks if the player wants to sprint and actually can sprint.
+-- @param Player ply
+-- @return boolean
+-- @realm shared
+function SPRINT:IsSprinting(ply)
+ return self.convars.enabled:GetBool() and self:PlayerWantsToSprint(ply) and ply:GetSprintStamina() > 0
+end
- ---
- -- @param Player ply
- -- @param number key
- -- @param boolean pressed
- -- @realm client
- function UpdateInputSprint(ply, key, pressed)
- if pressed then
- if ply:GetSprintingPredicted() or not enable_doubletap_sprint:GetBool() or ply.preventSprint then return end
+---
+-- Calculates the new stamina values for a given player.
+-- @param Player ply
+-- @realm shared
+function SPRINT:HandleStaminaCalculation(ply)
+ local staminaRegeneratonRate = self.convars.regeneration:GetFloat()
+ local staminaConsumptionRate = self.convars.consumption:GetFloat()
- local time = CurTime()
+ local sprintStamina = ply:GetSprintStamina()
+ local playerWantsToSprint = self:PlayerWantsToSprint(ply)
- if lastPressedMoveKey == key and time - lastPress < 0.4 then
- PlayerSprint(true, key)
- end
+ if (sprintStamina == 1 and not playerWantsToSprint) or (sprintStamina == 0 and playerWantsToSprint) then
+ return
+ end
- lastPressedMoveKey = key
- lastPress = time
- else
- if not ply:GetSprintingPredicted() then return end
+ -- Note: This is a table, because it is passed by reference and multiple addons can adjust the value.
+ local rateModifier = { 1 }
+ local newStamina = 0
- local moveKey = ply.moveKey
- local wantsToMove = ply:KeyDown(IN_FORWARD) or ply:KeyDown(IN_BACK) or ply:KeyDown(IN_MOVERIGHT) or ply:KeyDown(IN_MOVELEFT)
- local anyKey = doubletap_sprint_anykey:GetBool()
+ if playerWantsToSprint then
+ ---
+ -- @realm shared
+ hook.Run("TTT2StaminaDrain", ply, rateModifier)
- if not moveKey or anyKey and wantsToMove or not anyKey and key ~= moveKey then return end
+ newStamina = math.max(sprintStamina - FrameTime() * rateModifier[1] * staminaConsumptionRate, 0)
+ else
+ ---
+ -- @realm shared
+ hook.Run("TTT2StaminaRegen", ply, rateModifier)
- PlayerSprint(false, key)
- end
+ newStamina = math.min(sprintStamina + FrameTime() * rateModifier[1] * staminaRegeneratonRate, 1)
end
- bind.Register("ttt2_sprint", function()
- if not LocalPlayer().preventSprint then
- PlayerSprint(true)
- end
- end,
- function()
- PlayerSprint(false)
- end, "header_bindings_ttt2", "label_bind_sprint", KEY_LSHIFT)
+ ply:SetSprintStamina(newStamina)
end
---
+-- Calculates the sprint speed multiplier value for a given player.
+-- @param Player ply
-- @realm shared
-function UpdateSprint()
- local client
-
- if CLIENT then
- client = LocalPlayer()
-
- if not IsValid(client) then return end
+function SPRINT:HandleSpeedMultiplierCalculation(ply)
+ if not self:IsSprinting(ply) then
+ return 1
end
- local plys = client and {client} or player.GetAll()
-
- for i = 1, #plys do
- local ply = plys[i]
-
- if not ply:OnGround() then continue end
-
- local wantsToMove = ply:KeyDown(IN_FORWARD) or ply:KeyDown(IN_BACK) or ply:KeyDown(IN_MOVERIGHT) or ply:KeyDown(IN_MOVELEFT)
-
- if ply.sprintProgress == 1 and (not ply:GetSprintingPredicted() or not wantsToMove) then continue end
- if ply.sprintProgress == 0 and ply:GetSprintingPredicted() and wantsToMove then
- ply.sprintResetDelayCounter = ply.sprintResetDelayCounter + FrameTime()
-
- -- If the player keeps sprinting even though they have no stamina, start refreshing stamina after 1.5 seconds automatically
- if CLIENT and ply.sprintResetDelayCounter > 1.5 then
- PlayerSprint(false, ply.moveKey)
- end
+ local sprintMultiplierModifier = { 1 }
- continue
- end
-
- ply.sprintResetDelayCounter = 0
-
- local modifier = {1} -- Multiple hooking support
-
- if not ply:GetSprintingPredicted() or not wantsToMove then
- ---
- -- @realm shared
- hook.Run("TTT2StaminaRegen", ply, modifier)
-
- ply.sprintProgress = math.min((ply.sprintProgress or 0) + FrameTime() * modifier[1] * GetGlobalFloat("ttt2_sprint_stamina_regeneration"), 1)
- elseif wantsToMove then
- ---
- -- @realm shared
- hook.Run("TTT2StaminaDrain", ply, modifier)
+ ---
+ -- @realm shared
+ hook.Run("TTT2PlayerSprintMultiplier", ply, sprintMultiplierModifier)
- ply.sprintProgress = math.max((ply.sprintProgress or 0) - FrameTime() * modifier[1] * GetGlobalFloat("ttt2_sprint_stamina_consumption"), 0)
- end
- end
+ return (1 + self.convars.multiplier:GetFloat()) * sprintMultiplierModifier[1]
end
---
@@ -173,9 +126,7 @@ end
-- @param table modifierTbl The table in which the modifier can be changed
-- @hook
-- @realm shared
-function GM:TTT2StaminaRegen(ply, modifierTbl)
-
-end
+function GM:TTT2StaminaRegen(ply, modifierTbl) end
---
-- A hook that is called once every frame/tick to modify the stamina drain.
@@ -184,6 +135,4 @@ end
-- @param table modifierTbl The table in which the modifier can be changed
-- @hook
-- @realm shared
-function GM:TTT2StaminaDrain(ply, modifierTbl)
-
-end
+function GM:TTT2StaminaDrain(ply, modifierTbl) end