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; } } /// /// buff的逻辑控制脚本 /// public partial class BuffsComponent : Component, IBuffListener { private Dictionary _buffsMap = new Dictionary(); 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; /// /// 护盾buff是否有变化 /// public bool IsShieldDirty { get; set; } /// /// 所有护盾吸收值 /// public long TotalShieldVal { get; private set; } public List GetBuffs() { var buffs = ListPool.Acquire(); foreach (var buff in _buffsMap.Values) { if (!buff.IsShowIcon) continue; buffs.Add(buff); } return buffs; } public bool GetElementBuffs(ref List buffs) { if (buffs == null) { buffs = new List(); } var lastCount = buffs.Count; foreach (var buff in _buffsMap.Values) { if (buff is ElementAddDebuff element && element.IsReachLayer3()) { buffs.Add(buff); } } return buffs.Count > lastCount; } ///// ///// 获取最近的可触发效果的元素buff ///// ///// //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(); //} /// /// 护盾吸收 /// /// /// 护盾吸收后剩余的伤害值 负数 public int CalculateShieldAbsorb(int damage) { if (damage >= 0) return damage; var tempBuffs = ListPool.Acquire(); 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; } /// /// 获取技能伤害Buff加成 /// /// /// /// 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; } /// /// 检测受击目标的buff触发 /// /// /// /// public void TickBuffOrSkill(int damage, EElementType elementType, ICombatCalculation attacker) { if (elementType == EElementType.None) return; // TODO 目前只有元素技能会触发buff var tempBuffs = ListPool.Acquire(); 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.RandomTick(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(), EBuffType.Shield => ObjectPool.Acquire(), EBuffType.ElementAddFire or EBuffType.ElementAddThunder or EBuffType.ElementAddIce or EBuffType.ElementAddPoison or EBuffType.ElementAddWind => ObjectPool.Acquire(), _ => ObjectPool.Acquire(), }; } /// /// EBuffType => EEntityState /// /// /// /// 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 } }