c1_lua/lua/app/userdata/hero/hero_entity.lua
2025-09-12 15:11:47 +08:00

791 lines
19 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local HeroEntity = class("HeroEntity", BaseData)
local ATTR_NAME = GConst.BattleConst.ATTR_NAME
function HeroEntity:ctor(cfgId, lv, skin, star)
self.cfgId = cfgId
self.data.isDirty = false
self.data.lv = lv
self.data.skin = skin
self.data.star = star or 0
self.config = ConfigManager:getConfig("hero")[self.cfgId]
self.beginLv = 1 -- 激活等级
self.isNew = false
self.baseAttrOriginal = {}
self.starAttr = {}
self.skinAttr = {}
self.allBaseAttr = {}
self.allAttr = {}
self.attrDirty = true
self.attrBaseDirty = true
end
-- region 属性
function HeroEntity:initAttr()
self:setTotalAttrValue(ATTR_NAME.HP, 0)
self:setTotalAttrValue(ATTR_NAME.ATK, 0)
self:setTotalAttrValue(ATTR_NAME.ATK_RED, 0)
self:setTotalAttrValue(ATTR_NAME.ATK_YELLOW, 0)
self:setTotalAttrValue(ATTR_NAME.ATK_GREEN, 0)
self:setTotalAttrValue(ATTR_NAME.ATK_BLUE, 0)
self:setTotalAttrValue(ATTR_NAME.ATK_PURPLE, 0)
self:_updateAllBaseAttr()
end
function HeroEntity:onBaseAttrChange()
self:_updateBaseAttr()
self:_updateTotalAttr()
self:setDirty()
end
function HeroEntity:onStarAttrChange()
self:_updateStarAttr()
self:_updateTotalAttr()
self:setDirty()
end
function HeroEntity:onSkinAttrChange()
self:_updateSkinAttr()
self:_updateTotalAttr()
self:setDirty()
end
function HeroEntity:setDirty()
self.data.isDirty = not self.data.isDirty
end
function HeroEntity:setAttrDirty()
self.attrDirty = true
end
function HeroEntity:setBaseAttrDirty()
self.attrBaseDirty = true
end
function HeroEntity:getAllAttr()
if self.attrDirty == true then
self.attrDirty = false
self:_updateAllAttr()
end
return self.allAttr
end
-- 更新所有属性(包括其他英雄的加成)
function HeroEntity:_updateAllAttr()
self.allAttr = {}
self.allBaseAttr = self:_getAllBaseAttr()
for k, v in pairs(self.allBaseAttr) do
self.allAttr[k] = v
end
self.allAttr[GConst.MATCH_ALL_ATKP_NAME[self:getMatchType()]] = nil
-- 攻击力(百分比)
local atkType = GConst.MATCH_ATTACK_NAME[self:getMatchType()]
local atkpType = GConst.MATCH_ALL_ATKP_NAME[self:getMatchType()]
local factorValue = DataManager.HeroData:getAttrByMatchType(self:getMatchType(), atkpType)
if factorValue > 0 then
self.allAttr[atkType] = math.floor(self.allAttr[atkType] * (1 + factorValue / GConst.DEFAULT_FACTOR) + 0.0000001)
end
self:calcPower()
end
function HeroEntity:_getAllBaseAttr()
if self.attrBaseDirty == true then
self.attrBaseDirty = false
self:_updateAllBaseAttr()
end
return self.allBaseAttr
end
-- 更新所有属性(自己)
function HeroEntity:_updateAllBaseAttr()
self:_updateBaseAttr()
self:_updateStarAttr()
self:_updateSkinAttr()
self:_updateTotalAttr()
if self.allBaseAttr[GConst.MATCH_ALL_ATKP_NAME[self:getMatchType()]] ~= nil then
local attr = {}
attr[GConst.MATCH_ALL_ATKP_NAME[self:getMatchType()]] = self.allBaseAttr[GConst.MATCH_ALL_ATKP_NAME[self:getMatchType()]]
DataManager.HeroData:setHeroAttr(self:getCfgId(), attr)
end
end
-- 更新英雄基础属性
function HeroEntity:_updateBaseAttr()
self.baseAttrOriginal[ATTR_NAME.HP] = self:getCfgHp()
self.baseAttrOriginal[ATTR_NAME.ATK_RED] = 0
self.baseAttrOriginal[ATTR_NAME.ATK_YELLOW] = 0
self.baseAttrOriginal[ATTR_NAME.ATK_GREEN] = 0
self.baseAttrOriginal[ATTR_NAME.ATK_BLUE] = 0
self.baseAttrOriginal[ATTR_NAME.ATK_PURPLE] = 0
self.baseAttrOriginal[GConst.MATCH_ATTACK_NAME[self.config.position]] = self:getCfgAtk()
end
-- 更新皮肤属性
function HeroEntity:_updateStarAttr()
self.starAttr = {}
for i = 1, self.data.star do
local attr = self:getStarAttrCfg()[i]
self.starAttr[attr.type] = attr.num
end
end
function HeroEntity:getStarAttr()
return self.starAttr
end
-- 更新皮肤属性
function HeroEntity:_updateSkinAttr()
self.skinAttr = {}
-- local hp = DataManager.SkinData:getHp(self)
-- local atk = DataManager.SkinData:getAttack(self)
-- local normalHurt = DataManager.SkinData:getNormalHurt(self)
-- local skillHurt = DataManager.SkinData:getSkillHurt(self)
-- local critPer = DataManager.SkinData:getCritPercent(self)
-- local critHurtPer = DataManager.SkinData:getCritHurtPercent(self)
-- local normalHurtPer = DataManager.SkinData:getNormalHurtPercent(self)
-- local skillHurtPer = DataManager.SkinData:getSkillHurtPercent(self)
-- local healPer = DataManager.SkinData:getHealPercent(self)
-- self.skinAttr[GConst.MATCH_HP_NAME[self:getMatchType()]] = hp
-- self.skinAttr[GConst.MATCH_ATTACK_NAME[self:getMatchType()]] = atk
-- self.skinAttr[GConst.MATCH_NORMAL_HURT_NAME[self:getMatchType()]] = normalHurt
-- self.skinAttr[GConst.MATCH_SKILL_HURT_NAME[self:getMatchType()]] = skillHurt
-- self.skinAttr[GConst.MATCH_CRIT_NAME[self:getMatchType()]] = critPer
-- self.skinAttr[GConst.MATCH_CRIT_TIME_NAME[self:getMatchType()]] = critHurtPer
-- self.skinAttr[GConst.MATCH_NORMAL_HURTP_NAME[self:getMatchType()]] = normalHurtPer
-- self.skinAttr[GConst.MATCH_SKILL_HURTP_NAME[self:getMatchType()]] = skillHurtPer
-- self.skinAttr[GConst.MATCH_CURED_NAME[self:getMatchType()]] = healPer
-- if EDITOR_MODE then
-- local printStr = ""
-- printStr = printStr .. "更新皮肤数值:"..self:getCfgId() .. "\n"
-- printStr = printStr .. "生命:".. hp .. "\n"
-- printStr = printStr .. "攻击力:".. atk .. "\n"
-- printStr = printStr .. "普攻增伤:".. normalHurt .. "\n"
-- printStr = printStr .. "技能增伤:".. skillHurt .. "\n"
-- printStr = printStr .. "暴击率:".. critPer .. "\n"
-- printStr = printStr .. "暴击伤害百分比:".. critHurtPer .. "\n"
-- printStr = printStr .. "普攻增伤百分比:".. normalHurtPer .. "\n"
-- printStr = printStr .. "技能增伤百分比:".. skillHurtPer .. "\n"
-- printStr = printStr .. "治疗加成百分比:".. healPer .. "\n"
-- Logger.logHighlight(printStr)
-- end
end
-- 更新总属性
function HeroEntity:_updateTotalAttr()
self.allBaseAttr = {}
for k, v in pairs(self.baseAttrOriginal) do
self:setTotalAttrValue(k, v)
end
for k, v in pairs(self.starAttr) do
self:addTotalAttrValue(k, v)
end
for k, v in pairs(self.skinAttr) do
self:addTotalAttrValue(k, v)
end
end
function HeroEntity:setTotalAttrValue(name, value)
-- Logger.logHighlight("set "..name..":"..value)
self.allBaseAttr[name] = GFunc.encryptNumber(value or 0)
end
function HeroEntity:addTotalAttrValue(name, add)
-- Logger.logHighlight("add "..name..":"..add)
local before = self:getTotalAttrValue(name)
self.allBaseAttr[name] = GFunc.encryptNumber(before + (add or 0))
end
function HeroEntity:getTotalAttrValue(name)
if table.nums(self.allBaseAttr) <= 0 then
self:initAttr()
end
if not self.allBaseAttr[name] then
return 0
end
-- Logger.logHighlight("get "..name..":"..GFunc.decryptNumber(self.allBaseAttr[name]))
return GFunc.decryptNumber(self.allBaseAttr[name])
end
-- 获取总基础生命值(英雄+装备+皮肤)
function HeroEntity:getTotalBaseHp()
local result = self:isActived() and self:getCfgHp() or self:getCfgHp(self:getBeginLv())
result = result + DataManager.SkinData:getBaseHp(self)
return result
end
-- 获取总基础攻击值(英雄+装备+皮肤)
function HeroEntity:getTotalBaseAtk()
local result = self:isActived() and self:getCfgAtk() or self:getCfgAtk(self:getBeginLv())
-- local logStr = self:getCfgId() .. "总基础攻击值:\n英雄" .. result
-- 武器 + 防具
-- for partName, partType in pairs(GConst.EquipConst.PART_TYPE) do
-- local HeroEntity = self:getEquips(partType)
-- if HeroEntity then
-- -- logStr = logStr .. "\n" .. partName .. "" .. HeroEntity:getBaseAttack()
-- result = result + HeroEntity:getBaseAttack()
-- end
-- end
-- logStr = logStr .. "\nSKIN" .. DataManager.SkinData:getBaseAttack(self)
result = result + DataManager.SkinData:getBaseAttack(self)
-- Logger.logHighlight(logStr)
return result
end
function HeroEntity:getAtk()
local atkName = GConst.MATCH_ATTACK_NAME[self:getMatchType()]
local atkAddName = GConst.MATCH_ATTACK_ADD_NAME[self:getMatchType()]
return self:getTotalAttrValue(atkName) + self:getTotalAttrValue(atkAddName)
end
function HeroEntity:getHp()
local hpName = ATTR_NAME.HP
local hpAddName = GConst.MATCH_HP_ADD_NAME[self:getMatchType()]
return self:getTotalAttrValue(hpName) + self:getTotalAttrValue(hpAddName)
end
function HeroEntity:getCfgHp(lv)
lv = lv or self.data.lv
if lv > self:getMaxLv() then
lv = self:getMaxLv()
end
if self.config and self.config.hp then
return self.config.hp[lv] or 0
end
return 0
end
function HeroEntity:getCfgAtk(lv)
lv = lv or self.data.lv
if lv > self:getMaxLv() then
lv = self:getMaxLv()
end
if self.config and self.config.atk then
return self.config.atk[lv] or 0
end
return 0
end
-- endregion
-- region 基础
function HeroEntity:setLv(lv, onlyChangeLv)
if not lv then
return
end
if self.data.lv == lv then
return
end
self.isNew = lv == 1
self.oldLv = self.data.lv
self.data.lv = lv
self:_updateAllBaseAttr()
self:setDirty()
self:setAttrDirty()
if not onlyChangeLv then
ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_HERO_LV_UP, lv)
EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.HERO_UPGRADE_SUCCESS, self:getCfgId())
end
end
function HeroEntity:getIsNew()
local isNew = self.isNew
self.isNew = false
return isNew
end
function HeroEntity:getLv()
return self.data.lv
end
function HeroEntity:getBeginLv()
return self.beginLv
end
function HeroEntity:isMaxLv()
return self.data.lv >= self:getMaxLv()
end
function HeroEntity:getMaxLv()
if not self.maxLv then
self.maxLv = ConfigManager:getConfigNum("hero_level")
end
return self.maxLv
end
function HeroEntity:getCurrMaxLv()
local cfg = ConfigManager:getConfig("hero_level")
local lv = self.data.lv
if lv <= 0 then
return 1
end
for i = self.data.lv, #cfg do
if cfg[i].star > self.data.star then
break
else
lv = i
end
end
return lv
end
function HeroEntity:getNextMaxLv()
local cfg = ConfigManager:getConfig("hero_level")
local lv = self.data.lv
for i = self.data.lv + 1, #cfg do
if self.data.star + 1 >= cfg[i].star then
lv = i
else
break
end
end
return lv
end
function HeroEntity:getNextLv()
local cfg = ConfigManager:getConfig("hero_level")
local lv = self.data.lv
for i = self.data.lv + 1, #cfg do
if self.data.star >= cfg[i].star then
lv = i
else
break
end
end
return lv
end
function HeroEntity:getIsCurLvMax()
if self:isMaxLv() then
return true
end
local cfg = ConfigManager:getConfig("hero_level")[self.data.lv + 1]
if not cfg then
return true
end
return self.data.star < cfg.star
end
function HeroEntity:canLvUp(showToast)
if self:isMaxLv() then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.MAX_LV
end
if self:getIsCurLvMax() then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.NEED_STAR
end
local cost = self:getLvUpMaterials()
if not cost then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.NO_COST
end
local fragmentCost = cost[1] or 0
if not GFunc.checkCost(self:getFragmentId(), fragmentCost, showToast) then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.FRAGMENT_NOT_ENOUGH
end
local goldCost = cost[2] or 0
if not GFunc.checkCost(self:getLvUpCostId(), goldCost, showToast) then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.COIN_NOT_ENOUGH
end
return true, GConst.HeroConst.CHECK_LV_UP_STATE.SUCCESS
end
function HeroEntity:isUnlock()
if self:isActived() then
return true
else
if self:canLvUp() then
return true
end
end
return false
end
function HeroEntity:isActived()
return self.data.lv >= self:getBeginLv()
end
function HeroEntity:getLvUpMaterials()
local lv = self.data.lv + 1
if lv < self:getBeginLv() then
lv = self:getBeginLv()
end
local nextLvInfo = ConfigManager:getConfig("hero_level")[lv]
if not nextLvInfo then
return
end
-- local fieldName = "cost_" .. self:getQlt()
return nextLvInfo.cost
end
function HeroEntity:getLvUpLv()
local count = 0
local totalCost1 = 0
local totalCost2 = 0
local nextLv = self:getNextLv()
for i = 1, 5 do
if self.data.lv + i > nextLv then
break
end
local lv = self.data.lv + i
local nextLvInfo = ConfigManager:getConfig("hero_level")[lv]
if not nextLvInfo then
break
end
local fragmentCost = nextLvInfo.cost[1] or 0
local itemCost = nextLvInfo.cost[2] or 0
totalCost1 = totalCost1 + fragmentCost
totalCost2 = totalCost2 + itemCost
if not GFunc.checkCost(self:getFragmentId(), totalCost1, false) then
break
end
if not GFunc.checkCost(self:getLvUpCostId(), totalCost2, false) then
break
end
count = count + 1
end
return count + self.data.lv, count ~= 0
end
-- endregion
-- region 配置
function HeroEntity:getConfig()
return self.config
end
function HeroEntity:getModelId()
-- local skinModel = DataManager.SkinData:getModelId(self:getSkinId())
-- return skinModel or self.config.model_id
return self.config.model_id
end
function HeroEntity:getBaseSkill()
return self.config.base_skill
end
function HeroEntity:getHurtSkill()
return self.config.hurt_skill
end
function HeroEntity:getFragmentId()
return self.config.item_id
end
function HeroEntity:getIcon()
return self.config.icon
end
function HeroEntity:getHurtNum()
return self.config.hurt_num
end
function HeroEntity:getLvUpCostId()
return self.config.level_id
end
function HeroEntity:getCfgId()
return self.cfgId
end
function HeroEntity:getName()
return ModuleManager.HeroManager:getHeroName(self:getCfgId())
end
function HeroEntity:getDesc()
return ModuleManager.HeroManager:getHeroDesc(self:getCfgId())
end
function HeroEntity:getQlt()
return self.config.qlt
end
function HeroEntity:getMatchType()
return self.config.position
end
function HeroEntity:getStarUpCostId()
return self.config.star_id
end
function HeroEntity:getStarAttrCfg(star)
if star then
return self.config.star_attr[star]
end
return self.config.star_attr
end
function HeroEntity:getStarAttrTxt()
return self.config.star_txt
end
-- endregion
-- function HeroEntity:getActiveRogueCount()
-- local lvInfo = ConfigManager:getConfig("hero_level")[self.data.lv]
-- if not lvInfo then
-- return 0
-- end
-- --@TODO 123123
-- -- return lvInfo.unlock_skill
-- return 0
-- end
-- region 技能
function HeroEntity:getUnlockRogueId()
return self.config.rouge_skill
end
function HeroEntity:checkSkillUnlock()
if not self.oldLv then
return false
end
local needPop = false
local isUnlock = false
local skillIdx = 1
for i = 1, 4 do
local ids = self.config["rouge_skill_" .. i]
if ids then
for ii = #ids, 1, -1 do
if self.data.lv >= ids[ii][1] and self.oldLv < ids[ii][1] then
skillIdx = i
needPop = true
isUnlock = ii == 1
break
end
end
else
break
end
if needPop then
break
end
end
self.oldLv = nil
return needPop, isUnlock, skillIdx
end
function HeroEntity:getRogueSkillList()
if not self.rogueSkillList then
self.rogueSkillList = {}
local count = 1
while true do
local ids = self.config["rouge_skill_" .. count]
if ids then
for i = #ids, 1, -1 do
if self.data.lv >= ids[i][1] or i == 1 then
table.insert(self.rogueSkillList, ids[i])
break
end
end
else
break
end
count = count + 1
end
end
return self.rogueSkillList
end
function HeroEntity:getRogueSkillListByIdx(idx)
local ids = self.config["rouge_skill_" .. idx]
local lv = 0
if ids then
for i = #ids, 1, -1 do
if self.data.lv >= ids[i][1]then
lv = i
break
end
end
end
return ids, lv
end
function HeroEntity:getNextRougeLvUp(idx)
local ids = self.config["rouge_skill_" .. idx]
if ids then
for i,v in ipairs(ids) do
if self.data.lv < ids[i][1] then
return ids[i][1]
end
end
end
end
function HeroEntity:getActiveRogueSkills()
local list = {}
local count = 1
while true do
local ids = self.config["rouge_skill_" .. count]
if ids then
for i = #ids, 1, -1 do
if self.data.lv >= ids[i][1] then
table.insert(list, ids[i][2])
break
end
end
else
break
end
count = count + 1
end
return list
end
-- endregion
-- region 升星相关
function HeroEntity:getStar()
return self.data.star
end
function HeroEntity:getIsStarMax()
local nextLvInfo = ConfigManager:getConfig("hero_star")[self.data.star + 1]
if not nextLvInfo then
return true
end
return false
end
function HeroEntity:getStarUpMaterials()
local nextLvInfo = ConfigManager:getConfig("hero_star")[self.data.star + 1]
if not nextLvInfo then
return
end
local fieldName = "cost_" .. self:getQlt()
return nextLvInfo[fieldName]
end
function HeroEntity:canStarUp(showToast)
if self:getIsStarMax() then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.MAX_LV
end
if not self:getIsCurLvMax() then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.NEED_LV
end
local cost = self:getStarUpMaterials()
if not cost then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.NO_COST
end
local fragmentCost = cost[1] or 0
if not GFunc.checkCost(self:getFragmentId(), fragmentCost, showToast) then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.FRAGMENT_NOT_ENOUGH
end
local itemCost = cost[2] or 0
if not GFunc.checkCost(self:getStarUpCostId(), itemCost, showToast) then
return false, GConst.HeroConst.CHECK_LV_UP_STATE.COIN_NOT_ENOUGH
end
return true, GConst.HeroConst.CHECK_LV_UP_STATE.SUCCESS
end
function HeroEntity:onHeroStarUp()
self.data.star = self.data.star + 1
self:setBaseAttrDirty()
self:setDirty()
self:setAttrDirty()
end
function HeroEntity:getMaxStar()
return #self:getStarAttrCfg()
end
-- endregion
-- region 皮肤相关
-- 获取当前穿戴皮肤
function HeroEntity:getSkinId()
if self.data.skin == nil or self.data.skin == 0 then
return DataManager.SkinData:getOriginSkinId(self:getCfgId())
end
return self.data.skin
end
-- 穿戴皮肤
function HeroEntity:onChangeSkin(skinId)
self.data.skin = skinId
self:setDirty()
end
function HeroEntity:getSkins()
return self.unlockSkins
end
function HeroEntity:setSkins(skinIds)
self.unlockSkins = skinIds
self:getTotalAttrValue() -- 防止报错
self:onSkinAttrChange()
end
-- endregion
--@region 战力
function HeroEntity:setPowerDirty()
self.data.isPowerDirty = not self.data.isPowerDirty
end
function HeroEntity:getPower()
if not self.curPower or self.attrDirty then
self:getAllAttr()
end
return self.curPower
end
-- 计算战斗力
function HeroEntity:calcPower()
if self.lastPower then
self.lastPower = self.curPower
end
self.curPower = math.floor(self:_getAttrPower())
if not self.lastPower then
self.lastPower = self.curPower
end
if self.lastPower ~= self.curPower then
self:setPowerDirty()
end
end
function HeroEntity:_getAttrPower()
local power = 0
for attrName, attrNum in pairs(self:getAllAttr()) do
local cfg = GFunc.getAttrNameCfg()[attrName]
if cfg then
local realValue = attrNum
-- 特殊处理,玩家基础暴击伤害不算
if attrName == GConst.BattleConst.ATTR_NAME.CRIT_TIME then
realValue = attrNum - 15000
end
power = power + math.floor(realValue * cfg.power / GConst.DEFAULT_FACTOR + 0.0000001)
end
end
return power
end
--@endregion
--@region 红点
function HeroEntity:showRedPointEntrance()
return self:canLvUp() or self:canStarUp()
end
function HeroEntity:showRedPoint(page)
if page == GConst.HeroConst.PANEL_TYPE.HERO then
return self:canLvUp()
elseif page == GConst.HeroConst.PANEL_TYPE.STAR then
return self:canStarUp()
end
end
--@endregion
return HeroEntity