Monster.lua 42 KB

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