void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; //m_uiPoisonBolt_Timer if (m_uiPoisonBolt_Timer < uiDiff) { Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); if (pTarget && pTarget->IsWithinDistInMap(m_creature, 30.0f)) DoCastSpellIfCan(pTarget, SPELL_POISON_BOLT); m_uiPoisonBolt_Timer = urand(5000, 10000); } else m_uiPoisonBolt_Timer -= uiDiff; }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (flashheal_timer <= diff) { Unit* target = DoSelectLowestHpFriendly(99, 30000); if (target) { if (target->IsWithinDistInMap(me, 50)) DoCast(target, SPELL_FLASH_HEAL, false); else { // bugged //me->GetMotionMaster()->Clear(); //me->GetMotionMaster()->MoveChase(target, 20); } } else { if (urand(0, 1)) target = DoSelectLowestHpFriendly(50, 0); else target = SelectTarget(SELECT_TARGET_RANDOM, 0); if (target) DoCast(target, SPELL_DISPEL_MAGIC, false); } flashheal_timer = 2500; } else flashheal_timer -= diff; /*if (dispelmagic_timer <= diff) { if (urand(0, 1)) { Unit* target = SelectTarget(); DoCast(target, SPELL_DISPEL_MAGIC, false); } else me->CastSpell(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_DISPEL_MAGIC, false); dispelmagic_timer = 12000; } else dispelmagic_timer -= diff;*/ boss_hexlord_addAI::UpdateAI(diff); }
void GeddonArmageddonDealDamage() { std::vector<ObjectGuid> vGuids; m_creature->FillGuidsListFromThreatList(vGuids); if (vGuids.empty()) return; for (std::vector<ObjectGuid>::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { Unit* pTarget = m_creature->GetMap()->GetUnit(*itr); if (pTarget && pTarget->IsWithinDistInMap(m_creature, 20.0f) && pTarget->IsWithinLOSInMap(m_creature)) m_creature->DealDamage(pTarget, urand(7600, 8400), NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_FIRE, NULL, false); } m_creature->SetHealth(0); m_creature->SetDeathState(JUST_DIED); }
void UpdateAI(uint32 diff) override { // PoisonBoltTimer if (PoisonBoltTimer <= diff) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); if (target && target->IsWithinDistInMap(me, 30)) DoCast(target, SPELL_POISON_BOLT); PoisonBoltTimer = 5000 + rand32() % 5000; } else PoisonBoltTimer -= diff; // DespawnTimer if (DespawnTimer <= diff) { // call Unsummon() me->setDeathState(DEAD); // to prevent crashes DespawnTimer = 1000; } else DespawnTimer -= diff; }
void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; if (me->HasUnitState(UNIT_STATE_CASTING)) return; if (m_uiCheckTimer <= diff) { Unit *pTarget; std::list<HostileReference *> t_list = me->getThreatManager().getThreatList(); for (std::list<HostileReference *>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { pTarget = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); if (pTarget && pTarget->IsWithinDistInMap(me, 12)) { me->AddAura(SPELL_ADRENALINE, pTarget); m_uiCheckTimer = 1000; } } } else m_uiCheckTimer -= diff; }
void UpdateAI(const uint32 diff) { //PoisonBolt_Timer if (PoisonBolt_Timer <= diff) { Unit *pTarget = NULL; pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); if (pTarget && pTarget->IsWithinDistInMap(m_creature, 30)) DoCast(pTarget, SPELL_POISON_BOLT); PoisonBolt_Timer = 5000+rand()%5000; } else PoisonBolt_Timer -= diff; //Despawn_Timer if (Despawn_Timer <= diff) { //call Unsummon() m_creature->setDeathState(DEAD); //to prevent crashes Despawn_Timer = 1000; } else Despawn_Timer -= diff; }
void UpdateAI(const uint32 diff) { //Return since we have no target if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() ) return; //Earthquake_Timer if(Earthquake_Timer < diff) { if(!Earthquake) { DoCast(m_creature->getVictim(), SPELL_EARTHQUAKE); Earthquake = true; Earthquake_Timer = 10000; } else { switch(rand()%2) { case 0: DoPlaySoundToSet(m_creature, SOUND_SUMMON1); DoYell(SAY_SUMMON1, LANG_UNIVERSAL, NULL); break; case 1: DoPlaySoundToSet(m_creature, SOUND_SUMMON2); DoYell(SAY_SUMMON2, LANG_UNIVERSAL, NULL); break; } //north SummonMurloc(486.10, -723.64, -7.14); SummonMurloc(482.58, -723.78, -7.14); SummonMurloc(479.38, -723.91, -7.14); SummonMurloc(476.03, -723.86, -7.14); SummonMurloc(472.69, -723.69, -7.14); SummonMurloc(469.04, -723.63, -7.14); //south SummonMurloc(311.63, -725.04, -13.15); SummonMurloc(307.81, -725.34, -13.15); SummonMurloc(303.91, -725.64, -13.06); SummonMurloc(300.23, -726, -11.89); SummonMurloc(296.82, -726.33, -10.82); SummonMurloc(293.64, -726.64, -9.81); DoTextEmote(EMOTE_EARTHQUAKE, NULL); Earthquake = false; Earthquake_Timer = 40000+rand()%5000; } }else Earthquake_Timer -= diff; //TidalWave_Timer if(TidalWave_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_TIDAL_WAVE); TidalWave_Timer = 20000; }else TidalWave_Timer -= diff; if(!Phase2) { //WateryGrave_Timer if(WateryGrave_Timer < diff) { //Teleport 4 players under the waterfalls Unit *target; for(uint8 i = 0; i < 4; i++) { target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(target && (target->GetTypeId() == TYPEID_PLAYER) && !target->HasAura(SPELL_WATERY_GRAVE, 0) && target->IsWithinDistInMap(m_creature, 50)) ApplyWateryGrave(target, i); } switch(rand()%2) { case 0: DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL1); DoYell(SAY_SUMMON_BUBL1, LANG_UNIVERSAL, NULL); break; case 1: DoPlaySoundToSet(m_creature, SOUND_SUMMON_BUBL2); DoYell(SAY_SUMMON_BUBL2, LANG_UNIVERSAL, NULL); break; case 2: break; } DoTextEmote(EMOTE_WATERY_GRAVE, NULL); WateryGrave_Timer = 30000; }else WateryGrave_Timer -= diff; //Start Phase2 if((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 25) Phase2 = true; } else { //WateryGlobules_Timer if(WateryGlobules_Timer < diff) { SummonWaterGlobule(WATERY_GRAVE_X1, WATERY_GRAVE_Y1, WATERY_GRAVE_Z1); SummonWaterGlobule(WATERY_GRAVE_X2, WATERY_GRAVE_Y2, WATERY_GRAVE_Z2); SummonWaterGlobule(WATERY_GRAVE_X3, WATERY_GRAVE_Y3, WATERY_GRAVE_Z3); SummonWaterGlobule(WATERY_GRAVE_X4, WATERY_GRAVE_Y4, WATERY_GRAVE_Z4); DoTextEmote(EMOTE_WATERY_GLOBULES, NULL); WateryGlobules_Timer = 25000; }else WateryGlobules_Timer -= diff; } DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { //Sounds OOC, Kiljaeden Orders if(!m_creature->getVictim()) { if(m_uiKJOrdersTimer < diff) { switch (rand()%5) { case 0: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT3); break; case 3: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT4); break; case 4: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT5); break; } m_uiKJOrdersTimer = 30000; }else m_uiKJOrdersTimer -= diff; } /*//Rebirth After Phase1 if(pInstance && pInstance->GetData(DATA_KILJAEDEN) == IN_PROGRESS) { m_creature->setFaction(14); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //pInstance->SetData(DATA_KILJAEDEN_EVENT, IN_PROGRESS); //pInstance->SetData(DATA_DECIVER, NOT_STARTED); }*/ if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; //dragon cast blue shield for(uint8 i=0; i<4; ++i) { if(Unit* Dragon = Unit::GetUnit(*m_creature, DragonGUID[i])) if(Dragon && Dragon->HasAura(SPELL_SHIELD_OF_BLUE)) { m_uiCancelShieldTimer = 5000; std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *TargetedPlayer = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); if (TargetedPlayer && TargetedPlayer->GetTypeId() == TYPEID_PLAYER && TargetedPlayer->IsWithinDistInMap(Dragon, 10) && !TargetedPlayer->HasAura(AURA_BLUESHIELD)) TargetedPlayer->CastSpell(TargetedPlayer,AURA_BLUESHIELD,true); } } } //stop blue shield if(m_uiCancelShieldTimer < diff) { std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *ShieldedPlayer1 = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); if (ShieldedPlayer1 && ShieldedPlayer1->GetTypeId() == TYPEID_PLAYER && ShieldedPlayer1->HasAura(AURA_BLUESHIELD)) { ShieldedPlayer1->RemoveAurasDueToSpell(AURA_BLUESHIELD); } } m_uiCancelShieldTimer = 300000; }else m_uiCancelShieldTimer -= diff; //Kalecgos and Anvena Event if((m_uiKalecgosAnvenaTimer < diff) && m_bIsAnvena) { switch(m_uiKalecgosAnvenaCount) { case 0: DoPlaySoundToSet(m_creature, SAY_KALECGOS_AWAKEN); m_uiKalecgosAnvenaTimer = 5000; break; case 1: DoPlaySoundToSet(m_creature, SAY_ANVEENA_IMPRISONED); m_uiKalecgosAnvenaTimer = 3000; break; case 2: DoPlaySoundToSet(m_creature, SAY_KALECGOS_LETGO); m_uiKalecgosAnvenaTimer = 6000; break; case 5: DoPlaySoundToSet(m_creature, SAY_ANVEENA_LOST); m_uiKalecgosAnvenaTimer = 4000; break; case 4: DoPlaySoundToSet(m_creature, SAY_KALECGOS_FOCUS); m_uiKalecgosAnvenaTimer = 8000; break; case 3: DoPlaySoundToSet(m_creature, SAY_ANVEENA_KALEC); m_uiKalecgosAnvenaTimer = 5000; break; case 6: DoPlaySoundToSet(m_creature, SAY_KALECGOS_FATE); m_uiKalecgosAnvenaTimer = 5000; break; case 7: DoPlaySoundToSet(m_creature, SAY_ANVEENA_GOODBYE); m_creature->CastSpell(m_creature, SPELL_SACRIFICE_OF_ANVEENA, false); m_uiKalecgosAnvenaTimer = 5000; break; case 9: DoPlaySoundToSet(m_creature, SAY_KALECGOS_GOODBYE); ; m_bIsAnvena = false; break; case 8: DoPlaySoundToSet(m_creature, SAY_KALECGOS_ENCOURAGE); m_uiKalecgosAnvenaTimer = 14000; break; } ++m_uiKalecgosAnvenaCount; } m_uiKalecgosAnvenaTimer -= diff; //Kalecgos Event working if((m_uiKalecgosTimer < diff) && !m_bIsKalecgosSpawned) { DoPlaySoundToSet(m_creature, SAY_KALECGOS_JOIN); Kalecgos = m_creature->SummonCreature(ID_KALECGOS, m_creature->GetPositionX()-25, m_creature->GetPositionY()-25, m_creature->GetPositionZ()+10, 0.686f, TEMPSUMMON_TIMED_DESPAWN, 600000); Kalecgos->setFaction(35); //Kalecgos need to start shhooting arcane bolt into Kiljaeden //Dragon->AI()->AttackStart(m_creature); m_bIsKalecgosSpawned = true; }m_uiKalecgosTimer -= diff; //Shield Orb At Start each phases working /* if(m_uiShieldOrbTimer < diff && !m_bPhase5) { uint8 l=1; if(m_bPhase3) l=2; if(m_bPhase4) l=3; for(uint8 k=0; k<l; ++k) { Creature* ShieldOrb = m_creature->SummonCreature(ID_SHIELDORB, m_creature->GetPositionX()+urand(1,15), m_creature->GetPositionY()+urand(1,15), m_creature->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); if(ShieldOrb) ShieldOrb->AI()->AttackStart(m_creature->getVictim()); } m_uiShieldOrbTimer = 50000; }else m_uiShieldOrbTimer -= diff;*/ //Sinister Reflects Attack Spell Timer if(m_uiSinnisterCastTimer < diff) { uint8 m_uiSinisterCount = 4; /*if(m_bPhase3) m_uiSinisterCount = 4; if(m_bPhase4) m_uiSinisterCount = 8; if(m_bPhase5) m_uiSinisterCount = 12;*/ for(uint8 i=0; i<m_uiSinisterCount; ++i) { if(Unit* Sinister = Unit::GetUnit(*m_creature, m_uiSinisterGUID[i][0])) { if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) Sinister->CastSpell(target, m_uiSinisterGUID[i][1], true); } } m_uiSinnisterCastTimer = 8000; }else m_uiSinnisterCastTimer -= diff; //Phase4 //armageddon if((m_uiAramageddonTimer < diff) && m_bPhase4) { uint8 h=3; if(m_bPhase5) h=5; if(!m_bPhase5 && m_bDarknessOfSoulsCasting) h=0; for(uint8 i=0; i<h; ++i) { if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) Creature* Armagedon = m_creature->SummonCreature(ID_ARMAGEDON, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 15000); } m_uiAramageddonTimer = 14000; }else m_uiAramageddonTimer -= diff; if((m_uiShadowSpikeEndsTimer < diff) && m_bShadowSpikeEnds && m_bPhase3) { if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) { cShadowSpike = m_creature->SummonCreature(ID_SHADOWSPIKE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 6000); cShadowSpike->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); cShadowSpike->setFaction(14); //target->CastSpell(target, SPELL_SHADOWSPIKE_EXP, false); } ++m_uiSpikesCount; if(m_uiSpikesCount > 9) m_bShadowSpikeEnds = false; m_uiShadowSpikeEndsTimer = 3000; }else m_uiShadowSpikeEndsTimer -= diff; if(m_bShadowSpikeEnds) return; if(m_uiDarknessExplosionTimer < diff && m_bDarknessOfSoulsCasting) { m_creature->CastSpell(m_creature->getVictim(), SPELL_DARKNESS_EXPLOSION, true); m_bDarknessOfSoulsCasting = false; m_uiDarknessExplosionTimer = 600000; m_uiDarknessOfSoulsTimer = 45000; if(m_bPhase5) m_uiDarknessOfSoulsTimer = 25000; }else m_uiDarknessExplosionTimer -= diff; if(m_bDarknessOfSoulsCasting) return; // darkness of a thousand souls from phase 3 on if(m_uiDarknessOfSoulsTimer < diff && m_bPhase3) { switch (rand()%3) { case 0: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS3); break; } m_creature->CastSpell(m_creature, SPELL_DARKNESS_OF_SOULS, true); m_bDarknessOfSoulsCasting = true; m_uiDarknessExplosionTimer = 8500; }else m_uiDarknessOfSoulsTimer -= diff; // After Each Phase Dragons Are Spawned if((m_uiOrbTimer < diff) && !m_bBoolOrb) { for(uint8 i=0; i<4; ++i) DragonGUID[i] = 0; switch (rand()%4) { case 0: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY3); break; case 3: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY4); break; } uint8 m_uiMaxDragons = 1; if(m_bPhase5) m_uiMaxDragons = 4; for(uint8 i=0; i<m_uiMaxDragons; ++i) { Creature* Dragon = m_creature->SummonCreature(ID_DRAGON, m_creature->GetPositionX()+urand(5,20), m_creature->GetPositionY()+urand(5,20), m_creature->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 20000); DragonGUID[i] = Dragon->GetGUID(); } m_bBoolOrb = true; }else m_uiOrbTimer -= diff; //FireBloom Damage WorkArround if (m_uiFireBloomCheck < diff) { if(m_uiFireBloomCount < 10) for(uint8 i=0; i<5; ++i) { if(Unit* FireTarget = Unit::GetUnit(*m_creature, m_uiFireBloomTarget[i])) FireTarget->CastSpell(FireTarget, SPELL_FIREBLOOM_EFF, true); } ++m_uiFireBloomCount; m_uiFireBloomCheck = 2000; }else m_uiFireBloomCheck -= diff; //Phase 3 init if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 85) && !m_bPhase3) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE3); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),0,4); m_creature->MonsterYell("entering phase 3",LANG_UNIVERSAL,0); m_uiSinnisterCastTimer = 10000; m_uiShadowSpikeTimer = 30000; m_uiFlameDartTimer = 40000; m_uiDarknessOfSoulsTimer = 45000; m_bShadowSpikeEnds = false; m_bDarknessOfSoulsCasting = false; m_bPhase3 = true; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; } //phase 4 init if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 55) && !m_bPhase4) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE4); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),4,8); m_creature->MonsterYell("entering phase 4",LANG_UNIVERSAL,0); m_uiAramageddonTimer = 2000; //100% ok m_bPhase4 = true; m_uiDarknessOfSoulsTimer = 45000; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; } //phase 5 init if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 25) && !m_bPhase5) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE5); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),8,12); m_creature->MonsterYell("entering phase 5",LANG_UNIVERSAL,0); m_uiShadowSpikeTimer = 1000; m_uiDarknessOfSoulsTimer = 45000; m_bPhase5 = true; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; //Kalecgos and Anvena Event m_uiKalecgosAnvenaTimer = 20000; m_bIsAnvena = true; m_uiKalecgosAnvenaCount = 0; Creature* Anveena = m_creature->SummonCreature(ID_ANVEENA, m_creature->GetPositionX()+urand(20,30), m_creature->GetPositionY()+urand(20,30), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 120000); Anveena->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Anveena->setFaction(35); } //spells used from phase 3 on if(m_bPhase3) { if(m_uiShadowSpikeTimer < diff) { DoCast(m_creature->getVictim(), SPELL_SHADOWSPIKE); m_bShadowSpikeEnds = true; m_uiShadowSpikeEndsTimer = 500; m_uiSpikesCount = 0; m_uiShadowSpikeTimer = 90000; }else m_uiShadowSpikeTimer -= diff; //flame dart if(m_uiFlameDartTimer < diff ) { DoCast(m_creature->getVictim(), SPELL_FLAMEDARTS); m_uiFlameDartTimer = 33000; }else m_uiFlameDartTimer -= diff; } //Phase2 // legion lightning all phases if(m_uiLegionLightingTimer < diff) { DoCast(m_creature->getVictim(), SPELL_LEGION_LIGHTING); m_uiLegionLightingTimer = 11000; }else m_uiLegionLightingTimer -= diff; // fire bloom all phases if(m_uiFireBloomTimer < diff) { for(uint8 i=0; i<5; ++i) { Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); m_uiFireBloomTarget[i] = target->GetGUID(); m_uiFireBloomCount = 0; //DoCast(target, SPELL_FIREBLOOM, true); } m_uiFireBloomTimer = 25000; }else m_uiFireBloomTimer -= diff; // soul flay all phases if(m_uiSoulFlayTimer < diff) { DoCast(m_creature->getVictim(), SPELL_SOULFLAY); m_uiSoulFlayTimer = 7000; }else m_uiSoulFlayTimer -= diff; DoMeleeAttackIfReady(); }
void WorldSession::HandlePetAction(WorldPacket& recv_data) { ObjectGuid petGuid; uint32 data; ObjectGuid targetGuid; recv_data >> petGuid; recv_data >> data; recv_data >> targetGuid; uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); // delete = 0x07 CastSpell = C1 DETAIL_LOG("HandlePetAction: %s flag is %u, spellid is %u, target %s.", petGuid.GetString().c_str(), uint32(flag), spellid, targetGuid.GetString().c_str()); // used also for charmed creature/player Unit* petUnit = _player->GetMap()->GetUnit(petGuid); if (!petUnit) { sLog.outError("HandlePetAction: %s not exist.", petGuid.GetString().c_str()); return; } if (_player->GetObjectGuid() != petUnit->GetMasterGuid()) { sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), _player->GetGuidStr().c_str()); return; } if (!petUnit->isAlive()) return; CharmInfo* charmInfo = petUnit->GetCharmInfo(); if (!charmInfo) { sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", petUnit->GetGUIDLow(), petUnit->GetTypeId()); return; } Pet* pet = nullptr; Creature* creature = nullptr; if (petUnit->GetTypeId() == TYPEID_UNIT) { creature = static_cast<Creature*>(petUnit); if (creature->IsPet()) { pet = static_cast<Pet*>(petUnit); if (pet->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) return; } } if (!pet) { if (petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { // possess case if (flag != uint8(ACT_COMMAND)) { sLog.outError("PetHAndler: unknown PET flag Action %i and spellid %i. For possessed %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str()); return; } switch (spellid) { case COMMAND_STAY: case COMMAND_FOLLOW: charmInfo->SetCommandState(CommandStates(spellid)); break; case COMMAND_ATTACK: { Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; if (targetUnit && targetUnit != petUnit && petUnit->CanAttack(targetUnit)) { // This is true if pet has no target or has target but targets differs. if (petUnit->getVictim() != targetUnit) petUnit->Attack(targetUnit, true); } break; } case COMMAND_DISMISS: _player->BreakCharmOutgoing(petUnit); break; default: sLog.outError("PetHandler: Not allowed action %i and spellid %i. Pet %s owner is %s", uint32(flag), spellid, petUnit->GetGuidStr().c_str(), _player->GetGuidStr().c_str()); break; } } if (!petUnit->HasCharmer()) return; } switch (flag) { case ACT_COMMAND: // 0x07 switch (spellid) { case COMMAND_STAY: // flat=1792 // STAY { if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { petUnit->StopMoving(); petUnit->GetMotionMaster()->Clear(); } petUnit->AttackStop(true, true); charmInfo->SetCommandState(COMMAND_STAY); break; } case COMMAND_FOLLOW: // spellid=1792 // FOLLOW { if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { petUnit->StopMoving(); petUnit->GetMotionMaster()->Clear(); charmInfo->SetIsRetreating(true); } petUnit->AttackStop(true, true); charmInfo->SetCommandState(COMMAND_FOLLOW); break; } case COMMAND_ATTACK: // spellid=1792 // ATTACK { charmInfo->SetIsRetreating(); charmInfo->SetSpellOpener(); Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; if (targetUnit && targetUnit != petUnit && petUnit->CanAttack(targetUnit) && targetUnit->isInAccessablePlaceFor((Creature*)petUnit)) { // This is true if pet has no target or has target but targets differs. if (petUnit->getVictim() != targetUnit) { petUnit->AttackStop(); if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { petUnit->GetMotionMaster()->Clear(); petUnit->AI()->AttackStart(targetUnit); if (pet) { // 10% chance to play special warlock pet attack talk, else growl if (pet->getPetType() == SUMMON_PET && roll_chance_i(10)) pet->SendPetTalk((uint32)PET_TALK_ATTACK); pet->SendPetAIReaction(); } } else petUnit->Attack(targetUnit, true); } } break; } case COMMAND_DISMISS: // dismiss permanent pet, remove temporary pet, uncharm unit { if (pet) { pet->PlayDismissSound(); // No action for Hunter pets, Hunters must use their Dismiss Pet spell if (pet->getPetType() != HUNTER_PET) pet->ForcedDespawn(); } else { // dismissing a summoned pet is like killing them (this prevents returning a soulshard...) if (creature && creature->IsTemporarySummon()) creature->ForcedDespawn(); else _player->BreakCharmOutgoing(petUnit); } charmInfo->SetStayPosition(); break; } default: sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } break; case ACT_REACTION: // 0x6 switch (spellid) { case REACT_PASSIVE: // passive { petUnit->AttackStop(true, true); charmInfo->SetSpellOpener(); } case REACT_DEFENSIVE: // recovery case REACT_AGGRESSIVE: // activete { petUnit->AI()->SetReactState(ReactStates(spellid)); break; } } break; case ACT_DISABLED: // 0x81 spell (disabled), ignore case ACT_PASSIVE: // 0x01 case ACT_ENABLED: // 0xC1 spell { charmInfo->SetIsRetreating(); charmInfo->SetSpellOpener(); Unit* unit_target = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; // do not cast unknown spells SpellEntry const* spellInfo = sSpellTemplate.LookupEntry<SpellEntry>(spellid); if (!spellInfo) { sLog.outError("WORLD: unknown PET spell id %i", spellid); return; } // do not cast not learned spells if (IsPassiveSpell(spellInfo) || !petUnit->HasSpell(spellid)) return; if (!petUnit->IsSpellReady(*spellInfo)) return; for (unsigned int i : spellInfo->EffectImplicitTargetA) { if (i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_SRC_LOC || i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_DEST_LOC || i == TARGET_ENUM_UNITS_ENEMY_AOE_AT_DYNOBJ_LOC) return; } petUnit->clearUnitState(UNIT_STAT_MOVING); uint32 flags = TRIGGERED_NONE; if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) flags |= TRIGGERED_PET_CAST; Spell* spell = new Spell(petUnit, spellInfo, flags); SpellCastResult result = spell->CheckPetCast(unit_target); const SpellRangeEntry* sRange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); if (unit_target && !(petUnit->IsWithinDistInMap(unit_target, sRange->maxRange) && petUnit->IsWithinLOSInMap(unit_target)) && petUnit->CanAttackNow(unit_target)) { charmInfo->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange); spell->finish(false); delete spell; petUnit->AttackStop(); if (!petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { petUnit->GetMotionMaster()->Clear(); petUnit->AI()->AttackStart(unit_target); // 10% chance to play special warlock pet attack talk, else growl if (pet && pet->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10)) petUnit->SendPetTalk((uint32)PET_TALK_ATTACK); petUnit->SendPetAIReaction(); } else petUnit->Attack(unit_target, true); return; } // auto turn to target unless possessed if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !petUnit->hasUnitState(UNIT_STAT_POSSESSED)) { if (unit_target) { petUnit->SetInFront(unit_target); if (unit_target->GetTypeId() == TYPEID_PLAYER) petUnit->SendCreateUpdateToPlayer((Player*)unit_target); } else if (Unit* unit_target2 = spell->m_targets.getUnitTarget()) { petUnit->SetInFront(unit_target2); if (unit_target2->GetTypeId() == TYPEID_PLAYER) petUnit->SendCreateUpdateToPlayer((Player*)unit_target2); } if (Unit* powner = petUnit->GetMaster()) if (powner->GetTypeId() == TYPEID_PLAYER) petUnit->SendCreateUpdateToPlayer((Player*)powner); result = SPELL_CAST_OK; } if (result == SPELL_CAST_OK) { charmInfo->SetSpellOpener(); spell->SpellStart(&(spell->m_targets)); } else { if (creature && creature->IsSpellReady(*spellInfo)) GetPlayer()->SendClearCooldown(spellid, petUnit); charmInfo->SetSpellOpener(); spell->finish(false); delete spell; } break; } default: sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } }
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 UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if(m_uiIntroTimer < uiDiff) { if(m_bIsIntroNow) { m_creature->StopMoving(); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); switch(m_uiIntroCount) { case 0: DoPlaySoundToSet(m_creature, SOUND_MADR_ICE_BARRIER); m_uiIntroTimer = 6000; break; case 1: DoPlaySoundToSet(m_creature, SOUND_MADR_INTRO); m_uiIntroTimer = 5000; break; case 2: DoPlaySoundToSet(m_creature, SOUND_INTRO); m_uiIntroTimer = 6000; break; case 3: DoPlaySoundToSet(m_creature, SOUND_MADR_ICE_BLOCK); m_uiIntroTimer = 4000; break; case 4: DoPlaySoundToSet(m_creature, SOUND_INTRO_BREAK_ICE); m_uiIntroTimer = 5000; break; case 5: DoPlaySoundToSet(m_creature, SOUND_MADR_TRAP); m_uiIntroTimer = 5000; break; case 6: DoPlaySoundToSet(m_creature, SOUND_INTRO_CHARGE); m_uiIntroTimer = 5000; break; case 7: DoPlaySoundToSet(m_creature, SOUND_MADR_DEATH); m_uiIntroTimer = 5000; break; case 8: DoPlaySoundToSet(m_creature, SOUND_INTRO_KILL_MADRIGOSA); m_uiIntroTimer = 6000; break; case 9: DoPlaySoundToSet(m_creature, SOUND_INTRO_TAUNT); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_uiBerserkTimer = 360000; m_bIsIntroNow = false; break; } ++m_uiIntroCount; } }else m_uiIntroTimer -= uiDiff; if(m_bIsIntroNow) return; if (m_uiBurnCheckTimer < uiDiff) { std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *BurnedPlayer = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); if (BurnedPlayer && BurnedPlayer->GetTypeId() == TYPEID_PLAYER && BurnedPlayer->HasAura(SPELL_BURN_AURA)) { std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *TargetedPlayer = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); if (TargetedPlayer && TargetedPlayer->GetTypeId() == TYPEID_PLAYER && TargetedPlayer->IsWithinDistInMap(BurnedPlayer, 6) && !TargetedPlayer->HasAura(SPELL_BURN_AURA)) TargetedPlayer->CastSpell(TargetedPlayer,SPELL_BURN_AURA,true); } } } m_uiBurnCheckTimer = 1000; }else m_uiBurnCheckTimer -= uiDiff; if (m_uiLoveTimer < uiDiff) { switch(urand(0, 2)) { case 0: DoScriptText(YELL_LOVE1, m_creature); break; case 1: DoScriptText(YELL_LOVE2, m_creature); break; case 2: DoScriptText(YELL_LOVE3, m_creature); break; } m_uiLoveTimer = urand(15000, 23000); } else m_uiLoveTimer -= uiDiff; if (m_uiSlashTimer < uiDiff) { if (Unit* pTarget = m_creature->getVictim()) DoCast(pTarget,SPELL_METEOR_SLASH); m_uiSlashTimer = 11000; }else m_uiSlashTimer -= uiDiff; if (m_uiStompTimer < uiDiff) { if (Unit* pTarget = m_creature->getVictim()) { DoCast(pTarget,SPELL_STOMP); if (pTarget->HasAura(SPELL_BURN_AURA,0)) pTarget->RemoveAurasDueToSpell(SPELL_BURN_AURA); } m_uiStompTimer = 30000; } else m_uiStompTimer -= uiDiff; if (m_uiBurnTimer < uiDiff) { if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) { DoCast(target,SPELL_BURN); target->CastSpell(target,SPELL_BURN_AURA, true); } m_uiBurnTimer = 60000; } else m_uiBurnTimer -= uiDiff; if (m_uiBerserkTimer < uiDiff) { DoScriptText(YELL_BERSERK, m_creature); DoCast(m_creature,SPELL_BERSERK); m_uiBerserkTimer = 20000; } else m_uiBerserkTimer -= uiDiff; DoMeleeAttackIfReady(); }
void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner) { if (!i_target.isValid() || !i_target->IsInWorld()) return; if (owner.hasUnitState(UNIT_STAT_NOT_MOVE)) return; if (owner.GetTypeId() == TYPEID_PLAYER && ((Player*)&owner)->IsBot()) { Unit* bot = (Unit*)&owner; float x, y, z; if (i_target.getTarget()==bot) { // prevent redundant micro-movement for bots, other followers. if (i_offset && bot->IsWithinDistInMap(bot, i_x, i_y, i_z, 2*i_offset)) { if (!owner.movespline->Finalized()) return; owner.GetPosition(x, y, z); } else { x = i_x; y = i_y; z = i_z; } } else { // prevent redundant micro-movement for bots, other followers. if (i_offset && !i_target->GetTransport() && i_target->IsWithinDistInMap(&owner,2*i_offset)) { if (!owner.movespline->Finalized()) return; owner.GetPosition(x, y, z); } else if (!i_offset) { // to nearest contact position i_target->GetContactPoint( &owner, x, y, z ); } else { // to at i_offset distance from target and i_angle from target facing i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle, &owner); } } /*bool forceDest = false; // allow bots following their leader to cheat while generating paths (bypass mmaps) if(owner.GetTypeId() == TYPEID_PLAYER && ((Player*)&owner)->IsBot() && owner.hasUnitState(UNIT_STAT_FOLLOW)) forceDest = true;*/ if(!i_path) i_path = new PathInfo(&owner); /*// allow pets following their master to cheat while generating paths bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet() && owner.hasUnitState(UNIT_STAT_FOLLOW));*/ i_path->calculate(x, y, z, false, false); if(i_path->getPathType() & PATHFIND_NOPATH) { i_path->calculate(x, y, z, false, true); if(i_path->getPathType() & PATHFIND_NOPATH) { ((Player*)&owner)->TeleportTo(((Player*)&owner)->GetMapId(), x, y, z, 0.0f); return; } } D::_addUnitStateMove(owner); i_targetReached = false; i_recalculateTravel = false; Movement::MoveSplineInit init(owner); init.MovebyPath(i_path->getPath()); init.SetWalk(((D*)this)->EnableWalking()); init.Launch(); } else { float x, y, z; // prevent redundant micro-movement for pets, other followers. if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset)) { if (!owner.movespline->Finalized()) return; owner.GetPosition(x, y, z); } else if (!i_offset) { // to nearest contact position i_target->GetContactPoint( &owner, x, y, z ); } else { // to at i_offset distance from target and i_angle from target facing i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle, &owner); } /* We MUST not check the distance difference and avoid setting the new location for smaller distances. By that we risk having far too many GetContactPoint() calls freezing the whole system. In TargetedMovementGenerator<T>::Update() we check the distance to the target and at some range we calculate a new position. The calculation takes some processor cycles due to vmaps. If the distance to the target it too large to ignore, but the distance to the new contact point is short enough to be ignored, we will calculate a new contact point each update loop, but will never move to it. The system will freeze. ralf //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE; if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) return; */ if(!i_path) i_path = new PathInfo(&owner); // allow pets following their master to cheat while generating paths bool forceDest = (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->IsPet() && owner.hasUnitState(UNIT_STAT_FOLLOW)); i_path->calculate(x, y, z, false, forceDest); if(i_path->getPathType() & PATHFIND_NOPATH) return; D::_addUnitStateMove(owner); i_targetReached = false; i_recalculateTravel = false; Movement::MoveSplineInit init(owner); init.MovebyPath(i_path->getPath()); init.SetWalk(((D*)this)->EnableWalking()); init.Launch(); } }
void UpdateAI(const uint32 diff) { // return since we have no target if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_creature->HasAura(SPELL_BANISH)) { if (pInstance && pInstance->GetData(DATA_SACROLASH_EVENT) == DONE) { m_creature->SetVisibility(VISIBILITY_ON); m_creature->RemoveAurasDueToSpell(SPELL_BANISH); } if (pInstance && pInstance->GetData(DATA_EREDAR_TWINS_EVENT) == NOT_STARTED) { m_creature->SetVisibility(VISIBILITY_ON); m_creature->RemoveAurasDueToSpell(SPELL_BANISH); ((boss_alythessAI*)m_creature->AI())->Reset(); m_creature->AI()->EnterEvadeMode(); } return; } /* Banish at 1% hp working */ if (((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 1) && !m_bIsBanished) { if (pInstance && pInstance->GetData(DATA_SACROLASH_EVENT) != DONE) { pInstance->SetData(DATA_ALYSTHESS_EVENT, DONE); DoCast(m_creature, SPELL_BANISH, true); m_creature->SetVisibility(VISIBILITY_OFF); } m_bIsBanished = true; } if(m_uiConfCount = 10) { if(Unit* pPlayer = m_creature->GetMap()->GetUnit(m_uiConfTargetGUID)) pPlayer->RemoveAurasDueToSpell(AURA_CONF,0); ++m_uiConfCount; } if(m_uiConfCount < 10) { if(m_uiConfTimer < diff) { if(Unit* pPlayer = m_creature->GetMap()->GetUnit(m_uiConfTargetGUID)) { pPlayer->CastSpell(pPlayer, SPELL_CONFLAGRATION_DEV, true); std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *BurnedPlayer = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); if (BurnedPlayer && BurnedPlayer->GetTypeId() == TYPEID_PLAYER && BurnedPlayer->IsWithinDistInMap(pPlayer, 8)) { BurnedPlayer->CastSpell(BurnedPlayer, SPELL_CONFLAGRATION_DEV, true); } } } ++m_uiConfCount; m_uiConfTimer = 1000; }else m_uiConfTimer -= diff; } // does alysthes stand and cast spells, after someone is out of range she follows victim if(Unit *who = m_creature->getVictim()) { if(who && who->IsInRange(m_creature, 0.0f, 15.0f, false)) m_creature->StopMoving(); else m_creature->CanFreeMove(); } // enrage if(m_uiEnrageTimer < diff && !m_bIsEnraged) { DoScriptText(YELL_TWINS_ENRAGE, m_creature); DoCast(m_creature, SPELL_TWINS_ENRAGE); m_bIsEnraged = true; }else m_uiEnrageTimer -= diff; // 100% if(m_uiPyrogenicsTimer < diff) { DoCast(m_creature, SPELL_PYROGENICS); m_uiPyrogenicsTimer = 35000; }else m_uiPyrogenicsTimer -= diff; // 100% if(m_uiFlameTouchedTimer < diff) { if (Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) victim->CastSpell(victim, SPELL_FLAME_TOUCHED, true); m_uiFlameTouchedTimer = 30000; }else m_uiFlameTouchedTimer -= diff; // in progress if(m_uiConflagrationTimer < diff) { m_uiConfTargetGUID = 0; if (Unit *victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { m_uiConfTargetGUID = victim->GetGUID(); victim->CastSpell(victim, AURA_CONF, true); victim->CastSpell(victim, SPELL_CONFLAGRATION_DEV, true); } m_uiConfTimer = 1000; m_uiConfCount = 0; m_uiConflagrationTimer = 20000 + rand()%1000; }else m_uiConflagrationTimer -= diff; // 50% nie zostawia sumona pod soba if(m_uiBlazeTimer < diff) { if(Unit *victim = m_creature->getVictim()) DoCast(victim, SPELL_BLAZE); m_uiBlazeTimer = urand(5000,10000); }else m_uiBlazeTimer -= diff; // 100% if(m_uiFlameSearTimer < diff) { uint8 i = urand(3,5); for (uint8 k=0; k<i; ++k) if (Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) m_creature->CastSpell(victim, SPELL_FLAME_SEAR, true); m_uiFlameSearTimer = 30000; }else m_uiFlameSearTimer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 uiDiff) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; switch (stage) { case 0: { bsw->timedCast(SPELL_FEROCIOUS_BUTT, uiDiff); bsw->timedCast(SPELL_ARCTIC_BREATH, uiDiff); bsw->timedCast(SPELL_WHIRL, uiDiff); if (bsw->timedQuery(SPELL_MASSIVE_CRASH, uiDiff)) stage = 1; bsw->timedCast(SPELL_FROTHING_RAGE, uiDiff); DoMeleeAttackIfReady(); break; } case 1: { if (bsw->doCast(SPELL_MASSIVE_CRASH) == CAST_OK) stage = 2; break; } case 2: { if (pTarget = bsw->SelectUnit()) { TrampleCasted = false; m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); stage = 3; bsw->resetTimer(SPELL_TRAMPLE); DoScriptText(-1713506,m_creature,pTarget); SetCombatMovement(false); m_creature->GetMotionMaster()->MoveIdle(); } break; } case 3: { if (bsw->timedQuery(SPELL_TRAMPLE,uiDiff)) { pTarget->GetPosition(fPosX, fPosY, fPosZ); TrampleCasted = false; MovementStarted = true; m_creature->GetMotionMaster()->MovePoint(1, fPosX, fPosY, fPosZ); DoScriptText(-1713508,m_creature); bsw->doCast(SPELL_ADRENALINE); stage = 4; } break; } case 4: { if (MovementStarted) { Map* pMap = m_creature->GetMap(); Map::PlayerList const &lPlayers = pMap->GetPlayers(); for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { Unit* pPlayer = itr->getSource(); if (!pPlayer) continue; if (pPlayer->isAlive() && pPlayer->IsWithinDistInMap(m_creature, 5.0f)) { bsw->doCast(SPELL_TRAMPLE, pPlayer); TrampleCasted = true; MovementStarted = false; m_creature->GetMotionMaster()->MovementExpired(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } } } else stage = 5; if (TrampleCasted) stage = 5; break; } case 5: { if (!TrampleCasted) { bsw->doCast(SPELL_STAGGERED_DAZE); DoScriptText(-1713507,m_creature); } MovementStarted = false; m_creature->GetMotionMaster()->MovementExpired(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); SetCombatMovement(true); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); stage = 0; break; } } }
void UpdateAI(const uint32 uiDiff) { //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; //m_uiEarthquake_Timer if (m_uiEarthquake_Timer < uiDiff) { if (!m_bEarthquake) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_EARTHQUAKE); m_bEarthquake = true; m_uiEarthquake_Timer = 5000; } else { DoScriptText(urand(0,1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); //north m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A6,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A7,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A8,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A9,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A10,true); //south m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B6,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B7,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B8,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B9,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B10,true); DoScriptText(EMOTE_EARTHQUAKE, m_creature); m_bEarthquake = false; m_uiEarthquake_Timer = urand(40000, 45000); } }else m_uiEarthquake_Timer -= uiDiff; //m_uiTidalWave_Timer if (m_uiTidalWave_Timer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_TIDAL_WAVE); m_uiTidalWave_Timer = 20000; }else m_uiTidalWave_Timer -= uiDiff; if (!m_bPhase2) { //m_uiWateryGrave_Timer if (m_uiWateryGrave_Timer < uiDiff) { //Teleport 4 players under the waterfalls for(uint8 i = 0; i < 4; ++i) { Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1); if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER && !pTarget->HasAuraType(SPELL_AURA_MOD_STUN) && pTarget->IsWithinDistInMap(m_creature, 45.0f)) { switch(i) { case 0: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_1,false); break; case 1: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_2,false); break; case 2: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_3,false); break; case 3: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_4,false); break; } } } DoScriptText(urand(0,1) ? SAY_SUMMON_BUBL1 : SAY_SUMMON_BUBL2, m_creature); DoScriptText(EMOTE_WATERY_GRAVE, m_creature); m_uiWateryGrave_Timer = 30000; }else m_uiWateryGrave_Timer -= uiDiff; //Start Phase2 if (m_creature->GetHealthPercent() < 25.0f) m_bPhase2 = true; } else { //m_uiWateryGlobules_Timer if (m_uiWateryGlobules_Timer < uiDiff) { DoScriptText(EMOTE_WATERY_GLOBULES, m_creature); m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_1,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_2,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_3,true); m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_4,false); m_uiWateryGlobules_Timer = 25000; }else m_uiWateryGlobules_Timer -= uiDiff; } DoMeleeAttackIfReady(); }
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 UpdateAI(const uint32 uiDiff) { if (m_bIsActiveCheck) { if (!m_bIsActived && Active_Timer < uiDiff) { m_bIsActived = true; Active_Timer = 1000; }else Active_Timer -= uiDiff; } else { if (Active_Timer < uiDiff) { if(m_pInstance) { bool m_bIsAlive = false; Creature* pStalagg; Creature* pFeugen; if (pStalagg = ((Creature*)Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_STALAGG)))) if (pStalagg->isAlive()) m_bIsAlive = true; if (pFeugen = ((Creature*)Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_FEUGEN)))) if (pFeugen->isAlive()) m_bIsAlive = true; if (!m_bIsAlive) { m_bIsActiveCheck = true; Active_Timer = 15000; } else { if (pStalagg->isInCombat() && pFeugen->isInCombat()) { if (SwitchTarget_Timer < uiDiff) { Unit* pStalaggTarget; Unit* pFeugenTarget; float StalaggTargetThreat; float FeugenTargetThreat; // Get Stalagg's target threat if (pStalagg && pStalagg->isAlive()) { if (pStalaggTarget = pStalagg->getVictim()) StalaggTargetThreat = m_creature->getThreatManager().getThreat(pStalaggTarget); } // Get Feugen's target threat if (pFeugen && pFeugen->isAlive()) { if (pFeugenTarget = pFeugen->getVictim()) FeugenTargetThreat = m_creature->getThreatManager().getThreat(pFeugenTarget); } // Switch Feugen's target from Stalagg if (pStalagg && pStalagg->isAlive()) { if (pFeugen && pFeugen->isAlive()) { HostilReference* ref = pFeugen->getThreatManager().getOnlineContainer().getReferenceByTarget(pFeugenTarget); if (ref) { pStalagg->CastSpell(pFeugenTarget, 54517, true); ((Player*)pFeugenTarget)->TeleportTo(pFeugenTarget->GetMapId(), pStalagg->GetPositionX(), pStalagg->GetPositionY(), pStalagg->GetPositionZ(), 0, TELE_TO_NOT_LEAVE_COMBAT); ref->removeReference(); pStalagg->AddThreat(pFeugenTarget, FeugenTargetThreat); pStalagg->AI()->AttackStart(pFeugenTarget); } } } // Switch Stalagg's target from Feugen if (pFeugen && pFeugen->isAlive()) { if (pStalagg && pStalagg->isAlive()) { HostilReference* ref = pStalagg->getThreatManager().getOnlineContainer().getReferenceByTarget(pStalaggTarget); if (ref) { pFeugen->CastSpell(pStalaggTarget, 54517, true); ((Player*)pStalaggTarget)->TeleportTo(pStalaggTarget->GetMapId(), pFeugen->GetPositionX(), pFeugen->GetPositionY(), pFeugen->GetPositionZ(), 0, TELE_TO_NOT_LEAVE_COMBAT); ref->removeReference(); pFeugen->AddThreat(pStalaggTarget, StalaggTargetThreat); pFeugen->AI()->AttackStart(pStalaggTarget); } } } SwitchTarget_Timer = 20000; }else SwitchTarget_Timer -= uiDiff; } else if (pStalagg->isInCombat() || pFeugen->isInCombat()) { if (m_pInstance) m_pInstance->SetData(TYPE_THADDIUS, IN_PROGRESS); } else if (!pStalagg->isInCombat() && !pFeugen->isInCombat()) { if (m_pInstance) m_pInstance->SetData(TYPE_THADDIUS, NOT_STARTED); } Active_Timer = 1000; } } }else Active_Timer -= uiDiff; } if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; if (ChainLightning_Timer < uiDiff) { DoCast(m_creature, m_bIsHeroicMode ? H_SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING); ChainLightning_Timer = 15000; }else ChainLightning_Timer -= uiDiff; if(m_bIsPolarityShift) { // workaround for POLARITY_SHIFT if (PolarityShift_Timer < uiDiff) { Map *map = m_creature->GetMap(); if (map->IsDungeon()) { Map::PlayerList const &PlayerList = map->GetPlayers(); if (PlayerList.isEmpty()) return; for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (i->getSource()->isAlive() && i->getSource()->isTargetableForAttack()) { switch(rand()%2) { case 0: if (i->getSource()->HasAura(SPELL_CHARGE_NEGATIVE_NEARDMG)) i->getSource()->RemoveAurasDueToSpell(SPELL_CHARGE_NEGATIVE_NEARDMG); i->getSource()->CastSpell(i->getSource(), SPELL_CHARGE_POSITIVE_NEARDMG, true); break; case 1: if (i->getSource()->HasAura(SPELL_CHARGE_POSITIVE_NEARDMG)) i->getSource()->RemoveAurasDueToSpell(SPELL_CHARGE_POSITIVE_NEARDMG); i->getSource()->CastSpell(i->getSource(), SPELL_CHARGE_NEGATIVE_NEARDMG, true); break; } } } m_bIsPolarityShift = false; PolarityShift_Timer = 27000; }else PolarityShift_Timer -= uiDiff; } else { if(PolarityShift_Timer < uiDiff) { DoCast(m_creature, SPELL_POLARITY_SHIFT); // need core support m_bIsPolarityShift = true; PolarityShift_Timer = 3000; }else PolarityShift_Timer -= uiDiff; } if (Enrage_Timer < uiDiff) { DoCast(m_creature, SPELL_BESERK); Enrage_Timer = 300000; }else Enrage_Timer -= uiDiff; if (Scream_Timer < uiDiff) { switch(rand()%4) { case 0: DoScriptText(SAY_SCREAM1, m_creature);break; case 1: DoScriptText(SAY_SCREAM2, m_creature);break; case 2: DoScriptText(SAY_SCREAM3, m_creature);break; case 3: DoScriptText(SAY_SCREAM4, m_creature);break; } Scream_Timer = 60000+rand()%30000; }else Scream_Timer -= uiDiff; if (RangeCheck_Timer < uiDiff) { m_bInMeleeRange = false; std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit* pTarget = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); //if in melee range if (pTarget && pTarget->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) { m_bInMeleeRange = true; break; } } if (!m_bInMeleeRange) DoCast(SelectUnit(SELECT_TARGET_TOPAGGRO,0), SPELL_BALL_LIGHTNING); RangeCheck_Timer = 2000; }else RangeCheck_Timer -= uiDiff; //if nobody is in melee range if (m_bInMeleeRange) DoMeleeAttackIfReady(); }
void UpdateAI(uint32 diff) override { if (!CanAttack && Intro) { if (AggroTimer <= diff) { CanAttack = true; me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); AggroTimer=19000; } else { AggroTimer-=diff; return; } } // to prevent abuses during phase 2 if (Phase == 2 && !me->GetVictim() && me->IsInCombat()) { EnterEvadeMode(); return; } // Return since we have no target if (!UpdateVictim()) return; if (Phase == 1 || Phase == 3) { // ShockBlastTimer if (ShockBlastTimer <= diff) { // Shock Burst // Randomly used in Phases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. DoCastVictim(SPELL_SHOCK_BLAST); me->TauntApply(me->GetVictim()); ShockBlastTimer = 1000 + rand32() % 14000; // random cooldown } else ShockBlastTimer -= diff; // StaticChargeTimer if (StaticChargeTimer <= diff) { // Static Charge // Used on random people (only 1 person at any given time) in Phases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true); if (target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); // cast Static Charge every 2 seconds for 20 seconds StaticChargeTimer = 10000 + rand32() % 20000; } else StaticChargeTimer -= diff; // EntangleTimer if (EntangleTimer <= diff) { if (!Entangle) { // Entangle // Used in Phases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. DoCastVictim(SPELL_ENTANGLE); Entangle = true; EntangleTimer = 10000; } else { CastShootOrMultishot(); Entangle = false; EntangleTimer = 20000 + rand32() % 5000; } } else EntangleTimer -= diff; // Phase 1 if (Phase == 1) { // Start phase 2 if (HealthBelowPct(70)) { // Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. Phase = 2; me->GetMotionMaster()->Clear(); DoTeleportTo(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); for (uint8 i = 0; i < 4; ++i) if (Creature* creature = me->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0)) ShieldGeneratorChannel[i] = creature->GetGUID(); Talk(SAY_PHASE2); } } // Phase 3 else { // SummonSporebatTimer if (SummonSporebatTimer <= diff) { if (Creature* sporebat = me->SummonCreature(TOXIC_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_CORPSE_DESPAWN, 0)) if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) sporebat->AI()->AttackStart(target); // summon sporebats faster and faster if (SummonSporebatStaticTimer > 1000) SummonSporebatStaticTimer -= 1000; SummonSporebatTimer = SummonSporebatStaticTimer; if (SummonSporebatTimer < 5000) SummonSporebatTimer = 5000; } else SummonSporebatTimer -= diff; } // Melee attack DoMeleeAttackIfReady(); // CheckTimer - used to check if somebody is in melee range if (CheckTimer <= diff) { bool inMeleeRange = false; std::list<HostileReference*> t_list = me->getThreatManager().getThreatList(); for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); if (target && target->IsWithinDistInMap(me, 5)) // if in melee range { inMeleeRange = true; break; } } // if nobody is in melee range if (!inMeleeRange) CastShootOrMultishot(); CheckTimer = 5000; } else CheckTimer -= diff; } // Phase 2 else { // ForkedLightningTimer if (ForkedLightningTimer <= diff) { // Forked Lightning // Used constantly in Phase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); if (!target) target = me->GetVictim(); DoCast(target, SPELL_FORKED_LIGHTNING); ForkedLightningTimer = 2000 + rand32() % 6000; } else ForkedLightningTimer -= diff; // EnchantedElementalTimer if (EnchantedElementalTimer <= diff) { me->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElementalPos][0], ElementPos[EnchantedElementalPos][1], ElementPos[EnchantedElementalPos][2], ElementPos[EnchantedElementalPos][3], TEMPSUMMON_CORPSE_DESPAWN, 0); if (EnchantedElementalPos == 7) EnchantedElementalPos = 0; else ++EnchantedElementalPos; EnchantedElementalTimer = 10000 + rand32() % 5000; } else EnchantedElementalTimer -= diff; // TaintedElementalTimer if (TaintedElementalTimer <= diff) { uint32 pos = rand32() % 8; me->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_DEAD_DESPAWN, 0); TaintedElementalTimer = 120000; } else TaintedElementalTimer -= diff; // CoilfangEliteTimer if (CoilfangEliteTimer <= diff) { uint32 pos = rand32() % 3; Creature* coilfangElite = me->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); if (coilfangElite) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) coilfangElite->AI()->AttackStart(target); else if (me->GetVictim()) coilfangElite->AI()->AttackStart(me->GetVictim()); } CoilfangEliteTimer = 45000 + rand32() % 5000; } else CoilfangEliteTimer -= diff; // CoilfangStriderTimer if (CoilfangStriderTimer <= diff) { uint32 pos = rand32() % 3; if (Creature* CoilfangStrider = me->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) CoilfangStrider->AI()->AttackStart(target); else if (me->GetVictim()) CoilfangStrider->AI()->AttackStart(me->GetVictim()); } CoilfangStriderTimer = 60000 + rand32() % 10000; } else CoilfangStriderTimer -= diff; // CheckTimer if (CheckTimer <= diff) { // Start Phase 3 if (instance->GetData(DATA_CANSTARTPHASE3)) { // set life 50% me->SetHealth(me->CountPctFromMaxHealth(50)); me->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); Talk(SAY_PHASE3); Phase = 3; // return to the tank me->GetMotionMaster()->MoveChase(me->GetVictim()); } CheckTimer = 1000; } else CheckTimer -= diff; } }
void WorldSession::HandlePetAction(WorldPacket& recv_data) { ObjectGuid petGuid; uint32 data; ObjectGuid targetGuid; float x, y, z; recv_data >> petGuid; recv_data >> data; recv_data >> targetGuid; recv_data >> x >> y >> z; uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); // delete = 0x07 CastSpell = C1 DETAIL_LOG("HandlePetAction: %s flag is %u, spellid is %u, target %s.", petGuid.GetString().c_str(), uint32(flag), spellid, targetGuid.GetString().c_str()); // used also for charmed creature/player Unit* pet = _player->GetMap()->GetUnit(petGuid); if (!pet) { sLog.outError("HandlePetAction: %s not exist.", petGuid.GetString().c_str()); return; } if (_player->GetObjectGuid() != pet->GetCharmerOrOwnerGuid()) { sLog.outError("HandlePetAction: %s isn't controlled by %s.", petGuid.GetString().c_str(), _player->GetGuidStr().c_str()); return; } if (!pet->isAlive()) return; if (pet->GetTypeId() == TYPEID_PLAYER && pet->GetCharmer()->GetTypeId() == TYPEID_PLAYER) { // controller player cannot use controlled player's spells if (flag != (ACT_COMMAND || ACT_REACTION)) return; } else if (((Creature*)pet)->IsPet()) { // pet can have action bar disabled if (((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS) return; } CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); return; } switch (flag) { case ACT_COMMAND: // 0x07 switch (spellid) { case COMMAND_STAY: // flat=1792 // STAY { pet->StopMoving(); pet->AttackStop(true, true); pet->GetMotionMaster()->Clear(); ((Pet*)pet)->SetStayPosition(true); ((Pet*)pet)->SetIsRetreating(); ((Pet*)pet)->SetSpellOpener(); charmInfo->SetCommandState(COMMAND_STAY); break; } case COMMAND_FOLLOW: // spellid=1792 // FOLLOW { pet->StopMoving(); pet->AttackStop(true, true); pet->GetMotionMaster()->Clear(); ((Pet*)pet)->SetStayPosition(); ((Pet*)pet)->SetIsRetreating(true); ((Pet*)pet)->SetSpellOpener(); charmInfo->SetCommandState(COMMAND_FOLLOW); break; } case COMMAND_ATTACK: // spellid=1792 // ATTACK { ((Pet*)pet)->SetIsRetreating(); ((Pet*)pet)->SetSpellOpener(); Unit* targetUnit = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; if (targetUnit && targetUnit != pet && targetUnit->isTargetableForAttack() && targetUnit->isInAccessablePlaceFor((Creature*)pet)) { _player->SetInCombatState(true, targetUnit); // This is true if pet has no target or has target but targets differs. if (pet->getVictim() != targetUnit) { pet->AttackStop(); pet->GetMotionMaster()->Clear(); if (((Creature*)pet)->AI()) { ((Creature*)pet)->AI()->AttackStart(targetUnit); // 10% chance to play special warlock pet attack talk, else growl if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && roll_chance_i(10)) pet->SendPetTalk((uint32)PET_TALK_ATTACK); pet->SendPetAIReaction(); } else pet->Attack(targetUnit, true); } } break; } case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) { Creature* petC = (Creature*)pet; if (petC->IsPet()) { Pet* p = (Pet*)petC; if (p->getPetType() == HUNTER_PET) p->Unsummon(PET_SAVE_AS_DELETED, _player); else // dismissing a summoned pet is like killing them (this prevents returning a soulshard...) p->SetDeathState(CORPSE); } else // charmed _player->Uncharm(); if (petC->IsTemporarySummon()) // special case when pet was temporary summon through DoSummonPossesed { petC->ForcedDespawn(); return; } ((Pet*)pet)->SetStayPosition(); break; } default: sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } break; case ACT_REACTION: // 0x6 switch (spellid) { case REACT_PASSIVE: // passive { pet->AttackStop(true, true); ((Pet*)pet)->SetSpellOpener(); } case REACT_DEFENSIVE: // recovery case REACT_AGGRESSIVE: // activete { charmInfo->SetReactState(ReactStates(spellid)); break; } } break; case ACT_DISABLED: // 0x81 spell (disabled), ignore case ACT_PASSIVE: // 0x01 case ACT_ENABLED: // 0xC1 spell { ((Pet*)pet)->SetIsRetreating(); ((Pet*)pet)->SetSpellOpener(); Unit* unit_target = targetGuid ? _player->GetMap()->GetUnit(targetGuid) : nullptr; // do not cast unknown spells SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid); if (!spellInfo) { sLog.outError("WORLD: unknown PET spell id %i", spellid); return; } if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) return; for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i)); if (!spellEffect) continue; if (spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA || spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellEffect->EffectImplicitTargetA == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) return; } // do not cast not learned spells if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; pet->clearUnitState(UNIT_STAT_MOVING); Spell* spell = new Spell(pet, spellInfo, false); SpellCastResult result = spell->CheckPetCast(unit_target); const SpellRangeEntry* sRange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); if (unit_target && !(pet->IsWithinDistInMap(unit_target, sRange->maxRange) && pet->IsWithinLOSInMap(unit_target)) && !(GetPlayer()->IsFriendlyTo(unit_target) || pet->HasAuraType(SPELL_AURA_MOD_POSSESS))) { ((Pet*)pet)->SetSpellOpener(spellid, sRange->minRange, sRange->maxRange); spell->finish(false); delete spell; pet->AttackStop(); pet->GetMotionMaster()->Clear(); ((Creature*)pet)->AI()->AttackStart(unit_target); // 10% chance to play special warlock pet attack talk, else growl if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10)) pet->SendPetTalk((uint32)PET_TALK_ATTACK); pet->SendPetAIReaction(); return; } // auto turn to target unless possessed if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS)) { if (unit_target) { pet->SetInFront(unit_target); if (unit_target->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)unit_target); } else if (Unit* unit_target2 = spell->m_targets.getUnitTarget()) { pet->SetInFront(unit_target2); if (unit_target2->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)unit_target2); } if (Unit* powner = pet->GetCharmerOrOwner()) if (powner->GetTypeId() == TYPEID_PLAYER) pet->SendCreateUpdateToPlayer((Player*)powner); result = SPELL_CAST_OK; } if (result == SPELL_CAST_OK) { ((Creature*)pet)->AddCreatureSpellCooldown(spellid); unit_target = spell->m_targets.getUnitTarget(); if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS)) { // This is true if pet has no target or has target but targets differs. if (pet->getVictim() != unit_target) { pet->AttackStop(); pet->GetMotionMaster()->Clear(); _player->SetInCombatState(true, unit_target); if (((Creature*)pet)->AI()) { ((Creature*)pet)->AI()->AttackStart(unit_target); // 10% chance to play special warlock pet attack talk, else growl if (((Creature*)pet)->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != unit_target && roll_chance_i(10)) pet->SendPetTalk((uint32)PET_TALK_ATTACK); pet->SendPetAIReaction(); } else pet->Attack(unit_target, true); } } ((Pet*)pet)->SetSpellOpener(); spell->SpellStart(&(spell->m_targets)); } else { if (pet->HasAuraType(SPELL_AURA_MOD_POSSESS)) Spell::SendCastResult(GetPlayer(), spellInfo, 0, result); else { Unit* owner = pet->GetCharmerOrOwner(); if (owner && owner->GetTypeId() == TYPEID_PLAYER) Spell::SendCastResult((Player*)owner, spellInfo, 0, result, true); } if (!((Creature*)pet)->HasSpellCooldown(spellid)) GetPlayer()->SendClearCooldown(spellid, pet); ((Pet*)pet)->SetSpellOpener(); spell->finish(false); delete spell; } break; } default: sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } }
void UpdateAI(const uint32 diff) { if(!CanAttack && Intro) { if(AggroTimer < diff) { CanAttack = true; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); AggroTimer=19000; }else { AggroTimer-=diff; return; } } //to prevent abuses during phase 2 if(Phase == 2 && !m_creature->getVictim() && InCombat) { EnterEvadeMode(); return; } //Return since we have no target if (!UpdateVictim() ) return; if(Phase == 1 || Phase == 3) { //ShockBlast_Timer if (ShockBlast_Timer < diff) { //Shock Burst //Randomly used in Phases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. DoCast(m_creature->getVictim(), SPELL_SHOCK_BLAST); m_creature->TauntApply(m_creature->getVictim()); ShockBlast_Timer = 1000+rand()%14000; //random cooldown }else ShockBlast_Timer -= diff; //StaticCharge_Timer if(StaticCharge_Timer < diff) { //Static Charge //Used on random people (only 1 person at any given time) in Phases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of 3s, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER, 0) && target->GetTypeId() == TYPEID_PLAYER && !target->isDead()) //cast Static Charge every 2 seconds for 20 seconds DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); StaticCharge_Timer = 10000+rand()%20000; //blizzlike }else StaticCharge_Timer -= diff; //Entangle_Timer if (Entangle_Timer < diff) { if(!Entangle) { //Entangle //Used in Phases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. DoCast(m_creature->getVictim(), SPELL_ENTANGLE); Entangle = true; Entangle_Timer = 10000; } else { CastShootOrMultishot(); Entangle = false; Entangle_Timer = 20000+rand()%5000; } }else Entangle_Timer -= diff; //Phase 1 if(Phase == 1) { //Start phase 2 if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 70) { //Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. Phase = 2; m_creature->GetMotionMaster()->Clear(); DoTeleportTo(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); Creature *pCreature; for(uint8 i = 0; i < 4; i++) { pCreature = m_creature->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); if (pCreature) ShieldGeneratorChannel[i] = pCreature->GetGUID(); } DoScriptText(SAY_PHASE2, m_creature); } } //Phase 3 else { //SummonSporebat_Timer if(SummonSporebat_Timer < diff) { Creature *Sporebat = NULL; Sporebat = m_creature->SummonCreature(TOXIC_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_CORPSE_DESPAWN, 0); if(Sporebat) { Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(target) Sporebat->AI()->AttackStart(target); } //summon sporebats faster and faster if(SummonSporebat_StaticTimer > 1000) SummonSporebat_StaticTimer -= 1000; SummonSporebat_Timer = SummonSporebat_StaticTimer; if(SummonSporebat_Timer < 5000) SummonSporebat_Timer = 5000; }else SummonSporebat_Timer -= diff; } //Melee attack DoMeleeAttackIfReady(); //Check_Timer - used to check if somebody is in melee range if(Check_Timer < diff) { bool InMeleeRange = false; Unit *target; std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); //if in melee range if(target && target->IsWithinDistInMap(m_creature, 5)) { InMeleeRange = true; break; } } //if nobody is in melee range if(!InMeleeRange) CastShootOrMultishot(); Check_Timer = 5000; }else Check_Timer -= diff; } //Phase 2 else { //ForkedLightning_Timer if(ForkedLightning_Timer < diff) { //Forked Lightning //Used constantly in Phase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(!target) target = m_creature->getVictim(); DoCast(target, SPELL_FORKED_LIGHTNING); ForkedLightning_Timer = 2000+rand()%6000; //blizzlike }else ForkedLightning_Timer -= diff; //EnchantedElemental_Timer if(EnchantedElemental_Timer < diff) { Creature *Elemental; Elemental = m_creature->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElemental_Pos][0], ElementPos[EnchantedElemental_Pos][1], ElementPos[EnchantedElemental_Pos][2], ElementPos[EnchantedElemental_Pos][3], TEMPSUMMON_CORPSE_DESPAWN, 0); if(EnchantedElemental_Pos == 7) EnchantedElemental_Pos = 0; else EnchantedElemental_Pos++; EnchantedElemental_Timer = 10000+rand()%5000; }else EnchantedElemental_Timer -= diff; //TaintedElemental_Timer if(TaintedElemental_Timer < diff) { Creature *Tain_Elemental; uint32 pos = rand()%8; Tain_Elemental = m_creature->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_DEAD_DESPAWN, 0); TaintedElemental_Timer = 120000; }else TaintedElemental_Timer -= diff; //CoilfangElite_Timer if(CoilfangElite_Timer < diff) { uint32 pos = rand()%3; Creature* CoilfangElite = NULL; CoilfangElite = m_creature->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); if(CoilfangElite) { Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(target) CoilfangElite->AI()->AttackStart(target); else if(m_creature->getVictim()) CoilfangElite->AI()->AttackStart(m_creature->getVictim()); } CoilfangElite_Timer = 45000+rand()%5000; }else CoilfangElite_Timer -= diff; //CoilfangStrider_Timer if(CoilfangStrider_Timer < diff) { uint32 pos = rand()%3; Creature* CoilfangStrider = NULL; CoilfangStrider = m_creature->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); if(CoilfangStrider) { Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); if(target) CoilfangStrider->AI()->AttackStart(target); else if(m_creature->getVictim()) CoilfangStrider->AI()->AttackStart(m_creature->getVictim()); } CoilfangStrider_Timer = 60000+rand()%10000; }else CoilfangStrider_Timer -= diff; //Check_Timer if(Check_Timer < diff) { //Start Phase 3 if(pInstance && pInstance->GetData(DATA_CANSTARTPHASE3)) { //set life 50% m_creature->SetHealth(m_creature->GetMaxHealth()/2); m_creature->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); DoScriptText(SAY_PHASE3, m_creature); Phase = 3; //return to the tank m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } // check item tainted core. if player has item, cast root. if not has item and is rooted, remove root InstanceMap::PlayerList const &playerliste = ((InstanceMap*)m_creature->GetMap())->GetPlayers(); InstanceMap::PlayerList::const_iterator it; Map::PlayerList const &PlayerList = ((InstanceMap*)m_creature->GetMap())->GetPlayers(); for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { Player* i_pl = i->getSource(); { if(i_pl->HasItemCount(31088, 1, false)) { if(i_pl->HasAura(39666,0)) i_pl->RemoveAurasDueToSpell(39666); // cloak of shadowx if(!i_pl->HasAura(38132,0)) i_pl->CastSpell(i_pl, 38132, false); // spell root } else if(i_pl->HasAura(38132,0)) i_pl->RemoveAurasDueToSpell(38132); } } Check_Timer = 1000; }else Check_Timer -= diff; } }
void UpdateAI(const uint32 diff) { //Sounds OOC, Kiljaeden Orders if(!m_creature->getVictim()) { if(m_uiKJOrdersTimer < diff) { switch (rand()%5) { case 0: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT3); break; case 3: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT4); break; case 4: DoPlaySoundToSet(m_creature, SAY_KJ_OFFCOMBAT5); break; } m_uiKJOrdersTimer = 60000; }else m_uiKJOrdersTimer -= diff; } //Rebirth After Phase1 if(pInstance && pInstance->GetData(DATA_DECIVER) == SPECIAL) { m_creature->setFaction(14); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); pInstance->SetData(DATA_KILJAEDEN_EVENT, IN_PROGRESS); pInstance->SetData(DATA_DECIVER, NOT_STARTED); } if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; //FireBloom Damage WorkArround if(m_uiFireBloomCheck < diff) { if(m_uiFireBloomCount < 10) for(uint8 i=0; i<5; ++i) { if(Unit* FireTarget = m_creature->GetMap()->GetUnit(m_uiFireBloomTarget[i])) if(FireTarget->isAlive()) FireTarget->CastSpell(FireTarget, SPELL_FIREBLOOM_EFF, true); } ++m_uiFireBloomCount; m_uiFireBloomCheck = 2000; }else m_uiFireBloomCheck -= diff; if((m_uiOrbTimer < diff) && !m_bBoolOrb) { switch (rand()%4) { case 0: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY3); break; case 3: DoPlaySoundToSet(m_creature, SAY_KALEC_ORB_READY4); break; } uint8 m_uiMaxDragons = 1; if(m_bPhase5) m_uiMaxDragons = 4; for(uint8 i=0; i<m_uiMaxDragons; ++i) { Creature* Dragon = m_creature->SummonCreature(ID_DRAGON, m_creature->GetPositionX()+urand(20,35), m_creature->GetPositionY()+urand(20,35), m_creature->GetPositionZ()+1, 0, TEMPSUMMON_CORPSE_DESPAWN, 20000); m_uiDragonGUID[i] = Dragon->GetGUID(); } m_bBoolOrb = true; }else m_uiOrbTimer -= diff; //Shield of Blue m_uiDragonGUID[i] for(uint8 i=0; i<4; ++i) { if(Unit* Dragon = m_creature->GetMap()->GetUnit(m_uiDragonGUID[i])) if(Dragon && Dragon->HasAura(SPELL_SHIELD_OF_BLUE)) { m_uiCancelShieldTimer = 6000; std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit* TargetedPlayer = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); if (TargetedPlayer && TargetedPlayer->GetTypeId() == TYPEID_PLAYER && TargetedPlayer->IsWithinDistInMap(Dragon, 15) && !TargetedPlayer->HasAura(AURA_BLUESHIELD)) TargetedPlayer->CastSpell(TargetedPlayer,AURA_BLUESHIELD,true); } } } if(m_uiCancelShieldTimer < diff) { std::list<HostileReference *> t_list = m_creature->getThreatManager().getThreatList(); for(std::list<HostileReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *ShieldedPlayer1 = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); if (ShieldedPlayer1 && ShieldedPlayer1->GetTypeId() == TYPEID_PLAYER && ShieldedPlayer1->HasAura(AURA_BLUESHIELD)) { ShieldedPlayer1->RemoveAurasDueToSpell(AURA_BLUESHIELD); } } m_uiCancelShieldTimer = 300000; }else m_uiCancelShieldTimer -= diff; //Kalecgos and Anvena Event if((m_uiKalecgosAnvenaTimer < diff) && m_bIsAnvena) { switch(m_uiKalecgosAnvenaCount) { case 0: DoPlaySoundToSet(m_creature, SAY_KALECGOS_AWAKEN); m_uiKalecgosAnvenaTimer = 5000; break; case 1: DoPlaySoundToSet(m_creature, SAY_ANVEENA_IMPRISONED); m_uiKalecgosAnvenaTimer = 3000; break; case 2: DoPlaySoundToSet(m_creature, SAY_KALECGOS_LETGO); m_uiKalecgosAnvenaTimer = 6000; break; case 5: DoPlaySoundToSet(m_creature, SAY_ANVEENA_LOST); m_uiKalecgosAnvenaTimer = 4000; break; case 4: DoPlaySoundToSet(m_creature, SAY_KALECGOS_FOCUS); m_uiKalecgosAnvenaTimer = 8000; break; case 3: DoPlaySoundToSet(m_creature, SAY_ANVEENA_KALEC); m_uiKalecgosAnvenaTimer = 5000; break; case 6: DoPlaySoundToSet(m_creature, SAY_KALECGOS_FATE); m_uiKalecgosAnvenaTimer = 5000; break; case 7: DoPlaySoundToSet(m_creature, SAY_ANVEENA_GOODBYE); m_creature->CastSpell(m_creature, SPELL_SACRIFICE_OF_ANVEENA, false); if(Unit* Anveena = m_creature->GetMap()->GetUnit(m_uiAnveenaGUID)) if(Anveena && Anveena->isAlive()) Anveena->SetVisibility(VISIBILITY_OFF); m_uiKalecgosAnvenaTimer = 5000; break; case 9: DoPlaySoundToSet(m_creature, SAY_KALECGOS_GOODBYE); ; m_bIsAnvena = false; break; case 8: DoPlaySoundToSet(m_creature, SAY_KALECGOS_ENCOURAGE); m_uiKalecgosAnvenaTimer = 14000; break; } ++m_uiKalecgosAnvenaCount; }m_uiKalecgosAnvenaTimer -= diff; //Kalecgos Event if((m_uiKalecgosTimer < diff) && !m_bIsKalecgosSpawned) { DoPlaySoundToSet(m_creature, SAY_KALECGOS_JOIN); float x, y, z; m_creature->GetClosePoint(x, y, z, m_creature->GetObjectBoundingRadius(), 15.0f, urand(0, 6)); if(Creature* cKalecgos = m_creature->SummonCreature(ID_KALECGOS, x, y, z, 0.686f, TEMPSUMMON_TIMED_DESPAWN, 600000)) { m_uiKalecgosGUID = cKalecgos->GetGUID(); cKalecgos->setFaction(35); cKalecgos->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //Kalecgos need to start shhooting arcane bolt into Kiljaeden //Dragon->AI()->AttackStart(m_creature); } m_bIsKalecgosSpawned = true; }m_uiKalecgosTimer -= diff; //Shield Orb At Start each phases if(m_uiShieldOrbTimer < diff && !m_bPhase5) { uint8 l=1; if(m_bPhase3) l=2; if(m_bPhase4) l=3; for(uint8 k=0; k<l; ++k) { Creature* ShieldOrb = m_creature->SummonCreature(ID_SHIELDORB, m_creature->GetPositionX()+urand(1,15), m_creature->GetPositionY()+urand(1,15), m_creature->GetPositionZ()+10, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); if(ShieldOrb) ShieldOrb->AI()->AttackStart(m_creature->getVictim()); } m_uiShieldOrbTimer = 50000; }else m_uiShieldOrbTimer -= diff; //Sinister Reflects Attack if(m_uiSinnisterCastTimer < diff) { uint8 m_uiSinisterCount = 0; if(m_bPhase3) m_uiSinisterCount = 4; if(m_bPhase4) m_uiSinisterCount = 8; if(m_bPhase5) m_uiSinisterCount = 12; for(uint8 i=0; i<m_uiSinisterCount; ++i) if(Unit* Sinister = m_creature->GetMap()->GetUnit(m_uiSinisterGUID[i][0])) if(Sinister->isAlive()) if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) Sinister->CastSpell(target, m_uiSinisterGUID[i][1], true); m_uiSinnisterCastTimer = urand(8000,16000); }else m_uiSinnisterCastTimer -= diff; //Phase4 if((m_uiAramageddonTimer < diff) && m_bPhase4) { uint8 h=3; if(m_bPhase5) h=5; if(!m_bPhase5 && m_bDarknessOfSoulsCasting) h=0; for(uint8 i=0; i<h; ++i) if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) Creature* Armagedon = m_creature->SummonCreature(ID_ARMAGEDON, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 15000); m_uiAramageddonTimer = urand(20000,30000); }else m_uiAramageddonTimer -= diff; //ShadowSpike Explosions if((m_uiShadowSpikeEndsTimer < diff) && m_bShadowSpikeEnds && m_bPhase3) { if(Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if(Creature* cShadowSpike = m_creature->SummonCreature(ID_SHADOWSPIKE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 6000)) { cShadowSpike->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); cShadowSpike->setFaction(14); } //target->CastSpell(target, SPELL_SHADOWSPIKE_EXP, false); } ++m_uiSpikesCount; if(m_uiSpikesCount > 9) m_bShadowSpikeEnds = false; m_uiShadowSpikeEndsTimer = 3000; }else m_uiShadowSpikeEndsTimer -= diff; if(m_bShadowSpikeEnds) return; if(m_uiDarknessExplosionTimer < diff && m_bDarknessOfSoulsCasting) { //m_creature->CastSpell(m_creature->getVictim(), SPELL_DARKNESS_EXPLOSION, true); m_bDarknessOfSoulsCasting = false; m_uiDarknessExplosionTimer = 600000; m_uiDarknessOfSoulsTimer = 60000; m_uiFireBloomTimer = 25000; if(m_bPhase5) m_uiDarknessOfSoulsTimer = 35000; }else m_uiDarknessExplosionTimer -= diff; if(m_bDarknessOfSoulsCasting) return; if(m_uiDarknessOfSoulsTimer < diff && m_bPhase3) { switch (rand()%3) { case 0: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS1); break; case 1: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS2); break; case 2: DoPlaySoundToSet(m_creature, SAY_KJ_DARKNESS3); break; } m_creature->CastSpell(m_creature, SPELL_DARKNESS_OF_SOULS, false); m_bDarknessOfSoulsCasting = true; m_uiDarknessExplosionTimer = 8000; }else m_uiDarknessOfSoulsTimer -= diff; //Phases if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 85) && !m_bPhase3) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE3); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),0,4); //Start Timerow Dochodzacych w 3 Fazie m_uiFlameDartTimer = 20000; m_uiSinnisterCastTimer = 10000; m_uiShadowSpikeTimer = 30000; m_uiFlameDartTimer = 40000; m_uiDarknessOfSoulsTimer = 60000; m_bShadowSpikeEnds = false; m_bDarknessOfSoulsCasting = false; m_bPhase3 = true; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; } if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 55) && !m_bPhase4) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE4); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),4,8); //Start Timerow Dochodzacych w 4 Fazie m_uiFlameDartTimer = 20000; m_uiAramageddonTimer = 2000; //100% ok m_bPhase4 = true; m_uiDarknessOfSoulsTimer = 60000; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; } if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 25) && !m_bPhase5) { DoPlaySoundToSet(m_creature, SAY_KJ_PHASE5); if(Unit* victim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) if (victim && (victim->GetTypeId() == TYPEID_PLAYER)) Sinister(((Player*)victim),8,12); //Start Timerow Dochodzacych w 5 Fazie m_uiAramageddonTimer = urand(20000,30000); m_uiFlameDartTimer = 20000; m_uiShadowSpikeTimer = 1000; m_uiDarknessOfSoulsTimer = 60000; m_bPhase5 = true; //DragonsTimer m_uiOrbTimer = 35000; m_bBoolOrb = false; //Kalecgos and Anvena Event m_uiKalecgosAnvenaTimer = 20000; m_bIsAnvena = true; m_uiKalecgosAnvenaCount = 0; if(Creature* cAnveena = m_creature->SummonCreature(ID_ANVEENA, m_creature->GetPositionX()+urand(20,30), m_creature->GetPositionY()+urand(20,30), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 120000)) { m_uiAnveenaGUID = cAnveena->GetGUID(); cAnveena->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); cAnveena->setFaction(35); } } //Phase3 if(m_bPhase3) { if(m_uiShadowSpikeTimer < diff) { //DoCast(m_creature->getVictim(), SPELL_SHADOWSPIKE); m_bShadowSpikeEnds = true; m_uiShadowSpikeEndsTimer = 500; m_uiSpikesCount = 0; m_uiShadowSpikeTimer = urand(65000,95000); }else m_uiShadowSpikeTimer -= diff; if(m_uiFlameDartTimer < diff) { DoCast(m_creature->getVictim(), SPELL_FLAMEDARTS); m_uiFlameDartTimer = urand(41000,63000); }else m_uiFlameDartTimer -= diff; } //Phase2 if(m_uiLegionLightingTimer < diff) { DoCast(m_creature->getVictim(), SPELL_LEGION_LIGHTING); m_uiLegionLightingTimer = urand(18000,26000); }else m_uiLegionLightingTimer -= diff; if(m_uiFireBloomTimer < diff) { for(uint8 i=0; i<5; ++i) { if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) m_uiFireBloomTarget[i] = target->GetGUID(); else m_uiFireBloomTarget[i] = 0; m_uiFireBloomCount = 0; //DoCast(target, SPELL_FIREBLOOM, true); } m_uiFireBloomTimer = urand(34000,56000); }else m_uiFireBloomTimer -= diff; if(m_uiSoulFlyTimer < diff) { DoCast(m_creature->getVictim(), SPELL_SOULFLY); m_uiSoulFlyTimer = 7000; }else m_uiSoulFlyTimer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 uiDiff) { //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiPhase == PHASE_1 || m_uiPhase == PHASE_3) { //m_uiShockBlast_Timer if (m_uiShockBlast_Timer < uiDiff) { //Randomly used in m_uiPhases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK_BLAST); m_uiShockBlast_Timer = urand(1000, 15000); //random cooldown }else m_uiShockBlast_Timer -= uiDiff; //m_uiStaticCharge_Timer if (m_uiStaticCharge_Timer < uiDiff) { //Used on random people (only 1 person at any given time) in m_uiPhases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); //cast Static Charge every 2 seconds for 20 seconds if (pTarget && !pTarget->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) DoCastSpellIfCan(pTarget, SPELL_STATIC_CHARGE_TRIGGER); m_uiStaticCharge_Timer = urand(10000, 30000); }else m_uiStaticCharge_Timer -= uiDiff; //m_uiEntangle_Timer if (m_uiEntangle_Timer < uiDiff) { if (!m_bEntangle) { //Used in m_uiPhases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENTANGLE); m_bEntangle = true; m_uiEntangle_Timer = 10000; } else { CastShootOrMultishot(); m_bEntangle = false; m_uiEntangle_Timer = urand(20000, 25000); } }else m_uiEntangle_Timer -= uiDiff; //m_uiPhase 1 if (m_uiPhase == PHASE_1) { //m_uiPhase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. if (m_creature->GetHealthPercent() <= 70.0f) { DoScriptText(SAY_PHASE2, m_creature); if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) { //set false, so MoveChase is not triggered in AttackStart SetCombatMovement(false); m_creature->GetMotionMaster()->MovementExpired(); m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_CENTER, afMiddlePos[0], afMiddlePos[1], afMiddlePos[2]); } m_uiPhase = PHASE_2; return; } } //m_uiPhase PHASE_3 else { //m_uiSummonSporebat_Timer if (m_uiSummonSporebat_Timer < uiDiff) { m_creature->SummonCreature(NPC_TOXIC_SPOREBAT, afSporebatPos[0], afSporebatPos[1], afSporebatPos[2], afSporebatPos[3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); //summon sporebats faster and faster if (m_uiSummonSporebat_StaticTimer > 1000) m_uiSummonSporebat_StaticTimer -= 1000; m_uiSummonSporebat_Timer = m_uiSummonSporebat_StaticTimer; }else m_uiSummonSporebat_Timer -= uiDiff; } //Melee attack DoMeleeAttackIfReady(); //m_uiCheck_Timer - used to check if somebody is in melee range if (m_uiCheck_Timer < uiDiff) { bool bInMeleeRange = false; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) { Unit* pTarget = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); //if in melee range if (pTarget && pTarget->IsWithinDistInMap(m_creature, ATTACK_DISTANCE)) { bInMeleeRange = true; break; } } //if nobody is in melee range if (!bInMeleeRange) CastShootOrMultishot(); m_uiCheck_Timer = 1500; }else m_uiCheck_Timer -= uiDiff; } //m_uiPhase PHASE_2 else { //m_uiForkedLightning_Timer if (m_uiForkedLightning_Timer < uiDiff) { //Used constantly in m_uiPhase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); if (!pTarget) pTarget = m_creature->getVictim(); DoCastSpellIfCan(pTarget, SPELL_FORKED_LIGHTNING); m_uiForkedLightning_Timer = urand(3000, 9000); }else m_uiForkedLightning_Timer -= uiDiff; //NPC_ENCHANTED_ELEMENTAL if (m_uiEnchantedElemental_Timer < uiDiff) { if (Creature* pElemental = m_creature->SummonCreature(NPC_ENCHANTED_ELEMENTAL, afElementPos[m_uiEnchantedElemental_Pos][0], afElementPos[m_uiEnchantedElemental_Pos][1], afElementPos[m_uiEnchantedElemental_Pos][2], afElementPos[m_uiEnchantedElemental_Pos][3], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000)) pElemental->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); if (m_uiEnchantedElemental_Pos == 7) m_uiEnchantedElemental_Pos = 0; else ++m_uiEnchantedElemental_Pos; m_uiEnchantedElemental_Timer = urand(10000, 15000); }else m_uiEnchantedElemental_Timer -= uiDiff; //NPC_TAINTED_ELEMENTAL if (m_uiTaintedElemental_Timer < uiDiff) { uint32 uiPos = urand(0,7); m_creature->SummonCreature(NPC_TAINTED_ELEMENTAL, afElementPos[uiPos][0], afElementPos[uiPos][1], afElementPos[uiPos][2], afElementPos[uiPos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 15000); m_uiTaintedElemental_Timer = 120000; }else m_uiTaintedElemental_Timer -= uiDiff; //NPC_COILFANG_ELITE if (m_uiCoilfangElite_Timer < uiDiff) { uint32 uiPos = urand(0,2); m_creature->SummonCreature(NPC_COILFANG_ELITE, afCoilfangElitePos[uiPos][0], afCoilfangElitePos[uiPos][1], afCoilfangElitePos[uiPos][2], afCoilfangElitePos[uiPos][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); //wowwiki says 50 seconds, bosskillers says 45 m_uiCoilfangElite_Timer = urand(45000, 50000); }else m_uiCoilfangElite_Timer -= uiDiff; //NPC_COILFANG_STRIDER if (m_uiCoilfangStrider_Timer < uiDiff) { uint32 uiPos = urand(0,2); m_creature->SummonCreature(NPC_COILFANG_STRIDER, afCoilfangStriderPos[uiPos][0], afCoilfangStriderPos[uiPos][1], afCoilfangStriderPos[uiPos][2], afCoilfangStriderPos[uiPos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); //wowwiki says 60 seconds, bosskillers says 60-70 m_uiCoilfangStrider_Timer = urand(60000, 70000); }else m_uiCoilfangStrider_Timer -= uiDiff; //m_uiCheck_Timer if (m_uiCheck_Timer < uiDiff) { //Start m_uiPhase 3 if (m_pInstance && m_pInstance->GetData(TYPE_VASHJ_PHASE3_CHECK) == DONE) { DoScriptText(SAY_PHASE3, m_creature); //set life 50%, not correct. Must remove 5% for each generator switched off m_creature->SetHealth(m_creature->GetMaxHealth()/2); m_creature->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); SetCombatMovement(true); //return to chase top aggro if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); m_uiPhase = PHASE_3; } m_uiCheck_Timer = 1000; }else m_uiCheck_Timer -= uiDiff; } }
void UpdateAI(const uint32 diff) { advisorbase_ai::UpdateAI(diff); //Faking Death, don't do anything if (FakeDeath) return; //Return since we have no target if (!UpdateVictim()) return; //Yell_Timer if (!Yell) { if (Yell_Timer <= diff) { DoScriptText(SAY_CAPERNIAN_AGGRO, me); Yell = true; } else Yell_Timer -= diff; } //Fireball_Timer if (Fireball_Timer <= diff) { DoCast(me->getVictim(), SPELL_CAPERNIAN_FIREBALL); Fireball_Timer = 4000; } else Fireball_Timer -= diff; //Conflagration_Timer if (Conflagration_Timer <= diff) { Unit *pTarget = NULL; pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0); if (pTarget && me->IsWithinDistInMap(pTarget, 30)) DoCast(pTarget, SPELL_CONFLAGRATION); else DoCast(me->getVictim(), SPELL_CONFLAGRATION); Conflagration_Timer = 10000+rand()%5000; } else Conflagration_Timer -= diff; //ArcaneExplosion_Timer if (ArcaneExplosion_Timer <= diff) { bool InMeleeRange = false; Unit *pTarget = NULL; std::list<HostileReference*>& m_threatlist = me->getThreatManager().getThreatList(); for (std::list<HostileReference*>::const_iterator i = m_threatlist.begin(); i!= m_threatlist.end(); ++i) { Unit* pUnit = Unit::GetUnit((*me), (*i)->getUnitGuid()); //if in melee range if (pUnit && pUnit->IsWithinDistInMap(me, 5)) { InMeleeRange = true; pTarget = pUnit; break; } } if (InMeleeRange) DoCast(pTarget, SPELL_ARCANE_EXPLOSION); ArcaneExplosion_Timer = 4000+rand()%2000; } else ArcaneExplosion_Timer -= diff; //Do NOT deal any melee damage. }