示例:定时喊话器
本示例写一个「喊话器」:在界面上配置频道、间隔和多条喊话内容,任务按间隔循环或随机发送。
它串起了本教程的多个知识点:列表 + 子表单、Check / Main 分工、经 DoLuaString
调用游戏原生接口,以及 CurrentSettings 快照问题的处理。
目录结构
apps/作者@喊话器/
├── .hm.json
├── index.lua
└── ui/
├── index.lua
├── main.lua
└── form_add_message.lua
1. 清单
apps/作者@喊话器/.hm.json
{
"名称": "喊话器",
"作者": "作者",
"类型": "任务",
"版本": "v1.0",
"简介": "按频道与间隔自动喊话",
"仓库地址": "",
"依赖软件包": {}
}
2. 界面注册
apps/作者@喊话器/ui/index.lua
local main = require("ui.main")
local addMessage = require("ui.form_add_message")
function Init()
RegisterForm("main", main)
RegisterForm("addMessage", addMessage)
end
3. 主表单
apps/作者@喊话器/ui/main.lua
local main = {}
function main.uiSchema(form)
return {
type = "table",
children = {
{ type = "checkbox", field = "enabled", label = "启用喊话", default = false },
{ type = "select", field = "channel", label = "频道", default = "scene",
options = {
{ label = "附近", value = "near" },
{ label = "世界", value = "scene" },
{ label = "门派", value = "menpai" },
{ label = "帮会", value = "guild" },
{ label = "队伍", value = "team" },
},
},
{ type = "number", field = "intervalSec", label = "间隔(秒)", default = 30 },
{ type = "button", label = "添加喊话内容", event = "addMessage", class = "my-2",
click = function(f)
PushCommand(nil, "openForm", { formName = "addMessage", title = "添加喊话内容" })
end,
},
{ type = "list", field = "messages", label = "喊话内容列表",
titleKey = "label", deleteEnable = true, height = 200, default = {} },
},
}
end
function main.validateForm(form)
if form.enabled and #(form.messages or {}) == 0 then
return "启用前请至少添加一条喊话内容"
end
return nil
end
return main
4. 子表单
apps/作者@喊话器/ui/form_add_message.lua
local addMessage = {}
function addMessage.uiSchema()
return {
type = "table",
children = {
{ type = "input", field = "message", label = "喊话内容", default = "" },
},
}
end
function addMessage.validateForm(form)
if #(form.message or "") == 0 then
return "喊话内容不能为空"
end
return nil
end
function addMessage.submitForm(form)
-- 把内容推送到主表单的 messages 列表
PushCommand("messages", "addItems", { label = form.message })
return nil
end
return addMessage
5. 任务入口
apps/作者@喊话器/index.lua
local TASK_NAME = "作者@喊话器" -- 与目录名、.hm.json 一致
CheckTime = 1000
local lastSendAt = 0
-- 实时读取配置:CurrentSettings 只在启动时快照一次,
-- 若在任务运行中改了配置,需要这里才能读到最新值。
local function loadSettings()
local fresh = GetRoleSettings(TASK_NAME)
if type(fresh) == "table" and next(fresh) ~= nil then
return fresh
end
return CurrentSettings
end
local function getMessages(settings)
local list = {}
for _, item in ipairs(settings.messages or {}) do
if type(item.label) == "string" and #item.label > 0 then
table.insert(list, item.label)
end
end
return list
end
-- 经游戏环境发送喊话
local function sendShout(channel, text)
local code = string.format(
'if Talk and Talk.SendChatMessage then Talk:SendChatMessage("%s","%s") return 1 end return 0',
channel, text)
return tonumber(DoLuaStringAndGetInteger(code)) == 1
end
function Check()
local settings = loadSettings()
if not settings.enabled then return 0 end
if #getMessages(settings) == 0 then return 0 end
local interval = tonumber(settings.intervalSec) or 30
if os.time() - lastSendAt >= interval then
return 2 -- 返回 2:执行 Main 但不抢占其它任务
end
return 0
end
function Main()
local settings = loadSettings()
local messages = getMessages(settings)
if #messages == 0 then return end
local channel = settings.channel or "scene"
local text = messages[math.random(#messages)]
if sendShout(channel, text) then
GoPrint("已喊话:" .. text)
else
GoPrint("发送失败:未找到 Talk:SendChatMessage")
end
lastSendAt = os.time()
Delay(200)
end
关键点回顾
- 列表 + 子表单:主表单放
list,子表单用PushCommand("messages", "addItems", ...)回填。 Check/Main分工:Check只判断「到点没」,Main才真正发送。- 返回
2而非1:喊话不抢占打怪 / 挂机等主要任务。 - 实时读配置:用
GetRoleSettings(任务全名)拿到界面刚提交的值,避免「先启动后提交」不生效。 - 调用原生接口:
Talk:SendChatMessage需要在游戏环境执行,详见 游戏原生接口。
下一步:发布与安装。