BattleUtil.lua 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. BattleUtil = {}
  2. --local BattleUtil = BattleUtil
  3. local floor = math.floor
  4. local max = math.max
  5. local min = math.min
  6. --local Random = Random
  7. --local RoleDataName = RoleDataName
  8. --local BattleEventName = BattleEventName
  9. BattleUtil.Passivity = require("Modules/Battle/Logic/Base/Passivity")
  10. local function clamp(v, minValue, maxValue)
  11. if v < minValue then
  12. return minValue
  13. end
  14. if v > maxValue then
  15. return maxValue
  16. end
  17. return v
  18. end
  19. function BattleUtil.ErrorCorrection(f) --进行精度处理,避免前后端计算不一致
  20. return floor(f * 100000 + 0.5) / 100000
  21. end
  22. function BattleUtil.FP_Mul(...)
  23. local f = 1
  24. for i, v in ipairs{...} do
  25. f = floor(f * v * 100000 + 0.5) / 100000
  26. end
  27. return f
  28. end
  29. -- 选择前排
  30. function BattleUtil.ChooseFRow(arr)
  31. local tempArr = {}
  32. for _, r in ipairs(arr) do
  33. if r.position <= 3 and not r:IsRealDead() then
  34. table.insert(tempArr, r)
  35. end
  36. end
  37. table.sort(tempArr, function(a, b)
  38. return a.position < b.position
  39. end)
  40. return tempArr
  41. end
  42. -- 选择后排
  43. function BattleUtil.ChooseBRow(arr)
  44. local tempArr = {}
  45. for _, r in ipairs(arr) do
  46. if r.position > 6 and not r:IsRealDead() then
  47. table.insert(tempArr, r)
  48. end
  49. end
  50. table.sort(tempArr, function(a, b)
  51. return a.position < b.position
  52. end)
  53. return tempArr
  54. end
  55. --> 选择前两排
  56. function BattleUtil.ChooseF2Row(arr)
  57. local tempArr = {}
  58. for _, r in ipairs(arr) do
  59. if r.position <= 6 and not r:IsRealDead() then
  60. table.insert(tempArr, r)
  61. end
  62. end
  63. table.sort(tempArr, function(a, b)
  64. return a.position < b.position
  65. end)
  66. return tempArr
  67. end
  68. --> 选择后两排
  69. function BattleUtil.ChooseB2Row(arr)
  70. local tempArr = {}
  71. for _, r in ipairs(arr) do
  72. if r.position > 3 and not r:IsRealDead() then
  73. table.insert(tempArr, r)
  74. end
  75. end
  76. table.sort(tempArr, function(a, b)
  77. return a.position < b.position
  78. end)
  79. return tempArr
  80. end
  81. -- 选择一列(col == 0 表示第三列哦)
  82. function BattleUtil.ChooseCol(arr, col)
  83. local tempArr = {}
  84. for _, role in ipairs(arr) do
  85. if role.position % 3 == col then
  86. table.insert(tempArr, role)
  87. end
  88. end
  89. table.sort(tempArr, function(a, b)
  90. return a.position < b.position
  91. end)
  92. return tempArr
  93. end
  94. --> 数量最多列
  95. function BattleUtil.GetMaxCol(arr)
  96. local tempArr = {0, 0, 0}
  97. for _, role in ipairs(arr) do
  98. local idx = role.position % 3 + 1
  99. tempArr[idx] = tempArr[idx] + 1
  100. end
  101. local maxV = -1
  102. local maxIdx = 1
  103. for k, v in ipairs(tempArr) do
  104. if v > maxV then
  105. maxV = v
  106. maxIdx = k
  107. end
  108. end
  109. return maxIdx - 1
  110. end
  111. -- 根据属性排序
  112. function BattleUtil.SortByProp(arr, prop, sort)
  113. BattleUtil.Sort(arr, function(a, b)
  114. local r1 = a:GetRoleData(prop)
  115. local r2 = b:GetRoleData(prop)
  116. if sort == 1 then return r1 > r2 else return r1 < r2 end
  117. end)
  118. return arr
  119. end
  120. -- 按血量排序
  121. function BattleUtil.SortByHpFactor(arr, sort)
  122. BattleUtil.Sort(arr, function(a, b)
  123. local r1 = a:GetRoleData(RoleDataName.Hp) / a:GetRoleData(RoleDataName.MaxHp)
  124. local r2 = b:GetRoleData(RoleDataName.Hp) / b:GetRoleData(RoleDataName.MaxHp)
  125. if sort == 1 then return r1 > r2 else return r1 < r2 end
  126. end)
  127. return arr
  128. end
  129. -- 获取技能最大目标数
  130. function BattleUtil.GetMaxTargetNum(chooseId)
  131. local chooseType = floor(chooseId / 100000) % 10
  132. local chooseLimit = floor(chooseId / 10000) % 10
  133. local chooseWeight = floor(chooseId / 100) % 100
  134. local sort = floor(chooseId / 10) % 10
  135. local num = chooseId % 10
  136. --
  137. if chooseType == 3 or chooseType == 4 then
  138. return 1
  139. else
  140. if num == 0 then
  141. if chooseLimit == 0 then
  142. if chooseWeight == 7 then
  143. return 4
  144. elseif chooseLimit == 8 then
  145. return 1
  146. else
  147. return 6
  148. end
  149. elseif chooseLimit == 1 or chooseLimit == 2 then
  150. return 3
  151. elseif chooseLimit == 3 then
  152. return 2
  153. end
  154. else
  155. return num
  156. end
  157. end
  158. end
  159. --
  160. function BattleUtil.ChooseTarget(role, chooseId)
  161. WYLog("chooseId")
  162. WYLog(chooseId)
  163. local chooseType = floor(chooseId / 100000) % 10
  164. local chooseLimit = floor(chooseId / 10000) % 10
  165. local chooseWeight = floor(chooseId / 100) % 100
  166. local sort = floor(chooseId / 10) % 10
  167. local num = chooseId % 10
  168. local arr
  169. -- 选择类型
  170. if chooseType == 1 then
  171. arr = RoleManager.Query(function (r) return r.camp == role.camp end)
  172. elseif chooseType == 2 then
  173. if role.lockTarget and not role.lockTarget:IsRealDead() and num == 1 then --嘲讽时对单个敌军生效
  174. return {role.lockTarget}
  175. end
  176. arr = RoleManager.Query(function (r) return r.camp ~= role.camp end)
  177. elseif chooseType == 3 then
  178. if role.ctrl_blind then --致盲时自身变随机友军
  179. arr = RoleManager.Query(function (r) return r.camp == role.camp end)
  180. BattleUtil.RandomList(arr)
  181. return {arr[1]}
  182. end
  183. return {role}
  184. elseif chooseType == 4 then
  185. if role.lockTarget and not role.lockTarget:IsRealDead() then --嘲讽时对仇恨目标生效
  186. return {role.lockTarget}
  187. end
  188. if role.ctrl_blind then --致盲时仇恨目标变随机
  189. arr = RoleManager.Query(function (r) return r.camp ~= role.camp end)
  190. BattleUtil.RandomList(arr)
  191. return {arr[1]}
  192. end
  193. return {RoleManager.GetAggro(role)}
  194. elseif chooseType == 5 then --< 我方阵亡
  195. arr = RoleManager.QueryDead(function (r) return r.camp == role.camp end)
  196. else
  197. arr = RoleManager.Query()
  198. end
  199. --选择范围
  200. if chooseLimit == 0 then --选择全体不做任何操作
  201. elseif chooseLimit == 1 then-- 前排
  202. local tempArr = BattleUtil.ChooseFRow(arr)
  203. if #tempArr == 0 then -- 没有选择后排
  204. tempArr = BattleUtil.ChooseBRow(arr)
  205. end
  206. arr = tempArr
  207. elseif chooseLimit == 2 then-- 后排
  208. local tempArr = BattleUtil.ChooseBRow(arr)
  209. if #tempArr == 0 then -- 没有选择前排
  210. tempArr = BattleUtil.ChooseFRow(arr)
  211. end
  212. arr = tempArr
  213. elseif chooseLimit == 3 then-- 对列
  214. local myCol = role.position % 3
  215. local tempArr = BattleUtil.ChooseCol(arr, myCol)
  216. if #tempArr == 0 then -- 对列没有人,按顺序找到有人得列
  217. for i = 1, 3 do
  218. local col = i % 3 -- 0 表示第三列嗷
  219. tempArr = BattleUtil.ChooseCol(arr, col)
  220. if #tempArr ~= 0 then
  221. break
  222. end
  223. end
  224. end
  225. arr = tempArr
  226. elseif chooseLimit == 4 then --< 前二
  227. local tempArr = BattleUtil.ChooseF2Row(arr)
  228. if #tempArr == 0 then -- 没有选择最后一排
  229. tempArr = BattleUtil.ChooseBRow(arr)
  230. end
  231. arr = tempArr
  232. elseif chooseLimit == 5 then --< 后二
  233. local tempArr = BattleUtil.ChooseB2Row(arr)
  234. if #tempArr == 0 then -- 没有选择第一排
  235. tempArr = BattleUtil.ChooseFRow(arr)
  236. end
  237. arr = tempArr
  238. elseif chooseLimit == 6 then --< 全体,优先4职业
  239. elseif chooseLimit == 7 then --< 人数最多列
  240. local tempArr = BattleUtil.ChooseCol(arr, BattleUtil.GetMaxCol(arr))
  241. arr = tempArr
  242. elseif chooseLimit == 8 then --< 除自己外
  243. elseif chooseLimit == 9 then --< 9全体,优先2职业
  244. end
  245. if chooseWeight == 9 then --< 随机某属性 定死或走表
  246. chooseWeight = Random.RangeInt(1, 6)
  247. end
  248. -- 选择条件
  249. if chooseWeight == 0 or role.ctrl_blind then --致盲时排序无效
  250. BattleUtil.RandomList(arr)
  251. elseif chooseWeight == 1 then -- 生命值
  252. BattleUtil.SortByProp(arr, RoleDataName.Hp, sort)
  253. elseif chooseWeight == 2 then -- 血量百分比
  254. BattleUtil.SortByHpFactor(arr, sort)
  255. elseif chooseWeight == 3 then -- 攻击力
  256. BattleUtil.SortByProp(arr, RoleDataName.Attack, sort)
  257. elseif chooseWeight == 4 then -- 防御
  258. BattleUtil.SortByProp(arr, RoleDataName.PhysicalDefence, sort)
  259. elseif chooseWeight == 5 then -- 护甲
  260. BattleUtil.SortByProp(arr, RoleDataName.PhysicalDefence, sort)
  261. elseif chooseWeight == 6 then -- 魔抗
  262. BattleUtil.SortByProp(arr, RoleDataName.MagicDefence, sort)
  263. elseif chooseWeight == 7 then -- 对位及其相邻目标
  264. arr = RoleManager.GetNeighbor(role, chooseType)
  265. elseif chooseWeight == 8 then -- 对位
  266. arr = RoleManager.GetArrAggroList(role, arr)
  267. end
  268. if chooseLimit == 6 then --< 全体,优先4职业
  269. local tempArr = {}
  270. for i = 1, #arr do
  271. if arr[i].roleData.professionId == 4 then
  272. table.insert(tempArr, arr[i])
  273. end
  274. end
  275. for i = 1, #arr do
  276. if arr[i].roleData.professionId ~= 4 then
  277. table.insert(tempArr, arr[i])
  278. end
  279. end
  280. arr = tempArr
  281. elseif chooseLimit == 8 then --< 除自己
  282. local tempArr = {}
  283. for _, r in ipairs(arr) do
  284. if not r == role then
  285. table.insert(tempArr, r)
  286. end
  287. end
  288. table.sort(tempArr, function(a, b)
  289. return a.position < b.position
  290. end)
  291. arr = tempArr
  292. elseif chooseLimit == 9 then --< 全体,优先2职业
  293. local tempArr = {}
  294. for i = 1, #arr do
  295. if arr[i].roleData.professionId == 2 then
  296. table.insert(tempArr, arr[i])
  297. end
  298. end
  299. for i = 1, #arr do
  300. if arr[i].roleData.professionId ~= 2 then
  301. table.insert(tempArr, arr[i])
  302. end
  303. end
  304. arr = tempArr
  305. end
  306. local finalArr = {}
  307. if sort == 3 then --< 3随机(可重复,单体最多被选3次)
  308. local randArr = {}
  309. local randtimes = num == 0 and #arr or num
  310. local randTimesArr = {}
  311. for i = 1, #arr do
  312. table.insert(randTimesArr, 0)
  313. end
  314. while #randArr < randtimes
  315. do
  316. while true
  317. do
  318. local randIdx = Random.RangeInt(1, #arr)
  319. if randTimesArr[randIdx] >= 3 then
  320. break
  321. end
  322. randTimesArr[randIdx] = randTimesArr[randIdx] + 1
  323. table.insert(randArr, arr[randIdx])
  324. end
  325. end
  326. finalArr = randArr
  327. else
  328. --> 不随机按顺序
  329. if num == 0 then
  330. finalArr = arr
  331. else
  332. for i = 1, num do
  333. if arr[i] then
  334. table.insert(finalArr, arr[i])
  335. end
  336. end
  337. end
  338. end
  339. -- table.sort(finalArr, function(a, b)
  340. -- return a.position < b.position
  341. -- end)
  342. return finalArr
  343. end
  344. function BattleUtil.CreateBuffId(skill, index)
  345. local id = 0
  346. if skill.preAI then --主动技能生成buff
  347. id = skill.owner.uid * 10000 + index
  348. else --被动技能生成buff
  349. id = skill.owner.uid * 1000 + index
  350. end
  351. return id
  352. end
  353. -- 计算命中率
  354. function BattleUtil.CalHit(atkRole, defRole)
  355. --命中率 = clamp(自身命中率-敌方闪避率,0,1)
  356. local hit = atkRole:GetRoleData(RoleDataName.Hit)
  357. local dodge = defRole:GetRoleData(RoleDataName.Dodge)
  358. local bHit = Random.Range01() <= clamp(hit - dodge, 0, 1)
  359. if bHit then
  360. else
  361. atkRole.Event:DispatchEvent(BattleEventName.RoleDodge)
  362. defRole.Event:DispatchEvent(BattleEventName.RoleBeDodge)
  363. end
  364. return bHit
  365. end
  366. -- 计算护盾
  367. function BattleUtil.CalShield(atkRole, defRole, damage)
  368. for i=1, defRole.shield.size do
  369. local buff = defRole.shield.buffer[i]
  370. damage = buff:CountShield(damage, atkRole)
  371. end
  372. return damage
  373. end
  374. -- 提前计算护盾后伤害
  375. function BattleUtil.PreCountShield(defRole, damage)
  376. for i=1, defRole.shield.size do
  377. local buff = defRole.shield.buffer[i]
  378. damage = buff:PreCountShield(damage)
  379. end
  380. return damage
  381. end
  382. -- 秒杀
  383. function BattleUtil.Seckill(skill, atkRole, defRole)
  384. local damage = defRole:GetRoleData(RoleDataName.Hp)
  385. local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage)
  386. if finalDmg >= 0 then
  387. if defRole:GetRoleData(RoleDataName.Hp) <= 0 and not defRole:IsDead() then
  388. defRole:SetDead()
  389. defRole.Event:DispatchEvent(BattleEventName.RoleDead, atkRole)
  390. atkRole.Event:DispatchEvent(BattleEventName.RoleKill, defRole)
  391. BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole, atkRole)
  392. atkRole.Event:DispatchEvent(BattleEventName.Seckill, defRole)
  393. defRole.Event:DispatchEvent(BattleEventName.BeSeckill, atkRole)
  394. BattleLogic.Event:DispatchEvent(BattleEventName.Seckill, atkRole, defRole)
  395. end
  396. atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, false, finalDmg, 0, false, skill)
  397. defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, false, finalDmg, 0, false, skill)
  398. BattleLogic.Event:DispatchEvent(BattleEventName.RoleDamage, atkRole, defRole, damage, false, finalDmg, 0, false, skill)
  399. BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeDamaged, defRole, atkRole, damage, false, finalDmg, 0, false, skill)
  400. if skill then
  401. atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, nil, finalDmg, nil, skill)
  402. defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, nil, finalDmg, nil, skill)
  403. end
  404. end
  405. end
  406. -- 计算真实伤害
  407. function BattleUtil.ApplyDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType)
  408. LogGreen("BattleUtil.ApplyDamage")
  409. bCrit = bCrit or false
  410. damageType = damageType or 0
  411. -- if atkRole.isTeam then
  412. -- --max(技能基础伤害*(1+已方异妖伤害加成-目标异妖伤害减免),30%×技能基础伤害)
  413. -- local arr = RoleManager.Query(function (r) return r.camp == atkRole.camp end)
  414. -- local n = 0
  415. -- for i=1, #arr do
  416. -- n = n + arr[i]:GetRoleData(RoleDataName.TeamDamageBocusFactor)
  417. -- end
  418. -- damage = floor(max(damage * (1 + n / #arr - defRole:GetRoleData(RoleDataName.TeamDamageReduceFactor)), 0.3 * damage))
  419. -- end
  420. --加入被动效果
  421. local damagingFunc = function(dmgDeduction)
  422. damage = damage - dmgDeduction
  423. end
  424. atkRole.Event:DispatchEvent(BattleEventName.PassiveDamaging, damagingFunc, defRole, damage, skill, dotType, bCrit)
  425. defRole.Event:DispatchEvent(BattleEventName.PassiveBeDamaging, damagingFunc, atkRole, damage, skill, dotType, bCrit)
  426. BattleLogic.Event:DispatchEvent(BattleEventName.PassiveDamaging, damagingFunc, atkRole, defRole, damage, skill, dotType, bCrit)
  427. -- 计算护盾减伤
  428. damage = BattleUtil.CalShield(atkRole, defRole, damage)
  429. -- 造成的最终伤害
  430. local damagingFunc = function(dmgDeduction)
  431. damage = damage - dmgDeduction
  432. end
  433. atkRole.Event:DispatchEvent(BattleEventName.FinalDamage, damagingFunc, defRole, damage, skill, dotType, bCrit, damageType)
  434. defRole.Event:DispatchEvent(BattleEventName.FinalBeDamage, damagingFunc, atkRole, damage, skill, dotType, bCrit, damageType)
  435. BattleLogic.Event:DispatchEvent(BattleEventName.FinalDamage, damagingFunc, atkRole, defRole, damage, skill, dotType, bCrit, damageType)
  436. --
  437. return BattleUtil.FinalDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType)
  438. end
  439. --检测是否有是金翅大鹏有不灭效果
  440. function BattleUtil.CheckIsNoDead(target)
  441. if target then
  442. return target:IsAssignHeroAndHeroStar(10086,10)==false and BattleLogic.BuffMgr:HasBuff(target,BuffName.NoDead)==false
  443. end
  444. return false
  445. end
  446. function BattleUtil.FinalDamage(skill, atkRole, defRole, damage, bCrit, damageType, dotType)
  447. LogGreen("BattleUtil.FinalDamage")
  448. if damage < 0 then damage = 0 end
  449. local finalDmg = defRole.data:SubValue(RoleDataName.Hp, damage)
  450. if finalDmg >= 0 then
  451. if defRole:GetRoleData(RoleDataName.Hp) <= 0 and not defRole:IsDead() then
  452. defRole:SetDead()
  453. defRole.Event:DispatchEvent(BattleEventName.RoleDead, atkRole)
  454. atkRole.Event:DispatchEvent(BattleEventName.RoleKill, defRole, damage)
  455. BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoleDead, defRole, atkRole)
  456. end
  457. atkRole.Event:DispatchEvent(BattleEventName.RoleDamage, defRole, damage, bCrit, finalDmg, damageType, dotType, skill)
  458. defRole.Event:DispatchEvent(BattleEventName.RoleBeDamaged, atkRole, damage, bCrit, finalDmg, damageType, dotType, skill)
  459. BattleLogic.Event:DispatchEvent(BattleEventName.RoleDamage, atkRole, defRole, damage, bCrit, finalDmg, damageType, dotType, skill)
  460. BattleLogic.Event:DispatchEvent(BattleEventName.RoleBeDamaged, defRole, atkRole, damage, bCrit, finalDmg, damageType, dotType, skill)
  461. if bCrit then
  462. atkRole.Event:DispatchEvent(BattleEventName.RoleCrit, defRole, damage, bCrit, finalDmg, damageType, skill)
  463. defRole.Event:DispatchEvent(BattleEventName.RoleBeCrit, atkRole, damage, bCrit, finalDmg, damageType, skill)
  464. end
  465. if skill then
  466. atkRole.Event:DispatchEvent(BattleEventName.RoleHit, defRole, damage, bCrit, finalDmg, damageType, skill)
  467. defRole.Event:DispatchEvent(BattleEventName.RoleBeHit, atkRole, damage, bCrit, finalDmg, damageType, skill)
  468. end
  469. end
  470. --
  471. BattleLogManager.Log(
  472. "Final Damage",
  473. "acamp", atkRole.camp,
  474. "apos", atkRole.position,
  475. "tcamp", defRole.camp,
  476. "tpos", defRole.position,
  477. "damage", damage,
  478. "dotType", tostring(dotType)
  479. )
  480. return finalDmg
  481. end
  482. --执行完整的命中,伤害,暴击计算,返回命中,暴击
  483. --skill造成伤害的技能 atkRole攻击者 defRole受击者 damageType伤害类型 baseFactor伤害系数 ignoreDef无视防御参数 dotType是持续伤害类型
  484. function BattleUtil.CalDamage(skill, atkRole, defRole, damageType, baseFactor, ignoreDef, dotType)
  485. LogGreen("BattleUtil.CalDamage")
  486. -- 判断是否命中
  487. if skill and not skill:CheckTargetIsHit(defRole) then
  488. LogGreen("HitMiss")
  489. BattleLogic.Event:DispatchEvent(BattleEventName.HitMiss, atkRole, defRole, skill)
  490. atkRole.Event:DispatchEvent(BattleEventName.HitMiss, defRole, skill)
  491. defRole.Event:DispatchEvent(BattleEventName.BeHitMiss, atkRole, skill)
  492. return 0
  493. end
  494. -- 如果是队伍技能,计算真实伤害,则damageType为伤害值
  495. if atkRole.isTeam and not defRole:IsDead() then
  496. return BattleUtil.ApplyDamage(skill, atkRole, defRole, damageType), false
  497. end
  498. -- 计算技能额外伤害系数加成
  499. baseFactor = baseFactor or 1
  500. local factorFunc = function(exFactor) baseFactor = baseFactor + exFactor end
  501. atkRole.Event:DispatchEvent(BattleEventName.RoleDamageBefore, defRole, factorFunc, damageType, skill)
  502. defRole.Event:DispatchEvent(BattleEventName.RoleBeDamagedBefore, atkRole, factorFunc, damageType, skill)
  503. baseFactor = BattleUtil.ErrorCorrection(baseFactor)
  504. local baseDamage
  505. -- 防御(据伤害类型决定)
  506. local defence = 0
  507. if damageType == 1 then --1 物理 2 魔法
  508. defence = defRole:GetRoleData(RoleDataName.PhysicalDefence)
  509. else
  510. defence = defRole:GetRoleData(RoleDataName.MagicDefence)
  511. end
  512. -- 攻击力
  513. local attack = atkRole:GetRoleData(RoleDataName.Attack)
  514. -- 无视防御系数
  515. ignoreDef = 1 - (ignoreDef or 0)
  516. local onIgnoreDefFactor = function(outIgnoreDef)
  517. ignoreDef = 1 - math.max(0, outIgnoreDef)
  518. end
  519. atkRole.Event:DispatchEvent(BattleEventName.IgnoreDefFactor, onIgnoreDefFactor, atkRole, defRole)
  520. defRole.Event:DispatchEvent(BattleEventName.BeIgnoreDefFactor, onIgnoreDefFactor, atkRole, defRole)
  521. -- 基础伤害 = 攻击力 - 防御力
  522. baseDamage = max(attack - BattleUtil.FP_Mul(0.5, defence, ignoreDef), 0)
  523. -- 基础伤害增加系数
  524. local addDamageFactor = 1 + atkRole:GetRoleData(RoleDataName.DamageBocusFactor) - defRole:GetRoleData(RoleDataName.DamageReduceFactor)
  525. -- 是否暴击: 暴击率 = 自身暴击率 - 对方抗暴率
  526. local bCrit = false
  527. local critRandom = Random.Range01()
  528. local critCondition = clamp(atkRole:GetRoleData(RoleDataName.Crit) - defRole:GetRoleData(RoleDataName.Tenacity), 0, 1)
  529. bCrit = critRandom <= critCondition
  530. bCrit = bCrit or defRole.isFlagCrit == true -- 必定暴击
  531. -- 计算暴伤害系数
  532. local critDamageFactor = 1
  533. local critDamageReduceFactor = 0 -- 暴击伤害减免
  534. --计算暴击
  535. if bCrit then
  536. --加入被动效果 触发暴击被动
  537. local cl = {}
  538. local onCritDamageReduceFactor = function(v, ct)
  539. if v then
  540. table.insert(cl, {v, ct})
  541. end
  542. end
  543. atkRole.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole)
  544. defRole.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole)
  545. BattleLogic.Event:DispatchEvent(BattleEventName.CritDamageReduceFactor, onCritDamageReduceFactor, atkRole, defRole)
  546. critDamageReduceFactor = max(BattleUtil.CountChangeList(critDamageReduceFactor, cl), 0)
  547. -- 计算额外暴击伤害
  548. critDamageFactor = 1.3 + atkRole:GetRoleData(RoleDataName.CritDamageFactor) - critDamageReduceFactor
  549. --加入被动效果 触发暴击被动
  550. local critFunc = function(critEx) critDamageFactor = critEx end
  551. atkRole.Event:DispatchEvent(BattleEventName.PassiveCriting, critFunc)
  552. end
  553. -- 公式伤害 = 基础伤害 * 基础伤害系数 * 增伤系数 * 爆伤系数
  554. local fixDamage = floor(BattleUtil.FP_Mul(baseDamage, baseFactor, addDamageFactor, critDamageFactor))
  555. -- 公式计算完成
  556. local damageFunc = function(damage) fixDamage = damage end
  557. atkRole.Event:DispatchEvent(BattleEventName.RoleDamageAfter, defRole, damageFunc, fixDamage)
  558. defRole.Event:DispatchEvent(BattleEventName.RoleBeDamagedAfter, atkRole, damageFunc, fixDamage)
  559. fixDamage = max(floor(attack * 0.1), fixDamage)
  560. local finalDmg = 0 --计算实际造成的扣血
  561. if not defRole:IsRealDead() then
  562. finalDmg = BattleUtil.ApplyDamage(skill, atkRole, defRole, fixDamage, bCrit, damageType, dotType)
  563. end
  564. return finalDmg, bCrit
  565. end
  566. function BattleUtil.CalTreat(castRole, targetRole, value, baseFactor)
  567. if targetRole.ctrl_noheal or targetRole:IsDead() then --禁疗和死亡无法加血
  568. return
  569. end
  570. targetRole.Event:DispatchEvent(BattleEventName.RoleBeHealed, castRole)
  571. BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor)
  572. end
  573. function BattleUtil.ApplyTreat(castRole, targetRole, value, baseFactor)
  574. if targetRole.ctrl_noheal or targetRole:IsDead() then --禁疗和死亡无法加血
  575. return
  576. end
  577. baseFactor = baseFactor or 1
  578. local maxHp = targetRole:GetRoleData(RoleDataName.MaxHp)
  579. local hp = targetRole:GetRoleData(RoleDataName.Hp)
  580. -- 计算被动对治疗系数的影响
  581. local treatFactorFunc = function(df, dt)
  582. baseFactor = BattleUtil.CountValue(baseFactor, df, dt)
  583. end
  584. castRole.Event:DispatchEvent(BattleEventName.PassiveTreatingFactor, treatFactorFunc, targetRole)
  585. targetRole.Event:DispatchEvent(BattleEventName.PassiveBeTreatedFactor, treatFactorFunc, castRole)
  586. local factor = castRole.isTeam and 1 or castRole:GetRoleData(RoleDataName.TreatFacter) --释放者为team则不计算治疗加成属性
  587. local factor2 = targetRole:GetRoleData(RoleDataName.CureFacter)
  588. local baseTreat = BattleUtil.FP_Mul(value, baseFactor, factor, factor2)
  589. --加入被动效果
  590. local cl = {}
  591. local function treatingFunc(v, ct)
  592. if v then
  593. table.insert(cl, {v, ct})
  594. end
  595. end
  596. -- local treatingFunc = function(exFactor) baseTreat = floor(baseTreat * (exFactor + 1) + 0.5) end
  597. castRole.Event:DispatchEvent(BattleEventName.PassiveTreating, treatingFunc, targetRole)
  598. targetRole.Event:DispatchEvent(BattleEventName.PassiveBeTreated, treatingFunc, castRole)
  599. baseTreat = BattleUtil.CountChangeList(baseTreat, cl)
  600. -- 取整
  601. local baseTreat = floor(baseTreat + 0.5)
  602. local treat = min(baseTreat, maxHp - hp)
  603. if treat > 0 then
  604. targetRole.data:AddValue(RoleDataName.Hp, treat)
  605. end
  606. castRole.Event:DispatchEvent(BattleEventName.RoleTreat, targetRole, treat, baseTreat)
  607. targetRole.Event:DispatchEvent(BattleEventName.RoleBeTreated, castRole, treat, baseTreat)
  608. --
  609. BattleLogManager.Log(
  610. "Final Damage",
  611. "acamp", castRole.camp,
  612. "apos", castRole.position,
  613. "tcamp", targetRole.camp,
  614. "tpos", targetRole.position,
  615. "value", value
  616. )
  617. end
  618. -- 检测命中
  619. function BattleUtil.CheckIsHit(atkRole, defRole)
  620. -- 是否命中: 命中 = 自身命中率 - 对方闪避率
  621. local isHit = false
  622. local hitRandom = Random.Range01()
  623. LogGreen("命中率")
  624. LogGreen(atkRole:GetRoleData(RoleDataName.Hit))
  625. LogGreen(atkRole:GetRoleData(RoleDataName.Dodge))
  626. local hitCondition = clamp(atkRole:GetRoleData(RoleDataName.Hit) - defRole:GetRoleData(RoleDataName.Dodge), 0, 1)
  627. isHit = hitRandom <= hitCondition
  628. return isHit
  629. end
  630. function BattleUtil.RandomAction(rand, action)
  631. if Random.Range01() <= rand and action then
  632. action()
  633. return true
  634. end
  635. return false
  636. end
  637. --
  638. function BattleUtil.RandomControl(rand, ctrl, caster, target, round)
  639. local cl = {}
  640. local function _CallBack(v, ct)
  641. if v then
  642. table.insert(cl, {v, ct})
  643. end
  644. end
  645. caster.Event:DispatchEvent(BattleEventName.PassiveRandomControl, _CallBack, ctrl, target)
  646. target.Event:DispatchEvent(BattleEventName.PassiveBeRandomControl, _CallBack, ctrl, target)
  647. rand = BattleUtil.CountChangeList(rand, cl)
  648. return BattleUtil.RandomAction(rand, function()
  649. local buff = Buff.Create(caster, BuffName.Control, round, ctrl)
  650. target:AddBuff(buff)
  651. end)
  652. end
  653. --
  654. function BattleUtil.RandomDot(rand, dot, caster, target, round, interval, damage)
  655. local cl = {}
  656. local dcl = {}
  657. local function _CallBack(v, ct, dv, dct)
  658. if v then
  659. table.insert(cl, {v, ct})
  660. end
  661. if dv then
  662. table.insert(dcl, {dv, dct})
  663. end
  664. end
  665. caster.Event:DispatchEvent(BattleEventName.PassiveRandomDot, _CallBack, dot)
  666. target.Event:DispatchEvent(BattleEventName.PassiveBeRandomDot, _CallBack, dot)
  667. rand = BattleUtil.CountChangeList(rand, cl)
  668. damage = BattleUtil.CountChangeList(damage, dcl)
  669. return BattleUtil.RandomAction(rand, function()
  670. local buff = Buff.Create(caster, BuffName.DOT, round, interval, dot, damage)
  671. buff.isRealDamage = true
  672. target:AddBuff(buff)
  673. end)
  674. end
  675. function BattleUtil.RandomList(arr)
  676. if #arr <= 1 then return end
  677. local index
  678. for i=#arr, 1, -1 do
  679. index = Random.RangeInt(1, i)
  680. arr[i], arr[index] = arr[index], arr[i]
  681. end
  682. end
  683. function BattleUtil.Sort(arr, comp)
  684. if #arr <= 1 then return arr end
  685. for i=1, #arr do
  686. for j = #arr, i+1, -1 do
  687. if comp(arr[j-1], arr[j]) then
  688. arr[j-1], arr[j] = arr[j], arr[j-1]
  689. end
  690. end
  691. end
  692. return arr
  693. end
  694. function BattleUtil.GetPropertyName(type)
  695. if type == 1 then
  696. return RoleDataName.Strength
  697. elseif type == 2 then
  698. return RoleDataName.Energy
  699. elseif type == 3 then
  700. return RoleDataName.Vitality
  701. elseif type == 4 then
  702. return RoleDataName.Dexterity
  703. elseif type == 5 then
  704. return RoleDataName.Speed
  705. elseif type == 6 then
  706. return RoleDataName.PhysicalAttack
  707. elseif type == 7 then
  708. return RoleDataName.MagicAttack
  709. elseif type == 8 then
  710. return RoleDataName.PhysicalDefence
  711. elseif type == 9 then
  712. return RoleDataName.MagicDefence
  713. end
  714. end
  715. function BattleUtil.GetHPPencent(role)
  716. return role:GetRoleData(RoleDataName.Hp) / role:GetRoleData(RoleDataName.MaxHp)
  717. end
  718. -- 计算数值
  719. function BattleUtil.CountValue(v1, v2, ct)
  720. local v = v1
  721. if ct == 1 then --加算
  722. v = v + v2
  723. elseif ct == 2 then --乘加算(百分比属性加算)
  724. v = v * (1 + v2)
  725. elseif ct == 3 then --减算
  726. v = v - v2
  727. elseif ct == 4 then --乘减算(百分比属性减算)
  728. v = v * (1 - v2)
  729. elseif ct == 5 then -- 覆盖
  730. v = v2
  731. end
  732. -- 做一个正确性检测
  733. -- v = BattleUtil.ErrorCorrection(v)
  734. return v
  735. end
  736. -- 计算数值改变
  737. function BattleUtil.CountChangeList(v, changeList)
  738. local aplist = {}
  739. local splist = {}
  740. local cplist = {}
  741. local fv = v
  742. -- 先算绝对值
  743. for _, change in ipairs(changeList) do
  744. local cv = change[1]
  745. local ct = change[2]
  746. if ct then
  747. if ct == 1 or ct == 3 then
  748. fv = BattleUtil.CountValue(fv, cv, ct)
  749. elseif ct == 2 then
  750. table.insert(aplist, change)
  751. elseif ct == 4 then
  752. table.insert(splist, change)
  753. elseif ct == 5 then
  754. table.insert(cplist, change)
  755. end
  756. end
  757. end
  758. -- 加乘(对基数进行加乘)
  759. for _, change in ipairs(aplist) do
  760. local cv = change[1]
  761. local ct = change[2]
  762. fv = fv + (BattleUtil.CountValue(v, cv, ct) - v)
  763. end
  764. -- 减乘(对最终数值进行减乘算)
  765. for _, change in ipairs(splist) do
  766. local cv = change[1]
  767. local ct = change[2]
  768. fv = BattleUtil.CountValue(fv, cv, ct)
  769. end
  770. -- 覆盖
  771. for _, change in ipairs(cplist) do
  772. local cv = change[1]
  773. local ct = change[2]
  774. fv = BattleUtil.CountValue(fv, cv, ct)
  775. end
  776. return fv
  777. end
  778. -- 检测技能伤害治疗加乘
  779. function BattleUtil.CheckSkillDamageHeal(f, caster, target)
  780. local cl = {}
  781. local function _CallBack(v, ct)
  782. if v then
  783. table.insert(cl, {v, ct})
  784. end
  785. end
  786. caster.Event:DispatchEvent(BattleEventName.PassiveSkillDamageHeal, _CallBack)
  787. target.Event:DispatchEvent(BattleEventName.PassiveBeSkillDamageHeal, _CallBack)
  788. f = BattleUtil.CountChangeList(f, cl)
  789. return f
  790. end
  791. -- 检测技能伤害治疗加乘
  792. function BattleUtil.CheckSeckill(bf, kf, caster, target)
  793. local bcl = {}
  794. local kcl = {}
  795. local function _CallBack(bv, bct, kv, kct)
  796. if bv and bct then
  797. table.insert(bcl, {bv, bct})
  798. end
  799. if kv and kct then
  800. table.insert(kcl, {kv, kct})
  801. end
  802. end
  803. caster.Event:DispatchEvent(BattleEventName.PassiveSeckill, _CallBack)
  804. target.Event:DispatchEvent(BattleEventName.PassiveBeSeckill, _CallBack)
  805. bf = BattleUtil.CountChangeList(bf, bcl)
  806. kf = BattleUtil.CountChangeList(kf, kcl)
  807. return bf, kf
  808. end
  809. -- 获取位置类型
  810. -- 1 前排
  811. -- 2 后排
  812. function BattleUtil.GetRolePosType(pos)
  813. if pos <= 3 then
  814. return 1
  815. elseif pos > 3 then
  816. return 2
  817. end
  818. end
  819. -- 根据位置类型获取数据
  820. function BattleUtil.GetRoleListByPosType(camp, posType)
  821. if posType == 1 then
  822. return RoleManager.Query(function (r) return r.camp == camp and r.position <= 3 end)
  823. elseif posType == 2 then
  824. return RoleManager.Query(function (r) return r.camp == camp and r.position > 3 end)
  825. end
  826. end
  827. -- 通用增加属性的方法
  828. function BattleUtil.AddProp(role, prop, value, ct)
  829. if ct == 1 then --加算
  830. role.data:AddValue(BattlePropList[prop], value)
  831. elseif ct == 2 then --乘加算(百分比属性加算)
  832. role.data:AddPencentValue(BattlePropList[prop], value)
  833. elseif ct == 3 then --减算
  834. role.data:SubValue(BattlePropList[prop], value)
  835. elseif ct == 4 then --乘减算(百分比属性减算)
  836. role.data:SubPencentValue(BattlePropList[prop], value)
  837. end
  838. end