/// <summary> /// <para>Creates and returns a new buff applied to the owner of this AbilityInterface.</para> /// </summary> public NewBuff TryCreateBuff(BuffQueueInfo buffQueueInfo) { if (buffQueueInfo.BuffInfo == null) { Log.Error("TryCreateBuff", "NULL BUFFINFO"); return(null); } #if DEBUG && ABILITY_DEVELOPMENT _Owner.Say("+++ " + buffQueueInfo.BuffInfo.Name + " (" + buffQueueInfo.BuffInfo.Type + ")"); #endif // Cap the level of same-faction buffs if (buffQueueInfo.Caster.Realm == _unitOwner.Realm && (float)buffQueueInfo.Caster.EffectiveLevel / _unitOwner.EffectiveLevel > 1.3f) { buffQueueInfo.DesiredLevel = _unitOwner.EffectiveLevel; } Tuple <ushort, byte> buffSlotInfo = CanAcceptBuff(buffQueueInfo); if (buffSlotInfo == null || buffSlotInfo.Item1 == 32000) { return(null); } NewBuff myBuff = buffQueueInfo.BuffCreator == null ? new NewBuff() : buffQueueInfo.BuffCreator(); if (myBuff != null) { myBuff.Initialize(buffQueueInfo.Caster, (Unit)_Owner, buffSlotInfo.Item1, buffQueueInfo.DesiredLevel, Math.Min(buffQueueInfo.BuffInfo.MaxStack, buffSlotInfo.Item2), buffQueueInfo.BuffInfo, this); if (myBuff.BuffGroup == BuffGroups.SelfClassBuff) { _careerBuffs[0] = myBuff; } else if (myBuff.BuffGroup == BuffGroups.SelfClassSecondaryBuff) { _careerBuffs[1] = myBuff; } else if (myBuff.BuffGroup == BuffGroups.Guard && _Owner != myBuff.Caster) { myBuff.IsGroupBuff = true; _backingGuardBuffs?.Add((GuardBuff)myBuff); _guardsChanged = true; } else if (myBuff is AuraBuff && myBuff.Caster == _Owner) { _auraCount++; } } return(myBuff); }
public void InsertUnstoppable(BuffQueueInfo bqi) { NewBuff buff = TryCreateBuff(bqi); if (buff != null) { _pendingBuffs.Add(buff); _filledSlots[buff.BuffId] = true; } buff?.StartBuff(); }
public void QueueBuff(BuffQueueInfo queueInfo) { if (Stopping || (DetauntWard && queueInfo.BuffInfo.Group == BuffGroups.Detaunt)) { return; } if (queueInfo.BuffInfo == null) { Log.Error("BuffInterface", "Attempt to queue a null Buff Info: " + queueInfo.BuffInfo); //Environment.StackTrace); } else { lock (_queuedInfo) _queuedInfo.Add(queueInfo); } if (_unitOwner != null && _unitOwner.CbtInterface.IsInCombat) { queueInfo.Caster.CbtInterface.RefreshCombatTimer(); } }
/// <summary> /// <para>Checks whether a buff can be added to the list.</para> /// <para>Handles buffs which are grouped (Blade Enchantments, etc) and multiple copies of buffs.</para> /// </summary> /// <returns>The slot into which a new buff could be inserted, or 255 if no such slot exists.</returns> private Tuple <ushort, byte> CanAcceptBuff(BuffQueueInfo newInfo) { NewBuff existingBuff; List <NewBuff> existingBuffs; byte desiredStackLevel = (byte)newInfo.BuffInfo.InitialStacks; switch (newInfo.BuffInfo.Group) { #region Guard case BuffGroups.Guard: existingBuffs = _pendingBuffs.FindAll(buff => buff.BuffGroup == newInfo.BuffInfo.Group); if (existingBuffs.Any(buff => buff.Caster == newInfo.Caster)) { return(null); } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Hold The Line case BuffGroups.HoldTheLine: existingBuffs = _pendingBuffs.FindAll(buff => buff.BuffGroup == newInfo.BuffInfo.Group); if (existingBuffs.Count >= 3) { if (newInfo.Caster != _Owner) { return(null); } existingBuffs[0].BuffHasExpired = true; ushort newSlot = existingBuffs[0].BuffId; RemoveFromPending(existingBuffs[0]); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } if (existingBuffs.Any(buff => buff.Caster == newInfo.Caster)) { return(null); } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Oath Friend case BuffGroups.OathFriend: existingBuffs = _pendingBuffs.FindAll(buff => buff.BuffGroup == newInfo.BuffInfo.Group); if (existingBuffs.Count > 0) { // Self component of Oath Friend. Remove any existing version if (newInfo.Caster == _Owner) { foreach (NewBuff buff in existingBuffs) { if (buff.Caster != _Owner) { continue; } buff.BuffHasExpired = true; ushort newSlot2 = buff.BuffId; RemoveFromPending(buff); return(new Tuple <ushort, byte>(newSlot2, desiredStackLevel)); } } else { foreach (NewBuff buff in existingBuffs) { // Look for and replace existing OF/DP from the caster if (buff.Caster != newInfo.Caster) { continue; } buff.BuffHasExpired = true; ushort newSlot2 = buff.BuffId; RemoveFromPending(buff); return(new Tuple <ushort, byte>(newSlot2, desiredStackLevel)); } } } // Oath friend on enemy. Always apply. return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Class self-buffs case BuffGroups.SelfClassBuff: existingBuff = _pendingBuffs.Find(buff => buff.BuffGroup == newInfo.BuffInfo.Group); if (existingBuff != null) { if (existingBuff.Entry == newInfo.BuffInfo.Entry && !newInfo.BuffInfo.CanRefresh) { return(null); } ushort newSlot = existingBuff.BuffId; RemoveFromPending(existingBuff); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Class buffs for others case BuffGroups.OtherClassBuff: existingBuffs = _pendingBuffs.FindAll(buff => buff.BuffGroup == newInfo.BuffInfo.Group); foreach (var buff in existingBuffs) { if (buff.Entry == newInfo.BuffInfo.Entry) { if (buff.Caster != newInfo.Caster) { return(null); } //if (!newInfo.BuffInfo.CanRefresh) // return null; } if (buff.Caster == newInfo.Caster) { ushort newSlot = buff.BuffId; RemoveFromPending(buff); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Auras case BuffGroups.Aura: existingBuff = _pendingBuffs.Find(buff => buff.Entry == newInfo.BuffInfo.Entry); if (existingBuff != null) { // The owner's version of an aura must always persist over all others if (existingBuff.Caster == _Owner) { return(null); } if (newInfo.Caster == _Owner) { ushort newSlot = existingBuff.BuffId; RemoveFromPending(existingBuff); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } return(null); } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Potion Stat Buffs and other exclusives case BuffGroups.HealPotion: case BuffGroups.StatPotion: case BuffGroups.DefensePotion: case BuffGroups.SharedCooldown1: case BuffGroups.Vanity: existingBuff = _pendingBuffs.Find(buff => buff.BuffGroup == newInfo.BuffInfo.Group); if (existingBuff != null) { RemoveFromPending(existingBuff); } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion #region Resurrection case BuffGroups.Resurrection: existingBuff = _pendingBuffs.Find(buff => buff.BuffGroup == newInfo.BuffInfo.Group || buff.Entry == 1608 || buff.Entry == 8567); if (existingBuff == null) { return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); } if (newInfo.DesiredLevel > existingBuff.BuffLevel) { RemoveFromPending(existingBuff); return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); } return(null); #endregion #region Other buffs default: if (newInfo.BuffInfo.MaxCopies == 0) { existingBuff = _pendingBuffs.Find(buff => buff.Entry == newInfo.BuffInfo.Entry && buff.Caster == newInfo.Caster); if (existingBuff == null || newInfo.BuffInfo.StacksFromCaster) { return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); } if (newInfo.BuffInfo.CanRefresh) { desiredStackLevel += existingBuff.StackLevel; ushort newSlot = existingBuff.BuffId; RemoveFromPending(existingBuff, true); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } return(null); } existingBuffs = _pendingBuffs.FindAll(buff => buff.Entry == newInfo.BuffInfo.Entry); if (existingBuffs.Count > 0) { foreach (var buff in existingBuffs) { if (buff.Caster == newInfo.Caster || buff.BuffLevel < newInfo.DesiredLevel) { if (newInfo.BuffInfo.CanRefresh) { desiredStackLevel += buff.StackLevel; ushort newSlot = buff.BuffId; RemoveFromPending(buff, true); return(new Tuple <ushort, byte>(newSlot, desiredStackLevel)); } } } if (existingBuffs.Count >= newInfo.BuffInfo.MaxCopies) // B.MaxCopies) { return(null); } } return(new Tuple <ushort, byte>(GetFreeSlot(), desiredStackLevel)); #endregion } }