Offset und Rotation des Lampen-Props waren hart im Code, und die Rotation (180, 90, 0) war stumpf von der Maske uebernommen - daher stand die Lampe quer im Gesicht. d4rk_phone haengt sein Prop mit komplett null Offset und Rotation an, das ist der bessere Ausgangspunkt. - lampBone, lampPropOffset, lampPropRotation in die Config; Prop und Licht haengen jetzt am selben Bone, damit der Strahl aus der Lampe kommt - lampProp = '' erlaubt, dann nur Licht ohne Prop - Lichtwerte (Farbe, Reichweite, Helligkeit, Kegel) aus d4rk_phone uebernommen statt neu geraten; lampShadows wie dort auf false - /divelamp und /divelight stellen beides im laufenden Spiel ein und geben die Config-Zeile zum Uebernehmen aus (config.debug) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
12 KiB
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.
Normal — Luft, Tiefe, Fülldruck, Lampe an
Warnung — Restluft unter der ersten Schwelle, Tiefe über deepWarningDepth,
Druck unter reservePressure
Kritisch — letzte Sekunden, der Ring pulsiert
Das HUD erscheint nur mit angelegter Ausrüstung unter Wasser und blendet sich weich ein und aus.
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 und tiefenabhängiger Verbrauch — tiefer tauchen kostet mehr Luft. Abschaltbar.
- 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. Sechs Items, nichts weiter anzupassen. -
Die sechs 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
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 |
|---|---|---|
tanks |
4 Flaschen | name, capacity (Sekunden), pressure (bar) |
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 |
true |
Verbrauch steigt mit der Tiefe |
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 |
HUD
| Option | Default | Bedeutung |
|---|---|---|
hudEnabled |
true |
Ohne HUD bleibt die Ausrüstung voll nutzbar |
hudUpdateIntervalMs |
250 |
4 Updates pro Sekunde |
hudFollowGameHud |
true |
Mit dem Spiel-HUD ausblenden |
hudToggleKey |
'' |
Eigene Taste, leer = unbelegt |
reservePressure |
50 |
Ab hier wird die Druckanzeige rot |
Lampe
| Option | Default | Bedeutung |
|---|---|---|
lampKey |
'l' |
Vorbelegung |
lampBone |
12844 |
Bone für Prop und Licht — derselbe, damit der Strahl aus der Lampe kommt. 28422 = Hand statt Kopf |
lampProp |
'prop_cs_police_torch' |
Optik. Ungültiges Model → Warnung im Log, Licht funktioniert trotzdem. '' = kein Prop |
lampPropOffset / lampPropRotation |
vec3(0,0,0) |
Sitz des Props am Bone — mit /divelamp einstellen |
lampOffset |
vec3(0,0,0) |
Ursprung des Lichtkegels, bone-relativ |
lampDirection |
vec3(0, 1, 0) |
Richtung des Kegels, bone-relativ |
lampColour |
{255, 250, 235} |
RGB |
lampDistance / lampBrightness / lampRoundness / lampRadius / lampFalloff |
28/3/0/16/2 |
Form des Lichtkegels, Werte aus d4rk_phone übernommen |
lampShadows |
false |
true nutzt DrawSpotLightWithShadow — sieht besser aus, kostet aber deutlich Performance |
lampDrawDistance |
45.0 |
Ab hier werden fremde Lampen nicht mehr gezeichnet |
lampMaxLights |
4 |
Gleichzeitige Lampen, die nächstgelegenen gewinnen |
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.
Lampe einstellen
Wo Prop und Lichtkegel am Kopf sitzen, hängt daran, wie das Prop-Model selbst
ausgerichtet ist — das lässt sich nicht am Schreibtisch erraten. Mit
debug = true in config/client.lua gibt es zwei Befehle, die die Werte im
laufenden Spiel ändern und die fertige Config-Zeile ins Log schreiben:
/divelamp <x> <y> <z> <rx> <ry> <rz> Sitz des Lampen-Props
/divelight <x> <y> <z> <dx> <dy> <dz> Ursprung und Richtung des Lichtkegels
Das Prop wird sofort neu angehängt, das Licht zieht ohne Verzögerung mit — kein
Resource-Restart pro Versuch. Sind die Werte gut, die ausgegebenen Zeilen in die
Config übernehmen und debug wieder ausschalten.
Alternativ mit einem Prop-Attach-Editor wie noted_propattacher ausmessen: Prop spawnen, mit der Maus an die Stelle ziehen, Werte übernehmen.
Im Basegame gibt es keine Tauchlampe.
prop_cs_police_torchist eine Polizei-Taschenlampe; Varianten davon sindprop_police_torchundprop_scn_police_torch. Wer eine echte Tauchlampe will, braucht ein Custom-Model.
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 synchron wird
Licht ist in GTA nie synchronisiert — DrawSpotLight zeichnet nur lokal für den
aktuellen Frame. Der Lampenzustand wird deshalb als Statebag repliziert
(LocalPlayer.state:set('divelight', …, true)), und jeder Client zeichnet die
Lampen aller Taucher in seiner Nähe selbst.
Die Richtung kommt aus zwei bone-relativen Punkten am Kopf-Bone, nicht aus
GetEntityForwardVector: beim Tauchen liegt der Ped waagerecht im Wasser, der
Entity-Forward würde stur horizontal leuchten. Die Offsets von GetPedBoneCoords
sind laut Native-Doku "relative to the bone's rotation", die Differenz zweier
solcher Punkte enthält also den Pitch.
Entwicklung
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.
Der Umbau ist in PLAN.md dokumentiert, inklusive der offenen Punkte.
Bekannte Unsicherheiten
Bisher nicht im Spiel getestet — geprüft sind Lua-Syntax und Globals, die Locale-JSONs und das HUD im Browser.
lampProp— der Prop-Name ist ungeprüft. Falls falsch: Warnung im Log, das Licht funktioniert weiter, nur ohne sichtbares Prop. Ersatz finden: forge.plebmasters.de/objectslampDirection— welche lokale Achse des Kopf-Bones nach vorne zeigt, hängt am Skelett. Leuchtet der Kegel falsch herum: Achse tauschen oder Vorzeichen drehen.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.
Lizenz
GPL-3.0, wie das Original. Die Upstream-Historie ist erhalten und liegt auf dem
Remote upstream.