Documentación

Documentación de Yoga minigame

El minijuego de yoga del modo historia, sacado de su misión y convertido en una actividad de rol que puede empezar cualquiera. Alinea los dos marcadores, mantén la postura mientras el cuerpo entra en ella, y luego inspira y espira con los gatillos. Tres rutinas, catorce posturas, las animaciones originales y los sonidos de respiración del propio juego. Y una puntuación a la que tus propios scripts pueden reaccionar.

  • ESX
  • QBCore
  • Qbox
  • vRP
  • Standalone
01

Instalación

  1. Coloca el recurso

    Descarga el script desde tu cuenta Tebex, copia la carpeta avenida_yoga/ en tu directorio de recursos y añade ensure avenida_yoga a la config del servidor.

  2. Elige el idioma y las rutinas

    Config.Locale acepta cualquiera de los quince códigos que vienen en locales/. Config.EnabledMoves decide qué rutinas pueden empezar los jugadores, y Config.DefaultMove la que se usa cuando no se indica ninguna.

  3. Pon tus spots en el mapa

    Las dos coordenadas de Config.Spots son ejemplos, cámbialas por las tuyas. Cada una lleva su orientación, su rutina y un blip que puedes apagar. Una lista vacía desactiva toda esa parte y su thread.

  4. Apunta las notificaciones a tu stack

    Config.Notif está en auto y detecta ox_lib, okokNotify, QBCore o ESX en ese orden. Fuerza un target si tienes varios, o usa la rama custom de bridges/notif.lua para tu propio sistema.

  5. Engancha la recompensa, o no

    La actividad funciona tal cual, sin una línea de tu código. Cuando quieras que pague algo, escucha avenida_yoga:server:sessionCompleted y lee la puntuación. Es el único punto de integración.

02

Configuración

Convertir una sesión en una recompensa

Un event, lanzado una sola vez al final. La puntuación ya viene calculada: 1 por una rutina terminada, como mucho 0,4 si se abandona, y un 8 por ciento menos por cada postura fallada. Lo que pague lo decides tú.

lua
AddEventHandler('avenida_yoga:server:sessionCompleted', function(src, data)
    -- data.move       'warrior' | 'triangle' | 'sunsalutation'
    -- data.completed  true when the routine went to the end
    -- data.posesBest  poses held
    -- data.poses      poses in the routine
    -- data.fails      poses dropped
    -- data.score      0.0 to 1.0

    if not data.completed then return end

    -- your own reward: stress, stamina, a skill, a payout
    local reward = math.floor(250 * data.score)
end)
03

Exports

Server

  • StartYoga
    exports['avenida_yoga']:StartYoga(src, moveKey?) --> boolean

    Empieza una sesión para un jugador desde tu código de servidor, con la rutina que le pases o con la de por defecto. Devuelve false cuando la rutina no existe o el jugador ya está en una sesión, así que un trabajo o un prop puede reaccionar en lugar de lanzarla a ciegas.

  • IsDoingYoga
    exports['avenida_yoga']:IsDoingYoga(src) --> boolean

    Verdadero mientras el jugador tiene una sesión viva, caducidad incluida. Útil para bloquear una acción de trabajo, un teletransporte o una tienda mientras el minijuego se queda con el control.

Client

  • StartYoga
    exports['avenida_yoga']:StartYoga(moveKey?) --> boolean

    Pide una sesión al servidor desde tu código de cliente. La petición pasa igualmente por el registro del servidor, así que no es una forma de saltarse el control de sesión.

  • IsDoingYoga
    exports['avenida_yoga']:IsDoingYoga() --> boolean

    Verdadero mientras el jugador local está en una sesión. Es la versión de cliente del export de servidor, para todo lo que tenga que reaccionar en el mismo frame.

04

Recetas

Añadir un spot de yoga a tu mapa

Un spot necesita coordenadas y orientación. Lo demás es opcional: la rutina que arranca, el blip, e incluso si aparece la esterilla. Pon move en random para variar, o en menu para que elija el jugador.

lua
-- config/config.lua
Config.Spots = {
    {
        coords  = vector3(-1204.02, -1566.28, 3.63),
        heading = 125.0,
        move    = 'menu',
        blip    = { sprite = 311, colour = 2, scale = 0.7 },
    },
}

Lanzar yoga desde un trabajo o un prop

