Unit* PartyMemberToHeal::Calculate() { IsTargetOfHealingSpell predicate; Group* group = bot->GetGroup(); if (!group) return NULL; bool isRaid = bot->GetGroup()->isRaidGroup(); MinValueCalculator calc(100); for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* player = gref->getSource(); if (!Check(player) || !player->IsAlive()) continue; uint8 health = player->GetHealthPercent(); if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate)) calc.probe(health, player); Pet* pet = player->GetPet(); if (pet && CanHealPet(pet)) { health = pet->GetHealthPercent(); if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate)) calc.probe(health, player); } } return (Unit*)calc.param; }
void PlayerbotWarlockAI::DoNonCombatActions() { SpellSequence = SPELL_CURSES; PlayerbotAI *ai = GetAI(); Player * m_bot = GetPlayerBot(); if (!ai || !m_bot) return; Pet *pet = m_bot->GetPet(); // Initialize pet spells if (pet && pet->GetEntry() != m_lastDemon) { switch (pet->GetEntry()) { case DEMON_IMP: { BLOOD_PACT = ai->initPetSpell(BLOOD_PACT_ICON); FIREBOLT = ai->initPetSpell(FIREBOLT_ICON); FIRE_SHIELD = ai->initPetSpell(FIRE_SHIELD_ICON); break; } case DEMON_VOIDWALKER: { CONSUME_SHADOWS = ai->initPetSpell(CONSUME_SHADOWS_ICON); SACRIFICE = ai->initPetSpell(SACRIFICE_ICON); SUFFERING = ai->initPetSpell(SUFFERING_ICON); TORMENT = ai->initPetSpell(TORMENT_ICON); break; } case DEMON_SUCCUBUS: { LASH_OF_PAIN = ai->initPetSpell(LASH_OF_PAIN_ICON); SEDUCTION = ai->initPetSpell(SEDUCTION_ICON); SOOTHING_KISS = ai->initPetSpell(SOOTHING_KISS_ICON); break; } case DEMON_FELHUNTER: { DEVOUR_MAGIC = ai->initPetSpell(DEVOUR_MAGIC_ICON); FEL_INTELLIGENCE = ai->initPetSpell(FEL_INTELLIGENCE_ICON); SHADOW_BITE = ai->initPetSpell(SHADOW_BITE_ICON); SPELL_LOCK = ai->initPetSpell(SPELL_LOCK_ICON); break; } case DEMON_FELGUARD: { ANGUISH = ai->initPetSpell(ANGUISH_ICON); CLEAVE = ai->initPetSpell(CLEAVE_ICON); INTERCEPT = ai->initPetSpell(INTERCEPT_ICON); break; } } m_lastDemon = pet->GetEntry(); if (!m_isTempImp) m_demonOfChoice = pet->GetEntry(); } // Destroy extra soul shards uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, NULL); uint8 freeSpace = ai->GetFreeBagSpace(); if (shardCount > MAX_SHARD_COUNT || (freeSpace == 0 && shardCount > 1)) m_bot->DestroyItemCount(SOUL_SHARD, shardCount > MAX_SHARD_COUNT ? shardCount - MAX_SHARD_COUNT : 1, true, false); // buff myself DEMON_SKIN, DEMON_ARMOR, FEL_ARMOR if (FEL_ARMOR) { if (ai->SelfBuff(FEL_ARMOR)) return; } else if (DEMON_ARMOR) { if (ai->SelfBuff(DEMON_ARMOR)) return; } else if (DEMON_SKIN) if (ai->SelfBuff(DEMON_SKIN)) return; // healthstone creation if (CREATE_HEALTHSTONE && shardCount > 0) { Item* const healthStone = ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (!healthStone && ai->CastSpell(CREATE_HEALTHSTONE)) return; } // soulstone creation and use if (CREATE_SOULSTONE) { Item* soulStone = ai->FindConsumable(SOULSTONE_DISPLAYID); if (!soulStone) { if (shardCount > 0 && !m_bot->HasSpellCooldown(CREATE_SOULSTONE) && ai->CastSpell(CREATE_SOULSTONE)) return; } else { uint32 soulStoneSpell = soulStone->GetProto()->Spells[0].SpellId; Player * master = GetMaster(); if (!master->HasAura(soulStoneSpell) && !m_bot->HasSpellCooldown(soulStoneSpell)) { ai->UseItem(soulStone, master); return; } } } // firestone creation and use Item* const weapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); if (weapon && weapon->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) == 0) { Item* const stone = ai->FindConsumable(FIRESTONE_DISPLAYID); if (!stone) { if (CREATE_FIRESTONE && shardCount > 0 && ai->CastSpell(CREATE_FIRESTONE)) return; } else { ai->UseItem(stone, EQUIPMENT_SLOT_MAINHAND); return; } } if (m_bot->getStandState() != UNIT_STAND_STATE_STAND) m_bot->SetStandState(UNIT_STAND_STATE_STAND); // mana check if (pet && DARK_PACT && pet->GetPower(POWER_MANA) > 0 && ai->GetManaPercent() <= 50) if (ai->CastSpell(DARK_PACT, *m_bot)) return; if (LIFE_TAP && ai->GetManaPercent() <= 50 && ai->GetHealthPercent() > 50) if (ai->CastSpell(LIFE_TAP, *m_bot)) return; if (ai->GetManaPercent() < 25) { Item* pItem = ai->FindDrink(); if (pItem) { ai->TellMaster("I could use a drink."); ai->UseItem(pItem); return; } } // hp check if (ai->GetHealthPercent() < 30) { Item* pItem = ai->FindFood(); if (pItem) { ai->TellMaster("I could use some food."); ai->UseItem(pItem); return; } } if (ai->GetHealthPercent() < 50 && !m_bot->HasAura(RECENTLY_BANDAGED)) { Item* fItem = ai->FindBandage(); if (fItem) { ai->TellMaster("I could use first aid."); ai->UseItem(fItem); return; } } //Heal Voidwalker if (pet && pet->GetEntry() == DEMON_VOIDWALKER && CONSUME_SHADOWS && pet->GetHealthPercent() < 75 && !pet->HasAura(CONSUME_SHADOWS)) ai->CastPetSpell(CONSUME_SHADOWS); // Summon demon if (!pet || m_isTempImp) { uint32 summonSpellId; if (m_demonOfChoice != DEMON_IMP && shardCount > 0) { switch (m_demonOfChoice) { case DEMON_VOIDWALKER: summonSpellId = SUMMON_VOIDWALKER; break; case DEMON_FELGUARD: summonSpellId = SUMMON_FELGUARD; break; case DEMON_FELHUNTER: summonSpellId = SUMMON_FELHUNTER; break; case DEMON_SUCCUBUS: summonSpellId = SUMMON_SUCCUBUS; break; default: summonSpellId = 0; } if (ai->CastSpell(summonSpellId)) { ai->TellMaster("Summoning favorite demon..."); m_isTempImp = false; return; } } else if (!pet && SUMMON_IMP && ai->CastSpell(SUMMON_IMP)) { if (m_demonOfChoice != DEMON_IMP) m_isTempImp = true; ai->TellMaster("Summoning Imp..."); return; } } // Soul link demon if (pet && SOUL_LINK && !m_bot->HasAura(SOUL_LINK_AURA) && ai->CastSpell(SOUL_LINK, *m_bot)) return; // Check demon buffs if (pet && pet->GetEntry() == DEMON_IMP && BLOOD_PACT && !m_bot->HasAura(BLOOD_PACT) && ai->CastPetSpell(BLOOD_PACT)) return; if (pet && pet->GetEntry() == DEMON_FELHUNTER && FEL_INTELLIGENCE && !m_bot->HasAura(FEL_INTELLIGENCE) && ai->CastPetSpell(FEL_INTELLIGENCE)) return; } // end DoNonCombatActions
void PlayerbotWarlockAI::DoNonCombatActions() { if (!m_ai) return; if (!m_bot) return; //uint32 spec = m_bot->GetSpec(); Pet *pet = m_bot->GetPet(); // Initialize pet spells if (pet && pet->GetEntry() != m_lastDemon) { switch (pet->GetEntry()) { case DEMON_IMP: BLOOD_PACT = m_ai->initPetSpell(BLOOD_PACT_ICON); FIREBOLT = m_ai->initPetSpell(FIREBOLT_ICON); FIRE_SHIELD = m_ai->initPetSpell(FIRE_SHIELD_ICON); break; case DEMON_VOIDWALKER: CONSUME_SHADOWS = m_ai->initPetSpell(CONSUME_SHADOWS_ICON); SACRIFICE = m_ai->initPetSpell(SACRIFICE_ICON); SUFFERING = m_ai->initPetSpell(SUFFERING_ICON); TORMENT = m_ai->initPetSpell(TORMENT_ICON); break; case DEMON_SUCCUBUS: LASH_OF_PAIN = m_ai->initPetSpell(LASH_OF_PAIN_ICON); SEDUCTION = m_ai->initPetSpell(SEDUCTION_ICON); SOOTHING_KISS = m_ai->initPetSpell(SOOTHING_KISS_ICON); break; case DEMON_FELHUNTER: DEVOUR_MAGIC = m_ai->initPetSpell(DEVOUR_MAGIC_ICON); SPELL_LOCK = m_ai->initPetSpell(SPELL_LOCK_ICON); break; } m_lastDemon = pet->GetEntry(); } // Destroy extra soul shards uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); uint8 freeSpace = m_ai->GetFreeBagSpace(); if (shardCount > MAX_SHARD_COUNT || (freeSpace == 0 && shardCount > 1)) m_bot->DestroyItemCount(SOUL_SHARD, shardCount > MAX_SHARD_COUNT ? shardCount - MAX_SHARD_COUNT : 1, true, false); // buff myself DEMON_SKIN, DEMON_ARMOR, FEL_ARMOR - Strongest one available is chosen if (DEMON_ARMOR) { if (m_ai->SelfBuff(DEMON_ARMOR)) return; } else if (DEMON_SKIN) if (m_ai->SelfBuff(DEMON_SKIN)) return; // healthstone creation if (CREATE_HEALTHSTONE && shardCount > 0) { Item* const healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (!healthStone && m_ai->CastSpell(CREATE_HEALTHSTONE)) return; } // soulstone creation and use if (CREATE_SOULSTONE) { Item* soulStone = m_ai->FindConsumable(SOULSTONE_DISPLAYID); if (!soulStone) { if (shardCount > 0 && m_bot->IsSpellReady(CREATE_SOULSTONE) && m_ai->CastSpell(CREATE_SOULSTONE)) return; } else { uint32 soulStoneSpell = soulStone->GetProto()->Spells[0].SpellId; Player* master = GetMaster(); if (!master->HasAura(soulStoneSpell) && m_bot->IsSpellReady(soulStoneSpell)) { // TODO: first choice: healer. Second choice: anyone else with revive spell. Third choice: self or master. m_ai->UseItem(soulStone, master); return; } } } // hp/mana check if (pet && DARK_PACT && (100 * pet->GetPower(POWER_MANA) / pet->GetMaxPower(POWER_MANA)) > 40 && m_ai->GetManaPercent() <= 60) if (m_ai->CastSpell(DARK_PACT, *m_bot)) return; if (LIFE_TAP && m_ai->GetManaPercent() <= 80 && m_ai->GetHealthPercent() > 50) if (m_ai->CastSpell(LIFE_TAP, *m_bot)) return; // Do not waste time/soul shards to create spellstone or firestone // if two-handed weapon (staff) or off-hand item are already equiped // Spellstone creation and use (Spellstone dominates firestone completely as I understand it) Item* const weapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); Item* const offweapon = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (weapon && !offweapon && weapon->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_STAFF && weapon->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) == 0) { Item* const stone = m_ai->FindConsumable(SPELLSTONE_DISPLAYID); Item* const stone2 = m_ai->FindConsumable(FIRESTONE_DISPLAYID); uint8 spellstone_count = m_bot->GetItemCount(SPELLSTONE, false, nullptr); if (spellstone_count == 0) spellstone_count = m_bot->GetItemCount(GREATER_SPELLSTONE, false, nullptr); if (spellstone_count == 0) spellstone_count = m_bot->GetItemCount(MAJOR_SPELLSTONE, false, nullptr); uint8 firestone_count = m_bot->GetItemCount(LESSER_FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(GREATER_FIRESTONE, false, nullptr); if (firestone_count == 0) firestone_count = m_bot->GetItemCount(MAJOR_FIRESTONE, false, nullptr); if (spellstone_count == 0 && firestone_count == 0) { if (CREATE_SPELLSTONE && shardCount > 0 && m_ai->CastSpell(CREATE_SPELLSTONE)) return; else if (CREATE_SPELLSTONE == 0 && CREATE_FIRESTONE > 0 && shardCount > 0 && m_ai->CastSpell(CREATE_FIRESTONE)) return; } else if (stone) { m_ai->UseItem(stone, EQUIPMENT_SLOT_OFFHAND); return; } else { m_ai->UseItem(stone2, EQUIPMENT_SLOT_OFFHAND); return; } } if (EatDrinkBandage()) return; //Heal Voidwalker if (pet && pet->GetEntry() == DEMON_VOIDWALKER && CONSUME_SHADOWS && pet->GetHealthPercent() < 75 && !pet->HasAura(CONSUME_SHADOWS)) m_ai->CastPetSpell(CONSUME_SHADOWS); CheckDemon(); // Soul link demon if (pet && SOUL_LINK && !m_bot->HasAura(SOUL_LINK_AURA) && m_ai->CastSpell(SOUL_LINK, *m_bot)) return; // Check demon buffs if (pet && pet->GetEntry() == DEMON_IMP && BLOOD_PACT && !m_bot->HasAura(BLOOD_PACT) && m_ai->CastPetSpell(BLOOD_PACT)) return; } // end DoNonCombatActions
CombatManeuverReturns PlayerbotWarlockAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; //Unit* pVictim = pTarget->getVictim(); bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); Pet *pet = m_bot->GetPet(); uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); // Voidwalker is near death - sacrifice it for a shield if (pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE) && pet->GetHealthPercent() < 10) m_ai->CastPetSpell(SACRIFICE); // Use healthstone if (m_ai->GetHealthPercent() < 30) { Item* healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (healthStone) m_ai->UseItem(healthStone); } // Voidwalker sacrifice gives shield - but you lose the pet (and it's DPS/tank) - use only as last resort for your own health! if (m_ai->GetHealthPercent() < 20 && pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE)) m_ai->CastPetSpell(SACRIFICE); if (m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED && !meleeReach) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // switch to melee if in melee range AND can't shoot OR have no ranged (wand) equipped else if(m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE && meleeReach && (SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true))) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); //Used to determine if this bot is highest on threat Unit *newTarget = m_ai->FindAttacker((PlayerbotAI::ATTACKERINFOTYPE) (PlayerbotAI::AIT_VICTIMSELF | PlayerbotAI::AIT_HIGHESTTHREAT), m_bot); if (newTarget && !m_ai->IsNeutralized(newTarget)) // TODO: && party has a tank { // Have threat, can't quickly lower it. 3 options remain: Stop attacking, lowlevel damage (wand), keep on keeping on. if (newTarget->GetHealthPercent() > 25) { // If elite if (m_ai->IsElite(newTarget)) { // let warlock pet handle it to win some time Creature * pCreature = (Creature*) newTarget; if (pet) { switch (pet->GetEntry()) { // taunt the elite and tank it case DEMON_VOIDWALKER: if (TORMENT && m_ai->CastPetSpell(TORMENT, newTarget)) return RETURN_NO_ACTION_OK; // maybe give it some love? case DEMON_SUCCUBUS: if (pCreature && pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_HUMANOID) if (SEDUCTION && !newTarget->HasAura(SEDUCTION) && m_ai->CastPetSpell(SEDUCTION, newTarget)) return RETURN_NO_ACTION_OK; } } // if aggroed mob is a demon or an elemental: banish it if (pCreature && (pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON || pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_ELEMENTAL)) { if (BANISH && !newTarget->HasAura(BANISH) && CastSpell(BANISH, newTarget)) return RETURN_CONTINUE; } return RETURN_NO_ACTION_OK; // do nothing and pray tank gets aggro off you } // Not an elite. You could insert FEAR here but in any PvE situation that's 90-95% likely // to worsen the situation for the group. ... So please don't. return CastSpell(SHOOT, pTarget); } } // Create soul shard (only on non-worldboss) uint8 freeSpace = m_ai->GetFreeBagSpace(); uint8 HPThreshold = (m_ai->IsElite(pTarget) ? 10 : 25); if (!m_ai->IsElite(pTarget, true) && pTarget->GetHealthPercent() < HPThreshold && (shardCount < MAX_SHARD_COUNT && freeSpace > 0)) { if (SHADOWBURN && m_ai->In_Reach(pTarget, SHADOWBURN) && !pTarget->HasAura(SHADOWBURN) && m_bot->IsSpellReady(SHADOWBURN) && CastSpell(SHADOWBURN, pTarget)) return RETURN_CONTINUE; // Do not cast Drain Soul if Shadowburn is active on target if (DRAIN_SOUL && m_ai->In_Reach(pTarget, DRAIN_SOUL) && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(SHADOWBURN) && CastSpell(DRAIN_SOUL, pTarget)) { m_ai->SetIgnoreUpdateTime(15); return RETURN_CONTINUE; } } if (pet && DARK_PACT && (100 * pet->GetPower(POWER_MANA) / pet->GetMaxPower(POWER_MANA)) > 10 && m_ai->GetManaPercent() <= 20) if (m_ai->CastSpell(DARK_PACT, *m_bot)) return RETURN_CONTINUE; // Mana check and replenishment if (LIFE_TAP && m_ai->GetManaPercent() <= 20 && m_ai->GetHealthPercent() > 50) if (m_ai->CastSpell(LIFE_TAP, *m_bot)) return RETURN_CONTINUE; // HP, mana and aggro checks done // Curse the target if (CheckCurse(pTarget)) return RETURN_CONTINUE; // Damage Spells if (spec) { switch (spec) { case WARLOCK_SPEC_AFFLICTION: if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (SIPHON_LIFE > 0 && m_ai->In_Reach(pTarget,SIPHON_LIFE) && !pTarget->HasAura(SIPHON_LIFE) && CastSpell(SIPHON_LIFE, pTarget)) return RETURN_CONTINUE; break; case WARLOCK_SPEC_DEMONOLOGY: if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; break; case WARLOCK_SPEC_DESTRUCTION: if (SHADOWBURN && pTarget->GetHealthPercent() < (HPThreshold / 2.0) && m_ai->In_Reach(pTarget, SHADOWBURN) && !pTarget->HasAura(SHADOWBURN) && CastSpell(SHADOWBURN, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (CONFLAGRATE && m_ai->In_Reach(pTarget,CONFLAGRATE) && pTarget->HasAura(IMMOLATE) && m_bot->IsSpellReady(CONFLAGRATE) && CastSpell(CONFLAGRATE, pTarget)) return RETURN_CONTINUE; break; } // Shadow bolt is common to all specs if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_OK; //if (DRAIN_LIFE && LastSpellAffliction < 4 && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(DRAIN_LIFE) && !pTarget->HasAura(DRAIN_MANA) && m_ai->GetHealthPercent() <= 70) // m_ai->CastSpell(DRAIN_LIFE, *pTarget); // //m_ai->SetIgnoreUpdateTime(5); //else if (HOWL_OF_TERROR && !pTarget->HasAura(HOWL_OF_TERROR) && m_ai->GetAttackerCount() > 3 && LastSpellAffliction < 8) // m_ai->CastSpell(HOWL_OF_TERROR, *pTarget); // m_ai->TellMaster("casting howl of terror!"); //else if (FEAR && !pTarget->HasAura(FEAR) && pVictim == m_bot && m_ai->GetAttackerCount() >= 2 && LastSpellAffliction < 9) // m_ai->CastSpell(FEAR, *pTarget); // //m_ai->TellMaster("casting fear!"); // //m_ai->SetIgnoreUpdateTime(1.5); //else if (RAIN_OF_FIRE && LastSpellDestruction < 3 && m_ai->GetAttackerCount() >= 3) // m_ai->CastSpell(RAIN_OF_FIRE, *pTarget); // //m_ai->TellMaster("casting rain of fire!"); // //m_ai->SetIgnoreUpdateTime(8); //else if (SEARING_PAIN && LastSpellDestruction < 8) // m_ai->CastSpell(SEARING_PAIN, *pTarget); //else if (SOUL_FIRE && LastSpellDestruction < 9) // m_ai->CastSpell(SOUL_FIRE, *pTarget); // //m_ai->SetIgnoreUpdateTime(6); //else if (HELLFIRE && LastSpellDestruction < 12 && !m_bot->HasAura(HELLFIRE) && m_ai->GetAttackerCount() >= 5 && m_ai->GetHealthPercent() >= 50) // m_ai->CastSpell(HELLFIRE); // m_ai->TellMaster("casting hellfire!"); // //m_ai->SetIgnoreUpdateTime(15); } // No spec due to low level OR no spell found yet if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (IMMOLATE && m_ai->In_Reach(pTarget,IMMOLATE) && !pTarget->HasAura(IMMOLATE) && CastSpell(IMMOLATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT)) return CastSpell(SHADOW_BOLT, pTarget); // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
void PlayerbotHunterAI::DoNonCombatActions() { if (!m_ai) return; if (!m_bot) return; if (!m_rangedCombat || m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_MELEE) { m_rangedCombat = true; m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); } // buff group if (TRUESHOT_AURA > 0 && !m_bot->HasAura(TRUESHOT_AURA, EFFECT_INDEX_0)) m_ai->CastSpell(TRUESHOT_AURA, *m_bot); // buff myself if (ASPECT_OF_THE_HAWK > 0 && !m_bot->HasAura(ASPECT_OF_THE_HAWK, EFFECT_INDEX_0)) m_ai->CastSpell(ASPECT_OF_THE_HAWK, *m_bot); //create water if (m_ai->FindDrink() == nullptr && m_bot->getLevel() == 60) { if (Item* pItem = m_bot->StoreNewItemInInventorySlot(CRYSTAL_WATER, 20)) m_bot->SendNewItem(pItem, 20, true, false); return; } // hp/mana check if (EatDrinkBandage()) return; // check for pet if (PET_SUMMON > 0 && !m_petSummonFailed && HasPet(m_bot)) { // we can summon pet, and no critical summon errors before Pet *pet = m_bot->GetPet(); if (!pet) { // summon pet if (PET_SUMMON > 0 && m_ai->CastSpell(PET_SUMMON, *m_bot)) m_ai->TellMaster("summoning pet."); else { m_petSummonFailed = true; m_ai->TellMaster("summon pet failed!"); } } else if (!(pet->isAlive())) { if (PET_REVIVE > 0 && m_ai->CastSpell(PET_REVIVE, *m_bot)) m_ai->TellMaster("reviving pet."); } else if (pet->GetHealthPercent() < 50) { if (PET_MEND > 0 && pet->isAlive() && !pet->HasAura(PET_MEND, EFFECT_INDEX_0) && m_ai->CastSpell(PET_MEND, *m_bot)) m_ai->TellMaster("healing pet."); } else if (pet->GetHappinessState() != HAPPY) // if pet is hungry { Unit *caster = (Unit *) m_bot; // list out items in main backpack for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++) { Item* const pItem = m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (pItem) { const ItemPrototype* const pItemProto = pItem->GetProto(); if (!pItemProto) continue; if (pet->HaveInDiet(pItemProto)) // is pItem in pets diet { // DEBUG_LOG ("[PlayerbotHunterAI]: DoNonCombatActions - Food for pet: %s",pItemProto->Name1); caster->CastSpell(caster, 23355, true); // pet feed visual uint32 count = 1; // number of items used int32 benefit = pet->GetCurrentFoodBenefitLevel(pItemProto->ItemLevel); // nutritional value of food m_bot->DestroyItemCount(pItem, count, true); // remove item from inventory m_bot->CastCustomSpell(m_bot, PET_FEED, &benefit, nullptr, nullptr, true); // feed pet m_ai->TellMaster("feeding pet."); m_ai->SetIgnoreUpdateTime(10); return; } } } // list out items in other removable backpacks for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag) { const Bag* const pBag = (Bag *) m_bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag); if (pBag) for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot) { Item* const pItem = m_bot->GetItemByPos(bag, slot); if (pItem) { const ItemPrototype* const pItemProto = pItem->GetProto(); if (!pItemProto) continue; if (pet->HaveInDiet(pItemProto)) // is pItem in pets diet { // DEBUG_LOG ("[PlayerbotHunterAI]: DoNonCombatActions - Food for pet: %s",pItemProto->Name1); caster->CastSpell(caster, 23355, true); // pet feed visual uint32 count = 1; // number of items used int32 benefit = pet->GetCurrentFoodBenefitLevel(pItemProto->ItemLevel); // nutritional value of food m_bot->DestroyItemCount(pItem, count, true); // remove item from inventory m_bot->CastCustomSpell(m_bot, PET_FEED, &benefit, nullptr, nullptr, true); // feed pet m_ai->TellMaster("feeding pet."); m_ai->SetIgnoreUpdateTime(10); return; } } } } if (pet->HasAura(PET_MEND, EFFECT_INDEX_0) && !pet->HasAura(PET_FEED, EFFECT_INDEX_0)) m_ai->TellMaster("..no pet food!"); m_ai->SetIgnoreUpdateTime(7); } } } // end DoNonCombatActions
CombatManeuverReturns PlayerbotHunterAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; if (!pTarget) return RETURN_NO_ACTION_ERROR; Unit* pVictim = pTarget->getVictim(); // check for pet and heal if neccessary Pet *pet = m_bot->GetPet(); // TODO: clarify/simplify: !pet->getDeathState() != ALIVE if (pet && PET_MEND > 0 && pet->isAlive() && pet->GetHealthPercent() < 50 && pVictim != m_bot && !pet->HasAura(PET_MEND, EFFECT_INDEX_0) && m_ai->CastSpell(PET_MEND, *m_bot)) { m_ai->TellMaster("healing pet."); return RETURN_CONTINUE; } else if (pet && INTIMIDATION > 0 && pVictim == pet && !pet->HasAura(INTIMIDATION, EFFECT_INDEX_0) && m_ai->CastSpell(INTIMIDATION, *m_bot)) return RETURN_CONTINUE; // racial traits if (m_bot->getRace() == RACE_ORC && !m_bot->HasAura(BLOOD_FURY, EFFECT_INDEX_0)) m_ai->CastSpell(BLOOD_FURY, *m_bot); else if (m_bot->getRace() == RACE_TROLL && !m_bot->HasAura(BERSERKING, EFFECT_INDEX_0)) m_ai->CastSpell(BERSERKING, *m_bot); // check if ranged combat is possible bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); if (meleeReach || !m_has_ammo) { // switch to melee combat (target in melee range, out of ammo) m_rangedCombat = false; m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); if (!m_bot->GetUInt32Value(PLAYER_AMMO_ID)) m_ai->TellMaster("Out of ammo!"); // become monkey (increases dodge chance)... if (ASPECT_OF_THE_MONKEY > 0 && !m_bot->HasAura(ASPECT_OF_THE_MONKEY, EFFECT_INDEX_0)) m_ai->CastSpell(ASPECT_OF_THE_MONKEY, *m_bot); } else if (!meleeReach) { // switch to ranged combat m_rangedCombat = true; m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // increase ranged attack power... if (ASPECT_OF_THE_HAWK > 0 && !m_bot->HasAura(ASPECT_OF_THE_HAWK, EFFECT_INDEX_0)) m_ai->CastSpell(ASPECT_OF_THE_HAWK, *m_bot); // m_ai->TellMaster("target dist %f",m_bot->GetCombatDistance(pTarget,true)); if (AUTO_SHOT > 0) { if (m_bot->isAttackReady(RANGED_ATTACK)) m_bot->CastSpell(pTarget, AUTO_SHOT, true); m_bot->setAttackTimer(RANGED_ATTACK,500); const SpellEntry* spellInfo = sSpellStore.LookupEntry(AUTO_SHOT); if (!spellInfo) return RETURN_CONTINUE; if (m_ai->CheckBotCast(spellInfo) != SPELL_CAST_OK) m_bot->InterruptNonMeleeSpells(true, AUTO_SHOT); } } // damage spells if (m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_RANGED) { if (HUNTERS_MARK > 0 && m_ai->In_Reach(pTarget,HUNTERS_MARK) && !pTarget->HasAura(HUNTERS_MARK, EFFECT_INDEX_0) && m_ai->CastSpell(HUNTERS_MARK, *pTarget)) return RETURN_CONTINUE; else if (RAPID_FIRE > 0 && m_ai->In_Reach(pTarget,RAPID_FIRE) && !m_bot->HasAura(RAPID_FIRE, EFFECT_INDEX_0) && m_ai->CastSpell(RAPID_FIRE, *m_bot)) return RETURN_CONTINUE; else if (MULTI_SHOT > 0 && m_ai->In_Reach(pTarget,MULTI_SHOT) && m_ai->GetAttackerCount() >= 3 && m_ai->CastSpell(MULTI_SHOT, *pTarget)) return RETURN_CONTINUE; else if (ARCANE_SHOT > 0 && m_ai->In_Reach(pTarget,ARCANE_SHOT) && m_ai->CastSpell(ARCANE_SHOT, *pTarget)) return RETURN_CONTINUE; else if (CONCUSSIVE_SHOT > 0 && m_ai->In_Reach(pTarget,CONCUSSIVE_SHOT) && !pTarget->HasAura(CONCUSSIVE_SHOT, EFFECT_INDEX_0) && m_ai->CastSpell(CONCUSSIVE_SHOT, *pTarget)) return RETURN_CONTINUE; else if (VIPER_STING > 0 && m_ai->In_Reach(pTarget,VIPER_STING) && pTarget->GetPower(POWER_MANA) > 0 && m_ai->GetManaPercent() < 70 && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(VIPER_STING, *pTarget)) return RETURN_CONTINUE; else if (SERPENT_STING > 0 && m_ai->In_Reach(pTarget,SERPENT_STING) && !pTarget->HasAura(SERPENT_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SCORPID_STING, EFFECT_INDEX_0) && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(SERPENT_STING, *pTarget)) return RETURN_CONTINUE; else if (SCORPID_STING > 0 && m_ai->In_Reach(pTarget,SCORPID_STING) && !pTarget->HasAura(WYVERN_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SCORPID_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SERPENT_STING, EFFECT_INDEX_0) && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(SCORPID_STING, *pTarget)) return RETURN_CONTINUE; else if (VOLLEY > 0 && m_ai->In_Reach(pTarget,VOLLEY) && m_ai->GetAttackerCount() >= 3 && m_ai->CastSpell(VOLLEY, *pTarget)) return RETURN_CONTINUE; else if (BLACK_ARROW > 0 && m_ai->In_Reach(pTarget,BLACK_ARROW) && !pTarget->HasAura(BLACK_ARROW, EFFECT_INDEX_0) && m_ai->CastSpell(BLACK_ARROW, *pTarget)) return RETURN_CONTINUE; else if (AIMED_SHOT > 0 && m_ai->In_Reach(pTarget,AIMED_SHOT) && m_ai->CastSpell(AIMED_SHOT, *pTarget)) return RETURN_CONTINUE; else return RETURN_NO_ACTION_OK; } else { if (RAPTOR_STRIKE > 0 && m_ai->In_Reach(pTarget,RAPTOR_STRIKE) && m_ai->CastSpell(RAPTOR_STRIKE, *pTarget)) return RETURN_CONTINUE; else if (EXPLOSIVE_TRAP > 0 && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(EXPLOSIVE_TRAP, *pTarget)) return RETURN_CONTINUE; else if (WING_CLIP > 0 && m_ai->In_Reach(pTarget,WING_CLIP) && !pTarget->HasAura(WING_CLIP, EFFECT_INDEX_0) && m_ai->CastSpell(WING_CLIP, *pTarget)) return RETURN_CONTINUE; else if (IMMOLATION_TRAP > 0 && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(IMMOLATION_TRAP, *pTarget)) return RETURN_CONTINUE; else if (MONGOOSE_BITE > 0 && m_ai->Impulse() && m_ai->CastSpell(MONGOOSE_BITE, *pTarget)) return RETURN_CONTINUE; else if (FROST_TRAP > 0 && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(FROST_TRAP, *pTarget)) return RETURN_CONTINUE; else if (DETERRENCE > 0 && pVictim == m_bot && m_bot->GetHealthPercent() < 50 && !m_bot->HasAura(DETERRENCE, EFFECT_INDEX_0) && m_ai->CastSpell(DETERRENCE, *m_bot)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_TAUREN && !pTarget->HasAura(WAR_STOMP, EFFECT_INDEX_0) && m_ai->CastSpell(WAR_STOMP, *pTarget)) return RETURN_CONTINUE; // else if (m_bot->getRace() == RACE_DWARF && m_bot->HasAuraState(AURA_STATE_DEADLY_POISON) && m_ai->CastSpell(STONEFORM, *m_bot)) // return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_NIGHTELF && pVictim == m_bot && m_ai->GetHealthPercent() < 25 && !m_bot->HasAura(SHADOWMELD, EFFECT_INDEX_0) && m_ai->CastSpell(SHADOWMELD, *m_bot)) return RETURN_CONTINUE; /*else if(FREEZING_TRAP > 0 && !pTarget->HasAura(FREEZING_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(FREEZING_TRAP,*pTarget) ) out << " > Freezing Trap"; // this can trap your bots too else if(DISENGAGE > 0 && pVictim && m_ai->CastSpell(DISENGAGE,*pTarget) ) out << " > Disengage!"; // attempt to return to ranged combat*/ } return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
CombatManeuverReturns PlayerbotWarlockAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; //Unit* pVictim = pTarget->getVictim(); bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); Pet *pet = m_bot->GetPet(); uint32 spec = m_bot->GetSpec(); uint8 shardCount = m_bot->GetItemCount(SOUL_SHARD, false, nullptr); //If we have UA it will replace immolate in our rotation uint32 FIRE = (UNSTABLE_AFFLICTION > 0 ? UNSTABLE_AFFLICTION : IMMOLATE); // Voidwalker is near death - sacrifice it for a shield if (pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE) && pet->GetHealthPercent() < 10) m_ai->CastPetSpell(SACRIFICE); // Use healthstone if (m_ai->GetHealthPercent() < 30) { Item* healthStone = m_ai->FindConsumable(HEALTHSTONE_DISPLAYID); if (healthStone) m_ai->UseItem(healthStone); } // Voidwalker sacrifice gives shield - but you lose the pet (and it's DPS/tank) - use only as last resort for your own health! if (m_ai->GetHealthPercent() < 20 && pet && pet->GetEntry() == DEMON_VOIDWALKER && SACRIFICE && !m_bot->HasAura(SACRIFICE)) m_ai->CastPetSpell(SACRIFICE); if (m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED && !meleeReach) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // if in melee range OR can't shoot OR have no ranged (wand) equipped else if(m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE && (meleeReach || SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true))) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); //Used to determine if this bot is highest on threat Unit *newTarget = m_ai->FindAttacker((PlayerbotAI::ATTACKERINFOTYPE) (PlayerbotAI::AIT_VICTIMSELF | PlayerbotAI::AIT_HIGHESTTHREAT), m_bot); if (newTarget) // TODO: && party has a tank { if (SOULSHATTER > 0 && shardCount > 0 && !m_bot->HasSpellCooldown(SOULSHATTER)) if (CastSpell(SOULSHATTER, m_bot)) return RETURN_CONTINUE; // Have threat, can't quickly lower it. 3 options remain: Stop attacking, lowlevel damage (wand), keep on keeping on. if (newTarget->GetHealthPercent() > 25) { // If elite, do nothing and pray tank gets aggro off you // TODO: Is there an IsElite function? If so, find it and insert. //if (newTarget->IsElite()) // return; // Not an elite. You could insert FEAR here but in any PvE situation that's 90-95% likely // to worsen the situation for the group. ... So please don't. return CastSpell(SHOOT, pTarget); } } // Damage Spells switch (spec) { case WARLOCK_SPEC_AFFLICTION: if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (HAUNT && m_ai->In_Reach(pTarget,HAUNT) && !m_bot->HasSpellCooldown(HAUNT) && CastSpell(HAUNT, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; case WARLOCK_SPEC_DEMONOLOGY: if (pet && DEMONIC_EMPOWERMENT && !m_bot->HasSpellCooldown(DEMONIC_EMPOWERMENT) && CastSpell(DEMONIC_EMPOWERMENT)) return RETURN_CONTINUE; if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (INCINERATE && m_ai->In_Reach(pTarget,INCINERATE) && pTarget->HasAura(FIRE) && CastSpell(INCINERATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; case WARLOCK_SPEC_DESTRUCTION: if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY) && CastSpell(CURSE_OF_AGONY, pTarget)) return RETURN_CONTINUE; if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (CONFLAGRATE && m_ai->In_Reach(pTarget,CONFLAGRATE) && pTarget->HasAura(FIRE) && !m_bot->HasSpellCooldown(CONFLAGRATE) && CastSpell(CONFLAGRATE, pTarget)) return RETURN_CONTINUE; if (CHAOS_BOLT && m_ai->In_Reach(pTarget,CHAOS_BOLT) && !m_bot->HasSpellCooldown(CHAOS_BOLT) && CastSpell(CHAOS_BOLT, pTarget)) return RETURN_CONTINUE; if (INCINERATE && m_ai->In_Reach(pTarget,INCINERATE) && pTarget->HasAura(FIRE) && CastSpell(INCINERATE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT) && CastSpell(SHADOW_BOLT, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; //if (LIFE_TAP && LastSpellAffliction < 1 && m_ai->GetManaPercent() <= 50 && m_ai->GetHealthPercent() > 50) // m_ai->CastSpell(LIFE_TAP, *m_bot); //else if (DRAIN_SOUL && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.40 && !pTarget->HasAura(DRAIN_SOUL) && LastSpellAffliction < 3) // m_ai->CastSpell(DRAIN_SOUL, *pTarget); // //m_ai->SetIgnoreUpdateTime(15); //else if (DRAIN_LIFE && LastSpellAffliction < 4 && !pTarget->HasAura(DRAIN_SOUL) && !pTarget->HasAura(SEED_OF_CORRUPTION) && !pTarget->HasAura(DRAIN_LIFE) && !pTarget->HasAura(DRAIN_MANA) && m_ai->GetHealthPercent() <= 70) // m_ai->CastSpell(DRAIN_LIFE, *pTarget); // //m_ai->SetIgnoreUpdateTime(5); //else if (SEED_OF_CORRUPTION && !pTarget->HasAura(SEED_OF_CORRUPTION) && LastSpellAffliction < 7) // m_ai->CastSpell(SEED_OF_CORRUPTION, *pTarget); //else if (HOWL_OF_TERROR && !pTarget->HasAura(HOWL_OF_TERROR) && m_ai->GetAttackerCount() > 3 && LastSpellAffliction < 8) // m_ai->CastSpell(HOWL_OF_TERROR, *pTarget); // m_ai->TellMaster("casting howl of terror!"); //else if (FEAR && !pTarget->HasAura(FEAR) && pVictim == m_bot && m_ai->GetAttackerCount() >= 2 && LastSpellAffliction < 9) // m_ai->CastSpell(FEAR, *pTarget); // //m_ai->TellMaster("casting fear!"); // //m_ai->SetIgnoreUpdateTime(1.5); //else if ((pet) && (DARK_PACT > 0 && m_ai->GetManaPercent() <= 50 && LastSpellAffliction < 10 && pet->GetPower(POWER_MANA) > 0)) // m_ai->CastSpell(DARK_PACT, *m_bot); //if (SHADOWFURY && LastSpellDestruction < 1 && !pTarget->HasAura(SHADOWFURY)) // m_ai->CastSpell(SHADOWFURY, *pTarget); //else if (RAIN_OF_FIRE && LastSpellDestruction < 3 && m_ai->GetAttackerCount() >= 3) // m_ai->CastSpell(RAIN_OF_FIRE, *pTarget); // //m_ai->TellMaster("casting rain of fire!"); // //m_ai->SetIgnoreUpdateTime(8); //else if (SHADOWFLAME && !pTarget->HasAura(SHADOWFLAME) && LastSpellDestruction < 4) // m_ai->CastSpell(SHADOWFLAME, *pTarget); //else if (SEARING_PAIN && LastSpellDestruction < 8) // m_ai->CastSpell(SEARING_PAIN, *pTarget); //else if (SOUL_FIRE && LastSpellDestruction < 9) // m_ai->CastSpell(SOUL_FIRE, *pTarget); // //m_ai->SetIgnoreUpdateTime(6); //else if (SHADOWBURN && LastSpellDestruction < 11 && pTarget->GetHealth() < pTarget->GetMaxHealth() * 0.20 && !pTarget->HasAura(SHADOWBURN)) // m_ai->CastSpell(SHADOWBURN, *pTarget); //else if (HELLFIRE && LastSpellDestruction < 12 && !m_bot->HasAura(HELLFIRE) && m_ai->GetAttackerCount() >= 5 && m_ai->GetHealthPercent() >= 50) // m_ai->CastSpell(HELLFIRE); // m_ai->TellMaster("casting hellfire!"); // //m_ai->SetIgnoreUpdateTime(15); //else if (CURSE_OF_THE_ELEMENTS && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && LastSpellCurse < 2) // m_ai->CastSpell(CURSE_OF_THE_ELEMENTS, *pTarget); //else if (CURSE_OF_WEAKNESS && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 3) // m_ai->CastSpell(CURSE_OF_WEAKNESS, *pTarget); //else if (CURSE_OF_TONGUES && !pTarget->HasAura(CURSE_OF_TONGUES) && !pTarget->HasAura(SHADOWFLAME) && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_THE_ELEMENTS) && LastSpellCurse < 4) // m_ai->CastSpell(CURSE_OF_TONGUES, *pTarget); } // No spec due to low level OR no spell found yet if (CORRUPTION && m_ai->In_Reach(pTarget,CORRUPTION) && !pTarget->HasAura(CORRUPTION) && CastSpell(CORRUPTION, pTarget)) return RETURN_CONTINUE; if (FIRE && m_ai->In_Reach(pTarget,FIRE) && !pTarget->HasAura(FIRE) && CastSpell(FIRE, pTarget)) return RETURN_CONTINUE; if (SHADOW_BOLT && m_ai->In_Reach(pTarget,SHADOW_BOLT)) return CastSpell(SHADOW_BOLT, pTarget); return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
CombatManeuverReturns PlayerbotHunterAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; if (!pTarget) return RETURN_NO_ACTION_ERROR; Unit* pVictim = pTarget->getVictim(); // check for pet and heal if neccessary Pet *pet = m_bot->GetPet(); // TODO: clarify/simplify: !pet->getDeathState() != ALIVE if (pet && PET_MEND > 0 && pet->isAlive() && pet->GetHealthPercent() < 50 && pVictim != m_bot && !pet->HasAura(PET_MEND, EFFECT_INDEX_0) && m_ai->CastSpell(PET_MEND, *m_bot)) { m_ai->TellMaster("healing pet."); return RETURN_CONTINUE; } else if (pet && INTIMIDATION > 0 && pVictim == pet && !pet->HasAura(INTIMIDATION, EFFECT_INDEX_0) && m_ai->CastSpell(INTIMIDATION, *m_bot)) return RETURN_CONTINUE; // racial traits if (m_bot->getRace() == RACE_ORC && !m_bot->HasAura(BLOOD_FURY, EFFECT_INDEX_0)) m_ai->CastSpell(BLOOD_FURY, *m_bot); else if (m_bot->getRace() == RACE_TROLL && !m_bot->HasAura(BERSERKING, EFFECT_INDEX_0)) m_ai->CastSpell(BERSERKING, *m_bot); // check if ranged combat is possible float dist = m_bot->GetCombatDistance(pTarget, true); if ((dist <= ATTACK_DISTANCE || !m_bot->GetUInt32Value(PLAYER_AMMO_ID)) && m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_RANGED) { // switch to melee combat (target in melee range, out of ammo) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); if (!m_bot->GetUInt32Value(PLAYER_AMMO_ID)) m_ai->TellMaster("Out of ammo!"); } else if (dist > ATTACK_DISTANCE && m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_MELEE) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); // Set appropriate aspect if (m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_RANGED) { if (ASPECT_OF_THE_HAWK && !m_bot->HasAura(ASPECT_OF_THE_HAWK, EFFECT_INDEX_0)) m_ai->CastSpell(ASPECT_OF_THE_HAWK, *m_bot); } else { if (ASPECT_OF_THE_MONKEY && !m_bot->HasAura(ASPECT_OF_THE_MONKEY, EFFECT_INDEX_0)) m_ai->CastSpell(ASPECT_OF_THE_MONKEY, *m_bot); } // activate auto shot: Reworked to account for AUTO_SHOT being a triggered spell if (AUTO_SHOT > 0 && m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_RANGED && m_ai->GetCurrentSpellId() != AUTO_SHOT) m_bot->CastSpell(pTarget, AUTO_SHOT, true); // damage spells if (m_ai->GetCombatStyle() == PlayerbotAI::COMBAT_RANGED) { if (HUNTERS_MARK > 0 && !pTarget->HasAura(HUNTERS_MARK, EFFECT_INDEX_0) && m_ai->CastSpell(HUNTERS_MARK, *pTarget)) return RETURN_CONTINUE; else if (RAPID_FIRE > 0 && !m_bot->HasAura(RAPID_FIRE, EFFECT_INDEX_0) && m_ai->CastSpell(RAPID_FIRE, *m_bot)) return RETURN_CONTINUE; else if (MULTI_SHOT > 0 && m_ai->GetAttackerCount() >= 3 && m_ai->CastSpell(MULTI_SHOT, *pTarget)) return RETURN_CONTINUE; else if (ARCANE_SHOT > 0 && m_ai->CastSpell(ARCANE_SHOT, *pTarget)) return RETURN_CONTINUE; else if (CONCUSSIVE_SHOT > 0 && !pTarget->HasAura(CONCUSSIVE_SHOT, EFFECT_INDEX_0) && m_ai->CastSpell(CONCUSSIVE_SHOT, *pTarget)) return RETURN_CONTINUE; else if (EXPLOSIVE_SHOT > 0 && !pTarget->HasAura(EXPLOSIVE_SHOT, EFFECT_INDEX_0) && m_ai->CastSpell(EXPLOSIVE_SHOT, *pTarget)) return RETURN_CONTINUE; else if (VIPER_STING > 0 && pTarget->GetPower(POWER_MANA) > 0 && m_ai->GetManaPercent() < 70 && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(VIPER_STING, *pTarget)) return RETURN_CONTINUE; else if (SERPENT_STING > 0 && !pTarget->HasAura(SERPENT_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SCORPID_STING, EFFECT_INDEX_0) && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(SERPENT_STING, *pTarget)) return RETURN_CONTINUE; else if (SCORPID_STING > 0 && !pTarget->HasAura(WYVERN_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SCORPID_STING, EFFECT_INDEX_0) && !pTarget->HasAura(SERPENT_STING, EFFECT_INDEX_0) && !pTarget->HasAura(VIPER_STING, EFFECT_INDEX_0) && m_ai->CastSpell(SCORPID_STING, *pTarget)) return RETURN_CONTINUE; else if (CHIMERA_SHOT > 0 && m_ai->CastSpell(CHIMERA_SHOT, *pTarget)) return RETURN_CONTINUE; else if (VOLLEY > 0 && m_ai->GetAttackerCount() >= 3 && m_ai->CastSpell(VOLLEY, *pTarget)) return RETURN_CONTINUE; else if (BLACK_ARROW > 0 && !pTarget->HasAura(BLACK_ARROW, EFFECT_INDEX_0) && m_ai->CastSpell(BLACK_ARROW, *pTarget)) return RETURN_CONTINUE; else if (AIMED_SHOT > 0 && m_ai->CastSpell(AIMED_SHOT, *pTarget)) return RETURN_CONTINUE; else if (STEADY_SHOT > 0 && m_ai->CastSpell(STEADY_SHOT, *pTarget)) return RETURN_CONTINUE; else if (KILL_SHOT > 0 && pTarget->GetHealthPercent() < 20 && m_ai->CastSpell(KILL_SHOT, *pTarget)) return RETURN_CONTINUE; else return RETURN_NO_ACTION_OK; } else { if (RAPTOR_STRIKE > 0 && m_ai->CastSpell(RAPTOR_STRIKE, *pTarget)) return RETURN_CONTINUE; else if (EXPLOSIVE_TRAP > 0 && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(EXPLOSIVE_TRAP, *pTarget)) return RETURN_CONTINUE; else if (WING_CLIP > 0 && !pTarget->HasAura(WING_CLIP, EFFECT_INDEX_0) && m_ai->CastSpell(WING_CLIP, *pTarget)) return RETURN_CONTINUE; else if (IMMOLATION_TRAP > 0 && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(IMMOLATION_TRAP, *pTarget)) return RETURN_CONTINUE; else if (MONGOOSE_BITE > 0 && m_ai->CastSpell(MONGOOSE_BITE, *pTarget)) return RETURN_CONTINUE; else if (FROST_TRAP > 0 && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(FROST_TRAP, *pTarget)) return RETURN_CONTINUE; else if (ARCANE_TRAP > 0 && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(ARCANE_TRAP, *pTarget)) return RETURN_CONTINUE; else if (DETERRENCE > 0 && pVictim == m_bot && m_bot->GetHealthPercent() < 50 && !m_bot->HasAura(DETERRENCE, EFFECT_INDEX_0) && m_ai->CastSpell(DETERRENCE, *m_bot)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_TAUREN && !pTarget->HasAura(WAR_STOMP, EFFECT_INDEX_0) && m_ai->CastSpell(WAR_STOMP, *pTarget)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_BLOODELF && !pTarget->HasAura(ARCANE_TORRENT, EFFECT_INDEX_0) && m_ai->CastSpell(ARCANE_TORRENT, *pTarget)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_DWARF && m_bot->HasAuraState(AURA_STATE_DEADLY_POISON) && m_ai->CastSpell(STONEFORM, *m_bot)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_NIGHTELF && pVictim == m_bot && m_ai->GetHealthPercent() < 25 && !m_bot->HasAura(SHADOWMELD, EFFECT_INDEX_0) && m_ai->CastSpell(SHADOWMELD, *m_bot)) return RETURN_CONTINUE; else if (m_bot->getRace() == RACE_DRAENEI && m_ai->GetHealthPercent() < 25 && !m_bot->HasAura(GIFT_OF_THE_NAARU, EFFECT_INDEX_0) && m_ai->CastSpell(GIFT_OF_THE_NAARU, *m_bot)) return RETURN_CONTINUE; else if (pet && pet->isAlive() && MISDIRECTION > 0 && pVictim == m_bot && !m_bot->HasAura(MISDIRECTION, EFFECT_INDEX_0) && m_ai->CastSpell(MISDIRECTION, *pet)) return RETURN_CONTINUE; /*else if(FREEZING_TRAP > 0 && !pTarget->HasAura(FREEZING_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(FREEZING_TRAP,*pTarget) ) out << " > Freezing Trap"; // this can trap your bots too else if(BEAR_TRAP > 0 && !pTarget->HasAura(BEAR_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(ARCANE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(EXPLOSIVE_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(IMMOLATION_TRAP, EFFECT_INDEX_0) && !pTarget->HasAura(FROST_TRAP, EFFECT_INDEX_0) && m_ai->CastSpell(BEAR_TRAP,*pTarget) ) out << " > Bear Trap"; // this was just too annoying :) else if(DISENGAGE > 0 && pVictim && m_ai->CastSpell(DISENGAGE,*pTarget) ) out << " > Disengage!"; // attempt to return to ranged combat*/ else RETURN_NO_ACTION_OK; } return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver