Index: src/game/Group.cpp =================================================================== --- src/game/Group.cpp (revision 5523) +++ src/game/Group.cpp (working copy) @@ -69,6 +69,7 @@ m_groupType = GROUPTYPE_NORMAL; m_lootMethod = GROUP_LOOT; m_lootThreshold = ITEM_QUALITY_UNCOMMON; + m_looterGuid = guid; if(!AddMember(guid, name)) return false; @@ -445,13 +446,12 @@ void Group::NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature) { - std::vector::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) + uint8 itemSlot = 0; + for(std::vector::iterator i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot) { item = objmgr.GetItemPrototype(i->itemid); @@ -502,6 +502,50 @@ } } +void Group::MasterLoot(uint64 playerGUID, Loot *loot, Creature *creature) +{ + Player *player = objmgr.GetPlayer(playerGUID); + if(!player) + return; + + sLog.outDebug("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330) player = [%s].", player->GetName()); + + //mark threshold items amnd free for all items + for(std::vector::iterator i=loot->items.begin(); i != loot->items.end(); ++i) + { + ItemPrototype const* item = objmgr.GetItemPrototype(i->itemid); + if(item && (item->Quality < uint32(m_lootThreshold) || i->freeforall)) + i->is_underthreshold=1; + } + + uint32 real_count = 0; + + WorldPacket data(SMSG_LOOT_MASTER_LIST, 330); + data << (uint8)GetMembersCount(); + + for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *looter = itr->getSource(); + if (!looter->IsInWorld()) + continue; + + if (looter->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + { + data << looter->GetGUID(); + ++real_count; + } + } + + data.put(0,real_count); + + for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *looter = itr->getSource(); + if (looter->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + looter->GetSession()->SendPacket(&data); + } +} + void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise) { Rolls::iterator rollI = GetRoll(Guid); Index: src/game/Group.h =================================================================== --- src/game/Group.h (revision 5523) +++ src/game/Group.h (working copy) @@ -260,6 +260,7 @@ void SendLootAllPassed(uint64 Guid, uint32 NumberOfPlayers, const Roll &r); void GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature); void NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature); + void MasterLoot(uint64 playerGUID, Loot *loot, Creature *creature); Rolls::iterator GetRoll(uint64 Guid) { Rolls::iterator iter; Index: src/game/LootHandler.cpp =================================================================== --- src/game/LootHandler.cpp (revision 5523) +++ src/game/LootHandler.cpp (working copy) @@ -424,3 +424,78 @@ //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); } + +void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data ) +{ + CHECK_PACKET_SIZE(recv_data,8+1+8); + + uint8 slotid; + uint64 lootguid, target_playerguid; + + recv_data >> lootguid >> slotid >> target_playerguid; + + if(!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) + { + _player->SendLootRelease(GetPlayer()->GetLootGUID()); + return; + } + + Player *target = ObjectAccessor::FindPlayer(MAKE_GUID(target_playerguid,HIGHGUID_PLAYER)); + if(!target) + return; + + sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); + + if(_player->GetLootGUID() != lootguid) + return; + + Loot *pLoot = NULL; + + if(IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) + { + Creature *pCreature = ObjectAccessor::GetCreature(*GetPlayer(), lootguid); + if(!pCreature) + return; + + pLoot = &pCreature->loot; + } + else if(IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) + { + GameObject *pGO = ObjectAccessor::GetGameObject(*GetPlayer(), lootguid); + if(!pGO) + return; + + pLoot = &pGO->loot; + } + + if(!pLoot) + return; + + if (slotid > pLoot->items.size()) + { + sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %d)",GetPlayer()->GetName(), slotid, pLoot->items.size()); + return; + } + + uint32 amount = pLoot->items[slotid].count; + uint32 itemid = pLoot->items[slotid].itemid; + + ItemPosCountVec dest; + uint8 msg = target->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemid, amount ); + if ( msg != EQUIP_ERR_OK ) + { + target->SendEquipError( msg, NULL, NULL ); + _player->SendEquipError( msg, NULL, NULL ); // send duplicate of error massage to master looter + return; + } + + // not move item from loot to target inventory + Item * newitem = target->StoreNewItem( dest, itemid, true ); + + pLoot->items[slotid].count=0; + pLoot->items[slotid].is_looted=true; + + target->SendNewItem(newitem, uint32(amount), false, false, true ); + pLoot->NotifyItemRemoved(slotid); + --pLoot->unlootedCount; +} Index: src/game/Player.cpp =================================================================== --- src/game/Player.cpp (revision 5523) +++ src/game/Player.cpp (working copy) @@ -6880,17 +6880,28 @@ if (recipient->GetGroup()) { - // round robin style looting applies for all low - // quality items in each loot method except free for all GroupReference &group = recipient->GetGroupRef(); - // next by circle - uint64 next_guid = 0; - if (group.next()) next_guid = group.next()->getSource()->GetGUID(); - else if(group->GetFirstMember() && group->GetFirstMember()->isValid()) - next_guid = group->GetFirstMember()->getSource()->GetGUID(); - group->SetLooterGuid(next_guid); + switch (group->GetLootMethod()) + { + case MASTER_LOOT: + case FREE_FOR_ALL: + break; + default: + { + // round robin style looting applies for all low + // quality items in each loot method except free for all and master loot + // next by circle + uint64 next_guid = 0; + if (group.next()) next_guid = group.next()->getSource()->GetGUID(); + else if(group->GetFirstMember() && group->GetFirstMember()->isValid()) + next_guid = group->GetFirstMember()->getSource()->GetGUID(); + group->SetLooterGuid(next_guid); + break; + } + } + switch (group->GetLootMethod()) { case GROUP_LOOT: @@ -6900,6 +6911,9 @@ case NEED_BEFORE_GREED: group->NeedBeforeGreed(recipient->GetGUID(), loot, creature); break; + case MASTER_LOOT: + group->MasterLoot(recipient->GetGUID(), loot, creature); + break; default: break; } @@ -6969,14 +6983,80 @@ if(loot_type == LOOT_PICKPOCKETING || loot_type == LOOT_DISENCHANTING || loot_type == LOOT_PROSPECTING || loot_type == LOOT_INSIGNIA) loot_type = LOOT_SKINNING; - WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size - data << uint64(guid); - data << uint8(loot_type); - data << LootView(*loot, q_list, ffa_list, conditional_list, this, permission); - SendDirectMessage(&data); + + uint8 slottype = 0; // <-- SlotType is the type of the slot (0 = FFA/1 = GL/2 = ML) + if( GetGroup() ) + { + if( GetGroup()->GetLootMethod() == MASTER_LOOT ) slottype = 2; + } + + if( slottype == 2 && IS_CREATURE_GUID(guid) ) // <-- Only for Creature's Corpse (Offylike is also Object as Chest) + { + sLog.outDebug("Player::SendLoot Looter = [%s], LooterMaster = [%s]", GetName(), objmgr.GetPlayer(GetGroup()->GetLooterGuid())->GetName()); + WorldPacket data; + data.SetOpcode (SMSG_LOOT_RESPONSE); + data << uint64(guid); + data << uint8(loot_type); + data << loot->gold; + data << (uint8) 0; + + uint32 count = 0; + uint8 x = 0; + for(std::vector::iterator itr=loot->items.begin(); itr!=loot->items.end(); itr++,x++) + { + ItemPrototype const *itemProto = objmgr.GetItemPrototype(itr->itemid); + if (!itemProto) continue; + if (itr->is_looted) continue; + + data << uint8(x); + data << uint32(itr->itemid); + data << uint32(itr->count); + data << uint32(itr->displayid); + data << uint32(itr->randomSuffix); + data << uint32(itr->randomPropertyId); + + if( itemProto->Quality < GetGroup()->GetLootThreshold() || itr->freeforall ) + { + data << uint8(0); + itr->is_underthreshold = true; + } + else if( GetGUID() != GetGroup()->GetLooterGuid() ) + data << uint8(1); + else + data << slottype; + count++; + } + for(std::vector::iterator itq=loot->quest_items.begin(); itq!=loot->quest_items.end(); itq++,x++) + { + if(!HasQuestForItem(itq->itemid)) continue; + + data << uint8(x); + data << uint32(itq->itemid); + data << uint32(itq->count); + data << uint32(itq->displayid); + data << uint32(0); + data << uint32(0); + data << uint32(0); + count++; + } + data.wpos (13) ; + data << (uint8)count; + GetSession ()->SendPacket(&data); + } + else // <-- Normal loot in case Master Loot Not Set! + { + WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size + + data << uint64(guid); + data << uint8(loot_type); + data << LootView(*loot, q_list, ffa_list, conditional_list, this, permission); + + SendDirectMessage(&data); + } + // add 'this' player as one of the players that are looting 'loot' if (permission != NONE_PERMISSION) loot->AddLooter(GetGUID()); Index: src/game/WorldSession.cpp =================================================================== --- src/game/WorldSession.cpp (revision 5523) +++ src/game/WorldSession.cpp (working copy) @@ -87,6 +87,7 @@ objmgr.opcodeTable[ CMSG_LOOT_MONEY ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootMoneyOpcode ); objmgr.opcodeTable[ CMSG_LOOT ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootOpcode ); objmgr.opcodeTable[ CMSG_LOOT_RELEASE ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootReleaseOpcode ); + objmgr.opcodeTable[ CMSG_LOOT_MASTER_GIVE ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLootMasterGiveOpcode ); objmgr.opcodeTable[ CMSG_WHO ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleWhoOpcode ); objmgr.opcodeTable[ CMSG_LOGOUT_REQUEST ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandleLogoutRequestOpcode ); objmgr.opcodeTable[ CMSG_PLAYER_LOGOUT ] = OpcodeHandler( STATUS_LOGGEDIN, &WorldSession::HandlePlayerLogoutOpcode ); Index: src/game/WorldSession.h =================================================================== --- src/game/WorldSession.h (revision 5523) +++ src/game/WorldSession.h (working copy) @@ -241,6 +241,7 @@ void HandleLootMoneyOpcode(WorldPacket& recvPacket); void HandleLootOpcode(WorldPacket& recvPacket); void HandleLootReleaseOpcode(WorldPacket& recvPacket); + void HandleLootMasterGiveOpcode(WorldPacket& recvPacket); void HandleWhoOpcode(WorldPacket& recvPacket); void HandleLogoutRequestOpcode(WorldPacket& recvPacket); void HandlePlayerLogoutOpcode(WorldPacket& recvPacket);