123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- using FL.Battle.Buffs;
- using System.Collections.Generic;
- using UnityEngine;
- using XGame;
- using XGame.Database;
- using XGame.Framework;
- using XGame.Framework.Components;
- using XGame.Framework.Map;
- using XGame.Framework.Time;
- namespace FL.Battle.Components
- {
- public interface IBuffsContext
- {
- public IEntity Entity { get; }
- public ITimeModule Time { get; }
- public IMapAssetModule Asset { get; }
- Vector3 Position { get; }
- Transform OwnerTr { get; }
- ICombatCalculation Calculation { get; }
- StatesComponent States { get; }
- MoveComponent Move { get; }
- }
- /// <summary>
- /// buff的逻辑控制脚本
- /// </summary>
- public partial class BuffsComponent : Component<IBuffsContext>, IBuffListener
- {
- private Dictionary<long, Buff> _buffsMap = new Dictionary<long, Buff>();
- protected override void OnEnable(object intent)
- {
- TotalShieldVal = 0;
- }
- protected override void OnDisable()
- {
- Clear();
- }
- protected override void OnDispose()
- {
- Clear();
- }
- public bool IsDirty { get; set; }
- public int BuffCount => _buffsMap.Count;
- /// <summary>
- /// 护盾buff是否有变化
- /// </summary>
- public bool IsShieldDirty { get; set; }
- /// <summary>
- /// 所有护盾吸收值
- /// </summary>
- public long TotalShieldVal { get; private set; }
- public List<IBuff> GetBuffs()
- {
- var buffs = ListPool.Acquire<IBuff>();
- foreach (var buff in _buffsMap.Values)
- {
- if (!buff.IsShowIcon)
- continue;
- buffs.Add(buff);
- }
- return buffs;
- }
- public bool GetElementBuffs(ref List<IBuff> buffs)
- {
- if (buffs == null)
- {
- buffs = new List<IBuff>();
- }
- var lastCount = buffs.Count;
- foreach (var buff in _buffsMap.Values)
- {
- if (buff is ElementAddDebuff element && element.IsReachLayer3())
- {
- buffs.Add(buff);
- }
- }
- return buffs.Count > lastCount;
- }
- ///// <summary>
- ///// 获取最近的可触发效果的元素buff
- ///// </summary>
- ///// <returns></returns>
- //public IBuff GetPreTickElementBuff()
- //{
- // Buff result = null;
- // foreach (var buff in _buffsMap.Values)
- // {
- // if (buff.ElementType == EElementType.None)
- // continue;
- // if (buff.Layers == buff.LayerLimit)
- // {
- // result = buff;
- // break;
- // }
- // if (result == null || (float)buff.Layers / buff.LayerLimit > (float)result.Layers / result.LayerLimit)
- // {
- // result = buff;
- // }
- // }
- // return result;
- //}
- public bool IsContains(EBuffType buffType)
- {
- foreach (var buff in _buffsMap.Values)
- {
- if (buff.BuffType == buffType)
- return true;
- }
- return false;
- }
- public int GetLayers(long buffId)
- {
- if (_buffsMap.TryGetValue(buffId, out var buff))
- {
- return buff.Layers;
- }
- return 0;
- }
- //void IUpdate.Update(int millisecond)
- //{
- // _updateBuffs.AddRange(_buffsMap.Values);
- // foreach (var buff in _updateBuffs)
- // {
- // if (buff.Update(millisecond))
- // {
- // _buffsMap.Remove(buff.TableId);
- // }
- // }
- // _updateBuffs.Clear();
- //}
- /// <summary>
- /// 护盾吸收
- /// </summary>
- /// <param name="damage"></param>
- /// <returns>护盾吸收后剩余的伤害值 负数</returns>
- public int CalculateShieldAbsorb(int damage)
- {
- if (damage >= 0)
- return damage;
- var tempBuffs = ListPool.Acquire<Buff>();
- tempBuffs.AddRange(_buffsMap.Values);
- foreach (var buff in tempBuffs)
- { // 遍历中buff的数量可能会增减
- if (buff is ShieldBuff shieldBuff)
- {
- damage = shieldBuff.Reduce(damage);
- if (damage == 0)
- break; // 剩余伤害为零,全部吸收了
- }
- }
- ListPool.Recycle(tempBuffs);
- return damage;
- }
- /// <summary>
- /// 获取技能伤害Buff加成
- /// </summary>
- /// <param name="skill"></param>
- /// <param name="target"></param>
- /// <returns></returns>
- public int GetDamageAdd(EElementType elementType, IEntity target, BuffsComponent targetBuffs)
- {
- var result = 0;
- foreach (var buff in _buffsMap.Values)
- {
- var buffType = buff.BuffType;
- if (buffType is EBuffType.DizzAdd)
- {
- if (target.IsState(EEntityState.Dizzy))
- {
- result += buff.Table.BuffTypeNum[0];
- }
- }
- else if (buffType is EBuffType.FreezeAdd)
- {
- if (target.IsState(EEntityState.Freeze))
- {
- result += buff.Table.BuffTypeNum[0];
- }
- }
- else if (buffType is EBuffType.DotAdd)
- {
- if (targetBuffs.IsContains(EBuffType.Dot))
- {
- result += buff.Table.BuffTypeNum[0];
- }
- }
- else if (elementType == EElementType.None)
- { // 非元素技能
- continue;
- }
- else if (buffType != EBuffType.ElementAddIce || target.EntityId != Context.Entity.EntityId ||
- ((buff as ElementAddDebuff)?.IsReachLayer5(elementType) ?? false))
- { // 目标有冻伤
- continue;
- }
- else
- {// 目标有冻伤 且 本次攻击没有达到5层元素易伤条件
- result += buff.Table.BuffTypeNum[1];
- }
- }
- return result;
- }
- /// <summary>
- /// 检测受击目标的buff触发
- /// </summary>
- /// <param name="damage"></param>
- /// <param name="elementType"></param>
- /// <param name="attacker"></param>
- public void TickBuffOrSkill(int damage, EElementType elementType, ICombatCalculation attacker)
- {
- if (elementType == EElementType.None)
- return; // TODO 目前只有元素技能会触发buff
- var tempBuffs = ListPool.Acquire<Buff>();
- tempBuffs.AddRange(_buffsMap.Values);
- foreach (var buff in tempBuffs)
- { // 遍历中buff的数量可能会增减
- if (buff is ElementAddDebuff elementAddDebuff)
- {
- elementAddDebuff.TryTickBuff(damage, elementType, attacker);
- }
- }
- ListPool.Recycle(tempBuffs);
- }
- public void TryAddBuff(long buffId, int probability, int addLayer = 1, ICombatCalculation attacker = null, int damage = 0)
- {
- if (Context.Entity.IsDead)
- return;
- if (MathUtils.Random(probability) == false)
- {
- return;
- }
- var buff = AddBuff(buffId, addLayer);
- if (attacker != null && buff is ElementAddDebuff elementAddDebuff)
- { // 受击者buff触发攻击者的Buff或者技能
- if (elementAddDebuff.TryTickLayer3(attacker))
- {
- EventSingle.Instance.Notify(EventDefine.GameMainMapAddBuff, new BuffEventDto()
- {
- ownerId = Context.Entity.EntityId,
- buffTableId = buff.TableId,
- });
- }
- }
- else if (buff is DotDebuff dotDebuff)
- {
- dotDebuff.TryTickLayer5();
- }
- else if (damage != 0 && buff is ShieldBuff shieldBuff)
- {
- shieldBuff.Add(damage);
- }
- else if (buff.BuffType == EBuffType.Attribute)
- {
- AddAttributeBuff(buff);
- }
- }
- private Buff AddBuff(long buffId, int addLayer)
- {
- IsDirty = true;
- if (_buffsMap.TryGetValue(buffId, out var buff))
- {
- buff.Layers += addLayer;
- }
- else
- {
- var buffTable = BuffTableRepo.Get(buffId);
- buff = GenBuff((EBuffType)buffTable.BuffType);
- buff.Init(buffTable, UIDDefine.New(), Context, this);
- if (addLayer > 1)
- {
- buff.Layers = addLayer;
- }
- _buffsMap.Add(buff.TableId, buff);
- if (TryToEntityState(buff.BuffType, out var entityState))
- {
- Context.States.AddState(entityState);
- }
- }
- //Log.Debug($"AddBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId} Overlay:{buff.Layers}");
- return buff;
- }
- private void RemoveBuff(int buffId)
- {
- if (_buffsMap.TryGetValue(buffId, out var buff))
- {
- _buffsMap.Remove(buffId);
- if (TryToEntityState(buff.BuffType, out var entityState))
- { // TODO 需要判断剩余的buff是否有相同类型的状态
- Context.States.RemoveState(entityState);
- }
- else if (buff is ElementAddDebuff)
- {
- EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveBuff, new BuffEventDto()
- {
- ownerId = Context.Entity.EntityId,
- buffTableId = buffId,
- });
- }
- else if (buff is ShieldBuff shieldBuff)
- {
- // 减去剩余的护盾值
- (this as IBuffListener).OnShieldChanged(-shieldBuff.Absorption);
- }
- else if (buff.BuffType == EBuffType.Attribute)
- {
- RemoveAttributeBuff(buff);
- }
- ObjectPool.Recycle(buff);
- IsDirty = true;
- }
- }
- private Buff GenBuff(EBuffType buffType)
- {
- return buffType switch
- {
- EBuffType.Dot => ObjectPool.Acquire<DotDebuff>(),
- EBuffType.Shield => ObjectPool.Acquire<ShieldBuff>(),
- EBuffType.ElementAddFire or EBuffType.ElementAddThunder or EBuffType.ElementAddIce
- or EBuffType.ElementAddPoison or EBuffType.ElementAddWind => ObjectPool.Acquire<ElementAddDebuff>(),
- _ => ObjectPool.Acquire<Buff>(),
- };
- }
- /// <summary>
- /// EBuffType => EEntityState
- /// </summary>
- /// <param name="buffType"></param>
- /// <param name="entityState"></param>
- /// <returns></returns>
- private bool TryToEntityState(EBuffType buffType, out EEntityState entityState)
- {
- switch (buffType)
- {
- case EBuffType.Dizzy:
- entityState = EEntityState.Dizzy;
- return true;
- case EBuffType.Freeze:
- entityState = EEntityState.Freeze;
- return true;
- case EBuffType.Paralysis:
- entityState = EEntityState.Palsy;
- return true;
- default:
- entityState = EEntityState.Idle;
- return false;
- }
- }
- private void Clear()
- {
- foreach (var buff in _buffsMap.Values)
- {
- RemoveAttributeValue(buff);
- ObjectPool.Recycle(buff);
- }
- _buffsMap.Clear();
- TotalShieldVal = 0;
- ClearAttributes();
- }
- #region IBuffListener 实现
- void IBuffListener.OnShieldChanged(long val)
- {
- TotalShieldVal += val;
- if (TotalShieldVal < 0)
- {
- Log.Error($"护盾剩余值计算错误.OnShieldChanged total: {TotalShieldVal} value:{val}");
- TotalShieldVal = 0;
- }
- IsShieldDirty = true;
- }
- void IBuffListener.OnCompleted(int buffId)
- {
- RemoveBuff(buffId);
- //Log.Debug($"RemoveBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId}");
- }
- #endregion
- }
- }
|