SecretRealm.lua 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. -- 秘境副本 由于秘境副本比较特殊,无法复用副本大多数通用方法,所以没有使用通用方法,单独开发
  2. SecretRealm = {}
  3. local this = {}
  4. function SecretRealm.isSecretRealmMap(mapCfgId)
  5. local type = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monstertype", "repId", mapCfgId)
  6. return tonumber(type) == 3
  7. end
  8. function SecretRealm.UpdateHurtTopRank(uniqueMapId, mapCfgId)
  9. if not SecretRealm.isSecretRealmMap(mapCfgId) then
  10. return
  11. end
  12. local monActors = getmapmon(uniqueMapId)
  13. local playActors = getmapplayer(uniqueMapId)
  14. for _, playerActor in ipairs(playActors) do
  15. for _, monsterActor in pairs(monActors) do
  16. SecretRealm.getTop1HurtInfo0(playerActor, monsterActor:toString())
  17. end
  18. end
  19. end
  20. --- 请求进入秘境副本
  21. ---@param actor 玩家对象
  22. ---@param repId cfg_repfairyland表id
  23. function SecretRealm.reqEnterSecretRealm(actor, msgData)
  24. local repId = msgData["repId"]
  25. local tableValue = ConfigDataManager.getTable("cfg_repfairyland", "id", repId)
  26. if not tableValue then
  27. gameDebug.print("reqEnterSecretRealm cfg_repfairyland is nil")
  28. return
  29. end
  30. -- 检查进入秘境副本的条件
  31. if not this.checkEnterSecretRealmCondition(actor, tableValue[1]) then
  32. return
  33. end
  34. setplaydef(actor, PlayerDefKey.secretRealm.LAST_MAP_ID, getbaseinfo(actor, "mapid"))
  35. -- 满足条件执行传送进副本操作
  36. local mapId = tableValue[1]["mapid"]
  37. local mapMove = tableValue[1]["mapmove"]
  38. local x = ConfigDataManager.getTableValue("cfg_mapMove", "mapX", "id", mapMove)
  39. local y = ConfigDataManager.getTableValue("cfg_mapMove", "mapY", "id", mapMove)
  40. maptransfer(actor, x, y, mapId, 1)
  41. end
  42. --- 获取剩余挑战次数
  43. ---@param actor 玩家对象
  44. function SecretRealm.sendRemainingChallenges(actor)
  45. local secretRealmCount = getplaydef(actor, PlayerDefKey.secretRealm.COUNT)
  46. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_COUNT, {
  47. count = secretRealmCount and secretRealmCount or 0
  48. })
  49. end
  50. --- 进入地图后处理
  51. ---@param actor 玩家对象
  52. ---@param lastMapCfgId 上一个地图id
  53. ---@param mapCfgId 当前地图id
  54. function SecretRealm.afterEnterSecretRealm(actor, lastMapCfgId, mapCfgId)
  55. lastMapCfgId = tonumber(lastMapCfgId)
  56. mapCfgId = tonumber(mapCfgId)
  57. if lastMapCfgId == mapCfgId then
  58. gameDebug.print("afterEnterSecretRealm lastMapCfgId == mapCfgId")
  59. return
  60. end
  61. if this.isSecretRealmMap(mapCfgId) then
  62. -- 清除自身所有buff,并将血量和蓝量补满,刷新回血、技能的冷却时间
  63. -- 清除自身所有buff
  64. clearallbuff(actor)
  65. -- 血量和蓝量补满
  66. sethp(actor, getattrinfo(actor, "maxHP"))
  67. setmp(actor, getattrinfo(actor, "maxMP"))
  68. -- 刷新技能的冷却时间
  69. clearallskillcd(actor)
  70. -- 获取当前地图的boss信息
  71. local monsterId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", mapCfgId)
  72. local mapId = gamemap.getMapKey(mapCfgId, 1)
  73. local monsterInfo = mapbossinfo(actor, mapId, 3, monsterId)
  74. sendluamsg(actor, LuaMessageIdToClient.AFTER_ENTER_SECRET_REALM, {
  75. mapId = mapCfgId,
  76. monsterInfo = monsterInfo,
  77. time = 0,
  78. })
  79. end
  80. end
  81. --- 退出秘境副本
  82. ---@param actor 玩家对象
  83. function SecretRealm.reqExitSecretRealm(actor)
  84. -- 请求退出副本
  85. local mapId = getplaydef(actor, PlayerDefKey.secretRealm.LAST_MAP_ID)
  86. local x
  87. local y
  88. if mapId then
  89. x, y = CustomTransmit.GetPointFromMapMove(mapId)
  90. else
  91. local career = tonumber(getbaseinfo(actor, "getbasecareer"))
  92. local set = ConfigDataManager.getTableValue("cfg_character_create", "set", "id", career)
  93. local set_split = string.split(set, "#")
  94. mapId = set_split[1]
  95. x = set_split[2]
  96. y = set_split[3]
  97. end
  98. maptransfer(actor, x, y, mapId)
  99. -- 删除该玩家的对怪物的伤害信息
  100. SecretRealm.removePlayerHurt(actor, 0)
  101. sendluamsg(actor, LuaMessageIdToClient.RES_QUIT_SECRET_REALM, {})
  102. end
  103. --- 首次登录初始化秘境挑战次数
  104. ---@param actor 玩家对象
  105. function SecretRealm.login(actor)
  106. local count = getplaydef(actor, PlayerDefKey.secretRealm.COUNT)
  107. if not count then
  108. local secretRealmCountInit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.SECRET_REALM_INIT)
  109. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, tonumber(secretRealmCountInit))
  110. end
  111. -- 判断重新登录后玩家是否在秘境地图中,在秘境地图中并且没有超时发送消息给客户端
  112. local currentMapId = getbaseinfo(actor, "mapid")
  113. local countZeroTime = getplaydef(actor, PlayerDefKey.secretRealm.COUNT_ZERO_TIME)
  114. if this.isSecretRealmMap(currentMapId) and not string.isNullOrEmpty(countZeroTime) then
  115. local timeDiff = getbaseinfo(actor, "nowsec") - countZeroTime
  116. if countZeroTime and timeDiff > 30 then
  117. -- 退出秘境地图
  118. SecretRealm.reqExitSecretRealm(actor)
  119. else
  120. -- 获取当前地图的boss信息
  121. local monsterId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", currentMapId)
  122. local mapCfgId = gamemap.getMapKey(currentMapId, 1)
  123. local monsterInfo = mapbossinfo(actor, mapCfgId, 3, monsterId)
  124. sendluamsg(actor, LuaMessageIdToClient.AFTER_ENTER_SECRET_REALM, {
  125. mapId = currentMapId,
  126. monsterInfo = monsterInfo,
  127. time = 30 - timeDiff,
  128. })
  129. end
  130. end
  131. end
  132. --- 减少秘境副本挑战次数
  133. ---@param actor 玩家对象
  134. ---@param monsterId 怪物配置id
  135. ---@param mapId 地图唯一id
  136. function SecretRealm.reduceCount(actor, monsterId, mapId)
  137. local mapCfgId, _ = gamemap.parseMapKey(mapId)
  138. if this.isSecretRealmBoss(monsterId) and this.isSecretRealmMap(mapCfgId) then
  139. local count = tonumber(getplaydef(actor, PlayerDefKey.secretRealm.COUNT))
  140. if count == 1 then
  141. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, 0)
  142. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_COUNT_ZEROED, {
  143. secretRealmCount = 0
  144. })
  145. -- 记录玩家挑战次数为0的时间
  146. setplaydef(actor, PlayerDefKey.secretRealm.COUNT_ZERO_TIME, getbaseinfo(actor, "nowsec"))
  147. if isofflineplay(actor) then
  148. local exitMapId = getplaydef(actor, PlayerDefKey.secretRealm.LAST_MAP_ID)
  149. local x
  150. local y
  151. if exitMapId then
  152. x, y = CustomTransmit.GetPointFromMapMove(exitMapId)
  153. else
  154. local career = tonumber(getbaseinfo(actor, "getbasecareer"))
  155. local set = ConfigDataManager.getTableValue("cfg_character_create", "set", "id", career)
  156. local set_split = string.split(set, "#")
  157. exitMapId = set_split[1]
  158. x = set_split[2]
  159. y = set_split[3]
  160. end
  161. maptransfer(actor, x, y, exitMapId)
  162. end
  163. -- 删除该玩家的对怪物的伤害信息
  164. SecretRealm.removePlayerHurt(actor, 0)
  165. end
  166. if count > 1 then
  167. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, count - 1)
  168. end
  169. -- 宝箱直接发放到背包中
  170. local repId = ConfigDataManager.getTableValue("cfg_repfairyland", "id", "mapid", mapCfgId)
  171. local boxDrop = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "boxdrop", "repid", repId, "monsterid", monsterId)
  172. if not boxDrop then
  173. gameDebug.printTraceback("cfg_BOSS_challenge boxdrop is nil repId:[" .. repId .. "] monsterId:[" .. monsterId)
  174. return
  175. end
  176. local boxDropTable = string.split(boxDrop, "#")
  177. -- 专属奖励只有一个,所以此处没有循环遍历
  178. additemtobag(actor, boxDropTable[1], boxDropTable[2], 0, 9999, '秘境boss')
  179. -- 刷新任务进度
  180. TaskHandler.TriggerTaskGoal(actor, TaskTargetType.FINISH_SECRET_REALM_DUPLICATE, repId)
  181. end
  182. end
  183. --- 增加秘境副本挑战次数
  184. ---@param secretRealmCountStep number 每日增加次数
  185. ---@param secretRealmMaxCount number 最大次数
  186. function SecretRealm.incrementedSecretRealmCount(secretRealmCountStep, secretRealmMaxCount)
  187. local allRoleInfos = getallrolesummaryinfos()
  188. if table.isNullOrEmpty(allRoleInfos) then
  189. return
  190. end
  191. for _, roleInfo in pairs(allRoleInfos) do
  192. local actor = roleInfo["actor"]
  193. local count = getplaydef(actor, PlayerDefKey.secretRealm.COUNT)
  194. if count then
  195. info(actor, actor:toString() .. "玩家秘境副本次数刷新 count:" .. count)
  196. if tonumber(count) + secretRealmCountStep > secretRealmMaxCount then
  197. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, secretRealmMaxCount)
  198. else
  199. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, tonumber(count) + secretRealmCountStep)
  200. end
  201. else
  202. info(actor, actor:toString() .. "玩家秘境副本次数刷新")
  203. local secretRealmCountInit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.SECRET_REALM_INIT)
  204. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, tonumber(secretRealmCountInit))
  205. end
  206. end
  207. end
  208. --- 获取秘境副本怪物数量
  209. ---@param actor 玩家对象
  210. ---@param msgData 请求参数
  211. function SecretRealm.getMonsterCount(actor, msgData)
  212. local repId = msgData["repId"]
  213. if not repId then
  214. gameDebug.print("SecretRealm.getMonsterCount repId is nil")
  215. return
  216. end
  217. local res = {}
  218. local monsterInfo = ConfigDataManager.getTableValue("cfg_repfairyland_monster", "monster1", "id", repId)
  219. if not monsterInfo then
  220. return
  221. end
  222. local monsterList = string.split(monsterInfo, "|")
  223. for _, value in pairs(monsterList) do
  224. local splitString = string.split(value, "#")
  225. local monsterId = splitString[1]
  226. local x = splitString[3]
  227. local y = splitString[4]
  228. local range = splitString[5]
  229. local aiId = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterId)
  230. local maxMove = ConfigDataManager.getTableValue("cfg_monster_ai", "leavebasedistance", "id", aiId)
  231. local mapId = gamemap.getMapKey(repId, 1)
  232. local maxRange = range + tonumber(maxMove) + 1
  233. local monsterCount = getalivemonsterinmap(actor, mapId, x, y, maxRange)
  234. if monsterCount and table.count(monsterCount) > 0 then
  235. table.insert(res, {
  236. repId = tonumber(repId),
  237. x = tonumber(x),
  238. y = tonumber(y),
  239. range = tonumber(range),
  240. monsterId = tonumber(monsterId),
  241. count = table.count(monsterCount),
  242. time = 0
  243. })
  244. else
  245. local monInfo = mapbossinfo(actor, mapId, 3)
  246. if not table.isNullOrEmpty(monInfo) then
  247. for _, v in pairs(monInfo) do
  248. local minX = x - maxRange
  249. local maxX = x + maxRange
  250. local minY = y - maxRange
  251. local maxY = y + maxRange
  252. if v.isdead and v.x >= minX and v.x <= maxX and v.y >= minY and v.y <= maxY then
  253. local monId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", repId)
  254. local ai = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monId)
  255. local reliveDelay, reliveServiceTime = this.getMonsterReliveTime(ai)
  256. local dieTime = getsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, v.id))
  257. if not string.isNullOrEmpty(dieTime) then
  258. dieTime = tonumber(dieTime) + tonumber(reliveDelay) + tonumber(reliveServiceTime)
  259. end
  260. table.insert(res, {
  261. repId = tonumber(repId),
  262. x = tonumber(x),
  263. y = tonumber(y),
  264. range = tonumber(range),
  265. monsterId = tonumber(monId),
  266. count = 0,
  267. time = tostring(dieTime and dieTime or 0),
  268. id = v.id
  269. })
  270. end
  271. end
  272. end
  273. end
  274. end
  275. sendluamsg(actor, LuaMessageIdToClient.SEND_SECRET_REALM_MONSTER_COUNT, res)
  276. end
  277. --- 保存玩家实时伤害信息
  278. ---@param actor 玩家对象
  279. ---@param target 攻击怪物id
  280. ---@param hurt 造成的伤害
  281. function SecretRealm.savePlayerHurtInfo(actor, target, hurt)
  282. local hurtTable = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  283. if not hurtTable then
  284. hurtTable = {}
  285. end
  286. local roleName = getbaseinfo(actor, "rolename")
  287. local exist = false
  288. if hurtTable then
  289. for k, _ in pairs(hurtTable) do
  290. if tostring(k) == target:toString() then
  291. exist = true
  292. end
  293. end
  294. end
  295. if not exist then
  296. local temp = {}
  297. temp[roleName] = hurt
  298. hurtTable[target:toString()] = temp
  299. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  300. else
  301. for k, v in pairs(hurtTable) do
  302. if tostring(k) == target:toString() then
  303. if v[roleName] then
  304. v[roleName] = v[roleName] + hurt
  305. else
  306. v[roleName] = hurt
  307. end
  308. end
  309. end
  310. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  311. end
  312. this.sendSecretRealmHurt(actor, target)
  313. end
  314. --- 删除对应玩家存储的实时伤害
  315. ---@param actor 玩家对象
  316. function SecretRealm.removePlayerHurt(actor, monsterId)
  317. local hurtTable = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  318. local roleName = getbaseinfo(actor, "rolename")
  319. if table.isNullOrEmpty(hurtTable) then
  320. return
  321. end
  322. if monsterId == 0 then
  323. -- 删除该玩家所有伤害信息
  324. for _, value in pairs(hurtTable) do
  325. for k, v in pairs(value) do
  326. if k == roleName then
  327. value[roleName] = nil
  328. end
  329. end
  330. end
  331. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  332. else
  333. -- 清空对应怪物的伤害记录
  334. hurtTable[tostring(monsterId)] = nil
  335. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  336. end
  337. end
  338. --- boss死亡删除伤害信息与发送怪物列表信息
  339. ---@param actor 玩家对象
  340. ---@param mapId 地图唯一id
  341. ---@param monCfgId 怪物配置id
  342. ---@param monsterId 怪物id
  343. function SecretRealm.recordMonsterDie(actor, mapId, monCfgId, monsterId)
  344. local mapCfgId, _ = gamemap.parseMapKey(mapId)
  345. if this.isSecretRealmBoss(monCfgId) and this.isSecretRealmMap(mapCfgId) then
  346. setsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, monsterId), getbaseinfo("now"))
  347. this.sendMonsterListInfo(actor, mapId)
  348. SecretRealm.removePlayerHurt(actor, monsterId)
  349. end
  350. end
  351. --- 发送怪物列表信息
  352. ---@param actor 玩家对象
  353. ---@param msgData 客户端数据——地图id
  354. function SecretRealm.ReqBossList(actor, msgData)
  355. local mapId = msgData["mapId"]
  356. if not mapId then
  357. gameDebug.print("SecretRealm.ReqBossList mapId is nil")
  358. return
  359. end
  360. mapId = gamemap.getMapKey(mapId, 1)
  361. this.sendMonsterListInfo(actor, mapId)
  362. end
  363. --- 请求获取对制定怪物造成伤害的第一名信息
  364. function SecretRealm.getTop1HurtInfo(actor, msgData)
  365. local monsterId = msgData["monsterId"]
  366. SecretRealm.getTop1HurtInfo0(actor, monsterId)
  367. end
  368. function SecretRealm.getTop1HurtInfo0(actor, monsterId)
  369. local hurtInfo = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  370. local info = {}
  371. if hurtInfo then
  372. for _, v in pairs(hurtInfo) do
  373. for key, value in pairs(v) do
  374. if tostring(key) == tostring(monsterId) then
  375. info = value
  376. end
  377. end
  378. end
  379. end
  380. if table.isNullOrEmpty(info) then
  381. return
  382. end
  383. local message = {}
  384. local top1 = this.getTopN(info, 1)
  385. if table.isNullOrEmpty(top1) then
  386. message["monsterId"] = tonumber(monsterId)
  387. else
  388. message["monsterId"] = tonumber(monsterId)
  389. message["name"] = top1[1].name
  390. message["hurt"] = top1[1].hurt
  391. end
  392. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_HURT_TOP1, message)
  393. end
  394. --- 判断是否满足进入秘境副本的要求
  395. ---@param actor 玩家对象
  396. ---@param tableValue cfg_repfairyland表单行记录
  397. ---@return boolean 是否可以进入秘境副本,true-可以进入,false-不能进入
  398. function this.checkEnterSecretRealmCondition(actor, tableValue)
  399. -- 判断当前地图是否是在秘境地图中,如果在秘境地图先退出再进入
  400. local mapId = getbaseinfo(actor, "mapid")
  401. if this.isSecretRealmMap(mapId) then
  402. noticeTip.noticeinfo(actor, StringIdConst.DUPLICATE_CAN_NOT_TRANSMIT)
  403. return false
  404. end
  405. -- 等级判断
  406. local level = tableValue["level"]
  407. if string.isNullOrEmpty(level) then
  408. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland level is nil")
  409. else
  410. local actorLevel = getbaseinfo(actor, "level")
  411. if tonumber(level) > tonumber(actorLevel) then
  412. tipinfo(actor, string.format("等级不满足,%s等级后开启", level))
  413. return false
  414. end
  415. end
  416. -- 进入次数判断
  417. local secretRealmCount = getplaydef(actor, PlayerDefKey.secretRealm.COUNT)
  418. if string.isNullOrEmpty(secretRealmCount) or tonumber(secretRealmCount) <= 0 then
  419. tipinfo(actor, "今日次数不足")
  420. return false
  421. end
  422. -- 全身穿戴装备强化等级判断
  423. local strengthenLevel = tableValue["strengthenlevel"]
  424. if string.isNullOrEmpty(strengthenLevel) then
  425. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland strengthenLevel is nil")
  426. else
  427. if not string.isNullOrEmpty(strengthenLevel) then
  428. -- 获取全身强化等级
  429. local allStrengthLevel = EquipAndAppear.allequipstrengthlv(actor)
  430. if tonumber(allStrengthLevel) < tonumber(strengthenLevel) then
  431. tipinfo(actor, string.format("强化等级不满足,需要全身穿戴装备强化等级到达%s级",
  432. strengthenLevel))
  433. return false
  434. end
  435. end
  436. end
  437. -- 开服天数限制
  438. local startDay = tableValue["startday"]
  439. if string.isNullOrEmpty(startDay) then
  440. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland startDay is nil")
  441. else
  442. if not string.isNullOrEmpty(startDay) then
  443. local serverOpenDays = tonumber(getserveropendays(actor))
  444. return tonumber(startDay) <= serverOpenDays
  445. end
  446. end
  447. return true
  448. end
  449. --- 判断怪物类型是否是秘境副本中的怪物类型
  450. ---@param monCfgId 怪物id
  451. ---@return boolean true——是,false——否
  452. function this.isSecretRealmBoss(monCfgId)
  453. local bossChallenge = ConfigDataManager.getTable("cfg_BOSS_challenge", "monsterType", BossType.SECRET_REALM_BOSS)
  454. for i = 1, #bossChallenge do
  455. if tonumber(monCfgId) == tonumber(bossChallenge[i].monsterid) then
  456. return true
  457. end
  458. end
  459. return false
  460. end
  461. --- 判断指定地图是否为秘境副本地图
  462. ---@param mapId 地图id
  463. ---@return boolean 是否为秘境副本地图
  464. function this.isSecretRealmMap(mapId)
  465. local tableValue = ConfigDataManager.getList("cfg_repfairyland")
  466. for _, value in pairs(tableValue) do
  467. if tostring(value.id) == tostring(mapId) then
  468. return true
  469. end
  470. end
  471. return false
  472. end
  473. --- 发送秘境副本玩家实时伤害消息
  474. ---@param actor 玩家对象
  475. ---@param monsterId 怪物id
  476. function this.sendSecretRealmHurt(actor, monsterId)
  477. local roleName = getbaseinfo(actor, "rolename")
  478. local hurtInfo = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  479. local info = {}
  480. if hurtInfo then
  481. for k, v in pairs(hurtInfo) do
  482. if tostring(k) == monsterId:toString() then
  483. info = v
  484. end
  485. end
  486. end
  487. if table.isNullOrEmpty(info) then
  488. gameDebug.print("sendSecretRealmHurt hurtInfo is nil")
  489. return
  490. end
  491. local message = {}
  492. message["monsterId"] = monsterId:toString()
  493. local top3 = this.getTopN(info, 3)
  494. message["top3"] = top3
  495. local rank = 0
  496. for key, value in pairs(info) do
  497. rank = rank + 1
  498. if key == roleName then
  499. message["my"] = {
  500. name = roleName,
  501. hurt = value,
  502. rank = this.getRank(info, roleName)
  503. }
  504. end
  505. end
  506. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_DAMAGE, message)
  507. end
  508. --- 发送秘境boss列表信息
  509. ---@param actor 玩家对象
  510. ---@param mapId 地图id
  511. function this.sendMonsterListInfo(actor, mapId)
  512. local mapCfgId = gamemap.parseMapKey(mapId)
  513. local monsterId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", mapCfgId)
  514. local ai = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterId)
  515. local reliveDelayTime, reliveServiceTime = this.getMonsterReliveTime(ai)
  516. local monsterInfo = mapbossinfo(actor, mapId, 3)
  517. local message = {}
  518. if not table.isNullOrEmpty(monsterInfo) then
  519. for _, value in pairs(monsterInfo) do
  520. local dieTime = getsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, value.id))
  521. if not string.isNullOrEmpty(dieTime) then
  522. dieTime = tonumber(dieTime) + tonumber(reliveDelayTime) + tonumber(reliveServiceTime)
  523. end
  524. table.insert(message, {
  525. monsterId = value.id,
  526. monsterName = value.name,
  527. x = value.x,
  528. y = value.y,
  529. reviveTime = tostring(dieTime and dieTime or 0)
  530. })
  531. end
  532. end
  533. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_BOSS_LIST, message)
  534. end
  535. --- 获取boss复活时间
  536. ---@param id 怪物id
  537. function this.getMonsterReliveTime(id)
  538. local aiConfig = ConfigDataManager.getById("cfg_monster_ai", id)
  539. if aiConfig == nil then
  540. gameDebug.print("cfg_monster_ai为nil id:" .. id)
  541. return 0, 0
  542. end
  543. local reliveType = tonumber(aiConfig['relivetype'])
  544. local reliveDelay = aiConfig['relivedelay']
  545. local reliveServiceTime = 0
  546. if reliveType == 4 then
  547. local str = aiConfig['reliveservicetime']
  548. if string.isNullOrEmpty(str) then
  549. return 0, 0
  550. end
  551. local strShuXian = string.split(str, "|")
  552. local serverOpenDays = tonumber(getbaseinfo("serveropendays"))
  553. local cfg = {}
  554. for _, v in pairs(strShuXian) do
  555. local strJinHao = string.split(v, "#")
  556. local day = tonumber(strJinHao[1])
  557. if serverOpenDays >= day then
  558. cfg = strJinHao
  559. end
  560. end
  561. if table.isNullOrEmpty(cfg) then
  562. gameDebug.print("updateMonsterReliveTime 未找到匹配的数据 开服天数:" .. tostring(serverOpenDays) .. ",reliveDelay字段内容:" .. str)
  563. return
  564. end
  565. reliveServiceTime = tonumber(cfg[2])
  566. end
  567. if string.isNullOrEmpty(reliveDelay) then
  568. reliveDelay = 0
  569. end
  570. return reliveDelay, reliveServiceTime
  571. end
  572. --- 获取指定数据中的前N个数据
  573. ---@param info table 数据
  574. ---@param N number 前N个
  575. ---@return table 前N个数据
  576. function this.getTopN(info, N)
  577. local temp = {}
  578. for k, _ in pairs(info) do
  579. table.insert(temp, k)
  580. end
  581. table.sort(temp, function(a, b)
  582. return info[a] > info[b]
  583. end)
  584. local topNKey = table.getTopN(N, temp)
  585. local topN = {}
  586. for _, key in ipairs(topNKey) do
  587. table.insert(topN, {
  588. name = key,
  589. hurt = info[key]
  590. })
  591. end
  592. return topN
  593. end
  594. function this.getRank(info, key)
  595. local temp = {}
  596. for k, _ in pairs(info) do
  597. table.insert(temp, k)
  598. end
  599. table.sort(temp, function(a, b)
  600. return info[a] > info[b]
  601. end)
  602. for index, k in ipairs(temp) do
  603. if k == key then
  604. return index
  605. end
  606. end
  607. end
  608. --- 玩家死亡清空该玩家伤害
  609. --- @param actor table 玩家对象
  610. function SecretRealm.playerDie(actor)
  611. local mapId = getbaseinfo(actor, "mapid")
  612. if this.isSecretRealmMap(mapId) then
  613. SecretRealm.removePlayerHurt(actor, 0)
  614. end
  615. end
  616. --- 秘境副本次数刷新
  617. function SecretRealm.refreshCount()
  618. local serverType = getbaseinfo("servertype")
  619. if serverType == 2 then
  620. return
  621. end
  622. local seconds = getbaseinfo("nowsec")
  623. local now = TimeUtil.timeToDate(seconds)
  624. if now.min == 0 then
  625. local activityRule = ConfigDataManager.getTable("cfg_activity_rule", "id", DuplicateType.SECRET_REALM_BOSS)
  626. local numberTime = activityRule[1]["numbertime"]
  627. local numberAdd = activityRule[1]["numberadd"]
  628. if not string.isNullOrEmpty(numberTime) and not string.isNullOrEmpty(numberAdd) then
  629. local split = string.split(numberTime, "#")
  630. local type = tonumber(split[1])
  631. local numberTime1 = tonumber(split[2])
  632. local numSplit = string.split(numberAdd, "#")
  633. local secretRealmCountStep = tonumber(numSplit[1])
  634. local secretRealmMaxCount = tonumber(numSplit[2])
  635. if type == 1 then
  636. if numberTime1 == now.hour then
  637. SecretRealm.incrementedSecretRealmCount(secretRealmCountStep, secretRealmMaxCount)
  638. end
  639. else
  640. local numberTime2 = tonumber(split[3])
  641. if numberTime1 == now.wday and numberTime2 == now.hour then
  642. SecretRealm.incrementedSecretRealmCount(secretRealmCountStep, secretRealmMaxCount)
  643. end
  644. end
  645. end
  646. end
  647. end