Pular para o conteúdo principal

Scripting Lua: Primeiros Passos

webapp_banner.jpg

O que vai aprender

Esta pagina ensina a escrever o seu primeiro poder Lua para EliteMobs, desde um ficheiro vazio ate uma habilidade de boss funcional. No final, compreendera hooks, context, tempos de recarga e a estrutura geral de cada ficheiro de poder Lua.

Depois de se sentir confortavel com o basico, continue com as paginas complementares:

  • Hooks e Ciclo de Vida -- nomes de hooks, ordem de execucao e disponibilidade do context
  • Boss e Entidades -- as APIs context.boss, context.player, context.players e context.entities
  • Mundo e Ambiente -- particulas, sons, relampagos, spawning e a API context.world
  • Zonas e Alvos -- zonas Lua nativas, utilitarios de Script para alvos e as APIs context.zones / context.script
  • Exemplos e Padroes -- poderes completos e funcionais para estudar e adaptar
  • Enums e Valores -- links para os Javadocs do Spigot para Particle, Material, PotionEffectType e outras constantes de string
  • Resolucao de Problemas -- erros comuns, dicas de depuracao e a checklist QC
Funcionalidade Experimental

Os ficheiros de poder Lua sao atualmente experimentais. Nomes de hooks, metodos auxiliares e comportamentos ainda podem mudar conforme o EliteMobs evolui, por isso teste cuidadosamente antes de usar num servidor de producao.

Relacao com EliteScript

Lua nao substitui o sistema YAML eliteScript: existente.

  • Use EliteScript quando quiser scripting declarativo baseado em YAML com as paginas existentes de Acoes, Alvos, Zonas, Condicoes, Tempos de Recarga e Vetores Relativos.
  • Use ficheiros de poder Lua quando precisar de variaveis, loops, selecao aleatoria, funcoes auxiliares reutilizaveis, estado persistente por boss e um fluxo de programacao mais tradicional.

Lua tem o seu proprio sistema de alvos e zonas que usa os mesmos nomes de enum e conceitos familiares que ja conhece do EliteScript. A API Script Utilities (context.script) permite criar zonas, alvos e vetores relativos com os mesmos nomes de campo documentados nas paginas EliteScript.


O que sao poderes Lua

Poderes Lua sao ficheiros .lua autonomos que ficam na arvore normal de powers do EliteMobs e sao referenciados exatamente como ficheiros de poder normais.

Poderes de boss vs. scripts de NPC

Esta pagina ensina os poderes Lua de boss. Os scripts Lua de NPC sao uma funcionalidade separada: ficam em plugins/EliteMobs/npc_scripts/, ligam-se atraves de uma lista scripts: na configuracao do NPC e usam hooks especificos de NPC como on_npc_proximity_enter. Veja Scripts de NPC.

Para que servem os poderes Lua

Os poderes Lua destacam-se quando precisa de:

  • Rotacoes de ataque e selecao aleatoria de movimentos
  • Estado persistente entre hooks com context.state
  • Acoes atrasadas e repetidas sem construir tudo com esperas YAML
  • Funcoes auxiliares personalizadas partilhadas num ficheiro
  • Ramificacoes complexas que seriam inconvenientes em EliteScript puro
  • Logica de boss que ainda quer reutilizar definicoes de alvos e zonas estilo EliteScript

Se o seu poder e principalmente "ativar evento, executar algumas acoes com script", os docs existentes de EliteScript continuam a ser a forma mais rapida e clara de o construir. Se o seu poder precisa de fluxo de programa real, Lua e a ferramenta para esse trabalho.


Para quem e esta pagina

Esta pagina foi escrita para tres tipos de leitores:

  • Alguem que ja conhece EliteScript e quer aprender Lua sem aprender "programacao real" de uma so vez
  • Alguem novo no scripting de EliteMobs que precisa de uma referencia completa com nomes exatos
  • Alguem que usa IA para redigir poderes e precisa de detalhes suficientes para saber quando a IA inventou algo falso

