diff options
Diffstat (limited to 'src')
49 files changed, 1134 insertions, 878 deletions
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index 228996e5d2d..237bc479074 100755 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -140,6 +140,6 @@ void GuardAI::UpdateAI(const uint32 /*diff*/) void GuardAI::JustDied(Unit* killer) { - if (Player* pkiller = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) - me->SendZoneUnderAttackMessage(pkiller); + if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) + me->SendZoneUnderAttackMessage(player); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 653c37b1003..02cbacb8db0 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -20,29 +20,29 @@ enum ePoints POINT_COMBAT_START = 0xFFFFFF }; -FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature), +FollowerAI::FollowerAI(Creature* creature) : ScriptedAI(creature), m_uiLeaderGUID(0), m_uiUpdateFollowTimer(2500), m_uiFollowState(STATE_FOLLOW_NONE), m_pQuestForFollow(NULL) {} -void FollowerAI::AttackStart(Unit* pWho) +void FollowerAI::AttackStart(Unit* who) { - if (!pWho) + if (!who) return; - if (me->Attack(pWho, true)) + if (me->Attack(who, true)) { - me->AddThreat(pWho, 0.0f); - me->SetInCombatWith(pWho); - pWho->SetInCombatWith(me); + me->AddThreat(who, 0.0f); + me->SetInCombatWith(who); + who->SetInCombatWith(me); if (me->HasUnitState(UNIT_STAT_FOLLOW)) me->ClearUnitState(UNIT_STAT_FOLLOW); if (IsCombatMovementAllowed()) - me->GetMotionMaster()->MoveChase(pWho); + me->GetMotionMaster()->MoveChase(who); } } @@ -86,30 +86,30 @@ bool FollowerAI::AssistPlayerInCombat(Unit* who) return false; } -void FollowerAI::MoveInLineOfSight(Unit* pWho) +void FollowerAI::MoveInLineOfSight(Unit* who) { - if (!me->HasUnitState(UNIT_STAT_STUNNED) && pWho->isTargetableForAttack() && pWho->isInAccessiblePlaceFor(me)) + if (!me->HasUnitState(UNIT_STAT_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) { - if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(pWho)) + if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(who)) return; - if (!me->canFly() && me->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) + if (!me->canFly() && me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) return; - if (me->IsHostileTo(pWho)) + if (me->IsHostileTo(who)) { - float fAttackRadius = me->GetAttackDistance(pWho); - if (me->IsWithinDistInMap(pWho, fAttackRadius) && me->IsWithinLOSInMap(pWho)) + float fAttackRadius = me->GetAttackDistance(who); + if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who)) { if (!me->getVictim()) { - pWho->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); - AttackStart(pWho); + who->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + AttackStart(who); } else if (me->GetMap()->IsDungeon()) { - pWho->SetInCombatWith(me); - me->AddThreat(pWho, 0.0f); + who->SetInCombatWith(me); + me->AddThreat(who, 0.0f); } } } @@ -122,23 +122,23 @@ void FollowerAI::JustDied(Unit* /*pKiller*/) return; //TODO: need a better check for quests with time limit. - if (Player* pPlayer = GetLeaderForFollower()) + if (Player* player = GetLeaderForFollower()) { - if (Group* pGroup = pPlayer->GetGroup()) + if (Group* group = player->GetGroup()) { - for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) { - if (Player* pMember = pRef->getSource()) + if (Player* member = groupRef->getSource()) { - if (pMember->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE) - pMember->FailQuest(m_pQuestForFollow->GetQuestId()); + if (member->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE) + member->FailQuest(m_pQuestForFollow->GetQuestId()); } } } else { - if (pPlayer->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE) - pPlayer->FailQuest(m_pQuestForFollow->GetQuestId()); + if (player->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(m_pQuestForFollow->GetQuestId()); } } } @@ -198,24 +198,24 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) bool bIsMaxRangeExceeded = true; - if (Player* pPlayer = GetLeaderForFollower()) + if (Player* player = GetLeaderForFollower()) { if (HasFollowState(STATE_FOLLOW_RETURNING)) { sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI is returning to leader."); RemoveFollowState(STATE_FOLLOW_RETURNING); - me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); return; } - if (Group* pGroup = pPlayer->GetGroup()) + if (Group* group = player->GetGroup()) { - for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) { - Player* pMember = pRef->getSource(); + Player* member = groupRef->getSource(); - if (pMember && me->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE)) + if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE)) { bIsMaxRangeExceeded = false; break; @@ -224,7 +224,7 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) } else { - if (me->IsWithinDistInMap(pPlayer, MAX_PLAYER_DISTANCE)) + if (me->IsWithinDistInMap(player, MAX_PLAYER_DISTANCE)) bIsMaxRangeExceeded = false; } } @@ -253,12 +253,12 @@ void FollowerAI::UpdateFollowerAI(const uint32 /*uiDiff*/) DoMeleeAttackIfReady(); } -void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId) +void FollowerAI::MovementInform(uint32 motionType, uint32 pointId) { - if (uiMotionType != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS)) + if (motionType != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS)) return; - if (uiPointId == POINT_COMBAT_START) + if (pointId == POINT_COMBAT_START) { if (GetLeaderForFollower()) { @@ -270,7 +270,7 @@ void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId) } } -void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const Quest* pQuest) +void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Quest* quest) { if (me->getVictim()) { @@ -285,12 +285,12 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const } //set variables - m_uiLeaderGUID = pLeader->GetGUID(); + m_uiLeaderGUID = player->GetGUID(); - if (uiFactionForFollower) - me->setFaction(uiFactionForFollower); + if (factionForFollower) + me->setFaction(factionForFollower); - m_pQuestForFollow = pQuest; + m_pQuestForFollow = quest; if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) { @@ -303,30 +303,30 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const AddFollowState(STATE_FOLLOW_INPROGRESS); - me->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI start follow %s (GUID " UI64FMTD ")", pLeader->GetName(), m_uiLeaderGUID); + sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI start follow %s (GUID " UI64FMTD ")", player->GetName(), m_uiLeaderGUID); } Player* FollowerAI::GetLeaderForFollower() { - if (Player* pLeader = Unit::GetPlayer(*me, m_uiLeaderGUID)) + if (Player* player = Unit::GetPlayer(*me, m_uiLeaderGUID)) { - if (pLeader->isAlive()) - return pLeader; + if (player->isAlive()) + return player; else { - if (Group* pGroup = pLeader->GetGroup()) + if (Group* group = player->GetGroup()) { - for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) { - Player* pMember = pRef->getSource(); + Player* member = groupRef->getSource(); - if (pMember && pMember->isAlive() && me->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE)) + if (member && member->isAlive() && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE)) { sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI GetLeader changed and returned new leader."); - m_uiLeaderGUID = pMember->GetGUID(); - return pMember; + m_uiLeaderGUID = member->GetGUID(); + return member; break; } } @@ -360,12 +360,12 @@ void FollowerAI::SetFollowComplete(bool bWithEndEvent) AddFollowState(STATE_FOLLOW_COMPLETE); } -void FollowerAI::SetFollowPaused(bool bPaused) +void FollowerAI::SetFollowPaused(bool paused) { if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || HasFollowState(STATE_FOLLOW_COMPLETE)) return; - if (bPaused) + if (paused) { AddFollowState(STATE_FOLLOW_PAUSED); @@ -382,7 +382,7 @@ void FollowerAI::SetFollowPaused(bool bPaused) { RemoveFollowState(STATE_FOLLOW_PAUSED); - if (Player* pLeader = GetLeaderForFollower()) - me->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + if (Player* leader = GetLeaderForFollower()) + me->GetMotionMaster()->MoveFollow(leader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h index d352141e3e9..1c81b5f73fc 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h @@ -21,12 +21,12 @@ enum eFollowState class FollowerAI : public ScriptedAI { public: - explicit FollowerAI(Creature* pCreature); + explicit FollowerAI(Creature* creature); ~FollowerAI() {} //virtual void WaypointReached(uint32 uiPointId) = 0; - void MovementInform(uint32 uiMotionType, uint32 uiPointId); + void MovementInform(uint32 motionType, uint32 pointId); void AttackStart(Unit*); @@ -41,7 +41,7 @@ class FollowerAI : public ScriptedAI void UpdateAI(const uint32); //the "internal" update, calls UpdateFollowerAI() virtual void UpdateFollowerAI(const uint32); //used when it's needed to add code in update (abilities, scripted events, etc) - void StartFollow(Player* pPlayer, uint32 uiFactionForFollower = 0, const Quest* pQuest = NULL); + void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = NULL); void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow void SetFollowComplete(bool bWithEndEvent = false); @@ -55,7 +55,7 @@ class FollowerAI : public ScriptedAI void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; } void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; } - bool AssistPlayerInCombat(Unit* pWho); + bool AssistPlayerInCombat(Unit* who); uint64 m_uiLeaderGUID; uint32 m_uiUpdateFollowTimer; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 7817465c55e..7305d41ec2d 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -214,23 +214,23 @@ void SmartAI::EndPath(bool fail) { if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) { - Player* plr = (*targets->begin())->ToPlayer(); - if (!fail && plr->IsAtGroupRewardDistance(me) && !plr->GetCorpse()) - plr->GroupEventHappens(mEscortQuestID, me); + Player* player = (*targets->begin())->ToPlayer(); + if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse()) + player->GroupEventHappens(mEscortQuestID, me); - if (fail && plr->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) - plr->FailQuest(mEscortQuestID); + if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(mEscortQuestID); - if (Group* pGroup = plr->GetGroup()) + if (Group* group = player->GetGroup()) { - for (GroupReference* gr = pGroup->GetFirstMember(); gr != NULL; gr = gr->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) { - Player* pGroupGuy = gr->getSource(); + Player* groupGuy = groupRef->getSource(); - if (!fail && pGroupGuy->IsAtGroupRewardDistance(me) && !pGroupGuy->GetCorpse()) - pGroupGuy->AreaExploredOrEventHappens(mEscortQuestID); - if (fail && pGroupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) - pGroupGuy->FailQuest(mEscortQuestID); + if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->GetCorpse()) + groupGuy->AreaExploredOrEventHappens(mEscortQuestID); + if (fail && groupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) + groupGuy->FailQuest(mEscortQuestID); } } }else @@ -239,11 +239,11 @@ void SmartAI::EndPath(bool fail) { if (GetScript()->IsPlayer((*iter))) { - Player* plr = (*iter)->ToPlayer(); - if (!fail && plr->IsAtGroupRewardDistance(me) && !plr->GetCorpse()) - plr->AreaExploredOrEventHappens(mEscortQuestID); - if (fail && plr->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) - plr->FailQuest(mEscortQuestID); + Player* player = (*iter)->ToPlayer(); + if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse()) + player->AreaExploredOrEventHappens(mEscortQuestID); + if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) + player->FailQuest(mEscortQuestID); } } } @@ -346,12 +346,12 @@ void SmartAI::UpdateAI(const uint32 diff) { if (me->FindNearestCreature(mFollowArrivedEntry, INTERACTION_DISTANCE, true)) { - if (Player* plr = me->GetPlayer(*me, mFollowGuid)) + if (Player* player = me->GetPlayer(*me, mFollowGuid)) { if (!mFollowCreditType) - plr->RewardPlayerAndGroupAtEvent(mFollowCredit, me); + player->RewardPlayerAndGroupAtEvent(mFollowCredit, me); else - plr->GroupEventHappens(mFollowCredit, me); + player->GroupEventHappens(mFollowCredit, me); } mFollowGuid = 0; mFollowDist = 0; @@ -385,17 +385,17 @@ bool SmartAI::IsEscortInvokerInRange() { if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) { - Player* plr = (*targets->begin())->ToPlayer(); - if (me->GetDistance(plr) <= SMART_ESCORT_MAX_PLAYER_DIST) + Player* player = (*targets->begin())->ToPlayer(); + if (me->GetDistance(player) <= SMART_ESCORT_MAX_PLAYER_DIST) return true; - if (Group* pGroup = plr->GetGroup()) + if (Group* group = player->GetGroup()) { - for (GroupReference* gr = pGroup->GetFirstMember(); gr != NULL; gr = gr->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) { - Player* pGroupGuy = gr->getSource(); + Player* groupGuy = groupRef->getSource(); - if (me->GetDistance(pGroupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST) + if (me->GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST) return true; } } @@ -499,9 +499,9 @@ bool SmartAI::CanAIAttack(const Unit* /*who*/) const return true; } -bool SmartAI::AssistPlayerInCombat(Unit* pWho) +bool SmartAI::AssistPlayerInCombat(Unit* who) { - if (!pWho || !pWho->getVictim()) + if (!who || !who->getVictim()) return false; //experimental (unknown) flag not present @@ -509,26 +509,26 @@ bool SmartAI::AssistPlayerInCombat(Unit* pWho) return false; //not a player - if (!pWho->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (!who->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) return false; //never attack friendly - if (me->IsFriendlyTo(pWho)) + if (me->IsFriendlyTo(who)) return false; //too far away and no free sight? - if (me->IsWithinDistInMap(pWho, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(pWho)) + if (me->IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who)) { //already fighting someone? if (!me->getVictim()) { - AttackStart(pWho); + AttackStart(who); return true; } else { - pWho->SetInCombatWith(me); - me->AddThreat(pWho, 0.0f); + who->SetInCombatWith(me); + me->AddThreat(who, 0.0f); return true; } } @@ -606,29 +606,29 @@ void SmartAI::AttackStart(Unit* who) } } -void SmartAI::SpellHit(Unit* pUnit, const SpellInfo* pSpell) +void SmartAI::SpellHit(Unit* unit, const SpellInfo* spellInfo) { - GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, pUnit, 0, 0, false, pSpell); + GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, unit, 0, 0, false, spellInfo); } -void SmartAI::SpellHitTarget(Unit* target, const SpellInfo* pSpell) +void SmartAI::SpellHitTarget(Unit* target, const SpellInfo* spellInfo) { - GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target, 0, 0, false, pSpell); + GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target, 0, 0, false, spellInfo); } -void SmartAI::DamageTaken(Unit* done_by, uint32& damage) +void SmartAI::DamageTaken(Unit* doneBy, uint32& damage) { - GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, done_by, damage); + GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); } -void SmartAI::HealReceived(Unit* done_by, uint32& addhealth) +void SmartAI::HealReceived(Unit* doneBy, uint32& addhealth) { - GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_HEAL, done_by, addhealth); + GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_HEAL, doneBy, addhealth); } -void SmartAI::ReceiveEmote(Player* pPlayer, uint32 text_emote) +void SmartAI::ReceiveEmote(Player* player, uint32 textEmote) { - GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_EMOTE, pPlayer, text_emote); + GetScript()->ProcessEventsFor(SMART_EVENT_RECEIVE_EMOTE, player, textEmote); } void SmartAI::IsSummonedBy(Unit* summoner) @@ -636,9 +636,9 @@ void SmartAI::IsSummonedBy(Unit* summoner) GetScript()->ProcessEventsFor(SMART_EVENT_JUST_SUMMONED, summoner); } -void SmartAI::DamageDealt(Unit* done_to, uint32& damage, DamageEffectType /*damagetype*/) +void SmartAI::DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) { - GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED_TARGET, done_to, damage); + GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED_TARGET, doneTo, damage); } void SmartAI::SummonedCreatureDespawn(Creature* unit) @@ -705,14 +705,14 @@ void SmartAI::SetRun(bool run) mRun = run; } -void SmartAI::SetFly(bool bFly) +void SmartAI::SetFly(bool fly) { - me->SetFlying(bFly); + me->SetFlying(fly); } -void SmartAI::SetSwimm(bool bSwimm) +void SmartAI::SetSwim(bool swim) { - if (bSwimm) + if (swim) me->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING); else me->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 834a34bf17b..a4926226a91 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -100,22 +100,22 @@ class SmartAI : public CreatureAI void MoveInLineOfSight(Unit* who); // Called when hit by a spell - void SpellHit(Unit* pUnit, const SpellInfo* pSpell); + void SpellHit(Unit* unit, const SpellInfo* spellInfo); // Called when spell hits a target - void SpellHitTarget(Unit* target, const SpellInfo* pSpell); + void SpellHitTarget(Unit* target, const SpellInfo* spellInfo); // Called at any Damage from any attacker (before damage apply) - void DamageTaken(Unit* done_by, uint32& damage); + void DamageTaken(Unit* doneBy, uint32& damage); // Called when the creature receives heal - void HealReceived(Unit* done_by, uint32& addhealth); + void HealReceived(Unit* doneBy, uint32& addhealth); // Called at World update tick void UpdateAI(const uint32 diff); // Called at text emote receive from player - void ReceiveEmote(Player* pPlayer, uint32 text_emote); + void ReceiveEmote(Player* player, uint32 textEmote); // Called at waypoint reached or point movement finished void MovementInform(uint32 MovementType, uint32 Data); @@ -124,7 +124,7 @@ class SmartAI : public CreatureAI void IsSummonedBy(Unit* summoner); // Called at any Damage to any victim (before damage apply) - void DamageDealt(Unit* done_to, uint32& damage, DamageEffectType /*damagetype*/); + void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/); // Called when a summoned creature dissapears (UnSommoned) void SummonedCreatureDespawn(Creature* unit); @@ -169,11 +169,11 @@ class SmartAI : public CreatureAI void MovepointReached(uint32 id); // Makes the creature run/walk - void SetRun(bool bRun = true); + void SetRun(bool run = true); - void SetFly(bool bFly = true); + void SetFly(bool fly = true); - void SetSwimm(bool bSwimm = true); + void SetSwim(bool swim = true); void sGossipHello(Player* player); void sGossipSelect(Player* player, uint32 sender, uint32 action); @@ -220,7 +220,7 @@ class SmartAI : public CreatureAI bool mCanCombatMove; bool mForcedPaused; - bool AssistPlayerInCombat(Unit* pWho); + bool AssistPlayerInCombat(Unit* who); uint32 mDespawnTime; uint32 mDespawnState; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index d2cd386828b..cbcbc1e2290 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1212,12 +1212,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u CAST_AI(SmartAI, me->AI())->SetRun(e.action.setRun.run ? true : false); break; } - case SMART_ACTION_SET_SWIMM: + case SMART_ACTION_SET_SWIM: { if (!IsSmart()) return; - CAST_AI(SmartAI, me->AI())->SetSwimm(e.action.setSwimm.swimm ? true : false); + CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim ? true : false); break; } case SMART_ACTION_WP_START: @@ -1946,9 +1946,9 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (trigger) { l->push_back(trigger); - if (Player* plr = trigger->ToPlayer()) - if (Group* pGroup = plr->GetGroup()) - for (GroupReference* groupRef = pGroup->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) + if (Player* player = trigger->ToPlayer()) + if (Group* group = player->GetGroup()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next()) if (Player* member = groupRef->getSource()) l->push_back(member); } @@ -2263,10 +2263,10 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->isInCombat()) return; - Unit* pUnit = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit); - if (!pUnit) + Unit* unit = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit); + if (!unit) return; - ProcessAction(e, pUnit); + ProcessAction(e, unit); RecalcTimer(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax); break; } @@ -2881,15 +2881,15 @@ Unit* SmartScript::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) cell.data.Part.reserved = ALL_DISTRICT; cell.SetNoCreate(); - Unit* pUnit = NULL; + Unit* unit = NULL; Trinity::MostHPMissingInRange u_check(me, range, MinHPDiff); - Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(me, pUnit, u_check); + Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(me, unit, u_check); TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange>, GridTypeMapContainer > grid_unit_searcher(searcher); cell.Visit(p, grid_unit_searcher, *me->GetMap(), *me, range); - return pUnit; + return unit; } void SmartScript::DoFindFriendlyCC(std::list<Creature*>& _list, float range) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 0ff6f9efefc..62855154c8a 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -151,35 +151,35 @@ class SmartScript return NULL; } - GameObject* FindGameObjectNear(WorldObject* pSearchObject, uint32 guid) const + GameObject* FindGameObjectNear(WorldObject* searchObject, uint32 guid) const { - GameObject* pGameObject = NULL; + GameObject* gameObject = NULL; - CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY())); + CellPair p(Trinity::ComputeCellPair(searchObject->GetPositionX(), searchObject->GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; - Trinity::GameObjectWithDbGUIDCheck goCheck(*pSearchObject, guid); - Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(pSearchObject, pGameObject, goCheck); + Trinity::GameObjectWithDbGUIDCheck goCheck(*searchObject, guid); + Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(searchObject, gameObject, goCheck); TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > objectChecker(checker); - cell.Visit(p, objectChecker, *pSearchObject->GetMap()); + cell.Visit(p, objectChecker, *searchObject->GetMap()); - return pGameObject; + return gameObject; } - Creature* FindCreatureNear(WorldObject* pSearchObject, uint32 guid) const + Creature* FindCreatureNear(WorldObject* searchObject, uint32 guid) const { Creature* crea = NULL; - CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY())); + CellPair p(Trinity::ComputeCellPair(searchObject->GetPositionX(), searchObject->GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; - Trinity::CreatureWithDbGUIDCheck target_check(pSearchObject, guid); - Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(pSearchObject, crea, target_check); + Trinity::CreatureWithDbGUIDCheck target_check(searchObject, guid); + Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(searchObject, crea, target_check); TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); - cell.Visit(p, unit_checker, *pSearchObject->GetMap()); + cell.Visit(p, unit_checker, *searchObject->GetMap()); return crea; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index cc244f77dc2..ce40d42a74e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -334,13 +334,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_SPELLHIT_TARGET: if (e.event.spellHit.spell) { - SpellInfo const* pSpell = sSpellMgr->GetSpellInfo(e.event.spellHit.spell); - if (!pSpell) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell); + if (!spellInfo) { sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); return false; } - if (e.event.spellHit.school && (e.event.spellHit.school & pSpell->SchoolMask) != pSpell->SchoolMask) + if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask) { sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); return false; @@ -739,7 +739,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_WP_PAUSE: case SMART_ACTION_SET_FLY: case SMART_ACTION_SET_RUN: - case SMART_ACTION_SET_SWIMM: + case SMART_ACTION_SET_SWIM: case SMART_ACTION_FORCE_DESPAWN: case SMART_ACTION_SET_INGAME_PHASE_MASK: case SMART_ACTION_SET_UNIT_FLAG: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 2292a343c21..30024c42932 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -420,7 +420,7 @@ enum SMART_ACTION SMART_ACTION_INSTALL_AI_TEMPLATE = 58, // AITemplateID SMART_ACTION_SET_RUN = 59, // 0/1 SMART_ACTION_SET_FLY = 60, // 0/1 - SMART_ACTION_SET_SWIMM = 61, // 0/1 + SMART_ACTION_SET_SWIM = 61, // 0/1 SMART_ACTION_TELEPORT = 62, // mapID, SMART_ACTION_STORE_VARIABLE_DECIMAL = 63, // varID, number SMART_ACTION_STORE_TARGET_LIST = 64, // varID, @@ -754,8 +754,8 @@ struct SmartAction struct { - uint32 swimm; - } setSwimm; + uint32 swim; + } setSwim; struct { diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index 901d41e5c54..c7dec515d3c 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -3105,7 +3105,10 @@ bool ChatHandler::HandleBanInfoCharacterCommand(const char *args) stmt->setUInt32(0, target_guid); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) + { + PSendSysMessage(LANG_CHAR_NOT_BANNED, name.c_str()); return true; + } PSendSysMessage(LANG_BANINFO_BANHISTORY, name.c_str()); do diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index f8c6f6e8c1f..e9e7a9f4d2b 100755 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -16,11 +16,11 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "DisableMgr.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" #include "SpellMgr.h" #include "VMapManager2.h" +#include "DisableMgr.h" DisableMgr::DisableMgr() { diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b325a7fb407..5308c30a196 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -147,7 +147,7 @@ void GameObject::RemoveFromWorld() if (Unit* owner = GetOwner()) owner->RemoveGameObject(this, false); else - sLog->outError("Delete GameObject (GUID: %u Entry: %u) that have references in not found creature %u GO list. Crash possible later.", GetGUIDLow(), GetGOInfo()->entry, GUID_LOPART(owner_guid)); + sLog->outError("Delete GameObject (GUID: %u Entry: %u, Name: %s) that have references in not found creature %u GO list. Crash possible later.", GetGUIDLow(), GetGOInfo()->entry, GetGOInfo()->name.c_str(), GUID_LOPART(owner_guid)); } WorldObject::RemoveFromWorld(); sObjectAccessor->RemoveObject(this); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8067341b43b..3de39aa1d74 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -831,7 +831,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_lastFallTime = 0; m_lastFallZ = 0; - + m_grantableLevels = 0; m_ControlledByPlayer = true; @@ -1751,7 +1751,7 @@ void Player::Update(uint32 p_time) } // not auto-free ghost from body in instances - if (m_deathTimer > 0 && !GetBaseMap()->Instanceable()) + if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESSURECTION)) { if (p_time >= m_deathTimer) { @@ -5165,7 +5165,8 @@ bool Player::FallGround(uint8 FallMode) void Player::KillPlayer() { - if (IsFlying() && !GetTransport()) FallGround(); + if (IsFlying() && !GetTransport()) + FallGround(); SetMovement(MOVE_ROOT); @@ -5175,10 +5176,10 @@ void Player::KillPlayer() //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP); SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); - ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable()); + ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESSURECTION)); // 6 minutes until repop at graveyard - m_deathTimer = 6*MINUTE*IN_MILLISECONDS; + m_deathTimer = 6 * MINUTE * IN_MILLISECONDS; UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill SendCorpseReclaimDelay(); @@ -5677,8 +5678,6 @@ void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, floa m_auraBaseMod[modGroup][modType] += apply ? amount : -amount; break; case PCT_MOD: - if (amount <= -100.0f) - amount = -200.0f; ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply); break; } @@ -8094,7 +8093,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType att if (unitModType == TOTAL_VALUE) ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); else - ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, aura->GetAmount() / 100.0f, apply); + ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (aura->GetAmount()), apply); } } @@ -14213,7 +14212,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men break; case GOSSIP_OPTION_SPIRITHEALER: if (isDead()) - source->ToCreature()->CastSpell((source->ToCreature()), 17251, true, NULL, NULL, GetGUID()); + source->ToCreature()->CastSpell(source->ToCreature(), 17251, true, NULL, NULL, GetGUID()); break; case GOSSIP_OPTION_QUESTGIVER: PrepareQuestMenu(guid); @@ -14250,7 +14249,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men ResetPetTalents(); break; case GOSSIP_OPTION_TAXIVENDOR: - GetSession()->SendTaxiMenu((source->ToCreature())); + GetSession()->SendTaxiMenu(source->ToCreature()); break; case GOSSIP_OPTION_INNKEEPER: PlayerTalkClass->SendCloseGossip(); @@ -14268,7 +14267,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men GetSession()->SendTabardVendorActivate(guid); break; case GOSSIP_OPTION_AUCTIONEER: - GetSession()->SendAuctionHello(guid, (source->ToCreature())); + GetSession()->SendAuctionHello(guid, source->ToCreature()); break; case GOSSIP_OPTION_SPIRITGUIDE: PrepareGossipMenu(source); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5008f4a347e..eb789fde038 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10855,16 +10855,16 @@ uint32 Unit::SpellDamageBonus(Unit* victim, SpellInfo const* spellProto, uint32 coeff = DotFactor; } - float coeff2 = CalculateLevelPenalty(spellProto) * stack; - if (spellProto->SpellFamilyName) // TODO: fix this - TakenTotal+= int32(TakenAdvertisedBenefit * coeff * coeff2); + float factorMod = CalculateLevelPenalty(spellProto) * stack; + // level penalty still applied on Taken bonus - is it blizzlike? + TakenTotal+= int32(TakenAdvertisedBenefit * factorMod); if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); coeff /= 100.0f; } - DoneTotal += int32(DoneAdvertisedBenefit * coeff * coeff2); + DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); } // Some spells don't benefit from done mods @@ -11414,7 +11414,8 @@ uint32 Unit::SpellHealingBonus(Unit* victim, SpellInfo const* spellProto, uint32 } factorMod *= CalculateLevelPenalty(spellProto) * stack; - TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod); + // level penalty still applied on Taken bonus - is it blizzlike? + TakenTotal += int32(TakenAdvertisedBenefit * factorMod); if (Player* modOwner = GetSpellModOwner()) { coeff *= 100.0f; @@ -12257,6 +12258,9 @@ void Unit::ClearInCombat() bool Unit::isTargetableForAttack(bool checkFakeDeath) const { + if (!isAlive()) + return false; + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE)) return false; @@ -13347,7 +13351,7 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f break; case BASE_PCT: case TOTAL_PCT: - m_auraModifiersGroup[unitMod][modifierType] += (apply ? amount : -amount) / 100.0f; + ApplyPercentModFloatVar(m_auraModifiersGroup[unitMod][modifierType], amount, apply); break; default: break; @@ -16179,6 +16183,26 @@ bool Unit::IsInRaidWith(Unit const* unit) const return false; } +bool Unit::IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const +{ + switch (check) + { + case TARGET_SELECT_CHECK_ENEMY: + if (IsControlledByPlayer()) + return !IsFriendlyTo(target); + else + return IsHostileTo(target); + case TARGET_SELECT_CHECK_ALLY: + return IsFriendlyTo(target); + case TARGET_SELECT_CHECK_PARTY: + return IsInPartyWith(target); + case TARGET_SELECT_CHECK_RAID: + return IsInRaidWith(target); + default: + return true; + } +} + void Unit::GetRaidMember(std::list<Unit*> &nearMembers, float radius) { Player* owner = GetCharmerOrOwnerPlayerOrPlayerItself(); @@ -17364,7 +17388,7 @@ uint32 Unit::GetRemainingPeriodicAmount(uint64 caster, uint32 spellId, AuraType AuraEffectList const& periodicAuras = GetAuraEffectsByType(auraType); for (AuraEffectList::const_iterator i = periodicAuras.begin(); i != periodicAuras.end(); ++i) { - if ((*i)->GetCasterGUID() != caster || (*i)->GetId() != spellId || (*i)->GetEffIndex() != effectIndex) + if ((*i)->GetCasterGUID() != caster || (*i)->GetId() != spellId || (*i)->GetEffIndex() != effectIndex || (*i)->GetTotalTicks() == 0) continue; amount += uint32(((*i)->GetAmount() * std::max<int32>((*i)->GetTotalTicks() - int32((*i)->GetTickNumber()), 0)) / (*i)->GetTotalTicks()); break; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 0e6cccd0cd5..caf1f4e46ad 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -32,6 +32,7 @@ #include "EventProcessor.h" #include "MotionMaster.h" #include "DBCStructure.h" +#include "SpellInfo.h" #include "Path.h" #include "WorldPacket.h" #include "Timer.h" @@ -1391,6 +1392,7 @@ class Unit : public WorldObject bool IsNeutralToAll() const; bool IsInPartyWith(Unit const* unit) const; bool IsInRaidWith(Unit const* unit) const; + bool IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const; void GetPartyMemberInDist(std::list<Unit*> &units, float dist); void GetPartyMembers(std::list<Unit*> &units); void GetRaidMember(std::list<Unit*> &units, float dist); @@ -1545,7 +1547,6 @@ class Unit : public WorldObject bool isFrozen() const; bool isTargetableForAttack(bool checkFakeDeath = true) const; - bool isAttackableByAOE(SpellInfo const* spellProto = NULL) const; bool canAttack(Unit const* target, bool force = true) const; virtual bool IsInWater() const; virtual bool IsUnderWater() const; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 13a88a26b89..9914426215c 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -26,6 +26,7 @@ #include "Transport.h" #include "ObjectAccessor.h" #include "CellImpl.h" +#include "SpellInfo.h" using namespace Trinity; @@ -330,38 +331,41 @@ ObjectUpdater::Visit(GridRefManager<T> &m) } } -bool CannibalizeObjectCheck::operator()(Corpse* u) +bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u) { - // ignore bones - if (u->GetType() == CORPSE_BONES) - return false; - - Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); - - if (!owner || i_funit->IsFriendlyTo(owner)) - return false; + return !u->isAlive() && !u->HasAuraType(SPELL_AURA_GHOST) && i_searchObj->IsWithinDistInMap(u, i_range); +} - if (i_funit->IsWithinDistInMap(u, i_range)) - return true; +bool AnyDeadUnitObjectInRangeCheck::operator()(Corpse* u) +{ + return u->GetType() != CORPSE_BONES && i_searchObj->IsWithinDistInMap(u, i_range); +} - return false; +bool AnyDeadUnitObjectInRangeCheck::operator()(Creature* u) +{ + return !u->isAlive() && i_searchObj->IsWithinDistInMap(u, i_range); } -bool CarrionFeederObjectCheck::operator()(Corpse* u) +bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Player* u) { - // ignore bones - if (u->GetType() == CORPSE_BONES) - return false; + return AnyDeadUnitObjectInRangeCheck::operator()(u) + && i_spellInfo->CheckTarget(i_searchObj, u, true) + && i_searchObj->IsTargetMatchingCheck(u, i_check); +} +bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Corpse* u) +{ Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); + return owner && AnyDeadUnitObjectInRangeCheck::operator()(u) + && i_spellInfo->CheckTarget(i_searchObj, owner, true) + && i_searchObj->IsTargetMatchingCheck(owner, i_check); +} - if (!owner || i_funit->IsFriendlyTo(owner)) - return false; - - if (i_funit->IsWithinDistInMap(u, i_range)) - return true; - - return false; +bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u) +{ + return AnyDeadUnitObjectInRangeCheck::operator()(u) + && i_spellInfo->CheckTarget(i_searchObj, u, true) + && i_searchObj->IsTargetMatchingCheck(u, i_check); } template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &); diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index b4d20f25740..4d4f0bfe05e 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -554,56 +554,31 @@ namespace Trinity float i_range; }; - class CannibalizeObjectCheck + class AnyDeadUnitObjectInRangeCheck { public: - CannibalizeObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight()) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } + AnyDeadUnitObjectInRangeCheck(Unit const* searchObj, float range) : i_searchObj(searchObj), i_range(range) {} + bool operator()(Player* u); bool operator()(Corpse* u); - bool operator()(Creature* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } + bool operator()(Creature* u); template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; + protected: + Unit const* const i_searchObj; float i_range; }; - class CarrionFeederObjectCheck + class AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck { public: - CarrionFeederObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} - bool operator()(Player* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight()) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } + AnyDeadUnitSpellTargetInRangeCheck(Unit const* searchObj, float range, SpellInfo const* spellInfo, SpellTargetSelectionCheckTypes check) + : AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(check) {} + bool operator()(Player* u); bool operator()(Corpse* u); - bool operator()(Creature* u) - { - if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || - (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) != 0) - return false; - - return i_funit->IsWithinDistInMap(u, i_range); - } + bool operator()(Creature* u); template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } - private: - Unit* const i_funit; - float i_range; + protected: + SpellInfo const* i_spellInfo; + SpellTargetSelectionCheckTypes i_check; }; // WorldObject do classes diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 2fe38b0a953..101f0e4ce4d 100755 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -355,12 +355,19 @@ void InstanceScript::DoStopTimedAchievement(AchievementCriteriaTimedTypes type, // Remove Auras due to Spell on all players in instance void InstanceScript::DoRemoveAurasDueToSpellOnPlayers(uint32 spell) { - Map::PlayerList const &PlayerList = instance->GetPlayers(); - + Map::PlayerList const& PlayerList = instance->GetPlayers(); if (!PlayerList.isEmpty()) - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (Player* pPlayer = i->getSource()) - pPlayer->RemoveAurasDueToSpell(spell); + { + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + { + if (Player* player = itr->getSource()) + { + player->RemoveAurasDueToSpell(spell); + if (Pet* pet = player->GetPet()) + pet->RemoveAurasDueToSpell(spell); + } + } + } } // Cast spell on all players in instance diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 6ff4bf05d42..f430002fca6 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -416,6 +416,7 @@ class Map : public GridRefManager<NGridType> template<class T> void SwitchGridContainers(T* obj, bool active); template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier); + template<class NOTIFIER> void VisitFirstFound(const float &x, const float &y, float radius, NOTIFIER ¬ifier); template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier); template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); CreatureGroupHolderType CreatureGroupHolder; @@ -650,6 +651,25 @@ Map::VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier) cell.Visit(p, grid_object_notifier, *this, radius, x, y); } +// should be used with Searcher notifiers, tries to search world if nothing found in grid +template<class NOTIFIER> +inline void +Map::VisitFirstFound(const float &x, const float &y, float radius, NOTIFIER ¬ifier) +{ + CellPair p(Trinity::ComputeCellPair(x, y)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + TypeContainerVisitor<NOTIFIER, WorldTypeMapContainer> world_object_notifier(notifier); + cell.Visit(p, world_object_notifier, *this, radius, x, y); + if (!notifier.i_object) + { + TypeContainerVisitor<NOTIFIER, GridTypeMapContainer > grid_object_notifier(notifier); + cell.Visit(p, grid_object_notifier, *this, radius, x, y); + } +} + template<class NOTIFIER> inline void Map::VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier) diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 2846efe9189..e824a3cf5da 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -804,7 +804,8 @@ enum TrinityStrings LANG_BANLIST_CHARACTERS_HEADER = 1133, LANG_ALLOW_TICKETS = 1134, LANG_DISALLOW_TICKETS = 1135, - // Room for more level 3 1136-1199 not used + LANG_CHAR_NOT_BANNED = 1136, + // Room for more level 3 1137-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index b9c9c39028d..5e10a2c0fe4 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -400,7 +400,7 @@ enum SpellAttr3 SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED = 0x04000000, // 26 auras with this attribute can proc from triggered spell casts with SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2 (67736 + 52999) SPELL_ATTR3_DRAIN_SOUL = 0x08000000, // 27 only drain soul has this flag SPELL_ATTR3_UNK28 = 0x10000000, // 28 - SPELL_ATTR3_NO_DONE_BONUS = 0x20000000, // 29 Ignore caster spellpower and done damage mods? + SPELL_ATTR3_NO_DONE_BONUS = 0x20000000, // 29 Ignore caster spellpower and done damage mods? client doesn't apply spellmods for those spells SPELL_ATTR3_DONT_DISPLAY_RANGE = 0x40000000, // 30 client doesn't display range in tooltip for those spells SPELL_ATTR3_UNK31 = 0x80000000 // 31 }; @@ -510,7 +510,7 @@ enum SpellAttr6 SPELL_ATTR6_UNK28 = 0x10000000, // 28 SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS = 0x20000000, // 29 ignores done percent damage mods? SPELL_ATTR6_UNK30 = 0x40000000, // 30 - SPELL_ATTR6_UNK31 = 0x80000000 // 31 + SPELL_ATTR6_UNK31 = 0x80000000 // 31 some special cooldown calc? }; enum SpellAttr7 diff --git a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp index 63012a11707..5bccf511da3 100755 --- a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp @@ -370,7 +370,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) { - sLog->outError("BattlegroundHandler: invalid bgtype (%u) received.", bgTypeId_); + sLog->outError("BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId_, _player->GetName(), _player->GetGUIDLow()); return; } if (!_player->InBattlegroundQueue()) diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp index 09897dcde19..a5f84c411da 100755 --- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp @@ -57,9 +57,12 @@ void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data) recv_data.read_skip<uint8>(); - if (GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + if (GetPlayer()->isAlive() || GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) return; + if (GetPlayer()->HasAuraType(SPELL_AURA_PREVENT_RESSURECTION)) + return; // silently return, client should display the error by itself + // the world update order is sessions, players, creatures // the netcode runs in parallel with all of these // creatures can kill players @@ -1502,7 +1505,7 @@ void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) Map *map = _player->GetMap(); if (map && map->IsDungeon()) { - sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, GUID: %u) tried to reset the instance while player is inside!", _player->GetName(), _player->GetGUIDLow()); return; } @@ -1523,7 +1526,7 @@ void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) map = pGroupGuy->GetMap(); if (map && map->IsNonRaidDungeon()) { - sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while group member (Name: %s, GUID: %u) is inside!", _player->GetGUIDLow(), pGroupGuy->GetName(), pGroupGuy->GetGUIDLow()); return; } } diff --git a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp index 2043d88adfc..716aaa9e74f 100755 --- a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp @@ -540,6 +540,9 @@ void WorldSession::HandleSelfResOpcode(WorldPacket & /*recv_data*/) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SELF_RES"); // empty opcode + if (_player->HasAuraType(SPELL_AURA_PREVENT_RESSURECTION)) + return; // silent return, client should display error by itself and not send this opcode + if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) { SpellInfo const *spellInfo = sSpellMgr->GetSpellInfo(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 158a4d8c2eb..adfb0d67bfa 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -367,7 +367,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //311 0 spells in 3.3.5 &AuraEffect::HandleNULL, //312 0 spells in 3.3.5 &AuraEffect::HandleNULL, //313 0 spells in 3.3.5 - &AuraEffect::HandleNoImmediateEffect, //314 SPELL_AURA_PREVENT_RESSURECTION todo + &AuraEffect::HandlePreventResurrection, //314 SPELL_AURA_PREVENT_RESSURECTION todo &AuraEffect::HandleNoImmediateEffect, //315 SPELL_AURA_UNDERWATER_WALKING todo &AuraEffect::HandleNoImmediateEffect, //316 SPELL_AURA_PERIODIC_HASTE implemented in AuraEffect::CalculatePeriodic }; @@ -1516,7 +1516,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const // Heart of the Wild if ((*i)->GetSpellInfo()->SpellIconID == 240 && (*i)->GetMiscValue() == 3) { - int32 HotWMod = (*i)->GetAmount(); + int32 HotWMod = (*i)->GetAmount() / 2; // For each 2% Intelligence, you get 1% stamina and 1% attack power. target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this); break; @@ -1562,7 +1562,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const // Survival of the Fittest if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0)) { - int32 bp = 100 + aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + int32 bp = aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); } break; @@ -4518,7 +4518,7 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float (GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, GetAmount() / 100.0f, apply); + target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply); } else { @@ -4924,6 +4924,18 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool caster->CastSpell(target, GetAmount(), true); } break; + case SPELLFAMILY_PRIEST: + // Vampiric Touch + if (m_spellInfo->SpellFamilyFlags[1] & 0x0400 && aurApp->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && GetEffIndex() == 0) + { + if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) + { + int32 damage = aurEff->GetAmount() * 8; + // backfire damage + target->CastCustomSpell(target, 64085, &damage, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + } + } + break; case SPELLFAMILY_WARLOCK: // Haunt if (m_spellInfo->SpellFamilyFlags[1] & 0x40000) @@ -4952,18 +4964,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool } } break; - case SPELLFAMILY_PRIEST: - // Vampiric Touch - if (m_spellInfo->SpellFamilyFlags[1] & 0x0400 && aurApp->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && GetEffIndex() == 0) - { - if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) - { - int32 damage = aurEff->GetAmount() * 8; - // backfire damage - target->CastCustomSpell(target, 64085, &damage, NULL, NULL, true, NULL, NULL, GetCasterGUID()); - } - } - break; case SPELLFAMILY_HUNTER: // Misdirection if (GetId() == 34477) @@ -5600,6 +5600,20 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, } } +void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + if (aurApp->GetTarget()->GetTypeId() != TYPEID_PLAYER) + return; + + if (apply) + aurApp->GetTarget()->RemoveByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER); + else if (!aurApp->GetTarget()->GetBaseMap()->Instanceable()) + aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER); +} + void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const { switch (GetSpellInfo()->SpellFamilyName) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 0c5e500d887..86bb325aa3c 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -277,6 +277,7 @@ class AuraEffect void HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const; // aura effect periodic tick handlers void HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 3ef5d0d4777..15e0c1a9edf 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -451,7 +451,8 @@ SpellValue::SpellValue(SpellInfo const* proto) Spell::Spell(Unit* caster, SpellInfo const *info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID, bool skipCheck) : m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)), -m_caster(caster), m_spellValue(new SpellValue(m_spellInfo)) +m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster) +, m_spellValue(new SpellValue(m_spellInfo)) { m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; @@ -496,9 +497,6 @@ m_caster(caster), m_spellValue(new SpellValue(m_spellInfo)) if (Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK)) m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->Damage[0].DamageType); - if (info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER) - const_cast<Unit*>(m_caster) = caster->GetCharmerOrOwner(); - if (originalCasterGUID) m_originalCasterGUID = originalCasterGUID; else @@ -652,51 +650,10 @@ void Spell::SelectSpellTargets() { case SPELL_EFFECT_DUMMY: { - switch(m_spellInfo->Id) - { - case 20577: // Cannibalize - case 54044: // Carrion Feeder - { - WorldObject* result = NULL; - if (m_spellInfo->Id == 20577) - result = FindCorpseUsing<Trinity::CannibalizeObjectCheck>(); - else - result = FindCorpseUsing<Trinity::CarrionFeederObjectCheck>(); - - if (result) - { - switch(result->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - AddUnitTarget((Unit*)result, i); - break; - case TYPEID_CORPSE: - m_targets.SetCorpseTarget((Corpse*)result); - if (Player* owner = ObjectAccessor::FindPlayer(((Corpse*)result)->GetOwnerGUID())) - AddUnitTarget(owner, i); - break; - default: - break; - } - } - else - { - // clear cooldown at fail - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); - SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES); - finish(false); - } - break; - } - default: - if (m_targets.GetUnitTarget()) - AddUnitTarget(m_targets.GetUnitTarget(), i, false); - else - AddUnitTarget(m_caster, i, false); - break; - } + if (m_targets.GetUnitTarget()) + AddUnitTarget(m_targets.GetUnitTarget(), i, false); + else + AddUnitTarget(m_caster, i, false); break; } case SPELL_EFFECT_BIND: @@ -1230,7 +1187,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) break; } } - switch(m_spellInfo->DmgClass) + switch (m_spellInfo->DmgClass) { case SPELL_DAMAGE_CLASS_MAGIC: if (positive) @@ -1280,6 +1237,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit); unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); + m_healing = gain; } // Do damage and triggers else if (m_damage > 0) @@ -1311,9 +1269,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Haunt if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[1] & 0x40000 && m_spellAura && m_spellAura->GetEffect(1)) { - AuraEffect * aurEff = m_spellAura->GetEffect(1); + AuraEffect* aurEff = m_spellAura->GetEffect(1); aurEff->SetAmount(CalculatePctU(aurEff->GetAmount(), damageInfo.damage)); } + m_damage = damageInfo.damage; } // Passive spell hits/misses or active spells only misses (only triggers) else @@ -1358,18 +1317,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) p->CastedCreatureOrGO(spellHitTarget->GetEntry(), spellHitTarget->GetGUID(), m_spellInfo->Id); } - if (m_caster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsAIEnabled) + if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsAIEnabled) m_caster->ToCreature()->AI()->SpellHitTarget(spellHitTarget, m_spellInfo); // Needs to be called after dealing damage/healing to not remove breaking on damage auras DoTriggersOnSpellHit(spellHitTarget, mask); // if target is fallged for pvp also flag caster if a player - if (unit->IsPvP()) - { - if (m_caster->GetTypeId() == TYPEID_PLAYER) + if (unit->IsPvP() && m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->UpdatePvP(true); - } CallScriptAfterHitHandlers(); } @@ -1450,7 +1406,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool uint8 aura_effmask = 0; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i ) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) + if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) aura_effmask |= 1 << i; if (aura_effmask) @@ -4596,7 +4552,7 @@ void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOT SpellCastResult Spell::CheckCast(bool strict) { // check death state - if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURASTATE) && !m_caster->isAlive() && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)) + if (!m_caster->isAlive() && !(m_spellInfo->Attributes & SPELL_ATTR0_PASSIVE) && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)) return SPELL_FAILED_CASTER_DEAD; // check cooldowns to prevent cheating @@ -4738,10 +4694,6 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_DONT_REPORT; } - //! Client checks this already - if (m_spellInfo->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && !m_caster->GetCharmerOrOwnerGUID()) - return SPELL_FAILED_DONT_REPORT; - Unit* target = m_targets.GetUnitTarget(); // In pure self-cast spells, the client won't send any unit target if (!target && (m_targets.GetTargetMask() == TARGET_FLAG_SELF || m_targets.GetTargetMask() & TARGET_FLAG_UNIT_ALLY)) // TARGET_FLAG_SELF == 0, remember! @@ -5478,46 +5430,41 @@ SpellCastResult Spell::CheckCast(bool strict) SpellCastResult Spell::CheckPetCast(Unit* target) { - if (!m_caster->isAlive() && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)) - return SPELL_FAILED_CASTER_DEAD; - if (m_caster->HasUnitState(UNIT_STAT_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast return SPELL_FAILED_SPELL_IN_PROGRESS; - if (m_caster->isInCombat() && !m_spellInfo->CanBeUsedInCombat()) - return SPELL_FAILED_AFFECTING_COMBAT; - //dead owner (pets still alive when owners ressed?) - if (Unit *owner = m_caster->GetCharmerOrOwner()) - if (!owner->isAlive()) - return SPELL_FAILED_CASTER_DEAD; + // dead owner (pets still alive when owners ressed?) + if (Unit *owner = m_caster->GetCharmerOrOwner()) + if (!owner->isAlive()) + return SPELL_FAILED_CASTER_DEAD; - if (!target && m_targets.GetUnitTarget()) - target = m_targets.GetUnitTarget(); + if (!target && m_targets.GetUnitTarget()) + target = m_targets.GetUnitTarget(); - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (m_spellInfo->Effects[i].TargetA.GetType() == TARGET_TYPE_UNIT_TARGET + || m_spellInfo->Effects[i].TargetA.GetType() == TARGET_TYPE_DEST_TARGET) { - if (m_spellInfo->Effects[i].TargetA.GetType() == TARGET_TYPE_UNIT_TARGET - || m_spellInfo->Effects[i].TargetA.GetType() == TARGET_TYPE_DEST_TARGET) - { - if (!target) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - m_targets.SetUnitTarget(target); - break; - } + if (!target) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + m_targets.SetUnitTarget(target); + break; } + } - Unit* _target = m_targets.GetUnitTarget(); + Unit* _target = m_targets.GetUnitTarget(); - if (_target) //for target dead/target not valid - { - if (!_target->isAlive()) - return SPELL_FAILED_BAD_TARGETS; + // for target dead/target not valid + if (_target) + { + if (!IsValidSingleTargetSpell(_target)) + return SPELL_FAILED_BAD_TARGETS; + } - if (!IsValidSingleTargetSpell(_target)) - return SPELL_FAILED_BAD_TARGETS; - } - //cooldown - if (m_caster->ToCreature()->HasSpellCooldown(m_spellInfo->Id)) + // cooldown + if (Creature const* creatureCaster = m_caster->ToCreature()) + if (creatureCaster->HasSpellCooldown(m_spellInfo->Id)) return SPELL_FAILED_NOT_READY; return CheckCast(true); @@ -6393,7 +6340,7 @@ void Spell::UpdatePointers() m_targets.Update(m_caster); } -CurrentSpellTypes Spell::GetCurrentContainer() +CurrentSpellTypes Spell::GetCurrentContainer() const { if (IsNextMeleeSwingSpell()) return(CURRENT_MELEE_SPELL); @@ -6419,7 +6366,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const return false; if (target->GetCharmerGUID()) return false; - if (int32 damage = m_spellInfo->Effects[eff].CalcValue()) + if (int32 damage = CalculateDamage(eff, target)) if ((int32)target->getLevel() > damage) return false; break; @@ -7247,7 +7194,7 @@ enum GCDLimits MAX_GCD = 1500 }; -bool Spell::HasGlobalCooldown() +bool Spell::HasGlobalCooldown() const { // Only player or controlled units have global cooldown if (m_caster->GetCharmInfo()) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 50c3a093a13..bec2de1a8f7 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -411,7 +411,7 @@ class Spell SpellCastResult CheckRuneCost(uint32 runeCostID); SpellCastResult CheckCasterAuras() const; - int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]); } + int32 CalculateDamage(uint8 i, Unit const* target) const { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_spellValue->EffectBasePoints[i]); } bool HaveTargetsForEffect(uint8 effect) const; void Delayed(); @@ -489,7 +489,7 @@ class Spell bool IsNeedSendToClient() const; - CurrentSpellTypes GetCurrentContainer(); + CurrentSpellTypes GetCurrentContainer() const; Unit* GetCaster() const { return m_caster; } Unit* GetOriginalCaster() const { return m_originalCaster; } @@ -502,7 +502,7 @@ class Spell void SetSpellValue(SpellValueMod mod, int32 value); protected: - bool HasGlobalCooldown(); + bool HasGlobalCooldown() const; void TriggerGlobalCooldown(); void CancelGlobalCooldown(); @@ -727,6 +727,9 @@ namespace Trinity case SPELL_TARGETS_ENEMY: if (target->isTotem()) continue; + // can't be checked in SpellInfo::CheckTarget - needs more research + if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + continue; if (i_source->IsControlledByPlayer()) { if (i_source->IsFriendlyTo(target)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 5b8e23697df..825c8c4fb14 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -816,10 +816,6 @@ void Spell::EffectDummy(SpellEffIndex effIndex) } return; } - case 20577: // Cannibalize - if (unitTarget) - m_caster->CastSpell(m_caster, 20578, false, NULL); - return; case 23019: // Crystal Prison Dummy DND { if (!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || unitTarget->ToCreature()->isPet()) @@ -3139,7 +3135,7 @@ void Spell::EffectDispel(SpellEffIndex effIndex) if (aura->IsPassive()) continue; - if ((aura->GetSpellInfo()->GetDispelMask()) & dispelMask) + if (aura->GetSpellInfo()->GetDispelMask() & dispelMask) { if (aura->GetSpellInfo()->Dispel == DISPEL_MAGIC) { diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index a02c775e7ac..8b660d36a8d 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -15,8 +15,10 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "SpellAuraDefines.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "Spell.h" #include "DBCStores.h" SpellImplicitTargetInfo::SpellImplicitTargetInfo(uint32 target) @@ -423,17 +425,17 @@ bool SpellEffectInfo::IsAreaAuraEffect() const bool SpellEffectInfo::IsFarUnitTargetEffect() const { - return (Effect == SPELL_EFFECT_SUMMON_PLAYER); + return Effect == SPELL_EFFECT_SUMMON_PLAYER; } bool SpellEffectInfo::IsFarDestTargetEffect() const { - return (Effect == SPELL_EFFECT_TELEPORT_UNITS); + return Effect == SPELL_EFFECT_TELEPORT_UNITS; } bool SpellEffectInfo::IsUnitOwnedAuraEffect() const { - return (IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA); + return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA; } int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* /*target*/) const @@ -1101,7 +1103,7 @@ bool SpellInfo::IsRequiringDeadTarget() const bool SpellInfo::IsAllowingDeadTarget() const { - return AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD; + return AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD); } bool SpellInfo::CanBeUsedInCombat() const @@ -1154,15 +1156,23 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const return AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG; } +bool SpellInfo::IsAffectedBySpellMods() const +{ + return !(AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS); +} + bool SpellInfo::IsAffectedBySpellMod(SpellModifier* mod) const { + if (!IsAffectedBySpellMods()) + return false; + SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId); // False if affect_spell == NULL or spellFamily not equal if (!affectSpell || affectSpell->SpellFamilyName != SpellFamilyName) return false; // true - if (mod->mask & SpellFamilyFlags) + if (mod->mask & SpellFamilyFlags) return true; return false; @@ -1497,13 +1507,14 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !target->ToPlayer()) return SPELL_FAILED_TARGET_NOT_PLAYER; - if (!(AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD) && !target->isAlive()) + if (!IsAllowingDeadTarget() && !target->isAlive()) return SPELL_FAILED_TARGETS_DEAD; - if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS && !(target->ToPlayer() && !target->isAlive())) + if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS && !(!target->isAlive() && target->HasAuraType(SPELL_AURA_GHOST))) return SPELL_FAILED_TARGET_NOT_GHOST; - if (AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !target->CanFreeMove()) + // check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness + if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !target->CanFreeMove()) return SPELL_FAILED_BAD_TARGETS; // check visibility - ignore stealth for implicit (area) targets @@ -1512,7 +1523,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) return SPELL_FAILED_BAD_TARGETS; - + //if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS) if (!CheckTargetCreatureType(target)) @@ -1527,7 +1538,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b if (target != caster && target->GetCharmerOrOwnerGUID() != caster->GetGUID()) { // any unattackable target skipped - if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE)) + if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return SPELL_FAILED_BAD_TARGETS; } @@ -1589,6 +1600,11 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b } } } + + if (target->HasAuraType(SPELL_AURA_PREVENT_RESSURECTION)) + if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW)) + return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED; + return SPELL_CAST_OK; } @@ -1616,10 +1632,10 @@ uint32 SpellInfo::GetAllEffectsMechanicMask() const { uint32 mask = 0; if (Mechanic) - mask |= 1<< Mechanic; + mask |= 1 << Mechanic; for (int i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].Mechanic) - mask |= 1<< Effects[i].Mechanic; + mask |= 1 << Effects[i].Mechanic; return mask; } @@ -1644,7 +1660,7 @@ Mechanics SpellInfo::GetEffectMechanic(uint8 effIndex) const uint32 SpellInfo::GetDispelMask() const { - return SpellInfo::GetDispelMask(DispelType(Dispel)); + return GetDispelMask(DispelType(Dispel)); } uint32 SpellInfo::GetDispelMask(DispelType type) diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 9efc4701f19..b4fafa39b81 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -19,6 +19,8 @@ #define _SPELLINFO_H #include "SharedDefines.h" +#include "Util.h" +#include "DBCStructure.h" class Unit; class Player; @@ -390,6 +392,7 @@ public: bool IsRangedWeaponSpell() const; bool IsAutoRepeatRangedSpell() const; + bool IsAffectedBySpellMods() const; bool IsAffectedBySpellMod(SpellModifier* mod) const; bool CanPierceImmuneAura(SpellInfo const* aura) const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 62de179b64c..3234f573ec1 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2893,437 +2893,437 @@ void SpellMgr::LoadDbcDataCorrections() switch (spellInfo->Id) { - case 42835: // Spout - spellInfo->Effect[0] = 0; // remove damage effect, only anim is needed - break; - case 30657: // Quake - spellInfo->EffectTriggerSpell[0] = 30571; - break; - case 30541: // Blaze (needs conditions entry) - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; - spellInfo->EffectImplicitTargetB[0] = 0; - break; - case 31447: // Mark of Kaz'rogal (needs target selection script) - case 31298: // Sleep (needs target selection script) - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; - spellInfo->EffectImplicitTargetB[0] = 0; - break; - case 31344: // Howl of Azgalor - spellInfo->EffectRadiusIndex[0] = 12; // 100yards instead of 50000?! - break; - case 42818: // Headless Horseman - Wisp Flight Port - case 42821: // Headless Horseman - Wisp Flight Missile - spellInfo->rangeIndex = 6; // 100 yards - break; - case 36350: //They Must Burn Bomb Aura (self) - spellInfo->EffectTriggerSpell[0] = 36325; // They Must Burn Bomb Drop (DND) - break; - case 49838: // Stop Time - spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; - break; - case 61407: // Energize Cores - case 62136: // Energize Cores - case 54069: // Energize Cores - case 56251: // Energize Cores - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENTRY; - break; - case 50785: // Energize Cores - case 59372: // Energize Cores - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENEMY; - break; - case 3286: // Bind - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; - spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ENEMY; - break; - case 8494: // Mana Shield (rank 2) - // because of bug in dbc - spellInfo->procChance = 0; - break; - case 32182: // Heroism - spellInfo->excludeCasterAuraSpell = 57723; // Exhaustion - break; - case 2825: // Bloodlust - spellInfo->excludeCasterAuraSpell = 57724; // Sated - break; - case 20335: // Heart of the Crusader - case 20336: - case 20337: - case 63320: // Glyph of Life Tap - // Entries were not updated after spell effect change, we have to do that manually :/ - spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; - break; - case 16007: // Draco-Incarcinatrix 900 - // was 46, but effect is aura effect - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY; - spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_NEARBY_ENTRY; - break; - case 59725: // Improved Spell Reflection - aoe aura - // Target entry seems to be wrong for this spell :/ - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER_AREA_PARTY; - spellInfo->EffectRadiusIndex[0] = 45; - break; - case 44978: case 45001: case 45002: // Wild Magic - case 45004: case 45006: case 45010: // Wild Magic - case 31347: // Doom - case 41635: // Prayer of Mending - case 44869: // Spectral Blast - case 45027: // Revitalize - case 45976: // Muru Portal Channel - case 39365: // Thundering Storm - case 41071: // Raise Dead (HACK) - case 52124: // Sky Darkener Assault - case 42442: // Vengeance Landing Cannonfire - case 45863: // Cosmetic - Incinerate to Random Target - case 25425: // Shoot - case 45761: // Shoot - case 42611: // Shoot - case 62374: // Pursued - case 61588: // Blazing Harpoon - spellInfo->MaxAffectedTargets = 1; - break; - case 52479: // Gift of the Harvester - spellInfo->MaxAffectedTargets = 1; - // a trap always has dst = src? - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; - spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_CASTER; - break; - case 41376: // Spite - case 39992: // Needle Spine - case 29576: // Multi-Shot - case 40816: // Saber Lash - case 37790: // Spread Shot - case 46771: // Flame Sear - case 45248: // Shadow Blades - case 41303: // Soul Drain - case 54172: // Divine Storm (heal) - case 29213: // Curse of the Plaguebringer - Noth - case 28542: // Life Drain - Sapphiron - case 66588: // Flaming Spear - case 54171: // Divine Storm - spellInfo->MaxAffectedTargets = 3; - break; - case 38310: // Multi-Shot - case 53385: // Divine Storm (Damage) - spellInfo->MaxAffectedTargets = 4; - break; - case 42005: // Bloodboil - case 38296: // Spitfire Totem - case 37676: // Insidious Whisper - case 46008: // Negative Energy - case 45641: // Fire Bloom - case 55665: // Life Drain - Sapphiron (H) - case 28796: // Poison Bolt Volly - Faerlina - spellInfo->MaxAffectedTargets = 5; - break; - case 40827: // Sinful Beam - case 40859: // Sinister Beam - case 40860: // Vile Beam - case 40861: // Wicked Beam - case 54835: // Curse of the Plaguebringer - Noth (H) - case 54098: // Poison Bolt Volly - Faerlina (H) - spellInfo->MaxAffectedTargets = 10; - break; - case 50312: // Unholy Frenzy - spellInfo->MaxAffectedTargets = 15; - break; - case 38794: case 33711: //Murmur's Touch - spellInfo->MaxAffectedTargets = 1; - spellInfo->EffectTriggerSpell[0] = 33760; - break; - case 17941: // Shadow Trance - case 22008: // Netherwind Focus - case 31834: // Light's Grace - case 34754: // Clearcasting - case 34936: // Backlash - case 48108: // Hot Streak - case 51124: // Killing Machine - case 54741: // Firestarter - case 57761: // Fireball! - case 39805: // Lightning Overload - case 64823: // Item - Druid T8 Balance 4P Bonus - case 44401: // Missile Barrage - spellInfo->procCharges = 1; - break; - case 44544: // Fingers of Frost - spellInfo->EffectSpellClassMask[0] = flag96(685904631, 1151048, 0); - break; - case 74396: // Fingers of Frost visual buff - spellInfo->procCharges = 2; - spellInfo->StackAmount = 0; - break; - case 28200: // Ascendance (Talisman of Ascendance trinket) - spellInfo->procCharges = 6; - break; - case 47201: // Everlasting Affliction - case 47202: - case 47203: - case 47204: - case 47205: - // add corruption to affected spells - spellInfo->EffectSpellClassMask[1][0] |= 2; - break; - case 49305: // Teleport to Boss 1 DND - case 64981: // Summon Random Vanquished Tentacle - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_CASTER; - break; - case 51852: // The Eye of Acherus (no spawn in phase 2 in db) - spellInfo->EffectMiscValue[0] |= 1; - break; - case 51904: // Summon Ghouls On Scarlet Crusade (core does not know the triggered spell is summon spell) - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; - break; - case 29809: // Desecration Arm - 36 instead of 37 - typo? :/ - spellInfo->EffectRadiusIndex[0] = 37; - break; - // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data - // To prevent aura staying on target after talent unlearned - case 48420: - spellInfo->Stances = 1 << (FORM_CAT - 1); - break; - case 48421: - spellInfo->Stances = 1 << (FORM_MOONKIN - 1); - break; - case 48422: - spellInfo->Stances = 1 << (FORM_TREE - 1); - break; - case 47569: // Improved Shadowform (Rank 1) - // with this spell atrribute aura can be stacked several times - spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT; - break; - case 30421: // Nether Portal - Perseverence - spellInfo->EffectBasePoints[2] += 30000; - break; - case 16834: // Natural shapeshifter - case 16835: - spellInfo->DurationIndex = 21; - break; - case 51735: // Ebon Plague - case 51734: - case 51726: - spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; - spellInfo->SpellFamilyFlags[2] = 0x10; - break; - case 41013: // Parasitic Shadowfiend Passive - spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends - break; - case 27892: // To Anchor 1 - case 27928: // To Anchor 1 - case 27935: // To Anchor 1 - case 27915: // Anchor to Skulls - case 27931: // Anchor to Skulls - case 27937: // Anchor to Skulls - spellInfo->rangeIndex = 13; - break; - // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target - // this is the only known exception, probably just wrong data - case 29214: // Wrath of the Plaguebringer - case 54836: // Wrath of the Plaguebringer - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY; - spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ALLY; - break; - case 31687: // Summon Water Elemental - // 322-330 switch - effect changed to dummy, target entry not changed in client:( - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; - break; - case 57994: // Wind Shear - improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x - spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_MODIFY_THREAT_PERCENT; - spellInfo->EffectBasePoints[EFFECT_1] = -6; // -5% - break; - case 63675: // Improved Devouring Plague - spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; - break; - case 8145: // Tremor Totem (instant pulse) - case 6474: // Earthbind Totem (instant pulse) - spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY; - break; - case 53241: // Marked for Death (Rank 1) - case 53243: // Marked for Death (Rank 2) - case 53244: // Marked for Death (Rank 3) - case 53245: // Marked for Death (Rank 4) - case 53246: // Marked for Death (Rank 5) - spellInfo->EffectSpellClassMask[0] = flag96(423937, 276955137, 2049); - break; - case 70728: // Exploit Weakness - case 70840: // Devious Minds - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_PET; - break; - case 70893: // Culling The Herd - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_MASTER; - break; - case 54800: // Sigil of the Frozen Conscience - change class mask to custom extended flags of Icy Touch - // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch - // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a) - // this needs research on modifier applying rules, does not seem to be in Attributes fields - spellInfo->EffectSpellClassMask[0] = flag96(0x00000040, 0x00000000, 0x00000000); - break; - case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc - case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc - case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc - case 19973: // Entangling Roots (Rank 3) -- Nature's Grasp Proc - case 19974: // Entangling Roots (Rank 2) -- Nature's Grasp Proc - case 19975: // Entangling Roots (Rank 1) -- Nature's Grasp Proc - case 27010: // Entangling Roots (Rank 7) -- Nature's Grasp Proc - case 53313: // Entangling Roots (Rank 8) -- Nature's Grasp Proc - spellInfo->CastingTimeIndex = 1; - break; - case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with - spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; - break; - // ULDUAR SPELLS - // - case 63342: // Focused Eyebeam Summon Trigger (Kologarn) - spellInfo->MaxAffectedTargets = 1; - break; - case 62716: // Growth of Nature (Freya) - case 65584: // Growth of Nature (Freya) - case 64381: // Strength of the Pack (Auriaya) - spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; - break; - case 63018: // Searing Light (XT-002) - case 65121: // Searing Light (25m) (XT-002) - case 63024: // Gravity Bomb (XT-002) - case 64234: // Gravity Bomb (25m) (XT-002) - spellInfo->MaxAffectedTargets = 1; - break; - case 62834: // Boom (XT-002) - // This hack is here because we suspect our implementation of spell effect execution on targets - // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, - // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. - // The above situation causes the visual for this spell to be bugged, so we remove the instakill - // effect and implement a script hack for that. - spellInfo->Effect[EFFECT_1] = 0; - break; - case 64386: // Terrifying Screech (Auriaya) - case 64389: // Sentinel Blast (Auriaya) - case 64678: // Sentinel Blast (Auriaya) - spellInfo->DurationIndex = 28; // 5 seconds, wrong DBC data? - break; - case 64321: // Potent Pheromones (Freya) - // spell should dispel area aura, but doesn't have the attribute - // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity - // that will be clear if we get more spells with problem like this - spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; - break; - // ENDOF ULDUAR SPELLS - // - // TRIAL OF THE CRUSADER SPELLS - // - case 66258: // Infernal Eruption (10N) - case 67901: // Infernal Eruption (25N) - // increase duration from 15 to 18 seconds because caster is already - // unsummoned when spell missile hits the ground so nothing happen in result - spellInfo->DurationIndex = 85; - break; - // ENDOF TRIAL OF THE CRUSADER SPELLS - // - // ICECROWN CITADEL SPELLS - // - // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK - // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM - // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333) - case 70781: // Light's Hammer Teleport - case 70856: // Oratory of the Damned Teleport - case 70857: // Rampart of Skulls Teleport - case 70858: // Deathbringer's Rise Teleport - case 70859: // Upper Spire Teleport - case 70860: // Frozen Throne Teleport - case 70861: // Sindragosa's Lair Teleport - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; - break; - case 69055: // Saber Lash (Lord Marrowgar) - case 70814: // Saber Lash (Lord Marrowgar) - spellInfo->EffectRadiusIndex[0] = 8; // 5yd - break; - case 69075: // Bone Storm (Lord Marrowgar) - case 70834: // Bone Storm (Lord Marrowgar) - case 70835: // Bone Storm (Lord Marrowgar) - case 70836: // Bone Storm (Lord Marrowgar) - case 72864: // Death Plague (Rotting Frost Giant) - case 72378: // Blood Nova (Deathbringer Saurfang) - case 73058: // Blood Nova (Deathbringer Saurfang) - case 71160: // Plague Stench (Stinky) - case 71161: // Plague Stench (Stinky) - case 71123: // Decimate (Stinky & Precious) - spellInfo->EffectRadiusIndex[0] = 12; // 100yd - break; - case 72723: // Resistant Skin (Deathbringer Saurfang adds) - // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client - spellInfo->Effect[2] = 0; - break; - case 70460: // Coldflame Jets (Traps after Saurfang) - spellInfo->DurationIndex = 1; // 10 seconds - break; - case 71413: // Green Ooze Summon (Professor Putricide) - case 71414: // Orange Ooze Summon (Professor Putricide) - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; - break; - case 71159: // Awaken Plagued Zombies - spellInfo->DurationIndex = 21; - break; - // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS IS NOT IMPLEMENTED - case 71604: // Mutated Strength (Professor Putricide) - case 72673: // Mutated Strength (Professor Putricide) - case 72674: // Mutated Strength (Professor Putricide) - case 72675: // Mutated Strength (Professor Putricide) - spellInfo->Effect[1] = 0; - break; - case 72454: // Mutated Plague (Professor Putricide) - case 72464: // Mutated Plague (Professor Putricide) - case 72506: // Mutated Plague (Professor Putricide) - case 72507: // Mutated Plague (Professor Putricide) - spellInfo->EffectRadiusIndex[0] = 28; // 50000yd - break; - case 70911: // Unbound Plague (Professor Putricide) - case 72854: // Unbound Plague (Professor Putricide) - case 72855: // Unbound Plague (Professor Putricide) - case 72856: // Unbound Plague (Professor Putricide) - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ENEMY; - break; - case 71518: // Unholy Infusion Quest Credit (Professor Putricide) - case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel) - case 72289: // Frost Infusion Quest Credit (Sindragosa) - spellInfo->EffectRadiusIndex[0] = 28; // another missing radius - break; - case 71708: // Empowered Flare (Blood Prince Council) - case 72785: // Empowered Flare (Blood Prince Council) - case 72786: // Empowered Flare (Blood Prince Council) - case 72787: // Empowered Flare (Blood Prince Council) - spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; - break; - case 71266: // Swarming Shadows - case 72890: // Swarming Shadows - spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel - break; - case 70602: // Corruption - spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; - break; - case 70715: // Column of Frost (visual marker) - spellInfo->DurationIndex = 32; // 6 seconds (missing) - break; - case 71085: // Mana Void (periodic aura) - spellInfo->DurationIndex = 9; // 30 seconds (missing) - break; - case 70936: // Summon Suppressor - spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; - spellInfo->EffectImplicitTargetB[0] = 0; - break; - case 72706: // Achievement Check (Valithria Dreamwalker) - case 71357: // Order Whelp - spellInfo->EffectRadiusIndex[0] = 22; // 200yd - break; - case 70598: // Sindragosa's Fury - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; - break; - case 69846: // Frost Bomb - spellInfo->speed = 10; - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ANY; - spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ANY; - spellInfo->Effect[1] = 0; - break; - default: - break; + case 42835: // Spout + spellInfo->Effect[0] = 0; // remove damage effect, only anim is needed + break; + case 30657: // Quake + spellInfo->EffectTriggerSpell[0] = 30571; + break; + case 30541: // Blaze (needs conditions entry) + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; + spellInfo->EffectImplicitTargetB[0] = 0; + break; + case 31447: // Mark of Kaz'rogal (needs target selection script) + case 31298: // Sleep (needs target selection script) + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; + spellInfo->EffectImplicitTargetB[0] = 0; + break; + case 31344: // Howl of Azgalor + spellInfo->EffectRadiusIndex[0] = 12; // 100yards instead of 50000?! + break; + case 42818: // Headless Horseman - Wisp Flight Port + case 42821: // Headless Horseman - Wisp Flight Missile + spellInfo->rangeIndex = 6; // 100 yards + break; + case 36350: //They Must Burn Bomb Aura (self) + spellInfo->EffectTriggerSpell[0] = 36325; // They Must Burn Bomb Drop (DND) + break; + case 49838: // Stop Time + spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; + break; + case 61407: // Energize Cores + case 62136: // Energize Cores + case 54069: // Energize Cores + case 56251: // Energize Cores + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENTRY; + break; + case 50785: // Energize Cores + case 59372: // Energize Cores + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENEMY; + break; + case 3286: // Bind + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; + spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ENEMY; + break; + case 8494: // Mana Shield (rank 2) + // because of bug in dbc + spellInfo->procChance = 0; + break; + case 32182: // Heroism + spellInfo->excludeCasterAuraSpell = 57723; // Exhaustion + break; + case 2825: // Bloodlust + spellInfo->excludeCasterAuraSpell = 57724; // Sated + break; + case 20335: // Heart of the Crusader + case 20336: + case 20337: + case 63320: // Glyph of Life Tap + // Entries were not updated after spell effect change, we have to do that manually :/ + spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; + break; + case 16007: // Draco-Incarcinatrix 900 + // was 46, but effect is aura effect + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY; + spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_NEARBY_ENTRY; + break; + case 59725: // Improved Spell Reflection - aoe aura + // Target entry seems to be wrong for this spell :/ + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER_AREA_PARTY; + spellInfo->EffectRadiusIndex[0] = 45; + break; + case 44978: case 45001: case 45002: // Wild Magic + case 45004: case 45006: case 45010: // Wild Magic + case 31347: // Doom + case 41635: // Prayer of Mending + case 44869: // Spectral Blast + case 45027: // Revitalize + case 45976: // Muru Portal Channel + case 39365: // Thundering Storm + case 41071: // Raise Dead (HACK) + case 52124: // Sky Darkener Assault + case 42442: // Vengeance Landing Cannonfire + case 45863: // Cosmetic - Incinerate to Random Target + case 25425: // Shoot + case 45761: // Shoot + case 42611: // Shoot + case 62374: // Pursued + case 61588: // Blazing Harpoon + spellInfo->MaxAffectedTargets = 1; + break; + case 52479: // Gift of the Harvester + spellInfo->MaxAffectedTargets = 1; + // a trap always has dst = src? + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; + spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_CASTER; + break; + case 41376: // Spite + case 39992: // Needle Spine + case 29576: // Multi-Shot + case 40816: // Saber Lash + case 37790: // Spread Shot + case 46771: // Flame Sear + case 45248: // Shadow Blades + case 41303: // Soul Drain + case 54172: // Divine Storm (heal) + case 29213: // Curse of the Plaguebringer - Noth + case 28542: // Life Drain - Sapphiron + case 66588: // Flaming Spear + case 54171: // Divine Storm + spellInfo->MaxAffectedTargets = 3; + break; + case 38310: // Multi-Shot + case 53385: // Divine Storm (Damage) + spellInfo->MaxAffectedTargets = 4; + break; + case 42005: // Bloodboil + case 38296: // Spitfire Totem + case 37676: // Insidious Whisper + case 46008: // Negative Energy + case 45641: // Fire Bloom + case 55665: // Life Drain - Sapphiron (H) + case 28796: // Poison Bolt Volly - Faerlina + spellInfo->MaxAffectedTargets = 5; + break; + case 40827: // Sinful Beam + case 40859: // Sinister Beam + case 40860: // Vile Beam + case 40861: // Wicked Beam + case 54835: // Curse of the Plaguebringer - Noth (H) + case 54098: // Poison Bolt Volly - Faerlina (H) + spellInfo->MaxAffectedTargets = 10; + break; + case 50312: // Unholy Frenzy + spellInfo->MaxAffectedTargets = 15; + break; + case 38794: case 33711: //Murmur's Touch + spellInfo->MaxAffectedTargets = 1; + spellInfo->EffectTriggerSpell[0] = 33760; + break; + case 17941: // Shadow Trance + case 22008: // Netherwind Focus + case 31834: // Light's Grace + case 34754: // Clearcasting + case 34936: // Backlash + case 48108: // Hot Streak + case 51124: // Killing Machine + case 54741: // Firestarter + case 57761: // Fireball! + case 39805: // Lightning Overload + case 64823: // Item - Druid T8 Balance 4P Bonus + case 44401: // Missile Barrage + spellInfo->procCharges = 1; + break; + case 44544: // Fingers of Frost + spellInfo->EffectSpellClassMask[0] = flag96(685904631, 1151048, 0); + break; + case 74396: // Fingers of Frost visual buff + spellInfo->procCharges = 2; + spellInfo->StackAmount = 0; + break; + case 28200: // Ascendance (Talisman of Ascendance trinket) + spellInfo->procCharges = 6; + break; + case 47201: // Everlasting Affliction + case 47202: + case 47203: + case 47204: + case 47205: + // add corruption to affected spells + spellInfo->EffectSpellClassMask[1][0] |= 2; + break; + case 49305: // Teleport to Boss 1 DND + case 64981: // Summon Random Vanquished Tentacle + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_CASTER; + break; + case 51852: // The Eye of Acherus (no spawn in phase 2 in db) + spellInfo->EffectMiscValue[0] |= 1; + break; + case 51904: // Summon Ghouls On Scarlet Crusade (core does not know the triggered spell is summon spell) + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; + break; + case 29809: // Desecration Arm - 36 instead of 37 - typo? :/ + spellInfo->EffectRadiusIndex[0] = 37; + break; + // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data + // To prevent aura staying on target after talent unlearned + case 48420: + spellInfo->Stances = 1 << (FORM_CAT - 1); + break; + case 48421: + spellInfo->Stances = 1 << (FORM_MOONKIN - 1); + break; + case 48422: + spellInfo->Stances = 1 << (FORM_TREE - 1); + break; + case 47569: // Improved Shadowform (Rank 1) + // with this spell atrribute aura can be stacked several times + spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT; + break; + case 30421: // Nether Portal - Perseverence + spellInfo->EffectBasePoints[2] += 30000; + break; + case 16834: // Natural shapeshifter + case 16835: + spellInfo->DurationIndex = 21; + break; + case 51735: // Ebon Plague + case 51734: + case 51726: + spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; + spellInfo->SpellFamilyFlags[2] = 0x10; + break; + case 41013: // Parasitic Shadowfiend Passive + spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends + break; + case 27892: // To Anchor 1 + case 27928: // To Anchor 1 + case 27935: // To Anchor 1 + case 27915: // Anchor to Skulls + case 27931: // Anchor to Skulls + case 27937: // Anchor to Skulls + spellInfo->rangeIndex = 13; + break; + // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target + // this is the only known exception, probably just wrong data + case 29214: // Wrath of the Plaguebringer + case 54836: // Wrath of the Plaguebringer + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY; + spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ALLY; + break; + case 31687: // Summon Water Elemental + // 322-330 switch - effect changed to dummy, target entry not changed in client:( + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; + break; + case 57994: // Wind Shear - improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x + spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_MODIFY_THREAT_PERCENT; + spellInfo->EffectBasePoints[EFFECT_1] = -6; // -5% + break; + case 63675: // Improved Devouring Plague + spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; + break; + case 8145: // Tremor Totem (instant pulse) + case 6474: // Earthbind Totem (instant pulse) + spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY; + break; + case 53241: // Marked for Death (Rank 1) + case 53243: // Marked for Death (Rank 2) + case 53244: // Marked for Death (Rank 3) + case 53245: // Marked for Death (Rank 4) + case 53246: // Marked for Death (Rank 5) + spellInfo->EffectSpellClassMask[0] = flag96(423937, 276955137, 2049); + break; + case 70728: // Exploit Weakness + case 70840: // Devious Minds + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_PET; + break; + case 70893: // Culling The Herd + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_MASTER; + break; + case 54800: // Sigil of the Frozen Conscience - change class mask to custom extended flags of Icy Touch + // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch + // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a) + // this needs research on modifier applying rules, does not seem to be in Attributes fields + spellInfo->EffectSpellClassMask[0] = flag96(0x00000040, 0x00000000, 0x00000000); + break; + case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc + case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc + case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc + case 19973: // Entangling Roots (Rank 3) -- Nature's Grasp Proc + case 19974: // Entangling Roots (Rank 2) -- Nature's Grasp Proc + case 19975: // Entangling Roots (Rank 1) -- Nature's Grasp Proc + case 27010: // Entangling Roots (Rank 7) -- Nature's Grasp Proc + case 53313: // Entangling Roots (Rank 8) -- Nature's Grasp Proc + spellInfo->CastingTimeIndex = 1; + break; + case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with + spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; + break; + // ULDUAR SPELLS + // + case 63342: // Focused Eyebeam Summon Trigger (Kologarn) + spellInfo->MaxAffectedTargets = 1; + break; + case 62716: // Growth of Nature (Freya) + case 65584: // Growth of Nature (Freya) + case 64381: // Strength of the Pack (Auriaya) + spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; + break; + case 63018: // Searing Light (XT-002) + case 65121: // Searing Light (25m) (XT-002) + case 63024: // Gravity Bomb (XT-002) + case 64234: // Gravity Bomb (25m) (XT-002) + spellInfo->MaxAffectedTargets = 1; + break; + case 62834: // Boom (XT-002) + // This hack is here because we suspect our implementation of spell effect execution on targets + // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, + // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. + // The above situation causes the visual for this spell to be bugged, so we remove the instakill + // effect and implement a script hack for that. + spellInfo->Effect[EFFECT_1] = 0; + break; + case 64386: // Terrifying Screech (Auriaya) + case 64389: // Sentinel Blast (Auriaya) + case 64678: // Sentinel Blast (Auriaya) + spellInfo->DurationIndex = 28; // 5 seconds, wrong DBC data? + break; + case 64321: // Potent Pheromones (Freya) + // spell should dispel area aura, but doesn't have the attribute + // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity + // that will be clear if we get more spells with problem like this + spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; + break; + // ENDOF ULDUAR SPELLS + // + // TRIAL OF THE CRUSADER SPELLS + // + case 66258: // Infernal Eruption (10N) + case 67901: // Infernal Eruption (25N) + // increase duration from 15 to 18 seconds because caster is already + // unsummoned when spell missile hits the ground so nothing happen in result + spellInfo->DurationIndex = 85; + break; + // ENDOF TRIAL OF THE CRUSADER SPELLS + // + // ICECROWN CITADEL SPELLS + // + // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK + // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM + // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333) + case 70781: // Light's Hammer Teleport + case 70856: // Oratory of the Damned Teleport + case 70857: // Rampart of Skulls Teleport + case 70858: // Deathbringer's Rise Teleport + case 70859: // Upper Spire Teleport + case 70860: // Frozen Throne Teleport + case 70861: // Sindragosa's Lair Teleport + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; + break; + case 69055: // Saber Lash (Lord Marrowgar) + case 70814: // Saber Lash (Lord Marrowgar) + spellInfo->EffectRadiusIndex[0] = 8; // 5yd + break; + case 69075: // Bone Storm (Lord Marrowgar) + case 70834: // Bone Storm (Lord Marrowgar) + case 70835: // Bone Storm (Lord Marrowgar) + case 70836: // Bone Storm (Lord Marrowgar) + case 72864: // Death Plague (Rotting Frost Giant) + case 72378: // Blood Nova (Deathbringer Saurfang) + case 73058: // Blood Nova (Deathbringer Saurfang) + case 71160: // Plague Stench (Stinky) + case 71161: // Plague Stench (Stinky) + case 71123: // Decimate (Stinky & Precious) + spellInfo->EffectRadiusIndex[0] = 12; // 100yd + break; + case 72723: // Resistant Skin (Deathbringer Saurfang adds) + // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client + spellInfo->Effect[2] = 0; + break; + case 70460: // Coldflame Jets (Traps after Saurfang) + spellInfo->DurationIndex = 1; // 10 seconds + break; + case 71413: // Green Ooze Summon (Professor Putricide) + case 71414: // Orange Ooze Summon (Professor Putricide) + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; + break; + case 71159: // Awaken Plagued Zombies + spellInfo->DurationIndex = 21; + break; + // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS IS NOT IMPLEMENTED + case 71604: // Mutated Strength (Professor Putricide) + case 72673: // Mutated Strength (Professor Putricide) + case 72674: // Mutated Strength (Professor Putricide) + case 72675: // Mutated Strength (Professor Putricide) + spellInfo->Effect[1] = 0; + break; + case 72454: // Mutated Plague (Professor Putricide) + case 72464: // Mutated Plague (Professor Putricide) + case 72506: // Mutated Plague (Professor Putricide) + case 72507: // Mutated Plague (Professor Putricide) + spellInfo->EffectRadiusIndex[0] = 28; // 50000yd + break; + case 70911: // Unbound Plague (Professor Putricide) + case 72854: // Unbound Plague (Professor Putricide) + case 72855: // Unbound Plague (Professor Putricide) + case 72856: // Unbound Plague (Professor Putricide) + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ENEMY; + break; + case 71518: // Unholy Infusion Quest Credit (Professor Putricide) + case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel) + case 72289: // Frost Infusion Quest Credit (Sindragosa) + spellInfo->EffectRadiusIndex[0] = 28; // another missing radius + break; + case 71708: // Empowered Flare (Blood Prince Council) + case 72785: // Empowered Flare (Blood Prince Council) + case 72786: // Empowered Flare (Blood Prince Council) + case 72787: // Empowered Flare (Blood Prince Council) + spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; + break; + case 71266: // Swarming Shadows + case 72890: // Swarming Shadows + spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel + break; + case 70602: // Corruption + spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; + break; + case 70715: // Column of Frost (visual marker) + spellInfo->DurationIndex = 32; // 6 seconds (missing) + break; + case 71085: // Mana Void (periodic aura) + spellInfo->DurationIndex = 9; // 30 seconds (missing) + break; + case 70936: // Summon Suppressor + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; + spellInfo->EffectImplicitTargetB[0] = 0; + break; + case 72706: // Achievement Check (Valithria Dreamwalker) + case 71357: // Order Whelp + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + break; + case 70598: // Sindragosa's Fury + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; + break; + case 69846: // Frost Bomb + spellInfo->speed = 10; + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ANY; + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ANY; + spellInfo->Effect[1] = 0; + break; + default: + break; } switch (spellInfo->SpellFamilyName) diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 78a8b02c044..e8ac3ce9862 100755 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -24,6 +24,7 @@ #include <ace/Singleton.h> #include "Common.h" #include "SharedDefines.h" +#include "Unit.h" class SpellInfo; class Player; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index bb7b242a561..5c9a6a23304 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -477,6 +477,11 @@ void SpellScript::SetCustomCastResultMessage(SpellCustomErrors result) m_spell->m_customError = result; } +SpellValue const* SpellScript::GetSpellValue() +{ + return m_spell->m_spellValue; +} + bool AuraScript::_Validate(SpellInfo const* entry) { for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index e28030d7605..c9f88092028 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -256,6 +256,7 @@ class SpellScript : public _SpellScript Unit* GetCaster(); Unit* GetOriginalCaster(); SpellInfo const* GetSpellInfo(); + SpellValue const* GetSpellValue(); // methods useable after spell targets are set // accessors to the "focus" targets of the spell @@ -287,10 +288,12 @@ class SpellScript : public _SpellScript // returns: target of current effect if it was GameObject otherwise NULL GameObject* GetHitGObj(); // setter/getter for for damage done by spell to target of spell hit + // returns damage calculated before hit, and real dmg done after hit int32 GetHitDamage(); void SetHitDamage(int32 damage); void PreventHitDamage() { SetHitDamage(0); } // setter/getter for for heal done by spell to target of spell hit + // returns healing calculated before hit, and real dmg done after hit int32 GetHitHeal(); void SetHitHeal(int32 heal); void PreventHitHeal() { SetHitHeal(0); } diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp index e77d07f0762..f690b5401b4 100644 --- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp +++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp @@ -20,6 +20,7 @@ #include "CharacterDatabaseCleaner.h" #include "World.h" #include "Database/DatabaseEnv.h" +#include "SpellMgr.h" #include "DBCStores.h" void CharacterDatabaseCleaner::CleanDatabase() diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h index b3146ddafe6..3db1b503eb1 100755 --- a/src/server/game/Weather/Weather.h +++ b/src/server/game/Weather/Weather.h @@ -56,7 +56,8 @@ enum WeatherState WEATHER_STATE_MEDIUM_SANDSTORM = 41, WEATHER_STATE_HEAVY_SANDSTORM = 42, WEATHER_STATE_THUNDERS = 86, - WEATHER_STATE_BLACKRAIN = 90 + WEATHER_STATE_BLACKRAIN = 90, + WEATHER_STATE_BLACKSNOW = 106, }; /// Weather for one zone diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 1fa697f3f44..f077d6ec9c0 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -44,7 +44,6 @@ public: { "taxinode", SEC_MODERATOR, false, &HandleGoTaxinodeCommand, "", NULL }, { "trigger", SEC_MODERATOR, false, &HandleGoTriggerCommand, "", NULL }, { "zonexy", SEC_MODERATOR, false, &HandleGoZoneXYCommand, "", NULL }, - { "xy", SEC_MODERATOR, false, &HandleGoXYCommand, "", NULL }, { "xyz", SEC_MODERATOR, false, &HandleGoXYZCommand, "", NULL }, { "ticket", SEC_MODERATOR, false, &HandleGoTicketCommand, "", NULL }, { "", SEC_MODERATOR, false, &HandleGoXYZCommand, "", NULL }, @@ -477,8 +476,8 @@ public: return true; } - //teleport at coordinates - static bool HandleGoXYCommand(ChatHandler* handler, const char* args) + //teleport at coordinates, including Z and orientation + static bool HandleGoXYZCommand(ChatHandler* handler, const char* args) { if (!*args) return false; @@ -487,75 +486,51 @@ public: char* px = strtok((char*)args, " "); char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); char* pmapid = strtok(NULL, " "); + char* port = strtok(NULL, " "); if (!px || !py) return false; float x = (float)atof(px); float y = (float)atof(py); + float z; + float ort; uint32 mapid; + if (pmapid) mapid = (uint32)atoi(pmapid); else mapid = _player->GetMapId(); - - if (!MapManager::IsValidMapCoord(mapid, x, y)) - { - handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapid); - handler->SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if (_player->isInFlight()) + + if( port ) + ort = (float)atof(port); + else + ort = _player->GetOrientation(); + + if( pz ) { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); + z = (float)atof(pz); + if (!MapManager::IsValidMapCoord(mapid, x, y, z)) + { + handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapid); + handler->SetSentErrorMessage(true); + return false; + } } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = sMapMgr->CreateBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; - } - //teleport at coordinates, including Z - static bool HandleGoXYZCommand(ChatHandler* handler, const char* args) - { - if (!*args) - return false; - - Player* _player = handler->GetSession()->GetPlayer(); - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - char* pmapid = strtok(NULL, " "); - - if (!px || !py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); else - mapid = _player->GetMapId(); - - if (!MapManager::IsValidMapCoord(mapid, x, y, z)) { - handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapid); - handler->SetSentErrorMessage(true); - return false; + if (!MapManager::IsValidMapCoord(mapid, x, y)) + { + handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapid); + handler->SetSentErrorMessage(true); + return false; + } + Map const *map = sMapMgr->CreateBaseMap(mapid); + z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); } - + // stop flight if need if (_player->isInFlight()) { @@ -566,7 +541,7 @@ public: else _player->SaveRecallPosition(); - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); + _player->TeleportTo(mapid, x, y, z, ort); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.h b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.h index 926acc8c965..2282acaa233 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.h +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.h @@ -54,6 +54,7 @@ enum eTypes DATA_THRONE_DOOR = 24, DATA_SF_BRAZIER_N = 25, - DATA_SF_BRAZIER_S = 26 + DATA_SF_BRAZIER_S = 26, + DATA_MOIRA = 27, }; #endif diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp index 3ff21b428d6..1d9878a331a 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp @@ -24,6 +24,7 @@ SDCategory: Blackrock Depths EndScriptData */ #include "ScriptPCH.h" +#include "blackrock_depths.h" enum Yells { @@ -49,8 +50,12 @@ public: struct boss_draganthaurissanAI : public ScriptedAI { - boss_draganthaurissanAI(Creature* c) : ScriptedAI(c) {} + boss_draganthaurissanAI(Creature* c) : ScriptedAI(c) + { + instance = me->GetInstanceScript(); + } + InstanceScript* instance; uint32 HandOfThaurissan_Timer; uint32 AvatarOfFlame_Timer; //uint32 Counter; @@ -73,6 +78,15 @@ public: DoScriptText(SAY_SLAY, me); } + void JustDied(Unit* /*who*/) + { + if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(DATA_MOIRA) : 0)) + { + Moira->AI()->EnterEvadeMode(); + Moira->setFaction(35); + } + } + void UpdateAI(const uint32 diff) { //Return since we have no target diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/instance_blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/instance_blackrock_depths.cpp index 95d15ceb4bd..f6fa3ca18d9 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/instance_blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/instance_blackrock_depths.cpp @@ -42,6 +42,7 @@ enum eEnums NPC_GLOOMREL = 9037, NPC_DOOMREL = 9039, NPC_MAGMUS = 9938, + NPC_MOIRA = 8929, GO_ARENA1 = 161525, GO_ARENA2 = 161522, @@ -87,6 +88,7 @@ public: uint64 EmperorGUID; uint64 PhalanxGUID; uint64 MagmusGUID; + uint64 MoiraGUID; uint64 GoArena1GUID; uint64 GoArena2GUID; @@ -124,6 +126,7 @@ public: EmperorGUID = 0; PhalanxGUID = 0; MagmusGUID = 0; + MoiraGUID = 0; GoArena1GUID = 0; GoArena2GUID = 0; @@ -163,6 +166,7 @@ public: { case NPC_EMPEROR: EmperorGUID = creature->GetGUID(); break; case NPC_PHALANX: PhalanxGUID = creature->GetGUID(); break; + case NPC_MOIRA: MoiraGUID = creature->GetGUID(); break; case NPC_DOOMREL: TombBossGUIDs[0] = creature->GetGUID(); break; case NPC_DOPEREL: TombBossGUIDs[1] = creature->GetGUID(); break; case NPC_HATEREL: TombBossGUIDs[2] = creature->GetGUID(); break; @@ -308,6 +312,8 @@ public: return EmperorGUID; case DATA_PHALANX: return PhalanxGUID; + case DATA_MOIRA: + return MoiraGUID; case DATA_ARENA1: return GoArena1GUID; case DATA_ARENA2: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 62b00a90dc6..09f3bd49279 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -74,6 +74,7 @@ enum Event EVENT_TRIGGER, EVENT_PHASE, + EVENT_MORTAL_WOUND, }; enum Spells @@ -121,6 +122,10 @@ enum Spells //death knight SPELL_PLAGUE_STRIKE = 49921, SPELL_HOWLING_BLAST = 51411, + + // Abomination spells + SPELL_FRENZY = 28468, + SPELL_MORTAL_WOUND = 28467, }; enum Creatures @@ -302,6 +307,9 @@ public: FindGameObjects(); + if (instance) + instance->SetData(DATA_ABOMINATION_KILLED, 0); + if (GameObject* pKTTrigger = me->GetMap()->GetGameObject(KTTriggerGUID)) { pKTTrigger->ResetDoorOrButton(); @@ -709,8 +717,86 @@ public: }; +class npc_kelthuzad_abomination : public CreatureScript +{ + public: + npc_kelthuzad_abomination() : CreatureScript("npc_kelthuzad_abomination") { } + + struct npc_kelthuzad_abominationAI : public ScriptedAI + { + npc_kelthuzad_abominationAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + InstanceScript* instance; + EventMap events; + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(2000, 5000)); + DoCast(me, SPELL_FRENZY, true); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MORTAL_WOUND: + DoCastVictim(SPELL_MORTAL_WOUND, true); + events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(10000, 15000)); + break; + default: + break; + } + } + } + + void JustDied(Unit* /*who*/) + { + if (instance) + instance->SetData(DATA_ABOMINATION_KILLED, instance->GetData(DATA_ABOMINATION_KILLED) + 1); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_kelthuzad_abominationAI(creature); + } +}; + +class achievement_just_cant_get_enough : public AchievementCriteriaScript +{ + public: + achievement_just_cant_get_enough() : AchievementCriteriaScript("achievement_just_cant_get_enough") + { + } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (InstanceScript* instance = target->GetInstanceScript()) + if (instance->GetData(DATA_ABOMINATION_KILLED) >= 18) + return true; + + return false; + } +}; + void AddSC_boss_kelthuzad() { new boss_kelthuzad(); new at_kelthuzad_center(); + new npc_kelthuzad_abomination(); + new achievement_just_cant_get_enough(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index f57a81f4296..f08e0ccb5cf 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -140,11 +140,33 @@ public: uint64 uiKelthuzadTrigger; uint64 uiPortals[4]; + uint32 AbominationCount; + GOState gothikDoorState; time_t minHorsemenDiedTime; time_t maxHorsemenDiedTime; + void Initialize() + { + GothikGateGUID = 0; + HorsemenChestGUID = 0; + SapphironGUID = 0; + uiFaerlina = 0; + uiThane = 0; + uiLady = 0; + uiBaron = 0; + uiSir = 0; + uiThaddius = 0; + uiHeigan = 0; + uiFeugen = 0; + uiStalagg = 0; + uiKelthuzad = 0; + uiKelthuzadTrigger = 0; + + memset(uiPortals, 0, sizeof(uiPortals)); + } + void OnCreatureCreate(Creature* creature) { switch(creature->GetEntry()) @@ -273,7 +295,23 @@ public: maxHorsemenDiedTime = now; } break; + case DATA_ABOMINATION_KILLED: + AbominationCount = value; + break; + } + } + + uint32 GetData(uint32 id) + { + switch (id) + { + case DATA_ABOMINATION_KILLED: + return AbominationCount; + default: + break; } + + return 0; } uint64 GetData64(uint32 id) diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 86a7f67c11d..bb25ad691e0 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -48,6 +48,7 @@ enum Data DATA_HORSEMEN1, DATA_HORSEMEN2, DATA_HORSEMEN3, + DATA_ABOMINATION_KILLED, }; enum Data64 diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp index 4b2776b688f..a7abfcf42be 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_assembly_of_iron.cpp @@ -95,6 +95,7 @@ enum AssemblyActions ACTION_STEELBREAKER = 0, ACTION_MOLGEIM = 1, ACTION_BRUNDIR = 2, + ACTION_ADD_CHARGE = 3, }; enum AssemblyYells @@ -243,7 +244,10 @@ class boss_steelbreaker : public CreatureScript events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 30000); if (phase >= 3) events.RescheduleEvent(EVENT_OVERWHELMING_POWER, urand(2000, 5000)); - break; + break; + case ACTION_ADD_CHARGE: + DoCast(me, SPELL_ELECTRICAL_CHARGE, true); + break; } } @@ -413,7 +417,7 @@ class boss_runemaster_molgeim : public CreatureScript DoCast(SPELL_BERSERK); events.CancelEvent(EVENT_BERSERK); break; - case EVENT_RUNE_OF_POWER: // Improve target selection; random alive friendly + case EVENT_RUNE_OF_POWER: { Unit* target = NULL; switch (urand(0, 2)) @@ -628,7 +632,7 @@ class boss_stormcaller_brundir : public CreatureScript Steelbreaker->AI()->DoAction(ACTION_STEELBREAKER); // Prevent to have Brundir somewhere in the air when he die in Air phase - if (me->GetPositionZ() > FLOOR_Z/* + 5.0f*/) + if (me->GetPositionZ() > FLOOR_Z) me->GetMotionMaster()->MoveFall(FLOOR_Z); } @@ -765,6 +769,34 @@ class spell_shield_of_runes : public SpellScriptLoader } }; +class spell_assembly_meltdown : public SpellScriptLoader +{ + public: + spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { } + + class spell_assembly_meltdown_SpellScript : public SpellScript + { + PrepareSpellScript(spell_assembly_meltdown_SpellScript); + + void HandleInstaKill(SpellEffIndex /*effIndex*/) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(BOSS_STEELBREAKER))) + Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_assembly_meltdown_SpellScript(); + } +}; + void AddSC_boss_assembly_of_iron() { new boss_steelbreaker(); @@ -774,4 +806,5 @@ void AddSC_boss_assembly_of_iron() new mob_rune_of_summoning(); new mob_rune_of_power(); new spell_shield_of_runes(); + new spell_assembly_meltdown(); } diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp index 776b69d599b..9a0e912eab0 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_flame_leviathan.cpp @@ -25,13 +25,14 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" +#include "ScriptedEscortAI.h" #include "CombatAI.h" #include "PassiveAI.h" -#include "ScriptedEscortAI.h" #include "ObjectMgr.h" -#include "ulduar.h" #include "SpellInfo.h" +#include "SpellScript.h" #include "Vehicle.h" +#include "ulduar.h" enum Spells { diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 48deb028625..3d6b4fba8bc 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -25,6 +25,7 @@ #include "ScriptPCH.h" #include "SpellAuraEffects.h" #include "SkillDiscovery.h" +#include "GridNotifiers.h" class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader { @@ -161,6 +162,60 @@ class spell_gen_burn_brutallus : public SpellScriptLoader } }; +enum eCannibalizeSpells +{ + SPELL_CANNIBALIZE_TRIGGERED = 20578, +}; + +class spell_gen_cannibalize : public SpellScriptLoader +{ + public: + spell_gen_cannibalize() : SpellScriptLoader("spell_gen_cannibalize") { } + + class spell_gen_cannibalize_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_cannibalize_SpellScript); + + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_CANNIBALIZE_TRIGGERED)) + return false; + return true; + } + + SpellCastResult CheckIfCorpseNear() + { + Unit* caster = GetCaster(); + float max_range = GetSpellInfo()->GetMaxRange(false); + WorldObject* result = NULL; + // search for nearby enemy corpse in range + Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY); + Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); + caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); + if (!result) + return SPELL_FAILED_NO_EDIBLE_CORPSES; + return SPELL_CAST_OK; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + caster->CastSpell(caster, SPELL_CANNIBALIZE_TRIGGERED, false); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_gen_cannibalize_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnCheckCast += SpellCheckCastFn(spell_gen_cannibalize_SpellScript::CheckIfCorpseNear); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_cannibalize_SpellScript(); + } +}; + // 45472 Parachute enum eParachuteSpells { @@ -1264,6 +1319,7 @@ void AddSC_generic_spell_scripts() new spell_gen_aura_of_anger(); new spell_gen_av_drekthar_presence(); new spell_gen_burn_brutallus(); + new spell_gen_cannibalize(); new spell_gen_leeching_swarm(); new spell_gen_parachute(); new spell_gen_pet_summoned(); diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 79f92368ff9..0a81b13ed64 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -23,6 +23,7 @@ #include "ScriptPCH.h" #include "SpellAuraEffects.h" +#include "GridNotifiers.h" enum HunterSpells { @@ -468,10 +469,22 @@ public: return true; } + SpellCastResult CheckIfCorpseNear() + { + Unit* caster = GetCaster(); + float max_range = GetSpellInfo()->GetMaxRange(false); + WorldObject* result = NULL; + // search for nearby enemy corpse in range + Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY); + Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); + caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); + if (!result) + return SPELL_FAILED_NO_EDIBLE_CORPSES; + return SPELL_CAST_OK; + } + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (!GetHitUnit()) - return; Unit* caster = GetCaster(); caster->CastSpell(caster, HUNTER_PET_SPELL_CARRION_FEEDER_TRIGGERED, false); } @@ -480,6 +493,7 @@ public: { // add dummy effect spell handler to pet's Last Stand OnEffect += SpellEffectFn(spell_hun_pet_carrion_feeder_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnCheckCast += SpellCheckCastFn(spell_hun_pet_carrion_feeder_SpellScript::CheckIfCorpseNear); } bool Load() diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 1915697e018..f1add24fc73 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -351,7 +351,7 @@ class spell_rog_deadly_poison : public SpellScriptLoader SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->spellid[s]); if (!spellInfo) { - sLog->outError("Player::CastItemCombatSpell Enchant %i, cast unknown spell %i", enchant->ID, enchant->spellid[s]); + sLog->outError("Player::CastItemCombatSpell Enchant %i, player (Name: %s, GUID: %u) cast unknown spell %i", enchant->ID, player->GetName(), player->GetGUIDLow(), enchant->spellid[s]); continue; } |
