--[[
Предполагается мультиклассовая игра всеми 8-ю классами Альянса, т.е. пока что
всеми, кроме класса Shaman, и не учтены специфические заклинания которые
получают некоторые сочетания раса+класс за Орду. С полным прохождением всего
содержания WoW Classic 1.12: подземелий, overworld elites/bosses, рейдов.
Основной упор - на усиливающие заклинания, ближний бой и исцеление. Бега с
луками и AoE магией становятся необходимыми (в некоторых ситуациях) лишь на
высоких уровнях. Множитель талантов x8 на каждый уровень (начиная с L10),
работает в ядрах, производных от MANGoS, ретроактивно, очень корректно: при
изменении множителя и уровня персонажа всё пересчитывается.
]]

--[[
Customize Action Bar #6:
  1: Curse (Warlock)
  2: Sting (Hunter)
  3: Seal on enemy (Paladin). If empty: of Wisdom for 1H, none for 2H
  4: Seal on self (Paladin). If empty: of the Crusader
  5: Main-Hand Weapon
  6: Shield
  7: Off-Hand Weapon
  8: 2H-Weapon
  9: Backstab Weapon
  10-12: not used for now
Options (reset on ReloadUI):
  magres    /b mr
  nodrink   /b nd
  nocleave  /b nc
  noblock   /b nb
ItemRack addon: item set "sneak" will be unequipped before Ambush/Garrote
]]

aal_PaladinSealIcons = {
 "Ability_ThunderBolt",
 "Ability_Warrior_InnerRage",
 "Spell_Holy_SealOfWrath",
 "Spell_Holy_HolySmite",
 "Spell_Holy_HealingAura",
 "Spell_Holy_RighteousnessAura",
 "INV_Misc_Rune_01" -- slot with Hearthstone disables use of Paladin's Seal
}

function AAL_IsActBarPaladinSeal(slot)
  return AAL_IsActBar(slot, unpack(aal_PaladinSealIcons))
end


aal_WarlockCurseNames = { "Weakness","Agony","Recklessness","Tongues","Elements","Shadow","Doom","Exhaustion" }
aal_WarlockCurseIcons = {
 "Spell_Shadow_CurseOfMannoroth",
 "Spell_Shadow_CurseOfSargeras",
 "Spell_Shadow_UnholyStrength",
 "Spell_Shadow_CurseOfTounges",
 "Spell_Shadow_ChillTouch",
 "Spell_Shadow_CurseOfAchimonde",
 "Spell_Shadow_AuraOfDarkness",
 "Spell_Shadow_GrimWard"
}

aal_BleedBlocker = { ["Mechanical"]=true, ["Not specified"]=true, ["Totem"]=true, ["Gas Cloud"]=true}


-- Установка действий

function AAL_LoadActions(isInit --[[true при входе в игру или перезагрузке UI]] )

  if isInit then

     if aalcfg == nil then aalcfg = {} end
     -- частные настройки
     if UnitName("player") == "Osiriena" and UnitLevel("Player") >= 60 then
        aalcfg.nodrink=true;
        aalcfg.noblock=98; -- порог для Dodge+Parry+Block+calculatedMiss; passive uncrushable @ 102.4% для L60 vs L63
        AAL_Macro("MACRO BotAttack", "/run TargetNearestEnemy()\n/t Marenzu attack")
     end

     AAL_ASL_RANGED = 2
     -- Action Bar 6 contains user-defined spells and weapons acting as "variable parameters" for scripts
     AAL_ASL_CURSE  = 61
     AAL_ASL_STING  = 62
     AAL_ASL_SEAL_JUDGE  = 63
     AAL_ASL_SEAL_BUFF   = 64
     AAL_ASL_WEAPON_A = 65
     -- совместимость с "раскладкой" в прежних сохранениях игры
     if AAL_IsActBarPaladinSeal(AAL_ASL_SEAL_JUDGE) == false then
        AAL_ASL_WEAPON_A = 63
        AAL_ASL_SEAL_JUDGE  = AAL_ASL_WEAPON_A+4
        AAL_ASL_SEAL_BUFF   = AAL_ASL_WEAPON_A+5
     elseif AAL_IsActBarPaladinSeal(AAL_ASL_SEAL_BUFF) == false then
        AAL_ASL_WEAPON_A = 64
        AAL_ASL_SEAL_BUFF   = AAL_ASL_WEAPON_A+4
     end
     AAL_ASL_SHIELD = AAL_ASL_WEAPON_A+1
     AAL_ASL_WEAPON_B = AAL_ASL_WEAPON_A+2
     AAL_ASL_WEAPON_2H = AAL_ASL_WEAPON_A+3
     AAL_ASL_BACKSTABBER = AAL_ASL_WEAPON_A+4
  end

  local isBear = AAL_IsActiveSpell("Dire Bear Form") or AAL_IsActiveSpell("Bear Form")
  local isCat  = false
  if not isBear then isCat = AAL_IsActiveSpell("Cat Form"); end

  local _,class = UnitClass("player")
  local isCaster = (class ~= "WARRIOR" and class ~= "ROGUE")
  --print("AAL_LoadActions:", class)

  local ranged
  if     aal_RangedWeaponType == "Thrown" and aal_Abilities["Throw"] ~= nil then ranged = "Throw"
  elseif aal_RangedWeaponType == "Wands"  and aal_Abilities["Shoot"] ~= nil then ranged = "Shoot"
  elseif aal_Abilities["Auto Shot"] ~= nil then ranged = "Auto Shot"
  elseif aal_Abilities["Shoot Bow"] ~= nil then ranged = "Shoot Bow"
  else ranged = "Shoot"
  end

  local function LoadDefaultBar(i)
    if isCaster then
       AAL_Actions(
i,  "Frostbolt", ranged, "Attack", "Frost Nova/Blast Wave/Piercing Howl", "?Life Tap/Eviscerate/Slice and Dice", "Sunder Armor", "Evasion", "Divine Shield/Divine Protection", "Vanish", "Sprint/Blink/Goblin Rocket Boots/Gnomish Rocket Boots", "Cone of Cold", "?Retaliation"
       )
    else
       AAL_Actions(
i,  "Slam/Disarm", ranged, "Attack", "Piercing Howl/Frost Nova/Blast Wave", "?Life Tap/Eviscerate/Slice and Dice", "Sunder Armor", "Evasion", "Retaliation", "Vanish", "Sprint/Blink", "Execute", "?Retaliation"
       )
    end
    -- AAL_Macro("MACRO ComboAttack", "/run AAL_ComboAttack()", i+4) -- лучше добавить поддержку "MACRO ..." в AAL_Actions()
  end

  if isInit then
     LoadDefaultBar(1)  -- no stance
     LoadDefaultBar(85) -- Defensive Stance
  end

  if isCat then -- Cat Form
     AAL_Actions(
73, "Ravage", "Shred", "Attack", "Ferocious Bite", "Rip", "Rake", "Claw", "Tiger's Fury", "Pounce", "Dash", "Cower", ranged
     )
     aal_wasCat = true
  elseif isInit or aal_wasCat then -- восстановить Battle Stance
     LoadDefaultBar(73)
     aal_wasCat = nil
  end

  if isBear then -- Bear Form
     AAL_Actions(
97, "Enrage", "Maul", "Attack", "Swipe", "Bash", "Demoralizing Roar", "Challenging Roar", "Growl", "Frenzied Regeneration", "Counterspell", "Distract", ranged
     )
     aal_wasBear = true
  elseif isInit or aal_wasBear then -- восстановить Berserker Stance
     LoadDefaultBar(97)
     aal_wasBear = nil
  end

  if isInit then
     AAL_Actions(
-- action bars 2,3,4 дают возможность использовать IsActionInRange(aslot), а также IsUsableAction(aslot), которая проверяет достаточность Mana/Rage/Energy и некоторые др. условия (но не CD, не расстояние до цели, не правильность ориентации, не RequiredLevel consumable вещи, не "target is too low level" в случае Thorns)
13, "Bloodrage", "Berserker Rage", "Battle Shout", "Demoralizing Shout", "Intimidating Shout", "Challenging Shout", "Piercing Howl", "Thunder Clap", "Heroic Strike", "Cleave", "Whirlwind", "Shield Bash", "Pummel", "Sunder Armor", "Taunt", "Mocking Blow", "Hamstring", "Shield Block", "Shield Wall", "Shield Slam", "Concussion Blow", "Revenge", "Overpower", "Execute", "Charge", "Intercept", -- "Rend"
    "Riposte", "Ghostly Strike", "Sinister Strike", "Eviscerate", "Rupture", "Slice and Dice", "Kidney Shot", "Gouge", "Kick", "Sap", "Blind",
    "Raptor Strike", "Wing Clip", "Mongoose Bite", "Counterattack", "Scatter Shot", "Arcane Shot",
    "Hammer of Justice", "Judgement", "Holy Shield",
    "Fire Blast",
-- action bar 6, потенциально динамически модифицируемые операции
61, "?curse", "?sting", "?sealJudge", "?sealBuff", "?mainhand", "?shield", "?offhand", "?2Hand", "?", "?", "?", "?"
     )
  end
end



function AAL_SwitchWeapons()
  -- Меняет по правилам оружие, установленное в пользовательские * слоты ActionBar
  -- MH+S -> MH+OH / 2H; MH+OH -> !2H / MH+S; (2H) -> MH+S / MH+OH / 2H;
  -- ?+(S) -> ?+OH|MH+(S) / 2H; ?+(OH) -> ?+S / !MH+(OH) / 2H; ?+? -> ?+S / ?+OH / 2H
  if IsInventoryItemLocked(AAL_INV_MAINHAND) or IsInventoryItemLocked(AAL_INV_OFFHAND) then return end

  local canChangeStances = not UnitAffectingCombat("player") and not AAL_IsBuff("player", "Ability_Stealth", "Ability_Ambush"--[[Shadowmeld]])

  -- NB! В бою при взятии нового оружия (но не щита) запускается глобальный cooldown (GCD)

  local function TryEquip2H()
     if not IsUsableAction(AAL_ASL_WEAPON_2H) then return false; end
     if GetInventoryItemLink("player", AAL_INV_MAINHAND) ~= nil
        and GetInventoryItemLink("player", AAL_INV_OFFHAND) ~= nil
        and AAL_GetBagsFreeSpace() == 0 then
        return false
     end
     if canChangeStances and AAL_Cast("Berserker Stance", "Battle Stance") == false then return false; end
     UseAction(AAL_ASL_WEAPON_2H)
     return true
  end

  local function TryEquipWeaponAndShield(tryMain)
     if not IsUsableAction(AAL_ASL_SHIELD) then return false; end
     if tryMain and not IsUsableAction(AAL_ASL_WEAPON_A) then return false; end
     if canChangeStances and AAL_Cast("Defensive Stance") == false then return false; end
     if tryMain then UseAction(AAL_ASL_WEAPON_A); end
     UseAction(AAL_ASL_SHIELD);
     return true
  end

  local function TryEquipDual(tryMain, tryOffh)
     if tryOffh and not IsUsableAction(AAL_ASL_WEAPON_B) then return false; end
     if tryMain and not IsUsableAction(AAL_ASL_WEAPON_A) then return false; end
     if canChangeStances and AAL_Cast("Battle Stance", "Berserker Stance") == false then return false; end
     if tryMain then UseAction(AAL_ASL_WEAPON_A); end
     if not tryOffh then return tryMain; end
     if GetInventoryItemLink("player", AAL_INV_MAINHAND) ~= nil
        and GetInventoryItemLink("player", AAL_INV_OFFHAND) == nil
        then
        UseAction(AAL_ASL_WEAPON_B) -- наилучший способ, но обычно неприменим
        return true
     end
     -- Поиск по иконке, не исключены ложные совпадения, но если shield/offhand-оружие
     -- лежит в backpack и не меняет местоположение, то будет найдено первым.
     -- Простой код PickupInventoryItem(AAL_INV_OFFHAND); PutItemInBackpack(); UseAction(AAL_ASL_WEAPON_B)
     -- плох тем, что требует 1 свободное место в сумках и меняет местоположение вещей
     local bagID,i,eqLoc = AAL_FindInBagsByTexture(GetActionTexture(AAL_ASL_WEAPON_B))
     if bagID ~= nil then -- должно всегда выполняться, т.к. прошла проверка IsUsableAction(AAL_ASL_WEAPON_B)
        PickupContainerItem(bagID,i)
        PickupInventoryItem(AAL_INV_OFFHAND)
     end
     return true
  end

  local function EnsureStance(stance)
     if not canChangeStances then return false end
     local r = AAL_IsActiveSpell(stance)
     if r or r == false then return false; end
     CastSpellByName(stance)
     return true -- смена оружия только после того, как достигнут правильный stance для текущей комбинации
  end

  -- Если в руке ничего нет
  if GetInventoryItemLink("player", AAL_INV_MAINHAND) == nil then UseAction(AAL_ASL_WEAPON_A) end

  -- Логика смены оружия
  if IsEquippedAction(AAL_ASL_WEAPON_A) and IsEquippedAction(AAL_ASL_SHIELD) then
     --if EnsureStance("Defensive Stance") then return end
     if TryEquipDual(false,true) then return
     elseif TryEquip2H() then return
     end
  end
  if IsEquippedAction(AAL_ASL_WEAPON_A) and IsEquippedAction(AAL_ASL_WEAPON_B) then
     --if EnsureStance("Battle Stance") then return end
     -- во время боя с атакующего оружия приоритетно переключение на комбинацию с щитом
     if not UnitAffectingCombat("player") and TryEquip2H() then return
     elseif TryEquipWeaponAndShield(false) then return
     elseif TryEquip2H() then return
     end
  end
  local _,_,_,_,_,subclass = AAL_GetEquippedItem(AAL_INV_MAINHAND)
  if subclass~=nil and
     (string.sub(subclass,1,12) == "Fishing Pole" or subclass == "Polearms"
     or subclass == "Staves" or string.sub(subclass,1,10) == "Two-Handed")
     then
     --if EnsureStance("Berserker Stance") then return end
     if TryEquipWeaponAndShield(true) then return
     elseif TryEquipDual(true,true) then return
     elseif not IsEquippedAction(AAL_ASL_WEAPON_2H) and TryEquip2H() then return
     end
     return -- далее идут только одноручные варианты
  end
  local _,_,_,_,class,subclass = AAL_GetEquippedItem(AAL_INV_OFFHAND)
  if subclass == "Shields" then -- именно щиты, а не class "Armor", в который попадают +stat вещицы заклинателей
     local normal = not IsEquippedAction(AAL_ASL_WEAPON_B) -- ненормален случай, когда второе оружие поставлено в главную руку
     if TryEquipDual(not normal, normal) then return
     elseif TryEquip2H() then return
     end
  end
  if class == "Weapon" then
     if TryEquipWeaponAndShield(false) then return
     elseif not IsEquippedAction(AAL_ASL_WEAPON_A) and TryEquipDual(true,false) then return
     elseif TryEquip2H() then return
     end
  end
  if class == nil then
     -- одноручное оружие, а в левой руке ничего нет
     if TryEquip2H() then return
     elseif TryEquipWeaponAndShield(false) then return
     elseif TryEquipDual(false,true) then return
     end
  else
     -- все прочие одноручные варианты ?+?
     if TryEquipWeaponAndShield(false) then return
     elseif TryEquipDual(false,true) then return
     elseif TryEquip2H() then return
     end
  end
end


function AAL_Fishing()
  local poles = {
"Arcanite Fishing Pole",
"Nat Pagle's Extreme Angler FC-5000",
"Big Iron Fishing Pole",
"Darkwood Fishing Pole",
"Strong Fishing Pole",
"Blump Family Fishing Pole",
"Fishing Pole",
  }
  local main,_,_,_,_,mainsubtype = AAL_GetEquippedItem(AAL_INV_MAINHAND)
  if mainsubtype ~= nil and string.sub(mainsubtype,1,12) == "Fishing Pole" then
     CastSpellByName("Fishing")
     return
  end
  local off = AAL_GetEquippedItem(AAL_INV_OFFHAND)
  for i=1,table.getn(poles) do
    if AAL_Cast(poles[i]) then
       aal_UnequippedMainhand = main
       aal_UnequippedOffhand = off
       return
    end
  end
  CastSpellByName("Fishing")
end


function AAL_CheckSwapWeapons(reqMainDagger)
  -- reqMainDagger : true, false, nil
  -- returns : -1 = swapped, 0 = slow weapon, 1 = fast weapon, 2 = dagger in Main Hand

  local _, mainId, mainInv, mainIcon
  local main = GetInventoryItemLink("player", AAL_INV_MAINHAND)
  if main ~= nil then
     _,_,mainId = string.find(main, "item:(%d+):")
     if mainId ~= nil then
        _,_,_,_,_,main,_,mainInv,mainIcon = GetItemInfo( mainId )
        -- Берёт прежнее оружие, если в руках - удочка
        if string.sub(main,1,12) == "Fishing Pole" and not IsEquippedAction(AAL_ASL_WEAPON_2H)
           and AAL_Cast(aal_UnequippedMainhand) then
               AAL_Cast(aal_UnequippedOffhand)
               return -1
        end
     else
        main = nil
     end
  end

  local offId, offtype, offIcon
  local off = GetInventoryItemLink("player", AAL_INV_OFFHAND)
  if off ~= nil then
     --if reqMainDagger == nil then return 1; end -- оптимизация
     _,_,offId = string.find(off, "item:(%d+):")
     if offId ~= nil then
        _,_,_,_,offtype,off,_,_,offIcon = GetItemInfo( offId )
     else
        off = nil
     end
  end
  --print("Main:", main, mainId, mainInv, "Off:", offtype, off, offId)

  --if off == nil and mainInv ~= "INVTYPE_2HWEAPON" then UseAction(AAL_ASL_SHIELD) end

  -- NB! Распознавание оружия по иконкам может давать сбои при одинаковых картинках разного оружия
  if reqMainDagger == false and (GetActionTexture(AAL_ASL_WEAPON_A) == mainIcon or mainInv == "INVTYPE_2HWEAPON") then
     -- оптимизация
  elseif reqMainDagger == false and off == nil and IsUsableAction(AAL_ASL_WEAPON_2H)
  then
     -- Возвращаем двуручное оружие, признаком необходимости чего служит пустая левая рука
     UseAction(AAL_ASL_WEAPON_2H)
     return -1
  elseif reqMainDagger == false
     and (GetActionTexture(AAL_ASL_BACKSTABBER) == mainIcon or GetActionTexture(AAL_ASL_WEAPON_B) == mainIcon)
     and GetActionTexture(AAL_ASL_WEAPON_A) ~= offIcon and IsUsableAction(AAL_ASL_WEAPON_A)
  then
     UseAction(AAL_ASL_WEAPON_A)
     return -1
  elseif reqMainDagger == true and IsUsableAction(AAL_ASL_BACKSTABBER) then
     local bsIcon = GetActionTexture(AAL_ASL_BACKSTABBER)
     if bsIcon ~= mainIcon and bsIcon ~= offIcon  or mainInv == "INVTYPE_2HWEAPON" then
        UseAction(AAL_ASL_BACKSTABBER)
        return -1
     end
     if mainInv == "INVTYPE_WEAPONMAINHAND" and bsIcon == offIcon then
        UseAction(AAL_ASL_SHIELD)
        -- при следующем вызове этой функции вместо MainHand поставится Backstabber
        return -1
     end
  elseif mainInv == "INVTYPE_WEAPON" and ( -- в правой руке должно быть оружие, которое можно держать и в левой
     (reqMainDagger == true and main ~= "Daggers" and off == "Daggers") or
     (reqMainDagger == false and main == "Daggers" and offtype == "Weapon" and off ~= "Daggers" and off ~= "Miscellaneous"--[[like Skinning Knife]] and tonumber(offId) ~= 871--[[Flurry Axe]])
     ) -- NB! проверять mainSpeed < offSpeed не годится, т.к. на mainSpeed влияет SotC
  then
     ClearCursor()
     PickupInventoryItem(AAL_INV_MAINHAND)
     PickupInventoryItem(AAL_INV_OFFHAND)
     -- обмен срабатывает не сразу, и даже может не успеть до повторного нажатия клавиши
     -- вещи, по идее, блокируются, и повторные попытки обмена не должны повредить
     return -1
  end

  if main == "Daggers" then return 2; end
  if off ~= nil then return 1 end
  if mainId == 9449--[[Manual Crowd Pummeler]] or UnitAttackSpeed("player") < 1.4 then return 1; end
  return 0
end


