void PetAI::_AttackStart(Unit* target) { // Check all pet states to decide if we can attack this target if (!CanAttack(target)) return; // Only chase if not commanded to stay or if stay but commanded to attack DoAttack(target, (!me->GetCharmInfo()->HasCommandState(COMMAND_STAY) || me->GetCharmInfo()->IsCommandAttack())); }
void UpdateAI(uint32 diff) override { DoAttack(); if (!UpdateVictim()) return; DoMeleeAttackIfReady(); }
void CStateMachinen::Update(CMonster& monster, eStateEvent evt) { switch(monster.mStateParamter.stateCur) { case eMA_STAND: { DoStand( monster, evt); break; } case eMA_WALKAROUND: { DoWalkAround( monster, evt); break; } case eMA_PERSUIT: { DoPursuit( monster, evt); break; } case eMA_WALKAWAY: case eMA_RUNAWAY: { DoRunAway( monster, evt); break; } case eMA_ATTACK: { DoAttack( monster, evt); break; } case eMA_SCRIPT_RUN: case eMA_SCRIPT_WALK: { DoScriptMove( monster, evt); break; } case eMA_PAUSE: { DoPause( monster, evt); break; } } }
void PetAI::AttackStart(Unit *target) { // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!_CanAttack(target)) return; // We can attack, should we chase or not? if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) DoAttack(target,true); // FOLLOW, attack with chase else { if (me->GetCharmInfo()->IsCommandAttack()) DoAttack(target,true); // STAY or FOLLOW, player clicked "attack" so attack with chase else DoAttack(target,false); // STAY, target in range, attack not clicked so attack without chase } }
void PetAI::AttackStart(Unit* target) { // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!CanAttack(target)) return; // Only chase if not commanded to stay or if stay but commanded to attack DoAttack(target, ((!me->GetCharmInfo()->HasCommandState(COMMAND_STAY) && !me->GetCharmInfo()->HasCommandState(COMMAND_MOVE_TO)) || me->GetCharmInfo()->IsCommandAttack())); }
void PetAI::AttackStart(Unit *target) { // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!_CanAttack(target)) return; targetHasCC = _CheckTargetCC(target); DoAttack(target, true); }
void PetAI::AttackStart(Unit* target) { // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!CanAttack(target)) return; if (Unit* owner = me->GetOwner()) owner->SetInCombatWith(target); DoAttack(target, true); }
void PetAI::AttackStart(Unit* target) { // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!CanAttack(target)) return; if (Unit* owner = me->GetCharmerOrOwner()) owner->RemoveAurasByType(SPELL_AURA_MOD_CAMOUFLAGE); // Only chase if not commanded to stay or if stay but commanded to attack DoAttack(target, (!me->GetCharmInfo()->HasCommandState(COMMAND_STAY) || me->GetCharmInfo()->IsCommandAttack())); }
void CAICharCharm::ActionAttack() { SetBattleTarget(m_PChar->PMaster->PBattleAI->GetBattleTarget()); if (m_PBattleTarget == nullptr) { m_ActionType = ACTION_DISENGAGE; ActionDisengage(); return; } m_PPathFind->LookAt(m_PBattleTarget->loc.p); float currentDistance = distance(m_PChar->loc.p, m_PBattleTarget->loc.p); if (currentDistance > m_PBattleTarget->m_ModelSize) { if (m_PChar->speed != 0) { m_PPathFind->PathAround(m_PBattleTarget->loc.p, 2.0f, PATHFLAG_WALLHACK | PATHFLAG_RUN); // m_PPathFind->CurvePath(0.5f); m_PPathFind->FollowPath(); // recalculate currentDistance = distance(m_PChar->loc.p, m_PBattleTarget->loc.p); } } uint16 WeaponDelay = m_PChar->GetWeaponDelay(false); if (m_Tick > m_LastMeleeTime + WeaponDelay) { if (currentDistance < m_PBattleTarget->m_ModelSize) { m_LastMeleeTime = m_Tick; if (battleutils::IsParalyzed(m_PChar)) { m_PChar->loc.zone->PushPacket(m_PChar, CHAR_INRANGE_SELF, new CMessageBasicPacket(m_PChar, m_PBattleTarget, 0, 0, MSGBASIC_IS_PARALYZED)); } else if (battleutils::IsIntimidated(m_PChar, m_PBattleTarget)) { m_PChar->loc.zone->PushPacket(m_PChar, CHAR_INRANGE_SELF, new CMessageBasicPacket(m_PChar, m_PBattleTarget, 0, 0, MSGBASIC_IS_INTIMIDATED)); } else { DoAttack(); } } } }
void PetAI::AttackStart(Unit* target) { if (me->GetCharmInfo() == NULL) return; // Overrides Unit::AttackStart to correctly evaluate Pet states // Check all pet states to decide if we can attack this target if (!_CanAttack(target)) return; targetHasCC = _CheckTargetCC(target); if (Unit* owner = me->GetOwner()) owner->SetInCombatWith(target); DoAttack(target, true); }
void UpdateAI(const uint32 diff) { if (!m_pInstance) return; //Bomb_Timer if (Bomb_Timer < diff) Bomb_Timer = 0; else Bomb_Timer -= diff; switch (m_pInstance->GetData(TYPE_JEKLIK)) { case IN_PROGRESS: DoAttack(); break; default: m_creature->AddObjectToRemoveList(); break; } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive() || !m_creature->GetCharmInfo()) return; Unit* owner = m_creature->GetCharmerOrOwner(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; // First checking if we have some taunt on us Unit* tauntTarget = NULL; const Unit::AuraList& tauntAuras = m_creature->GetAurasByType(SPELL_AURA_MOD_TAUNT); if (!tauntAuras.empty()) { Unit* caster = NULL; // Auras are pushed_back, last caster will be on the end Unit::AuraList::const_iterator aura = tauntAuras.end(); while (aura != tauntAuras.begin()) { --aura; caster = (*aura)->GetCaster(); if (caster && caster->isTargetableForAttack()) { tauntTarget = caster; break; } } if (tauntTarget) DoAttack(tauntTarget, true); } if (m_creature->getVictim() && m_creature->getVictim()->isAlive()) { if (_needToStop()) { _stopAttack(); return; } if (hasMelee) { // Check before attacking to prevent pets from leaving stay position bool attacked = false; if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY)) { if (m_creature->GetCharmInfo()->IsCommandAttack() || (m_creature->GetCharmInfo()->IsAtStay() && m_creature->CanReachWithMeleeAttack(m_creature->getVictim()))) attacked = DoMeleeAttackIfReady(); } else attacked = DoMeleeAttackIfReady(); if (attacked && owner) if (Unit* v = m_creature->getVictim()) // Victim may have died between owner->SetInCombatWith(v); } } else { if (m_creature->HasReactState(REACT_AGGRESSIVE) || m_creature->GetCharmInfo()->IsAtStay()) { // Every update we need to check targets only in certain cases // Aggressive - Allow auto select if owner or pet don't have a target // Stay - Only pick from pet or owner targets / attackers so targets won't run by // while chasing our owner. Don't do auto select. // All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc. Unit* nextTarget = SelectNextTarget(m_creature->HasReactState(REACT_AGGRESSIVE)); if (nextTarget) AttackStart(nextTarget); else HandleReturnMovement(); } else HandleReturnMovement(); } // Autocast (casted only in combat or persistent spells in any state) if (!m_creature->IsNonMeleeSpellCasted(false)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const *spellInfo = sSpellMgr.GetSpellEntry(spellID); if (!spellInfo) continue; if (m_creature->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; // check spell cooldown if (m_creature->HasSpellCooldown(spellInfo->Id)) continue; if (IsPositiveSpell(spellInfo->Id)) { if (!IsNonCombatSpell(spellInfo)) // Can be used in combat. { /* Spells handled here: Dash (1850), Dive (23145), Furious Howl (24604), Tainted Blood (19478) Blood Pact (6307), Fire Shield (11771), Sacrifice ... Consume Shadows (17767) */ // Warlock Sacrifice: do not auto cast if not in combat bool castOnlyInCombat = IsSpellHaveEffect(spellInfo, SPELL_EFFECT_INSTAKILL); if (!castOnlyInCombat) { int32 duration = GetSpellDuration(spellInfo); int32 cooldown = GetSpellRecoveryTime(spellInfo); // Keep this spell for when we will be in combat. if (cooldown >= 0 && duration >= 0 && cooldown > duration) castOnlyInCombat = true; } // 19478 - Tainted Blood, rank 1 enUS if (spellInfo->SpellIconID == 153) castOnlyInCombat = true; // 2947 - Fire Shield, rank 1 enUS // When set to auto-cast, the Imp will cast this on any party members within 30 yds if they receive a melee attack. if (spellInfo->IsFitToFamily<SPELLFAMILY_WARLOCK, CF_WARLOCK_IMP_BUFFS>() && spellInfo->SpellVisual == 289) castOnlyInCombat = false; // Furious Howl: in combat only if (IsSpellHaveAura(spellInfo, SPELL_AURA_MOD_DAMAGE_DONE)) castOnlyInCombat = true; if (castOnlyInCombat && !m_creature->getVictim()) continue; } Spell *spell = new Spell(m_creature, spellInfo, false); bool spellUsed = false; // Some spells can target enemy or friendly (DK Ghoul's Leap) // Check for enemy first (pet then owner) Unit* target = m_creature->getAttackerForHelper(); if (!target && owner) target = owner->getAttackerForHelper(); if (target) { if (CanAttack(target) && spell->CanAutoCast(target)) { targetSpellStore.push_back(std::make_pair(target, spell)); spellUsed = true; } } // No enemy, check friendly if (!spellUsed) { for (std::set<uint64>::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* ally = m_creature->GetMap()->GetUnit(*tar); //only buff targets that are in combat, unless the spell can only be cast while out of combat if (!ally) continue; if (spell->CanAutoCast(ally)) { targetSpellStore.push_back(std::make_pair(ally, spell)); spellUsed = true; break; } } } // No valid targets at all if (!spellUsed) spell->Delete(); } else if (m_creature->getVictim() && CanAttack(m_creature->getVictim()) && !IsNonCombatSpell(spellInfo)) { Spell *spell = new Spell(m_creature, spellInfo, false); if (spell->CanAutoCast(m_creature->getVictim())) targetSpellStore.push_back(std::make_pair(m_creature->getVictim(), spell)); else spell->Delete(); } } //found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); Spell* spell = targetSpellStore[index].second; Unit* target = targetSpellStore[index].first; targetSpellStore.erase(targetSpellStore.begin() + index); SpellCastTargets targets; targets.setUnitTarget(target); if (!m_creature->HasInArc(M_PI_F, target)) { m_creature->SetInFront(target); if (target->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)target); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)owner); } if (((Creature*)m_creature)->IsPet()) ((Pet*)m_creature)->CheckLearning(spell->m_spellInfo->Id); // 10% chance to play special pet attack talk, else growl // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell if (((Creature*)m_creature)->IsPet() && (((Pet*)m_creature)->getPetType() == SUMMON_PET) && (m_creature != target) && (urand(0, 100) < 10)) m_creature->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else m_creature->SendPetAIReaction(); spell->prepare(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) itr->second->Delete(); } // Update speed as needed to prevent dropping too far behind and despawning m_creature->UpdateSpeed(MOVE_RUN, true); m_creature->UpdateSpeed(MOVE_WALK, true); }