BuffsComponent.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. using FL.Battle.Buffs;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using XGame;
  5. using XGame.Database;
  6. using XGame.Framework;
  7. using XGame.Framework.Components;
  8. using XGame.Framework.Map;
  9. using XGame.Framework.Time;
  10. namespace FL.Battle.Components
  11. {
  12. public interface IBuffsContext
  13. {
  14. public IEntity Entity { get; }
  15. public ITimeModule Time { get; }
  16. public IMapAssetModule Asset { get; }
  17. Vector3 Position { get; }
  18. Transform OwnerTr { get; }
  19. ICombatCalculation Calculation { get; }
  20. StatesComponent States { get; }
  21. MoveComponent Move { get; }
  22. }
  23. /// <summary>
  24. /// buff的逻辑控制脚本
  25. /// </summary>
  26. public partial class BuffsComponent : Component<IBuffsContext>, IBuffListener
  27. {
  28. private Dictionary<long, Buff> _buffsMap = new Dictionary<long, Buff>();
  29. protected override void OnEnable(object intent)
  30. {
  31. TotalShieldVal = 0;
  32. }
  33. protected override void OnDisable()
  34. {
  35. Clear();
  36. }
  37. protected override void OnDispose()
  38. {
  39. Clear();
  40. }
  41. public bool IsDirty { get; set; }
  42. public int BuffCount => _buffsMap.Count;
  43. /// <summary>
  44. /// 护盾buff是否有变化
  45. /// </summary>
  46. public bool IsShieldDirty { get; set; }
  47. /// <summary>
  48. /// 所有护盾吸收值
  49. /// </summary>
  50. public long TotalShieldVal { get; private set; }
  51. public List<IBuff> GetBuffs()
  52. {
  53. var buffs = ListPool.Acquire<IBuff>();
  54. foreach (var buff in _buffsMap.Values)
  55. {
  56. if (!buff.IsShowIcon)
  57. continue;
  58. buffs.Add(buff);
  59. }
  60. return buffs;
  61. }
  62. public bool GetElementBuffs(ref List<IBuff> buffs)
  63. {
  64. if (buffs == null)
  65. {
  66. buffs = new List<IBuff>();
  67. }
  68. var lastCount = buffs.Count;
  69. foreach (var buff in _buffsMap.Values)
  70. {
  71. if (buff is ElementAddDebuff element && element.IsReachLayer3())
  72. {
  73. buffs.Add(buff);
  74. }
  75. }
  76. return buffs.Count > lastCount;
  77. }
  78. ///// <summary>
  79. ///// 获取最近的可触发效果的元素buff
  80. ///// </summary>
  81. ///// <returns></returns>
  82. //public IBuff GetPreTickElementBuff()
  83. //{
  84. // Buff result = null;
  85. // foreach (var buff in _buffsMap.Values)
  86. // {
  87. // if (buff.ElementType == EElementType.None)
  88. // continue;
  89. // if (buff.Layers == buff.LayerLimit)
  90. // {
  91. // result = buff;
  92. // break;
  93. // }
  94. // if (result == null || (float)buff.Layers / buff.LayerLimit > (float)result.Layers / result.LayerLimit)
  95. // {
  96. // result = buff;
  97. // }
  98. // }
  99. // return result;
  100. //}
  101. public bool IsContains(EBuffType buffType)
  102. {
  103. foreach (var buff in _buffsMap.Values)
  104. {
  105. if (buff.BuffType == buffType)
  106. return true;
  107. }
  108. return false;
  109. }
  110. public int GetLayers(long buffId)
  111. {
  112. if (_buffsMap.TryGetValue(buffId, out var buff))
  113. {
  114. return buff.Layers;
  115. }
  116. return 0;
  117. }
  118. //void IUpdate.Update(int millisecond)
  119. //{
  120. // _updateBuffs.AddRange(_buffsMap.Values);
  121. // foreach (var buff in _updateBuffs)
  122. // {
  123. // if (buff.Update(millisecond))
  124. // {
  125. // _buffsMap.Remove(buff.TableId);
  126. // }
  127. // }
  128. // _updateBuffs.Clear();
  129. //}
  130. /// <summary>
  131. /// 护盾吸收
  132. /// </summary>
  133. /// <param name="damage"></param>
  134. /// <returns>护盾吸收后剩余的伤害值 负数</returns>
  135. public int CalculateShieldAbsorb(int damage)
  136. {
  137. if (damage >= 0)
  138. return damage;
  139. var tempBuffs = ListPool.Acquire<Buff>();
  140. tempBuffs.AddRange(_buffsMap.Values);
  141. foreach (var buff in tempBuffs)
  142. { // 遍历中buff的数量可能会增减
  143. if (buff is ShieldBuff shieldBuff)
  144. {
  145. damage = shieldBuff.Reduce(damage);
  146. if (damage == 0)
  147. break; // 剩余伤害为零,全部吸收了
  148. }
  149. }
  150. ListPool.Recycle(tempBuffs);
  151. return damage;
  152. }
  153. /// <summary>
  154. /// 获取技能伤害Buff加成
  155. /// </summary>
  156. /// <param name="skill"></param>
  157. /// <param name="target"></param>
  158. /// <returns></returns>
  159. public int GetDamageAdd(EElementType elementType, IEntity target, BuffsComponent targetBuffs)
  160. {
  161. var result = 0;
  162. foreach (var buff in _buffsMap.Values)
  163. {
  164. var buffType = buff.BuffType;
  165. if (buffType is EBuffType.DizzAdd)
  166. {
  167. if (target.IsState(EEntityState.Dizzy))
  168. {
  169. result += buff.Table.BuffTypeNum[0];
  170. }
  171. }
  172. else if (buffType is EBuffType.FreezeAdd)
  173. {
  174. if (target.IsState(EEntityState.Freeze))
  175. {
  176. result += buff.Table.BuffTypeNum[0];
  177. }
  178. }
  179. else if (buffType is EBuffType.DotAdd)
  180. {
  181. if (targetBuffs.IsContains(EBuffType.Dot))
  182. {
  183. result += buff.Table.BuffTypeNum[0];
  184. }
  185. }
  186. else if (elementType == EElementType.None)
  187. { // 非元素技能
  188. continue;
  189. }
  190. else if (buffType != EBuffType.ElementAddIce || target.EntityId != Context.Entity.EntityId ||
  191. ((buff as ElementAddDebuff)?.IsReachLayer5(elementType) ?? false))
  192. { // 目标有冻伤
  193. continue;
  194. }
  195. else
  196. {// 目标有冻伤 且 本次攻击没有达到5层元素易伤条件
  197. result += buff.Table.BuffTypeNum[1];
  198. }
  199. }
  200. return result;
  201. }
  202. /// <summary>
  203. /// 检测受击目标的buff触发
  204. /// </summary>
  205. /// <param name="damage"></param>
  206. /// <param name="elementType"></param>
  207. /// <param name="attacker"></param>
  208. public void TickBuffOrSkill(int damage, EElementType elementType, ICombatCalculation attacker)
  209. {
  210. if (elementType == EElementType.None)
  211. return; // TODO 目前只有元素技能会触发buff
  212. var tempBuffs = ListPool.Acquire<Buff>();
  213. tempBuffs.AddRange(_buffsMap.Values);
  214. foreach (var buff in tempBuffs)
  215. { // 遍历中buff的数量可能会增减
  216. if (buff is ElementAddDebuff elementAddDebuff)
  217. {
  218. elementAddDebuff.TryTickBuff(damage, elementType, attacker);
  219. }
  220. }
  221. ListPool.Recycle(tempBuffs);
  222. }
  223. public void TryAddBuff(long buffId, int probability, int addLayer = 1, ICombatCalculation attacker = null, int damage = 0)
  224. {
  225. if (Context.Entity.IsDead)
  226. return;
  227. if (MathUtils.RandomTick(probability) == false)
  228. {
  229. return;
  230. }
  231. var buff = AddBuff(buffId, addLayer);
  232. if (attacker != null && buff is ElementAddDebuff elementAddDebuff)
  233. { // 受击者buff触发攻击者的Buff或者技能
  234. if (elementAddDebuff.TryTickLayer3(attacker))
  235. {
  236. EventSingle.Instance.Notify(EventDefine.GameMainMapAddBuff, new BuffEventDto()
  237. {
  238. ownerId = Context.Entity.EntityId,
  239. buffTableId = buff.TableId,
  240. });
  241. }
  242. }
  243. else if (buff is DotDebuff dotDebuff)
  244. {
  245. dotDebuff.TryTickLayer5();
  246. }
  247. else if (damage != 0 && buff is ShieldBuff shieldBuff)
  248. {
  249. shieldBuff.Add(damage);
  250. }
  251. else if (buff.BuffType == EBuffType.Attribute)
  252. {
  253. AddAttributeBuff(buff);
  254. }
  255. }
  256. private Buff AddBuff(long buffId, int addLayer)
  257. {
  258. IsDirty = true;
  259. if (_buffsMap.TryGetValue(buffId, out var buff))
  260. {
  261. buff.Layers += addLayer;
  262. }
  263. else
  264. {
  265. var buffTable = BuffTableRepo.Get(buffId);
  266. buff = GenBuff((EBuffType)buffTable.BuffType);
  267. buff.Init(buffTable, UIDDefine.New(), Context, this);
  268. if (addLayer > 1)
  269. {
  270. buff.Layers = addLayer;
  271. }
  272. _buffsMap.Add(buff.TableId, buff);
  273. if (TryToEntityState(buff.BuffType, out var entityState))
  274. {
  275. Context.States.AddState(entityState);
  276. }
  277. }
  278. //Log.Debug($"AddBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId} Overlay:{buff.Layers}");
  279. return buff;
  280. }
  281. private void RemoveBuff(int buffId)
  282. {
  283. if (_buffsMap.TryGetValue(buffId, out var buff))
  284. {
  285. _buffsMap.Remove(buffId);
  286. if (TryToEntityState(buff.BuffType, out var entityState))
  287. { // TODO 需要判断剩余的buff是否有相同类型的状态
  288. Context.States.RemoveState(entityState);
  289. }
  290. else if (buff is ElementAddDebuff)
  291. {
  292. EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveBuff, new BuffEventDto()
  293. {
  294. ownerId = Context.Entity.EntityId,
  295. buffTableId = buffId,
  296. });
  297. }
  298. else if (buff is ShieldBuff shieldBuff)
  299. {
  300. // 减去剩余的护盾值
  301. (this as IBuffListener).OnShieldChanged(-shieldBuff.Absorption);
  302. }
  303. else if (buff.BuffType == EBuffType.Attribute)
  304. {
  305. RemoveAttributeBuff(buff);
  306. }
  307. ObjectPool.Recycle(buff);
  308. IsDirty = true;
  309. }
  310. }
  311. private Buff GenBuff(EBuffType buffType)
  312. {
  313. return buffType switch
  314. {
  315. EBuffType.Dot => ObjectPool.Acquire<DotDebuff>(),
  316. EBuffType.Shield => ObjectPool.Acquire<ShieldBuff>(),
  317. EBuffType.ElementAddFire or EBuffType.ElementAddThunder or EBuffType.ElementAddIce
  318. or EBuffType.ElementAddPoison or EBuffType.ElementAddWind => ObjectPool.Acquire<ElementAddDebuff>(),
  319. _ => ObjectPool.Acquire<Buff>(),
  320. };
  321. }
  322. /// <summary>
  323. /// EBuffType => EEntityState
  324. /// </summary>
  325. /// <param name="buffType"></param>
  326. /// <param name="entityState"></param>
  327. /// <returns></returns>
  328. private bool TryToEntityState(EBuffType buffType, out EEntityState entityState)
  329. {
  330. switch (buffType)
  331. {
  332. case EBuffType.Dizzy:
  333. entityState = EEntityState.Dizzy;
  334. return true;
  335. case EBuffType.Freeze:
  336. entityState = EEntityState.Freeze;
  337. return true;
  338. case EBuffType.Paralysis:
  339. entityState = EEntityState.Palsy;
  340. return true;
  341. default:
  342. entityState = EEntityState.Idle;
  343. return false;
  344. }
  345. }
  346. private void Clear()
  347. {
  348. foreach (var buff in _buffsMap.Values)
  349. {
  350. RemoveAttributeValue(buff);
  351. ObjectPool.Recycle(buff);
  352. }
  353. _buffsMap.Clear();
  354. TotalShieldVal = 0;
  355. ClearAttributes();
  356. }
  357. #region IBuffListener 实现
  358. void IBuffListener.OnShieldChanged(long val)
  359. {
  360. TotalShieldVal += val;
  361. if (TotalShieldVal < 0)
  362. {
  363. Log.Error($"护盾剩余值计算错误.OnShieldChanged total: {TotalShieldVal} value:{val}");
  364. TotalShieldVal = 0;
  365. }
  366. IsShieldDirty = true;
  367. }
  368. void IBuffListener.OnCompleted(int buffId)
  369. {
  370. RemoveBuff(buffId);
  371. //Log.Debug($"RemoveBuff EntityId:{Context.Entity.EntityId} BuffId:{buffId}");
  372. }
  373. #endregion
  374. }
  375. }