void PlayerbotRogueAI::DoNextCombatManeuver(Unit *pTarget) { if (!pTarget || pTarget->isDead()) return; PlayerbotAI *ai = GetAI(); if (!ai) return; Player *m_bot = GetPlayerBot(); if (!m_bot || m_bot->isDead()) return; Unit *pVictim = pTarget->getVictim(); Unit *m_tank = FindMainTankInRaid(GetMaster()); if (!m_tank && m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup()) { FindMainTankInRaid(m_bot); } if (!m_tank) { m_tank = m_bot; } uint32 masterHP = GetMaster()->GetHealth()*100 / GetMaster()->GetMaxHealth(); float pDist = m_bot->GetDistance(pTarget); uint8 pThreat = GetThreatPercent(pTarget); /*switch (ai->GetScenarioType()) { case SCENARIO_DUEL: ((CastSpell(BACKSTAB)) || (pTarget->IsNonMeleeSpellCasted(true) && CastSpell(KICK)) || ((GetPlayerBot()->GetComboPoints()==5) && CastSpell(SLICE_DICE)) || (CastSpell(SINISTER_STRIKE))); return; }*/ #pragma region Choose Target // Choose actions accoring to talents (ROGUE is always MELEE DPS) m_role = BOT_ROLE_DPS_MELEE; // if i am under attack and if i am not tank or offtank: change target if needed if (m_tank->GetGUID() != m_bot->GetGUID() && isUnderAttack() ) { // Keep hitting but reduce threat if (CastSpell(FEINT,m_bot)) { return; } else if (CastSpell(TRICKS_OF_THE_TRADE,m_tank)) { return; } else if (CastSpell(VANISH,m_bot)) { return; } //else if (m_bot->getRace() == (uint8) RACE_NIGHTELF && CastSpell(R_SHADOWMELD,m_bot)) { return; } else //I cannot reduce threat so { if (pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist <= 2) { } // My target is almost up to me, no need to search else //Have to select nearest target { Unit *curAtt = GetNearestAttackerOf(m_bot); if (curAtt && curAtt->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(curAtt->GetGUID()); //ai->AddLootGUID(curAtt->GetGUID()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } } #pragma endregion // wait until we actually reach our target b4 we actually do anything /*if (m_bot->GetDistance(pTarget)>10.0 && !m_bot->HasAura(STEALTH) && !m_bot->isInCombat() && CastSpell(STEALTH)) { return; }*/ TakePosition(pTarget); // If there's a cast stop if (m_bot->hasUnitState(UNIT_STAT_CASTING)) { return; } // wait until we actually reach our target b4 we actually do anything if (GetPlayerBot()->GetDistance(pTarget)>10.0 && !HasAuraName(GetPlayerBot(),STEALTH) && !GetPlayerBot()->isInCombat() && CastSpell(STEALTH)) { return; } //Buff if (CastSpell(PREMEDITATION,m_bot)) { return; } //PROTECT UP if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { if (CastSpell(FEINT,m_bot)) { return; } if (CastSpell(TRICKS_OF_THE_TRADE,m_tank)) { return; } if (CastSpell(VANISH,m_bot)) { return; } } if (isUnderAttack() && pDist <= MELEE_RANGE && ai->GetHealthPercent() <= 85 && CastSpell(EVASION, m_bot)) { } //no GCD if (ai->GetHealthPercent() <= 55 && CastSpell(CLOAK_OF_SHADOWS, m_bot)) { return; } if (isUnderAttack() && ai->GetHealthPercent() <= 65 && CastSpell(GOUGE, m_bot)) { return; } if (isUnderAttack() && ai->GetHealthPercent() <= 45 && CastSpell(BLIND, m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_DWARF && ai->GetHealthPercent() < 75 && CastSpell(R_STONEFORM,m_bot)) { } //no gcd if (m_bot->getRace() == (uint8) RACE_DRAENEI && ai->GetHealthPercent() < 55 && CastSpell(R_GIFT_OF_NAARU,m_bot)) { return; } //no Gcd, but has cast if (m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //no gcd but is cast //Break spells if (m_bot->getRace() == (uint8) RACE_BLOODELF && pDist < 8 && (pTarget->IsNonMeleeSpellCasted(true) || ai->GetManaPercent() < 40) && CastSpell(R_ARCANE_TORRENT, pTarget)) { } //no gcd else if (pTarget->IsNonMeleeSpellCasted(true) && CastSpell(KICK, pTarget)) { return; } else if (pTarget->IsNonMeleeSpellCasted(true) && CastSpell(GOUGE, pTarget)) { return; } else if (pTarget->IsNonMeleeSpellCasted(true) && m_bot->GetComboPoints() >= 1 && CastSpell(KIDNEY_SHOT, pTarget)) { return; } // If at threat limit, try to reduce threat if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack()) { if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) // I am attacking wrong target!! { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); return; } else { if (CastSpell(FEINT,m_bot)) { return; } //Lets see if we can manage else if (CastSpell(TRICKS_OF_THE_TRADE,m_tank)) { return; } else { return; } //use no spells and wait threat to be reduced } } //Transfer threat if (m_tank->GetGUID() != m_bot->GetGUID() && CastSpell(TRICKS_OF_THE_TRADE,m_tank)) { return; } //Urgent DPS if ((m_bot->HasAura(STEALTH) || m_bot->HasAura(VANISH))&& CastSpell(CHEAP_SHOT,pTarget)) { return; } //DPS UP if (m_bot->getRace() == (uint8) RACE_TROLL && CastSpell(R_BERSERKING,m_bot)) {} //no GCD if (m_bot->getRace() == (uint8) RACE_ORC && CastSpell(R_BLOOD_FURY,m_bot)) {} //no GCD if (CastSpell(COLD_BLOOD,m_bot)) { } //no gcd if (CastSpell(HUNGER_FOR_BLOOD,m_bot)) { return; } if (CastSpell(BLADE_FLURRY,m_bot)) { return; } if (ai->GetEnergyAmount() < 20 && CastSpell(ADRENALINE_RUSH,m_bot)) { return; } if (CastSpell(SHADOW_DANCE,m_bot)) { return; } if (CastSpell(DISMANTLE,pTarget)) { return; } if (CastSpell(PREPARATION,m_bot)) { return; } if (m_bot->GetComboPoints() < 5) { if (CastSpell(RIPOSTE,pTarget)) { return; } if (CastSpell(KILLING_SPREE,m_bot,1,0,1)) { return; } // KILLING SPREE works great on 1 mob if (isUnderAttack(m_tank,3) && CastSpell(FAN_OF_KNIVES,pTarget)) { return; } if (BACKSTAB && !pTarget->HasInArc(M_PI,m_bot)) { if (CastSpell(BACKSTAB, pTarget)) { return; } } else if (CastSpell(MUTILATE, pTarget)) { return; } if (CastSpell(SINISTER_STRIKE,pTarget)) { return; } if (CastSpell(HEMORRHAGE,pTarget)) { return; } if (CastSpell(GHOSTLY_STRIKE,pTarget)) { return; } } else { if (ai->GetHealthPercent(*pTarget) > 30 && !m_bot->HasAura(SLICE_AND_DICE) && CastSpell(SLICE_AND_DICE)) { return; } if (ai->GetHealthPercent(*pTarget) < 20 && CastSpell(EVISCERATE)) { return; } if (!pTarget->HasAura(RUPTURE) && CastSpell(RUPTURE)) { return; } if (CastSpell(EVISCERATE)) { return; } // default if all else fails } } //end DoNextCombatManeuver
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if(StormCount) { Unit* target = Unit::GetUnit(*m_creature, CloudGUID); if(!target || !target->isAlive()) { EnterEvadeMode(); return; } else if(Unit* Cyclone = Unit::GetUnit(*m_creature, CycloneGUID)) Cyclone->CastSpell(target, 25160, true); // keep casting or... if(StormSequenceTimer < diff) { HandleStormSequence(target); }else StormSequenceTimer -= diff; return; } if (Enrage_Timer < diff) { DoYell(SAY_ONENRAGE, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_ONENRAGE); m_creature->CastSpell(m_creature, SPELL_BERSERK, true); Enrage_Timer = 600000; }else Enrage_Timer -= diff; if (StaticDisruption_Timer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(!target) target = m_creature->getVictim(); TargetGUID = target->GetGUID(); m_creature->CastSpell(target, SPELL_STATIC_DISRUPTION, false); m_creature->SetInFront(m_creature->getVictim()); StaticDisruption_Timer = (10+rand()%8)*1000; // < 20s /*float dist = m_creature->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); if (dist < 5.0f) dist = 5.0f; SDisruptAOEVisual_Timer = 1000 + floor(dist / 30 * 1000.0f);*/ }else StaticDisruption_Timer -= diff; if (GustOfWind_Timer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(!target) target = m_creature->getVictim(); DoCast(target, SPELL_GUST_OF_WIND); GustOfWind_Timer = (20+rand()%10)*1000; //20 to 30 seconds(bosskillers) } else GustOfWind_Timer -= diff; if (CallLighting_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_CALL_LIGHTNING); CallLighting_Timer = (12 + rand()%5)*1000; //totaly random timer. can't find any info on this } else CallLighting_Timer -= diff; if (!isRaining && ElectricalStorm_Timer < 8000 + rand()%5000) { SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f); isRaining = true; } if (ElectricalStorm_Timer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 50, true); if(!target) { EnterEvadeMode(); return; } target->CastSpell(target, 44007, true);//cloud visual m_creature->CastSpell(target, SPELL_ELECTRICAL_STORM, false);//storm cyclon + visual float x,y,z; target->GetPosition(x,y,z); if (target) { target->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); target->SendMonsterMove(x,y,m_creature->GetPositionZ()+15,0); } Unit *Cloud = m_creature->SummonTrigger(x, y, m_creature->GetPositionZ()+16, 0, 15000); if(Cloud) { CloudGUID = Cloud->GetGUID(); Cloud->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); Cloud->StopMoving(); Cloud->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); Cloud->setFaction(35); Cloud->SetMaxHealth(9999999); Cloud->SetHealth(9999999); Cloud->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } ElectricalStorm_Timer = 60000; //60 seconds(bosskillers) StormCount = 1; StormSequenceTimer = 0; } else ElectricalStorm_Timer -= diff; if (SummonEagles_Timer < diff) { DoYell(SAY_ONSUMMON, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_ONSUMMON); float x, y, z; m_creature->GetPosition(x, y, z); for (uint8 i = 0; i < 8; i++) { Unit* bird = Unit::GetUnit(*m_creature,BirdGUIDs[i]); if(!bird)//they despawned on die { if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) { x = target->GetPositionX() + 10 - rand()%20; y = target->GetPositionY() + 10 - rand()%20; z = target->GetPositionZ() + 6 + rand()%5 + 10; if(z > 95) z = 95 - rand()%5; } Creature *pCreature = m_creature->SummonCreature(MOB_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); if (pCreature) { pCreature->AddThreat(m_creature->getVictim(), 1.0f); pCreature->AI()->AttackStart(m_creature->getVictim()); BirdGUIDs[i] = pCreature->GetGUID(); } } } SummonEagles_Timer = 999999; } else SummonEagles_Timer -= diff; DoMeleeAttackIfReady(); }
void PlayerbotMageAI::DoNextCombatManeuver(Unit *pTarget) { if (!pTarget || pTarget->isDead()) return; PlayerbotAI *ai = GetAI(); if (!ai) return; Player *m_bot = GetPlayerBot(); if (!m_bot || m_bot->isDead()) return; Unit *pVictim = pTarget->getVictim(); Unit *m_tank = FindMainTankInRaid(GetMaster()); if (!m_tank && m_bot->GetGroup() && GetMaster()->GetGroup() != m_bot->GetGroup()) { FindMainTankInRaid(m_bot); } if (!m_tank) { m_tank = m_bot; } uint32 masterHP = GetMaster()->GetHealth()*100 / GetMaster()->GetMaxHealth(); float pDist = m_bot->GetDistance(pTarget); uint8 pThreat = GetThreatPercent(pTarget); #pragma region Choose Actions // Choose actions accoring to talents (MAGE is always ranged dps) m_role = BOT_ROLE_DPS_RANGED; // if i am under attack and if i am not tank or offtank: change target if needed if (isUnderAttack()) { // Keep hitting but reduce threat //else if (m_bot->getRace() == (uint8) RACE_NIGHTELF && CastSpell(R_SHADOWMELD,m_bot)) { return; } if (pVictim && pVictim->GetGUID() == m_bot->GetGUID() && pDist <= 2) { } // My target is almost up to me, no need to search else //Have to select nearest target { Unit *curAtt = GetNearestAttackerOf(m_bot); if (curAtt && curAtt->GetGUID() != pTarget->GetGUID()) { m_bot->SetSelection(curAtt->GetGUID()); DoNextCombatManeuver(curAtt); //Restart new update to get variables fixed.. return; } } //my target is attacking me } #pragma endregion TakePosition(pTarget); // If there's a cast stop if (m_bot->HasUnitState(UNIT_STAT_CASTING)) { return; } if (DoSupportRaid(m_bot,30,0,0,0,1,1)) { return; } if (m_tank->GetGUID() != m_bot->GetGUID() && pVictim && pVictim->GetGUID() == m_bot->GetGUID() ) { //if (CastSpell(INVISIBILITY, m_bot)) { return; } if (ai->GetHealthPercent(*pTarget) > 50 && CastSpell(POLYMORPH)) { return; } //if (m_bot->getRace() == (uint8) RACE_NIGHTELF && isUnderAttack() && CastSpell(R_SHADOWMELD, m_bot)) { return; } } if (isUnderAttack() && pDist > 5 && CastSpell(FROST_NOVA, pTarget)) { return; } if (DEEP_FREEZE && pTarget->isFrozen() && CastSpell(DEEP_FREEZE,pTarget)) { return; } if (isUnderAttack() && CastSpell(DRAGONS_BREATH, pTarget)) { return; } if ((isUnderAttack() || ai->GetHealthPercent() < 75 && !HasAuraName(m_bot, MANA_SHIELD)) && ai->GetManaPercent() > 40 && CastSpell(MANA_SHIELD,m_bot)) { return; } if (m_bot->getRace() == (uint8) RACE_DWARF && ai->GetHealthPercent() < 75 && CastSpell(R_STONEFORM,m_bot)) { } //no gcd if (m_bot->getRace() == (uint8) RACE_DRAENEI && ai->GetHealthPercent() < 55 && CastSpell(R_GIFT_OF_NAARU,m_bot)) { return; } //no Gcd, but has cast if (m_bot->getRace() == (uint8) RACE_TAUREN && pDist < 8 && CastSpell(R_WAR_STOMP, pTarget)) { return; } //no gcd but is cast if ((ai->GetHealthPercent() < 65 || ai->GetManaPercent() < 5) && CastSpell(ICE_BLOCK,m_bot)) { return; } if (isUnderAttack() && CastSpell(ICE_BARRIER, pTarget)) { return; } if (ai->GetManaPercent() < 30 && CastSpell (EVOCATION, m_bot)) { return; } //Break spells if (m_bot->getRace() == (uint8) RACE_BLOODELF && pDist < 8 && (pTarget->IsNonMeleeSpellCasted(true) || ai->GetManaPercent() < 40) && CastSpell(R_ARCANE_TORRENT, pTarget)) { } //no gcd else if (pThreat < threatThreshold && pTarget->IsNonMeleeSpellCasted(true) && CastSpell(COUNTER_SPELL, pTarget)) { return; } //High threat if (!m_bot->HasAura(MOLTEN_ARMOR) && CastSpell(MOLTEN_ARMOR,m_bot)) { return; } if (ai->GetHealthPercent(*pTarget) > 96) { return; } // dont dps too early //Catch if (pTarget->HasUnitMovementFlag(UNIT_FLAG_FLEEING)) { if (CastSpell(FROST_NOVA,pTarget)) return; if (CastSpell(FROSTBOLT,pTarget)) return; } // If at threat limit, try to reduce threat if (pThreat > threatThreshold && m_tank->GetGUID() != m_bot->GetGUID() && !isUnderAttack()) { if (m_tank->getVictim() && m_tank->getVictim()->GetGUID() != pTarget->GetGUID()) // I am attacking wrong target!! { m_bot->SetSelection(m_tank->getVictim()->GetGUID()); return; } else { if (CastSpell(INVISIBILITY,m_bot)) { return; } //Lets see if we can manage else if (m_bot->FindCurrentSpellBySpellId(SHOOT)) { m_bot->InterruptNonMeleeSpells( true, SHOOT ); return; } //Disable wand else { return; } //use no spells and wait threat to be reduced } } // buff up if (CastSpell(ICY_VEINS,m_bot)) {} //nogcd if (m_bot->getRace() == (uint8) RACE_TROLL && CastSpell(R_BERSERKING,m_bot)) {} //no GCD if (m_bot->getRace() == (uint8) RACE_ORC && CastSpell(R_BLOOD_FURY,m_bot)) {} //no GCD if (CastSpell(POM,m_bot)) {} //nogcd if (TALENT_ARCANE) { if (CastSpell(ARCANE_POWER,m_bot)) {} //nogcd if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(BLIZZARD,pTarget)) { return; } } //DPS if (ARCANE_BLAST) { Aura *abaura = m_bot->GetAura(P_ARCANE_BLAST); if (abaura && abaura->GetStackAmount() >= 3) { if (m_bot->HasAura(P_MISSILE_BARRAGE) && CastSpell(ARCANE_MISSILES,pTarget)) { return; } else if (CastSpell(ARCANE_BARRAGE,pTarget)) { return; } } } if (CastSpell(ARCANE_BARRAGE,pTarget) ) { return; } } if (TALENT_FIRE) { if (CastSpell(COMBUSTION,m_bot)) { } //nogcd if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(FLAMESTRIKE,pTarget)) { return; } if (CastSpell(BLAST_WAVE,pTarget)) { return; } if (CastSpell(LIVING_BOMB,pTarget)) { return; } if (CastSpell(DRAGONS_BREATH,pTarget)) { return; } } //DPS if (m_bot->HasAura(P_HOT_STREAK) && CastSpell(PYROBLAST,pTarget)) { return; } if (!pTarget->HasAura(LIVING_BOMB,m_bot->GetGUID()) && CastSpell(LIVING_BOMB,pTarget)) { return; } //if (!pTarget->HasAura(IMP_SCORCH) && CastSpell(SCORCH,pTarget)) { return; } if (CastSpell(FIREBALL,pTarget)) { return; } } if (TALENT_FROST) { if (CastSpell(MIRROR_IMAGE,m_bot)) { return; } if (CastSpell(WATER_ELEMENTAL,m_bot)) { return; } uint64 pet_guid = m_bot->GetPetGUID(); if (pet_guid>0){ Pet* pet = ObjectAccessor::GetPet(*m_bot, pet_guid); Unit *unit = ObjectAccessor::GetUnit(*m_bot, pet_guid); if (unit!=NULL){ if (!unit->isInCombat()) { m_bot->GetSession()->HandlePetActionHelper(unit, pet_guid, COMMAND_ATTACK, ACT_COMMAND, pTarget->GetGUID()); } } } //if (CastSpell(33395, pTarget)) // pet freeze spell // sLog.outError ("successfully casted freeze"); //AOE if (isUnderAttack(m_tank,5)) { if (CastSpell(BLIZZARD,pTarget)) { return; } } //DPS if (m_bot->HasAura(P_FINGERS_OF_FROST) && CastSpell(DEEP_FREEZE,pTarget)) { return; } if (m_bot->HasAura(P_BRAIN_FREEZE) && CastSpell(FROSTFIRE_BOLT,pTarget)) { return; } if (CastSpell(FROSTBOLT,pTarget,true,true)) { return; } } // Defaults especialy for lower levels if (m_bot->HasAura(P_BRAIN_FREEZE) && CastSpell(FIREBALL,pTarget,1,1)) { return; } if (m_bot->HasAura(P_FIRESTARTER) && CastSpell(FLAMESTRIKE,pTarget,1,1)) { return; } if (m_bot->HasAura(P_HOT_STREAK) && CastSpell(PYROBLAST,pTarget,1,1)) { return; } if (m_bot->HasAura(POM) && (CastSpell(PYROBLAST,pTarget,1,1) || CastSpell(FIREBALL,pTarget,1,1) || CastSpell(FROSTBOLT,pTarget,1,1))) { return; } if (pTarget->isFrozen() && CastSpell(ICE_LANCE,pTarget)) { return; } if (m_bot->isMoving() && (CastSpell(FIRE_BLAST,pTarget,1,1) || CastSpell(ARCANE_BARRAGE,pTarget) || CastSpell(ICE_LANCE,pTarget))) { return; } if (CastSpell(FIREBALL,pTarget)) { return; } if (CastSpell(FROSTBOLT,pTarget)) { return; } if (CastSpell(ARCANE_MISSILES,pTarget)) { return; } // drink potion if(ai->GetManaPercent() < 5 ) { Item *pItem = ai->FindPotion(); if(pItem != NULL) { if (pItem->GetSpell() && m_bot->HasSpellCooldown(pItem->GetSpell()) ) { return; } //pot is in cooldown ai->UseItem(*pItem); } } // if we get down here, it means we are out of mana, so use wand CastSpell(SHOOT, pTarget); } //end DoNextCombatManeuver
void UpdateAI(const uint32 diff) { //Inhibitmagic_Timer if (Inhibitmagic_Timer <= diff) { float dist; Map* map = me->GetMap(); Map::PlayerList const &PlayerList = map->GetPlayers(); for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* i_pl = i->getSource()) if (i_pl->isAlive() && (dist = i_pl->IsWithinDist(me, 45))) { i_pl->RemoveAurasDueToSpell(SPELL_INHIBITMAGIC); me->AddAura(SPELL_INHIBITMAGIC, i_pl); if (dist < 35) me->AddAura(SPELL_INHIBITMAGIC, i_pl); if (dist < 25) me->AddAura(SPELL_INHIBITMAGIC, i_pl); if (dist < 15) me->AddAura(SPELL_INHIBITMAGIC, i_pl); } Inhibitmagic_Timer = 3000+(rand()%1000); } else Inhibitmagic_Timer -= diff; //Return since we have no target if (!UpdateVictim()) return; //Attractmagic_Timer if (Attractmagic_Timer <= diff) { DoCast(me, SPELL_ATTRACTMAGIC); Attractmagic_Timer = 30000; Carnivorousbite_Timer = 1500; } else Attractmagic_Timer -= diff; //Carnivorousbite_Timer if (Carnivorousbite_Timer <= diff) { DoCast(me, SPELL_CARNIVOROUSBITE); Carnivorousbite_Timer = 10000; } else Carnivorousbite_Timer -= diff; //FocusFire_Timer if (FocusFire_Timer <= diff) { // Summon Focus Fire & Emote Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); if (target && target->GetTypeId() == TYPEID_PLAYER && target->isAlive()) { FocusedTargetGUID = target->GetGUID(); me->SummonCreature(ENTRY_FOCUS_FIRE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5500); // TODO: Find better way to handle emote // Emote std::string emote(EMOTE_FOCUSES_ON); emote.append(target->GetName()); emote.push_back('!'); me->MonsterTextEmote(emote.c_str(), 0, true); } FocusFire_Timer = 15000+(rand()%5000); } else FocusFire_Timer -= diff; DoMeleeAttackIfReady(); }
void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.t_guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { foundNewTransport = true; plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); movementInfo.t_time = 0; movementInfo.t_seat = -1; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); movementInfo.t_time = 0; movementInfo.t_seat = -1; } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->isInFlight()) plrMover->HandleFall(movementInfo); if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recvData.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); float underMapValueZ; switch (plrMover->GetMapId()) { case 617: underMapValueZ = 3.0f; break; // Dalaran Sewers case 618: underMapValueZ = 28.0f; break; // Ring of Valor case 562: underMapValueZ = -10.0f; break; // Blade Edge Arena case 559: underMapValueZ = -18.0f; break; // Nagrand arena case 572: underMapValueZ = 28.0f; break; // Lordearon case 571: underMapValueZ = -400.0f; break; // Northrend default: underMapValueZ = -500.0f; break; } if (movementInfo.pos.GetPositionZ() < underMapValueZ) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // NOTE: this is actually called many times while falling // even after the player has been teleported away /// @todo discard movement packets after the player is rooted if (plrMover->isAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plrMover->isAlive()) plrMover->KillPlayer(); } } } } }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (ResetTimer <= diff) { if (me->IsWithinDist3d(119.223f, 1035.45f, 29.4481f, 10)) { EnterEvadeMode(); return; } ResetTimer = 5000; } else ResetTimer -= diff; if (CheckAddState_Timer <= diff) { for (uint8 i = 0; i < 4; ++i) if (Creature* temp = Unit::GetCreature(*me, AddGUID[i])) if (temp->isAlive() && !temp->getVictim()) temp->AI()->AttackStart(me->getVictim()); CheckAddState_Timer = 5000; } else CheckAddState_Timer -= diff; if (DrainPower_Timer <= diff) { DoCast(me, SPELL_DRAIN_POWER, true); me->MonsterYell(YELL_DRAIN_POWER, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_YELL_DRAIN_POWER); DrainPower_Timer = urand(40000, 55000); // must cast in 60 sec, or buff/debuff will disappear } else DrainPower_Timer -= diff; if (SpiritBolts_Timer <= diff) { if (DrainPower_Timer < 12000) // channel 10 sec SpiritBolts_Timer = 13000; // cast drain power first else { DoCast(me, SPELL_SPIRIT_BOLTS, false); me->MonsterYell(YELL_SPIRIT_BOLTS, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_YELL_SPIRIT_BOLTS); SpiritBolts_Timer = 40000; SiphonSoul_Timer = 10000; // ready to drain PlayerAbility_Timer = 99999; } } else SpiritBolts_Timer -= diff; if (SiphonSoul_Timer <= diff) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true); Unit* trigger = DoSpawnCreature(MOB_TEMP_TRIGGER, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); if (!target || !trigger) { EnterEvadeMode(); return; } else { trigger->SetDisplayId(11686); trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); trigger->CastSpell(target, SPELL_SIPHON_SOUL, true); trigger->GetMotionMaster()->MoveChase(me); //DoCast(target, SPELL_SIPHON_SOUL, true); //me->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, target->GetGUID()); //me->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SIPHON_SOUL); PlayerGUID = target->GetGUID(); PlayerAbility_Timer = urand(8000, 10000); PlayerClass = target->getClass() - 1; if (PlayerClass == CLASS_DRUID-1) PlayerClass = CLASS_DRUID; else if (PlayerClass == CLASS_PRIEST-1 && target->HasSpell(15473)) PlayerClass = CLASS_PRIEST; // shadow priest SiphonSoul_Timer = 99999; // buff lasts 30 sec } } else SiphonSoul_Timer -= diff; if (PlayerAbility_Timer <= diff) { //Unit* target = Unit::GetUnit(*me, PlayerGUID); //if (target && target->isAlive()) //{ UseAbility(); PlayerAbility_Timer = urand(8000, 10000); //} } else PlayerAbility_Timer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (ArcingSmashTimer <= diff) { DoCast(me->getVictim(), SPELL_ARCING_SMASH); ArcingSmashTimer = 10000; } else ArcingSmashTimer -= diff; if (FelAcidTimer <= diff) { DoCast(me->getVictim(), SPELL_FEL_ACID); FelAcidTimer = 25000; } else FelAcidTimer -= diff; if (!me->HasAura(SPELL_BERSERK)) { if (EnrageTimer <= diff) { DoCast(me, SPELL_BERSERK); DoScriptText(RAND(SAY_ENRAGE1, SAY_ENRAGE2), me); } else EnrageTimer -= diff; } if (Phase1) { if (BewilderingStrikeTimer <= diff) { DoCast(me->getVictim(), SPELL_BEWILDERING_STRIKE); float mt_threat = DoGetThreat(me->getVictim()); if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1)) me->AddThreat(target, mt_threat); BewilderingStrikeTimer = 20000; } else BewilderingStrikeTimer -= diff; if (EjectTimer <= diff) { DoCast(me->getVictim(), SPELL_EJECT1); DoModifyThreatPercent(me->getVictim(), -40); EjectTimer = 15000; } else EjectTimer -= diff; if (AcidicWoundTimer <= diff) { DoCast(me->getVictim(), SPELL_ACIDIC_WOUND); AcidicWoundTimer = 10000; } else AcidicWoundTimer -= diff; if (BloodboilTimer <= diff) { if (BloodboilCount < 5) // Only cast it five times. { //CastBloodboil(); // Causes issues on windows, so is commented out. DoCast(me->getVictim(), SPELL_BLOODBOIL); ++BloodboilCount; BloodboilTimer = 10000*BloodboilCount; } } else BloodboilTimer -= diff; } if (!Phase1) { if (AcidGeyserTimer <= diff) { DoCast(me->getVictim(), SPELL_ACID_GEYSER); AcidGeyserTimer = 30000; } else AcidGeyserTimer -= diff; if (EjectTimer <= diff) { DoCast(me->getVictim(), SPELL_EJECT2); EjectTimer = 15000; } else EjectTimer -= diff; } if (PhaseChangeTimer <= diff) { if (Phase1) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); if (target && target->isAlive()) { Phase1 = false; TargetThreat = DoGetThreat(target); TargetGUID = target->GetGUID(); target->CastSpell(me, SPELL_TAUNT_GURTOGG, true); if (DoGetThreat(target)) DoModifyThreatPercent(target, -100); me->AddThreat(target, 50000000.0f); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); // If VMaps are disabled, this spell can call the whole instance DoCast(me, SPELL_INSIGNIFIGANCE, true); DoCast(target, SPELL_FEL_RAGE_TARGET, true); DoCast(target, SPELL_FEL_RAGE_2, true); /* These spells do not work, comment them out for now. DoCast(target, SPELL_FEL_RAGE_2, true); DoCast(target, SPELL_FEL_RAGE_3, true);*/ //Cast this without triggered so that it appears in combat logs and shows visual. DoCast(me, SPELL_FEL_RAGE_SELF); DoScriptText(RAND(SAY_SPECIAL1, SAY_SPECIAL2), me); AcidGeyserTimer = 1000; PhaseChangeTimer = 30000; } } else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage { if (TargetGUID) RevertThreatOnTarget(TargetGUID); TargetGUID = 0; Phase1 = true; BloodboilTimer = 10000; BloodboilCount = 0; AcidicWoundTimer += 2000; ArcingSmashTimer += 2000; FelAcidTimer += 2000; EjectTimer += 2000; PhaseChangeTimer = 60000; me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); } } else PhaseChangeTimer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (Summon_Timer <= diff) { me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_SUMMON_FIENDISH_HOUND); Summon_Timer = 24100+rand()%2800; } else Summon_Timer -= diff; if (CanPullBack) { if (ShadowWhip_Timer <= diff) { if (Unit* temp = Unit::GetUnit(*me, playerGUID)) { //if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) if (temp->HasUnitMovementFlag(MOVEFLAG_FALLING)) { me->InterruptNonMeleeSpells(false); DoCast(temp, SPELL_SHADOW_WHIP); } else if (!temp->HasUnitMovementFlag(MOVEFLAG_FALLING)) { playerGUID = 0; CanPullBack = false; } } ShadowWhip_Timer = 2000; } else ShadowWhip_Timer -= diff; } else if (OrbitalStrike_Timer <= diff) { Unit* temp = NULL; if (me->IsWithinMeleeRange(me->getVictim())) temp = me->getVictim(); else temp = SelectUnit(SELECT_TARGET_RANDOM, 0); if (temp && temp->GetTypeId() == TYPEID_PLAYER) { me->InterruptNonMeleeSpells(false); DoCast(temp, SPELL_ORBITAL_STRIKE); OrbitalStrike_Timer = 14000+rand()%2000; playerGUID = temp->GetGUID(); if (playerGUID) { CanPullBack = true; ShadowWhip_Timer = 2500; } } } else OrbitalStrike_Timer -= diff; if ((me->GetHealth()*100) / me->GetMaxHealth() < 20) { if (DemonicShield_Timer <= diff) { DoCast(me, SPELL_DEMONIC_SHIELD); DemonicShield_Timer = 15000; } else DemonicShield_Timer -= diff; } if (Aura_Timer <= diff) { DoScriptText(SAY_CURSE, me); if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) { DoCast(pTarget, HeroicMode ? H_SPELL_BANE_OF_TREACHERY : SPELL_TREACHEROUS_AURA); Aura_Timer = 8000+rand()%8000; } } else Aura_Timer -= diff; if (Shadowbolt_Timer <= diff) { if (Unit *pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) { if (pTarget) pTarget = me->getVictim(); DoCast(pTarget, HeroicMode ? H_SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT); Shadowbolt_Timer = 4000+rand()%3100; } } else Shadowbolt_Timer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if(!UpdateVictim()) return; if(Phase1) { if(pulse_Timer < diff) { if(me->GetPositionZ() > (COORD_Z_HOME+15)) { EnterEvadeMode(); return; } DoAttackerAreaInCombat(me->getVictim(),50); pulse_Timer = 10000; }else pulse_Timer -= diff; } if(!me->HasAura(SPELL_BERSERK, 0)) { if(EnrageTimer < diff) { DoCast(me, SPELL_BERSERK); switch(rand()%2) { case 0: DoScriptText(SAY_ENRAGE1, me); break; case 1: DoScriptText(SAY_ENRAGE2, me); break; } }else EnrageTimer -= diff; } if(ArcingSmashTimer < diff) { DoCast(me->getVictim(),Phase1 ? SPELL_ARCING_SMASH_1 : SPELL_ARCING_SMASH_2); ArcingSmashTimer = 10000; }else ArcingSmashTimer -= diff; if(FelBreathTimer < diff) { DoCast(me->getVictim(),Phase1 ? SPELL_FELBREATH_1 : SPELL_FELBREATH_2); FelBreathTimer = 25000; }else FelBreathTimer -= diff; if(EjectTimer < diff) { DoCast(me->getVictim(),Phase1 ? SPELL_EJECT_1 : SPELL_EJECT_2); EjectTimer = 15000; }else EjectTimer -= diff; if(Charge_Timer < diff) { if(me->GetDistance2d(me->getVictim()) > 15) DoCast(me->getVictim(),SPELL_CHARGE); Charge_Timer = 10000; }else Charge_Timer -= diff; if(Phase1) { if(BewilderingStrikeTimer < diff) { DoCast(me->getVictim(), SPELL_BEWILDERING_STRIKE); //float mt_threat = DoGetThreat(me->getVictim()); //if (Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO, 1)) // me->AddThreat(target, mt_threat); BewilderingStrikeTimer = 20000; }else BewilderingStrikeTimer -= diff; //if(EjectTimer < diff) //{ // DoCast(me->getVictim(), SPELL_EJECT1); // DoModifyThreatPercent(me->getVictim(), -40); // EjectTimer = 15000; //}else EjectTimer -= diff; //if(AcidicWoundTimer < diff) //{ // DoCast(me->getVictim(), SPELL_ACIDIC_WOUND); // AcidicWoundTimer = 10000; //}else AcidicWoundTimer -= diff; if(BloodboilTimer < diff) { if(BloodboilCount < 5) // Only cast it five times. { CastBloodboil(); // Causes issues on windows, so is commented out. //DoCast(me->getVictim(), SPELL_BLOODBOIL); ++BloodboilCount; BloodboilTimer = 10000; } }else BloodboilTimer -= diff; } if(!Phase1) { //if(FelGeyserTimer < diff) //{ // DoCast(me->getVictim(), SPELL_FEL_GEYSER,true); // FelGeyserTimer = 30000; //}else FelGeyserTimer -= diff; if(me->getVictim() && me->getVictim()->IsImmunedToDamage(SPELL_SCHOOL_MASK_ALL)) me->getThreatManager().modifyThreatPercent(me->getVictim(),-100); } if(PhaseChangeTimer < diff) { if(Phase1) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0,100,true); if(target && target->isAlive()) { Phase1 = false; TargetThreat = DoGetThreat(target); TargetGUID = target->GetGUID(); if(DoGetThreat(target)) DoModifyThreatPercent(target, -100); me->AddThreat(target, 50000000.0f); target->CastSpell(me, SPELL_TAUNT_GURTOGG, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); // If VMaps are disabled, this spell can call the whole instance DoCast(me, SPELL_INSIGNIFIGANCE, true); DoCast(target,SPELL_FEL_RAGE_1, true); DoCast(target,SPELL_FEL_RAGE_2, true); DoCast(target,SPELL_FEL_RAGE_3, true); DoCast(target,SPELL_FEL_RAGE_SCALE, true); DoCast(target,SPELL_FEL_GEYSER,true); //Cast this without triggered so that it appears in combat logs and shows visual. DoCast(me, SPELL_FEL_RAGE_SELF); switch(rand()%2) { case 0: DoScriptText(SAY_SPECIAL1, me); break; case 1: DoScriptText(SAY_SPECIAL2, me); break; } FelGeyserTimer = 1; PhaseChangeTimer = 30000; } }else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage { if(TargetGUID) RevertThreatOnTarget(TargetGUID); TargetGUID = 0; Phase1 = true; BloodboilTimer = 10000; BloodboilCount = 0; /*AcidicWoundTimer += 2000;*/ ArcingSmashTimer += 2000; FelBreathTimer += 2000; EjectTimer += 2000; PhaseChangeTimer = 65000; me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); me->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, false); } }else PhaseChangeTimer -= diff; DoMeleeAttackIfReady(); }
void HandleDummy(SpellEffIndex /* effIndex */) { int32 damage = GetEffectValue(); Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) { // apply percent damage mods damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); ApplyPctN(damage, 16 * sSpellMgr->GetSpellRank(GetSpellInfo()->Id)); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_DEEP_WOUNDS_RANK_PERIODIC); uint32 ticks = spellInfo->GetDuration() / spellInfo->Effects[EFFECT_0].Amplitude; // Add remaining ticks to damage done if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_DEEP_WOUNDS_RANK_PERIODIC, EFFECT_0, caster->GetGUID())) damage += aurEff->GetAmount() * (ticks - aurEff->GetTickNumber()); damage = damage / ticks; caster->CastCustomSpell(target, SPELL_DEEP_WOUNDS_RANK_PERIODIC, &damage, NULL, NULL, true); } }
void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; //only two may be wrong, perhaps increase timer and spawn periodically instead. if (SummonedCount < 2) { if (Summon_Timer <= diff) { me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_SUMMON_FIENDISH_HOUND); Summon_Timer = 15000 + rand32() % 15000; } else Summon_Timer -= diff; } if (CanPullBack) { if (ShadowWhip_Timer <= diff) { if (Player* temp = ObjectAccessor::GetPlayer(*me, PlayerGUID)) { //if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) if (temp->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) { me->InterruptNonMeleeSpells(false); DoCast(temp, SPELL_SHADOW_WHIP); } } PlayerGUID = 0; ShadowWhip_Timer = 2000; CanPullBack = false; } else ShadowWhip_Timer -= diff; } else if (OrbitalStrike_Timer <= diff) { Unit* temp = NULL; if (me->IsWithinMeleeRange(me->GetVictim())) temp = me->GetVictim(); else temp = SelectTarget(SELECT_TARGET_RANDOM, 0); if (temp && temp->GetTypeId() == TYPEID_PLAYER) { DoCast(temp, SPELL_ORBITAL_STRIKE); OrbitalStrike_Timer = 14000 + rand32() % 2000; PlayerGUID = temp->GetGUID(); if (PlayerGUID) CanPullBack = true; } } else OrbitalStrike_Timer -= diff; if (HealthBelowPct(20)) { if (DemonicShield_Timer <= diff) { DoCast(me, SPELL_DEMONIC_SHIELD); DemonicShield_Timer = 15000; } else DemonicShield_Timer -= diff; } if (Aura_Timer <= diff) { Talk(SAY_CURSE); if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { DoCast(target, SPELL_TREACHEROUS_AURA); Aura_Timer = 8000 + rand32() % 8000; } } else Aura_Timer -= diff; if (Shadowbolt_Timer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { if (target) target = me->GetVictim(); DoCast(target, SPELL_SHADOW_BOLT); Shadowbolt_Timer = 4000 + rand32() % 2500; } } else Shadowbolt_Timer -= diff; DoMeleeAttackIfReady(); }
/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ void WorldSession::HandleRequestPartyMemberStatsOpcode( WorldPacket &recv_data ) { sLog.outDebug("WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); uint64 Guid; recv_data >> Guid; Player *player = sObjectMgr.GetPlayer(Guid); if(!player) { WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data.appendPackGUID(Guid); data << uint32(GROUP_UPDATE_FLAG_STATUS); data << uint16(MEMBER_STATUS_OFFLINE); SendPacket(&data); return; } Unit *pet = player->GetCharmOrPet(); WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related data << player->GetPackGUID(); uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF if(pet) mask1 = 0xFFFFFFFF; // for hunters and other classes with pets Powers powerType = player->getPowerType(); data << uint32(mask1); // group update mask data << uint16(MEMBER_STATUS_ONLINE); // member's online status data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP data << uint8(powerType); // GROUP_UPDATE_FLAG_POWER_TYPE data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION uint64 auramask = 0; size_t maskPos = data.wpos(); data << uint64(auramask); // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 aura = player->GetVisibleAura(i)) { auramask |= (uint64(1) << i); data << uint32(aura); data << uint8(1); } } data.put<uint64>(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS if(pet) { Powers petpowertype = pet->getPowerType(); data << uint64(pet->GetGUID()); // GROUP_UPDATE_FLAG_PET_GUID data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME data << uint16(pet->GetDisplayId()); // GROUP_UPDATE_FLAG_PET_MODEL_ID data << uint32(pet->GetHealth()); // GROUP_UPDATE_FLAG_PET_CUR_HP data << uint32(pet->GetMaxHealth()); // GROUP_UPDATE_FLAG_PET_MAX_HP data << uint8(petpowertype); // GROUP_UPDATE_FLAG_PET_POWER_TYPE data << uint16(pet->GetPower(petpowertype)); // GROUP_UPDATE_FLAG_PET_CUR_POWER data << uint16(pet->GetMaxPower(petpowertype)); // GROUP_UPDATE_FLAG_PET_MAX_POWER uint64 petauramask = 0; size_t petMaskPos = data.wpos(); data << uint64(petauramask); // placeholder for(uint8 i = 0; i < MAX_AURAS; ++i) { if(uint32 petaura = pet->GetVisibleAura(i)) { petauramask |= (uint64(1) << i); data << uint32(petaura); data << uint8(1); } } data.put<uint64>(petMaskPos,petauramask); // GROUP_UPDATE_FLAG_PET_AURAS data << (uint32) player->m_SeatData.dbc_seat; } else { data << uint8(0); // GROUP_UPDATE_FLAG_PET_NAME data << uint64(0); // GROUP_UPDATE_FLAG_PET_AURAS } SendPacket(&data); }
void WorldSession::BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data) { uint32 mask = player->GetGroupUpdateFlag(); if (mask == GROUP_UPDATE_FLAG_NONE) return; if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); uint32 byteCount = 0; for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) if (mask & (1 << i)) byteCount += GroupUpdateLength[i]; data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); *data << player->GetPackGUID(); *data << uint32(mask); if (mask & GROUP_UPDATE_FLAG_STATUS) { if (player) { if (player->IsPvP()) *data << uint16(MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); else *data << uint16(MEMBER_STATUS_ONLINE); } else *data << uint16(MEMBER_STATUS_OFFLINE); } if (mask & GROUP_UPDATE_FLAG_CUR_HP) *data << uint32(player->GetHealth()); if (mask & GROUP_UPDATE_FLAG_MAX_HP) *data << uint32(player->GetMaxHealth()); Powers powerType = player->getPowerType(); if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) *data << uint8(powerType); if (mask & GROUP_UPDATE_FLAG_CUR_POWER) *data << uint16(player->GetPower(powerType)); if (mask & GROUP_UPDATE_FLAG_MAX_POWER) *data << uint16(player->GetMaxPower(powerType)); if (mask & GROUP_UPDATE_FLAG_LEVEL) *data << uint16(player->getLevel()); if (mask & GROUP_UPDATE_FLAG_ZONE) *data << uint16(player->GetZoneId()); if (mask & GROUP_UPDATE_FLAG_POSITION) *data << uint16(player->GetPositionX()) << uint16(player->GetPositionY()); if (mask & GROUP_UPDATE_FLAG_AURAS) { const uint64& auramask = player->GetAuraUpdateMask(); *data << uint64(auramask); for(uint32 i = 0; i < MAX_AURAS; ++i) { if(auramask & (uint64(1) << i)) { *data << uint32(player->GetVisibleAura(i)); *data << uint8(1); } } } Unit *pet = player->GetCharmOrPet(); if (mask & GROUP_UPDATE_FLAG_PET_GUID) { if(pet) *data << uint64(pet->GetGUID()); else *data << uint64(0); } if (mask & GROUP_UPDATE_FLAG_PET_NAME) { if(pet) *data << pet->GetName(); else *data << uint8(0); } if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) { if(pet) *data << uint16(pet->GetDisplayId()); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) { if(pet) *data << uint32(pet->GetHealth()); else *data << uint32(0); } if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) { if(pet) *data << uint32(pet->GetMaxHealth()); else *data << uint32(0); } if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) { if(pet) *data << uint8(pet->getPowerType()); else *data << uint8(0); } if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) { if(pet) *data << uint16(pet->GetPower(pet->getPowerType())); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) { if(pet) *data << uint16(pet->GetMaxPower(pet->getPowerType())); else *data << uint16(0); } if (mask & GROUP_UPDATE_FLAG_PET_AURAS) { if(pet) { const uint64& auramask = pet->GetAuraUpdateMask(); *data << uint64(auramask); for(uint32 i = 0; i < MAX_AURAS; ++i) { if(auramask & (uint64(1) << i)) { *data << uint32(pet->GetVisibleAura(i)); *data << uint8(1); } } } else *data << uint64(0); } if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) { *data << (uint32) player->m_SeatData.dbc_seat; } }
void UpdateAI(uint32 diff) override { if (TalkTimer) { if (!TalkSequence) { me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); me->InterruptNonMeleeSpells(true); me->RemoveAllAuras(); me->DeleteThreatList(); me->CombatStop(); ++TalkSequence; } if (TalkTimer <= diff) { if (isFriendly) GoodEnding(); else BadEnding(); ++TalkSequence; } else TalkTimer -= diff; } else { if (bJustReset) { if (ResetTimer <= diff) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); me->SetDisableGravity(false); me->SetVisible(true); me->SetStandState(UNIT_STAND_STATE_SLEEP); ResetTimer = 10000; bJustReset = false; } else ResetTimer -= diff; return; } if (!UpdateVictim()) return; if (CheckTimer <= diff) { if (me->GetDistance(CENTER_X, CENTER_Y, DRAGON_REALM_Z) >= 75) { EnterEvadeMode(); return; } if (HealthBelowPct(10) && !isEnraged) { if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) Sath->AI()->DoAction(DO_ENRAGE); DoAction(DO_ENRAGE); } if (!isBanished && HealthBelowPct(1)) { if (Creature* Sath = ObjectAccessor::GetCreature(*me, SathGUID)) { if (Sath->HasAura(SPELL_BANISH)) { Sath->DealDamage(Sath, Sath->GetHealth()); return; } else DoAction(DO_BANISH); } else { TC_LOG_ERROR("scripts", "Didn't find Shathrowar. Kalecgos event reseted."); EnterEvadeMode(); return; } } CheckTimer = 1000; } else CheckTimer -= diff; if (ArcaneBuffetTimer <= diff) { DoCastAOE(SPELL_ARCANE_BUFFET); ArcaneBuffetTimer = 8000; } else ArcaneBuffetTimer -= diff; if (FrostBreathTimer <= diff) { DoCastAOE(SPELL_FROST_BREATH); FrostBreathTimer = 15000; } else FrostBreathTimer -= diff; if (TailLashTimer <= diff) { DoCastAOE(SPELL_TAIL_LASH); TailLashTimer = 15000; } else TailLashTimer -= diff; if (WildMagicTimer <= diff) { DoCastAOE(WildMagic[rand()%6]); WildMagicTimer = 20000; } else WildMagicTimer -= diff; if (SpectralBlastTimer <= diff) { ThreatContainer::StorageType const& m_threatlist = me->getThreatManager().getThreatList(); std::list<Unit*> targetList; for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) { Unit* target = (*itr)->getTarget(); if (target && target->GetTypeId() == TYPEID_PLAYER && (!target->GetVictim() || target->GetGUID() != me->EnsureVictim()->GetGUID()) && target->GetPositionZ() > me->GetPositionZ() - 5 && !target->HasAura(AURA_SPECTRAL_EXHAUSTION)) { targetList.push_back(target); } } if (targetList.empty()) { SpectralBlastTimer = 1000; return; } std::list<Unit*>::const_iterator i = targetList.begin(); advance(i, rand()%targetList.size()); if ((*i)) { (*i)->CastSpell((*i), SPELL_SPECTRAL_BLAST, true); SpectralBlastTimer = 20000+rand()%5000; } else SpectralBlastTimer = 1000; } else SpectralBlastTimer -= diff; DoMeleeAttackIfReady(); } }
void UpdateAI(const uint32 diff) { //Check if we have a target if (!m_creature->SelectHostilTarget() || !m_creature->getVictim()) return; //No instance if (!pInstance) return; switch (pInstance->GetData(DATA_CTHUN_PHASE)) { case 0: { //BeamTimer if (BeamTimer < diff) { //SPELL_GREEN_BEAM Unit* target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) { m_creature->InterruptNonMeleeSpells(false); DoCast(target,SPELL_GREEN_BEAM); //Correctly update our target m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); } //Beam every 3 seconds BeamTimer = 3000; }else BeamTimer -= diff; //ClawTentacleTimer if (ClawTentacleTimer < diff) { Unit* target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) { Creature* Spawned = NULL; //Spawn claw tentacle on the random target Spawned = (Creature*)m_creature->SummonCreature(MOB_CLAW_TENTACLE,target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); if (Spawned) Spawned->AI()->AttackStart(target); } //One claw tentacle every 12.5 seconds ClawTentacleTimer = 12500; }else ClawTentacleTimer -= diff; //EyeTentacleTimer if (EyeTentacleTimer < diff) { //Spawn the 8 Eye Tentacles in the corret spots SpawnEyeTentacle(0, 20); //south SpawnEyeTentacle(10, 10); //south west SpawnEyeTentacle(20, 0); //west SpawnEyeTentacle(10, -10); //north west SpawnEyeTentacle(0, -20); //north SpawnEyeTentacle(-10, -10); //north east SpawnEyeTentacle(-20, 0); // east SpawnEyeTentacle(-10, 10); // south east //No point actually putting a timer here since //These shouldn't trigger agian until after phase shifts EyeTentacleTimer = 45000; }else EyeTentacleTimer -= diff; //PhaseTimer if (PhaseTimer < diff) { //Switch to Dark Beam pInstance->SetData(DATA_CTHUN_PHASE, 1); m_creature->InterruptNonMeleeSpells(false); //Select random target for dark beam to start on Unit* target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM,0); if (target) { //Correctly update our target m_creature->SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); //Face our target DarkGlareAngle = m_creature->GetAngle(target); DarkGlareTickTimer = 1000; DarkGlareTick = 0; ClockWise = rand()%2; } //Add red coloration to C'thun DoCast(m_creature,SPELL_RED_COLORATION); //Freeze animation //Darkbeam for 35 seconds PhaseTimer = 35000; }else PhaseTimer -= diff; } break; case 1: { //EyeTentacleTimer if (DarkGlareTick < 35) if (DarkGlareTickTimer < diff) { //Remove any target m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); //Set angle and cast if (ClockWise) m_creature->SetOrientation(DarkGlareAngle + ((float)DarkGlareTick*PI/35)); else m_creature->SetOrientation(DarkGlareAngle - ((float)DarkGlareTick*PI/35)); m_creature->StopMoving(); //Actual dark glare cast, maybe something missing here? m_creature->CastSpell(NULL, SPELL_DARK_GLARE, false); //Increase tick DarkGlareTick++; //1 second per tick DarkGlareTickTimer = 1000; }else DarkGlareTickTimer -= diff; //PhaseTimer if (PhaseTimer < diff) { //Switch to Eye Beam pInstance->SetData(DATA_CTHUN_PHASE, 0); BeamTimer = 3000; EyeTentacleTimer = 45000; //Always spawns 5 seconds before Dark Beam ClawTentacleTimer = 12500; //4 per Eye beam phase (unsure if they spawn durring Dark beam) m_creature->InterruptNonMeleeSpells(false); //Remove Red coloration from c'thun m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); //Freeze animation m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); //Eye Beam for 50 seconds PhaseTimer = 50000; }else PhaseTimer -= diff; }break; //Transition phase case 2: { //Remove any target m_creature->SetUInt64Value(UNIT_FIELD_TARGET, 0); m_creature->SetHealth(0); } //Dead phase case 5: { m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); } } }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; events.Update(diff); if (Phase == 1) { while (uint32 eventId = events.GetEvent()) { switch(eventId) { case EVENT_WASTE: DoSummon(NPC_WASTE, Pos[RAND(0, 3, 6, 9)]); events.RepeatEvent(urand(2000, 5000)); break; case EVENT_ABOMIN: if (nAbomination < 8) { DoSummon(NPC_ABOMINATION, Pos[RAND(1, 4, 7, 10)]); nAbomination++; events.RepeatEvent(20000); } else events.PopEvent(); break; case EVENT_WEAVER: if (nWeaver < 8) { DoSummon(NPC_WEAVER, Pos[RAND(0, 3, 6, 9)]); nWeaver++; events.RepeatEvent(25000); } else events.PopEvent(); break; case EVENT_TRIGGER: if (GameObject *pKTTrigger = me->GetMap()->GetGameObject(KTTriggerGUID)) pKTTrigger->SetPhaseMask(2, true); events.PopEvent(); break; case EVENT_PHASE: events.Reset(); DoScriptText(RAND(SAY_AGGRO_1, SAY_AGGRO_2, SAY_AGGRO_3), me); spawns.DespawnAll(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE); me->CastStop(); DoStartMovement(me->getVictim()); events.ScheduleEvent(EVENT_BOLT, urand(5000, 10000)); events.ScheduleEvent(EVENT_NOVA, 15000); events.ScheduleEvent(EVENT_DETONATE, urand(30000, 40000)); events.ScheduleEvent(EVENT_FISSURE, urand(10000, 30000)); events.ScheduleEvent(EVENT_BLAST, urand(60000, 120000)); if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) events.ScheduleEvent(EVENT_CHAIN, urand(30000, 60000)); Phase = 2; break; default: events.PopEvent(); break; } } } else { //start phase 3 when we are 45% health if (Phase != 3) { if (HealthBelowPct(45)) { Phase = 3 ; DoScriptText(SAY_REQUEST_AID, me); //here Lich King should respond to KelThuzad but I don't know which Creature to make talk //so for now just make Kelthuzad says it. DoScriptText(SAY_ANSWER_REQUEST, me); for (uint8 i = 0; i <= 3; ++i) { if (GameObject *pPortal = me->GetMap()->GetGameObject(PortalsGUID[i])) { if (pPortal->getLootState() == GO_READY) pPortal->UseDoorOrButton(); } } } } else if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4)) { if (uiGuardiansOfIcecrownTimer <= diff) { // TODO : Add missing text if (Creature* pGuardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)])) pGuardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2); ++nGuardiansOfIcecrownCount; uiGuardiansOfIcecrownTimer = 5000; } else uiGuardiansOfIcecrownTimer -= diff; } if (me->HasUnitState(UNIT_STAT_CASTING)) return; if (uint32 eventId = events.GetEvent()) { switch(eventId) { case EVENT_BOLT: DoCastVictim(RAID_MODE(SPELL_FROST_BOLT, H_SPELL_FROST_BOLT)); events.RepeatEvent(urand(5000, 10000)); break; case EVENT_NOVA: DoCastAOE(RAID_MODE(SPELL_FROST_BOLT_AOE, H_SPELL_FROST_BOLT_AOE)); events.RepeatEvent(urand(15000, 30000)); break; case EVENT_CHAIN: { uint32 count = urand(1, 3); for (uint8 i = 1; i <= count; i++) { Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true); if (pTarget && !pTarget->isCharmed() && (chained.find(pTarget->GetGUID()) == chained.end())) { DoCast(pTarget, SPELL_CHAINS_OF_KELTHUZAD); float scale = pTarget->GetFloatValue(OBJECT_FIELD_SCALE_X); chained.insert(std::make_pair(pTarget->GetGUID(), scale)); pTarget->SetFloatValue(OBJECT_FIELD_SCALE_X, scale * 2); events.ScheduleEvent(EVENT_CHAINED_SPELL, 2000); //core has 2000ms to set unit flag charm } } if (!chained.empty()) DoScriptText(RAND(SAY_CHAIN_1, SAY_CHAIN_2), me); events.RepeatEvent(urand(100000, 180000)); break; } case EVENT_CHAINED_SPELL: { std::map<uint64, float>::iterator itr; for (itr = chained.begin(); itr != chained.end();) { if (Unit* player = Unit::GetPlayer(*me, (*itr).first)) { if (!player->isCharmed()) { player->SetFloatValue(OBJECT_FIELD_SCALE_X, (*itr).second); std::map<uint64, float>::iterator next = itr; ++next; chained.erase(itr); itr = next; continue; } if (Unit *pTarget = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, NotCharmedTargetSelector())) { switch(player->getClass()) { case CLASS_DRUID: if (urand(0, 1)) player->CastSpell(pTarget, SPELL_MOONFIRE, false); else player->CastSpell(me, SPELL_LIFEBLOOM, false); break; case CLASS_HUNTER: player->CastSpell(pTarget, RAND(SPELL_MULTI_SHOT, SPELL_VOLLEY), false); break; case CLASS_MAGE: player->CastSpell(pTarget, RAND(SPELL_FROST_FIREBOLT, SPELL_ARCANE_MISSILES), false); break; case CLASS_WARLOCK: player->CastSpell(pTarget, RAND(SPELL_CURSE_OF_AGONY, SPELL_SHADOW_BOLT), true); break; case CLASS_WARRIOR: player->CastSpell(pTarget, RAND(SPELL_BLADESTORM, SPELL_CLEAVE), false); break; case CLASS_PALADIN: if (urand(0, 1)) player->CastSpell(pTarget, SPELL_HAMMER_OF_JUSTICE, false); else player->CastSpell(me, SPELL_HOLY_SHOCK, false); break; case CLASS_PRIEST: if (urand(0, 1)) player->CastSpell(pTarget, SPELL_VAMPIRIC_TOUCH, false); else player->CastSpell(me, SPELL_RENEW, false); break; case CLASS_SHAMAN: if (urand(0, 1)) player->CastSpell(pTarget, SPELL_EARTH_SHOCK, false); else player->CastSpell(me, SPELL_HEALING_WAVE, false); break; case CLASS_ROGUE: player->CastSpell(pTarget, RAND(SPELL_HEMORRHAGE, SPELL_MUTILATE), false); break; case CLASS_DEATH_KNIGHT: if (urand(0, 1)) player->CastSpell(pTarget, SPELL_PLAGUE_STRIKE, true); else player->CastSpell(pTarget, SPELL_HOWLING_BLAST, true); break; } } } ++itr; } if (chained.empty()) events.PopEvent(); else events.RepeatEvent(5000); break; } case EVENT_DETONATE: { std::vector<Unit*> unitList; std::list<HostileReference*> *threatList = &me->getThreatManager().getThreatList(); for (std::list<HostileReference*>::const_iterator itr = threatList->begin(); itr != threatList->end(); ++itr) { if ((*itr)->getTarget()->GetTypeId() == TYPEID_PLAYER && (*itr)->getTarget()->getPowerType() == POWER_MANA && (*itr)->getTarget()->GetPower(POWER_MANA)) unitList.push_back((*itr)->getTarget()); } if (!unitList.empty()) { std::vector<Unit*>::const_iterator itr = unitList.begin(); advance(itr, rand()%unitList.size()); DoCast(*itr, SPELL_MANA_DETONATION); DoScriptText(RAND(SAY_SPECIAL_1, SAY_SPECIAL_2, SAY_SPECIAL_3), me); } events.RepeatEvent(urand(20000, 50000)); break; } case EVENT_FISSURE: if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(pTarget, SPELL_SHADOW_FISURE); events.RepeatEvent(urand(10000, 45000)); break; case EVENT_BLAST: if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, RAID_MODE(1, 0), 0, true)) DoCast(pTarget, SPELL_FROST_BLAST); if (rand()%2) DoScriptText(SAY_FROST_BLAST, me); events.RepeatEvent(urand(30000, 90000)); break; default: events.PopEvent(); break; } } DoMeleeAttackIfReady(); } }
void UpdateAI(const uint32 uiDiff) { if (m_bSummonKilrek) { if (m_uiSummonKilrekTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_IMP) == CAST_OK) { m_uiSummonKilrekTimer = 45000; m_bSummonKilrek = false; } } else m_uiSummonKilrekTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiSacrifice_Timer < uiDiff) { Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1); if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) { DoCastSpellIfCan(pTarget, SPELL_SACRIFICE, CAST_TRIGGERED); Creature* pChains = m_creature->SummonCreature(NPC_DEMONCHAINS, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 21000); if (pChains) { ((mob_demon_chainAI*)pChains->AI())->m_uiSacrificeGUID = pTarget->GetGUID(); pChains->CastSpell(pChains, SPELL_DEMON_CHAINS, true); DoScriptText(urand(0, 1) ? SAY_SACRIFICE1 : SAY_SACRIFICE2, m_creature); m_uiSacrifice_Timer = 30000; } } } else m_uiSacrifice_Timer -= uiDiff; if (m_uiShadowbolt_Timer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT); m_uiShadowbolt_Timer = 10000; } else m_uiShadowbolt_Timer -= uiDiff; if (!m_bSummonedPortals) { if (m_uiSummon_Timer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FIENDISH_PORTAL, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); m_bSummonedPortals = true; } } else m_uiSummon_Timer -= uiDiff; } if (!m_bBerserk) { if (m_uiBerserk_Timer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_INTERRUPT_PREVIOUS); m_bBerserk = true; } else m_uiBerserk_Timer -= uiDiff; } DoMeleeAttackIfReady(); }
void DynamicObject::UpdateTargets() { if (!m_aliveDuration) return; if (m_aliveDuration >= 100) { Unit* target; Aura* pAura; float radius = m_floatValues[DYNAMICOBJECT_RADIUS] * m_floatValues[DYNAMICOBJECT_RADIUS]; // Looking for targets in the Object set for (std::set< Object* >::iterator itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr) { Object* o = *itr; if (!o && !o->IsUnit() || !TO< Unit* >(o)->isAlive()) continue; target = TO< Unit* >(o); if (!isAttackable(u_caster, target, !(m_spellProto->c_is_flags & SPELL_FLAG_IS_TARGETINGSTEALTHED))) continue; // skip units already hit, their range will be tested later if (targets.find(target->GetGUID()) != targets.end()) continue; if (GetDistanceSq(target) <= radius) { pAura = sSpellFactoryMgr.NewAura(m_spellProto, m_aliveDuration, u_caster, target, true); for (uint8 i = 0; i < 3; i++) { if (m_spellProto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) { pAura->AddMod(m_spellProto->EffectApplyAuraName[i], m_spellProto->EffectBasePoints[i] + 1, m_spellProto->EffectMiscValue[i], i); } } target->AddAura(pAura); if (p_caster) { p_caster->HandleProc(PROC_ON_CAST_SPECIFIC_SPELL | PROC_ON_CAST_SPELL, target, m_spellProto); p_caster->m_procCounter = 0; } // add to target list targets.insert(target->GetGUID()); } } // loop the targets, check the range of all of them DynamicObjectList::iterator jtr = targets.begin(); DynamicObjectList::iterator jtr2; DynamicObjectList::iterator jend = targets.end(); while (jtr != jend) { target = GetMapMgr() ? GetMapMgr()->GetUnit(*jtr) : NULL; jtr2 = jtr; ++jtr; if (target && GetDistanceSq(target) > radius) { target->RemoveAura(m_spellProto->Id); targets.erase(jtr2); } } m_aliveDuration -= 100; } else m_aliveDuration = 0; if (!m_aliveDuration) Remove(); }
void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) m_multip = (target->GetDiseasesByCaster(caster->GetGUID()) * GetEffectValue()) / 100.0f; }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->m_mover; Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ uint64 guid; if(!recv_data.readPackGUID(guid)) return; MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ if(!(movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) && _player->GetVehicleGUID()) { if(mover->GetGUID() == _player->GetGUID()) { return; } } // we sent a movement packet with MOVEMENTFLAG_ONTRANSPORT and we are on vehicle // this can be moving on vehicle or entering another transport (eg. boat) if((movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) && _player->GetVehicleGUID()) { // we are controlling that vehicle if(mover->GetGUID() == _player->GetVehicleGUID()) { // we sent movement packet, related to movement ON vehicle, // but not WITH vehicle, so mover = player if(_player->GetVehicleGUID() == movementInfo.t_guid) { // this is required to avoid client crash, otherwise it will result // in moving with vehicle on the same vehicle and that = crash mover = _player; plMover = _player; } } if(_player->GetVehicleGUID() == movementInfo.t_guid) { _player->m_SeatData.OffsetX = movementInfo.t_x; _player->m_SeatData.OffsetY = movementInfo.t_y; _player->m_SeatData.OffsetZ = movementInfo.t_z; _player->m_SeatData.Orientation = movementInfo.t_o; } } recv_data.rpos(recv_data.wpos()); // prevent warnings spam if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && !mover->GetVehicleGUID()) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if( movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if( !MaNGOS::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y + movementInfo.t_y, movementInfo.z + movementInfo.t_z, movementInfo.o + movementInfo.t_o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_x = 0.0f; movementInfo.t_y = 0.0f; movementInfo.t_z = 0.0f; movementInfo.t_o = 0.0f; movementInfo.t_time = 0; movementInfo.t_seat = -1; } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) ); } if (movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING)) { if(mover->GetTypeId() == TYPEID_UNIT) { if(((Creature*)mover)->isVehicle() && !((Creature*)mover)->canSwim()) { // NOTE : we should enter evade mode here, but... ((Vehicle*)mover)->SetSpawnDuration(1); } } } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); GetPlayer()->SendMessageToSet(&data, false); if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); plMover->m_movementInfo = movementInfo; plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(mover->IsInWorld()) { mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); if(((Creature*)mover)->isVehicle()) ((Vehicle*)mover)->RellocatePassengers(mover->GetMap()); } } }
void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) { uint32 opcode = recv_data.GetOpcode(); recv_data.hexlike(); Unit *mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*) mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ uint64 guid; recv_data.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); recv_data.rpos(recv_data.wpos()); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord( movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject *go = mover->GetMap()->GetGameObject( movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plMover && plMover->GetTransport()) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); movementInfo.t_time = 0; movementInfo.t_seat = -1; } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater( movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->SetPosition(movementInfo.pos); if (plMover) // nothing is charmed, or player charmed { if (plMover->GetEmoteState() != 0 && opcode == MSG_MOVE_START_FORWARD && opcode != MSG_MOVE_SET_FACING && opcode != MSG_MOVE_START_TURN_LEFT && opcode != MSG_MOVE_START_TURN_RIGHT && opcode != MSG_MOVE_STOP_TURN) plMover->SetEmoteState(0); plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -5000.0f) { if (!(plMover->InBattleground() && plMover->GetBattleground() && plMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if (plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if (!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } else if (movementInfo.pos.GetPositionZ() < -50.0f) { if (plMover->InBattleground()) if (Battleground* bg = plMover->GetBattleground()) if (bg->isArena()) bg->HandlePlayerUnderMap(_player); } } }
void HandleDummy(SpellEffIndex /* effIndex */) { Unit* target = GetHitUnit(); Unit* caster = GetCaster(); target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, NULL, NULL, caster->GetGUID()); }
void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Unit* unitTarget = GetHitUnit()) if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x2, 0, 0, caster->GetGUID())) { Aura* aura = aurEff->GetBase(); uint32 countMin = aura->GetMaxDuration(); uint32 countMax = aura->GetSpellInfo()->GetMaxDuration() + 9000; if (caster->HasAura(SPELL_DRUID_INCREASED_MOONFIRE_DURATION)) countMax += 3000; if (countMin < countMax) { aura->SetDuration(uint32(aura->GetDuration() + 3000)); aura->SetMaxDuration(countMin + 3000); } } }
void UpdateAI(const uint32 diff) { //Return since we have no target if (!UpdateVictim() ) 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: DoScriptText(SAY_SUMMON1, m_creature); break; case 1: DoScriptText(SAY_SUMMON2, m_creature); break; } for(uint8 i = 0; i < 10; i++) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); Creature* Murloc = m_creature->SummonCreature(MurlocCords[i][0],MurlocCords[i][1],MurlocCords[i][2],MurlocCords[i][3],MurlocCords[i][4], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); if(target && Murloc) Murloc->AI()->AttackStart(target); } DoScriptText(EMOTE_EARTHQUAKE, m_creature); 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; using std::set; set<int>list; set<int>::iterator itr; for(uint8 i = 0; i < 4; i++) { counter = 0; do{target = SelectUnit(SELECT_TARGET_RANDOM, 1, 50, true); //target players only if(counter < Playercount) break; if(target) itr = list.find(target->GetGUID()); counter++; }while(itr != list.end()); if(target){list.insert(target->GetGUID()); ApplyWateryGrave(target, i); } } switch(rand()%2) { case 0: DoScriptText(SAY_SUMMON_BUBL1, m_creature); break; case 1: DoScriptText(SAY_SUMMON_BUBL2, m_creature); break; } DoScriptText(EMOTE_WATERY_GRAVE, m_creature); 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) { Unit* globuletarget; using std::set; set<int>globulelist; set<int>::iterator itr; for (int8 g = 0; g < 4; g++) //one unit cant cast more than one spell per update, so some players have to cast for us XD { counter = 0; do {globuletarget = SelectUnit(SELECT_TARGET_RANDOM, 0,50,true); if(globuletarget) itr = globulelist.find(globuletarget->GetGUID()); if (counter > Playercount) break; counter++; } while (itr != globulelist.end()); if(globuletarget)globulelist.insert(globuletarget->GetGUID()); globuletarget->CastSpell(globuletarget, globulespell[g], true); } DoScriptText(EMOTE_WATERY_GLOBULES, m_creature); WateryGlobules_Timer = 25000; }else WateryGlobules_Timer -= diff; } DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 uiDiff) { if (!UpdateVictim()) return; switch (m_uiStage) { case 0: if (m_uiFerociousButtTimer <= uiDiff) { DoCastVictim(SPELL_FEROCIOUS_BUTT); m_uiFerociousButtTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); } else m_uiFerociousButtTimer -= uiDiff; if (m_uiArticBreathTimer <= uiDiff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_ARCTIC_BREATH); m_uiArticBreathTimer = urand(25*IN_MILLISECONDS, 40*IN_MILLISECONDS); } else m_uiArticBreathTimer -= uiDiff; if (m_uiWhirlTimer <= uiDiff) { DoCastAOE(SPELL_WHIRL); m_uiWhirlTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); } else m_uiWhirlTimer -= uiDiff; if (m_uiMassiveCrashTimer <= uiDiff) { me->GetMotionMaster()->MoveJump(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 10.0f, 20.0f); // 1: Middle of the room m_uiStage = 7; //Invalid (Do nothing more than move) m_uiMassiveCrashTimer = 30*IN_MILLISECONDS; } else m_uiMassiveCrashTimer -= uiDiff; DoMeleeAttackIfReady(); break; case 1: DoCastAOE(SPELL_MASSIVE_CRASH); m_uiStage = 2; break; case 2: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) { m_uiTrampleTargetGUID = target->GetGUID(); me->SetTarget(m_uiTrampleTargetGUID); DoScriptText(SAY_TRAMPLE_STARE, me, target); m_bTrampleCasted = false; SetCombatMovement(false); me->GetMotionMaster()->MoveIdle(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_uiTrampleTimer = 4*IN_MILLISECONDS; m_uiStage = 3; } else m_uiStage = 6; break; case 3: if (m_uiTrampleTimer <= uiDiff) { if (Unit* target = Unit::GetPlayer(*me, m_uiTrampleTargetGUID)) { m_bTrampleCasted = false; m_bMovementStarted = true; m_fTrampleTargetX = target->GetPositionX(); m_fTrampleTargetY = target->GetPositionY(); m_fTrampleTargetZ = target->GetPositionZ(); me->GetMotionMaster()->MoveJump(2*me->GetPositionX()-m_fTrampleTargetX, 2*me->GetPositionY()-m_fTrampleTargetY, me->GetPositionZ(), 10.0f, 20.0f); // 2: Hop Backwards m_uiStage = 7; //Invalid (Do nothing more than move) } else m_uiStage = 6; } else m_uiTrampleTimer -= uiDiff; break; case 4: DoScriptText(SAY_TRAMPLE_START, me); me->GetMotionMaster()->MoveCharge(m_fTrampleTargetX, m_fTrampleTargetY, m_fTrampleTargetZ+2, 42, 1); me->SetTarget(0); m_uiStage = 5; break; case 5: if (m_bMovementFinish) { if (m_uiTrampleTimer <= uiDiff) DoCastAOE(SPELL_TRAMPLE); m_bMovementFinish = false; m_uiStage = 6; return; } if (m_uiTrampleTimer <= uiDiff) { Map::PlayerList const &lPlayers = me->GetMap()->GetPlayers(); for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { if (Unit* player = itr->getSource()) if (player->isAlive() && player->IsWithinDistInMap(me, 6.0f)) { DoCastAOE(SPELL_TRAMPLE); m_uiTrampleTimer = IN_MILLISECONDS; break; } } } else m_uiTrampleTimer -= uiDiff; break; case 6: if (!m_bTrampleCasted) { DoCast(me, SPELL_STAGGERED_DAZE); DoScriptText(SAY_TRAMPLE_FAIL, me); } m_bMovementStarted = false; me->GetMotionMaster()->MovementExpired(); me->GetMotionMaster()->MoveChase(me->getVictim()); SetCombatMovement(true); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_uiStage = 0; break; } }
void UpdateAI(const uint32 Diff) { if (!UpdateVictim()) return; if (!_bIsPhaseTwo) { if (ShadowWordPain_Timer <= Diff) { DoCast(me->getVictim(), SPELL_SHADOWWORDPAIN); ShadowWordPain_Timer = 15000; } else ShadowWordPain_Timer -= Diff; if (Mark_Timer <= Diff) { Unit* markedTarget = SelectTarget(SELECT_TARGET_RANDOM, 0); if (markedTarget) { DoCast(markedTarget, SPELL_MARK); MarkedTargetGUID = markedTarget->GetGUID(); } else sLog->outError("TSCR: boss_arlokk could not accuire MarkedTarget."); Mark_Timer = 15000; } else Mark_Timer -= Diff; } else { //Cleave_Timer if (Cleave_Timer <= Diff) { DoCast(me->getVictim(), SPELL_CLEAVE); Cleave_Timer = 16000; } else Cleave_Timer -= Diff; //Gouge_Timer if (Gouge_Timer <= Diff) { DoCast(me->getVictim(), SPELL_GOUGE); DoModifyThreatPercent(me->getVictim(), -80); Gouge_Timer = 17000+rand()%10000; } else Gouge_Timer -= Diff; } if (SummonCount <= 30) { if (Summon_Timer <= Diff) { DoSummonPhanters(); Summon_Timer = 5000; } else Summon_Timer -= Diff; } if (Vanish_Timer <= Diff) { //Invisble Model me->SetDisplayId(MODEL_ID_BLANK); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->AttackStop(); DoResetThreat(); _bIsVanished = true; Vanish_Timer = 45000; Visible_Timer = 6000; } else Vanish_Timer -= Diff; if (_bIsVanished) { if (Visible_Timer <= Diff) { //The Panther Model me->SetDisplayId(MODEL_ID_PANTHER); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); const CreatureTemplate* cinfo = me->GetCreatureInfo(); me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); me->UpdateDamagePhysical(BASE_ATTACK); if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) AttackStart(target); _bIsPhaseTwo = true; _bIsVanished = false; } else Visible_Timer -= Diff; } else DoMeleeAttackIfReady(); }
void UpdateAI(uint32 const diff) { if (!UpdateVictim() || !CheckInRoom()) return; events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { case EVENT_BERSERK: DoScriptText(EMOTE_GENERIC_BERSERK_RAID, me); Talk(SAY_BERSERK); DoCast(me, SPELL_BERSERK); break; case EVENT_VAMPIRIC_BITE: { std::list<Player*> targets; SelectRandomTarget(false, &targets); if (!targets.empty()) { Unit* target = targets.front(); DoCast(target, SPELL_VAMPIRIC_BITE); Talk(SAY_VAMPIRIC_BITE); _vampires.insert(target->GetGUID()); } break; } case EVENT_BLOOD_MIRROR: { // victim can be NULL when this is processed in the same update tick as EVENT_AIR_PHASE if (me->getVictim()) { Player* newOfftank = SelectRandomTarget(true); if (_offtank != newOfftank) { _offtank = newOfftank; if (_offtank) { // both spells have SPELL_ATTR5_SINGLE_TARGET_SPELL, no manual removal needed _offtank->CastSpell(me->getVictim(), SPELL_BLOOD_MIRROR_DAMAGE, true); me->getVictim()->CastSpell(_offtank, SPELL_BLOOD_MIRROR_DUMMY, true); DoCastVictim(SPELL_BLOOD_MIRROR_VISUAL); if (Item* shadowsEdge = _offtank->GetWeaponForAttack(BASE_ATTACK, true)) if (!_offtank->HasAura(SPELL_THIRST_QUENCHED) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE && !_offtank->HasAura(SPELL_GUSHING_WOUND)) _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, true); } } } events.ScheduleEvent(EVENT_BLOOD_MIRROR, 2500, EVENT_GROUP_CANCELLABLE); break; } case EVENT_DELIRIOUS_SLASH: if (_offtank && !me->HasByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER)) DoCast(_offtank, SPELL_DELIRIOUS_SLASH); events.ScheduleEvent(EVENT_DELIRIOUS_SLASH, urand(20000, 24000), EVENT_GROUP_NORMAL); break; case EVENT_PACT_OF_THE_DARKFALLEN: { std::list<Player*> targets; SelectRandomTarget(false, &targets); uint32 targetCount = 2; // do not combine these checks! we want it incremented TWICE when both conditions are met if (IsHeroic()) ++targetCount; if (Is25ManRaid()) ++targetCount; Trinity::RandomResizeList<Player*>(targets, targetCount); if (targets.size() > 1) { Talk(SAY_PACT_OF_THE_DARKFALLEN); for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) DoCast(*itr, SPELL_PACT_OF_THE_DARKFALLEN); } events.ScheduleEvent(EVENT_PACT_OF_THE_DARKFALLEN, 30500, EVENT_GROUP_NORMAL); break; } case EVENT_SWARMING_SHADOWS: if (Player* target = SelectRandomTarget(false)) { Talk(EMOTE_SWARMING_SHADOWS, target->GetGUID()); Talk(SAY_SWARMING_SHADOWS); DoCast(target, SPELL_SWARMING_SHADOWS); } events.ScheduleEvent(EVENT_SWARMING_SHADOWS, 30500, EVENT_GROUP_NORMAL); break; case EVENT_TWILIGHT_BLOODBOLT: { std::list<Player*> targets; SelectRandomTarget(false, &targets); Trinity::RandomResizeList<Player*>(targets, uint32(Is25ManRaid() ? 4 : 2)); for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) DoCast(*itr, SPELL_TWILIGHT_BLOODBOLT); DoCast(me, SPELL_TWILIGHT_BLOODBOLT_TARGET); events.ScheduleEvent(EVENT_TWILIGHT_BLOODBOLT, urand(10000, 15000), EVENT_GROUP_NORMAL); break; } case EVENT_AIR_PHASE: DoStopAttack(); me->SetReactState(REACT_PASSIVE); events.DelayEvents(10000, EVENT_GROUP_NORMAL); events.CancelEventGroup(EVENT_GROUP_CANCELLABLE); me->GetMotionMaster()->MovePoint(POINT_CENTER, centerPos); break; case EVENT_AIR_START_FLYING: me->SetDisableGravity(true); me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND); me->SetCanFly(true); me->SendMovementFlagUpdate(); me->GetMotionMaster()->MovePoint(POINT_AIR, airPos); break; case EVENT_AIR_FLY_DOWN: me->GetMotionMaster()->MovePoint(POINT_GROUND, centerPos); break; default: break; } } DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; events.Update(diff); _DoAggroPulse(diff); if (me->HasUnitState(UNIT_STAT_CASTING)) return; switch (events.GetEvent()) { case EVENT_MELEE_CHECK: if (!me->IsWithinMeleeRange(me->getVictim())) DoCast(SPELL_PETRIFY_BREATH); events.RepeatEvent(1000); break; case EVENT_SWEEP: if (left) { DoCast(SPELL_ARM_SWEEP); DoScriptText(SAY_SHOCKWAVE, me); } events.RepeatEvent(25000); break; case EVENT_SMASH: if (left && right) DoCastVictim(SPELL_TWO_ARM_SMASH); else if (left || right) DoCastVictim(SPELL_ONE_ARM_SMASH); events.RepeatEvent(urand(8000, 10000)); break; case EVENT_STONE_SHOUT: DoCast(SPELL_STONE_SHOUT); events.RepeatEvent(2000); break; case EVENT_ENRAGE: DoCast(SPELL_BERSERK); DoScriptText(SAY_BERSERK, me); events.CancelEvent(EVENT_ENRAGE); break; case EVENT_RESPAWN_LEFT_ARM: { RespawnArm(NPC_LEFT_ARM); me->MonsterTextEmote(EMOTE_LEFT, 0, true); events.CancelEvent(EVENT_RESPAWN_LEFT_ARM); break; } case EVENT_RESPAWN_RIGHT_ARM: { RespawnArm(NPC_RIGHT_ARM); me->MonsterTextEmote(EMOTE_RIGHT, 0, true); events.CancelEvent(EVENT_RESPAWN_RIGHT_ARM); break; } case EVENT_STONE_GRIP: { if (right) { DoCast(SPELL_STONE_GRIP); me->MonsterTextEmote(EMOTE_STONE, 0, true); DoScriptText(SAY_GRAB_PLAYER, me); } events.RepeatEvent(25000); break; } case EVENT_SHOCKWAVE: if (left) { DoScriptText(SAY_SHOCKWAVE, me); DoCastAOE(SPELL_SHOCKWAVE, true); DoCastAOE(SPELL_SHOCKWAVE_VISUAL, true); } events.RepeatEvent(urand(15000, 25000)); break; case EVENT_FOCUSED_EYEBEAM: Unit* eyebeamTargetUnit = GetEyeBeamTarget(); if (!eyebeamTargetUnit) eyebeamTargetUnit = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true, -SPELL_STONE_GRIP_DOT); if (eyebeamTargetUnit) { eyebeamTarget = eyebeamTargetUnit->GetGUID(); me->MonsterWhisper(EMOTE_EYEBEAM, eyebeamTarget, true); DoCast(SPELL_SUMMON_FOCUSED_EYEBEAM); } events.RepeatEvent(urand(15000, 35000)); break; } DoMeleeAttackIfReady(); }
bool PetAI::CanAttack(Unit* target) { // Evaluates wether a pet can attack a specific target based on CommandState, ReactState and other flags // IMPORTANT: The order in which things are checked is important, be careful if you add or remove checks // Hmmm... if (!target) return false; // If pet disabled dont start attack (for example owner in mount) if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !me->HasUnitState(UNIT_STATE_STUNNED)) return false; if (!target->IsAlive()) { // Clear target to prevent getting stuck on dead targets me->AttackStop(); me->InterruptNonMeleeSpells(false); me->SendMeleeAttackStop(); return false; } // Passive - passive pets can attack if told to if (me->HasReactState(REACT_PASSIVE)) return me->GetCharmInfo()->IsCommandAttack(); // CC - mobs under crowd control can be attacked if owner commanded if (target->HasCrowdControlAura()) return me->GetCharmInfo()->IsCommandAttack(); // Returning - pets ignore attacks only if owner clicked follow if (me->GetCharmInfo()->IsReturning()) return !me->GetCharmInfo()->IsCommandFollow(); // Stay - can attack if target is within range or commanded to if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) return (me->IsWithinMeleeRange(target) || me->GetCharmInfo()->IsCommandAttack()); if (me->HasReactState(REACT_ASSIST)) { Unit* ownerTarget = NULL; if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) ownerTarget = owner->GetSelectedUnit(); else ownerTarget = me->GetCharmerOrOwner()->GetVictim(); if (target != ownerTarget) return false; } // Pets attacking something (or chasing) should only switch targets if owner tells them to if (me->GetVictim() && me->GetVictim() != target) { // Check if our owner selected this target and clicked "attack" Unit* ownerTarget = NULL; if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) ownerTarget = owner->GetSelectedUnit(); else ownerTarget = me->GetCharmerOrOwner()->GetVictim(); if (ownerTarget && me->GetCharmInfo()->IsCommandAttack()) return (target->GetGUID() == ownerTarget->GetGUID()); } // Follow if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) return !me->GetCharmInfo()->IsReturning(); // default, though we shouldn't ever get here return false; }
void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { plrMover->m_transport = transport; transport->AddPassenger(plrMover); } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { foundNewTransport = true; plrMover->m_transport = transport; transport->AddPassenger(plrMover); } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.transport.Reset(); } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight()) plrMover->HandleFall(movementInfo); if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } uint32 mstime = getMSTime(); /*----------------------*/ if (m_clientTimeDelay == 0) m_clientTimeDelay = mstime - movementInfo.time; /* process position-change */ WorldPacket data(opcode, recvData.size()); movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // NOTE: this is actually called many times while falling // even after the player has been teleported away /// @todo discard movement packets after the player is rooted if (plrMover->IsAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plrMover->IsAlive()) plrMover->KillPlayer(); } } } } }