Macht ein Tiefenlimit mechanisch statt zur Absprache - und oeffnet die tiefen Spots fuer den, der die richtige Flasche dabei hat. Der Grund fuer die realen 40-45 m ist nicht der Druck, sondern der Stickstoff in der Pressluft: tiefer wirkt er narkotisch, ab ~56 m wird auch der Sauerstoff giftig. Wer tiefer will, atmet Trimix, wo Helium einen Teil des Stickstoffs ersetzt. Genau so umgesetzt: - maxDepth und gas pro Flasche in config/shared.lua; Pressluft 45 m, neues diving_tank_trimix 100 m - Darunter Tiefenrausch in drei Stufen: Bildschirmeffekt, Kamerawackeln, hoeherer Luftverbrauch, in der letzten Stufe Schaden. Schwellen, Effekte, Staerken und Schaden komplett in config.narcosis - Vorwarnung 5 m vor der Grenze, Tiefenanzeige im HUD wird rot und pulsiert - Effekte werden beim Auftauchen, Ablegen, Tod und Resource-Stop aufgeraeumt - Auswahlmenue zeigt Gas und Tiefengrenze pro Flasche - Icon fuer die Trimix-Flasche, violett abgesetzt Keine Dekompression - auf Wunsch bewusst weggelassen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+105
-3
@@ -55,13 +55,61 @@ local function getDepth()
|
||||
return math.max(0.0, waterZ - coords.z)
|
||||
end
|
||||
|
||||
--- Aktuell aktive Tiefenrausch-Stufe (Index in config.narcosis.stages), 0 = keine.
|
||||
local narcosisStage = 0
|
||||
local narcosisWarned = false
|
||||
local narcosisDamageBuffer = 0.0
|
||||
|
||||
--- Wie weit die aktuelle Tiefe unter der Grenze der getragenen Flasche liegt.
|
||||
--- @return number Meter unterhalb der Grenze, negativ solange alles gut ist
|
||||
local function getDepthOverLimit()
|
||||
if not activeTank or not activeTank.maxDepth then return -math.huge end
|
||||
|
||||
return currentDepth - activeTank.maxDepth
|
||||
end
|
||||
|
||||
--- Setzt Bildschirmeffekt und Kamerawackeln auf die angegebene Stufe.
|
||||
--- @param stage number 0 = alles aus
|
||||
local function applyNarcosisStage(stage)
|
||||
if stage == narcosisStage then return end
|
||||
|
||||
narcosisStage = stage
|
||||
|
||||
ClearTimecycleModifier()
|
||||
StopGameplayCamShaking(true)
|
||||
|
||||
local data = stage > 0 and config.narcosis.stages[stage]
|
||||
|
||||
if not data then return end
|
||||
|
||||
if data.timecycle then
|
||||
SetTimecycleModifier(data.timecycle)
|
||||
SetTimecycleModifierStrength(data.strength or 1.0)
|
||||
end
|
||||
|
||||
if data.shake then
|
||||
ShakeGameplayCam(data.shake, data.shakeIntensity or 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
--- Verbrauchsfaktor. Tiefer tauchen kostet mehr Luft.
|
||||
--- Nutzt die geglättete Tiefe aus dem HUD-Thread, damit Wellengang den Verbrauch
|
||||
--- nicht im Sekundentakt springen lässt.
|
||||
local function getDecayFactor()
|
||||
if not config.depthDecayEnabled then return 1.0 end
|
||||
local factor = 1.0
|
||||
|
||||
return math.min(config.maxDecayFactor, 1.0 + currentDepth / config.depthDecayReference)
|
||||
if config.depthDecayEnabled then
|
||||
factor = math.min(config.maxDecayFactor, 1.0 + currentDepth / config.depthDecayReference)
|
||||
end
|
||||
|
||||
-- Tiefenrausch: unter Stress atmet man mehr.
|
||||
local stage = narcosisStage > 0 and config.narcosis.stages[narcosisStage]
|
||||
|
||||
if stage then
|
||||
factor = factor * (stage.drainFactor or 1.0)
|
||||
end
|
||||
|
||||
return factor
|
||||
end
|
||||
|
||||
--- @param ped number? default cache.ped - beim Model-Wechsel muss der neue Ped explizit rein
|
||||
@@ -198,8 +246,11 @@ local function removeGear(outOfAir, immediateSync)
|
||||
|
||||
currentGear.enabled = false
|
||||
setLamp(false)
|
||||
applyNarcosisStage(0)
|
||||
activeTank = nil
|
||||
warned = {}
|
||||
narcosisWarned = false
|
||||
narcosisDamageBuffer = 0.0
|
||||
|
||||
deleteGear()
|
||||
disableScuba(outOfAir)
|
||||
@@ -220,7 +271,8 @@ local function chooseTank(tanks)
|
||||
options[i] = {
|
||||
title = tank.label,
|
||||
description = locale('info.tank_remaining', formatTime(tank.oxygen),
|
||||
math.floor(tank.oxygen / tank.capacity * 100)),
|
||||
math.floor(tank.oxygen / tank.capacity * 100),
|
||||
tank.gas or '?', math.floor(tank.maxDepth or 0)),
|
||||
icon = 'fa-solid fa-bottle-water',
|
||||
onSelect = function() selection:resolve(tank) end
|
||||
}
|
||||
@@ -331,6 +383,8 @@ local function sendHudState(visible)
|
||||
reserve = pressure > 0 and pressure <= config.reservePressure,
|
||||
level = level,
|
||||
deep = currentDepth >= config.deepWarningDepth,
|
||||
-- Grenze der getragenen Flasche überschritten: Tiefenrausch läuft.
|
||||
overLimit = config.narcosis.enabled and getDepthOverLimit() >= 0,
|
||||
hasLamp = true,
|
||||
lamp = lampOn
|
||||
})
|
||||
@@ -396,6 +450,51 @@ local function startHudThread()
|
||||
end)
|
||||
end
|
||||
|
||||
--- Wertet die Tiefe gegen die Grenze der getragenen Flasche aus und setzt Effekte,
|
||||
--- Verbrauchsaufschlag und Schaden. Läuft auch über Wasser weiter, damit die
|
||||
--- Effekte beim Auftauchen wieder verschwinden.
|
||||
--- @param elapsed number Sekunden seit dem letzten Aufruf
|
||||
local function updateNarcosis(elapsed)
|
||||
if not config.narcosis.enabled then return end
|
||||
|
||||
local over = getDepthOverLimit()
|
||||
local stages = config.narcosis.stages
|
||||
local stage = 0
|
||||
|
||||
for i = 1, #stages do
|
||||
if over >= stages[i].over then stage = i end
|
||||
end
|
||||
|
||||
applyNarcosisStage(stage)
|
||||
|
||||
-- Vorwarnung, solange noch Zeit zum Umkehren ist.
|
||||
if activeTank and over >= -config.narcosis.warnBeforeMeters then
|
||||
if not narcosisWarned then
|
||||
narcosisWarned = true
|
||||
exports.qbx_core:Notify(locale('info.depth_limit', math.floor(activeTank.maxDepth or 0)), 'warning')
|
||||
end
|
||||
else
|
||||
narcosisWarned = false
|
||||
end
|
||||
|
||||
local data = stage > 0 and stages[stage]
|
||||
|
||||
if not data or (data.damagePerTick or 0) <= 0 then
|
||||
narcosisDamageBuffer = 0.0
|
||||
return
|
||||
end
|
||||
|
||||
-- Schaden sammeln statt jeden Tick zu runden, sonst geht bei 250 ms Takt
|
||||
-- alles unter 4 Schaden pro Sekunde verloren.
|
||||
narcosisDamageBuffer = narcosisDamageBuffer + data.damagePerTick * elapsed
|
||||
|
||||
if narcosisDamageBuffer >= 1.0 then
|
||||
local damage = math.floor(narcosisDamageBuffer)
|
||||
narcosisDamageBuffer -= damage
|
||||
ApplyDamageToPed(cache.ped, damage, false)
|
||||
end
|
||||
end
|
||||
|
||||
--- Zieht Luft über die tatsächlich vergangene Zeit ab statt über gezählte Ticks.
|
||||
--- Ein Wait(1000) läuft bei Last spürbar länger als eine Sekunde - über einen
|
||||
--- 20-Minuten-Tauchgang summiert sich das sichtbar auf.
|
||||
@@ -411,6 +510,8 @@ local function startOxygenLevelDecrementerThread()
|
||||
local elapsed = (now - lastTick) / 1000
|
||||
lastTick = now
|
||||
|
||||
updateNarcosis(elapsed)
|
||||
|
||||
if not activeTank then goto continue end
|
||||
|
||||
if IsPedSwimmingUnderWater(cache.ped) and activeTank.oxygen > 0 then
|
||||
@@ -622,6 +723,7 @@ AddEventHandler('onResourceStop', function(resource)
|
||||
|
||||
syncTank(true)
|
||||
setLamp(false)
|
||||
applyNarcosisStage(0)
|
||||
deleteGear()
|
||||
SendNUIMessage({ action = 'state', visible = false })
|
||||
SetEnableScuba(cache.ped, false)
|
||||
|
||||
Reference in New Issue
Block a user