メインコンテンツまでスキップ

Luaスクリプティング:はじめに

webapp_banner.jpg

学べること

このページでは、EliteMobs用の最初のLuaパワーを書く方法を、空のファイルから動作するボス能力まで段階的に解説します。最後にはフック、コンテキスト、クールダウン、およびすべてのLuaパワーファイルの一般的な構造を理解できるようになります。

基本に慣れたら、以下の関連ページに進んでください:

まだ進化中です

EliteMobs自身の同梱パワーはLuaで書かれているため、このシステムは実運用されています — ただし、ヘルパーメソッド名や動作はリリース間で変更される可能性があります。カスタムのLuaパワーを本番へ投入する前にステージングサーバーでテストし、更新後はこのページを再確認してください。

EliteScriptとの関係

Luaは既存のeliteScript: YAMLシステムを置き換えません。また、EliteScriptは非推奨ではありません。

  • 既存のアクションターゲットゾーン条件クールダウン相対ベクトルページを使った宣言的なYAMLベースのスクリプティングが必要な場合はEliteScriptを使用してください。
  • 変数、ループ、ランダム選択、再利用可能なヘルパー関数、ボスごとの永続状態、より伝統的なプログラミングフローが必要な場合はLuaパワーファイルを使用してください。

この2つは見た目以上に密接に関係しています。Script Utilities API(context.script)は、渡した spec テーブルを実際のEliteScriptエンジンへ引き渡します。そのため、EliteScriptページで文書化されているターゲット、ゾーン、相対ベクトル、パーティクルの各フィールドは、Luaからそのまま機能します。EliteScriptの学習に費やした時間は完全に活かされます。


Luaパワーとは

Luaパワーは、EliteMobsの通常のpowersディレクトリツリーに配置される独立した.luaファイルで、通常のパワーファイルと全く同じように参照されます。

ボスパワーとNPCスクリプトの違い

このページで扱うのはボス用のLuaパワーです。NPCのLuaスクリプトは別の機能で、plugins/EliteMobs/npc_scripts/に配置し、NPC設定のscripts:リストを通じて割り当て、on_npc_proximity_enterのようなNPC専用のフックを使用します。NPCスクリプトを参照してください。

Luaパワーが得意なこと

Luaパワーは以下のような場合に力を発揮します:

  • 攻撃ローテーションとランダムな技選択
  • context.stateを使ったフック間の永続状態
  • YAMLの待機で全てを構築せずに行う遅延・繰り返しアクション
  • 1ファイル内で共有されるカスタムヘルパー関数
  • 純粋なEliteScriptでは扱いにくい複雑な分岐
  • EliteScriptスタイルのターゲティングとゾーン定義を再利用したいボスロジック

パワーが主に「イベントをトリガーし、いくつかのスクリプトアクションを実行する」だけであれば、既存のEliteScriptドキュメントが最も速く明確な構築方法です。パワーに本格的なプログラムフローが必要な場合は、Luaがそのためのツールです。


このページの対象読者

このページは3種類の読者向けに書かれています:

  • EliteScriptを既に知っていて、「本格的なプログラミング」を一度に全て学ぶことなくLuaを学びたい人
  • EliteMobsスクリプティングが初めてで、正確な名前の完全なリファレンスが必要な人
  • AIを使ってパワーを作成し、AIが偽の情報を生成した時にそれを見分けるための十分な詳細が必要な人

有用なパワーを書く前に、完全なLua開発者になる必要はありません。ほとんどの実用的なEliteMobsパワーに必要なのは:

  • 返されるテーブルに有効なフックを配置する方法
  • contextから値を読み取る方法
  • if ... then return endで早期終了する方法
  • いくつかのヘルパーメソッドを正確に呼び出す方法
  • 既存のEliteScriptドキュメントから適切なターゲットとゾーンの仕様をコピーする方法

メンタルモデル:EliteScript vs. Lua

EliteScriptを知っている場合、この比較がLuaパワーを理解する最速の方法です:

EliteScriptの用語で考える場合Luaでは通常以下を意味する
Eventson_spawnon_boss_damaged_by_playerのようなフック名
Cooldownscontext.cooldowns(下記のcontext.cooldownsを参照)
Actionscontext.world:spawn_particle_at_location(...)context.script:damage(...)のような直接メソッド呼び出し
Targetscontext.script:target({...}) -- EliteScript Targetのフィールド名を使用
Zonescontext.script:zone({...})またはネイティブcontext.zonesヘルパー -- ゾーンとターゲティングを参照
Relative vectorscontext.script:relative_vector({...})またはcontext.vectors
Script flow自分自身のLuaのif文、ヘルパー関数、タイマー、状態

最大の違いは以下の通りです:

  • EliteScriptはYAMLで何が起こるべきかを記述します。
  • Luaはコードを使っていつなぜどの分岐が実行されるべきかを決定できます。

EliteScriptが「設定」のように感じるなら、Luaは「設定+意思決定」のように感じます。


Luaミニ入門

EliteMobsのパワーを書くために、Luaの専門家である必要はありません。ほとんどのパワーが使うのはほんの一握りの概念だけです。変数local x = 5)、関数function foo() end)、ifチェックif x then ... end)、テーブル{key = value})、そしてnil(Luaにおける「何もない」を表す値)です。構文は軽量で、セミコロンも波括弧も不要、ブロックを閉じるのはendだけです。

例を交えた完全な解説は、**MagmaCore Luaスクリプティングエンジン — Luaミニ入門**を参照してください。この入門はすべてのNightbreakプラグインで共通なので、一度学べばどこでも活かせます。


最初の動作するパワー、ステップバイステップ

完全に初めての場合、これが「最初の成功」への最適な進行順です。

ステップ1の前:保存してボスに割り当てる

Luaファイルを通常のEliteMobsパワーフォルダーに保存します。例:

plugins/
EliteMobs/
powers/
first_test.lua

そのファイル名を通常のpowers:リストを使ってボス設定に追加します:

powers:
- first_test.lua

初心者の完全なループは:

  1. plugins/EliteMobs/powers/にファイルを保存
  2. .luaファイル名をボスのpowers:リストに追加
  3. そのボスをスポーンまたはリロード
  4. 現在構築中のフックをテスト

ボスファイル、パワーリスト、カスタムボスの構造についてより詳しい背景が必要な場合は、カスタムボスの作成を参照してください。そのページでは、powers:リストの動作を含め、ボスのセットアップを詳しく解説しています。

ステップ1:ファイルをロードさせる

return {
api_version = 1,

on_spawn = function(context)
end
}

これがエラーなくロードされれば、既に以下を証明しています:

  • ファイルは有効なLuaである
  • EliteMobsがファイルを見つけた
  • 返されるテーブルの形状が正しい
  • on_spawnは有効なフック名である

ステップ2:ボスに目に見えることをさせる

return {
api_version = 1,

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

これで最も重要な初心者の証明が得られます:フックが発動しています。

ステップ3:プレイヤーのヒットに反応する

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
}

これは3つの核心的な概念を教えます:

  • on_boss_damaged_by_playerがフック名
  • context.playerがそのフックに関わるプレイヤー
  • returnは必要なデータがない場合に早期終了する

ステップ4:クールダウンでスパムを防ぐ

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
}

これはほとんどの作者が最初に必要とする本当に実用的なパターンです。このパターンを理解すれば、多くの実用的なパワーを構築できます。

ステップ5:本物のエフェクトを追加する

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
}

この時点で、既に本物のパワーを書いています。


最初の実践的ワークフロー

新しいLuaパワーを一から構築する際は、この順序を使ってください:

  1. ファイルを作成し、on_spawnを動作させる。
  2. 実際に使いたいフックに変更する。
  3. フックにcontext.playercontext.eventなど期待するデータがあることを確認する。
  4. ダメージやパーティクルの前に、まずメッセージやサウンドを追加する。
  5. クールダウンを追加する。
  6. ゲームプレイエフェクトを1つ追加する。
  7. その後に初めて、ヘルパー、状態、スケジューラーロジック、ゾーンを追加する。

この順序により、一度に1つのことだけが変わるため、デバッグが大幅に容易になります。


Luaファイルの配置場所

.luaファイルを通常のパワー.ymlファイルと同じフォルダーツリーに配置します:

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

LuaパワーはEliteMobsが既にロードするパワーディレクトリから自動検出されます。

ボスがLuaパワーを参照する方法

ボスファイルは引き続き通常のpowers:リストを使用します:

powers:
- attack_push.yml
- mycoolpower.lua

特別なフィールドは不要です。LuaパワーはeliteScript:を通してロードされません。

ファイル命名規則

  • ボスはLuaパワーをファイル名で参照し、フォルダーパスではありません。
  • EliteMobsは現在、検出されたLuaパワーをベース名のみで登録します。
  • powers/fire.luapowers/bosses/fire.luaのような重複名は避けてください。検出時に一方が他方を上書きする可能性があります。

既製のLuaパワー

EliteMobs自身の同梱パワーは、現在Luaで書かれています。初回起動時に約70個が plugins/EliteMobs/powers/ へ書き出されます — attack_fire.luafrost_cone.luameteor_shower.luashield_wall.lua などです。これらは入手できる最良のリファレンスです。そのディレクトリの任意の .lua ファイルを開いて読んでみてください。

既製ファイルは存在しない場合にのみ書き出されるため、加えた編集は再起動をまたいで維持されます。ファイルを削除すれば、EliteMobsが標準版を再生成します。

レガシーの .yml 名も引き続き解決されます

古い attack_fire.yml を参照しているボス設定はそのまま機能します。パワーが .yml(または .yaml)の名前で参照された場合、EliteMobsはまず同じベース名の .lua ファイルを探し、存在すればそれを使用し、なければ元の名前にフォールバックします。つまり、.lua パワーは同名の .yml パワーを上書きします — 移行後にボスファイルを編集する必要はなく、同梱パワーの隣に自分の .lua を置くだけで上書きできます。


最小ファイル契約

すべてのLuaパワーはreturnでテーブルを返す必要があります。このテーブルは意図的に厳格です。

必須およびオプションのトップレベルフィールド

フィールド必須備考
api_versionはいNumber現在は1でなければならない
priorityいいえNumber実行優先度。低い値が先に実行される。デフォルトは0
サポートされるフックキーいいえFunctionフックリファレンスに記載されている正確なフック名の1つを使用する必要がある

バリデーションルール

  • ファイルはテーブルを返す必要があります
  • api_versionは必須で、現在は1でなければなりません。
  • priorityは存在する場合、数値でなければなりません。
  • 追加のトップレベルキーはすべてサポートされるフック名でなければなりません。
  • すべてのフックキーは関数を指している必要があります。
  • 不明なトップレベルキーは拒否されます。

ヘルパー関数とローカル定数は最終的なreturnに配置し、実際のフックでない限り返されるテーブルの内部に置かないでください。


コピー&ペーストスターターテンプレート

最小の有効なLuaパワー

return {
api_version = 1,

on_spawn = function(context)
end
}

推奨スターターテンプレート

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
}

大きなファイルのレイアウト

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
}

フック

フックは、返すテーブル内の特別な名前の関数です。EliteMobsは何かが起こったとき(ボスがスポーンする、ダメージを受ける、戦闘に入るなど)にそれらを呼び出します。上記のチュートリアルでon_spawnon_boss_damaged_by_playerを既に見ました。

最も一般的な開始フックはon_spawnon_boss_damaged_by_playeron_enter_combaton_exit_combatです。すべてのフックの完全なリスト、各フックで利用可能なコンテキストキー、実行順序の仕組みについては、フックとライフサイクルを参照してください。


contextとは?

すべてのフック関数はcontextと呼ばれる1つの引数を受け取ります。これは何かが起こるたびにEliteMobsがあなたに渡すツールボックスと考えてください。ボス、プレイヤー、ワールド、クールダウンなどとやり取りするために必要なすべてが含まれています。

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

contextは自分で作成しません。EliteMobsがそれを作成してフックに渡します。そこから読み取り、メソッドを呼び出すだけです。

備考

contextはフック呼び出しごとに新しく作成されます。ただしcontext.stateはボスの全ライフタイムにわたって永続します。これにより、context.stateにデータを保存し、別のフックで後から読み取ることができます。


主要なcontext API

contextから使用する最も重要なAPIは以下の通りです:

  • context.state -- ボスのライフタイム中永続する単純なLuaテーブル。フェーズ番号、タスクID、フラグ、フック間で記憶する必要があるものを保存するために使用します。context.stateのみが永続します。他のすべてのコンテキストテーブルは呼び出しごとに新しく作成されます。

  • context.log -- log:info(msg)log:warn(msg)log:debug(msg)によるコンソールログ。開発中に非常に有用です。

  • context.cooldowns -- パワーごとのローカルクールダウンとボスごとのグローバルクールダウン。キーメソッドはcooldowns:check_local(key, ticks)で、クールダウンをアトミックにチェックしてセットします。完全なクールダウンAPIについてはフックとライフサイクルページを参照してください。

  • context.scheduler -- scheduler:run_after(ticks, callback)scheduler:run_every(ticks, callback)による遅延・繰り返しタスク。コールバックは新しいcontextを受け取ります。外側のcontextではなく、常にコールバックパラメータを使用してください。繰り返しタスクはon_exit_combatでキャンセルしてください。詳細はフックとライフサイクルを参照してください。

  • context.boss / context.player -- 現在のイベントに関わるボスとプレイヤー。すべてのフィールドとメソッドについてはボスとエンティティを参照してください。

  • context.world -- パーティクル、エンティティ、サウンド、雷、ブロックのスポーン。ワールドと環境を参照してください。

  • context.zones / context.script -- ゾーンジオメトリ、ターゲティング、ダメージ、パーティクル。ゾーンとターゲティングを参照してください。


メソッド構文::.

:. の違いは MagmaCore Luaスクリプティングエンジンを参照してください。エンティティメソッドと共有サービスは両方の形式に対応しますが、context.event.set_damage_amount(value)context.event.multiply_damage_amount(multiplier) にはドットが必要です。コロンを使うとイベントテーブルが第1引数として渡されます。


次のステップ

基本を理解したら、Luaスクリプティングドキュメントの残りを探索してください:

YAMLベースのスクリプティングについては、EliteScriptページが引き続き正式なリファレンスです: