跳到主要内容

示例:定时喊话器

本示例写一个「喊话器」:在界面上配置频道、间隔和多条喊话内容,任务按间隔循环或随机发送。 它串起了本教程的多个知识点:列表 + 子表单、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 需要在游戏环境执行,详见 游戏原生接口。

下一步:发布与安装。