function AAL_ChangeStance()
  local _,_,_,_,_,subclass = AAL_GetEquippedItem(AAL_INV_OFFHAND)

  if AAL_IsActiveSpell("Defensive Stance") then AAL_Cast("Battle Stance", "Berserker Stance")
  elseif AAL_IsActiveSpell("Berserker Stance") then
    if subclass == "Shields" then AAL_Cast("Defensive Stance", "Battle Stance")
    else AAL_Cast("Battle Stance", "Defensive Stance") end
  else -- from Battle Stance
    if subclass == "Shields" then AAL_Cast("Defensive Stance", "Berserker Stance")
    else AAL_Cast("Berserker Stance", "Defensive Stance") end
  end
end



-- Буффы

function AAL_TargetAllyOrPet()
  if not UnitIsEnemy("player", "target") and UnitIsPVP("target") and not UnitIsUnit("target", "player") then return "target"
  elseif not UnitExists("pet") then return nil
  else return "pet"
  end
end


function AAL_BuffPet()
  local tar = AAL_TargetAllyOrPet()
  if tar == nil then return end

  if tar == "pet" and UnitCreatureFamily("pet") == "Imp" then
     if not AAL_IsAura("Spell_Shadow_BloodBoil") then AAL_PetCast("Blood Pact")
     elseif not AAL_IsAura("Spell_Fire_FireArmor") then
        TargetUnit("player")
        AAL_PetCast("Fire Shield")
        AAL_RestoreTarget()
     end
  end

  local otherBlessings = {"Spell_Holy_SealOfValor"--[[Freedom]], "Spell_Holy_PrayerOfHealing02"--[[Light]], "Spell_Holy_SealOfProtection", "Spell_Holy_SealOfSacrifice", "Spell_Holy_SealOfSalvation", "Spell_Nature_LightningShield"--[[Sanctuary]], "Spell_Holy_SealOfWisdom" }
  local spellbuffs = {
    "Thorns",                {"Spell_Nature_Thorns"},
    "Blessing of Kings",     {"Spell_Magic_MageArmor"--[[Kings]], unpack(otherBlessings)},
    "Blessing of Might",     {"Spell_Holy_FistOfJustice"--[[Might]], unpack(otherBlessings)},
    "Power Word: Fortitude", {"Spell_Holy_WordFortitude"},
    "Mark of the Wild",      {"Spell_Nature_Regeneration"},
  }

  if AAL_IsBuff("player", "Spell_Shadow_AntiShadow"--[[Shadow Protection, Shadow Ward]]) then
     table.insert(spellbuffs, "Shadow Protection");
     table.insert(spellbuffs, {"Spell_Shadow_AntiShadow"});
  end

  for i = 1,table.getn(spellbuffs),2 do
    if aal_Abilities[ spellbuffs[i] ] ~= nil and not AAL_IsBuff(tar, unpack(spellbuffs[i+1])) then
       local flag = (spellbuffs[i] == "Blessing of Might" and 0) or (spellbuffs[i] == "Blessing of Kings" and 1)
       if flag then -- если 0 или 1, но не false
          -- Если Growl отключён, то вместо Blessing of Kings использовать Blessing of Might (больше DPS, меньше HP)
          local _, _,_,_,_,_,_,autoCastEnabled = AAL_GetPetAction("Growl")
          if autoCastEnabled then flag = 1 - flag end
       end
       if flag ~= 1 then
          if tar ~= "target" then TargetUnit(tar) end
          CastSpellByName( spellbuffs[i] )
          AAL_RestoreTarget()
          return
       end
    end
  end
end


function AAL_ProtectPet()
  local tar = AAL_TargetAllyOrPet()
  if tar == nil then return end
  if tar ~= "target" then TargetUnit(tar) end
  CastSpellByName("Blessing of Protection")
end

function AAL_PetAttackOrSummon()
  if PetHasActionBar() then
     if not UnitExists("target") and UnitAffectingCombat("player") then TargetNearestEnemy() end
     local i,_,_,icon = AAL_GetPetAction("Prowl")
     if i and string.sub(icon, -6) == "Vanish" and UnitAffectingCombat("player") then CastPetAction(i) end
     -- Для worldboss'ов придётся нажимать иконку атаки. Случайное нажатие
     -- клавиши фатально если это Lord Kazzak, и лишь приводит к
     -- преждевременной смерти питомца на других worldboss'ах
     if UnitClassification("target") == "worldboss" and UnitName("target") ~= "Buru the Gorger" then
        UIErrorsFrame:AddMessage("Use pet action bar icon to attack worldboss",1,0,0)
        return
     end
     PetAttack()
  else
     CastSpellByName("Call Pet")
  end
end

function AAL_PetReviveOrFeedOrTauntOrTame()
  if UnitIsDead("pet") then CastSpellByName("Revive Pet")
  elseif PetHasActionBar() then
     if UnitAffectingCombat("pet") then
        AAL_PetCast("Growl","Torment")
        if AAL_Cast(3, "-20 Feint", ".Disengage") or AAL_Cast(".Fade") then end
        -- У Feint, Disengage и Fade общий CD; по идее вблизи надо применять сперва Feint, но минимальное проверяемое расстояние 10, а Feint и Disengage действуют в пределах 5
     elseif UnitAffectingCombat("player") then PetAttack()
     else
        OpenAllBags(true)
        CastSpellByName("Feed Pet")
     end
  else CastSpellByName("Tame Beast")
  end
end


function AAL_TravelOrAquaticForm()
  if AAL_Dismount() then SetView(3); return end
  local k = AAL_IsAura("Ability_Mount_JungleTiger")
  if k then
     if UnitAffectingCombat("player") then CancelPlayerBuff(k)
     elseif AAL_Cast(".Aspect of the Monkey") then return
     end
  end
  AAL_TrapErrors()
  if not AAL_Cast(".Travel Form") then aal_ErrorMsg = true end
  if aal_ErrorMsg == nil then SetView(4)
  elseif aal_ErrorMsg == SPELL_FAILED_ONLY_ABOVEWATER then
    AAL_ClearErrorMsg()
    CastSpellByName("Aquatic Form")
    if aal_ErrorMsg == nil then SetView(1) end
  end
  if aal_ErrorMsg == true then aal_ErrorMsg = nil; CastSpellByName("Ghost Wolf") end
  AAL_ShowErrorMsg()
  AAL_UntrapErrors()
end


function AAL_Mount()
  local form = AAL_GetForm()
  if form then CastSpellByName(form); return end
  if AAL_IsAura("Ability_Mount_JungleTiger", "Ability_Mount_WhiteTiger") and AAL_Cast("Aspect of the Monkey") ~= nil then return end
  if AAL_Cast("Black Qiraji Resonating Crystal") then return end
  if GetRealZoneText() == "Ahn'Qiraj"--[[AQ40]] and AAL_Cast("Red Qiraji Resonating Crystal", "Green Qiraji Resonating Crystal", "Yellow Qiraji Resonating Crystal", "Blue Qiraji Resonating Crystal") then return end

  local link = GetInventoryItemLink("player", 5--[[slot ID @chest]])
  local e1,e2, r1,r2 = "Summon Charger","Summon Dreadsteed", "Summon Warhorse","Summon Felsteed"
  if link ~= nil then
     local _,_, itemId = string.find(link, "item:(%d+):");
     local _,_,_,_,_,subtype = GetItemInfo( itemId )
     if subtype == "Cloth" then e1,e2, r1,r2 = e2,e1, r2,r1 end
  end
  AAL_Cast(
    --[[epic]] "Black Ram","Deathcharger's Reins","Frost Ram","Great Brown Kodo","Great Gray Kodo","Great White Kodo","Green Kodo","Green Skeletal Warhorse","Horn of the Arctic Wolf","Horn of the Frostwolf Howler","Horn of the Red Wolf","Horn of the Swift Brown Wolf","Horn of the Swift Gray Wolf","Horn of the Swift Timber Wolf","Icy Blue Mechanostrider Mod A","Palomino Bridle","Purple Skeletal Warhorse","Reins of the Frostsaber","Reins of the Nightsaber","Reins of the Swift Dawnsaber","Reins of the Swift Frostsaber","Reins of the Swift Mistsaber","Reins of the Swift Stormsaber","Reins of the Winterspring Frostsaber","Stormpike Battle Charger","Swift Blue Raptor","Swift Brown Ram","Swift Brown Steed","Swift Gray Ram","Swift Green Mechanostrider","Swift Olive Raptor","Swift Orange Raptor","Swift Palomino","Swift Razzashi Raptor","Swift White Mechanostrider","Swift White Ram","Swift White Steed","Swift Yellow Mechanostrider","Swift Zulian Tiger","Teal Kodo","Whistle of the Ivory Raptor","Whistle of the Mottled Red Raptor","White Mechanostrider Mod A","White Stallion Bridle",
    e1,e2, --[[rare]] "Black Battlestrider","Black War Kodo","Black War Ram","Black War Steed Bridle","Horn of the Black War Wolf","Red Skeletal Warhorse","Reins of the Black War Tiger","Whistle of the Black War Raptor","Black Stallion Bridle","Blue Mechanostrider","Blue Skeletal Horse","Brown Horse Bridle","Brown Kodo","Brown Ram","Brown Skeletal Horse","Chestnut Mare Bridle","Gray Kodo","Gray Ram","Green Mechanostrider","Horn of the Brown Wolf","Horn of the Dire Wolf","Horn of the Timber Wolf","Pinto Bridle","Red Mechanostrider","Red Skeletal Horse","Reins of the Golden Sabercat","Reins of the Primal Leopard","Reins of the Spotted Frostsaber","Reins of the Striped Frostsaber","Reins of the Striped Nightsaber","Reins of the Tawny Sabercat","Unpainted Mechanostrider","Whistle of the Emerald Raptor","Whistle of the Turquoise Raptor","Whistle of the Violet Raptor","White Ram","Reins of the Spotted Nightsaber",
    r1,r2
  )
end

