aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorSubv <subv2112@gmail.com>2014-06-07 20:27:23 -0500
committerSubv <subv2112@gmail.com>2014-06-07 20:27:23 -0500
commitf71abd173ebad2da329c04f5ea3b1d8704007303 (patch)
tree993fad51c1ab97b1b83adc4f1e0640033c7ae56f /src/server/game
parentbbe51bbd130908603c0a5c0c5d14eae2f0495ede (diff)
parente1e5f2a196240707f1671a02df6bd4966fed67f3 (diff)
Merge branch '4.3.4' of github.com:TrinityCore/TrinityCore into 4.3.4_phases
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/CreatureAIImpl.h349
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp1
-rw-r--r--src/server/game/Entities/Player/Player.cpp38
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp3
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp82
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp2
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp1
-rw-r--r--src/server/game/Handlers/PetHandler.cpp7
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp39
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp7
-rw-r--r--src/server/game/Maps/Map.cpp7
-rw-r--r--src/server/game/Quests/QuestDef.cpp2
-rw-r--r--src/server/game/Quests/QuestDef.h4
-rw-r--r--src/server/game/Server/WorldSession.cpp9
-rw-r--r--src/server/game/Server/WorldSession.h3
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp20
-rw-r--r--src/server/game/Spells/SpellMgr.cpp15
-rw-r--r--src/server/game/Texts/CreatureTextMgr.cpp13
20 files changed, 192 insertions, 418 deletions
diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h
index 378d3ca18ab..838171a544e 100644
--- a/src/server/game/AI/CreatureAIImpl.h
+++ b/src/server/game/AI/CreatureAIImpl.h
@@ -311,355 +311,6 @@ const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, c
}
}
-class EventMap
-{
- /**
- * Internal storage type.
- * Key: Time as uint32 when the event should occur.
- * Value: The event data as uint32.
- *
- * Structure of event data:
- * - Bit 0 - 15: Event Id.
- * - Bit 16 - 23: Group
- * - Bit 24 - 31: Phase
- * - Pattern: 0xPPGGEEEE
- */
- typedef std::multimap<uint32, uint32> EventStore;
-
- public:
- EventMap() : _time(0), _phase(0), _lastEvent(0) { }
-
- /**
- * @name Reset
- * @brief Removes all scheduled events and resets time and phase.
- */
- void Reset()
- {
- _eventMap.clear();
- _time = 0;
- _phase = 0;
- }
-
- /**
- * @name Update
- * @brief Updates the timer of the event map.
- * @param time Value to be added to time.
- */
- void Update(uint32 time)
- {
- _time += time;
- }
-
- /**
- * @name GetTimer
- * @return Current timer value.
- */
- uint32 GetTimer() const
- {
- return _time;
- }
-
- /**
- * @name GetPhaseMask
- * @return Active phases as mask.
- */
- uint8 GetPhaseMask() const
- {
- return _phase;
- }
-
- /**
- * @name Empty
- * @return True, if there are no events scheduled.
- */
- bool Empty() const
- {
- return _eventMap.empty();
- }
-
- /**
- * @name SetPhase
- * @brief Sets the phase of the map (absolute).
- * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
- */
- void SetPhase(uint8 phase)
- {
- if (!phase)
- _phase = 0;
- else if (phase <= 8)
- _phase = (1 << (phase - 1));
- }
-
- /**
- * @name AddPhase
- * @brief Activates the given phase (bitwise).
- * @param phase Phase which should be activated. Values: 1 - 8
- */
- void AddPhase(uint8 phase)
- {
- if (phase && phase <= 8)
- _phase |= (1 << (phase - 1));
- }
-
- /**
- * @name RemovePhase
- * @brief Deactivates the given phase (bitwise).
- * @param phase Phase which should be deactivated. Values: 1 - 8.
- */
- void RemovePhase(uint8 phase)
- {
- if (phase && phase <= 8)
- _phase &= ~(1 << (phase - 1));
- }
-
- /**
- * @name ScheduleEvent
- * @brief Creates new event entry in map.
- * @param eventId The id of the new event.
- * @param time The time in milliseconds until the event occurs.
- * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
- * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
- */
- void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
- {
- if (group && group <= 8)
- eventId |= (1 << (group + 15));
-
- if (phase && phase <= 8)
- eventId |= (1 << (phase + 23));
-
- _eventMap.insert(EventStore::value_type(_time + time, eventId));
- }
-
- /**
- * @name RescheduleEvent
- * @brief Cancels the given event and reschedules it.
- * @param eventId The id of the event.
- * @param time The time in milliseconds until the event occurs.
- * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
- * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
- */
- void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
- {
- CancelEvent(eventId);
- ScheduleEvent(eventId, time, group, phase);
- }
-
- /**
- * @name RepeatEvent
- * @brief Repeats the mostly recently executed event.
- * @param time Time until the event occurs.
- */
- void Repeat(uint32 time)
- {
- _eventMap.insert(EventStore::value_type(_time + time, _lastEvent));
- }
-
- /**
- * @name RepeatEvent
- * @brief Repeats the mostly recently executed event.
- * @param time Time until the event occurs. Equivalent to Repeat(urand(minTime, maxTime).
- */
- void Repeat(uint32 minTime, uint32 maxTime)
- {
- Repeat(urand(minTime, maxTime));
- }
-
- /**
- * @name ExecuteEvent
- * @brief Returns the next event to execute and removes it from map.
- * @return Id of the event to execute.
- */
- uint32 ExecuteEvent()
- {
- while (!Empty())
- {
- EventStore::iterator itr = _eventMap.begin();
-
- if (itr->first > _time)
- return 0;
- else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
- _eventMap.erase(itr);
- else
- {
- uint32 eventId = (itr->second & 0x0000FFFF);
- _lastEvent = itr->second; // include phase/group
- _eventMap.erase(itr);
- return eventId;
- }
- }
-
- return 0;
- }
-
- /**
- * @name DelayEvents
- * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
- * @param delay Amount of delay.
- */
- void DelayEvents(uint32 delay)
- {
- _time = delay < _time ? _time - delay : 0;
- }
-
- /**
- * @name DelayEvents
- * @brief Delay all events of the same group.
- * @param delay Amount of delay.
- * @param group Group of the events.
- */
- void DelayEvents(uint32 delay, uint32 group)
- {
- if (!group || group > 8 || Empty())
- return;
-
- EventStore delayed;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (itr->second & (1 << (group + 15)))
- {
- delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
- _eventMap.erase(itr++);
- }
- else
- ++itr;
- }
-
- _eventMap.insert(delayed.begin(), delayed.end());
- }
-
- /**
- * @name CancelEvent
- * @brief Cancels all events of the specified id.
- * @param eventId Event id to cancel.
- */
- void CancelEvent(uint32 eventId)
- {
- if (Empty())
- return;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (eventId == (itr->second & 0x0000FFFF))
- _eventMap.erase(itr++);
- else
- ++itr;
- }
- }
-
- /**
- * @name CancelEventGroup
- * @brief Cancel events belonging to specified group.
- * @param group Group to cancel.
- */
- void CancelEventGroup(uint32 group)
- {
- if (!group || group > 8 || Empty())
- return;
-
- for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
- {
- if (itr->second & (1 << (group + 15)))
- _eventMap.erase(itr++);
- else
- ++itr;
- }
- }
-
- /**
- * @name GetNextEventTime
- * @brief Returns closest occurence of specified event.
- * @param eventId Wanted event id.
- * @return Time of found event.
- */
- uint32 GetNextEventTime(uint32 eventId) const
- {
- if (Empty())
- return 0;
-
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first;
-
- return 0;
- }
-
- /**
- * @name GetNextEventTime
- * @return Time of next event.
- */
- uint32 GetNextEventTime() const
- {
- return Empty() ? 0 : _eventMap.begin()->first;
- }
-
- /**
- * @name IsInPhase
- * @brief Returns wether event map is in specified phase or not.
- * @param phase Wanted phase.
- * @return True, if phase of event map contains specified phase.
- */
- bool IsInPhase(uint8 phase)
- {
- return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
- }
-
- /**
- * @name GetTimeUntilEvent
- * @brief Returns time in milliseconds until next event.
- * @param Id of the event.
- * @return Time of next event.
- */
- uint32 GetTimeUntilEvent(uint32 eventId) const
- {
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first - _time;
-
- return std::numeric_limits<uint32>::max();
- }
-
- private:
- /**
- * @name _time
- * @brief Internal timer.
- *
- * This does not represent the real date/time value.
- * It's more like a stopwatch: It can run, it can be stopped,
- * it can be resetted and so on. Events occur when this timer
- * has reached their time value. Its value is changed in the
- * Update method.
- */
- uint32 _time;
-
- /**
- * @name _phase
- * @brief Phase mask of the event map.
- *
- * Contains the phases the event map is in. Multiple
- * phases from 1 to 8 can be set with SetPhase or
- * AddPhase. RemovePhase deactives a phase.
- */
- uint8 _phase;
-
- /**
- * @name _eventMap
- * @brief Internal event storage map. Contains the scheduled events.
- *
- * See typedef at the beginning of the class for more
- * details.
- */
- EventStore _eventMap;
-
-
- /**
- * @name _lastEvent
- * @brief Stores information on the most recently executed event
- */
- uint32 _lastEvent;
-};
-
enum AITarget
{
AITARGET_SELF,
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index c21d730b04c..9e72a124ae0 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -513,7 +513,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
data << uint32(quest->GetRewHonorAddition());
data << float(quest->GetRewHonorMultiplier());
data << uint32(quest->GetSrcItemId()); // source item id
- data << uint32(quest->GetFlags() & 0xFFFF); // quest flags
+ data << uint32(quest->GetFlags()); // quest flags
data << uint32(quest->GetMinimapTargetMark()); // minimap target mark (skull, etc. missing enum)
data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
data << uint32(quest->GetPlayersSlain()); // players slain
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 9b931f0ba6a..d07c3cb4bad 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -1413,6 +1413,7 @@ void GameObject::Use(Unit* user)
// prevent removing GO at spell cancel
RemoveFromOwner();
SetOwnerGUID(player->GetGUID());
+ SetSpellId(0); // prevent removing unintended auras at Unit::RemoveGameObject
/// @todo find reasonable value for fishing hole search
GameObject* ok = LookupFishingHoleAround(20.0f + CONTACT_DISTANCE);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index b1d0cc88cde..283d4ead1a7 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14846,7 +14846,7 @@ void Player::SendPreparedQuest(uint64 guid)
if (quest->IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true))
AddQuestAndCheckCompletion(quest, object);
- if ((quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) || quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
+ if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, CanCompleteRepeatableQuest(quest), true);
else
PlayerTalkClass->SendQuestGiverQuestDetails(quest, guid, true);
@@ -14914,7 +14914,7 @@ Quest const* Player::GetNextQuest(uint64 guid, Quest const* quest)
switch (GUID_HIPART(guid))
{
case HIGHGUID_PLAYER:
- ASSERT(quest->HasFlag(QUEST_FLAGS_AUTO_SUBMIT));
+ ASSERT(quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE));
return sObjectMgr->GetQuestTemplate(nextQuestID);
case HIGHGUID_UNIT:
case HIGHGUID_PET:
@@ -15015,7 +15015,7 @@ bool Player::CanCompleteQuest(uint32 quest_id)
return false; // not allow re-complete quest
// auto complete quest
- if ((qInfo->IsAutoComplete() || qInfo->GetFlags() & QUEST_FLAGS_AUTOCOMPLETE) && CanTakeQuest(qInfo, false))
+ if (qInfo->IsAutoComplete() && CanTakeQuest(qInfo, false))
return true;
QuestStatusMap::iterator itr = m_QuestStatus.find(quest_id);
@@ -15095,7 +15095,7 @@ bool Player::CanCompleteRepeatableQuest(Quest const* quest)
bool Player::CanRewardQuest(Quest const* quest, bool msg)
{
// not auto complete quest and not completed quest (only cheating case, then ignore without message)
- if (!quest->IsDFQuest() && !quest->IsAutoComplete() && !(quest->GetFlags() & QUEST_FLAGS_AUTOCOMPLETE) && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE)
+ if (!quest->IsDFQuest() && !quest->IsAutoComplete() && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE)
return false;
// daily quest can't be rewarded (25 daily quest already completed)
@@ -16450,9 +16450,7 @@ void Player::ItemAddedQuestCheck(uint32 entry, uint32 count)
uint16 curitemcount = q_status.ItemCount[j];
if (curitemcount < reqitemcount)
{
- uint16 additemcount = curitemcount + count <= reqitemcount ? count : reqitemcount - curitemcount;
- q_status.ItemCount[j] += additemcount;
-
+ q_status.ItemCount[j] = std::min<uint16>(q_status.ItemCount[j] + count, reqitemcount);
m_QuestStatusSave[questid] = true;
//SendQuestUpdateAddItem(qInfo, j, additemcount);
@@ -16474,9 +16472,11 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count)
uint32 questid = GetQuestSlotQuestId(i);
if (!questid)
continue;
+
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
if (!qInfo)
continue;
+
if (!qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
continue;
@@ -16488,18 +16488,17 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count)
QuestStatusData& q_status = m_QuestStatus[questid];
uint32 reqitemcount = qInfo->RequiredItemCount[j];
- uint16 curitemcount;
- if (q_status.Status != QUEST_STATUS_COMPLETE)
- curitemcount = q_status.ItemCount[j];
- else
- curitemcount = GetItemCount(entry, true);
- if (curitemcount < reqitemcount + count)
- {
- uint16 remitemcount = curitemcount <= reqitemcount ? count : count + reqitemcount - curitemcount;
- q_status.ItemCount[j] = (curitemcount <= remitemcount) ? 0 : curitemcount - remitemcount;
+ uint16 curitemcount = q_status.ItemCount[j];
- m_QuestStatusSave[questid] = true;
+ if (q_status.ItemCount[j] >= reqitemcount) // we may have more than what the status shows
+ curitemcount = GetItemCount(entry, false);
+ uint16 newItemCount = (count > curitemcount) ? 0 : curitemcount - count;
+ newItemCount = std::min<uint16>(newItemCount, reqitemcount);
+ if (newItemCount != q_status.ItemCount[j])
+ {
+ q_status.ItemCount[j] = newItemCount;
+ m_QuestStatusSave[questid] = true;
IncompleteQuest(questid);
}
return;
@@ -27573,6 +27572,11 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
return pet;
}
+bool Player::IsLoading() const
+{
+ return GetSession()->PlayerLoading();
+}
+
bool Player::CanUseMastery() const
{
return HasSpell(MasterySpells[getClass()]);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 1758ed20808..3d0300a681b 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1894,7 +1894,7 @@ class Player : public Unit, public GridObject<Player>
void UpdateZone(uint32 newZone, uint32 newArea);
void UpdateArea(uint32 newArea);
void SetNeedsZoneUpdate(bool needsUpdate) { m_needsZoneUpdate = needsUpdate; }
-
+
void UpdateZoneDependentAuras(uint32 zone_id); // zones
void UpdateAreaDependentAuras(uint32 area_id); // subzones
@@ -2523,6 +2523,8 @@ class Player : public Unit, public GridObject<Player>
std::string GetMapAreaAndZoneString();
std::string GetCoordsMapAreaAndZoneString();
+ bool IsLoading() const;
+
// Void Storage
bool IsVoidStorageUnlocked() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); }
void UnlockVoidStorage() { SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); }
@@ -2813,7 +2815,7 @@ class Player : public Unit, public GridObject<Player>
bool IsAlwaysDetectableFor(WorldObject const* seer) const;
uint8 m_grantableLevels;
-
+
bool m_needsZoneUpdate;
CUFProfile* _CUFProfiles[MAX_CUF_PROFILES];
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 7c042dad0c1..31425faf584 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -9473,8 +9473,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
// Check for immune to application of harmful magical effects
AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
- if (spellInfo->Dispel == DISPEL_MAGIC && // Magic debuff
- ((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
+ if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
!spellInfo->IsPositiveEffect(index)) // Harmful
return true;
}
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index b72d79539aa..741dec9bfec 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -87,6 +87,18 @@ void WorldSession::HandleSwapInvItemOpcode(WorldPacket& recvData)
return;
}
+ if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, srcslot) && !CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleSwapInvItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
+ if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, dstslot) && !CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleSwapInvItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
@@ -139,6 +151,18 @@ void WorldSession::HandleSwapItem(WorldPacket& recvData)
return;
}
+ if (_player->IsBankPos(srcbag, srcslot) && !CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleSwapItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
+ if (_player->IsBankPos(dstbag, dstslot) && !CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleSwapItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
_player->SwapItem(src, dst);
}
@@ -780,15 +804,11 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket)
uint64 guid;
recvPacket >> guid;
- // cheating protection
- /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command.
- Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER);
- if (!creature)
+ if (!CanUseBank(guid))
{
- TC_LOG_DEBUG("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
+ TC_LOG_DEBUG("network", "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
return;
}
- */
uint32 slot = _player->GetBankBagSlotCount();
@@ -834,6 +854,12 @@ void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket)
recvPacket >> srcbag >> srcslot;
TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
+ if (!CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleAutoBankItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
if (!pItem)
return;
@@ -865,6 +891,12 @@ void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket)
recvPacket >> srcbag >> srcslot;
TC_LOG_DEBUG("network", "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot);
+ if (!CanUseBank())
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleAutoStoreBankItemOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(m_currentBankerGUID)));
+ return;
+ }
+
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
if (!pItem)
return;
@@ -1463,6 +1495,12 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData)
}
else
{
+ if (itemTransmogrifier->GetEntry() != newEntries[i])
+ {
+ TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid entry (entry: %u) for item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), newEntries[i], GUID_LOPART(itemGuids[i]));
+ return;
+ }
+
if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, itemTransmogrifier))
{
TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
@@ -1549,6 +1587,13 @@ void WorldSession::HandleReforgeItemOpcode(WorldPacket& recvData)
if (!reforgeEntry)
{
+ if (!item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT))
+ {
+ TC_LOG_ERROR("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to remove reforge from non-reforged item (Entry: %u)", player->GetGUIDLow(), player->GetName().c_str(), item->GetEntry());
+ SendReforgeResult(false);
+ return;
+ }
+
// Reset the item
if (item->IsEquipped())
player->ApplyReforgeEnchantment(item, false);
@@ -1557,6 +1602,13 @@ void WorldSession::HandleReforgeItemOpcode(WorldPacket& recvData)
return;
}
+ if (item->GetEnchantmentId(REFORGE_ENCHANTMENT_SLOT))
+ {
+ TC_LOG_ERROR("network", "WORLD: HandleReforgeItemOpcode - Player (Guid: %u Name: %s) tried to reforge an already reforged item (Entry: %u)", player->GetGUIDLow(), player->GetName().c_str(), item->GetEntry());
+ SendReforgeResult(false);
+ return;
+ }
+
ItemReforgeEntry const* stats = sItemReforgeStore.LookupEntry(reforgeEntry);
if (!stats)
{
@@ -1586,3 +1638,21 @@ void WorldSession::HandleReforgeItemOpcode(WorldPacket& recvData)
if (item->IsEquipped())
player->ApplyReforgeEnchantment(item, true);
}
+
+bool WorldSession::CanUseBank(uint64 bankerGUID) const
+{
+ // bankerGUID parameter is optional, set to 0 by default.
+ if (!bankerGUID)
+ bankerGUID = m_currentBankerGUID;
+
+ bool isUsingBankCommand = (bankerGUID == GetPlayer()->GetGUID() && bankerGUID == m_currentBankerGUID);
+
+ if (!isUsingBankCommand)
+ {
+ Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(bankerGUID, UNIT_NPC_FLAG_BANKER);
+ if (!creature)
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 1d4c2f57311..3b5f9e16637 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -496,7 +496,7 @@ void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recvData)
// use server side data, but only after update the player position. See Player::UpdatePosition().
GetPlayer()->SetNeedsZoneUpdate(true);
-
+
//GetPlayer()->SendInitWorldStates(true, newZone);
}
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 59ab27968f4..0a77a941b5f 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -101,6 +101,7 @@ void WorldSession::SendShowBank(uint64 guid)
{
WorldPacket data(SMSG_SHOW_BANK, 8);
data << guid;
+ m_currentBankerGUID = guid;
SendPacket(&data);
}
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 974f06975fa..301e9a7d2c8 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -874,7 +874,10 @@ void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData)
uint32 talentId, talentRank;
- for (uint32 i = 0; i < talentsCount; ++i)
+ // Client has max 19 talents, rounded up : 25
+ uint32 const MaxTalentsCount = 25;
+
+ for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i)
{
recvData >> talentId >> talentRank;
@@ -882,4 +885,6 @@ void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData)
}
_player->SendTalentsInfoData(true);
+
+ recvData.rfinish();
}
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index 206238cbea2..19473edb6b4 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -273,7 +273,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
Object* object = _player;
- if (!quest->HasFlag(QUEST_FLAGS_AUTO_SUBMIT))
+ if (!quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
{
object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if (!object || !object->hasInvolvedQuest(questId))
@@ -469,26 +469,43 @@ void WorldSession::HandleQuestConfirmAccept(WorldPacket& recvData)
void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData)
{
uint32 questId;
- uint64 playerGuid;
+ uint64 guid; // NPC / GameObject guid for normal quest completion. Player guid for self-completed quests
bool autoCompleteMode; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
- recvData >> playerGuid >> questId >> autoCompleteMode;
+ recvData >> guid >> questId >> autoCompleteMode;
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, questId = %u", uint32(GUID_LOPART(playerGuid)), questId);
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, questId = %u self-complete: %u", uint32(GUID_LOPART(guid)), questId, autoCompleteMode ? 1 : 0);
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
if (!quest)
return;
- Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, playerGuid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
- if (!object || !object->hasInvolvedQuest(questId))
+ if (autoCompleteMode && !quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
+ return;
+
+ Object* object = nullptr;
+ if (autoCompleteMode)
+ object = _player;
+ else
+ object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
+
+ if (!object)
return;
if (autoCompleteMode == 0)
{
+ if (!object->hasInvolvedQuest(questId))
+ return;
+
// some kind of WPE protection
if (!_player->CanInteractWithQuestGiver(object))
return;
}
+ else
+ {
+ // Do not allow completing quests on other players.
+ if (guid != _player->GetGUID())
+ return;
+ }
if (!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE)
{
@@ -503,16 +520,16 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData)
if (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE)
{
if (quest->IsRepeatable())
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, playerGuid, _player->CanCompleteRepeatableQuest(quest), false);
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanCompleteRepeatableQuest(quest), false);
else
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, playerGuid, _player->CanRewardQuest(quest, false), false);
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
}
else
{
if (quest->GetReqItemsCount()) // some items required
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, playerGuid, _player->CanRewardQuest(quest, false), false);
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
else // no items required
- _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, playerGuid, true);
+ _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
}
if (Creature* creature = object->ToCreature())
@@ -586,7 +603,7 @@ void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket)
if (quest->IsAutoAccept() && receiver->CanAddQuest(quest, true) && receiver->CanTakeQuest(quest, true))
receiver->AddQuestAndCheckCompletion(quest, sender);
- if ((quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) || quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
+ if (quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
receiver->PlayerTalkClass->SendQuestGiverRequestItems(quest, sender->GetGUID(), receiver->CanCompleteRepeatableQuest(quest), true);
else
{
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index 2108b654d6b..67c36b1940e 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -61,7 +61,10 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
uint32 talentId, talentRank;
- for (uint32 i = 0; i < talentsCount; ++i)
+ // Client has max 21 talents for tree for 3 trees, rounded up : 70
+ uint32 const MaxTalentsCount = 70;
+
+ for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i)
{
recvPacket >> talentId >> talentRank;
@@ -73,6 +76,8 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
}
_player->SendTalentsInfoData(false);
+
+ recvPacket.rfinish();
}
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 3dbc4e99e52..92467487525 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2879,10 +2879,9 @@ bool InstanceMap::CanEnter(Player* player)
return false;
}
- // cannot enter while an encounter is in progress on raids
- /*Group* group = player->GetGroup();
- if (!player->IsGameMaster() && group && group->InCombatToInstance(GetInstanceId()) && player->GetMapId() != GetId())*/
- if (IsRaid() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
+ // cannot enter while an encounter is in progress
+ // allow if just loading
+ if (!player->IsLoading() && IsRaid() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
{
player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
return false;
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index 9a17175b1a8..5f811714f3a 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -326,7 +326,7 @@ bool Quest::IsAutoAccept() const
bool Quest::IsAutoComplete() const
{
- return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) ? false : (Method == 0 || HasFlag(QUEST_FLAGS_AUTOCOMPLETE));
+ return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) || (Method == 0);
}
bool Quest::IsRaidQuest(Difficulty difficulty) const
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 4ab41ba13f8..3a9fdf024bf 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -147,11 +147,11 @@ enum QuestFlags
QUEST_FLAGS_FLAGS_PVP = 0x00002000, // Having this quest in log forces PvP flag
QUEST_FLAGS_UNAVAILABLE = 0x00004000, // Used on quests that are not generically available
QUEST_FLAGS_WEEKLY = 0x00008000,
- QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // auto complete
+ QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // Quests with this flag player submit automatically by special button in player gui
QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x00020000, // Displays usable item in quest tracker
QUEST_FLAGS_OBJ_TEXT = 0x00040000, // use Objective text as Complete text
QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // The client recognizes this flag as auto-accept. However, NONE of the current quests (3.3.5a) have this flag. Maybe blizz used to use it, or will use it in the future.
- QUEST_FLAGS_AUTO_SUBMIT = 0x00100000, // Quests with this flag player submit automatically by special button in player gui
+ QUEST_FLAGS_UNK1 = 0x00100000, //
QUEST_FLAGS_AUTO_TAKE = 0x00200000, // Automatically suggestion of accepting quest. Not from npc.
//QUEST_FLAGS_UNK2 = 0x00400000,
//QUEST_FLAGS_UNK3 = 0x00800000, // Found in quest 14069
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index e40470c5cdb..201235b4a40 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -126,7 +126,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8
isRecruiter(isARecruiter),
_RBACData(NULL),
expireTime(60000), // 1 min after socket loss, session is deleted
- forceExit(false)
+ forceExit(false),
+ m_currentBankerGUID(0)
{
memset(m_Tutorials, 0, sizeof(m_Tutorials));
@@ -1199,11 +1200,11 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
if (++packetCounter.amountCounter > maxPacketCounterAllowed)
{
dosTriggered = true;
- TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
- Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetPlayerName().c_str(),
+ TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
+ Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(),
opcodeTable[p.GetOpcode()]->Name, p.GetOpcode(), packetCounter.amountCounter);
}
-
+
// Then check if player is sending packets not allowed
if (!IsOpcodeAllowed(p.GetOpcode()))
{
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 9e6f52ac8dd..3eb9f5cb3c5 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -1032,6 +1032,8 @@ class WorldSession
// private trade methods
void moveItems(Item* myItems[], Item* hisItems[]);
+ bool CanUseBank(uint64 bankerGUID = 0) const;
+
// logging helper
void LogUnexpectedOpcode(WorldPacket* packet, const char* status, const char *reason);
void LogUnprocessedTail(WorldPacket* packet);
@@ -1083,6 +1085,7 @@ class WorldSession
rbac::RBACData* _RBACData;
uint32 expireTime;
bool forceExit;
+ uint64 m_currentBankerGUID;
WorldSession(WorldSession const& right) = delete;
WorldSession& operator=(WorldSession const& right) = delete;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 94295878c4f..c767d4da9ed 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1756,9 +1756,6 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
if (aurApp->GetRemoveMode())
return;
- if (modelid > 0)
- target->SetDisplayId(modelid);
-
if (PowerType != POWER_MANA)
{
int32 oldPower = target->GetPower(PowerType);
@@ -1788,6 +1785,12 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
return;
target->SetShapeshiftForm(form);
+ if (modelid > 0)
+ {
+ SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm());
+ if (!transformSpellInfo || !GetSpellInfo()->IsPositive())
+ target->SetDisplayId(modelid);
+ }
}
else
{
@@ -1907,9 +1910,11 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode,
if (apply)
{
- // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case
- if (!target->GetModelForForm(target->GetShapeshiftForm()) || !GetSpellInfo()->IsPositive())
+ // update active transform spell only when transform not set or not overwriting negative by positive case
+ SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm());
+ if (!transformSpellInfo || !GetSpellInfo()->IsPositive() || transformSpellInfo->IsPositive())
{
+ target->setTransForm(GetId());
// special case (spell specific functionality)
if (GetMiscValue() == 0)
{
@@ -2078,11 +2083,6 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode,
}
}
- // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case
- SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm());
- if (!transformSpellInfo || !GetSpellInfo()->IsPositive() || transformSpellInfo->IsPositive())
- target->setTransForm(GetId());
-
// polymorph case
if ((mode & AURA_EFFECT_HANDLE_REAL) && target->GetTypeId() == TYPEID_PLAYER && target->IsPolymorphed())
{
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 218f7b5a37d..277d2b701c4 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -787,14 +787,14 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
bool hasFamilyMask = false;
- /**
-
+ /**
+
* @brief Check auras procced by periodics
*Only damaging Dots can proc auras with PROC_FLAG_TAKEN_DAMAGE
*Only Dots can proc if ONLY has PROC_FLAG_DONE_PERIODIC or PROC_FLAG_TAKEN_PERIODIC.
-
+
*Hots can proc if ONLY has PROC_FLAG_DONE_PERIODIC and spellfamily != 0
*Only Dots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
@@ -809,7 +809,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
* @param procFlags proc_flags of spellProc
* @param procExtra proc_EX of procSpell
* @param EventProcFlag proc_flags of aura to be procced
- * @param spellProto SpellInfo of aura to be procced
+ * @param spellProto SpellInfo of aura to be procced
*/
@@ -818,7 +818,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
return true;
if (procFlags & PROC_FLAG_DONE_PERIODIC && EventProcFlag & PROC_FLAG_DONE_PERIODIC)
- {
+ {
if (procExtra & PROC_EX_INTERNAL_HOT)
{
if (EventProcFlag == PROC_FLAG_DONE_PERIODIC)
@@ -838,7 +838,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell
}
if (procFlags & PROC_FLAG_TAKEN_PERIODIC && EventProcFlag & PROC_FLAG_TAKEN_PERIODIC)
- {
+ {
if (procExtra & PROC_EX_INTERNAL_HOT)
{
/// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT.
@@ -3395,6 +3395,9 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd
spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd
break;
+ case 72830: // Achievement Check
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
+ break;
case 72900: // Start Halls of Reflection Quest AE
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
break;
diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp
index 35f5cb82036..3fbbd34777b 100644
--- a/src/server/game/Texts/CreatureTextMgr.cpp
+++ b/src/server/game/Texts/CreatureTextMgr.cpp
@@ -24,6 +24,7 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CreatureTextMgr.h"
+#include "Group.h"
class CreatureTextBuilder
{
@@ -347,6 +348,18 @@ void CreatureTextMgr::SendNonChatPacket(WorldObject* source, WorldPacket* data,
}
break;
}
+ case CHAT_MSG_MONSTER_PARTY:
+ if (!whisperTarget)
+ return;
+
+ if (Player const* player = whisperTarget->ToPlayer())
+ {
+ if (Group* group = const_cast<Group*>(player->GetGroup()))
+ for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ if (Player* member = itr->GetSource())
+ member->GetSession()->SendPacket(data);
+ }
+ return;
default:
break;
}