Nao precisa de se tornar um programador Lua completo antes de escrever poderes uteis. Para a maioria dos poderes praticos de EliteMobs, so precisa de:

  • Como colocar um hook valido na tabela retornada
  • Como ler valores do context
  • Como parar cedo com if ... then return end
  • Como chamar alguns metodos auxiliares corretamente
  • Como copiar as especificacoes corretas de alvos e zonas dos docs existentes de EliteScript

Modelo Mental: EliteScript vs. Lua

Se conhece EliteScript, esta comparacao e a forma mais rapida de entender poderes Lua:

Se pensa em termos de EliteScriptEm Lua isso normalmente significa
EventsNomes de hooks como on_spawn ou on_boss_damaged_by_player
Cooldownscontext.cooldowns (ver context.cooldowns abaixo)
AcoesChamadas diretas de metodos como context.world:spawn_particle_at_location(...) ou context.script:damage(...)
Alvoscontext.script:target({...}) -- usa os nomes de campo de EliteScript Target
Zonascontext.script:zone({...}) ou auxiliares nativos context.zones -- ver Zonas e Alvos
Vetores relativoscontext.script:relative_vector({...}) ou context.vectors
Fluxo do scriptAs suas proprias instrucoes if de Lua, funcoes auxiliares, temporizadores e estado

A maior diferenca e esta:

  • EliteScript diz o que deveria acontecer em YAML.
  • Lua permite decidir quando, porque e qual ramo deveria executar usando codigo.

Se EliteScript parece "configuracao", Lua parece "configuracao mais tomada de decisao".


Mini introducao a Lua

Nao precisa de ser um especialista em Lua para escrever poderes do EliteMobs. A maioria dos poderes usa apenas um punhado de conceitos: variaveis (local x = 5), funcoes (function foo() end), verificacoes if (if x then ... end), tabelas ({key = value}) e nil (o valor "nada" de Lua). A sintaxe e leve -- sem ponto e virgula, sem chavetas, apenas end para fechar blocos.

Para uma explicacao completa com exemplos, veja o Motor de Scripting Lua do MagmaCore -- Mini introducao a Lua. Essa introducao e partilhada por todos os plugins Nightbreak, por isso aprende-la uma vez aplica-se em todo o lado.


O seu primeiro poder funcional, construido passo a passo

Se e completamente novo, esta e a melhor progressao para a "primeira vitoria".

Antes do Passo 1: Guarde e anexe a um boss

Guarde o ficheiro Lua na pasta normal de poderes do EliteMobs, por exemplo:

plugins/
EliteMobs/
powers/
first_test.lua

Depois adicione esse nome de ficheiro a configuracao do boss usando a lista normal powers::

powers:
- first_test.lua

O loop completo para iniciantes e:

  1. Guardar o ficheiro em plugins/EliteMobs/powers/
  2. Adicionar o nome do ficheiro .lua a lista powers: do boss
  3. Invocar ou recarregar esse boss
  4. Testar o hook que esta a construir

Se precisar de mais contexto sobre ficheiros de boss, listas de poderes ou como os bosses personalizados sao estruturados, veja Criar Bosses Personalizados.

Passo 1: Fazer o ficheiro carregar

return {
api_version = 1,

on_spawn = function(context)
end
}

Se isto carregar sem erros, ja provou:

  • O ficheiro e Lua valido
  • EliteMobs encontrou-o
  • A forma da tabela retornada esta correta
  • on_spawn e um nome de hook valido

Passo 2: Fazer o boss fazer algo visivel

return {
api_version = 1,

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

Agora tem a prova mais importante para iniciantes: o seu hook esta a disparar.

Passo 3: Reagir ao golpe de um jogador

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
}

Isto ensina tres ideias fundamentais:

  • on_boss_damaged_by_player e o nome do hook
  • context.player e o jogador envolvido nesse hook
  • return sai cedo quando os dados necessarios estao em falta

Passo 4: Prevenir spam com um tempo de recarga

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 e o primeiro padrao genuinamente util que a maioria dos autores precisa. Se entender este padrao, ja pode construir muitos poderes praticos.

Passo 5: Adicionar um efeito 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
}

Neste ponto, ja esta a escrever um poder real.


Primeiro fluxo de trabalho real

Ao construir um novo poder Lua do zero, use esta ordem:

  1. Criar o ficheiro e fazer on_spawn funcionar.
  2. Mudar para o hook que realmente quer.
  3. Confirmar que o hook tem os dados esperados, como context.player ou context.event.
  4. Adicionar primeiro uma mensagem ou som, antes de dano ou particulas.
  5. Adicionar tempos de recarga.
  6. Adicionar um efeito de jogo.
  7. So depois disso, adicionar auxiliares, estado, logica de agendador ou zonas.

Essa ordem torna a depuracao dramaticamente mais facil porque so muda uma coisa de cada vez.


Onde ficam os ficheiros Lua

Coloque ficheiros .lua na mesma arvore de pastas que os ficheiros de poder .yml normais:

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

Os poderes Lua sao descobertos automaticamente a partir dos diretorios de poderes que o EliteMobs ja carrega.

Como os bosses referenciam poderes Lua

Os ficheiros de boss continuam a usar a lista normal powers::

powers:
- attack_push.yml
- mycoolpower.lua

Nao e necessario nenhum campo especial. Os poderes Lua nao sao carregados atraves de eliteScript:.

Regras de nomenclatura de ficheiros

  • Os bosses referenciam poderes Lua pelo nome de ficheiro, nao pelo caminho da pasta.
  • O EliteMobs atualmente regista os poderes Lua descobertos apenas pelo nome base.
  • Evite nomes duplicados como powers/fire.lua e powers/bosses/fire.lua, porque um pode sobrescrever o outro durante a descoberta.

Poderes Lua pre-fabricados

Os poderes distribuidos com o proprio EliteMobs sao agora escritos em Lua. Cerca de setenta deles sao escritos em plugins/EliteMobs/powers/ no primeiro arranque -- attack_fire.lua, frost_cone.lua, meteor_shower.lua, shield_wall.lua e muitos mais. Estas sao as melhores referencias disponiveis: abra qualquer ficheiro .lua nessa pasta e leia-o.

Os ficheiros pre-fabricados so sao escritos se estiverem em falta, por isso as suas edicoes sobrevivem a reinicios. Apague um ficheiro para que o EliteMobs regenere a versao de origem.

Os nomes .yml antigos continuam a resolver

As configuracoes de boss que referenciam o antigo attack_fire.yml continuam a funcionar. Quando um poder e procurado por um nome .yml (ou .yaml), o EliteMobs verifica primeiro se existe um ficheiro .lua com o mesmo nome base e usa-o se existir, recorrendo ao nome literal caso contrario. Por outras palavras, um poder .lua substitui o poder .yml com o mesmo nome -- nao precisa de editar ficheiros de boss depois da migracao, e pode sobrepor-se a um poder distribuido colocando o seu proprio .lua ao lado dele.


Contrato minimo do ficheiro

Cada poder Lua deve retornar uma tabela com return. Essa tabela e intencionalmente restrita.

Campos de nivel superior obrigatorios e opcionais

CampoObrigatorioTipoNotas
api_versionSimNumberAtualmente deve ser 1
priorityNaoNumberPrioridade de execucao. Valores mais baixos executam primeiro. Padrao e 0
Chaves de hook suportadasNaoFunctionDeve usar um dos nomes de hook exatos listados na Referencia de Hooks

Regras de validacao

  • O ficheiro deve retornar uma tabela.
  • api_version e obrigatorio e atualmente deve ser 1.
  • priority deve ser numerico se presente.
  • Cada chave de nivel superior adicional deve ser um nome de hook suportado.
  • Cada chave de hook deve apontar para uma funcao.
  • Chaves de nivel superior desconhecidas sao rejeitadas.

Isto significa que funcoes auxiliares e constantes locais devem ficar acima do return final, nao dentro da tabela retornada a menos que sejam hooks reais.


Templates para copiar e colar

Menor poder Lua valido

return {
api_version = 1,

on_spawn = function(context)
end
}

Template inicial recomendado

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
}

Layout para ficheiros maiores

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

Hooks sao funcoes com nomes especiais na tabela que retorna. EliteMobs chama-os quando algo acontece -- o boss aparece, recebe dano, entra em combate, etc. Ja viu on_spawn e on_boss_damaged_by_player no tutorial acima.

Os hooks mais comuns para comecar sao on_spawn, on_boss_damaged_by_player, on_enter_combat e on_exit_combat. Para a lista completa de todos os hooks, que chaves de context estao disponiveis em cada um e como funciona a ordem de execucao, consulte Hooks e Ciclo de Vida.


O que e context?

Cada funcao de hook recebe um argumento chamado context. Pense nele como uma caixa de ferramentas que o EliteMobs lhe entrega cada vez que algo acontece -- contem tudo o que precisa para interagir com o boss, o jogador, o mundo, os tempos de recarga e mais.

on_boss_damaged_by_player = function(context)
-- context.boss = the boss that was hit
-- context.player = the player who hit it
-- context.world = tools for spawning particles, sounds, etc.
-- context.cooldowns = cooldown management
-- context.state = your own persistent storage
end

Voce nao cria context -- o EliteMobs cria-o e passa-o ao seu hook. Basta ler dele e chamar metodos nele.

informação

context e criado de novo para cada chamada de hook, exceto context.state que persiste durante toda a vida do boss. Isto significa que pode armazenar dados em context.state e le-los mais tarde num hook diferente.


APIs chave de context

Aqui estao as APIs mais importantes que usara de context:

  • context.state -- Uma tabela Lua simples que persiste durante a vida do boss. Use-a para guardar numeros de fase, IDs de tarefas, flags e tudo o que precisa de lembrar entre hooks. So context.state persiste -- todas as outras tabelas de context sao criadas de novo em cada chamada.

  • context.log -- Registo na consola com log:info(msg), log:warn(msg) e log:debug(msg). Inestimavel durante o desenvolvimento.

  • context.cooldowns -- Tempos de recarga locais por poder e globais por boss. O metodo chave e cooldowns:check_local(key, ticks) que verifica E define um cooldown atomicamente. Consulte a pagina Hooks e Ciclo de Vida para a API completa de cooldowns.

  • context.scheduler -- Tarefas atrasadas e repetidas com scheduler:run_after(ticks, callback) e scheduler:run_every(ticks, callback). Os callbacks recebem um context fresco -- use sempre o parametro do callback, nao o context externo. Cancele tarefas repetidas em on_exit_combat. Consulte Hooks e Ciclo de Vida para detalhes.

  • context.boss / context.player -- O boss e o jogador envolvidos no evento atual. Consulte Boss e Entidades para todos os campos e metodos.

  • context.world -- Gerar particulas, entidades, sons, relampagos, blocos. Consulte Mundo e Ambiente.

  • context.zones / context.script -- Geometria de zonas, alvos, dano, particulas. Consulte Zonas e Alvos.


Sintaxe de metodos: : vs. .

Para uma explicação de : e ., consulte o Motor de Scripting Lua do MagmaCore. Os métodos de entidades e os serviços partilhados aceitam ambas as formas. context.event.set_damage_amount(value) e context.event.multiply_damage_amount(multiplier) exigem ponto; os dois pontos passam a tabela do evento como primeiro argumento.


Proximos passos

Agora que conhece o basico, explore o resto da documentacao de scripting Lua:

  • Hooks e Ciclo de Vida -- nomes de hooks, ordem de execucao e que chaves de context estao disponiveis em cada hook
  • Boss e Entidades -- context.boss, context.player, context.players, context.entities e context.event
  • Mundo e Ambiente -- particulas, sons, relampagos, spawning e context.world
  • Zonas e Alvos -- zonas Lua nativas, utilitarios de Script para alvos/zonas/particulas e vetores relativos
  • Exemplos e Padroes -- poderes completos e funcionais com explicacoes
  • Enums e Valores -- links para os Javadocs do Spigot para Particle, Material, PotionEffectType e mais
  • Resolucao de Problemas -- erros comuns, dicas de depuracao e checklist QC
  • Scripts de NPC -- scripts Lua para NPCs, com a tabela context.npc

Para scripting baseado em YAML, as paginas de EliteScript continuam a ser a referencia canonica: