void UpdateAI(const uint32 diff) { if (!Vorpil) { me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } if (move <= diff) { if (sacrificed) { SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(HeroicMode?H_SPELL_EMPOWERING_SHADOWS:SPELL_EMPOWERING_SHADOWS); if (spell) Vorpil->AddAura(new EmpoweringShadowsAura(spell, 0, NULL, Vorpil, me)); Vorpil->SetHealth(Vorpil->GetHealth()+Vorpil->GetMaxHealth()/25); DoCast(me, SPELL_SHADOW_NOVA, true); me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } me->GetMotionMaster()->MoveFollow(Vorpil, 0, 0); if (me->GetDistance(Vorpil) < 3) { DoCast(me, SPELL_SACRIFICE, false); sacrificed = true; move = 500; return; } if (!Vorpil->isInCombat() || Vorpil->isDead()) { me->DealDamage(me, me->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } move = 1000; } else move -= diff; }
//Flesh tentacle functions void flesh_tentacleAI::UpdateAI(const uint32 diff) { //Check if we have a target if (!UpdateVictim()) return; if (Parent) { if (CheckTimer <= diff) { Unit* pUnit = Unit::GetUnit(*me, Parent); if (!pUnit || !pUnit->isAlive() || !pUnit->isInCombat()) { Parent = 0; me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); return; } CheckTimer = 1000; } else CheckTimer -= diff; } DoMeleeAttackIfReady(); }
SpellCastResult CheckCast() { Unit* caster = GetCaster(); if (caster->GetTypeId() == TYPEID_PLAYER && !caster->isInCombat()) return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; return SPELL_CAST_OK; }
void EnterCombat(Unit* /*who*/) { DoCast(me, SPELL_STRENGHT_OF_THE_PACK, true); if (me->ToTempSummon()) { Unit* auriaya = me->ToTempSummon()->GetSummoner(); if (auriaya && auriaya->ToCreature() && !auriaya->isInCombat()) auriaya->ToCreature()->SetInCombatWithZone(); } }
void EnterCombat(Unit* /*who*/) { me->AddAura(SPELL_STRENGTH_OF_THE_PACK, me); DoCast(RAID_MODE(SPELL_SAVAGE_POUNCE_10, SPELL_SAVAGE_POUNCE_25)); if (me->ToTempSummon()) { Unit* auriaya = me->ToTempSummon()->GetSummoner(); if (auriaya && auriaya->ToCreature() && !auriaya->isInCombat()) auriaya->ToCreature()->SetInCombatWithZone(); } }
void ScriptedPetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) // should not be needed, isAlive is checked in mangos before calling UpdateAI return; // UpdateAllies() is done in the generic PetAI in Mangos, but we can't do this from script side. // Unclear what side effects this has, but is something to be resolved from Mangos. if (m_creature->getVictim()) // in combat { if (!m_creature->CanAttack(m_creature->getVictim())) { // target no longer valid for pet, so either attack stops or new target are selected // doesn't normally reach this, because of how petAi is designed in Mangos. CombatStop // are called before this update diff, and then pet will already have no victim. ResetPetCombat(); return; } // update when in combat UpdatePetAI(diff); } else if (m_creature->GetCharmInfo()) { if (m_creature->isInCombat()) m_creature->CombatStop(true, true); Unit* owner = m_creature->GetMaster(); if (!owner) return; if (owner->isInCombat() && !HasReactState(REACT_PASSIVE)) { // Not correct in all cases. // When mob initiate attack by spell, pet should not start attack before spell landed. AttackStart(owner->getAttackerForHelper()); } else if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) { // not following, so start follow if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW)) m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); // update when not in combat UpdatePetOOCAI(diff); } } }
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGUID) { Unit* pCaster = m_creature; if (uiCastFlags & CAST_FORCE_TARGET_SELF) pCaster = pTarget; // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS))) { if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell)) { // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them if (uiCastFlags & CAST_AURA_NOT_PRESENT) { if (pTarget->HasAura(uiSpell)) return CAST_FAIL_TARGET_AURA; } // Check if cannot cast spell if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST))) { CanCastResult castResult = CanCastSpell(pTarget, pSpell, !!(uiCastFlags & CAST_TRIGGERED)); if (castResult != CAST_OK) return castResult; } // Interrupt any previous spell if (uiCastFlags & CAST_INTERRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false)) pCaster->InterruptNonMeleeSpells(false); // Creature should always stop before it will cast a new spell (logic applies to combat movement only) if (pCaster->isInCombat()) pCaster->StopMoving(); pCaster->CastSpell(pTarget, pSpell, !!(uiCastFlags & CAST_TRIGGERED), nullptr, nullptr, uiOriginalCasterGUID); return CAST_OK; } else { sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell); return CAST_FAIL_OTHER; } } else return CAST_FAIL_IS_CASTING; }
void WaypointReached(uint32 uiPointId) { switch (uiPointId) { case 0: DoScriptText(EMOTE_WOLF_LIFT_HEAD, me); break; case 2: DoScriptText(EMOTE_WOLF_HOWL, me); break; case 50: if (pRyga && pRyga->isAlive() && !pRyga->isInCombat()) DoScriptText(SAY_WOLF_WELCOME, pRyga); break; } }
void UpdateAI(const uint32 diff) { /* if(Unit *Vorpil = Unit::GetUnit(*me, VorpilGUID)) { me->DealDamage(me, me->GetMaxHealth(), DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } */ if(move < diff) { Unit *Vorpil = Unit::GetUnit(*me, VorpilGUID); if(!Vorpil) return; if(sacrificed) { Vorpil->CastSpell(Vorpil, HeroicMode?H_SPELL_EMPOWERING_SHADOWS:SPELL_EMPOWERING_SHADOWS, true); DoCast(me, SPELL_SHADOW_NOVA, true); //me->DealDamage(me, me->GetMaxHealth(), DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); me->setDeathState(JUST_DIED); me->RemoveCorpse(); return; } me->GetMotionMaster()->MoveFollow(Vorpil,0,0); me->SetSpeed(MOVE_RUN, 0.3f, true); if(me->IsWithinDistInMap(Vorpil, 3)) { DoCast(me, SPELL_SACRIFICE, false); sacrificed = true; move = 500; return; } if(!Vorpil->isInCombat() || Vorpil->isDead()) { me->DealDamage(me, me->GetMaxHealth(), DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); return; } move = 1000; } else move -= diff; }
void GuardianAI::UpdateAI(const uint32 diff) { Unit* owner = m_creature->GetOwner(); if (!owner) return; switch (m_reactState) { case REACT_AGGRESSIVE: case REACT_DEFENSIVE: if (!m_creature->isInCombat() && owner->isInCombat()) AttackStart(owner->getAttackerForHelper()); // check for getAttackerForHelper() == nullpter in AttackStart() break; default: break; } CreatureEventAI::UpdateAI(diff); }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && (!m_creature->getVictim() || (m_creature->IsPet() && m_creature->GetCharmInfo()->HasState(CHARM_STATE_ACTION,ACTIONS_DISABLE)))) _stopAttack(); // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim()); if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (!m_creature->getVictim()->isAlive()) // Stop attack if target dead { m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } else if (m_creature->IsStopped() || meleeReach) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (DoMeleeAttackIfReady()) { if (!m_creature->getVictim()) return; //if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } } else if (owner && m_creature->GetCharmInfo()) { if (owner->isInCombat() && !(m_creature->GetCharmInfo()->HasState(CHARM_STATE_REACT,REACT_PASSIVE) || m_creature->GetCharmInfo()->HasState(CHARM_STATE_COMMAND,COMMAND_STAY))) { AttackStart(owner->getAttackerForHelper()); } else if(m_creature->GetCharmInfo()->HasState(CHARM_STATE_COMMAND,COMMAND_FOLLOW)) { if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW) ) { m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->IsPet() ? ((Pet*)m_creature)->GetPetFollowAngle() : PET_FOLLOW_ANGLE); } } } // Autocast (casted only in combat or persistent spells in any state) if (!m_creature->IsNonMeleeSpellCasted(false) && !m_creature->GetObjectGuid().IsVehicle()) { typedef std::vector<std::pair<ObjectGuid, uint32> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { // allow only spell without spell cost or with spell cost but not duration limit int32 duration = GetSpellDuration(spellInfo); if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } } else { // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } if (inCombat && m_creature->getVictim() && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && CanAutoCast(m_creature->getVictim(), spellInfo)) { targetSpellStore.push_back(TargetSpellList::value_type(m_creature->getVictim()->GetObjectGuid(), spellInfo->Id)); continue; } else { for (AllySet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_creature->GetMap()->GetUnit(*tar); //only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (CanAutoCast(Target, spellInfo)) { targetSpellStore.push_back(TargetSpellList::value_type(Target->GetObjectGuid(), spellInfo->Id)); break; } } } } //found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); uint32 spellId = targetSpellStore[index].second; ObjectGuid targetGuid = targetSpellStore[index].first; if (Unit* target = m_creature->GetMap()->GetUnit(targetGuid)) { m_creature->DoPetCastSpell(target, spellId); } targetSpellStore.erase(targetSpellStore.begin() + index); } targetSpellStore.clear(); } }
void PetAI::UpdateAI(const uint32 diff) { if (!me->isAlive()) return; Unit* owner = me->GetCharmerOrOwner(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; // me->getVictim() can't be used for check in case stop fighting, me->getVictim() clear at Unit death etc. if (me->getVictim()) { // is only necessary to stop casting, the pet must not exit combat if (me->getVictim()->HasCrowdControlAura(me)) { me->InterruptNonMeleeSpellsExcept(false, 90337); // hack for Bad Manner return; } if (_needToStop()) { sLog->outDebug(LOG_FILTER_GENERAL, "Pet AI stopped attacking [guid=%u]", me->GetGUIDLow()); _stopAttack(); return; } if (owner && !owner->isInCombat()) owner->SetInCombatWith(me->getVictim()); DoMeleeAttackIfReady(); } else if (owner && me->GetCharmInfo()) //no victim { // Only aggressive pets do target search every update. // Defensive pets do target search only in these cases: // * Owner attacks something - handled by OwnerAttacked() // * Owner receives damage - handled by OwnerDamagedBy() // * Pet is in combat and current target dies - handled by KilledUnit() if (me->HasReactState(REACT_AGGRESSIVE)) { Unit* nextTarget = SelectNextTarget(); if (nextTarget) AttackStart(nextTarget); else HandleReturnMovement(); } else HandleReturnMovement(); } else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); if (!me->GetCharmInfo()) return; // Autocast (casted only in combat or persistent spells in any state) if (!me->HasAura(130201)) // stampede cannot auto cast spells if (!me->HasUnitState(UNIT_STATE_CASTING)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i) { uint32 spellID = me->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); if (!spellInfo) continue; if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; if (spellInfo->IsPositive()) { if (spellInfo->CanBeUsedInCombat()) { // check spell cooldown if (me->HasSpellCooldown(spellInfo->Id)) continue; // Check if we're in combat or commanded to attack if (!me->isInCombat() && !me->GetCharmInfo()->IsCommandAttack()) continue; } Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0); bool spellUsed = false; // Some spells can target enemy or friendly (DK Ghoul's Leap) // Check for enemy first (pet then owner) Unit* target = me->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 = ObjectAccessor::GetUnit(*me, *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) delete spell; } else if (me->getVictim() && CanAttack(me->getVictim()) && spellInfo->CanBeUsedInCombat()) { Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0); if (spell->CanAutoCast(me->getVictim())) targetSpellStore.push_back(std::make_pair(me->getVictim(), spell)); else delete spell; } } //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 (!me->HasInArc(M_PI, target)) { me->SetInFront(target); if (target && target->GetTypeId() == TYPEID_PLAYER) me->SendUpdateToPlayer(target->ToPlayer()); if (owner && owner->GetTypeId() == TYPEID_PLAYER) me->SendUpdateToPlayer(owner->ToPlayer()); } me->AddCreatureSpellCooldown(spell->m_spellInfo->Id); spell->prepare(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } // Update speed as needed to prevent dropping too far behind and despawning // This not need to call every update. //me->UpdateSpeed(MOVE_RUN, true); //me->UpdateSpeed(MOVE_WALK, true); //me->UpdateSpeed(MOVE_FLIGHT, true); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (me->getVictim() && me->isAlive()) { //Check for Frost Bolt if (FrostBolt_Timer <= diff) { DoCast(me->getVictim(),SPELL_FROST_BOLT); //Cast again on time FrostBolt_Timer = (rand()%60)*1000; } else FrostBolt_Timer -= diff; //Check for Frost Bolt Nova if (FrostBoltNova_Timer <= diff) { DoCast(me->getVictim(),SPELL_FROST_BOLT_NOVA); FrostBoltNova_Timer = 15000; } else FrostBoltNova_Timer -= diff; //Check for Chains Of Kelthuzad if (ChainsOfKelthuzad_Timer <= diff) { //DoCast(me->getVictim(),SPELL_CHAINS_OF_KELTHUZAD); //if (rand()%2 == 0) //DoScriptText(SAY_CHAIN1, me); //else //DoScriptText(SAY_CHAIN2, me); ChainsOfKelthuzad_Timer = (rand()%30+30)*1000; } else ChainsOfKelthuzad_Timer -= diff; //Check for Mana Detonation if (ManaDetonation_Timer <= diff) { //time to cast DoCast(me->getVictim(),SPELL_MANA_DETONATION); if (rand()%2) DoScriptText(SAY_SPECIAL1_MANA_DET, me); ManaDetonation_Timer = 20000; } else ManaDetonation_Timer -= diff; //Check for Shadow Fissure if (ShadowFisure_Timer <= diff) { DoCast(me->getVictim(),SPELL_SHADOW_FISURE); if (rand()%2) DoScriptText(SAY_SPECIAL3_MANA_DET, me); ShadowFisure_Timer = 25000; } else ShadowFisure_Timer -= diff; //Check for Frost Blast if (FrostBlast_Timer <= diff) { //time to cast DoCast(me->getVictim(),SPELL_FROST_BLAST); if (rand()%2 == 0) DoScriptText(SAY_FROST_BLAST, me); FrostBlast_Timer = (rand()%30+30)*1000; } else FrostBlast_Timer -= diff; //start phase 3 when we are 40% health if (!Phase3 && (me->GetHealth()*100 / me->GetMaxHealth()) < 40) { Phase3 = true; DoScriptText(SAY_REQUEST_AID, me); //here Lich King should respond to KelThuzad but I don't know which creature to make talk //so for now just make Kelthuzad says it. DoScriptText(SAY_ANSWER_REQUEST, me); } if (Phase3 && (GuardiansOfIcecrown_Count < 5)) { if (GuardiansOfIcecrown_Timer <= diff) { //Summon a Guardian of Icecrown in a random alcove (Creature # 16441) //uint32 TimeToWalk; Unit* pUnit = NULL; float Walk_Pos_X; float Walk_Pos_Y; float Walk_Pos_Z; switch (rand()%6) { case 0: pUnit = me->SummonCreature(16441,ADDX_LEFT_FAR,ADDY_LEFT_FAR,ADDZ_LEFT_FAR,ADDO_LEFT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Setting walk position Walk_Pos_X = WALKX_LEFT_FAR; Walk_Pos_Y = WALKY_LEFT_FAR; Walk_Pos_Z = WALKZ_LEFT_FAR; break; case 1: pUnit = me->SummonCreature(16441,ADDX_LEFT_MIDDLE,ADDY_LEFT_MIDDLE,ADDZ_LEFT_MIDDLE,ADDO_LEFT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Start moving guardian towards the center of the room Walk_Pos_X = WALKX_LEFT_MIDDLE; Walk_Pos_Y = WALKY_LEFT_MIDDLE; Walk_Pos_Z = WALKZ_LEFT_MIDDLE; break; case 2: pUnit = me->SummonCreature(16441,ADDX_LEFT_NEAR,ADDY_LEFT_NEAR,ADDZ_LEFT_NEAR,ADDO_LEFT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Start moving guardian towards the center of the room Walk_Pos_X = WALKX_LEFT_NEAR; Walk_Pos_Y = WALKY_LEFT_NEAR; Walk_Pos_Z = WALKZ_LEFT_NEAR; break; case 3: pUnit = me->SummonCreature(16441,ADDX_RIGHT_FAR,ADDY_RIGHT_FAR,ADDZ_RIGHT_FAR,ADDO_RIGHT_FAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Start moving guardian towards the center of the room Walk_Pos_X = WALKX_RIGHT_FAR; Walk_Pos_Y = WALKY_RIGHT_FAR; Walk_Pos_Z = WALKZ_RIGHT_FAR; break; case 4: pUnit = me->SummonCreature(16441,ADDX_RIGHT_MIDDLE,ADDY_RIGHT_MIDDLE,ADDZ_RIGHT_MIDDLE,ADDO_RIGHT_MIDDLE,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Start moving guardian towards the center of the room Walk_Pos_X = WALKX_RIGHT_MIDDLE; Walk_Pos_Y = WALKY_RIGHT_MIDDLE; Walk_Pos_Z = WALKZ_RIGHT_MIDDLE; break; case 5: pUnit = me->SummonCreature(16441,ADDX_RIGHT_NEAR,ADDY_RIGHT_NEAR,ADDZ_RIGHT_NEAR,ADDO_RIGHT_NEAR,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,1000); //Start moving guardian towards the center of the room Walk_Pos_X = WALKX_RIGHT_NEAR; Walk_Pos_Y = WALKY_RIGHT_NEAR; Walk_Pos_Z = WALKZ_RIGHT_NEAR; break; } if (pUnit) { //if we find no one to figth walk to the center if (!pUnit->isInCombat()) pUnit->SendMonsterMoveWithSpeed(Walk_Pos_X,Walk_Pos_Y,Walk_Pos_Z,MOVEFLAG_WALK_MODE); //Safe storing of creatures GuardiansOfIcecrown[GuardiansOfIcecrown_Count] = pUnit->GetGUID(); //Update guardian count GuardiansOfIcecrown_Count++; } //5 seconds until summoning next guardian GuardiansOfIcecrown_Timer = 5000; } else GuardiansOfIcecrown_Timer -= diff; } DoMeleeAttackIfReady(); } }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (me->getVictim() && me->isAlive()) { if (!CombatStart) { //At combat Start Mandokir is mounted so we must unmount it first me->Dismount(); //And summon his raptor me->SummonCreature(14988, me->getVictim()->GetPositionX(), me->getVictim()->GetPositionY(), me->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); CombatStart = true; } if (Watch_Timer <= diff) //Every 20 Sec Mandokir will check this { if (WatchTarget) //If someone is watched and If the Position of the watched target is different from the one stored, or are attacking, mandokir will charge him { Unit* unit = Unit::GetUnit(*me, WatchTarget); if (unit && ( targetX != unit->GetPositionX() || targetY != unit->GetPositionY() || targetZ != unit->GetPositionZ() || unit->isInCombat())) { if (me->IsWithinMeleeRange(unit)) { DoCast(unit, 24316); } else { DoCast(unit, SPELL_CHARGE); //me->SendMonsterMove(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), 0, true, 1); AttackStart(unit); } } } someWatched = false; Watch_Timer = 20000; } else Watch_Timer -= diff; if ((Watch_Timer < 8000) && !someWatched) //8 sec(cast time + expire time) before the check for the watch effect mandokir will cast watch debuff on a random target { if (Unit* p = SelectTarget(SELECT_TARGET_RANDOM, 0)) { DoScriptText(SAY_WATCH, me, p); DoCast(p, SPELL_WATCH); WatchTarget = p->GetGUID(); someWatched = true; endWatch = true; } } if ((Watch_Timer < 1000) && endWatch) //1 sec before the debuf expire, store the target position { Unit* unit = Unit::GetUnit(*me, WatchTarget); if (unit) { targetX = unit->GetPositionX(); targetY = unit->GetPositionY(); targetZ = unit->GetPositionZ(); } endWatch = false; } if (!someWatched) { //Cleave if (Cleave_Timer <= diff) { DoCast(me->getVictim(), SPELL_CLEAVE); Cleave_Timer = 7000; } else Cleave_Timer -= diff; //Whirlwind if (Whirlwind_Timer <= diff) { DoCast(me, SPELL_WHIRLWIND); Whirlwind_Timer = 18000; } else Whirlwind_Timer -= diff; //If more then 3 targets in melee range mandokir will cast fear if (Fear_Timer <= diff) { TargetInRange = 0; std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); for (; i != me->getThreatManager().getThreatList().end(); ++i) { Unit* unit = Unit::GetUnit(*me, (*i)->getUnitGuid()); if (unit && me->IsWithinMeleeRange(unit)) ++TargetInRange; } if (TargetInRange > 3) DoCast(me->getVictim(), SPELL_FEAR); Fear_Timer = 4000; } else Fear_Timer -=diff; //Mortal Strike if target below 50% hp if (me->getVictim() && me->getVictim()->HealthBelowPct(50)) { if (MortalStrike_Timer <= diff) { DoCast(me->getVictim(), SPELL_MORTAL_STRIKE); MortalStrike_Timer = 15000; } else MortalStrike_Timer -= diff; } } //Checking if Ohgan is dead. If yes Mandokir will enrage. if (Check_Timer <= diff) { if (instance) { if (instance->GetData(DATA_OHGAN) == DONE) { if (!RaptorDead) { DoCast(me, SPELL_ENRAGE); RaptorDead = true; } } } Check_Timer = 1000; } else Check_Timer -= diff; DoMeleeAttackIfReady(); } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); if(m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && !m_creature->getVictim()) _stopAttack(); // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { if (_needToStop()) { DEBUG_LOG("Pet AI stoped attacking [guid=%u]", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (m_creature->IsStopped() || m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (m_creature->isAttackReady() && m_creature->canReachWithAttack(m_creature->getVictim())) { m_creature->AttackerStateUpdate(m_creature->getVictim()); m_creature->resetAttackTimer(); if (!m_creature->getVictim()) return; //if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature,0.0f); if( _needToStop() ) _stopAttack(); } } } else if (owner && m_creature->GetCharmInfo()) { if (owner->isInCombat() && !(m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY))) { AttackStart(owner->getAttackerForHelper()); } else if(m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) { if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW) ) { m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); } } } if (m_creature->GetGlobalCooldown() == 0 && !m_creature->IsNonMeleeSpellCasted(false)) { //Autocast for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); i++) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { if (!IsPositiveSpell(spellInfo->Id)) continue; } else { if (IsNonCombatSpell(spellInfo)) continue; } Spell *spell = new Spell(m_creature, spellInfo, false, 0); if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim())) { m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell)); continue; } else { bool spellUsed = false; for(std::set<uint64>::iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = ObjectAccessor::GetUnit(*m_creature,*tar); //only buff targets that are in combat, unless the spell can only be cast while out of combat if(!Target) continue; if(spell->CanAutoCast(Target)) { m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell)); spellUsed = true; break; } } if (!spellUsed) delete spell; } } //found units to cast on to if (!m_targetSpellStore.empty()) { uint32 index = urand(0, m_targetSpellStore.size() - 1); Spell* spell = m_targetSpellStore[index].second; Unit* target = m_targetSpellStore[index].first; m_targetSpellStore.erase(m_targetSpellStore.begin() + index); SpellCastTargets targets; targets.setUnitTarget( target ); if (!m_creature->HasInArc(M_PI, target)) { m_creature->SetInFront(target); if (target->GetTypeId() == TYPEID_PLAYER) m_creature->SendUpdateToPlayer((Player*)target); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_creature->SendUpdateToPlayer( (Player*)owner ); } m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id); if (m_creature->isPet()) ((Pet*)m_creature)->CheckLearning(spell->m_spellInfo->Id); spell->prepare(&targets); } while (!m_targetSpellStore.empty()) { delete m_targetSpellStore.begin()->second; m_targetSpellStore.erase(m_targetSpellStore.begin()); } } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_unit->isAlive()) return; Creature* creature = (m_unit->GetTypeId() == TYPEID_UNIT) ? static_cast<Creature*>(m_unit) : nullptr; Pet* pet = (creature && creature->IsPet()) ? static_cast<Pet*>(m_unit) : nullptr; Unit* owner = m_unit->GetMaster(); if (!owner) return; Unit* victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && !victim) { m_unit->AttackStop(true, true); inCombat = false; } CharmInfo* charminfo = m_unit->GetCharmInfo(); MANGOS_ASSERT(charminfo); if (charminfo->GetIsRetreating()) { if (!owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2))) { if (!m_unit->hasUnitState(UNIT_STAT_FOLLOW)) m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); return; } else charminfo->SetIsRetreating(); } else if (charminfo->GetSpellOpener() != 0) // have opener stored { uint32 minRange = charminfo->GetSpellOpenerMinRange(); if (!(victim = m_unit->getVictim()) || (minRange != 0 && m_unit->IsWithinDistInMap(victim, minRange))) charminfo->SetSpellOpener(); else if (m_unit->IsWithinDistInMap(victim, charminfo->GetSpellOpenerMaxRange()) && m_unit->IsWithinLOSInMap(victim)) { // stop moving m_unit->clearUnitState(UNIT_STAT_MOVING); // auto turn to target m_unit->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)victim); if (owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); uint32 spell_id = charminfo->GetSpellOpener(); SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spell_id); Spell* spell = new Spell(m_unit, spellInfo, false); SpellCastResult result = spell->CheckPetCast(victim); if (result == SPELL_CAST_OK) spell->SpellStart(&(spell->m_targets)); else delete spell; charminfo->SetSpellOpener(); } else return; } // Auto cast (casted only in combat or persistent spells in any state) else if (!m_unit->IsNonMeleeSpellCasted(false)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; if (pet) { for (uint8 i = 0; i < pet->GetPetAutoSpellSize(); ++i) { uint32 spellID = pet->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellID); if (!spellInfo) continue; if (!m_unit->IsSpellReady(*spellInfo)) continue; // ignore some combinations of combat state and combat/non combat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this requirements: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { int32 duration = GetSpellDuration(spellInfo); int32 cooldown = GetSpellRecoveryTime(spellInfo); // allow only spell not on cooldown if (cooldown != 0 && duration < cooldown) continue; // not allow instant kill auto casts as full health cost if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_INSTAKILL)) continue; } } // just ignore non-combat spells else if (IsNonCombatSpell(spellInfo)) continue; Spell* spell = new Spell(m_unit, spellInfo, false); if (inCombat && !m_unit->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(victim)) { targetSpellStore.push_back(TargetSpellList::value_type(victim, spell)); continue; } else { bool spellUsed = false; for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_unit->GetMap()->GetUnit(*tar); // only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (spell->CanAutoCast(Target)) { targetSpellStore.push_back(TargetSpellList::value_type(Target, spell)); spellUsed = true; break; } } if (!spellUsed) delete spell; } } } // 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_unit->HasInArc(M_PI_F, target)) { m_unit->SetInFront(target); if (target->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)target); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); } spell->SpellStart(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } // Stop here if casting spell (No melee and no movement) if (m_unit->IsNonMeleeSpellCasted(false)) return; // we may get our actions disabled during spell casting, so do entire recheck for victim victim = (pet && pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) ? nullptr : m_unit->getVictim(); if (victim) { // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. // This is needed for charmed creatures, as once their target was reset other effects can trigger threat if (!victim->isTargetableForAttack()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_unit->GetGUIDLow()); m_unit->CombatStop(); inCombat = false; return; } // if pet misses its target, it will also be the first in threat list if ((!creature || !(creature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE)) && m_unit->CanReachWithMeleeAttack(victim)) { if (!m_unit->HasInArc(2 * M_PI_F / 3, victim)) { m_unit->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)victim); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_unit->SendCreateUpdateToPlayer((Player*)owner); } DoMeleeAttackIfReady(); } else if (!m_unit->hasUnitState(UNIT_STAT_MOVING)) AttackStart(victim); } else if (owner) { CharmInfo* charmInfo = m_unit->GetCharmInfo(); if (owner->isInCombat() && !(charmInfo && charmInfo->HasReactState(REACT_PASSIVE))) AttackStart(owner->getAttackerForHelper()); else { if (charmInfo && charmInfo->HasCommandState(COMMAND_STAY)) { //if stay command is set but we don't have stay pos set then we need to establish current pos as stay position if (!charminfo->IsStayPosSet()) charminfo->SetStayPosition(true); float stayPosX = charminfo->GetStayPosX(); float stayPosY = charminfo->GetStayPosY(); float stayPosZ = charminfo->GetStayPosZ(); if (m_unit->GetPositionX() == stayPosX && m_unit->GetPositionY() == stayPosY && m_unit->GetPositionZ() == stayPosZ) { float StayPosO = charminfo->GetStayPosO(); if (m_unit->hasUnitState(UNIT_STAT_MOVING)) { m_unit->GetMotionMaster()->Clear(false); m_unit->GetMotionMaster()->MoveIdle(); } else if (m_unit->GetOrientation() != StayPosO) m_unit->SetOrientation(StayPosO); } else m_unit->GetMotionMaster()->MovePoint(0, stayPosX, stayPosY, stayPosZ, false); } else if (m_unit->hasUnitState(UNIT_STAT_FOLLOW)) { if (owner->IsWithinDistInMap(m_unit, PET_FOLLOW_DIST)) { m_unit->GetMotionMaster()->Clear(false); m_unit->GetMotionMaster()->MoveIdle(); } } else if (charmInfo && charmInfo->HasCommandState(COMMAND_FOLLOW) && !owner->IsWithinDistInMap(m_unit, (PET_FOLLOW_DIST * 2))) m_unit->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } }
void PlayerbotMageAI::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); #pragma region Choose Actions // Choose actions accoring to talents (MAGE is always ranged dps) m_role = BOT_ROLE_DPS_RANGED; // if i am under attack and if i am not tank or offtank: change target if needed if (isUnderAttack()) { // Keep hitting but reduce threat //else if (m_bot->getRace() == (uint8) RACE_NIGHTELF && CastSpell(R_SHADOWMELD,m_bot)) { return; } 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()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } #pragma endregion TakePosition(pTarget); // If there's a cast stop if (m_bot->HasUnitState(UNIT_STAT_CASTING)) { return; } if (DoSupportRaid(m_bot,30,0,0,0,1,1)) { return; } if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { //if (CastSpell(INVISIBILITY, m_bot)) { return; } if (ai->GetHealthPercent(*pTarget) > 50 && CastSpell(POLYMORPH)) { return; } //if (m_bot->getRace() == (uint8) RACE_NIGHTELF && isUnderAttack() && CastSpell(R_SHADOWMELD, m_bot)) { return; } } if (isUnderAttack() && pDist > 5 && CastSpell(FROST_NOVA, pTarget)) { return; } if (DEEP_FREEZE && pTarget->isFrozen() && CastSpell(DEEP_FREEZE,pTarget)) { return; } if (isUnderAttack() && CastSpell(DRAGONS_BREATH, pTarget)) { return; } if ((isUnderAttack() || ai->GetHealthPercent() < 75 && !HasAuraName(m_bot, MANA_SHIELD)) && ai->GetManaPercent() > 40 && CastSpell(MANA_SHIELD,m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_DWARF && ai->GetHealthPercent() < 75 && CastSpell(R_STONEFORM,m_bot)) { } //no gcd if (m_bot->getRace() == (uint8) RACE_DRAENEI && ai->GetHealthPercent() < 55 && CastSpell(R_GIFT_OF_NAARU,m_bot)) { return; } //no Gcd, but has cast if (m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //no gcd but is cast if ((ai->GetHealthPercent() < 65 || ai->GetManaPercent() < 5) && CastSpell(ICE_BLOCK,m_bot)) { return; } if (isUnderAttack() && CastSpell(ICE_BARRIER, pTarget)) { return; } if (ai->GetManaPercent() < 30 && CastSpell (EVOCATION, m_bot)) { return; } //Break spells if (m_bot->getRace() == (uint8) RACE_BLOODELF && pDist < 8 && (pTarget->IsNonMeleeSpellCasted(true) || ai->GetManaPercent() < 40) && CastSpell(R_ARCANE_TORRENT, pTarget)) { } //no gcd else if (pThreat < threatThreshold && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(COUNTER_SPELL, pTarget)) { return; } //High threat if (!m_bot->HasAura(MOLTEN_ARMOR) && CastSpell(MOLTEN_ARMOR,m_bot)) { return; } if (ai->GetHealthPercent(*pTarget) > 96) { return; } // dont dps too early //Catch if (pTarget->HasUnitMovementFlag(UNIT_FLAG_FLEEING)) { if (CastSpell(FROST_NOVA,pTarget)) return; if (CastSpell(FROSTBOLT,pTarget)) return; } // If at threat limit, try 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(INVISIBILITY,m_bot)) { return; } //Lets see if we can manage else if (m_bot->FindCurrentSpellBySpellId(SHOOT)) { m_bot->InterruptNonMeleeSpells( true, SHOOT ); return; } //Disable wand else { return; } //use no spells and wait threat to be reduced } } // buff up if (CastSpell(ICY_VEINS,m_bot)) {} //nogcd 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 (CastSpell(POM,m_bot)) {} //nogcd if (TALENT_ARCANE) { if (CastSpell(ARCANE_POWER,m_bot)) {} //nogcd if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(BLIZZARD,pTarget)) { return; } } //DPS if (ARCANE_BLAST) { Aura *abaura = m_bot->GetAura(P_ARCANE_BLAST); if (abaura && abaura->GetStackAmount() >= 3) { if (m_bot->HasAura(P_MISSILE_BARRAGE) && CastSpell(ARCANE_MISSILES,pTarget)) { return; } else if (CastSpell(ARCANE_BARRAGE,pTarget)) { return; } } } if (CastSpell(ARCANE_BARRAGE,pTarget) ) { return; } } if (TALENT_FIRE) { if (CastSpell(COMBUSTION,m_bot)) { } //nogcd if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(FLAMESTRIKE,pTarget)) { return; } if (CastSpell(BLAST_WAVE,pTarget)) { return; } if (CastSpell(LIVING_BOMB,pTarget)) { return; } if (CastSpell(DRAGONS_BREATH,pTarget)) { return; } } //DPS if (m_bot->HasAura(P_HOT_STREAK) && CastSpell(PYROBLAST,pTarget)) { return; } if (!pTarget->HasAura(LIVING_BOMB,m_bot->GetGUID()) && CastSpell(LIVING_BOMB,pTarget)) { return; } //if (!pTarget->HasAura(IMP_SCORCH) && CastSpell(SCORCH,pTarget)) { return; } if (CastSpell(FIREBALL,pTarget)) { return; } } if (TALENT_FROST) { if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } if (CastSpell(WATER_ELEMENTAL,m_bot)) { return; } uint64 pet_guid = m_bot->GetPetGUID(); if (pet_guid>0){ Pet* pet = ObjectAccessor::GetPet(*m_bot, pet_guid); Unit *unit = ObjectAccessor::GetUnit(*m_bot, pet_guid); if (unit!=NULL){ if (!unit->isInCombat()) { m_bot->GetSession()->HandlePetActionHelper(unit, pet_guid, COMMAND_ATTACK, ACT_COMMAND, pTarget->GetGUID()); } } } //if (CastSpell(33395, pTarget)) // pet freeze spell // sLog.outError ("successfully casted freeze"); //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(BLIZZARD,pTarget)) { return; } } //DPS if (m_bot->HasAura(P_FINGERS_OF_FROST) && CastSpell(DEEP_FREEZE,pTarget)) { return; } if (m_bot->HasAura(P_BRAIN_FREEZE) && CastSpell(FROSTFIRE_BOLT,pTarget)) { return; } if (CastSpell(FROSTBOLT,pTarget,true,true)) { return; } } // Defaults especialy for lower levels if (m_bot->HasAura(P_BRAIN_FREEZE) && CastSpell(FIREBALL,pTarget,1,1)) { return; } if (m_bot->HasAura(P_FIRESTARTER) && CastSpell(FLAMESTRIKE,pTarget,1,1)) { return; } if (m_bot->HasAura(P_HOT_STREAK) && CastSpell(PYROBLAST,pTarget,1,1)) { return; } if (m_bot->HasAura(POM) && (CastSpell(PYROBLAST,pTarget,1,1) || CastSpell(FIREBALL,pTarget,1,1) || CastSpell(FROSTBOLT,pTarget,1,1))) { return; } if (pTarget->isFrozen() && CastSpell(ICE_LANCE,pTarget)) { return; } if (m_bot->isMoving() && (CastSpell(FIRE_BLAST,pTarget,1,1) || CastSpell(ARCANE_BARRAGE,pTarget) || CastSpell(ICE_LANCE,pTarget))) { return; } if (CastSpell(FIREBALL,pTarget)) { return; } if (CastSpell(FROSTBOLT,pTarget)) { return; } if (CastSpell(ARCANE_MISSILES,pTarget)) { return; } // drink potion if(ai->GetManaPercent() < 5 ) { Item *pItem = ai->FindPotion(); if(pItem != NULL) { if (pItem->GetSpell() && m_bot->HasSpellCooldown(pItem->GetSpell()) ) { return; } //pot is in cooldown ai->UseItem(*pItem); } } // if we get down here, it means we are out of mana, so use wand CastSpell(SHOOT, pTarget); } //end DoNextCombatManeuver
void UpdateEscortAI(const uint32 diff) { if (!m_pInstance) return; Unit* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; EventStarter = pPlayer; Creature* Naralex = m_creature->GetMap()->GetCreature(m_pInstance->GetData64(DATA_NARALEX)); if (!Naralex) return; if (Event_Timer && Event_Timer <= diff) { switch (Point) { case 0: { Debug(Point); Map *map = m_creature->GetMap(); if (map && map->IsDungeon()) { Map::PlayerList const &PlayerList = map->GetPlayers(); if (!PlayerList.isEmpty()) { for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { if (i->getSource()->isAlive() && (i->getSource()->GetDistance(m_creature)<30)) m_creature->CastSpell(i->getSource(),SPELL_MARK,false); } } } SetEscortPaused(false); Event_Timer = 0; break; } case 1: Debug(Point); SetEscortPaused(false); Event_Timer = 0; break; case 15: Debug(Point); switch (Subevent_Phase) { case 0: DoScriptText(SAY_BEFORE_CIRCLE,m_creature); Subevent_Phase = 1; Event_Timer = 2000; break; case 1: m_creature->CastSpell(m_creature,SPELL_CLEANSING,false); Subevent_Phase = 2; Event_Timer = 30000; break; case 2: for (int i=0; i <3; ++i) { SummonAttacker(MOB_DEVIATE_VIPER,PointCoord[i][0],PointCoord[i][1],PointCoord[i][2]); } Subevent_Phase = 3; Event_Timer = 2000; break; case 3: if (!m_creature->isInCombat() && !pPlayer->isInCombat()) { DoScriptText(SAY_AFTER_CIRCLE,m_creature); Point = 16; Event_Timer = 2000; SetEscortPaused(false); break; } else { Event_Timer = 2000; Subevent_Phase = 3; break; } } break; case 30: Debug(Point); SetEscortPaused(true); switch (Subevent_Phase) { case 0: DoScriptText(SAY_BEFORE_RITUAL,m_creature); Subevent_Phase = 1; Event_Timer = 2000; break; case 1: m_creature->CastSpell(m_creature,SPELL_AWAKENING,false); DoScriptText(EMOTE_DISCIPLE_1,m_creature); Subevent_Phase = 2; Event_Timer = 4000; break; case 2: DoScriptText(EMOTE_NARALEX_1, Naralex); Subevent_Phase = 3; Event_Timer = 5000; break; case 3: for (int i = 3; i <6; ++i) { SummonAttacker(MOB_DEVIATE_MOCCASIN, PointCoord[i][0],PointCoord[i][1],PointCoord[i][2]); } Event_Timer = 40000; Subevent_Phase = 4; break; case 4: for (int i = 3; i <10; ++i) { SummonAttacker(MOB_NIGHTMARE_ECTOPLASM, PointCoord[i][0],PointCoord[i][1],PointCoord[i][2]); } Event_Timer = 40000; Subevent_Phase = 5; break; case 5: Subevent_Phase = 6; Event_Timer = 10000; DoScriptText(EMOTE_NARALEX_2,Naralex); DoScriptText(SAY_BEFORE_MUTANOUS,m_creature); break; case 6: SummonAttacker(MOB_MUTANOUS_DEVOURER, PointCoord[4][0],PointCoord[4][1],PointCoord[4][2]); Subevent_Phase = 7; Event_Timer = 2000; break; case 7: if (m_pInstance->GetData(TYPE_MUTANUS) == DONE) { Naralex->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_SIT); DoScriptText(SAY_NARALEX_AWAKEN,Naralex); m_creature->InterruptNonMeleeSpells(false,SPELL_AWAKENING); m_creature->RemoveAurasDueToSpell(SPELL_AWAKENING); m_pInstance->SetData(TYPE_DISCIPLE,DONE); Event_Timer = 2000; Subevent_Phase = 8; break; }else { Event_Timer = 2000; Subevent_Phase = 7; break; } case 8: DoScriptText(SAY_DISCIPLE_FINAL,m_creature); Subevent_Phase = 9; Event_Timer = 5000; break; case 9: DoScriptText(SAY_NARALEX_FINAL1,Naralex); Naralex->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_STAND); Event_Timer = 5000; Subevent_Phase = 10; break; case 10: DoScriptText(SAY_NARALEX_FINAL2,Naralex); m_creature->CastSpell(m_creature,SPELL_SHAPESHIFT,false); Naralex->CastSpell(Naralex,SPELL_SHAPESHIFT,false); Event_Timer = 10000; Subevent_Phase = 11; break; case 11: m_creature->SendMonsterMove(PointCoord[9][0], PointCoord[9][1], PointCoord[9][2], SPLINETYPE_NORMAL, SPLINEFLAG_FLYING, 5000); Naralex->SendMonsterMove(PointCoord[9][0], PointCoord[9][1], PointCoord[9][2], SPLINETYPE_NORMAL, SPLINEFLAG_FLYING, 5000); Event_Timer = 5000; Subevent_Phase = 12; break; case 12: m_creature->SetVisibility(VISIBILITY_OFF); Naralex->SetVisibility(VISIBILITY_OFF); break; } break; default: break; } }else Event_Timer -= diff; if (Potion_Timer < diff) { if ((m_creature->GetHealth()/m_creature->GetMaxHealth())<0.8) m_creature->CastSpell(m_creature, SPELL_POTION, false); Potion_Timer = 45000; } else Potion_Timer -= diff; if (m_creature->SelectHostileTarget() && m_creature->isInCombat() && m_creature->getVictim()) { if (!Yelled) { DoScriptText(SAY_ATTACKED,m_creature,m_creature->getVictim()); Yelled = true; } if (Sleep_Timer < diff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) DoCastSpellIfCan(pTarget, SPELL_SLEEP); Sleep_Timer = 30000; } else Sleep_Timer -= diff; DoMeleeAttackIfReady(); } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); Unit* victim = m_creature->getVictim(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && (!victim || (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS))) _stopAttack(); if (((Pet*)m_creature)->GetIsRetreating()) { if (!owner->_IsWithinDist(m_creature, (PET_FOLLOW_DIST * 2), true)) { if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW)) m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); return; } else ((Pet*)m_creature)->SetIsRetreating(); } else if (((Pet*)m_creature)->GetSpellOpener() != 0) // have opener stored { uint32 minRange = ((Pet*)m_creature)->GetSpellOpenerMinRange(); if (!(victim = m_creature->getVictim()) || (minRange != 0 && m_creature->IsWithinDistInMap(victim, minRange))) ((Pet*)m_creature)->SetSpellOpener(); else if (m_creature->IsWithinDistInMap(victim, ((Pet*)m_creature)->GetSpellOpenerMaxRange()) && m_creature->IsWithinLOSInMap(victim)) { // stop moving m_creature->clearUnitState(UNIT_STAT_MOVING); // auto turn to target m_creature->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)victim); if (owner->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)owner); uint32 spell_id = ((Pet*)m_creature)->GetSpellOpener(); SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id); Spell* spell = new Spell(m_creature, spellInfo, false); SpellCastResult result = spell->CheckPetCast(victim); if (result == SPELL_CAST_OK) { m_creature->AddCreatureSpellCooldown(spell_id); spell->SpellStart(&(spell->m_targets)); } else delete spell; ((Pet*)m_creature)->SetSpellOpener(); } else return; } // Autocast (casted only in combat or persistent spells in any state) else 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 = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { int32 duration = GetSpellDuration(spellInfo); int32 cooldown = GetSpellRecoveryTime(spellInfo); // allow only spell not on cooldown if (cooldown != 0 && duration < cooldown) continue; // not allow instant kill autocasts as full health cost if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_INSTAKILL)) continue; } } // just ignore non-combat spells else if (IsNonCombatSpell(spellInfo)) continue; Spell* spell = new Spell(m_creature, spellInfo, false); if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim())) { targetSpellStore.push_back(TargetSpellList::value_type(m_creature->getVictim(), spell)); continue; } else { bool spellUsed = false; for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_creature->GetMap()->GetUnit(*tar); // only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (spell->CanAutoCast(Target)) { targetSpellStore.push_back(TargetSpellList::value_type(Target, spell)); spellUsed = true; break; } } if (!spellUsed) delete spell; } } // 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); } m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id); if (m_creature->IsPet()) ((Pet*)m_creature)->CheckLearning(spell->m_spellInfo->Id); spell->SpellStart(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } else if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); if (victim = m_creature->getVictim()) { // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); } else if (m_creature->CanReachWithMeleeAttack(victim)) { if (DoMeleeAttackIfReady()) // if pet misses its target, it will also be the first in threat list victim->AddThreat(m_creature); else AttackStart(victim); } } else if (owner && m_creature->GetCharmInfo()) { if (owner->isInCombat() && !(m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY))) { AttackStart(owner->getAttackerForHelper()); } else if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) { // The distance is to prevent the pet from running around to reach the owners back when walking towards it // and the reason for increasing it more than the follow distance is to prevent the same thing // from happening when the owner turns and twists (as this increases the distance between them) if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW) && !owner->IsWithinDistInMap(m_creature, (PET_FOLLOW_DIST * 2))) m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); // This is to stop the pet from following you when you're close to each other, to support the above condition. else if (m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); } } } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (!inCombat && !m_savedTargetGuid.IsEmpty()) { if (Unit* saved_target = m_creature->GetMap()->GetUnit(m_savedTargetGuid)) { if (!saved_target->isAlive()) m_savedTargetGuid.Clear(); else if (!saved_target->IsCrowdControlled()) AttackStart(saved_target); } else m_savedTargetGuid.Clear(); } if (inCombat && (!m_creature->getVictim() || !m_creature->getVictim()->isAlive() || (m_creature->IsPet() && m_creature->GetCharmInfo()->HasState(CHARM_STATE_ACTION,ACTIONS_DISABLE)))) _stopAttack(); if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) { UpdateAIType(); return; } // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim()); if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (!m_creature->getVictim()->isAlive()) // Stop attack if target dead { m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } else if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && IsInCombat() && m_creature->getVictim() && m_creature->getVictim()->IsCrowdControlled()) // Stop attack if target under CC effect { m_savedTargetGuid = m_creature->getVictim()->GetObjectGuid(); m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } else if (m_creature->IsStopped() || meleeReach) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (DoMeleeAttackIfReady()) { if (!m_creature->getVictim()) return; //if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } if (!m_creature->IsNonMeleeSpellCasted(true)) { if ( m_attackDistanceRecheckTimer <= diff) { m_attackDistanceRecheckTimer = TIME_INTERVAL_LOOK; if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType == PET_AI_RANGED) { float dist = m_creature->GetDistance(m_creature->getVictim()); if ((m_creature->CanReachWithMeleeAttack(m_creature->getVictim()) && m_creature->IsWithinDist(m_creature->GetOwner(), m_creature->GetMap()->GetVisibilityDistance()/2.0f)) || dist > (attackDistance + 2.0f)) { MoveToVictim(m_creature->getVictim()); return; } } if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI)) { // AOE check } } else m_attackDistanceRecheckTimer -= diff; } } else if (owner && m_creature->GetCharmInfo()) { if (owner->isInCombat() && owner->getVictim() && owner->getVictim()->isAlive() && !(m_creature->GetCharmInfo()->HasState(CHARM_STATE_REACT,REACT_PASSIVE) || m_creature->GetCharmInfo()->HasState(CHARM_STATE_COMMAND,COMMAND_STAY))) { AttackStart(owner->getAttackerForHelper()); } else m_creature->GetMotionMaster()->MoveTargetedHome(); } UpdateAIType(); if (m_creature->IsNonMeleeSpellCasted(true)) return; // Autocast (casted only in combat or persistent spells in any state) if (!sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType != PET_AI_PASSIVE) { typedef std::vector<std::pair<ObjectGuid, uint32> > TargetSpellList; TargetSpellList targetSpellStore; for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); if (!spellID) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; if (m_creature->HasSpellCooldown(spellInfo->Id)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { // allow only spell without spell cost or with spell cost but not duration limit int32 duration = GetSpellDuration(spellInfo); if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } } else { // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } if (inCombat && m_creature->getVictim() && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && CanAutoCast(m_creature->getVictim(), spellInfo)) { targetSpellStore.push_back(TargetSpellList::value_type(m_creature->getVictim()->GetObjectGuid(), spellInfo->Id)); continue; } else { for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_creature->GetMap()->GetUnit(*tar); //only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (CanAutoCast(Target, spellInfo)) { targetSpellStore.push_back(TargetSpellList::value_type(Target->GetObjectGuid(), spellInfo->Id)); break; } } } } //found units to cast on to if (!targetSpellStore.empty()) { uint32 index = urand(0, targetSpellStore.size() - 1); if (Unit* target = m_creature->GetMap()->GetUnit(targetSpellStore[index].first)) m_creature->DoPetCastSpell(target, targetSpellStore[index].second); } } else { AutoSpellList currentSpells; switch (m_AIType) { case PET_AI_PASSIVE: { currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_SLACKER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || m_creature->GetCharmerOrOwner()->IsCrowdControlled()) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_DEFENCE)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_HEALER: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || m_creature->GetCharmerOrOwner()->IsCrowdControlled()) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); if (m_creature->GetHealth() < m_creature->GetMaxHealth() || m_creature->GetOwner()->GetHealth() < m_creature->GetOwner()->GetMaxHealth()) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); break; } case PET_AI_RANGED: { if (!IsInCombat()) break; if (m_creature->IsCrowdControlled() || m_creature->GetCharmerOrOwner()->IsCrowdControlled()) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } case PET_AI_MELEE: case PET_AI_RANGED_NOAMMO: { if (!IsInCombat()) break; if (Unit* victim = m_creature->getVictim()) { if (!victim->getVictim() || (victim->getVictim()->GetObjectGuid() != m_creature->GetObjectGuid())) { currentSpells.push_back(GetSpellType(PET_SPELL_ATTACKSTART)); currentSpells.push_back(GetSpellType(PET_SPELL_THREAT)); } } if (m_creature->IsCrowdControlled() || m_creature->GetCharmerOrOwner()->IsCrowdControlled()) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); } /* no break here!*/ default: { if (!IsInCombat()) break; currentSpells.push_back(GetSpellType(PET_SPELL_MELEE)); currentSpells.push_back(GetSpellType(PET_SPELL_DEBUFF)); currentSpells.push_back(GetSpellType(PET_SPELL_RANGED)); currentSpells.push_back(GetSpellType(PET_SPELL_BUFF)); break; } } if (!IsInCombat()) { currentSpells.push_back(GetSpellType(PET_SPELL_NONCOMBAT)); if ((m_creature->GetHealth() < m_creature->GetMaxHealth()*0.95f) || m_creature->GetHealth() < m_creature->GetMaxHealth()*0.5f) currentSpells.push_back(GetSpellType(PET_SPELL_HEAL)); } else currentSpells.push_back(GetSpellType(PET_SPELL_SPECIAL)); for (AutoSpellList::const_iterator itr = currentSpells.begin(); itr != currentSpells.end(); ++itr) { uint32 spellID = *itr; if (!spellID) continue; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; Unit* pTarget = m_creature->IsPet() ? ((Pet*)m_creature)->SelectPreferredTargetForSpell(spellInfo) : ((Creature*)m_creature)->SelectPreferredTargetForSpell(spellInfo); bool b_castOk = false; if (pTarget) { SpellCastResult result = CanAutoCast(pTarget, spellInfo); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update %s, AI %u try cast %u Target %s", m_creature->GetObjectGuid().GetString().c_str(), m_AIType, spellID, pTarget ? pTarget->GetObjectGuid().GetString().c_str() : "<none>"); switch (result) { case SPELL_FAILED_UNIT_NOT_INFRONT: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) { b_castOk = true; m_creature->SetInFront(pTarget); if (pTarget->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)pTarget ); } break; } case SPELL_CAST_OK: { if (DoCastSpellIfCan(pTarget, spellID) == CAST_OK) b_castOk = true; break; } default: { Player* owner = (Player*)m_creature->GetOwner(); if (owner && m_creature->HasAuraType(SPELL_AURA_MOD_POSSESS)) Spell::SendCastResult(owner,spellInfo,0,result); else m_creature->SendPetCastFail(spellID, result); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"PetAI::Update cast %s, AI %u Target %s spell %u result %u", m_creature->GetObjectGuid().GetString().c_str(), m_AIType, pTarget ? pTarget->GetObjectGuid().GetString().c_str() : "<none>", spellID, result); break; } } } else continue; if (b_castOk) { m_creature->AddCreatureSpellCooldown(spellID); if (m_creature->IsPet()) { if(((Pet*)m_creature)->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) m_creature->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); else m_creature->SendPetAIReaction(); } break; } } } }
void bot_ai::ResetOrGetNextTarget() { if (master->GetBotMustDie()) return; uint64 targetGUID = 0; // check if anyone has raid target //targetGUID = getTargetWithIcon(); Group *group = master->GetGroup(); targetGUID = group->GetTargetWithIconByGroup (m_creature->GetGUID()); if (targetGUID && targetGUID!=master->GetGUID()) { Unit * target = m_creature->GetCreature(*master, targetGUID); if (target && target->isAlive() && target->IsHostileTo(master) && target->isInCombat() /*&& m_creature->IsWithinDist(target, 30)*/) { BotAttackStart(target); return; } } AttackerSet m_attackers = master->getAttackers(); //check if anyone is attacking master if(gettingAttacked(m_attackers)) return; //check if anyone is attacking me m_attackers = m_creature->getAttackers(); if(gettingAttacked(m_attackers)) return; //check if master has a victim if(master->getVictim() && master->getVictim()->IsHostileTo(master)) { if(m_creature->IsWithinDist(m_creature->getVictim(), 50)) { BotAttackStart(master->getVictim()); return; } } //lastly check a random victim, including bots, pets, etc Unit *target = DoSelectLowestHpFriendly(30); if(target != NULL && target->isAlive() && !target->IsHostileToPlayers()) { m_attackers = target->getAttackers(); if(gettingAttacked(m_attackers)) { return; } } //if there is no one to attack, make sure we are following master if(m_creature->getVictim() == NULL && m_creature->GetCharmInfo()->GetCommandState() != COMMAND_STAY && master->GetDistance(m_creature) > 20 && !master->IsBeingTeleported()) { if (!master->isAlive()) master->SetBotCommandState(COMMAND_STAY); else if (master->GetBotCommandState()==COMMAND_ATTACK) master->SetBotCommandState(prevCommandState); return; } }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (me->getVictim() && me->isAlive()) { if (!CombatStart) { // At combat Start Mandokir is mounted so we must unmount it first me->Unmount(); // And summon his raptor me->SummonCreature(OHGAN, me->getVictim()->GetPositionX(), me->getVictim()->GetPositionY(), me->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); CombatStart = true; } if (Gaze_Timer <= diff) // Every 20 seconds Mandokir will check this { if (GazeTarget) { Unit* pUnit = Unit::GetUnit(*me, GazeTarget); if (pUnit && ( targetX != pUnit->GetPositionX() || targetY != pUnit->GetPositionY() || targetZ != pUnit->GetPositionZ() || pUnit->isInCombat())) { if (me->IsWithinMeleeRange(pUnit)) { DoCast(pUnit, 24316); } else { DoCast(pUnit, SPELL_CHARGE); //me->SendMonsterMove(pUnit->GetPositionX(), pUnit->GetPositionY(), pUnit->GetPositionZ(), 0, true,1); AttackStart(pUnit); } } } someGazed = false; Gaze_Timer = 20000; } else Gaze_Timer -= diff; if (Gaze_Timer < 8000 && !someGazed) // 8 second(cast time + expire time) before the check for the gaze effect Mandokir will cast gaze debuff on a random target { if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { DoScriptText(SAY_GAZE, me, pTarget); DoCast(pTarget, SPELL_GAZE); me->MonsterWhisper(SAY_GAZE_WHISPER, pTarget->GetGUID()); GazeTarget = pTarget->GetGUID(); someGazed = true; endGaze = true; } } if (Gaze_Timer < 1000 && endGaze) // 1 second before the debuff expires, check whether the GazeTarget is in LoS { Unit* pUnit = Unit::GetUnit(*me, GazeTarget); if (pUnit) { targetX = pUnit->GetPositionX(); targetY = pUnit->GetPositionY(); targetZ = pUnit->GetPositionZ(); } endGaze = false; } if (!someGazed) { // Cleave if (Cleave_Timer <= diff) { DoCast(me->getVictim(), SPELL_CLEAVE); Cleave_Timer = 7000; } else Cleave_Timer -= diff; // Whirlwind if (Whirlwind_Timer <= diff) { DoCast(me, SPELL_WHIRLWIND); Whirlwind_Timer = 18000; } else Whirlwind_Timer -= diff; // If more than 3 targets in melee range Mandokir will cast fear if (Fear_Timer <= diff) { TargetInRange = 0; std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); for (; i != me->getThreatManager().getThreatList().end(); ++i) { Unit* pUnit = Unit::GetUnit(*me, (*i)->getUnitGuid()); if (pUnit && me->IsWithinMeleeRange(pUnit)) ++TargetInRange; } if (TargetInRange > 3) DoCast(me->getVictim(), SPELL_FEAR); Fear_Timer = 4000; } else Fear_Timer -=diff; // Mortal Strike if target is below 50% hp if (me->getVictim() && me->getVictim()->GetHealth() < me->getVictim()->GetMaxHealth() * 0.5f) { if (MortalStrike_Timer <= diff) { DoCast(me->getVictim(), SPELL_MORTAL_STRIKE); MortalStrike_Timer = 15000; } else MortalStrike_Timer -= diff; } } // Checking if Ohgan is dead. If yes Mandokir will enrage. if (Check_Timer <= diff) { if (pInstance) { if (pInstance->GetData(TYPE_OHGAN) == DONE) { if (!RaptorDead) { DoCast(me, SPELL_ENRAGE); RaptorDead = true; } } } Check_Timer = 1000; } else Check_Timer -= diff; DoMeleeAttackIfReady(); } }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && (!m_creature->getVictim() || (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS))) _stopAttack(); // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (m_creature->getVictim()) { if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } bool meleeReach = m_creature->CanReachWithMeleeAttack(m_creature->getVictim()); if (m_creature->IsStopped() || meleeReach) { // required to be stopped cases if (m_creature->IsStopped() && m_creature->IsNonMeleeSpellCasted(false)) { if (m_creature->hasUnitState(UNIT_STAT_FOLLOW_MOVE)) m_creature->InterruptNonMeleeSpells(false); else return; } // not required to be stopped case else if (DoMeleeAttackIfReady()) { if (!m_creature->getVictim()) return; // if pet misses its target, it will also be the first in threat list m_creature->getVictim()->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } } else if (owner && m_creature->GetCharmInfo()) { if (owner->isInCombat() && !(m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY))) { AttackStart(owner->getAttackerForHelper()); } else if (m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) { if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } } // 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 = sSpellStore.LookupEntry(spellID); if (!spellInfo) continue; if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) continue; // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; // non combat spells allowed // only pet spells have IsNonCombatSpell and not fit this reqs: // Consume Shadows, Lesser Invisibility, so ignore checks for its if (!IsNonCombatSpell(spellInfo)) { // allow only spell without spell cost or with spell cost but not duration limit int32 duration = GetSpellDuration(spellInfo); SpellPowerEntry const* spellPower = spellInfo->GetSpellPower(); if (spellPower && (spellPower->manaCost || spellPower->ManaCostPercentage || spellPower->manaPerSecond) && duration > 0) continue; // allow only spell without cooldown > duration int32 cooldown = GetSpellRecoveryTime(spellInfo); if (cooldown >= 0 && duration >= 0 && cooldown > duration) continue; } } else { // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } Spell* spell = new Spell(m_creature, spellInfo, false); if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim())) { targetSpellStore.push_back(TargetSpellList::value_type(m_creature->getVictim(), spell)); continue; } else { bool spellUsed = false; for (GuidSet::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar) { Unit* Target = m_creature->GetMap()->GetUnit(*tar); // only buff targets that are in combat, unless the spell can only be cast while out of combat if (!Target) continue; if (spell->CanAutoCast(Target)) { targetSpellStore.push_back(TargetSpellList::value_type(Target, spell)); spellUsed = true; break; } } if (!spellUsed) delete spell; } } // 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); } m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id); spell->prepare(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } }
void UpdateAI(uint32 const diff) { if (!_entered) { if (_enterTimer <= diff) { uint32 spellId = 0; _entered = true; switch (me->GetEntry()) { case NPC_EMERALD_DRAKE: spellId = 49346; break; case NPC_AMBER_DRAKE: spellId = 49460; break; case NPC_RUBY_DRAKE: spellId = 49464; break; } if (!me->ToTempSummon()) return; Unit* summoner = me->ToTempSummon()->GetSummoner(); if (summoner && summoner->isAlive() && summoner->GetDistance(me) < 30.0f && !summoner->isInCombat()) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); summoner->CastSpell(me, spellId, true); } else me->DespawnOrUnsummon(); } else _enterTimer -= diff; } }