void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; switch(stage) { case 0: { timedCast(SPELL_POUND, uiDiff); timedCast(SPELL_COLD, uiDiff); if (timedQuery(SUMMON_BORROWER, uiDiff)) { doCast(SUMMON_BORROWER); DoScriptText(-1713556,m_creature); }; if (timedQuery(SPELL_SUBMERGE_0, uiDiff)) stage = 1; break;} case 1: { doCast(SPELL_SUBMERGE_0); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); stage = 2; DoScriptText(-1713557,m_creature); break;} case 2: { if (timedQuery(SPELL_SPIKE_CALL, uiDiff)) { pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); // doCast(SPELL_SPIKE_CALL); // This summon not supported in database. Temporary override. Unit* spike = doSummon(NPC_SPIKE,TEMPSUMMON_TIMED_DESPAWN,60000); if (spike) { spike->AddThreat(pTarget, 1000.0f); DoScriptText(-1713558,m_creature,pTarget); doCast(SPELL_MARK,pTarget); spike->GetMotionMaster()->MoveChase(pTarget); } }; if (timedQuery(SPELL_SUMMON_BEATLES, uiDiff)) { doCast(SPELL_SUMMON_BEATLES); doCast(SUMMON_SCARAB); DoScriptText(-1713560,m_creature); }; if (timedQuery(SPELL_SUBMERGE_0, uiDiff)) stage = 3; break;} case 3: { stage = 0; DoScriptText(-1713559,m_creature); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); doRemove(SPELL_SUBMERGE_0,m_creature); break;} case 4: { doCast(SPELL_LEECHING_SWARM); DoScriptText(-1713561,m_creature); stage = 5; break;} case 5: { timedCast(SPELL_POUND, uiDiff); timedCast(SPELL_COLD, uiDiff); break;} } timedCast(SUMMON_FROSTSPHERE, uiDiff); timedCast(SPELL_BERSERK, uiDiff); if (m_creature->GetHealthPercent() < 30.0f && stage == 0) stage = 4; DoMeleeAttackIfReady(); }
void UpdateAI(uint32 diff) override { _events.Update(diff); if (UpdateVictim()) { while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_FROST_SHOCK: DoCastVictim(SPELL_FROST_SHOCK); _events.DelayEvents(1 * IN_MILLISECONDS); _events.ScheduleEvent(EVENT_FROST_SHOCK, urand(10, 15) * IN_MILLISECONDS); break; case EVENT_SEARING_TOTEM: DoCast(me, SPELL_SEARING_TOTEM); _events.DelayEvents(1 * IN_MILLISECONDS); _events.ScheduleEvent(EVENT_SEARING_TOTEM, urand(110, 130) * IN_MILLISECONDS); break; case EVENT_STRENGTH_OF_EARTH_TOTEM: DoCast(me, SPELL_STRENGTH_OF_EARTH_TOTEM); _events.DelayEvents(1 * IN_MILLISECONDS); _events.ScheduleEvent(EVENT_STRENGTH_OF_EARTH_TOTEM, urand(110, 130) * IN_MILLISECONDS); break; case EVENT_HEALING_SURGE: { Unit* target = NULL; if (me->GetHealthPct() < 85) target = me; else if (Player* player = GetPlayerForEscort()) if (player->GetHealthPct() < 85) target = player; if (target) { DoCast(target, SPELL_HEALING_SURGE); _events.ScheduleEvent(EVENT_HEALING_SURGE, 10 * IN_MILLISECONDS); } else _events.ScheduleEvent(EVENT_HEALING_SURGE, 2 * IN_MILLISECONDS); break; } default: break; } } DoMeleeAttackIfReady(); } if (HasEscortState(STATE_ESCORT_NONE)) return; npc_escortAI::UpdateAI(diff); if (_phase) { if (_moveTimer <= diff) { switch (_phase) { case PHASE_WP_26: //debug skip path to point 26, buggy path calculation me->GetMotionMaster()->MovePoint(WP_DEBUG_2, -2021.77f, -10648.8f, 129.903f, false); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_CONTINUE: // continue escort SetEscortPaused(false); _moveTimer = 0 * IN_MILLISECONDS; _phase = PHASE_NONE; break; case PHASE_WP_22: //debug skip path to point 22, buggy path calculation me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_PLANT, -1958.026f, -10660.465f, 111.547f, false); Talk(SAY_LEGOSO_3); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_KNEEL; break; case PHASE_PLANT_FIRST_KNEEL: // plant first explosives stage 1 kneel me->SetStandState(UNIT_STAND_STATE_KNEEL); _moveTimer = 10 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_STAND; break; case PHASE_PLANT_FIRST_STAND: // plant first explosives stage 1 stand me->SetStandState(UNIT_STAND_STATE_STAND); _moveTimer = 0.5* IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_WORK; break; case PHASE_PLANT_FIRST_WORK: // plant first explosives stage 2 work Talk(SAY_LEGOSO_4); _moveTimer = 17.5 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_FINISH; break; case PHASE_PLANT_FIRST_FINISH: // plant first explosives finish _explosivesGuids.clear(); for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i) { if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_1, ExplosivesPos[0][i], G3D::Quat(), 0)) _explosivesGuids.push_back(explosive->GetGUID()); } me->HandleEmoteCommand(EMOTE_ONESHOT_NONE); // reset anim state // force runoff movement so he will not screw up next waypoint me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_RUNOFF, -1955.6f, -10669.8f, 110.65f, false); Talk(SAY_LEGOSO_5); _moveTimer = 1.5 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_PLANT_FIRST_TIMER_1: // first explosives detonate timer 1 Talk(SAY_LEGOSO_6); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_TIMER_2; break; case PHASE_PLANT_FIRST_TIMER_2: // first explosives detonate timer 2 Talk(SAY_LEGOSO_7); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_TIMER_3; break; case PHASE_PLANT_FIRST_TIMER_3: // first explosives detonate timer 3 Talk(SAY_LEGOSO_8); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_DETONATE; break; case PHASE_PLANT_FIRST_DETONATE: // first explosives detonate finish for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr) { if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr)) me->RemoveGameObject(explosive, true); } _explosivesGuids.clear(); me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_SPEECH; break; case PHASE_PLANT_FIRST_SPEECH: // after detonation 1 speech Talk(SAY_LEGOSO_9); _moveTimer = 4 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_ROTATE; break; case PHASE_PLANT_FIRST_ROTATE: // after detonation 1 rotate to next point me->SetFacingTo(2.272f); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_FIRST_POINT; break; case PHASE_PLANT_FIRST_POINT: // after detonation 1 send point anim and go on to next point me->HandleEmoteCommand(EMOTE_ONESHOT_POINT); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_FEEL_SIRONAS_1: // legoso exclamation before sironas 1.1 Talk(SAY_LEGOSO_10); _moveTimer = 4 * IN_MILLISECONDS; _phase = PHASE_FEEL_SIRONAS_2; break; case PHASE_FEEL_SIRONAS_2: // legoso exclamation before sironas 1.2 Talk(SAY_LEGOSO_11); _moveTimer = 4 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_MEET_SIRONAS_ROAR: // legoso exclamation before sironas 2.1 Talk(SAY_LEGOSO_12); _moveTimer = 4 * IN_MILLISECONDS; _phase = PHASE_MEET_SIRONAS_TURN; break; case PHASE_MEET_SIRONAS_TURN: // legoso exclamation before sironas 2.2 if (Player* player = GetPlayerForEscort()) me->SetFacingToObject(player); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_MEET_SIRONAS_SPEECH; break; case PHASE_MEET_SIRONAS_SPEECH: // legoso exclamation before sironas 2.3 Talk(SAY_LEGOSO_13); _moveTimer = 7 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_PLANT_SECOND_KNEEL: // plant second explosives stage 1 kneel me->SetStandState(UNIT_STAND_STATE_KNEEL); _moveTimer = 11 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_SPEECH; break; case PHASE_PLANT_SECOND_SPEECH: // plant second explosives stage 2 kneel Talk(SAY_LEGOSO_14); _moveTimer = 13 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_STAND; break; case PHASE_PLANT_SECOND_STAND: // plant second explosives finish me->SetStandState(UNIT_STAND_STATE_STAND); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_FINISH; break; case PHASE_PLANT_SECOND_FINISH: // plant second explosives finish - create explosives _explosivesGuids.clear(); for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i) { if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_2, ExplosivesPos[1][i], G3D::Quat(), 0)) _explosivesGuids.push_back(explosive->GetGUID()); } Talk(SAY_LEGOSO_15); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_WAIT; break; case PHASE_PLANT_SECOND_WAIT: // plant second explosives finish - proceed to next point _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_PLANT_SECOND_TIMER_1: // second explosives detonate timer 1 Talk(SAY_LEGOSO_16); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_TIMER_2; break; case PHASE_PLANT_SECOND_TIMER_2: // second explosives detonate timer 2 Talk(SAY_LEGOSO_17); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_TIMER_3; break; case PHASE_PLANT_SECOND_TIMER_3: // second explosives detonate timer 3 Talk(SAY_LEGOSO_18); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_PLANT_SECOND_DETONATE; break; case PHASE_PLANT_SECOND_DETONATE: // second explosives detonate finish for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr) { if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr)) me->RemoveGameObject(explosive, true); } _explosivesGuids.clear(); if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS)) { sironas->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); me->SetFacingToObject(sironas); } _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_FIGHT_SIRONAS_STOP; break; case PHASE_FIGHT_SIRONAS_STOP: // sironas channel stop if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS)) sironas->AI()->DoAction(ACTION_SIRONAS_CHANNEL_STOP); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_FIGHT_SIRONAS_SPEECH_1; break; case PHASE_FIGHT_SIRONAS_SPEECH_1: // sironas exclamation before aggro if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS)) sironas->AI()->Talk(SAY_SIRONAS_1); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_FIGHT_SIRONAS_SPEECH_2; break; case PHASE_FIGHT_SIRONAS_SPEECH_2: // legoso exclamation before aggro if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS)) sironas->SetObjectScale(3.0f); Talk(SAY_LEGOSO_19); _moveTimer = 1 * IN_MILLISECONDS; _phase = PHASE_FIGHT_SIRONAS_START; break; case PHASE_FIGHT_SIRONAS_START: // legoso exclamation at aggro if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS)) { Unit* target = GetPlayerForEscort(); if (!target) target = me; target->AddThreat(sironas, 0.001f); sironas->Attack(target, true); sironas->GetMotionMaster()->MoveChase(target); } _moveTimer = 10 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; case PHASE_SIRONAS_SLAIN_SPEECH_1: // legoso exclamation after battle - stage 1.1 Talk(SAY_LEGOSO_20); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_SIRONAS_SLAIN_EMOTE_1; break; case PHASE_SIRONAS_SLAIN_EMOTE_1: // legoso exclamation after battle - stage 1.2 me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); _moveTimer = 2 * IN_MILLISECONDS; _phase = PHASE_SIRONAS_SLAIN_EMOTE_2; break; case PHASE_SIRONAS_SLAIN_EMOTE_2: // legoso exclamation after battle - stage 1.3 if (Player* player = GetPlayerForEscort()) player->GroupEventHappens(QUEST_ENDING_THEIR_WORLD, me); me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER); _moveTimer = 5 * IN_MILLISECONDS; _phase = PHASE_SIRONAS_SLAIN_SPEECH_2; break; case PHASE_SIRONAS_SLAIN_SPEECH_2: // legoso exclamation after battle - stage 2 Talk(SAY_LEGOSO_21); _moveTimer = 30 * IN_MILLISECONDS; _phase = PHASE_CONTINUE; break; default: break; } } else if (!me->IsInCombat()) _moveTimer -= diff; } }
void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Corrupted Mind if (m_uiCorruptedMindTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORRUPTED_MIND); m_uiCorruptedMindTimer = 62000; } else m_uiCorruptedMindTimer -= uiDiff; // Poison Aura if (m_uiPoisonAuraTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON_AURA); m_uiPoisonAuraTimer = 60000; } else m_uiPoisonAuraTimer -= uiDiff; // Inevitable Doom if (m_uiInevitableDoomTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_INEVITABLE_DOOM); m_uiInevitableDoomTimer = 120000; } else m_uiInevitableDoomTimer -= uiDiff; // Inevitable Doom 5mins if (m_uiInevitableDoom5minsTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_INEVITABLE_DOOM); m_uiInevitableDoom5minsTimer = 15000; } else m_uiInevitableDoom5minsTimer -= uiDiff; // Remove Curse if (m_uiRemoveCurseTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_REMOVE_CURSE); m_uiRemoveCurseTimer = 30000; } else m_uiRemoveCurseTimer -= uiDiff; // Summon if (m_uiSummonTimer < uiDiff) { Unit* pSummonedSpores = NULL; pSummonedSpores = m_creature->SummonCreature(16286, ADD_1X, ADD_1Y, ADD_1Z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); pSummonedSpores = m_creature->SummonCreature(16286, ADD_2X, ADD_2Y, ADD_2Z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); pSummonedSpores = m_creature->SummonCreature(16286, ADD_3X, ADD_3Y, ADD_3Z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (pSummonedSpores) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) pSummonedSpores->AddThreat(pTarget); } m_uiSummonTimer = 28000; } else m_uiSummonTimer -= uiDiff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; //MortalWound_Timer if (MortalWound_Timer <= diff) { DoCast(me->getVictim(),SPELL_MORTALWOUND); MortalWound_Timer = 10000; } else MortalWound_Timer -= diff; //Decimate_Timer if (Decimate_Timer <= diff) { DoCast(me->getVictim(),SPELL_DECIMATE); Decimate_Timer = 100000; } else Decimate_Timer -= diff; //TerrifyingRoar_Timer if (TerrifyingRoar_Timer <= diff) { DoCast(me->getVictim(),SPELL_TERRIFYINGROAR); TerrifyingRoar_Timer = 20000; } else TerrifyingRoar_Timer -= diff; //Frenzy_Timer if (Frenzy_Timer <= diff) { DoCast(me,SPELL_FRENZY); Frenzy_Timer = 10500; } else Frenzy_Timer -= diff; //Enrage_Timer if (Enrage_Timer <= diff) { DoCast(me,SPELL_ENRAGE); Enrage_Timer = 61000; } else Enrage_Timer -= diff; //Summon_Timer if (Summon_Timer <= diff) { Unit* pTarget = NULL; Unit* SummonedZombies = NULL; SummonedZombies = me->SummonCreature(16360,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_4X,ADD_4Y,ADD_4Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_5X,ADD_5Y,ADD_5Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_6X,ADD_6Y,ADD_6Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_7X,ADD_7Y,ADD_7Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_8X,ADD_8Y,ADD_8Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedZombies = me->SummonCreature(16360,ADD_9X,ADD_9Y,ADD_9Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { pTarget = SelectUnit(SELECT_TARGET_RANDOM,0); if (pTarget) SummonedZombies->AddThreat(pTarget,1.0f); } Summon_Timer = 28000; } else Summon_Timer -= diff; DoMeleeAttackIfReady(); }
void PetAI::UpdateAI(const uint32 diff) { if (!m_creature->isAlive()) return; m_updateAlliesTimer.Update(diff); if (m_updateAlliesTimer.Passed()) { UpdateAllies(); m_updateAlliesTimer.Reset(); } if (!inCombat && m_savedTargetGuid) { if (Unit* savedTarget = m_creature->GetMap()->GetUnit(m_savedTargetGuid)) { if (!savedTarget->isAlive()) m_savedTargetGuid.Clear(); else if (!savedTarget->IsCrowdControlled()) AttackStart(savedTarget); } else m_savedTargetGuid.Clear(); } Unit* pVictim = m_creature->getVictim(); if (inCombat && (!pVictim || !pVictim->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; } Unit* owner = m_creature->GetCharmerOrOwner(); // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc. if (pVictim) { bool meleeReach = m_creature->CanReachWithMeleeAttack(pVictim); if (_needToStop()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); _stopAttack(); return; } else if (!pVictim->isAlive()) // Stop attack if target dead { m_creature->InterruptNonMeleeSpells(false); _stopAttack(); return; } // Stop attack if target under CC effect else if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && IsInCombat() && pVictim->IsCrowdControlled() && !m_creature->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) { m_savedTargetGuid = pVictim->GetObjectGuid(); m_creature->InterruptSpell(CURRENT_GENERIC_SPELL, true); if (!m_creature->IsNonMeleeSpellCasted(false, false, true)) _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()) { pVictim = m_creature->getVictim(); if (!pVictim) return; // if pet misses its target, it will also be the first in threat list pVictim->AddThreat(m_creature); if (_needToStop()) _stopAttack(); } } if (!m_creature->IsNonMeleeSpellCasted(true)) { m_attackDistanceRecheckTimer.Update(diff); if (m_attackDistanceRecheckTimer.Passed()) { m_attackDistanceRecheckTimer.Reset(); if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI) && m_AIType == PET_AI_RANGED && pVictim) { float dist = m_creature->GetDistance(pVictim); if ((m_creature->CanReachWithMeleeAttack(pVictim) && m_creature->IsWithinDist(owner, m_creature->GetMap()->GetVisibilityDistance() / 2.0f)) || dist > (m_attackDistance + 2.0f)) { MoveToVictim(pVictim); return; } } if (sWorld.getConfig(CONFIG_BOOL_PET_ADVANCED_AI)) { // FIXME: AOE check } } } } else if (Unit* target = GetPrimaryTarget()) { AttackStart(target); } else if (owner) { switch (m_creature->GetCharmState(CHARM_STATE_REACT)) { case REACT_DEFENSIVE: { if (!m_primaryTargetGuid) { Unit* ownerVictim = owner->getVictim(); if (ownerVictim && ownerVictim->isAlive()) AttackStart(ownerVictim); } break; } case REACT_AGGRESSIVE: { if (Unit* pTarget = owner->getAttackerForHelper()) AttackStart(pTarget); break; } // case REACT_PASSIVE: default: break; } } 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)) 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; } Unit* autoCastTarget = NULL; if (inCombat) { Unit* pVictim = m_creature->getVictim(); if (pVictim && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { SpellCastResult result = CanAutoCast(pVictim, spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) autoCastTarget = pVictim; } } if (!autoCastTarget) { 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; SpellCastResult result = CanAutoCast(target, spellInfo); if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) { autoCastTarget = target; break; } } } if (autoCastTarget) targetSpellStore.push_back(TargetSpellList::value_type(autoCastTarget->GetObjectGuid(), spellInfo->Id)); } // 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() || (owner && owner->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() || (owner && owner->IsCrowdControlled())) currentSpells.push_back(GetSpellType(PET_SPELL_FREEACTION)); if (m_creature->GetHealth() < m_creature->GetMaxHealth() || (owner && (owner->GetHealth() < owner->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() || (owner && owner->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()) { Unit* victimVictim = victim->getVictim(); if (!victimVictim || (victimVictim->GetObjectGuid() != m_creature->GetObjectGuid())) { currentSpells.push_back(GetSpellType(PET_SPELL_ATTACKSTART)); currentSpells.push_back(GetSpellType(PET_SPELL_THREAT)); } } if (m_creature->IsCrowdControlled() || (owner && owner->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->GetHealthPercent() < 95.0f) 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->GetGuidStr().c_str(), m_AIType, spellID, pTarget ? pTarget->GetGuidStr().c_str() : "<none>"); switch (result) { case SPELL_FAILED_TOO_CLOSE: case SPELL_FAILED_OUT_OF_RANGE: break; // ignore 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) Spell::SendCastResult(owner, spellInfo, 0, result, true); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI::Update cast %s, AI %u Target %s spell %u result %u", m_creature->GetGuidStr().c_str(), m_AIType, pTarget ? pTarget->GetGuidStr().c_str() : "<none>", spellID, result); break; } } } else continue; if (b_castOk) { 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 PetAI::UpdateAI(const uint32 diff) { if (!m_creature->IsAlive()) return; Unit* owner = m_creature->GetCharmerOrOwner(); Unit* victim = NULL; if (!((Pet*)m_creature)->isControlled()) m_creature->SelectHostileTarget(); // Creature pets and guardians will always look in threat list for victim if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE) || (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS))) victim = m_creature->getVictim(); if (m_updateAlliesTimer <= diff) // UpdateAllies self set update timer UpdateAllies(); else m_updateAlliesTimer -= diff; if (inCombat && !victim) { m_creature->AttackStop(true); inCombat = false; } if (((Pet*)m_creature)->GetIsRetreating()) { if (!owner->IsWithinDistInMap(m_creature, (PET_FOLLOW_DIST * 2))) { 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); 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); // allow only spell not on cooldown if (cooldown != 0 && duration < cooldown) 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(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_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->SpellStart(&targets); } // deleted cached Spell objects for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) delete itr->second; } // Guardians will always look in threat list for victim if (!((Pet*)m_creature)->isControlled()) m_creature->SelectHostileTarget(); if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE) || (m_creature->IsPet() && ((Pet*)m_creature)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS))) victim = m_creature->getVictim(); // Stop here if casting spell (No melee and no movement) if (m_creature->IsNonMeleeSpellCasted(false)) return; 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 ((m_creature->IsCharmed() && victim == m_creature->GetCharmer()) || !victim->IsTargetableForAttack()) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "PetAI (guid = %u) is stopping attack.", m_creature->GetGUIDLow()); m_creature->CombatStop(); inCombat = false; return; } // if pet misses its target, it will also be the first in threat list if (!(m_creature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE) && m_creature->CanReachWithMeleeAttack(victim)) { if (!m_creature->HasInArc(2 * M_PI_F / 3, victim)) { m_creature->SetInFront(victim); if (victim->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)victim); if (owner && owner->GetTypeId() == TYPEID_PLAYER) m_creature->SendCreateUpdateToPlayer((Player*)owner); } if (DoMeleeAttackIfReady()) victim->AddThreat(m_creature); } else if (!(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE) || m_creature->hasUnitState(UNIT_STAT_MOVING))) AttackStart(victim); } else if (owner) { CharmInfo* charmInfo = m_creature->GetCharmInfo(); if (owner->IsInCombat() && !(m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE) || (charmInfo && charmInfo->HasReactState(REACT_PASSIVE)))) AttackStart(owner->getAttackerForHelper()); else if (!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) { if (charmInfo && charmInfo->HasCommandState(COMMAND_STAY)) { if (Pet* pet = (Pet*)m_creature) { //if stay command is set but we dont have stay pos set then we need to establish current pos as stay position if (!pet->IsStayPosSet()) pet->SetStayPosition(true); float stayPosX = pet->GetStayPosX(); float stayPosY = pet->GetStayPosY(); float stayPosZ = pet->GetStayPosZ(); if (m_creature->GetPositionX() == stayPosX && m_creature->GetPositionY() == stayPosY && m_creature->GetPositionZ() == stayPosZ) { float StayPosO = pet->GetStayPosO(); if (m_creature->hasUnitState(UNIT_STAT_MOVING)) { m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); } else if (m_creature->GetOrientation() != StayPosO) m_creature->SetOrientation(StayPosO); } else pet->GetMotionMaster()->MovePoint(0, stayPosX, stayPosY, stayPosZ, false); } } else if (m_creature->hasUnitState(UNIT_STAT_FOLLOW)) { if (owner->IsWithinDistInMap(m_creature, PET_FOLLOW_DIST)) { m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); } } else if (charmInfo && charmInfo->HasCommandState(COMMAND_FOLLOW) && !owner->IsWithinDistInMap(m_creature, (PET_FOLLOW_DIST * 2))) m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } }
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 createClassMirrors() { for (int i = 0; i <= 5; i++) { Map* pMap = m_creature->GetMap(); Map::PlayerList const &players = pMap->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if(Unit* target = m_creature->GetMap()->GetUnit(itr->getSource()->GetGUID())) { Unit* pClone = m_creature->SummonCreature(m_bIsRegularMode ? CLONE : CLONE_H, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); if (pClone) { pClone->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PASSIVE); pClone->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_SELECTABLE); pClone->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_OOC_NOT_ATTACKABLE); pClone->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNK_6); pClone->SetDisplayId(target->GetNativeDisplayId()); pClone->SetName(target->GetName()); pClone->setFaction(FAC_HOSTILE); switch (target->getClass()) { case CLASS_PRIEST: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_PRIEST : CLONE_HEALTH_PRIEST_H); break; case CLASS_PALADIN: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_PALA : CLONE_HEALTH_PALA_H); break; case CLASS_WARLOCK: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_WARLOCK : CLONE_HEALTH_WARLOCK_H); break; case CLASS_MAGE: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_MAGE : CLONE_HEALTH_MAGE_H); break; case CLASS_ROGUE: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_ROGUE : CLONE_HEALTH_ROGUE_H); break; case CLASS_WARRIOR: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_WARRIOR : CLONE_HEALTH_WARRIOR_H); break; case CLASS_DRUID: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_DRUID : CLONE_HEALTH_DRUID_H); break; case CLASS_SHAMAN: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_SHAMAN : CLONE_HEALTH_SHAMAN_H); break; case CLASS_HUNTER: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_HUNT : CLONE_HEALTH_HUNT_H); break; case CLASS_DEATH_KNIGHT: pClone->SetMaxHealth(m_bIsRegularMode ? CLONE_HEALTH_DK : CLONE_HEALTH_DK_H); break; default: break; } pClone->SetHealth(pClone->GetMaxHealth()); pClone->Attack(target, true); pClone->AddThreat(target, 10.0f); cloneGUIDList.push_back(pClone->GetGUID()); } switch(i) { case 1: pClone->SetPhaseMask(16, true); clone16GUIDList.push_back(pClone->GetGUID()); break; case 2: pClone->SetPhaseMask(32, true); clone32GUIDList.push_back(pClone->GetGUID()); break; case 3: pClone->SetPhaseMask(64, true); clone64GUIDList.push_back(pClone->GetGUID()); break; case 4: pClone->SetPhaseMask(128, true); clone128GUIDList.push_back(pClone->GetGUID()); break; case 5: pClone->SetPhaseMask(256, true); clone256GUIDList.push_back(pClone->GetGUID()); break; default: break; } } } } }
void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bFirstPlanar && !m_bIsRegularMode && m_creature->GetHealthPercent() < 50.0f) { m_bFirstPlanar = true; Events.ScheduleEvent(EVENT_PLANAR_SHIFT, 0); } if (!m_bSecondPlanar && !m_bIsRegularMode && m_creature->GetHealthPercent() < 25.0f) { m_bSecondPlanar = true; Events.ScheduleEvent(EVENT_PLANAR_SHIFT, 0); } if (m_creature->GetDistance2d(m_creature->getVictim()) > 35.0f && !m_bIsMove) { m_bIsMove = true; SetCombatMovement(m_bIsMove); if (Unit* pTarget = m_creature->getVictim()) m_creature->GetMotionMaster()->MoveChase(pTarget); } if (m_creature->GetDistance2d(m_creature->getVictim()) < 20.0f && m_bIsMove) { m_bIsMove = false; SetCombatMovement(m_bIsMove); m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); m_creature->StopMoving(); } Events.Update(uiDiff); while (uint32 uiEventId = Events.ExecuteEvent()) switch (uiEventId) { case EVENT_DRAKE_COLOR_CHECK: CheckDrakeColors(); break; case EVENT_ARCANE_BARRAGE: DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_BARRAGE_N : SPELL_ARCANE_BARRAGE_H); break; case EVENT_ARCANE_VOLLEY: DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ARCANE_VOLLEY_N : SPELL_ARCANE_VOLLEY_H); break; case EVENT_PLANAR_SHIFT: m_creature->MonsterTextEmote(EMOTE_PLANAR_SHIFT, m_creature, true); Events.DelayEvents(18*IN_MILLISECONDS); m_creature->InterruptNonMeleeSpells(false); DoCast(m_creature, SPELL_PLANAR_SHIFT, false); Events.ScheduleEvent(EVENT_ENRAGED_ASSAULT, 19*IN_MILLISECONDS); Events.ScheduleEvent(EVENT_PLANAR_ANOMALITIES, 2*IN_MILLISECONDS); break; case EVENT_ENRAGED_ASSAULT: DoCast(m_creature, SPELL_ENRAGED_ASSAULT, true); break; case EVENT_PLANAR_ANOMALITIES: DoCast(m_creature, SPELL_PLANAR_ANOMALIES, true); break; case EVENT_SUMMON_DRAKES: if (SummonMgr.GetSummonCount(NPC_DRAGON) > MAX_DRAGON_COUNT) break; for (int i = 0 ; i < 3 ; i++) { //DoCast(m_creature, SPELL_SUMMON_DRAKE, true); // summoned @ ground position Unit* pSumm = SummonMgr.SummonCreature(NPC_DRAGON, m_creature->GetPositionX() - 5 + urand(0, 10), m_creature->GetPositionY() - 5 + urand(0, 10), m_creature->GetPositionZ() - 5 + urand(0, 10), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); if (Unit* pPlayer = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM_PLAYER, 0)) { if (pPlayer->GetVehicle()) if (Unit* pDrake = pPlayer->GetVehicle()->GetBase()) { pSumm->AddThreat(pDrake, 10000.0f); pSumm->GetMotionMaster()->MoveIdle(); pSumm->StopMoving(); pSumm->GetMotionMaster()->MoveChase(pDrake, 20.0f); } } } break; default: break; } DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (EnfeebleResetTimer) { if (EnfeebleResetTimer <= diff) //Let's not forget to reset that { EnfeebleResetHealth(); EnfeebleResetTimer=0; } else EnfeebleResetTimer -= diff; } if (m_creature->hasUnitState(UNIT_STAT_STUNNED)) //While shifting to phase 2 malchezaar stuns himself return; if (m_creature->GetUInt64Value(UNIT_FIELD_TARGET)!=m_creature->getVictim()->GetGUID()) m_creature->SetUInt64Value(UNIT_FIELD_TARGET, m_creature->getVictim()->GetGUID()); if (phase == 1) { if (m_creature->GetHealthPercent() < 60.0f) { m_creature->InterruptNonMeleeSpells(false); phase = 2; //animation DoCastSpellIfCan(m_creature, SPELL_EQUIP_AXES); //text DoScriptText(SAY_AXE_TOSS1, m_creature); //passive thrash aura m_creature->CastSpell(m_creature, SPELL_THRASH_AURA, true); //models SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE); //damage const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 2*cinfo->mindmg); m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 2*cinfo->maxdmg); m_creature->UpdateDamagePhysical(BASE_ATTACK); m_creature->SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg); m_creature->SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg); //Sigh, updating only works on main attack , do it manually .... m_creature->SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, cinfo->mindmg); m_creature->SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, cinfo->maxdmg); m_creature->SetAttackTime(OFF_ATTACK, (m_creature->GetAttackTime(BASE_ATTACK)*150)/100); } } else if (phase == 2) { if (m_creature->GetHealthPercent() < 30.0f) { InfernalTimer = 15000; phase = 3; ClearWeapons(); //remove thrash m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); DoScriptText(SAY_AXE_TOSS2, m_creature); Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); for(uint32 i=0; i<2; ++i) { Creature *axe = m_creature->SummonCreature(MALCHEZARS_AXE, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); if (axe) { axe->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); axe->setFaction(m_creature->getFaction()); axes[i] = axe->GetGUID(); if (target) { axe->AI()->AttackStart(target); // axe->getThreatManager().tauntApply(target); //Taunt Apply and fade out does not work properly // So we'll use a hack to add a lot of threat to our target axe->AddThreat(target, 10000000.0f); } } } if (ShadowNovaTimer > 35000) ShadowNovaTimer = EnfeebleTimer + 5000; return; } if (SunderArmorTimer < diff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR); SunderArmorTimer = urand(10000, 18000); }else SunderArmorTimer -= diff; if (Cleave_Timer < diff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); Cleave_Timer = urand(6000, 12000); }else Cleave_Timer -= diff; } else { if (AxesTargetSwitchTimer < diff) { AxesTargetSwitchTimer = urand(7500, 20000); Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); if (target) { for(int i = 0; i < 2; ++i) { Unit *axe = Unit::GetUnit(*m_creature, axes[i]); if (axe) { float threat = 1000000.0f; if (axe->getVictim() && m_creature->getThreatManager().getThreat(axe->getVictim())) { threat = axe->getThreatManager().getThreat(axe->getVictim()); axe->getThreatManager().modifyThreatPercent(axe->getVictim(), -100); } if (target) axe->AddThreat(target, threat); //axe->getThreatManager().tauntFadeOut(axe->getVictim()); //axe->getThreatManager().tauntApply(target); } } } } else AxesTargetSwitchTimer -= diff; if (AmplifyDamageTimer < diff) { if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) DoCastSpellIfCan(pTarget, SPELL_AMPLIFY_DAMAGE); AmplifyDamageTimer = urand(20000, 30000); }else AmplifyDamageTimer -= diff; } //Time for global and double timers if (InfernalTimer < diff) { SummonInfernal(diff); InfernalTimer = phase == 3 ? 14500 : 44500; //15 secs in phase 3, 45 otherwise }else InfernalTimer -= diff; if (ShadowNovaTimer < diff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWNOVA); ShadowNovaTimer = phase == 3 ? 31000 : -1; } else ShadowNovaTimer -= diff; if (phase != 2) { if (SWPainTimer < diff) { Unit* target = NULL; if (phase == 1) target = m_creature->getVictim(); // the tank else //anyone but the tank target = SelectUnit(SELECT_TARGET_RANDOM, 1); if (target) DoCastSpellIfCan(target, SPELL_SW_PAIN); SWPainTimer = 20000; }else SWPainTimer -= diff; } if (phase != 3) { if (EnfeebleTimer < diff) { EnfeebleHealthEffect(); EnfeebleTimer = 30000; ShadowNovaTimer = 5000; EnfeebleResetTimer = 9000; }else EnfeebleTimer -= diff; } if (phase==2) DoMeleeAttacksIfReady(); else DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Necrotic Aura if ( NecroticAuraTimer < uiDiff) { DoCast(m_creature->getVictim(),SPELL_NECROTIC_AURA); NecroticAuraTimer = 20000; }else NecroticAuraTimer -= uiDiff; // Necrotic Aura fade warning if ( NecroticAuraFadeWarning < uiDiff) { DoScriptText(SAY_NECROTIC_AURA_FADE, m_creature); NecroticAuraFadeWarning = 20000; }else NecroticAuraFadeWarning -= uiDiff; // Deathbloom if ( DeathbloomTimer < uiDiff) { DoCast(m_creature, m_bIsRegularMode ? SPELL_DEATHBLOOM: H_SPELL_DEATHBLOOM); DeathbloomTimer = 30000; }else DeathbloomTimer -= uiDiff; // Inevitable Doom if ( InevitableDoomTimer < uiDiff) { DoCast(m_creature->getVictim(), m_bIsRegularMode ? SPELL_INEVITABLE_DOOM : H_SPELL_INEVITABLE_DOOM); InevitableDoomTimer = 120000 - ( IDoomCount* IDoomTimeShortage); IDoomCount ++; }else InevitableDoomTimer -= uiDiff; // Inevitable Doom 7mins if ( IDoom7minsTimer < uiDiff) { DoCast(m_creature->getVictim(), SPELL_INEVITABLE_DOOM); IDoom7minsTimer = 15000; }else IDoom7minsTimer -= uiDiff; // Summon if ( SummonTimer < uiDiff) { Unit* pSummonedSpores = NULL; pSummonedSpores = m_creature->SummonCreature(16286,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); pSummonedSpores = m_creature->SummonCreature(16286,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); pSummonedSpores = m_creature->SummonCreature(16286,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (pSummonedSpores) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) pSummonedSpores->AddThreat(pTarget); } SummonTimer = 28000; } else SummonTimer -= uiDiff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { //Return since we have no target if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; //MortalWound_Timer if (MortalWound_Timer < diff) { //Cast DoCast(m_creature->getVictim(),SPELL_MORTALWOUND); //10 seconds MortalWound_Timer = 10000; }else MortalWound_Timer -= diff; //Decimate_Timer if (Decimate_Timer < diff) { //Cast DoCast(m_creature,SPELL_DECIMATE); Unit* Temp = NULL; std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin(); for (; i != m_creature->getThreatManager().getThreatList().end(); ++i) { Temp = Unit::GetUnit((*m_creature),(*i)->getUnitGuid()); if (Temp ) Temp->SetHealth(Temp->GetMaxHealth()* 0.05); } //105 seconds until we should cast this agian Decimate_Timer = 105000; }else Decimate_Timer -= diff; //TerrifyingRoar_Timer if (TerrifyingRoar_Timer < diff) { //Cast DoCast(m_creature->getVictim(),SPELL_TERRIFYINGROAR); //20 seconds until we should cast this agian TerrifyingRoar_Timer = 20000; }else TerrifyingRoar_Timer -= diff; //Frenzy_Timer if (Frenzy_Timer < diff) { //Cast DoCast(m_creature,SPELL_FRENZY); //10.5 seconds until we should cast this agian Frenzy_Timer = 10500; }else Frenzy_Timer -= diff; if (Enrage_Timer < diff) { //Cast DoCast(m_creature,SPELL_ENRAGE); //61 seconds until we should cast this agian Enrage_Timer = 61000; }else Enrage_Timer -= diff; //Summon_Timer if (Summon_Timer < diff) { Unit* target = NULL; Unit* SummonedZombies = NULL; for (int i = 0; i < 6; i++); { switch (rand()%9) { case 0: SummonedZombies = m_creature->SummonCreature(16360,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 1: SummonedZombies = m_creature->SummonCreature(16360,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } case 2: SummonedZombies = m_creature->SummonCreature(16360,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 3: SummonedZombies = m_creature->SummonCreature(16360,ADD_4X,ADD_4Y,ADD_4Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 4: SummonedZombies = m_creature->SummonCreature(16360,ADD_5X,ADD_5Y,ADD_5Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 5: SummonedZombies = m_creature->SummonCreature(16360,ADD_6X,ADD_6Y,ADD_6Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 6: SummonedZombies = m_creature->SummonCreature(16360,ADD_7X,ADD_7Y,ADD_7Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 7: SummonedZombies = m_creature->SummonCreature(16360,ADD_8X,ADD_8Y,ADD_8Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; case 8: SummonedZombies = m_creature->SummonCreature(16360,ADD_9X,ADD_9Y,ADD_9Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedZombies) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedZombies->AddThreat(target,0.0f); } break; } } //24 seconds until we should cast this agian Summon_Timer = 120000; } else Summon_Timer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; //CorruptedMind_Timer if (CorruptedMind_Timer < diff) { DoCast(m_creature->getVictim(),SPELL_CORRUPTED_MIND); CorruptedMind_Timer = 62000; }else CorruptedMind_Timer -= diff; //PoisonAura_Timer if (PoisonAura_Timer < diff) { DoCast(m_creature->getVictim(),SPELL_POISON_AURA); PoisonAura_Timer = 60000; }else PoisonAura_Timer -= diff; //InevitableDoom_Timer if (InevitableDoom_Timer < diff) { DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); InevitableDoom_Timer = 120000; }else InevitableDoom_Timer -= diff; //InevitableDoom5mins_Timer if (InevitableDoom5mins_Timer < diff) { DoCast(m_creature->getVictim(),SPELL_INEVITABLE_DOOM); InevitableDoom5mins_Timer = 15000; }else InevitableDoom5mins_Timer -= diff; //RemoveCurse_Timer if (RemoveCurse_Timer < diff) { DoCast(m_creature,SPELL_REMOVE_CURSE); RemoveCurse_Timer = 30000; }else RemoveCurse_Timer -= diff; //Summon_Timer if (Summon_Timer < diff) { Unit* target = NULL; Unit* SummonedSpores = NULL; SummonedSpores = m_creature->SummonCreature(16286,ADD_1X,ADD_1Y,ADD_1Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedSpores = m_creature->SummonCreature(16286,ADD_2X,ADD_2Y,ADD_2Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); SummonedSpores = m_creature->SummonCreature(16286,ADD_3X,ADD_3Y,ADD_3Z,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); if (SummonedSpores) { target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) SummonedSpores->AddThreat(target,1.0f); } Summon_Timer = 28000; } else Summon_Timer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; switch(stage) { case 0: { bsw->timedCast(SPELL_POUND, uiDiff); bsw->timedCast(SPELL_COLD, uiDiff); if (bsw->timedQuery(SUMMON_BORROWER, uiDiff)) { bsw->doCast(SUMMON_BORROWER); DoScriptText(-1713556,m_creature); }; if (bsw->timedQuery(SPELL_SUBMERGE_0, uiDiff)) stage = 1; break;} case 1: { bsw->doCast(SPELL_SUBMERGE_0); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); stage = 2; DoScriptText(-1713557,m_creature); break;} case 2: { if (bsw->timedQuery(SPELL_SPIKE_CALL, uiDiff)) { pTarget = bsw->SelectUnit(); // bsw->doCast(SPELL_SPIKE_CALL); Unit* spike = bsw->doSummon(NPC_SPIKE,TEMPSUMMON_TIMED_DESPAWN,60000); // Creature* spike = GetClosestCreatureWithEntry(m_creature, NPC_SPIKE, 50.0f); if (spike) { spike->AddThreat(pTarget, 1000.0f); DoScriptText(-1713558,m_creature,pTarget); bsw->doCast(SPELL_MARK,pTarget); spike->GetMotionMaster()->MoveChase(pTarget); } }; if (bsw->timedQuery(SPELL_SUMMON_BEATLES, uiDiff)) { bsw->doCast(SPELL_SUMMON_BEATLES); bsw->doCast(SUMMON_SCARAB); DoScriptText(-1713560,m_creature); }; if (bsw->timedQuery(SPELL_SUBMERGE_0, uiDiff)) stage = 3; break;} case 3: { stage = 0; DoScriptText(-1713559,m_creature); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); bsw->doRemove(SPELL_SUBMERGE_0,m_creature); break;} case 4: { bsw->doCast(SPELL_LEECHING_SWARM); DoScriptText(-1713561,m_creature); stage = 5; break;} case 5: { bsw->timedCast(SPELL_POUND, uiDiff); bsw->timedCast(SPELL_COLD, uiDiff); break;} } bsw->timedCast(SUMMON_FROSTSPHERE, uiDiff); bsw->timedCast(SPELL_BERSERK, uiDiff); if (m_creature->GetHealthPercent() < 30.0f && stage == 0) stage = 4; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; int i; //PHASE 1 if(phase==1) { if(Phase_Timer < diff) { phase = 2; Phase_Timer = 60000; //phase 2 lasts 60 seconds } else Phase_Timer -= diff; //summon trainees if(Trainee_Timer < diff) { for(i=0; i<trainees; i++) { Unit *mob = m_creature->SummonCreature(CR_UN_TRAINEE, LiveX[i], LiveY[i], LiveZ[i], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(mob && target) mob->AddThreat(target, 1.0f); } Trainee_Timer = 15000; } else Trainee_Timer -= diff; //summon death knights if(DeathKnight_Timer < diff) { i = irand(0,2); Unit *mob = m_creature->SummonCreature(CR_UN_DEATHKNIGHT, LiveX[i], LiveY[i], LiveZ[i], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(mob && target) mob->AddThreat(target, 1.0f); DeathKnight_Timer = 30000; } else DeathKnight_Timer -= diff; //summon rider if(Rider_Timer < diff) { i = irand(0,2); Unit *mob = m_creature->SummonCreature(CR_UN_RIDER, LiveX[i], LiveY[i], LiveZ[i], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(mob && target) mob->AddThreat(target, 1.0f); Rider_Timer = 45000; } else Rider_Timer -= diff; } //PHASE 2 if(phase==2) { if(Phase_Timer < diff) { //teleport gothik down m_creature->NearTeleportTo(UNDEAD_X, UNDEAD_Y, UNDEAD_Z, 0); Phase_Timer = 15000; phase = 3; SetCombatMovement(true); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } else Phase_Timer -= diff; } //PHASE 3,4 if(phase==3 || phase==4) { if(Phase_Timer < diff) { //cast Harvest Soul (-10% stats to the raid) Unit* target = NULL; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) { if (Unit* target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid())) if(target->isAlive()) DoCast(target, SP_HARVEST_SOUL, true); } //teleport gothik to the other side if(phase==3) m_creature->NearTeleportTo(LIVE_X, LIVE_Y, LIVE_Z, 0); else m_creature->NearTeleportTo(UNDEAD_X, UNDEAD_Y, UNDEAD_Z, 0); Phase_Timer = 15000; phase = (phase==3) ? 4 : 3; } else Phase_Timer -= diff; //cast shadowbolts if(Shadowbolt_Timer < diff) { DoCast(m_creature->getVictim(), Regular ? SP_SHADOWBOLT : H_SP_SHADOWBOLT); Shadowbolt_Timer = 1200; } else Shadowbolt_Timer -= diff; //if 30% left, stop teleporting if ((m_creature->GetHealth()*100) / m_creature->GetMaxHealth() <= 30) { phase=5; if(pInstance) pInstance->SetData(TYPE_GOTHIK, SPECIAL); } } //PHASE 5 if(phase==5) { if(Shadowbolt_Timer < diff) { DoCast(m_creature->getVictim(), Regular ? SP_SHADOWBOLT : H_SP_SHADOWBOLT); Shadowbolt_Timer = 1200; } else Shadowbolt_Timer -= diff; } }