Monster_1.lua 46 KB

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