Monster.lua 49 KB

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