Saltar al contenido principal

Scripting Lua: Primeros Pasos

webapp_banner.jpg

Lo que aprenderás

Esta página te enseña a escribir tu primer poder Lua para EliteMobs, desde un archivo vacío hasta una habilidad de jefe funcional. Al final comprenderás los hooks, el context, los tiempos de reutilización y la estructura general de cada archivo de poder Lua.

Una vez que te sientas cómodo con los conceptos básicos, continúa con las páginas complementarias:

  • Hooks y Ciclo de Vida -- nombres de hooks, orden de ejecución y disponibilidad del context
  • Jefe y Entidades -- las APIs context.boss, context.player, context.players y context.entities
  • Mundo y Entorno -- partículas, sonidos, rayos, aparición y la API context.world
  • Zonas y Objetivos -- zonas nativas de Lua, utilidades de Script para objetivos y las APIs context.zones / context.script
  • Ejemplos y Patrones -- poderes completos y funcionales que puedes estudiar y adaptar
  • Enums y Valores -- enlaces a los Javadocs de Spigot para Particle, Material, PotionEffectType y otras constantes de cadena
  • Solución de Problemas -- errores comunes, consejos de depuración y la lista de verificación QC
Característica Experimental

Los archivos de poder Lua son actualmente experimentales. Los nombres de hooks, métodos auxiliares y comportamientos aún pueden cambiar a medida que EliteMobs evoluciona, así que prueba cuidadosamente antes de usarlos en un servidor de producción.

Relación con EliteScript

Lua no reemplaza el sistema YAML eliteScript: existente.

  • Usa EliteScript cuando quieras scripting declarativo basado en YAML con las páginas existentes de Acciones, Objetivos, Zonas, Condiciones, Tiempos de Reutilización y Vectores Relativos.
  • Usa archivos de poder Lua cuando necesites variables, bucles, selección aleatoria, funciones auxiliares reutilizables, estado persistente por jefe y un flujo de programación más tradicional.

Lua tiene su propio sistema de objetivos y zonas que usa los mismos nombres de enum y conceptos familiares que ya conoces de EliteScript. La API de Script Utilities (context.script) te permite crear zonas, objetivos y vectores relativos con los mismos nombres de campo documentados en las páginas de EliteScript.


Qué son los poderes Lua

Los poderes Lua son archivos .lua independientes que se encuentran en el árbol normal de powers de EliteMobs y se referencian exactamente como los archivos de poder normales.

Para qué son buenos los poderes Lua

Los poderes Lua brillan cuando necesitas:

  • Rotaciones de ataque y selección aleatoria de movimientos
  • Estado persistente entre hooks con context.state
  • Acciones retrasadas y repetidas sin construir todo con esperas YAML
  • Funciones auxiliares personalizadas compartidas dentro de un archivo
  • Ramificaciones complejas que serían incómodas en EliteScript puro
  • Lógica de jefe que aún quiere reutilizar definiciones de objetivos y zonas estilo EliteScript

Si tu poder es principalmente "activar evento, ejecutar unas pocas acciones con script", los documentos existentes de EliteScript siguen siendo la forma más rápida y clara de construirlo. Si tu poder necesita flujo de programa real, Lua es la herramienta para ese trabajo.


Para quién es esta página

Esta página está escrita para tres tipos de lectores:

  • Alguien que ya conoce EliteScript y quiere aprender Lua sin aprender "programación real" de golpe
  • Alguien que es nuevo en el scripting de EliteMobs y necesita una referencia completa con nombres exactos
  • Alguien que usa IA para redactar poderes y necesita suficiente detalle para saber cuándo la IA inventó algo falso

No necesitas convertirte en un desarrollador Lua completo antes de escribir poderes útiles. Para la mayoría de los poderes prácticos de EliteMobs, lo único que realmente necesitas es:

  • Cómo colocar un hook válido en la tabla devuelta
  • Cómo leer valores de context
  • Cómo detenerte temprano con if ... then return end
  • Cómo llamar a algunos métodos auxiliares correctamente
  • Cómo copiar las especificaciones correctas de objetivos y zonas de los documentos existentes de EliteScript

Modelo Mental: EliteScript vs. Lua

Si conoces EliteScript, esta comparación es la forma más rápida de entender los poderes Lua:

