aboutsummaryrefslogtreecommitdiff
path: root/src/game/Group.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Group.cpp')
-rw-r--r--src/game/Group.cpp269
1 files changed, 154 insertions, 115 deletions
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index 4fac78bf63f..23fbf1f1010 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -560,16 +560,34 @@ void Group::SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r)
}
}
-void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature)
+// notify group members which player is the allowed looter for the given creature
+void Group::SendLooter(Creature *pCreature, Player *pLooter)
+{
+ assert(pCreature);
+
+ WorldPacket data(SMSG_LOOT_LIST, (8+8));
+ data << uint64(pCreature->GetGUID());
+ data << uint8(0); // unk1
+
+ if (pLooter)
+ data.append(pLooter->GetPackGUID());
+ else
+ data << uint8(0);
+
+ BroadcastPacket(&data, false);
+}
+
+void Group::GroupLoot(Loot *loot, WorldObject* pLootedObject)
{
std::vector<LootItem>::iterator i;
ItemPrototype const *item;
uint8 itemSlot = 0;
- Player *player = objmgr.GetPlayer(playerGUID);
- Group *group = player->GetGroup();
- for (i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
+ for (i = loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
{
+ if (i->freeforall)
+ continue;
+
item = objmgr.GetItemPrototype(i->itemid);
if (!item)
{
@@ -578,57 +596,72 @@ void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature)
}
//roll for over-threshold item if it's one-player loot
- if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
+ if (item->Quality >= uint32(m_lootThreshold))
{
uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
- Roll* r=new Roll(newitemGUID,*i);
+ Roll* r = new Roll(newitemGUID,*i);
//a vector is filled with only near party members
for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *member = itr->getSource();
- if(!member || !member->GetSession())
+ if (!member || !member->GetSession())
continue;
- if ( i->AllowedForPlayer(member) )
+ if (i->AllowedForPlayer(member))
{
- if (member->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ if (member->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
- ++r->totalPlayersRolling;
+ r->totalPlayersRolling++;
}
}
}
- r->setLoot(loot);
- r->itemSlot = itemSlot;
+ if (r->totalPlayersRolling > 0)
+ {
+ r->setLoot(loot);
+ r->itemSlot = itemSlot;
- group->SendLootStartRoll(60000, *r);
+ loot->items[itemSlot].is_blocked = true;
- loot->items[itemSlot].is_blocked = true;
- creature->m_groupLootTimer = 60000;
- creature->lootingGroupLeaderGUID = GetLeaderGUID();
+ SendLootStartRoll(60000, *r);
- RollId.push_back(r);
+ RollId.push_back(r);
+
+ if (Creature* creature = dynamic_cast<Creature *>(pLootedObject))
+ {
+ creature->m_groupLootTimer = 60000;
+ creature->lootingGroupLeaderGUID = GetLeaderGUID();
+ }
+ else if (GameObject* go = dynamic_cast<GameObject *>(pLootedObject))
+ {
+ go->m_groupLootTimer = 60000;
+ go->lootingGroupLeaderGUID = GetLeaderGUID();
+ }
+ }
+ else
+ {
+ delete r;
+ }
}
else
i->is_underthreshold=1;
-
}
}
-void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *creature)
+void Group::NeedBeforeGreed(Loot *loot, WorldObject* pLootedObject)
{
ItemPrototype const *item;
- Player *player = objmgr.GetPlayer(playerGUID);
- Group *group = player->GetGroup();
-
uint8 itemSlot = 0;
for (std::vector<LootItem>::iterator i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
{
+ if (i->freeforall)
+ continue;
+
item = objmgr.GetItemPrototype(i->itemid);
- //only roll for one-player items, not for ones everyone can get
- if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
+ //roll for over-threshold item if it's one-player loot
+ if (item->Quality >= uint32(m_lootThreshold))
{
uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
Roll* r=new Roll(newitemGUID,*i);
@@ -636,15 +669,15 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea
for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *playerToRoll = itr->getSource();
- if(!playerToRoll || !playerToRoll->GetSession())
+ if (!playerToRoll || !playerToRoll->GetSession())
continue;
- if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
+ if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll))
{
- if (playerToRoll->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ if (playerToRoll->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
- ++r->totalPlayersRolling;
+ r->totalPlayersRolling++;
}
}
}
@@ -654,11 +687,17 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea
r->setLoot(loot);
r->itemSlot = itemSlot;
- group->SendLootStartRoll(60000, *r);
-
loot->items[itemSlot].is_blocked = true;
+ SendLootStartRoll(60000, *r);
+
RollId.push_back(r);
+
+ if (Creature* creature = dynamic_cast<Creature *>(pLootedObject))
+ {
+ creature->m_groupLootTimer = 60000;
+ creature->lootingGroupLeaderGUID = GetLeaderGUID();
+ }
}
else
{
@@ -670,13 +709,9 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea
}
}
-void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creature)
+void Group::MasterLoot(Loot* /*loot*/, WorldObject* pLootedObject)
{
- Player *player = objmgr.GetPlayer(playerGUID);
- if(!player)
- return;
-
- sLog.outDebug("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330) player = [%s].", player->GetName());
+ sLog.outDebug("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330)");
uint32 real_count = 0;
@@ -689,7 +724,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
if (!looter->IsInWorld())
continue;
- if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ if (looter->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
data << looter->GetGUID();
++real_count;
@@ -701,12 +736,12 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
Player *looter = itr->getSource();
- if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ if (looter->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
looter->GetSession()->SendPacket(&data);
}
}
-void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 NumberOfPlayers, uint8 Choise)
+void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 NumberOfPlayers, uint8 Choice)
{
Rolls::iterator rollI = GetRoll(Guid);
if (rollI == RollId.end())
@@ -722,37 +757,30 @@ void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 N
if (roll->getLoot()->items.empty())
return;
- switch (Choise)
+ switch (Choice)
{
case ROLL_PASS: // Player choose pass
- {
SendLootRoll(0, playerGUID, 128, ROLL_PASS, *roll);
++roll->totalPass;
itr->second = PASS;
- }
- break;
+ break;
case ROLL_NEED: // player choose Need
- {
SendLootRoll(0, playerGUID, 0, 0, *roll);
++roll->totalNeed;
itr->second = NEED;
- }
- break;
+ break;
case ROLL_GREED: // player choose Greed
- {
SendLootRoll(0, playerGUID, 128, ROLL_GREED, *roll);
++roll->totalGreed;
itr->second = GREED;
- }
- break;
+ break;
case ROLL_DISENCHANT: // player choose Disenchant
- {
SendLootRoll(0, playerGUID, 128, ROLL_DISENCHANT, *roll);
++roll->totalGreed;
itr->second = DISENCHANT;
- }
- break;
+ break;
}
+
if (roll->totalPass + roll->totalNeed + roll->totalGreed >= roll->totalPlayersRolling)
{
CountTheRoll(rollI, NumberOfPlayers);
@@ -760,21 +788,23 @@ void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 N
}
//called when roll timer expires
-void Group::EndRoll()
+void Group::EndRoll(Loot *pLoot)
{
- Rolls::iterator itr;
- while(!RollId.empty())
+ for (Rolls::iterator itr = RollId.begin(); itr != RollId.end(); )
{
- //need more testing here, if rolls disappear
- itr = RollId.begin();
- CountTheRoll(itr, GetMembersCount()); //i don't have to edit player votes, who didn't vote ... he will pass
+ if ((*itr)->getLoot() == pLoot) {
+ CountTheRoll(itr, GetMembersCount()); //i don't have to edit player votes, who didn't vote ... he will pass
+ itr = RollId.begin();
+ }
+ else
+ itr++;
}
}
void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
{
Roll* roll = *rollI;
- if(!roll->isValid()) // is loot already deleted ?
+ if (!roll->isValid()) // is loot already deleted ?
{
RollId.erase(rollI);
delete roll;
@@ -783,7 +813,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
//end of the roll
if (roll->totalNeed > 0)
{
- if(!roll->playerVote.empty())
+ if (!roll->playerVote.empty())
{
uint8 maxresul = 0;
uint64 maxguid = (*roll->playerVote.begin()).first;
@@ -794,7 +824,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
if (itr->second != NEED)
continue;
- uint8 randomN = urand(1, 99);
+ uint8 randomN = urand(1, 100);
SendLootRoll(0, itr->first, randomN, ROLL_NEED, *roll);
if (maxresul < randomN)
{
@@ -805,18 +835,18 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
SendLootRollWon(0, maxguid, maxresul, ROLL_NEED, *roll);
player = objmgr.GetPlayer(maxguid);
- if(player && player->GetSession())
+ if (player && player->GetSession())
{
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT, roll->itemid, maxresul);
ItemPosCountVec dest;
LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
+ uint8 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;
+ roll->getLoot()->unlootedCount--;
player->StoreNewItem( dest, roll->itemid, true, item->randomPropertyId);
}
else
@@ -829,7 +859,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
}
else if (roll->totalGreed > 0)
{
- if(!roll->playerVote.empty())
+ if (!roll->playerVote.empty())
{
uint8 maxresul = 0;
uint64 maxguid = (*roll->playerVote.begin()).first;
@@ -837,12 +867,12 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
RollVote rollvote;
Roll::PlayerVote::iterator itr;
- for (itr=roll->playerVote.begin(); itr!=roll->playerVote.end(); ++itr)
+ for (itr = roll->playerVote.begin(); itr != roll->playerVote.end(); ++itr)
{
if (itr->second != GREED && itr->second != DISENCHANT)
continue;
- uint8 randomN = urand(1, 99);
+ uint8 randomN = urand(1, 100);
SendLootRoll(0, itr->first, randomN, itr->second, *roll);
if (maxresul < randomN)
{
@@ -854,34 +884,34 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
SendLootRollWon(0, maxguid, maxresul, rollvote, *roll);
player = objmgr.GetPlayer(maxguid);
- if(player && player->GetSession())
+ if (player && player->GetSession())
{
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT, roll->itemid, maxresul);
LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- if(rollvote == GREED)
+ if (rollvote == GREED)
{
ItemPosCountVec dest;
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
+ uint8 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->randomPropertyId);
+ roll->getLoot()->unlootedCount--;
+ player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId);
}
else
{
item->is_blocked = false;
- player->SendEquipError( msg, NULL, NULL );
+ player->SendEquipError(msg, NULL, NULL);
}
}
else if(rollvote == DISENCHANT)
{
item->is_looted = true;
roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
- --roll->getLoot()->unlootedCount;
+ roll->getLoot()->unlootedCount--;
ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(roll->itemid);
player->AutoStoreLoot(pProto->DisenchantID, LootTemplates_Disenchant, true);
}
@@ -891,8 +921,11 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
else
{
SendLootAllPassed(NumberOfPlayers, *roll);
+
+ // remove is_blocked so that the item is lootable by all players
LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- if(item) item->is_blocked = false;
+ if (item)
+ item->is_blocked = false;
}
RollId.erase(rollI);
delete roll;
@@ -1372,7 +1405,18 @@ void Group::ChangeMembersGroup(Player *player, const uint8 &group)
}
}
-void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
+// Retrieve the next Round-Roubin player for the group
+//
+// No update done if loot method is Master or FFA.
+//
+// If the RR player is not yet set for the group, the first group member becomes the round-robin player.
+// If the RR player is set, the next player in group becomes the round-robin player.
+//
+// If ifneed is true,
+// the current RR player is checked to be near the looted object.
+// if yes, no update done.
+// if not, he looses his turn.
+void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
{
switch (GetLootMethod())
{
@@ -1385,64 +1429,59 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
break;
}
- member_citerator guid_itr = _getMemberCSlot(GetLooterGuid());
- if(guid_itr != m_memberSlots.end())
+ uint64 oldLooterGUID = GetLooterGuid();
+ member_citerator guid_itr = _getMemberCSlot(oldLooterGUID);
+ if (guid_itr != m_memberSlots.end())
{
- if(ifneed)
+ if (ifneed)
{
// not update if only update if need and ok
Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
- if(looter && looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ if (looter && looter->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
return;
}
++guid_itr;
}
// search next after current
- if(guid_itr != m_memberSlots.end())
+ Player *pNewLooter = NULL;
+ for (member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
{
- for (member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
- {
- if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ if (Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ if (pl->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
- if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
+ pNewLooter = pl;
+ break;
+ }
+ }
+
+ if (!pNewLooter)
+ {
+ // search from start
+ for (member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
+ {
+ if (Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ if (pl->IsWithinDist(pLootedObject,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
{
- bool refresh = pl->GetLootGUID()==creature->GetGUID();
-
- //if(refresh) // update loot for new looter
- // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
- SetLooterGuid(pl->GetGUID());
- SendUpdate();
- if(refresh) // update loot for new looter
- pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
- return;
+ pNewLooter = pl;
+ break;
}
- }
}
}
- // search from start
- for (member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
+ if (pNewLooter)
{
- if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ if (oldLooterGUID != pNewLooter->GetGUID())
{
- if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
- {
- bool refresh = pl->GetLootGUID()==creature->GetGUID();
-
- //if(refresh) // update loot for new looter
- // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
- SetLooterGuid(pl->GetGUID());
- SendUpdate();
- if(refresh) // update loot for new looter
- pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
- return;
- }
+ SetLooterGuid(pNewLooter->GetGUID());
+ SendUpdate();
}
}
-
- SetLooterGuid(0);
- SendUpdate();
+ else
+ {
+ SetLooterGuid(0);
+ SendUpdate();
+ }
}
uint32 Group::CanJoinBattleGroundQueue(BattleGround const* bgOrTemplate, BattleGroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)