Beispiel #1
0
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
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::DoFirstCombatManeuver(Unit* pTarget)
{
    bool meleeReach = m_bot->CanReachWithMeleeAttack(pTarget);
    // There are NPCs in BGs and Open World PvP, so don't filter this on PvP scenarios (of course if PvP targets anyone but tank, all bets are off anyway)
    // Wait until the tank says so, until any non-tank gains aggro or X seconds - whichever is shortest
    if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_TEMP_WAIT_TANKAGGRO)
    {
        if (m_WaitUntil > m_ai->CurrentTime() && m_ai->GroupTankHoldsAggro())
        {
            if (PlayerbotAI::ORDERS_TANK & m_ai->GetCombatOrder())
            {
                if (meleeReach)
                {
                    // Set everyone's UpdateAI() waiting to 2 seconds
                    m_ai->SetGroupIgnoreUpdateTime(2);
                    // Clear their TEMP_WAIT_TANKAGGRO flag
                    m_ai->ClearGroupCombatOrder(PlayerbotAI::ORDERS_TEMP_WAIT_TANKAGGRO);
                    // Start attacking, force target on current target
                    m_ai->Attack(m_ai->GetCurrentTarget());

                    // While everyone else is waiting 2 second, we need to build up aggro, so don't return
                }
                else
                {
                    // TODO: add check if target is ranged
                    return RETURN_NO_ACTION_OK; // wait for target to get nearer
                }
            }
            else if (PlayerbotAI::ORDERS_HEAL & m_ai->GetCombatOrder())
               return _DoNextPVECombatManeuverHeal();
            else
                return RETURN_NO_ACTION_OK; // wait it out
        }
        else
        {
            m_ai->ClearGroupCombatOrder(PlayerbotAI::ORDERS_TEMP_WAIT_TANKAGGRO);
        }
    }

    if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_TEMP_WAIT_OOC)
    {
        if (m_WaitUntil > m_ai->CurrentTime() && !m_ai->IsGroupInCombat())
            return RETURN_NO_ACTION_OK; // wait it out
        else
            m_ai->ClearGroupCombatOrder(PlayerbotAI::ORDERS_TEMP_WAIT_OOC);
    }

    switch (m_ai->GetScenarioType())
    {
        case PlayerbotAI::SCENARIO_PVP_DUEL:
        case PlayerbotAI::SCENARIO_PVP_BG:
        case PlayerbotAI::SCENARIO_PVP_ARENA:
        case PlayerbotAI::SCENARIO_PVP_OPENWORLD:
            return DoFirstCombatManeuverPVP(pTarget);

        case PlayerbotAI::SCENARIO_PVE:
        case PlayerbotAI::SCENARIO_PVE_ELITE:
        case PlayerbotAI::SCENARIO_PVE_RAID:
        default:
            return DoFirstCombatManeuverPVE(pTarget);
    }

    return RETURN_NO_ACTION_ERROR;
}
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