2026-04-14 17:41:39 +02:00

196 lines
7.0 KiB
Lua

-- ============================================================
-- mercyv-stamina | Client
-- ============================================================
local currentStamina = Config.StartStamina
local isJogForced = false
local lastSprintTime = 0
local regenBlocked = false
-- ============================================================
-- Hilfsfunktionen
-- ============================================================
local function log(msg)
if Config.ShowDebug then
print("^3[mercyv-stamina]^7 " .. tostring(msg))
end
end
local function clamp(val, minVal, maxVal)
return math.max(minVal, math.min(maxVal, val))
end
local function getStamina()
return currentStamina
end
-- ============================================================
-- Vanilla Stamina neutralisieren
-- ============================================================
local function suppressVanilla()
if not Config.DisableVanilla then return end
RestorePlayerStamina(PlayerId(), 100.0)
SetRunSprintMultiplierForPlayer(PlayerId(), 1.0)
end
-- ============================================================
-- Jog-Modus steuern
-- ============================================================
local function enableJog()
if isJogForced then return end
isJogForced = true
SetPedMovementClipset(PlayerPedId(), Config.JogClipset, 0.3)
log("Jog aktiviert | Stamina: " .. math.floor(currentStamina) .. "%")
TriggerServerEvent("mercyv-stamina:log", "jog_start", math.floor(currentStamina))
end
local function disableJog()
if not isJogForced then return end
isJogForced = false
ResetPedMovementClipset(PlayerPedId(), 0.3)
log("Jog deaktiviert | Stamina: " .. math.floor(currentStamina) .. "%")
TriggerServerEvent("mercyv-stamina:log", "jog_stop", math.floor(currentStamina))
end
-- ============================================================
-- Sprint-Erkennung
-- ============================================================
local function isSprinting()
local ped = PlayerPedId()
-- Nicht im Fahrzeug + Sprint-Taste gedrückt + Charakter bewegt sich
return not IsPedInAnyVehicle(ped, false)
and IsControlPressed(0, 21) -- INPUT_SPRINT
and IsPedRunning(ped)
end
-- ============================================================
-- Haupt-Loop
-- ============================================================
CreateThread(function()
while true do
Wait(Config.TickInterval)
local ped = PlayerPedId()
local inVehicle = IsPedInAnyVehicle(ped, false)
-- Vanilla immer unterdrücken solange aktiviert
suppressVanilla()
if not inVehicle then
local sprinting = isSprinting()
-- Stamina verringern beim Sprinten (nur wenn nicht schon im Jog-Modus)
if sprinting and not isJogForced then
currentStamina = clamp(currentStamina - Config.StaminaDrain, 0, 100)
lastSprintTime = GetGameTimer()
regenBlocked = true
log("Sprinten | Stamina: " .. string.format("%.1f", currentStamina) .. "%")
end
-- Regen-Delay prüfen
if regenBlocked and (GetGameTimer() - lastSprintTime) >= Config.RegenDelay then
regenBlocked = false
end
-- Stamina regenerieren (Fuß)
if not sprinting and not regenBlocked then
currentStamina = clamp(currentStamina + Config.StaminaRegen, 0, 100)
end
-- Jog-Modus einschalten wenn Schwellwert unterschritten
if currentStamina <= Config.JogThreshold then
enableJog()
end
-- Jog-Modus ausschalten wenn genug Stamina regeneriert (Hysterese)
if isJogForced and currentStamina >= (Config.JogThreshold + Config.JogHysteresis) then
disableJog()
end
else
-- Im Fahrzeug: schnellere Regen, kein Jog
if not regenBlocked then
currentStamina = clamp(
currentStamina + (Config.StaminaRegen * Config.VehicleRegenMultiplier),
0, 100
)
end
-- Jog zurücksetzen falls noch aktiv
disableJog()
end
end
end)
-- ============================================================
-- Chat-Befehl: /stamina [0-100]
-- ============================================================
if Config.AllowCommand then
RegisterCommand("stamina", function(source, args)
local val = tonumber(args[1])
if not val then
TriggerEvent("chat:addMessage", {
color = { 255, 200, 50 },
args = { "mercyv-stamina", "Nutzung: /stamina [" .. Config.CommandMin .. "-" .. Config.CommandMax .. "]" }
})
TriggerEvent("chat:addMessage", {
color = { 200, 200, 200 },
args = { "mercyv-stamina", "Aktueller Jog-Schwellwert: " .. Config.JogThreshold .. "% | Aktuelle Stamina: " .. math.floor(currentStamina) .. "%" }
})
return
end
if val < Config.CommandMin or val > Config.CommandMax then
TriggerEvent("chat:addMessage", {
color = { 255, 80, 80 },
args = { "mercyv-stamina", "Wert muss zwischen " .. Config.CommandMin .. " und " .. Config.CommandMax .. " liegen." }
})
return
end
Config.JogThreshold = val
TriggerEvent("chat:addMessage", {
color = { 100, 220, 130 },
args = { "mercyv-stamina", "Jog-Schwellwert auf " .. val .. "% gesetzt. (Rückkehr zum Sprint ab " .. (val + Config.JogHysteresis) .. "%)" }
})
log("JogThreshold via Befehl geändert → " .. val .. "%")
end, false)
end
-- ============================================================
-- Netzwerk-Events (von anderen Scripts aufrufbar)
-- ============================================================
-- Stamina auffüllen: TriggerEvent("mercyv-stamina:refill", 50)
RegisterNetEvent("mercyv-stamina:refill")
AddEventHandler("mercyv-stamina:refill", function(amount)
local old = currentStamina
currentStamina = clamp(currentStamina + (tonumber(amount) or 100), 0, 100)
log("Refill: +" .. tostring(amount) .. " | " .. string.format("%.1f", old) .. "% → " .. string.format("%.1f", currentStamina) .. "%")
end)
-- Stamina direkt setzen: TriggerEvent("mercyv-stamina:set", 75)
RegisterNetEvent("mercyv-stamina:set")
AddEventHandler("mercyv-stamina:set", function(amount)
currentStamina = clamp(tonumber(amount) or 100, 0, 100)
log("Stamina gesetzt auf: " .. string.format("%.1f", currentStamina) .. "%")
end)
-- Aktuellen Wert abrufen (callback-basiert für andere Scripts)
-- Beispiel: exports["mercyv-stamina"]:GetStamina()
exports("GetStamina", getStamina)
-- Jog-Status abrufen
exports("IsJogging", function()
return isJogForced
end)
log("Client geladen | JogThreshold: " .. Config.JogThreshold .. "% | Stamina Start: " .. Config.StartStamina .. "%")