跳到主要内容

Lua 脚本:区域与目标选择

webapp_banner.jpg

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(或 typestring"sphere", "dome", "cylinder", "cuboid", "cone", "static_ray", "rotating_ray", "translating_ray"
radiusnumber0区域半径(sphere、dome、cylinder、cone)
heightnumber0圆柱体高度
originlocationBoss 位置中心位置
destinationlocationBoss 位置射线和锥体的终点
x, y, znumber0长方体半尺寸
thickness / point_radius / pointRadiusnumber0.5射线粗细
border_radius / borderRadiusnumber1边界宽度
x_border, y_border, z_bordernumber1长方体边界宽度
animation_durationint0动画射线的动画长度(tick 为单位)
pitch_pre_rotation, yaw_pre_rotationnumber0预旋转角度(旋转射线)
pitch_rotation, yaw_rotationnumber0每 tick 旋转角度(旋转射线)
origin_end, destination_endlocationBoss 位置平移射线的结束位置
ignores_solid_blocksbooleantrue射线是否穿过实体方块
lengthnumber0仅在省略 destination 时读取,详见下文。

每个多词字段同样接受 camelCase 写法(borderRadiusxBorderanimationDurationpitchPreRotationignoresSolidBlocks……),因此从 EliteScript Zone: 块复制过来的规格大多可以直接使用。

kind 区分大小写

与 Lua API 中几乎所有其他字符串不同,kind 是精确匹配的,且必须小写。"SPHERE""Sphere" 不会匹配任何东西,该区域会静默地解析为空 —— 查询只会返回空列表,且没有控制台警告。

Cones and rays need an explicit destination

省略时,origindestination 都会回退到 Boss 自身的位置。对于锥体或射线来说,这会产生一个零长度的形状而不是报错。请务必在 conestatic_rayrotating_raytranslating_ray 上设置 destination。不存在 length 简写 —— 请设置一个明确的终点位置。

锥体和射线需要 destinationlength

省略 origin 时使用 Boss 的位置。省略 destination 时,从 origin 沿着 origin 位置表中保存的朝向延伸 length 格,得到终点。

可以通过以下两种方式定义锥体或射线:

-- Explicit endpoint
local explicit_ray = { kind = "static_ray", origin = context.boss:get_eye_location(),
destination = context.player:get_eye_location() }

-- Or a length along the origin's own facing
local forward_ray = { kind = "static_ray", origin = context.boss:get_eye_location(), length = 15 }

使用 length 简写时,只有 origin 包含 yaw/pitch 才能朝向预期方向。API 返回的位置表(get_location()get_eye_location()current_location)包含这些值。手写的 { x = .., y = .., z = .. } 不包含;em.create_location(x, y, z) 也需要传入可选的 yawpitch

两者都省略时,length 默认为 0,形状长度为零,所有查询都会返回空结果且不发出警告。

查询选项

说明
filter"player" / "players", "elite" / "elites", "mob" / "mobs", "living"(默认)
mode"full"(默认)或 "border"
coverage0.01.0 -- 采样位置的比例(默认 1.0

监视回调

说明
on_enterfunction(entity) -- 当实体进入区域时调用
on_leavefunction(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

脚本工具提供目标解析、区域句柄、相对向量、粒子生成和战斗动作。

context.script runs the EliteScript engine

context.script 不只是"带有 EliteScript 风格的命名" —— 你传入的规格表会被转换为普通的 Java map,并直接交给驱动 YAML EliteScript 的那同一批目标、区域、相对向量和粒子类。不存在另一套实现。

这在实践中意味着:

  • EliteScript 目标EliteScript 区域EliteScript 相对向量上记录的每一个字段都能在这些规格表中使用,包括本页未列出的任何字段。
  • 枚举值是精确的 UPPER_SNAKE_CASE("NEARBY_PLAYERS""SPHERE""ZONE_FULL"),与 YAML 相同。
  • 字段名就是 YAML 的名称,因此 TargetTarget2 首字母大写,而 targetTypeborderRadius 是 camelCase。
  • YAML 的加载期行为同样适用:无法解析的值会记录一条 EliteScript 警告并清空该字段,而不是回退到其默认值。

这与 context.zones 恰好相反 —— 后者是真正独立的轻量实现,使用小写的 kind 名称。

方法

方法说明
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"任意 EliteScript 目标类型
range20附近类型目标的范围
coverage1.00.01.0仅对区域类目标类型生效;用在其他任何类型上都会被重置为 1.0 并给出控制台警告
offset0,0,0"x,y,z" 字符串或 { x = n, y = n, z = n }
relativeOffset相对向量规格表,用于相对 Boss 朝向的偏移
location单个位置,用于 "LOCATION"
locations位置列表,用于 "LOCATIONS"
tracktrue是否重新解析移动的目标

全部 17 种 EliteScript 目标类型都被接受,而不只是常见的那几种:SELFSELF_SPAWNDIRECT_TARGETNEARBY_PLAYERSNEARBY_MOBSNEARBY_ELITESWORLD_PLAYERSALL_PLAYERSLOCATIONLOCATIONSZONE_FULLZONE_BORDERLANDING_LOCATIONACTION_TARGETINHERIT_SCRIPT_TARGETINHERIT_SCRIPT_ZONE_FULLINHERIT_SCRIPT_ZONE_BORDERACTION_TARGETINHERIT_* 类型只有在存在外层 EliteScript 上下文时才会解析出内容,因此从 Lua 使用意义不大。

示例:创建和使用目标

示例
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"CYLINDER""SPHERE", "DOME", "CYLINDER", "CUBOID", "CONE", "STATIC_RAY", "ROTATING_RAY", "TRANSLATING_RAY"
radius5球体、穹顶、圆柱体、锥体
height1仅圆柱体
x, y, z0长方体半尺寸
xBorder, yBorder, zBorder0长方体边界宽度
borderRadius1球体 / 穹顶 / 圆柱体 / 锥体的边界宽度
pointRadius0.5射线粗细
animationDuration0动画射线的动画长度(tick 为单位)
Target{targetType = "SELF"}中心目标规格(表) -- 使用相同的目标规格格式
Target2第二个点。锥体和所有射线形状必需
FinalTarget, FinalTarget2结束位置,仅平移射线
filter"PLAYER""PLAYER""ELITE""LIVING" —— 注意这里是大写,与 context.zones 不同
ignoresSolidBlockstrue仅射线
pitchPreRotation, yawPreRotation0仅旋转射线
pitchRotation, yawRotation0仅旋转射线

不适用于所选 shape 的键会被读取但随后忽略,且不会有任何提示 —— 在球体上写 height 不会有任何效果。

示例:带伤害和粒子的区域

示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a sphere zone centered on the boss
if context.state.zone_task_id ~= nil then return end
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.state.zone_task_id = 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,
on_exit_combat = function(context)
if context.state.zone_task_id ~= nil then
context.scheduler:cancel_task(context.state.zone_task_id)
context.state.zone_task_id = nil
end
end
}

相对向量规格键

说明
SourceTarget源目标规格(表)
DestinationTarget目的地目标规格(表)
normalizeboolean -- 是否归一化结果向量
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
}

粒子规格格式

粒子规格可以是字符串、单个表或表的数组。由于这条路径运行的是 EliteScript 粒子引擎,这里的键就是 SPAWN_PARTICLE 下记录的 EliteScript 键:

默认值说明
particle"FLAME"粒子名称(如 "FLAME""DUST""SMOKE"
amount1粒子数量。为 0 时会把 x/y/z 变成速度向量
x, y, z0.01偏移/扩散值,或在 amount0 时作为速度
speed0.01粒子速度
red, green, blue255DUSTDUST_COLOR_TRANSITIONWITCH 及其他颜色数据粒子的颜色(0-255)
toRed, toGreen, toBlue255DUST_COLOR_TRANSITION 的过渡目标颜色
material"STONE"携带方块/物品数据的粒子(BLOCKITEMFALLING_DUST……)所显示的方块或物品
relativeVector相对向量规格。设置它会强制 amount0,并用解析出的方向覆盖 x/y/z
Two different particle key sets

这些 EliteScript 键与 context.world:spawn_particle_at_location(loc, spec) 所接受的键不相同。world 表有它自己更小的读取器,默认值也不同(amount1x/y/z/speed0),没有 material 也没有 relativeVector,并且它还额外接受 snake_case 的 to_red / to_green / to_blue。参见 世界与环境

有关完整的粒子名称列表,请参阅枚举参考

重要注意事项

  • 脚本工具句柄绑定到创建它们的事件上下文。不要将它们存储在 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 兼容的区域定义表。每个构建器返回带有可链式调用的修改器方法的表。

The length argument is not used

锥体和射线构建器会把 length 存入规格表,但 context.zones 从不读取它 —— 形状是从 origin 走到 destination 的。请务必在这些构建器上同时链式调用 :set_origin(...) :set_destination(...);否则两者都会默认为 Boss 的位置,形状长度为零。

函数参数修改器
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_PLAYERSZONE_FULL脚本工具(context.script
动画区域(旋转/平移射线)都可以 -- 原生区域也支持这些形状
watch/contains/entities 方法的区域句柄脚本工具
在区域位置生成粒子脚本工具(spawn_particles
与目标选择绑定的伤害和推动动作脚本工具(damagepush
方向性效果的相对向量脚本工具(relative_vector
将 Lua 控制流与丰富的目标选择结合脚本工具

在实践中,许多能力同时使用两者。原生区域非常适合在冷却守卫中进行初始的"附近有玩家吗?"检查,而脚本工具处理随后的复杂攻击逻辑。


后续步骤

  • 示例与模式 -- 可供学习和改编的完整工作能力
  • API 参考 -- 完整的 context.* 方法参考
  • 枚举参考 -- Particle、Sound、Material 及其他字符串常量的有效值