local asset = require "model.asset" local equip = require "model.equip" local talent = require "model.talent" local logger = require "logger" local stringify = require "stringify" local RATENUM = 10000 local function nan_to_zero(value) -- 检查值是否为 NaN local key = tostring(value) if key == "nan" or key == "-nan" then return 0 else return value end end local this = {} local ENTRY = { HP = 1, attack = 2, spellAttack = 3, defense = 4, spellDefense = 5, attackCrit = 6, critNum = 7, hit = 8, dodge = 9, attackSpeed = 10, moveSpeed = 11, realAttack = 12, addRoleHP = 13, talAddHP = 14, talAddattack = 15, talAddspellAttack = 16, talAdddefense = 17, talAddspellDefense = 18, equipAddAttack = 19, talAddAllDefense = 20, HPRate = 21, attackRate = 22, spellAttackRate = 23, defenseRate = 24, spellDefenseRate = 25, attackCritRate = 26, critNumRate = 27, hitRate = 28, dodgeRate = 29, attackSpeedRate = 30, moveSpeedRate = 31, realAttackRate = 32, } do local o = {} for k, v in pairs(ENTRY) do o[v] = k end setmetatable(ENTRY, {__index = o}) end local function toFixed(a, b) local num = 10 ^ b local ret = math.floor(a * num + 0.5)/num return ret end function this.buildIBaseAttr(cfg, isZero) local baseAttr = { HP= isZero and 0 or cfg.HP, attack= isZero and 0 or cfg.attack, spellAttack= isZero and 0 or cfg.spellAttack, realAttack= isZero and 0 or cfg.realAttack, defense= isZero and 0 or cfg.defense, spellDefense= isZero and 0 or cfg.spellDefense, attackSpeed= isZero and 0 or cfg.attackSpeed, attackCrit= isZero and 0 or cfg.attackCrit, critNum= isZero and 0 or cfg.critNum, hit= isZero and 0 or cfg.hit, dodge= isZero and 0 or cfg.dodge, moveSpeed= isZero and 0 or cfg.moveSpeed, } return baseAttr end function this.entryBaseAttrAdd(baseAttr, entryID) local EntryConfig = asset.EntryConfig_proto for _, id in ipairs(entryID) do local entryCfg = EntryConfig[id] if entryCfg.type >= ENTRY.HP and entryCfg.type <= ENTRY.realAttack then local key = ENTRY[entryCfg.type] baseAttr[key] = baseAttr[key] + entryCfg.parmArr[1] end if entryCfg.type == ENTRY.talAddAllDefense then baseAttr.defense = baseAttr.defense + entryCfg.parmArr[1] baseAttr.spellDefense = baseAttr.spellDefense + entryCfg.parmArr[1] end end end function this.initTalentAdd(character) local talent_data = talent.get_talent_data(character) local EntryConfig = asset.EntryConfig_proto local TalentConfig = asset.TalentConfig_proto local profession_entrys = {} local all_entrys = {} local addAllAttrRateArr = { [ENTRY.talAddHP] = ENTRY.HP, [ENTRY.talAddattack] = ENTRY.attack, [ENTRY.talAddspellAttack] = ENTRY.spellAttack, [ENTRY.talAdddefense] = ENTRY.defense, [ENTRY.talAddspellDefense] = ENTRY.spellDefense, } for _, talent_conf in pairs(TalentConfig) do local data = talent_data[talent_conf.talentType] if data and data.id >= talent_conf.ID then local conf = EntryConfig[talent_conf.entryID] if conf and conf.type then if addAllAttrRateArr[conf.type] then table.insert(all_entrys, talent_conf.entryID) else for _, v in ipairs(conf.profession) do profession_entrys[v] = profession_entrys[v] or {} table.insert(profession_entrys[v], talent_conf.entryID) end end end end end local talentAdds = {} local EntryConfig = asset.EntryConfig_proto for i = 1, 6 do local talentAdd = this.buildIBaseAttr(nil, true) local entryIDs = profession_entrys[i] or {} this.entryBaseAttrAdd(talentAdd, entryIDs) for _, id in ipairs(all_entrys) do local entryCfg = EntryConfig[id] local key = addAllAttrRateArr[entryCfg.type] if key and ENTRY[key] then talentAdd[ENTRY[key]] = talentAdd[ENTRY[key]] * (1+ entryCfg.rateArr[1] /RATENUM) end end talentAdds[i] = talentAdd end return talentAdds end function this.changeBaseAttr(baseAttr, changeAttr, isAdd) baseAttr.HP = isAdd and baseAttr.HP + changeAttr.HP or changeAttr.HP baseAttr.attack = isAdd and baseAttr.attack + changeAttr.attack or changeAttr.attack baseAttr.attackSpeed = isAdd and baseAttr.attackSpeed + changeAttr.attackSpeed or changeAttr.attackSpeed baseAttr.attackCrit = isAdd and baseAttr.attackCrit + changeAttr.attackCrit or changeAttr.attackCrit baseAttr.critNum = isAdd and baseAttr.critNum + changeAttr.critNum or changeAttr.critNum baseAttr.defense = isAdd and baseAttr.defense + changeAttr.defense or changeAttr.defense baseAttr.dodge = isAdd and baseAttr.dodge + changeAttr.dodge or changeAttr.dodge baseAttr.hit = isAdd and baseAttr.hit + changeAttr.hit or changeAttr.hit baseAttr.spellAttack = isAdd and baseAttr.spellAttack + changeAttr.spellAttack or changeAttr.spellAttack baseAttr.spellDefense = isAdd and baseAttr.spellDefense + changeAttr.spellDefense or changeAttr.spellDefense baseAttr.realAttack = isAdd and baseAttr.realAttack + changeAttr.realAttack or changeAttr.realAttack baseAttr.moveSpeed = isAdd and baseAttr.moveSpeed + changeAttr.moveSpeed or changeAttr.moveSpeed return baseAttr end function this.buildIEquip(equip) local ArmorConfig = asset.ArmorConfig_proto local curCfg = ArmorConfig[equip.id] if (equip.id > 0 and not curCfg) then return end local baseAttr = this.buildIBaseAttr(curCfg) --等级加成为固定值 local lvAddAttr = {"HP", "attack", "spellAttack"} for _, attr in ipairs(lvAddAttr) do if (baseAttr[attr] and baseAttr[attr] > 0) then baseAttr[attr] = baseAttr[attr] + (equip.lv - 1) * curCfg.increaseLv end end baseAttr.entry = curCfg.entry return baseAttr end function this.setIBaseAttr(obj, cfg, lvAdd, equips, talentAdd) --装备加成 local attr = this.buildIBaseAttr(nil, true) or {} local allEntryArr = {} if equips then for _, data in pairs(equips) do local add_attr = this.buildIEquip(data) if add_attr then this.changeBaseAttr(attr, add_attr, true) if add_attr.entry > 0 then table.insert(allEntryArr, add_attr.entry) end end end end obj.HP = (cfg.HP or 0) * lvAdd + attr.HP obj.attack = (cfg.attack or 0) * lvAdd + attr.attack obj.attackSpeed = (cfg.attackSpeed or 0) * lvAdd + attr.attackSpeed obj.attackCrit = (cfg.attackCrit or 0) * lvAdd + attr.attackCrit obj.critNum = (cfg.critNum or 0) * lvAdd + attr.critNum obj.defense = (cfg.defense or 0) * lvAdd + attr.defense obj.dodge = (cfg.dodge or 0) * lvAdd + attr.dodge obj.hit = (cfg.hit or 0) * lvAdd + attr.hit obj.spellAttack = (cfg.spellAttack or 0) * lvAdd + attr.spellAttack obj.spellDefense = (cfg.spellDefense or 0) * lvAdd + attr.spellDefense obj.realAttack = (cfg.realAttack or 0) * lvAdd + attr.realAttack obj.moveSpeed = (cfg.moveSpeed or 0) + (attr.moveSpeed or 0) if obj.hero then local profession = cfg.profession if(talentAdd and talentAdd[profession]) then this.changeBaseAttr(obj, talentAdd[profession], true) end end local EntryConfig = asset.EntryConfig_proto -- 所有角色卡牌基础属性万分比词条加成 for _, entry in ipairs(allEntryArr) do if entry == ENTRY.addRoleHP then obj.HP = obj.HP * (1 + EntryConfig[entry].rateArr[1] / RATENUM) elseif entry == ENTRY.equipAddAttack then obj.attack = obj.attack * (1 + EntryConfig[entry].rateArr[1] / RATENUM) end end obj.HP = math.floor(obj.HP) obj.attack = math.floor(obj.attack) obj.attackSpeed = math.floor(obj.attackSpeed) obj.attackCrit = math.floor(obj.attackCrit) obj.critNum = math.floor(obj.critNum) obj.defense = math.floor(obj.defense) obj.dodge = math.floor(obj.dodge) obj.hit = math.floor(obj.hit) obj.spellAttack = math.floor(obj.spellAttack) obj.spellDefense = math.floor(obj.spellDefense) obj.realAttack = math.floor(obj.realAttack) obj.moveSpeed = math.floor(obj.moveSpeed) end function this.getPowerByAttr(obj) local defenseCoe = toFixed((1 / toFixed((1 - obj.defense / (obj.defense + 325)), 2)), 2) -- 法术防御系数 1 - 法术防御/(法术防御+防御常数) local spellDefenseCoe = toFixed((1 / toFixed((1 - obj.spellDefense / (obj.spellDefense + 325)), 2)), 2) --攻速系数 攻速/比例值 local attackSpeedCoe = toFixed((obj.attackSpeed / RATENUM), 2) --暴击系数 暴击伤害倍数/比例值 * 暴击率/比例值 * 2 local critCoe = toFixed((obj.critNum / RATENUM), 2) * toFixed((obj.attackCrit / RATENUM), 2)* 2 --命中系数 1/攻击CD/比例值 * 命中率/比例值 local hitCoe = toFixed((1 / toFixed((obj.attackSpeed / RATENUM), 2)), 2) * toFixed((obj.hit / RATENUM), 2) --闪避系数 1/(1-闪避率/比例值) local dodgeCoe = toFixed((1 / toFixed((1 - obj.dodge / RATENUM), 2)), 2) defenseCoe = nan_to_zero(defenseCoe) spellDefenseCoe = nan_to_zero(spellDefenseCoe) attackSpeedCoe = nan_to_zero(attackSpeedCoe) critCoe = nan_to_zero(critCoe) hitCoe = nan_to_zero(hitCoe) dodgeCoe = nan_to_zero(dodgeCoe) -- logger.trace(defenseCoe) -- logger.trace(spellDefenseCoe) -- logger.trace(attackSpeedCoe) -- logger.trace(critCoe) -- logger.trace(hitCoe) -- logger.trace(dodgeCoe) -- logger.trace(stringify(obj)) obj.power = obj.attack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 + obj.spellAttack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 + obj.HP * (1 + defenseCoe + spellDefenseCoe + dodgeCoe) * 0.8 --取地板值 obj.power = math.floor(obj.power) return obj.power end function this.buildIRole(character, hero) local RoleConfig = asset.RoleConfig_proto local iRole = {} if hero.id > 0 and not RoleConfig[hero.id] then return 0 end local baseAttr = this.buildIBaseAttr(RoleConfig[hero.id]) local talents = this.initTalentAdd(character) iRole = { cfg = RoleConfig[hero.id], hero = hero, power = 0, equips = {}, } setmetatable(iRole, {__index = baseAttr}) for k, sid in pairs(hero.equip or {}) do if sid and sid ~= "" then local equip_data = equip.equip_get(character, sid) if equip_data then iRole.equips[k] = equip_data end end end -- logger.trace(stringify(iRole.equips)) --比例值(万分比) --等级加成 1 + 等级/100 local lvAdd = 1 + toFixed(((iRole.hero.lv - 1) / 100), 2) this.setIBaseAttr(iRole, iRole.cfg, lvAdd, iRole.equips, talents) -- 物理防御系数 1 - 物理防御/(物理防御+防御常数) return this.getPowerByAttr(iRole) end function this.buildICard(character, card) local iCard local CardSkillConfig = asset.CardSkillConfig_proto if (card.id > 0 and not CardSkillConfig[card.id]) then return 0 end local baseAttr = this.buildIBaseAttr(CardSkillConfig[card.id]) iCard = { cfg= CardSkillConfig[card.id], card= card, power= 0, } -- -- -----卡牌战斗力不受装备,天赋加成---- --等级加成 1 + 等级/比例值 local lvAdd = 1 + toFixed(((iCard.card.lv - 1) / 100), 2) this.setIBaseAttr(iCard, iCard.cfg, lvAdd) return this.getPowerByAttr(iCard) end return {build_role = this.buildIRole, build_card = this.buildICard}