void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); ObjectGuid lguid = player->GetLootGuid(); Loot* loot; uint8 lootSlot; Item* pItem = NULL; recv_data >> lootSlot; switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { 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->GetObjectGuid() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) { player->SendLootRelease(lguid); return; } loot = &go->loot; break; } case HIGHGUID_ITEM: { pItem = player->GetItemByGuid(lguid); if (!pItem || !pItem->HasGeneratedLoot()) { 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; } } 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; } if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); ItemPosCountVec dest; InventoryResult 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) item->is_looted = true; --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); } else player->SendEquipError(msg, NULL, NULL, item->itemid); }
void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) { DEBUG_LOG("WORLD: CMSG_LOOT_MONEY"); Player* player = GetPlayer(); ObjectGuid guid = player->GetLootGuid(); if (!guid) return; Loot* pLoot = NULL; Item* pItem = NULL; switch (guid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject* pGameObject = GetPlayer()->GetMap()->GetGameObject(guid); // not check distance for GO in case owned GO (fishing bobber case, for example) if (pGameObject && (pGameObject->GetOwnerGuid() == _player->GetObjectGuid() || pGameObject->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) pLoot = &pGameObject->loot; break; } case HIGHGUID_CORPSE: // remove insignia ONLY in BG { Corpse* bones = _player->GetMap()->GetCorpse(guid); if (bones && bones->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) pLoot = &bones->loot; break; } case HIGHGUID_ITEM: { pItem = GetPlayer()->GetItemByGuid(guid); if (!pItem || !pItem->HasGeneratedLoot()) return; pLoot = &pItem->loot; break; } case HIGHGUID_UNIT: { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); if (ok_loot && pCreature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) pLoot = &pCreature->loot ; break; } default: return; // unlootable type } if (pLoot) { pLoot->NotifyMoneyRemoved(); if (!guid.IsItem() && player->GetGroup()) // item can be looted only single player { Group* group = player->GetGroup(); std::vector<Player*> playersNear; for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* playerGroup = itr->getSource(); if (!playerGroup) continue; if (player->IsWithinDistInMap(playerGroup, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false)) playersNear.push_back(playerGroup); } uint32 money_per_player = uint32((pLoot->gold) / (playersNear.size())); for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) { (*i)->ModifyMoney(money_per_player); WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4); data << uint32(money_per_player); (*i)->GetSession()->SendPacket(&data); } } else player->ModifyMoney(pLoot->gold); pLoot->gold = 0; if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); } }
void WorldSession::DoLootRelease(ObjectGuid lguid) { Player* player = GetPlayer(); Loot* loot; player->SetLootGuid(ObjectGuid()); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) return; switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { 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->GetObjectGuid() && 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.getConfig(CONFIG_FLOAT_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.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 // 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 at 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); break; } case HIGHGUID_CORPSE: // 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()) { loot->clear(); corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); } break; } case HIGHGUID_ITEM: { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) return; switch (pItem->loot.loot_type) { // temporary loot in stacking items, clear loot state, no auto loot move case LOOT_PROSPECTING: { 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; // reset loot for allow repeat looting if stack > 5 pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItemCount(pItem, count, true); break; } // temporary loot, auto loot move case LOOT_DISENCHANTING: { if (!pItem->loot.isLooted()) player->AutoStoreLoot(pItem->loot); // can be lost if no space pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); break; } // normal persistence loot default: { // must be destroyed only if no loot if (pItem->loot.isLooted()) { pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } break; } } return; // item can be looted only single player } 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)) return; loot = &pCreature->loot; // update next looter if (Group* group = pCreature->GetGroupLootRecipient()) if (group->GetLooterGuid() == player->GetObjectGuid()) group->UpdateLooterGuid(pCreature); if (loot->isLooted()) { // for example skinning after normal loot pCreature->PrepareBodyLootState(); if (!pCreature->isAlive()) pCreature->AllLootRemovedFromCorpse(); } break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } // Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetObjectGuid()); }
bool ChatHandler::HandleTargetAndDeleteObjectCommand(char *args) { Player* pl = m_session->GetPlayer(); QueryResult *result; uint32 id = args && *args ? atoi((char*)args) : 0; float distance = 100; // should be ok as max. if(id) { // copied from HandleGameObjectNearCommand result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' AND id = '%u' ORDER BY order_", pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(), pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance, id); } else { // copied from HandleGameObjectNearCommand, added id = '...' to WHERE part result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(), pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(),distance*distance); } if (!result) { SendSysMessage("Nothing found!"); return true; } Field *fields = result->Fetch(); uint32 guid32 = fields[0].GetUInt32(); id = fields[1].GetUInt32(); float x = fields[2].GetFloat(); float y = fields[3].GetFloat(); float z = fields[4].GetFloat(); float o = fields[5].GetFloat(); int mapid = fields[6].GetUInt16(); delete result; const GameObjectInfo *goI = sObjectMgr.GetGameObjectInfo(id); if (!goI) { PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id); return false; } ObjectGuid guid(HIGHGUID_GAMEOBJECT, id, guid32); GameObject* obj = m_session->GetPlayer()->GetMap()->GetGameObject(guid); if(!obj) { PSendSysMessage("Game Object (GUID: %u) not found", guid32); return true; } ObjectGuid owner_guid = obj->GetOwnerGuid(); if(!owner_guid.IsEmpty()) { Unit* owner = ObjectAccessor::Instance().GetUnit(*m_session->GetPlayer(),owner_guid); if(!owner && !owner_guid.IsPlayer()) { PSendSysMessage("Game Object (GUID: %u) have references in not found creature %u GO list, can't be deleted.", owner_guid.GetCounter(), obj->GetGUIDLow()); return true; } owner->RemoveGameObject(obj,false); } obj->Delete(); obj->DeleteFromDB(); PSendSysMessage("Game Object (GUID: %u) [%s] removed", obj->GetGUIDLow(),goI->name); return true; }
void WorldSession::DoLootRelease(ObjectGuid lguid) { Player* player = GetPlayer(); Loot* loot; player->SetLootGuid(ObjectGuid()); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); if (!player->IsInWorld()) { return; } switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { 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->GetObjectGuid() && 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.getConfig(CONFIG_FLOAT_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.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 // 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 at 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); } go->SetGoState(GO_STATE_READY); break; } /* Only used for removing insignia in battlegrounds */ case HIGHGUID_CORPSE: { /* Get pointer to corpse */ Corpse* corpse = _player->GetMap()->GetCorpse(lguid); /* If corpse is invalid or not in a valid position, dont allow looting */ 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; } case HIGHGUID_ITEM: { Item* pItem = player->GetItemByGuid(lguid); if (!pItem) { return; } switch (pItem->loot.loot_type) { // temporary loot in stacking items, clear loot state, no auto loot move case LOOT_PROSPECTING: { 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; // reset loot for allow repeat looting if stack > 5 pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItemCount(pItem, count, true); break; } // temporary loot, auto loot move case LOOT_DISENCHANTING: { if (!pItem->loot.isLooted()) { player->AutoStoreLoot(pItem->loot); } // can be lost if no space pItem->loot.clear(); pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); break; } // normal persistence loot default: { // must be destroyed only if no loot if (pItem->loot.isLooted()) { pItem->SetLootState(ITEM_LOOT_REMOVED); player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } break; } } return; // item can be looted only single player } case HIGHGUID_UNIT: { /* Get creature pointer */ Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = (pCreature && // The creature exists (we dont have a null pointer) pCreature->IsAlive() == // Creature is alive and we're a rogue and creature can be pickpocketed (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed)); if (!ok_loot || !pCreature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { return; } /* Copy creature loot to loot variable */ loot = &pCreature->loot; /* Update for other players. */ if(!loot->isLooted()) { Group const* group = pCreature->GetGroupLootRecipient(); if (group && !pCreature->hasBeenLootedOnce) { // Checking whether it has been looted once by the designed looter (master loot case). switch (group->GetLootMethod()) { case FREE_FOR_ALL: case NEED_BEFORE_GREED: case ROUND_ROBIN: case GROUP_LOOT: { pCreature->hasBeenLootedOnce = true; break; } case MASTER_LOOT: { pCreature->hasBeenLootedOnce = (group->GetLooterGuid() == player->GetObjectGuid()); break; } } pCreature->MarkFlagUpdateForClient(UNIT_DYNAMIC_FLAGS); } } /* We've completely looted the creature, mark it as available for skinning */ if (loot->isLooted() && !pCreature->IsAlive()) { /* Update Creature: for example skinning after normal loot */ pCreature->PrepareBodyLootState(); pCreature->AllLootRemovedFromCorpse(); } break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } // Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetObjectGuid()); }
void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: %s", LookupOpcodeName(recv_data.GetOpcode())); Player* player = GetPlayer(); ObjectGuid lguid = player->GetLootGuid(); Loot* loot; uint8 lootSlot; Item* pItem = NULL; recv_data >> lootSlot; switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { 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->GetObjectGuid() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) { player->SendLootRelease(lguid); return; } loot = &go->loot; break; } case HIGHGUID_ITEM: { pItem = player->GetItemByGuid(lguid); if (!pItem || !pItem->HasGeneratedLoot()) { 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: case HIGHGUID_VEHICLE: { 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; } } QuestItem* qitem = NULL; QuestItem* ffaitem = NULL; QuestItem* conditem = NULL; QuestItem* currency = NULL; LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem, ¤cy); 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; } if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); if (currency) { if (CurrencyTypesEntry const * currencyEntry = sCurrencyTypesStore.LookupEntry(item->itemid)) player->ModifyCurrencyCount(item->itemid, int32(item->count * currencyEntry->GetPrecision())); player->SendNotifyLootItemRemoved(lootSlot, true); currency->is_looted = true; --loot->unlootedCount; return; } ItemPosCountVec dest; InventoryResult 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, item->GetAllowedLooters()); 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) item->is_looted = true; --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); if (ItemPrototype const* proto = sObjectMgr.GetItemPrototype(item->itemid)) if (proto->Quality > ITEM_QUALITY_EPIC || (proto->Quality == ITEM_QUALITY_EPIC && proto->ItemLevel >= MinNewsItemLevel[sWorld.getConfig(CONFIG_UINT32_EXPANSION)])) if (Guild* guild = sGuildMgr.GetGuildById(player->GetGuildId())) guild->LogNewsEvent(GUILD_NEWS_ITEM_LOOTED, time(NULL), player->GetObjectGuid(), 0, item->itemid); } else player->SendEquipError(msg, NULL, NULL, item->itemid); }
void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recv_data*/) { DEBUG_LOG("WORLD: CMSG_LOOT_MONEY"); Player* player = GetPlayer(); ObjectGuid guid = player->GetLootGuid(); if (!guid) return; Loot* pLoot = NULL; Item* pItem = NULL; switch (guid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject* pGameObject = GetPlayer()->GetMap()->GetGameObject(guid); // not check distance for GO in case owned GO (fishing bobber case, for example) if (pGameObject && (pGameObject->GetOwnerGuid() == _player->GetObjectGuid() || pGameObject->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) pLoot = &pGameObject->loot; break; } case HIGHGUID_CORPSE: // remove insignia ONLY in BG { Corpse* bones = _player->GetMap()->GetCorpse(guid); if (bones && bones->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) pLoot = &bones->loot; break; } case HIGHGUID_ITEM: { pItem = GetPlayer()->GetItemByGuid(guid); if (!pItem || !pItem->HasGeneratedLoot()) return; pLoot = &pItem->loot; break; } case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); if (ok_loot && pCreature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) pLoot = &pCreature->loot ; break; } default: return; // unlootable type } if (pLoot) { pLoot->NotifyMoneyRemoved(); if (!guid.IsItem() && player->GetGroup()) // item can be looted only single player { Group* group = player->GetGroup(); std::vector<Player*> playersNear; for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* playerGroup = itr->getSource(); if (!playerGroup) continue; if (player->IsWithinDistInMap(playerGroup, sWorld.getConfig(CONFIG_FLOAT_GROUP_XP_DISTANCE), false)) playersNear.push_back(playerGroup); } if (playersNear.size() == 0) { sLog.outError("WorldSession::HandleLootMoneyOpcode %s try aquire group loot without any group member! Cheat attempt assumed.", player->GetObjectGuid().GetString().c_str()); return; } uint64 money_per_player = uint32((pLoot->gold) / (playersNear.size())); for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) { (*i)->ModifyMoney(money_per_player); (*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player); if (Guild* guild = sGuildMgr.GetGuildById((*i)->GetGuildId())) if (uint32 guildGold = (*i)->GetTotalAuraModifier(SPELL_AURA_MOD_MONEY_TO_GUILD_BANK) / 100.0f * money_per_player) guild->HandleCashFlow(guildGold, *i); WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4+1); data << uint32(money_per_player); data << uint8(playersNear.size() > 1 ? 0 : 1);// 0 is "you share of loot..." (*i)->GetSession()->SendPacket(&data); } } else { player->ModifyMoney(pLoot->gold); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold); if (Guild* guild = sGuildMgr.GetGuildById(player->GetGuildId())) if (uint32 guildGold = player->GetTotalAuraModifier(SPELL_AURA_MOD_MONEY_TO_GUILD_BANK) / 100.0f * pLoot->gold) guild->HandleCashFlow(guildGold, player); WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4+1); data << uint32(pLoot->gold); data << uint8(1); // 1 is "you loot..." player->GetSession()->SendPacket(&data); } pLoot->gold = 0; if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); } }
void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player *player = GetPlayer(); ObjectGuid lguid = player->GetLootGuid(); Loot *loot; uint8 lootSlot; recv_data >> lootSlot; switch( lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { 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->GetObjectGuid() && 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 || !pItem->HasGeneratedLoot()) { 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: case HIGHGUID_VEHICLE: { 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; } } player->StoreLootItem(lootSlot, loot); }