void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); uint32 count = 0; 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) { uint8 questStatus = DIALOG_STATUS_NONE; uint8 defstatus = DIALOG_STATUS_NONE; if (IS_CREATURE_OR_PET_GUID(*itr)) { // need also pet quests case support Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr); if(!questgiver || questgiver->IsHostileTo(_player)) continue; if(!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; questStatus = Script->NPCDialogStatus(_player, questgiver); if( questStatus > 6 ) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint8(questStatus); ++count; } else if(IS_GAMEOBJECT_GUID(*itr)) { GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); if(!questgiver) continue; if(questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; questStatus = Script->GODialogStatus(_player, questgiver); if( questStatus > 6 ) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint8(questStatus); ++count; } } data.put<uint32>(0, count); // write real count SendPacket(&data); }
void WorldSession::HandleQuestgiverStatusQueryMultipleOpcode(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); uint32 count = 0; WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); data << uint32(count); // placeholder for (Player::ClientGUIDs::iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) { uint8 questStatus = DIALOG_STATUS_NONE; uint8 defstatus = DIALOG_STATUS_NONE; if (IS_CREATURE_GUID(*itr)) { Creature *questgiver = GetPlayer()->GetMap()->GetCreature(*itr); if (!questgiver || questgiver->IsHostileTo(_player)) continue; if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; questStatus = sScriptMgr.GetDialogStatus(_player, questgiver); if (questStatus == DIALOG_STATUS_SCRIPTED_NO_STATUS) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint8(questStatus); ++count; } else if (IS_GAMEOBJECT_GUID(*itr)) { GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); if (!questgiver) continue; if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; questStatus = sScriptMgr.GetDialogStatus(_player, questgiver); if (questStatus == DIALOG_STATUS_SCRIPTED_NO_STATUS) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint8(questStatus); ++count; } } data.put<uint32>(0, count); // write real count SendPacket(&data); }
void WorldSession::SendStatusOfQuestGivers() { uint32 count = 0; WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 16); data << uint32(count); // placeholder for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) { uint32 questStatus = DIALOG_STATUS_NONE; uint32 defstatus = DIALOG_STATUS_NONE; if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) { // need also pet quests case support Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(), *itr); if (!questgiver || questgiver->IsHostileTo(_player)) continue; if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint32(questStatus); ++count; } else if (IS_GAMEOBJECT_GUID(*itr)) { GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); if (!questgiver) continue; if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); data << uint64(questgiver->GetGUID()); data << uint32(questStatus); ++count; } } data.put<uint32>(0, count); // write real count SendPacket(&data); }
bool WorldSession::CanOpenMailBox(uint64 guid) { if (guid == _player->GetGUID()) { sLog->outError("%s attempt open mailbox in cheating way.", _player->GetName().c_str()); return false; } else if (IS_GAMEOBJECT_GUID(guid)) { if (!_player->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_MAILBOX)) return false; } else if (IS_CRE_OR_VEH_OR_PET_GUID(guid)) { if (!_player->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_MAILBOX)) return false; } else return false; return true; }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { 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) { // 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) { 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) { float amount_rate = sWorld.getRate(RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if (uses < max_amount) { if (uses >= min_amount) { float chance_rate = sWorld.getRate(RATE_MINING_NEXT); int32 ReqValue = 175; LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); if (lockInfo) ReqValue = lockInfo->requiredminingskill; 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(100*chance+skill)) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already 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() >= irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else // not fully looted object go->SetLootState(GO_ACTIVATED); } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse *corpse = ObjectAccessor::GetCorpse(*player, 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); } } else if (IS_ITEM_GUID(lguid)) { Item *pItem = player->GetItemByGuid(lguid); if (!pItem) return; if ((pItem->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) && pItem->GetProto()->Class == ITEM_CLASS_TRADE_GOODS && pItem->GetCount() >= 5) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 count = 5; player->DestroyItemCount(pItem, count, true); } else // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating 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()) { // 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(); } } //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& recvData) { uint8 slotid; uint64 lootguid, target_playerguid; recvData >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName().c_str()); if (_player->GetLootGUID() != lootguid) return; Loot* loot = NULL; if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid >= loot->items.size() + loot->quest_items.size()) { TC_LOG_DEBUG(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = slotid >= loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (item.follow_loot_rules && !item.AllowedForPlayer(target)) msg = EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; // Obtener informaciĆ³n del item a entregar. ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item.itemid); std::string NombreItem = itemProto? itemProto->Name1:"Item"; if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); // Mandar alerta a todos los jugadores de la raid. if (Group* group = _player->GetGroup()) { for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { if (Player* member = itr->GetSource()) { ChatHandler(member->GetSession()).PSendSysMessage("No se pudo entregar por ML [|Hitem:%i:0:0:0:0:0:0:0:80|h%s|h|r] a %s", item.itemid, NombreItem.c_str(), target->GetName().c_str()); } } } return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // not move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; loot->NotifyItemRemoved(slotid); --loot->unlootedCount; // Mandar alerta a todos los jugadores de la raid. if (Group* group = _player->GetGroup()) { for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { if (Player* member = itr->GetSource()) { ChatHandler(member->GetSession()).PSendSysMessage("Entregado por ML [|Hitem:%i:0:0:0:0:0:0:0:80|h%s|h|r] a %s", item.itemid, NombreItem.c_str(), target->GetName().c_str()); } } } }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot* loot = NULL; uint8 lootSlot = 0; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(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; } 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 = ObjectAccessor::GetCorpse(*player, lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } loot = &creature->loot; } player->StoreLootItem(lootSlot, loot); }
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_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if (_player->GetLootGUID() != lootguid) return; if (_player->GetInstanceId() != target->GetInstanceId()) return; Loot *pLoot = NULL; if (IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) { Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!pCreature) return; pLoot = &pCreature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(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; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); 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, item.itemid, true, item.randomPropertyId); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->SaveToDB(); // mark as looted item.count=0; pLoot->setItemLooted(&item, target); pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { 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) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if ((go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.consumable) || loot->isLooted()) { 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()>=irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens)) { go->SetLootState(GO_JUST_DEACTIVATED); } else go->SetLootState(GO_READY); } else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse *corpse = ObjectAccessor::GetCorpse(*player, 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); } } 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) && proto->Class == ITEM_CLASS_TRADE_GOODS) { pItem->m_lootGenerated = false; pItem->loot.clear(); uint32 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 { 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; if (player->GetGUID() == loot->looterGUID) { loot->looterGUID = 0; if (Group *group = player->GetGroup()) group->SendRoundRobin(loot, 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(); } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); // should be fixed after some research in loot implementation etc // loot->RemoveQuestLoot(player); }
void WorldSession::HandleLootMasterAskForRoll(WorldPacket& recvData) { ObjectGuid guid = 0; uint8 slot = 0; recvData >> slot; uint8 bitOrder[8] = {6, 0, 4, 3, 2, 7, 1, 5}; recvData.ReadBitInOrder(guid, bitOrder); uint8 byteOrder[8] = {2, 0, 7, 5, 3, 6, 1, 4}; recvData.ReadBytesSeq(guid, byteOrder); if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Loot* loot = NULL; if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(guid); if (!creature) return; loot = &creature->loot; if (loot->isLinkedLoot(slot)) { LinkedLootInfo linkedLootInfo = loot->getLinkedLoot(slot); creature = GetPlayer()->GetCreature(*GetPlayer(), linkedLootInfo.creatureGUID); if (!creature) return; loot = &creature->loot; slot = linkedLootInfo.slot; } } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(guid); if (!pGO) return; loot = &pGO->loot; } if (!loot || loot->alreadyAskedForRoll) return; if (slot >= loot->items.size() + loot->quest_items.size()) { sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slot, (unsigned long)loot->items.size()); return; } LootItem& item = slot >= loot->items.size() ? loot->quest_items[slot - loot->items.size()] : loot->items[slot]; loot->alreadyAskedForRoll = true; _player->GetGroup()->DoRollForAllMembers(guid, slot, _player->GetMapId(), loot, item, _player); }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot* loot = NULL; uint8 lootSlot = 0; uint8 linkedLootSlot = 255; uint32 count = recvData.ReadBits(23); std::vector<ObjectGuid> guids; guids.resize(count); uint8 bitOrder[8] = { 2, 1, 5, 7, 4, 3, 0, 6 }; for (uint32 i = 0; i < count; i++) recvData.ReadBitInOrder(guids[i], bitOrder); recvData.FlushBits(); for (uint32 i = 0; i < count; i++) { recvData.ReadByteSeq(guids[i][0]); recvData.ReadByteSeq(guids[i][3]); recvData >> lootSlot; recvData.ReadByteSeq(guids[i][7]); recvData.ReadByteSeq(guids[i][2]); recvData.ReadByteSeq(guids[i][4]); recvData.ReadByteSeq(guids[i][1]); recvData.ReadByteSeq(guids[i][6]); recvData.ReadByteSeq(guids[i][5]); linkedLootSlot = 0xFF; if (IS_GAMEOBJECT_GUID(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; } 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 = ObjectAccessor::GetCorpse(*player, lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || (!creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE) && !_player->HasSpell(125048))) { player->SendLootRelease(lguid); return; } loot = &creature->loot; if (loot->isLinkedLoot(lootSlot)) { LinkedLootInfo linkedLootInfo = loot->getLinkedLoot(lootSlot); creature = player->GetCreature(*player, linkedLootInfo.creatureGUID); if (!creature) { player->SendLootRelease(lguid); return; } loot = &creature->loot; linkedLootSlot = lootSlot; lootSlot = linkedLootInfo.slot; } } player->StoreLootItem(lootSlot, loot, linkedLootSlot); } }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recv_data) { uint8 slotid; uint64 lootguid, target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetMasterLooterGuid() != _player->GetGUID() || _player->GetGroup()->GetLootMethod() != MASTER_LOOT) { _player->SendLootError(lootguid, LOOT_ERROR_DIDNT_KILL); return; } Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) { _player->SendLootError(lootguid, LOOT_ERROR_PLAYER_NOT_FOUND); return; } // TODO : add some error message? if (_player->GetMapId() != target->GetMapId() || _player->GetDistance(target) > sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) return; sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if (_player->GetLootGUID() != lootguid) { _player->SendLootError(lootguid, LOOT_ERROR_DIDNT_KILL); return; } Loot* pLoot = NULL; if (IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!pCreature) return; pLoot = &pCreature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(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 %lu)", GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (msg != EQUIP_ERR_OK) { if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) _player->SendLootError(lootguid, LOOT_ERROR_MASTER_UNIQUE_ITEM); else if (msg == EQUIP_ERR_INVENTORY_FULL) _player->SendLootError(lootguid, LOOT_ERROR_MASTER_INV_FULL); else _player->SendLootError(lootguid, LOOT_ERROR_MASTER_OTHER); target->SendEquipError(msg, NULL, NULL); return; } // now move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId); target->SendNewItem(newitem, uint32(item.count), false, false, true); // mark as looted item.count = 0; item.is_looted = true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) { 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_NEW_GUID(target_playerguid, 0, 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_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!pCreature) return; pLoot = &pCreature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(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 %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // not move item from loot to target inventory Item * newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot* loot = NULL; uint8 lootSlot = 0; recvData >> lootSlot; if (IS_GAMEOBJECT_GUID(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; } 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 = ObjectAccessor::GetCorpse(*player, lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); return; } loot = &creature->loot; } player->StoreLootItem(lootSlot, loot); // If player is removing the last LootItem, delete the empty container. if (loot->isLooted() && IS_ITEM_GUID(lguid)) player->GetSession()->DoLootRelease(lguid); }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { 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) { // locked doors are opened with spelleffect openlock, prevent remove its as looted go->UseDoorOrButton(); } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { 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() >= go->GetGOValue()->FishingHole.MaxOpens) go->SetLootState(GO_JUST_DEACTIVATED); else go->SetLootState(GO_READY); } else go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else { // not fully looted object go->SetLootState(GO_ACTIVATED, player); // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) loot->roundRobinPlayer = 0; } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse* corpse = ObjectAccessor::GetCorpse(*player, 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); } } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) return; ItemTemplate const* proto = pItem->GetTemplate(); // destroy only 5 items from stack in case prospecting and milling if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) { pItem->m_lootGenerated = false; pItem->loot.clear(); 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 { if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db) player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } return; // item can be looted only single player } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &creature->loot; if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->IsAlive()) creature->AllLootRemovedFromCorpse(); creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } else { // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { loot->roundRobinPlayer = 0; if (Group* group = player->GetGroup()) { group->SendLooter(creature, NULL); // force update of dynamic flags, otherwise other group's players still not able to loot. creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); } } } } //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& recvData) { uint8 slotid; uint64 lootguid, target_playerguid; recvData >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetMasterLooterGuid() != _player->GetGUID() || _player->GetGroup()->GetLootMethod() != MASTER_LOOT) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; TC_LOG_DEBUG("network", "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName().c_str()); if (_player->GetLootGUID() != lootguid) return; if (!_player->IsInRaidWith(target) || !_player->IsInMap(target)) { TC_LOG_INFO("loot", "MasterLootItem: Player %s tried to give an item to ineligible player %s !", GetPlayer()->GetName().c_str(), target->GetName().c_str()); return; } Loot* loot = NULL; if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid >= loot->items.size() + loot->quest_items.size()) { TC_LOG_DEBUG("loot", "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = slotid >= loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (item.follow_loot_rules && !item.AllowedForPlayer(target)) msg = EQUIP_ERR_CANT_EQUIP_EVER; if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // not move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item.itemid, item.count, loot->loot_type); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; loot->NotifyItemRemoved(slotid); --loot->unlootedCount; }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 guid = player->GetLootGUID(); Loot* loot = NULL; uint8 count = 0; if (IS_GAMEOBJECT_GUID(guid)) { GameObject* go = player->GetMap()->GetGameObject(guid); // 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(guid); return; } loot = &go->loot; } else if (IS_ITEM_GUID(guid)) { Item* pItem = player->GetItemByGuid(guid); if (!pItem) { player->SendLootRelease(guid); return; } loot = &pItem->loot; } else if (IS_CORPSE_GUID(guid)) { Corpse* bones = ObjectAccessor::GetCorpse(*player, guid); if (!bones) { player->SendLootRelease(guid); return; } loot = &bones->loot; } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(guid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootRelease(guid); return; } loot = &creature->loot; } uint32 Count = recvData.ReadBits(23); std::map<uint32, ObjectGuid> Guids; for (uint32 i = 0 ; i < Count ; ++i) { (Guids[i])[2] = recvData.ReadBit(); (Guids[i])[7] = recvData.ReadBit(); (Guids[i])[0] = recvData.ReadBit(); (Guids[i])[6] = recvData.ReadBit(); (Guids[i])[5] = recvData.ReadBit(); (Guids[i])[3] = recvData.ReadBit(); (Guids[i])[1] = recvData.ReadBit(); (Guids[i])[4] = recvData.ReadBit(); } for (uint32 i = 0 ; i < Count ; ++i) { recvData.ReadByteSeq((Guids[i])[0]); recvData.ReadByteSeq((Guids[i])[4]); recvData.ReadByteSeq((Guids[i])[1]); recvData.ReadByteSeq((Guids[i])[7]); recvData.ReadByteSeq((Guids[i])[6]); recvData.ReadByteSeq((Guids[i])[5]); recvData.ReadByteSeq((Guids[i])[3]); recvData.ReadByteSeq((Guids[i])[2]); uint8 lootSlot; recvData >> lootSlot; player->StoreLootItem(lootSlot, loot, guid); } // If player is removing the last LootItem, delete the empty container. if (loot->isLooted() && IS_ITEM_GUID(guid)) player->GetSession()->DoLootRelease(guid); }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data,1); sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player *player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot *loot; uint8 lootSlot; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(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; } 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 = ObjectAccessor::GetCorpse(*player, 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; QuestItem *ffaitem = NULL; QuestItem *conditem = NULL; LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); if (!item) { player->SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); return; } // questitems use the blocked field for other purposes if (!qitem && item->is_blocked) { player->SendLootRelease(lguid); return; } ItemPosCountVec dest; uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); if (msg == EQUIP_ERR_OK) { Item * newitem = player->StoreNewItem(dest, item->itemid, true, item->randomPropertyId); if (qitem) { qitem->is_looted = true; //freeforall is 1 if everyone's supposed to get the quest item. if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) player->SendNotifyLootItemRemoved(lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } else { if (ffaitem) { //freeforall case, notify only one player of the removal ffaitem->is_looted = true; player->SendNotifyLootItemRemoved(lootSlot); } else { //not freeforall, notify everyone if (conditem) conditem->is_looted = true; loot->NotifyItemRemoved(lootSlot); } } //if only one person is supposed to loot the item, then set it to looted if (!item->freeforall) loot->setItemLooted(item, player); --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); } else player->SendEquipError(msg, NULL, NULL); }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) { ObjectGuid target_playerguid = 0; target_playerguid[6] = recvData.ReadBit(); target_playerguid[2] = recvData.ReadBit(); target_playerguid[1] = recvData.ReadBit(); target_playerguid[3] = recvData.ReadBit(); target_playerguid[7] = recvData.ReadBit(); target_playerguid[5] = recvData.ReadBit(); uint32 count = recvData.ReadBits(25); if (count > 40) return; std::vector<ObjectGuid> guids(count); std::vector<uint8> types(count); uint8 bitOrder[8] = {4, 6, 7, 5, 0, 1, 3, 2}; for (uint32 i = 0; i < count; ++i) recvData.ReadBitInOrder(guids[i], bitOrder); target_playerguid[4] = recvData.ReadBit(); target_playerguid[0] = recvData.ReadBit(); recvData.FlushBits(); uint8 byteOrder[8] = {6, 7, 3, 1, 0, 5, 4, 2}; for (uint32 i = 0; i < count; ++i) { recvData.ReadBytesSeq(guids[i], byteOrder); recvData >> types[i]; } uint8 byteOrder2[8] = {7, 0, 5, 6, 4, 3, 2, 1}; recvData.ReadBytesSeq(target_playerguid, byteOrder2); //recvData >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); for (uint32 i = 0; i < count; ++i) { ObjectGuid lootguid = guids[i]; uint8 slotid = types[i]; Loot* loot = NULL; if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid >= loot->items.size() + loot->quest_items.size()) { sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = slotid >= loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (item.follow_loot_rules && !item.AllowedForPlayer(target)) msg = EQUIP_ERR_CANT_EQUIP_EVER; if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // not move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; loot->NotifyItemRemoved(slotid, _player->GetLootGUID()); --loot->unlootedCount; } }
void WorldSession::DoLootRelease(uint64 lguid) { Player *player = GetPlayer(); Loot *loot; player->SetLootGUID(0); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; if (IS_GAMEOBJECT_GUID(lguid)) { 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) { // 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) { 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) { float amount_rate = sWorld->getRate(RATE_MINING_AMOUNT); float min_amount = go_min*amount_rate; float max_amount = go_max*amount_rate; go->AddUse(); float uses = float(go->GetUseCount()); if (uses < max_amount) { if (uses >= min_amount) { float chance_rate = sWorld->getRate(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*chance+skill))) { go->SetLootState(GO_READY); } else // not have more uses go->SetLootState(GO_JUST_DEACTIVATED); } else // 100% chance until min uses go->SetLootState(GO_READY); } else // max uses already 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 go->SetLootState(GO_READY); } else // not chest (or vein/herb/etc) go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); } else { // not fully looted object go->SetLootState(GO_ACTIVATED, player); // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) { loot->roundRobinPlayer = 0; } } else loot->roundRobinPlayer = 0; } } } else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG { Corpse* corpse = ObjectAccessor::GetCorpse(*player, 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); } } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) return; ItemTemplate const* proto = pItem->GetTemplate(); // destroy only 5 items from stack in case prospecting and milling if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) { pItem->m_lootGenerated = false; pItem->loot.clear(); 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 must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); return; // item can be looted only single player } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) return; loot = &creature->loot; if (loot->isLooted()) { // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->isAlive()) creature->AllLootRemovedFromCorpse(); creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } else { // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) { if (Group* group = player->GetGroup()) { if (group->GetLootMethod() != MASTER_LOOT) { loot->roundRobinPlayer = 0; group->SendLooter(creature, NULL); // force update of dynamic flags, otherwise other group's players still not able to loot. creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); } } else loot->roundRobinPlayer = 0; } } } //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) { bool isCurrency = recv_data.GetOpcode() == CMSG_AUTOSTORE_LOOT_CURRENCY; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot* loot = NULL; uint8 lootSlot = 0; uint32 objEntry = 0; uint32 objType = 0; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(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; } objEntry = go->GetGOInfo()->entry; objType = 3; loot = &go->loot; } else if (IS_ITEM_GUID(lguid)) { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) { player->SendLootRelease(lguid); return; } objEntry = pItem->GetTemplate()->ItemId; objType = 2; loot = &pItem->loot; } else if (IS_CORPSE_GUID(lguid)) { Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; } else { Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } objEntry = creature->GetCreatureTemplate()->Entry; objType = 1; loot = &creature->loot; } if (isCurrency && loot) { uint8 currencys = 0; std::list<CurrencyLoot> temp = sObjectMgr->GetCurrencyLoot(objEntry, objType); for (std::list<CurrencyLoot>::iterator i = temp.begin(); i != temp.end(); ++i) { if (currencys == lootSlot) player->SetCurrency(i->CurrencyId, i->CurrencyAmount * 100); ++currencys; } } else if (loot) player->StoreLootItem(lootSlot, loot); }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) { 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_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if (_player->GetLootGUID() != lootguid) return; Loot* loot = NULL; if (IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid > loot->items.size()) { sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // not move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); // mark as looted item.count=0; item.is_looted=true; loot->NotifyItemRemoved(slotid); --loot->unlootedCount; }
void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); uint32 count = 0; ByteBuffer byteData; WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 3 + count * (1 + 8 + 4)); size_t pos = data.bitwpos(); data.WriteBits(count, 21); // placeholder for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) { uint32 questStatus = DIALOG_STATUS_NONE; uint32 defstatus = DIALOG_STATUS_NONE; if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) { // need also pet quests case support Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(), *itr); if (!questgiver || questgiver->IsHostileTo(_player)) continue; if (!questgiver->HasFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); ObjectGuid guid = questgiver->GetGUID(); data.WriteBit(guid[4]); data.WriteBit(guid[0]); data.WriteBit(guid[3]); data.WriteBit(guid[6]); data.WriteBit(guid[5]); data.WriteBit(guid[7]); data.WriteBit(guid[1]); data.WriteBit(guid[2]); byteData.WriteByteSeq(guid[6]); byteData.WriteByteSeq(guid[2]); byteData.WriteByteSeq(guid[7]); byteData.WriteByteSeq(guid[5]); byteData.WriteByteSeq(guid[4]); byteData << uint32(questStatus); byteData.WriteByteSeq(guid[1]); byteData.WriteByteSeq(guid[3]); byteData.WriteByteSeq(guid[0]); ++count; } else if (IS_GAMEOBJECT_GUID(*itr)) { GameObject* questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); if (!questgiver) continue; if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); ObjectGuid guid = questgiver->GetGUID(); data.WriteBit(guid[4]); data.WriteBit(guid[0]); data.WriteBit(guid[3]); data.WriteBit(guid[6]); data.WriteBit(guid[5]); data.WriteBit(guid[7]); data.WriteBit(guid[1]); data.WriteBit(guid[2]); byteData.WriteByteSeq(guid[6]); byteData.WriteByteSeq(guid[2]); byteData.WriteByteSeq(guid[7]); byteData.WriteByteSeq(guid[5]); byteData.WriteByteSeq(guid[4]); byteData << uint32(questStatus); byteData.WriteByteSeq(guid[1]); byteData.WriteByteSeq(guid[3]); byteData.WriteByteSeq(guid[0]); ++count; } } data.FlushBits(); data.PutBits(pos, count, 21); data.append(byteData); SendPacket(&data); }