Scripting Lua: Primeros Pasos
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.playersycontext.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
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.
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 EliteScript | En Lua eso normalmente significa |
|---|---|
| Events | Nombres de hooks como on_spawn o on_boss_damaged_by_player |
| Cooldowns | context.cooldowns (ver context.cooldowns más abajo) |
| Acciones | Llamadas directas a métodos como context.world:spawn_particle_at_location(...) o context.script:damage(...) |
| Objetivos | context.script:target({...}) -- usa los nombres de campo de EliteScript Target |
| Zonas | context.script:zone({...}) o ayudantes nativos context.zones -- ver Zonas y Objetivos |
| Vectores relativos | context.script:relative_vector({...}) o context.vectors |
| Flujo del script | Tus 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:
- Guardar el archivo en
plugins/EliteMobs/powers/ - Añadir el nombre de archivo
.luaa la listapowers:del jefe - Invocar o recargar ese jefe
- 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_spawnes 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_playeres el nombre del hookcontext.playeres el jugador involucrado en ese hookreturnsale 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:
- Crear el archivo y hacer que
on_spawnfuncione. - Cambiar al hook que realmente quieres.
- Confirmar que el hook tiene los datos que esperas, como
context.playerocontext.event. - Añadir primero un mensaje o sonido, antes del daño o las partículas.
- Añadir tiempos de reutilización.
- Añadir un efecto de juego.
- 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.luaypowers/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
| Campo | Requerido | Tipo | Notas |
|---|---|---|---|
api_version | Sí | Number | Actualmente debe ser 1 |
priority | No | Number | Prioridad de ejecución. Los valores más bajos se ejecutan primero. Por defecto es 0 |
| Claves de hook soportadas | No | Function | Debe 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_versiones requerido y actualmente debe ser1.prioritydebe 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.
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. Solocontext.statepersiste — todas las demás tablas de context se crean nuevas en cada llamada. -
context.log— Registro en consola conlog:info(msg),log:warn(msg)ylog:debug(msg). Invaluable durante el desarrollo. -
context.cooldowns— Tiempos de reutilización locales por poder y globales por jefe. El método clave escooldowns: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 conscheduler:run_after(ticks, callback)yscheduler:run_every(ticks, callback). Los callbacks reciben un context fresco — siempre usa el parámetro del callback, no elcontextexterno. Cancela las tareas repetidas enon_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.entitiesycontext.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:
