void AIUpdate() { if((GetHealthPercent() <= 85 && mSummon == 0) || ( GetHealthPercent() <= 70 && mSummon == 1 ) || ( GetHealthPercent() <= 55 && mSummon == 2 ) || ( GetHealthPercent() <= 40 && mSummon == 3 ) || ( GetHealthPercent() <= 25 && mSummon == 4 )) { CastSpell(mPureEnergy); ++mSummon; //SpawnCreature(CN_PURE_ENERGY, 231, -207, 6, 0, true); } if( GetHealthPercent() <= 10 && GetPhase() == 1 ) SetPhase(2); ParentClass::AIUpdate(); }
bool PlayerbotPaladinAI::ChangeAura(uint32 aura) { Player *m_bot = GetPlayerBot(); if(!aura) return false; if(!CanCast(aura,m_bot)) return false; if(m_bot->HasAura(aura)) { if (aura == DEVOTION_AURA) { if (ChangeAura(FIRE_AURA)) return true; if (ChangeAura(FROST_AURA)) return true; if (ChangeAura(SHADOW_AURA)) return true; return true; } else return ChangeAura(DEVOTION_AURA); } return CastSpell(aura,m_bot,false); }
CombatManeuverReturns PlayerbotDruidAI::_DoNextPVECombatManeuverHeal() { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; // (un)Shapeshifting is considered one step closer so will return true (and have the bot wait a bit for the GCD) if (TREE_OF_LIFE > 0 && !m_bot->HasAura(TREE_OF_LIFE, EFFECT_INDEX_0)) if (CastSpell(TREE_OF_LIFE, m_bot)) return RETURN_CONTINUE; if (m_bot->HasAura(CAT_FORM, EFFECT_INDEX_0)) { m_bot->RemoveAurasDueToSpell(CAT_FORM_1); //m_ai->TellMaster("FormClearCat"); return RETURN_CONTINUE; } if (m_bot->HasAura(BEAR_FORM, EFFECT_INDEX_0)) { m_bot->RemoveAurasDueToSpell(BEAR_FORM_1); //m_ai->TellMaster("FormClearBear"); return RETURN_CONTINUE; } if (m_bot->HasAura(DIRE_BEAR_FORM, EFFECT_INDEX_0)) { m_bot->RemoveAurasDueToSpell(DIRE_BEAR_FORM_1); //m_ai->TellMaster("FormClearDireBear"); return RETURN_CONTINUE; } // spellcasting form, but disables healing spells so it's got to go if (m_bot->HasAura(MOONKIN_FORM, EFFECT_INDEX_0)) { m_bot->RemoveAurasDueToSpell(MOONKIN_FORM_1); //m_ai->TellMaster("FormClearMoonkin"); return RETURN_CONTINUE; } if (HealPlayer(GetHealTarget()) & (RETURN_NO_ACTION_OK | RETURN_CONTINUE)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; }
bool PlayerbotShamanAI::HealTarget(Unit *target, uint8 hp) { if(!target || target->isDead()) return false; Player *m_bot = GetPlayerBot(); if(hp < 30 && m_bot->isInCombat() && CastSpell(NATURES_SWIFTNESS, m_bot)) {} // NO gcd if(hp < 60 && CanCast(HEAL,target,true) && m_bot->HasAura(NATURES_SWIFTNESS) && CastSpell(HEAL, target, false)) { return true; } if(hp < 30 && CastSpell(LESSER_HEAL,target,true,true)) { return true; } if(hp < 40 && m_bot->getRace() == (uint8) RACE_DRAENEI && CastSpell(R_GIFT_OF_NAARU,target)) {} // no GCD if(hp < 65 && CanCast(EARTH_SHIELD,target) && !m_bot->HasAura(EARTH_SHIELD,m_bot->GetGUID()) && CastSpell(EARTH_SHIELD,target,false)) { return true; } if(hp < 65 && CastSpell(HEAL,target,true,true)) { return true; } if(hp < 85 && CastSpell(LESSER_HEAL,target,true,true)) { return true; } return false; } //end HealTarget
bool PlayerbotClassAI::castDispel (uint32 dispelSpell, Unit *dTarget, bool checkFirst, bool castExistingAura, bool skipFriendlyCheck, bool skipEquipStanceCheck) { if (dispelSpell == 0 || !dTarget ) return false; //if (!canCast(dispelSpell, dTarget, true)) return false; //Needless cpu cycles wasted, usually a playerbot can cast a dispell const SpellEntry *dSpell = GetSpellStore()->LookupEntry(dispelSpell); if (!dSpell) return false; for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i) { if (dSpell->Effect[i] != (uint32)SPELL_EFFECT_DISPEL) continue; uint32 dispel_type = dSpell->EffectMiscValue[i]; uint32 dispelMask = GetDispellMask(DispelType(dispel_type)); Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if ((1<<aura->GetSpellProto()->Dispel) & dispelMask) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; // do not remove positive auras if friendly target // negative auras if non-friendly target if(positive == dTarget->IsFriendlyTo(GetPlayerBot())) continue; } // If there is a successfull match return, else continue searching. if (CastSpell(dSpell, dTarget, checkFirst, castExistingAura, skipFriendlyCheck, skipEquipStanceCheck)) { return true; } } } } return false; }
CombatManeuverReturns PlayerbotDruidAI::_DoNextPVECombatManeuverBear(Unit* pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; if (!m_bot->HasAura( (DIRE_BEAR_FORM > 0 ? DIRE_BEAR_FORM : BEAR_FORM) )) return RETURN_NO_ACTION_ERROR; // 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); Unit* pVictim = pTarget->getVictim(); // Face enemy, make sure you're attacking if (!m_bot->HasInArc(M_PI_F, pTarget)) { m_bot->SetFacingTo(m_bot->GetAngle(pTarget)); if (pVictim) pVictim->Attack(pTarget, true); } if (PlayerbotAI::ORDERS_TANK & m_ai->GetCombatOrder() && !newTarget && GROWL > 0 && !m_bot->HasSpellCooldown(GROWL)) if (CastSpell(GROWL, pTarget)) return RETURN_CONTINUE; if (FAERIE_FIRE_FERAL > 0 && m_ai->In_Reach(pTarget,FAERIE_FIRE_FERAL) && !pTarget->HasAura(FAERIE_FIRE_FERAL, EFFECT_INDEX_0)) if (CastSpell(FAERIE_FIRE_FERAL, pTarget)) return RETURN_CONTINUE; if (SWIPE > 0 && m_ai->In_Reach(pTarget,SWIPE) && m_ai->GetAttackerCount() >= 2 && CastSpell(SWIPE, pTarget)) return RETURN_CONTINUE; if (ENRAGE > 0 && !m_bot->HasSpellCooldown(ENRAGE) && CastSpell(ENRAGE, m_bot)) return RETURN_CONTINUE; if (DEMORALIZING_ROAR > 0 && !pTarget->HasAura(DEMORALIZING_ROAR, EFFECT_INDEX_0) && CastSpell(DEMORALIZING_ROAR, pTarget)) return RETURN_CONTINUE; if (MANGLE_BEAR > 0 && !pTarget->HasAura(MANGLE_BEAR) && CastSpell(MANGLE_BEAR, pTarget)) return RETURN_CONTINUE; if (LACERATE > 0 && !pTarget->HasAura(LACERATE, EFFECT_INDEX_0) && CastSpell(LACERATE, pTarget)) return RETURN_CONTINUE; if (MAUL > 0 && CastSpell(MAUL, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; }
void PlayerbotPaladinAI::DoNonCombatActions() { PlayerbotAI *ai = GetAI(); Player *m_bot = GetPlayerBot(); if (!m_bot || !ai || m_bot->isDead()) { return; } //If Casting or Eating/Drinking return if (m_bot->HasUnitState(UNIT_STATE_CASTING)) { return; } if (m_bot->getStandState() == UNIT_STAND_STATE_SIT) { return; } //buff and heal raid if (DoSupportRaid(m_bot)) { return; } //heal pets and bots Unit *target = DoSelectLowestHpFriendly(40, 1000); if (target && target->isAlive() && HealTarget(target, target->GetHealth()*100 / target->GetMaxHealth())) { return; } //mana/hp check //Don't bother with eating, if low on hp, just let it heal themself if (m_bot->getRace() == (uint8) RACE_UNDEAD_PLAYER && ai->GetHealthPercent() < 75 && CastSpell(R_CANNIBALIZE,m_bot)) { return; } if (m_bot->GetHealth() < m_bot->GetMaxHealth() && CastSpell(FLASH_OF_LIGHT,m_bot)) { return; } if (ai->GetManaPercent() < 70) { ai->Feast(); } } //end DoNonCombatActions
void Totem::InitStats(uint32 duration) { // client requires SMSG_TOTEM_CREATED to be sent before adding to world and before removing old totem if (m_owner->GetTypeId() == TYPEID_PLAYER && m_Properties->Slot >= SUMMON_SLOT_TOTEM && m_Properties->Slot < MAX_TOTEM_SLOT) { WorldPacket data(SMSG_TOTEM_CREATED, 1 + 8 + 4 + 4); data << uint8(m_Properties->Slot - 1); data << uint64(GetGUID()); data << uint32(duration); data << uint32(GetUInt32Value(UNIT_CREATED_BY_SPELL)); m_owner->ToPlayer()->SendDirectMessage(&data); // set display id depending on caster's race SetDisplayId(m_owner->GetModelForTotem(PlayerTotemType(m_Properties->Id))); } if (m_owner->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2019, EFFECT_0)) if (m_Properties->Slot == SUMMON_SLOT_TOTEM) CastSpell(this, 77747, true); Minion::InitStats(duration); // Get spell cast by totem if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(GetSpell())) if (totemSpell->CalcCastTime()) // If spell has cast time -> its an active totem m_type = TOTEM_ACTIVE; if (GetEntry() == SENTRY_TOTEM_ENTRY) SetReactState(REACT_AGGRESSIVE); m_duration = duration; SetLevel(m_owner->getLevel()); }
CombatManeuverReturns PlayerbotPriestAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (RESURRECTION && m_ai->In_Reach(target,RESURRECTION) && m_ai->CastSpell(RESURRECTION, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } return RETURN_NO_ACTION_ERROR; // not error per se - possibly just OOM } // Remove negative magic on group members if orders allow bot to do so if (Player* pCursedTarget = GetDispelTarget(DISPEL_MAGIC)) { if (PRIEST_DISPEL_MAGIC > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && CastSpell(PRIEST_DISPEL_MAGIC, pCursedTarget)) return RETURN_CONTINUE; } // Remove disease on group members if orders allow bot to do so if (Player* pDiseasedTarget = GetDispelTarget(DISPEL_DISEASE)) { uint32 cure = ABOLISH_DISEASE > 0 ? ABOLISH_DISEASE : CURE_DISEASE; // uint32 poison = ABOLISH_POISON ? ABOLISH_POISON : CURE_POISON; if (cure > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && CastSpell(cure, pDiseasedTarget)) return RETURN_CONTINUE; } uint8 hp = target->GetHealthPercent(); uint8 hpSelf = m_ai->GetHealthPercent(); // Define a tank bot will look at Unit* pMainTank = GetHealTarget(JOB_TANK); if (hp >= 90) return RETURN_NO_ACTION_OK; // If target is out of range (40 yards) and is a tank: move towards it // Other classes have to adjust their position to the healers // TODO: This code should be common to all healers and will probably // move to a more suitable place if (pMainTank && !m_ai->In_Reach(pMainTank, FLASH_HEAL)) { m_bot->GetMotionMaster()->MoveFollow(target, 39.0f, m_bot->GetOrientation()); return RETURN_CONTINUE; } // Get a free and more efficient heal if needed: low mana for bot or average health for target if (m_ai->IsInCombat() && (hp < 50 || m_ai->GetManaPercent() < 40)) if (INNER_FOCUS > 0 && m_bot->IsSpellReady(INNER_FOCUS) && !m_bot->HasAura(INNER_FOCUS, EFFECT_INDEX_0) && CastSpell(INNER_FOCUS, m_bot)) return RETURN_CONTINUE; if (hp < 25 && POWER_WORD_SHIELD > 0 && m_ai->In_Reach(target,POWER_WORD_SHIELD) && !m_bot->HasAura(POWER_WORD_SHIELD, EFFECT_INDEX_0) && !target->HasAura(WEAKNED_SOUL,EFFECT_INDEX_0) && m_ai->CastSpell(POWER_WORD_SHIELD, *target)) return RETURN_CONTINUE; if (hp < 35 && FLASH_HEAL > 0 && m_ai->In_Reach(target,FLASH_HEAL) && m_ai->CastSpell(FLASH_HEAL, *target)) return RETURN_CONTINUE; if (hp < 50 && GREATER_HEAL > 0 && m_ai->In_Reach(target,GREATER_HEAL) && m_ai->CastSpell(GREATER_HEAL, *target)) return RETURN_CONTINUE; // Heals target AND self for equal amount if (hp < 60 && hpSelf < 80 && BINDING_HEAL > 0 && m_ai->In_Reach(target,BINDING_HEAL) && m_ai->CastSpell(BINDING_HEAL, *target)) return RETURN_CONTINUE; if (hp < 60 && PRAYER_OF_MENDING > 0 && m_ai->In_Reach(target,PRAYER_OF_MENDING) && !target->HasAura(PRAYER_OF_MENDING, EFFECT_INDEX_0) && CastSpell(PRAYER_OF_MENDING, target)) return RETURN_FINISHED_FIRST_MOVES; if (hp < 70 && HEAL > 0 && m_ai->In_Reach(target,HEAL) && m_ai->CastSpell(HEAL, *target)) return RETURN_CONTINUE; if (hp < 90 && RENEW > 0 && m_ai->In_Reach(target,RENEW) && !target->HasAura(RENEW) && m_ai->CastSpell(RENEW, *target)) return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 40 && PRAYER_OF_HEALING > 0 && m_ai->CastSpell(PRAYER_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 50 && CIRCLE_OF_HEALING > 0 && m_ai->CastSpell(CIRCLE_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; } // end HealTarget
CombatManeuverReturns PlayerbotPriestAI::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 spec = m_bot->GetSpec(); // Define a tank bot will look at Unit* pMainTank = GetHealTarget(JOB_TANK); 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 AND is not healer else if(m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_MELEE && meleeReach && (SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true)) && !m_ai->IsHealer()) m_ai->SetCombatStyle(PlayerbotAI::COMBAT_MELEE); // Priests will try to buff with Fear Ward if (FEAR_WARD > 0 && m_bot->IsSpellReady(FEAR_WARD)) { // Buff tank first if (pMainTank) { if (m_ai->In_Reach(pMainTank, FEAR_WARD) && !pMainTank->HasAura(FEAR_WARD, EFFECT_INDEX_0) && CastSpell(FEAR_WARD, pMainTank)) return RETURN_CONTINUE; } // Else try to buff master else if (GetMaster()) { if (m_ai->In_Reach(GetMaster(), FEAR_WARD) && !GetMaster()->HasAura(FEAR_WARD, EFFECT_INDEX_0) && CastSpell(FEAR_WARD, GetMaster())) 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->IsNeutralized(newTarget)) // TODO: && party has a tank { if (FADE > 0 && !m_bot->HasAura(FADE, EFFECT_INDEX_0) && m_bot->IsSpellReady(FADE)) { if (CastSpell(FADE, m_bot)) { m_ai->TellMaster("I'm casting fade."); return RETURN_CONTINUE; } else m_ai->TellMaster("I have AGGRO."); } // Heal myself // TODO: move to HealTarget code if (m_ai->GetHealthPercent() < 35 && POWER_WORD_SHIELD > 0 && !m_bot->HasAura(POWER_WORD_SHIELD, EFFECT_INDEX_0) && !m_bot->HasAura(WEAKNED_SOUL, EFFECT_INDEX_0)) { if (CastSpell(POWER_WORD_SHIELD) & RETURN_CONTINUE) { m_ai->TellMaster("I'm casting PW:S on myself."); return RETURN_CONTINUE; } else if (m_ai->IsHealer()) // Even if any other RETURN_ANY_OK - aside from RETURN_CONTINUE m_ai->TellMaster("Your healer's about TO DIE. HELP ME."); } if (m_ai->GetHealthPercent() < 35 && DESPERATE_PRAYER > 0 && m_ai->In_Reach(m_bot,DESPERATE_PRAYER) && CastSpell(DESPERATE_PRAYER, m_bot) & RETURN_CONTINUE) { m_ai->TellMaster("I'm casting desperate prayer."); return RETURN_CONTINUE; } // Night Elves priest bot can also cast Elune's Grace to improve his/her dodge rating if (ELUNES_GRACE && !m_bot->HasAura(ELUNES_GRACE, EFFECT_INDEX_0) && m_bot->IsSpellReady(ELUNES_GRACE) && CastSpell(ELUNES_GRACE, m_bot)) return RETURN_CONTINUE; // If enemy comes in melee reach if (meleeReach) { // Already healed self or tank. If healer, do nothing else to anger mob if (m_ai->IsHealer()) return RETURN_NO_ACTION_OK; // In a sense, mission accomplished. // 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 if (m_ai->IsElite(newTarget)) return RETURN_NO_ACTION_OK; // Not an elite. You could insert PSYCHIC SCREAM 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 tweaking for healers if (m_ai->IsHealer()) { // Heal other players/bots first if (HealPlayer(GetHealTarget()) & RETURN_CONTINUE) return RETURN_CONTINUE; // No one needs to be healed: do small damage instead // If target is elite and not handled by MT: do nothing if (m_ai->IsElite(pTarget) && pMainTank && pMainTank->getVictim() != pTarget) return RETURN_NO_ACTION_OK; // Cast Shadow Word:Pain on current target and keep its up (if mana >= 40% or target HP < 15%) if (SHADOW_WORD_PAIN > 0 && m_ai->In_Reach(pTarget,SHADOW_WORD_PAIN) && !pTarget->HasAura(SHADOW_WORD_PAIN, EFFECT_INDEX_0) && (pTarget->GetHealthPercent() < 15 || m_ai->GetManaPercent() >= 40) && CastSpell(SHADOW_WORD_PAIN, pTarget)) return RETURN_CONTINUE; else // else shoot at it return CastSpell(SHOOT, pTarget); } // Damage Spells switch (spec) { case PRIEST_SPEC_HOLY: if (HOLY_FIRE > 0 && m_ai->In_Reach(pTarget,HOLY_FIRE) && !pTarget->HasAura(HOLY_FIRE, EFFECT_INDEX_0) && CastSpell(HOLY_FIRE, pTarget)) return RETURN_CONTINUE; if (SMITE > 0 && m_ai->In_Reach(pTarget,SMITE) && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; //if (HOLY_NOVA > 0 && m_ai->In_Reach(pTarget,HOLY_NOVA) && meleeReach && m_ai->CastSpell(HOLY_NOVA)) // return RETURN_CONTINUE; break; case PRIEST_SPEC_SHADOW: if (DEVOURING_PLAGUE > 0 && m_ai->In_Reach(pTarget,DEVOURING_PLAGUE) && !pTarget->HasAura(DEVOURING_PLAGUE, EFFECT_INDEX_0) && CastSpell(DEVOURING_PLAGUE, pTarget)) return RETURN_CONTINUE; if (VAMPIRIC_TOUCH > 0 && m_ai->In_Reach(pTarget,VAMPIRIC_TOUCH) && !pTarget->HasAura(VAMPIRIC_TOUCH, EFFECT_INDEX_0) && CastSpell(VAMPIRIC_TOUCH, pTarget)) return RETURN_CONTINUE; if (SHADOW_WORD_PAIN > 0 && m_ai->In_Reach(pTarget,SHADOW_WORD_PAIN) && !pTarget->HasAura(SHADOW_WORD_PAIN, EFFECT_INDEX_0) && CastSpell(SHADOW_WORD_PAIN, pTarget)) return RETURN_CONTINUE; if (MIND_BLAST > 0 && m_ai->In_Reach(pTarget,MIND_BLAST) && (m_bot->IsSpellReady(MIND_BLAST)) && CastSpell(MIND_BLAST, pTarget)) return RETURN_CONTINUE; if (MIND_FLAY > 0 && m_ai->In_Reach(pTarget,MIND_FLAY) && CastSpell(MIND_FLAY, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } if (SHADOWFIEND > 0 && m_ai->In_Reach(pTarget,SHADOWFIEND) && !m_bot->GetPet() && CastSpell(SHADOWFIEND)) return RETURN_CONTINUE; if (SHADOWFORM == 0 && MIND_FLAY == 0 && SMITE > 0 && m_ai->In_Reach(pTarget,SMITE) && CastSpell(SMITE, pTarget)) // low levels return RETURN_CONTINUE; break; case PRIEST_SPEC_DISCIPLINE: if (POWER_INFUSION > 0 && m_ai->In_Reach(GetMaster(),POWER_INFUSION) && CastSpell(POWER_INFUSION, GetMaster())) // TODO: just master? return RETURN_CONTINUE; if (INNER_FOCUS > 0 && m_ai->In_Reach(m_bot,INNER_FOCUS) && !m_bot->HasAura(INNER_FOCUS, EFFECT_INDEX_0) && CastSpell(INNER_FOCUS, m_bot)) return RETURN_CONTINUE; if (SMITE > 0 && m_ai->In_Reach(pTarget,SMITE) && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; break; } // No spec due to low level OR no spell found yet if (MIND_BLAST > 0 && m_ai->In_Reach(pTarget,MIND_BLAST) && (m_bot->IsSpellReady(MIND_BLAST)) && CastSpell(MIND_BLAST, pTarget)) return RETURN_CONTINUE; if (SHADOW_WORD_PAIN > 0 && m_ai->In_Reach(pTarget,SHADOW_WORD_PAIN) && !pTarget->HasAura(SHADOW_WORD_PAIN, EFFECT_INDEX_0) && CastSpell(SHADOW_WORD_PAIN, pTarget)) return RETURN_CONTINUE; if (MIND_FLAY > 0 && m_ai->In_Reach(pTarget,MIND_FLAY) && CastSpell(MIND_FLAY, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } if (SHADOWFORM == 0 && SMITE > 0 && m_ai->In_Reach(pTarget,SMITE) && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
CombatManeuverReturns PlayerbotPriestAI::DoFirstCombatManeuverPVE(Unit* /*pTarget*/) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; if (m_ai->IsHealer()) { // TODO: This must be done with toggles: FullHealth allowed Unit* healTarget = GetHealTarget(JOB_TANK); // This is cast on a target, which activates (and switches to another target within the group) upon receiving+healing damage // Mana efficient even at one use if (healTarget && PRAYER_OF_MENDING > 0 && m_ai->In_Reach(healTarget,PRAYER_OF_MENDING) && !healTarget->HasAura(PRAYER_OF_MENDING, EFFECT_INDEX_0) && CastSpell(PRAYER_OF_MENDING, healTarget) & RETURN_CONTINUE) return RETURN_FINISHED_FIRST_MOVES; // Cast renew on tank if (CastHoTOnTank()) return RETURN_FINISHED_FIRST_MOVES; } return RETURN_NO_ACTION_OK; }
bool Client::UseDiscipline(uint32 spell_id, uint32 target) { // Dont let client waste a reuse timer if they can't use the disc if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet()) { return(false); } //make sure we have the spell... int r; for(r = 0; r < MAX_PP_DISCIPLINES; r++) { if(m_pp.disciplines.values[r] == spell_id) break; } if(r == MAX_PP_DISCIPLINES) return(false); //not found. //Check the disc timer pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex; if(!p_timers.Expired(&database, DiscTimer)) { /*char val1[20]={0};*/ //unused /*char val2[20]={0};*/ //unused uint32 remain = p_timers.GetRemainingTime(DiscTimer); //Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2)); Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60)); return(false); } //make sure we can use it.. if(!IsValidSpell(spell_id)) { Message(13, "This tome contains invalid knowledge."); return(false); } //can we use the spell? const SPDat_Spell_Struct &spell = spells[spell_id]; uint8 level_to_use = spell.classes[GetClass() - 1]; if(level_to_use == 255) { Message(13, "Your class cannot learn from this tome."); //should summon them a new one... return(false); } if(level_to_use > GetLevel()) { Message_StringID(13, DISC_LEVEL_USE_ERROR); //should summon them a new one... return(false); } if(GetEndurance() > spell.EndurCost) { SetEndurance(GetEndurance() - spell.EndurCost); } else { Message(11, "You are too fatigued to use this skill right now."); return(false); } if(spell.recast_time > 0) { uint32 reduced_recast = spell.recast_time / 1000; reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id); if(reduced_recast < 0) reduced_recast = 0; CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); if(spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); DisciplineTimer_Struct *dts = (DisciplineTimer_Struct *)outapp->pBuffer; dts->TimerID = spells[spell_id].EndurTimerIndex; dts->Duration = reduced_recast; QueuePacket(outapp); safe_delete(outapp); } } else { CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); } return(true); }
CombatManeuverReturns PlayerbotMageAI::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); uint32 spec = m_bot->GetSpec(); 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); // Remove curse on group members if (Player* pCursedTarget = GetDispelTarget(DISPEL_CURSE)) { if (MAGE_REMOVE_CURSE > 0 && CastSpell(MAGE_REMOVE_CURSE, pCursedTarget)) return RETURN_CONTINUE; } if (newTarget && !m_ai->IsNeutralized(newTarget)) // Bot has aggro and the mob is not already crowd controled { if (newTarget->GetHealthPercent() > 25) { // If elite if (m_ai->IsElite(newTarget)) { // If the attacker is a beast or humanoid, let's the bot give it a form more suited to the low intellect of something fool enough to attack a mage Creature * pCreature = (Creature*) newTarget; if (pCreature && (pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_HUMANOID || pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_BEAST)) { if (POLYMORPH > 0 && CastSpell(POLYMORPH, newTarget)) return RETURN_CONTINUE; } // Things are getting dire: cast Ice block if (ICE_BLOCK > 0 && !m_bot->HasSpellCooldown(ICE_BLOCK) && m_ai->GetHealthPercent() < 30 && !m_bot->HasAura(ICE_BLOCK, EFFECT_INDEX_0) && m_ai->CastSpell(ICE_BLOCK)) return RETURN_CONTINUE; // Cast Ice Barrier if health starts to goes low if (ICE_BARRIER > 0 && !m_bot->HasSpellCooldown(ICE_BARRIER) && m_ai->GetHealthPercent() < 50 && !m_bot->HasAura(ICE_BARRIER) && m_ai->SelfBuff(ICE_BARRIER)) return RETURN_CONTINUE; // Have threat, can't quickly lower it. 3 options remain: Stop attacking, lowlevel damage (wand), keep on keeping on. return CastSpell(SHOOT, pTarget); } else // not elite { // Cast mana shield if no shield is already up if (MANA_SHIELD > 0 && m_ai->GetHealthPercent() < 70 && !m_bot->HasAura(MANA_SHIELD) && !m_bot->HasAura(ICE_BARRIER) && m_ai->SelfBuff(MANA_SHIELD)) return RETURN_CONTINUE; } } } // Mana check and replenishment if (EVOCATION && m_ai->GetManaPercent() <= 10 && !m_bot->HasSpellCooldown(EVOCATION) && !newTarget && m_ai->SelfBuff(EVOCATION)) return RETURN_CONTINUE; if (m_ai->GetManaPercent() <= 20) { Item* gem = FindManaGem(); if (gem) m_ai->UseItem(gem); } // If bot has frost/fire resist order use Frost/Fire Ward when available if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_RESIST_FROST && FROST_WARD && !m_bot->HasSpellCooldown(FROST_WARD) && m_ai->SelfBuff(FROST_WARD)) return RETURN_CONTINUE; if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_RESIST_FIRE && FIRE_WARD && !m_bot->HasSpellCooldown(FIRE_WARD) && m_ai->SelfBuff(FIRE_WARD)) return RETURN_CONTINUE; if (COUNTERSPELL > 0 && !m_bot->HasSpellCooldown(COUNTERSPELL) && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(COUNTERSPELL, pTarget)) return RETURN_CONTINUE; // If Clearcasting is active, cast arcane missiles // Bot could also cast flamestrike or blizzard for free, but the AoE could break some crowd control // or add threat on mobs ignoring the bot currently, so only focus on the bot's current target if (m_bot->HasAura(CLEARCASTING_1) && ARCANE_MISSILES > 0 && CastSpell(ARCANE_MISSILES, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } switch (spec) { case MAGE_SPEC_FROST: if (COLD_SNAP && !m_bot->HasSpellCooldown(COLD_SNAP) && CheckFrostCooldowns() > 2 && m_ai->SelfBuff(COLD_SNAP)) // Clear frost spell cooldowns if bot has more than 2 active return RETURN_CONTINUE; if (CONE_OF_COLD > 0 && !m_bot->HasSpellCooldown(CONE_OF_COLD) && meleeReach) { // Cone of Cold does not require a target, so ensure that the bot faces the current one before casting m_ai->FaceTarget(pTarget); if (m_ai->CastSpell(CONE_OF_COLD)) return RETURN_CONTINUE; } if (FROSTBOLT > 0 && m_ai->In_Reach(pTarget,FROSTBOLT) && !pTarget->HasAura(FROSTBOLT, EFFECT_INDEX_0) && CastSpell(FROSTBOLT, pTarget)) return RETURN_CONTINUE; if (FROST_NOVA > 0 && !m_bot->HasSpellCooldown(FROST_NOVA) && meleeReach && !pTarget->HasAura(FROST_NOVA, EFFECT_INDEX_0) && CastSpell(FROST_NOVA, pTarget)) return RETURN_CONTINUE; // Default frost spec action if (FROSTBOLT > 0 && m_ai->In_Reach(pTarget,FROSTBOLT)) return CastSpell(FROSTBOLT, pTarget); /* if (BLIZZARD > 0 && m_ai->In_Reach(pTarget,BLIZZARD) && m_ai->GetAttackerCount() >= 5 && CastSpell(BLIZZARD, pTarget)) { m_ai->SetIgnoreUpdateTime(8); return RETURN_CONTINUE; } */ break; case MAGE_SPEC_FIRE: if (COMBUSTION > 0 && m_ai->SelfBuff(COMBUSTION)) return RETURN_CONTINUE; if (BLAST_WAVE > 0 && m_ai->GetAttackerCount() >= 3 && meleeReach && CastSpell(BLAST_WAVE, pTarget)) return RETURN_CONTINUE; // Try to have 3 scorch stacks to let tank build aggro while getting a nice crit% bonus if (IMPROVED_SCORCH > 0 && SCORCH > 0) { if (!pTarget->HasAura(FIRE_VULNERABILITY, EFFECT_INDEX_0) && CastSpell(SCORCH, pTarget)) // no stacks: cast it return RETURN_CONTINUE; else { SpellAuraHolder* holder = pTarget->GetSpellAuraHolder(FIRE_VULNERABILITY); if (holder && (holder->GetStackAmount() < 3) && CastSpell(SCORCH, pTarget)) return RETURN_CONTINUE; } } // At least 3 stacks of Scorch: cast an opening fireball if (FIREBALL > 0 && !pTarget->HasAura(FIREBALL, EFFECT_INDEX_1) && CastSpell(FIREBALL, pTarget)) return RETURN_CONTINUE; // 3 stacks of Scorch and fireball DoT: use fire blast if available if (FIRE_BLAST > 0 && !m_bot->HasSpellCooldown(FIRE_BLAST) && CastSpell(FIRE_BLAST, pTarget)) return RETURN_CONTINUE; // All DoTs, cooldowns used, try to maximise scorch stacks (5) to get a even nicer crit% bonus if (IMPROVED_SCORCH > 0 && SCORCH > 0) { SpellAuraHolder* holder = pTarget->GetSpellAuraHolder(FIRE_VULNERABILITY); if (holder && (holder->GetStackAmount() < 5) && CastSpell(SCORCH, pTarget)) return RETURN_CONTINUE; } // Default fire spec action if (FIREBALL > 0 && m_ai->In_Reach(pTarget,FIREBALL)) return CastSpell(FIREBALL, pTarget); /* if (FLAMESTRIKE > 0 && m_ai->In_Reach(pTarget,FLAMESTRIKE) && CastSpell(FLAMESTRIKE, pTarget)) return RETURN_CONTINUE; */ break; case MAGE_SPEC_ARCANE: if (ARCANE_POWER > 0 && !m_bot->HasSpellCooldown(ARCANE_POWER) && m_ai->IsElite(pTarget) && m_ai->CastSpell(ARCANE_POWER)) // Do not waste Arcane Power on normal NPCs as the bot is likely in a group return RETURN_CONTINUE; if (PRESENCE_OF_MIND > 0 && !m_bot->HasAura(PRESENCE_OF_MIND) && !m_bot->HasSpellCooldown(PRESENCE_OF_MIND) && m_ai->IsElite(pTarget) && m_ai->SelfBuff(PRESENCE_OF_MIND)) return RETURN_CONTINUE; // If bot has presence of mind active, cast long casting time spells if (PRESENCE_OF_MIND && m_bot->HasAura(PRESENCE_OF_MIND)) { // Instant Pyroblast, yeah! Tanks will probably hate this, but what do they know about power? Nothing... if (PYROBLAST > 0 && CastSpell(PYROBLAST, pTarget)) return RETURN_CONTINUE; if (FIREBALL > 0 && CastSpell(FIREBALL, pTarget)) return RETURN_CONTINUE; } if (ARCANE_EXPLOSION > 0 && m_ai->GetAttackerCount() >= 3 && meleeReach && CastSpell(ARCANE_EXPLOSION, pTarget)) return RETURN_CONTINUE; // Default arcane spec actions (yes, two fire spells) if (FIRE_BLAST > 0 && !m_bot->HasSpellCooldown(FIRE_BLAST) && CastSpell(FIRE_BLAST, pTarget)) return RETURN_CONTINUE; if (FIREBALL > 0 && m_ai->In_Reach(pTarget,FIREBALL)) return CastSpell(FIREBALL, pTarget); // If no fireball, arcane missiles if (ARCANE_MISSILES > 0 && CastSpell(ARCANE_MISSILES, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } break; } // No spec due to low level OR no spell found yet if (FROSTBOLT > 0 && m_ai->In_Reach(pTarget,FROSTBOLT) && !pTarget->HasAura(FROSTBOLT, EFFECT_INDEX_0) && CastSpell(FROSTBOLT, pTarget)) return RETURN_CONTINUE; if (FIREBALL > 0 && m_ai->In_Reach(pTarget,FIREBALL) && CastSpell(FIREBALL, pTarget)) // Very low levels return RETURN_CONTINUE; // Default: shoot with wand return CastSpell(SHOOT, pTarget); return RETURN_NO_ACTION_ERROR; // What? Not even Fireball or wand are available? } // end DoNextCombatManeuver
void AIUpdate() { float OggCast = (float)RandomFloat(100.0f); CastSpell(OggCast); }
bool PlayerbotShamanAI::ChangeTotems(uint32 mode) { uint32 earth=0, fire=0, water=0, air=0; PlayerbotAI *ai = GetAI(); if(!ai) return false; Player *m_bot = GetPlayerBot(); if(!m_bot || m_bot->isDead()) return false; Unit *pTarget = m_bot->GetSelectedUnit(); Unit *pVictim = NULL; if (m_bot->GetSelectedUnit()->IsFriendlyTo(m_bot)) pTarget = NULL; if (pTarget) pVictim = pTarget->getVictim(); //Defaults if (!HasAuraName(m_bot,"Horn of Winter") )earth = STRENGTH_OF_EARTH_TOTEM; if (!earth) earth = STONESKIN_TOTEM; if (!earth) earth = EARTHBIND_TOTEM; fire = TOTEM_OF_WRATH; if (!fire) fire = FLAMETONGUE_TOTEM; if (!fire) fire = SEARING_TOTEM; water = MANA_SPRING_TOTEM; if (!water) water = HEALING_STREAM_TOTEM; if (TALENT_ELEMENTAL || TALENT_RESTO) air = WRATH_OF_AIR_TOTEM; else air = WINDFURY_TOTEM; //Target reactive stuff if (pTarget) { if (GROUNDING_TOTEM && pTarget->IsNonMeleeSpellCasted(true)) air = GROUNDING_TOTEM; } if (STONESKIN_TOTEM && isUnderAttack()) earth = STONESKIN_TOTEM; uint32 totz[4] = {earth, fire, water, air}; for (int i = 0; i < 4; i++) { if (!totz[i]) continue; SpellEntry const *tSpell = GetSpellStore()->LookupEntry(totz[i]); if (!tSpell) continue; uint32 tEntry = (uint32) tSpell->EffectMiscValue[0]; if (!tEntry) continue; CreatureTemplate const *totemEntry = sObjectMgr->GetCreatureTemplate(tEntry); if (!tEntry) continue; if (CanCast(totz[i], m_bot) && !m_bot->FindNearestCreature(tEntry,30)) { return CastSpell(totz[i],m_bot,false); } } return false; }
// Decision tree for putting a curse on the current target bool PlayerbotWarlockAI::CheckCurse(Unit* pTarget) { Creature * pCreature = (Creature*) pTarget; uint32 CurseToCast = 0; // Prevent low health humanoid from fleeing or fleeing too fast // Curse of Exhaustion first to avoid increasing damage output on tank if (pCreature && pCreature->GetCreatureInfo()->CreatureType == CREATURE_TYPE_HUMANOID && pTarget->GetHealthPercent() < 20 && !pCreature->IsWorldBoss()) { if (CURSE_OF_EXHAUSTION && m_ai->In_Reach(pTarget,CURSE_OF_EXHAUSTION) && !pTarget->HasAura(CURSE_OF_EXHAUSTION)) { if (AMPLIFY_CURSE && m_bot->IsSpellReady(AMPLIFY_CURSE)) CastSpell(AMPLIFY_CURSE, m_bot); if (CastSpell(CURSE_OF_EXHAUSTION, pTarget)) { m_CurrentCurse = CURSE_OF_EXHAUSTION; return true; } } else if (CURSE_OF_RECKLESSNESS && m_ai->In_Reach(pTarget,CURSE_OF_RECKLESSNESS) && !pTarget->HasAura(CURSE_OF_RECKLESSNESS) && !pTarget->HasAura(CURSE_OF_EXHAUSTION) && CastSpell(CURSE_OF_RECKLESSNESS, pTarget)) { m_CurrentCurse = CURSE_OF_RECKLESSNESS; return true; } } // If bot already put a curse and curse is still active on target: no need to go further if (m_CurrentCurse > 0 && pTarget->HasAura(m_CurrentCurse)) return false; // No curse or effect worn off: choose again which curse to use // Target is a boss if (pCreature && pCreature->IsWorldBoss()) { if (m_bot->GetGroup()) { uint8 mages = 0; uint8 warlocks = 1; Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember || !groupMember->isAlive()) continue; switch (groupMember->getClass()) { case CLASS_WARLOCK: warlocks++; continue; case CLASS_MAGE: mages++; continue; } } if (warlocks > 1 && warlocks > mages) CurseToCast = CURSE_OF_SHADOW; else if (mages > warlocks) CurseToCast = CURSE_OF_THE_ELEMENTS; else CurseToCast = CURSE_OF_AGONY; } // If target is not elite, no need to put a curse useful // in the long run: go for direct damage } else if (!m_ai->IsElite(pTarget)) CurseToCast = CURSE_OF_AGONY; // Enemy elite mages have low health but can cast dangerous spells: group safety before bot DPS else if (pCreature && pCreature->GetCreatureInfo()->UnitClass == 8) CurseToCast = CURSE_OF_TONGUES; // Default case: Curse of Agony else CurseToCast = CURSE_OF_AGONY; // Try to curse the target with the selected curse if (CurseToCast && m_ai->In_Reach(pTarget,CurseToCast) && !pTarget->HasAura(CurseToCast)) { if (CurseToCast == CURSE_OF_AGONY) if (AMPLIFY_CURSE && m_bot->IsSpellReady(AMPLIFY_CURSE)) CastSpell(AMPLIFY_CURSE, m_bot); if (CastSpell(CurseToCast, pTarget)) { m_CurrentCurse = CurseToCast; return true; } } // else: go for Curse of Agony else if (CURSE_OF_AGONY && m_ai->In_Reach(pTarget,CURSE_OF_AGONY) && !pTarget->HasAura(CURSE_OF_AGONY)) { if (AMPLIFY_CURSE && m_bot->IsSpellReady(AMPLIFY_CURSE)) CastSpell(AMPLIFY_CURSE, m_bot); if (CastSpell(CURSE_OF_AGONY, pTarget)) { m_CurrentCurse = CURSE_OF_AGONY; return true; } } // else: go for Curse of Weakness else if (CURSE_OF_WEAKNESS && !pTarget->HasAura(CURSE_OF_WEAKNESS) && !pTarget->HasAura(CURSE_OF_AGONY)) { if (AMPLIFY_CURSE && m_bot->IsSpellReady(AMPLIFY_CURSE)) CastSpell(AMPLIFY_CURSE, m_bot); if (CastSpell(CURSE_OF_WEAKNESS, pTarget)) { m_CurrentCurse = CURSE_OF_WEAKNESS; return true; } } return false; }
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 GameObject::Update(uint32 diff) { if (IS_MO_TRANSPORT(GetGUID())) { //((Transport*)this)->Update(p_time); return; } switch (m_lootState) { case GO_NOT_READY: { switch(GetGoType()) { case GAMEOBJECT_TYPE_TRAP: { // Arming Time for GAMEOBJECT_TYPE_TRAP (6) Unit* owner = GetOwner(); if (owner && ((Player*)owner)->isInCombat()) m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay; m_lootState = GO_READY; break; } case GAMEOBJECT_TYPE_FISHINGNODE: { // fishing code (bobber ready) if( time(NULL) > m_respawnTime - FISHING_BOBBER_READY_TIME ) { // splash bobber (bobber ready now) Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { SetGoState(0); SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); UpdateData udata; WorldPacket packet; BuildValuesUpdateBlockForPlayer(&udata,((Player*)caster)); udata.BuildPacket(&packet); ((Player*)caster)->GetSession()->SendPacket(&packet); WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); data << GetGUID(); data << (uint32)(0); ((Player*)caster)->SendMessageToSet(&data,true); } m_lootState = GO_READY; // can be successfully open with some chance } return; } default: m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY break; } // NO BREAK for switch (m_lootState) } case GO_READY: { if (m_respawnTime > 0) // timer on { if (m_respawnTime <= time(NULL)) // timer expired { m_respawnTime = 0; m_SkillupList.clear(); m_usetimes = 0; switch (GetGoType()) { case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now { Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]) { caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0); caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish(false); } WorldPacket data(SMSG_FISH_NOT_HOOKED,0); ((Player*)caster)->GetSession()->SendPacket(&data); } // can be delete m_lootState = GO_JUST_DEACTIVATED; return; } case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds) if( !GetGoState() ) SwitchDoorOrButton(false); //flags in AB are type_button and we need to add them here so no break! default: if(!m_spawnedByDefault) // despawn timer { // can be despawned or destroyed SetLootState(GO_JUST_DEACTIVATED); return; } // respawn timer MapManager::Instance().GetMap(GetMapId(), this)->Add(this); break; } } } // traps can have time and can not have GameObjectInfo const* goInfo = GetGOInfo(); if(goInfo->type == GAMEOBJECT_TYPE_TRAP) { // traps Unit* owner = GetOwner(); Unit* ok = NULL; // pointer to appropriate target if found any if(m_cooldownTime >= time(NULL)) return; bool IsBattleGroundTrap = false; //FIXME: this is activation radius (in different casting radius that must be selected from spell data) //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state float radius = goInfo->trap.radius; if(!radius) { if(goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call) { // try to read radius from trap spell if(const SpellEntry *spellEntry = sSpellStore.LookupEntry(goInfo->trap.spellId)) radius = GetSpellRadius(spellEntry,0,false); // radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[0])); if(!radius) break; } else { if(m_respawnTime > 0) break; radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 IsBattleGroundTrap = true; } } bool NeedDespawn = (goInfo->trap.charges != 0); CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; // Note: this hack with search required until GO casting not implemented // search unfriendly creature if(owner && NeedDespawn) // hunter trap { Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck u_check(this, owner, radius); Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> checker(ok, u_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker); cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); // or unfriendly player/pet if(!ok) { TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); } } else // environmental trap { // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support // affect only players Player* p_ok = NULL; Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius); Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); ok = p_ok; } if (ok) { //Unit *caster = owner ? owner : ok; //caster->CastSpell(ok, goInfo->trap.spellId, true); CastSpell(ok, goInfo->trap.spellId); m_cooldownTime = time(NULL) + 4; // 4 seconds if(NeedDespawn) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) { //BattleGround gameobjects case if(((Player*)ok)->InBattleGround()) if(BattleGround *bg = ((Player*)ok)->GetBattleGround()) bg->HandleTriggerBuff(GetGUID()); } } } if (m_charges && m_usetimes >= m_charges) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed break; } case GO_ACTIVATED: { switch(GetGoType()) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: if(GetAutoCloseTime() && (m_cooldownTime < time(NULL))) { SwitchDoorOrButton(false); SetLootState(GO_JUST_DEACTIVATED); } break; case GAMEOBJECT_TYPE_CHEST: if(m_groupLootTimer && lootingGroupLeaderGUID) { if(diff <= m_groupLootTimer) { m_groupLootTimer -= diff; } else { Group* group = objmgr.GetGroupByLeader(lootingGroupLeaderGUID); if (group) group->EndRoll(); m_groupLootTimer = 0; lootingGroupLeaderGUID = 0; } } break; } break; } case GO_JUST_DEACTIVATED: { //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed if (GetGoType() == GAMEOBJECT_TYPE_GOOBER) { uint32 spellId = GetGOInfo()->goober.spellId; if(spellId) { std::set<uint32>::iterator it = m_unique_users.begin(); std::set<uint32>::iterator end = m_unique_users.end(); for (; it != end; it++) { Unit* owner = Unit::GetUnit(*this, uint64(*it)); if (owner) owner->CastSpell(owner, spellId, false); } m_unique_users.clear(); m_usetimes = 0; } //any return here in case battleground traps } if(GetOwnerGUID()) { m_respawnTime = 0; Delete(); return; } //burning flags in some battlegrounds, if you find better condition, just add it if (GetGoAnimProgress() > 0) { SendObjectDeSpawnAnim(this->GetGUID()); //reset flags SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); } loot.clear(); SetLootState(GO_READY); if(!m_respawnDelayTime) return; if(!m_spawnedByDefault) { m_respawnTime = 0; return; } m_respawnTime = time(NULL) + m_respawnDelayTime; // if option not set then object will be saved at grid unload if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) SaveRespawnTime(); ObjectAccessor::UpdateObjectVisibility(this); break; } } }
void PlayerbotMageAI::DoNonCombatActions() { Player* master = GetMaster(); if (!m_bot || !master) return; // Remove curse on group members if orders allow bot to do so if (Player* pCursedTarget = GetDispelTarget(DISPEL_CURSE)) { if (MAGE_REMOVE_CURSE > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && CastSpell(MAGE_REMOVE_CURSE, pCursedTarget)) return; } // Buff armor if (MAGE_ARMOR) { if (m_ai->SelfBuff(MAGE_ARMOR)) return; } else if (ICE_ARMOR) { if (m_ai->SelfBuff(ICE_ARMOR)) return; } else if (FROST_ARMOR) { if (m_ai->SelfBuff(FROST_ARMOR)) return; } if (COMBUSTION && !m_bot->HasSpellCooldown(COMBUSTION) && m_ai->SelfBuff(COMBUSTION)) return; // buff group // the check for group targets is performed by NeedGroupBuff (if group is found for bots by the function) if (NeedGroupBuff(ARCANE_BRILLIANCE, ARCANE_INTELLECT) && m_ai->HasSpellReagents(ARCANE_BRILLIANCE)) { if (Buff(&PlayerbotMageAI::BuffHelper, ARCANE_BRILLIANCE) & RETURN_CONTINUE) return; } else if (Buff(&PlayerbotMageAI::BuffHelper, ARCANE_INTELLECT, JOB_MANAONLY) & RETURN_CONTINUE) return; Item* gem = FindManaGem(); if (!gem && CONJURE_MANA_GEM && m_ai->CastSpell(CONJURE_MANA_GEM, *m_bot)) { m_ai->SetIgnoreUpdateTime(3); return; } // TODO: The beauty of a mage is not only its ability to supply itself with water, but to share its water // So, conjure at *least* 1.25 stacks, ready to trade a stack and still have some left for self if (m_ai->FindDrink() == nullptr && CONJURE_WATER && m_ai->CastSpell(CONJURE_WATER, *m_bot)) { m_ai->TellMaster("I'm conjuring some water."); m_ai->SetIgnoreUpdateTime(3); return; } if (m_ai->FindFood() == nullptr && CONJURE_FOOD && m_ai->CastSpell(CONJURE_FOOD, *m_bot)) { m_ai->TellMaster("I'm conjuring some food."); m_ai->SetIgnoreUpdateTime(3); return; } if (EatDrinkBandage()) return; } // end DoNonCombatActions
void PlayerbotShamanAI::DoNextCombatManeuver(Unit *pTarget) { if (!pTarget || pTarget->isDead()) return; PlayerbotAI *ai = GetAI(); if (!ai) return; Player *m_bot = GetPlayerBot(); if (!m_bot || m_bot->isDead()) return; Unit *pVictim = pTarget->getVictim(); Unit *m_tank = FindMainTankInRaid(GetMaster()); if (!m_tank && m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup()) { FindMainTankInRaid(m_bot); } if (!m_tank) { m_tank = m_bot; } uint32 masterHP = GetMaster()->GetHealth()*100 / GetMaster()->GetMaxHealth(); float pDist = m_bot->GetDistance(pTarget); uint8 pThreat = GetThreatPercent(pTarget); uint8 reqHeal = 0; uint8 OwnPartyHP = GetHealthPercentRaid(m_bot, reqHeal); switch(ai->GetScenarioType()) { case SCENARIO_DUEL: ((ai->GetHealthPercent() < 80 && CastSpell(LESSER_HEAL)) || CastSpell(LIGHTNING_BOLT, pTarget)); return; } // Cast CC breakers if any match found (include any dispels first) does not work yet //uint32 ccSpells[4] = { R_ESCAPE_ARTIST, R_EVERY_MAN_FOR_HIMSELF, R_WILL_OF_FORSAKEN, R_STONEFORM }; //if (ai->GetManaPercent() < 35) { ccSpells[0] = 0; ccSpells[1] = 0; } //We dont have any mana to waste... //if (castSelfCCBreakers(ccSpells)) { } // Most of them don't trigger gcd #pragma region Choose Actions // Choose actions accoring to talents if (m_tank->GetGUID() == m_bot->GetGUID()) { m_role=BOT_ROLE_TANK; } // Hey! I am Main Tank else if (TALENT_ENHANCEMENT) { m_role = BOT_ROLE_DPS_MELEE; } else if (TALENT_ELEMENTAL) { m_role = BOT_ROLE_DPS_RANGED; } else if (TALENT_RESTO) { m_role = BOT_ROLE_SUPPORT; } else { m_role = BOT_ROLE_DPS_MELEE; } //Unknown build or low level.. Mainly attack // if i am under attack and if i am not tank or offtank: change target if needed if (m_tank->GetGUID() != m_bot->GetGUID() && isUnderAttack() ) { if (pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist <= 2) { } // My target is almost up to me, no need to search else //Have to select nearest target { Unit *curAtt = GetNearestAttackerOf(m_bot); if (curAtt && curAtt->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(curAtt->GetGUID()); //ai->AddLootGUID(curAtt->GetGUID()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } #pragma endregion // Choose Weapon Enchant if (ChangeWeaponEnchants()) return; if (TALENT_ELEMENTAL){ if (!m_bot->HasAura(WATER_SHIELD) && CastSpell(WATER_SHIELD,m_bot)) { return; }} if (TALENT_ENHANCEMENT){ if (!m_bot->HasAura(LIGHTNING_SHIELD) && CastSpell(LIGHTNING_SHIELD,m_bot)) { return; }} if (TALENT_RESTO){ if (!m_bot->HasAura(WATER_SHIELD) && CastSpell(WATER_SHIELD,m_bot)) { return; }} // Choose shield /* if (EARTH_SHIELD && ai->GetHealthPercent() < 80 && isUnderAttack()) { if (CastSpell(EARTH_SHIELD,m_bot)) { return; } } else if (WATER_SHIELD && ai->GetManaPercent() < 40) { if (CastSpell(WATER_SHIELD,m_bot)) { return; } } else if (LIGHTNING_SHIELD && ( isUnderAttack() || m_tank->GetGUID() == m_bot->GetGUID() ) && !(m_bot->HasAura(WATER_SHIELD) && ai->GetManaPercent() < 80) ) { if (CastSpell(LIGHTNING_SHIELD,m_bot)) { return; } } else if (CastSpell(WATER_SHIELD,m_bot)) { return; } */ // If there's a cast stop if(m_bot->HasUnitState(UNIT_STAT_CASTING)) return; switch(m_role) { #pragma region BOT_ROLE_TANK / BOT_ROLE_OFFTANK case BOT_ROLE_TANK: case BOT_ROLE_OFFTANK: if (!TALENT_ELEMENTAL && !TALENT_RESTO) { TakePosition(pTarget); } else { TakePosition(pTarget,BOT_ROLE_DPS_RANGED); } // mob will come to you sooner or later no need to hurry // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 70 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_DPS_MELEE case BOT_ROLE_DPS_MELEE: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 40 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_DPS_RANGED case BOT_ROLE_DPS_RANGED: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (ai->GetManaPercent() > 40 && DoSupportRaid(m_bot)) { return; } break; #pragma endregion #pragma region BOT_ROLE_SUPPORT case BOT_ROLE_SUPPORT: TakePosition(pTarget); // Do support stuff if (!m_bot->isMoving() && ChangeTotems(m_role)) { return; } if (DoSupportRaid(m_bot)) { return; } //heal pets and bots Unit *target = DoSelectLowestHpFriendly(40, 1000); if(target && target->isAlive() && HealTarget(target, target->GetHealth()*100 / target->GetMaxHealth()) ) { return; } break; #pragma endregion } #pragma region ShamanCommon //Defensive Stuff if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { if (pDist > 5 && CastSpell(FROST_SHOCK, pTarget)) { return; } if ((pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_BEAST || pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_HUMANOID) && CastSpell(HEX, pTarget)) { return; } // no gcd if (CastSpell(WIND_SHEAR, pTarget)) { } // no gcd } if (m_bot->getRace() == (uint8) RACE_BLOODELF && pDist < 8 && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(R_ARCANE_TORRENT, pTarget)) { } //no gcd if (pTarget->IsNonMeleeSpellCasted(true) && CastSpell(WIND_SHEAR, pTarget)) { } //no gcd if (m_bot->getRace() == (uint8) RACE_TAUREN && pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //Catch if (pTarget->HasUnitMovementFlag(UNIT_FLAG_FLEEING)) { if (CastSpell(FROST_SHOCK,pTarget)) return; } //Buff and restores if ( ( (ai->GetHealthPercent() < 60 && isUnderAttack()) || (ai->GetManaPercent() < 30) ) && CastSpell(SHAMANISTIC_RAGE, m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_TROLL && CastSpell(R_BERSERKING,m_bot)) {} // no GCD if (m_bot->getRace() == (uint8) RACE_ORC && CastSpell(R_BLOOD_FURY,m_bot)) {} // no GCD if (!m_bot->HasAura(HEROISM) && !m_bot->HasAura(EXHAUSTION) && !m_bot->HasAura(SATED) && CastSpell(HEROISM,m_bot)) { return; } if (m_role != BOT_ROLE_SUPPORT && CastSpell(NATURES_SWIFTNESS, m_bot)) { } //healers keep it for healing no gcd else if (CastSpell(ELEMENTAL_MASTERY, m_bot)) { } //no gcd // If at threat limit, use WIND_SHEAR to reduce threat if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack()) { if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) // I am attacking wrong target!! { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); return; } else { if (CastSpell(WIND_SHEAR,pTarget)) { return; } //Lets see if we can manage else { return; } //use no spells and wait threat to be reduced } } if (TALENT_ELEMENTAL) { if (CastSpell(ELEMENTAL_MASTERY, m_bot)) { } //no gcd if (!pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) && CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(LAVA_BURST,pTarget)) { return; } if (CastSpell(CHAIN_LIGHTNING,pTarget)) { return; } if (CastSpell(LIGHTNING_BOLT,pTarget)) { return; } } //dps if (MAELSTROM_WEAPON) { Aura *maelaura = m_bot->GetAura(MAELSTROM_WEAPON); if (maelaura && maelaura->GetStackAmount() == 5) { if ((isUnderAttack(m_tank,3) || m_tank->GetGUID() == m_bot->GetGUID()) && CastSpell(CHAIN_LIGHTNING,pTarget,true,true)) { return; } if (CastSpell(LIGHTNING_BOLT,pTarget,true,true)) { return; } } } if (CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(STORMSTRIKE,pTarget,true,true)) { return; } //if (!TALENT_ENHANCEMENT && CanCast(LAVA_BURST,pTarget,true) && pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) && CastSpell(LAVA_BURST,pTarget,false)) { return; } if (CastSpell(FERAL_SPIRIT,m_bot)) { return; } if (CanCast(EARTH_SHOCK,pTarget,true) && (pTarget->HasAura(STORMSTRIKE,m_bot->GetGUID()) || pTarget->HasAura(FLAME_SHOCK,m_bot->GetGUID()) ) && CastSpell(EARTH_SHOCK,pTarget)) { return; } //if (CanCast(FLAME_SHOCK,pTarget) && CastSpell(FLAME_SHOCK,pTarget)) { return; } if (CastSpell(LAVA_LASH,pTarget,true,true)) { return; } if (CastSpell(FIRE_NOVA,pTarget)) { return; } //if ((isUnderAttack(m_tank,4) || m_tank->GetGUID() == m_bot->GetGUID()) && CastSpell(FIRE_NOVA,pTarget)) { return; } if (ai->GetManaPercent() > 60 && castDispel(PURGE,pTarget)) { return; } //PURGE but dont overpurge #pragma endregion // drink potion if support / healer (Other builds simply overuse mana and waste mana pots) if(ai->GetManaPercent() < 5 && (m_role == BOT_ROLE_SUPPORT || m_role == BOT_ROLE_HEALER) ) { Item *pItem = ai->FindPotion(); if(pItem != NULL) { if (pItem->GetSpell() && m_bot->HasSpellCooldown(pItem->GetSpell()) ) { return; } //pot is in cooldown ai->UseItem(*pItem); } } } //end DoNextCombatManeuver
void PlayerbotDruidAI::DoNextCombatManeuver(Unit *pTarget) { if (!pTarget || pTarget->isDead()) return; PlayerbotAI *ai = GetAI(); if (!ai) return; Player *m_bot = GetPlayerBot(); if (!m_bot || m_bot->isDead()) return; Unit *pVictim = pTarget->getVictim(); Unit *m_tank = FindMainTankInRaid(GetMaster()); if (!m_tank && m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup()) { FindMainTankInRaid(m_bot); } if (!m_tank) { m_tank = m_bot; } uint32 masterHP = GetMaster()->GetHealth()*100 / GetMaster()->GetMaxHealth(); float pDist = m_bot->GetDistance(pTarget); uint8 pThreat = GetThreatPercent(pTarget); uint8 reqHeal = 0; uint8 OwnPartyHP = GetHealthPercentRaid(m_bot, reqHeal); #pragma region Select behaviour if (m_tank->GetGUID() == m_bot->GetGUID()) // Hey! I am Main Tank { if (TALENT_FERAL && BEAR_FORM) { m_role = BOT_ROLE_TANK; } //Just Keep Tanking dont even change forms for healing else { if (TALENT_BALANCE) { if ((ai->GetHealthPercent() <= 40 || masterHP <30 ) && (ai->GetManaPercent() >= 40)) { m_role = BOT_ROLE_SUPPORT; } else if (OwnPartyHP < 20 && ai->GetManaPercent() >= 30) { m_role = BOT_ROLE_SUPPORT; } else if (ai->GetManaPercent() < 25 ) { m_role = BOT_ROLE_TANK; } else { m_role = BOT_ROLE_DPS_RANGED; } } else //I am both healer and tank?? Hmm { if ((ai->GetHealthPercent() <= 70 || masterHP <70 ) && (ai->GetManaPercent() >= 50)) { m_role = BOT_ROLE_SUPPORT; } else if (OwnPartyHP < 20 && ai->GetManaPercent() >= 30) { m_role = BOT_ROLE_SUPPORT; } else if (ai->GetManaPercent() < 15 ) { m_role = BOT_ROLE_TANK; } else { m_role = BOT_ROLE_DPS_RANGED; } } } } else if (isUnderAttack() && !( ai->GetForm() == FORM_MOONKIN || ai->GetForm() == FORM_TREE) ) // if i am under attack { // Keep being in Cat Form if you can reduce threat if (ai->GetForm() == FORM_CAT && CastSpell(COWER,pTarget)) {return; } else if (TALENT_RESTO && ai->GetManaPercent() > 10 ) { m_role = BOT_ROLE_SUPPORT; } else { m_role = BOT_ROLE_OFFTANK; } } else if (TALENT_FERAL && CAT_FORM) { // If has any feral forms at all if ((ai->GetHealthPercent() <= 40 || masterHP <40 ) && (ai->GetManaPercent() >= 40)) { m_role = BOT_ROLE_SUPPORT; } else if (OwnPartyHP < 30 && ai->GetManaPercent() >= 30) { m_role = BOT_ROLE_SUPPORT; } else{ m_role = BOT_ROLE_DPS_MELEE; } } else if (TALENT_BALANCE) { if ((ai->GetHealthPercent() <= 50 || masterHP <40 ) && (ai->GetManaPercent() >= 10)) { m_role = BOT_ROLE_SUPPORT; } else if (OwnPartyHP < 40 && ai->GetManaPercent() >= 30) { m_role = BOT_ROLE_SUPPORT; } else { m_role = BOT_ROLE_DPS_RANGED; } } else if (TALENT_RESTO) { m_role = BOT_ROLE_SUPPORT; } else { // Unknown build or low level : Do not change forms rapidly.. if ( (ai->GetManaPercent() < 30 && BEAR_FORM) || ( (ai->GetForm() == FORM_CAT || ai->GetForm() == FORM_DIREBEAR || ai->GetForm() == FORM_BEAR) && ai->GetManaPercent() < 70 ) ) m_role = BOT_ROLE_DPS_MELEE; else { m_role = BOT_ROLE_DPS_RANGED; } } if (!isUnderAttack() && m_tank->GetGUID() != m_bot->GetGUID()) { // Select Attacking target if (pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist <= 2) {} //if my target is attacking me continue else { Unit *curAtt = GetNearestAttackerOf(m_bot); if (curAtt && curAtt->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(curAtt->GetGUID()); //ai->AddLootGUID(curAtt->GetGUID()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } #pragma endregion // If there's a cast stop if (m_bot->HasUnitState(UNIT_STAT_CASTING)) return; // Return to normal form from non combat forms if (ai->GetForm() == FORM_NONE || ai->GetForm() == FORM_CAT || ai->GetForm() == FORM_TREE || ai->GetForm() == FORM_MOONKIN || ai->GetForm() == FORM_DIREBEAR || ai->GetForm() == FORM_BEAR ) { } //Those are valid incombat auras else if (ai->GetForm() != FORM_NONE && ChangeForm(1)) { } //return to caster form switch(m_role) { #pragma region BOT_ROLE_DPS_MELEE case BOT_ROLE_DPS_MELEE: //ai->TellMaster("DruidCombat"); // Do caster form stuff if (ai->GetForm() == FORM_NONE) { //We have little mana probably cant change form if (ai->GetManaPercent() < 20 && CastSpell (INNERVATE, m_bot) ) { return; } else if(m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return;} else if(DoSupportRaid(GetMaster(),false,false,false)) return; else if(m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup() && DoSupportRaid(m_bot,false,false,false)) { return; } } if (CAT_FORM) { if (ChangeForm(CAT_FORM)) { return; } } else if (BEAR_FORM) { if (ChangeForm(BEAR_FORM)) { return; } } else if (ai->GetForm() != FORM_NONE && ChangeForm(1)) { } //Normal Form TakePosition(pTarget); break; #pragma endregion #pragma region BOT_ROLE_TANK / BOT_ROLE_OFFTANK case BOT_ROLE_OFFTANK: case BOT_ROLE_TANK: // It is a tank druid or a defending druid // Do what you must before getting attacked... if (ai->GetForm() == FORM_NONE) { // Non tank stuff to avoid if (m_tank->GetGUID() != m_bot->GetGUID()) { if (ROOTS && !pTarget->HasAura(CYCLONE) && !pTarget->HasAura(HIBERNATE) && CastSpell(ROOTS, pTarget)) { return; } if (CYCLONE && pDist > 5 && !pTarget->HasAura(ROOTS) && !pTarget->HasAura(HIBERNATE) && CastSpell(CYCLONE, pTarget)) { return; } if (HIBERNATE && pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_BEAST && !pTarget->HasAura(ROOTS) && !pTarget->HasAura(CYCLONE) && CastSpell(HIBERNATE, pTarget)) { return; } //if (m_bot->getRace() == (uint8) RACE_NIGHTELF && isUnderAttack() && CastSpell(R_SHADOWMELD, m_bot)) { return; } } // Things to do wheter Tank or not if (m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //no gcd if (ai->GetManaPercent() < 20 && CastSpell (INNERVATE, m_bot) ) { return; } //We have little mana probably cant change form } TakePosition(pTarget); if (ChangeForm(BEAR_FORM)) { return; } // if i am main tank, protect master by taunt if(m_tank->GetGUID() == m_bot->GetGUID()) { // Taunt if needed (Only for master) Unit *curAtt = GetAttackerOf(GetMaster()); if (curAtt) { if (isUnderAttack(GetMaster(),2) && CastSpell(CHALLENGING_ROAR, curAtt)) { return; } if (CastSpell(GROWL, curAtt)) { return; } } // My target is not attacking me, taunt.. if (pVictim && pVictim->GetGUID() != m_bot->GetGUID() && CastSpell(GROWL, pTarget) ) { return; } } break; #pragma endregion #pragma region BOT_ROLE_DPS_RANGED case BOT_ROLE_DPS_RANGED: if ( ai->GetManaPercent() < 20 && CastSpell (INNERVATE, m_bot)) { return; } // Do caster form stuff if (ai->GetForm() == FORM_NONE) { if(DoSupportRaid(GetMaster())) return; else if(m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup() && DoSupportRaid(m_bot)) { return; } } if (MOONKIN_FORM) { if (ChangeForm(MOONKIN_FORM)) { return; } } else if (ai->GetForm() != FORM_NONE && ChangeForm(1)) { } //Normal Form TakePosition(pTarget); // BUFF UP if(DoSupportRaid(GetMaster(),false,false,false)) return; else if(m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup() && DoSupportRaid(m_bot,false,false,false)) { return; } break; #pragma endregion #pragma region BOT_ROLE_SUPPORT case BOT_ROLE_SUPPORT: if ( ai->GetManaPercent() < 20 && CastSpell (INNERVATE,m_bot)) { return; } //Get to tree form only if you will no longer cast attack spells if( TREE_OF_LIFE_FORM && (ai->GetManaPercent() < offensiveSpellThreshold || isUnderAttack()) ) { if (ChangeForm(TREE_OF_LIFE_FORM)) { return; } } else if (ai->GetForm() != FORM_NONE && ChangeForm(1)) { } //Normal Form no gcd TakePosition(pTarget); //RezGroup(REBIRTH, GetMaster()); if (DoSupportRaid(GetMaster())) { return; } if (m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup() && DoSupportRaid(m_bot)) { return; } //heal pets and bots Unit *target = DoSelectLowestHpFriendly(30, 1000); if(target && target->isAlive() && HealTarget(target, target->GetHealth()*100 / target->GetMaxHealth()) ) { return; } break; #pragma endregion } #pragma region DruidCommon // Common Dps and protection routine if (ai->GetHealthPercent() <= 70 && CastSpell(BARKSKIN,m_bot)) { return; } if (isUnderAttack() && CastSpell(NATURES_GRASP,m_bot)) { return; } if (ai->GetForm() == FORM_CAT) { // If at threat limit, use Cower to reduce threat if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack()) { if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) // I am attacking wrong target!! { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); return; } else { if (CastSpell(COWER,pTarget)) { return; } //Lets see if we can manage else { return; } //use no spells and wait threat to be reduced } } if (CastSpell(FERAL_CHARGE_CAT,pTarget)) { return; } if (m_bot->GetComboPoints() >= 1 && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(MAIM, pTarget)) { return; } if (CastSpell(BERSERK, m_bot)) { return; } if (ai->GetHealthPercent() <= 75 && CastSpell(SURVIVAL_INSTINCTS, m_bot)) { return; } if (isUnderAttack() && CastSpell(NATURES_GRASP, m_bot)) { return; } if (CastSpell(FAERIE_FIRE_FERAL, pTarget)) { return; } if (m_bot->GetComboPoints() < 5) { if (CastSpell(RAKE, pTarget)) { return; } if (CastSpell(MANGLE_CAT, pTarget)) { return; } if (!pTarget->HasInArc(M_PI,m_bot) && CastSpell(SHRED, pTarget)) { return; } if (ai->GetEnergyAmount() > 65 && CastSpell(MANGLE_CAT, pTarget)) { return; } //Spam mangle if cannot cast shred if (ai->GetEnergyAmount() > 65 && CastSpell(CLAW, pTarget) ) { return; } //Spam Claw if there is no mangle // if (CanCast(COWER, pTarget) && CastSpell(COWER, pTarget)) { return; } //if still nothing, use COWER to reduce threat } else { if (CastSpell(SAVAGE_ROAR)) { return; } if (CastSpell(RIP, pTarget)) { return; } if (ai->GetEnergyAmount() >= 65 && CastSpell(FEROCIOUS_BITE, pTarget)) { return; } //maxhit for feracious bite } if (CastSpell(TIGERS_FURY, m_bot)) { return; } //if nothing is ready yet, use tigers fury } else if (ai->GetForm() == FORM_DIREBEAR || ai->GetForm() == FORM_BEAR) { // If at threat limit, stop if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack() ) { //Change to tank's target if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); } return; //use no spells and wait threat to be reduced } if (CastSpell(FERAL_CHARGE_BEAR,pTarget)) { return; } if (CastSpell(BASH, pTarget,true,true)) { return; } //Need check for immunity if (CastSpell(BERSERK, m_bot)) { return; } if (CastSpell(DEMORALIZING_ROAR, pTarget)) { return; } if (ai->GetHealthPercent() > 90 && ai->GetRageAmount() < 50 && CastSpell(ENRAGE, m_bot)) { return; } if (ai->GetHealthPercent() <= 75 && CastSpell(SURVIVAL_INSTINCTS, m_bot)) { return; } if ( ( ai->GetHealthPercent() <= 30 || (ai->GetHealthPercent() < 85 && m_tank->GetGUID() != m_bot->GetGUID()) ) && CastSpell(FRENZIED_REGENERATION)) { return; } if (CastSpell(FAERIE_FIRE_FERAL, pTarget)) { return; } if (CastSpell(MANGLE_BEAR, pTarget)) { return; } if ((ai->GetRageAmount() > 70 || m_tank->GetGUID() == m_bot->GetGUID()) && CastSpell(SWIPE_BEAR, pTarget)) { return; } if (ai->GetRageAmount() > 50 && CastSpell(MAUL, pTarget)) {} // Low Priority, Next Attack effect if (ai->GetRageAmount() > 60 && CastSpell(LACERATE, pTarget)) { return; } //Currently applies only 1 } else { //Defensive stuff if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { if (ROOTS && !pTarget->HasAura(CYCLONE) && !pTarget->HasAura(HIBERNATE) && CastSpell(ROOTS, pTarget)) { return; } if (CYCLONE && pDist > 5 && !pTarget->HasAura(ROOTS) && !pTarget->HasAura(HIBERNATE) && CastSpell(CYCLONE, pTarget)) { return; } if (HIBERNATE && pTarget->GetCreatureType() == (uint32) CREATURE_TYPE_BEAST && !pTarget->HasAura(ROOTS) && !pTarget->HasAura(CYCLONE) && CastSpell(HIBERNATE, pTarget)) { return; } //if (m_bot->getRace() == (uint8) RACE_NIGHTELF && isUnderAttack() && CastSpell(R_SHADOWMELD, m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } } if (CastSpell(FAERIE_FIRE, pTarget)) { return; } // If at threat limit, stop if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack() ) { //Change to tank's target if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); } return; //use no spells and wait threat to be reduced } // Continue attacking if theres excess mana (for healers) if (m_role == BOT_ROLE_SUPPORT && ai->GetManaPercent() < offensiveSpellThreshold) { return; } if (m_role != BOT_ROLE_SUPPORT && CastSpell(NATURES_SWIFTNESS, m_bot)) { } //only balance no gcd if (m_bot->HasAura(NATURES_SWIFTNESS) && CastSpell(STARFIRE, pTarget)) { return; } if (CastSpell(INSECT_SWARM, pTarget)) { return; } if (CastSpell(TYPHOON, pTarget)) { return; } if (isUnderAttack(m_tank,4) && CastSpell(HURRICANE, pTarget)) { ai->SetIgnoreUpdateTime(8); return; } if (isUnderAttack(m_tank,5) && CastSpell(FORCE_OF_NATURE, m_bot)) { return; } if (isUnderAttack(m_tank,4) && CastSpell(STARFALL, pTarget)) { return; } if (CastSpell(MOONFIRE, pTarget)) { return; } if (CastSpell(WRATH, pTarget)) { return; } if (CastSpell(STARFIRE, pTarget)) { return; } } // If there is nothing else to do buff UP if (m_role == BOT_ROLE_DPS_MELEE) //Those already healed and buffed or should never buff in combat { if (DoSupportRaid(GetMaster(),false,false,false)) { return; } if (m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup() && DoSupportRaid(m_bot,false,false,false)) { return; } } // drink potion if support / healer (Other builds simply overuse mana and waste mana pots) if(ai->GetManaPercent() < 5 && (m_role == BOT_ROLE_SUPPORT || m_role == BOT_ROLE_HEALER) ) { Item *pItem = ai->FindPotion(); if(pItem != NULL) { if (pItem->GetSpell() && m_bot->HasSpellCooldown(pItem->GetSpell()) ) { return; } //pot is in cooldown ai->UseItem(*pItem); } } #pragma endregion } //end DoNextCombatManeuver
void AIUpdate() { float BazCast = (float)RandomFloat(100.0f); CastSpell(BazCast); }
void Vehicle::AddPassenger(Unit *unit, int8 seatId, bool force) { SeatMap::iterator seat; seat = m_Seats.find(seatId); // this should never happen if(seat == m_Seats.end()) return; unit->SetVehicleGUID(GetGUID()); seat->second.passenger = unit; if(unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->isVehicle()) { if(((Vehicle*)unit)->GetEmptySeatsCount(true) == 0) seat->second.flags = SEAT_VEHICLE_FULL; else seat->second.flags = SEAT_VEHICLE_FREE; } else { seat->second.flags = SEAT_FULL; } if(unit->GetTypeId() == TYPEID_PLAYER) { WorldPacket data0(SMSG_FORCE_MOVE_ROOT, 10); data0 << unit->GetPackGUID(); data0 << (uint32)((seat->second.vs_flags & SF_CAN_CAST) ? 2 : 0); unit->SendMessageToSet(&data0,true); } if(seat->second.vs_flags & SF_MAIN_RIDER) { if(!(GetVehicleFlags() & VF_MOVEMENT)) { GetMotionMaster()->Clear(false); GetMotionMaster()->MoveIdle(); SetCharmerGUID(unit->GetGUID()); unit->SetUInt64Value(UNIT_FIELD_CHARM, GetGUID()); if(unit->GetTypeId() == TYPEID_PLAYER) { ((Player*)unit)->SetMover(this); ((Player*)unit)->SetMoverInQueve(this); ((Player*)unit)->SetClientControl(this, 1); } if(canFly() || HasAuraType(SPELL_AURA_FLY) || HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED)) { WorldPacket data3(SMSG_MOVE_SET_CAN_FLY, 12); data3 << GetPackGUID(); data3 << (uint32)(0); SendMessageToSet(&data3,false); } //Make vehicle fly if(GetVehicleFlags() & VF_FLYING) CastSpell(this, 49303, false); } SpellClickInfoMapBounds clickPair = sObjectMgr.GetSpellClickInfoMapBounds(GetEntry()); for(SpellClickInfoMap::const_iterator itr = clickPair.first; itr != clickPair.second; ++itr) { if (unit->GetTypeId() == TYPEID_UNIT || itr->second.IsFitToRequirements((Player*)unit)) { Unit *caster = (itr->second.castFlags & 0x1) ? unit : this; Unit *target = (itr->second.castFlags & 0x2) ? unit : this; caster->CastSpell(target, itr->second.spellId, true); } } if(unit->GetTypeId() == TYPEID_PLAYER) { // it should be added only on rider enter? if(((Player*)unit)->GetGroup()) ((Player*)unit)->SetGroupUpdateFlag(GROUP_UPDATE_VEHICLE); ((Player*)unit)->SetFarSightGUID(GetGUID()); BuildVehicleActionBar((Player*)unit); } if(!(GetVehicleFlags() & VF_FACTION)) setFaction(unit->getFaction()); if(GetVehicleFlags() & VF_CANT_MOVE) { WorldPacket data2(SMSG_FORCE_MOVE_ROOT, 10); data2 << GetPackGUID(); data2 << (uint32)(2); SendMessageToSet(&data2,false); } if(GetVehicleFlags() & VF_CAST_AURA && m_VehicleData && m_VehicleData->v_spells[0] != 0) CastSpell(unit, m_VehicleData->v_spells[0], true); if(GetVehicleFlags() & VF_NON_SELECTABLE) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } if(seat->second.vs_flags & SF_UNATTACKABLE) unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); EmptySeatsCountChanged(); }
void Totem::InitSummon() { if (m_type == TOTEM_PASSIVE) for(uint32 spellId, i = 0; spellId = GetSpell(i); i++) CastSpell(this, spellId, false, NULL, NULL, GetOwnerGUID()); }
void AIUpdate() { float TarCast = (float)RandomFloat(100.0f); CastSpell(TarCast); }
void UpdateAI(uint32 timeDelta) override { if (mJustStepped) return; if (mEventTimer > timeDelta) { mEventTimer -= timeDelta; return; } if (mEventStep == 0) { m_creature->GetMotionMaster()->MovePoint(0, -11817.48f, 1250.02f, 2.64f); mJustStepped = true; } else if (mEventStep == 1) { m_creature->GetMotionMaster()->MovePoint(0, -11829.73f, 1258.05f, 1.88f); mJustStepped = true; } else if (mEventStep == 2) { m_creature->GetMotionMaster()->MovePoint(0, -11837.02f, 1293.10f, 0.69f); mJustStepped = true; } else if (mEventStep == 3) { m_creature->GetMotionMaster()->MovePoint(0, -11825.56f, 1322.88f, 0.29f); mJustStepped = true; mEventTimer = 1000; } else if (mEventStep == 4) { m_creature->CastSpell(m_creature, SPELL_QUEST_TROLL_HERO_SUMMON_VISUAL, false); ++mEventStep; mEventTimer = 30000; } else if (mEventStep == 5) { for (int i = 0; i < 4; ++i) { auto cr = m_creature->SummonCreature(NPC_SERVANT, servant_positions[i][0], servant_positions[i][1], servant_positions[i][2], servant_positions[i][3], TEMPSUMMON_MANUAL_DESPAWN, 0); if (!cr) { m_creature->MonsterSay("Etwas lief falsch, bitte beim Team melden!", 0); m_creature->Respawn(); Reset(); return; } cr->CastSpell(cr, SPELL_SPAWN_RED_LIGHTNING, true); servants.push_back(cr); } ++mEventStep; mEventTimer = 2000; } else if (mEventStep == 6) { if (Unit* pTarget = m_creature->GetMap()->GetUnit(targetDummy)) m_creature->CastSpell(pTarget, SPELL_HEART_OF_HAKKAR_MOLTHOR_CHUCKS_THE_HEART, true); ++mEventStep; mEventTimer = 5000; } else if (mEventStep == 7) { if (Unit* pTarget = m_creature->GetMap()->GetUnit(targetDummy)) pTarget->CastSpell(pTarget, SPELL_CREATE_HEART_OF_HAKKAR_RIFT, true); ++mEventStep; mEventTimer = 500; } else if (mEventStep == 8) { DoScriptText(-1200000, m_creature); for (int i = 0; i < 4; ++i) { servants[i]->CastSpell(servants[i], SPELL_HEART_OF_HAKKAR_SUMMON_CIRCLE, true); servants[i]->CastSpell(servants[i], SPELL_HEART_OF_HAKKAR_RITUAL_CAST, true); } m_creature->CastSpell(m_creature, SPELL_HEART_OF_HAKKAR_BANNING, true); ++mEventStep; mEventTimer = 30000; } else if (mEventStep == 9) { if (Unit* pTarget = m_creature->GetMap()->GetUnit(targetDummy)) { m_creature->CastSpell(pTarget, SPELL_CREATE_HEART_OF_HAKKAR_EXPLOISON, true); m_creature->CastSpell(pTarget, SPELL_HELLFIRE_CAST_VISUAL, true); } ++mEventStep; mEventTimer = 4000; } else if (mEventStep == 10) { DoScriptText(-1200001, m_creature); ++mEventStep; mEventTimer = 1000; } else if (mEventStep == 11) { if (Unit* pTarget = m_creature->GetMap()->GetUnit(target)) m_creature->CastSpell(pTarget, SPELL_SPIRIT_OF_ZANDALAR, false); ++mEventStep; mEventTimer = 4000; } else if (mEventStep == 12) { m_creature->GetMotionMaster()->MovePoint(0, -11837.02f, 1293.10f, 0.69f); mJustStepped = true; } else if (mEventStep == 13) { m_creature->GetMotionMaster()->MovePoint(0, -11829.73f, 1258.05f, 1.88f); mJustStepped = true; } else if (mEventStep == 14) { m_creature->GetMotionMaster()->MovePoint(0, -11817.48f, 1250.02f, 2.64f); mJustStepped = true; } else if (mEventStep == 15) { auto a = m_creature->GetMotionMaster()->top(); float x, y, z; m_creature->GetRespawnCoord(x, y, z); m_creature->GetMotionMaster()->MovePoint(0, x, y, z); mJustStepped = true; } else if (mEventStep == 16) { m_creature->SetFacingTo(4.24f); if (Creature* pTarget = m_creature->GetMap()->GetCreature(targetDummy)) pTarget->ForcedDespawn(); for (int i = 0; i < 4; ++i) servants[i]->ForcedDespawn(); if (GameObject* pObject = m_creature->GetMap()->GetGameObject(heart)) { pObject->SetLootState(GO_JUST_DEACTIVATED); pObject->RemoveFromWorld(); } Reset(); } }
void CMobController::DoRoamTick(time_point tick) { // If there's someone on our enmity list, go from roaming -> engaging if (PMob->PEnmityContainer->GetHighestEnmity() != nullptr && !(PMob->m_roamFlags & ROAMFLAG_IGNORE)) { Engage(PMob->PEnmityContainer->GetHighestEnmity()->targid); return; } else if (PMob->m_OwnerID.id != 0 && !(PMob->m_roamFlags & ROAMFLAG_IGNORE)) { // i'm claimed by someone and need hate towards this person PTarget = (CBattleEntity*)PMob->GetEntity(PMob->m_OwnerID.targid, TYPE_PC | TYPE_MOB | TYPE_PET); battleutils::ClaimMob(PMob, PTarget); Engage(PTarget->targid); return; } //#TODO else if (PMob->GetDespawnTime() > time_point::min() && PMob->GetDespawnTime() < m_Tick) { Despawn(); return; } if (PMob->m_roamFlags & ROAMFLAG_IGNORE) { // don't claim me if I ignore PMob->m_OwnerID.clean(); } //skip roaming if waiting if (m_Tick >= m_WaitTime) { // don't aggro a little bit after I just disengaged PMob->m_neutral = PMob->CanBeNeutral() && m_Tick <= m_NeutralTime + 10s; if (PMob->PAI->PathFind->IsFollowingPath()) { FollowRoamPath(); } else if (m_Tick >= m_LastActionTime + std::chrono::milliseconds(PMob->getBigMobMod(MOBMOD_ROAM_COOL))) { // lets buff up or move around if (PMob->CalledForHelp()) { PMob->CallForHelp(false); } // can't rest with poison or disease if (PMob->CanRest()) { // recover 10% health if (PMob->Rest(0.1f)) { // health updated PMob->updatemask |= UPDATE_HP; } if (PMob->GetHPP() == 100) { // at max health undirty exp PMob->m_giveExp = true; } } // if I just disengaged check if I should despawn if (PMob->IsFarFromHome()) { if (PMob->CanRoamHome() && PMob->PAI->PathFind->PathTo(PMob->m_SpawnPoint)) { // walk back to spawn if too far away // limit total path to just 10 or // else we'll move straight back to spawn PMob->PAI->PathFind->LimitDistance(10.0f); FollowRoamPath(); // move back every 5 seconds m_LastActionTime = m_Tick - (std::chrono::milliseconds(PMob->getBigMobMod(MOBMOD_ROAM_COOL)) + 10s); } else if (!PMob->getMobMod(MOBMOD_NO_DESPAWN) != 0 && !map_config.mob_no_despawn) { PMob->PAI->Despawn(); return; } } else { if (PMob->getMobMod(MOBMOD_SPECIAL_SKILL) != 0 && m_Tick >= m_LastSpecialTime + std::chrono::milliseconds(PMob->getBigMobMod(MOBMOD_SPECIAL_COOL)) && TrySpecialSkill()) { // I spawned a pet } else if (PMob->GetMJob() == JOB_SMN && CanCastSpells() && PMob->SpellContainer->HasBuffSpells() && m_Tick >= m_LastMagicTime + std::chrono::milliseconds(PMob->getBigMobMod(MOBMOD_MAGIC_COOL))) { // summon pet CastSpell(PMob->SpellContainer->GetBuffSpell()); } else if (CanCastSpells() && dsprand::GetRandomNumber(10) < 3 && PMob->SpellContainer->HasBuffSpells()) { // cast buff CastSpell(PMob->SpellContainer->GetBuffSpell()); } else if ((PMob->m_roamFlags & ROAMFLAG_AMBUSH)) { //#TODO: #AIToScript move to scripts // stay underground PMob->HideName(true); PMob->HideModel(true); PMob->animationsub = 0; PMob->updatemask |= UPDATE_HP; } else if ((PMob->m_roamFlags & ROAMFLAG_STEALTH)) { // hidden name PMob->HideName(true); PMob->Untargetable(true); PMob->updatemask |= UPDATE_HP; } else if (PMob->m_roamFlags & ROAMFLAG_EVENT) { // allow custom event action luautils::OnMobRoamAction(PMob); m_LastActionTime = m_Tick; } else if (PMob->CanRoam() && PMob->PAI->PathFind->RoamAround(PMob->m_SpawnPoint, PMob->GetRoamDistance(), PMob->getMobMod(MOBMOD_ROAM_TURNS), PMob->m_roamFlags)) { //#TODO: #AIToScript (event probably) if (PMob->m_roamFlags & ROAMFLAG_WORM) { // move down PMob->animationsub = 1; PMob->HideName(true); // don't move around until i'm fully in the ground Wait(2s); } else { FollowRoamPath(); } } else { m_LastActionTime = m_Tick; } } } } if (m_Tick >= m_LastRoamScript + 3s) { luautils::OnMobRoam(PMob); m_LastRoamScript = m_Tick; } }
CombatManeuverReturns PlayerbotPriestAI::DoNextCombatManeuverPVE(Unit *pTarget) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; Unit* pVictim = pTarget->getVictim(); float dist = m_bot->GetCombatDistance(pTarget); uint32 spec = m_bot->GetSpec(); Group *m_group = m_bot->GetGroup(); if (m_ai->GetCombatStyle() != PlayerbotAI::COMBAT_RANGED && dist > ATTACK_DISTANCE) 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 && (SHOOT == 0 || !m_bot->GetWeaponForAttack(RANGED_ATTACK, true, true)) && !m_ai->IsHealer()) 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 (newTarget && FADE > 0 && !m_bot->HasAura(FADE, EFFECT_INDEX_0)) { if (CastSpell(FADE, m_bot)) { //m_ai->TellMaster("I'm casting fade."); return RETURN_CONTINUE; } else m_ai->TellMaster("I have AGGRO."); } // Heal myself // TODO: move to HealTarget code // TODO: you forgot to check for the 'temporarily immune to PW:S because you only just got it cast on you' effect // - which is different effect from the actual shield. if (m_ai->GetHealthPercent() < 25 && POWER_WORD_SHIELD > 0 && !m_bot->HasAura(POWER_WORD_SHIELD, EFFECT_INDEX_0)) { if (CastSpell(POWER_WORD_SHIELD) & RETURN_CONTINUE) { //m_ai->TellMaster("I'm casting PW:S on myself."); return RETURN_CONTINUE; } else if (m_ai->IsHealer()) // Even if any other RETURN_ANY_OK - aside from RETURN_CONTINUE m_ai->TellMaster("Your healer's about TO DIE. HELP ME."); } if (m_ai->GetHealthPercent() < 35 && DESPERATE_PRAYER > 0 && CastSpell(DESPERATE_PRAYER, m_bot) & RETURN_CONTINUE) { //m_ai->TellMaster("I'm casting desperate prayer."); return RETURN_CONTINUE; } // Already healed self or tank. If healer, do nothing else to anger mob. if (m_ai->IsHealer()) return RETURN_NO_ACTION_OK; // In a sense, mission accomplished. // 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 PSYCHIC SCREAM 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); } } // Heal if (m_ai->IsHealer()) { if (HealPlayer(GetHealTarget()) & RETURN_CONTINUE) return RETURN_CONTINUE; } else { // Is this desirable? Debatable. // ... Certainly could be very detrimental to a shadow priest // TODO: In a group/raid with a healer you'd want this bot to focus on DPS (it's not specced/geared for healing either) if (HealPlayer(m_bot) & RETURN_CONTINUE) return RETURN_CONTINUE; } // Do damage tweaking for healers here if (m_ai->IsHealer()) { // TODO: elite exception //if (Any target is an Elite) // return; return CastSpell(SHOOT, pTarget); } // Damage Spells switch (spec) { case PRIEST_SPEC_HOLY: if (HOLY_FIRE > 0 && !pTarget->HasAura(HOLY_FIRE, EFFECT_INDEX_0) && CastSpell(HOLY_FIRE, pTarget)) return RETURN_CONTINUE; if (SMITE > 0 && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; //if (HOLY_NOVA > 0 && dist <= ATTACK_DISTANCE && m_ai->CastSpell(HOLY_NOVA)) // return RETURN_CONTINUE; break; case PRIEST_SPEC_SHADOW: if (DEVOURING_PLAGUE > 0 && !pTarget->HasAura(DEVOURING_PLAGUE, EFFECT_INDEX_0) && CastSpell(DEVOURING_PLAGUE, pTarget)) return RETURN_CONTINUE; if (VAMPIRIC_TOUCH > 0 && !pTarget->HasAura(VAMPIRIC_TOUCH, EFFECT_INDEX_0) && CastSpell(VAMPIRIC_TOUCH, pTarget)) return RETURN_CONTINUE; if (SHADOW_WORD_PAIN > 0 && !pTarget->HasAura(SHADOW_WORD_PAIN, EFFECT_INDEX_0) && CastSpell(SHADOW_WORD_PAIN, pTarget)) return RETURN_CONTINUE; if (MIND_BLAST > 0 && (!m_bot->HasSpellCooldown(MIND_BLAST)) && CastSpell(MIND_BLAST, pTarget)) return RETURN_CONTINUE; if (MIND_FLAY > 0 && CastSpell(MIND_FLAY, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } if (SHADOWFIEND > 0 && !m_bot->GetPet() && CastSpell(SHADOWFIEND)) return RETURN_CONTINUE; /*if (MIND_SEAR > 0 && m_ai->GetAttackerCount() >= 3 && CastSpell(MIND_SEAR, pTarget)) { m_ai->SetIgnoreUpdateTime(5); return RETURN_CONTINUE; }*/ if (SHADOWFORM == 0 && MIND_FLAY == 0 && SMITE > 0 && CastSpell(SMITE, pTarget)) // low levels return RETURN_CONTINUE; break; case PRIEST_SPEC_DISCIPLINE: if (POWER_INFUSION > 0 && CastSpell(POWER_INFUSION, GetMaster())) // TODO: just master? return RETURN_CONTINUE; if (INNER_FOCUS > 0 && !m_bot->HasAura(INNER_FOCUS, EFFECT_INDEX_0) && CastSpell(INNER_FOCUS, m_bot)) return RETURN_CONTINUE; if (PENANCE > 0 && CastSpell(PENANCE)) return RETURN_CONTINUE; if (SMITE > 0 && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; break; } // No spec due to low level OR no spell found yet if (MIND_BLAST > 0 && (!m_bot->HasSpellCooldown(MIND_BLAST)) && CastSpell(MIND_BLAST, pTarget)) return RETURN_CONTINUE; if (SHADOW_WORD_PAIN > 0 && !pTarget->HasAura(SHADOW_WORD_PAIN, EFFECT_INDEX_0) && CastSpell(SHADOW_WORD_PAIN, pTarget)) return RETURN_CONTINUE; if (MIND_FLAY > 0 && CastSpell(MIND_FLAY, pTarget)) { m_ai->SetIgnoreUpdateTime(3); return RETURN_CONTINUE; } if (SHADOWFORM == 0 && SMITE > 0 && CastSpell(SMITE, pTarget)) return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; } // end DoNextCombatManeuver
bool PlayerbotClassAI::castSelfCCBreakers (uint32 castList[]) { uint32 dispelSpell = 0; Player *dTarget = GetPlayerBot(); /* dispelSpell = (uint32) R_ESCAPE_ARTIST; // this is script effect, Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if ( ( aura->GetSpellProto()->Mechanic == MECHANIC_SNARE ) || ( aura->GetSpellProto()->Mechanic == MECHANIC_ROOT ) ) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; // do not remove positive auras if friendly target // negative auras if non-friendly target if(positive == dTarget->IsFriendlyTo(caster)) continue; } return castSpell(dispelSpell, dTarget); } } return false; */ // racial abilities /* if( GetPlayerBot()->getRace() == RACE_BLOODELF && !pTarget->HasAura( ARCANE_TORRENT,0 ) && castSpell( ARCANE_TORRENT,pTarget ) ) { //GetPlayerBot()->Say("Arcane Torrent!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_HUMAN && (GetPlayerBot()->HasUnitState( UNIT_STAT_STUNNED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_FEAR ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_DECREASE_SPEED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_CHARM )) && castSpell( EVERY_MAN_FOR_HIMSELF, GetPlayerBot() ) ) { //GetPlayerBot()->Say("EVERY MAN FOR HIMSELF!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_UNDEAD_PLAYER && (GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_FEAR ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_CHARM )) && castSpell( WILL_OF_THE_FORSAKEN, GetPlayerBot() ) ) { // GetPlayerBot()->Say("WILL OF THE FORSAKEN!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_DWARF && GetPlayerBot()->HasAuraState( AURA_STATE_DEADLY_POISON ) && castSpell( STONEFORM, GetPlayerBot() ) ) { //GetPlayerBot()->Say("STONEFORM!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_GNOME && (GetPlayerBot()->HasUnitState( UNIT_STAT_STUNNED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_DECREASE_SPEED )) && castSpell( ESCAPE_ARTIST, GetPlayerBot() ) ) { // GetPlayerBot()->Say("ESCAPE ARTIST!", LANG_UNIVERSAL); } */ for (uint8 j = 0; j < sizeof (castList); j++) { dispelSpell = castList[j]; if (dispelSpell == 0 || !dTarget->HasSpell(dispelSpell) || !CanCast(dispelSpell, dTarget, true)) continue; SpellEntry const *dSpell = GetSpellStore()->LookupEntry(dispelSpell); if (!dSpell) continue; for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i) { if (dSpell->Effect[i] != (uint32)SPELL_EFFECT_DISPEL && dSpell->Effect[i] != (uint32)SPELL_EFFECT_APPLY_AURA) continue; if (dSpell->Effect[i] == (uint32)SPELL_EFFECT_APPLY_AURA && ( (dSpell->EffectApplyAuraName[i] != (uint32) SPELL_AURA_MECHANIC_IMMUNITY) || (dSpell->EffectApplyAuraName[i] != (uint32) SPELL_AURA_DISPEL_IMMUNITY) )) continue; Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if (aura->GetSpellProto() && ( (dSpell->Effect[i] == (uint32)SPELL_EFFECT_DISPEL && ((1<<aura->GetSpellProto()->Dispel) & GetDispellMask(DispelType(dSpell->EffectMiscValue[i]))) ) || (dSpell->EffectApplyAuraName[i] == (uint32) SPELL_AURA_MECHANIC_IMMUNITY && ( GetAllSpellMechanicMask(aura->GetSpellProto()) & ( 1 << dSpell->EffectMiscValue[i]) ) ) || (dSpell->EffectApplyAuraName[i] == (uint32) SPELL_AURA_DISPEL_IMMUNITY && ( (1<<aura->GetSpellProto()->Dispel) & GetDispellMask(DispelType(dSpell->EffectMiscValue[i])) ) ) ) ) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; if(positive)continue; } return CastSpell(dispelSpell, dTarget, false); } } } } return false; }
CombatManeuverReturns PlayerbotPriestAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (RESURRECTION && m_ai->CastSpell(RESURRECTION, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } return RETURN_NO_ACTION_ERROR; // not error per se - possibly just OOM } if (CURE_DISEASE > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { uint32 dispelMask = GetDispellMask(DISPEL_DISEASE); Unit::SpellAuraHolderMap const& auras = target->GetSpellAuraHolderMap(); for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { SpellAuraHolder *holder = itr->second; if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) { if (holder->GetSpellProto()->Dispel == DISPEL_DISEASE) { m_ai->CastSpell(CURE_DISEASE, *target); return RETURN_CONTINUE; } } } } uint8 hp = target->GetHealthPercent(); uint8 hpSelf = m_ai->GetHealthPercent(); if (hp >= 90) return RETURN_NO_ACTION_OK; // TODO: Integrate shield here if (hp < 35 && FLASH_HEAL > 0 && m_ai->CastSpell(FLASH_HEAL, *target)) return RETURN_CONTINUE; if (hp < 45 && GREATER_HEAL > 0 && m_ai->CastSpell(GREATER_HEAL, *target)) return RETURN_CONTINUE; // Heals target AND self for equal amount if (hp < 60 && hpSelf < 80 && BINDING_HEAL > 0 && m_ai->CastSpell(BINDING_HEAL, *target)) return RETURN_CONTINUE; if (hp < 60 && PRAYER_OF_MENDING > 0 && !target->HasAura(PRAYER_OF_MENDING, EFFECT_INDEX_0) && CastSpell(PRAYER_OF_MENDING, target)) return RETURN_FINISHED_FIRST_MOVES; if (hp < 60 && HEAL > 0 && m_ai->CastSpell(HEAL, *target)) return RETURN_CONTINUE; if (hp < 90 && RENEW > 0 && !target->HasAura(RENEW) && m_ai->CastSpell(RENEW, *target)) return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 40 && PRAYER_OF_HEALING > 0 && m_ai->CastSpell(PRAYER_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 50 && CIRCLE_OF_HEALING > 0 && m_ai->CastSpell(CIRCLE_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; } // end HealTarget