function AAL_IsMounted(dismount)
  for i = 0, 100 do
    local k = GetPlayerBuff(i,"HELPFUL")
    if k < 0 --[[ or (AAL_wow_build >= 7000 and k == 0) ]] then break end
    local t = GetPlayerBuffTexture(k)
    if    string.find(t, "Ability_Druid_TravelForm",1,true)
       or string.find(t, "Ability_Druid_AquaticForm",1,true)
       or string.find(t, "Spell_Nature_SpiritWolf",1,true)
       then
       if dismount then
          CancelPlayerBuff(k)
          SetView(3)
       end
       return true
    end
    if    string.find(t, "Ability_Mount_",1,true) and not string.find(t, "Ability_Mount_JungleTiger",1,true)--[[Aspect of Cheetah => cannot recognize Swift Zulian Tiger]]
       or string.find(t, "Ability_Racial_BearForm",1,true)
       or string.find(t, "Ability_Druid_CatForm",1,true)
       or string.find(t, "Ability_EyeOfTheOwl",1,true)    -- Hunter: Eyes of the Beast
       or string.find(t, "Spell_Shadow_EvilEye",1,true)   -- Warlock: Eye of Kilrogg
       or string.find(t, "Spell_Nature_Swiftness",1,true) -- Paladin: Summon Warhorse
       or string.find(t, "INV_Misc_Fish_04",1,true) -- Hook of the Master Angler
       or string.find(t, "INV_Misc_Qiraji",1,true) -- Qiraji mounts
       or string.find(t, "INV_Misc_Branch_01",1,true) -- Reindeer
       then
       if dismount then
          CancelPlayerBuff(k)
       end
       return true
    end
  end
  return nil
end

function AAL_Dismount()
  return AAL_IsMounted(true)
end

function AAL_DismountOrToggleHunterRunAspect()
  if AAL_Dismount() then return end

  if AAL_IsAura("Ability_Hunter_AspectOfTheMonkey") or not UnitAffectingCombat("player") and not AAL_IsAura("Ability_Mount_JungleTiger") then CastSpellByName("Aspect of the Cheetah")
  else CastSpellByName("Aspect of the Monkey")
  end
end


function AAL_FindResourceSwitcher()
  local icon = GetTrackingTexture()
  local list = {"Find Treasure", "Find Minerals", "Find Herbs", "Track Humanoids", "Track Beasts"};
  if icon == nil then 
  elseif string.find(icon, "FindTreasure",1,true) then list = {"Find Minerals", "Find Herbs", "Track Humanoids", "Track Beasts"};
  elseif string.find(icon, "Earthquake",1,true) then list = {"Find Herbs", "Find Treasure", "Track Humanoids", "Track Beasts"};
  end
  AAL_Cast(unpack(list))
end


function AAL_StealthOrVanish()
  local k, i = AAL_IsAura("Ability_Stealth", "Ability_Druid_CatForm")
  if k then
     if i == 2 then CastSpellByName("Prowl"); return end -- иконка Prowl совпадает с Shadowmeld
     CancelPlayerBuff(k)
     -- если убрать след. строчку, то после Vanish при быстром выходе ещё несколько секунд может оставаться Improved Stealth
     k = AAL_IsAura("Ability_Vanish"); if k then CancelPlayerBuff(k) end
     return
  end
  if AAL_Dismount() then return end

  if UnitAffectingCombat("player") then AAL_StopAction(); AAL_Cast("Vanish", "Preparation", "Vanish")
  else AAL_Cast("Stealth", "Shadowmeld") -- из Shadowmeld переходит в Stealth, отмена Shadowmeld - движением
  end
end

function AAL_EmergencyCleanse()
  local i = AAL_IsDebuff("player",
"Spell_Arcane_PortalDarnassus"--[[Twisted Reflection]],
"Spell_Shadow_AntiShadow"--[[Mark of Kazzak]],
"INV_Misc_Head_Dragon_Bronze"--[[Brood Affliction: Bronze]],
"INV_Misc_Head_Dragon_Black","INV_Misc_Head_Dragon_Blue","INV_Misc_Head_Dragon_Green","INV_Misc_Head_Dragon_Red"--[[Brood Affliction: ...]] 
)
  if not i then
  elseif i == 1 or i >= 5 and i <= 7 then if AAL_Cast(true, ".Cleanse") then return true end
  elseif i == 2 or i == 4 then if AAL_Cast(true, ".Remove Curse") then return true end
  elseif i == 3 then if AAL_Cast("Hourglass Sand") then return true end
  end
  return false
end



-- Атакующие действия

local function meleeAttack_Cat()
  -- Melee Auto-Attack
  local aslot = aal_AbiSlots["Attack"]
  if not IsCurrentAction(aslot) then UseAction(aslot) end
end

local function meleeAttack_Bear()
  -- Melee Auto-Attack
  local aslot = aal_AbiSlots["Attack"]
  if not IsCurrentAction(aslot) then UseAction(aslot) end
  local r = aal_AbiSlots["Maul"] 
  if r and not IsCurrentAction(r) then AAL_Cast(".15 Maul") end
end


--[[
function AAL_IsAlreadyNextMelee()
  -- Не выполняет ожидаемую функцию, т.к. обнаруживает ожидание лишь сразу
  -- после Cast Heroic Strike и проч., но не после ещё действия/spell'а
  local r = aal_AbiSlots["Heroic Strike"]
  if r then r = IsCurrentAction(r); end
  if r == nil then
     r = aal_AbiSlots["Raptor Strike"]
     if r then r = IsCurrentAction(r); end
  end
  if r == nil then
     r = aal_AbiSlots["Cleave"]
     if r then r = IsCurrentAction(r); end
  end
  --if r then print("AAL_IsAlreadyNextMelee = [", r, "]") end
  return r
end
]]

function AAL_MeleeAttack()
  if not UnitExists("target") or UnitIsDead("target") and not UnitIsPlayer("target") then TargetNearestEnemy(); end

  local form, stance = AAL_GetForm()
  if not form then
  elseif form == "Cat Form" then return meleeAttack_Cat()
  elseif form == "Bear Form" or form == "Dire Bear Form" then return meleeAttack_Bear()
  else CastSpellByName(form); return end

  local isCombat = UnitAffectingCombat("player")

  if isCombat then
     if AAL_EmergencyCleanse() then return end

     local k,i = AAL_IsAura("Ability_Mount_JungleTiger", "Spell_Nature_SpiritWolf", "Spell_Shadow_ManaBurn"--[[Clearcasting - Mage's, not Druid's]])
     if not k then
     elseif i == 1 then if AAL_Cast(".Aspect of the Monkey") then return end -- Aspect of the Cheetah (can be dazed, no Dodge Bonus) ==> Aspect of the Monkey
     elseif i == 2 then CancelPlayerBuff(k)
     elseif i == 3 then
      -- Любое заклинание мага без расхода маны, в данном случае - из числа моментальных
      if aalcfg.nocleave then  if AAL_Cast(".0 Fire Blast") then return end
      elseif AAL_Cast(".0 Cone of Cold", ".0 Arcane Explosion", ".0 Fire Blast") then return
      end
     end
  end
  
  if stance == nil and not AAL_IsActiveSpell("Shadowform") and AAL_Cast("Battle Stance") then return end

  if not aalcfg.noblock or type(aalcfg.noblock)=="number" and AAL_GetBlockedAvoidance() < aalcfg.noblock then
     if stance == "Defensive Stance" -- and not AAL_IsAura("Spell_Holy_BlessingOfProtection"--[[Holy Shield]])
        and AAL_Cast("*Shield Block") then return end
     if not AAL_IsAura("Ability_Defend"--[[Shield Block]]) and AAL_Cast(stance == "Defensive Stance" and ".60 Holy Shield" or ".10 Holy Shield") then return end -- Holy Shield в Battle/Berserker Stance - полезная защита и доп. урон (не слишком экономный по мане и без заметных прибавок от SP+)
  end

  -- Melee Auto-Attack
  local aslot = aal_AbiSlots["Attack"]
  if not IsCurrentAction(aslot) then UseAction(aslot) end

  local weapons = AAL_CheckSwapWeapons(false)
  if weapons < 0 then return end

  if isCombat then
     if stance == "Berserker Stance" and AAL_Cast("Berserker Rage") then return end
  else
     if AAL_Cast("$60 Bloodrage") then return end
     if not(aalcfg.nocleave and isCombat) and AAL_Cast(stance == "Battle Stance" and "Charge" or "Intercept") then return end
  end

  local targetHP = UnitHealth("target")
  --if targetHP ~= 0 and (isCombat or targetHP < UnitHealthMax("target")) and AAL_Cast("*Intercept") then return end

  local myLevel = UnitLevel("player")
  local lowHP = (targetHP < myLevel*10);

  -- магия бесполезна из-за слишком высокого уровня?
  local uber = UnitLevel("target")
  uber = (uber == nil or uber > myLevel+5 or uber < 0 and UnitClassification("target") ~= "worldboss")

  if (targetHP >= 1500 or uber) and targetHP/UnitHealthMax("target") <= 0.20 and AAL_Cast("*Execute") then return end

  -- Коды определённых пользователем печатей паладина _JSeal и _BSeal
  -- 1:Righteousness, 2: Command, 3: Justice, 4: Crusader, 5: Light, 6: Wisdom, 7:DISABLE, nil/false: DEFAULT

  local _JSeal, JSeal
  if not lowHP then
     _JSeal = AAL_IsActBarPaladinSeal(AAL_ASL_SEAL_JUDGE)
     -- печать, которую сейчас имеет смысл сбрасывать на врага; для медленного оружия печать не сбрасывается
     JSeal = _JSeal~=7 and (_JSeal or weapons > 0 and (aal_Abilities["Seal of Wisdom"] and 6 or 4))
  end

  local ESeal = AAL_IsDebuff( unpack(aal_PaladinSealIcons) ) -- текущая печать на враге
  local indexOSeal, OSeal = AAL_IsAura( unpack(aal_PaladinSealIcons) ) -- печать на себе?

  -- Условие использования Heroic Strike и Raptor Strike (эффект SotC+SoR с ними срабатывает заметно реже)
  local useNextMelee = not ESeal or ESeal>=5 or ESeal==3 or  ESeal==4 and not OSeal

  -- Определить, сражаемся мы с одним врагом или с двумя и более
  local manyFoes = nil
  if not aalcfg.nocleave and UnitIsUnit("target", "playertarget") then
     -- Блокируем временно всплывающие сообщения в бою, т.к. смена цели вызывает повторные всплывающие сообшения о возможности применения способностей, что особенно досаждает, когда у врага < 20% HP, а у игрока есть Execute и Hammer of Wrath
     local savCTAM = CombatText_AddMessage;
     CombatText_AddMessage=function() end

     TargetNearestEnemy()
     if not UnitIsUnit("target", "playertarget") and CheckInteractDistance("target", 3) then -- в пределах 10 ярдов
        manyFoes = true
     end
     TargetUnit("playertarget")

     CombatText_AddMessage = savCTAM;
  end

  -- NB! Из-за NextMelee может выводиться поток сообщений Interrupted и
  -- "холостые" щелчки, связанные с несколькими подряд вызовами CastSpell...(),
  -- через AAL_Cast(), для Heroic Strike или Raptor Strike
  if not manyFoes and AAL_Cast("*Shield Slam") then return end
  if not manyFoes and useNextMelee --[[and not AAL_IsAlreadyNextMelee()]] then
     -- NextMelee-атаки не активируют GCD, и сразу после них можно ещё что-то использовать
     AAL_Cast("*Heroic Strike", ".80 Raptor Strike")
  else
     -- пытаемся набрать Rage для Whirlwind (если он доступен и если Berserker Stance)
     local isUsable = nil
     local noRage = nil
     local asl = aal_AbiSlots["Whirlwind"]
     if asl ~= nil then
        local _, duration = GetActionCooldown(asl)
        if duration <= 0 then isUsable, noRage = IsUsableAction(asl); end
     end
     if not isUsable and noRage then --print("Waiting for Whirlwind", GetTime())
     else
        if isUsable and AAL_Cast("*Whirlwind") then return end
        if manyFoes --[[and not AAL_IsAlreadyNextMelee()]] then
           if not AAL_Cast("*Cleave") and useNextMelee then
              if not AAL_Cast(".80 Raptor Strike", "*Heroic Strike")
                 and AAL_Cast("*Shield Slam") then return end
           end
        end
     end
  end

  if OSeal and not (uber and OSeal<=2) and (
     JSeal and (not ESeal or ESeal ~= JSeal and JSeal == OSeal) -- сброс OSeal на врага, в качестве нужной JSeal или чтобы освободить себя для JSeal
     or GetPlayerBuffTimeLeft(indexOSeal) <= 2 and (OSeal<=2 or not ESeal and OSeal~=3) -- сброс почти закончившейся OSeal на врага, но так, чтобы не сбить уже наложенную печать
     )
  then
     -- SotC сбрасывается на врага только если на себе предполагается держать SoR, иначе бесполезный расход маны и CD Judgement
     local function isSelfSoR()
       local r = AAL_IsActBarPaladinSeal(AAL_ASL_SEAL_BUFF)
       return not r and not aal_Abilities["Seal of Wisdom"]  or  r==1
     end
     if (OSeal~=4 or isSelfSoR()) and AAL_Cast((OSeal<=2 and ".40 " or OSeal==6 and "." or ".20 ").."Judgement") then return end
  end

  if JSeal and (not ESeal or ESeal ~= JSeal) then -- надо JSeal на врага?
     if OSeal ~= JSeal then
        -- JSeal на себя, чтобы затем сбросить на врага - сразу же, если на враге ничего нет, или к окончанию действия на себе, если что-то есть
        -- по умолчанию либо Seal of Wisdom, либо, если она ещё недоступна, Seal of the Crusader
        if _JSeal==6 or not _JSeal and aal_Abilities["Seal of Wisdom"] then
           if AAL_Cast(".7 Seal of Wisdom") then return end
        elseif _JSeal then if AAL_Cast(".30 " .. tostring(AAL_ASL_SEAL_JUDGE)) then return end
        else if AAL_Cast(".30 Seal of the Crusader") then return end
        end
     end
  elseif not OSeal then
     local _BSeal = AAL_IsActBarPaladinSeal(AAL_ASL_SEAL_BUFF) -- печать, которую надо удерживать на себе
     if _BSeal == 7 then -- ничего не удерживать на себе
     elseif _BSeal then
        if AAL_Cast((_BSeal==6 and ".10 " or ".30 ")..tostring(AAL_ASL_SEAL_BUFF)) then return end
     elseif weapons > 0 or manyFoes or targetHP > 70*myLevel then
        --if weapons == 0 and AAL_Cast(".30 Seal of Command(Rank 1)") then return end -- Увеличение ранга Seal of Command (на себе) лишь повышает урон от Judgement и невыгодно по мане

        -- Когда печати не определены: если есть Seal of Wisdom, то на себе удерживать SotC, иначе SoR
        if aal_Abilities["Seal of Wisdom"] then if AAL_Cast(".10 Seal of the Crusader") then return end
        else
           if AAL_Cast(".40 Seal of Righteousness", ".20 Seal of Righteousness(Rank 3)")
              or ESeal==4 --[[только если на враге есть SotC]] and AAL_Cast(".10 Seal of Righteousness(Rank 1)")
              then return end
        end
     end
  end

  -- local stunned = AAL_IsDebuffStunned()
  -- if not stunned and not uber and not lowHP and AAL_Cast(".50 Hammer of Justice") then return end


  -- Можно перенести "Rogue блок" в начало, но тогда DPS понижается
  if not AAL_IsAura("Ability_Rogue_SliceDice") and AAL_Cast("-Slice and Dice") then return end

  if AAL_Cast("-Riposte") then return end

  -- Overpower, Challenging Shout, Demoralizing Shout сбрасывают combo points
  if AAL_Cast("*Overpower") then return end -- NB! Возможность Overpower определяется клиентом WoW.exe по полю combo points, из-за чего Overpower становится совмещённой Warrior/Rogue способностью

  local gs = AAL_RemainingCD("Ghostly Strike")
  if gs > 0 and gs < 4 then -- ничего не делать, пусть набираются нужные 40 Energy, ~ +20 каждые 2 секунды
  elseif AAL_Cast(gs==0 and "-Ghostly Strike"
          or aal_Abilities["Hemorrhage"] and not aal_BleedBlocker[UnitCreatureType("target")] and not AAL_IsDebuff("Spell_Shadow_LifeDrain") and "-Hemorrhage"
          or "-Sinister Strike" ) then return
  -- Из-за мультиклассовых коллизий в игре классом Rogue клиент WoW.exe может занизить расход энергии на Sinister Strike, из-за чего нажатия клавиш вызывают лишь сообщения "Not Enough Energy", и снижается DPS
  end


  if not lowHP then
     for i = 0,1 do
       if i == (stance == "Defensive Stance" and 0  or  1) then
          if not uber and not AAL_IsDebuff("Ability_Warrior_WarCry") and AAL_Cast("*Demoralizing Shout") then return end
       else
          if not AAL_IsAura("Ability_Warrior_BattleShout") and AAL_Cast("*Battle Shout") then return end
       end
     end

     if not uber and not AAL_IsDebuff("Spell_Nature_ThunderClap") and AAL_Cast("*Thunder Clap") then return end

     if not uber and not AAL_IsDebuff("Ability_Warrior_Sunder") then
        local _, armor = UnitArmor("target")
        if armor ~= nil and armor > 500 and AAL_Cast("*Sunder Armor") then return end
     end
  end

  if AAL_Cast("*20 Revenge", ".80 Mongoose Bite", ".80 Counterattack", "$90 Bloodrage") then return end
end



function AAL_Shoot()
  if not UnitExists("target") then TargetNearestEnemy(); return end

  local form = AAL_GetForm()
  if form == "Cat Form" then UseAction(73-1 +1); return end
  if form == "Bear Form" or form == "Dire Bear Form" then UseAction(97-1 +1); return end
  if form then CastSpellByName(form) return end

  if aal_RangedWeaponType == "Thrown" then
     if IsActionInRange(AAL_ASL_RANGED)~=1 and CheckInteractDistance("target",3) then AAL_MeleeAttack(); return end
     AAL_Cast("Throw")
     return
  end

  if aal_RangedWeaponType == "Wands" then
     if not IsUsableAction(AAL_ASL_RANGED) then AAL_Actions(AAL_ASL_RANGED, "Shoot") end

  else
   if IsActionInRange(AAL_ASL_RANGED)~=1 and CheckInteractDistance("target",3) then AAL_MeleeAttack(); return end

   local ranged
   if aal_Abilities["Auto Shot"] ~= nil then ranged = "Auto Shot"
   elseif aal_Abilities["Shoot Bow"] ~= nil then ranged = "Shoot Bow"
   end
   if ranged ~= nil and not AAL_IsGCD() then
      if not IsUsableAction(AAL_ASL_RANGED) then AAL_Actions(AAL_ASL_RANGED, ranged) end

      if not UnitAffectingCombat("player") and not AAL_IsDebuff("Ability_Hunter_SniperShot") then
         if AAL_Cast(".Hunter's Mark") then return end
      end
      if UnitClassification("target") ~= "worldboss" and not AAL_IsDebuffSlowed() then
         if AAL_Cast(--[["Scatter Shot",]] ".85 Concussive Shot") then return end
      end

      local castDone
      if not AAL_IsDebuff("Ability_Hunter_Quickshot", "Ability_Hunter_CriticalShot", "Ability_Hunter_AimedShot", "INV_Spear_02") then
         local cast = tostring(AAL_ASL_STING)
         if AAL_IsActBar(AAL_ASL_STING, "Ability_Hunter_AimedShot"--[[Viper Sting]]) == 1 then
            local m = UnitPowerType("target")==0 and UnitMana("target") or 0;
            if m < 100 or m > 20000 then cast = ".Serpent Sting" end
         end
         castDone = AAL_Cast(cast)
      end
      if not castDone then
         if not AAL_Cast(".40 Arcane Shot") and not aalcfg.nocleave then AAL_Cast(".40 Multi-Shot", ".25 Multi-Shot(Rank 2)", ".15 Multi-Shot(Rank 1)") end
      end
   end
  end
  -- Ranged [Auto-]Attack -- IsCurrentAction(aslot) не работает для Auto Shot и Shoot
  if not IsAutoRepeatAction(AAL_ASL_RANGED) then UseAction(AAL_ASL_RANGED) end
end


function AAL_MarkRapidAimedMultiShot()
  if not AAL_IsDebuff("Ability_Hunter_SniperShot") and not AAL_IsBuff("player","Ability_Hunter_RunningShot")
     and AAL_Cast(".Hunter's Mark") then return end
  if AAL_Cast(".Rapid Fire") then return end
  if not UnitAffectingCombat("player") and AAL_Cast(".Aimed Shot")
     or not aalcfg.nocleave and AAL_Cast(".20 Multi-Shot", ".5 Multi-Shot(Rank 1)") or AAL_Cast(".20 Arcane Shot") then return end
end



function AAL_PresencedMageSpell(spellName, HP)
  if not AAL_IsAura("Spell_Nature_EnchantArmor"--[[Presence of Mind]]) then return nil end
  local rank = HP==nil and 0 and
    HP<19 and 1 or HP<32 and 2 or HP<52 and 3 or HP<75 and 4 or HP<127 and 5
    or HP<175 and 6 or HP<228 and 7 or HP<293 and 8 or HP<354 and 9 or HP<430 and 10
    or 0;
  return AAL_Cast(rank>0 and ".20 "..spellName.."(Rank "..rank..")" or ".20 "..spellName, "."..spellName.."(Rank 1)")
end


function AAL_SpellAttack()

  local form = AAL_GetForm()
  if form == "Cat Form" then UseAction(73-1 +2); return end
  if form == "Bear Form" or form == "Dire Bear Form" then UseAction(97-1 +2); return end
  if form then CastSpellByName(form); return end

  local HP = UnitHealth("target")
  if AAL_PresencedMageSpell("Fireball", HP) then return end
  if AAL_PresencedMageSpell("Frostbolt", HP) then return end

  if HP <= 13 and AAL_Cast(".Smite(Rank 1)", ".Lightning Bolt(Rank 1)", ".Frostbolt(Rank 1)", ".Wrath(Rank 1)", ".Shadow Bolt(Rank 1)") then return end
  if HP <= 18 and AAL_Cast(".Frostbolt(Rank 1)") then return end
  if HP <= 25 and AAL_Cast(".Wrath(Rank 2)") then return end
  if HP <= 31 and AAL_Cast(".Frostbolt(Rank 2)") then return end
  if HP <= 51 and AAL_Cast(".Frostbolt(Rank 3)") then return end

  --if AAL_Cast("*Slam") then return end

  local SotC = AAL_IsDebuff("Spell_Holy_HolySmite") -- SotC on Enemy, adds to any Holy Damage
  --if SotC and not AAL_IsDebuff("Spell_Holy_SearingLight") and AAL_Cast(".Holy Fire") then return end

  if UnitClassification("target") == "worldboss" then
     if not AAL_IsDebuff("Spell_Shadow_AbominationExplosion") and AAL_Cast(".Corruption") then return end
     if SotC and AAL_Cast(".Smite(Rank 4)") then return end
     AAL_Cast(".Fireball", ".Frostbolt", ".Lightning Bolt", ".Smite", ".Wrath", ".Shadow Bolt")
     return
  end

  if not AAL_IsDebuffSlowed()
     and AAL_Cast(combat and ".Frostbolt(Rank 1)" or ".Frostbolt") then return end

  if SotC and AAL_Cast(".Smite(Rank 4)") then return end
  AAL_Cast(".Frostbolt", ".Fireball", ".Lightning Bolt", ".Smite", ".Wrath", ".Shadow Bolt", ".Corruption")
end


function AAL_SpellInstant()
  if AAL_EmergencyCleanse() then return end

  local HP = UnitHealth("target")
  local family = UnitCreatureType("target")
  local useExorcism = (family == "Undead" or family == "Demon")

  -- у Fire Blast и Exorcism общий CD; Exorcism эффективнее, но CD не 8s, а 15s
  if     HP <=  24 and AAL_Cast(".Fire Blast(Rank 1)") then return
  elseif HP <=  57 and AAL_Cast(".Fire Blast(Rank 2)") then return
  elseif useExorcism and HP <= 84 and AAL_Cast(".Exorcism(Rank 1)") then return
  elseif HP <= 103 and AAL_Cast(".Fire Blast(Rank 3)") then return
  elseif useExorcism and HP <= 152 and AAL_Cast(".Exorcism(Rank 2)") then return
  elseif HP <= 170 and AAL_Cast(".Fire Blast(Rank 4)") then return
  elseif useExorcism and HP <= 217 and AAL_Cast(".Exorcism(Rank 3)") then return
  elseif HP <= 242 and AAL_Cast(".Fire Blast(Rank 5)") then return
  elseif useExorcism and HP <= 304 and AAL_Cast(".Exorcism(Rank 4)") then return
  elseif HP <= 350 and AAL_Cast(".Fire Blast(Rank 6)") then return
  end

  --[[
  if AAL_IsBuff("player", "Spell_Shadow_ManaBurn") then -- Clearcasting от Omen of Clarity и Arcane Concentration работают для разных групп заклинаний, а иконка одна. Как их различать?
     if AAL_Cast(".Moonfire") then return end
  end
  ]]

  local LevDiff = UnitLevel("target")
  if LevDiff == nil or LevDiff < 0 then LevDiff = 10
  else LevDiff = LevDiff - UnitLevel("player")
  end

  local isFat
  local rank = UnitClassification("target")
  if LevDiff > -20 and (rank == "elite" or rank == "rareelite") or rank == "worldboss" then
     isFat = true
  else
     isFat = (LevDiff >= 5) or HP > 4000
  end

  local percentHP = HP * 100 / UnitHealthMax("target")

  if isFat and (percentHP > 50 or HP > 2000) and not AAL_IsDebuff(unpack(aal_WarlockCurseIcons)) then
     --[[
     local k = AAL_IsActBar(AAL_ASL_CURSE, unpack(aal_WarlockCurseIcons))
     if k and AAL_Cast( ".Curse of "..aal_WarlockCurseNames[k] ) then return end
     ]]
     if AAL_Cast(tostring(AAL_ASL_CURSE)) == false then AAL_Cast(".Curse of Agony")--[[if Curse of Doom is on CD]] end
  end

  if (isFat or LevDiff >= -2) and (percentHP > 15 or HP > 2000) and not AAL_IsDebuff("Spell_Shadow_ShadowWordPain") then
     if AAL_Cast(".Shadow Word: Pain") then return end
  end

  if isFat and (HP > 500) and not AAL_IsDebuff("Spell_Nature_InsectSwarm") then
     if AAL_Cast(".Insect Swarm") then return end
  end

  if isFat and (percentHP > 50 or HP > 2000) and not AAL_IsDebuff("Spell_Nature_FaerieFire") then
     local _, armor = UnitArmor("target")
     if armor ~= nil and armor > 500 and AAL_Cast(".Faerie Fire") then return end
  end

  -- Далее идут способности, требующие ориентации игрока лицом к врагу

  if rank ~= "worldboss" then
     if rank ~= nil and isFat and LevDiff < 5 then
        if aal_Free500mana then
           aal_Free500mana = nil
           if AAL_Cast("Death Coil") then return end
        end
        if AAL_Cast(-3, "Scatter Shot") then return end
        if AAL_Cast(2, "Robes of Insight") then aal_Free500mana = true; return; end
     end
     aal_Free500mana = nil
  end
  if useExorcism and AAL_Cast(".Exorcism") then return end
  if not AAL_IsDebuff("Spell_Nature_StarFall"--[[Moonfire]]) and AAL_Cast(".Moonfire") then return end
  if AAL_Cast(".Fire Blast") then return end
  if AAL_Cast(-3, ".30 Arcane Shot") then return end  -- можно стрелять на бегу
  if AAL_Cast("Presence of Mind") then return end
  if AAL_PresencedMageSpell("Frostbolt", HP) then return end -- стрелять на бегу можно только классом Mage
end



function AAL_ComboAttack()
  local form = AAL_GetForm()
  if form == "Cat Form" then UseAction(73-1 +5); return end
  if form == "Bear Form" or form == "Dire Bear Form" then UseAction(97-1 +5); return end
  if form then CastSpellByName(form) return end

  if not AAL_IsAura("Ability_Rogue_SliceDice") and AAL_Cast("-Slice and Dice") then return end
  local L = UnitLevel("player")
  if UnitHealth("target") > 50*L and UnitArmor("target") > 30*L and not aal_BleedBlocker[UnitCreatureType("target")] and not AAL_IsDebuff("Ability_Rogue_Rupture") and AAL_Cast("-Rupture") then return end -- в отличие от Eviscerate, Rupture не понижается вражеским Armor
  -- if not AAL_IsDebuff("Ability_Warrior_Riposte") and AAL_Cast("-Expose Armor") then return end -- не объединяет действие с Sunder Armor
  if AAL_Cast("-Eviscerate") then return end
end


function AAL_BackMeleeAttack()
  -- Не получается перехватить события SPELL_FAILED_NOT_BEHIND, SPELL_FAILED_NOT_INFRONT,
  -- чтобы выбирать Backstab или Gouge. Эти события просто не проходят через
  -- обработчик UIErrorsFrame_OnEvent
  if not AAL_IsActiveSpell("Stealth") then
     local weapons = AAL_CheckSwapWeapons(true)
     if weapons == 2 then AAL_Cast("Backstab") end
  else
     local weapons = AAL_CheckSwapWeapons(true)
     if weapons < 0 then return end
     if IR_FORM and LoadSet then LoadSet("sneak") end -- call ItemRack addon to unequip +Stealth boots
     if weapons == 2 then AAL_Cast("Ambush", "Backstab")
     else AAL_Cast("Garrote")
     end
     return
  end
  -- Melee Auto-Attack -- для "Attack" IsCurrentCast() не работает, всегда возвращает nil
  local aslot = aal_AbiSlots["Attack"]
  if not IsCurrentAction(aslot) then UseAction(aslot) end
end



function AAL_StunAttack()
  if AAL_IsActiveSpell("Stealth") and AAL_Cast("-Cheap Shot") then return end
  AAL_Cast("-Kidney Shot", "-Gouge", "*Concussion Blow", ".Hammer of Justice", "Tidal Charm", "Scatter Shot") -- "*Hamstring", ".Wing Clip"
  AAL_StopAction()
end


function AAL_HinderEnemy()
  local form = AAL_GetForm()
  if form and AAL_Cast("*Bash", "Counterspell") then return end -- доступно из кота, медведя, леопарда и т.д.

  if UnitClassification("target") == "worldboss" or aal_StunImmune[ UnitName("target") ] then
     -- Прерывать можно только магические заклинания, а не любые cast-способности
     if AAL_Cast("-Kick", "*Pummel", "*Shield Bash", ".Counterspell") then return end
     if AAL_PetCast("Spell Lock") then return end
     return
  end

  if AAL_IsActiveSpell("Stealth") and AAL_Cast("-Cheap Shot") then return end
  if AAL_IsDebuffStunned() then return end

  -- if not CheckInteractDistance("target",3) then AAL_Cast(".Counterspell"); return end

  if UnitPowerType("target")==0 and UnitMana("target") > 50 then
     if AAL_Cast("-Kick", "*Pummel", "*Shield Bash", "-Gouge", "-Kidney Shot", ".Counterspell", "*Concussion Blow", ".Hammer of Justice", "Scatter Shot") then return end
     if AAL_PetCast("Spell Lock") then return end
  end

  if not AAL_IsDebuff("Ability_Warrior_Challange"--[[Counterattack]], "Ability_Rogue_Trip"--[[Wing Clip]], "Ability_ShockWave"--[[Hamstring]]) then
     if AAL_Cast("*Concussion Blow", ".Hammer of Justice", "-Kidney Shot", "-Gouge", ".Counterattack", "*Hamstring", ".Wing Clip", "Scatter Shot") then return end
  end
end


function AAL_TranqShotOrDisarmOrFinishEnemy()
  if AAL_Cast(-4, ".Tranquilizing Shot") then return end
  if AAL_IsActiveSpell("Defensive Stance") then if AAL_Cast("*Disarm") then return end
  else
    local HP = UnitHealth("target")
    if --[[HP < 10000 and]] HP / UnitHealthMax("target") <= 0.20 then
       SpellStopCasting()
       if AAL_Cast("*Execute", -1, ".Hammer of Wrath") then return end
    end
    if AAL_Cast("*Hamstring") then return end
  end
  AAL_MeleeAttack()
end


function AAL_Bomb()
  AAL_Cast("Big Bronze Bomb", "Large Copper Bomb", "Explosive Rocket")
end


