Lua 脚本编写:世界与环境
本页面介绍 EliteMobs Boss 对 context.world 的扩展,以及 context.vectors、context.settings 和 context.event。Lua 能力可以用它们生成实体、播放特效、查询方块和改变世界状态。如果你刚接触 Lua 能力,请先从 入门 开始。
EliteMobs 的 Boss 能力复用了 MagmaCore 的 Lua 沙箱。Boss 的 context.world 起源于共享的 MagmaCore world 表,因此诸如 get_block_at(...)、set_block_at(...) 和 spawn_particle(...) 这类通用坐标辅助方法仍然可用。本页面聚焦于 EliteMobs Boss 专有的 context.world、context.vectors、context.settings 和 context.event 新增内容与覆盖实现。关于通用的 world API,请参见 MagmaCore Lua 脚本引擎。
两边存在同名方法时,以 EliteMobs 版本为准。下文的方法保留了 EliteMobs 的行为,包括闪电生成保护绕过、更丰富的粒子规格和临时方块跟踪。其他共享方法仍然可用,包括 get_entity(uuid)、block_is_passable(x, y, z)、location_is_protected(location)、spawn_dust(...) 和 raycast(...)。参数及未加载区块的处理方式见 共享 API 参考;这些保证不会自动适用于 EliteMobs 的覆盖实现。
FreeMinecraftModels 只会在它自己的道具脚本中,向 context.world 添加 drop_elitemobs_procedural_loot、drop_elitemobs_random_loot、drop_elitemobs_custom_loot 和 start_elitemobs_transport。每个插件都带有一份独立的共享脚本库副本,因此即使安装了 FreeMinecraftModels,这些辅助方法也不会出现在 EliteMobs 的 Boss 能力或 NPC 脚本中。Boss 能力请改用 generate_player_loot 和 drop_bonus_coins。
context.world
world 表提供生成实体、播放特效、修改方块和改变世界状态的方法。它们接受冒号语法 world:method(),也接受不显式传入 self 参数的点语法。
下文的 Boss 覆盖方法通过 x、y、z、可选的 yaw/pitch 和 world 中已加载的世界名称转换位置表。缺失的坐标为 0;省略世界时使用 Boss 当前的世界,但明确指定未知世界会导致转换失败。也可以传入嵌套的 current_location 表。nil 或非表位置默认使用 Boss 位置。共享方法仍遵循各自的位置规则,并使用共享表创建时保存的世界。
Lua 实例关闭时,世界修改和已生成的实体不会自动撤销。脚本管理的监视任务会停止,但独立的实体移除计时器、爆炸再生、强化闪电和金币弹幕任务有各自的生命周期。方块和生成覆盖方法不会自动检查 location_is_protected,也不会自动采用共享方法的未加载区块保护;修改世界前应自行检查相关限制。
world:spawn_particle_at_location(location, particleSpec)
在指定位置生成粒子。第二个参数可以是粒子名称字符串或粒子规格表。可选的第三个整数参数指定未提供 amount 时的数量,默认为 1。查询前会将名称转换为大写。无效名称或不支持的粒子数据会产生警告,且不会生成粒子。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 生成粒子的位置 |
particleSpec | 字符串或表 | 粒子名称 或粒子规格表(见下文) |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Simple particle by name
context.world:spawn_particle_at_location(context.boss:get_location(), "FLAME")
-- Full particle spec table with red dust
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 10,
x = 0.5,
y = 0.5,
z = 0.5,
speed = 0.02,
red = 255,
green = 0,
blue = 0,
})
end
}
粒子规格表格式
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
particle | 字符串 | 必填 | 粒子名称 |
amount | 整数 | 1 | 粒子数量 |
x、y、z | 数字 | 0 | 各轴上的扩散/偏移 |
speed | 数字 | 0 | 粒子速度 |
red、green、blue | 整数 | 255 | 用于 DUST 和 DUST_COLOR_TRANSITION 的 RGB 颜色 |
toRed、toGreen、toBlue | 整数 | 255 | DUST_COLOR_TRANSITION 的过渡目标颜色 |
对于 DUST_COLOR_TRANSITION,也可以使用 to_red、to_green、to_blue,但驼峰形式的值优先。两种粉尘粒子的大小固定为 1,RGB 分量必须在 0..255 范围内。其他粒子不会收到附加数据,因此该方法无法支持所有需要额外数据的粒子。
与 EliteScript 的 YAML 配置不同,Lua 中的粒子名称不支持旧版粒子名称转换。你必须使用当前的 Spigot API 名称(例如用 FIREWORK 而不是 FIREWORKS_SPARK,用 SMOKE 而不是 SMOKE_NORMAL,用 DUST 而不是 REDSTONE)。完整的当前名称列表及其旧版对应名称,请参见 有效粒子列表。
world:play_sound_at_location(location, sound, volume, pitch)
在某个位置播放声音。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
location | location 表 | 播放声音的位置 | |
sound | 字符串 | Minecraft 声音键(例如 "entity.blaze.shoot")或 Spigot 的 Sound 枚举名称。资源包中的键同样可用。 | |
volume | 数字 | 1.0 | 音量 |
pitch | 数字 | 1.0 | 音调 |
示例
return {
api_version = 1,
on_spawn = function(context)
context.world:play_sound_at_location(
context.boss:get_location(),
"entity.wither.spawn",
1.0,
0.5
)
end
}
world:strike_lightning_at_location(location)
在指定位置生成会造成伤害的真实闪电,并启用 EliteMobs 的闪电生成保护绕过。它不同于共享 API 中仅有视觉效果的闪电方法,且无法保证绕过其他插件的所有伤害或保护规则。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 降下闪电的位置 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("lightning", 100) then return end
context.world:strike_lightning_at_location(context.player:get_location())
context.player:send_message("&eA bolt of lightning strikes you!")
end
}
world:spawn_entity_at_location(entityType, location, options)
直接在指定位置的世界中生成原版 Minecraft 实体。未知实体名称返回 nil;已识别但不可生成的类型仍可能报错。该方法不会自动设置投射物的发射者,也不会将实体注册为精英增援。
| 参数 | 类型 | 说明 |
|---|---|---|
entityType | 字符串 | 实体类型名称(例如 "FIREBALL"、"ARROW") |
location | location 表 | 生成位置 |
options | 表(可选) | 生成选项(见下文) |
实体生成选项
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
velocity | vector 表 | nil | 初始速度 {x, y, z} |
effect | 字符串 | nil | 生成时播放的 EntityEffect |
duration | 整数 | 0 | 正值表示经过指定游戏刻后移除;非正值不添加移除计时器 |
on_land | 函数 | nil | 实体着地、失效或超过 max_ticks 时调用 function(land_location, entity_ref);这不是投射物命中事件,也不能证明实体确实落地 |
max_ticks | 整数 | 6000 | 强制触发 on_land 回调前最多监视的游戏刻数 |
persistent | 布尔值 | Minecraft 的默认值 | 设为 false 时,该实体不会写入区块存档,因此特效进行期间关服或区块卸载都不会让它留在世界中 |
返回一个实体包装器表。非生物实体(FIREBALL、ARROW、TNT 等)返回的是
非生物引用包装器,其中 is_valid() 是一个方法。
生物实体类型(ZOMBIE、GIANT 等)返回的则是完整的
生物实体包装器,其中 is_valid 是一个布尔字段——对这类包装器调用
entity:is_valid() 会抛出 attempt to call a boolean value。
落地监视器在脚本活动期间每游戏刻检查一次,并随脚本管理的任务停止。正值 duration 对应的计时器独立运行,即使脚本关闭也可能移除实体。未知的 effect 名称会被忽略。
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("fireball_spawn", 100) then return end
-- Spawn a fireball aimed at the player
local boss_loc = context.boss:get_location()
local dir = context.vectors.get_vector_between_locations(boss_loc, context.player:get_location())
dir = context.vectors.normalize_vector(dir)
context.world:spawn_entity_at_location("FIREBALL", boss_loc, {
velocity = { x = dir.x * 2, y = dir.y * 2, z = dir.z * 2 },
duration = 100,
})
end
}
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Spawn a primed TNT with a landing callback
context.world:spawn_entity_at_location("TNT", context.boss:get_location(), {
velocity = { x = 0, y = 1.5, z = 0 },
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, {
particle = "EXPLOSION_EMITTER",
amount = 1,
})
end,
})
end
}
world:spawn_display_at_location(location, options)
生成物品展示实体或方块展示实体:一种没有碰撞箱、重力和 AI 的悬浮视觉效果。适用于环绕的石块、投掷的道具,以及其他只需要被看见的特效,无需再给盔甲架设置外观。展示实体以 location 为中心,并按其偏航角旋转。
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
item | 字符串 | 作为物品显示的材质。"AMETHYST_BLOCK" 这样的方块物品会显示为居中的方块 | |
block | 字符串 | 作为方块展示的方块,可以是材质,也可以是 "lantern[hanging=true]" 这样的方块数据 | |
scale | 数字或向量表 | 1 | 数字会缩放所有轴;{x, y, z} 分别缩放各轴。为 1 时,一个方块宽一格 |
duration | 整数 | 0 | 正值表示经过这么多游戏刻后移除该展示实体 |
teleport_duration | 整数 | 0 | 客户端滑行到每个新位置所用的游戏刻数,范围 0 到 59。如果你每刻都传送该展示实体,请使用 1 |
billboard | 字符串 | FIXED | FIXED、VERTICAL、HORIZONTAL 或 CENTER |
glowing | 布尔值 | false | 轮廓发光 |
brightness | 整数 | 世界光照 | 0 到 15,覆盖展示实体处的光照 |
bedrock_fallback | 布尔值 | true | 见下文 |
item 和 block 必须且只能给出一个。缺少或未知的 item 或 block、两者同时给出,或 scale 不是正数,都会返回 nil,并记录一条写明该能力名称的警告。未知的 billboard 值会保持为 FIXED。
展示实体永远不会随区块保存。它们会在 duration 用尽、你调用 remove(),或能力关闭时被移除,以先发生者为准。
Bedrock 客户端无法渲染展示实体。在展示实体生成时已身处该世界的 Bedrock 玩家,会改为看到一个穿戴同一物品的隐形盔甲架(方块展示实体则使用该方块的物品),展示实体对他们则是隐藏的。该盔甲架跟随展示实体移动,并随它一起移除。之后才进入该世界的 Bedrock 玩家不会获得盔甲架,没有物品形态的方块(例如 fire)则完全不会生成盔甲架。对于 Bedrock 玩家不需要看到的特效,可以用 bedrock_fallback = false 关闭此行为。
返回的包装器带有 uuid 和 entity_type,以及以下方法:
| 方法 | 说明 |
|---|---|
is_valid()、is_alive() | 该展示实体是否仍然存在 |
get_location() | 当前位置 |
teleport_to_location(location) | 移动该展示实体及其 Bedrock 盔甲架 |
remove() | 移除该展示实体及其 Bedrock 盔甲架 |
set_scale(scale) | 取值与 scale 选项相同 |
set_item(material) | 仅适用于物品展示实体;否则返回 false |
set_block(block) | 仅适用于方块展示实体;否则返回 false |
set_glowing(enabled) | 轮廓发光 |
set_brightness(level) | 0 到 15,或用 nil 恢复使用世界光照 |
set_teleport_duration(ticks) | 与 teleport_duration 选项相同 |
示例
-- Three amethyst stones circle the target for three seconds.
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil or not context.cooldowns:check_local("orbit", 200) then return end
local target = context.player
local stones = {}
for i = 1, 3 do
stones[i] = context.world:spawn_display_at_location(target:get_location(), {
item = "AMETHYST_BLOCK", scale = 0.3, duration = 60, teleport_duration = 1
})
end
local elapsed = 0
local task
task = context.scheduler:run_every(1, function(context)
elapsed = elapsed + 1
if elapsed >= 60 then
context.scheduler:cancel_task(task)
return
end
local center = target:get_location()
for i = 1, 3 do
local angle = elapsed * 0.2 + i * (2 * math.pi / 3)
if stones[i] ~= nil and stones[i]:is_valid() then
stones[i]:teleport_to_location(em.create_location(
center.x + math.cos(angle) * 1.5, center.y + 1.2, center.z + math.sin(angle) * 1.5, center.world, 0, 0))
end
end
end)
end
}
world:spawn_falling_block_at_location(location, material, options)
使用方块材质生成下落方块实体。提供 on_land 时,EliteMobs 会拦截其方块变化事件,取消放置,并调用一次 function(land_location, entity_ref)。没有该回调时,可能正常放置方块。该方法没有 duration 或 max_ticks 选项,也不会因实体失效或超时而调用回调。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 生成位置 |
material | 字符串 | 材料名称(例如 "STONE"、"MAGMA_BLOCK") |
options | 表(可选) | 生成选项(见下文) |
下落方块选项
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
velocity | vector 表 | nil | 初始速度 {x, y, z} |
drop_item | 布尔值 | false | 该方块是否作为物品掉落 |
hurt_entities | 布尔值 | false | 该方块是否对它砸中的实体造成伤害 |
on_land | 函数 | nil | 方块落地时的回调 function(land_location, entity_ref) |
返回非生物实体引用表;位置或材质无法解析时返回 nil。即使材质名称有效,非方块材质也可能在创建方块数据时导致错误。
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Rain magma blocks from above
local loc = context.boss:get_location()
for i = 1, 5 do
local offset_loc = {
x = loc.x + math.random(-3, 3),
y = loc.y + 10,
z = loc.z + math.random(-3, 3),
world = loc.world
}
context.world:spawn_falling_block_at_location(offset_loc, "MAGMA_BLOCK", {
velocity = { x = 0, y = -0.5, z = 0 },
hurt_entities = true,
on_land = function(land_location, entity_ref)
context.world:spawn_particle_at_location(land_location, { particle = "LAVA", amount = 8 })
end,
})
end
end
}
world:spawn_custom_boss_at_location(filename, location, options)
根据配置文件生成一个 EliteMobs 自定义 Boss。
| 参数 | 类型 | 说明 |
|---|---|---|
filename | 字符串 | Boss 配置文件名(例如 "my_boss.yml") |
location | location 表 | 生成位置 |
options | 表(可选) | 生成选项(见下文) |
自定义 Boss 生成选项
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
level | 整数 | 自定义 Boss 自身配置或动态等级规则 | 覆盖生成的 Boss 等级;省略时不会继承施放者等级 |
silent | 布尔值 | false | 抑制生成消息 |
velocity | vector 表 | nil | 初始速度 |
add_as_reinforcement | 布尔值 | false | 注册为当前 Boss 的增援 |
返回一个实体包装器表;如果无法创建该 Boss,则返回 nil。
示例
return {
api_version = 1,
on_enter_combat = function(context)
local minion = context.world:spawn_custom_boss_at_location(
"skeleton_minion.yml",
context.boss:get_location(),
{ level = 10, add_as_reinforcement = true }
)
if minion ~= nil then
context.boss:send_message("&cMinions, arise!")
end
end
}
world:spawn_boss_at_location(filename, location, level)
更简单的 Boss 生成方法。省略位置和等级时,使用施放者的位置和等级。生成结果不会注册为增援。要使用默认等级,应省略第三个参数;该位置不接受显式传入的 nil。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
filename | 字符串 | Boss 配置文件名 | |
location | location 表 | Boss 位置 | 生成位置(可选,默认为 Boss 所在位置) |
level | 整数 | Boss 等级 | 覆盖生成等级(可选) |
返回一个实体包装器表,或 nil。
示例
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_boss_at_location("zombie_guard.yml", context.boss:get_location(), 5)
context.boss:send_message("&cGuards, defend me!")
end
}
world:spawn_reinforcement_at_location(filename, location, duration, velocity)
通过 EliteMobs 增援系统静默生成实体并记录召唤者。如果自定义 Boss 召唤者使用归一化战斗,增援会继承该设置。等级由增援自身的配置和动态等级规则决定;duration 是逃离计时器,不是等级覆盖值。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
filename | 字符串 | Boss 配置文件名 | |
location | location 表 | 生成位置 | |
duration | 整数 | 0 | 逃离前的游戏刻数;0 禁用该计时器 |
velocity | vector 表 | nil | 初始速度(可选) |
返回一个实体包装器表,或 nil。
示例
return {
api_version = 1,
on_enter_combat = function(context)
context.world:spawn_reinforcement_at_location(
"necro_skeleton.yml",
context.boss:get_location(),
0,
{ x = 0, y = 0.5, z = 0 }
)
context.boss:send_message("&5Rise, my servant!")
end
}
world:spawn_fireworks_at_location(location, spec)
生成真实烟花实体,不会自动禁止伤害。每个效果至少需要一种有效颜色;缺少颜色的效果可能在构造时失败。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 生成位置 |
spec | 表 | 烟花规格(见下文) |
烟花规格表
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
power | 整数 | 1 | 飞行力度(高度) |
velocity | vector 表 | nil | 初始速度 |
shot_at_angle | 布尔值 | true | 烟花是否以一定角度射出(设置了 velocity 时使用) |
effects | 表的数组 | nil | 烟花效果规格的数组。如果省略,则把顶层规格当作单个效果处理。 |
烟花效果规格
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | 字符串 | "BALL_LARGE" | "BALL"、"BALL_LARGE"、"STAR"、"BURST"、"CREEPER" |
flicker | 布尔值 | true | 闪烁效果 |
trail | 布尔值 | true | 拖尾效果 |
colors | 表 | 每个效果必填 | 非空数组,元素为颜色名称或 {red = 255, green = 0, blue = 0} 表 |
fade_colors | 表 | nil | 渐隐颜色名称或 {red, green, blue} 表的数组 |
颜色名称:"WHITE"、"SILVER"、"GRAY"、"BLACK"、"RED"、"MAROON"、"YELLOW"、"OLIVE"、"LIME"、"GREEN"、"AQUA"、"TEAL"、"BLUE"、"NAVY"、"FUCHSIA"、"PURPLE"、"ORANGE"
返回非生物实体引用表;位置无法解析时返回 nil。调用 :detonate() 可请求引爆。类型和颜色名称不区分大小写,未知类型回退到 BALL_LARGE,未知颜色回退到白色。RGB 值必须在 0..255 范围内。
示例
return {
api_version = 1,
on_spawn = function(context)
local fw = context.world:spawn_fireworks_at_location(context.boss:get_location(), {
power = 0,
effects = {
{
type = "STAR",
flicker = true,
trail = true,
colors = { "RED", "ORANGE", { red = 255, green = 200, blue = 0 } },
fade_colors = { "YELLOW" },
},
},
})
if fw == nil then return end
-- Detonate on the next tick for a visual burst
context.scheduler:run_after(1, function()
fw:detonate()
end)
end
}
world:spawn_splash_potion_at_location(location, spec)
生成真实的投掷喷溅药水。未知的 Bukkit 效果名称会产生警告并被跳过。该方法不会设置发射者,也不会应用直接 Boss 药水方法使用的副本效果过滤规则;药水遵循正常的喷溅行为。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 生成位置 |
spec | 表 | 药水规格(见下文) |
喷溅药水规格表
| 键 | 类型 | 说明 |
|---|---|---|
velocity | vector 表 | 被投掷药水的初始速度 |
effects | 表的数组 | 药水效果规格的数组 |
药水效果规格
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | 字符串 | 必填 | 药水效果类型名称(例如 "SLOWNESS"、"POISON") |
duration | 整数 | 0 | 持续时间,单位为游戏刻 |
amplifier | 整数 | 0 | 效果等级增幅(0 = I 级) |
overwrite | 布尔值 | true | 替换此药水元数据中先前添加的同类型效果;不控制玩家身上已有的效果 |
返回一个实体引用表,或 nil。
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("potion_throw", 200) then return end
local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)
context.world:spawn_splash_potion_at_location(context.boss:get_location(), {
velocity = { x = dir.x * 1.5, y = 0.5, z = dir.z * 1.5 },
effects = {
{ type = "SLOWNESS", duration = 100, amplifier = 1 },
{ type = "WEAKNESS", duration = 60, amplifier = 0 },
},
})
end
}
world:place_temporary_block_at_location(location, material, duration, requireAir)
放置受跟踪的方块,持续时间为正值时会恢复原有方块数据。只保存方块数据,不保存容器内容。在计时器结束、区块或世界卸载,或插件关闭时,原方块会恢复,但前提是该位置仍是这个临时方块,因此之后的编辑不会被覆盖。在仍为临时方块的位置再次放置,会重新开始计时,并保留第一次保存的原方块。带有方块实体的方块(例如箱子和告示牌)、未加载区块中的方块,以及被其他临时方块所有者占用的方块会被跳过。破坏受跟踪的方块不会掉落物品,并会结束跟踪且不恢复。必须使用方块材质。此 Boss 覆盖方法返回 nil,包括 requireAir 或跳过规则阻止放置的情况;它不会报告成功状态,也不会自动检查区域保护。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
location | location 表 | 放置位置 | |
material | 字符串 | 材料名称 | |
duration | 整数 | 0 | 恢复前的游戏刻数;0 或负值会永久放置方块且不跟踪 |
requireAir | 布尔值 | false | 若为 true,则仅在该处当前为空气时才放置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Create a temporary ice floor under the boss
local loc = context.boss:get_location()
for dx = -2, 2 do
for dz = -2, 2 do
context.world:place_temporary_block_at_location(
{ x = loc.x + dx, y = loc.y - 1, z = loc.z + dz, world = loc.world },
"PACKED_ICE",
100,
false
)
end
end
end
}
world:set_block_at_location(location, material, requireAir)
通过临时方块管理器永久设置方块,不添加恢复计时器,也不进行跟踪,因此插件关闭后修改依然保留。如果该方块当前是带计时的临时方块,它将不再受跟踪,也不会被恢复。被其他临时方块所有者占用的方块保持不变。需要定时恢复时,使用持续时间为正值的 place_temporary_block_at_location。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
location | location 表 | 放置位置 | |
material | 字符串 | 材料名称 | |
requireAir | 布尔值 | false | 若为 true,则仅在该处当前为空气时才放置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Place fire at the boss's location
context.world:set_block_at_location(context.boss:get_location(), "FIRE", true)
end
}
world:get_block_type_at_location(location)
返回指定位置的大写材质名称,位置无法解析时返回 nil。与共享坐标查询不同,此覆盖方法直接访问方块,不检查区块是否已加载。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
local block_type = context.world:get_block_type_at_location(context.boss:get_location())
if block_type == "WATER" then
context.boss:send_message("&bThe boss is empowered by water!")
context.boss:apply_potion_effect("SPEED", 200, 1)
end
end
}
world:get_highest_block_y_at_location(location)
返回 Bukkit 提供的最高方块 Y 坐标,位置无法解析时返回 nil。不会检查区块是否已加载,也不会判断该位置是否适合安全传送。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置(只使用 X 和 Z) |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("skyport", 200) then return end
local loc = context.player:get_location()
local ground_y = context.world:get_highest_block_y_at_location(loc)
-- Teleport the player to the surface
context.player:teleport_to_location({
x = loc.x, y = ground_y + 1, z = loc.z, world = loc.world
})
context.player:send_message("&eYou are teleported to the surface!")
end
}
world:get_blast_resistance_at_location(location)
返回指定位置材质的爆炸抗性,位置无法解析时返回 0。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
local resistance = context.world:get_blast_resistance_at_location(context.boss:get_location())
context.log:info("Blast resistance at boss: " .. resistance)
end
}
world:is_air_at_location(location)
如果该位置的方块是空气,则返回 true。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 2, z = loc.z, world = loc.world }
if context.world:is_air_at_location(above) then
-- There is space above the boss, launch upward
context.boss:set_velocity_vector({ x = 0, y = 1.5, z = 0 })
end
end
}
world:is_passable_at_location(location)
返回 Bukkit 的 Block.isPassable() 结果,位置无法解析时返回 false。它只查询单个方块,不检查整个实体是否有足够空间或能否通过路径到达。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_passable_at_location(context.boss:get_location()) then
context.log:info("Boss is in a passable block")
end
end
}
world:is_passthrough_at_location(location)
如果该位置的方块不是实心方块,则返回 true(与 passable 类似,但基于实心判定)。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local above = { x = loc.x, y = loc.y + 1, z = loc.z, world = loc.world }
if context.world:is_passthrough_at_location(above) then
context.log:info("Boss can move upward")
end
end
}
world:is_on_floor_at_location(location)
如果该位置的方块非实心,且 Y 坐标低一格的方块为实心,则返回 true。不会检查实体的着地状态、碰撞箱或头顶空间。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
if context.world:is_on_floor_at_location(context.boss:get_location()) then
context.boss:send_message("&aThe boss slams the ground!")
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "CLOUD",
amount = 30,
})
end
end
}
world:is_standing_on_material(location, material)
如果该位置正下方的方块与给定材料相符,则返回 true。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 要查询的位置 |
material | 字符串 | 要检查的 材料名称 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if context.world:is_standing_on_material(context.player:get_location(), "SOUL_SAND") then
context.player:send_message("&8The soul sand saps your strength!")
context.player:apply_potion_effect("SLOWNESS", 60, 2)
end
end
}
world:set_world_time(time) / world:set_world_time(location, time)
设置整个世界的时间。可通过可选位置指定世界。脚本关闭时不会恢复原时间。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表(可选) | 要影响的世界。默认为 Boss 所在的世界。 |
time | 整数 | 以游戏刻表示的世界时间(0 = 黎明,6000 = 正午,13000 = 夜晚,18000 = 午夜) |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Set to midnight when combat starts
context.world:set_world_time(18000)
context.boss:send_message("&8Darkness falls...")
end
}
world:set_world_weather(weather, duration) / world:set_world_weather(location, weather, duration)
设置 Boss 所在世界或可选位置所在世界的天气。名称不区分大小写,未知名称只会产生警告。RAIN/CLEAR 设置天气持续时间,THUNDER 设置雷暴持续时间。它影响整个世界,脚本关闭时不会恢复原状态。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
location | location 表(可选) | Boss 所在世界 | 要影响的世界 |
weather | 字符串 | "CLEAR"、"RAIN"(或 "PRECIPITATION")、"THUNDER" | |
duration | 整数 | 6000 | 天气持续时间,单位为游戏刻 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Start a thunderstorm for 200 ticks
context.world:set_world_weather("THUNDER", 200)
context.boss:send_message("&eA storm gathers!")
end
}
world:generate_fake_explosion(blockLocations, sourceLocation)
通过 EliteMobs 爆炸再生系统移除真实方块并生成下落方块碎片。碎片可以伤害实体,因此这不是无害的粒子效果。必须启用 doExplosionRegen;提供源位置时会检查 WorldGuard 的爆炸再生标志。空气、火、液体和受跟踪的临时方块会被跳过,相邻依附方块也可能受到影响。经过 1200 游戏刻后开始恢复,每游戏刻处理一个记录的方块。所有输入位置应位于 Boss 所在世界。该操作返回 nil,关闭脚本不会撤销它。
| 参数 | 类型 | 说明 |
|---|---|---|
blockLocations | location 表的数组 | 要“炸毁”的方块位置数组 |
sourceLocation | location 表(可选) | 用于方向计算的爆炸源位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
local loc = context.boss:get_location()
local blocks = {}
for dx = -1, 1 do
for dz = -1, 1 do
table.insert(blocks, { x = loc.x + dx, y = loc.y, z = loc.z + dz, world = loc.world })
end
end
context.world:generate_fake_explosion(blocks, loc)
end
}
world:run_console_command(command)
立即以服务器身份执行控制台命令,返回 nil,不提供命令是否成功的结果。不会自动替换玩家或 Boss 占位符。
原版命令会报告其结果,而在默认的 broadcast-console-to-ops=true 下,服务器会把每条结果显示给所有在线管理员。频繁执行的命令(例如 data merge entity、kill 或 damage)会让他们的聊天栏被刷屏。请改用原生方法:视觉效果用 spawn_display_at_location,盔甲架用盔甲架方法,移除脚本生成的实体用 entity:remove(),而需要由 Boss 造成精确伤害时用 entity:deal_custom_damage(amount)。
| 参数 | 类型 | 说明 |
|---|---|---|
command | 字符串 | 要执行的命令(不带开头的 /) |
示例
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_console_command("say The boss has entered phase 2!")
end
}
world:run_empowered_lightning_task_at_location(location)
在保存的位置启动独立 Bukkit 任务。先发出 SOUL_FIRE_FLAME,持续 60 次迭代,然后生成带生成保护绕过的真实闪电,并向下发射爆炸强度为 5 的火球,标记为 ender_dragon_empowered_lightning.yml。这是会造成伤害的攻击。关闭或暂停 Lua 脚本不会取消该任务,该方法也不会读取预警效果设置。
| 参数 | 类型 | 说明 |
|---|---|---|
location | location 表 | 降下闪电的位置 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
context.world:run_empowered_lightning_task_at_location(context.boss:get_location())
context.boss:send_message("&eFeel the power of the storm!")
end
}
world:spawn_fake_gold_nugget_at_location(location, velocity, hasGravity)
通过数据包为附近玩家显示金粒,玩家和漏斗无法拾取。仅创建它不会使其移动或造成伤害。应将其作为一批投射物传给 run_fake_gold_nugget_damage,调用一次即可,或者显式移除。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
location | location 表 | 生成位置 | |
velocity | vector 表 | 初始速度 | |
hasGravity | 布尔值 | false | 该弹射物是否受重力影响 |
返回假投射物表,位置或向量无法解析时返回 nil。表包含 get_location()、set_gravity(bool)、remove()、is_removed() 方法。
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("nugget", 60) then return end
local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
dir = context.vectors.normalize_vector(dir)
local nugget = context.world:spawn_fake_gold_nugget_at_location(
context.boss:get_location(),
{ x = dir.x, y = dir.y, z = dir.z }
)
if nugget ~= nil then
context.world:run_fake_gold_nugget_damage({ nugget })
end
end
}
world:run_fake_gold_nugget_damage(projectiles)
启动独立 Bukkit 任务,每游戏刻移动并检查整批投射物。每批只调用一次,每次调用都会创建新任务。它在新位置查询半尺寸为 0.5 的方框内的生物,跳过发起攻击的 Boss 和正在格挡的玩家,并通过 Boss 伤害规则提交 1 点自定义伤害。即使伤害被拒绝,碰撞仍可能移除投射物。触地或任务达到 100 游戏刻也会移除它。这是采样碰撞检查,不是连续射线检测;关闭或暂停 Lua 实例不会取消该任务。
| 参数 | 类型 | 说明 |
|---|---|---|
projectiles | 表 | 由 spawn_fake_gold_nugget_at_location 返回的假弹射物表的数组 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
-- Keep this batch separate from later combat entries.
local projectiles = {}
local loc = context.boss:get_location()
for i = 1, 5 do
local angle = (i / 5) * math.pi * 2
local nugget = context.world:spawn_fake_gold_nugget_at_location(
loc,
{ x = math.cos(angle) * 0.5, y = 0.3, z = math.sin(angle) * 0.5 }
)
if nugget ~= nil then table.insert(projectiles, nugget) end
end
-- Start the batch once; the helper runs its own per-tick task.
context.world:run_fake_gold_nugget_damage(projectiles)
-- Remove any surviving projectiles after 3 seconds.
context.scheduler:run_after(60, function()
for _, projectile in ipairs(projectiles) do
projectile:remove()
end
end)
end
}
world:generate_player_loot(times)
运行正常的玩家战利品生成流程 times 次,非正值不执行。要求启用 eliteLoot、未触发防利用状态、已加载玩家数据,并记录了至少最大生命值 10% 的伤害。副本奖励锁定中的玩家会被跳过。每次可能发放金币,启用随机战利品时,还会按照正常设置和队伍规则生成随机或特殊战利品及卷轴。不会重新执行所有自定义掉落,也不保证每次必出一件物品。重复调用会增加奖励尝试次数,没有每个 Boss 只能执行一次的保护。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
times | 整数 | 1 | 战利品掷取次数 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.5 and not context.boss:has_tag("bonus_loot") then
context.boss:add_tag("bonus_loot")
context.world:generate_player_loot(2)
context.boss:send_message("&6Bonus loot drops!")
end
end
}
world:drop_bonus_coins(multiplier)
为记录伤害严格超过 Boss 最大生命值 10% 的合格玩家掉落额外金币。跳过 NPC 和缺少已加载数据的玩家。奖励按 Boss 奖励等级及 multiplier 缩放。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
multiplier | 数字 | 2.0 | 金币数量倍率 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
local pct = context.boss:get_health() / context.boss:get_maximum_health()
if pct < 0.25 and not context.boss:has_tag("bonus_coins") then
context.boss:add_tag("bonus_coins")
context.world:drop_bonus_coins(3.0)
context.boss:send_message("&6Gold spills everywhere!")
end
end
}
context.vectors
向量数学辅助工具接受示例中的点语法,也支持冒号语法。输入可以使用命名字段 x、y、z、数字索引 1..3,或嵌套的 direction 表。缺失分量为 0。结果是新表,不会修改输入。
| 方法 | 返回值 | 说明 |
|---|---|---|
vectors.get_vector_between_locations(loc1, loc2[, options]) | vector 表 | 位移 loc2 - loc1,默认不归一化 |
vectors.normalize_vector(vec) | vector 表 | 非零输入得到单位向量;零向量仍为零 |
vectors.rotate_vector(vec, pitch, yaw) | vector 表 | 先绕世界 X 轴,再绕世界 Y 轴旋转,单位为度 |
所有 vector 表都包含 x、y、z 字段。
vectors.get_vector_between_locations(loc1, loc2, options)
| 参数 | 类型 | 说明 |
|---|---|---|
loc1 | location 表 | 起点 |
loc2 | location 表 | 终点 |
options | 表(可选) | 后处理选项(见下文) |
向量选项
| 键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
normalize | 布尔值 | false | 对结果向量做归一化 |
multiplier | 数字 | 1.0 | 缩放该向量 |
offset | vector 表 | nil | 加上一个偏移向量 |
选项按顺序执行:归一化非零位移,乘以倍率,再加世界轴偏移。位置无法解析或位于不同世界时,在应用任何选项前直接返回零向量。有效但重合的位置仍可加上偏移。
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("dash", 100) then return end
-- Compute a normalized direction from boss to player, scaled to speed 2
local dir = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location(),
{ normalize = true, multiplier = 2.0 }
)
-- Launch the boss toward the player
context.boss:set_velocity_vector(dir)
end
}
vectors.normalize_vector(vec)
| 参数 | 类型 | 说明 |
|---|---|---|
vec | vector 表 | 输入向量 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
local raw = context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
local unit = context.vectors.normalize_vector(raw)
context.log:info("Direction: " .. unit.x .. ", " .. unit.y .. ", " .. unit.z)
end
}
vectors.rotate_vector(vec, pitch, yaw)
| 参数 | 类型 | 说明 |
|---|---|---|
vec | vector 表 | 输入向量 |
pitch | 数字 | 绕 X 轴旋转的角度 |
yaw | 数字 | 绕 Y 轴旋转的角度 |
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then return end
if not context.cooldowns:check_local("spread_shot", 100) then return end
local forward = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(
context.boss:get_location(),
context.player:get_location()
)
)
-- Fire three fireballs in a spread pattern
for _, yaw_offset in ipairs({ -30, 0, 30 }) do
local dir = context.vectors.rotate_vector(forward, 0, yaw_offset)
context.boss:summon_projectile(
"FIREBALL",
context.boss:get_eye_location(),
{
x = context.boss:get_location().x + dir.x * 10,
y = context.boss:get_location().y + dir.y * 10,
z = context.boss:get_location().z + dir.z * 10,
world = context.boss:get_location().world
},
1.0
)
end
end
}
你可以在循环中旋转一个基准向量,从而构建出一组扩散方向:
local base = context.vectors.normalize_vector(
context.vectors.get_vector_between_locations(boss_loc, target_loc)
)
for angle = 0, 330, 30 do
local dir = context.vectors.rotate_vector(base, 0, angle)
-- Use dir for spawning projectiles in a ring
end
context.settings
以只读方式访问能力配置。此方法在调用时读取当前设置,不会自动禁止粒子或其他效果。脚本需要根据返回值决定是否显示预警。
| 方法 | 返回值 | 说明 |
|---|---|---|
settings:warning_visual_effects_enabled() | 布尔值 | 怪物战斗设置中是否启用了警示视觉特效 |
示例
return {
api_version = 1,
on_enter_combat = function(context)
if context.settings:warning_visual_effects_enabled() then
context.world:spawn_particle_at_location(context.boss:get_location(), {
particle = "DUST",
amount = 20,
red = 255, green = 0, blue = 0,
})
end
end
}
context.event
当前钩子的事件数据。可用字段取决于底层事件,使用可选字段前应检查。数值伤害设置方法必须使用点语法,例如 event.set_damage_amount(value);transfer_damage 支持点和冒号语法。Boss 事件表不提供共享事件表中的 cancel、uncancel 或 is_cancelled。
| 字段或方法 | 可用时机 | 说明 |
|---|---|---|
event.damage_amount | 伤害类钩子 | 延迟创建的事件表首次解析时的伤害快照 |
event.get_damage_amount() | 伤害类钩子 | 读取修改后的当前伤害值 |
event.damage_cause | 伤害类钩子 | Bukkit DamageCause 枚举名称(例如 "ENTITY_ATTACK") |
event.cancel_event() | 可取消的事件 | 取消该事件 |
event.set_damage_amount(value) | 基于 EliteDamageEvent 的钩子 | 直接设置伤害值 |
event.multiply_damage_amount(multiplier) | 基于 EliteDamageEvent 的钩子 | 对当前伤害做乘法 |
event.damager | 带有伤害来源实体的伤害事件 | 原始 Bukkit 伤害来源包装器;投射物命中时是投射物本身,不是发射者 |
event.projectile | 伤害来源是弹射物的伤害事件 | 弹射物的实体引用包装器 |
event.spawn_reason | on_spawn | 生成原因的枚举名称 |
event.entity | 玩家对 Boss 的伤害、on_death、区域事件 | 受伤 Boss、死亡实体或穿越区域的实体;增援受伤时为该增援 |
event.is_damage_transfer | 玩家对 Boss 的伤害,包括增援转发 | 此伤害是否由 transfer_damage 转移而来 |
event:transfer_damage(target, amount) | 玩家对 Boss 的伤害,包括增援转发 | 向另一个符合条件的精英实体提交独立伤害;详见 伤害转移规则 |
示例:把受到的伤害减半
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil then
local dmg = context.event.damage_amount
context.log:info("Boss took " .. dmg .. " damage, halving it")
context.event.multiply_damage_amount(0.5)
end
end
}
示例:取消来自弹射物的伤害
示例
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.event ~= nil and context.event.damage_cause == "PROJECTILE" then
context.event.cancel_event()
if context.player ~= nil then
context.player:send_message("&cThe boss deflects your projectile!")
end
end
end
}
示例:读取伤害来源
示例
return {
api_version = 1,
on_player_damaged_by_boss = function(context)
if context.event ~= nil then
context.log:info("Damage cause: " .. (context.event.damage_cause or "unknown"))
end
end
}
damage_amount是一个快照。在调用set_damage_amount()或multiply_damage_amount()之后,它不会自动刷新。- 调度回调收到的新上下文中
event = nil。即使保存了原钩子上下文,也不能在事件结束后有效修改它;应在事件钩子执行期间修改事件。 - 伤害设置方法修改的是待处理事件,不是已经损失的生命值。后续监听器仍可修改或取消伤害。成功转移会提交额外的一次伤害,不会自动减少或取消原伤害。
