aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxinef1 <w.szyszko2@gmail.com>2017-02-04 22:37:16 +0100
committerShauren <shauren.trinity@gmail.com>2019-07-21 21:06:54 +0200
commitad008c43b75080ec59aa973f1e2e4424332c34a4 (patch)
treef5b7e98e0fc47a25246ce999e15d6f413b8018ab /src
parent92e95ddf558db5fdcdf3c54ecd1d694da92c3a44 (diff)
Core/Misc: Fix various crashes, also related to multithreading (#19012)
* When iterating groups we have to either do it not in multithreaded context (map updates) or start with checking maps (they are guaranteed to change in single thread update). * Properly clear ComboPoint references on player remove * remove some possible references item may have when it is deleted during save. * Also clear all hostile references when unit is removed from map. (cherrypicked from 86da1a19bb36edf3242dafac6e45e87434ddff73)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp2
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp3
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp7
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp5
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp6
-rw-r--r--src/server/game/Combat/ThreatManager.h1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp4
-rw-r--r--src/server/game/Entities/Player/KillRewarder.cpp5
-rw-r--r--src/server/game/Entities/Player/Player.cpp30
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp16
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp2
-rw-r--r--src/server/game/Groups/Group.cpp166
-rw-r--r--src/server/game/Groups/Group.h4
-rw-r--r--src/server/game/Loot/Loot.cpp3
-rw-r--r--src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp6
-rw-r--r--src/server/scripts/Outland/zone_terokkar_forest.cpp2
20 files changed, 159 insertions, 110 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index bd9a0fdf5d5..1124edcfc81 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -282,7 +282,7 @@ void PetAI::UpdateAllies()
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* Target = itr->GetSource();
- if (!Target || !group->SameSubGroup(owner->ToPlayer(), Target))
+ if (!Target || !Target->IsInMap(owner) || !group->SameSubGroup(owner->ToPlayer(), Target))
continue;
if (Target->GetGUID() == owner->GetGUID())
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 0128a8d55a1..1dda5017208 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -126,7 +126,8 @@ void npc_escortAI::JustDied(Unit* /*killer*/)
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
- member->FailQuest(m_pQuestForEscort->GetQuestId());
+ if (member->IsInMap(player))
+ member->FailQuest(m_pQuestForEscort->GetQuestId());
}
else
player->FailQuest(m_pQuestForEscort->GetQuestId());
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 07294655449..8d2803b10b7 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -152,7 +152,8 @@ void FollowerAI::JustDied(Unit* /*killer*/)
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
- member->FailQuest(m_pQuestForFollow->GetQuestId());
+ if (member->IsInMap(player))
+ member->FailQuest(m_pQuestForFollow->GetQuestId());
}
else
player->FailQuest(m_pQuestForFollow->GetQuestId());
@@ -230,7 +231,6 @@ void FollowerAI::UpdateAI(uint32 uiDiff)
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
{
Player* member = groupRef->GetSource();
-
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE))
{
bIsMaxRangeExceeded = false;
@@ -338,8 +338,7 @@ Player* FollowerAI::GetLeaderForFollower()
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
{
Player* member = groupRef->GetSource();
-
- if (member && member->IsAlive() && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE))
+ if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE) && member->IsAlive())
{
TC_LOG_DEBUG("scripts", "FollowerAI GetLeader changed and returned new leader.");
m_uiLeaderGUID = member->GetGUID();
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index acd2f794bca..96ed78b08de 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -243,6 +243,8 @@ void SmartAI::EndPath(bool fail)
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
{
Player* groupGuy = groupRef->GetSource();
+ if (!groupGuy->IsInMap(player))
+ continue;
if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse())
groupGuy->AreaExploredOrEventHappens(mEscortQuestID);
@@ -411,8 +413,7 @@ bool SmartAI::IsEscortInvokerInRange()
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
{
Player* groupGuy = groupRef->GetSource();
-
- if (me->GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
+ if (groupGuy->IsInMap(player) && me->GetDistance(groupGuy) <= SMART_ESCORT_MAX_PLAYER_DIST)
return true;
}
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index f5026728012..be37c0e671e 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2831,7 +2831,8 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
- l->push_back(member);
+ if (member->IsInMap(player))
+ l->push_back(member);
}
// We still add the player to the list if there is no group. If we do
// this even if there is a group (thus the else-check), it will add the
@@ -3048,7 +3049,8 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
{
for (GroupReference* it = lootGroup->GetFirstMember(); it != nullptr; it = it->next())
if (Player* recipient = it->GetSource())
- l->push_back(recipient);
+ if (recipient->IsInMap(me))
+ l->push_back(recipient);
}
else
{
diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h
index a0678613fe0..61e9fcb60fb 100644
--- a/src/server/game/Combat/ThreatManager.h
+++ b/src/server/game/Combat/ThreatManager.h
@@ -221,6 +221,7 @@ class TC_GAME_API ThreatManager
float getThreat(Unit* victim, bool alsoSearchOfflineList = false);
bool isThreatListEmpty() const { return iThreatContainer.empty(); }
+ bool areThreatListsEmpty() const { return iThreatContainer.empty() && iThreatOfflineContainer.empty(); }
void processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent);
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index e8a5eafe527..5a97aec51ea 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -554,7 +554,7 @@ void Creature::Update(uint32 diff)
if (m_groupLootTimer <= diff)
{
if (Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID))
- group->EndRoll(&loot);
+ group->EndRoll(&loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index a2e58bccdd2..1fb30cb49a2 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -714,7 +714,7 @@ void GameObject::Update(uint32 diff)
if (m_groupLootTimer <= diff)
{
if (Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID))
- group->EndRoll(&loot);
+ group->EndRoll(&loot, GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
@@ -1441,7 +1441,7 @@ void GameObject::Use(Unit* user)
if (!itr->second.IsEmpty())
{
- if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
+ if (Player* ChairUser = ObjectAccessor::GetPlayer(*this, itr->second))
{
if (ChairUser->IsSitState() && ChairUser->GetStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required.
diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp
index 2c0ddc20fba..5250dc6bfa5 100644
--- a/src/server/game/Entities/Player/KillRewarder.cpp
+++ b/src/server/game/Entities/Player/KillRewarder.cpp
@@ -94,7 +94,7 @@ inline void KillRewarder::_InitGroupData()
// 2. In case when player is in group, initialize variables necessary for group calculations:
for (GroupReference* itr = _group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
- if (member->IsAlive() && member->IsAtGroupRewardDistance(_victim))
+ if (_killer == member || (member->IsAtGroupRewardDistance(_victim) && member->IsAlive()))
{
const uint8 lvl = member->getLevel();
// 2.1. _count - number of alive group members within reward distance;
@@ -240,7 +240,8 @@ void KillRewarder::_RewardGroup()
{
if (Player* member = itr->GetSource())
{
- if (member->IsAtGroupRewardDistance(_victim))
+ // Killer may not be at reward distance, check directly
+ if (_killer == member || member->IsAtGroupRewardDistance(_victim))
{
_RewardPlayer(member, isDungeon);
member->UpdateCriteria(CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, 0, _victim);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 6df63e2c386..c668944d843 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1742,6 +1742,7 @@ void Player::RemoveFromWorld()
StopCastingCharm();
StopCastingBindSight();
UnsummonPetTemporaryIfAny();
+ ClearComboPoints();
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
}
@@ -13684,6 +13685,17 @@ void Player::RemoveEnchantmentDurations(Item* item)
}
}
+void Player::RemoveEnchantmentDurationsReferences(Item* item)
+{
+ for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end();)
+ {
+ if (itr->item == item)
+ itr = m_enchantDuration.erase(itr);
+ else
+ ++itr;
+ }
+}
+
void Player::RemoveArenaEnchantments(EnchantmentSlot slot)
{
// remove enchantments from equipped items first to clean up the m_enchantDuration list
@@ -20477,6 +20489,10 @@ void Player::_SaveInventory(SQLTransaction& trans)
stmt->setUInt64(2, GetGUID().GetCounter());
trans->Append(stmt);
+ RemoveTradeableItem(item);
+ RemoveEnchantmentDurationsReferences(item);
+ RemoveItemDurations(item);
+
// also THIS item should be somewhere else, cheat attempt
item->FSetState(ITEM_REMOVED); // we are IN updateQueue right now, can't use SetState which modifies the queue
DeleteRefundReference(item->GetGUID());
@@ -24892,15 +24908,13 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{
- if (!pRewardSource)
+ if (!pRewardSource || !IsInMap(pRewardSource))
return false;
+
const WorldObject* player = GetCorpse();
if (!player || IsAlive())
player = this;
- if (player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceId() != pRewardSource->GetInstanceId())
- return false;
-
if (player->GetMap()->IsDungeon())
return true;
@@ -24909,15 +24923,13 @@ bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const
{
- if (!pOther)
+ if (!pOther || !IsInMap(pOther))
return false;
+
const WorldObject* player = GetCorpse();
if (!player || IsAlive())
player = this;
- if (player->GetMapId() != pOther->GetMapId() || player->GetInstanceId() != pOther->GetInstanceId())
- return false;
-
return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE);
}
@@ -25150,7 +25162,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid guidMember) const
/// @todo Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer.
for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
- if (itr->GetSource() && itr->GetSource()->IsInCombat())
+ if (itr->GetSource() && itr->GetSource()->IsInMap(this) && itr->GetSource()->IsInCombat())
return ERR_PARTY_LFG_BOOT_IN_COMBAT;
/* Missing support for these types
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index a482ad4c5c1..b027fa928e5 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1263,6 +1263,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void UpdateItemDuration(uint32 time, bool realtimeonly = false);
void AddEnchantmentDurations(Item* item);
void RemoveEnchantmentDurations(Item* item);
+ void RemoveEnchantmentDurationsReferences(Item* item);
void RemoveArenaEnchantments(EnchantmentSlot slot);
void AddEnchantmentDuration(Item* item, EnchantmentSlot slot, uint32 duration);
void ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool apply_dur = true, bool ignore_condition = false);
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 2c17b7fbfb3..17be943b823 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -129,7 +129,7 @@ void Totem::UnSummon(uint32 msTime)
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* target = itr->GetSource();
- if (target && group->SameSubGroup(owner, target))
+ if (target && target->IsInMap(owner) && group->SameSubGroup(owner, target))
target->RemoveAurasDueToSpell(GetSpell(), GetGUID());
}
}
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e046dc17402..9dc36a84021 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -6304,12 +6304,12 @@ Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
if (Player* Target = itr->GetSource())
{
// IsHostileTo check duel and controlled by enemy
- if (Target != this && Target->IsAlive() && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target))
+ if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
nearMembers.push_back(Target);
// Push player's pet to vector
if (Unit* pet = Target->GetGuardianPet())
- if (pet != this && pet->IsAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet))
+ if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
nearMembers.push_back(pet);
}
@@ -9617,7 +9617,7 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup)
m_Events.KillAllEvents(false); // non-delatable (currently cast spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
CombatStop();
DeleteThreatList();
- getHostileRefManager().setOnlineOfflineState(false);
+ getHostileRefManager().deleteReferences();
GetMotionMaster()->Clear(false); // remove different non-standard movement generators.
}
@@ -11859,23 +11859,23 @@ void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
Player* Target = itr->GetSource();
// IsHostileTo check duel and controlled by enemy
- if (Target && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
+ if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
{
- if (Target->IsAlive() && IsInMap(Target))
+ if (Target->IsAlive())
TagUnitMap.push_back(Target);
if (Guardian* pet = Target->GetGuardianPet())
- if (pet->IsAlive() && IsInMap(Target))
+ if (pet->IsAlive())
TagUnitMap.push_back(pet);
}
}
}
else
{
- if (owner->IsAlive() && (owner == this || IsInMap(owner)))
+ if ((owner == this || IsInMap(owner)) && owner->IsAlive())
TagUnitMap.push_back(owner);
if (Guardian* pet = owner->GetGuardianPet())
- if (pet->IsAlive() && (pet == this || IsInMap(pet)))
+ if ((pet == this || IsInMap(pet)) && pet->IsAlive())
TagUnitMap.push_back(pet);
}
}
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index 01928bc5e01..6d1fb267d7f 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -221,7 +221,7 @@ void ObjectGridStoper::Visit(CreatureMapType &m)
iter->GetSource()->RemoveAllDynObjects();
iter->GetSource()->RemoveAllAreaTriggers();
- if (iter->GetSource()->IsInCombat())
+ if (iter->GetSource()->IsInCombat() || !iter->GetSource()->getThreatManager().areThreatListsEmpty())
{
iter->GetSource()->CombatStop();
iter->GetSource()->DeleteThreatList();
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 068502a6bbe..8fa7be7dda9 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -617,7 +617,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R
if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
{
- CountTheRoll(it);
+ CountTheRoll(it, nullptr);
it = RollId.begin();
}
}
@@ -1199,17 +1199,17 @@ void Group::CountRollVote(ObjectGuid playerGuid, ObjectGuid lootObjectGuid, uint
}
if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
- CountTheRoll(rollI);
+ CountTheRoll(rollI, nullptr);
}
//called when roll timer expires
-void Group::EndRoll(Loot* pLoot)
+void Group::EndRoll(Loot* pLoot, Map* allowedMap)
{
for (Rolls::iterator itr = RollId.begin(); itr != RollId.end();)
{
if ((*itr)->getLoot() == pLoot)
{
- CountTheRoll(itr); //i don't have to edit player votes, who didn't vote ... he will pass
+ CountTheRoll(itr, allowedMap); //i don't have to edit player votes, who didn't vote ... he will pass
itr = RollId.begin();
}
else
@@ -1217,7 +1217,7 @@ void Group::EndRoll(Loot* pLoot)
}
}
-void Group::CountTheRoll(Rolls::iterator rollI)
+void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
{
Roll* roll = *rollI;
if (!roll->isValid()) // is loot already deleted ?
@@ -1233,14 +1233,21 @@ void Group::CountTheRoll(Rolls::iterator rollI)
if (!roll->playerVote.empty())
{
uint8 maxresul = 0;
- ObjectGuid maxguid = (*roll->playerVote.begin()).first;
- Player* player;
+ ObjectGuid maxguid = ObjectGuid::Empty;
+ Player* player = nullptr;
for (Roll::PlayerVote::const_iterator itr=roll->playerVote.begin(); itr != roll->playerVote.end(); ++itr)
{
if (itr->second != NEED)
continue;
+ player = ObjectAccessor::FindPlayer(itr->first);
+ if (!player || (allowedMap != nullptr && player->FindMap() != allowedMap))
+ {
+ --roll->totalNeed;
+ continue;
+ }
+
uint8 randomN = urand(1, 100);
SendLootRoll(itr->first, randomN, ROLL_NEED, *roll);
if (maxresul < randomN)
@@ -1249,39 +1256,46 @@ void Group::CountTheRoll(Rolls::iterator rollI)
maxresul = randomN;
}
}
- SendLootRollWon(maxguid, maxresul, ROLL_NEED, *roll);
- player = ObjectAccessor::FindConnectedPlayer(maxguid);
- if (player && player->GetSession())
+ if (!maxguid.IsEmpty())
{
- player->UpdateCriteria(CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul);
+ SendLootRollWon(maxguid, maxresul, ROLL_NEED, *roll);
+ player = ObjectAccessor::FindConnectedPlayer(maxguid);
- ItemPosCountVec dest;
- LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
- InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
- if (msg == EQUIP_ERR_OK)
+ if (player && player->GetSession())
{
- item->is_looted = true;
- roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
- roll->getLoot()->unlootedCount--;
- player->StoreNewItem(dest, roll->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context, item->BonusListIDs);
- }
- else
- {
- item->is_blocked = false;
- item->rollWinnerGUID = player->GetGUID();
- player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
+ player->UpdateCriteria(CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul);
+
+ ItemPosCountVec dest;
+ LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
+ InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
+ if (msg == EQUIP_ERR_OK)
+ {
+ item->is_looted = true;
+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
+ roll->getLoot()->unlootedCount--;
+ player->StoreNewItem(dest, roll->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context, item->BonusListIDs);
+ }
+ else
+ {
+ item->is_blocked = false;
+ item->rollWinnerGUID = player->GetGUID();
+ player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
+ }
}
}
+ else
+ roll->totalNeed = 0;
}
}
- else if (roll->totalGreed > 0)
+
+ if (roll->totalNeed == 0 && roll->totalGreed > 0) // if (roll->totalNeed == 0 && ...), not else if, because numbers can be modified above if player is on a different map
{
if (!roll->playerVote.empty())
{
uint8 maxresul = 0;
- ObjectGuid maxguid = (*roll->playerVote.begin()).first;
- Player* player;
+ ObjectGuid maxguid = ObjectGuid::Empty;
+ Player* player = nullptr;
RollVote rollvote = NOT_VALID;
Roll::PlayerVote::iterator itr;
@@ -1290,6 +1304,13 @@ void Group::CountTheRoll(Rolls::iterator rollI)
if (itr->second != GREED && itr->second != DISENCHANT)
continue;
+ player = ObjectAccessor::FindPlayer(itr->first);
+ if (!player || (allowedMap != NULL && player->FindMap() != allowedMap))
+ {
+ --roll->totalGreed;
+ continue;
+ }
+
uint8 randomN = urand(1, 100);
SendLootRoll(itr->first, randomN, itr->second, *roll);
if (maxresul < randomN)
@@ -1299,64 +1320,71 @@ void Group::CountTheRoll(Rolls::iterator rollI)
rollvote = itr->second;
}
}
- SendLootRollWon(maxguid, maxresul, rollvote, *roll);
- player = ObjectAccessor::FindConnectedPlayer(maxguid);
- if (player && player->GetSession())
+ if (!maxguid.IsEmpty())
{
- player->UpdateCriteria(CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul);
-
- LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
+ SendLootRollWon(maxguid, maxresul, rollvote, *roll);
+ player = ObjectAccessor::FindConnectedPlayer(maxguid);
- if (rollvote == GREED)
+ if (player && player->GetSession())
{
- ItemPosCountVec dest;
- InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
- if (msg == EQUIP_ERR_OK)
+ player->UpdateCriteria(CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul);
+
+ LootItem* item = &(roll->itemSlot >= roll->getLoot()->items.size() ? roll->getLoot()->quest_items[roll->itemSlot - roll->getLoot()->items.size()] : roll->getLoot()->items[roll->itemSlot]);
+
+ if (rollvote == GREED)
+ {
+ ItemPosCountVec dest;
+ InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
+ if (msg == EQUIP_ERR_OK)
+ {
+ item->is_looted = true;
+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
+ roll->getLoot()->unlootedCount--;
+ player->StoreNewItem(dest, roll->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context, item->BonusListIDs);
+ }
+ else
+ {
+ item->is_blocked = false;
+ item->rollWinnerGUID = player->GetGUID();
+ player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
+ }
+ }
+ else if (rollvote == DISENCHANT)
{
item->is_looted = true;
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
roll->getLoot()->unlootedCount--;
- player->StoreNewItem(dest, roll->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context, item->BonusListIDs);
- }
- else
- {
- item->is_blocked = false;
- item->rollWinnerGUID = player->GetGUID();
- player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
- }
- }
- else if (rollvote == DISENCHANT)
- {
- item->is_looted = true;
- roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
- roll->getLoot()->unlootedCount--;
- player->UpdateCriteria(CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant
-
- ItemDisenchantLootEntry const* disenchant = ASSERT_NOTNULL(roll->GetItemDisenchantLoot(player));
+ player->UpdateCriteria(CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant
- ItemPosCountVec dest;
- InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
- if (msg == EQUIP_ERR_OK)
- player->AutoStoreLoot(disenchant->ID, LootTemplates_Disenchant, true);
- else // If the player's inventory is full, send the disenchant result in a mail.
- {
- Loot loot;
- loot.FillLoot(disenchant->ID, LootTemplates_Disenchant, player, true);
+ ItemDisenchantLootEntry const* disenchant = ASSERT_NOTNULL(roll->GetItemDisenchantLoot(player));
- uint32 max_slot = loot.GetMaxSlotInLootFor(player);
- for (uint32 i = 0; i < max_slot; ++i)
+ ItemPosCountVec dest;
+ InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count);
+ if (msg == EQUIP_ERR_OK)
+ player->AutoStoreLoot(disenchant->ID, LootTemplates_Disenchant, true);
+ else // If the player's inventory is full, send the disenchant result in a mail.
{
- LootItem* lootItem = loot.LootItemInSlot(i, player);
- player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
- player->SendItemRetrievalMail(lootItem->itemid, lootItem->count);
+ Loot loot;
+ loot.FillLoot(disenchant->ID, LootTemplates_Disenchant, player, true);
+
+ uint32 max_slot = loot.GetMaxSlotInLootFor(player);
+ for (uint32 i = 0; i < max_slot; ++i)
+ {
+ LootItem* lootItem = loot.LootItemInSlot(i, player);
+ player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
+ player->SendItemRetrievalMail(lootItem->itemid, lootItem->count);
+ }
}
}
}
}
+ else
+ roll->totalGreed = 0;
}
}
- else
+
+ if (roll->totalNeed == 0 && roll->totalGreed == 0) // if, not else, because numbers can be modified above if player is on a different map
{
SendLootAllPassed(*roll);
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 520d1da80dd..dcec9759536 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -391,9 +391,9 @@ class TC_GAME_API Group
void GroupLoot(Loot* loot, WorldObject* pLootedObject);
void MasterLoot(Loot* loot, WorldObject* pLootedObject);
Rolls::iterator GetRoll(ObjectGuid lootObjectGuid, uint8 lootListId);
- void CountTheRoll(Rolls::iterator roll);
+ void CountTheRoll(Rolls::iterator roll, Map* allowedMap);
void CountRollVote(ObjectGuid playerGuid, ObjectGuid lootObjectGuid, uint8 lootListId, uint8 choice);
- void EndRoll(Loot* loot);
+ void EndRoll(Loot* loot, Map* allowedMap);
// related to disenchant rolls
void ResetMaxEnchantingLevel();
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index ab32019a4cc..c16178da814 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -266,7 +266,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
- FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner));
+ if (player->IsInMap(lootOwner))
+ FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner));
for (uint8 i = 0; i < items.size(); ++i)
{
diff --git a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
index a48587849b5..3fae22e8e50 100644
--- a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
+++ b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp
@@ -65,7 +65,7 @@ public:
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* pGroupie = itr->GetSource();
- if (!pGroupie)
+ if (!pGroupie || !pGroupie->IsInMap(player))
continue;
if (pGroupie->GetQuestStatus(QUEST_DEAD_MAN_PLEA) == QUEST_STATUS_INCOMPLETE &&
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index ce0163d1f98..3e5755713db 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -371,7 +371,8 @@ class boss_lady_deathwhisper : public CreatureScript
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
- member->KilledMonsterCredit(NPC_DARNAVAN_CREDIT);
+ if (member->IsInMap(owner))
+ member->KilledMonsterCredit(NPC_DARNAVAN_CREDIT);
}
else
owner->KilledMonsterCredit(NPC_DARNAVAN_CREDIT);
@@ -885,7 +886,8 @@ class npc_darnavan : public CreatureScript
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
- member->FailQuest(QUEST_DEPROGRAMMING);
+ if (member->IsInMap(owner))
+ member->FailQuest(QUEST_DEPROGRAMMING);
}
else
owner->FailQuest(QUEST_DEPROGRAMMING);
diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp
index 6e24ad8d462..a266e88ee90 100644
--- a/src/server/scripts/Outland/zone_terokkar_forest.cpp
+++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp
@@ -114,7 +114,7 @@ public:
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* groupie = itr->GetSource();
- if (groupie &&
+ if (groupie && groupie->IsInMap(player) &&
groupie->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE &&
groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, NPC_BOULDERFIST_INVADER) == REQUIRED_KILL_COUNT)
{