Un trabajo de bienestar, un patio de prisión, una actividad de desintoxicación: dale la sesión al jugador sin pasar por el comando. Lee el valor devuelto, te dice si el jugador podía empezar.

lua
local started = exports['avenida_yoga']:StartYoga(src, 'sunsalutation')

if not started then
    -- unknown routine, or the player is already in a session
    return
end

Hacer la sesión más fácil, o implacable

Cuatro números controlan toda la dificultad. Sube los intentos y los fallos para un servidor casual, bájalos para algo más cercano al juego base. El tiempo de aguante es lo que impide que alguien se quede clavado en el gatillo.

lua
-- config/config.lua
Config.BreathingAttempts = 3      -- missed cycles before a pose fails
Config.MaxFails          = 5      -- failed poses before the session stops
Config.HoldBreathFailMs  = 15000  -- holding the breath longer fails the pose
Config.MouseGain         = 3.0    -- marker sensitivity on mouse and keyboard

Abrir una rutina ahora y el resto después

Solo se pueden empezar las rutinas listadas en la config, por comando, por export o por spot. Un servidor puede abrir solo con el Guerrero y desbloquear las largas en un evento, sin tocar nada más.

lua
-- config/config.lua
Config.EnabledMoves = { 'warrior' }
Config.DefaultMove  = 'warrior'
05

Preguntas

¿Hace falta un framework?

No. La actividad nunca lee dinero, items, trabajos ni identidad, así que no hay nada que un framework pudiera aportar. El mismo archivo funciona en ESX, QBCore, Qbox, vRP, ox_core o un servidor standalone sin configurar un solo bridge. La única parte que sabe de tu framework es la línea de notificaciones, un archivo abierto con seis ramas.

¿Necesito ox_lib?

No, y aquí es fácil ser preciso: ox_lib se usa exactamente para una cosa, el selector de rutina en un spot puesto en menu. Sin él, ese spot arranca la rutina por defecto. Config.UseOxLib también cambia la carga de assets entre los helpers de ox_lib y las llamadas nativas, y viene apagado, así que el recurso tira de las nativas por defecto.

¿Hay base de datos?

Ninguna, ni archivo SQL tampoco. El servidor guarda las sesiones vivas en memoria, una por jugador, con un temporizador que limpia las que se abandonan. No se escribe nada en ningún sitio. Si quieres un historial por jugador, para eso está el event de final de sesión: guardas lo que te interese, en tu propio esquema.

¿Puede un cliente modificado fingir una sesión perfecta?

No. La sesión la abre el servidor y el resultado se acota antes de llegar a tu event: las posturas mantenidas no pueden pasar de las de la rutina, los fallos no pueden pasar de treinta, el indicador de sesión completada se comprueba con una comparación estricta y la puntuación se recalcula en servidor a partir de esos valores acotados. Lo peor que puede hacer un cliente modificado es declarar una sesión que abrió de verdad.

¿Qué pasa cuando un jugador suelta una postura?

El cuerpo se levanta. El script lee la animación exacta que está reproduciendo el ped y elige la recuperación que le corresponde entre las doce que trae el juego, y cuatro de ellas tienen una variante propia para cuando la postura se suelta pronto. La postura cuenta como fallada, y tras cinco posturas falladas la sesión se para sola.

¿Se puede hacer yoga en cualquier sitio o solo en un spot?

Las dos cosas. El comando funciona en cualquier parte a pie, y los spots son una capa opcional encima, para los sitios que quieras señalizar con una esterilla y un blip. Deja Config.Spots vacío y solo quedan el comando y los exports, sin que el thread de spots llegue a arrancar.

¿Funciona con mando?

Sí, y de hecho se pensó primero para él, como en el juego base. Dos sticks llevan los marcadores y los gatillos superiores la respiración, con vibración mientras los dos marcadores están sobre el objetivo. Con ratón y teclado la misma sesión se juega con WASD y el ratón, y los avisos en pantalla cambian solos según lo último que haya usado el jugador.

¿Cuánto cuesta el script cuando nadie hace yoga?

0.00ms. El bucle de sesión solo existe mientras hay una sesión, y el thread de los spots se duerme cuando no hay ningún jugador cerca. Sin ningún spot declarado, ese thread ni siquiera arranca.

Carrito
Spirit RP
Discord