Files
d4rk_divegear/README.md
T
D4rkst3randClaude Opus 5 6432550f68
Lint / Lint Resource (push) Has been cancelled
feat(icons): Item-Icons fuer alle sechs Items
128x128 PNG mit transparentem Hintergrund, aus SVG-Quellen per ImageMagick
(librsvg) erzeugt und damit reproduzierbar statt handgemalt.

- Tauchmaske, quer liegende Pressluft-Kartusche mit Manometer, drei
  Einzelflaschen und die Doppelflasche fuer XL
- Laufzeit als Zahl auf dem Farbband: ohne die waren die Einzelflaschen bei
  Slot-Groesse nur noch an der Bandfarbe zu unterscheiden, im 56px-Test gar
  nicht mehr
- Kartusche bewusst liegend statt hochkant, damit sie sich von den Flaschen
  abhebt - die erste Fassung las sich wie eine Flasche mit Download-Pfeil
- client.image faellt weg: ox_inventory laedt <imagepath>/<itemname>.png, und
  die Dateien heissen genau wie die Items

gen-icons.mjs schreibt zusaetzlich ein Kontrollblatt (Schachbrett, Slot-Groesse,
klein), mit dem die Icons gegengeprueft wurden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 00:25:39 +02:00

242 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# d4rk_divegear
Tauchausrüstung für QBox. Fork von [qbx_divegear](https://github.com/Qbox-project/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 mit `docs/gen-hud-svg.mjs`.
**Normal** — Luft, Tiefe, Fülldruck, Lampe an
![HUD, normaler Zustand](docs/hud-normal.svg)
**Warnung** — Restluft unter der ersten Schwelle, Tiefe über `deepWarningDepth`,
Druck unter `reservePressure`
![HUD, Warnstufe](docs/hud-warnung.svg)
**Kritisch** — letzte Sekunden, der Ring pulsiert
![HUD, kritischer Luftstand](docs/hud-kritisch.svg)
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`](https://github.com/Qbox-project/qbx_core) ·
[`ox_lib`](https://github.com/overextended/ox_lib) ·
[`ox_inventory`](https://github.com/overextended/ox_inventory)
## Installation
1. Ordner nach `resources/` und in der `server.cfg` starten — **nach**
`ox_inventory` und `qbx_core`:
```cfg
ensure d4rk_divegear
```
2. [`items_for_ox_inventory.lua`](items_for_ox_inventory.lua) komplett markieren
und in `ox_inventory/data/items.lua` innerhalb der `return { … }`-Klammer
einfügen. Sechs Items, nichts weiter anzupassen.
3. Die sechs PNGs aus [`icons/`](icons) nach `cdn.d4rkst3r.de/items/` hochladen.
Sie heißen genau wie die Items, deshalb braucht es kein `client.image`.
Es gibt bewusst **keine** fertige `items.lua` zum Ersetzen — die würde die
restlichen Items des Servers überschreiben.
## Items
| Icon | Item | Label | Laufzeit | Fülldruck | Gewicht |
|---|---|---|---|---|---|
| <img src="icons/diving_gear.png" width="40"> | `diving_gear` | Tauchausrüstung | — | — | 5000 |
| <img src="icons/diving_fill.png" width="40"> | `diving_fill` | Pressluft-Kartusche | — | — | 1000 |
| <img src="icons/diving_tank_small.png" width="40"> | `diving_tank_small` | Tauchflasche (5 Min) | 300 s | 300 bar | 4000 |
| <img src="icons/diving_tank_medium.png" width="40"> | `diving_tank_medium` | Tauchflasche (10 Min) | 600 s | 300 bar | 7000 |
| <img src="icons/diving_tank_large.png" width="40"> | `diving_tank_large` | Tauchflasche (15 Min) | 900 s | 300 bar | 10000 |
| <img src="icons/diving_tank_xl.png" width="40"> | `diving_tank_xl` | Tauchflasche (20 Min) | 1200 s | 300 bar | 13000 |
Die Icons liegen als 128×128 PNG mit transparentem Hintergrund in
[`icons/`](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
| 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) |
| `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 |
| `lampProp` | `'prop_cs_police_torch'` | Optik. Ungültiges Model → Warnung im Log, Licht funktioniert trotzdem |
| `lampOffset` | `vec3(0, 0.15, 0)` | Position relativ zum Kopf-Bone |
| `lampDirection` | `vec3(0, 1, 0)` | Richtung des Kegels, bone-relativ |
| `lampColour` | `{225, 245, 255}` | RGB |
| `lampDistance` / `lampBrightness` / `lampRoundness` / `lampRadius` / `lampFalloff` | `30/6/1/14/1.5` | Form des Lichtkegels |
| `lampShadows` | `true` | `false` nutzt `DrawSpotLight` statt der Schattenvariante — flacher, aber spürbar schneller |
| `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 über
> `maxDecayFactor` (client) liegen. Sonst hält der Server den ehrlichen Verbrauch
> in großer Tiefe für Cheat und schreibt Luft zurück.
## Exports
```lua
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
```bash
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](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/objects](https://forge.plebmasters.de/objects)
- **`lampDirection`** — 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 auf `DisplayHud(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`.