using System.Collections.Generic;
|
using UnityEngine;
|
using System;
|
using DG.Tweening;
|
using Spine;
|
|
|
public class SkillBase
|
{
|
protected H0604_tagUseSkillAttack 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<GameNetPackBasic> packList;
|
|
protected SkillBase otherSkill;
|
|
protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>();
|
|
protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>();
|
|
public SkillBase(BattleObject _caster, SkillConfig _skillCfg, H0604_tagUseSkillAttack vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null)
|
{
|
caster = _caster;
|
skillConfig = _skillCfg;
|
tagUseSkillAttack = vNetData;
|
battleField = _battleField;
|
packList = _packList;
|
|
}
|
|
public virtual void Run()
|
{
|
if (startCounting)
|
{
|
curFrame++;
|
}
|
}
|
|
protected virtual void OnActiveSkillFrame()
|
{
|
|
}
|
|
protected virtual void OnStartSkillFrame()
|
{
|
|
}
|
|
protected virtual void OnEndSkillFrame()
|
{
|
|
}
|
|
public void Pause()
|
{
|
pauseState = startCounting;
|
startCounting = false;
|
}
|
|
public void Resume()
|
{
|
startCounting = pauseState;
|
}
|
|
// 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身)
|
// 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类)
|
public virtual void Cast()
|
{
|
// 高亮所有本次技能相关的目标
|
HighLightAllTargets();
|
|
// 距离配成负数要转身 TurnBack
|
|
switch (skillConfig.castMode)
|
{
|
case SkillCastMode.Self:
|
PlayCastAnimation(() => DoSkillLogic(OnSkillFinished));
|
break;
|
case SkillCastMode.Enemy:
|
MoveToTarget(caster.GetEnemyCamp(), skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
|
break;
|
case SkillCastMode.Target:
|
// 目标是敌方主目标
|
BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.AttackID);
|
if (mainTarget == null)
|
{
|
Debug.LogError("目标为空 mainTarget == null AttackID : " + tagUseSkillAttack.AttackID);
|
OnSkillFinished();
|
return;
|
}
|
MoveToTarget(mainTarget.Camp, mainTarget, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
|
break;
|
case SkillCastMode.Allies:
|
MoveToTarget(caster.Camp, skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
|
break;
|
// case SkillCastMode.DashCast:
|
// DashToTarget(() => BackToOrigin(OnSkillFinished));
|
// break;
|
default:
|
Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划");
|
break;
|
}
|
}
|
|
// 冲刺的技能 动作 跟移动 是同时进行的 移动到目标的一瞬间就要进行技能逻辑
|
// protected void DashToTarget(Action _onComplete)
|
// {
|
// TrackEntry entry = PlayCastAnimation();
|
// BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.AttackID);
|
// if (mainTarget == null)
|
// {
|
// Debug.LogError("目标为空 mainTarget == null AttackID : " + tagUseSkillAttack.AttackID);
|
// _onComplete?.Invoke();
|
// return;
|
// }
|
|
// // 做一个微微的提前
|
// MoveToTarget(mainTarget.Camp, mainTarget.teamHero.positionNum, entry.AnimationEnd - 0.05f, () => DoSkillLogic(_onComplete));
|
// }
|
|
// 这里其实是技能后摇结束的地方
|
protected virtual void DoSkillLogic(Action _onComplete = null)
|
{
|
|
}
|
|
protected TrackEntry PlayCastAnimation(Action onComplete = null)
|
{
|
// 播放施法动作
|
return caster.motionBase.PlaySkillAnimation(skillConfig, onComplete,
|
OnStartSkillFrame,//攻击前摇结束
|
OnActiveSkillFrame);//攻击中摇结束
|
}
|
|
public void MoveToTarget(BattleCamp camp, BattleObject target, float duration = 0.2f, Action _onComplete = null)
|
{
|
targetNode = battleField.GetTeamNode(camp, target);
|
|
Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
|
RectTransform selfRect = caster.heroRectTrans;
|
RectTransform targetRect = targetNode;
|
|
var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
|
battleField.battleTweenMgr.OnPlayTween(tweener);
|
}
|
|
public void MoveToTarget(BattleCamp camp, SkillConfig skillCfg, float duration = 0.2f, Action _onComplete = null)
|
{
|
targetNode = battleField.GetTeamNode(camp, skillCfg);
|
|
Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
|
RectTransform selfRect = caster.heroRectTrans;
|
RectTransform targetRect = targetNode;
|
|
var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
|
battleField.battleTweenMgr.OnPlayTween(tweener);
|
}
|
|
public void TurnBack(Action _onComplete)
|
{
|
if (skillConfig.CastDistance < 0)
|
{
|
// 转身
|
caster.heroGo.transform.localScale = new Vector3(-1, 1, 1);
|
}
|
_onComplete?.Invoke();
|
}
|
|
public void BackToOrigin(Action _onComplete = null)
|
{
|
RectTransform selfRect = caster.heroRectTrans;
|
Vector2 targetAnchoredPos = Vector2.zero;
|
var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f)
|
.SetEase(Ease.Linear)
|
.OnComplete(() =>
|
{
|
// 转成正确方向
|
caster.heroGo.transform.localScale = Vector3.one;
|
_onComplete?.Invoke();
|
});
|
|
battleField.battleTweenMgr.OnPlayTween(tween);
|
}
|
|
protected void HighLightAllTargets()
|
{
|
// 高亮所有目标
|
HashSet<BattleObject> highlightList = new HashSet<BattleObject>(battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack));
|
highlightList.Add(caster);
|
|
|
// 把这些BO全高亮 或者说把除了这些的都放在遮罩后面
|
// YYL TODO
|
}
|
|
// 命中目标后的回调 正常是以各技能的方式来处理的
|
protected virtual void OnHitTargets(int _hitIndex, List<H0604_tagUseSkillAttack.tagSkillHurtObj> hitList)
|
{
|
for (int i = 0; i < hitList.Count; i++)
|
{
|
H0604_tagUseSkillAttack.tagSkillHurtObj hurt = hitList[i];
|
|
BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
|
if (target == null)
|
{
|
Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
|
continue;
|
}
|
|
// 伤害分布 (万分比)
|
int[] damageDivide = skillConfig.DamageDivide[_hitIndex];
|
|
long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
|
|
// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差
|
List<long> damageList = DivideDamageToList(damageDivide, totalDamage);
|
|
OnHitEachTarget(target, totalDamage, damageList, ref hurt);
|
}
|
}
|
|
/// <summary>
|
/// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差
|
/// </summary>
|
protected List<long> DivideDamageToList(int[] damageDivide, long totalDamage)
|
{
|
List<long> fixedDamageList = new List<long>();
|
long assigned = 0;
|
int count = damageDivide.Length;
|
|
for (int i = 0; i < count; i++)
|
{
|
long damage;
|
if (i == count - 1)
|
{
|
// 最后一个分配项修正为剩余
|
damage = totalDamage - assigned;
|
}
|
else
|
{
|
damage = (totalDamage * damageDivide[i] + 5000) / 10000; // 四舍五入
|
assigned += damage;
|
}
|
fixedDamageList.Add(damage);
|
}
|
return fixedDamageList;
|
}
|
|
protected virtual void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
|
{
|
target.Hurt(damageList, totalDamage, hurt.AttackType);
|
|
// 击中目标的时候,不管近战远程 都确认一下是否有爆炸特效 然后播放
|
if (skillConfig.ExplosionEffectId > 0)
|
{
|
// 播放爆炸特效
|
target.battleField.battleEffectMgr.PlayEffect(
|
target.ObjID,
|
skillConfig.ExplosionEffectId,
|
target.heroGo.transform
|
);
|
}
|
|
// 受伤之后辨别死亡状态 死亡包其实前后帧会多次触发 应该要即时remove其他的包来保证不重复
|
if (target.IsDead())
|
{
|
// SkillRecordAction里的drop事件前移到dead之后
|
HB422_tagMCTurnFightObjDead deadPack = FindDeadPack(target);
|
CheckAfterDeadhPack(target, deadPack);
|
if (deadPack != null)
|
{
|
// 处理掉落包
|
for (int i = 0; i < dropPackList.Count; i++)
|
{
|
PackageRegedit.Distribute(dropPackList[i]);
|
}
|
|
dropPackList.Clear();
|
|
target.PushExpPackList(new List<HB405_tagMCAddExp>(expPackList));
|
|
expPackList.Clear();
|
|
// 处理死亡包
|
PackageRegedit.Distribute(deadPack);
|
packList.Remove(deadPack);
|
}
|
|
// 复活包暂时不管 可能是技能的包
|
// HB423_tagMCTurnFightObjReborn rebornPack = FindRebornPack(target);
|
// if (rebornPack != null)
|
// {
|
// // 处理复活包
|
// PackageRegedit.Distribute(rebornPack);
|
// packList.Remove(rebornPack);
|
// }
|
}
|
}
|
|
protected HB423_tagMCTurnFightObjReborn FindRebornPack(BattleObject target)
|
{
|
HB423_tagMCTurnFightObjReborn rebornPack = null;
|
for (int i = 0; i < packList.Count; i++)
|
{
|
var pack = packList[i];
|
if (pack is HB423_tagMCTurnFightObjReborn)
|
{
|
rebornPack = pack as HB423_tagMCTurnFightObjReborn;
|
if (rebornPack.ObjID == target.ObjID)
|
{
|
return rebornPack;
|
}
|
}
|
else if (pack is CustomHB426CombinePack)
|
{
|
var combinePack = pack as CustomHB426CombinePack;
|
if (combinePack.startTag.Tag.StartsWith("Skill_"))
|
{
|
break; // 找到技能包就不需要再处理了
|
}
|
}
|
}
|
return null;
|
}
|
|
protected HB422_tagMCTurnFightObjDead FindDeadPack(BattleObject target)
|
{
|
HB422_tagMCTurnFightObjDead deadPack = null;
|
for (int i = 0; i < packList.Count; i++)
|
{
|
var pack = packList[i];
|
// 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包
|
if (pack is HB422_tagMCTurnFightObjDead)
|
{
|
deadPack = pack as HB422_tagMCTurnFightObjDead;
|
if (deadPack.ObjID == target.ObjID)
|
{
|
return deadPack;
|
}
|
}
|
else if (pack is CustomHB426CombinePack)
|
{
|
// 找死亡包不要越过技能包
|
var combinePack = pack as CustomHB426CombinePack;
|
if (combinePack.startTag.Tag.StartsWith("Skill_"))
|
{
|
break;
|
}
|
}
|
}
|
return null;
|
}
|
|
protected void CheckAfterDeadhPack(BattleObject target, HB422_tagMCTurnFightObjDead deadPack)
|
{
|
if (null == deadPack)
|
{
|
return;
|
}
|
var deadPackIndex = packList.IndexOf(deadPack);
|
if (deadPackIndex < 0)
|
{
|
return;
|
}
|
List<int> removeIndexList = new List<int>();
|
for (int i = deadPackIndex + 1; 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()
|
{
|
return isFinished;
|
}
|
|
public virtual void ForceFinished()
|
{
|
isFinished = true;
|
}
|
|
public void OnSkillFinished()
|
{
|
isFinished = true;
|
}
|
}
|