GodsDescended.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. GodsDescended = {}
  2. local this = {}
  3. ---@class GodsDescendedMonsterData
  4. ---@field monsterdata table<number, table<number, GodsDescendedMapMonsterData>>
  5. ---@class GodsDescendedMapMonsterData
  6. ---@field mapdata table<number, GodsDescendedMonsterState[]>
  7. ---@class GodsDescendedMonsterState
  8. ---@field id number
  9. ---@field cfgid number
  10. ---@field name string
  11. ---@field state number
  12. ---@field ownerid number
  13. ---@field ownername string
  14. ---@field mapid number
  15. ---@field date_id number
  16. this.monster_count = 2
  17. this.act_open_tips_id = 331
  18. this.monster_state = {
  19. none = 0, -- 未创建
  20. life = 1, -- 存活中
  21. died = 2, -- 已死亡
  22. }
  23. GodsDescended.monster_state_list_key = "R$_gods_descended_monster_date_key"
  24. GodsDescended.monster_state_list_key_cross = "R$_gods_descended_monster_date_key_cross"
  25. function GodsDescended.sendMonsterStateData(actor)
  26. this.sendMonsterStateData(actor)
  27. end
  28. function GodsDescended.actorActivityChange(actor, activityId, action)
  29. if tonumber(activityId) == DuplicateType.GODS_DESCENDED then
  30. intervalcalldelay(actor, 2000, 1000, 1, "l_gods_descended_delaycallsendclientdata")
  31. if action == 1 then
  32. this.sendOpenTips(actor)
  33. end
  34. end
  35. end
  36. function GodsDescended.sysActivityChange(activityId, action)
  37. local success, result = xpcall(this.sysActivityChange, debug.traceback, activityId, action)
  38. gameDebug.assertPrint(success, "诸神降临活动初始化异常!", result, "参数", activityId, action)
  39. end
  40. function GodsDescended.monsterDie(monster, actor, monsterCfgId)
  41. local success, errorInfo = xpcall(this.monsterDie, debug.traceback, monster, actor, monsterCfgId)
  42. gameDebug.assertPrint(success, "怪物死亡更新诸神降临活动数据异常:", monster, actor, monsterCfgId, errorInfo)
  43. end
  44. function l_gods_descended_delaycallsendclientdata(actor)
  45. this.sendMonsterStateData(actor)
  46. end
  47. function GodsDescended.clearActivityCache()
  48. local serverType = getbaseinfo("servertype")
  49. if serverType == 1 then
  50. setsysvar(GodsDescended.monster_state_list_key, nil)
  51. else
  52. setsysvar(GodsDescended.monster_state_list_key_cross, nil, 1)
  53. end
  54. end
  55. function GodsDescended.serverHeart()
  56. local serverType = getbaseinfo("servertype")
  57. if serverType == 1 then
  58. return
  59. end
  60. local data_list = this.getMonsterStateList()
  61. if table.isEmpty(data_list) then
  62. return
  63. end
  64. local now = getbaseinfo("now")
  65. local has_change = false
  66. local all_rid_map = this.getAllOnlineRoleIds()
  67. for map_id, cfg_data_list in pairs(data_list) do
  68. for _, state_data_map in pairs(cfg_data_list) do
  69. for _, state_data in pairs(state_data_map) do
  70. local data = getmaxthreattarget(state_data.id, 1, map_id)
  71. local rid = (not table.isEmpty(data)) and data["rid"] or 0
  72. -- 如果 ownerid 需要更新,才进行操作
  73. if state_data.ownerid ~= tonumber(rid) and state_data.state ~= this.monster_state.died then
  74. state_data.ownerid = tonumber(rid)
  75. state_data.ownername = rid ~= 0 and getbaseinfo(getactor(rid), "rolename") or ""
  76. state_data.date_id = now
  77. has_change = true
  78. local ret_data = { [tonumber(map_id)] = state_data }
  79. this.debug("--- all_rid_map send data ---", all_rid_map, ret_data)
  80. for _, rid_list in pairs(all_rid_map) do
  81. for _, member_id in pairs(rid_list) do
  82. local member = getactor(member_id)
  83. local msg_id = LuaMessageIdToClient.RES_GODS_DESCENDED_MONSTER_STATE_CHANGE
  84. sendluamsg(member, msg_id, ret_data)
  85. end
  86. end
  87. end
  88. end
  89. end
  90. end
  91. if has_change then
  92. this.jprint("---- 怪物归属更新 持久化数据 ----")
  93. this.setMonsterStateData(data_list)
  94. end
  95. end
  96. function this.getAllOnlineRoleIds()
  97. local hosts = gethosts()
  98. if table.isEmpty(hosts) then
  99. this.jprint("获取Host为空!")
  100. end
  101. local all_rid_data = {}
  102. for _, host in pairs(hosts) do
  103. local rids = getallonlineroleids(host)
  104. if table.isEmpty(rids) then
  105. this.jprint("获取在线角色列表为空!")
  106. this.jprint("host")
  107. this.jprint(host)
  108. end
  109. all_rid_data[host] = rids
  110. end
  111. return all_rid_data
  112. end
  113. function this.sysActivityChange(activityId, action)
  114. if tonumber(action) == 1 then
  115. this.createMonster(activityId)
  116. else
  117. this.clearMonster()
  118. end
  119. end
  120. function this.sendOpenTips(actor)
  121. local level_limit = ConfigDataManager.getTableValue("cfg_activity_rule", "level", "id", DuplicateType.GODS_DESCENDED)
  122. if tonumber(level_limit) > 0 then
  123. local level = getbaseinfo(actor, "level")
  124. if tonumber(level_limit) > tonumber(level) then
  125. return
  126. end
  127. end
  128. noticeTip.noticeinfo(actor, this.act_open_tips_id)
  129. end
  130. function this.clearMonster()
  131. local data_list = this.getMonsterStateList()
  132. this.debug("-- 清理地图中的怪物 --", data_list)
  133. if table.isEmpty(data_list) then
  134. return
  135. end
  136. for map_id, monster_data in pairs(data_list) do
  137. for _, data in pairs(monster_data) do
  138. this.debug("-- map_id --", map_id, data)
  139. for _, state_data in pairs(data) do
  140. local monster = getactor(state_data.id, map_id)
  141. removemapobject(monster)
  142. end
  143. end
  144. end
  145. this.setMonsterStateData(nil)
  146. this.jprint("---- 移除地图中怪物 ----")
  147. --this.sendAllServerAndPlayerMsg(LuaMessageIdToClient.RES_GODS_DESCENDED_DATA, data_list)
  148. end
  149. function this.createMonster(activityId)
  150. this.clearMonster()
  151. local config_list = ConfigDataManager.getList("cfg_monster_attack")
  152. if table.isEmpty(config_list) then
  153. this.jprint("获取诸神降临配置信息失败!")
  154. return
  155. end
  156. this.jprint("----- 开始刷新诸神降临Boss -----")
  157. local monster_data_map = {}
  158. for _, config in pairs(config_list) do
  159. if tonumber(config.ruleid) ~= tonumber(activityId) then
  160. goto continue
  161. end
  162. this.monGenMonster(config, monster_data_map)
  163. :: continue ::
  164. end
  165. this.debug("-- monster_map --", monster_data_map)
  166. this.setMonsterStateData(monster_data_map)
  167. end
  168. function this.monGenMonster(config, monster_map)
  169. local map_cfg_id = tonumber(config.mapid)
  170. local map_line = config.line
  171. local positions = config.poz
  172. local range = config.range
  173. local monster_cfg_id = config.monid
  174. local monster_name = config.name
  175. local lines = string.split(map_line, "#")
  176. local poz = string.split(positions, "#")
  177. local now = getbaseinfo("now")
  178. for _, line in pairs(lines) do
  179. local map_id = gamemap.getMapKey(map_cfg_id, line)
  180. local mon_list = mongen(map_id, poz[1], poz[2], range, monster_cfg_id, this.monster_count)
  181. if not table.isEmpty(mon_list) then
  182. for _, monster in pairs(mon_list) do
  183. local monster_id = tonumber(monster:toString())
  184. ---@type GodsDescendedMonsterState
  185. local monster_data = {}
  186. monster_data.id = monster_id
  187. monster_data.cfgid = monster_cfg_id
  188. monster_data.name = monster_name
  189. monster_data.state = this.monster_state.life
  190. monster_data.ownerid = 0
  191. monster_data.ownername = ""
  192. monster_data.mapid = map_id
  193. monster_data.date_id = now
  194. this.debug("-- 生成怪物 --", monster_name, monster_data)
  195. local map_data_info = monster_map[tonumber(map_id)]
  196. if table.isNullOrEmpty(map_data_info) then
  197. map_data_info = {}
  198. end
  199. local monster_data_list = map_data_info[tonumber(monster_cfg_id)]
  200. if table.isNullOrEmpty(monster_data_list) then
  201. monster_data_list = {}
  202. end
  203. table.insert(monster_data_list, monster_data)
  204. map_data_info[tonumber(monster_cfg_id)] = monster_data_list
  205. monster_map[tonumber(map_id)] = map_data_info
  206. end
  207. end
  208. end
  209. end
  210. function this.sendMonsterStateData(actor)
  211. local list = this.getMonsterStateList(actor)
  212. this.debug("-- monster_data_map --", list)
  213. if table.isEmpty(list) then
  214. list = {}
  215. end
  216. -----@type GodsDescendedMonsterData
  217. local monster_data = {}
  218. monster_data.monsterdata = list
  219. --this.debug("发送诸神降临怪物状态数据", monster_data)
  220. --this.jprint(monster_data)
  221. sendluamsg(actor, LuaMessageIdToClient.RES_GODS_DESCENDED_DATA, monster_data)
  222. end
  223. function this.monsterDie(monster, actor, monsterCfgId)
  224. local monsterId = tonumber(monster:toString())
  225. local map_id = getbaseinfo(monster, "unimapid")
  226. local state_data = this.getMonsterStateList(actor)
  227. if table.isEmpty(state_data) or table.isEmpty(state_data[tonumber(map_id)]) then
  228. return
  229. end
  230. ---@type GodsDescendedMonsterState[]
  231. local monster_cfg_data = state_data[tonumber(map_id)]
  232. if table.isEmpty(monster_cfg_data) then
  233. return
  234. end
  235. local list = monster_cfg_data[tonumber(monsterCfgId)]
  236. if table.isEmpty(list) then
  237. return
  238. end
  239. local now = getbaseinfo("now")
  240. local all_rid_map = this.getAllOnlineRoleIds()
  241. local has_change = false
  242. for _, monster_state in pairs(list) do
  243. if monster_state.state == this.monster_state.died or monster_state.id ~= monsterId then
  244. goto continue
  245. end
  246. monster_state.ownerid = actor:toString()
  247. monster_state.ownername = getbaseinfo(actor, "rolename")
  248. monster_state.state = this.monster_state.died
  249. monster_state.date_id = now
  250. has_change = true
  251. -- 同步发送的所有跨服服务器中在线的玩家
  252. local ret_data = { [tonumber(map_id)] = monster_state }
  253. this.debug("--- all_rid_map send data ---", all_rid_map, ret_data)
  254. for _, rid_list in pairs(all_rid_map) do
  255. for _, member_id in pairs(rid_list) do
  256. local member = getactor(member_id)
  257. local msg_id = LuaMessageIdToClient.RES_GODS_DESCENDED_MONSTER_STATE_CHANGE
  258. sendluamsg(member, msg_id, ret_data)
  259. end
  260. end
  261. :: continue ::
  262. end
  263. this.debug("has_change", has_change)
  264. if not has_change then
  265. return
  266. end
  267. this.jprint("---- 击杀怪物 持久化数据 ----")
  268. this.setMonsterStateData(state_data)
  269. end
  270. ---@return table<number, GodsDescendedMonsterData[]>
  271. function this.getMonsterStateList_1()
  272. return getsysvar(GodsDescended.monster_state_list_key, 1)
  273. end
  274. ---@return table<number, GodsDescendedMonsterData[]>
  275. function this.getMonsterStateList(actor)
  276. local serverType = getbaseinfo("servertype")
  277. if serverType == 1 then
  278. this.debug("---- 获取本服数据 ----", data)
  279. if actor == nil then
  280. actor = getactor(0)
  281. end
  282. return getsysvar(actor, GodsDescended.monster_state_list_key)
  283. else
  284. this.debug("==== 获取跨服数据 ====", data)
  285. return getsysvar(GodsDescended.monster_state_list_key_cross, 1)
  286. end
  287. end
  288. function this.setMonsterStateData(data)
  289. local serverType = getbaseinfo("servertype")
  290. -- 其他服务器关闭数据修改
  291. if serverType == 1 then
  292. return
  293. end
  294. local hosts = gethosts()
  295. for _, host in pairs(hosts) do
  296. this.jprint("设置其他服务器数据:host")
  297. this.jprint(host)
  298. setsysvar(host, GodsDescended.monster_state_list_key, data)
  299. end
  300. this.debug("==== 设置跨服数据 ====", data)
  301. setsysvar(GodsDescended.monster_state_list_key_cross, data, 1)
  302. end
  303. -- -------------------------------------------------------------------------- --
  304. -- 日志打印
  305. this.log_open = false
  306. function this.debug(...)
  307. if not this.log_open then
  308. return
  309. end
  310. gameDebug.print(...)
  311. end
  312. function this.jprint(param)
  313. if not this.log_open then
  314. return
  315. end
  316. if param == nil then
  317. param = "error! 输出内容为空. nil"
  318. end
  319. jprint(param)
  320. end
  321. function this.loginfo(actor, param)
  322. if not this.log_open then
  323. return
  324. end
  325. if param == nil then
  326. param = "error! 日志输出内容为空. nil"
  327. end
  328. jprint(param)
  329. info(actor, param)
  330. end
  331. -- --------------------- GM 调试函数 --------------------
  332. local gm_open = true
  333. function l_gods_descended_create_monster(actor)
  334. if not gm_open then
  335. return
  336. end
  337. this.createMonster(23001)
  338. end
  339. function l_gods_descended_send_monster_state_data(actor)
  340. if not gm_open then
  341. return
  342. end
  343. this.sendMonsterStateData(actor)
  344. end
  345. function l_gods_descended_remove_monster(actor)
  346. if not gm_open then
  347. return
  348. end
  349. this.clearMonster()
  350. end
  351. function l_gods_descended_clear_monster(actor)
  352. if not gm_open then
  353. return
  354. end
  355. clearmapmon(getbaseinfo(actor, "unimapid"))
  356. end