Si piensas en términos de EliteScriptEn Lua eso normalmente significa
EventsNombres de hooks como on_spawn o on_boss_damaged_by_player
Cooldownscontext.cooldowns (ver context.cooldowns más abajo)
AccionesLlamadas directas a métodos como context.world:spawn_particle_at_location(...) o context.script:damage(...)
Objetivoscontext.script:target({...}) -- usa los nombres de campo de EliteScript Target
Zonascontext.script:zone({...}) o ayudantes nativos context.zones -- ver Zonas y Objetivos
Vectores relativoscontext.script:relative_vector({...}) o context.vectors
Flujo del scriptTus propias sentencias if de Lua, funciones auxiliares, temporizadores y estado

La mayor diferencia es esta:

  • EliteScript dice qué debería pasar en YAML.
  • Lua te permite decidir cuándo, por qué y qué rama debería ejecutarse usando código.

Así que si EliteScript se siente como "configuración", Lua se siente como "configuración más toma de decisiones".


Mini introducción a Lua

No necesitas ser un experto en Lua para escribir poderes de EliteMobs. La mayoría de los poderes solo usan un puñado de conceptos: variables (local x = 5), funciones (function foo() end), comprobaciones if (if x then ... end), tablas ({key = value}) y nil (el valor "nada" de Lua). La sintaxis es ligera -- sin punto y coma, sin llaves, solo end para cerrar bloques.

Para un recorrido completo con ejemplos, consulta el Motor de Scripting Lua de MagmaCore -- Mini introducción a Lua. Esa introducción es compartida entre todos los plugins de Nightbreak, así que aprenderla una vez aplica en todas partes.


Tu primer poder funcional, construido paso a paso

Si eres completamente nuevo, esta es la mejor progresión para la "primera victoria".

Antes del Paso 1: Guárdalo y adjúntalo a un jefe

Guarda el archivo Lua en la carpeta normal de poderes de EliteMobs, por ejemplo:

plugins/
EliteMobs/
powers/
first_test.lua

Luego añade ese nombre de archivo a la configuración del jefe usando la lista normal powers::

powers:
- first_test.lua

Así que el bucle completo para principiantes es:

  1. Guardar el archivo en plugins/EliteMobs/powers/
  2. Añadir el nombre de archivo .lua a la lista powers: del jefe
  3. Invocar o recargar ese jefe
  4. Probar el hook que estás construyendo actualmente

Si necesitas más contexto sobre archivos de jefe, listas de poderes o cómo están estructurados los jefes personalizados, consulta Crear Jefes Personalizados. Esa página cubre la configuración de jefes en detalle, incluyendo cómo funciona la lista powers:.

Paso 1: Hacer que el archivo cargue

return {
api_version = 1,

on_spawn = function(context)
end
}

Si esto carga sin errores, ya has demostrado:

  • El archivo es Lua válido
  • EliteMobs lo encontró
  • La forma de la tabla devuelta es correcta
  • on_spawn es un nombre de hook válido

Paso 2: Hacer que el jefe haga algo visible

return {
api_version = 1,

on_spawn = function(context)
context.boss:play_sound_at_self("entity.blaze.ambient", 1.0, 1.0)
end
}

Ahora tienes la prueba más importante para principiantes: tu hook se está ejecutando.

Paso 3: Reaccionar al golpe de un jugador

return {
api_version = 1,

on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end

context.player:send_message("&eYou hit the boss.")
end
}

Esto enseña tres ideas fundamentales:

  • on_boss_damaged_by_player es el nombre del hook
  • context.player es el jugador involucrado en ese hook
  • return sale temprano cuando faltan los datos que necesitas

Paso 4: Prevenir spam con un tiempo de reutilización

return {
api_version = 1,

on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end

if not context.cooldowns:local_ready("hello_message") then
return
end

context.player:send_message("&eYou woke up the boss.")
context.cooldowns:set_local(60, "hello_message")
end
}

Este es el primer patrón genuinamente útil que la mayoría de los autores necesitan. Si entiendes este patrón, ya puedes construir muchos poderes prácticos.

Paso 5: Añadir un efecto real

return {
api_version = 1,

on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end

if not context.cooldowns:local_ready("shock") then
return
end

context.player:send_message("&cStatic jumps from the boss into your armor!")
context.world:strike_lightning_at_location(context.player.current_location)
context.cooldowns:set_local(100, "shock")
end
}

En este punto, ya estás escribiendo un poder real.


Primer flujo de trabajo real

Al construir un nuevo poder Lua desde cero, usa este orden:

  1. Crear el archivo y hacer que on_spawn funcione.
  2. Cambiar al hook que realmente quieres.
  3. Confirmar que el hook tiene los datos que esperas, como context.player o context.event.
  4. Añadir primero un mensaje o sonido, antes del daño o las partículas.
  5. Añadir tiempos de reutilización.
  6. Añadir un efecto de juego.
  7. Solo después de eso, añadir auxiliares, estado, lógica de planificador o zonas.

Ese orden hace que la depuración sea dramáticamente más fácil porque solo cambia una cosa a la vez.


Dónde van los archivos Lua

Coloca los archivos .lua en el mismo árbol de carpetas que los archivos de poder .yml normales:

plugins/
EliteMobs/
powers/
mycoolpower.lua
attack_push.yml
subfolder/
myotherpower.lua

Los poderes Lua se descubren automáticamente desde los directorios de poderes que EliteMobs ya carga.

Cómo los jefes referencian poderes Lua

Los archivos de jefe siguen usando la lista normal powers::

powers:
- attack_push.yml
- mycoolpower.lua

No se requiere ningún campo especial. Los poderes Lua no se cargan a través de eliteScript:.

Reglas de nomenclatura de archivos

  • Los jefes referencian poderes Lua por nombre de archivo, no por ruta de carpeta.
  • EliteMobs actualmente registra los poderes Lua descubiertos solo por nombre base.
  • Evita nombres duplicados como powers/fire.lua y powers/bosses/fire.lua, porque uno puede sobrescribir al otro durante el descubrimiento.

Poderes Lua prefabricados

EliteMobs viene con docenas de poderes Lua prefabricados en la carpeta powers, como attack_fire.lua, frost_cone.lua, meteor_shower.lua y muchos más. Son excelentes referencias para estudiar — simplemente abre cualquier archivo .lua en tu directorio plugins/EliteMobs/powers/. Por compatibilidad retroactiva, los poderes prefabricados también se registran bajo sus nombres .yml heredados.


Contrato mínimo del archivo

Cada poder Lua debe devolver una tabla con return. Esa tabla es intencionalmente estricta.

Campos de nivel superior requeridos y opcionales

CampoRequeridoTipoNotas
api_versionNumberActualmente debe ser 1
priorityNoNumberPrioridad de ejecución. Los valores más bajos se ejecutan primero. Por defecto es 0
Claves de hook soportadasNoFunctionDebe usar uno de los nombres de hook exactos listados en la Referencia de Hooks

Reglas de validación

  • El archivo debe devolver una tabla.
  • api_version es requerido y actualmente debe ser 1.
  • priority debe ser numérico si está presente.
  • Cada clave de nivel superior adicional debe ser un nombre de hook soportado.
  • Cada clave de hook debe apuntar a una función.
  • Las claves de nivel superior desconocidas son rechazadas.

Esto significa que las funciones auxiliares y las constantes locales deben ubicarse encima del return final, no dentro de la tabla devuelta a menos que sean hooks reales.


Plantillas para copiar y pegar

Poder Lua válido más pequeño

return {
api_version = 1,

on_spawn = function(context)
end
}

Plantilla inicial recomendada

local ATTACK_COOLDOWN = "my_attack"

local function can_run_attack(context)
return context.cooldowns:local_ready(ATTACK_COOLDOWN)
and context.cooldowns:global_ready()
end

local function run_attack(context)
context.boss:play_sound_at_self("entity.blaze.shoot", 1.0, 1.0)
context.cooldowns:set_local(100, ATTACK_COOLDOWN)
context.cooldowns:set_global(20)
end

return {
api_version = 1,
priority = 0,

on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end

if not can_run_attack(context) then
return
end

run_attack(context)
end
}

Diseño para archivos más grandes

local CONSTANT_NAME = "value"

local function helper_function(context)
end

local function another_helper(context, value)
end

