powerfunc.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. local asset = require "model.asset"
  2. local equip = require "model.equip"
  3. local talent = require "model.talent"
  4. local logger = require "logger"
  5. local stringify = require "stringify"
  6. local RATENUM = 10000
  7. local function nan_to_zero(value)
  8. -- 检查值是否为 NaN
  9. local key = tostring(value)
  10. if key == "nan" or key == "-nan" then
  11. return 0
  12. else
  13. return value
  14. end
  15. end
  16. local this = {}
  17. local ENTRY = {
  18. HP = 1,
  19. attack = 2,
  20. spellAttack = 3,
  21. defense = 4,
  22. spellDefense = 5,
  23. attackCrit = 6,
  24. critNum = 7,
  25. hit = 8,
  26. dodge = 9,
  27. attackSpeed = 10,
  28. moveSpeed = 11,
  29. realAttack = 12,
  30. addRoleHP = 13,
  31. talAddHP = 14,
  32. talAddattack = 15,
  33. talAddspellAttack = 16,
  34. talAdddefense = 17,
  35. talAddspellDefense = 18,
  36. equipAddAttack = 19,
  37. talAddAllDefense = 20,
  38. HPRate = 21,
  39. attackRate = 22,
  40. spellAttackRate = 23,
  41. defenseRate = 24,
  42. spellDefenseRate = 25,
  43. attackCritRate = 26,
  44. critNumRate = 27,
  45. hitRate = 28,
  46. dodgeRate = 29,
  47. attackSpeedRate = 30,
  48. moveSpeedRate = 31,
  49. realAttackRate = 32,
  50. }
  51. do
  52. local o = {}
  53. for k, v in pairs(ENTRY) do
  54. o[v] = k
  55. end
  56. setmetatable(ENTRY, {__index = o})
  57. end
  58. local function toFixed(a, b)
  59. local num = 10 ^ b
  60. local ret = math.floor(a * num + 0.5)/num
  61. return ret
  62. end
  63. function this.buildIBaseAttr(cfg, isZero)
  64. local baseAttr = {
  65. HP= isZero and 0 or cfg.HP,
  66. attack= isZero and 0 or cfg.attack,
  67. spellAttack= isZero and 0 or cfg.spellAttack,
  68. realAttack= isZero and 0 or cfg.realAttack,
  69. defense= isZero and 0 or cfg.defense,
  70. spellDefense= isZero and 0 or cfg.spellDefense,
  71. attackSpeed= isZero and 0 or cfg.attackSpeed,
  72. attackCrit= isZero and 0 or cfg.attackCrit,
  73. critNum= isZero and 0 or cfg.critNum,
  74. hit= isZero and 0 or cfg.hit,
  75. dodge= isZero and 0 or cfg.dodge,
  76. moveSpeed= isZero and 0 or cfg.moveSpeed,
  77. }
  78. return baseAttr
  79. end
  80. function this.entryBaseAttrAdd(baseAttr, entryID)
  81. local EntryConfig = asset.EntryConfig_proto
  82. for _, id in ipairs(entryID) do
  83. local entryCfg = EntryConfig[id]
  84. if entryCfg.type >= ENTRY.HP and entryCfg.type <= ENTRY.realAttack then
  85. local key = ENTRY[entryCfg.type]
  86. baseAttr[key] = baseAttr[key] + entryCfg.parmArr[1]
  87. end
  88. if entryCfg.type == ENTRY.talAddAllDefense then
  89. baseAttr.defense = baseAttr.defense + entryCfg.parmArr[1]
  90. baseAttr.spellDefense = baseAttr.spellDefense + entryCfg.parmArr[1]
  91. end
  92. end
  93. end
  94. function this.initTalentAdd(character)
  95. local talent_data = talent.get_talent_data(character)
  96. local EntryConfig = asset.EntryConfig_proto
  97. local TalentConfig = asset.TalentConfig_proto
  98. local profession_entrys = {}
  99. local all_entrys = {}
  100. local addAllAttrRateArr = {
  101. [ENTRY.talAddHP] = ENTRY.HP,
  102. [ENTRY.talAddattack] = ENTRY.attack,
  103. [ENTRY.talAddspellAttack] = ENTRY.spellAttack,
  104. [ENTRY.talAdddefense] = ENTRY.defense,
  105. [ENTRY.talAddspellDefense] = ENTRY.spellDefense,
  106. }
  107. for _, talent_conf in pairs(TalentConfig) do
  108. local data = talent_data[talent_conf.talentType]
  109. if data and data.id >= talent_conf.ID then
  110. local conf = EntryConfig[talent_conf.entryID]
  111. if conf and conf.type then
  112. if addAllAttrRateArr[conf.type] then
  113. table.insert(all_entrys, talent_conf.entryID)
  114. else
  115. for _, v in ipairs(conf.profession) do
  116. profession_entrys[v] = profession_entrys[v] or {}
  117. table.insert(profession_entrys[v], talent_conf.entryID)
  118. end
  119. end
  120. end
  121. end
  122. end
  123. local talentAdds = {}
  124. local EntryConfig = asset.EntryConfig_proto
  125. for i = 1, 6 do
  126. local talentAdd = this.buildIBaseAttr(nil, true)
  127. local entryIDs = profession_entrys[i] or {}
  128. this.entryBaseAttrAdd(talentAdd, entryIDs)
  129. for _, id in ipairs(all_entrys) do
  130. local entryCfg = EntryConfig[id]
  131. local key = addAllAttrRateArr[entryCfg.type]
  132. if key and ENTRY[key] then
  133. talentAdd[ENTRY[key]] = talentAdd[ENTRY[key]] * (1+ entryCfg.rateArr[1] /RATENUM)
  134. end
  135. end
  136. talentAdds[i] = talentAdd
  137. end
  138. return talentAdds
  139. end
  140. function this.changeBaseAttr(baseAttr, changeAttr, isAdd)
  141. baseAttr.HP = isAdd and baseAttr.HP + changeAttr.HP or changeAttr.HP
  142. baseAttr.attack = isAdd and baseAttr.attack + changeAttr.attack or changeAttr.attack
  143. baseAttr.attackSpeed = isAdd and baseAttr.attackSpeed + changeAttr.attackSpeed or changeAttr.attackSpeed
  144. baseAttr.attackCrit = isAdd and baseAttr.attackCrit + changeAttr.attackCrit or changeAttr.attackCrit
  145. baseAttr.critNum = isAdd and baseAttr.critNum + changeAttr.critNum or changeAttr.critNum
  146. baseAttr.defense = isAdd and baseAttr.defense + changeAttr.defense or changeAttr.defense
  147. baseAttr.dodge = isAdd and baseAttr.dodge + changeAttr.dodge or changeAttr.dodge
  148. baseAttr.hit = isAdd and baseAttr.hit + changeAttr.hit or changeAttr.hit
  149. baseAttr.spellAttack = isAdd and baseAttr.spellAttack + changeAttr.spellAttack or changeAttr.spellAttack
  150. baseAttr.spellDefense = isAdd and baseAttr.spellDefense + changeAttr.spellDefense or changeAttr.spellDefense
  151. baseAttr.realAttack = isAdd and baseAttr.realAttack + changeAttr.realAttack or changeAttr.realAttack
  152. baseAttr.moveSpeed = isAdd and baseAttr.moveSpeed + changeAttr.moveSpeed or changeAttr.moveSpeed
  153. return baseAttr
  154. end
  155. function this.buildIEquip(equip)
  156. local ArmorConfig = asset.ArmorConfig_proto
  157. local curCfg = ArmorConfig[equip.id]
  158. if (equip.id > 0 and not curCfg) then
  159. return
  160. end
  161. local baseAttr = this.buildIBaseAttr(curCfg)
  162. --等级加成为固定值
  163. local lvAddAttr = {"HP", "attack", "spellAttack"}
  164. for _, attr in ipairs(lvAddAttr) do
  165. if (baseAttr[attr] and baseAttr[attr] > 0) then
  166. baseAttr[attr] = baseAttr[attr] + (equip.lv - 1) * curCfg.increaseLv
  167. end
  168. end
  169. baseAttr.entry = curCfg.entry
  170. return baseAttr
  171. end
  172. function this.setIBaseAttr(obj, cfg, lvAdd, equips, talentAdd)
  173. --装备加成
  174. local attr = this.buildIBaseAttr(nil, true) or {}
  175. local allEntryArr = {}
  176. if equips then
  177. for _, data in pairs(equips) do
  178. local add_attr = this.buildIEquip(data)
  179. if add_attr then
  180. this.changeBaseAttr(attr, add_attr, true)
  181. if add_attr.entry > 0 then
  182. table.insert(allEntryArr, add_attr.entry)
  183. end
  184. end
  185. end
  186. end
  187. obj.HP = (cfg.HP or 0) * lvAdd + attr.HP
  188. obj.attack = (cfg.attack or 0) * lvAdd + attr.attack
  189. obj.attackSpeed = (cfg.attackSpeed or 0) * lvAdd + attr.attackSpeed
  190. obj.attackCrit = (cfg.attackCrit or 0) * lvAdd + attr.attackCrit
  191. obj.critNum = (cfg.critNum or 0) * lvAdd + attr.critNum
  192. obj.defense = (cfg.defense or 0) * lvAdd + attr.defense
  193. obj.dodge = (cfg.dodge or 0) * lvAdd + attr.dodge
  194. obj.hit = (cfg.hit or 0) * lvAdd + attr.hit
  195. obj.spellAttack = (cfg.spellAttack or 0) * lvAdd + attr.spellAttack
  196. obj.spellDefense = (cfg.spellDefense or 0) * lvAdd + attr.spellDefense
  197. obj.realAttack = (cfg.realAttack or 0) * lvAdd + attr.realAttack
  198. obj.moveSpeed = (cfg.moveSpeed or 0) + (attr.moveSpeed or 0)
  199. if obj.hero then
  200. local profession = cfg.profession
  201. if(talentAdd and talentAdd[profession]) then
  202. this.changeBaseAttr(obj, talentAdd[profession], true)
  203. end
  204. end
  205. local EntryConfig = asset.EntryConfig_proto
  206. -- 所有角色卡牌基础属性万分比词条加成
  207. for _, entry in ipairs(allEntryArr) do
  208. if entry == ENTRY.addRoleHP then
  209. obj.HP = obj.HP * (1 + EntryConfig[entry].rateArr[1] / RATENUM)
  210. elseif entry == ENTRY.equipAddAttack then
  211. obj.attack = obj.attack * (1 + EntryConfig[entry].rateArr[1] / RATENUM)
  212. end
  213. end
  214. obj.HP = math.floor(obj.HP)
  215. obj.attack = math.floor(obj.attack)
  216. obj.attackSpeed = math.floor(obj.attackSpeed)
  217. obj.attackCrit = math.floor(obj.attackCrit)
  218. obj.critNum = math.floor(obj.critNum)
  219. obj.defense = math.floor(obj.defense)
  220. obj.dodge = math.floor(obj.dodge)
  221. obj.hit = math.floor(obj.hit)
  222. obj.spellAttack = math.floor(obj.spellAttack)
  223. obj.spellDefense = math.floor(obj.spellDefense)
  224. obj.realAttack = math.floor(obj.realAttack)
  225. obj.moveSpeed = math.floor(obj.moveSpeed)
  226. end
  227. function this.getPowerByAttr(obj)
  228. local defenseCoe = toFixed((1 / toFixed((1 - obj.defense / (obj.defense + 325)), 2)), 2)
  229. -- 法术防御系数 1 - 法术防御/(法术防御+防御常数)
  230. local spellDefenseCoe = toFixed((1 / toFixed((1 - obj.spellDefense / (obj.spellDefense + 325)), 2)), 2)
  231. --攻速系数 攻速/比例值
  232. local attackSpeedCoe = toFixed((obj.attackSpeed / RATENUM), 2)
  233. --暴击系数 暴击伤害倍数/比例值 * 暴击率/比例值 * 2
  234. local critCoe = toFixed((obj.critNum / RATENUM), 2) * toFixed((obj.attackCrit / RATENUM), 2)* 2
  235. --命中系数 1/攻击CD/比例值 * 命中率/比例值
  236. local hitCoe = toFixed((1 / toFixed((obj.attackSpeed / RATENUM), 2)), 2) * toFixed((obj.hit / RATENUM), 2)
  237. --闪避系数 1/(1-闪避率/比例值)
  238. local dodgeCoe = toFixed((1 / toFixed((1 - obj.dodge / RATENUM), 2)), 2)
  239. defenseCoe = nan_to_zero(defenseCoe)
  240. spellDefenseCoe = nan_to_zero(spellDefenseCoe)
  241. attackSpeedCoe = nan_to_zero(attackSpeedCoe)
  242. critCoe = nan_to_zero(critCoe)
  243. hitCoe = nan_to_zero(hitCoe)
  244. dodgeCoe = nan_to_zero(dodgeCoe)
  245. -- logger.trace(defenseCoe)
  246. -- logger.trace(spellDefenseCoe)
  247. -- logger.trace(attackSpeedCoe)
  248. -- logger.trace(critCoe)
  249. -- logger.trace(hitCoe)
  250. -- logger.trace(dodgeCoe)
  251. -- logger.trace(stringify(obj))
  252. obj.power =
  253. obj.attack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 +
  254. obj.spellAttack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 +
  255. obj.HP * (1 + defenseCoe + spellDefenseCoe + dodgeCoe) * 0.8
  256. --取地板值
  257. obj.power = math.floor(obj.power)
  258. return obj.power
  259. end
  260. function this.buildIRole(character, hero)
  261. local RoleConfig = asset.RoleConfig_proto
  262. local iRole = {}
  263. if hero.id > 0 and not RoleConfig[hero.id] then
  264. return 0
  265. end
  266. local baseAttr = this.buildIBaseAttr(RoleConfig[hero.id])
  267. local talents = this.initTalentAdd(character)
  268. iRole = {
  269. cfg = RoleConfig[hero.id],
  270. hero = hero,
  271. power = 0,
  272. equips = {},
  273. }
  274. setmetatable(iRole, {__index = baseAttr})
  275. for k, sid in pairs(hero.equip or {}) do
  276. if sid and sid ~= "" then
  277. local equip_data = equip.equip_get(character, sid)
  278. if equip_data then
  279. iRole.equips[k] = equip_data
  280. end
  281. end
  282. end
  283. -- logger.trace(stringify(iRole.equips))
  284. --比例值(万分比)
  285. --等级加成 1 + 等级/100
  286. local lvAdd = 1 + toFixed(((iRole.hero.lv - 1) / 100), 2)
  287. this.setIBaseAttr(iRole, iRole.cfg, lvAdd, iRole.equips, talents)
  288. -- 物理防御系数 1 - 物理防御/(物理防御+防御常数)
  289. return this.getPowerByAttr(iRole)
  290. end
  291. function this.buildICard(character, card)
  292. local iCard
  293. local CardSkillConfig = asset.CardSkillConfig_proto
  294. if (card.id > 0 and not CardSkillConfig[card.id]) then
  295. return 0
  296. end
  297. local baseAttr = this.buildIBaseAttr(CardSkillConfig[card.id])
  298. iCard = {
  299. cfg= CardSkillConfig[card.id],
  300. card= card,
  301. power= 0,
  302. }
  303. -- -- -----卡牌战斗力不受装备,天赋加成----
  304. --等级加成 1 + 等级/比例值
  305. local lvAdd = 1 + toFixed(((iCard.card.lv - 1) / 100), 2)
  306. this.setIBaseAttr(iCard, iCard.cfg, lvAdd)
  307. return this.getPowerByAttr(iCard)
  308. end
  309. return {build_role = this.buildIRole, build_card = this.buildICard}