diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index d25078b83..ca2e6fdfd 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -94,7 +94,7 @@ VisibleNotifier::Notify() // generate outOfRange for not iterate objects i_data.AddOutOfRangeGUID(i_clientGUIDs); - for(Player::ClientGUIDs::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr) + for(ObjectGuidSet::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr) { i_player.m_clientGUIDs.erase(*itr); @@ -123,8 +123,8 @@ VisibleNotifier::Notify() i_player.GetSession()->SendPacket(&packet); // send out of range to other players if need - std::set const& oor = i_data.GetOutOfRangeGUIDs(); - for(std::set::const_iterator iter = oor.begin(); iter != oor.end(); ++iter) + ObjectGuidSet const& oor = i_data.GetOutOfRangeGUIDs(); + for(ObjectGuidSet::const_iterator iter = oor.begin(); iter != oor.end(); ++iter) { if(!iter->IsPlayer()) continue; diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 9c4c66ce4..11debc165 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -50,7 +50,7 @@ namespace MaNGOS Player &i_player; UpdateData i_data; UpdateDataMapType i_data_updates; - Player::ClientGUIDs i_clientGUIDs; + ObjectGuidSet i_clientGUIDs; std::set i_visibleNow; explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {} diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index ef0666e85..d090e0aca 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -35,60 +35,72 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data ) { sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player *player = GetPlayer(); - uint64 lguid = player->GetLootGUID(); + ObjectGuid lguid = player->GetLootGUID(); Loot *loot; uint8 lootSlot; recv_data >> lootSlot; - if (IS_GAMEOBJECT_GUID(lguid)) + switch( lguid.GetHigh()) { - GameObject *go = player->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) + case HIGHGUID_GAMEOBJECT: { - player->SendLootRelease(lguid); + GameObject *go = player->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) + { + player->SendLootRelease(lguid); + return; + } + + loot = &go->loot; + break; + } + case HIGHGUID_ITEM: + { + Item *pItem = player->GetItemByGuid( lguid ); + + if (!pItem) + { + player->SendLootRelease(lguid); + return; + } + + loot = &pItem->loot; + break; + } + case HIGHGUID_CORPSE: + { + Corpse *bones = player->GetMap()->GetCorpse(lguid); + if (!bones) + { + player->SendLootRelease(lguid); + return; + } + loot = &bones->loot; + break; + } + case HIGHGUID_UNIT: + { + Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); + + bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); + + if( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) + { + player->SendLootRelease(lguid); + return; + } + + loot = &pCreature->loot; + break; + } + default: + { + sLog.outError("%s is unsupported for looting.",lguid.GetString().c_str()); return; } - - loot = &go->loot; - } - else if (IS_ITEM_GUID(lguid)) - { - Item *pItem = player->GetItemByGuid( lguid ); - - if (!pItem) - { - player->SendLootRelease(lguid); - return; - } - - loot = &pItem->loot; - } - else if (IS_CORPSE_GUID(lguid)) - { - Corpse *bones = player->GetMap()->GetCorpse(lguid); - if (!bones) - { - player->SendLootRelease(lguid); - return; - } - loot = &bones->loot; - } - else - { - Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); - - if( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) - { - player->SendLootRelease(lguid); - return; - } - - loot = &pCreature->loot; } QuestItem *qitem = NULL; @@ -162,13 +174,13 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ ) sLog.outDebug("WORLD: CMSG_LOOT_MONEY"); Player *player = GetPlayer(); - uint64 guid = player->GetLootGUID(); - if(!guid) + ObjectGuid guid = player->GetLootGUID(); + if (guid.IsEmpty()) return; Loot *pLoot = NULL; - switch(GUID_HIPART(guid)) + switch(guid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { @@ -210,9 +222,9 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ ) return; // unlootable type } - if( pLoot ) + if (pLoot) { - if (!IS_ITEM_GUID(guid) && player->GetGroup()) //item can be looted only single player + if (!guid.IsItem() && player->GetGroup()) //item can be looted only single player { Group *group = player->GetGroup(); @@ -274,7 +286,7 @@ void WorldSession::HandleLootReleaseOpcode( WorldPacket & recv_data ) DoLootRelease(lguid); } -void WorldSession::DoLootRelease( uint64 lguid ) +void WorldSession::DoLootRelease(ObjectGuid lguid) { Player *player = GetPlayer(); Loot *loot; @@ -287,152 +299,163 @@ void WorldSession::DoLootRelease( uint64 lguid ) if(!player->IsInWorld()) return; - if (IS_GAMEOBJECT_GUID(lguid)) + switch(lguid.GetHigh()) { - GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) - return; - - loot = &go->loot; - - if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) + case HIGHGUID_GAMEOBJECT: { - // locked doors are opened with spelleffect openlock, prevent remove its as looted - go->UseDoorOrButton(); - } - else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) - { - // GO is mineral vein? so it is not removed after its looted - if(go->GetGoType() == GAMEOBJECT_TYPE_CHEST) + GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE))) + return; + + loot = &go->loot; + + if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { - uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; - uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; - - // only vein pass this check - if(go_min != 0 && go_max > go_min) + // locked doors are opened with spelleffect openlock, prevent remove its as looted + go->UseDoorOrButton(); + } + else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) + { + // GO is mineral vein? so it is not removed after its looted + if(go->GetGoType() == GAMEOBJECT_TYPE_CHEST) { - float amount_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_AMOUNT); - float min_amount = go_min*amount_rate; - float max_amount = go_max*amount_rate; + uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; + uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; - go->AddUse(); - float uses = float(go->GetUseCount()); - - if(uses < max_amount) + // only vein pass this check + if(go_min != 0 && go_max > go_min) { - if(uses >= min_amount) - { - float chance_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_NEXT); + float amount_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_AMOUNT); + float min_amount = go_min*amount_rate; + float max_amount = go_max*amount_rate; - int32 ReqValue = 175; - LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); - if(lockInfo) - ReqValue = lockInfo->Skill[0]; - float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); - double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); - if(roll_chance_f(float(100.0f*chance+skill))) + go->AddUse(); + float uses = float(go->GetUseCount()); + + if(uses < max_amount) + { + if(uses >= min_amount) { - go->SetLootState(GO_READY); + float chance_rate = sWorld.getConfig(CONFIG_FLOAT_RATE_MINING_NEXT); + + int32 ReqValue = 175; + LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); + if(lockInfo) + ReqValue = lockInfo->Skill[0]; + float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); + double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses)); + if(roll_chance_f(float(100.0f*chance+skill))) + { + go->SetLootState(GO_READY); + } + else // not have more uses + go->SetLootState(GO_JUST_DEACTIVATED); } - else // not have more uses - go->SetLootState(GO_JUST_DEACTIVATED); + else // 100% chance until min uses + go->SetLootState(GO_READY); } - else // 100% chance until min uses - go->SetLootState(GO_READY); + else // max uses already + go->SetLootState(GO_JUST_DEACTIVATED); } - else // max uses already + else // not vein go->SetLootState(GO_JUST_DEACTIVATED); } - else // not vein - go->SetLootState(GO_JUST_DEACTIVATED); - } - else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) - { // The fishing hole used once more - go->AddUse(); // if the max usage is reached, will be despawned in next tick - if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) - { - go->SetLootState(GO_JUST_DEACTIVATED); + else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) + { // The fishing hole used once more + go->AddUse(); // if the max usage is reached, will be despawned in next tick + if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) + { + go->SetLootState(GO_JUST_DEACTIVATED); + } + else + go->SetLootState(GO_READY); } - else - go->SetLootState(GO_READY); + else // not chest (or vein/herb/etc) + go->SetLootState(GO_JUST_DEACTIVATED); + + loot->clear(); } - else // not chest (or vein/herb/etc) - go->SetLootState(GO_JUST_DEACTIVATED); - - loot->clear(); + else + // not fully looted object + go->SetLootState(GO_ACTIVATED); + break; } - else - // not fully looted object - go->SetLootState(GO_ACTIVATED); - } - else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG - { - Corpse *corpse = _player->GetMap()->GetCorpse(lguid); - if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) - return; - - loot = &corpse->loot; - - if (loot->isLooted()) + case HIGHGUID_CORPSE: // ONLY remove insignia at BG { - loot->clear(); - corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); + Corpse *corpse = _player->GetMap()->GetCorpse(lguid); + if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) + return; + + loot = &corpse->loot; + + if (loot->isLooted()) + { + loot->clear(); + corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); + } + break; } - } - else if (IS_ITEM_GUID(lguid)) - { - Item *pItem = player->GetItemByGuid(lguid ); - if(!pItem) - return; - - ItemPrototype const* proto = pItem->GetProto(); - - // destroy only 5 items from stack in case prospecting and milling - if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) && - proto->Class == ITEM_CLASS_TRADE_GOODS) + case HIGHGUID_ITEM: { - pItem->m_lootGenerated = false; - pItem->loot.clear(); + Item *pItem = player->GetItemByGuid(lguid ); + if(!pItem) + return; - uint32 count = pItem->GetCount(); + ItemPrototype const* proto = pItem->GetProto(); - // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. - if(count > 5) - count = 5; + // destroy only 5 items from stack in case prospecting and milling + if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) && + proto->Class == ITEM_CLASS_TRADE_GOODS) + { + pItem->m_lootGenerated = false; + pItem->loot.clear(); - player->DestroyItemCount(pItem, count, true); + uint32 count = pItem->GetCount(); + + // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. + if(count > 5) + count = 5; + + player->DestroyItemCount(pItem, count, true); + } + else + // FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible. + player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true); + return; // item can be looted only single player } - else - // FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible. - player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true); - return; // item can be looted only single player - } - else - { - Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); - if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) - return; - - loot = &pCreature->loot; - - // update next looter - if(Player *recipient = pCreature->GetLootRecipient()) - if(Group* group = recipient->GetGroup()) - if (group->GetLooterGuid() == player->GetGUID()) - group->UpdateLooterGuid(pCreature); - - if (loot->isLooted()) + case HIGHGUID_UNIT: { - // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact - if(!pCreature->isAlive()) - pCreature->AllLootRemovedFromCorpse(); + Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); - pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - loot->clear(); + bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); + if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) + return; + + loot = &pCreature->loot; + + // update next looter + if(Player *recipient = pCreature->GetLootRecipient()) + if(Group* group = recipient->GetGroup()) + if (group->GetLooterGuid() == player->GetGUID()) + group->UpdateLooterGuid(pCreature); + + if (loot->isLooted()) + { + // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact + if(!pCreature->isAlive()) + pCreature->AllLootRemovedFromCorpse(); + + pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + loot->clear(); + } + break; + } + default: + { + sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); + return; } } diff --git a/src/game/ObjectGuid.h b/src/game/ObjectGuid.h index c8ac65228..ed649af37 100644 --- a/src/game/ObjectGuid.h +++ b/src/game/ObjectGuid.h @@ -75,9 +75,7 @@ enum HighGuid #define IS_PLAYER_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_PLAYER && Guid!=0 ) #define IS_UNIT_GUID(Guid) ( IS_CREATURE_OR_PET_GUID(Guid) || IS_PLAYER_GUID(Guid) ) // special case for empty guid need check -#define IS_ITEM_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_ITEM ) #define IS_GAMEOBJECT_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_GAMEOBJECT ) -#define IS_CORPSE_GUID(Guid) ( GUID_HIPART(Guid) == HIGHGUID_CORPSE ) #define IS_MO_TRANSPORT(Guid) ( GUID_HIPART(Guid) == HIGHGUID_MO_TRANSPORT ) // l - OBJECT_FIELD_GUID @@ -233,6 +231,8 @@ class ObjectGuid uint64 m_guid; }; +typedef std::set ObjectGuidSet; + class PackedGuid { friend ByteBuffer& operator<< (ByteBuffer& buf, PackedGuid const& guid); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 867f16297..2e5f72d31 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -7533,14 +7533,15 @@ void Player::RemovedInsignia(Player* looterPlr) looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA); } -void Player::SendLootRelease( uint64 guid ) +void Player::SendLootRelease(ObjectGuid guid) { WorldPacket data( SMSG_LOOT_RELEASE_RESPONSE, (8+1) ); - data << uint64(guid) << uint8(1); + data << guid; + data << uint8(1); SendDirectMessage( &data ); } -void Player::SendLoot(uint64 guid, LootType loot_type) +void Player::SendLoot(ObjectGuid guid, LootType loot_type) { if (uint64 lguid = GetLootGUID()) m_session->DoLootRelease(lguid); @@ -7549,224 +7550,236 @@ void Player::SendLoot(uint64 guid, LootType loot_type) PermissionTypes permission = ALL_PERMISSION; sLog.outDebug("Player::SendLoot"); - if (IS_GAMEOBJECT_GUID(guid)) + switch(guid.GetHigh()) { - sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)"); - GameObject *go = GetMap()->GetGameObject(guid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) - // And permit out of range GO with no owner in case fishing hole - if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this,INTERACTION_DISTANCE))) + case HIGHGUID_GAMEOBJECT: { - SendLootRelease(guid); - return; - } + sLog.outDebug(" IS_GAMEOBJECT_GUID(guid)"); + GameObject *go = GetMap()->GetGameObject(guid); - loot = &go->loot; - - if (go->getLootState() == GO_READY) - { - uint32 lootid = go->GetGOInfo()->GetLootId(); - if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) - if (BattleGround *bg = GetBattleGround()) - if (bg->GetTypeID() == BATTLEGROUND_AV) - if (!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(), GetTeam()))) - { - SendLootRelease(guid); - return; - } - - if (lootid) + // not check distance for GO in case owned GO (fishing bobber case, for example) + // And permit out of range GO with no owner in case fishing hole + if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this,INTERACTION_DISTANCE))) { - sLog.outDebug(" if(lootid)"); - loot->clear(); - loot->FillLoot(lootid, LootTemplates_Gameobject, this, false); + SendLootRelease(guid); + return; } - if (loot_type == LOOT_FISHING) - go->getFishLoot(loot,this); + loot = &go->loot; - go->SetLootState(GO_ACTIVATED); - } - } - else if (IS_ITEM_GUID(guid)) - { - Item *item = GetItemByGuid( guid ); - - if (!item) - { - SendLootRelease(guid); - return; - } - - loot = &item->loot; - - if (!item->m_lootGenerated) - { - item->m_lootGenerated = true; - loot->clear(); - - switch(loot_type) + if (go->getLootState() == GO_READY) { - case LOOT_DISENCHANTING: - loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true); - break; - case LOOT_PROSPECTING: - loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true); - break; - case LOOT_MILLING: - loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true); - break; - default: - loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true); - loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); - break; - } - } - } - else if (IS_CORPSE_GUID(guid)) // remove insignia - { - Corpse *bones = GetMap()->GetCorpse(guid); + uint32 lootid = go->GetGOInfo()->GetLootId(); + if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) + if (BattleGround *bg = GetBattleGround()) + if (bg->GetTypeID() == BATTLEGROUND_AV) + if (!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(), GetTeam()))) + { + SendLootRelease(guid); + return; + } - if (!bones || !((loot_type == LOOT_CORPSE) || (loot_type == LOOT_INSIGNIA)) || (bones->GetType() != CORPSE_BONES) ) - { - SendLootRelease(guid); - return; - } - - loot = &bones->loot; - - if (!bones->lootForBody) - { - bones->lootForBody = true; - uint32 pLevel = bones->loot.gold; - bones->loot.clear(); - if (GetBattleGround()->GetTypeID() == BATTLEGROUND_AV) - loot->FillLoot(0, LootTemplates_Creature, this, false); - // It may need a better formula - // Now it works like this: lvl10: ~6copper, lvl70: ~9silver - bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY) ); - } - - if (bones->lootRecipient != this) - permission = NONE_PERMISSION; - } - else - { - Creature *creature = GetMap()->GetCreature(guid); - - // must be in range and creature must be alive for pickpocket and must be dead for another loot - if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this,INTERACTION_DISTANCE)) - { - SendLootRelease(guid); - return; - } - - if (loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature)) - { - SendLootRelease(guid); - return; - } - - loot = &creature->loot; - - if (loot_type == LOOT_PICKPOCKETING) - { - if (!creature->lootForPickPocketed) - { - creature->lootForPickPocketed = true; - loot->clear(); - - if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) - loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false); - - // Generate extra money for pick pocket loot - const uint32 a = urand(0, creature->getLevel()/2); - const uint32 b = urand(0, getLevel()/2); - loot->gold = uint32(10 * (a + b) * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY)); - } - } - else - { - // the player whose group may loot the corpse - Player *recipient = creature->GetLootRecipient(); - if (!recipient) - { - creature->SetLootRecipient(this); - recipient = this; - } - - if (creature->lootForPickPocketed) - { - creature->lootForPickPocketed = false; - loot->clear(); - } - - if (!creature->lootForBody) - { - creature->lootForBody = true; - loot->clear(); - - if (uint32 lootid = creature->GetCreatureInfo()->lootid) - loot->FillLoot(lootid, LootTemplates_Creature, recipient, false); - - loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold); - - if (Group* group = recipient->GetGroup()) + if (lootid) { - group->UpdateLooterGuid(creature,true); + sLog.outDebug(" if(lootid)"); + loot->clear(); + loot->FillLoot(lootid, LootTemplates_Gameobject, this, false); + } - switch (group->GetLootMethod()) - { - case GROUP_LOOT: - // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with qualityGroupLoot(recipient->GetGUID(), loot, creature); - break; - case NEED_BEFORE_GREED: - group->NeedBeforeGreed(recipient->GetGUID(), loot, creature); - break; - case MASTER_LOOT: - group->MasterLoot(recipient->GetGUID(), loot, creature); - break; - default: - break; - } + if (loot_type == LOOT_FISHING) + go->getFishLoot(loot,this); + + go->SetLootState(GO_ACTIVATED); + } + break; + } + case HIGHGUID_ITEM: + { + Item *item = GetItemByGuid( guid ); + + if (!item) + { + SendLootRelease(guid); + return; + } + + loot = &item->loot; + + if (!item->m_lootGenerated) + { + item->m_lootGenerated = true; + loot->clear(); + + switch(loot_type) + { + case LOOT_DISENCHANTING: + loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true); + break; + case LOOT_PROSPECTING: + loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true); + break; + case LOOT_MILLING: + loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true); + break; + default: + loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true); + loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); + break; } } + break; + } + case HIGHGUID_CORPSE: // remove insignia + { + Corpse *bones = GetMap()->GetCorpse(guid); - // possible only if creature->lootForBody && loot->empty() at spell cast check - if (loot_type == LOOT_SKINNING) + if (!bones || !((loot_type == LOOT_CORPSE) || (loot_type == LOOT_INSIGNIA)) || (bones->GetType() != CORPSE_BONES) ) { - loot->clear(); - loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false); + SendLootRelease(guid); + return; + } + + loot = &bones->loot; + + if (!bones->lootForBody) + { + bones->lootForBody = true; + uint32 pLevel = bones->loot.gold; + bones->loot.clear(); + if (GetBattleGround()->GetTypeID() == BATTLEGROUND_AV) + loot->FillLoot(0, LootTemplates_Creature, this, false); + // It may need a better formula + // Now it works like this: lvl10: ~6copper, lvl70: ~9silver + bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY) ); + } + + if (bones->lootRecipient != this) + permission = NONE_PERMISSION; + break; + } + case HIGHGUID_UNIT: + { + Creature *creature = GetMap()->GetCreature(guid); + + // must be in range and creature must be alive for pickpocket and must be dead for another loot + if (!creature || creature->isAlive()!=(loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this,INTERACTION_DISTANCE)) + { + SendLootRelease(guid); + return; + } + + if (loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature)) + { + SendLootRelease(guid); + return; + } + + loot = &creature->loot; + + if (loot_type == LOOT_PICKPOCKETING) + { + if (!creature->lootForPickPocketed) + { + creature->lootForPickPocketed = true; + loot->clear(); + + if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) + loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false); + + // Generate extra money for pick pocket loot + const uint32 a = urand(0, creature->getLevel()/2); + const uint32 b = urand(0, getLevel()/2); + loot->gold = uint32(10 * (a + b) * sWorld.getConfig(CONFIG_FLOAT_RATE_DROP_MONEY)); + } } - // set group rights only for loot_type != LOOT_SKINNING else { - if(Group* group = GetGroup()) + // the player whose group may loot the corpse + Player *recipient = creature->GetLootRecipient(); + if (!recipient) { - if (group == recipient->GetGroup()) + creature->SetLootRecipient(this); + recipient = this; + } + + if (creature->lootForPickPocketed) + { + creature->lootForPickPocketed = false; + loot->clear(); + } + + if (!creature->lootForBody) + { + creature->lootForBody = true; + loot->clear(); + + if (uint32 lootid = creature->GetCreatureInfo()->lootid) + loot->FillLoot(lootid, LootTemplates_Creature, recipient, false); + + loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold,creature->GetCreatureInfo()->maxgold); + + if (Group* group = recipient->GetGroup()) { - if (group->GetLootMethod() == FREE_FOR_ALL) - permission = ALL_PERMISSION; - else if (group->GetLooterGuid() == GetGUID()) + group->UpdateLooterGuid(creature,true); + + switch (group->GetLootMethod()) { - if (group->GetLootMethod() == MASTER_LOOT) - permission = MASTER_PERMISSION; - else + case GROUP_LOOT: + // GroupLoot delete items over threshold (threshold even not implemented), and roll them. Items with qualityGroupLoot(recipient->GetGUID(), loot, creature); + break; + case NEED_BEFORE_GREED: + group->NeedBeforeGreed(recipient->GetGUID(), loot, creature); + break; + case MASTER_LOOT: + group->MasterLoot(recipient->GetGUID(), loot, creature); + break; + default: + break; + } + } + } + + // possible only if creature->lootForBody && loot->empty() at spell cast check + if (loot_type == LOOT_SKINNING) + { + loot->clear(); + loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false); + } + // set group rights only for loot_type != LOOT_SKINNING + else + { + if(Group* group = GetGroup()) + { + if (group == recipient->GetGroup()) + { + if (group->GetLootMethod() == FREE_FOR_ALL) permission = ALL_PERMISSION; + else if (group->GetLooterGuid() == GetGUID()) + { + if (group->GetLootMethod() == MASTER_LOOT) + permission = MASTER_PERMISSION; + else + permission = ALL_PERMISSION; + } + else + permission = GROUP_PERMISSION; } else - permission = GROUP_PERMISSION; + permission = NONE_PERMISSION; } + else if (recipient == this) + permission = ALL_PERMISSION; else permission = NONE_PERMISSION; } - else if (recipient == this) - permission = ALL_PERMISSION; - else - permission = NONE_PERMISSION; } + break; + } + default: + { + sLog.outError("%s is unsupported for looting.", guid.GetString().c_str()); + return; } } @@ -7785,7 +7798,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size - data << uint64(guid); + data << guid; data << uint8(loot_type); data << LootView(*loot, this, permission); @@ -7795,7 +7808,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (permission != NONE_PERMISSION) loot->AddLooter(GetGUID()); - if (loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid)) + if (loot_type == LOOT_CORPSE && !guid.IsItem()) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); } @@ -8670,47 +8683,31 @@ Item* Player::GetItemByLimitedCategory(uint32 limitedCategory) const return NULL; } -Item* Player::GetItemByGuid( uint64 guid ) const +Item* Player::GetItemByGuid(ObjectGuid guid) const { for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } + if (Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (pItem->GetGUID() == guid.GetRawValue()) + return pItem; + for(int i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) - { - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } + if (Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (pItem->GetGUID() == guid.GetRawValue()) + return pItem; for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { + if (Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) for(uint32 j = 0; j < pBag->GetBagSize(); ++j) - { - Item* pItem = pBag->GetItemByPos( j ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - } - } + if (Item* pItem = pBag->GetItemByPos(j)) + if (pItem->GetGUID() == guid.GetRawValue()) + return pItem; + for(int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) - { - Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if( pBag ) - { + if (Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) for(uint32 j = 0; j < pBag->GetBagSize(); ++j) - { - Item* pItem = pBag->GetItemByPos( j ); - if( pItem && pItem->GetGUID() == guid ) - return pItem; - } - } - } + if (Item* pItem = pBag->GetItemByPos(j)) + if (pItem->GetGUID() == guid.GetRawValue()) + return pItem; return NULL; } @@ -18876,13 +18873,13 @@ void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* targe } template -inline void UpdateVisibilityOf_helper(std::set& s64, T* target) +inline void UpdateVisibilityOf_helper(ObjectGuidSet& s64, T* target) { s64.insert(target->GetGUID()); } template<> -inline void UpdateVisibilityOf_helper(std::set& s64, GameObject* target) +inline void UpdateVisibilityOf_helper(ObjectGuidSet& s64, GameObject* target) { if(!target->IsTransport()) s64.insert(target->GetGUID()); @@ -19529,7 +19526,7 @@ void Player::UpdateForQuestWorldObjects() UpdateData udata; WorldPacket packet; - for(ClientGUIDs::const_iterator itr=m_clientGUIDs.begin(); itr!=m_clientGUIDs.end(); ++itr) + for(ObjectGuidSet::const_iterator itr=m_clientGUIDs.begin(); itr!=m_clientGUIDs.end(); ++itr) { if (itr->IsGameobject()) { diff --git a/src/game/Player.h b/src/game/Player.h index a4166be9a..cb67f1b7e 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1149,7 +1149,7 @@ class MANGOS_DLL_SPEC Player : public Unit uint8 FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const; uint32 GetItemCount( uint32 item, bool inBankAlso = false, Item* skipItem = NULL ) const; uint32 GetItemCountWithLimitCategory(uint32 limitCategory) const; - Item* GetItemByGuid( uint64 guid ) const; + Item* GetItemByGuid(ObjectGuid uint64) const; Item* GetItemByEntry(uint32 item) const; // only for special cases Item* GetItemByLimitedCategory(uint32 limitedCategory) const; Item* GetItemByPos( uint16 pos ) const; @@ -1789,8 +1789,8 @@ class MANGOS_DLL_SPEC Player : public Unit void ApplyManaRegenBonus(int32 amount, bool apply); void UpdateManaRegen(); - const uint64& GetLootGUID() const { return m_lootGuid; } - void SetLootGUID(const uint64 &guid) { m_lootGuid = guid; } + const uint64& GetLootGUID() const { return m_lootGuid.GetRawValue(); } + void SetLootGUID(ObjectGuid const& guid) { m_lootGuid = guid; } void RemovedInsignia(Player* looterPlr); @@ -1985,8 +1985,8 @@ class MANGOS_DLL_SPEC Player : public Unit PlayerMenu* PlayerTalkClass; std::vector ItemSetEff; - void SendLoot(uint64 guid, LootType loot_type); - void SendLootRelease( uint64 guid ); + void SendLoot(ObjectGuid guid, LootType loot_type); + void SendLootRelease(ObjectGuid guid ); void SendNotifyLootItemRemoved(uint8 lootSlot); void SendNotifyLootMoneyRemoved(); @@ -2178,8 +2178,7 @@ class MANGOS_DLL_SPEC Player : public Unit Object* GetObjectByTypeMask(ObjectGuid guid, TypeMask typemask); // currently visible objects at player client - typedef std::set ClientGUIDs; - ClientGUIDs m_clientGUIDs; + ObjectGuidSet m_clientGUIDs; bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } @@ -2375,7 +2374,7 @@ class MANGOS_DLL_SPEC Player : public Unit time_t m_lastHonorUpdateTime; void outDebugValues() const; - uint64 m_lootGuid; + ObjectGuid m_lootGuid; uint32 m_team; uint32 m_nextSave; diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index e925099af..d484ceb0b 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -639,7 +639,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); data << uint32(count); // placeholder - for(Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) + for(ObjectGuidSet::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) { uint8 questStatus = DIALOG_STATUS_NONE; uint8 defstatus = DIALOG_STATUS_NONE; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 037a6fa90..9e77eec3e 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -192,7 +192,7 @@ void SpellCastTargets::Update(Unit* caster) if(caster->GetTypeId() == TYPEID_PLAYER) { if(m_targetMask & TARGET_FLAG_ITEM) - m_itemTarget = ((Player*)caster)->GetItemByGuid(m_itemTargetGUID.GetRawValue()); + m_itemTarget = ((Player*)caster)->GetItemByGuid(m_itemTargetGUID); else if(m_targetMask & TARGET_FLAG_TRADE_ITEM) { Player* pTrader = ((Player*)caster)->GetTrader(); diff --git a/src/game/UpdateData.cpp b/src/game/UpdateData.cpp index ec3ba1434..8c9546f4d 100644 --- a/src/game/UpdateData.cpp +++ b/src/game/UpdateData.cpp @@ -30,7 +30,7 @@ UpdateData::UpdateData() : m_blockCount(0) { } -void UpdateData::AddOutOfRangeGUID(std::set& guids) +void UpdateData::AddOutOfRangeGUID(ObjectGuidSet& guids) { m_outOfRangeGUIDs.insert(guids.begin(),guids.end()); } @@ -115,7 +115,7 @@ bool UpdateData::BuildPacket(WorldPacket *packet) buf << (uint8) UPDATETYPE_OUT_OF_RANGE_OBJECTS; buf << (uint32) m_outOfRangeGUIDs.size(); - for(std::set::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) + for(ObjectGuidSet::const_iterator i = m_outOfRangeGUIDs.begin(); i != m_outOfRangeGUIDs.end(); ++i) buf << i->WriteAsPacked(); } diff --git a/src/game/UpdateData.h b/src/game/UpdateData.h index d6845b286..db8a9d227 100644 --- a/src/game/UpdateData.h +++ b/src/game/UpdateData.h @@ -20,9 +20,9 @@ #define __UPDATEDATA_H #include "ByteBuffer.h" +#include "ObjectGuid.h" class WorldPacket; -class ObjectGuid; enum OBJECT_UPDATE_TYPE { @@ -54,18 +54,18 @@ class UpdateData public: UpdateData(); - void AddOutOfRangeGUID(std::set& guids); + void AddOutOfRangeGUID(ObjectGuidSet& guids); void AddOutOfRangeGUID(ObjectGuid const &guid); void AddUpdateBlock(const ByteBuffer &block); bool BuildPacket(WorldPacket *packet); bool HasData() { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty(); } void Clear(); - std::set const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } + ObjectGuidSet const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } protected: uint32 m_blockCount; - std::set m_outOfRangeGUIDs; + ObjectGuidSet m_outOfRangeGUIDs; ByteBuffer m_data; void Compress(void* dst, uint32 *dst_size, void* src, int src_size); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 3c4cd778b..4a755ade5 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -255,7 +255,7 @@ class MANGOS_DLL_SPEC WorldSession void BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data); - void DoLootRelease( uint64 lguid ); + void DoLootRelease(ObjectGuid lguid); // Account mute time time_t m_muteTime; diff --git a/src/game/debugcmds.cpp b/src/game/debugcmds.cpp index ae04a623f..74a76c6d3 100644 --- a/src/game/debugcmds.cpp +++ b/src/game/debugcmds.cpp @@ -692,7 +692,7 @@ bool ChatHandler::HandleDebugGetItemValueCommand(const char* args) uint32 guid = (uint32)atoi(e); uint32 index = (uint32)atoi(f); - Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + Item *i = m_session->GetPlayer()->GetItemByGuid(ObjectGuid(HIGHGUID_ITEM, guid)); if (!i) return false; @@ -723,7 +723,7 @@ bool ChatHandler::HandleDebugSetItemValueCommand(const char* args) uint32 index = (uint32)atoi(f); uint32 value = (uint32)atoi(g); - Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + Item *i = m_session->GetPlayer()->GetItemByGuid(ObjectGuid(HIGHGUID_ITEM, guid)); if (!i) return false; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d00a99ed8..0f21bef72 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "9578" + #define REVISION_NR "9579" #endif // __REVISION_NR_H__