Installation
Installation
1. Drop the resource
Extract suty-shower into resources/[suty]/suty-shower.
2. Ensure dependencies and the resource
server.cfg:
ensure ox_lib
ensure oxmysql
ensure ox_target
ensure ox_inventory
ensure dpclothing
ensure suty-shower
3. Database
Both tables are created automatically on first start. Verify with:
SHOW TABLES LIKE 'player_hygiene';
SHOW TABLES LIKE 'player_dental';
player_hygiene stores body cleanliness, player_dental stores dental hygiene — both keyed by citizenid (VARCHAR(60)).
4. Items
The script uses 4 items. The item names are configurable in config/items.lua and config/dental.lua; the defaults are:
| Item | Default name | Purpose |
|---|---|---|
| Soap | jabon |
Required to shower |
| Deodorant | deodorant |
Slows decay, extends freshness |
| Perfume | perfume |
Bigger decay slowdown + pheromone effect |
| Toothbrush + paste | toothbrush_paste |
Brush teeth (dental track) |
Pick the snippet that matches your inventory system and drop it in.
Add to ox_inventory/data/items.lua:
["jabon"] = {
label = "Jabon", weight = 50, stack = true, close = true,
consume = 1,
description = "Jabon para ducharte. Usalo cerca de una ducha dentro de tu casa para mantenerte limpio.",
client = { image = "soap.png", export = "suty-shower.jabon" }
},
["deodorant"] = {
label = "Desodorante", weight = 100, stack = true, close = true,
consume = 1,
description = "Desodorante para mantenerte fresco. Usalo despues de ducharte para que tu higiene dure mas tiempo.",
client = { image = "deodorant.png", export = "suty-shower.deodorant" }
},
["perfume"] = {
label = "Perfume", weight = 150, stack = true, close = true,
consume = 1,
description = "Perfume de alta calidad. Te mantiene con buen olor por mas tiempo que el desodorante.",
client = { image = "perfume.png", export = "suty-shower.perfume" }
},
["toothbrush_paste"] = {
label = "Cepillo y Pasta de Dientes", weight = 100, stack = true, close = true,
description = "Cepillo con su pasta. Usalo para mantener tu higiene dental al maximo.",
client = { image = "toothbrush_paste.png", export = "suty-shower.toothbrush_paste" }
},
The client.export field wires each item directly to its suty-shower handler — no manual exports.ox_inventory:registerHook calls required. The consumable items (soap / deodorant / perfume) carry consume = 1 so they're removed on use; the toothbrush is reusable.
Add to qb-core/shared/items.lua:
jabon = {
name = "jabon",
label = "Jabon",
weight = 50,
type = "item",
image = "soap.png",
unique = false,
useable = true,
shouldClose = true,
description = "Jabon para ducharte. Usalo cerca de una ducha dentro de tu casa para mantenerte limpio.",
},
deodorant = {
name = "deodorant",
label = "Desodorante",
weight = 100,
type = "item",
image = "deodorant.png",
unique = false,
useable = true,
shouldClose = true,
description = "Desodorante para mantenerte fresco. Usalo despues de ducharte para que tu higiene dure mas tiempo.",
},
perfume = {
name = "perfume",
label = "Perfume",
weight = 150,
type = "item",
image = "perfume.png",
unique = false,
useable = true,
shouldClose = true,
description = "Perfume de alta calidad. Te mantiene con buen olor por mas tiempo que el desodorante.",
},
Drop matching PNGs (soap.png, deodorant.png, perfume.png) into your inventory's image directory (e.g. qb-inventory/html/images/) so the icons render.
Run this against your server's database:
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
('jabon', 'Jabon', 1, 0, 1),
('deodorant', 'Desodorante', 1, 0, 1),
('perfume', 'Perfume', 1, 0, 1);
On legacy ESX builds where items aren't registered via SQL, mirror the same three names in your inventory's items list (e.g. esx_inventoryhud config). The script triggers the usable callbacks directly, so as long as the item names match config/items.lua you're good.
5. Choose your HUD mode
Open config/main.lua → Config.HygieneSystem:
useCustomPanel = true→ the built-in standalone HUD (no qbx_hud needed)useCustomPanel = false→ values are forwarded toqbx_hud(hud:client:UpdateHygiene/hud:client:UpdateDental)
If you use the built-in HUD, also set showHUD = true so it appears on screen.
6. 📊 HUD API — use your own HUD
Want to drive a custom HUD (NUI overlay, in-world prop, ESX status, anything)? Turn the built-in panel off and pull values straight from the resource's exports.
First, in config/main.lua:
Config.HygieneSystem.showHUD = false -- silence the built-in panel
Then read live values from client exports any time you need them:
exports['suty-shower']:GetHygiene() -- 0-100
exports['suty-shower']:GetDentalHygiene() -- 0-100
exports['suty-shower']:GetHygieneData() -- { hygiene, dental, deodorant = { active, secondsLeft }, perfume = { active, secondsLeft } }
Or subscribe to the change event — fires whenever hygiene or dental ticks, and whenever deodorant / perfume start or expire:
AddEventHandler('suty-shower:client:onHygieneChange', function(data)
-- data = { hygiene, dental, deodorant = { active, secondsLeft }, perfume = { active, secondsLeft } }
-- redraw your HUD here, push to NUI, update a 3D prop, whatever
end)
The event-driven path is the lightest: zero per-frame work, the resource only sends a payload when something actually changes.
7. Verify
In-game:
/hygiene
You should see a notification with your current Higiene and Dental percentages. Walk up to a shower prop and use the ox_target eye (with soap in your inventory) to test cleaning.
8. (Optional) Discord logging
Open config/discord.lua, set Config.Discord.enabled = true, paste your webhook, and toggle logShower / logStink.
