SecretRealm.lua 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  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. -- 重置玩家挑战次数为0的时间
  195. setplaydef(actor, PlayerDefKey.secretRealm.COUNT_ZERO_TIME, "")
  196. if count then
  197. info(actor, actor:toString() .. "玩家秘境副本次数刷新 count:" .. count)
  198. if tonumber(count) + secretRealmCountStep > secretRealmMaxCount then
  199. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, secretRealmMaxCount)
  200. else
  201. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, tonumber(count) + secretRealmCountStep)
  202. end
  203. else
  204. info(actor, actor:toString() .. "玩家秘境副本次数刷新")
  205. local secretRealmCountInit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.SECRET_REALM_INIT)
  206. setplaydef(actor, PlayerDefKey.secretRealm.COUNT, tonumber(secretRealmCountInit))
  207. end
  208. end
  209. end
  210. --- 获取秘境副本怪物数量
  211. ---@param actor 玩家对象
  212. ---@param msgData 请求参数
  213. function SecretRealm.getMonsterCount(actor, msgData)
  214. local repId = msgData["repId"]
  215. if not repId then
  216. gameDebug.print("SecretRealm.getMonsterCount repId is nil")
  217. return
  218. end
  219. local res = {}
  220. local monsterInfo = ConfigDataManager.getTableValue("cfg_repfairyland_monster", "monster1", "id", repId)
  221. if not monsterInfo then
  222. return
  223. end
  224. local monsterList = string.split(monsterInfo, "|")
  225. for _, value in pairs(monsterList) do
  226. local splitString = string.split(value, "#")
  227. local monsterId = splitString[1]
  228. local x = splitString[3]
  229. local y = splitString[4]
  230. local range = splitString[5]
  231. local aiId = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterId)
  232. local maxMove = ConfigDataManager.getTableValue("cfg_monster_ai", "leavebasedistance", "id", aiId)
  233. local mapId = gamemap.getMapKey(repId, 1)
  234. local maxRange = range + tonumber(maxMove) + 1
  235. local monsterCount = getalivemonsterinmap(actor, mapId, x, y, maxRange)
  236. if monsterCount and table.count(monsterCount) > 0 then
  237. table.insert(res, {
  238. repId = tonumber(repId),
  239. x = tonumber(x),
  240. y = tonumber(y),
  241. range = tonumber(range),
  242. monsterId = tonumber(monsterId),
  243. count = table.count(monsterCount),
  244. time = 0
  245. })
  246. else
  247. local monInfo = mapbossinfo(actor, mapId, 3)
  248. if not table.isNullOrEmpty(monInfo) then
  249. for _, v in pairs(monInfo) do
  250. local minX = x - maxRange
  251. local maxX = x + maxRange
  252. local minY = y - maxRange
  253. local maxY = y + maxRange
  254. if v.isdead and v.x >= minX and v.x <= maxX and v.y >= minY and v.y <= maxY then
  255. local monId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", repId)
  256. local ai = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monId)
  257. local reliveDelay, reliveServiceTime = this.getMonsterReliveTime(ai)
  258. local dieTime = getsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, v.id))
  259. if not string.isNullOrEmpty(dieTime) then
  260. dieTime = tonumber(dieTime) + tonumber(reliveDelay) + tonumber(reliveServiceTime)
  261. end
  262. table.insert(res, {
  263. repId = tonumber(repId),
  264. x = tonumber(x),
  265. y = tonumber(y),
  266. range = tonumber(range),
  267. monsterId = tonumber(monId),
  268. count = 0,
  269. time = tostring(dieTime and dieTime or 0),
  270. id = v.id
  271. })
  272. end
  273. end
  274. end
  275. end
  276. end
  277. sendluamsg(actor, LuaMessageIdToClient.SEND_SECRET_REALM_MONSTER_COUNT, res)
  278. end
  279. --- 保存玩家实时伤害信息
  280. ---@param actor 玩家对象
  281. ---@param target 攻击怪物id
  282. ---@param hurt 造成的伤害
  283. function SecretRealm.savePlayerHurtInfo(actor, target, hurt)
  284. local hurtTable = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  285. if not hurtTable then
  286. hurtTable = {}
  287. end
  288. local roleName = getbaseinfo(actor, "rolename")
  289. local exist = false
  290. if hurtTable then
  291. for k, _ in pairs(hurtTable) do
  292. if tostring(k) == target:toString() then
  293. exist = true
  294. end
  295. end
  296. end
  297. if not exist then
  298. local temp = {}
  299. temp[roleName] = hurt
  300. hurtTable[target:toString()] = temp
  301. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  302. else
  303. for k, v in pairs(hurtTable) do
  304. if tostring(k) == target:toString() then
  305. if v[roleName] then
  306. v[roleName] = v[roleName] + hurt
  307. else
  308. v[roleName] = hurt
  309. end
  310. end
  311. end
  312. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  313. end
  314. this.sendSecretRealmHurt(actor, target)
  315. end
  316. --- 删除对应玩家存储的实时伤害
  317. ---@param actor 玩家对象
  318. function SecretRealm.removePlayerHurt(actor, monsterId)
  319. local hurtTable = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  320. local roleName = getbaseinfo(actor, "rolename")
  321. if table.isNullOrEmpty(hurtTable) then
  322. return
  323. end
  324. if monsterId == 0 then
  325. -- 删除该玩家所有伤害信息
  326. for _, value in pairs(hurtTable) do
  327. for k, v in pairs(value) do
  328. if k == roleName then
  329. value[roleName] = nil
  330. end
  331. end
  332. end
  333. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  334. else
  335. -- 清空对应怪物的伤害记录
  336. hurtTable[tostring(monsterId)] = nil
  337. setsysvar(actor, PlayerDefKey.secretRealm.HURT, hurtTable)
  338. end
  339. end
  340. --- boss死亡删除伤害信息与发送怪物列表信息
  341. ---@param actor 玩家对象
  342. ---@param mapId 地图唯一id
  343. ---@param monCfgId 怪物配置id
  344. ---@param monsterId 怪物id
  345. function SecretRealm.recordMonsterDie(actor, mapId, monCfgId, monsterId)
  346. local mapCfgId, _ = gamemap.parseMapKey(mapId)
  347. if this.isSecretRealmBoss(monCfgId) and this.isSecretRealmMap(mapCfgId) then
  348. setsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, monsterId), getbaseinfo("now"))
  349. this.sendMonsterListInfo(actor, mapId)
  350. SecretRealm.removePlayerHurt(actor, monsterId)
  351. end
  352. end
  353. --- 发送怪物列表信息
  354. ---@param actor 玩家对象
  355. ---@param msgData 客户端数据——地图id
  356. function SecretRealm.ReqBossList(actor, msgData)
  357. local mapId = msgData["mapId"]
  358. if not mapId then
  359. gameDebug.print("SecretRealm.ReqBossList mapId is nil")
  360. return
  361. end
  362. mapId = gamemap.getMapKey(mapId, 1)
  363. this.sendMonsterListInfo(actor, mapId)
  364. end
  365. --- 请求获取对制定怪物造成伤害的第一名信息
  366. function SecretRealm.getTop1HurtInfo(actor, msgData)
  367. local monsterId = msgData["monsterId"]
  368. SecretRealm.getTop1HurtInfo0(actor, monsterId)
  369. end
  370. function SecretRealm.getTop1HurtInfo0(actor, monsterId)
  371. local hurtInfo = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  372. local info = {}
  373. if hurtInfo then
  374. for _, v in pairs(hurtInfo) do
  375. for key, value in pairs(v) do
  376. if tostring(key) == tostring(monsterId) then
  377. info = value
  378. end
  379. end
  380. end
  381. end
  382. if table.isNullOrEmpty(info) then
  383. return
  384. end
  385. local message = {}
  386. local top1 = this.getTopN(info, 1)
  387. if table.isNullOrEmpty(top1) then
  388. message["monsterId"] = tonumber(monsterId)
  389. else
  390. message["monsterId"] = tonumber(monsterId)
  391. message["name"] = top1[1].name
  392. message["hurt"] = top1[1].hurt
  393. end
  394. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_HURT_TOP1, message)
  395. end
  396. --- 判断是否满足进入秘境副本的要求
  397. ---@param actor 玩家对象
  398. ---@param tableValue cfg_repfairyland表单行记录
  399. ---@return boolean 是否可以进入秘境副本,true-可以进入,false-不能进入
  400. function this.checkEnterSecretRealmCondition(actor, tableValue)
  401. -- 判断当前地图是否是在秘境地图中,如果在秘境地图先退出再进入
  402. local mapId = getbaseinfo(actor, "mapid")
  403. if this.isSecretRealmMap(mapId) then
  404. noticeTip.noticeinfo(actor, StringIdConst.DUPLICATE_CAN_NOT_TRANSMIT)
  405. return false
  406. end
  407. -- 等级判断
  408. local level = tableValue["level"]
  409. if string.isNullOrEmpty(level) then
  410. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland level is nil")
  411. else
  412. local actorLevel = getbaseinfo(actor, "level")
  413. if tonumber(level) > tonumber(actorLevel) then
  414. tipinfo(actor, string.format("等级不满足,%s等级后开启", level))
  415. return false
  416. end
  417. end
  418. -- 进入次数判断
  419. local secretRealmCount = getplaydef(actor, PlayerDefKey.secretRealm.COUNT)
  420. if string.isNullOrEmpty(secretRealmCount) or tonumber(secretRealmCount) <= 0 then
  421. tipinfo(actor, "今日次数不足")
  422. return false
  423. end
  424. -- 全身穿戴装备强化等级判断
  425. local strengthenLevel = tableValue["strengthenlevel"]
  426. if string.isNullOrEmpty(strengthenLevel) then
  427. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland strengthenLevel is nil")
  428. else
  429. if not string.isNullOrEmpty(strengthenLevel) then
  430. -- 获取全身强化等级
  431. local allStrengthLevel = EquipAndAppear.allequipstrengthlv(actor)
  432. if tonumber(allStrengthLevel) < tonumber(strengthenLevel) then
  433. tipinfo(actor, string.format("强化等级不满足,需要全身穿戴装备强化等级到达%s级",
  434. strengthenLevel))
  435. return false
  436. end
  437. end
  438. end
  439. -- 开服天数限制
  440. local startDay = tableValue["startday"]
  441. if string.isNullOrEmpty(startDay) then
  442. gameDebug.print("checkEnterSecretRealmCondition cfg_repfairyland startDay is nil")
  443. else
  444. if not string.isNullOrEmpty(startDay) then
  445. local serverOpenDays = tonumber(getserveropendays(actor))
  446. return tonumber(startDay) <= serverOpenDays
  447. end
  448. end
  449. return true
  450. end
  451. --- 判断怪物类型是否是秘境副本中的怪物类型
  452. ---@param monCfgId 怪物id
  453. ---@return boolean true——是,false——否
  454. function this.isSecretRealmBoss(monCfgId)
  455. local bossChallenge = ConfigDataManager.getTable("cfg_BOSS_challenge", "monsterType", BossType.SECRET_REALM_BOSS)
  456. for i = 1, #bossChallenge do
  457. if tonumber(monCfgId) == tonumber(bossChallenge[i].monsterid) then
  458. return true
  459. end
  460. end
  461. return false
  462. end
  463. --- 判断指定地图是否为秘境副本地图
  464. ---@param mapId 地图id
  465. ---@return boolean 是否为秘境副本地图
  466. function this.isSecretRealmMap(mapId)
  467. local tableValue = ConfigDataManager.getList("cfg_repfairyland")
  468. for _, value in pairs(tableValue) do
  469. if tostring(value.id) == tostring(mapId) then
  470. return true
  471. end
  472. end
  473. return false
  474. end
  475. --- 发送秘境副本玩家实时伤害消息
  476. ---@param actor 玩家对象
  477. ---@param monsterId 怪物id
  478. function this.sendSecretRealmHurt(actor, monsterId)
  479. local roleName = getbaseinfo(actor, "rolename")
  480. local hurtInfo = getsysvar(actor, PlayerDefKey.secretRealm.HURT)
  481. local info = {}
  482. if hurtInfo then
  483. for k, v in pairs(hurtInfo) do
  484. if tostring(k) == monsterId:toString() then
  485. info = v
  486. end
  487. end
  488. end
  489. if table.isNullOrEmpty(info) then
  490. gameDebug.print("sendSecretRealmHurt hurtInfo is nil")
  491. return
  492. end
  493. local message = {}
  494. message["monsterId"] = monsterId:toString()
  495. local top3 = this.getTopN(info, 3)
  496. message["top3"] = top3
  497. local rank = 0
  498. for key, value in pairs(info) do
  499. rank = rank + 1
  500. if key == roleName then
  501. message["my"] = {
  502. name = roleName,
  503. hurt = value,
  504. rank = this.getRank(info, roleName)
  505. }
  506. end
  507. end
  508. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_DAMAGE, message)
  509. end
  510. --- 发送秘境boss列表信息
  511. ---@param actor 玩家对象
  512. ---@param mapId 地图id
  513. function this.sendMonsterListInfo(actor, mapId)
  514. local mapCfgId = gamemap.parseMapKey(mapId)
  515. local monsterId = ConfigDataManager.getTableValue("cfg_BOSS_challenge", "monsterid", "repid", mapCfgId)
  516. local ai = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterId)
  517. local reliveDelayTime, reliveServiceTime = this.getMonsterReliveTime(ai)
  518. local monsterInfo = mapbossinfo(actor, mapId, 3)
  519. local message = {}
  520. if not table.isNullOrEmpty(monsterInfo) then
  521. for _, value in pairs(monsterInfo) do
  522. local dieTime = getsysvar(actor, string.format(PlayerDefKey.secretRealm.BOSS_TIME_BY_ID, value.id))
  523. if not string.isNullOrEmpty(dieTime) then
  524. dieTime = tonumber(dieTime) + tonumber(reliveDelayTime) + tonumber(reliveServiceTime)
  525. end
  526. table.insert(message, {
  527. monsterId = value.id,
  528. monsterName = value.name,
  529. x = value.x,
  530. y = value.y,
  531. reviveTime = tostring(dieTime and dieTime or 0)
  532. })
  533. end
  534. end
  535. sendluamsg(actor, LuaMessageIdToClient.SECRET_REALM_BOSS_LIST, message)
  536. end
  537. --- 获取boss复活时间
  538. ---@param id 怪物id
  539. function this.getMonsterReliveTime(id)
  540. local aiConfig = ConfigDataManager.getById("cfg_monster_ai", id)
  541. if aiConfig == nil then
  542. gameDebug.print("cfg_monster_ai为nil id:" .. id)
  543. return 0, 0
  544. end
  545. local reliveType = tonumber(aiConfig['relivetype'])
  546. local reliveDelay = aiConfig['relivedelay']
  547. local reliveServiceTime = 0
  548. if reliveType == 4 then
  549. local str = aiConfig['reliveservicetime']
  550. if string.isNullOrEmpty(str) then
  551. return 0, 0
  552. end
  553. local strShuXian = string.split(str, "|")
  554. local serverOpenDays = tonumber(getbaseinfo("serveropendays"))
  555. local cfg = {}
  556. for _, v in pairs(strShuXian) do
  557. local strJinHao = string.split(v, "#")
  558. local day = tonumber(strJinHao[1])
  559. if serverOpenDays >= day then
  560. cfg = strJinHao
  561. end
  562. end
  563. if table.isNullOrEmpty(cfg) then
  564. gameDebug.print("updateMonsterReliveTime 未找到匹配的数据 开服天数:" .. tostring(serverOpenDays) .. ",reliveDelay字段内容:" .. str)
  565. return
  566. end
  567. reliveServiceTime = tonumber(cfg[2])
  568. end
  569. if string.isNullOrEmpty(reliveDelay) then
  570. reliveDelay = 0
  571. end
  572. return reliveDelay, reliveServiceTime
  573. end
  574. --- 获取指定数据中的前N个数据
  575. ---@param info table 数据
  576. ---@param N number 前N个
  577. ---@return table 前N个数据
  578. function this.getTopN(info, N)
  579. local temp = {}
  580. for k, _ in pairs(info) do
  581. table.insert(temp, k)
  582. end
  583. table.sort(temp, function(a, b)
  584. return info[a] > info[b]
  585. end)
  586. local topNKey = table.getTopN(N, temp)
  587. local topN = {}
  588. for _, key in ipairs(topNKey) do
  589. table.insert(topN, {
  590. name = key,
  591. hurt = info[key]
  592. })
  593. end
  594. return topN
  595. end
  596. function this.getRank(info, key)
  597. local temp = {}
  598. for k, _ in pairs(info) do
  599. table.insert(temp, k)
  600. end
  601. table.sort(temp, function(a, b)
  602. return info[a] > info[b]
  603. end)
  604. for index, k in ipairs(temp) do
  605. if k == key then
  606. return index
  607. end
  608. end
  609. end
  610. --- 玩家死亡清空该玩家伤害
  611. --- @param actor table 玩家对象
  612. function SecretRealm.playerDie(actor)
  613. local mapId = getbaseinfo(actor, "mapid")
  614. if this.isSecretRealmMap(mapId) then
  615. SecretRealm.removePlayerHurt(actor, 0)
  616. end
  617. end
  618. --- 秘境副本次数刷新
  619. function SecretRealm.refreshCount()
  620. local serverType = getbaseinfo("servertype")
  621. if serverType == 2 then
  622. return
  623. end
  624. local seconds = getbaseinfo("nowsec")
  625. local now = TimeUtil.timeToDate(seconds)
  626. if now.min == 0 then
  627. local activityRule = ConfigDataManager.getTable("cfg_activity_rule", "id", DuplicateType.SECRET_REALM_BOSS)
  628. local numberTime = activityRule[1]["numbertime"]
  629. local numberAdd = activityRule[1]["numberadd"]
  630. if not string.isNullOrEmpty(numberTime) and not string.isNullOrEmpty(numberAdd) then
  631. local split = string.split(numberTime, "#")
  632. local type = tonumber(split[1])
  633. local numberTime1 = tonumber(split[2])
  634. local numSplit = string.split(numberAdd, "#")
  635. local secretRealmCountStep = tonumber(numSplit[1])
  636. local secretRealmMaxCount = tonumber(numSplit[2])
  637. if type == 1 then
  638. if numberTime1 == now.hour then
  639. SecretRealm.incrementedSecretRealmCount(secretRealmCountStep, secretRealmMaxCount)
  640. end
  641. else
  642. local numberTime2 = tonumber(split[3])
  643. if numberTime1 == now.wday and numberTime2 == now.hour then
  644. SecretRealm.incrementedSecretRealmCount(secretRealmCountStep, secretRealmMaxCount)
  645. end
  646. end
  647. end
  648. end
  649. end