Documentation

Tattoo shop documentation

The whole vanilla tattoo catalogue, with a cart and a chair you actually sit in. 1615 designs across 26 DLC collections, previewed live on your own character as you add them, paid for in one go. Laser removal included, and an artist who walks in and does the work.

  • ESX
  • QBCore
  • vRP
  • Standalone
  • oxmysql
01

Installation

  1. Drop the resource

    Grab the script from your Tebex account, then copy the avenida_tattoo/ folder into your resources directory and add ensure avenida_tattoo to your server config, after ensure oxmysql.

  2. Run the SQL

    Run section [A] of INSTALL.sql on your database. Section [B] is conditional, the file header says when you need it.

  3. Set your prices

    Open config/tattoo.lua. The flat rate, the per-collection multipliers and the laser fee are the three numbers worth deciding before you open the doors. config/config.lua holds the language and the bridges.

  4. Verify the integrations

    Set Config.Debug = true, restart, and read the console: one line per bridge category names the target that was picked. Set it back to false once the lines match your server, the diagnostic commands it unlocks cost a frame hitch.

  5. Grant yourself the admin features

    Add add_ace group.admin avenida_tattoo.admin allow to your server config, then run /avenida_tattoo_check in game for the full install report.

02

Configuration

Set the price of ink

One flat rate covers the whole catalogue, and the multipliers make old collections cheap and rare ones expensive without pricing 1615 designs by hand. Everything is recomputed server side at payment.

lua
-- config/tattoo.lua
Config.Tattoo.Prices = {
    flat  = 1000,   -- every tattoo, unless PricePerZone is on
    hair  = 500,
    reset = 3000,   -- laser removal, per tattoo removed
}

Config.Tattoo.PricePerZone = false

Config.Tattoo.CollectionMultipliers = {
    multiplayer_overlays = 0.80,   -- base game, cheaper
    mpHipster_overlays   = 0.85,
    mpBeach_overlays     = 0.85,
    -- anything not listed stays at 1.0
}
03

Exports

Client

  • GetHairbase
    exports['avenida_tattoo']:GetHairbase() --> { c = collection, t = nameHash } | nil

    The hair base the ped currently wears. The ink studio does not own it, but it has to give it back after every redraw, and so does any resource of yours that clears decorations.

  • GetTattoos
    exports['avenida_tattoo']:GetTattoos() --> { { c, t }, ... }

    The full list of tattoos worn, as collection and name hash pairs. This is the authoritative copy: the laser removes from it, and a purchase adds to it, so read it rather than caching your own.

  • GetSkinData
    exports['avenida_tattoo']:GetSkinData()

    The stored character, including the zone corrections that place ink correctly on torso, arms and legs. Handy when your own script needs to know what body it is drawing on.

  • ApplySkin
    exports['avenida_tattoo']:ApplySkin(data, ped)

    Pushes an appearance onto a ped, tattoos included. The decoration slot is rebuilt in one pass, which avoids the flicker you get when ink is applied piece by piece.

  • ApplyClothing
    exports['avenida_tattoo']:ApplyClothing(data, ped, temporary)

    Dresses a ped without touching the ink. The third argument keeps the change out of the database, which is what you want for a scene that ends when the player walks away.

04

Recipes

Bill by body zone instead of a flat rate

With PricePerZone on, the server bills from the GTA decoration zone of each design. Careful with the trade-off documented in the config: only tattoos that resolve to a declared zone are sold, so anything left uncorrected disappears from the shop rather than being sold at the wrong price.

lua
-- config/tattoo.lua
Config.Tattoo.PricePerZone = true

Config.Tattoo.Prices = {
    [0] = 1250, -- torso / back
    [1] = 1000, -- head
    [2] = 600,  -- left arm
    [3] = 600,  -- right arm
    [4] = 750,  -- left leg
    [5] = 750,  -- right leg
    [6] = 750,  -- unknown
    reset = 3000,
}

Move a tattoo to the right tab

GTA files a lot of DLC designs in the wrong zone. 368 are already corrected, and the list is open so you can add yours. Turn Config.Debug on to read a nameHash in game, then declare it.

lua
-- config/tattoo.lua
Config.Tattoo.SubZoneOverrides = {
    ['FM_Hip_M_Tat_000'] = 'back',
    ['MP_Buis_M_Tat_021'] = 'neck',
    -- 'back' | 'chest' | 'neck' | 'head'
}

Frame the tattoo session your way

The scene camera is measured on the player, in their own axes, not on the chair prop. That is deliberate: the seat is rarely where the prop origin sits, and the gap varies by several metres between chairs, which is what makes a naive chair-relative camera film the player back.

lua
-- config/tattoo.lua
Config.Tattoo.ApplyScene = true

Config.Tattoo.SceneCamera = {
    Enabled      = true,
    Distance     = 1.5,   -- metres in front of the player
    Height       = 0.75,  -- metres above their feet
    TargetHeight = 0.6,   -- aim at chest height
    Fov          = 42.0,
}

Redraw decorations from your own script

The ped has one decoration slot for the whole server. If your script calls ClearPedDecorations, read what this resource owns first and hand it back afterwards, otherwise you wipe every tattoo the player paid for.

lua
local hairbase = exports['avenida_tattoo']:GetHairbase()
local tattoos  = exports['avenida_tattoo']:GetTattoos()

ClearPedDecorations(PlayerPedId())
-- your own decoration work here

if hairbase then
    AddPedDecorationFromHashes(PlayerPedId(), hairbase.c, hairbase.t)
end
for _, dec in ipairs(tattoos) do
    AddPedDecorationFromHashes(PlayerPedId(), dec.c, dec.t)
end
05

Questions

Why are some tattoos missing from the shop?

Two reasons, both deliberate. Newer DLC collections are merged in by game build, so a design your client cannot render is never listed rather than listed and broken. And with PricePerZone on, only tattoos that resolve to a declared zone are sold, which is stated in the config: most of the catalogue disappears until you fill the overrides in. With PricePerZone off, the default, the whole catalogue is on sale.

A tattoo shows up in the wrong tab

That is GTA, not the script: the game files a large share of DLC designs under a zone that does not match where they land on the body. 368 are already corrected by hand, 310 to back and 58 to neck. For the rest, turn Config.Debug on to read the nameHash in game and add a line to Config.Tattoo.SubZoneOverrides, which is escrow exempt.

Which frameworks does it actually support?

QBCore, ESX and vRP, plus a standalone mode that needs no framework at all and a custom branch in bridges/framework.lua for anything else. Detection runs at startup and probes the real export. Qbox and ox_core have no dedicated branch: they run through the standalone or custom path, not through a tested target.

Does it work with the ox stack?

Yes, everywhere it matters: ox_lib for notifications through Config.UseOxLib, ox_target for the interaction prompt, ox_inventory for items, and oxmysql as the one hard dependency. Nothing there is required except oxmysql. What has no dedicated branch is ox_core as a framework: on an ox_core server the resource runs standalone, or through the custom branch of bridges/framework.lua.

What does vRP cost me?

vRP stores clothing components and props, and nothing else. It has no field for ped decorations, so tattoos have nowhere to live in it. On vRP this resource keeps the whole character in its own table instead. The practical consequence: a vRP native skinshop will not show the ink. vRP 2 and vRP 0.5 are not supported, and the resource says so in the console rather than misbehaving quietly.

Can I run it next to avenida_barber and avenida_clotheshops?

Yes, that is what they are built for. Each one owns its half of the single ped decoration slot and puts the others back after any redraw. What you must not do is run the separate resources and the avenida_skin bundle at the same time: they would each place their own blip and each write their own copy of the same character. The resource detects the overlap and says so in the console at startup.

Are the tattoo names translated?

They are not retyped at all: each entry carries the Rockstar locale key and the game resolves it in the language the player runs. That is why the names match what a player already knows from story mode, in every language the game ships, and why nothing has to be maintained when a name changes.

What does it cost when nobody is in a shop?

0.00ms. The interaction points share one thread that parks at one second when nobody is nearby, blips are created once, and every session thread is killed on exit. Nothing runs between two customers.

Cart
Spirit RP
Discord