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