> For the complete documentation index, see [llms.txt](https://kharan-studio.gitbook.io/kharanstudio/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kharan-studio.gitbook.io/kharanstudio/custom-peds/the-diubis.md).

# The Diubis

Meet the Diubis: small, shy creatures that live along the rivers and lakes of RDR2. Groups of them gather on the banks, wander, sit by the water and chatter in their own voices.

### Features

* Shoreline habitats. Small groups of 2–4 Diubis appear on their own along the rivers and lakes of the map, near players, always on solid ground right next to the water. You can also place fixed habitats at hand-picked spots.
* Shared world. Every player sees the same Diubis in the same place. The server picks one nearby player to create and direct each group, so nothing is duplicated.
* Flee into the water. When you get close they freeze for a moment and stare at you, one of them raises the alarm, then they all run to the water and vanish as they dive in. Every nearby player sees the dive.
* Stealth matters. Crouching lets you get much closer. Running, riding or driving a wagon scares them from further away, and a gunshot nearby sends the whole group into the water.
* Catching. While they are alert or fleeing, press E to grab one and win a quick reflex struggle (a random sequence of keys). The server locks each Diubi so two players can never catch the same one.
* Named companions. Every caught Diubi gets its own name (Pip, Nimi, Gota…), stored in the inventory item together with the river or lake where it was caught.
* Pet system. Use the item to call or dismiss your Diubi. It follows you (also through water), cannot die, and can ride on your shoulders (G). Take it to a habitat and the wild Diubis will not flee: they gather around to greet it.
* Cinematic interaction (R). A full camera scene with a menu: talk (six conversation topics in the Diubi language with live translation), pet, share food, dance, ask for a trick, sing together (with the Diubi's own song), watch the horizon together, stay here / follow me, and lift onto your shoulders.
* Synced 3D voices. Five original Diubi sounds. Everyone nearby hears the same Diubi at the same time, with distance falloff and stereo panning based on your camera.
* No black or invisible peds. Each Diubi stays hidden until its MetaPed outfit and textures have fully loaded, then gets an extra refresh the first time it comes close to you. Pets use an even more conservative preparation, on every player's screen.
* Shoreline life. Diubis wander along the bank, sit down for a while or crouch to inspect things.
* Framework support. VORP out of the box, an RSG adapter included, and a small bridge file to plug in any other inventory. Without an inventory, everything works except catching.
* English and Spanish for all texts and dialogue, with an easy way to add more languages.
* Admin tools to test spawning, inspect water detection and record fixed habitats in game.

### How it works

A habitat is a spot on a shoreline where a small group of Diubis lives. Habitats are either dynamic (found automatically near players) or fixed (listed in the config). Both behave the same way:

1. Discovery. Every 35–45 seconds, each player's game looks for a shoreline 40–85 m away, with a 30% chance per search. It checks that the water belongs to an allowed river or lake, that the spot is solid ground and that the water is a few metres away. The server then checks the global limits and the spacing to other habitats before accepting it.
2. Population. When a player is within 95 m (but not close enough to scare them), the server asks that player's game to create 2–4 Diubis on solid ground. They become shared network entities that every player sees.
3. Life on the shore. They wander a few metres inland from the water. Now and then one sits down or crouches to inspect something. They talk to each other with synced voices.
4. Alert and flight. When a player gets within the fear distance (or fires a gun nearby), the group freezes for about a second and stares at the intruder, one of them raises the alarm, and they sprint to the nearest water.
5. The dive. As each Diubi touches the water it sinks and fades out for every nearby player, then it is removed.
6. Catching window. During the alert and the run, a player standing next to a Diubi can grab it (E) and play the struggle minigame. A caught Diubi becomes an inventory item.
7. Cooldown. Once every Diubi has dived or been caught, the habitat rests until all players have moved 110 m away. A fixed habitat then becomes available again; a dynamic one disappears so that new ones can appear elsewhere.

If nobody stays within 140 m, the group is quietly removed (nobody can see it), and a dynamic habitat with nobody around for 2 minutes is retired. If a player brings their pet Diubi within 22 m of a populated habitat, the wild Diubis do not flee: they walk over and circle the pet to greet it until it leaves.

All distances and timings above are the defaults; each one is a config option described below.

### Requirements and installation

Requirements

* RedM server with OneSync enabled (the resource will not start without it).
* vorp\_inventory (tested) or rsg-core (adapter included) for catching and the pet item. Without an inventory, everything else still works.
* Optional: kh\_notifications. If it is running it is used automatically; otherwise kh\_diubi shows its own notifications.

Installation

1. Copy the kh\_diubi folder into your resources folder. If you are updating from 2.x, replace the whole folder; do not mix files from different versions.
2. Create the inventory item (see below) and add an item image named diubi.png.
3. Add the resource to server.cfg, after your inventory, and give admins the permission:

ensure vorp\_inventory

ensure kh\_diubi

add\_ace group.admin kh\_diubi.admin allow

4. Restart the server, stand 40–80 m from a river or lake and run /diubitest to see a habitat appear straight away.

VORP item. Run install/vorp\_items.sql on your database and place the image at vorp\_inventory/html/img/items/diubi.png. The limit column is how many Diubis one player can carry (default 5).

INSERT INTO \`items\` (\`item\`, \`label\`, \`limit\`, \`can\_remove\`, \`type\`, \`usable\`, \`desc\`)

VALUES ('diubi', 'Diubi', 5, 1, 'item\_standard', 1, 'A small Diubi from the riverbank. Use it to call it or to let it return to the water.')

ON DUPLICATE KEY UPDATE \`label\` = VALUES(\`label\`), \`usable\` = VALUES(\`usable\`), \`desc\` = VALUES(\`desc\`);

RSG item. Add the entry from install/rsg\_items.txt to rsg-core/shared/items.lua and place the image at rsg-inventory/html/images/diubi.png. The item must be unique so each Diubi keeps its own name.

diubi = {

&#x20;   name = 'diubi', label = 'Diubi', weight = 200, type = 'item',

&#x20;   image = 'diubi.png', unique = true, useable = true, shouldClose = true,

&#x20;   description = 'A small Diubi from the riverbank. Use it to call it or to let it return to the water.'

},

If you rename the item, change Config.Capture.ItemName to match.

Included files you can edit even when the resource is escrow-protected: config.lua, water\_zones.lua, locales.lua, dialogue.lua and server/bridge.lua.

### Configuration: general, notifications and voices

Everything is set in config.lua. Distances are in metres and times in milliseconds (ms) unless stated otherwise. Each table lists the option, its default value and what it does.

General

| Option           | Default     | What it does                                                                                                                                         |
| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Config.Locale    | 'es'        | Language of all texts and dialogue: 'en' (English) or 'es' (Spanish). Set it to 'en' for English servers.                                            |
| Config.Model     | 'kh\_diubi' | Ped model of the creature. Only change it if you rename the streamed MetaPed.                                                                        |
| Config.Framework | 'auto'      | Inventory used for the Diubi item. 'auto' detects vorp\_inventory, then rsg-core. Force one with 'vorp' or 'rsg', or use 'none' to disable catching. |
| Config.Debug     | false       | Prints extra information in the F8 console and the server console.                                                                                   |

Notifications (Config.Notify)

| Option | Default | What it does                                                                                                                                                                                          |
| ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Mode   | 'auto'  | 'auto' uses kh\_notifications when it is running and the built-in notifications otherwise. 'kh' always uses kh\_notifications, 'nui' always uses the built-in ones, 'custom' calls your own function. |
| Title  | 'DIUBI' | Title shown on every notification.                                                                                                                                                                    |
| Custom | nil     | Your own function for Mode = 'custom': function(message, kind, duration) ... end, where kind is 'info', 'success' or 'error'.                                                                         |

Voices (Config.Voice)

| Option                                | Default       | What it does                                                                                                      |
| ------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------- |
| Enabled                               | true          | Turns the ambient Diubi voices on or off.                                                                         |
| Files                                 | 5 sounds      | Sound files in html/sounds and their length in ms. Add your own .mp3 files here to give Diubis new sounds.        |
| MinDelayMs / MaxDelayMs               | 16000 / 34000 | Random time between two calls from the same wild Diubi.                                                           |
| InitialDelayMinMs / InitialDelayMaxMs | 3000 / 12000  | Delay before a Diubi's first call after it appears.                                                               |
| SocialDelayMinMs / SocialDelayMaxMs   | 5000 / 9000   | Faster chatter while wild Diubis are greeting a player's pet.                                                     |
| PetDelayMinMs / PetDelayMaxMs         | 35000 / 70000 | How often your pet makes a sound while following you. It stays quiet while carried or during the cinematic scene. |
| ServerCooldownMs                      | 4000          | Minimum time between two sounds from the same Diubi, enforced by the server to prevent spam and duplicates.       |
| HearingDistance                       | 32.0          | Beyond this distance a voice is not heard.                                                                        |
| FullVolumeDistance                    | 2.5           | Within this distance the voice plays at full volume.                                                              |
| MaxVolume                             | 0.55          | Loudest volume, from 0 to 1.                                                                                      |
| AttenuationPower                      | 1.4           | Shape of the volume falloff. Higher values make voices fade faster with distance.                                 |
| NetworkMargin                         | 10.0          | Extra distance added to HearingDistance when the server decides which players to send a voice to.                 |
| VolumeUpdateMs                        | 100           | How often volume and stereo position are updated while a voice plays.                                             |
| StereoPan                             | true          | Plays each voice from the side where the Diubi is, relative to your camera.                                       |
| PanStrength                           | 0.8           | How far voices pan left or right, from 0 (centred) to 1 (fully to one side).                                      |
| AlarmCall                             | true          | When a group gets scared, one Diubi makes a sound before they run.                                                |

### Configuration: rendering (black ped protection)

Custom MetaPeds can show up completely black or invisible when their textures finish loading after the ped is drawn. kh\_diubi hides every Diubi while its outfit loads, rebuilds its appearance several times a few hundred milliseconds apart, and only then shows it. This also applies to Diubis spawned by Spooner or other resources. The defaults are tuned to be safe; only change them if you still see black Diubis.

Rendering (Config.Rendering)

| Option               | Default | What it does                                                                                                                                        |
| -------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Enabled              | true    | Turns the whole protection on or off.                                                                                                               |
| ReadyTimeout         | 7000    | Maximum time to wait for the game to report the ped as ready to draw.                                                                               |
| InitialWait          | 100     | Wait before preparing a wild Diubi.                                                                                                                 |
| RefreshPasses        | 3       | How many times a wild Diubi's appearance is rebuilt.                                                                                                |
| RefreshInterval      | 220     | Time between two rebuilds of a wild Diubi.                                                                                                          |
| FinalWait            | 180     | Extra wait before a wild Diubi becomes visible.                                                                                                     |
| PetInitialWait       | 180     | Same as InitialWait, for pets.                                                                                                                      |
| PetRefreshPasses     | 4       | Same as RefreshPasses, for pets.                                                                                                                    |
| PetRefreshInterval   | 300     | Same as RefreshInterval, for pets.                                                                                                                  |
| PetFinalWait         | 450     | Same as FinalWait, for pets.                                                                                                                        |
| PetSafetyRefresh1    | 1500    | First extra rebuild after the pet is already visible, in case a texture arrived late.                                                               |
| PetSafetyRefresh2    | 3500    | Second extra rebuild after the pet is visible.                                                                                                      |
| CloseRefresh         | true    | Rebuilds a Diubi's appearance once more (without hiding it) the first time it comes close to you, fixing low-quality textures loaded from far away. |
| CloseRefreshDistance | 25.0    | Distance that triggers CloseRefresh.                                                                                                                |

If black Diubis still appear on slow connections, raise FinalWait and PetFinalWait (for example to 400 and 800) and add one more pass.

### Configuration: habitats

These options control how many Diubis live in each habitat, when they appear, and how close players can get before they flee.

Habitats (Config.Habitats)

| Option                          | Default   | What it does                                                                                                                         |
| ------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Enabled                         | true      | Turns wild Diubis on or off. Pets and the item keep working when off.                                                                |
| MinDiubis / MaxDiubis           | 2 / 4     | How many Diubis spawn in each habitat.                                                                                               |
| SpawnRadiusMin / SpawnRadiusMax | 1.5 / 5.5 | Ring around the wander centre where they spawn. Points in the water are always skipped.                                              |
| InlandOffset                    | 2.5       | How far inland from the water's edge the wander centre is placed, so they live on the bank rather than at the waterline.             |
| WanderRadius                    | 6.0       | Radius they wander in around that centre.                                                                                            |
| PopulationDistance              | 95.0      | A player this close to an empty habitat makes its Diubis spawn.                                                                      |
| PopulationDespawnDistance       | 140.0     | When no player is this close, the group is removed (nobody can see it).                                                              |
| ResetDistance                   | 110.0     | After the Diubis have fled, every player must move this far away before the habitat can be used again.                               |
| FearDistance                    | 16.0      | Distance to the nearest Diubi that scares the group when you walk.                                                                   |
| SneakFearDistance               | 7.0       | Same, while crouching. This is how players sneak up to catch one.                                                                    |
| RunFearDistance                 | 24.0      | Same, while running or sprinting. Also the minimum distance for a habitat to populate, so groups never spawn right next to a player. |
| MountedFearDistance             | 24.0      | Same, on horseback or in a vehicle.                                                                                                  |
| GunshotFearDistance             | 45.0      | Firing a weapon within this distance of a habitat scares the whole group.                                                            |
| UpdateInterval                  | 250       | How often each player's game checks the habitats around them.                                                                        |
| FleeUpdateInterval              | 75        | Faster checks for the player directing a flight, so the dive at the waterline feels instant.                                         |
| ModelLoadTimeout                | 10000     | Maximum time to load the Diubi model before giving up.                                                                               |
| ServerSpawnTimeout              | 15000     | If the chosen player has not created the group in this time, the server frees the habitat for another attempt.                       |

Ambient routines (Config.Habitats.Ambient) are small behaviours run by the player whose game controls each Diubi.

| Option                        | Default                                                       | What it does                                                                             |
| ----------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Enabled                       | true                                                          | Turns the routines on or off. Off means they only wander.                                |
| IntervalMinMs / IntervalMaxMs | 22000 / 45000                                                 | Time between two routine checks for the same Diubi.                                      |
| SitChance                     | 35                                                            | Chance (%) to sit down at each check.                                                    |
| CrouchChance                  | 30                                                            | Chance (%) to crouch and inspect at each check. The rest of the time it keeps wandering. |
| SitMinMs / SitMaxMs           | 10000 / 18000                                                 | How long it stays seated.                                                                |
| CrouchMinMs / CrouchMaxMs     | 6000 / 10000                                                  | How long it stays crouched.                                                              |
| SitScenario / CrouchScenario  | 'WORLD\_HUMAN\_SIT\_GROUND' / 'WORLD\_HUMAN\_CROUCH\_INSPECT' | Game scenarios used for each routine.                                                    |

Fixed habitats (Config.Habitats.Fixed) is a list of hand-picked spots that always exist. Stand on the bank next to the water and type /diubipos: the F8 console prints a line ready to paste here. water is the point in the water where they dive; it is optional but recommended.

Fixed = {

&#x20;   { name = 'Flat Iron Lake pier', coords = vector3(0.0, 0.0, 0.0), water = vector3(0.0, 0.0, 0.0) },

},

Automatic discovery (Config.Habitats.Discovery) creates dynamic habitats along the rivers and lakes listed in water\_zones.lua.

| Option                    | Default     | What it does                                                                                                                              |
| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Enabled                   | true        | Turns automatic habitats on or off. Set it to false to use only fixed habitats.                                                           |
| IntervalMs                | 35000       | Time between two searches by each player's game.                                                                                          |
| IntervalJitterMs          | 10000       | Random extra time added to each interval, so players do not search in sync.                                                               |
| Chance                    | 0.30        | Chance (0–1) that a search actually looks for a shoreline. Raise it for more Diubis.                                                      |
| MinDistance / MaxDistance | 40.0 / 85.0 | Distance from the player where a new habitat may appear. Keep MinDistance above RunFearDistance and MaxDistance below PopulationDistance. |
| SearchAttempts            | 20          | Points tested in each search. More attempts find shores more often but cost more.                                                         |
| MaxHabitats               | 6           | Maximum dynamic habitats on the whole server at once.                                                                                     |
| MaxPerWaterZone           | 2           | Maximum dynamic habitats on the same river or lake.                                                                                       |
| MinSpacing                | 150.0       | Minimum distance between any two habitats, fixed or dynamic.                                                                              |
| ProposalCooldownMs        | 12000       | Minimum time between two habitat proposals from the same player.                                                                          |
| EmptyLifetimeMs           | 120000      | A dynamic habitat with nobody nearby for this long is removed, freeing a slot for a new one elsewhere.                                    |
| RemoveAfterFlee           | true        | After its Diubis flee and players leave, a dynamic habitat disappears instead of repopulating. Set false to keep it.                      |

### Configuration: water, shores and fleeing

Water bodies (Config.Water). Habitats only appear by rivers and lakes listed in water\_zones.lua, a built-in catalogue of 35 RDR2 water bodies (Flat Iron Lake, Dakota River, Lake Isabella, Kamassa River, Sea of Coronado…). Each entry is a name and the game's hash for that water body.

| Option                | Default | What it does                                                                                                                             |
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| AllowUnknownZones     | false   | Allows water bodies that are not in the catalogue.                                                                                       |
| AllowedHashes         | nil     | Restricts habitats to specific water bodies. nil allows the whole catalogue. Example: { \[370072007] = true } for the Dakota River only. |
| ExcludedHashes        | {}      | Water bodies that never get habitats. Example: { \[-247856387] = true } to exclude the Sea of Coronado.                                  |
| ExcludedAreas         | {}      | Circles where no habitat may appear (towns, event areas, private property). Example: { x = -300.0, y = 600.0, radius = 180.0 }.          |
| SurfaceProbeAbove     | 35.0    | Height above the player from which the water surface is searched.                                                                        |
| UseWaterProbeFallback | true    | Uses a third detection method when the two standard water-height natives do not answer. Leave it on.                                     |

Shorelines (Config.Shore). From a water point, the search walks outward in several directions until it reaches land, then checks the bank.

| Option           | Default | What it does                                                                                                     |
| ---------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| EdgeStep         | 1.5     | Step size when walking from the water towards the shore.                                                         |
| EdgeDirections   | 8       | Number of directions tried from each water point.                                                                |
| MaxEdgeSearch    | 40.0    | Maximum distance from the water point to the shore. Points in the middle of large lakes beyond this are skipped. |
| Inset            | 1.2     | How far onto land, past the water's edge, the habitat is placed.                                                 |
| MaxWaterDistance | 4.5     | A shoreline point must have water within this distance. Lower it to keep Diubis tighter to the water.            |
| MaxBankHeight    | 1.8     | Maximum height of the bank above the water. Steeper banks and cliffs are rejected.                               |
| DivePointDepth   | 2.0     | How far into the water the dive point is placed.                                                                 |

Fleeing (Config.Flee)

| Option                  | Default    | What it does                                                                                                               |
| ----------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------- |
| AlertMinMs / AlertMaxMs | 450 / 1200 | How long each Diubi freezes and stares before running. This is the main catching window; raise it to make catching easier. |
| Speed                   | 2.8        | Running speed towards the water (about 1 = walk, 2 = jog, 3 = sprint). Lower it to make catching easier.                   |
| TaskTimeout             | 12000      | Reserved for the running task's timeout.                                                                                   |
| WaterSearchRadius       | 12.0       | How far each Diubi looks for water to run to.                                                                              |
| DiveDistance            | 1.1        | A Diubi dives when it touches water or gets this close to its dive point.                                                  |
| DiveFadeMs              | 900        | Duration of the fade-out while diving.                                                                                     |
| DiveSinkDepth           | 0.9        | How far it sinks during the fade.                                                                                          |
| FleeTimeout             | 15000      | Any Diubi that has not reached the water by then dives where it stands.                                                    |
| StuckCheckInterval      | 1200       | How often a running Diubi is checked for being stuck.                                                                      |
| StuckMovementThreshold  | 0.18       | Movement below this between two checks counts as stuck.                                                                    |
| StuckRetaskDelay        | 2800       | Time a Diubi must stay stuck before it is sent to the water again. Healthy runs are never restarted.                       |

### Configuration: capture and the pet

Capture (Config.Capture). A Diubi can only be grabbed while it is alert or running to the water. The player then has to press a random sequence of keys, each within a short time.

| Option                | Default        | What it does                                                                                                  |
| --------------------- | -------------- | ------------------------------------------------------------------------------------------------------------- |
| Enabled               | true           | Turns catching on or off.                                                                                     |
| ItemName              | 'diubi'        | Inventory item given on a successful catch. Must match the item you created.                                  |
| PromptDistance        | 2.6            | How close you must be for the CATCH DIUBI prompt to appear.                                                   |
| PromptControl         | 0xCEFD9220 (E) | Key that starts the catch.                                                                                    |
| SequenceLength        | 5              | Number of keys in the struggle.                                                                               |
| StepTime              | 850            | Time to press each key. Lower = harder.                                                                       |
| StepGap               | 60             | Pause between two keys.                                                                                       |
| FailedAttemptCooldown | 3000           | After a failed struggle, that Diubi cannot be grabbed again for this long.                                    |
| ServerCaptureCooldown | 5000           | Minimum time between two catches by the same player, enforced by the server.                                  |
| ServerLockTimeout     | 20000          | How long the server reserves a Diubi for the player struggling with it.                                       |
| Keys                  | 23 keys        | Keys that can appear in the struggle (label shown on screen and game control). Remove keys to make it easier. |
| Names                 | 30 names       | Names given at random to caught Diubis. The name is stored in the item and used for the pet.                  |

The item stores: a label (Diubi "Pip"), a description with the river or lake where it was caught, the name, a unique id and the capture date. Using the same item again sends that Diubi back; using a different Diubi item swaps them.

Pet (Config.Pet)

| Option                               | Default                        | What it does                                                                                                      |
| ------------------------------------ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| FollowOffset                         | vector3(0.8, -1.25, 0.0)       | Where the pet walks relative to you (right, behind, height).                                                      |
| FollowSpeed                          | 2.6                            | Walking speed while following.                                                                                    |
| StopDistance                         | 1.5                            | Distance at which it stops when you stand still.                                                                  |
| Invincible                           | true                           | The pet cannot die (stray bullets, falls, drowning).                                                              |
| CarryEnabled                         | true                           | Allows carrying the pet on your shoulders.                                                                        |
| CarryDistance                        | 2.0                            | How close you must be to pick it up.                                                                              |
| CarryControl                         | 0x760A9C6F (G)                 | Key to pick it up and put it down.                                                                                |
| CarryBone                            | 'SKEL\_R\_CLAVICLE'            | Bone of the player the pet is attached to.                                                                        |
| CarryAnimDict / CarryAnimName        | seated eating idle             | Animation the pet plays while carried.                                                                            |
| CarryAnimFlag                        | 1                              | Animation flag (1 = loop).                                                                                        |
| CarryAnimBlendIn / CarryAnimBlendOut | 4.0 / 4.0                      | Animation blend speeds.                                                                                           |
| CarryOffset                          | vector3(0.180, -0.280, -0.050) | Position on the shoulder. Adjust if it floats or clips.                                                           |
| CarryRotation                        | vector3(0.0, 0.0, 8.0)         | Rotation on the shoulder.                                                                                         |
| DropOffset                           | vector3(0.8, -0.8, 0.0)        | Where it is placed when you put it down.                                                                          |
| TeleportDistance                     | 35.0                           | If the pet gets this far behind, it is placed next to you again.                                                  |
| MonitorInterval                      | 500                            | How often the pet's movement is checked.                                                                          |
| StuckCheckDistance                   | 3.0                            | The stuck check only runs when the pet is further than this.                                                      |
| StuckRetaskDelay                     | 4000                           | Time without progress before the follow order is given again. The follow order is never restarted while it works. |
| MinMovingSpeed                       | 0.12                           | Speed below which the pet counts as not moving.                                                                   |
| MinDistanceProgress                  | 0.12                           | Distance gained between checks that counts as progress.                                                           |

Greeting (Config.Pet.Greeting). When your pet is near a populated habitat, the wild Diubis come over and circle it instead of fleeing.

| Option           | Default | What it does                                               |
| ---------------- | ------- | ---------------------------------------------------------- |
| Enabled          | true    | Turns the greeting on or off.                              |
| GreetingDistance | 22.0    | Your pet this close to a habitat starts the greeting.      |
| LeaveDistance    | 30.0    | The greeting ends when your pet moves this far away.       |
| CircleRadius     | 2.0     | Radius of the circle the wild Diubis form around your pet. |
| ApproachSpeed    | 2.0     | Speed at which they walk to your pet.                      |

### Configuration: cinematic interaction

Standing next to your pet, press R to open the scene. The player crouches, the HUD hides, black bars slide in and a scripted camera cuts between shots while a menu on the right lists the actions. The Diubi speaks in its own language: the words appear one by one, voiced by chopping its own sounds into syllables, with the translation underneath. Players navigate with the arrow keys or W/S, confirm with Enter and go back with Esc.

General (Config.Interaction)

| Option               | Default                         | What it does                                                                                                                                             |
| -------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Enabled              | true                            | Turns the whole scene on or off.                                                                                                                         |
| PromptControl        | 0xE30CD707 (R)                  | Key that opens the scene.                                                                                                                                |
| PromptDistance       | 2.4                             | How close you must be to your pet.                                                                                                                       |
| CanInteract          | nil                             | Optional function to block the scene on your server, for example while cuffed: function(playerPed) return not IsPedCuffed(playerPed) end.                |
| HideHud              | true                            | Hides the game HUD and radar during the scene.                                                                                                           |
| HudEvents            | {}                              | Events for NUI HUDs: { name = 'my\_hud:toggle', open = false, close = true } fires my\_hud:toggle(false) when the scene opens and (true) when it closes. |
| Actions              | all true                        | Which actions appear in the menu: Talk, Pet, Feed, Play, Stay, Contemplate, Carry.                                                                       |
| PlayerCrouchScenario | 'WORLD\_HUMAN\_CROUCH\_INSPECT' | Player pose during the conversation. false = standing.                                                                                                   |
| PlayerSitScenario    | 'WORLD\_HUMAN\_SIT\_GROUND'     | Player pose during Watch together.                                                                                                                       |
| DanceMs              | 11000                           | Length of a dance.                                                                                                                                       |
| ContemplateMs        | 15000                           | Length of Watch together.                                                                                                                                |
| Tricks               | 7 emotes                        | Emotes the Diubi can pick when asked for a trick (keys of Emotes).                                                                                       |

Safety (Config.Interaction.Abort). The scene closes on its own if something goes wrong.

| Option          | Default | What it does                                                            |
| --------------- | ------- | ----------------------------------------------------------------------- |
| MaxDurationMs   | 600000  | Maximum length of a scene (10 minutes).                                 |
| MaxDistance     | 7.0     | Closes the scene if the player and the pet end up further apart.        |
| HealthLossAbort | 3       | Closes the scene if the player loses this much health (attacked, hurt). |

It also closes if the player dies or the pet disappears.

Camera (Config.Interaction.Camera)

| Option                                  | Default                                                  | What it does                                                            |
| --------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| Enabled                                 | true                                                     | Uses the cinematic camera.                                              |
| Side                                    | 1                                                        | 1 or -1 mirrors every shot, useful when a rock or wall blocks one side. |
| EaseInMs / EaseOutMs                    | 1400 / 1000                                              | Transition into and out of the scene.                                   |
| ShotBlendMs                             | 1300                                                     | Transition between two shots.                                           |
| PushInMs / PushInAmount                 | 5200 / 0.14                                              | Slow push-in on every shot: duration and how far (0–1).                 |
| DiubiHeadOffset                         | 0.35                                                     | Fallback height of the Diubi's head if its bone cannot be read.         |
| PlayerHeadStanding / PlayerHeadCrouched | 0.65 / 0.10                                              | Fallback heights of the player's head.                                  |
| Fov                                     | Wide 46, Over 30, Close 25, Low 36, Reverse 32, Orbit 44 | Field of view of each shot type. Lower = more zoom.                     |
| OrbitRadius / OrbitHeight               | 3.1 / 0.75                                               | Size of the circling camera used while dancing and singing.             |
| OrbitDegreesPerSecond                   | 14.0                                                     | Speed of that circling camera.                                          |

Voice (Config.Interaction.Voice)

| Option                                 | Default               | What it does                                              |
| -------------------------------------- | --------------------- | --------------------------------------------------------- |
| Volume                                 | 0.62                  | Volume of the Diubi's speech.                             |
| WordBaseMs / WordPerLetterMs           | 210 / 48              | Speaking rhythm: base time per word plus time per letter. |
| PauseCommaMs / PausePeriodMs           | 170 / 340             | Pauses after commas and full stops.                       |
| ShowTranslation                        | true                  | Shows the translation under each line.                    |
| TranslationDelayMs / TranslationWordMs | 380 / 48              | When the translation starts and how fast it appears.      |
| SongFiles                              | the three long sounds | Sounds used for Sing together.                            |
| SongVolume                             | 0.6                   | Volume of the song.                                       |

Stay (Config.Interaction.Stay)

| Option        | Default                     | What it does                                                                      |
| ------------- | --------------------------- | --------------------------------------------------------------------------------- |
| Scenario      | 'WORLD\_HUMAN\_SIT\_GROUND' | Pose of the pet while it waits. false = standing.                                 |
| BreakDistance | 80.0                        | If you walk further than this, the pet gets tired of waiting and comes after you. |

Feed (Config.Interaction.Feed)

| Option      | Default                     | What it does                                                           |
| ----------- | --------------------------- | ---------------------------------------------------------------------- |
| Enabled     | true                        | Shows the Share food action.                                           |
| RequireItem | false                       | false = a free gesture. true = needs and consumes one item from Items. |
| Items       | apple, carrot, bread, berry | Accepted food items (inventory item names).                            |
| CooldownMs  | 8000                        | Minimum time between two feedings.                                     |

Emotes and dances. Emotes maps a short key to an animation (dict, clip) and how long it may play (ms); dialogue lines and tricks refer to these keys. Dances lists looped dance animations with their intro, loop and outro clips. All of them are standard RDR2 multiplayer emotes and can be replaced without touching the code.

### Commands, permissions and exports

Admin commands need the ACE permission set in Config.Admin.Ace (default kh\_diubi.admin); the server console is always allowed. Grant it in server.cfg with add\_ace group.admin kh\_diubi.admin allow. Every command name can be renamed in Config.Admin.Commands, and setting a name to '' disables that command.

| Command      | Config key | What it does                                                                                                                                                                                                                                                                    |
| ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| /diubitest   | Test       | Searches for a shoreline near you right now, without the random chance, and creates a habitat if one is found. If nothing is found, F8 shows how many points were tested and why each was rejected (no water, river not listed, bank too steep, too close to another habitat…). |
| /diubistatus | Status     | Lists habitats (fixed and dynamic), their phase, wild Diubis and active pets.                                                                                                                                                                                                   |
| /diubiclear  | Clear      | Removes every dynamic habitat and its Diubis; fixed habitats are reset.                                                                                                                                                                                                         |
| /diubipos    | Pos        | Stand on the bank next to the water: F8 prints a line ready to paste into Config.Habitats.Fixed, including the dive point.                                                                                                                                                      |
| /diubidiag   | Diag       | Shows the water body under your feet (hash, listed, allowed), the water height and which detection method answered, the nearest water and the habitats your game knows about.                                                                                                   |

Player controls

| Key          | Where                             | Action                                                |
| ------------ | --------------------------------- | ----------------------------------------------------- |
| E            | Next to an alert or fleeing Diubi | Catch it                                              |
| G            | Next to your pet                  | Carry it on your shoulders / put it down              |
| R            | Next to your pet                  | Open the cinematic scene                              |
| Use the item | Inventory                         | Call your Diubi, send it back, or swap it for another |

Exports

\-- Server

local stats = exports.kh\_diubi:GetStats()

\-- { habitats, fixed, dynamic, maxDynamic, populated, wild, pets }

<br>

local removed = exports.kh\_diubi:ClearHabitats()

\-- removes every dynamic habitat, returns how many

<br>

\-- Client: stop new habitats from appearing around this player

\-- (cutscenes, character selection, events), then resume

exports.kh\_diubi:SetDiscoveryPaused(true)

exports.kh\_diubi:SetDiscoveryPaused(false)

SetEcosystemPaused still works as an alias for scripts written for version 2.x.

### Customising texts, dialogue and inventory

Interface texts live in locales.lua, one block per language (Locales.en, Locales.es). To add a language, copy the en block, rename the key (for example Locales.fr), translate the values and set Config.Locale = 'fr'. Keep the %s and %.0f placeholders: they are replaced by names, distances and so on.

Dialogue lives in dialogue.lua, with one block per language (Dialogues.en, Dialogues.es). The Diubi words are the same in every language; only the translations and the player's answers change. It is plain text: you can edit lines, add topics or remove them without touching the code.

The Diubi language (diubí) follows a few rules so new lines stay consistent:

* Word order is subject – verb – object: mi gip ti = I look at you.
* Repeating a word intensifies it: lu-lu = very good.
* Adding -i makes people plural: oro = big one, oroi = the Big Ones (humans).
* pa before a verb marks the past, po the future: mi pa beni = I came, mi po da = I will give.
* nu before a verb negates it: mi nu kib = I am not afraid.
* ki at the end makes a question: ti fum ki? = do you have food?
* bi = with, sa = without, after the noun: bi ti = with you.

The full vocabulary (52 words) is in the Lexicon list, which also feeds the Teach me your language topic.

A dialogue line looks like this:

{ text = 'Piu, wem! Lu-lu!', tr = 'Hello, friend! Very good!', mood = 'happy', emote = 'wave' }

* text: what the Diubi says, in diubí.
* tr: the translation shown underneath.
* mood: neutral, happy, sad, angry, scared, curious, shy or proud. It changes the voice pitch and rhythm, the camera shot and the text animation.
* emote (optional): a key from Config.Interaction.Emotes played while it speaks.

Reactions are short random lines for each action (open, goodbye, pet, feed, stay, follow, dance, trick, sing, contemplate\_start…). A list with the suffix \_night (for example open\_night) is used between 21:00 and 06:00 game time.

Topics are small conversation trees. TopicOrder sets their order in the Talk menu. Each node has the Diubi's line (or a list of lines), optional choices for the player, and next for the following node:

fishing = {

&#x20;   label = 'Fishing',

&#x20;   sub = 'Ask about its favourite food',

&#x20;   start = 'f1',

&#x20;   nodes = {

&#x20;       f1 = {

&#x20;           diubi = { text = 'Shi! Shi lu-lu!', tr = 'Fish! Fish are the best!', mood = 'happy', emote = 'clap' },

&#x20;           choices = {

&#x20;               { text = 'Do you catch them yourself?', next = 'f2' },

&#x20;               { text = 'I will bring you one.',       next = nil }

&#x20;           }

&#x20;       },

&#x20;       f2 = {

&#x20;           diubi = { text = 'Wi! Mi plof, mi ñam.', tr = 'Yes! I dive, I eat.', mood = 'proud', emote = 'chest' }

&#x20;       }

&#x20;   }

},

Add the new key ('fishing') to TopicOrder so it appears in the menu. A node can also be a function that receives ctx.night and ctx.hour, to change the line at night.

Sounds. Replace or add .mp3 files in html/sounds and list them in Config.Voice.Files (ambient voices and the speech syllables) and Config.Interaction.Voice.SongFiles (the song).

Another inventory or framework. All inventory calls go through server/bridge.lua, which is left editable. Copy the Adapters.vorp block, give it a new key (for example Adapters.myinv), implement its functions (available, registerUsable, canCarry, addItem, findAnyItem, removeItem, closeInventory) with your inventory's API and set Config.Framework = 'myinv'. When a usable item is used, call the callback with the player's id and the item's metadata so the pet keeps its name.

Water bodies. To add a river or lake that is not listed, stand in its water, run /diubidiag, copy the hash it prints and add { name = 'My river', hash = \<hash> } to water\_zones.lua.

### Troubleshooting

No Diubis appear. Stand 40–85 m from a river or lake and run /diubitest. The F8 report says why each point was rejected:

| Reason in the report           | What to do                                                                                                                       |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| No water                       | No point had water. Move closer to the shore, or run /diubidiag with your feet in the water to check that water detection works. |
| Water body not allowed         | The river is not in water\_zones.lua or is excluded. Add the hash shown in the report, or set AllowUnknownZones = true.          |
| No solid ground near the water | You are next to a very large lake. Move to a narrower stretch or closer to its edge.                                             |
| Bank too high or steep         | The shore is a cliff. Try elsewhere, or raise Shore.MaxBankHeight.                                                               |
| Ground not measurable          | The terrain had not loaded yet. Move a little closer and try again.                                                              |
| Shore outside the spawn range  | The only shoreline found is too close or too far. Stand 40–80 m from it.                                                         |
| Close to another habitat       | One already exists within MinSpacing. Move away or use /diubiclear.                                                              |

If the report says the server rejected the habitat, it names the limit reached (MaxHabitats, MaxPerWaterZone, spacing). Also check /diubistatus.

They are too hard to catch. Raise Flee.AlertMinMs / AlertMaxMs, lower Flee.Speed, raise Capture.StepTime or lower Capture.SequenceLength. Remind players to approach crouched.

They flee too early or too late. Adjust FearDistance, SneakFearDistance, RunFearDistance and MountedFearDistance.

The CATCH prompt does not appear. It only appears while they are alert or running, within Capture.PromptDistance, and only when an inventory was detected (the server console shows which inventory was detected at start-up; it should say inventory: vorp on a VORP server).

Using the item does nothing. Check that the item exists in your inventory database, is marked usable, and that Config.Capture.ItemName matches. Start kh\_diubi after the inventory in server.cfg.

Black or invisible Diubis. Raise Rendering.FinalWait and Rendering.PetFinalWait, and check that no other resource streams a file with the same name as the files in stream/ (cs\_mp\_camp\_cook\_ms1\_pants\_000).

They appear in odd places (towns, private land). Add those areas to Water.ExcludedAreas, or exclude the whole river with Water.ExcludedHashes.

Too many or too few Diubis. Change Discovery.Chance, Discovery.MaxHabitats, MinDiubis / MaxDiubis and Discovery.MinSpacing.

Asking for support. Include the resource version, your framework, and the F8 output of /diubitest (next to water) and /diubidiag (standing in water), with Config.Debug = true.

<br>
