GodsDescended = {} local this = {} ---@class GodsDescendedMonsterData ---@field monsterdata table> ---@class GodsDescendedMapMonsterData ---@field mapdata table ---@class GodsDescendedMonsterState ---@field id number ---@field cfgid number ---@field name string ---@field state number ---@field ownerid number ---@field ownername string ---@field mapid number ---@field date_id number this.monster_count = 2 this.act_open_tips_id = 331 this.monster_state = { none = 0, -- 未创建 life = 1, -- 存活中 died = 2, -- 已死亡 } GodsDescended.monster_state_list_key = "R$_gods_descended_monster_date_key" GodsDescended.monster_state_list_key_cross = "R$_gods_descended_monster_date_key_cross" function GodsDescended.sendMonsterStateData(actor) this.sendMonsterStateData(actor) end function GodsDescended.actorActivityChange(actor, activityId, action) if tonumber(activityId) == DuplicateType.GODS_DESCENDED then intervalcalldelay(actor, 2000, 1000, 1, "l_gods_descended_delaycallsendclientdata") if action == 1 then this.sendOpenTips(actor) end end end function GodsDescended.sysActivityChange(activityId, action) local success, result = xpcall(this.sysActivityChange, debug.traceback, activityId, action) gameDebug.assertPrint(success, "诸神降临活动初始化异常!", result, "参数", activityId, action) end function GodsDescended.monsterDie(monster, actor, monsterCfgId) local success, errorInfo = xpcall(this.monsterDie, debug.traceback, monster, actor, monsterCfgId) gameDebug.assertPrint(success, "怪物死亡更新诸神降临活动数据异常:", monster, actor, monsterCfgId, errorInfo) end function l_gods_descended_delaycallsendclientdata(actor) this.sendMonsterStateData(actor) end function GodsDescended.clearActivityCache() local serverType = getbaseinfo("servertype") if serverType == 1 then setsysvar(GodsDescended.monster_state_list_key, nil) else setsysvar(GodsDescended.monster_state_list_key_cross, nil, 1) end end function GodsDescended.serverHeart() local serverType = getbaseinfo("servertype") if serverType == 1 then return end local data_list = this.getMonsterStateList() if table.isEmpty(data_list) then return end local now = getbaseinfo("now") local has_change = false local all_rid_map = this.getAllOnlineRoleIds() for map_id, cfg_data_list in pairs(data_list) do for _, state_data_map in pairs(cfg_data_list) do for _, state_data in pairs(state_data_map) do local data = getmaxthreattarget(state_data.id, 1, map_id) local rid = (not table.isEmpty(data)) and data["rid"] or 0 -- 如果 ownerid 需要更新,才进行操作 if state_data.ownerid ~= tonumber(rid) and state_data.state ~= this.monster_state.died then state_data.ownerid = tonumber(rid) state_data.ownername = rid ~= 0 and getbaseinfo(getactor(rid), "rolename") or "" state_data.date_id = now has_change = true local ret_data = { [tonumber(map_id)] = state_data } this.debug("--- all_rid_map send data ---", all_rid_map, ret_data) for _, rid_list in pairs(all_rid_map) do for _, member_id in pairs(rid_list) do local member = getactor(member_id) local msg_id = LuaMessageIdToClient.RES_GODS_DESCENDED_MONSTER_STATE_CHANGE sendluamsg(member, msg_id, ret_data) end end end end end end if has_change then this.jprint("---- 怪物归属更新 持久化数据 ----") this.setMonsterStateData(data_list) end end function this.getAllOnlineRoleIds() local hosts = gethosts() if table.isEmpty(hosts) then this.jprint("获取Host为空!") end local all_rid_data = {} for _, host in pairs(hosts) do local rids = getallonlineroleids(host) if table.isEmpty(rids) then this.jprint("获取在线角色列表为空!") this.jprint("host") this.jprint(host) end all_rid_data[host] = rids end return all_rid_data end function this.sysActivityChange(activityId, action) if tonumber(action) == 1 then this.createMonster(activityId) else this.clearMonster() end end function this.sendOpenTips(actor) local level_limit = ConfigDataManager.getTableValue("cfg_activity_rule", "level", "id", DuplicateType.GODS_DESCENDED) if tonumber(level_limit) > 0 then local level = getbaseinfo(actor, "level") if tonumber(level_limit) > tonumber(level) then return end end noticeTip.noticeinfo(actor, this.act_open_tips_id) end function this.clearMonster() local data_list = this.getMonsterStateList() this.debug("-- 清理地图中的怪物 --", data_list) if table.isEmpty(data_list) then return end for map_id, monster_data in pairs(data_list) do for _, data in pairs(monster_data) do this.debug("-- map_id --", map_id, data) for _, state_data in pairs(data) do local monster = getactor(state_data.id, map_id) removemapobject(monster) end end end this.setMonsterStateData(nil) this.jprint("---- 移除地图中怪物 ----") --this.sendAllServerAndPlayerMsg(LuaMessageIdToClient.RES_GODS_DESCENDED_DATA, data_list) end function this.createMonster(activityId) this.clearMonster() local config_list = ConfigDataManager.getList("cfg_monster_attack") if table.isEmpty(config_list) then this.jprint("获取诸神降临配置信息失败!") return end this.jprint("----- 开始刷新诸神降临Boss -----") local monster_data_map = {} for _, config in pairs(config_list) do if tonumber(config.ruleid) ~= tonumber(activityId) then goto continue end this.monGenMonster(config, monster_data_map) :: continue :: end this.debug("-- monster_map --", monster_data_map) this.setMonsterStateData(monster_data_map) end function this.monGenMonster(config, monster_map) local map_cfg_id = tonumber(config.mapid) local map_line = config.line local positions = config.poz local range = config.range local monster_cfg_id = config.monid local monster_name = config.name local lines = string.split(map_line, "#") local poz = string.split(positions, "#") local now = getbaseinfo("now") for _, line in pairs(lines) do local map_id = gamemap.getMapKey(map_cfg_id, line) local mon_list = mongen(map_id, poz[1], poz[2], range, monster_cfg_id, this.monster_count) if not table.isEmpty(mon_list) then for _, monster in pairs(mon_list) do local monster_id = tonumber(monster:toString()) ---@type GodsDescendedMonsterState local monster_data = {} monster_data.id = monster_id monster_data.cfgid = monster_cfg_id monster_data.name = monster_name monster_data.state = this.monster_state.life monster_data.ownerid = 0 monster_data.ownername = "" monster_data.mapid = map_id monster_data.date_id = now this.debug("-- 生成怪物 --", monster_name, monster_data) local map_data_info = monster_map[tonumber(map_id)] if table.isNullOrEmpty(map_data_info) then map_data_info = {} end local monster_data_list = map_data_info[tonumber(monster_cfg_id)] if table.isNullOrEmpty(monster_data_list) then monster_data_list = {} end table.insert(monster_data_list, monster_data) map_data_info[tonumber(monster_cfg_id)] = monster_data_list monster_map[tonumber(map_id)] = map_data_info end end end end function this.sendMonsterStateData(actor) local list = this.getMonsterStateList(actor) this.debug("-- monster_data_map --", list) if table.isEmpty(list) then list = {} end -----@type GodsDescendedMonsterData local monster_data = {} monster_data.monsterdata = list --this.debug("发送诸神降临怪物状态数据", monster_data) --this.jprint(monster_data) sendluamsg(actor, LuaMessageIdToClient.RES_GODS_DESCENDED_DATA, monster_data) end function this.monsterDie(monster, actor, monsterCfgId) local monsterId = tonumber(monster:toString()) local map_id = getbaseinfo(monster, "unimapid") local state_data = this.getMonsterStateList(actor) if table.isEmpty(state_data) or table.isEmpty(state_data[tonumber(map_id)]) then return end ---@type GodsDescendedMonsterState[] local monster_cfg_data = state_data[tonumber(map_id)] if table.isEmpty(monster_cfg_data) then return end local list = monster_cfg_data[tonumber(monsterCfgId)] if table.isEmpty(list) then return end local now = getbaseinfo("now") local all_rid_map = this.getAllOnlineRoleIds() local has_change = false for _, monster_state in pairs(list) do if monster_state.state == this.monster_state.died or monster_state.id ~= monsterId then goto continue end monster_state.ownerid = actor:toString() monster_state.ownername = getbaseinfo(actor, "rolename") monster_state.state = this.monster_state.died monster_state.date_id = now has_change = true -- 同步发送的所有跨服服务器中在线的玩家 local ret_data = { [tonumber(map_id)] = monster_state } this.debug("--- all_rid_map send data ---", all_rid_map, ret_data) for _, rid_list in pairs(all_rid_map) do for _, member_id in pairs(rid_list) do local member = getactor(member_id) local msg_id = LuaMessageIdToClient.RES_GODS_DESCENDED_MONSTER_STATE_CHANGE sendluamsg(member, msg_id, ret_data) end end :: continue :: end this.debug("has_change", has_change) if not has_change then return end this.jprint("---- 击杀怪物 持久化数据 ----") this.setMonsterStateData(state_data) end ---@return table function this.getMonsterStateList_1() return getsysvar(GodsDescended.monster_state_list_key, 1) end ---@return table function this.getMonsterStateList(actor) local serverType = getbaseinfo("servertype") if serverType == 1 then this.debug("---- 获取本服数据 ----", data) if actor == nil then actor = getactor(0) end return getsysvar(actor, GodsDescended.monster_state_list_key) else this.debug("==== 获取跨服数据 ====", data) return getsysvar(GodsDescended.monster_state_list_key_cross, 1) end end function this.setMonsterStateData(data) local serverType = getbaseinfo("servertype") -- 其他服务器关闭数据修改 if serverType == 1 then return end local hosts = gethosts() for _, host in pairs(hosts) do this.jprint("设置其他服务器数据:host") this.jprint(host) setsysvar(host, GodsDescended.monster_state_list_key, data) end this.debug("==== 设置跨服数据 ====", data) setsysvar(GodsDescended.monster_state_list_key_cross, data, 1) end -- -------------------------------------------------------------------------- -- -- 日志打印 this.log_open = false function this.debug(...) if not this.log_open then return end gameDebug.print(...) end function this.jprint(param) if not this.log_open then return end if param == nil then param = "error! 输出内容为空. nil" end jprint(param) end function this.loginfo(actor, param) if not this.log_open then return end if param == nil then param = "error! 日志输出内容为空. nil" end jprint(param) info(actor, param) end -- --------------------- GM 调试函数 -------------------- local gm_open = true function l_gods_descended_create_monster(actor) if not gm_open then return end this.createMonster(23001) end function l_gods_descended_send_monster_state_data(actor) if not gm_open then return end this.sendMonsterStateData(actor) end function l_gods_descended_remove_monster(actor) if not gm_open then return end this.clearMonster() end function l_gods_descended_clear_monster(actor) if not gm_open then return end clearmapmon(getbaseinfo(actor, "unimapid")) end