using System.Collections.Generic; using UnityEngine; using System; using DG.Tweening; using Spine; using System.Linq; public class SkillBase { const float moveTime = 0.5f; protected SkillEffect skillEffect; protected HB427_tagSCUseSkill tagUseSkillAttack; protected SkillConfig skillConfig; protected bool isFinished = false; protected BattleField battleField = null; // 战场 protected RectTransform targetNode = null; // 目标节点 protected BattleObject caster = null; // 施法者 protected bool startCounting = false; protected bool pauseState = false; protected int curFrame = 0; protected List packList; protected SkillRecordAction otherSkillAction; protected List dropPackList = new List(); protected List expPackList = new List(); protected bool moveFinished = false; public SkillBase(BattleObject _caster, SkillConfig _skillCfg, HB427_tagSCUseSkill vNetData, List _packList, BattleField _battleField = null) { caster = _caster; skillConfig = _skillCfg; tagUseSkillAttack = vNetData; battleField = _battleField; packList = _packList; } public virtual void Run() { if (startCounting) { curFrame++; } if (null != skillEffect) { skillEffect.Run(); } if (otherSkillAction != null) { if (otherSkillAction.IsFinished()) { otherSkillAction = null; OnSkillFinished(); } else { otherSkillAction.Run(); } } } public void Pause() { pauseState = startCounting; startCounting = false; } public void Resume() { startCounting = pauseState; } // 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身) // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类) public virtual void Cast() { EventBroadcast.Instance.Broadcast(EventName.BATTLE_CAST_SKILL, battleField.guid, skillConfig, caster.teamHero); // 高亮所有本次技能相关的目标 HighLightAllTargets(); // 距离配成负数要转身 TurnBack switch (skillConfig.castMode) { case SkillCastMode.Self: CastImpl(OnAttackFinish); break; case SkillCastMode.Enemy: CastToEnemy(); break; case SkillCastMode.Target: CastToTarget(); break; case SkillCastMode.Allies: CastToAllies(); break; case SkillCastMode.DashCast: DashCast(OnAttackFinish); break; default: Debug.LogError("强制结束技能 暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition); ForceFinished(); break; } } // 冲撞攻击 protected void DashCast(Action _onComplete) { Debug.LogError("DashCast 还没实现"); ForceFinished(); // YYL TODO // var entry = caster.motionBase.PlayAnimation(skillConfig.GetMotionName(), false); // float animationTime = entry.AnimationTime; // int mainTargetPosNum = BattleUtility.GetMainTargetPositionNum(caster, tagUseSkillAttack.HurtList.ToList(), skillConfig); // BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); // RectTransform targetTrans = battleField.GetTeamNode(battleCamp, mainTargetPosNum); // var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, targetTrans, new Vector2(skillConfig.CastDistance, 0), animationTime * 0.9f, () => // { // caster.motionBase.PlayAnimation(MotionName.idle, true); // _onComplete?.Invoke(); // }); // battleField.battleTweenMgr.OnPlayTween(tweener); } protected void MoveToTarget(RectTransform target, Vector2 offset, Action _onComplete = null) { // 原地释放 if (skillConfig.CastDistance >= 9999) { _onComplete?.Invoke(); return; } caster.motionBase.PlayAnimation(MotionName.run, true); var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, target, offset, () => { caster.motionBase.PlayAnimation(MotionName.idle, true); _onComplete?.Invoke(); }); battleField.battleTweenMgr.OnPlayTween(tweener); } protected void TurnBack(Action _onComplete, float forward) { if (skillConfig.CastDistance < 0) { // 转身 Vector3 scale = caster.heroGo.transform.localScale; scale.x = Mathf.Abs(scale.x) * forward; caster.heroGo.transform.localScale = scale; } _onComplete?.Invoke(); } protected void CastToEnemy() { RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig); MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { // 回到原来的位置 MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, OnAttackFinish); } , -1f); }); }, -1f); }); } protected void CastToTarget() { // 目标是敌方主目标 if (tagUseSkillAttack.HurtCount <= 0) { Debug.LogError("技能攻击包没有目标 HurtCount <= 0"); OnSkillFinished(); return; } int mainTargetPosNum = BattleUtility.GetMainTargetPositionNum(caster, tagUseSkillAttack.HurtList.ToList(), skillConfig); BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); RectTransform targetTrans = battleField.GetTeamNode(battleCamp, mainTargetPosNum); MoveToTarget(targetTrans, new Vector2(skillConfig.CastDistance, 0), () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { RectTransform rectTransform = battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum); // 回到原来的位置 MoveToTarget(rectTransform, Vector2.zero, OnAttackFinish); } , -1f); }); }, -1f); }); } protected virtual void OnAllAttackMoveFinished() { moveFinished = true; } protected void CastToAllies() { RectTransform target = battleField.GetTeamNode(caster.Camp, skillConfig); MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { // 回到原来的位置 MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, OnAttackFinish); } , -1f); }); }, -1f); }); } protected void OnAttackFinish() { TurnBack(null, 1f); OnAllAttackMoveFinished(); caster.motionBase.PlayAnimation(MotionName.idle, true); } // 承载技能大部分的逻辑 protected TrackEntry CastImpl(Action onComplete = null) { // 播放施法动作 // onComplete是指施法动作播放完的回调 不代表是技能结束 // 具体技能结束的时间应该看技能对应的逻辑 // 这里只提供6个动作相关的函数 // OnSkillStart 动作第一帧 // OnStartSkillFrameEnd 前摇结束 // OnMiddleFrameStart 中摇开始 // OnMiddleFrameEnd 中摇结束 // OnFinalFrameStart 后摇开始 // OnFinalFrameEnd 后摇结束 return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete); } // 技能开始 public void OnSkillStart() { skillEffect = SkillEffectFactory.CreateSkillEffect( caster, skillConfig, tagUseSkillAttack ); // if (skillEffect != null) { skillEffect.Play(OnHitTargets); } } // 技能前摇帧结束 public virtual void OnStartSkillFrameEnd() { } /// /// 中摇开始 times=第几次循环 从0开始 /// /// public virtual void OnMiddleFrameStart(int times) { // if (skillEffect != null) { skillEffect.OnMiddleFrameStart(times); } } public virtual void OnMiddleFrameEnd(int times, int hitIndex) { // if (skillEffect != null) { skillEffect.OnMiddleFrameEnd(times, hitIndex); } } /// /// 后摇开始 /// public virtual void OnFinalFrameStart() { // if (skillEffect != null) { skillEffect.OnFinalFrameStart(); } } /// /// 后摇结束 /// public virtual void OnFinalFrameEnd() { // if (skillEffect != null) { skillEffect.OnFinalFrameEnd(); } HandleDead(); } protected void HighLightAllTargets() { // 高亮所有目标 HashSet highlightList = new HashSet(battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack)); highlightList.Add(caster); // caster.battleField.skillMask // 把这些BO全高亮 或者说把除了这些的都放在遮罩后面 // YYL TODO } // 命中目标后的回调 正常是以各技能的方式来处理的 protected virtual void OnHitTargets(int _hitIndex, List hitList) { for (int i = 0; i < hitList.Count; i++) { HB427_tagSCUseSkill.tagSCUseSkillHurt hurt = hitList[i]; BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); if (target == null) { Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); continue; } OnHitEachTarget(_hitIndex, target, hurt); } } protected virtual void OnHitEachTarget(int _hitIndex, BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt) { // 伤害分布 (万分比) // Debug.LogError("skillConfig.DamageDivide.Count " + skillConfig.DamageDivide.Length + " _hitIndex " + _hitIndex); int[] damageDivide = skillConfig.DamageDivide[_hitIndex]; long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx); // 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 List damageList = BattleUtility.DivideDamageToList(damageDivide, totalDamage); // public uint ObjID; // public uint AttackTypes; // 飘血类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避 // public uint HurtHP; // 飘血值,求余亿部分 // public uint HurtHPEx; // 飘血值,整除亿部分 // public uint CurHP; // 更新剩余血量,求余亿部分 // public uint CurHPEx; // 更新剩余血量,整除亿部分 // public uint SuckHP; // 本次伤害转化的吸血量 // public uint BounceHP; // 本次伤害反弹的伤害量 // TODO YYL AttackTypes 要表现成什么样呢? 支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避 target.Hurt(damageList, totalDamage, hurt, skillConfig); // TODO YYL 这里是要做统一计算后再hurt跟suckhp还是怎样 caster.SuckHp(hurt.SuckHP, skillConfig);// 吸血 caster.HurtByReflect(hurt.BounceHP, skillConfig);// 反弹伤害 } protected void HandleDead() { var deadPackList = BattleUtility.FindDeadPack(packList); int deadCount = deadPackList.Count; if (deadCount <= 0) { // 如果没死亡就不用管 return; } CheckAfterDeadhPack(); // 处理掉落包 提前distribute之后 PackManager才有掉落物 所以不跟assignexp一样distribute foreach (var _dropPack in dropPackList) { PackageRegedit.Distribute(_dropPack); packList.Remove(_dropPack); } // 获取掉落物品 var dropPack = PackManager.Instance.GetSinglePack(PackType.DropItem); var itemDict = dropPack.GetAllItems(); List itemList = new List( from item in itemDict.Values where item != null && item.isAuction select item); // 分配掉落和经验 var dropAssign = AssignDrops(itemList, deadCount); var expAssign = AssignExp(expPackList, deadCount); // 构造 BattleDrops 并分配 for (int i = 0; i < deadCount; i++) { BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject((int)deadPackList[i].ObjID); List itemModelDrops = dropAssign[i]; List itemModelDropsIndexList = new List( from item in itemModelDrops select item.gridIndex); BattleDrops battleDrops = new BattleDrops() { rectTransform = deadTarget.heroRectTrans, dropItemPackIndex = itemModelDropsIndexList, expDrops = expAssign[i] }; deadTarget.PushDropItems(battleDrops); } // 分发死亡包 battleField.OnObjsDead(new List(deadPackList)); foreach (var deadPack in deadPackList) { packList.Remove(deadPack); } deadPackList.Clear(); } // 分配掉落 protected List> AssignDrops(List itemList, int deadCount) { var dropAssign = new List>(deadCount); for (int i = 0; i < deadCount; i++) dropAssign.Add(new List()); for (int i = 0; i < itemList.Count; i++) dropAssign[i % deadCount].Add(itemList[i]); return dropAssign; } // 分配经验:每个原始包都平均分配到每个死亡对象 protected List> AssignExp(List expList, int deadCount) { var expAssign = new List>(deadCount); for (int i = 0; i < deadCount; i++) expAssign.Add(new List()); foreach (var expPack in expList) { long totalExp = GeneralDefine.GetFactValue(expPack.Exp, expPack.ExpPoint); long avgExp = totalExp / deadCount; long remain = totalExp % deadCount; for (int i = 0; i < deadCount; i++) { long assignExp = avgExp + (i < remain ? 1 : 0); long expPoint = assignExp / 100000000; long exp = assignExp % 100000000; var newPack = new HB405_tagMCAddExp { Exp = (uint)exp, ExpPoint = (uint)expPoint, Source = expPack.Source // 保持原包来源 }; expAssign[i].Add(newPack); } packList.Remove(expPack); } return expAssign; } protected void CheckAfterDeadhPack() { List removeIndexList = new List(); for (int i = 0; i < packList.Count; i++) { var pack = packList[i]; // 复活基本都靠技能包 if (pack is CustomHB426CombinePack) { var combinePack = pack as CustomHB426CombinePack; if (combinePack.startTag.Tag.StartsWith("Skill_")) { break; // 找到技能包就不需要再处理了 } } else if (pack is H0704_tagRolePackRefresh) { var h0704Pack = pack as H0704_tagRolePackRefresh; if (h0704Pack.PackType == (byte)PackType.DropItem) { // 掉落的 if (h0704Pack.IsBind == 1) { // 掉落的物品 dropPackList.Add(h0704Pack); removeIndexList.Add(i); } else if (h0704Pack.IsBind == 0) { // 替换的 } } } else if (pack is HB405_tagMCAddExp) { var h405Pack = pack as HB405_tagMCAddExp; //B4 05 获得经验 #tagMCAddExp 通知获得的经验, //可用于做经验获得表现 Source = 2 时为主线击杀怪物获得经验 if (h405Pack.Source == 2) { expPackList.Add(h405Pack); removeIndexList.Add(i); } } } for (int i = removeIndexList.Count - 1; i >= 0; i--) { packList.RemoveAt(removeIndexList[i]); } } public virtual bool IsFinished() { if (skillEffect != null) { if (!skillEffect.IsFinished()) { return false; } else { OnSkillFinished(); skillEffect = null; } } return isFinished && moveFinished; } public virtual void ForceFinished() { skillEffect?.ForceFinished(); isFinished = true; moveFinished = true; while (packList.Count > 0) { var pack = packList[0]; packList.RemoveAt(0); if (pack is CustomHB426CombinePack) { var combinePack = pack as CustomHB426CombinePack; if (combinePack.startTag.Tag.StartsWith("Skill_")) { BattleDebug.LogError("other skill casting " + combinePack.startTag.Tag); otherSkillAction = combinePack.CreateSkillAction(); // 强制结束其他技能 otherSkillAction.ForceFinish(); return; } } PackageRegedit.Distribute(pack); } } public void OnSkillFinished() { if (skillEffect != null) { if (!skillEffect.IsFinished()) { return; } } while (packList.Count > 0) { var pack = packList[0]; packList.RemoveAt(0); if (pack is CustomHB426CombinePack) { var combinePack = pack as CustomHB426CombinePack; if (combinePack.startTag.Tag.StartsWith("Skill_")) { BattleDebug.LogError("other skill casting " + combinePack.startTag.Tag); otherSkillAction = combinePack.CreateSkillAction(); return; } } PackageRegedit.Distribute(pack); } isFinished = true; } }