local monster = {}
function monster:main(actor)
local mark = getflagstatus(actor, 700)
if mark == 0 then
p(222222222)
local player_x = getbaseinfo(actor, 4) -- 获取玩家X坐标
local player_y = getbaseinfo(actor, 5) -
🤖 回答引擎: 后端Lua |
🕒 时间: 2026-04-19 18:26:27 |
👁️ 阅读: 9
我是lua后端老师!
小仙,看到你的代码了,想给宝宝划个活动圈,不让它跑太远是吧?这个需求很常见,咱们用996引擎的 `setmonmaster` 和 `setmonmaster` 的参数就能搞定。
不过,你提供的代码里有几个小问题咱们先调整一下:
1. 你用了 `p(222222222)`,这个函数在996里不是标准输出,应该用 `release_print`。
2. `genmon` 和 `recallmobex` 都召唤了宝宝,逻辑上有点重复了。通常我们只用其中一个。
3. `lib:msg` 这个函数在标准库里没有,发消息给玩家要用 `sendmsg`。
要让宝宝固定在人物周围,关键在于正确使用 `recallmobex` 函数。根据资料,这个函数有一个 `inherit` 参数,它可以让宝宝“继承”人物的部分状态,但这主要指的是伤害百分比。要限制活动范围,我们需要结合其他思路。
一个更直接有效的方法是:**不依赖宝宝自身的AI寻路,而是通过定时器 (`ontimer`) 定期检查宝宝与主人的距离,如果超出范围,就立即将宝宝传送回主人身边。**
下面我给你一个修改后的示例,它实现了以下功能:
1. 只在玩家没有标记时召唤一次宝宝。
2. 为每个宝宝启动一个定时器,定期检查距离。
3. 如果宝宝离主人超过指定格子数,就将其传送回主人脚下。
```lua
local monster = {}
function monster:main(actor)
local mark = getflagstatus(actor, 700)
if mark == 0 then
release_print("玩家", actor, "开始召唤宝宝流程")
local player_x = getbaseinfo(actor, 4) -- 获取玩家X坐标
local player_y = getbaseinfo(actor, 5) -- 获取玩家Y坐标
local monname = "新加一" -- 怪物名称
-- 最大允许距离(格子数)
local max_distance = 5
-- 使用 recallmobex 召唤宝宝,参数含义见注释
local mons = recallmobex(actor, monname, player_x, player_y, 0, 1, 65535, 0, 1, 1, 1, 0, 0, "")
-- 参数解释:
-- actor: 主人
-- monname: 怪物名
-- x, y: 出生坐标(和主人相同)
-- level: 0级
-- count: 1个
-- time: 65535分钟(超长时间)
-- color: 0(不变色)
-- ignore: 1(M2检测数量时忽略这个宝宝)
-- nolevelup: 1(宝宝不升级)
-- hide: 1(隐藏主人名)
-- inherit: 0(不继承人物伤害)
-- hp: 0(使用默认血量)
-- buff: ""(无附加BUFF)
if mons and #mons > 0 then
for i, mon_obj in ipairs(mons) do
-- 设置怪物主人,这一步很重要,决定了怪物归属
setmonmaster(mon_obj, actor)
release_print("宝宝", i, "召唤成功,对象ID:", mon_obj)
-- 为这个宝宝启动一个专属的定时器,每2秒检查一次距离
-- 定时器ID可以设计为 70000 + i,避免和其他定时器冲突
local timerId = 70000 + i
setontimer(actor, timerId, 2) -- 2秒触发一次
-- 我们需要把宝宝对象和最大距离信息存起来,供定时器触发时使用
-- 这里用 setplayvar 存储到玩家变量中(简单演示,实际项目可能需要更复杂的管理)
-- 格式:宝宝对象ID#最大距离
setplayvar(actor, tostring(timerId), mon_obj .. "#" .. max_distance)
end
sendmsg(actor, "你获得了" .. monname .. "宝宝,它将跟随在你身边")
setflagstatus(actor, 700, 1) -- 设置标记为1,表示已召唤
else
sendmsg(actor, "召唤宝宝失败!")
end
else
-- 如果已经召唤过,给个提示
sendmsg(actor, "你已经召唤过宝宝了")
end
end
-- 定义一个定时器触发函数,需要在QF中注册 ontimer(70001) 等
-- 注意:这个函数需要你在QF(QuestDiary)文件夹下的对应脚本中注册事件触发
function monster:ontimer(actor, timerId)
-- 检查是否是我们的宝宝定时器(ID在70001-70005之间,对应5个宝宝)
if timerId >= 70001 and timerId <= 70005 then
local var_str = getplayvar(actor, tostring(timerId))
if var_str ~= "" then
local t = {}
for k, v in string.gmatch(var_str, "([^#]+)") do
table.insert(t, k)
end
local mon_obj = t[1]
local max_distance = tonumber(t[2])
-- 检查宝宝对象是否还有效
if ismon(mon_obj) then
local owner = getmonmaster(mon_obj)
-- 检查宝宝是否还属于这个玩家
if owner == actor then
local mon_x = getbaseinfo(mon_obj, 4)
local mon_y = getbaseinfo(mon_obj, 5)
local player_x = getbaseinfo(actor, 4)
local player_y = getbaseinfo(actor, 5)
-- 计算距离(简单的曼哈顿距离,也可用几何距离)
local distance = math.abs(mon_x - player_x) + math.abs(mon_y - player_y)
-- release_print("宝宝距离检查:", distance, "最大允许:", max_distance)
if distance > max_distance then
-- 超出范围,传送宝宝到玩家脚下
mapmove(mon_obj, getbaseinfo(actor, 0), player_x, player_y) -- 参数:对象,地图名,X,Y
release_print("宝宝", mon_obj, "超出范围,已传送回主人身边")
end
else
-- 宝宝不属于玩家了(可能死亡或叛变),清除定时器和变量
setofftimer(actor, timerId)
setplayvar(actor, tostring(timerId), "")
release_print("宝宝", mon_obj, "已脱离,定时器清理")
end
else
-- 宝宝对象已不存在,清除定时器和变量
setofftimer(actor, timerId)
setplayvar(actor, tostring(timerId), "")
release_print("宝宝对象已失效,定时器清理")
end
end
end
end
return monster
```
**核心要点和后续步骤:**
1. **距离控制**:代码通过定时器持续计算宝宝与主人的坐标差,一旦超出 `max_distance`(这里设为5格),就使用 `mapmove` 将宝宝传回。
2. **定时器管理**:我们为每个宝宝分配了一个独立的定时器ID,并将其与宝宝对象信息绑定存储在玩家变量中。当宝宝死亡或消失时,定时器会被清理。
3. **QF脚本注册**:上面的 `monster:ontimer` 函数**不会自动生效**。你需要在服务端的 `QuestDiary` 系统文件夹中,找到对应的脚本(比如 `\QuestDiary\你的脚本系统\monster.lua`),并在其顶部或关联的QF文件中,注册定时器事件。例如:
```lua
-- 在QF文件中或脚本初始化部分添加
function ontimer_70001(actor)
require("你的脚本路径.monster"):ontimer(actor, 70001)
end
```
(注意:实际注册方式取决于你的项目结构,你可能需要查阅996引擎的QF事件绑定文档。)
4. **优化建议**:对于多个宝宝,上述存储方式在变量管理上可能显得简陋。在实际大型系统中,你可能会用更结构化的方式(如用 `setplayvar` 存储一个序列化的table,或用 `ini` 文件)来管理所有宝宝的信息。
这个方案的核心思想是“主动拉回”,而不是依赖引擎的默认跟随逻辑。这样就能确保宝宝永远不会跑出你规定的圈子了。
小仙,先试试这个思路,如果还有不明白的,随时再来问我!
我是lua后端老师!
小仙,看到你的代码了,想给宝宝划个活动圈,不让它跑太远是吧?这个需求很常见,咱们用996引擎的 `setmonmaster` 和 `setmonmaster` 的参数就能搞定。
不过,你提供的代码里有几个小问题咱们先调整一下:
1. 你用了 `p(222222222)`,这个函数在996里不是标准输出,应该用 `release_print`。
2. `genmon` 和 `recallmobex` 都召唤了宝宝,逻辑上有点重复了。通常我们只用其中一个。
3. `lib:msg` 这个函数在标准库里没有,发消息给玩家要用 `sendmsg`。
要让宝宝固定在人物周围,关键在于正确使用 `recallmobex` 函数。根据资料,这个函数有一个 `inherit` 参数,它可以让宝宝“继承”人物的部分状态,但这主要指的是伤害百分比。要限制活动范围,我们需要结合其他思路。
一个更直接有效的方法是:**不依赖宝宝自身的AI寻路,而是通过定时器 (`ontimer`) 定期检查宝宝与主人的距离,如果超出范围,就立即将宝宝传送回主人身边。**
下面我给你一个修改后的示例,它实现了以下功能:
1. 只在玩家没有标记时召唤一次宝宝。
2. 为每个宝宝启动一个定时器,定期检查距离。
3. 如果宝宝离主人超过指定格子数,就将其传送回主人脚下。
```lua
local monster = {}
function monster:main(actor)
local mark = getflagstatus(actor, 700)
if mark == 0 then
release_print("玩家", actor, "开始召唤宝宝流程")
local player_x = getbaseinfo(actor, 4) -- 获取玩家X坐标
local player_y = getbaseinfo(actor, 5) -- 获取玩家Y坐标
local monname = "新加一" -- 怪物名称
-- 最大允许距离(格子数)
local max_distance = 5
-- 使用 recallmobex 召唤宝宝,参数含义见注释
local mons = recallmobex(actor, monname, player_x, player_y, 0, 1, 65535, 0, 1, 1, 1, 0, 0, "")
-- 参数解释:
-- actor: 主人
-- monname: 怪物名
-- x, y: 出生坐标(和主人相同)
-- level: 0级
-- count: 1个
-- time: 65535分钟(超长时间)
-- color: 0(不变色)
-- ignore: 1(M2检测数量时忽略这个宝宝)
-- nolevelup: 1(宝宝不升级)
-- hide: 1(隐藏主人名)
-- inherit: 0(不继承人物伤害)
-- hp: 0(使用默认血量)
-- buff: ""(无附加BUFF)
if mons and #mons > 0 then
for i, mon_obj in ipairs(mons) do
-- 设置怪物主人,这一步很重要,决定了怪物归属
setmonmaster(mon_obj, actor)
release_print("宝宝", i, "召唤成功,对象ID:", mon_obj)
-- 为这个宝宝启动一个专属的定时器,每2秒检查一次距离
-- 定时器ID可以设计为 70000 + i,避免和其他定时器冲突
local timerId = 70000 + i
setontimer(actor, timerId, 2) -- 2秒触发一次
-- 我们需要把宝宝对象和最大距离信息存起来,供定时器触发时使用
-- 这里用 setplayvar 存储到玩家变量中(简单演示,实际项目可能需要更复杂的管理)
-- 格式:宝宝对象ID#最大距离
setplayvar(actor, tostring(timerId), mon_obj .. "#" .. max_distance)
end
sendmsg(actor, "你获得了" .. monname .. "宝宝,它将跟随在你身边")
setflagstatus(actor, 700, 1) -- 设置标记为1,表示已召唤
else
sendmsg(actor, "召唤宝宝失败!")
end
else
-- 如果已经召唤过,给个提示
sendmsg(actor, "你已经召唤过宝宝了")
end
end
-- 定义一个定时器触发函数,需要在QF中注册 ontimer(70001) 等
-- 注意:这个函数需要你在QF(QuestDiary)文件夹下的对应脚本中注册事件触发
function monster:ontimer(actor, timerId)
-- 检查是否是我们的宝宝定时器(ID在70001-70005之间,对应5个宝宝)
if timerId >= 70001 and timerId <= 70005 then
local var_str = getplayvar(actor, tostring(timerId))
if var_str ~= "" then
local t = {}
for k, v in string.gmatch(var_str, "([^#]+)") do
table.insert(t, k)
end
local mon_obj = t[1]
local max_distance = tonumber(t[2])
-- 检查宝宝对象是否还有效
if ismon(mon_obj) then
local owner = getmonmaster(mon_obj)
-- 检查宝宝是否还属于这个玩家
if owner == actor then
local mon_x = getbaseinfo(mon_obj, 4)
local mon_y = getbaseinfo(mon_obj, 5)
local player_x = getbaseinfo(actor, 4)
local player_y = getbaseinfo(actor, 5)
-- 计算距离(简单的曼哈顿距离,也可用几何距离)
local distance = math.abs(mon_x - player_x) + math.abs(mon_y - player_y)
-- release_print("宝宝距离检查:", distance, "最大允许:", max_distance)
if distance > max_distance then
-- 超出范围,传送宝宝到玩家脚下
mapmove(mon_obj, getbaseinfo(actor, 0), player_x, player_y) -- 参数:对象,地图名,X,Y
release_print("宝宝", mon_obj, "超出范围,已传送回主人身边")
end
else
-- 宝宝不属于玩家了(可能死亡或叛变),清除定时器和变量
setofftimer(actor, timerId)
setplayvar(actor, tostring(timerId), "")
release_print("宝宝", mon_obj, "已脱离,定时器清理")
end
else
-- 宝宝对象已不存在,清除定时器和变量
setofftimer(actor, timerId)
setplayvar(actor, tostring(timerId), "")
release_print("宝宝对象已失效,定时器清理")
end
end
end
end
return monster
```
**核心要点和后续步骤:**
1. **距离控制**:代码通过定时器持续计算宝宝与主人的坐标差,一旦超出 `max_distance`(这里设为5格),就使用 `mapmove` 将宝宝传回。
2. **定时器管理**:我们为每个宝宝分配了一个独立的定时器ID,并将其与宝宝对象信息绑定存储在玩家变量中。当宝宝死亡或消失时,定时器会被清理。
3. **QF脚本注册**:上面的 `monster:ontimer` 函数**不会自动生效**。你需要在服务端的 `QuestDiary` 系统文件夹中,找到对应的脚本(比如 `\QuestDiary\你的脚本系统\monster.lua`),并在其顶部或关联的QF文件中,注册定时器事件。例如:
```lua
-- 在QF文件中或脚本初始化部分添加
function ontimer_70001(actor)
require("你的脚本路径.monster"):ontimer(actor, 70001)
end
```
(注意:实际注册方式取决于你的项目结构,你可能需要查阅996引擎的QF事件绑定文档。)
4. **优化建议**:对于多个宝宝,上述存储方式在变量管理上可能显得简陋。在实际大型系统中,你可能会用更结构化的方式(如用 `setplayvar` 存储一个序列化的table,或用 `ini` 文件)来管理所有宝宝的信息。
这个方案的核心思想是“主动拉回”,而不是依赖引擎的默认跟随逻辑。这样就能确保宝宝永远不会跑出你规定的圈子了。
小仙,先试试这个思路,如果还有不明白的,随时再来问我!
← 返回问答库