diff options
Diffstat (limited to 'src/game/Group.cpp')
-rw-r--r-- | src/game/Group.cpp | 269 |
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) |