-- 技能 - 时间相关 -- cd、gcd、passTime, progressTime等 local SkillTimeSystem = {} local private = {} local HERO_COMMON_CD_KEYPOS_LIST = LuaConst.HERO_COMMON_CD_KEYPOS_LIST --事件系统 local EventSystem = require('Event/EventSystem') local FP=FP local FP_Zero = FP.Const.Zero local LuaConst=LuaConst local EventID=EventID local pairs=pairs local _tempFinalSkillCD = FP.newV1(0) local _tempTimeScaleV1 = FP.newV1(0) --[[ Tick 更新所有技能的 CD、PassTime 和ProgressTime --]] function SkillTimeSystem.OnLogicUpdate(entity) local components=entity.components local comp_SkillBase = components.skillBase local curSkill = comp_SkillBase.CurSkillData if curSkill or #comp_SkillBase.CurSkillSwitchList > 0 then -- PassTime local comp_TimeScale = components.timeScale comp_SkillBase.CurLastPassTime:Reset(comp_SkillBase.CurPassTime) _tempTimeScaleV1:Reset(LuaConst.TimeSpanMs):Mul(comp_TimeScale:GetCurTimeScale()) comp_SkillBase.CurPassTime:Add(_tempTimeScaleV1) end if curSkill then local belongToSkill = entity:GetSkillData(curSkill.BelongTo) if belongToSkill.Type == LuaConst.SkillType.Enegy then local updateData = comp_SkillBase.CurUpdateDataGroup[belongToSkill.ID] if updateData and updateData.Enegy > FP_Zero then private.CutEnegy(entity, comp_SkillBase, belongToSkill, updateData) comp_SkillBase.NeedUpdateSkillCD = true end end end if comp_SkillBase.NeedUpdateSkillCD then -- 先判断是否需要更新cd再更新,用内存换cpu local haveSkillCD = 0 for characterID, group in pairs(comp_SkillBase.AllUpdateDataGroup) do local curGroup = group == comp_SkillBase.CurUpdateDataGroup for belongID, updateData in pairs(group) do --CD if FP.Greater(updateData.CD,0) then updateData.CD:Sub(LuaConst.TimeSpanMs) haveSkillCD = haveSkillCD + 1 if FP.LessEquals(updateData.CD,0) then if updateData.ChargeCount then -- 充能技能 local isFull = private.ChargeOnceOver(entity,belongID,updateData,curGroup) if isFull then --充满了 haveSkillCD = haveSkillCD - 1 end elseif updateData.Enegy then private.ExitCD(entity,belongID,updateData,curGroup) --这里不调 haveSkillCD = haveSkillCD - 1, 下面 if updateData.Enegy then 块里面调,因为需要判断多种因素 else private.ExitCD(entity,belongID,updateData,curGroup) haveSkillCD = haveSkillCD - 1 end end end if updateData.Enegy then--能量技能, 在能量没满或者进入cd的时候需要每帧都刷新,所以有特殊的 haveSkillCD = haveSkillCD + 1 if curSkill == nil or curSkill.BelongTo ~= belongID then local isFull = private.TryAddEnegy(entity, belongID, updateData, curGroup) if isFull then if FP.LessEquals(updateData.CD,0) then haveSkillCD = haveSkillCD - 1 end end end end -- ProgressTime if updateData.ProgressTime then haveSkillCD = haveSkillCD + 1 if FP.LessEquals(updateData.ProgressTime,0) then private.EnterCD(entity, belongID, updateData,curGroup, curSkill) else updateData.ProgressTime:Sub(LuaConst.TimeSpanMs) end end end end if haveSkillCD == 0 then comp_SkillBase.NeedUpdateSkillCD = false end end -- 公共CD的处理 if comp_SkillBase:GetCurCommonCD() > FP_Zero then _tempTimeScaleV1:Reset(LuaConst.TimeSpanMs):Mul(components.timeScale:GetCurTimeScale()) comp_SkillBase:CurCommonCDSub(_tempTimeScaleV1) if comp_SkillBase:GetCurCommonCD() <= FP_Zero then comp_SkillBase:ClearCurCommonCD() -- 通知界面 ↓ if private.NeedNotifyUI(entity) then local _skillDataTemp local _updateDataTemp for i,keyPos in ipairs(HERO_COMMON_CD_KEYPOS_LIST) do _skillDataTemp = comp_SkillBase:GetSkillDataByKeyPosition(keyPos) if _skillDataTemp then _updateDataTemp = comp_SkillBase.CurUpdateDataGroup[_skillDataTemp.BelongTo] if _updateDataTemp.CD <= FP_Zero and not _skillDataTemp.IgnoreCommonCD then EventSystem.Dispatch(EventID.Player_SkillCoolDown, keyPos, _updateDataTemp.CD) end end end end end end comp_SkillBase:CallAllSkillDecoratorFunc("OnLogicUpdate") end --[[ 进入攻击 --]] function SkillTimeSystem.OnAttackEnter(entity) local comp_SkillBase = entity.components.skillBase local skillData = comp_SkillBase.CurSkillData if not skillData then return end local belongID = entity:GetSkillData(comp_SkillBase.CurrentSkillID).BelongTo local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if skillData.Type == LuaConst.SkillType.Serial then --for i,skillSwitch in pairs(skillData.SkillSwitch_Table) do --old for i,skillSwitch in ipairs(comp_SkillBase:GetSkillSwitchTable(skillData.ID)) do --new local nextSkillID = skillData.ParamInt1 if skillSwitch.SwitchPutOut == nextSkillID then private.EnterProgress(entity, belongID, updateData, skillSwitch, nextSkillID, true, skillData) break end end elseif skillData.Type == LuaConst.SkillType.Charge then --充能技能需要扣除能量点,设置充能时间 private.EnterCharge(entity, belongID, updateData ,true) elseif skillData.Type == LuaConst.SkillType.Enegy then --do nothing --能量技能啥也不用干 else private.EnterCD(entity, belongID, updateData, true, skillData) end end function SkillTimeSystem.OnInterruptSkill(entity, skillData) local comp_SkillBase = entity.components.skillBase local belongID = entity:GetSkillData(skillData.ID).BelongTo local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if updateData then comp_SkillBase:GetFinalSkillCD(belongID, _tempFinalSkillCD) private.ExitProgress(entity, belongID, updateData, true) private.EnterCD(entity, belongID, updateData, true) if updateData.Enegy then --如果是能量技能被打断,则无脑开启一次刷新CD comp_SkillBase.NeedUpdateSkillCD = true end end comp_SkillBase:ClearCurSkillCacheInfo() end --time传入number, 毫秒 * 1000 (千倍毫秒) function SkillTimeSystem.SetSkillCurrentCD(entity, belongID, time, chargeCount) --需要在 SkillTimeSystem 里开接口,并且正确dispatch事件给UI层 --需要正确处理从没有cd到有cd的情况 local comp_SkillBase = entity.components.skillBase local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if updateData then local isChanged = false if FP.Greater(updateData.CD, 0) then --有CD的情况 updateData.CD[1] = time isChanged = true else if time > 0 then updateData.CD[1] = time local skillData = entity:GetSkillData(belongID) private.EnterCD(entity, belongID, updateData, true, skillData) isChanged = true end end if chargeCount then local belongSkillData = entity:GetSkillData(belongID) if belongSkillData.Type == LuaConst.SkillType.Charge then updateData.ChargeCount = chargeCount if private.NeedNotifyUI(entity) then local factor = entity.components.skillBase:GetCDReduceFactor() EventSystem.Dispatch(EventID.Player_ChargeSkillAdd, belongSkillData.KeyPosition, updateData.ChargeCount, entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData), belongSkillData.ParamInt2 * factor, FP.tonumberV1(updateData.CD)) end end end if isChanged then if private.NeedNotifyUI(entity) then local skillData = entity:GetSkillData(belongID) EventSystem.Dispatch(EventID.Player_SkillCoolDown, skillData.KeyPosition, updateData.CD) end end end end --减少指定ID技能的CD, time必须为number function SkillTimeSystem.ReduceSkillCurrentCD(entity, skillID, time) local comp_SkillBase = entity.components.skillBase local belongID = entity:GetSkillData(skillID).BelongTo local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if updateData then if FP.Greater(updateData.CD, 0) then if FP.Greater(updateData.CD,time) then updateData.CD:Sub(time) else updateData.CD:Reset(0) end if updateData.ChargeCount then if FP.LessEquals(updateData.CD, 0) then private.ChargeOnceOver(entity, belongID, updateData, true) end else if updateData.CD == FP_Zero then BattleEventSystem.OnEntitySkillExitCD(entity, belongID) end if private.NeedNotifyUI(entity) then local skillData = entity:GetSkillData(belongID) EventSystem.Dispatch(EventID.Player_SkillCoolDown,skillData.KeyPosition,updateData.CD) end end end --else --do nothing --正常情况,因为策划有时候不知道单位到底有什么技能,所以会配给多个技能减cd,有可能会试图给替换掉了的技能减CD --logging.error(LTAG.ERROR, "HYW : 试图减少不存在CD的技能的CD : " , belongID) end end --减少单位所有技能的CD,time必须为number function SkillTimeSystem.ReduceCurrentCDOfAllSkill(entity, time) local sortedSkillIDlist = entity.components.skillBase:GetSortedSkillUpdateDataKeyList() --为了保证一致性,这里遍历排序过的SkillIDList,再进行减CD for i,skillID in ipairs(sortedSkillIDlist) do SkillTimeSystem.ReduceSkillCurrentCD(entity, skillID, time) end end --百分比减少CD function SkillTimeSystem.ReduceSkillCurrentCDByPercent(entity, skillID, percent) entity.components.skillBase:GetFinalSkillCD(skillID, _tempFinalSkillCD) local comp_SkillBase = entity.components.skillBase local belongID = entity:GetSkillData(skillID).BelongTo local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if updateData then if updateData.CD > _tempFinalSkillCD then _tempFinalSkillCD:Reset(updateData.CD) end end local time = FP.tonumberV1(_tempFinalSkillCD:Mul(percent)) if time > 0 then SkillTimeSystem.ReduceSkillCurrentCD(entity, skillID, time) end end --百分比减少单位所有技能的CD function SkillTimeSystem.ReduceCurrentCDOfAllSkillByPercent(entity, percent) local sortedSkillIDlist = entity.components.skillBase:GetSortedSkillUpdateDataKeyList() for i,skillID in ipairs(sortedSkillIDlist) do SkillTimeSystem.ReduceSkillCurrentCDByPercent(entity, skillID, percent) end end -- gws:强制某个技能进入CD function SkillTimeSystem.ForceEnterCD(entity, skillIndex) SkillTimeSystem.ForceEnterCDBySkillData(entity, entity.components.skillBase:GetSkillDataBySkillIndex(skillIndex)) end function SkillTimeSystem.ForceEnterCDBySkillData(entity, skillData) if skillData then local belongID = skillData.BelongTo local comp_SkillBase = entity.components.skillBase local updateData = comp_SkillBase.CurUpdateDataGroup[belongID] if updateData then private.ExitProgress(entity, belongID, updateData, true) -- 连续技能退出 private.EnterCD(entity, belongID, updateData, true) --清理下SkillSwitch,防止连续技能CD好了后释放出后段的技能 if skillData.Type == LuaConst.SkillType.Serial then local list = comp_SkillBase.CurSkillSwitchList for i = #list, 1, -1 do --new if list[i].SwitchPutIn == skillData.KeyPosition then table.remove(list, i) end end end end end end --[[ 进入CD --]] function private.EnterCD(entity, belongID, updateData, curGroup, curSkillData) repeat if not updateData then break end local belongSkillData = entity:GetSkillData(belongID) local skillBaseComp = entity.components.skillBase -- 如果是连续技能则需要清除其数据 if belongSkillData.Type == LuaConst.SkillType.Serial then private.ExitProgress(entity, belongID, updateData, curGroup, curSkillData) end if FP.Greater(updateData.CD,0) then entity.components.skillBase.NeedUpdateSkillCD = true break end if GlobalBattleData.Get_IsSkillNoCD() and entity._logicInitData.IsPlayerSelf then break end entity.components.skillBase:GetFinalSkillCD(belongID, _tempFinalSkillCD) if FP.Greater(_tempFinalSkillCD,0) then updateData.CD:Reset(_tempFinalSkillCD) skillBaseComp.NeedUpdateSkillCD = true if belongSkillData.KeyPosition > 1 and belongSkillData.KeyPosition < 9 then -- LuaConst.ESkillKeyPosition的枚举 BattleEventSystem.OnEntitySkillEnterCDOrCharge(entity, curSkillData or belongSkillData) end if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_SkillCoolDown,belongSkillData.KeyPosition,updateData.CD) end end until true end function private.ExitCD(entity, belongID, updateData,curGroup) if not updateData then return end updateData.CD:Reset(0) BattleEventSystem.OnEntitySkillExitCD(entity, belongID) if private.NeedNotifyUI(entity) and curGroup then local skillData = entity:GetSkillData(belongID) if skillData.IgnoreCommonCD or entity.components.skillBase.CurCommonCD <= FP_Zero then EventSystem.Dispatch(EventID.Player_SkillCoolDown, skillData.KeyPosition, nil) end end end -- 连续技能使用的更新数据方法 function private.EnterProgress(entity, belongID, updateData, skillSwitch, nextSkillID, curGroup, skillData) if not updateData then return end local belongSkill = entity:GetSkillData(belongID) local time = skillSwitch.SwitchDuration + skillSwitch.SwitchStartTime if FP.Greater(time,0) then if skillData.AutoNextConditionStr == "pointerUp" then -- gws:比较临时的方案,防止类似马超蓄力技能,当网络不稳定时cmd堆积到一帧里面,蓄力技能释放不出来。最好是为蓄力技能单独开启一个技能类型,写特定逻辑。 time:Reset(9999999) -- gws: 目的是为了防止丢失cmd时,不进入到CD中。这样做后还存在的问题1:若策划配置的后摇时间比技能时长只少n帧,而cmd堆积量(一般不会多余4)大于n帧时,还是会出现下段技能释放不出来的问题。 end -- 问题2: 如果策划想蓄力10帧进入下一段技能,在切换技能时出现n个无cmd的帧,则会导致蓄力时间变长n帧(一般在3帧以内)。 updateData.ProgressTime = time updateData.CurSerialNextSkillID = nextSkillID entity.components.skillBase.NeedUpdateSkillCD = true if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_SkillProgress,belongSkill.KeyPosition,updateData.ProgressTime,skillData) if belongSkill.KeyPosition == skillData.KeyPosition then EventSystem.Dispatch(EventID.Player_BelongSkillProgress,belongSkill,skillData, entity) end end end end function private.ExitProgress(entity, belongID, updateData, curGroup, curSkillData) if not updateData then return end local belongSkill = entity:GetSkillData(belongID) updateData.ProgressTime = nil updateData.CurSerialNextSkillID = nil if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_SkillProgress,belongSkill.KeyPosition,nil) EventSystem.Dispatch(EventID.Player_BelongSkillProgress,belongSkill, nil) end end --clearAllCharge 是否清除所有充能点 function SkillTimeSystem.ForceEnterCharge(entity, belongID, updateData, curGroup, clearAllCharge) if updateData.ChargeCount == 0 then local belongSkillData = entity:GetSkillData(belongID) local factor = entity.components.skillBase:GetCDReduceFactor() updateData.CD:Reset(belongSkillData.ParamInt2):Mul(factor) if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_ChargeSkillSub, belongSkillData.KeyPosition, updateData.ChargeCount, entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData), belongSkillData.ParamInt2 * factor, FP.tonumberV1(updateData.CD)) end else private.EnterCharge(entity, belongID, updateData, curGroup) end end function private.EnterCharge(entity, belongID, updateData ,curGroup) if GlobalBattleData.Get_IsSkillNoCD() and entity._logicInitData.IsPlayerSelf then return end local belongSkillData = entity:GetSkillData(belongID) local factor = entity.components.skillBase:GetCDReduceFactor() if updateData.ChargeCount == entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData) then updateData.CD:Reset(belongSkillData.ParamInt2):Mul(factor) -- 注意还存在着技能cd, 不能丢弃 end updateData.ChargeCount = updateData.ChargeCount - 1 entity.components.skillBase.NeedUpdateSkillCD = true if belongSkillData.KeyPosition > 1 and belongSkillData.KeyPosition < 9 then -- LuaConst.ESkillKeyPosition的枚举 BattleEventSystem.OnEntitySkillEnterCDOrCharge(entity, belongSkillData) end if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_ChargeSkillSub,belongSkillData.KeyPosition, updateData.ChargeCount, entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData), belongSkillData.ParamInt2 * factor, FP.tonumberV1(updateData.CD)) end --print("使用 --- 点数 " ,updateData.ChargeCount ," ,时间 :" ,updateData.CD[1]/1000) end -- 充能一次结束 function private.ChargeOnceOver(entity, belongID, updateData ,curGroup) updateData.CD:Reset(0) updateData.ChargeCount = updateData.ChargeCount + 1 local belongSkillData = entity:GetSkillData(belongID) local isFull = updateData.ChargeCount == entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData) local factor = entity.components.skillBase:GetCDReduceFactor() if not isFull then updateData.CD:Reset(belongSkillData.ParamInt2):Mul(factor) end if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_ChargeSkillAdd, belongSkillData.KeyPosition, updateData.ChargeCount, entity.components.skillBase:GetMaxChargeCountOfSkillData(belongSkillData) ,belongSkillData.ParamInt2 * factor, FP.tonumberV1(updateData.CD)) end --print(" 充电 --- 点数 " ,updateData.ChargeCount ," ,时间 :" ,updateData.CD[1]/1000) return isFull end function SkillTimeSystem.ClearEnegy(entity, skillData, updateData, curGroup) updateData.Enegy:Reset(0); local comp_SkillBase = entity.components.skillBase private.CutEnegy(entity, comp_SkillBase, skillData, updateData, curGroup) comp_SkillBase.NeedUpdateSkillCD = true end function private.CutEnegy(entity, comp_SkillBase, skillData, updateData, curGroup) if updateData.Enegy > FP_Zero then updateData.Enegy:Sub(comp_SkillBase:GetEnegyCutOfSkill(skillData)) if updateData.Enegy < FP_Zero then updateData.Enegy:Reset(0) end local BattleEffect = require("Battle/Logic/BattleEffect/BattleEffect") local params = {target = entity} BattleEffect.SetWantRotateToSkillJoystickDir(params) if private.NeedNotifyUI(entity) then EventSystem.Dispatch(EventID.Player_SkillEnegyChanged, skillData.KeyPosition, updateData.Enegy, comp_SkillBase:GetMaxEnegyOfSkillData(skillData), true) end end end function private.TryAddEnegy(entity, belongID, updateData, curGroup) local isFull = true local belongSkillData = entity:GetSkillData(belongID) local maxEnegy = entity.components.skillBase:GetMaxEnegyOfSkillData(belongSkillData) if FP.tonumberV1(updateData.Enegy) < maxEnegy then updateData.Enegy:Add(1) if FP.tonumberV1(updateData.Enegy) > maxEnegy then updateData.Enegy:Reset(maxEnegy) else isFull = false end if private.NeedNotifyUI(entity) and curGroup then EventSystem.Dispatch(EventID.Player_SkillEnegyChanged, belongSkillData.KeyPosition, updateData.Enegy, maxEnegy) end end return isFull end function private.NeedNotifyUI(entity) if entity == BattleDataGetter.GetCurSkillUIEntity() then return true end return false end return SkillTimeSystem