return {
api_version = 1,
priority = 0,

on_spawn = function(context)
end,

on_enter_combat = function(context)
end,

on_boss_damaged_by_player = function(context)
end,

on_exit_combat = function(context)
end
}

Hooks

Los hooks son funciones con nombres especiales en la tabla que devuelves. EliteMobs los llama cuando algo sucede — el jefe aparece, recibe daño, entra en combate, etc. Ya viste on_spawn y on_boss_damaged_by_player en el tutorial anterior.

Los hooks más comunes para empezar son on_spawn, on_boss_damaged_by_player, on_enter_combat y on_exit_combat. Para la lista completa de todos los hooks, qué claves de context están disponibles en cada uno y cómo funciona el orden de ejecución, consulta Hooks y Ciclo de Vida.


¿Qué es context?

Cada función de hook recibe un argumento llamado context. Piensa en él como una caja de herramientas que EliteMobs te entrega cada vez que algo sucede — contiene todo lo que necesitas para interactuar con el jefe, el jugador, el mundo, los tiempos de reutilización y más.

on_boss_damaged_by_player = function(context)
-- context.boss = el jefe que fue golpeado
-- context.player = el jugador que lo golpeó
-- context.world = herramientas para generar partículas, sonidos, etc.
-- context.cooldowns = gestión de tiempos de reutilización
-- context.state = tu propio almacenamiento persistente
end

Tú no creas context — EliteMobs lo crea y lo pasa a tu hook. Simplemente lees de él y llamas métodos en él.

info

context se crea nuevo para cada llamada de hook, excepto context.state que persiste durante toda la vida del jefe. Esto significa que puedes almacenar datos en context.state y leerlos más tarde en un hook diferente.


APIs clave de context

Aquí están las APIs más importantes que usarás de context:

  • context.state — Una tabla Lua simple que persiste durante la vida del jefe. Úsala para almacenar números de fase, IDs de tareas, banderas y cualquier cosa que necesites recordar entre hooks. Solo context.state persiste — todas las demás tablas de context se crean nuevas en cada llamada.

  • context.log — Registro en consola con log:info(msg), log:warn(msg) y log:debug(msg). Invaluable durante el desarrollo.

  • context.cooldowns — Tiempos de reutilización locales por poder y globales por jefe. El método clave es cooldowns:check_local(key, ticks) que verifica Y establece un cooldown atómicamente. Consulta la página Hooks y Ciclo de Vida para la API completa de cooldowns.

  • context.scheduler — Tareas retrasadas y repetidas con scheduler:run_after(ticks, callback) y scheduler:run_every(ticks, callback). Los callbacks reciben un context fresco — siempre usa el parámetro del callback, no el context externo. Cancela las tareas repetidas en on_exit_combat. Consulta Hooks y Ciclo de Vida para detalles.

  • context.boss / context.player — El jefe y el jugador involucrados en el evento actual. Consulta Jefe y Entidades para todos los campos y métodos.

  • context.world — Generar partículas, entidades, sonidos, rayos, bloques. Consulta Mundo y Entorno.

  • context.zones / context.script — Geometría de zonas, objetivos, daño, partículas. Consulta Zonas y Objetivos.


Sintaxis de métodos: : vs. .

Para una explicación de la sintaxis de métodos : vs . en Lua, consulta la página del Motor de Scripting Lua de MagmaCore. La API de EliteMobs acepta ambas formas.


Próximos pasos

Ahora que conoces los conceptos básicos, explora el resto de la documentación de scripting Lua:

  • Hooks y Ciclo de Vida -- nombres de hooks, orden de ejecución y qué claves de context están disponibles en cada hook
  • Jefe y Entidades -- context.boss, context.player, context.players, context.entities y context.event
  • Mundo y Entorno -- partículas, sonidos, rayos, aparición y context.world
  • Zonas y Objetivos -- zonas nativas de Lua, utilidades de Script para objetivos/zonas/partículas y vectores relativos
  • Ejemplos y Patrones -- poderes completos y funcionales con explicaciones
  • Enums y Valores -- enlaces a los Javadocs de Spigot para Particle, Material, PotionEffectType y más
  • Solución de Problemas -- errores comunes, consejos de depuración y una lista de verificación QC

Para scripting basado en YAML, las páginas de EliteScript siguen siendo la referencia canónica: