Lua 脚本:区域与目标选择
EliteMobs 的 Lua 功能提供了两种互补的方法来定义空间区域和解析目标:
- 原生区域 (
context.zones) -- 简单直接。将区域定义构建为普通的 Lua 表,然后查询实体或位置。最适合简单的"这个区域内有东西吗?"检查。 - 脚本工具 (
context.script) -- 更丰富的目标选择,带有 watch/contains/entities 方法的区域句柄,粒子生成、伤害和推动动作。使用与 EliteScript 区域和 EliteScript 目标相同的字段名称以便于熟悉。
两种方法都是原生 Lua API。选择适合你能力复杂度的方法。
原生区域:context.zones
原生区域让你将区域定义为普通的 Lua 表并直接查询。没有句柄,没有额外抽象 -- 只是一个描述形状的表和一个查询它的方法调用。
方法
| 方法 | 说明 |
|---|---|
zones:get_entities_in_zone(zoneDef, options) | 返回区域内实体包装器的数组 |
zones:get_locations_in_zone(zoneDef, options) | 返回区域内位置表的数组 |
zones:zone_contains(zoneDef, location[, "full"|"border"]) | 如果位置在区域内则返回 true |
zones:watch_zone(zoneDef, callbacks, options) | 注册一个每 tick 触发的持久区域观察器 |
区域定义字段
| 字段 | 类型 | 说明 |
|---|---|---|
kind | string | "sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray" |
radius | number | 区域半径(sphere、dome、cylinder、cone) |
height | number | 圆柱体高度 |
origin | location | 中心位置(省略时默认为 Boss 位置) |
destination | location | 射线和锥体的终点 |
x, y, z | number | 长方体半尺寸 |
length | number | 锥体和射线的长度 |
thickness / point_radius | number | 射线粗细 |
border_radius | number | 边界宽度(默认 1) |
x_border, y_border, z_border | number | 长方体边界宽度(默认 1) |
animation_duration | int | 动画射线的动画长度(tick 为单位) |
pitch_pre_rotation, yaw_pre_rotation | number | 预旋转角度(旋转射线) |
pitch_rotation, yaw_rotation | number | 每 tick 旋转角度(旋转射线) |
origin_end, destination_end | location | 平移射线的结束位置 |
ignores_solid_blocks | boolean | 射线是否穿过实体方块(默认 true) |
查询选项
| 键 | 说明 |
|---|---|
filter | "player" / "players", "elite" / "elites", "mob" / "mobs", "living"(默认) |
mode | "full"(默认)或 "border" |
coverage | 0.0 到 1.0 -- 采样位置的比例(默认 1.0) |
监视回调
| 键 | 说明 |
|---|---|
on_enter | function(entity) -- 当实体进入区域时调用 |
on_leave | function(entity) -- 当实体离开区域时调用 |
示例:基本球体查询
示例
return {
api_version = 1,
on_spawn = function(context)
-- Store a zone definition for reuse
context.state.danger_zone = {
kind = "sphere",
origin = context.boss:get_location(),
radius = 10
}
end,
on_boss_damaged_by_player = function(context)
-- Update the origin to the boss's current position
context.state.danger_zone.origin = context.boss:get_location()
local players = context.zones:get_entities_in_zone(
context.state.danger_zone,
{ filter = "players" }
)
for _, player in ipairs(players) do
player:send_message("&cYou are in the danger zone!")
end
end
}
示例:带进入/离开的区域监视
示例
return {
api_version = 1,
on_spawn = function(context)
context.zones:watch_zone(
{
kind = "sphere",
origin = context.boss:get_location(),
radius = 8
},
{
on_enter = function(entity)
entity:apply_potion_effect("SLOWNESS", 40, 1)
entity:send_message("&7You feel sluggish near the boss...")
end,
on_leave = function(entity)
entity:send_message("&aYou escape the slowing aura.")
end
},
{ filter = "players", mode = "full" }
)
end
}
观察器注意事项:
- 观察器回调直接接收单个实体包装器,而不是通过
context.event - 当 Boss 被移除时,观察器会自动清理
- 每个观察器每 tick 运行一次,因此保持回调逻辑轻量
- Boss 实体本身被排除在区域查询之外
脚本工具:context.script
脚本工具提供目标解析、区域句柄、相对向量、粒子生成和战斗动作。它们使用与 EliteScript 区域和 EliteScript 目标相同的字段名称以便于熟悉 -- 枚举名称(如 "NEARBY_PLAYERS"、"SPHERE"、"ZONE_FULL")完全相同,这样已经熟悉 EliteScript 的作者可以直接转移这些知识。
信息
context.script 是原生 Lua API。它不是通向 YAML 或 EliteScript 运行时的桥梁。它只是重用了相同的命名约定,这样你就不必学习第二套枚举名称。
方法
| 方法 | 说明 |
|---|---|
script:target(spec) | 从目标规格表创建目标句柄 |
script:zone(spec) | 从区域规格表创建区域句柄 |
script:relative_vector(spec[, actionLocation][, zoneHandle]) | 创建相对向量句柄 |
script:damage(targetHandle, amount[, multiplier]) | 对已解析的目标造成伤害 |
script:push(targetHandle, vectorOrHandle[, additive]) | 推动已解析的目标 |
script:set_facing(targetHandle, vectorOrHandle) | 设置目标的朝向方向 |
script:spawn_particles(targetHandle, particleSpec) | 在已解析的目标位置生成粒子 |
目标句柄方法
| 方法 | 说明 |
|---|---|
handle:entities() | 返回实体包装器数组 |
handle:locations() | 返回位置表数组 |
handle:first_entity() | 返回第一个实体或 nil |
handle:first_location() | 返回第一个位置或 nil |
目标规格键
| 键 | 说明 |
|---|---|
targetType | "SELF", "DIRECT_TARGET", "NEARBY_PLAYERS", "NEARBY_MOBS", "NEARBY_ELITES", "ZONE_FULL", "ZONE_BORDER", "ALL_PLAYERS", "WORLD_PLAYERS", "SELF_SPAWN", "LOCATION" |
range | 附近类型目标的范围 |
coverage | 区域目标的 0.0 到 1.0 |
offset | "x,y,z" 字符串或 { x = n, y = n, z = n } 表 |
track | 是否重新解析移动的目标 |
示例:创建和使用目标
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("roar", 200) then return end
-- Find all players within 20 blocks
local nearby = context.script:target({
targetType = "NEARBY_PLAYERS",
range = 20
})
for _, player in ipairs(nearby:entities()) do
player:send_message("&eThe boss roars in fury!")
end
-- Single-entity access
local closest = nearby:first_entity()
if closest then
closest:show_title("&cRUN!", "&7The boss is targeting you")
end
end
}
区域句柄方法
| 方法 | 说明 |
|---|---|
handle:full_target([coverage]) | 返回整个区域体积的目标句柄 |
handle:border_target([coverage]) | 返回区域边界的目标句柄 |
handle:full_locations([coverage]) | 返回整个区域体积中的位置 |
handle:border_locations([coverage]) | 返回区域边界上的位置 |
handle:full_entities() | 返回整个区域体积中的实体 |
handle:border_entities() | 返回区域边界上的实体 |
handle:contains(location[, "full"|"border"]) | 如果位置在区域内则返回 true |
handle:watch(callbacks[, mode]) | 监视区域的进入/离开事件,返回任务 ID |
区域规格键
| 键 | 说明 |
|---|---|
shape | "SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY" |
radius | 区域半径 |
height | 圆柱体高度 |
x, y, z | 长方体半尺寸 |
borderRadius | 边界宽度 |
pointRadius | 射线粗细 |
animationDuration | 动画射线的动画长度(tick 为单位) |
Target | 中心目标规格(表) -- 使用相同的目标规格格式 |
Target2 | 射线和锥体的第二个点 |
filter | 实体过滤器 |
ignoresSolidBlocks | boolean |
pitchPreRotation, yawPreRotation | 预旋转角度 |
pitchRotation, yawRotation | 每 tick 旋转角度 |
示例:带伤害和粒子的区域
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a sphere zone centered on the boss
local zone = context.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})
-- Spawn warning particles on the zone border
context.script:spawn_particles(
zone:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)
-- Damage all players inside the zone
local targets = zone:full_target()
context.script:damage(targets, 5.0)
-- Repeat every 20 ticks
context.scheduler:run_every(20, function(ctx)
local z = ctx.script:zone({
shape = "SPHERE",
radius = 6,
Target = { targetType = "SELF" }
})
ctx.script:spawn_particles(
z:border_target(0.3),
{ particle = "FLAME", amount = 1, speed = 0.02 }
)
ctx.script:damage(z:full_target(), 5.0)
end)
end
}
相对向量规格键
| 键 | 说明 |
|---|---|
SourceTarget | 源目标规格(表) |
DestinationTarget | 目的地目标规格(表) |
normalize | boolean -- 是否归一化结果向量 |
multiplier | 归一化后应用的缩放因子 |
offset | "x,y,z" 字符串或 { x = n, y = n, z = n } 表 |
相对向量句柄方法
| 方法 | 说明 |
|---|---|
handle:resolve() | 返回计算后的向量表 |
示例:使用相对向量推动目标
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if not context.cooldowns:check_local("knockback", 100) then return end
-- Build a vector from the boss toward the attacker
local vec = context.script:relative_vector({
SourceTarget = { targetType = "SELF" },
DestinationTarget = { targetType = "DIRECT_TARGET" },
normalize = true,
multiplier = 2.5
})
-- Push the attacker away
local target = context.script:target({
targetType = "DIRECT_TARGET"
})
context.script:push(target, vec)
end
}
粒子规格格式
粒子规格可以是字符串、单个表或表的数组:
| 键 | 说明 |
|---|---|
particle | 粒子名称(如 "FLAME"、"DUST"、"SMOKE") |
amount | 粒子数量 |
x, y, z | 偏移/扩散值 |
speed | 粒子速度 |
red, green, blue | DUST / DUST_COLOR_TRANSITION 的颜色(0-255) |
toRed, toGreen, toBlue | DUST_COLOR_TRANSITION 的过渡目标颜色 |
有关完整的粒子名称列表,请参阅枚举参考。
重要注意事项
- 脚本工具句柄绑定到创建它们的事件上下文。不要将它们存储在
context.state中以供后续钩子调用使用。 - 区域
watch()返回一个任务 ID,可以用context.scheduler:cancel_task()取消。 - Coverage 值仅适用于基于位置的解析,不适用于实体查询。
- 所有字符串值使用与 EliteScript YAML 相同的 UPPER_SNAKE_CASE 枚举名称(如
"SELF"、"NEARBY_PLAYERS"、"SPHERE")。
em 辅助命名空间
em 命名空间在所有 Lua 能力文件中全局可用。它提供了位置、向量和区域定义的便捷构造函数。
位置和向量构造函数
| 函数 | 说明 |
|---|---|
em.create_location(x, y, z[, world][, yaw][, pitch]) | 返回带有 add(dx, dy, dz) 方法的位置表 |
em.create_vector(x, y, z) | 返回向量表 |
区域构建器辅助函数
em.zone 子表提供构建器函数,返回与 context.zones 兼容的区域定义表。每个构建器返回带有可链式调用的修改器方法的表。
| 函数 | 参数 | 修改器 |
|---|---|---|
em.zone.create_sphere_zone(radius) | radius | :set_center(location) |
em.zone.create_dome_zone(radius) | radius | :set_center(location) |
em.zone.create_cylinder_zone(radius, height) | radius, height | :set_center(location) |
em.zone.create_cuboid_zone(x, y, z) | x, y, z(半尺寸) | :set_center(location) |
em.zone.create_cone_zone(length, radius) | length, radius | :set_origin(location), :set_destination(location) |
em.zone.create_static_ray_zone(length, thickness) | length, thickness | :set_origin(location), :set_destination(location) |
em.zone.create_rotating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
em.zone.create_translating_ray_zone(length, point_radius, animation_duration) | length, point_radius, animation_duration | :set_origin(location), :set_destination(location) |
示例
示例
return {
api_version = 1,
on_spawn = function(context)
-- Create a location offset from the boss
local boss_loc = context.boss:get_location()
local above = em.create_location(boss_loc.x, boss_loc.y + 5, boss_loc.z)
-- Create a sphere zone using the builder
local zone = em.zone.create_sphere_zone(10):set_center(boss_loc)
-- Use with native zone queries
local players = context.zones:get_entities_in_zone(zone, { filter = "players" })
for _, p in ipairs(players) do
p:send_message("&cYou are within the boss's aura!")
end
-- Create a directional vector
local push_vec = em.create_vector(0, 1.5, 0)
context.boss:set_velocity_vector(push_vec)
end
}
信息
em 命名空间不是按实例的 -- 所有 Lua 能力实例共享相同的 em 辅助函数。这些函数是纯构造函数,不携带任何状态。
原生区域 vs. 脚本工具
两个系统使用相同的底层区域几何。以下是每种方法的使用时机:
| 使用场景 | 推荐方法 |
|---|---|
| 简单的"这个区域内有东西吗?"检查 | 原生区域(context.zones) |
| 使用形状快速查询实体 | 原生区域 |
带 coverage 的 NEARBY_PLAYERS、ZONE_FULL | 脚本工具(context.script) |
| 动画区域(旋转/平移射线) | 都可以 -- 原生区域也支持这些形状 |
带 watch/contains/entities 方法的区域句柄 | 脚本工具 |
| 在区域位置生成粒子 | 脚本工具(spawn_particles) |
| 与目标选择绑定的伤害和推动动作 | 脚本工具(damage、push) |
| 方向性效果的相对向量 | 脚本工具(relative_vector) |
| 将 Lua 控制流与丰富的目标选择结合 | 脚本工具 |
在实践中,许多能力同时使用两者。原生区域非常适合在冷却守卫中进行初始的"附近有玩家吗?"检查,而脚本工具处理随后的复杂攻击逻辑。
