Gleicher Dateiname bei neuem Inhalt bleibt im Browser-Cache haengen - beim Layout-Wechsel sah man weiter die alte Zweispalten-Version. Der Parameter erzwingt einen frischen Abruf. Bei der naechsten Layout-Aenderung mitziehen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
d4rk_divegear
Tauchausrüstung für QBox. Fork von qbx_divegear mit Flaschengrößen, gesyncter Lampe, Tiefen- und Druckanzeige — und Ausrüstung, die bei Animationen nicht mehr verschwindet.
HUD
Die Bilder sind maßstabsgetreue Renderings des Overlays aus denselben Werten wie
nui/style.css— keine In-Game-Aufnahmen. Erzeugt mitdocs/gen-hud-svg.mjs.
Eine Dreier-Konsole wie am echten Tauchgerät: Finimeter links, Restluft als Ring in der Mitte, Tiefenmesser rechts; die Werte darunter auf einer Linie. Das HUD ist auf 1080p entworfen und skaliert mit der Bildschirmhöhe mit, damit es auf 1440p und 4K nicht schrumpft.
Normal — Druck im grünen Bereich, flach getaucht, Lampe an
Warnung — Zeiger in der Reserve (roter Bereich ab reservePressure),
Restluft unter der ersten Schwelle, Tiefe über deepWarningDepth
Kritisch — unter der Tiefengrenze des Atemgases: der Zeiger steht im roten Bereich des Tiefenmessers, die Uhr pulsiert, Tiefenrausch läuft
Das HUD erscheint, sobald die Ausrüstung angelegt ist — also auch an Land, damit
sich der Flaschendruck am Finimeter ablesen lässt, ohne das Inventar zu öffnen.
Wer es nur unter Wasser will: hudOnlyUnderwater = true.
Features
- Vier Flaschengrößen — 5, 10, 15 und 20 Minuten. Die Restluft liegt in der Item-Metadata und überlebt Ablegen, Relog, Resource-Restart und Tod. Der Füllstand ist als Balken direkt im Inventar-Slot sichtbar.
- Manometer in bar — physikalisch korrekt aus dem Restanteil abgeleitet, Reservedruck wird eingefärbt.
- Gesyncte Tauchlampe — an der Ausrüstung, An/Aus per Taste. Andere Spieler sehen den Lichtkegel, und zwar in die Richtung, in die tatsächlich geschaut wird.
- Tiefenanzeige in Metern. Optional steigt der Luftverbrauch mit der Tiefe
(
depthDecayEnabled, per Default aus). - Tiefengrenze übers Atemgas — mit Pressluft ab 45 m Tiefenrausch, mit Trimix erst ab 100 m. Macht das Tiefenlimit mechanisch statt zur Absprache.
- Ausrüstung bleibt — bei Emotes, Ragdoll, Kleiderwechsel und aufräumenden Fremd-Scripts.
- HUD ausblendbar für Unterwasser-Screenshots.
- Serverseitige Prüfung — die Restluft kann nur sinken, und nicht schneller als physikalisch möglich.
Abhängigkeiten
qbx_core ·
ox_lib ·
ox_inventory
Installation
-
Ordner nach
resources/und in derserver.cfgstarten — nachox_inventoryundqbx_core:ensure d4rk_divegear -
items_for_ox_inventory.luakomplett markieren und inox_inventory/data/items.luainnerhalb derreturn { … }-Klammer einfügen. Sieben Items, nichts weiter anzupassen. -
Die sieben PNGs aus
icons/nachcdn.d4rkst3r.de/items/hochladen. Sie heißen genau wie die Items, deshalb braucht es keinclient.image.
Es gibt bewusst keine fertige items.lua zum Ersetzen — die würde die
restlichen Items des Servers überschreiben.
Items
Alle Flaschen starten bei 300 bar.
diving_gear und diving_fill stammen aus dem Original (dort hießen sie
Diving Gear und Diving Tube). Neu sind nur die vier Flaschen: im Original war
die Luft eine Client-Variable, die an keinem Item hing — eine Sauerstoffflasche
als Item gab es dort gar nicht. Für unterschiedliche Laufzeiten und persistente
Restluft braucht es aber ein Item, an dem beides hängen kann.
Ein Taucher trägt damit zwei Dinge: die Ausrüstung und eine Flasche. Die Kartusche nur, wer unterwegs nachfüllen will.
Die Icons liegen als 128×128 PNG mit transparentem Hintergrund in
icons/, die SVG-Quellen in icons/src/. Die Laufzeit steht als Zahl
auf dem Farbband — ohne die sind die Einzelflaschen im Inventar nur noch an der
Bandfarbe auseinanderzuhalten. Wer capacity ändert, sollte die Zahlen in
icons/gen-icons.mjs mitziehen.
Dass alle Flaschen mit demselben Fülldruck starten, ist gewollt: in echt macht das Volumen die Laufzeit, nicht der Druck. Die große Flasche hält 300 bar einfach länger.
Metadata
| Key | Bedeutung |
|---|---|
oxygen |
Restluft in Sekunden — die eigentliche Wahrheit |
durability |
Füllstand in Prozent, nur für den Balken im Inventar-Slot |
Kein decay = true auf den Flaschen. ox_inventory löscht Items mit decay,
sobald durability 0 erreicht — die leere Flasche würde also verschwinden statt
auffüllbar zu bleiben.
Bedienung
Die Flasche wird nicht separat angezogen. Sie muss nur im Inventar liegen — beim Anlegen der Ausrüstung fragt das Script, welche angeschlossen werden soll.
| Aktion | Wie |
|---|---|
| Ausrüstung an-/ausziehen | diving_gear benutzen |
| Flasche wählen | Menü beim Anlegen (entfällt bei nur einer Flasche) |
| Flasche auffüllen | diving_fill benutzen — nicht unter Wasser, nicht bei voller Flasche |
| Lampe an/aus | L |
| HUD ein-/ausblenden | Eigene Taste, standardmäßig unbelegt |
Beide Tasten sind vom Spieler in den FiveM-Einstellungen unter Tastenbelegung → FiveM umlegbar.
Konfiguration
config/shared.lua — Client und Server
| Option | Default | Bedeutung |
|---|---|---|
gearItem / fillItem |
diving_gear / diving_fill |
Item-Namen für Ausrüstung und Füll-Kartusche |
tanks |
5 Flaschen | name, capacity (Sekunden), pressure (bar), maxDepth (Meter), gas (Label fürs Menü) |
newTanksFull |
true |
Flaschen ohne Metadata (Shop, AddItem, Admin-Befehl) gelten als voll. Auf false muss jede neue Flasche erst mit einer Kartusche befüllt werden |
syncIntervalSeconds |
15 |
Wie oft die Restluft an den Server gemeldet wird. Bei einem Crash gehen maximal so viele Sekunden verloren |
maxDrainPerSecond |
5.0 |
Obergrenze der serverseitigen Prüfung |
config/client.lua
Ablauf
| Option | Default | Bedeutung |
|---|---|---|
putOnSuitTimeMs / takeOffSuitTimeMs / refillTankTimeMs |
5000 |
Dauer der Progressbars |
decayRate |
1.0 |
Sekunden Luft pro echter Sekunde, vor dem Tiefenfaktor |
warnAtSeconds |
{60, 30, 10} |
Warnschwellen, jede einmal pro Tauchgang |
removeGearOnDeath |
true |
Ausrüstung beim Tod abnehmen. Die Flasche bleibt mit ihrer Restluft im Inventar |
gearWatchdogIntervalMs |
1000 |
Prüfintervall, ob die Props noch am Ped hängen |
maxTimeUnderwater |
50.0 |
Sekunden unter Wasser ohne Ausrüstung (Vanilla-Verhalten) |
maxTimeUnderwaterOutOfAir |
1.0 |
Sekunden, sobald die Flasche leer ist |
Tiefe
| Option | Default | Bedeutung |
|---|---|---|
depthDecayEnabled |
false |
Verbrauch steigt mit der Tiefe. Aus, damit die 5/10/15/20 Minuten exakt stimmen |
depthDecayReference |
30.0 |
Faktor 1 + tiefe / referenz |
maxDecayFactor |
4.0 |
Deckel für den Faktor |
deepWarningDepth |
25.0 |
Ab hier wird die Tiefenanzeige eingefärbt |
Tiefenrausch (narcosis)
| Option | Default | Bedeutung |
|---|---|---|
enabled |
true |
Komplett abschaltbar |
warnBeforeMeters |
5.0 |
Vorwarnung so viele Meter vor der Grenze |
engineDepthLimit |
160.0 |
Tiefe, ab der das Spiel selbst Schluss macht — ingame gemessen, dagegen hilft keine Flasche |
engineWarnBeforeMeters |
20.0 |
Vorwarnung davor |
stages |
3 Stufen | Pro Stufe: over (Meter unter der Grenze), timecycle + strength, shake + shakeIntensity, drainFactor, damagePerTick |
damagePerTick steht überall auf 0 — Tiefenrausch kostet also erstmal nur Sicht,
Kontrolle und Luft, kein Leben. Wer es härter will, setzt es in der letzten Stufe
auf z.B. 2.
HUD
| Option | Default | Bedeutung |
|---|---|---|
hudEnabled |
true |
Ohne HUD bleibt die Ausrüstung voll nutzbar |
hudUpdateIntervalMs |
250 |
4 Updates pro Sekunde |
hudScale |
1.0 |
Größenfaktor obendrauf. Das HUD skaliert schon selbst mit der Bildschirmhöhe |
hudOnlyUnderwater |
false |
Auf false schon sichtbar, sobald die Ausrüstung an ist — Finimeter ablesen ohne Inventar |
hudFollowGameHud |
true |
Mit dem Spiel-HUD ausblenden |
hudToggleKey |
'' |
Eigene Taste, leer = unbelegt |
reservePressure |
50 |
Roter Bereich des Finimeters, ab hier färbt sich der Zeiger |
depthDialMax |
100.0 |
Skalenende des Tiefenmessers. Tiefer schlägt der Zeiger an, die Zahl stimmt weiter |
Lampe
| Option | Default | Bedeutung |
|---|---|---|
lampKey |
'l' |
Vorbelegung der Taste |
lampReconcileIntervalMs |
500 |
Wie oft der Lampen-Zustand auf die Peds in der Nähe nachgezogen wird |
Beim Balancing beachten:
maxDrainPerSecond(shared) muss übermaxDecayFactor(client) liegen. Sonst hält der Server den ehrlichen Verbrauch in großer Tiefe für Cheat und schreibt Luft zurück.
Exports
exports.d4rk_divegear:setHudVisible(false) -- HUD ausblenden
local shown = exports.d4rk_divegear:isHudVisible()
Gedacht für HUD- und Screenshot-Resources. Zusätzlich folgt das HUD automatisch
IsHudHidden(), greift also bei allem was DisplayHud(false) setzt, ohne dass
etwas angebunden werden muss.
Wie die Lampe funktioniert
Es wird kein Licht selbst gezeichnet. GTA bringt seit v1493 (Cayo Perico) eine eigene Lampe an der Tauchausrüstung mit:
SetEnableScubaGearLight(ped, toggle) -- 0xEE2476B9EE4A094F
IsScubaGearLightEnabled(ped) -- 0x88274C11CF0D866D
Die sitzt an der richtigen Stelle, leuchtet in Blickrichtung und braucht weder Prop noch Offsets noch einen Draw-Thread.
Sie funktioniert auch ohne Scuba-Kleidung am Ped — ingame bestätigt. Der Hinweis in esx_scuba, das Licht hänge am Kleidungs-Component, trifft hier also nicht zu. Das Outfit wird nicht angefasst. Sollte die Native bei einem Ped-Model doch nicht anschlagen, gibt es beim Einschalten eine Meldung statt stiller Wirkungslosigkeit.
Der Flag ist ein lokaler Ped-Zustand und wird nicht von selbst repliziert.
Deshalb läuft der Zustand über einen Statebag
(LocalPlayer.state:set('divelight', …, true)), und jeder Client setzt den Flag
für die Taucher in seiner Nähe selbst — sofort per AddStateBagChangeHandler,
plus ein Abgleich alle lampReconcileIntervalMs, weil Peds beim Streaming,
Respawn und Model-Wechsel neu erzeugt werden und den Flag dabei verlieren.
Entwicklung
Es gibt bewusst keine CI: die Workflows aus dem Original liefen gegen Qbox' Discord und GitHub-Releases, und Linting passiert lokal vor dem Commit.
node ../.tools/lint.mjs # Lua-Lint, CfxLua-tauglich
node ../.tools/nui-preview.mjs nui # HUD im Browser anschauen
node docs/gen-hud-svg.mjs docs # Renderings für diese README neu bauen
# Item-Icons neu bauen (SVG -> PNG, braucht ImageMagick mit librsvg)
node icons/gen-icons.mjs
for f in icons/src/*.svg; do
magick -background none "$f" -resize 128x128 "icons/$(basename "$f" .svg).png"
done
gen-icons.mjs schreibt außerdem icons/_check.html — alle Icons auf
Schachbrett, in Slot-Größe und klein, zum Gegenschauen nach Änderungen.
librsvg 2.40 wirft beim Rendern der Zahlen ein
Invalid UTF-8 string passed to pango_layout_set_text(). Das ist harmlos und passiert bei jedem<text>-Element, auch im minimalsten Testfall — die Zahlen kommen korrekt raus.
Warum die Dinge so gebaut sind — und welche Fallstricke dahinterstecken — steht
in ENTSCHEIDUNGEN.md, zusammen mit den offenen Punkten.
Die Abnahme läuft über die
Issues —
ein Issue pro Testbereich, mit prio:-Labels und ungeprueft für alles, was
sich ohne laufendes Spiel nicht verifizieren ließ.
Offene Punkte
Ingame getestet sind Anlegen und Ablegen, Flaschenauswahl, Luftverbrauch, HUD mit Tiefe und Druck sowie die Lampe. Noch offen:
- Scuba-Lampe ohne passendes Outfit — sie hängt an der Scuba-Kleidung (Component 8). Wer die nicht trägt, bekommt eine Meldung. Soll die Ausrüstung das Outfit selbst setzen, muss das noch gebaut werden (inklusive Sichern und Wiederherstellen der vorherigen Kleidung).
IsHudHidden()— ob die Native aufDisplayHud(false)anspringt, ist ungetestet. Falls nicht, greifen Taste und Export weiterhin.- Nach einem Relog muss die Ausrüstung neu angelegt werden. Die Restluft geht dabei nicht verloren, die liegt auf der Flasche.
- HUD-Position ist nur in
nui/style.csseinstellbar, nicht in der Config. - Balancing — die Laufzeiten sind gesetzt, aber nicht am Spielgefühl geprüft.
Lizenz
GPL-3.0, wie das Original. Die Upstream-Historie ist erhalten und liegt auf dem
Remote upstream.