bayuMIR/Mirserver/Mir200/Envir/QuestDiary/游戏功能/A0_通用类/MainLineTask.lua
2026-06-22 00:12:04 +08:00

411 lines
No EOL
12 KiB
Lua

MainLineTaskOBJ = {}
MainLineTaskOBJ._name = "MainLineTaskOBJ"
MainLineTaskOBJ.STATUS_WAIT_VISIT = 0
MainLineTaskOBJ.STATUS_DOING = 1
MainLineTaskOBJ.STATUS_FINISH = 9
MainLineTaskOBJ.cfg = Func.require("cfg_Ö÷ÏßÈÎÎñ")
local function appendCfgValue(list, value)
if value == nil or value == "" or tonumber(value) == 0 then
return
end
table.insert(list, value)
end
local function normalizeTaskCfg(cfg)
for id, task in pairs(cfg or {}) do
task.id = tonumber(task.id or id) or id
if not task.visit and task.visit_type and task.visit_type ~= "" then
local visit = { type = task.visit_type }
if visit.type == "module" then
visit.keys = {}
appendCfgValue(visit.keys, task.visit_keys_1)
if #visit.keys <= 0 and task.ShouChongOBJ ~= nil then
table.insert(visit.keys, "ShouChongOBJ")
end
if #visit.keys <= 0 and task.visit_open and task.visit_open ~= "" then
table.insert(visit.keys, string.gsub(task.visit_open, "_main$", ""))
end
if task.visit_open and task.visit_open ~= "" then
visit.open = task.visit_open
end
elseif visit.type == "npc" then
visit.ids = {}
appendCfgValue(visit.ids, task.visit_ids_1)
visit.scripts = {}
appendCfgValue(visit.scripts, task.visit_scripts_1)
end
task.visit = visit
end
if not task.target and task.target_type and task.target_type ~= "" then
task.target = {
type = task.target_type,
count = tonumber(task.target_count) or 0,
map = task.target_map,
mon = task.target_mon,
}
end
if not task.rewards then
task.rewards = {}
for _, reward in ipairs(task.reward or {}) do
table.insert(task.rewards, {
reward.type,
reward.name,
tonumber(reward.num) or 0,
tonumber(reward.bind) or 0,
})
end
end
end
return cfg
end
MainLineTaskOBJ.cfg = normalizeTaskCfg(MainLineTaskOBJ.cfg)
function MainLineTaskOBJ:getTask(id)
return self.cfg[tonumber(id or 1)]
end
function MainLineTaskOBJ:setTask(id, cfg)
if not id or not cfg then
return false
end
cfg.id = tonumber(id)
self.cfg[tonumber(id)] = cfg
return true
end
function MainLineTaskOBJ:deleteTask(id)
id = tonumber(id)
if not id then
return false
end
self.cfg[id] = nil
return true
end
function MainLineTaskOBJ:getValidTask(id)
id = tonumber(id)
if not id then
return nil
end
local task = self:getTask(id)
local guard = 0
while task and task.enabled == false and task.next and guard < 100 do
task = self:getTask(task.next)
guard = guard + 1
end
return task
end
function MainLineTaskOBJ:getTaskId(actor)
local id = Player.getint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñID"]) or 0
if id <= 0 then
id = 1
self:setState(actor, id, self.STATUS_WAIT_VISIT, 0)
end
local task = self:getValidTask(id)
if task and task.id ~= id then
id = task.id
local status = task.finish and self.STATUS_FINISH or self.STATUS_WAIT_VISIT
self:setState(actor, id, status, 0)
elseif not task then
id = 9
self:setState(actor, id, self.STATUS_FINISH, 0)
end
return id
end
function MainLineTaskOBJ:getStatus(actor)
return Player.getint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ״̬"]) or self.STATUS_WAIT_VISIT
end
function MainLineTaskOBJ:getProgress(actor)
return Player.getint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ½ø¶È"]) or 0
end
function MainLineTaskOBJ:setState(actor, id, status, progress)
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñID"], id)
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ״̬"], status)
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ½ø¶È"], progress or 0)
end
function MainLineTaskOBJ:contains(list, value)
if not list then
return false
end
for _, v in ipairs(list) do
if tostring(v) == tostring(value) then
return true
end
end
return false
end
function MainLineTaskOBJ:visitMatched(task, visitKey, npcID, sScript)
if not task or not task.visit then
return false
end
local visit = task.visit
if visit.type == "module" then
return self:contains(visit.keys, visitKey)
end
if visit.type == "npc" then
return self:contains(visit.ids, npcID) or self:contains(visit.scripts, sScript)
end
return false
end
function MainLineTaskOBJ:getRewardView(task)
local itemRewards = {}
local moneyRewards = {}
for _, reward in ipairs((task and task.rewards) or {}) do
local rtype = reward[1]
local name = reward[2]
local num = tonumber(reward[3]) or 0
local bind = tonumber(reward[4]) or 0
if name and num > 0 then
if rtype == "item" then
table.insert(itemRewards, { name = name, count = num, bind = bind, type = rtype })
elseif rtype == "money" then
table.insert(itemRewards, { name = name, count = num, bind = 0, type = rtype })
table.insert(moneyRewards, { name = name, count = num })
end
end
end
return itemRewards, moneyRewards
end
function MainLineTaskOBJ:getTaskView(actor)
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task then
task = self.cfg[9]
id = 9
self:setState(actor, id, self.STATUS_FINISH, 0)
end
local status = self:getStatus(actor)
local progress = self:getProgress(actor)
local target = task and task.target or nil
local need = target and target.count or 0
if task and task.finish then
status = self.STATUS_FINISH
progress = 0
need = 0
end
local statusText = "´ý°Ý·Ã"
local desc = task and task.desc or ""
if status == self.STATUS_DOING then
statusText = "½øÐÐÖÐ"
desc = task.doingDesc or desc
elseif status == self.STATUS_FINISH or (task and task.finish) then
statusText = "ÒÑÍê³É"
desc = task.desc or "Ö÷ÏßÈÎÎñÒÑÍê³É¡£"
end
local rewardItems, rewardMoneys = self:getRewardView(task)
return {
id = task and task.id or id,
title = task and task.title or "[Ö÷Ïß]ÈÎÎñ",
desc = desc,
status = status,
statusText = statusText,
progress = progress,
need = need,
rewardText = task and task.rewardText or "",
rewardItems = rewardItems,
rewardMoneys = rewardMoneys,
finish = task and task.finish and true or false,
}
end
function MainLineTaskOBJ:sync(actor)
if not isnotnull(actor) then
return
end
if self:tryCompleteReady(actor) then
return
end
Message:SubLink(actor, self._name .. "_sync", self:getTaskView(actor))
end
function MainLineTaskOBJ:startTask(actor, task)
self:setState(actor, task.id, self.STATUS_DOING, 0)
Func.sendmsg9(actor, string.format("[Ö÷ÏßÈÎÎñ]:#70|ÒѽÓÈ¡£º%s", task.title))
self:sync(actor)
end
function MainLineTaskOBJ:onVisit(actor, visitKey)
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task or task.finish or self:getStatus(actor) ~= self.STATUS_WAIT_VISIT then
self:sync(actor)
return
end
if self:visitMatched(task, visitKey, nil, nil) then
self:startTask(actor, task)
else
self:sync(actor)
end
end
function MainLineTaskOBJ:onVisitNpc(actor, npcID, sScript)
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task or task.finish or self:getStatus(actor) ~= self.STATUS_WAIT_VISIT then
self:sync(actor)
return
end
if self:visitMatched(task, nil, npcID, sScript) then
self:startTask(actor, task)
else
self:sync(actor)
end
end
function MainLineTaskOBJ:giveItemRewards(actor, items)
if #items <= 0 then
return
end
local itemStrs = {}
for _, item in ipairs(items) do
table.insert(itemStrs, string.format("%s#%s#%s", item[1], item[2], item[3] or 0))
end
gives(actor, table.concat(itemStrs, "&"), "Ö÷ÏßÈÎÎñ")
end
function MainLineTaskOBJ:giveRewards(actor, rewards)
local items = {}
for _, reward in ipairs(rewards or {}) do
local rtype = reward[1]
local name = reward[2]
local num = tonumber(reward[3]) or 0
local bind = tonumber(reward[4]) or 0
if rtype == "money" then
local moneyId = ConstCfg.sysMoney[name]
if moneyId and num > 0 then
changemoney(actor, moneyId, "+", num, "Ö÷ÏßÈÎÎñ", true)
end
elseif rtype == "item" and name and num > 0 then
table.insert(items, { name, num, bind })
end
end
self:giveItemRewards(actor, items)
end
function MainLineTaskOBJ:completeTask(actor, task)
self:giveRewards(actor, task.rewards)
Func.sendmsg9(actor, string.format("[Ö÷ÏßÈÎÎñ]:#70|Íê³É%s£¬½±ÀøÒÑ·¢·Å¡£", task.title))
local nextTask = self:getValidTask(task.next)
if nextTask then
if nextTask.finish then
self:setState(actor, nextTask.id, self.STATUS_FINISH, 0)
else
self:setState(actor, nextTask.id, self.STATUS_WAIT_VISIT, 0)
end
else
self:setState(actor, 9, self.STATUS_FINISH, 0)
end
self:sync(actor)
end
function MainLineTaskOBJ:tryCompleteReady(actor)
if self:getStatus(actor) ~= self.STATUS_DOING then
return false
end
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task or not task.target or task.target.type ~= "kill_mon" then
return false
end
local need = tonumber(task.target.count) or 0
if need > 0 and self:getProgress(actor) >= need then
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ½ø¶È"], need)
self:completeTask(actor, task)
return true
end
return false
end
function MainLineTaskOBJ:onKillMon(actor, mon, itype, kill, monName, mapID)
if self:getStatus(actor) ~= self.STATUS_DOING then
return
end
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task or not task.target or task.target.type ~= "kill_mon" then
return
end
local target = task.target
if target.map and target.map ~= "*" and tostring(target.map) ~= tostring(mapID) then
return
end
if target.mon and target.mon ~= "*" and tostring(target.mon) ~= tostring(monName) then
return
end
local need = tonumber(target.count) or 0
local progress = self:getProgress(actor) + 1
if progress >= need then
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ½ø¶È"], need)
self:completeTask(actor, task)
else
Player.setint(actor, VarCfg.Player.int["Ö÷ÏßÈÎÎñ½ø¶È"], progress)
self:sync(actor)
end
end
GameEvent.add(EventCfg.onLogin, function(actor)
MainLineTaskOBJ:sync(actor)
end, MainLineTaskOBJ)
GameEvent.add(EventCfg.onqfloadend, function(actor)
MainLineTaskOBJ:sync(actor)
end, MainLineTaskOBJ)
GameEvent.add(EventCfg.onKillMon, function(actor, mon, itype, kill, monName, mapID)
MainLineTaskOBJ:onKillMon(actor, mon, itype, kill, monName, mapID)
end, MainLineTaskOBJ)
MainLineTaskOBJ.allowFunc = { "query", "visit", "route" }
function MainLineTaskOBJ:query(actor)
self:sync(actor)
end
function MainLineTaskOBJ:route(actor)
if not isnotnull(actor) then
return
end
if self:getStatus(actor) ~= self.STATUS_WAIT_VISIT then
return
end
local id = self:getTaskId(actor)
local task = self:getValidTask(id)
if not task or task.finish or not task.visit then
return
end
local visit = task.visit
if visit.type == "module" and visit.open then
Message:SubLink(actor, visit.open)
return
end
if visit.type == "npc" and visit.ids and visit.ids[1] then
opennpcshowex(actor, tonumber(visit.ids[1]), 6, 2)
end
end
function MainLineTaskOBJ:visit(actor, p1, p2, p3, data)
local visitKey = p1
if type(data) == "table" then
visitKey = data[1] or data.visitKey or visitKey
end
if visitKey then
self:onVisit(actor, visitKey)
else
self:sync(actor)
end
end
return MainLineTaskOBJ