Monster.lua 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. ---
  2. --- Generated by EmmyLua(https://github.com/EmmyLua)
  3. --- Created by zhangkai.
  4. --- DateTime: 2024/7/25 下午8:55
  5. ---
  6. MonsterScript = {}
  7. local this = {}
  8. ---玩家击杀怪物记录
  9. local MONSTER_DROP_RECORD = "T$monster_drop_record"
  10. --全服道具掉落记录(每日清空数据)
  11. local GLOBAL_ITEM_DROP = "Q$global_item_record"
  12. ---怪物组掉落记录
  13. local DECAY_GROUP_RECORD = "T$decay_group_record"
  14. ---怪物组记录重置时间
  15. local DECAY_GROUP_REST_TIME = "T$decay_group_rest_time"
  16. ---怪物首刀信息记录
  17. local MONSTER_FIRST_ATTACK_INFO = "@monster_first_attack_info"
  18. ---怪物伤害列表
  19. local MONSTER_HURT_LIST = "@monster_hurt_list"
  20. ---道具掉落限制类型
  21. local ItemLimitType = {
  22. -- 小时限制
  23. HOUR = 1,
  24. -- 天限制
  25. DAY = 2
  26. }
  27. local MonsterType = {
  28. ---普通怪
  29. NORMAL = 1
  30. }
  31. ---怪物掉落类型
  32. local DropType = {
  33. ---无归属
  34. NOT_OWNER = 0,
  35. ---最大伤害
  36. MAX_THREAT = 1,
  37. ---尾刀(击杀者)
  38. LAST_ATTACK = 2,
  39. ---最大伤害
  40. MAX_HURT = 3,
  41. ---参与者
  42. PARTAKE = 4,
  43. ---获取首刀玩家
  44. FIRST_ATTACK = 5
  45. }
  46. ---怪物仇恨类型
  47. local ThreatType = {
  48. ---累计仇恨值越高,优先级越高
  49. MAX_HATE = 1,
  50. ---目标对怪物的总伤害越高,优先级越高
  51. MAX_HURT = 2
  52. }
  53. function this.GetMonsterDropRecord(actor)
  54. local dropRecord = getplaydef(actor, MONSTER_DROP_RECORD)
  55. if dropRecord == nil then
  56. dropRecord = {}
  57. end
  58. return dropRecord
  59. end
  60. function this.SaveMonsterDropRecord(actor, dropRecord)
  61. setplaydef(actor, MONSTER_DROP_RECORD, dropRecord)
  62. end
  63. function this.GetGlobalItemDrop()
  64. local itemDrop = getsysvar(GLOBAL_ITEM_DROP)
  65. if itemDrop == nil then
  66. itemDrop = {}
  67. end
  68. return itemDrop
  69. end
  70. function this.SaveGlobalItemDrop(itemDrop)
  71. setsysvar(GLOBAL_ITEM_DROP, itemDrop)
  72. end
  73. function this.GetDecayGroupRecord(actor)
  74. local record = getplaydef(actor, DECAY_GROUP_RECORD)
  75. if record == nil then
  76. record = {}
  77. end
  78. return record
  79. end
  80. function this.SaveDecayGroupRecord(actor, record)
  81. setplaydef(actor, DECAY_GROUP_RECORD, record)
  82. end
  83. function this.GetDecayGroupRestTime(actor)
  84. local restTime = getplaydef(actor, DECAY_GROUP_REST_TIME)
  85. if restTime == nil then
  86. return 0
  87. end
  88. return restTime
  89. end
  90. function this.SaveDecayGroupRestTime(actor, restTime)
  91. setplaydef(actor, DECAY_GROUP_REST_TIME, restTime)
  92. end
  93. function this.GetMonsterFirstAttack(monsterActor)
  94. local firstAttackInfo = getplaydef(monsterActor, MONSTER_FIRST_ATTACK_INFO)
  95. if firstAttackInfo == nil then
  96. firstAttackInfo = {}
  97. end
  98. return firstAttackInfo
  99. end
  100. function this.SaveMonsterFirstAttack(monsterActor, firstAttackInfo)
  101. setplaydef(monsterActor, MONSTER_FIRST_ATTACK_INFO, firstAttackInfo)
  102. end
  103. function this.GetMonsterHurtList(monsterActor)
  104. local hurtList = getplaydef(monsterActor, MONSTER_HURT_LIST)
  105. if hurtList == nil then
  106. hurtList = {}
  107. end
  108. return hurtList
  109. end
  110. function this.SaveMonsterHurtList(monsterActor, hurtList)
  111. setplaydef(monsterActor, MONSTER_HURT_LIST, hurtList)
  112. end
  113. ---获取怪物首刀归属时长限制
  114. function this.GetMonsterFirstAttackTimeLimit()
  115. local timeLimit =
  116. tonumber(
  117. ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.MONSTER_FIRST_ATTACK_TIME_LIMIT)
  118. )
  119. if timeLimit == nil then
  120. return 0
  121. end
  122. return timeLimit
  123. end
  124. ---获取怪物最高伤害归属时长限制
  125. function this.GetMonsterMaxHurtTimeLimit()
  126. local timeLimit =
  127. tonumber(
  128. ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.MONSTER_MAX_HURT_TIME_LIMIT)
  129. )
  130. if timeLimit == nil then
  131. return 0
  132. end
  133. return timeLimit
  134. end
  135. ---怪物死亡触发
  136. function MonsterScript.MonsterDieTrigger(monsterActor, dieParam)
  137. local success, errorInfo = xpcall(this.MonsterDieTrigger, debug.traceback, monsterActor, dieParam)
  138. gameDebug.assertPrint(success, "怪物死亡触发事件异常:", monsterActor, dieParam, errorInfo)
  139. end
  140. ---怪物死亡触发的功能
  141. function this.MonsterDieTrigger(monsterActor, dieParam)
  142. local mapId = tonumber(dieParam["mapid"])
  143. local monsterCfgId = tonumber(dieParam["monstercfg"])
  144. local killerId = tonumber(dieParam["killer"])
  145. local mongenCfgId = tonumber(dieParam["mongencfg"])
  146. local maxHurtRid = tonumber(dieParam["maxhurt"])
  147. local ownerId = tonumber(dieParam["owner"])
  148. --更新怪物复活时间
  149. MonsterScript.updateMonsterReliveTime(monsterActor, monsterCfgId)
  150. local killerActor = getactor(killerId, mapId)
  151. local ownerActor = getactor(ownerId, mapId)
  152. local type = getbaseinfo(monsterActor, "mapobjecttype")
  153. if type == MapObjectType.PET then
  154. --宠物死亡
  155. Pet.PetDie(monsterActor, monsterCfgId)
  156. return
  157. end
  158. if (killerId == nil or killerId == 0) and (ownerId == nil or ownerId == 0) then
  159. error("怪物死亡触发事件参数异常, killId、ownerId为空:", monsterActor, dieParam)
  160. return
  161. end
  162. if killerId == nil or killerId == 0 or killerActor == nil then
  163. killerActor = ownerActor
  164. end
  165. --更新黄金任务
  166. GoldTask.UpdateTaskProgress(killerActor, monsterCfgId)
  167. --更新boss悬赏
  168. BossBounty.KillMonster(killerActor, monsterCfgId)
  169. --更新开服首杀
  170. OpenServerAct.UpdateFirstKill(killerActor, maxHurtRid, 0, monsterCfgId)
  171. --更新黄金首杀
  172. GoldFirstKill.UpdateTaskProgress(killerActor, monsterCfgId)
  173. --更新大天使福利任务
  174. AngelBenefit.UpdateTaskProgress(killerActor, AngelBenefit.TASK_TYPE.MONSTER, monsterCfgId)
  175. --更新诸神降临活动数据
  176. GodsDescended.monsterDie(monsterActor, ownerActor, monsterCfgId)
  177. --更新圣域BOSS数据
  178. SanctuaryBoss.monsterDie(monsterActor)
  179. --更新猎魔勋章数据
  180. MonsterHunt.MonsterDie(ownerId, monsterCfgId)
  181. --触发任务目标刷新
  182. this.TriggerMonsterDieTaskGoal(monsterActor, killerActor, monsterCfgId, mongenCfgId)
  183. end
  184. ---更新怪物死亡任务目标
  185. function this.TriggerMonsterDieTaskGoal(monsterActor, actor, monsterCfgId, mongenCfgId)
  186. local owner = this.GetFirstAttack(monsterActor, actor)
  187. TaskHandler.TriggerTaskGoal(owner, TaskTargetType.KILL_LEVEL_MONSTER, monsterCfgId)
  188. -- 触发任务目标
  189. local cfg_map_id = getbaseinfo(actor, "mapid")
  190. local param = {
  191. [1] = monsterCfgId,
  192. [2] = cfg_map_id,
  193. [3] = mongenCfgId
  194. }
  195. TaskHandler.TriggerTaskGoal(owner, TaskTargetType.KILL_TYPE_MONSTER, param)
  196. TaskHandler.TriggerTaskGoal(actor, TaskTargetType.LAST_KILL_MONSTER, param)
  197. TaskHandler.TriggerTaskGoal(owner, TaskTargetType.FIRST_ATTACK_MONSTER, param)
  198. end
  199. ---获取首刀玩家
  200. function this.GetFirstAttack(monsterActor, killer)
  201. local owner = nil
  202. --改为首刀归属
  203. local firstAttack = this.GetMonsterFirstAttack(monsterActor)
  204. if not table.isNullOrEmpty(firstAttack) then
  205. local mapId = getbaseinfo(killer, "unimapid")
  206. owner = getactor(firstAttack["rid"], mapId)
  207. end
  208. if owner == nil then
  209. owner = killer
  210. end
  211. return owner
  212. end
  213. function MonsterScript.updateMonsterReliveTime(monsterActor, monsterCfgId)
  214. local success, errorInfo = xpcall(this.updateMonsterReliveTime, debug.traceback, monsterActor, monsterCfgId)
  215. gameDebug.assertPrint(success, "怪物死亡更新复活时间异常:", monsterActor, monsterCfgId, errorInfo)
  216. end
  217. --- 更新怪物复活时间
  218. function this.updateMonsterReliveTime(monsterActor, monsterCfgId)
  219. local ai = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterCfgId)
  220. if ai == nil then
  221. error("updateMonsterReliveTime cfg_monster表ai字段为空 monsterCfgId:" .. monsterCfgId)
  222. return
  223. end
  224. local aiConfig = ConfigDataManager.getById("cfg_monster_ai", ai)
  225. if aiConfig == nil then
  226. error("updateMonsterReliveTime cfg_monster_ai为nil id:" .. ai)
  227. return
  228. end
  229. local reliveType = tonumber(aiConfig["relivetype"])
  230. --local str = aiConfig['relivedelay']
  231. if reliveType == 4 then
  232. local str = aiConfig["reliveservicetime"]
  233. if string.isNullOrEmpty(str) then
  234. return
  235. end
  236. -- 1#50|3#100|6#150
  237. local strShuXian = string.split(str, "|")
  238. --local serverOpenDays1 = tonumber(getserveropendays(monsterActor))
  239. local serverOpenDays = getbaseinfo(monsterActor, "serveropendays")
  240. local cfg = {}
  241. for _, v in pairs(strShuXian) do
  242. local strJinHao = string.split(v, "#")
  243. local day = tonumber(strJinHao[1])
  244. if tonumber(serverOpenDays) >= day then
  245. cfg = strJinHao
  246. end
  247. end
  248. if table.isNullOrEmpty(cfg) then
  249. error("updateMonsterReliveTime 未找到匹配的数据 开服天数:" .. tostring(serverOpenDays) .. ",reliveDelay字段内容:" .. str)
  250. return
  251. end
  252. local cfgTime = tonumber(cfg[2])
  253. local curTime = tonumber(getbaseinfo(monsterActor, "now"))
  254. local reliveTime = curTime + cfgTime
  255. setmonsterrelivetime(monsterActor, reliveTime)
  256. --jprint("复活时间:" , reliveTime,",怪物信息:" , monsterActor,",开服天数:",serverOpenDays, ",当前时间:", curTime,",配置时间:", cfgTime, ",配置:", cfg, ",str:", str)
  257. end
  258. end
  259. ---怪物掉落道具
  260. function MonsterScript.MonsterDieCulDrop(monsterActor, dieParam)
  261. local success, dropResult = xpcall(this.MonsterDieCulDrop, debug.traceback, monsterActor, dieParam)
  262. if not success then
  263. gameDebug.assertPrint(success, "怪物死亡掉落执行异常:", dropResult, "参数", monsterActor, dieParam)
  264. return nil
  265. end
  266. return dropResult
  267. end
  268. function this.MonsterDieCulDrop(monsterActor, dieParam)
  269. local mapId = tonumber(dieParam["mapid"])
  270. local monsterCfgId = tonumber(dieParam["monstercfg"])
  271. local killerId = tonumber(dieParam["killer"])
  272. local killerActor = getactor(killerId, mapId)
  273. local owner = this.GetFirstAttack(monsterActor, killerActor)
  274. local itemDecay, itemGroupDecay = this.GetDecayCfg(owner, monsterCfgId)
  275. --jprint("获取掉落衰减配置:", itemDecay,itemGroupDecay)
  276. local dropRecord = this.GetMonsterDropRecord(owner)
  277. local allDropCfg = this.GetAllDropCfg(owner, monsterCfgId, dropRecord, itemGroupDecay)
  278. if table.isNullOrEmpty(allDropCfg) then
  279. return nil
  280. end
  281. --掉落道具结果
  282. local dropResult = {}
  283. --全服道具掉落记录
  284. local globalItemDrop = this.GetGlobalItemDrop()
  285. --先检查重置记录
  286. this.CheckDropItemReset(globalItemDrop)
  287. --计算掉落结果
  288. this.GetDropResult(
  289. dieParam,
  290. owner,
  291. monsterActor,
  292. allDropCfg,
  293. globalItemDrop,
  294. dropRecord,
  295. dropResult,
  296. itemDecay,
  297. false
  298. )
  299. --保存掉落记录
  300. this.SaveMonsterDropRecord(owner, dropRecord)
  301. --更新衰减组记录
  302. this.RecordDecayGroupCount(owner, monsterCfgId)
  303. --jprint("怪物掉落记录:", dropRecord)
  304. --清理怪物伤害列表、首刀信息
  305. this.ClearMonsterAttackInfo(monsterActor)
  306. if table.isNullOrEmpty(dropResult) then
  307. return
  308. end
  309. --保存道具记录
  310. this.SaveGlobalItemDrop(globalItemDrop)
  311. -- 特权BOSS奖励弹窗
  312. PrivilegeBoss.resRewardPanel(owner, monsterCfgId, mapId, dropResult)
  313. return dropResult
  314. end
  315. ---清理怪物伤害列表、首刀信息
  316. function this.ClearMonsterAttackInfo(monsterActor)
  317. this.SaveMonsterFirstAttack(monsterActor, nil)
  318. this.SaveMonsterHurtList(monsterActor, nil)
  319. end
  320. ---获取所有掉落组配置
  321. function this.GetAllDropCfg(actor, monsterCfgId, dropRecord, itemGroupDecayCfg)
  322. local mGroupList = ConfigDataManager.getTableValue("cfg_monster", "mgroup", "id", monsterCfgId)
  323. if string.isNullOrEmpty(mGroupList) then
  324. return nil
  325. end
  326. local groupArray = string.split(mGroupList, "#")
  327. local monsterLv = tonumber(ConfigDataManager.getTableValue("cfg_monster", "level", "id", monsterCfgId))
  328. local killerLv = tonumber(getbaseinfo(actor, "level"))
  329. --衰减配置
  330. local decayCfg = 0
  331. local mDecayGroup = ConfigDataManager.getTableValue("cfg_monster", "mdecaygroup", "id", monsterCfgId)
  332. if not string.isNullOrEmpty(mDecayGroup) then
  333. decayCfg = tonumber(mDecayGroup)
  334. end
  335. local dropGroupList = {}
  336. --玩家掉落加成倍率
  337. local bonusRate = this.GetRoleBonusRate(actor, monsterCfgId)
  338. for _, mGroup in pairs(groupArray) do
  339. local group = tonumber(mGroup)
  340. local dropTimes = dropRecord[group]
  341. if dropTimes == nil then
  342. dropTimes = 0
  343. end
  344. local startCount = dropTimes + 1
  345. local dropCfgList = this.GetDropCfgList(killerLv, monsterLv, group, startCount, bonusRate, itemGroupDecayCfg)
  346. --此处不判空后续要计次
  347. dropGroupList[group] = dropCfgList
  348. end
  349. return dropGroupList
  350. end
  351. ---获取角色综合加成倍率
  352. function this.GetRoleBonusRate(actor, monsterCfgId)
  353. local bonusRate = 1
  354. -- --三倍收益倍率
  355. -- local tripleRate = TripleIncome.GetRate(actor)
  356. -- --属性倍率
  357. -- local attrRate = this.GetAttrDropRate(actor)
  358. -- bonusRate = tripleRate * attrRate
  359. --jprint("获取玩家掉落倍率:", bonusRate, tripleRate,attrRate)
  360. return bonusRate
  361. end
  362. ---获取属性倍率
  363. function this.GetAttrDropRate(actor)
  364. local attrRate = tonumber(getattrinfo(actor, "propdropincrease"))
  365. if attrRate == nil then
  366. return 1
  367. end
  368. return 1 + attrRate
  369. end
  370. ---获取一个掉落组中的配置列表
  371. function this.GetDropCfgList(killerLv, monsterLv, group, dropTimes, roleRate, itemGroupDecayCfg)
  372. local cfgList = ConfigDataManager.getTable("cfg_boss_drop", "mgroup", group)
  373. if table.isNullOrEmpty(cfgList) then
  374. return nil
  375. end
  376. local dropCfgList = {}
  377. for _, dropBossCfg in pairs(cfgList) do
  378. local dropParam = this.GetDropCfg(killerLv, monsterLv, dropBossCfg, dropTimes, roleRate, itemGroupDecayCfg)
  379. if not table.isNullOrEmpty(dropParam) then
  380. local dropCfgId = tonumber(dropBossCfg["id"])
  381. dropCfgList[dropCfgId] = dropParam
  382. end
  383. end
  384. return dropCfgList
  385. end
  386. ---获取一个掉落配置
  387. function this.GetDropCfg(killerLv, monsterLv, dropCfg, dropTimes, roleRate, itemGroupDecayCfg)
  388. local numLimit = string.split(dropCfg["dropnum"], "#")
  389. local min = tonumber(numLimit[1])
  390. local max = tonumber(numLimit[2])
  391. if dropTimes < min or dropTimes > max then
  392. return nil
  393. end
  394. local dropRate = this.CulDropRate(killerLv, monsterLv, dropCfg, roleRate)
  395. local extractNum = tonumber(dropCfg["extractnum"])
  396. local itemGroup = dropCfg["itemgroup"]
  397. if string.isNullOrEmpty(itemGroup) then
  398. local randomGroupCfg = dropCfg["itemgrouprandom"]
  399. local tableName, addExtract = this.GetRandomItemGroup(randomGroupCfg, dropRate, itemGroupDecayCfg)
  400. if addExtract ~= nil and addExtract > 0 then
  401. itemGroup = tableName
  402. extractNum = extractNum * addExtract
  403. end
  404. end
  405. if string.isNullOrEmpty(itemGroup) then
  406. return nil
  407. end
  408. local dropParam = {
  409. id = tonumber(dropCfg["id"]),
  410. table_name = itemGroup,
  411. extract_times = extractNum,
  412. rate = dropRate
  413. }
  414. return dropParam
  415. end
  416. ---获取配置的随机道具组
  417. function this.GetRandomItemGroup(randomGroupCfg, dropRate, itemGroupDecayCfg)
  418. if string.isNullOrEmpty(randomGroupCfg) then
  419. return nil
  420. end
  421. local itemGroupCfg = string.split(randomGroupCfg, "#")
  422. local tableName = itemGroupCfg[1]
  423. ---随机概率万分比
  424. local probabilityCfg = tonumber(itemGroupCfg[2])
  425. local percent = 10000
  426. local extractNum = 0
  427. local decayRate = this.GetItemGroupDecayRate(tableName, itemGroupDecayCfg)
  428. local realProbability = probabilityCfg * dropRate * decayRate
  429. --jprint("随机掉落组配置:", tableName,dropRate,decayRate, realProbability)
  430. if realProbability >= percent then
  431. extractNum = math.floor(realProbability / percent)
  432. realProbability = math.fmod(realProbability, percent)
  433. end
  434. local randomNum = math.random(1, percent)
  435. if randomNum <= realProbability then
  436. extractNum = extractNum + 1
  437. end
  438. --jprint("随机掉落组配置:", tableName, extractNum,realProbability)
  439. return tableName, extractNum
  440. end
  441. function this.GetItemGroupDecayRate(tableName, itemGroupDecayCfg)
  442. if table.isNullOrEmpty(itemGroupDecayCfg) then
  443. return 1
  444. end
  445. for tableNames, rate in pairs(itemGroupDecayCfg) do
  446. if string.contains(tableNames, tableName) then
  447. return rate
  448. end
  449. end
  450. return 1
  451. end
  452. ---计算最终掉落倍率
  453. function this.CulDropRate(killerLv, monsterLv, dropCfg, roleRate)
  454. local finalRate = roleRate
  455. local lvDecaySign = dropCfg["decaysign"]
  456. --掉落等级衰减
  457. finalRate = this.CulLevelRate(killerLv, monsterLv, lvDecaySign, finalRate)
  458. return finalRate
  459. end
  460. ---获取配置掉落概率
  461. function this.GetLevelRateCfg(killerLv, monsterLv, decayCfg)
  462. local roleSection = string.split(decayCfg["rolesection"], "#")
  463. local roleLvMin = tonumber(roleSection[1])
  464. local roleLvMax = tonumber(roleSection[2])
  465. if killerLv < roleLvMin or killerLv > roleLvMax then
  466. return nil
  467. end
  468. local monsterSection = string.split(decayCfg["monstersection"], "#")
  469. local monsterLvMin = tonumber(monsterSection[1])
  470. local monsterLvMax = tonumber(monsterSection[2])
  471. if monsterLv < monsterLvMin or monsterLv > monsterLvMax then
  472. return nil
  473. end
  474. return tonumber(decayCfg["dropdecayrate"])
  475. end
  476. function this.CulLevelRate(killerLv, monsterLv, decaySign, roleRate)
  477. local cfgList = ConfigDataManager.getTable("cfg_boss_dropDecay", "decaysign", decaySign)
  478. if table.isNullOrEmpty(cfgList) then
  479. return roleRate
  480. end
  481. for _, decayCfg in pairs(cfgList) do
  482. local rateCfg = this.GetLevelRateCfg(killerLv, monsterLv, decayCfg)
  483. if rateCfg ~= nil then
  484. return roleRate * (rateCfg / 10000)
  485. end
  486. end
  487. return roleRate
  488. end
  489. ---计算掉落结果
  490. function this.GetDropResult(
  491. dieParam,
  492. actor,
  493. monsterActor,
  494. allDropCfg,
  495. globalItemDrop,
  496. dropRecord,
  497. dropResult,
  498. itemDecay,
  499. gm)
  500. --随机道具
  501. for dropGroup, dropCfgList in pairs(allDropCfg) do
  502. local dropCount = dropRecord[dropGroup]
  503. if dropCount == nil then
  504. dropCount = 0
  505. end
  506. if not table.isNullOrEmpty(dropCfgList) then
  507. for dropCfgId, dropCfg in pairs(dropCfgList) do
  508. this.CulDropItem(
  509. dieParam,
  510. actor,
  511. monsterActor,
  512. dropCfg,
  513. dropCount,
  514. globalItemDrop,
  515. dropResult,
  516. itemDecay,
  517. gm
  518. )
  519. end
  520. end
  521. --记录掉落次数
  522. dropRecord[dropGroup] = dropCount + 1
  523. end
  524. end
  525. function this.CulDropItem(dieParam, actor, monsterActor, dropCfg, dropCount, globalItemDrop, dropResult, itemDecay, gm)
  526. local extractTimes = dropCfg.extract_times
  527. --按配置次数随机
  528. for i = 1, extractTimes do
  529. this.RandomDropItem(
  530. dieParam,
  531. actor,
  532. monsterActor,
  533. dropCfg,
  534. dropCount,
  535. globalItemDrop,
  536. dropResult,
  537. itemDecay,
  538. gm
  539. )
  540. end
  541. end
  542. ---随机掉落道具
  543. function this.RandomDropItem(
  544. dieParam,
  545. actor,
  546. monsterActor,
  547. dropCfg,
  548. dropCount,
  549. globalItemDrop,
  550. dropResult,
  551. itemDecay,
  552. gm)
  553. local tableName = dropCfg.table_name
  554. local bossDropCfgId = dropCfg.id
  555. local dropRate = dropCfg.rate
  556. local dropRet = culdroptablebyname(actor, tableName, dropRate, dropCount, itemDecay)
  557. if dropRet == false or table.isNullOrEmpty(dropRet) then
  558. return
  559. end
  560. --掉落道具数量
  561. local dropItem = this.GetDropItem(dropRet, globalItemDrop)
  562. if table.isNullOrEmpty(dropItem) then
  563. return
  564. end
  565. --掉落道具
  566. if gm == false then
  567. local firstAttack = tonumber(getbaseinfo(actor, "rid"))
  568. local mapId = tonumber(dieParam["mapid"])
  569. local mainOwner, owners = this.SettingOwners(monsterActor, dieParam, bossDropCfgId, firstAttack)
  570. local ret = monsterdiedroptomap(monsterActor, mapId, bossDropCfgId, dropItem, mainOwner, owners)
  571. if ret == false or ret == nil then
  572. return
  573. end
  574. end
  575. --记录道具抽取次数
  576. this.MergeDropItem(dropItem, globalItemDrop, dropResult)
  577. end
  578. ---计算掉落归属
  579. function this.SettingOwners(monsterActor, dieParam, bossDropCfgId, firstAttack)
  580. local owners = {}
  581. local mainOwner = firstAttack
  582. local mapId = tonumber(dieParam["mapid"])
  583. local dropType = tonumber(ConfigDataManager.getTableValue("cfg_boss_drop", "droptype", "id", bossDropCfgId))
  584. if dropType == DropType.NOT_OWNER then
  585. return mainOwner, owners
  586. elseif dropType == DropType.MAX_THREAT then
  587. local maxThreat = tonumber(dieParam["maxthreat"])
  588. mainOwner = maxThreat
  589. elseif dropType == DropType.LAST_ATTACK then
  590. local killerId = tonumber(dieParam["killer"])
  591. mainOwner = killerId
  592. elseif dropType == DropType.MAX_HURT then
  593. local maxHurtRid = this.GetMaxHurtPlayer(monsterActor)
  594. if maxHurtRid ~= nil and maxHurtRid > 0 then
  595. mainOwner = maxHurtRid
  596. end
  597. elseif dropType == DropType.PARTAKE then
  598. local threatList = dieParam["threatlist"]
  599. this.AddOwners(owners, threatList)
  600. elseif dropType == DropType.FIRST_ATTACK then
  601. mainOwner = firstAttack
  602. end
  603. table.insert(owners, mainOwner)
  604. --添加队友
  605. local ownerActor = getactor(mainOwner, mapId)
  606. local memberRids = Team.GetAllMemberRids(ownerActor)
  607. this.AddOwners(owners, memberRids)
  608. return mainOwner, owners
  609. end
  610. function this.AddOwners(owners, ridList)
  611. if table.isNullOrEmpty(ridList) then
  612. return
  613. end
  614. for _, rid in pairs(ridList) do
  615. if not table.contains(owners, rid) then
  616. table.insert(owners, rid)
  617. end
  618. end
  619. end
  620. ---获取实际掉落的道具
  621. function this.GetDropItem(dropRet, globalItemDrop)
  622. if table.isNullOrEmpty(dropRet) then
  623. return nil
  624. end
  625. local itemList = {}
  626. for itemCfgId, itemCount in pairs(dropRet) do
  627. local realCount = this.GetRealDropCount(itemCfgId, itemCount, globalItemDrop)
  628. if realCount > 0 then
  629. itemList[itemCfgId] = realCount
  630. end
  631. end
  632. return itemList
  633. end
  634. ---合并掉落道具
  635. function this.MergeDropItem(dropItem, globalItemDrop, dropResult)
  636. --记录道具抽取次数
  637. for itemCfgId, timeCount in pairs(dropItem) do
  638. --全服道具记录(无限制不记录)
  639. this.UpdateItemDropRecord(itemCfgId, timeCount, globalItemDrop)
  640. --怪物掉落结果
  641. this.MergeItemRecord(itemCfgId, timeCount, dropResult)
  642. end
  643. end
  644. ---更新限制道具掉落数量
  645. function this.UpdateItemDropRecord(itemCfgId, timeCount, globalItemDrop)
  646. --小时记录
  647. local hourLimit = ConfigDataManager.getTableValue("cfg_item", "droplimithour", "id", itemCfgId)
  648. if not string.isNullOrEmpty(hourLimit) and tonumber(hourLimit) > 0 then
  649. this.MergeItemDropRecord(itemCfgId, timeCount, globalItemDrop, ItemLimitType.HOUR)
  650. end
  651. --每日记录
  652. local dayLimit = ConfigDataManager.getTableValue("cfg_item", "droplimitday", "id", itemCfgId)
  653. if not string.isNullOrEmpty(dayLimit) and tonumber(dayLimit) > 0 then
  654. this.MergeItemDropRecord(itemCfgId, timeCount, globalItemDrop, ItemLimitType.DAY)
  655. end
  656. end
  657. function this.MergeItemDropRecord(itemCfgId, timeCount, globalItemDrop, limitType)
  658. local record = globalItemDrop[limitType]
  659. if record == nil then
  660. local nowTime = tonumber((getbaseinfo("nowsec")))
  661. record = {
  662. item_record = {},
  663. reset_time = nowTime
  664. }
  665. end
  666. this.MergeItemRecord(itemCfgId, timeCount, record.item_record)
  667. globalItemDrop[limitType] = record
  668. --jprint("更新每日道具记录,",record)
  669. end
  670. function this.MergeItemRecord(itemCfgId, timeCount, itemRecord)
  671. local recordCount = itemRecord[itemCfgId]
  672. if recordCount == nil then
  673. recordCount = 0
  674. end
  675. itemRecord[itemCfgId] = recordCount + timeCount
  676. end
  677. ---获取道具实际掉落数量
  678. function this.GetRealDropCount(itemCfgId, itemCount, globalItemDrop)
  679. local realCount = itemCount
  680. --小时限制
  681. local hourLimit = ConfigDataManager.getTableValue("cfg_item", "droplimithour", "id", itemCfgId)
  682. if not string.isNullOrEmpty(hourLimit) and tonumber(hourLimit) then
  683. local hourRecord = globalItemDrop[ItemLimitType.HOUR]
  684. local dropCount = this.CanDropCount(itemCfgId, itemCount, hourRecord, tonumber(hourLimit))
  685. realCount = math.min(dropCount, realCount)
  686. end
  687. --每日限制
  688. local dayLimit = ConfigDataManager.getTableValue("cfg_item", "droplimitday", "id", itemCfgId)
  689. if not string.isNullOrEmpty(dayLimit) and tonumber(dayLimit) and realCount > 0 then
  690. local dayRecord = globalItemDrop[ItemLimitType.DAY]
  691. local dropCount = this.CanDropCount(itemCfgId, itemCount, dayRecord, tonumber(dayLimit))
  692. realCount = math.min(dropCount, realCount)
  693. end
  694. return realCount
  695. end
  696. ---获取可掉落数量
  697. function this.CanDropCount(itemCfgId, itemCount, record, dropLimit)
  698. if table.isNullOrEmpty(record) or table.isNullOrEmpty(record.item_record) then
  699. return math.min(dropLimit, itemCount)
  700. end
  701. local recordCount = 0
  702. if record.item_record[itemCfgId] ~= nil then
  703. recordCount = record.item_record[itemCfgId]
  704. end
  705. local canDrop = dropLimit - recordCount
  706. return math.min(canDrop, itemCount)
  707. end
  708. ---检查掉落记录重置
  709. function this.CheckDropItemReset(globalItemDrop)
  710. if table.isNullOrEmpty(globalItemDrop) then
  711. return
  712. end
  713. local nowTime = tonumber((getbaseinfo("nowsec")))
  714. for limitType, typeRecord in pairs(globalItemDrop) do
  715. local resetTime = typeRecord.reset_time
  716. local flush = this.TryResetItemRecord(resetTime, nowTime, limitType)
  717. if flush then
  718. typeRecord.item_record = {}
  719. typeRecord.reset_time = nowTime
  720. end
  721. end
  722. end
  723. ---重置掉落记录
  724. function this.TryResetItemRecord(resetTime, nowSec, limitType)
  725. --每天重置
  726. if limitType == ItemLimitType.DAY then
  727. if not TimeUtil.isSameDay(nowSec, resetTime) then
  728. return true
  729. end
  730. end
  731. --小时重置
  732. if limitType == ItemLimitType.HOUR then
  733. if not TimeUtil.isSameHour4Sec(nowSec, resetTime) then
  734. return true
  735. end
  736. end
  737. return false
  738. end
  739. ---记录怪物组
  740. function this.RecordDecayGroupCount(actor, monsterCfgId)
  741. local mDecayGroup = ConfigDataManager.getTableValue("cfg_monster", "mdecaygroup", "id", monsterCfgId)
  742. if string.isNullOrEmpty(mDecayGroup) or tonumber(mDecayGroup) == 0 then
  743. return
  744. end
  745. local decayGroup = tonumber(mDecayGroup)
  746. local decayRecord = this.GetDecayGroupRecord(actor)
  747. local oldCount = decayRecord[decayGroup]
  748. if oldCount == nil then
  749. oldCount = 0
  750. end
  751. decayRecord[decayGroup] = oldCount + 1
  752. this.SaveDecayGroupRecord(actor, decayRecord)
  753. --jprint("保存怪物组衰减次数",decayRecord)
  754. end
  755. ---获取衰减配置
  756. function this.GetDecayCfg(actor, monsterCfgId)
  757. local mDecayGroup = ConfigDataManager.getTableValue("cfg_monster", "mdecaygroup", "id", monsterCfgId)
  758. if string.isNullOrEmpty(mDecayGroup) or tonumber(mDecayGroup) == 0 then
  759. return nil
  760. end
  761. local decayGroup = tonumber(mDecayGroup)
  762. local decayRecord = this.GetDecayGroupRecord(actor)
  763. local nowTime = tonumber((getbaseinfo("nowsec")))
  764. local resetTime = this.GetDecayGroupRestTime(actor)
  765. local sameDay = true
  766. if resetTime > 0 then
  767. sameDay = TimeUtil.isSameDayWithNum(nowTime, resetTime, 5)
  768. else
  769. sameDay = false
  770. end
  771. if not sameDay then
  772. --重置衰减记录
  773. decayRecord = {}
  774. this.SaveDecayGroupRestTime(actor, nowTime)
  775. this.SaveDecayGroupRecord(actor, decayRecord)
  776. --jprint("衰减记录重置",decayRecord)
  777. end
  778. local oldCount = decayRecord[decayGroup]
  779. if oldCount == nil then
  780. oldCount = 0
  781. end
  782. local itemDecay = {}
  783. local groupDecay = {}
  784. this.GetDecayGroup(decayGroup, oldCount + 1, itemDecay, groupDecay)
  785. return itemDecay, groupDecay
  786. end
  787. function this.GetDecayGroup(decayGroup, recordCount, itemDecay, groupDecay)
  788. local allCfgList = ConfigDataManager.getTable("cfg_boss_numdecay", "mdecaygroup", decayGroup)
  789. if table.isNullOrEmpty(allCfgList) then
  790. return nil
  791. end
  792. for _, decayCfg in pairs(allCfgList) do
  793. this.GetDecayCfgParam(decayCfg, recordCount, itemDecay, groupDecay)
  794. end
  795. end
  796. function this.GetDecayCfgParam(decayCfg, recordCount, itemDecay, groupDecay)
  797. local limitArray = string.split(decayCfg["monstersection"], "#")
  798. local minLimit = tonumber(limitArray[1])
  799. local maxLimit = tonumber(limitArray[2])
  800. if recordCount < minLimit or recordCount > maxLimit then
  801. return nil
  802. end
  803. local decayRate = tonumber(decayCfg["dropdecayrate"]) / 10000
  804. if not string.isNullOrEmpty(decayCfg["item"]) then
  805. local itemCfgId = tonumber(decayCfg["item"])
  806. itemDecay[itemCfgId] = decayRate
  807. end
  808. if not string.isNullOrEmpty(decayCfg["itemgroup"]) then
  809. local itemGroup = decayCfg["itemgroup"]
  810. groupDecay[itemGroup] = decayRate
  811. end
  812. end
  813. ---获取怪物经验衰减倍率
  814. function MonsterScript.GetExpDecayRate(actor, monsterCfgId)
  815. local decaySign = ConfigDataManager.getTableValue("cfg_monster", "decaysign", "id", monsterCfgId)
  816. if string.isNullOrEmpty(decaySign) or tonumber(decaySign) == 0 then
  817. return 1
  818. end
  819. local allDecayCfg = ConfigDataManager.getTable("cfg_boss_dropdecay", "decaysign", decaySign)
  820. if table.isNullOrEmpty(allDecayCfg) then
  821. return 1
  822. end
  823. local monsterLv = tonumber(ConfigDataManager.getTableValue("cfg_monster", "level", "id", monsterCfgId))
  824. local roleLv = tonumber(getbaseinfo(actor, "level"))
  825. for _, decayCfg in pairs(allDecayCfg) do
  826. local rate = this.GetExpDecayCfg(roleLv, monsterLv, decayCfg)
  827. if rate ~= nil then
  828. return rate
  829. end
  830. end
  831. return 1
  832. end
  833. function this.GetExpDecayCfg(roleLv, monsterLv, decayCfg)
  834. local roleSection = string.split(decayCfg["rolesection"], "#")
  835. local roleLvMin = tonumber(roleSection[1])
  836. local roleLvMax = tonumber(roleSection[2])
  837. if roleLv < roleLvMin or roleLv > roleLvMax then
  838. return nil
  839. end
  840. local monsterSection = string.split(decayCfg["monstersection"], "#")
  841. local monsterLvMin = tonumber(monsterSection[1])
  842. local monsterLvMax = tonumber(monsterSection[2])
  843. if monsterLv < monsterLvMin or monsterLv > monsterLvMax then
  844. return nil
  845. end
  846. return tonumber(decayCfg["dropdecayrate"]) / 10000
  847. end
  848. ---gm掉落测试
  849. ------@param actor table 玩家对象
  850. -----@param monsterCfgId number 怪物配置id
  851. -----@param killNum number 击杀数量
  852. -----@param isSum boolean 掉落是否汇总
  853. function gmmonsterdroptest(actor, isSum, monster, count)
  854. if monster == nil or tonumber(monster) < 1 then
  855. return
  856. end
  857. if count == nil or tonumber(count) < 1 then
  858. return
  859. end
  860. local monsterCfgId = tonumber(monster)
  861. local killNum = tonumber(count)
  862. local dropResult = {}
  863. for i = 1, killNum do
  864. local dropRet = this.GmDropTest(actor, monsterCfgId)
  865. if dropRet ~= nil then
  866. for itemCfgId, itemCount in pairs(dropRet) do
  867. this.MergeItemRecord(itemCfgId, itemCount, dropResult)
  868. end
  869. end
  870. end
  871. if table.isNullOrEmpty(dropResult) then
  872. tipinfo(actor, "未掉落道具")
  873. return
  874. end
  875. local monsterName = ConfigDataManager.getTableValue("cfg_monster", "name", "id", monsterCfgId)
  876. local title = "掉落测试:击杀" .. killNum .. "只" .. monsterName
  877. local content = this.GetDropStringContent(dropResult, isSum)
  878. sendmail(actor, title, content, nil)
  879. end
  880. function this.GetDropStringContent(dropResult, isSum)
  881. if table.isNullOrEmpty(dropResult) then
  882. return "未掉落道具"
  883. end
  884. local resultStr = {}
  885. for itemCfgId, itemCount in pairs(dropResult) do
  886. local itemName = ConfigDataManager.getTableValue("cfg_item", "name", "id", itemCfgId)
  887. local itemStr = itemName .. ":" .. itemCount
  888. if itemStr then
  889. table.insert(resultStr, itemStr)
  890. end
  891. end
  892. return table.concat(resultStr, " |")
  893. end
  894. function this.GmDropTest(actor, monsterCfgId)
  895. local itemDecay, itemGroupDecay = this.GetDecayCfg(actor, monsterCfgId)
  896. --jprint("获取掉落衰减配置:", itemDecay,itemGroupDecay)
  897. local dropRecord = this.GetMonsterDropRecord(actor)
  898. local allDropCfg = this.GetAllDropCfg(actor, monsterCfgId, dropRecord, itemGroupDecay)
  899. if table.isNullOrEmpty(allDropCfg) then
  900. return nil
  901. end
  902. --掉落道具结果
  903. local dropResult = {}
  904. --全服道具掉落记录
  905. local globalItemDrop = this.GetGlobalItemDrop()
  906. --先检查重置记录
  907. this.CheckDropItemReset(globalItemDrop)
  908. --计算掉落结果
  909. this.GetDropResult(nil, actor, nil, allDropCfg, globalItemDrop, dropRecord, dropResult, itemDecay, true)
  910. --保存掉落记录
  911. this.SaveMonsterDropRecord(actor, dropRecord)
  912. --更新衰减组记录
  913. this.RecordDecayGroupCount(actor, monsterCfgId)
  914. --jprint("怪物掉落记录:", dropRecord)
  915. if table.isNullOrEmpty(dropResult) then
  916. return nil
  917. end
  918. --保存道具记录
  919. this.SaveGlobalItemDrop(globalItemDrop)
  920. --jprint("全服道具限制记录:", globalItemDrop)
  921. --jprint("掉落结果:", dropResult)
  922. return dropResult
  923. end
  924. --被攻击时触发
  925. function MonsterScript.OnUnderAttack(targetActor, fightParam)
  926. --this.OnUnderAttack(targetActor,fightParam)
  927. this.UpdateMonsterAttackInfo(targetActor, fightParam)
  928. end
  929. function this.OnUnderAttack(actor, fightParam)
  930. local type = getbaseinfo(actor, "mapobjecttype")
  931. if type ~= MapObjectType.MONSTER and type ~= MapObjectType.PET then
  932. return
  933. end
  934. --local monInfo = getmonsterinfo(actor)
  935. --local monsterId = monInfo["cfgid"]
  936. monsterId = fightParam["targetcfgid"]
  937. local aiId = ConfigDataManager.getTableValue("cfg_monster", "ai", "id", monsterId)
  938. local beattackTime = ConfigDataManager.getTableValue("cfg_monster_ai", "beattacktime", "id", aiId)
  939. jprint("怪物被攻击时设置休眠时间", monsterId, aiId, beattackTime)
  940. setsleeptime(actor, beattackTime)
  941. end
  942. ---更新怪物受击信息
  943. function this.UpdateMonsterAttackInfo(targetActor, fightParam)
  944. local targetType = tonumber(fightParam["targettype"])
  945. if targetType ~= MapObjectType.MONSTER then
  946. return
  947. end
  948. local playerActor = nil
  949. local casterType = tonumber(fightParam["castertype"])
  950. if casterType == MapObjectType.PLAYER then
  951. playerActor = fightParam["caster"]
  952. end
  953. if casterType == MapObjectType.PET or casterType == MapObjectType.PARTNER then
  954. local masterId = tonumber(fightParam["masterid"])
  955. if masterId == nil or masterId == 0 then
  956. return
  957. end
  958. local mapId = tonumber(fightParam["mapid"])
  959. playerActor = getactor(masterId, mapId)
  960. end
  961. if playerActor == nil then
  962. return
  963. end
  964. local maxHurtRid = this.UpdateHurtList(targetActor, playerActor, fightParam)
  965. this.TryUpdateMonsterFirstAttackInfo(targetActor, playerActor, fightParam, maxHurtRid)
  966. end
  967. ---尝试更新怪物首刀归属
  968. function this.TryUpdateMonsterFirstAttackInfo(monsterActor, playerActor, fightParam, maxHurtRid)
  969. local rid = tonumber(getbaseinfo(playerActor, "rid"))
  970. local nowTime = tonumber((getbaseinfo("nowsec")))
  971. local firstAttackInfo = this.GetMonsterFirstAttack(monsterActor)
  972. local timeLimit = this.GetMonsterFirstAttackTimeLimit()
  973. local updateFirstAttack = true
  974. local oldMaxHurt = nil
  975. if not table.isNullOrEmpty(firstAttackInfo) then
  976. local attackTime = tonumber(firstAttackInfo["attack_time"])
  977. local roleId = tonumber(firstAttackInfo["rid"])
  978. oldMaxHurt = tonumber(firstAttackInfo["max_hurt"])
  979. if rid ~= roleId and attackTime + timeLimit > nowTime then
  980. updateFirstAttack = false
  981. end
  982. end
  983. --更新首刀记录
  984. if updateFirstAttack then
  985. firstAttackInfo["rid"] = rid
  986. firstAttackInfo["attack_time"] = nowTime
  987. end
  988. --更新最大伤害玩家
  989. local maxHurtChange = false
  990. if maxHurtRid > 0 and maxHurtRid ~= oldMaxHurt then
  991. firstAttackInfo["max_hurt"] = maxHurtRid
  992. maxHurtChange = true
  993. end
  994. --jprint("更新怪物首刀归属", targetActor,rid)
  995. local monsterCfgId = tonumber(fightParam["targetcfgid"])
  996. local send = this.NeedSendOwnerMsg(monsterCfgId)
  997. local isMaxHurt = this.IsMaxHurtTarget(monsterCfgId)
  998. if send then
  999. local msgTime = tonumber(firstAttackInfo["msg_time"])
  1000. if maxHurtChange or msgTime == nil or nowTime - msgTime >= timeLimit then
  1001. --发送首刀归属信息
  1002. local endTime = nowTime + timeLimit
  1003. local maxHurtId = 0
  1004. if isMaxHurt == true then
  1005. maxHurtId = maxHurtRid
  1006. rid = 0
  1007. end
  1008. local ownerInfo = {
  1009. target = monsterActor,
  1010. owner = rid,
  1011. endTime = endTime,
  1012. maxHurt = maxHurtId
  1013. }
  1014. this.SendFirstAttackOwnerMsg(nil, monsterActor, ownerInfo)
  1015. --保存发送时间
  1016. firstAttackInfo["msg_time"] = nowTime
  1017. end
  1018. end
  1019. --保存首刀归属记录
  1020. this.SaveMonsterFirstAttack(monsterActor, firstAttackInfo)
  1021. end
  1022. ---怪物进入视野
  1023. function MonsterScript.MonsterEnterView(actor, monsterActor, monsterCfgId)
  1024. local send = this.NeedSendOwnerMsg(monsterCfgId)
  1025. if not send then
  1026. return
  1027. end
  1028. this.SendFirstAttackOwnerMsg(actor, monsterActor)
  1029. end
  1030. ---是否通知客户端归属信息
  1031. function this.NeedSendOwnerMsg(monsterCfgId)
  1032. local monsterType = tonumber(ConfigDataManager.getTableValue("cfg_monster", "type", "id", monsterCfgId))
  1033. if monsterType == nil or monsterType == MonsterType.NORMAL then
  1034. return false
  1035. end
  1036. return true
  1037. end
  1038. ---发送首刀归属信息
  1039. function this.SendFirstAttackOwnerMsg(actor, targetActor, ownerInfo)
  1040. --只发生boss归属
  1041. if ownerInfo == nil then
  1042. ownerInfo = this.GetFirstAttackOwner(targetActor)
  1043. end
  1044. --jprint("发送首刀归属信息", ownerInfo)
  1045. if actor == nil then
  1046. sendrefluamsg(targetActor, LuaMessageIdToClient.RES_MONSTER_FIRST_ATTACK_OWNER_CHANGE, ownerInfo)
  1047. else
  1048. sendluamsg(actor, LuaMessageIdToClient.RES_MONSTER_FIRST_ATTACK_OWNER_CHANGE, ownerInfo)
  1049. end
  1050. end
  1051. ---获取首刀归属信息
  1052. function this.GetFirstAttackOwner(targetActor)
  1053. local firstAttackInfo = this.GetMonsterFirstAttack(targetActor)
  1054. local rid = 0
  1055. local endTime = 0
  1056. if not table.isNullOrEmpty(firstAttackInfo) then
  1057. rid = tonumber(firstAttackInfo["rid"])
  1058. endTime = tonumber(firstAttackInfo["attack_time"])
  1059. end
  1060. if endTime > 0 then
  1061. local timeLimit = this.GetMonsterFirstAttackTimeLimit()
  1062. endTime = endTime + timeLimit
  1063. end
  1064. local maxHurtRid = 0
  1065. local monsterInfo = getmonsterinfo(targetActor)
  1066. if not table.isNullOrEmpty(monsterInfo) then
  1067. local monsterCfgId = monsterInfo["cfgid"]
  1068. local isMaxHurt = this.IsMaxHurtTarget(monsterCfgId)
  1069. if isMaxHurt == true then
  1070. maxHurtRid = this.GetMaxHurtPlayer(targetActor, nil)
  1071. rid = 0
  1072. end
  1073. end
  1074. local ownerInfo = {
  1075. target = targetActor,
  1076. owner = rid,
  1077. endTime = endTime,
  1078. maxHurt = maxHurtRid
  1079. }
  1080. return ownerInfo
  1081. end
  1082. ---更新伤害列表
  1083. function this.UpdateHurtList(monsterActor, playerActor, fightParam)
  1084. local targetHurt = tonumber(fightParam["targethurt"])
  1085. if targetHurt == nil or targetHurt < 0 then
  1086. return 0
  1087. end
  1088. local hurtList = MonsterScript.GetHurtList(monsterActor)
  1089. local rid = tonumber(getbaseinfo(playerActor, "rid"))
  1090. local oldHurt = 0
  1091. if not table.isNullOrEmpty(hurtList) then
  1092. if hurtList[rid] ~= nil then
  1093. oldHurt = hurtList[rid]
  1094. end
  1095. end
  1096. hurtList[rid] = targetHurt + oldHurt
  1097. this.SaveMonsterHurtList(monsterActor, hurtList)
  1098. return this.GetMaxHurtPlayer(monsterActor, hurtList)
  1099. end
  1100. ---获取最大伤害玩家
  1101. ---@param hurtList table 伤害列表
  1102. function this.GetMaxHurtPlayer(monsterActor, hurtList)
  1103. if table.isNullOrEmpty(hurtList) then
  1104. hurtList = MonsterScript.GetHurtList(monsterActor)
  1105. end
  1106. if table.isNullOrEmpty(hurtList) then
  1107. return 0
  1108. end
  1109. local maxHurt = 0
  1110. local maxRid = 0
  1111. for rid, hurt in pairs(hurtList) do
  1112. if hurt > maxHurt then
  1113. maxHurt = hurt
  1114. maxRid = rid
  1115. end
  1116. end
  1117. return maxRid
  1118. end
  1119. function MonsterScript.GetHurtList(monsterActor)
  1120. local hurtList = this.GetMonsterHurtList(monsterActor)
  1121. if table.isNullOrEmpty(hurtList) then
  1122. return hurtList
  1123. end
  1124. local mapId = getbaseinfo(monsterActor, "unimapid")
  1125. local removeList = {}
  1126. for rid, hurt in pairs(hurtList) do
  1127. local isRemove = this.needRemoveHurt(rid, mapId)
  1128. if isRemove == true then
  1129. table.insert(removeList, rid)
  1130. end
  1131. end
  1132. if not table.isNullOrEmpty(removeList) then
  1133. for _, rid in pairs(removeList) do
  1134. hurtList[rid] = nil
  1135. end
  1136. this.SaveMonsterHurtList(monsterActor, hurtList)
  1137. end
  1138. return hurtList
  1139. end
  1140. ---是否需要移除伤害
  1141. function this.needRemoveHurt(rid, monsterMapId)
  1142. local playerActor = getactor(rid)
  1143. if playerActor == nil then
  1144. return true
  1145. end
  1146. local mapId = getbaseinfo(playerActor, "unimapid") or getplayermaininfo(playerActor)["mapid"]
  1147. if mapId == nil or mapId ~= monsterMapId then
  1148. return true
  1149. end
  1150. playerActor = getactor(rid, mapId)
  1151. local dead = isdead(playerActor)
  1152. if dead == nil or dead == true then
  1153. return true
  1154. end
  1155. return false
  1156. end
  1157. ---移除伤害列表玩家
  1158. function MonsterScript.RemoveHurtListRid(monsterActor, rid)
  1159. if monsterActor == nil or rid == nil then
  1160. return
  1161. end
  1162. local hurtList = this.GetMonsterHurtList(monsterActor)
  1163. if table.isNullOrEmpty(hurtList) then
  1164. return
  1165. end
  1166. hurtList[rid] = nil
  1167. this.SaveMonsterHurtList(monsterActor, hurtList)
  1168. this.SendFirstAttackOwnerMsg(nil, monsterActor)
  1169. end
  1170. ---仇恨目标是否为最大伤害
  1171. function this.IsMaxHurtTarget(monsterCfgId)
  1172. local threatType = tonumber(ConfigDataManager.getTableValue("cfg_monster_ai", "hate", "id", monsterCfgId))
  1173. if threatType == nil then
  1174. return false
  1175. end
  1176. if threatType == ThreatType.MAX_HURT then
  1177. return true
  1178. end
  1179. return false
  1180. end