void PlayerbotDruidAI::DoNextCombatManeuver(Unit *pTarget) { PlayerbotAI* ai = GetAI(); if (!ai) return; switch (ai->GetScenarioType()) { case PlayerbotAI::SCENARIO_DUEL: ai->CastSpell(MOONFIRE); return; default: break; } uint32 masterHP = GetMaster()->GetHealth() * 100 / GetMaster()->GetMaxHealth(); Player *m_bot = GetPlayerBot(); Unit* pVictim = pTarget->getVictim(); if (ai->GetCombatOrder() == PlayerbotAI::ORDERS_HEAL) // && ai->GetMovementOrder() == PlayerbotAI::MOVEMENT_STAY) SpellSequence = DruidHeal; else if (IsFeral() && ai->GetCombatOrder() == PlayerbotAI::ORDERS_ASSIST) // && ai->GetMovementOrder() == PlayerbotAI::MOVEMENT_STAY) SpellSequence = DruidCombat; else if (IsFeral() && ai->GetCombatOrder() == PlayerbotAI::ORDERS_TANK) SpellSequence = DruidTank; else SpellSequence = DruidSpell; switch (SpellSequence) { case DruidTank: // Its now a tank druid! //ai->TellMaster("DruidTank"); _DoNextPVECombatManeuverBear(pTarget); break; case DruidSpell: //ai->TellMaster("DruidSpell"); _DoNextPVECombatManeuverSpellDPS(pTarget); break; case DruidHeal: //ai->TellMaster("DruidHeal"); _DoNextPVECombatManeuverHeal(pTarget); break; case DruidCombat: //ai->TellMaster("DruidCombat"); _DoNextPVECombatManeuverMeleeDPS(pTarget); break; } } // end DoNextCombatManeuver
void PlayerbotDruidAI::DoNextCombatManeuver(Unit *pTarget) { PlayerbotAI* ai = GetAI(); if (!ai) return; switch (ai->GetScenarioType()) { case PlayerbotAI::SCENARIO_DUEL: ai->CastSpell(MOONFIRE); return; } uint32 masterHP = GetMaster()->GetHealth() * 100 / GetMaster()->GetMaxHealth(); Player *m_bot = GetPlayerBot(); Unit* pVictim = pTarget->getVictim(); if (ai->GetCombatOrder() == PlayerbotAI::ORDERS_HEAL) SpellSequence = DruidHeal; else if (ai->GetCombatOrder() == PlayerbotAI::ORDERS_ASSIST && CAT_FORM > 0) SpellSequence = DruidCombat; // No check for Dire Bear here: you must have Bear form to learn Dire Bear form. else if (ai->GetCombatOrder() == PlayerbotAI::ORDERS_TANK && BEAR_FORM > 0) SpellSequence = DruidTank; else SpellSequence = DruidSpell; switch (SpellSequence) { case DruidTank: // Its now a tank druid! //ai->TellMaster("DruidTank"); _DoNextPVECombatManeuverBear(pTarget); break; case DruidSpell: //ai->TellMaster("DruidSpell"); _DoNextPVECombatManeuverSpellDPS(pTarget); break; case DruidHeal: //ai->TellMaster("DruidHeal"); _DoNextPVECombatManeuverHeal(pTarget); break; case DruidCombat: //ai->TellMaster("DruidCombat"); _DoNextPVECombatManeuverMeleeDPS(pTarget); break; } } // end DoNextCombatManeuver
void PlayerbotDruidAI::_DoNextPVECombatManeuverMeleeDPS(Unit* pTarget) { PlayerbotAI* ai = GetAI(); if (!ai) return; // True, bear form is set up for tanking but even then it's better DPS for levels 10-19 than humanoid form if (CAT_FORM == 0 && BEAR_FORM > 0) // but only go there if you can get into bear form. else stay here. if (ai->CastSpell(BEAR_FORM)) return _DoNextPVECombatManeuverBear(pTarget); //uint32 masterHP = GetMaster()->GetHealth() * 100 / GetMaster()->GetMaxHealth(); Player *m_bot = GetPlayerBot(); Unit* pVictim = pTarget->getVictim(); if (!m_bot->HasInArc(M_PI_F, pTarget)) { m_bot->SetFacingTo(m_bot->GetAngle(pTarget)); if (pVictim) pVictim->Attack(pTarget, true); } if (CAT_FORM > 0 && !m_bot->HasAura(CAT_FORM, EFFECT_INDEX_0)) if (!ai->CastSpell(CAT_FORM)) { if (ai->GetManaPercent() < 30) // TODO: tweak this value. Pretty sure bear form mana Req is way less than 30% of base mana, let alone total mana return; // conserve mana else _DoNextPVECombatManeuverSpellDPS(pTarget); } // Commented out: Above should take care of it //// Technically bear form is better than no form for melee druids levels 10-19. //if (m_bot->HasAura(BEAR_FORM, EFFECT_INDEX_0)) //{ // m_bot->RemoveAurasDueToSpell(BEAR_FORM_1); // //ai->TellMaster("FormClearBear"); // return; //} //if (m_bot->HasAura(DIRE_BEAR_FORM, EFFECT_INDEX_0)) //{ // m_bot->RemoveAurasDueToSpell(DIRE_BEAR_FORM_1); // //ai->TellMaster("FormClearDireBear"); // return; //} //if (m_bot->HasAura(MOONKIN_FORM, EFFECT_INDEX_0)) //{ // m_bot->RemoveAurasDueToSpell(MOONKIN_FORM_1); // //ai->TellMaster("FormClearMoonkin"); // return; //} //if (COWER > 0 && m_bot->GetComboPoints() == 1 && ai->GetEnergyAmount() >= 20) // && HasAnyAggroWhereSecondAggroIsNotHealer() //{ // ai->CastSpell(COWER); // //ai->TellMaster("Cower"); //} if (MAIM > 0 && m_bot->GetComboPoints() >= 1 && pTarget->IsNonMeleeSpellCasted(true)) { ai->CastSpell(MAIM, *pTarget); //ai->TellMaster("SpellPreventing Maim"); return; } if (RAKE > 0 && m_bot->GetComboPoints() < 1 && ai->GetEnergyAmount() >= 40) // should be replaced by a check for the bleed effect it causes (along with Combo != 5) { ai->CastSpell(RAKE, *pTarget); //ai->TellMaster("Rake"); return; } if (MANGLE > 0 && m_bot->GetComboPoints() == 1 && ai->GetEnergyAmount() >= 45) { ai->CastSpell(MANGLE, *pTarget); //ai->TellMaster("Mangle"); return; } if (CLAW > 0 && m_bot->GetComboPoints() < 5 && ai->GetEnergyAmount() >= 45) { ai->CastSpell(CLAW, *pTarget); //ai->TellMaster("Claw"); return; } if (m_bot->GetComboPoints() == 5) { if (RIP > 0 && pTarget->getClass() == CLASS_ROGUE && ai->GetEnergyAmount() >= 30) ai->CastSpell(RIP, *pTarget); else if (FEROCIOUS_BITE > 0 && ai->GetEnergyAmount() >= 35 && (pTarget->getClass() == CLASS_HUNTER || pTarget->getClass() == CLASS_WARRIOR || pTarget->getClass() == CLASS_PALADIN || pTarget->getClass() == CLASS_DEATH_KNIGHT)) ai->CastSpell(FEROCIOUS_BITE, *pTarget); else if (ai->GetEnergyAmount() >= 35) { //ai->TellMaster("Else Maim, Ferocious Bite or Rip."); // MAIM must be first check, best option against other classes if (MAIM > 0) ai->CastSpell(MAIM, *pTarget); else if (FEROCIOUS_BITE > 0) ai->CastSpell(FEROCIOUS_BITE, *pTarget); else if (RIP > 0) // Fair enough, only needs 30 energy... but that means 35 is plenty ai->CastSpell(RIP, *pTarget); } return; } }
CombatManeuverReturns PlayerbotDruidAI::DoNextCombatManeuverPVE(Unit* pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; //uint32 masterHP = GetMaster()->GetHealth() * 100 / GetMaster()->GetMaxHealth(); uint32 spec = m_bot->GetSpec(); if (spec == 0) // default to spellcasting or healing for healer spec = (PlayerbotAI::ORDERS_HEAL & m_ai->GetCombatOrder() ? DRUID_SPEC_RESTORATION : DRUID_SPEC_BALANCE); // Make sure healer stays put, don't even melee (aggro) if in range. if (m_ai->IsHealer() && m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); else if (!m_ai->IsHealer() && m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); //Unit* pVictim = pTarget->getVictim(); uint32 BEAR = (DIRE_BEAR_FORM > 0 ? DIRE_BEAR_FORM : BEAR_FORM); // TODO: do something to allow emergency heals for non-healers? switch (CheckForms()) { case RETURN_OK_SHIFTING: return RETURN_CONTINUE; case RETURN_FAIL: case RETURN_OK_CANNOTSHIFT: if (spec == DRUID_SPEC_FERAL) spec = DRUID_SPEC_BALANCE; // Can't shift, force spellcasting break; // rest functions without form //case RETURN_OK_NOCHANGE: // great! //case RETURN_FAIL_WAITINGONSELFBUFF: // This is war dammit! No time for silly buffs during combat... default: break; } //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 (HealPlayer(m_bot) == RETURN_CONTINUE) return RETURN_CONTINUE; // TODO: Heal tank // We have aggro, don't need to heal self or tank, wait for aggro to subside //if (m_ai->IsHealer()) // Commented out: not necessary because of below. Leave code here in case below ever changes. // return RETURN_NO_ACTION_OK; // We have no shoot spell; Assume auto-attack is on return RETURN_NO_ACTION_OK; } if (m_ai->IsHealer()) return _DoNextPVECombatManeuverHeal(); switch (spec) { case DRUID_SPEC_FERAL: if (BEAR > 0 && m_bot->HasAura(BEAR)) return _DoNextPVECombatManeuverBear(pTarget); if (CAT_FORM > 0 && m_bot->HasAura(CAT_FORM)) return _DoNextPVECombatManeuverCat(pTarget); // NO break - failover to DRUID_SPEC_BALANCE case DRUID_SPEC_RESTORATION: // There is no Resto DAMAGE rotation. If you insist, go Balance... case DRUID_SPEC_BALANCE: if (m_bot->HasAura(BEAR) || m_bot->HasAura(CAT_FORM) || m_bot->HasAura(TREE_OF_LIFE)) return RETURN_NO_ACTION_UNKNOWN; // Didn't shift out of inappropriate form return _DoNextPVECombatManeuverSpellDPS(pTarget); /*if (BASH > 0 && !pTarget->HasAura(BASH, EFFECT_INDEX_0) && DruidSpellCombat < 5 && CastSpell(BASH, pTarget)) return RETURN_CONTINUE; if (CHALLENGING_ROAR > 0 && pVictim != m_bot && !pTarget->HasAura(CHALLENGING_ROAR, EFFECT_INDEX_0) && !pTarget->HasAura(GROWL, EFFECT_INDEX_0) && CastSpell(CHALLENGING_ROAR, pTarget)) return RETURN_CONTINUE; if (ROOTS > 0 && !pTarget->HasAura(ROOTS, EFFECT_INDEX_0) && CastSpell(ROOTS, pTarget)) return RETURN_CONTINUE; if (HURRICANE > 0 && ai->In_Reach(target,HURRICANE) && m_ai->GetAttackerCount() >= 5 && CastSpell(HURRICANE, pTarget)) { m_ai->SetIgnoreUpdateTime(10); return RETURN_CONTINUE; } if (STARFALL > 0 && ai->In_Reach(target,STARFALL) && !m_bot->HasAura(STARFALL, EFFECT_INDEX_0) && m_ai->GetAttackerCount() >= 3 && CastSpell(STARFALL, pTarget)) return RETURN_CONTINUE; if (BARKSKIN > 0 && pVictim == m_bot && m_ai->GetHealthPercent() < 75 && !m_bot->HasAura(BARKSKIN, EFFECT_INDEX_0) && CastSpell(BARKSKIN, m_bot)) return RETURN_CONTINUE; if (INNERVATE > 0 && ai->In_Reach(m_bot,INNERVATE) && !m_bot->HasAura(INNERVATE, EFFECT_INDEX_0) && CastSpell(INNERVATE, m_bot)) return RETURN_CONTINUE; */ } return RETURN_NO_ACTION_UNKNOWN; } // end DoNextCombatManeuver
CombatManeuverReturns PlayerbotDruidAI::DoNextCombatManeuverPVE(Unit* pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget); //uint32 masterHP = GetMaster()->GetHealth() * 100 / GetMaster()->GetMaxHealth(); uint32 spec = m_bot->GetSpec(); if (spec == 0) // default to spellcasting or healing for healer spec = (PlayerbotAI::ORDERS_HEAL & m_ai->GetCombatOrder() ? DRUID_SPEC_RESTORATION : DRUID_SPEC_BALANCE); // Make sure healer stays put, don't even melee (aggro) if in range: only melee if feral spec AND not healer if (!m_ai->IsHealer() && spec == DRUID_SPEC_FERAL && m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); else // ranged combat in all other cases m_ai->SetCombatStyle(PlayerbotAI::COMBAT_RANGED); //Unit* pVictim = pTarget->getVictim(); uint32 BEAR = (DIRE_BEAR_FORM > 0 ? DIRE_BEAR_FORM : BEAR_FORM); // TODO: do something to allow emergency heals for non-healers? switch (CheckForms()) { case RETURN_OK_SHIFTING: return RETURN_CONTINUE; case RETURN_FAIL: case RETURN_OK_CANNOTSHIFT: if (spec == DRUID_SPEC_FERAL) spec = DRUID_SPEC_BALANCE; // Can't shift, force spellcasting break; // rest functions without form //case RETURN_OK_NOCHANGE: // great! //case RETURN_FAIL_WAITINGONSELFBUFF: // This is war dammit! No time for silly buffs during combat... default: break; } // Low mana and bot is a caster/healer: cast Innervate on self // TODO add group check to also cast on low mana healers or master if (m_ai->GetManaPercent() < 15 && ((m_ai->IsHealer() || spec == DRUID_SPEC_RESTORATION))) if (INNERVATE > 0 && !m_bot->HasAura(INNERVATE, EFFECT_INDEX_0) && CastSpell(INNERVATE, m_bot)) return RETURN_CONTINUE; //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->GetCombatOrder() & PlayerbotAI::ORDERS_TANK) && !m_ai->IsNeutralized(newTarget)) // TODO: && party has a tank { if (HealPlayer(m_bot) == RETURN_CONTINUE) return RETURN_CONTINUE; // Aggroed by an elite that came in melee range if (m_ai->IsElite(newTarget) && meleeReach) { // protect the bot with barkskin: the increased casting time is meaningless // because bot will then avoid to cast to not angry mob further if (m_ai->IsHealer() || spec == DRUID_SPEC_RESTORATION || spec == DRUID_SPEC_BALANCE) { if (BARKSKIN > 0 && !m_bot->HasAura(BARKSKIN, EFFECT_INDEX_0) && CastSpell(BARKSKIN, m_bot)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; } //no other cases: cats have cower in the damage rotation and bears can tank } } if (m_ai->IsHealer()) if (_DoNextPVECombatManeuverHeal() & RETURN_CONTINUE) return RETURN_CONTINUE; switch (spec) { case DRUID_SPEC_FERAL: if (BEAR > 0 && m_bot->HasAura(BEAR)) return _DoNextPVECombatManeuverBear(pTarget); if (CAT_FORM > 0 && m_bot->HasAura(CAT_FORM)) return _DoNextPVECombatManeuverCat(pTarget); // NO break - failover to DRUID_SPEC_BALANCE case DRUID_SPEC_RESTORATION: // There is no Resto DAMAGE rotation. If you insist, go Balance... case DRUID_SPEC_BALANCE: if (m_bot->HasAura(BEAR) || m_bot->HasAura(CAT_FORM)) return RETURN_NO_ACTION_UNKNOWN; // Didn't shift out of inappropriate form return _DoNextPVECombatManeuverSpellDPS(pTarget); /*if (BASH > 0 && !pTarget->HasAura(BASH, EFFECT_INDEX_0) && DruidSpellCombat < 5 && CastSpell(BASH, pTarget)) return RETURN_CONTINUE; if (CHALLENGING_ROAR > 0 && pVictim != m_bot && !pTarget->HasAura(CHALLENGING_ROAR, EFFECT_INDEX_0) && !pTarget->HasAura(GROWL, EFFECT_INDEX_0) && CastSpell(CHALLENGING_ROAR, pTarget)) return RETURN_CONTINUE; if (ROOTS > 0 && !pTarget->HasAura(ROOTS, EFFECT_INDEX_0) && CastSpell(ROOTS, pTarget)) return RETURN_CONTINUE; */ } return RETURN_NO_ACTION_UNKNOWN; } // end DoNextCombatManeuver