shared/config.lua y los archivos de data/ contienen los valores de fábrica. En el primer arranque se escriben en la base de datos y, desde entonces, casi todo se edita en vivo desde /tabletadmin. Solo unas pocas opciones se leen del archivo en cada arranque.
Después del primer arranque, editar shared/config.lua o data/*.lua no cambia lo que ven los jugadores. Edita desde el panel de administración, o usa Fábrica en una sección del panel para volver a cargar los valores del archivo. Las excepciones son las opciones estáticas.
Opciones estáticas
Se leen de shared/config.lua en cada arranque y no aparecen en el panel.
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
debug | boolean | false | true imprime consultas y eventos en consola. La convar cuxial_tablet_debug a 1 hace lo mismo. |
ui.accent | string (hex) | configurable | Color de acento de la interfaz. |
ui.sounds | boolean | true | true reproduce sonidos de interfaz en las acciones. |
commands.admin | string | 'tabletadmin' | Comando que abre el panel de administración, sin barra. |
admin.permission | string | 'admin' | Permiso necesario para el panel, las operaciones y la moderación de noticias, directos y galería. Consulta Permisos. |
El nombre que sale en la cabecera de la tablet viene de las claves UI_SHELL_BRAND, UI_SHELL_BRAND_A y UI_SHELL_BRAND_B de locales/en.json y locales/es.json.
Tablet · tablet
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false impide a todos abrir la tablet. El panel de administración sigue funcionando. |
keybind | string | 'F1' | Tecla por defecto. Cambiarla exige que los jugadores vuelvan a conectar; cada jugador puede reasignarla en los ajustes de teclas de GTA. Se aceptan botones del ratón como MOUSE_BUTTON. |
startPage | string | 'player' | Página que se muestra al abrir: player, news, jobsOnline, jobsCity, crosshair o vip. |
rememberPage | boolean | true | true reabre en la última página visitada. |
prop.model | string | 'prop_cs_tablet' | Prop que se lleva en la mano. |
prop.bone | number | 60309 | Hueso al que se engancha. 60309 es la mano izquierda. |
prop.offset | table | { x = 0.0, y = 0.0, z = 0.03 } | Desplazamiento respecto al hueso. |
prop.rotation | table | { x = 10.0, y = 160.0, z = 0.0 } | Rotación del prop. |
anim.dict, anim.clip | string | animación de tablet | Animación que se reproduce con la tablet abierta. |
anim.flag | number | 50 | Flag de la animación. 50 es parte superior y bucle. |
canOpen.dead | boolean | false | true permite abrirla muerto o herido. |
canOpen.swimming | boolean | false | true permite abrirla nadando. |
canOpen.driving | boolean | false | true permite abrirla siendo el conductor. |
canOpen.passenger | boolean | true | true permite abrirla de pasajero. |
canOpen.cuffed | boolean | false | true permite abrirla esposado. |
pages.player, pages.news, pages.jobsOnline, pages.jobsCity, pages.crosshair, pages.vip | boolean | true | false quita esa página de la tablet. |
VIP · vip
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
account | string | 'coins' | Cuenta de dinero del framework que guarda las coins. Debe existir. Consulta Instalación. |
cooldownMs | number | 2000 | Milisegundos que un jugador debe esperar entre dos compras. |
stockMode | string | 'perItem' | 'perItem' mantiene un stock global por artículo y descuenta cada venta. 'none' ignora el stock. |
newDays | number | 7 | Días que un artículo lleva la etiqueta nuevo desde que entra al catálogo. |
topSellersCount | number | 5 | Artículos marcados top ventas, por ventas de los últimos 30 días. |
cart.maxItems | number | 10 | Líneas máximas en el carrito. |
gift.enabled | boolean | true | true permite regalar artículos a jugadores conectados. |
gift.feePct | number | 0 | Porcentaje que se añade al precio al regalar. |
gift.messageMaxLen | number | 120 | Longitud máxima del mensaje del regalo. |
wallet.transfer.enabled | boolean | true | true permite transferir coins entre jugadores. |
wallet.transfer.feePct | number | 5 | Porcentaje que se pierde como comisión en cada transferencia. |
wallet.transfer.min | number | 10 | Coins mínimas por transferencia. |
wallet.transfer.maxPerDay | number | 5000 | Coins que un jugador puede enviar al día. 0 quita el tope. |
wallet.historyLimit | number | 50 | Movimientos que se muestran en la cartera. |
codes.prefix | string | 'VIP' | Prefijo de los códigos canjeables, como en VIP-XXXX-XXXX. Hasta 12 caracteres. |
codes.redeemPerHour | number | 10 | Intentos de canje por hora y jugador. |
loyalty.enabled | boolean | true | true activa los niveles de lealtad. |
loyalty.tiers | table[] | cuatro niveles | Niveles ordenados por spent, ver abajo. |
Cada nivel de lealtad:
| Campo | Tipo | Qué hace |
|---|---|---|
id | string | Nombre interno. |
label | string | Nombre que ve el jugador. |
spent | number | Coins gastadas necesarias para alcanzar el nivel. El primer nivel es 0. |
discountPct | number | Descuento en los precios de la tienda. |
extraDailyDay | boolean | true añade un día extra al final de cada ciclo diario. |
accent | string (hex) | Color del nivel. |
Los niveles por defecto son Bronce (0 coins, sin descuento), Plata (2.500 coins, 3 %), Oro (10.000 coins, 6 %, día extra) y Diamante (30.000 coins, 10 %, día extra).
Recompensa diaria · daily
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false oculta la pestaña de la diaria. |
cycleDays | number | 7 | Días del ciclo. Debe coincidir con los días de data/daily.lua. |
claimWindowHours | number | 24 | Horas entre dos reclamos. |
breakStreakOnMiss | boolean | true | true reinicia la racha en 1 cuando un jugador reclama tras más de graceHours sin reclamar. false nunca la rompe. |
graceHours | number | 48 | Horas sin reclamar antes de que la racha quede en riesgo. Nunca menos que claimWindowHours. |
streakBonusPct | number | 5 | Porcentaje de coins extra por día de racha, solo en premios de coins. |
streakBonusMaxPct | number | 50 | Tope del bonus de racha. |
rescue.enabled | boolean | true | true permite pagar para conservar una racha en riesgo. |
rescue.price | number | 150 | Coins por rescate. |
rescue.maxPerCycle | number | 1 | Rescates permitidos por ciclo. |
Pase de temporada · pass
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false oculta la pestaña del pase y detiene el XP. |
season.name | string | 'SEASON 1' | Nombre que se muestra. |
season.number | number | 1 | Número de temporada. Cambiar el nombre o el número inicia una temporada nueva para todos. |
season.endsAt | number | 0 | Hora Unix, en segundos, del fin de temporada que se muestra en el pase. 0 no muestra fecha. |
totalTiers | number | 15 | Niveles. Debe coincidir con los niveles de data/pass.lua. |
xpPerLevel | number | 1000 | XP por nivel. |
premiumPrice | number | 3000 | Coins para activar el premium de la temporada. |
xpSources.daily | number | 100 | XP por reclamo diario. |
xpSources.shopPerCoin | number | 1 | XP por coin gastada en la tienda o en cajas. |
xpSources.jobComplete | number | 150 | XP por trabajo completado. Consulta EmitJobCompleted. |
xpSources.playtimePerMin | number | 2 | XP por minuto conectado. 0 lo desactiva. |
missions.weeklyCount | number | 3 | Misiones activas cada semana, elegidas de data/missions.lua. |
missions.resetDay | number | 1 | Día en que se reinicia la semana: 1 lunes a 7 domingo. |
Cajas · cases
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false oculta la pestaña de cajas. |
showOdds | boolean | true | true muestra las probabilidades por rareza en cada nivel. |
multiOpen | number[] | { 1, 3, 5 } | Cantidades que un jugador puede abrir a la vez. |
stripLength | number | 40 | Tarjetas en la tira de la ruleta. |
winnerIndex | number | 32 | Posición de la tarjeta ganadora en la tira. Como máximo stripLength. |
pity.enabled | boolean | true | true garantiza una legendaria tras un número de aperturas sin ella. |
pity.legendaryAfter | number | 50 | Aperturas sin legendaria antes de forzar una. |
Noticias · news
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false apaga las noticias; la página no muestra nada y nadie puede publicar. |
trendingCount | number | 3 | Entradas que se muestran como tendencia. |
autoTrendingLikeThreshold | number | 500 | Likes a partir de los que una entrada pasa a tendencia. |
publisherJobs | string[] | { 'journalist', 'reporter' } | Trabajos que pueden publicar. El staff siempre puede. |
allowAnonLikes | boolean | false | true acepta likes de jugadores sin personaje cargado. |
pageSize | number | 20 | Entradas por página del feed. |
categories | string[] | siete categorías | Categorías que se ofrecen al redactar. Las categorías ya usadas por entradas guardadas se suman a la lista. |
Directos · live
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false apaga los directos. |
broadcasterJobs | string[] | { 'journalist', 'reporter', 'police' } | Trabajos que pueden emitir. El staff siempre puede. |
maxDurationSec | number | 14400 | Duración máxima de un directo, en segundos. |
maxViewers | number | 50 | Espectadores por directo. |
enc.width, enc.bitrate, enc.fps | number | 960, 1500000, 20 | Perfil de vídeo que se usa cuando el relay está configurado. |
chat.enabled | boolean | true | true activa el chat del directo. |
chat.maxLen | number | 140 | Longitud máxima de un mensaje del chat. |
chat.perMinute | number | 20 | Mensajes por minuto y espectador. |
camera.prop | string | 'prop_v_cam_01' | Prop de cámara que lleva el locutor. |
camera.bone | number | 28422 | Hueso al que se engancha. 28422 es la mano derecha. |
camera.offset, camera.rotation | table | ver archivo | Posición y rotación del prop. |
camera.animDict, camera.animClip, camera.animFlag | string, string, number | animación de cámara al hombro | Animación que se reproduce mientras se emite. |
camera.lensForward | number | 0.30 | Metros por delante del prop donde se coloca la cámara de la emisión. |
camera.zoomMin, camera.zoomMax | number | 20.0, 60.0 | Rango de campo de visión del zoom. |
camera.stopKey | string | 'BACK' | Tecla por defecto que corta el directo. Cambiarla exige que los jugadores vuelvan a conectar. |
Mira · crosshair
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
enabled | boolean | true | false apaga toda la función. |
hideNative | boolean | true | true oculta la retícula del juego mientras la mira propia está activa. |
allowHitmarker | boolean | true | false quita el hitmarker y los números de daño a todos. |
allowDamageNumbers | boolean | true | false quita los números de daño a todos. Necesita allowHitmarker. |
tickMs | number | 50 | Milisegundos entre actualizaciones del estado de la mira. |
maxLayers | number | 6 | Capas por mira. |
maxSize | number | 64 | Tamaño máximo de una capa, en píxeles a 1080p. |
gallery.enabled | boolean | true | true activa la galería comunitaria. |
gallery.maxPerPlayer | number | 5 | Entradas que puede publicar un jugador. |
gallery.nameMaxLen | number | 24 | Longitud máxima del nombre de una entrada. |
gallery.pageSize | number | 30 | Entradas por página. |
defaults.enabled | boolean | false | true activa la mira propia a los jugadores que no han configurado nada. |
defaults.preset | string | 'classic_cross' | Preset inicial, por id de data/crosshair_presets.lua. |
defaults.color | string (hex) | '#ffffff' | Color inicial. |
defaults.alwaysShow | boolean | false | true la dibuja sin apuntar. |
defaults.dynamic | table | { enabled = true, moveGap = 4, sprintGap = 8, vehicleGap = 6, aimGap = -2, smooth = 0.2 } | Separación dinámica inicial: separación extra al moverse, esprintar y conducir, reducción al apuntar, y suavizado. |
defaults.perWeapon.enabled | boolean | false | true empieza con un perfil por grupo de arma. |
hitmarkerDefaults.enabled | boolean | true | Hitmarker activo para los jugadores que no han configurado nada. |
hitmarkerDefaults.style | string | 'cross' | cross, x, ring o dot. |
hitmarkerDefaults.sound | boolean | true | true reproduce un tick al impactar. |
hitmarkerDefaults.volume | number | 0.35 | Volumen del tick, de 0 a 1. |
hitmarkerDefaults.showDamage | boolean | true | true muestra el número de daño. |
hitmarkerDefaults.durationMs | number | 220 | Duración del marcador, de 100 a 600. |
weaponGroups | string[] | ocho grupos | Grupos de arma que se ofrecen para los perfiles por arma: melee, pistol, smg, rifle, shotgun, sniper, heavy, throwable. |
data/crosshair_presets.lua contiene los 146 presets y los valores por defecto de cada tipo de capa. Se lee del archivo en cada arranque y no se edita desde el panel.
Trabajos · jobs
| Opción | Tipo | Por defecto | Qué hace |
|---|---|---|---|
onlineRefreshSec | number | 5 | Segundos que se guardan en caché los recuentos de servicio. |
city.startMode | string | 'waypoint' | 'waypoint' marca las coordenadas del trabajo en el mapa. 'event' dispara un evento de cliente con el id del trabajo. |
city.startEvent | string | '' | Evento de cliente que se dispara cuando startMode = 'event' y el trabajo no tiene evento propio. |
Catálogos · data/
Los archivos de data/ son los catálogos de fábrica. Se entregan con filas de muestra que apuntan a ítems habituales del inventario; sustitúyelas por las tuyas desde el panel de administración. Cada fila tiene los campos de abajo.
Tienda · data/shop.lua
| Campo | Qué hace |
|---|---|
id | Único y estable. Nunca reutilices un id: el stock y el historial lo referencian. |
enabled | false oculta el artículo. |
itemKey | Nombre del ítem en el inventario. |
name, description | Se muestran en la tarjeta. |
category | Una de las categorías listadas al final del archivo (shopCategories). |
rarity | common, rare, epic o legendary. |
price | Coins. |
amount | Unidades del ítem principal. |
stock | Unidades a la venta con stockMode = 'perItem'. -1 es ilimitado. |
image | URL completa o ruta dentro de la carpeta de imágenes del inventario. Vacío usa la imagen del inventario para itemKey. |
bundle | Ítems extra que se entregan con el principal: { itemKey, amount, label, metadata }. |
metadata | Metadatos del ítem principal. |
featured | true lo muestra en el orden de destacados. |
discount.pct, discount.untilAt | Oferta flash: porcentaje y hora Unix de su fin. 0 es sin oferta. |
limited.untilAt | Hora Unix tras la cual el artículo sale de la tienda. 0 es permanente. |
requires.loyaltyTier | Id del nivel de lealtad necesario para comprar. Vacío es ninguno. |
addedAt | Hora Unix en que el artículo entró al catálogo, para la etiqueta nuevo. El panel la rellena. |
sort | Orden manual, menor primero. |
theme | Tema de la tarjeta. Vacío o uno de shopThemes. |
preview3d | true muestra el botón Ver en 3D. |
previewModel | Modelo que se muestra en 3D. Vacío usa itemKey como modelo de arma. |
Diaria · data/daily.lua
Una fila por día del ciclo: day, enabled, kind (item, coins o cash), itemKey, amount, label, milestone y metadata.
Pase · data/pass.lua
Una fila por nivel: level, free y premium. Cada premio tiene kind (item, coins, cash o none), itemKey, amount, label, milestone y metadata.
Cajas · data/cases.lua
tiers:id,enabled,label,accent,price,image(vacío usaimages/cases/<id>.webpde la interfaz) yweights, la probabilidad decommon,rare,epicylegendary, que suman 1.pool: los premios, compartidos por todos los niveles:id,enabled,kind,itemKey,name,rarity,amount,imageymetadata.
Misiones · data/missions.lua
id, enabled, label, type, target, xp e icon. El tipo decide qué cuenta target:
| Tipo | Objetivo |
|---|---|
jobs | Trabajos completados |
playtime | Minutos conectado |
daily | Reclamos diarios |
shop | Coins gastadas |
distance | Metros recorridos |
cases | Cajas abiertas |
Trabajos online · data/jobs_online.lua
id, enabled, job (nombre del trabajo en el framework), name, image, description, category, color y priority (mayor primero).
Empleos · data/jobs_city.lua
id, enabled, name, image, description, coords y event (evento de cliente de este trabajo cuando startMode = 'event'; vacío usa jobs.city.startEvent). Las coordenadas se eligen en el mundo desde el panel de administración.
Las imágenes de trabajos y cajas son rutas dentro de la carpeta web/dist del recurso, como images/cityjobs/trucker.webp.
Hooks
La carpeta hooks/ contiene adaptadores Lua que conectan la tablet con tus propios recursos. Edítalos con libertad; mantén los nombres de las funciones y la forma de lo que devuelven.
| Archivo | Función | Devuelve | De fábrica |
|---|---|---|---|
hooks/server/vehicles.lua | GetVehicles(src) | { name, model, plate, class?, status }[] con status uno de garage, out, destroyed, impound | Lee qbx_vehicles |
hooks/server/properties.lua | GetProperties(src) | { name, address, type }[] con type uno de house, apartment, garage, business | Lee nolag_properties |
hooks/server/playtime.lua | GetWorkedHours(citizenid), GetSessionMinutes(src) | Horas enteras, minutos | Horas de la tabla player_jobs_activity si existe; minutos de sesión contados por la tablet |
hooks/server/stats.lua, hooks/client/stats.lua | GetStats(src), GetStats() | { label, value, max?, icon? }[] estadísticas extra del perfil | Vacío |
hooks/server/xp.lua | OnJobCompleted(cb), EmitJobCompleted(src, info) | — | Escucha cuxial_jobs:server:JobCompleted |
hooks/server/images.lua | GetItemImage(itemKey), GetItemLabel(itemKey) | URL de la imagen y etiqueta de un ítem del inventario | Detecta ox_inventory o qb-inventory |
Cuando el recurso de origen no está en marcha, el adaptador devuelve una lista vacía y la tablet funciona igual.
function Hooks.GetVehicles(src)
local player = CuxialTablet.getPlayer(src)
if not player then return {} end
local rows = MySQL.query.await('SELECT plate, vehicle FROM my_vehicles WHERE owner = ?', { player.citizenid })
local out = {}
for i, v in ipairs(rows or {}) do
out[i] = { name = v.vehicle, model = v.vehicle, plate = v.plate, status = 'garage' }
end
return out
endCambios habituales
Usar una cuenta de dinero existente para las coins
Desde el panel, sección VIP, pon account en bank. O, antes del primer arranque:
vip = {
account = 'bank',
...
},Arrancar los empleos desde tu propio recurso de trabajos
Sección Trabajos del panel: city.startMode = event y city.startEvent = myjobs:client:start. El evento recibe el id del trabajo.
RegisterNetEvent('myjobs:client:start', function(jobId)
-- arrancar el trabajo
end)Apagar la economía VIP y conservar el resto
Sección Tablet del panel: pages.vip = false. La página desaparece y no hacen falta coins.
Cambiar la tecla de la tablet
Sección Tablet del panel: keybind = F2. Los jugadores que ya habían entrado conservan su asignación y pueden cambiarla en los ajustes de teclas de GTA.
