diff --git a/README.md b/README.md index 6d9d0db..00da0b5 100644 --- a/README.md +++ b/README.md @@ -4,50 +4,19 @@ Tauchausrüstung für QBox. Fork von [qbx_divegear](https://github.com/Qbox-proj 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`. - -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 - -![HUD, normaler Zustand](docs/hud-normal.svg?v=konsole) - -**Warnung** — Zeiger in der Reserve (roter Bereich ab `reservePressure`), -Restluft unter der ersten Schwelle, Tiefe über `deepWarningDepth` - -![HUD, Warnstufe](docs/hud-warnung.svg?v=konsole) - -**Kritisch** — unter der Tiefengrenze des Atemgases: der Zeiger steht im roten -Bereich des Tiefenmessers, die Uhr pulsiert, Tiefenrausch läuft - -![HUD, kritischer Luftstand](docs/hud-kritisch.svg?v=konsole) - -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`. +![HUD](docs/hud-normal.svg?v=konsole) ## 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). +- **Fünf Flaschen** — 5, 10, 15, 20 Minuten Pressluft plus Trimix. Die Restluft + liegt in der Item-Metadata und überlebt Ablegen, Relog, Restart und Tod. +- **Tauchkonsole als HUD** — Finimeter, Restluft und Tiefenmesser mit Zeigern und + farbigen Gefahrenbereichen. Skaliert mit der Bildschirmauflösung. +- **Gesyncte Tauchlampe** über die spieleigene Scuba-Lampe. - **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. + erst ab 100 m. Macht ein Tiefenlimit mechanisch statt zur Absprache. +- **Ausrüstung bleibt dran** — bei Emotes, Ragdoll, Kleiderwechsel und + aufräumenden Fremd-Scripts. - **Serverseitige Prüfung** — die Restluft kann nur sinken, und nicht schneller als physikalisch möglich. @@ -59,239 +28,29 @@ Wer es nur unter Wasser will: `hudOnlyUnderwater = true`. ## Installation -1. Ordner nach `resources/` und in der `server.cfg` starten — **nach** - `ox_inventory` und `qbx_core`: +1. `ensure d4rk_divegear` in der `server.cfg`, **nach** `ox_inventory` und `qbx_core` +2. [`items_for_ox_inventory.lua`](items_for_ox_inventory.lua) in + `ox_inventory/data/items.lua` einfügen +3. Die sieben PNGs aus [`icons/`](icons) aufs Icon-CDN hochladen - ```cfg - ensure d4rk_divegear - ``` +Ausführlich, inklusive der beiden häufigsten Stolpersteine: +**[Wiki → Installation](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Installation)** -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. Sieben Items, nichts weiter anzupassen. +## Dokumentation -3. Die sieben PNGs aus [`icons/`](icons) nach `cdn.d4rkst3r.de/items/` hochladen. - Sie heißen genau wie die Items, deshalb braucht es kein `client.image`. +Alles Weitere steht im +**[Wiki](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki)**: -Es gibt bewusst **keine** fertige `items.lua` zum Ersetzen — die würde die -restlichen Items des Servers überschreiben. +[Items](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Items) · +[Bedienung](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Bedienung) · +[Konfiguration](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Konfiguration) · +[Tiefe und Atemgas](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Tiefe-und-Atemgas) · +[Lampe](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Lampe) · +[Exports](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Exports) · +[Entwicklung](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/wiki/Entwicklung) -## Items - -| Icon | Item | Label | Laufzeit | Gas | max. Tiefe | Gewicht | -|---|---|---|---|---|---|---| -| | `diving_gear` | Tauchausrüstung | — | — | — | 5000 | -| | `diving_fill` | Pressluft-Kartusche | — | — | — | 1000 | -| | `diving_tank_small` | Tauchflasche (5 Min) | 300 s | Pressluft | 45 m | 4000 | -| | `diving_tank_medium` | Tauchflasche (10 Min) | 600 s | Pressluft | 45 m | 7000 | -| | `diving_tank_large` | Tauchflasche (15 Min) | 900 s | Pressluft | 45 m | 10000 | -| | `diving_tank_xl` | Tauchflasche (20 Min) | 1200 s | Pressluft | 45 m | 13000 | -| | `diving_tank_trimix` | Trimix-Flasche (15 Min) | 900 s | Trimix | 100 m | 11000 | - -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/`](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 ü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 funktioniert - -Es wird kein Licht selbst gezeichnet. GTA bringt seit v1493 (Cayo Perico) eine -eigene Lampe an der Tauchausrüstung mit: - -```lua -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](https://github.com/wobozkyng/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. - -```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 ``-Element, auch im minimalsten Testfall — die Zahlen -> kommen korrekt raus. - -Warum die Dinge so gebaut sind — und welche Fallstricke dahinterstecken — steht -in [ENTSCHEIDUNGEN.md](ENTSCHEIDUNGEN.md), zusammen mit den offenen Punkten. -Die Abnahme läuft über die -[Issues](https://git.d4rkst3r.de/D4rkst3r/d4rk_divegear/issues?labels=test) — -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 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. -- **HUD-Position** ist nur in `nui/style.css` einstellbar, nicht in der Config. -- **Balancing** — die Laufzeiten sind gesetzt, aber nicht am Spielgefühl geprüft. +Warum die Dinge so gebaut sind und welche Fallstricke dahinterstecken, steht +code-nah hier im Repo: [ENTSCHEIDUNGEN.md](ENTSCHEIDUNGEN.md). ## Lizenz