using System; using System.Collections.Generic; using System.Threading; using robotManager.Helpful; using robotManager.Products; using wManager; using wManager.Wow; using wManager.Wow.Class; using wManager.Wow.Helpers; using wManager.Wow.ObjectManager; using MemoryRobot; public class Main : ICustomClass { private bool _isLaunched; private readonly Random _humanRnd = new Random(); // ==================== НАСТРОЙКИ СПЕЛЛОВ ==================== // true = спелл используется, false = отключён // Бафы private const bool USE_DEMON_ARMOR = true; private const bool USE_SOUL_LINK = true; private const bool USE_UNENDING_BREATH = true; // Питомец private const bool USE_FELGUARD = true; private const bool USE_FEL_DOMINATION = true; // Защитные private const bool USE_DEATH_COIL = true; private const bool USE_FEAR = true; // Боевые DoT private const bool USE_CORRUPTION = true; private const bool USE_CURSE_OF_AGONY = true; // Боевые прямые private const bool USE_SHADOW_BOLT = false; private const bool USE_SHADOWBURN = true; private const bool USE_DRAIN_LIFE = true; private const bool USE_DRAIN_SOUL = true; // Утилита private const bool USE_LIFE_TAP = true; private const bool USE_HEALTHSTONE = true; private const bool USE_HEALTH_FUNNEL = true; private const bool USE_WAND = true; // ============================================================ // ==================== АГРО-МЕНЕДЖМЕНТ ==================== private const bool USE_AGGRO_MANAGEMENT = true; private const bool USE_LOWEST_HP_TARGETING = true; private const bool USE_PET_INTERCEPT_AGGRO = true; // Felguard Intercept на мобов, атакующих варлока private const bool USE_LIFE_TAP_PET_MANA = true; // Life Tap когда у пета мало маны (талант Mana Feed) private const int LIFE_TAP_PET_MANA_THRESHOLD = 15; // % маны пета, ниже которого тапаем private const int LOW_MANA_THRESHOLD = 20; // % маны, ниже которого только drain/tap (без дотов) // ========================================================== // ==================== ПОРОГИ И КОНСТАНТЫ ==================== private const double LIFE_TAP_MANA_THRESHOLD = 70; private const double LIFE_TAP_HP_MIN = 50; private const double DRAIN_LIFE_HP_THRESHOLD = 100; private const double DRAIN_LIFE_MANA_MIN = 30; private const double FEAR_HP_THRESHOLD = 20; private const double DEATH_COIL_HP_THRESHOLD = 25; private const double HEALTHSTONE_HP_THRESHOLD = 40; private const double SHADOWBURN_TARGET_HP = 20; private const double DOT_MIN_TARGET_HP = 25; private const double DRAIN_SOUL_TARGET_HP = 20; private const int MAX_SOUL_SHARDS = 5; private const double DRAIN_SOUL_MANA_THRESHOLD = 80; private const double SHADOW_BOLT_MANA_MIN = 70; private const double SHADOW_BOLT_TARGET_HP_MIN = 20; private const int SHADOWBURN_SHARDS_MIN = 4; private const double PET_HEAL_THRESHOLD = 50; private const double HEALTH_FUNNEL_HP_MIN = 30; private const int BUFF_REBUFF_TIME_MS = 600000; // ============================================================ // ==================== ID ПРЕДМЕТОВ ==================== private const uint SOUL_SHARD_ID = 6265; private const uint HS_MINOR_ID = 5512; private const uint HS_LESSER_ID = 5511; private const uint HS_NORMAL_ID = 5509; private const uint HS_GREATER_ID = 5510; private const uint HS_MAJOR_ID = 9421; private const uint HS_MASTER_ID = 22103; // ====================================================== // Бафы / Утилита private Spell DemonArmor = new Spell("Demon Armor"); private Spell DemonSkin = new Spell("Demon Skin"); private Spell SoulLink = new Spell("Soul Link"); private Spell UnendingBreath = new Spell("Unending Breath"); private Spell FelDomination = new Spell("Fel Domination"); // Хилстоны private Spell CreateHealthstone = new Spell("Create Healthstone"); // Питомец private Spell SummonFelguard = new Spell("Summon Felguard"); // Защитные private Spell DeathCoil = new Spell("Death Coil"); private Spell Fear = new Spell("Fear"); // Боевые private Spell Corruption = new Spell("Corruption"); private Spell CurseOfAgony = new Spell("Curse of Agony"); private Spell ShadowBolt = new Spell("Shadow Bolt"); private Spell Shadowburn = new Spell("Shadowburn"); private Spell DrainLife = new Spell("Drain Life"); private Spell DrainSoul = new Spell("Drain Soul"); private Spell LifeTap = new Spell("Life Tap"); private Spell HealthFunnel = new Spell("Health Funnel"); // ==================== PET ATTACK TRACKING ==================== // Быстрая отправка пета при смене таргета (с ретраями) private string _lastTargetGuidForPet = ""; private DateTime _petLastSendTime = DateTime.MinValue; private DateTime _petRetryUntil = DateTime.MinValue; private int _petRetryCount = 0; // ==================== AGGRO MANAGEMENT ==================== private ulong _priorityTargetGuid = 0; private WoWUnit _priorityTargetUnit = null; private DateTime _lastTargetSwitch = DateTime.MinValue; // Unending Breath ребафф с рандомом (90-120 сек до конца) private int _unendingBreathRebuffMs; public float Range { get { return 30f; } } public void Initialize() { _isLaunched = true; _unendingBreathRebuffMs = _humanRnd.Next(90000, 120000); Logging.Write("[Warlock Demo] Initialized - v2 with AggroMgmt, PetAttack"); Rotation(); } public void Dispose() { _isLaunched = false; _priorityTargetGuid = 0; _priorityTargetUnit = null; Logging.Write("[Warlock Demo] Stopped."); } public void ShowConfiguration() { } // ==================== ГЛАВНЫЙ ЦИКЛ ==================== private void Rotation() { Logging.Write("[Warlock Demo] Running."); while (_isLaunched) { try { if (!Products.InPause && !ObjectManager.Me.IsDeadMe) { // Отправка пета в атаку мгновенно при смене таргета (до ротации) EnsurePetAttack(); if (!ObjectManager.Me.InCombat) { _priorityTargetGuid = 0; _priorityTargetUnit = null; } PetManager(); BuffRotation(); CraftHealthstone(); DeleteExtraSoulShards(); if (Fight.InFight && ObjectManager.Target != null && ObjectManager.Target.IsValid && ObjectManager.Target.IsAttackable) { // Агро-менеджмент bool holdingAggroTarget = false; if (ObjectManager.Me.InCombat) { holdingAggroTarget = HandleAggroManagement(); } CombatRotation(); // Повторная проверка агро после ротации if (ObjectManager.Me.InCombat && holdingAggroTarget) { HandleAggroManagement(); } } } } catch (Exception ex) { Logging.WriteError("[Warlock Demo] ERROR: " + ex); } Thread.Sleep(50); } } // ============================================================ // PET ATTACK - мгновенная отправка пета при смене таргета + ретраи // ============================================================ private void EnsurePetAttack() { if (ObjectManager.Pet == null || !ObjectManager.Pet.IsValid || !ObjectManager.Pet.IsAlive) return; if (ObjectManager.Target == null || !ObjectManager.Target.IsValid || !ObjectManager.Target.IsAlive) return; string guid = ""; try { guid = ObjectManager.Target.Guid.ToString(); } catch { guid = ""; } if (string.IsNullOrEmpty(guid)) return; // Если таргет сменился -> отправляем мгновенно + открываем окно ретраев if (guid != _lastTargetGuidForPet) { _lastTargetGuidForPet = guid; SendPetAttackLuaSafe(); _petLastSendTime = DateTime.Now; _petRetryUntil = DateTime.Now.AddSeconds(2.0); _petRetryCount = 0; return; } // Ретраи (на случай если клиент ещё не "подхватил" таргет) if (_petRetryCount < 2 && DateTime.Now < _petRetryUntil) { if ((DateTime.Now - _petLastSendTime).TotalMilliseconds >= 350) { SendPetAttackLuaSafe(); _petLastSendTime = DateTime.Now; _petRetryCount++; } } } private void SendPetAttackLuaSafe() { try { string lua = "if UnitExists('target') and UnitCanAttack('player','target') and (not UnitIsDead('target')) then " + " PetFollow(); " + " PetAttack(); " + "end"; Lua.LuaDoString(lua); } catch { // no spam } } // ============================================================ // AGGRO MANAGEMENT - перехват мобов, атакующих варлока // ============================================================ private List GetMobsAttackingMe() { List result = new List(); try { List allUnits = ObjectManager.GetObjectWoWUnit(); for (int i = 0; i < allUnits.Count; i++) { WoWUnit u = allUnits[i]; if (u == null || !u.IsValid) continue; if (!u.IsAlive || !u.IsAttackable) continue; // Атакует МЕНЯ, но НЕ пета if (!u.IsTargetingMe || u.IsTargetingMyPet) continue; if (u.GetDistance > 45f) continue; if (!u.InCombat) continue; result.Add(u); } } catch (Exception ex) { Logging.Write("[Warlock] GetMobsAttackingMe error: " + ex.Message); } return result; } private List GetAllEngagedMobs() { List result = new List(); try { List allUnits = ObjectManager.GetObjectWoWUnit(); for (int i = 0; i < allUnits.Count; i++) { WoWUnit u = allUnits[i]; if (u == null || !u.IsValid) continue; if (!u.IsAlive || !u.IsAttackable) continue; if (!u.IsTargetingMeOrMyPet) continue; if (u.GetDistance > 45f) continue; if (!u.InCombat) continue; result.Add(u); } } catch (Exception ex) { Logging.Write("[Warlock] GetAllEngagedMobs error: " + ex.Message); } return result; } private bool IsPetTankingMob(WoWUnit mob) { if (mob == null || !mob.IsValid || ObjectManager.Pet == null || !ObjectManager.Pet.IsValid) return false; return mob.IsTargetingMyPet; } private WoWUnit GetLowestHpTarget(List mobs) { if (mobs == null || mobs.Count == 0) return null; WoWUnit lowest = null; double lowestHp = 101; for (int i = 0; i < mobs.Count; i++) { WoWUnit m = mobs[i]; if (m != null && m.IsValid && m.IsAlive) { if (m.HealthPercent < lowestHp) { lowestHp = m.HealthPercent; lowest = m; } } } return lowest; } private ulong GetUnitGuid(WoWUnit unit) { if (unit == null || !unit.IsValid) return 0; try { return (ulong)unit.Guid.GetHashCode(); } catch { return 0; } } private bool HandleAggroManagement() { if (!USE_AGGRO_MANAGEMENT) return false; if (ObjectManager.Pet == null || !ObjectManager.Pet.IsValid || !ObjectManager.Pet.IsAlive) return false; List mobsAttackingMe = GetMobsAttackingMe(); if (mobsAttackingMe.Count > 0) { WoWUnit priorityTarget = mobsAttackingMe[0]; _priorityTargetGuid = GetUnitGuid(priorityTarget); _priorityTargetUnit = priorityTarget; ulong currentGuid = GetUnitGuid(ObjectManager.Target); if (currentGuid != _priorityTargetGuid) { Logging.Write("[Warlock] AGGRO: Switching to " + priorityTarget.Name); ObjectManager.Me.Target = priorityTarget.Guid; } // Отправляем пета на моба, атакующего варлока Lua.LuaDoString("PetAttack();"); // Felguard Intercept если доступен и пет не на КД if (USE_PET_INTERCEPT_AGGRO && priorityTarget.GetDistance <= 25f && ObjectManager.Pet.Position.DistanceTo(priorityTarget.Position) >= 8f && ObjectManager.Pet.Position.DistanceTo(priorityTarget.Position) <= 25f) { TryPetIntercept(); } _lastTargetSwitch = DateTime.Now; return true; } // Если приоритетная цель ещё жива и всё ещё на нас if (_priorityTargetGuid != 0) { if (_priorityTargetUnit == null || !_priorityTargetUnit.IsValid || !_priorityTargetUnit.IsAlive || !_priorityTargetUnit.IsTargetingMe) { _priorityTargetGuid = 0; _priorityTargetUnit = null; } else { ulong currentGuid = GetUnitGuid(ObjectManager.Target); if (currentGuid != _priorityTargetGuid) { ObjectManager.Me.Target = _priorityTargetUnit.Guid; } Lua.LuaDoString("PetAttack();"); return true; } } // Lowest HP targeting - переключаемся на моба с минимальным HP if (!USE_LOWEST_HP_TARGETING) return false; if ((DateTime.Now - _lastTargetSwitch).TotalSeconds < 3) return false; List allEngaged = GetAllEngagedMobs(); if (allEngaged.Count <= 1) return false; // Только если ВСЕ мобы на пете (не на нас) bool allOnPet = true; for (int i = 0; i < allEngaged.Count; i++) { if (!IsPetTankingMob(allEngaged[i])) { allOnPet = false; break; } } if (!allOnPet) return false; WoWUnit lowestHp = GetLowestHpTarget(allEngaged); if (lowestHp == null || !ObjectManager.Target.IsValid) return false; ulong myCurrentGuid = GetUnitGuid(ObjectManager.Target); ulong lowestGuid = GetUnitGuid(lowestHp); if (myCurrentGuid == lowestGuid) return false; double currentTargetHp = ObjectManager.Target.HealthPercent; double lowestHpPercent = lowestHp.HealthPercent; if (currentTargetHp - lowestHpPercent > 25 || lowestHpPercent < 10) { ObjectManager.Me.Target = lowestHp.Guid; _lastTargetSwitch = DateTime.Now; Logging.Write("[Warlock] Lowest HP: " + lowestHp.Name + " (" + lowestHp.HealthPercent.ToString("F0") + "%)"); } return false; } // Felguard Intercept через pet action bar private void TryPetIntercept() { try { // В TBC Felguard Intercept находится на pet action bar. // Ищем слот с Intercept и кастуем если не на КД. string lua = "for i=1,10 do " + " local name, _, _, _, _, _, _ = GetPetActionInfo(i); " + " if name == 'Intercept' then " + " local start, duration, enable = GetPetActionCooldown(i); " + " if enable == 1 and (start == 0 or (start + duration - GetTime()) <= 0) then " + " CastPetAction(i); " + " end " + " break; " + " end " + "end"; Lua.LuaDoString(lua); } catch { // ignore } } // ==================== УПРАВЛЕНИЕ ПИТОМЦЕМ ==================== private void PetManager() { WoWLocalPlayer me = ObjectManager.Me; WoWUnit pet = ObjectManager.Pet; if (me.IsDeadMe || me.IsMounted || me.IsCast) return; // Призыв Felguard если нет питомца if (USE_FELGUARD && (!pet.IsValid || !pet.IsAlive) && SummonFelguard.KnownSpell && SummonFelguard.IsSpellUsable && ItemsManager.HasItemById(SOUL_SHARD_ID)) { Logging.Write("[Warlock Demo] Summoning Felguard..."); SummonFelguard.Launch(); Thread.Sleep(Usefuls.Latency + 12000); return; } // Fel Domination — экстренный быстрый призыв если питомец умер в бою if (USE_FEL_DOMINATION && Fight.InFight && (!pet.IsValid || !pet.IsAlive) && FelDomination.KnownSpell && FelDomination.IsSpellUsable && SummonFelguard.KnownSpell && ItemsManager.HasItemById(SOUL_SHARD_ID) && !me.IsCast) { Logging.Write("[Warlock Demo] Fel Domination - emergency summon."); FelDomination.Launch(); Thread.Sleep(Usefuls.Latency + 200); SummonFelguard.Launch(); Thread.Sleep(Usefuls.Latency + 6000); } } // ==================== SOUL LINK ==================== private void TrySoulLink() { if (USE_SOUL_LINK && SoulLink.KnownSpell && SoulLink.IsSpellUsable && !ObjectManager.Me.HaveBuff("Soul Link") && ObjectManager.Pet.IsValid && ObjectManager.Pet.IsAlive && !ObjectManager.Me.IsCast) { SoulLink.Launch(); Thread.Sleep(Usefuls.Latency + 100); } } // ==================== БАФЫ ==================== private void BuffRotation() { if (Fight.InFight || ObjectManager.Me.InCombat) return; WoWLocalPlayer me = ObjectManager.Me; if (me.IsCast) return; // Demon Armor (приоритет над Demon Skin) if (USE_DEMON_ARMOR && DemonArmor.KnownSpell && DemonArmor.IsSpellUsable) { int timeLeft = me.BuffTimeLeft("Demon Armor"); if (timeLeft <= 0 || (timeLeft > 0 && timeLeft < BUFF_REBUFF_TIME_MS && !me.IsMounted)) { DemonArmor.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } } // Demon Skin если Armor не известен else if (DemonSkin.KnownSpell && DemonSkin.IsSpellUsable && !DemonArmor.KnownSpell) { int timeLeft = me.BuffTimeLeft("Demon Skin"); if (timeLeft <= 0 || (timeLeft > 0 && timeLeft < BUFF_REBUFF_TIME_MS && !me.IsMounted)) { DemonSkin.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } } // Soul Link TrySoulLink(); // Unending Breath под водой (ребафф за 1.5-2 мин до конца) if (USE_UNENDING_BREATH && UnendingBreath.KnownSpell && UnendingBreath.IsSpellUsable && me.IsSwimming && !me.IsCast) { int breathTimeLeft = me.BuffTimeLeft("Unending Breath"); // breathTimeLeft в мс: 0 = нет бафа, rebuff за 90-120 сек до конца if (breathTimeLeft <= 0 || breathTimeLeft < _unendingBreathRebuffMs) { UnendingBreath.Launch(); Thread.Sleep(Usefuls.Latency + 100); // Новый рандомный порог для следующего ребаффа _unendingBreathRebuffMs = _humanRnd.Next(90000, 120000); } } } // ==================== КРАФТ ХИЛСТОНА ==================== private void CraftHealthstone() { if (Fight.InFight || ObjectManager.Me.InCombat) return; if (ObjectManager.Me.IsDeadMe) return; if (!ItemsManager.HasItemById(SOUL_SHARD_ID)) return; // Не тратить последний шард на хилстон int shardCount = ItemsManager.GetItemCountById((int)SOUL_SHARD_ID); if (shardCount <= 1) return; WoWLocalPlayer me = ObjectManager.Me; if (me.IsCast || me.IsMounted) return; if (!ObjectManager.Pet.IsValid || !ObjectManager.Pet.IsAlive) return; if (GetAvailableHealthstoneId() > 0) return; MovementManager.StopMoveTo(false, 5000); CreateHealthstone.Launch(); Thread.Sleep(Usefuls.Latency); Usefuls.WaitIsCasting(); } // ==================== УДАЛЕНИЕ ШАРДОВ ==================== private void DeleteExtraSoulShards() { if (Fight.InFight || ObjectManager.Me.InCombat) return; int count = ItemsManager.GetItemCountById((int)SOUL_SHARD_ID); while (count > MAX_SOUL_SHARDS) { Logging.Write("[Warlock Demo] Deleting extra Soul Shard (" + count + " > " + MAX_SOUL_SHARDS + ")."); Lua.LuaDoString("for bag=0,4 do for slot=1,C_Container.GetContainerNumSlots(bag) do local info=C_Container.GetContainerItemInfo(bag,slot) if info and info.itemID==6265 then C_Container.PickupContainerItem(bag,slot) DeleteCursorItem() return end end end"); Thread.Sleep(300); count = ItemsManager.GetItemCountById((int)SOUL_SHARD_ID); } } // ==================== БОЕВАЯ РОТАЦИЯ ==================== private void CombatRotation() { WoWLocalPlayer me = ObjectManager.Me; WoWUnit target = ObjectManager.Target; WoWUnit pet = ObjectManager.Pet; if (target == null || !target.IsAlive) return; if (target.IsTapDenied && !target.IsTargetingMeOrMyPet) { Logging.Write("[Warlock] Target tagged by other player, skipping"); Lua.LuaDoString("PetFollow()"); Fight.StopFight(); Interact.ClearTarget(); return; } if (target.InCombat && !target.IsTargetingMeOrMyPet && target.GetMove && !target.Fleeing) { Logging.Write("[Warlock] Target in evade mode, skipping"); Fight.StopFight(); Interact.ClearTarget(); return; } bool isCasting = me.IsCast; bool petValid = pet.IsValid && pet.IsAlive; double myHp = me.HealthPercent; double myMana = me.ManaPercentage; double targetHp = target.HealthPercent; int shards = ItemsManager.GetItemCountById(SOUL_SHARD_ID); bool lowMana = myMana <= LOW_MANA_THRESHOLD; // Pet attack обрабатывается через EnsurePetAttack() в главном цикле // Soul Link — восстановление в бою (диспел, ресумон пета и т.д.) TrySoulLink(); // ===== ЭКСТРЕННАЯ ЗАЩИТА ===== // Death Coil при критическом хп if (USE_DEATH_COIL && DeathCoil.KnownSpell && DeathCoil.IsSpellUsable && myHp <= DEATH_COIL_HP_THRESHOLD && !isCasting) { Logging.Write("[Warlock Demo] Death Coil - HP critical!"); DeathCoil.Launch(); Thread.Sleep(Usefuls.Latency + 500); return; } // Fear при критическом хп (цель не на питомце) if (USE_FEAR && Fear.KnownSpell && Fear.IsSpellUsable && myHp <= FEAR_HP_THRESHOLD && Fear.IsDistanceGood && !target.HaveBuff("Fear") && !target.IsTargetingMyPet && !isCasting) { Logging.Write("[Warlock Demo] Fear - HP critical!"); Fear.Launch(); Thread.Sleep(Usefuls.Latency + 1200); return; } // ===== ХИЛСТОН ===== if (USE_HEALTHSTONE && myHp <= HEALTHSTONE_HP_THRESHOLD) { uint hsId = GetAvailableHealthstoneId(); if (hsId > 0 && !(Bag.GetContainerItemCooldown((int)hsId) > 0)) { Logging.Write("[Warlock Demo] Using Healthstone."); ItemsManager.UseItem(hsId); Thread.Sleep(Usefuls.Latency + 100); } } // ===== ХИЛ ПИТОМЦА (высокий приоритет) ===== // Health Funnel — хил питомца if (USE_HEALTH_FUNNEL && HealthFunnel.KnownSpell && HealthFunnel.IsSpellUsable && petValid && pet.HealthPercent <= PET_HEAL_THRESHOLD && myHp >= HEALTH_FUNNEL_HP_MIN && HealthFunnel.IsDistanceGood && !isCasting) { Logging.Write("[Warlock Demo] Health Funnel - healing pet."); HealthFunnel.Launch(); DateTime hfTimeout = DateTime.Now.AddSeconds(11); while (_isLaunched && DateTime.Now < hfTimeout && me.IsCast) { Thread.Sleep(100); if (!ObjectManager.Pet.IsValid || !ObjectManager.Pet.IsAlive || ObjectManager.Pet.HealthPercent > 95) break; } return; } // ===== УПРАВЛЕНИЕ РЕСУРСАМИ ===== // Life Tap для маны пета (талант Mana Feed) if (USE_LIFE_TAP_PET_MANA && LifeTap.KnownSpell && LifeTap.IsSpellUsable && petValid && pet.ManaPercentage <= (uint)LIFE_TAP_PET_MANA_THRESHOLD && myHp >= LIFE_TAP_HP_MIN && !isCasting) { Logging.Write("[Warlock] Life Tap - pet mana low (" + pet.ManaPercentage + "%)"); LifeTap.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } // Life Tap при низкой мане и достаточном хп if (USE_LIFE_TAP && LifeTap.KnownSpell && LifeTap.IsSpellUsable && myMana <= LIFE_TAP_MANA_THRESHOLD && myHp >= LIFE_TAP_HP_MIN && !isCasting) { LifeTap.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } // Drain Soul — фарм осколков или регенерация маны через талант if (USE_DRAIN_SOUL && DrainSoul.KnownSpell && DrainSoul.IsSpellUsable && targetHp <= DRAIN_SOUL_TARGET_HP && (shards <= MAX_SOUL_SHARDS || myMana <= DRAIN_SOUL_MANA_THRESHOLD) && DrainSoul.IsDistanceGood && !isCasting) { DrainSoul.Launch(); DateTime dsTimeout = DateTime.Now.AddSeconds(16); while (_isLaunched && DateTime.Now < dsTimeout && me.IsCast) { Thread.Sleep(100); if (ObjectManager.Target == null || !ObjectManager.Target.IsAlive) break; } return; } // ===== DOT-ФАЗА (пропускаем при low mana) ===== if (!lowMana) { // Corruption if (USE_CORRUPTION && Corruption.KnownSpell && Corruption.IsSpellUsable && targetHp >= DOT_MIN_TARGET_HP && !target.HaveBuff("Corruption") && Corruption.IsDistanceGood && !isCasting) { Corruption.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } // Curse of Agony if (USE_CURSE_OF_AGONY && CurseOfAgony.KnownSpell && CurseOfAgony.IsSpellUsable && targetHp >= DOT_MIN_TARGET_HP && !target.HaveBuff("Curse of Agony") && CurseOfAgony.IsDistanceGood && !isCasting) { CurseOfAgony.Launch(); Thread.Sleep(Usefuls.Latency + 100); return; } // ===== ДОБИВАНИЕ ===== // Shadowburn при низком хп цели if (USE_SHADOWBURN && Shadowburn.KnownSpell && Shadowburn.IsSpellUsable && targetHp <= SHADOWBURN_TARGET_HP && shards >= SHADOWBURN_SHARDS_MIN && Shadowburn.IsDistanceGood && !isCasting) { Shadowburn.Launch(); Thread.Sleep(Usefuls.Latency + 500); return; } } // Drain Life при низком хп ИЛИ при low mana (основной инструмент восстановления) if (USE_DRAIN_LIFE && DrainLife.KnownSpell && DrainLife.IsSpellUsable && (myHp <= DRAIN_LIFE_HP_THRESHOLD || lowMana) && (myMana >= DRAIN_LIFE_MANA_MIN || lowMana) && DrainLife.IsDistanceGood && !isCasting && !(shards <= MAX_SOUL_SHARDS && targetHp <= SHADOW_BOLT_TARGET_HP_MIN)) { DrainLife.Launch(); DateTime dlTimeout = DateTime.Now.AddSeconds(6); while (_isLaunched && DateTime.Now < dlTimeout && me.IsCast) { Thread.Sleep(100); if (ObjectManager.Me.HealthPercent > DRAIN_LIFE_HP_THRESHOLD + 15) break; } return; } // ===== ФИЛЛЕР (пропускаем при low mana) ===== if (!lowMana) { // Shadow Bolt if (USE_SHADOW_BOLT && ShadowBolt.KnownSpell && ShadowBolt.IsSpellUsable && ShadowBolt.IsDistanceGood && myMana >= SHADOW_BOLT_MANA_MIN && targetHp > SHADOW_BOLT_TARGET_HP_MIN && !isCasting) { ShadowBolt.Launch(); } } // Wand — если не кастуем и не стреляем if (USE_WAND && !isCasting && !SpellManager.IsAutoRepeating("Shoot")) { SpellManager.CastSpellByNameLUA("Shoot"); } } // ==================== ХЕЛПЕРЫ ==================== private uint GetAvailableHealthstoneId() { uint[] healthstoneIds = { HS_MASTER_ID, HS_MAJOR_ID, HS_GREATER_ID, HS_NORMAL_ID, HS_LESSER_ID, HS_MINOR_ID }; foreach (uint id in healthstoneIds) { if (ItemsManager.HasItemById(id)) return id; } return 0; } }