Skip to content

Exports y eventos

API pública de Cuxial Interactions: registra NPC, diálogos y tiendas desde tus propios recursos.

Registra tus propios NPC desde cualquier recurso, cuelga un diálogo de un ped que ya creaste, o abre un diálogo o una tienda directamente. Los puntos se registran en el cliente; los precios de una tienda, en el servidor.

Referencia rápida ​

LadoExportDevuelve
ClienteRegister(id, def)boolean
ClienteUpdate(id, patch)boolean
ClienteRemove(id)boolean
ClienteExists(id)boolean
ClienteGetEntity(id)integer o nil
ClienteInteract(id)boolean
ClienteShowDialog(data)id del botón que cerró, o nil
ClienteSwitchDialog(dialogId)boolean
ClienteShowShop(data)boolean o nil
ClienteClose()boolean
ClienteIsOpen()boolean
ServidorRegisterShop(id, items, options)boolean
ServidorRemoveShop(id)boolean
ServidorGetShop(id)table o nil

Ejemplo completo: un NPC con diálogo y tienda ​

Un NPC comprador registrado desde un recurso llamado my_resource. El cliente registra el punto; el servidor registra qué compra la tienda y a qué precio.

Declara la dependencia ​

my_resource/fxmanifest.lua
lua
dependency 'cuxial_interactions'

Registra la tienda en el servidor ​

my_resource/server.lua
lua
local SHOP_ID = 'my_resource:scrap_buyer'

local function registerShop()
    if GetResourceState('cuxial_interactions') ~= 'started' then return end

    exports.cuxial_interactions:RegisterShop(SHOP_ID, {
        { name = 'scrapmetal', price = 12 },
        { name = 'copper', price = 20, label = 'Cable de cobre' },
    }, {
        coords = vec3(25.7, -1347.3, 29.49),
        distance = 6.0,
        account = 'cash',
    })
end

CreateThread(registerShop)

AddEventHandler('onResourceStart', function(resource)
    if resource == 'cuxial_interactions' then registerShop() end
end)

RegisterNetEvent('my_resource:server:AskForWork', function(args, info)
    local src = source
    -- args e info vienen del cliente: comprueba aquí al jugador, la distancia y el estado.
    print(('el jugador %s pidió trabajo en el punto %s'):format(src, info.id))
end)

Registra el NPC en el cliente ​

my_resource/client.lua
lua
local POINT_ID = 'my_resource:scrap_buyer'

local function registerNpc()
    if GetResourceState('cuxial_interactions') ~= 'started' then return end

    exports.cuxial_interactions:Register(POINT_ID, {
        coords = vec4(25.7, -1347.3, 29.49, 271.0),
        model = 's_m_y_dealer_01',
        scenario = 'WORLD_HUMAN_STAND_IMPATIENT',
        behavior = { invincible = true, noTemporaryEvents = true, freeze = true },

        label = 'Hablar con el comprador',
        targetIcon = 'fas fa-comment-dots',
        activeDistance = 2.5,
        blip = { id = 52, scale = 0.6, colour = 5, name = 'Chatarrero' },

        -- shop.id vale por defecto el id del punto, así coincide con RegisterShop.
        shop = { name = 'Sam', job = 'Comprador', icon = 'store' },

        dialog = {
            {
                id = 'inicio',
                name = 'Sam',
                job = 'Comprador',
                icon = 'store',
                text = '¿Traes algo para mí?',
                buttons = {
                    { id = 'vender', label = 'Enseñar lo que llevo', icon = 'hand-coins', shop = true },
                    { id = 'trabajo', label = '¿Tienes trabajo?', icon = 'briefcase', nextDialog = 'trabajo' },
                    { id = 'adios', label = 'Hoy no', icon = 'x', close = true },
                },
            },
            {
                id = 'trabajo',
                name = 'Sam',
                job = 'Comprador',
                text = 'Puede. Tráeme una ganzúa y hablamos.',
                buttons = {
                    {
                        id = 'aceptar',
                        label = 'Tengo una',
                        icon = 'key',
                        item = 'lockpick',
                        close = true,
                        serverEvent = 'my_resource:server:AskForWork',
                        args = { job = 'scrap' },
                    },
                    {
                        id = 'despedirse',
                        label = 'Despedirse',
                        icon = 'hand',
                        close = true,
                        onSelect = function(ctx)
                            PlayAmbientSpeech1(ctx.entity, 'GENERIC_BYE', 'SPEECH_PARAMS_FORCE')
                        end,
                    },
                    { id = 'volver', label = 'Volver', icon = 'undo-2', nextDialog = 'inicio' },
                },
            },
        },
    })
end

CreateThread(registerNpc)

AddEventHandler('onClientResourceStart', function(resource)
    if resource == 'cuxial_interactions' then registerNpc() end
end)

Reiniciar cuxial_interactions borra todos los puntos y tiendas registrados por otros recursos. Conserva los manejadores onClientResourceStart y onResourceStart del ejemplo para que los tuyos se registren de nuevo.

Propiedad y limpieza ​

  • Cada punto y cada tienda pertenece al recurso que lo registró.
  • Registrar un id que ya es tuyo lo sustituye. Un id de otro recurso se rechaza con un aviso en consola.
  • Solo el dueño puede modificar o quitar un punto o una tienda.
  • Al parar un recurso se quitan sus puntos, se cierra su diálogo abierto y se borran sus tiendas.
  • Los ids son comunes a todo el servidor. Ponles de prefijo el nombre de tu recurso: 'my_resource:scrap_buyer'.

Exports de cliente ​

Register ​

Registra un punto: un NPC, o un lugar sin ped, que abre un diálogo o una tienda.

lua
exports.cuxial_interactions:Register(id, def)
ParámetroTipoDescripción
idstringId único del punto. No vacío.
deftableDefinición del punto. Consulta Campos del punto.

Devuelve: boolean. false cuando id o def no son válidos, cuando el id es de otro recurso, cuando def.enabled == false, o cuando def no tiene ninguno de coords, entity y netId.

lua
-- Cuelga un diálogo de un ped que tu recurso ya creó.
exports.cuxial_interactions:Register('my_resource:doctor', {
    entity = doctorPed,
    label = 'Hablar',
    dialog = {
        {
            id = 'inicio',
            name = 'Dra. Lee',
            text = '¿En qué puedo ayudarte?',
            buttons = { { id = 'adios', label = 'Nada, gracias', close = true } },
        },
    },
})

Update ​

Mezcla patch en la definición de un punto tuyo y lo reconstruye.

lua
exports.cuxial_interactions:Update(id, patch)
ParámetroTipoDescripción
idstringId del punto.
patchtableCampos a sustituir. Solo se mezcla el primer nivel: un dialog o un blip en el parche sustituye la tabla entera.

Devuelve: boolean. false cuando el punto no existe o es de otro recurso.

lua
exports.cuxial_interactions:Update('my_resource:scrap_buyer', { label = 'Cerrado por hoy', dialog = closedDialog })

Update no puede borrar un campo, porque un valor nil no viaja en el parche. Para eso llama otra vez a Register con la definición completa.

Remove ​

Quita un punto tuyo: su ped, su blip y su opción de target. Si su diálogo está abierto, se cierra.

lua
exports.cuxial_interactions:Remove(id)

Devuelve: boolean. false cuando el punto no existe o es de otro recurso.

lua
exports.cuxial_interactions:Remove('my_resource:scrap_buyer')

Exists ​

Indica si un punto está registrado, sea de quien sea.

lua
local registered = exports.cuxial_interactions:Exists(id)

Devuelve: boolean.

GetEntity ​

Devuelve el ped de un punto.

lua
local ped = exports.cuxial_interactions:GetEntity(id)

Devuelve: integer o nil. nil cuando el punto no existe, no tiene ped, o el jugador está lejos y el ped no está creado.

lua
local ped = exports.cuxial_interactions:GetEntity('my_resource:scrap_buyer')
if ped then PlayAmbientSpeech1(ped, 'GENERIC_HI', 'SPEECH_PARAMS_FORCE') end

Interact ​

Abre un punto como si el jugador lo hubiera seleccionado. Aplica las mismas condiciones (job, item, canInteract). Úsalo en los puntos con interaction = 'none', que abres desde tu propio marcador, tecla o menú.

lua
exports.cuxial_interactions:Interact(id)

Devuelve: boolean. false cuando el punto no existe, ya hay un diálogo o una tienda abiertos, no se cumplen las condiciones, o el punto no tiene dialog, shop ni onInteract.

lua
if not exports.cuxial_interactions:Interact('my_resource:scrap_buyer') then
    lib.notify({ description = 'No quiere hablar contigo.', type = 'error' })
end

ShowDialog ​

Abre un diálogo que no está ligado a un punto registrado. La llamada espera hasta que el diálogo se cierra.

lua
local result = exports.cuxial_interactions:ShowDialog(data)
ParámetroTipoDescripción
data.dialogtableLista de páginas. Obligatorio. Consulta «Página de diálogo» más abajo.
data.entityintegerPed al que enfoca la cámara. Opcional.
data.shoptableTienda que abren los botones con shop = true. Consulta Tienda.
data.extraDatatableTus propios datos, que llegan en ctx.extraData.
data.camerabooleanfalse abre sin mover la cámara.
data.idstringId que se informa en ctx.id y en los eventos. Opcional.

Devuelve: el id del botón con close = true que cerró el diálogo, o su posición si no tiene id. nil cuando se cerró con Esc o con Close(), cuando los datos no son válidos, o al momento si ya hay algo abierto.

lua
local answer = exports.cuxial_interactions:ShowDialog({
    entity = guardPed,
    dialog = {
        {
            id = 'pregunta',
            name = 'Guardia',
            text = 'Esta zona está cerrada. ¿Quieres pagar la tasa?',
            buttons = {
                { id = 'si', label = 'Pagar', icon = 'dollar-sign', close = true },
                { id = 'no', label = 'Irme', icon = 'x', close = true },
            },
        },
    },
})

if answer == 'si' then
    TriggerServerEvent('my_resource:server:PayFee')
end

ShowDialog bloquea el hilo que lo llama. Llámalo dentro de CreateThread o de un manejador de evento, nunca en un bucle que corre cada frame.

SwitchDialog ​

Cambia la página del diálogo abierto.

lua
exports.cuxial_interactions:SwitchDialog(dialogId)
ParámetroTipoDescripción
dialogIdstring | numberid de una página del diálogo abierto.

Devuelve: boolean. false cuando no hay ningún diálogo abierto o la página no existe o está desactivada.

lua
onSelect = function()
    local hasLicense = lib.callback.await('my_resource:server:HasLicense', false)
    exports.cuxial_interactions:SwitchDialog(hasLicense and 'aprobado' or 'denegado')
end,

ShowShop ​

Abre una tienda. Con un diálogo abierto, pasa a la tienda y añade un botón para volver. Sin nada abierto, abre la tienda directamente y espera hasta que se cierra.

lua
exports.cuxial_interactions:ShowShop(data)
ParámetroTipoDescripción
datatableUna tabla de tienda, o { shop = tablaDeTienda, entity = ped, camera = boolean, id = string }. Consulta Tienda.

Devuelve: boolean cuando pasó a la tienda desde un diálogo abierto. nil cuando la abrió directamente, una vez cerrada.

lua
exports.cuxial_interactions:ShowShop({
    entity = buyerPed,
    shop = { id = 'my_resource:scrap_buyer', name = 'Sam', job = 'Comprador' },
})

Abierta así, la tienda necesita su propio id, y ese id debe estar registrado en el servidor con RegisterShop. Si no, se muestra como no disponible.

Close ​

Cierra el diálogo o la tienda que esté abierto.

lua
exports.cuxial_interactions:Close()

Devuelve: boolean. false cuando no había nada abierto.

IsOpen ​

Indica si hay un diálogo o una tienda abiertos.

lua
local open = exports.cuxial_interactions:IsOpen()

Devuelve: boolean.

lua
if exports.cuxial_interactions:IsOpen() then return end

El mismo valor está en LocalPlayer.state.isDialogOpen. Es local al cliente del jugador y no se envía al servidor.

Alias de compatibilidad ​

Se conservan nombres antiguos en minúscula para que el código existente siga funcionando. En código nuevo usa los nombres de arriba.

AliasEquivalente
showDialog(data)ShowDialog(data). Acepta además data.ped como entidad.
switchDialog(id)SwitchDialog(id)
showShop(shop)Pasa a la tienda desde un diálogo abierto.
showShopDirect({ ped, shop })Abre la tienda directamente.

Exports de servidor ​

RegisterShop ​

Registra qué compra una tienda y a qué precio. El servidor solo acepta ventas a tiendas registradas, y siempre paga el precio registrado aquí.

lua
exports.cuxial_interactions:RegisterShop(id, items, options)
ParámetroTipoDescripción
idstringId de la tienda. El mismo que shop.id en el cliente; en un punto registrado con Register, el id del punto salvo que pongas otro.
itemstableLista de { name, price, label, image }. name es el nombre del objeto y price un número de 0 en adelante; los dos son obligatorios. label toma por defecto el nombre del inventario. image es una URL. Un objeto repetido se toma una vez.
options.coordsvector3 | vector4 | tablePosición de la tienda, o una lista de posiciones.
options.netIdintegerId de red de un ped en red; la distancia se mide hasta él.
options.anywherebooleantrue acepta ventas desde cualquier distancia.
options.distancenumberMetros máximos hasta coords o hasta el ped. Por defecto, shop.maxDistance del config.
options.accountstringCuenta en la que se paga la venta. Por defecto, shop.account del config.

Es obligatorio uno de coords, netId o anywhere = true.

Devuelve: boolean. false cuando el id no es válido o es de otro recurso, cuando la lista está vacía o algún objeto no tiene nombre o un precio válido, o cuando no se indica ubicación.

lua
exports.cuxial_interactions:RegisterShop('my_resource:scrap_buyer', {
    { name = 'scrapmetal', price = 12 },
}, { coords = vec3(25.7, -1347.3, 29.49) })

Lo que comprueba el servidor en cada venta, en este orden:

  1. La tienda está registrada y compra ese objeto.
  2. La cantidad es un número entero entre 1 y shop.maxQuantity.
  3. El jugador esperó shop.cooldown desde su última venta.
  4. El jugador está dentro de la distancia de la tienda.
  5. El jugador lleva las unidades.

Después quita los objetos y paga precio × cantidad, redondeado a un número entero. Si el pago falla, se devuelven los objetos.

Con la tienda registrada, el jugador ve la lista y los precios del servidor. Los items de la tabla de tienda del cliente solo se muestran cuando la tienda no está registrada, y entonces no se puede vender nada.

RemoveShop ​

Quita una tienda tuya.

lua
exports.cuxial_interactions:RemoveShop(id)

Devuelve: boolean. false cuando la tienda no existe o es de otro recurso.

GetShop ​

Devuelve una tienda registrada.

lua
local shop = exports.cuxial_interactions:GetShop(id)

Devuelve: { id, account, items } o nil. Cada objeto trae name, label, price e image.

lua
local shop = exports.cuxial_interactions:GetShop('my_resource:scrap_buyer')
if shop then
    for _, item in ipairs(shop.items) do
        print(item.name, item.price)
    end
end

Referencia de datos ​

Campos del punto ​

La tabla que se pasa a Register, y el valor de cada NPC en un archivo de data/.

Dónde. Es obligatorio uno de los tres.

CampoTipoDescripción
coordsvector3 | vector4Posición del punto. Con model o usePlayerSkin se crea un ped ahí; sin ellos es un lugar sin ped. La w de un vector4 es la orientación.
entityintegerUn ped u objeto que ya existe en este cliente. El punto no lo crea ni lo borra.
netIdintegerLo mismo, por id de red. El punto se engancha cuando la entidad entra en rango.

Ped. Solo en los puntos con coords que crean su propio ped.

CampoTipoDescripción
modelstring | numberModelo del ped. Si no existe, se usa npc.fallbackModel.
usePlayerSkinbooleantrue da al ped el aspecto de un personaje activo al azar. Recurre a model cuando no hay ningún aspecto disponible.
headingnumberOrientación, cuando coords es un vector3.
scenariostringEscenario que hace el ped, como 'WORLD_HUMAN_CLIPBOARD'.
animationtable{ dict, clip, speed, blendOut, duration, flag }. dict y clip son obligatorios. Por defecto: 8.0, -8.0, -1, 1.
clothingtableLista de { componentIndex, variation, texture }. No se aplica cuando el ped recibió el aspecto de un jugador.
behaviortable{ invincible, noTemporaryEvents, freeze }, cada uno un boolean.
spawnDistancenumberMetros a los que se crea el ped. Por defecto, npc.spawnDistance.

Interacción.

CampoTipoDescripción
labelstringTexto de la opción de target. Por defecto, «Hablar».
targetIconstringClase Font Awesome de la opción de target. Por defecto, target.icon.
activeDistancenumberMetros desde los que el jugador puede interactuar. Por defecto, target.distance.
interactionstring'target', 'sprite' o 'none'. Por defecto, interaction del config.
camerabooleanfalse abre sin mover la cámara.
bliptable{ id, scale, colour, name }. id es el sprite del blip. Por defecto: escala 0.6, color 0. Necesita coords. El blip se crea al registrar el punto, esté a la distancia que esté el jugador.

Condiciones. Deben cumplirse todas para que aparezca la opción.

CampoTipoDescripción
jobstring | table'police', { 'police', 'ambulance' } (cualquiera), o { police = 2 } (grado mínimo).
itemstring | table'lockpick', { 'lockpick', 'phone' } (todos), o { lockpick = 3 } (unidades mínimas).
canInteractfunctionfunction(ctx). Debe devolver true.
enabledbooleanfalse deja el punto sin registrar.

Contenido.

CampoTipoDescripción
dialogtableLista de páginas. Se muestra la primera página activa.
shoptableTienda del punto. Sin dialog, el punto abre la tienda directamente; con dialog, la abre un botón con shop = true.
onInteractfunctionfunction(ctx). Se ejecuta en lugar de abrir el diálogo o la tienda.
extraDatatableTus propios datos, que llegan en ctx.extraData.
CampoTipoDescripción
idstring | numberÚnico dentro del diálogo. Lo usan nextDialog y SwitchDialog.
namestringQuién habla.
jobstringCargo que aparece en la cabecera. Solo texto, no es una condición.
textstringLo que dice el NPC.
textSpeednumberMilisegundos por carácter. Por defecto, dialog.textSpeed.
iconstringIcono de la cabecera. Consulta Iconos.
enabledbooleanfalse omite la página.
buttonstableLista de botones.
CampoTipoDescripción
idstring | numberId del botón. Es lo que devuelve ShowDialog cuando el botón cierra.
labelstringTexto del botón.
iconstringIcono del botón. Consulta Iconos.
enabledbooleanfalse oculta el botón.
job, item, canInteractCondiciones, como en el punto. Un botón que no las cumple no se envía a la interfaz ni se puede ejecutar.
closebooleanCierra el diálogo.
onSelectfunctionfunction(ctx).
eventstringEvento de cliente: TriggerEvent(event, args, info).
serverEventstringEvento de servidor: TriggerServerEvent(serverEvent, args, info).
argsanyValor que se envía como primer argumento de event y serverEvent.
shopbooleanAbre la tienda del punto.
nextDialogstring | numberid de la página que se muestra a continuación.

Un botón ejecuta sus acciones en este orden: close, onSelect, event, serverEvent, y después shop o nextDialog. Con close = true se omite el último paso. shop tiene prioridad sobre nextDialog.

Tienda ​

CampoTipoDescripción
idstringId registrado con RegisterShop. En un punto vale por defecto el id del punto.
namestringNombre del comprador. Por defecto, «Vendedor».
jobstringCargo que aparece en la cabecera. Por defecto, «Comerciante».
iconstringIcono de la cabecera. Consulta Iconos.
itemstableLista de { name, label, price, image }. Obligatoria en los archivos de data/, donde es también la lista que se registra en el servidor. Desde otro recurso es opcional: se usa la lista del servidor.

La tabla ctx ​

La reciben onSelect, canInteract y onInteract.

CampoTipoDescripción
idstringId del punto. nil en un diálogo abierto con ShowDialog sin data.id.
entityintegerPed del punto, si lo hay. ctx.ped contiene el mismo valor.
dialogIdstring | numberid de la página actual. Solo en botones.
buttonIdstring | numberid del botón. Solo en botones.
indexintegerPosición del botón en la página. Solo en botones.
extraDatatableEl extraData del punto o de ShowDialog.

La tabla info ​

Segundo argumento de event y serverEvent.

CampoTipoDescripción
idstringId del punto.
dialogIdstring | numberid de la página.
buttonIdstring | numberid del botón.
entityintegerHandle del ped en el cliente que lo envió.
netIdintegerId de red del ped. Solo cuando el ped está en red; los peds que crea un punto son locales y no lo tienen.

Cualquier cliente puede lanzar un evento de servidor en cualquier momento. En su manejador, comprueba al jugador (source), la distancia al NPC y lo que la acción requiera. No te fíes nunca de args ni de info.

Funciones enviadas a través de exports ​

onSelect, canInteract y onInteract son funciones de tu recurso a las que llama Cuxial Interactions. Ten en cuenta:

  • El canInteract de un punto se evalúa mientras el jugador le apunta, reutilizando el resultado durante dialog.conditionInterval milisegundos, y una vez más al seleccionar. Que sea ligero.
  • Un error dentro de cualquiera de ellas no rompe el diálogo. Deja un aviso en la consola del cliente.
  • No guardes ctx después de que la llamada termine.
  • Cuando baste con un evento, usa event o serverEvent: no dependen de referencias a funciones.

Iconos ​

targetIcon recibe una clase Font Awesome, porque lo dibuja tu recurso de target.

El icon de páginas, botones y tiendas recibe uno de estos nombres:

arrow-left, arrow-right, bed, book, book-open, briefcase, car, check, circle-alert, circle-check, circle-play, circle-question-mark, circle-x, clipboard, clipboard-plus, dollar-sign, door-open, fish, folder-open, gamepad-2, hand, hand-coins, hand-heart, heart, hospital, house, id-card, info, key, log-out, message-circle, message-circle-more, messages-square, package, phone, pill, shield, shopping-cart, skull, stethoscope, store, thumbs-up, undo-2, user, user-pen, venetian-mask, wrench, x.

Cualquier otro nombre muestra un bocadillo de diálogo. En la cabecera de una tienda muestra una tienda.

Eventos ​

Cuxial Interactions no tiene eventos propios para otros recursos. Usa los campos event y serverEvent de un botón para recibir los tuyos.

© Cuxial