function AAL_DisableEnemy()
  local isCombat = UnitAffectingCombat("player")
  if isCombat and AAL_Cast(3, "-Blind") then return end
  --print("AAL_DisableEnemy:", family, aal_DisableEnemy_alt)
  local family = UnitCreatureType("target")
  if family == "Humanoid" and AAL_IsActiveSpell("Stealth") and not isCombat
     and CheckInteractDistance("target", 3) and not AAL_IsDebuff("Ability_Sap") and AAL_Cast("-Sap") then return end
  if family == "Undead" and AAL_Cast(".Shackle Undead") then return end
  if (family == "Demon" or family == "Elemental") and AAL_Cast(".Banish") then return end
  if family == "Dragonkin" and AAL_Cast(".Hibernate") then return end
  if family == "Beast" and UnitName("target") ~= "The Razza" then
     -- против зверей, во время боя, Polymorph чередуется с Hibernate; однако Immune/Resist будут сбивать логику
     if not isCombat then aal_DisableEnemy_alt = false; end
     if not aal_DisableEnemy_alt and AAL_Cast(".Polymorph", ".Polymorph(Rank 1)") then aal_DisableEnemy_alt = true; return end
     if AAL_Cast(".Hibernate", ".Hibernate(Rank 1)") then aal_DisableEnemy_alt = false; return end
     if aal_DisableEnemy_alt and AAL_Cast(".Polymorph", ".Polymorph(Rank 1)") then return end
  elseif family ~= "Not specified" and family ~= "Undead" and family ~= "Demon" and family ~= "Elemental" and family ~= "Giant" then
     if AAL_Cast(".Polymorph", ".Polymorph(Rank 1)") then aal_DisableEnemy_alt = true; return end
  end
  if family == "Humanoid" and AAL_Cast(".Repentance") then return end
  --if AAL_PetCast("Seduction") then return end -- :( not working in cMangos
  if AAL_Cast("Magic Dust") then return end
  if AAL_Cast(".Entangling Roots") then return end
end


function AAL_ControlEnemy()
  local family = UnitCreatureType("target")
  local L = UnitLevel("target")
  if family == "Demon" then
     AAL_Cast(".Enslave Demon"..(L <= 32 and "(Rank 1)" or L <= 47 and "(Rank 2)" or ""))
  elseif family == "Humanoid" then
     AAL_Cast(".Mind Control"..(L <= 32 and "(Rank 1)" or L <= 47 and "(Rank 2)" or ""))
  elseif family == "Beast" then
     AAL_Cast(".Tame Beast")
  end
end


function AAL_ScareEnemy()
  local family = UnitCreatureType("target")
  if family == "Undead" and AAL_Cast(".Turn Undead") then return end
  if family == "Beast" and AAL_Cast(3, ".Scare Beast") then return end
  AAL_Cast("Fear") -- работает и без маны
end


function AAL_ScareMultipleEnemies()
  AAL_Cast("*Intimidating Shout", ".Psychic Scream", ".Howl of Terror")
end





-- Защита и лечение

function AAL_Protection()
  local gcd = AAL_IsGCD()
  if gcd and UnitHealth("player")*100 / UnitHealthMax("player") > 30 then return end

  local k = AAL_IsBuff("player",
    "Spell_Shadow_ShadowWard"--[[Evasion]], "Ability_Whirlwind"--[[Deterrence]], "Ability_Warrior_ShieldWall", "Spell_Holy_Elunes_Grace",
    --[[5]] "Spell_Holy_PowerWordShield", "Spell_Ice_Lament"--[[Ice Barrier]], "Spell_Holy_DivineIntervention"--[[Divine Shield]], "Spell_Holy_Restoration"--[[Divine Protection]], "Spell_Shadow_DetectLesserInvisibility"--[[Mana Shield]], "Spell_Shadow_SacrificialShield"--[[Sacrifice]], "Spell_Holy_DivineIntervention"--[[Limited Invulnerability Potion]]
    -- к сожалению, "Spell_Holy_DevotionAura"--[[Arena Grand Master]] неотличима по иконке от Devotion Aura
  )
  if k and k >= 5 then return end

  if gcd then
     -- действия, которые могут выполняться во время Global CoolDown (но только при низком HP)
     if not k and AAL_Cast("Evasion", "Deterrence")  or AAL_PetCast("Sacrifice")  or AAL_Cast("Limited Invulnerability Potion", "Arena Grand Master") then end
     return
  end
  -- действия, которые допустимы под некоторыми защитными аурами
  if AAL_Cast(true, ".Power Word: Shield", ".Ice Barrier") then return end

  if k then return end
  if AAL_Cast(true, "Evasion", "Deterrence", ".Elune's Grace", "Arena Grand Master", "Shield Wall", ".Divine Shield", ".Divine Protection", ".Blessing of Protection", "Limited Invulnerability Potion", "Preparation", ".30 Mana Shield") then return end
  AAL_PetCast("Sacrifice")
end


function AAL_EmergencyProtection()
  if AAL_IsAura("Spell_Holy_DivineIntervention"--[[Divine Shield]], "Spell_Holy_Restoration"--[[Divine Protection]]) then
     if AAL_IsAura("Spell_Frost_WindWalkOn"--[[Inner Focus]]) and AAL_Cast(true, ".0 Greater Heal") then return end
     if AAL_Cast(true, "Goblin Sapper Charge") then return end
     if not AAL_IsGCD() and AAL_Cast(true, ".0 Evocation", "Inner Focus", ".20 Greater Heal", ".10 Greater Heal(Rank 1)", "Heavy Runecloth Bandage", ".0 Life Tap") then return end
     return
  end
  if UnitHealth("player")*100 / UnitHealthMax("player") >= 30 and AAL_IsGCD() then return end
  if AAL_Cast(true, ".Divine Shield", ".Divine Protection", ".Blessing of Protection") then return end

  if not AAL_IsAura("Spell_Shadow_ShadowWard"--[[Evasion]], "Ability_Whirlwind"--[[Deterrence]], "Ability_Warrior_ShieldWall", "Spell_Holy_Elunes_Grace") and
     AAL_Cast("Shield Wall", "Evasion", "Deterrence", ".Elune's Grace", "Preparation") then return end
  
  if AAL_Cast("Arena Grand Master") then return end
  if AAL_PetCast("Sacrifice") then return end
  AAL_Cast(true, ".Power Word: Shield", ".Ice Barrier")
end


function TryPriorityPotion() -- Включается пока только если aalcfg.magres == true
  local usePotions = true
  if aalcfg.magres then
     if AAL_IsAura("INV_Potion_08") then return false -- Запрет использования других зелий с тем же CD
     else if AAL_Cast("Magic Resistance Potion") then return nil end -- Действие выполнено, нужен return
     end
  end
  return true -- Разрешение использования других зелий с тем же CD, если приоритетного зелья нет в инвентаре
end


function AAL_ReplenishMana()
  local usePotions = TryPriorityPotion()
  if aalcfg.nodrink then usePotions = false end
  if usePotions == nil then return end

  pw = UnitPowerType("player")
  if pw == 0 and not UnitAffectingCombat("player") and aal_Abilities["Life Tap"] ~= nil then
     AAL_Cast("Life Tap")
     return
  end
  local manaPercent = UnitMana("player")*100 / UnitManaMax("player")
  if manaPercent >= 100 then
     UIErrorsFrame:AddMessage("No need to Replenish Power",1,0,0)
     return
  end
  if pw == 1 then -- Rage
     AAL_Cast("Mighty Rage Potion","Great Rage Potion","Rage Potion")
     return
  elseif pw == 3 then -- Energy
     AAL_Cast("Thistle Tea")
     return
  end
  -- Mana
  if UnitHealth("player") > 0.70 * UnitHealthMax("player") and AAL_Cast("Life Tap") then return end
  if manaPercent > 70 then return end -- случайные повторные нажатия могут привести к напрасному расходу зелий
  if AAL_Cast("Mana Ruby","Mana Citrine","Mana Jade", "Lily Root", "Mana Agate") then return end
  if usePotions and AAL_Cast("Combat Mana Potion", "Superior Mana Potion","Major Mana Potion","Major Rejuvenation Potion","Greater Mana Potion","Mana Potion","Lesser Mana Potion","Minor Mana Potion") then return end
  if AAL_Cast(".Innervate") then return end
  if UnitExists("pet") and UnitPowerType("pet") == 0 and UnitMana("pet") > 50 and AAL_Cast("Dark Pact") then return end
  -- if UnitPowerType("target") == 0 and UnitMana("target") >= 250 and AAL_Cast(".Drain Mana") then return end
end


function AAL_Heal(tar, instant)
  if AAL_IsDebuff("player", "Spell_Shadow_Teleport"--[[Stunned]]) and AAL_Cast(true, "Insignia of the Alliance") then return end

  if AAL_EmergencyCleanse() then return end

  local onSelf = UnitIsUnit(tar, "player") and true  or false

  local dispel -- nil, false, number

  local usePotions

  if instant then
     if onSelf and AAL_IsDebuff("player", "Ability_Ensnare", "Ability_Warrior_WarCry"--[[Incapacitating Shout]]) and AAL_Cast(true, "Blessing of Freedom") then return end
     local n = AAL_IsDispellableDebuff(tar, "Poison", "Disease", "Curse", "Magic")
     -- Заклинания Paladin'а Purify и Cleanse расходуют гораздо меньше маны
     if     n == 1 then dispel = AAL_Cast(onSelf, "Cleanse", "Purify", "Abolish Poison", "Cure Poison") -- Paladin, Druid, Shaman
     elseif n == 2 then dispel = AAL_Cast(onSelf, "Cleanse", "Purify", "Abolish Disease", "Cure Disease") -- Paladin, Priest, Shaman
     elseif n == 3 then dispel = AAL_Cast(onSelf, "Remove Curse", "Remove Lesser Curse") -- Druid, Mage
     elseif n == 4 then dispel = AAL_Cast(onSelf, "Cleanse", "Purge", "Dispel Magic") -- Paladin, Shaman, Priest
     end
     if dispel then return true end

     usePotions = TryPriorityPotion()
     if aalcfg.nodrink then usePotions = false end
     if usePotions == nil then return true end
  end

  local HP = UnitHealth(tar)
  local maxHP = UnitHealthMax(tar)
  if maxHP <= 0 then return false end
  local H = maxHP - HP
  local percentHP = HP*100 / maxHP

  if instant then
     if onSelf and UnitAffectingCombat("player") then

        -- невозможность применить dispel из-за GCD (global cooldown) в бою не должна приводить к ненужному расходу зелий исцеления
        if dispel == false and percentHP >= 40 then usePotions = false end

        --print("AAL_Heal:", H, percentHP)
        if (H > 1000 or percentHP < 40) and AAL_Cast("Major Healthstone", "Greater Healthstone", "Healthstone", "Lesser Healthstone", "Minor Healthstone") then return end
        if H > 1000 and AAL_Cast("Lily Root") then return end
        if usePotions then
           if H > 1000 and AAL_Cast("Superior Healing Potion", "Major Healing Potion", "Major Rejuvenation Potion") then return end
           if H > 600 and AAL_Cast("Combat Healing Potion", "Superior Healing Potion") then return end
           if H > 400 and AAL_Cast("Greater Healing Potion") then return end
           if H > 200 and AAL_Cast("Healing Potion") then return end
           if H > 140 and AAL_Cast("Discolored Healing Potion", "Lesser Healing Potion") then return end
           if H > 80  and AAL_Cast("Minor Healing Potion") then return end
        end
        if percentHP < 25 and AAL_Cast("Desperate Prayer") then return end
        if percentHP < 15 and AAL_Cast("Arena Grand Master", "Lay on Hands", "Minor Recombobulator", "Crystal Restore") then return end

        -- Если здоровье (почти) полное, а мана - нет, то пытаемся перевести часть HP в MP
        if UnitPowerType("player") == 0 and UnitMana("player") < 0.8*UnitManaMax("player") and
           (percentHP >= 90 or percentHP >=70 and AAL_IsAura("Spell_Nature_Rejuvenation", "Spell_Holy_Renew")) then
           if AAL_Cast("Life Tap") then return end
        end
     end

     if UnitPowerType("player") == 0 and UnitMana("player") < 400 then AAL_Cast("Burst of Knowledge") end

     if H <= 0 then return false end
     AAL_Cast(onSelf, ".8 Renew", ".8 Rejuvenation", ".1 Rejuvenation(Rank 1)"--[[прибавка от Idol of Rejuvenation]], ".2 Renew(Rank 2)")
     return
  end

  if H <= 0 then return false end

  -- if UnitIsDead(tar) ...

  -- На случай, если у питомца-танка осталось мало HP, и можно не успеть вылечить
  if not onSelf and percentHP < 15 and UnitAffectingCombat("target") and AAL_Cast(".10 Power Word: Shield") then return end

  -- Paladin's Holy Light наименее эффективен по HP/mana

  if H <  50 and AAL_Cast(onSelf, "Lesser Heal(Rank 1)", "Healing Touch(Rank 1)", "Healing Wave(Rank 1)", "Holy Light(Rank 1)") then return end

  if AAL_IsAura("Spell_Frost_WindWalkOn"--[[Inner Focus]]) and AAL_Cast(onSelf, "Greater Heal", "Heal", "Renew", "Lesser Heal") then return end

  if onSelf and UnitAffectingCombat("player") then -- в бою используем для себя быстродействующие заклинания
     if H <  75 and AAL_Cast(onSelf, "Flash of Light(Rank 1)") then return end
     if H < 145 and AAL_Cast(onSelf, "Flash of Light(Rank 2)") then return end
     if H < 215 and AAL_Cast(onSelf, "Flash Heal(Rank 1)") then return end
     if H < 290 and AAL_Cast(onSelf, "Flash Heal(Rank 2)") then return end
     -- далее Flash of Light не используем из-за низкого показателя HP/time
     if percentHP > 25 and not AAL_IsBuff(tar, "Spell_Nature_ResistNature"--[[Regrowth]]) and AAL_Cast(onSelf, "Regrowth") then return end
     -- если игрок временно неуязвим, то можно использовать долгие заклинания
     if not AAL_IsAura("Spell_Holy_DivineIntervention"--[[Divine Shield]], "Spell_Holy_Restoration"--[[Divine Protection]], "Spell_Holy_PowerWordShield", "Spell_Ice_Lament"--[[Ice Barrier]], "Spell_Shadow_DetectLesserInvisibility"--[[Mana Shield]], "Spell_Shadow_SacrificialShield"--[[Sacrifice]], "Spell_Holy_DivineIntervention"--[[Limited Invulnerability Potion]])
        and AAL_Cast(onSelf, "Flash Heal") then return end
  end
  local M = UnitMana("player")

  if H <  75 and AAL_Cast(onSelf, "Flash of Light(Rank 1)", "Lesser Heal(Rank 2)", "Healing Wave(Rank 2)", "Holy Light(Rank 2)") then return end
  if H < 100 and AAL_Cast(onSelf, "Flash of Light(Rank 2)", "Healing Touch(Rank 2)", "Lesser Heal(Rank 2)", "Healing Wave(Rank 2)", "Flash of Light(Rank 1)", "Holy Light(Rank 2)") then return end
  if H < 150 and AAL_Cast(onSelf, "Flash of Light(Rank 3)", "Lesser Heal(Rank 3)", "Healing Wave(Rank 3)") then return end
  if (H < 215 or M <= 110) and
     AAL_Cast(onSelf, "Flash Heal(Rank 1)", "Healing Touch(Rank 3)", "Lesser Healing Wave(Rank 1)", "Holy Light(Rank 3)") then return end
  if (H < 346 or M <= 155) and AAL_Cast(onSelf, "Flash Heal(Rank 2)") then return end
  if (H < 396 or M <= 155) and AAL_Cast(onSelf, "Heal(Rank 1)") then return end
  if (H < 433 or M <= 185) and AAL_Cast(onSelf, "Flash Heal(Rank 3)") then return end
  if (H < 356 or M <= 190) and AAL_Cast(onSelf, "Holy Light(Rank 4)") then return end
  if (H < 445 or M <= 185) and AAL_Cast(onSelf, "Healing Touch(Rank 4)") then return end
  if (H < 570 or M <= 205) and AAL_Cast(onSelf, "Heal(Rank 2)") then return end
  if (H < 745 or M <= 255) and AAL_Cast(onSelf, "Heal(Rank 3)") then return end
  if (H < 694 or M <= 270) and AAL_Cast(onSelf, "Healing Touch(Rank 5)") then return end
  if (H < 553 or M <= 275) and AAL_Cast(onSelf, "Holy Light(Rank 5)") then return end
  if (H < 933 or M <= 305) and AAL_Cast(onSelf, "Heal(Rank 4)") then return end
  if aal_Abilities["Greater Heal"] then -- с талантами Priest гораздо предпочтительнее, чем Druid
  if (H <1115 or M <= 370) and AAL_Cast(onSelf, "Greater Heal(Rank 1)") then return end
  if (H <1418 or M <= 455) and AAL_Cast(onSelf, "Greater Heal(Rank 2)") then return end
  if (H <1770 or M <= 545) and AAL_Cast(onSelf, "Greater Heal(Rank 3)") then return end
  --if (H <2207 or M <= 655) and AAL_Cast(onSelf, "Greater Heal(Rank 4)") then return end
  elseif aal_Abilities["Healing Touch"] then
  if (H < 894 or M <= 335) and AAL_Cast(onSelf, "Healing Touch(Rank 6)") then return end
  if (H <1120 or M <= 405) and AAL_Cast(onSelf, "Healing Touch(Rank 7)") then return end
  if (H <1427 or M <= 495) and AAL_Cast(onSelf, "Healing Touch(Rank 8)") then return end
  if (H <1796 or M <= 600) and AAL_Cast(onSelf, "Healing Touch(Rank 9)") then return end
  --if (H <2230 or M <= 720) and AAL_Cast(onSelf, "Healing Touch(Rank 10)") then return end
  end
  AAL_Cast(onSelf, "Greater Heal", "Healing Touch", "Heal", "Healing Wave", "Flash Heal", "Flash of Light", "Lesser Healing Wave", "Holy Light", "Lesser Heal")
end


function AAL_SmartHeal(instant)
  local pet = UnitExists("pet") and not UnitIsDead("pet")
  local petTank
  if pet then
     local _; _, _,_,_,_,_,_,petTank--[[autoCastEnabled]] = AAL_GetPetAction("Growl")
  end

  if not UnitCanAttack("player", "target") and (not petTank or not UnitAffectingCombat("player")) and AAL_Heal("target", instant) ~= false then return end

  if (not petTank or instant) and AAL_Heal("player", instant) ~= false then return end
  if pet then
     TargetUnit("pet")
     local result = AAL_Heal("pet", instant)
     AAL_RestoreTarget()
     if result ~= false then return end
  end
  if (petTank and not instant) and AAL_Heal("player", instant) ~= false then return end

  UIErrorsFrame:AddMessage("No need to Heal",1,0,0)
end


