RedFortress.lua 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. --赤色要塞副本
  2. RedFortress = {}
  3. local this = {}
  4. local NoteType = { KILL = 1, RELIVE = 2 }
  5. -- @description 请求进入副本
  6. -- @param 玩家对象;cfg_rep的id
  7. -- @return
  8. function RedFortress.ReqEnterFortress(actor, configId)
  9. -- 验证等级
  10. local playerLevel = tonumber(getbaseinfo(actor, "level"))
  11. local levelConfig = ConfigDataManager.getTableValue("cfg_rep", "level", "id", configId)
  12. local levelList = string.split(levelConfig, "#")
  13. local minLevel = tonumber(levelList[1])
  14. local maxLevel = tonumber(levelList[2])
  15. if playerLevel < minLevel or playerLevel > maxLevel then
  16. tipinfo(actor, "等级不足")
  17. error(actor:toString() .. "赤色要塞副本进入等级不符合要求{" .. playerLevel .. "}{" .. configId .. "}")
  18. return
  19. end
  20. -- 寻找空闲副本
  21. local mapId = DuplicateCommon.FindEnterableDupCommon(configId, 1)
  22. if mapId == 0 then
  23. mapId = DuplicateCommon.CreateDupMapCommon(actor, configId, true)
  24. end
  25. local x, y = DuplicateCommon.GetEnterPointXYCommon(configId)
  26. --回蓝回血
  27. DuplicateCommon.RecoverHPMP(actor)
  28. enterduplicate(actor, mapId, x, y)
  29. end
  30. -- @description 副本阶段更新
  31. -- @param 系统id;地图唯一id;副本类型;副本阶段(1-准备 2-战斗 3-结算);下一阶段开始时间戳;配置id(cfg_rep的id)
  32. -- @return
  33. function RedFortress.RedFortressStateUpdate(system, mapId, state, nextStateStartTime, configId)
  34. if state == DuplicateState.PREPARE then
  35. --准备阶段
  36. -- 初始化副本数据
  37. -- 战斗区域
  38. local fightAreaConfig = ConfigDataManager.getTableValue("cfg_repRedfortress", "start", "repId", configId)
  39. local fightAreaList = string.split(fightAreaConfig, "#")
  40. setenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA, fightAreaList)
  41. setenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_PHASE, 1) --地图每减少一次阶段+1
  42. elseif state == DuplicateState.FIGHT then
  43. --更新阶段信息
  44. this.ResAllPlayCurrencyStateInfo(mapId)
  45. --战斗阶段
  46. -- 生成怪物
  47. local config = ConfigDataManager.getTableFirst("cfg_repRedfortress", "repId", configId)
  48. local monsterConfig = config.monsterid
  49. local monsterList = string.split(monsterConfig, "#")
  50. local playerCount = getplaycountinmap(mapId)
  51. playerCount = tonumber(playerCount or 1)
  52. local maxUnit = config.maxunit
  53. local leftCount = tonumber(maxUnit) - playerCount
  54. for i = 1, leftCount do
  55. --怪物id
  56. local randomIndex = math.random(#monsterList)
  57. local monsterId = monsterList[randomIndex]
  58. --随机点位
  59. local x, y = this.RandomFightPointXY(mapId, 100)
  60. mongen(mapId, x, y, 0, monsterId, 1)
  61. end
  62. -- 玩家传送到战斗区域
  63. local players = getmapplayer(mapId)
  64. for index, player in ipairs(players) do
  65. --随机点位
  66. local x, y = this.RandomFightPointXY(mapId, 100)
  67. maptransfer(player, x, y, 0, 0, 0)
  68. end
  69. this.ResAllPlayersTaskInfo(mapId, maxUnit)
  70. elseif state == DuplicateState.FINISH then
  71. --结算阶段
  72. this.ResAllPlayCurrencyStateInfo(mapId)
  73. -- 计算积分
  74. this.CalcuAndSetPlayerPointRank(mapId)
  75. end
  76. end
  77. -- @description 副本5秒钟心跳
  78. -- @param
  79. -- @return
  80. function RedFortress.Dup5SecondHeart(mapId, dupConfig, state)
  81. if state == DuplicateState.FIGHT then
  82. local area = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA)
  83. local x1 = tonumber(area[1])
  84. local x2 = tonumber(area[2])
  85. local y1 = tonumber(area[3])
  86. local y2 = tonumber(area[4])
  87. -- 不在区域内的怪物死亡
  88. local monsterInfoList = mapbossinfo(mapId)
  89. for key, monInfo in pairs(monsterInfoList) do
  90. local monId = monInfo["id"]
  91. local px = monInfo["x"]
  92. local py = monInfo["y"]
  93. local isIn = this.IsPointInArea(px, py, x1, x2, y1, y2)
  94. if isIn == false then
  95. local monster = getactor(monId, mapId)
  96. removemapobject(monster)
  97. end
  98. end
  99. end
  100. end
  101. -- @description 玩家进入副本后
  102. -- @param 玩家对象;地图唯一id;副本类型;副本阶段(1-准备 2-战斗 3-结算);下一阶段开始时间戳;配置id(cfg_rep的id)
  103. -- @return
  104. function RedFortress.AfterRedFortressEnter(actor, mapId, state, nextStateStartTime, configId)
  105. -- 清除召唤兽
  106. local petId = getbaseinfo(actor, "petid")
  107. local petActor = getactor(petId, mapId)
  108. removemapobject(petActor)
  109. local playerDupInfo = getplaydef(actor, RedFortressPlayerConst.MAP_INFO)
  110. -- 是否是新进入的副本
  111. local newEnter = false
  112. if playerDupInfo == nil or playerDupInfo == "" then
  113. newEnter = true
  114. else
  115. local lastMapId = playerDupInfo[1]
  116. if mapId ~= lastMapId then
  117. newEnter = true
  118. end
  119. end
  120. if newEnter == true then
  121. -- 进入新的副本,初始化玩家变量
  122. playerDupInfo = { mapId, configId }
  123. setplaydef(actor, RedFortressPlayerConst.MAP_INFO, playerDupInfo)
  124. -- 复活次数
  125. setplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES, 0)
  126. -- 积分
  127. setplaydef(actor, RedFortressPlayerConst.KILL_SCORES, 0)
  128. -- 击杀数
  129. setplaydef(actor, RedFortressPlayerConst.KILL_COUNT, 0)
  130. -- 排名
  131. setplaydef(actor, RedFortressPlayerConst.PLAYER_RANK, 0)
  132. end
  133. this.ResCurrencyStateInfo(actor, mapId)
  134. if state == DuplicateState.PREPARE then
  135. -- 发送副本人数
  136. this.ResAllPreparePlayerCount(mapId)
  137. elseif state == DuplicateState.FIGHT then
  138. -- 随机传送
  139. local x, y = this.RandomFightPointXY(mapId, 100)
  140. maptransfer(actor, x, y, 0, 0, 0)
  141. this.ResPlayerTaskInfo(actor, mapId)
  142. end
  143. end
  144. -- @description 玩家退出副本
  145. -- @param 玩家对象;地图唯一id;副本类型;副本阶段(1-准备 2-战斗 3-结算);下一阶段开始时间戳;配置id(cfg_rep的id)
  146. -- @return
  147. function RedFortress.AfterRedFortressQuit(actor, mapId, state, nextStateStartTime, configId)
  148. -- 排名更新;战斗阶段是人数;结算阶段是积分
  149. if state == DuplicateState.PREPARE then
  150. this.ResAllPreparePlayerCount(mapId)
  151. elseif state == DuplicateState.FIGHT then
  152. local players = getmapplayer(mapId)
  153. local playerCount = #players
  154. local monCount = getmoncount(mapId)
  155. local totalCount = monCount + playerCount
  156. setplaydef(actor, RedFortressPlayerConst.PLAYER_RANK, totalCount + 1)
  157. this.LeftCountChange(mapId, 0)
  158. end
  159. end
  160. -- @description 怪物死亡事件
  161. -- @param 地图id;击杀者
  162. -- @return
  163. function RedFortress.OnMonsterDie(mapId, killer)
  164. this.LeftCountChange(mapId, 0)
  165. local dupInfo = getduplicate(mapId)
  166. local configId = dupInfo["dupcfgid"]
  167. if killer:toString() ~= "0" then
  168. -- 击杀者加积分;显示图标
  169. local oldCount = getplaydef(killer, RedFortressPlayerConst.KILL_SCORES)
  170. local pointConfig = ConfigDataManager.getTableValue("cfg_repRedfortress", "points", "repId", configId)
  171. local pointList = string.split(pointConfig, "#")
  172. local addPoint = tonumber(pointList[2])
  173. local newPoint = oldCount + addPoint
  174. setplaydef(killer, RedFortressPlayerConst.KILL_SCORES, newPoint)
  175. -- 加击杀次数
  176. local oldKill = getplaydef(killer, RedFortressPlayerConst.KILL_COUNT)
  177. setplaydef(killer, RedFortressPlayerConst.KILL_COUNT, oldKill + 1)
  178. sendluamsg(killer, LuaMessageIdToClient.RES_RED_FORTRESS_KILL_RELIVE, { NoteType.KILL, oldKill + 1 })
  179. end
  180. end
  181. -- @description 击杀玩家
  182. -- @param 玩家对象;被击杀的玩家
  183. -- @return
  184. function RedFortress.KillPlayer(actor, diePlayer)
  185. local mapId = getbaseinfo(actor, "unimapid")
  186. local dupInfo = getduplicate(mapId)
  187. if dupInfo == nil or dupInfo == "" then
  188. return
  189. end
  190. local type = dupInfo["type"]
  191. if type ~= DuplicateType.RED_FORTRESS then
  192. return
  193. end
  194. local configId = dupInfo["dupcfgids"]
  195. -- 加积分
  196. local oldCount = getplaydef(actor, RedFortressPlayerConst.KILL_SCORES)
  197. local pointConfig = ConfigDataManager.getTableValue("cfg_repRedfortress", "points", "repId", configId)
  198. local pointList = string.split(pointConfig, "#")
  199. local addPoint = tonumber(pointList[1])
  200. local newPoint = oldCount + addPoint
  201. setplaydef(actor, RedFortressPlayerConst.KILL_SCORES, newPoint)
  202. -- 加击杀次数
  203. local oldKill = getplaydef(actor, RedFortressPlayerConst.KILL_COUNT)
  204. setplaydef(actor, RedFortressPlayerConst.KILL_COUNT, oldKill + 1)
  205. -- 击杀图标
  206. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_KILL_RELIVE, { NoteType.KILL, oldKill + 1 })
  207. end
  208. -- @description 玩家死亡事件
  209. -- @param 玩家对象
  210. -- @return
  211. function RedFortress.PlayerDie(actor)
  212. local mapId = getbaseinfo(actor, "unimapid")
  213. local dupInfo = getduplicate(mapId)
  214. if dupInfo == nil then
  215. return
  216. end
  217. local type = dupInfo["type"]
  218. if type ~= DuplicateType.RED_FORTRESS then
  219. return
  220. end
  221. local configId = dupInfo["dupcfgid"]
  222. -- 更新死亡次数
  223. local oldCount = getplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES)
  224. local maxCount = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornChance", "repId", configId)
  225. if oldCount >= tonumber(maxCount) then
  226. -- 退出副本并结算
  227. DuplicateCommon.ReqQuitDuplicate(actor)
  228. else
  229. -- 延迟执行复活
  230. local delaySec = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornTime", "repId", configId)
  231. local delayMillis = tonumber(delaySec) * 1000
  232. intervalcalldelay(actor, delayMillis, 0, 1, "redfortressdorelive")
  233. end
  234. end
  235. function redfortressdorelive(actor)
  236. playrevive(actor, 7, 3)
  237. end
  238. function redfortresskillnotinrange(system, mapId, isFinal)
  239. local area = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA)
  240. local x1 = tonumber(area[1])
  241. local x2 = tonumber(area[2])
  242. local y1 = tonumber(area[3])
  243. local y2 = tonumber(area[4])
  244. -- 不在区域内的怪物死亡
  245. local monsterInfoList = mapbossinfo(mapId)
  246. for key, monInfo in pairs(monsterInfoList) do
  247. local monId = monInfo["id"]
  248. local px = monInfo["x"]
  249. local py = monInfo["y"]
  250. local isIn = this.IsPointInArea(px, py, x1, x2, y1, y2)
  251. if isIn == false then
  252. local monster = getactor(monId, mapId)
  253. removemapobject(monster)
  254. end
  255. end
  256. -- 缩圈阻挡点
  257. this.ShrinkingCircleBlockPoint(system, mapId)
  258. local players = getmapplayer(mapId)
  259. for key, actor in pairs(players) do
  260. local px = getbaseinfo(actor, "x")
  261. local py = getbaseinfo(actor, "y")
  262. local isIn = this.IsPointInArea(px, py, x1, x2, y1, y2)
  263. if isIn == false then
  264. sethp(actor, 0)
  265. local dupInfo = getduplicate(mapId)
  266. local configId = dupInfo["dupcfgid"]
  267. -- 延迟执行复活
  268. local delaySec = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornTime", "repId", configId)
  269. local delayMillis = tonumber(delaySec) * 1000
  270. intervalcalldelay(actor, delayMillis, 0, 1, "redfortressdorelive")
  271. end
  272. end
  273. if isFinal then
  274. local dupInfo = getduplicate(mapId)
  275. local configId = dupInfo["dupcfgid"]
  276. local maxCount = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornChance", "repId", configId)
  277. maxCount = tonumber(maxCount)
  278. for key, player in pairs(players) do
  279. setplaydef(player, RedFortressPlayerConst.RELIVE_TIMES, maxCount)
  280. clearallbuff(player)
  281. end
  282. end
  283. end
  284. -- @description 缩圈阻挡点
  285. -- @param
  286. -- @return
  287. function this.ShrinkingCircleBlockPoint(system, mapId)
  288. local area = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA)
  289. local x1 = tonumber(area[1]) - 1
  290. local x2 = tonumber(area[2]) + 1
  291. local y1 = tonumber(area[3]) - 1
  292. local y2 = tonumber(area[4]) + 1
  293. for x = x1, x2 do
  294. setblockpoint(x, y1, true, mapId) -- 下边
  295. end
  296. for y = y1 + 1, y2 - 1 do
  297. setblockpoint(x2, y, true, mapId) -- 右边(不包括顶点)
  298. end
  299. for x = x2 - 1, x1 + 1, -1 do
  300. setblockpoint(x, y2, true, mapId) -- 上边(不包括顶点)
  301. end
  302. for y = y2 - 1, y1 + 1, -1 do
  303. setblockpoint(x1, y, true, mapId) -- 左边(不包括顶点)
  304. end
  305. -- 设置四个顶点
  306. setblockpoint(x1, y1, true, mapId) -- 左下角
  307. setblockpoint(x2, y1, true, mapId) -- 右下角
  308. setblockpoint(x1, y2, true, mapId) -- 左上角
  309. setblockpoint(x2, y2, true, mapId) -- 右上角
  310. end
  311. -- @description 玩家复活事件
  312. -- @param 玩家对象
  313. -- @return
  314. function RedFortress.PlayerRelive(actor)
  315. local mapId = getbaseinfo(actor, "unimapid")
  316. local dupInfo = getduplicate(mapId)
  317. if dupInfo == nil then
  318. return
  319. end
  320. local type = dupInfo["type"]
  321. if type ~= DuplicateType.RED_FORTRESS then
  322. return
  323. end
  324. local configId = dupInfo["dupcfgid"]
  325. local maxCount = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornChance", "repId", configId)
  326. maxCount = tonumber(maxCount)
  327. -- 扣除复活次数
  328. local oldCount = getplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES)
  329. local newCount = oldCount + 1
  330. if newCount > maxCount then
  331. newCount = maxCount
  332. end
  333. setplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES, newCount)
  334. -- 传送
  335. --随机点位
  336. local x, y = this.RandomFightPointXY(mapId, 100)
  337. maptransfer(actor, x, y, 0, 0, 0)
  338. -- 被击杀图标
  339. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_KILL_RELIVE, { NoteType.RELIVE, newCount })
  340. -- 面板消息
  341. this.ResPlayerTaskInfo(actor, mapId)
  342. end
  343. -- @description 地图玩家怪物数量改变
  344. -- @param 地图id;偏移量
  345. -- @return
  346. function this.LeftCountChange(mapId, offset)
  347. -- 回包
  348. local dupInfo = getduplicate(mapId)
  349. local state = dupInfo["state"]
  350. local players = dupInfo["players"]
  351. local configId = dupInfo["dupcfgid"]
  352. local monCount = getmoncount(mapId)
  353. local totalCount = tonumber(monCount) + #players - offset
  354. if state == DuplicateState.PREPARE then
  355. elseif state == DuplicateState.FIGHT then
  356. this.ResAllPlayersTaskInfo(mapId, totalCount)
  357. -- 只剩最后一个玩家,则结束副本
  358. if totalCount <= 1 then
  359. setduplicatestate(mapId, SetDuplicateStateConst.TO_FINISH)
  360. return
  361. end
  362. -- 阶段更新,地形,
  363. local phase = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_PHASE)
  364. local mapCutConfig = ConfigDataManager.getTableValue("cfg_repRedfortress", "mapCut", "repId", configId)
  365. local mapCutList = string.split(mapCutConfig, "|")
  366. if phase <= #mapCutList then
  367. local mapCutItemStr = mapCutList[phase]
  368. local mapCutItemList = string.split(mapCutItemStr, "#")
  369. local countCondition = mapCutItemList[1]
  370. if totalCount < tonumber(countCondition) then
  371. -- 阶段更新,地形
  372. local percentage = mapCutItemList[2]
  373. local area = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA)
  374. local oldX1 = tonumber(area[1])
  375. local oldX2 = tonumber(area[2])
  376. local oldY1 = tonumber(area[3])
  377. local oldY2 = tonumber(area[4])
  378. local newX1, newX2, newY1, newY2 = this.ShrinkRectangle(oldX1, oldX2, oldY1, oldY2, tonumber(percentage))
  379. -- 取整
  380. newX1 = math.floor(newX1)
  381. newX2 = math.floor(newX2)
  382. newY1 = math.floor(newY1)
  383. newY2 = math.floor(newY2)
  384. local newArea = { newX1, newX2, newY1, newY2 }
  385. setenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA, newArea)
  386. -- 回包
  387. this.ResAllShrinkingStage(mapId, phase, newArea)
  388. -- 延迟5秒,击杀所有不在区域内的玩家
  389. local warningCfg = ConfigDataManager.getTableValue("cfg_repRedfortress", "warning", "repId", configId)
  390. local warningList = string.split(warningCfg, "#")
  391. local delayMillis = tonumber(warningList[phase]) * 1000
  392. if phase >= #mapCutList then
  393. -- 如果是最后一个阶段,扣除玩家所有复活次数和增益效果
  394. -- local maxCount = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornChance", "repId", configId)
  395. -- for key, player in pairs(players) do
  396. -- setplaydef(player, RedFortressPlayerConst.RELIVE_TIMES, maxCount)
  397. -- clearallbuff(player)
  398. -- end
  399. setenvirontimer(mapId, delayMillis, 0, 1, "redfortresskillnotinrange", mapId, true)
  400. else
  401. setenvirontimer(mapId, delayMillis, 0, 1, "redfortresskillnotinrange", mapId, false)
  402. end
  403. setenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_PHASE, phase + 1)
  404. end
  405. end
  406. end
  407. end
  408. -- @description 玩家进入任意地图事件
  409. -- @param 玩家对象;上一个地图配置id;当前地图配置id
  410. -- @return
  411. function RedFortress.EnterAllMap(actor, lastMapCfgId, mapCfgId)
  412. -- 判断发送副本结算
  413. local dupInfo = getplaydef(actor, RedFortressPlayerConst.MAP_INFO)
  414. if dupInfo == nil or dupInfo == "" then
  415. return
  416. end
  417. local bloodyId = dupInfo[1]
  418. local mapId = getbaseinfo(actor, "unimapid")
  419. local mapInfo = getmapinfobyid(mapId)
  420. local isDup = mapInfo["isdup"]
  421. if isDup == true and bloodyId ~= mapId then
  422. error(actor:toString() .. "赤色要塞有未结算的奖励")
  423. RedFortress.ClearPlayerDef(actor)
  424. return
  425. end
  426. if bloodyId ~= mapId then
  427. -- 结算
  428. this.Settlement(actor)
  429. end
  430. end
  431. -- @description 结算
  432. -- @param 玩家对象
  433. -- @return
  434. function this.Settlement(actor)
  435. local dupInfo = getplaydef(actor, RedFortressPlayerConst.MAP_INFO)
  436. if dupInfo == nil or dupInfo == "" then
  437. error("赤色要塞副本结算找不到副本信息")
  438. return
  439. end
  440. local killCount = getplaydef(actor, RedFortressPlayerConst.KILL_COUNT)
  441. local rank = getplaydef(actor, RedFortressPlayerConst.PLAYER_RANK)
  442. -- 发邮件奖励
  443. local configId = dupInfo[2]
  444. local rewardCfg = ConfigDataManager.getTableValue("cfg_repRedfortress", "reward", "repId", configId)
  445. local rewardRank = string.split(rewardCfg, "|")
  446. local itemBing = ConfigDataManager.getTableValue("cfg_bind", "bind", "id", 9)
  447. for key, value in pairs(rewardRank) do
  448. local innerList = string.split(value, "#")
  449. local min = tonumber(innerList[1])
  450. local max = tonumber(innerList[2])
  451. local itemId = innerList[3]
  452. local itemCount = innerList[4]
  453. if min <= rank and rank <= max then
  454. sendconfigmailbyrid(actor, actor:toString(), MailConfig.RED_FORTRESS_REWARD, { [tonumber(itemId)] = tonumber(itemCount == nil and 1 or itemCount) }, rank, itemBing)
  455. break
  456. end
  457. end
  458. -- 发包
  459. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_SETTLEMENT_PANEL, { killCount, rank })
  460. -- 清楚玩家变量
  461. RedFortress.ClearPlayerDef(actor)
  462. end
  463. function RedFortress.ClearPlayerDef(actor)
  464. setplaydef(actor, RedFortressPlayerConst.MAP_INFO, nil)
  465. setplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES, 0)
  466. setplaydef(actor, RedFortressPlayerConst.KILL_SCORES, 0)
  467. setplaydef(actor, RedFortressPlayerConst.KILL_COUNT, 0)
  468. setplaydef(actor, RedFortressPlayerConst.PLAYER_RANK, 0)
  469. end
  470. -- @description 准备阶段人数响应
  471. -- @param 地图id
  472. -- @return
  473. function this.ResAllPreparePlayerCount(mapId)
  474. local dupInfo = getduplicate(mapId)
  475. local state = dupInfo["state"]
  476. if state ~= DuplicateState.PREPARE then
  477. return
  478. end
  479. local players = dupInfo["players"]
  480. for index, actor in ipairs(players) do
  481. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_PREPARE_COUNT, #players)
  482. end
  483. end
  484. -- @description 响应给客户端当前阶段
  485. -- @param 玩家对象;地图id
  486. -- @return
  487. function this.ResCurrencyStateInfo(actor, mapId)
  488. local dupInfo = getduplicate(mapId)
  489. local state = dupInfo["state"]
  490. local configId = dupInfo["dupcfgid"]
  491. local nextStateStartTime = dupInfo["nextstatetime"]
  492. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_STATE_UPDATE, { state, tostring(nextStateStartTime), configId })
  493. end
  494. -- @description 通知地图所有玩家更新当前阶段
  495. -- @param 地图id
  496. -- @return
  497. function this.ResAllPlayCurrencyStateInfo(mapId)
  498. local dupInfo = getduplicate(mapId)
  499. local players = dupInfo["players"]
  500. for index, actor in ipairs(players) do
  501. this.ResCurrencyStateInfo(actor, mapId)
  502. end
  503. end
  504. -- @description 通知当前玩家任务数据
  505. -- @param 地图id
  506. -- @return
  507. function this.ResPlayerTaskInfo(actor, mapId, totalCount)
  508. totalCount = tonumber(totalCount)
  509. if totalCount == nil or totalCount <= 0 then
  510. local monCount = getmoncount(mapId)
  511. local players = getmapplayer(mapId)
  512. totalCount = monCount + #players
  513. end
  514. -- 剩余复活次数
  515. local reliveCount = getplaydef(actor, RedFortressPlayerConst.RELIVE_TIMES)
  516. local dupInfo = getplaydef(actor, RedFortressPlayerConst.MAP_INFO)
  517. local configId = dupInfo[2]
  518. local maxCount = ConfigDataManager.getTableValue("cfg_repRedfortress", "rebornChance", "repId", configId)
  519. local leftCount = maxCount - reliveCount
  520. -- 协议待定
  521. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_TASK_INFO, { totalCount, leftCount })
  522. end
  523. -- @description 通知地图所有玩家任务数据
  524. -- @param 地图id
  525. -- @return
  526. function this.ResAllPlayersTaskInfo(mapId, totalCount)
  527. local dupInfo = getduplicate(mapId)
  528. local players = dupInfo["players"]
  529. for index, actor in ipairs(players) do
  530. this.ResPlayerTaskInfo(actor, mapId, totalCount)
  531. end
  532. end
  533. -- @description 通知地图所有玩家缩圈信息
  534. -- @param 地图id
  535. -- @return
  536. function this.ResAllShrinkingStage(mapId, phase, newArea)
  537. local dupInfo = getduplicate(mapId)
  538. local players = dupInfo["players"]
  539. for index, actor in ipairs(players) do
  540. sendluamsg(actor, LuaMessageIdToClient.RES_RED_FORTRESS_SHRINKING_STAGE, { phase, newArea })
  541. end
  542. end
  543. -- @description 找一个战斗区域可用的点
  544. -- @param 地图id;递归次数
  545. -- @return
  546. function this.RandomFightPointXY(mapId, times)
  547. -- 设置递归最大次数
  548. local maxTimes = 100
  549. if times > maxTimes then
  550. times = maxTimes
  551. end
  552. local area = getenvirvar(mapId, DuplicateVarConst.RED_FORTRESS_FIGHT_AREA)
  553. -- 检查 area 数据格式
  554. if not area or #area ~= 4 then
  555. gameDebug.printTraceback("获取战斗区域错误", area)
  556. return 0, 0
  557. end
  558. local x1 = tonumber(area[1])
  559. local x2 = tonumber(area[2])
  560. local y1 = tonumber(area[3])
  561. local y2 = tonumber(area[4])
  562. -- 检查转换后的数据是否为数字
  563. if not (x1 and x2 and y1 and y2) then
  564. gameDebug.printTraceback("参数错误", x1, x2, y1, y2)
  565. return 0, 0
  566. end
  567. local randomX = this.GetRandomInt(x1, x2)
  568. local randomY = this.GetRandomInt(y1, y2)
  569. local notEmpty = isnotemptyinmap(mapId, randomX, randomY)
  570. local notBlock = notblockpoint(randomX, randomY, mapId)
  571. if notEmpty == false or notBlock == false then
  572. if times > 0 then
  573. times = times - 1
  574. return this.RandomFightPointXY(mapId, times)
  575. else
  576. return 0, 0
  577. end
  578. else
  579. return randomX, randomY
  580. end
  581. end
  582. function this.GetRandomInt(a, b)
  583. -- 确保 a 小于等于 b
  584. if a > b then
  585. a, b = b, a
  586. end
  587. -- 生成 (a, b) 区间内的随机整数
  588. return math.random(a + 1, b - 1)
  589. end
  590. -- @description 计算缩小后的坐标点
  591. -- @param x1, x2, y1, y2坐标点;缩小的百分比,例如20
  592. -- @return x1, x2, y1, y2坐标点
  593. function this.ShrinkRectangle(x1, x2, y1, y2, percentage)
  594. if x1 > x2 then
  595. x1, x2 = x2, x1
  596. end
  597. if y1 > y2 then
  598. y1, y2 = y2, y1
  599. end
  600. local r = percentage / 100
  601. local center_x = (x1 + x2) / 2
  602. local center_y = (y1 + y2) / 2
  603. local width = math.abs(x2 - x1)
  604. local height = math.abs(y2 - y1)
  605. local new_width = width * (1 - r)
  606. local new_height = height * (1 - r)
  607. local x1_new = center_x - new_width / 2
  608. local y1_new = center_y - new_height / 2
  609. local x2_new = center_x + new_width / 2
  610. local y2_new = center_y + new_height / 2
  611. return x1_new, x2_new, y1_new, y2_new
  612. end
  613. -- @description 判断坐标点在不在矩形区域内
  614. -- @param
  615. -- @return
  616. function this.IsPointInArea(px, py, x1, x2, y1, y2)
  617. if x1 > x2 then
  618. x1, x2 = x2, x1
  619. end
  620. if y1 > y2 then
  621. y1, y2 = y2, y1
  622. end
  623. local isIn = not (px < x1 or px > x2 or py < y1 or py > y2)
  624. return isIn
  625. end
  626. -- @description 获取积分排名列表
  627. -- @param 地图id
  628. -- @return 列表<玩家id字符串;排名>
  629. function this.GetScoreRanking(mapId)
  630. local players = getmapplayer(mapId)
  631. local playerList = {}
  632. for index, actor in ipairs(players) do
  633. local score = getplaydef(actor, RedFortressPlayerConst.KILL_SCORES)
  634. table.insert(playerList, { actor = actor, score = score })
  635. end
  636. -- 按积分从高到低排序,如果积分相同,保持原有顺序
  637. table.sort(
  638. playerList,
  639. function(a, b)
  640. return a.score > b.score
  641. end
  642. )
  643. -- 计算排名
  644. local ranks = {}
  645. local rank = 1 -- 当前排名
  646. local sameRankCount = 0 -- 相同积分的计数
  647. local lowestRank = 1 -- 当前积分组的最低排名
  648. for i = 1, #playerList do
  649. local player = playerList[i]
  650. local nextPlayer = playerList[i + 1]
  651. -- 判断下一名玩家是否与当前玩家积分相同
  652. if nextPlayer and player.score == nextPlayer.score then
  653. sameRankCount = sameRankCount + 1
  654. else
  655. -- 更新最低排名为当前排名加上相同积分玩家的数量
  656. lowestRank = rank + sameRankCount
  657. -- 将当前积分相同的所有玩家设为最低排名
  658. for j = i - sameRankCount, i do
  659. ranks[playerList[j].actor.toString] = lowestRank
  660. end
  661. -- 更新排名和计数
  662. rank = lowestRank + 1
  663. sameRankCount = 0
  664. end
  665. end
  666. return ranks
  667. end
  668. -- @description 获取指定玩家的积分排名
  669. -- @param 玩家对象;地图id
  670. -- @return 排名
  671. function this.GetPlayerRank(actor, mapId)
  672. local ranking = this.GetScoreRanking(mapId)
  673. return ranking[actor.toString]
  674. end
  675. -- @description 计算并设置玩家积分
  676. -- @param 地图id
  677. -- @return
  678. function this.CalcuAndSetPlayerPointRank(mapId)
  679. local players = getmapplayer(mapId)
  680. if #players <= 0 then
  681. return
  682. end
  683. local playerList = {}
  684. for index, actor in ipairs(players) do
  685. local score = getplaydef(actor, RedFortressPlayerConst.KILL_SCORES)
  686. table.insert(playerList, { actor = actor, score = score })
  687. end
  688. -- 按积分从高到低排序,如果积分相同,保持原有顺序
  689. table.sort(
  690. playerList,
  691. function(a, b)
  692. return a.score > b.score
  693. end
  694. )
  695. -- 计算排名
  696. local rank = 1 -- 当前排名
  697. local sameRankCount = 0 -- 相同积分的计数
  698. local lowestRank = 1 -- 当前积分组的最低排名
  699. if #playerList > 1 then
  700. for i = 1, #playerList do
  701. local player = playerList[i]
  702. local nextPlayer = playerList[i + 1]
  703. -- 判断下一名玩家是否与当前玩家积分相同
  704. if nextPlayer and player.score == nextPlayer.score then
  705. sameRankCount = sameRankCount + 1
  706. else
  707. -- 更新最低排名为当前排名加上相同积分玩家的数量
  708. lowestRank = rank + sameRankCount
  709. -- 将当前积分相同的所有玩家设为最低排名
  710. for j = i - sameRankCount, i do
  711. local actor = playerList[j].actor
  712. setplaydef(actor, RedFortressPlayerConst.PLAYER_RANK, lowestRank)
  713. end
  714. -- 更新排名和计数
  715. rank = lowestRank + 1
  716. sameRankCount = 0
  717. end
  718. end
  719. else
  720. local player = playerList[1].actor
  721. setplaydef(player, RedFortressPlayerConst.PLAYER_RANK, 1)
  722. end
  723. end