//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSellItem& packet) { if (packet.Items.size() > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } for (auto const& item : packet.Items) if (!item.Guid || !item.UseCount || item.UseCount > 1000) return; if (!packet.MinBid || !packet.RunTime) return; if (packet.MinBid > MAX_MONEY_AMOUNT || packet.BuyoutPrice > MAX_MONEY_AMOUNT) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (%s) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUID().ToString().c_str()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) not found or you can't interact with him.", packet.Auctioneer.ToString().c_str()); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", packet.Auctioneer.ToString().c_str()); return; } packet.RunTime *= MINUTE; switch (packet.RunTime) { case 1 * MIN_AUCTION_TIME: case 2 * MIN_AUCTION_TIME: case 4 * MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); uint32 finalCount = 0; for (auto const& packetItem : packet.Items) { Item* item = _player->GetItemByGuid(packetItem.Guid); if (!item) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < packetItem.UseCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } finalCount += packetItem.UseCount; } if (packet.Items.empty()) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } if (!finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } // check if there are 2 identical guids, in this case user is most likely cheating for (uint32 i = 0; i < packet.Items.size() - 1; ++i) { for (uint32 j = i + 1; j < packet.Items.size(); ++j) { if (packet.Items[i].Guid == packet.Items[j].Guid) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } } for (auto const& packetItem : packet.Items) { Item* item = _player->GetItemByGuid(packetItem.Guid); if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = _player->GetItemByGuid(packet.Items[0].Guid); uint32 auctionTime = uint32(packet.RunTime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, packet.RunTime, item, finalCount); if (!_player->HasEnoughMoney((uint64)deposit)) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = UI64LIT(23442); ///@TODO - HARDCODED DB GUID, BAD BAD BAD else AH->auctioneer = packet.Auctioneer.GetCounter(); // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (packet.Items.size() == 1 && item->GetCount() == packet.Items[0].UseCount) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUID().GetCounter(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = packet.MinBid; AH->bidder = UI64LIT(0); AH->bid = 0; AH->buyout = packet.BuyoutPrice; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: %s %s is selling item %s %s to auctioneer " UI64FMTD " with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), item->GetGUID().ToString().c_str(), item->GetTemplate()->GetDefaultLocaleName(), AH->auctioneer, item->GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->GetDefaultLocaleName(), newItem->GetEntry(), newItem->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUID().GetCounter(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = packet.MinBid; AH->bidder = UI64LIT(0); AH->bid = 0; AH->buyout = packet.BuyoutPrice; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: %s %s is selling %s %s to auctioneer " UI64FMTD " with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), newItem->GetGUID().ToString().c_str(), newItem->GetTemplate()->GetDefaultLocaleName(), AH->auctioneer, newItem->GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (auto const& packetItem : packet.Items) { Item* item2 = _player->GetItemByGuid(packetItem.Guid); // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == packetItem.UseCount) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); delete item2; } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - packetItem.UseCount); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), packetItem.UseCount); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } _player->ModifyMoney(-int32(deposit)); }
void WorldSession::HandleSendMail(WorldPacket& recvData) { ObjectGuid mailbox; uint64 money, COD; std::string receiverName, subject, body; uint32 bodyLength, subjectLength, receiverLength; uint32 unk1, unk2; recvData >> unk1; recvData >> unk2; // Stationery? recvData >> COD >> money; // money and cod bodyLength = recvData.ReadBits(12); subjectLength = recvData.ReadBits(9); uint8 items_count = recvData.ReadBits(5); // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recvData.rfinish(); // set to end to avoid warnings spam return; } mailbox[0] = recvData.ReadBit(); ObjectGuid itemGUIDs[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { itemGUIDs[i][2] = recvData.ReadBit(); itemGUIDs[i][6] = recvData.ReadBit(); itemGUIDs[i][3] = recvData.ReadBit(); itemGUIDs[i][7] = recvData.ReadBit(); itemGUIDs[i][1] = recvData.ReadBit(); itemGUIDs[i][0] = recvData.ReadBit(); itemGUIDs[i][4] = recvData.ReadBit(); itemGUIDs[i][5] = recvData.ReadBit(); } mailbox[3] = recvData.ReadBit(); mailbox[4] = recvData.ReadBit(); receiverLength = recvData.ReadBits(7); mailbox[2] = recvData.ReadBit(); mailbox[6] = recvData.ReadBit(); mailbox[1] = recvData.ReadBit(); mailbox[7] = recvData.ReadBit(); mailbox[5] = recvData.ReadBit(); recvData.ReadByteSeq(mailbox[4]); for (uint8 i = 0; i < items_count; ++i) { recvData.ReadByteSeq(itemGUIDs[i][6]); recvData.ReadByteSeq(itemGUIDs[i][1]); recvData.ReadByteSeq(itemGUIDs[i][7]); recvData.ReadByteSeq(itemGUIDs[i][2]); recvData.read_skip<uint8>(); // item slot in mail, not used recvData.ReadByteSeq(itemGUIDs[i][3]); recvData.ReadByteSeq(itemGUIDs[i][0]); recvData.ReadByteSeq(itemGUIDs[i][4]); recvData.ReadByteSeq(itemGUIDs[i][5]); } recvData.ReadByteSeq(mailbox[7]); recvData.ReadByteSeq(mailbox[3]); recvData.ReadByteSeq(mailbox[6]); recvData.ReadByteSeq(mailbox[5]); subject = recvData.ReadString(subjectLength); receiverName = recvData.ReadString(receiverLength); recvData.ReadByteSeq(mailbox[2]); recvData.ReadByteSeq(mailbox[0]); body = recvData.ReadString(bodyLength); recvData.ReadByteSeq(mailbox[1]); // packet read complete, now do check if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; if (receiverName.empty()) return; Player* player = _player; if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } uint64 receiverGuid = 0; if (normalizePlayerName(receiverName)) receiverGuid = sObjectMgr->GetPlayerGUIDByName(receiverName); if (!receiverGuid) { sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: not existed!) with subject %s " "and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: %u) with subject %s and body %s " "includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), GUID_LOPART(receiverGuid), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (player->GetGUID() == receiverGuid) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client uint64 reqmoney = cost + money; if (!player->HasEnoughMoney(reqmoney) && !player->isGameMaster()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receiver = ObjectAccessor::FindPlayer(receiverGuid); uint32 receiverTeam = 0; uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; if (receiver) { receiverTeam = receiver->GetTeam(); mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); } else { receiverTeam = sObjectMgr->GetPlayerTeamByGUID(receiverGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt32(0, GUID_LOPART(receiverGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); mailsCount = fields[0].GetUInt64(); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); stmt->setUInt32(0, GUID_LOPART(receiverGuid)); result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); receiverLevel = fields[0].GetUInt8(); } receiverAccountId = sObjectMgr->GetPlayerAccountIdByGUID(receiverGuid); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mailsCount > 100) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... or all items are account bound bool accountBound = items_count ? true : false; for (uint8 i = 0; i < items_count; ++i) { if (Item* item = player->GetItemByGuid(itemGUIDs[i])) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { if (!itemGUIDs[i]) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = player->GetItemByGuid(itemGUIDs[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); return; } if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsNotEmptyBag()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_DESTROY_NONEMPTY_BAG); return; } items[i] = item; } player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-int64(reqmoney)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (items_count > 0 || money > 0) { bool log = HasPermission(RBAC_PERM_LOG_GM_TRADE); if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (log) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) " "to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiverName.c_str(), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SetOwnerGUID(receiverGuid); item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } if (log && money > 0) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail money: " UI64FMTD " to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), money, receiverName.c_str(), receiverAccountId); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list draft .AddMoney(money) .AddCOD(COD) .SendMailTo(trans, MailReceiver(receiver, GUID_LOPART(receiverGuid)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { ObjectGuid auctioneer; uint32 itemsCount, etime, bid, buyout; recvData >> auctioneer; recvData >> itemsCount; ObjectGuid itemGUIDs[MAX_AUCTION_ITEMS]; // 160 slot = 4x 36 slot bag + backpack 16 slot uint32 count[MAX_AUCTION_ITEMS]; memset(count, 0, sizeof(count)); if (itemsCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } for (uint32 i = 0; i < itemsCount; ++i) { recvData >> itemGUIDs[i]; recvData >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000) { recvData.rfinish(); return; } } recvData >> bid; recvData >> buyout; recvData >> etime; if (!bid || !etime) return; if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (GUID %u) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUID().GetCounter()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) not found or you can't interact with him.", auctioneer.ToString().c_str()); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (%s) has wrong faction.", auctioneer.ToString().c_str()); return; } etime *= MINUTE; switch (etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; uint32 itemEntry = 0; for (uint32 i = 0; i < itemsCount; ++i) { Item* item = _player->GetItemByGuid(itemGUIDs[i]); if (!item) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (itemEntry == 0) itemEntry = item->GetTemplate()->ItemId; if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < count[i] || itemEntry != item->GetTemplate()->ItemId) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } // check if there are 2 identical guids, in this case user is most likely cheating for (uint32 i = 0; i < itemsCount - 1; ++i) { for (uint32 j = i + 1; j < itemsCount; ++j) { if (itemGUIDs[i] == itemGUIDs[j]) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = items[0]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->houseId = AUCTIONHOUSE_NEUTRAL; else { CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(creature->GetSpawnId()); if (!auctioneerData) { TC_LOG_ERROR("misc", "Data for auctioneer not found (%s)", auctioneer.ToString().c_str()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id); if (!auctioneerInfo) { TC_LOG_ERROR("misc", "Non existing auctioneer (%s)", auctioneer.ToString().c_str()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } const AuctionHouseEntry* AHEntry = sAuctionMgr->GetAuctionHouseEntry(auctioneerInfo->faction); AH->houseId = AHEntry->houseId; } // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemsCount == 1 && item->GetCount() == count[0]) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUID().GetCounter(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->etime = etime; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUID().GetCounter(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUID().GetCounter(), item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); sAuctionMgr->PendingAuctionAdd(_player, AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->Id = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUID().GetCounter(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUID().GetCounter(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->etime = etime; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUID().GetCounter(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUID().GetCounter(), newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); sAuctionMgr->PendingAuctionAdd(_player, AH); for (uint32 j = 0; j < itemsCount; ++j) { Item* item2 = items[j]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); delete item2; } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) { uint64 auctioneer; uint32 itemsCount, etime, bid, buyout; recv_data >> auctioneer; recv_data >> itemsCount; uint64 itemGUIDs[MAX_AUCTION_ITEMS]; // 160 slot = 4x 36 slot bag + backpack 16 slot uint32 count[MAX_AUCTION_ITEMS]; if (itemsCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { recv_data >> itemGUIDs[i]; recv_data >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000 ) return; } recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!bid || !etime) return; Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(auctioneer)); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", GUID_LOPART(auctioneer)); return; } etime *= MINUTE; switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; for (uint32 i = 0; i < itemsCount; ++i) { Item* item = _player->GetItemByGuid(itemGUIDs[i]); if (!item) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUIDLow()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < count[i]) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } _player->ModifyMoney(-int32(deposit)); AuctionEntry* AH = new AuctionEntry; AH->Id = sObjectMgr->GenerateAuctionID(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; else AH->auctioneer = GUID_LOPART(auctioneer); if (itemsCount == 1 && item->GetCount() == count[i]) { if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->item_guidlow = item->GetGUIDLow(); AH->item_template = item->GetEntry(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; sLog->outDetail("CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); return; } else { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { sLog->outError("CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->item_guidlow = newItem->GetGUIDLow(); AH->item_template = newItem->GetEntry(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; sLog->outDetail("CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to auctioneer %u with count %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", _player->GetName(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (uint32 j = 0; j < itemsCount; ++j) { Item* item2 = items[j]; if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } else { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); return; } } }
void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) { sLog.outDebug("Received opcode CMSG_WRAP_ITEM"); uint8 gift_bag, gift_slot, item_bag, item_slot; //recv_data.hexlike(); recv_data >> gift_bag >> gift_slot; // paper recv_data >> item_bag >> item_slot; // item sLog.outDebug("WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); Item *gift = _player->GetItemByPos(gift_bag, gift_slot); if (!gift) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); return; } if (!(gift->GetProto()->Flags & ITEM_PROTO_FLAG_WRAPPER)) // cheating: non-wrapper wrapper { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); return; } Item *item = _player->GetItemByPos(item_bag, item_slot); if (!item) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); return; } if (item == gift) // not possable with pacjket from real client { _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); return; } if (item->IsEquipped()) { _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); return; } if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); { _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); return; } if (item->IsBag()) { _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); return; } if (item->IsSoulBound()) { _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); return; } if (item->GetMaxStackCount() != 1) { _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); return; } // maybe not correct check (it is better than nothing) if (item->GetProto()->MaxCount>0) { _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); item->SetEntry(gift->GetEntry()); switch (item->GetEntry()) { case 5042: item->SetEntry(5043); break; case 5048: item->SetEntry(5044); break; case 17303: item->SetEntry(17302); break; case 17304: item->SetEntry(17305); break; case 17307: item->SetEntry(17308); break; case 21830: item->SetEntry(21831); break; } item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED); item->SetState(ITEM_CHANGED, _player); if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` { // after save it will be impossible to remove the item from the queue item->RemoveFromUpdateQueueOf(_player); item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone } CharacterDatabase.CommitTransaction(trans); uint32 count = 1; _player->DestroyItemCount(gift, count, true); }
void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { if (!_player->IsInWorld()) return; uint64 guid,item; uint32 bid,buyout,etime; // etime is in minutes recv_data >> guid >> item; recv_data >> bid >> buyout >> etime; Creature * pCreature = _player->GetMapMgr()->GetCreature(GET_LOWGUID_PART(guid)); if( !pCreature || !pCreature->auctionHouse ) return; // NPC doesnt exist or isnt an auctioneer // Get item Item * pItem = _player->GetItemInterface()->GetItemByGUID(item); if( !pItem || pItem->IsSoulbound() || pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_CONJURED ) ) { WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 8); data << uint32(0); data << uint32(AUCTION_CREATE); data << uint32(AUCTION_ERROR_ITEM); SendPacket(&data); return; }; AuctionHouse * ah = pCreature->auctionHouse; uint32 item_worth = pItem->GetProto()->SellPrice * pItem->GetUInt32Value(ITEM_FIELD_STACK_COUNT); uint32 item_deposit = (uint32)(item_worth * ah->deposit_percent) * (uint32)(etime / 240.0f); // deposit is per 4 hours if (_player->GetUInt32Value(PLAYER_FIELD_COINAGE) < item_deposit) // player cannot afford deposit { WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 8); data << uint32(0); data << uint32(AUCTION_CREATE); data << uint32(AUCTION_ERROR_MONEY); SendPacket(&data); return; } pItem = _player->GetItemInterface()->SafeRemoveAndRetreiveItemByGuid(item, false); if (!pItem){ WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 8); data << uint32(0); data << uint32(AUCTION_CREATE); data << uint32(AUCTION_ERROR_ITEM); SendPacket(&data); return; }; if( pItem->IsInWorld() ) { pItem->RemoveFromWorld(); } pItem->SetOwner(NULL); pItem->m_isDirty = true; pItem->SaveToDB(INVENTORY_SLOT_NOT_SET, 0, true, NULL); // Create auction Auction * auct = new Auction; auct->BuyoutPrice = buyout; auct->ExpiryTime = (uint32)UNIXTIME + (etime * 60); auct->HighestBid = bid; auct->HighestBidder = 0; // hm auct->Id = sAuctionMgr.GenerateAuctionId(); auct->Owner = _player->GetLowGUID(); auct->pItem = pItem; auct->Deleted = false; auct->DeletedReason = 0; auct->DepositAmount = item_deposit; // remove deposit _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -(int32)item_deposit); // Add and save auction to DB ah->AddAuction(auct); auct->SaveToDB(ah->GetID()); // Send result packet WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 8); data << auct->Id; data << uint32(AUCTION_CREATE); data << uint32(AUCTION_ERROR_NONE); SendPacket(&data); }
void WorldSession::HandleSendMail(WorldPacket& recvData) { ObjectGuid mailbox, unk3; std::string receiverName, subject, body; uint32 stationery, package, money, COD; uint8 unk4; uint8 items_count; recvData >> mailbox >> receiverName >> subject >> body >> stationery // stationery? >> package // 0x00000000 >> items_count; // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recvData.rfinish(); // set to end to avoid warnings spam return; } ObjectGuid itemGUIDs[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { recvData.read_skip<uint8>(); // item slot in mail, not used recvData >> itemGUIDs[i]; } recvData >> money >> COD; // money and cod recvData >> unk3; // const 0 recvData >> unk4; // const 0 // packet read complete, now do check if (!CanOpenMailBox(mailbox)) return; if (receiverName.empty()) return; Player* player = _player; if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } ObjectGuid receiverGuid; if (normalizePlayerName(receiverName)) receiverGuid = sCharacterCache->GetCharacterGuidByName(receiverName); if (!receiverGuid) { TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: non-existing!) with subject %s " "and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUID().GetCounter(), receiverName.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, stationery, package); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } TC_LOG_INFO("network", "Player %u is sending mail to %s (%s) with subject %s and body %s " "including %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUID().GetCounter(), receiverName.c_str(), receiverGuid.ToString().c_str(), subject.c_str(), body.c_str(), items_count, money, COD, stationery, package); if (player->GetGUID() == receiverGuid) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client uint32 reqmoney = cost + money; // Check for overflow if (reqmoney < money) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receiver = ObjectAccessor::FindConnectedPlayer(receiverGuid); uint32 receiverTeam = 0; uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; if (receiver) { receiverTeam = receiver->GetTeam(); mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); } else { if (CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(receiverGuid)) { receiverTeam = Player::TeamForRace(characterInfo->Race); receiverLevel = characterInfo->Level; receiverAccountId = characterInfo->AccountId; } PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt32(0, receiverGuid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); mailsCount = fields[0].GetUInt64(); } } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mailsCount > 100) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... or all items are account bound bool accountBound = items_count ? true : false; for (uint8 i = 0; i < items_count; ++i) { if (Item* item = player->GetItemByGuid(itemGUIDs[i])) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { if (!itemGUIDs[i]) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = player->GetItemByGuid(itemGUIDs[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; } if ((item->GetTemplate()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsNotEmptyBag()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS); return; } items[i] = item; } player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-int32(reqmoney)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (items_count > 0 || money > 0) { bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE); if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (log) { sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail item: %s (Entry: %u Count: %u) " "to: %s (%s) (Account: %u)", GetPlayerName().c_str(), GetGUIDLow(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SetOwnerGUID(receiverGuid); item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } if (log && money > 0) { sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail money: %u to: %s (%s) (Account: %u)", GetPlayerName().c_str(), GetGUIDLow(), GetAccountId(), money, receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // don't ask for COD if there are no items if (items_count == 0) COD = 0; // will delete item or place to receiver mail list draft .AddMoney(money) .AddCOD(COD) .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { ObjectGuid auctioneer; uint64 bid, buyout; uint32 etime; uint8 itemCount; // 32 slots, value sent as 5 bits ObjectGuid itemGuids[MAX_AUCTION_ITEMS]; uint32 count[MAX_AUCTION_ITEMS]; recvData >> auctioneer; // auctioneer GUID recvData >> bid; recvData >> buyout; recvData >> etime; if (!bid || !etime) { recvData.rfinish(); return; } if (bid > MAX_MONEY_AMOUNT || buyout > MAX_MONEY_AMOUNT) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Player %s (GUID %u) attempted to sell item with higher price than max gold amount.", _player->GetName().c_str(), _player->GetGUIDLow()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } itemCount = recvData.ReadBits(5); // Item Counts recvData.FlushBits(); if (itemCount > MAX_AUCTION_ITEMS) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); recvData.rfinish(); return; } for (uint8 i = 0; i < itemCount; i++) { recvData >> itemGuids[i]; // Item GUID recvData >> count[i]; // Count of Item if (!itemGuids[i] || !count[i] || count[i] > 1000) { recvData.rfinish(); return; } } Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(auctioneer)); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); if (!auctionHouseEntry) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", GUID_LOPART(auctioneer)); return; } etime *= MINUTE; switch (etime) { case 1 * MIN_AUCTION_TIME: case 2 * MIN_AUCTION_TIME: case 4 * MIN_AUCTION_TIME: break; default: return; } if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; for (uint32 i = 0; i < itemCount; ++i) { Item* item = _player->GetItemByGuid(itemGuids[i]); if (!item) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_ITEM_NOT_FOUND); return; } if (sAuctionMgr->GetAItem(item->GetGUIDLow()) || !item->CanBeTraded() || item->IsNotEmptyBag() || item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_EXPIRATION) || item->GetCount() < count[i]) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } for (uint32 i = 0; i < itemCount; ++i) { Item* item = items[i]; if (item->GetMaxStackCount() < finalCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); return; } } Item* item = items[0]; uint32 auctionTime = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, item, finalCount); if (!_player->HasEnoughMoney((uint64)deposit)) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } AuctionEntry* AH = new AuctionEntry(); if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD else AH->auctioneer = GUID_LOPART(auctioneer); // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemCount == 1 && item->GetCount() == count[0]) { if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } AH->autcionId = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = item->GetGUIDLow(); AH->itemEntry = item->GetEntry(); AH->itemCount = item->GetCount(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) " "to auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetGUIDLow(), AH->auctioneer, item->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(item); auctionHouse->AddAuction(AH); _player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(trans); item->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size { Item* newItem = item->CloneItem(finalCount, _player); if (!newItem) { TC_LOG_ERROR("network", "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); delete AH; return; } if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } AH->autcionId = sObjectMgr->GenerateAuctionID(); AH->itemGUIDLow = newItem->GetGUIDLow(); AH->itemEntry = newItem->GetEntry(); AH->itemCount = newItem->GetCount(); AH->owner = _player->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auctionTime; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; TC_LOG_INFO("network", "CMSG_AUCTION_SELL_ITEM: Player %s (guid %d) is selling item %s entry %u (guid %d) to " "auctioneer %u with count %u with initial bid " UI64FMTD " with buyout " UI64FMTD " and with time %u (in sec) in auctionhouse %u", _player->GetName().c_str(), _player->GetGUIDLow(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetGUIDLow(), AH->auctioneer, newItem->GetCount(), bid, buyout, auctionTime, AH->GetHouseId()); sAuctionMgr->AddAItem(newItem); auctionHouse->AddAuction(AH); for (uint32 j = 0; j < itemCount; ++j) { Item* item2 = items[j]; // Item stack count equals required count, ready to delete item - cloned item will be used for auction if (item2->GetCount() == count[j]) { _player->MoveItemFromInventory(item2->GetBagSlot(), item2->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->DeleteFromInventoryDB(trans); item2->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); } else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction { item2->SetCount(item2->GetCount() - count[j]); item2->SetState(ITEM_CHANGED, _player); _player->ItemRemovedQuestCheck(item2->GetEntry(), count[j]); item2->SendUpdateToPlayer(_player); SQLTransaction trans = CharacterDatabase.BeginTransaction(); item2->SaveToDB(trans); CharacterDatabase.CommitTransaction(trans); } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); newItem->SaveToDB(trans); AH->SaveToDB(trans); _player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } _player->ModifyMoney(-int32(deposit)); }
bool GuildTaskMgr::Reward(uint32 owner, uint32 guildId) { Guild *guild = sGuildMgr->GetGuildById(guildId); if (!guild) return false; Player* player = sObjectMgr->GetPlayerByLowGUID(owner); if (!player) return false; Player* leader = sObjectMgr->GetPlayerByLowGUID(guild->GetLeaderGUID()); if (!leader) return false; uint32 itemTask = GetTaskValue(owner, guildId, "itemTask"); uint32 killTask = GetTaskValue(owner, guildId, "killTask"); if (!itemTask && !killTask) return false; ostringstream body; body << "Hello, " << player->GetName() << ",\n"; body << "\n"; if (itemTask) { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTask); if (!proto) return false; body << "We wish to thank you for the " << proto->Name1 << " you provided so kindly. We really appreciate this and may this small gift bring you our thanks!\n"; body << "\n"; body << "Many thanks,\n"; body << guild->GetName() << "\n"; body << leader->GetName() << "\n"; } else if (killTask) { CreatureTemplate const* proto = sObjectMgr->GetCreatureTemplate(killTask); if (!proto) return false; body << "We wish to thank you for the " << proto->Name << " you've killed recently. We really appreciate this and may this small gift bring you our thanks!\n"; body << "\n"; body << "Many thanks,\n"; body << guild->GetName() << "\n"; body << leader->GetName() << "\n"; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft draft("Thank You", body.str()); uint32 itemId = sRandomItemMgr.GetRandomItem(RANDOM_ITEM_GUILD_TASK_REWARD); if (itemId) { Item* item = Item::CreateItem(itemId, 1, leader); item->SaveToDB(trans); draft.AddItem(item); } draft.AddMoney(GetTaskValue(owner, guildId, "payment")).SendMailTo(trans, MailReceiver(player), MailSender(leader)); CharacterDatabase.CommitTransaction(trans); SetTaskValue(owner, guildId, "activeTask", 0, 0); return true; }
void WorldSession::HandleAuctionSellItem(WorldPacket& recv_data) { CHECK_INWORLD_RETURN uint64 auctioneer, bid, buyout; uint32 itemsCount, etime; recv_data >> auctioneer; recv_data >> itemsCount; uint64 itemGUIDs[MAX_AUCTION_ITEMS]; // 160 slot = 4x 36 slot bag + backpack 16 slot uint32 count[MAX_AUCTION_ITEMS]; for (uint32 i = 0; i < itemsCount; ++i) { recv_data >> itemGUIDs[i]; recv_data >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000) return; } recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!bid || !etime) return; Creature* pCreature = _player->GetMapMgr()->GetCreature(GET_LOWGUID_PART(auctioneer)); if (!pCreature || !pCreature->auctionHouse) return; // NPC doesn't exist or isn't an auctioneer AuctionHouse* ah = pCreature->auctionHouse; etime *= MINUTE; switch (etime) { case 1 * MIN_AUCTION_TIME: case 2 * MIN_AUCTION_TIME: case 4 * MIN_AUCTION_TIME: break; default: return; } Item* items[MAX_AUCTION_ITEMS]; uint32 finalCount = 0; for (uint32 i = 0; i < itemsCount; ++i) { Item* item = _player->GetItemInterface()->GetItemByGUID(itemGUIDs[i]); if (!item) { _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_ITEM_NOT_FOUND); return; } items[i] = item; finalCount += count[i]; } if (!finalCount) { _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_DATABASE_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; if (item->GetStackCount() < finalCount) { _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_DATABASE_ERROR); return; } } for (uint32 i = 0; i < itemsCount; ++i) { Item* item = items[i]; uint32 auctionTime = uint32(etime); AuctionHouse* ah = pCreature->auctionHouse; uint32 item_worth = item->GetProto()->SellPrice * item->GetStackCount(); uint32 item_deposit = (uint32)(item_worth * ah->deposit_percent) * (uint32)(etime / 240.0f); // deposit is per 4 hours if (!_player->HasGold((uint64)item_deposit)) { _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } _player->TakeGold(-int32(item_deposit)); item = _player->GetItemInterface()->SafeRemoveAndRetreiveItemByGuid(itemGUIDs[i], false); if (!item) { _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_ITEM_NOT_FOUND); return; }; if (item->IsInWorld()) { item->RemoveFromWorld(); } item->SetOwner(NULL); item->m_isDirty = true; item->SaveToDB(INVENTORY_SLOT_NOT_SET, 0, true, NULL); // Create auction Auction* auct = new Auction; auct->BuyoutPrice = buyout; auct->ExpiryTime = (uint32)UNIXTIME + (etime * 60); auct->StartingPrice = bid; auct->HighestBid = 0; auct->HighestBidder = 0; // hm auct->Id = sAuctionMgr.GenerateAuctionId(); auct->Owner = _player->GetLowGUID(); auct->pItem = item; auct->Deleted = false; auct->DeletedReason = 0; auct->DepositAmount = item_deposit; // Add and save auction to DB ah->AddAuction(auct); auct->SaveToDB(ah->GetID()); // Send result packet _player->SendAuctionCommandResult(NULL, AUCTION_CREATE, ERR_AUCTION_OK); } ah->SendOwnerListPacket(_player, &recv_data); }
void WorldSession::HandleTakeItem(WorldPacket & recv_data ) { uint64 mailbox; uint32 message_id; uint32 lowguid; vector< uint64 >::iterator itr; recv_data >> mailbox >> message_id >> lowguid; WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); data << message_id << uint32(MAIL_RES_ITEM_TAKEN); MailMessage * message = _player->m_mailBox.GetMessage(message_id); if(message == 0 || message->items.empty()) { data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } for( itr = message->items.begin( ); itr != message->items.end( ); ++itr ) { if ( (*itr) == lowguid ) break; } if( itr == message->items.end( ) ) { data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } // check for cod credit if(message->cod > 0) { if(_player->GetUInt32Value(PLAYER_FIELD_COINAGE) < message->cod) { data << uint32(MAIL_ERR_NOT_ENOUGH_MONEY); SendPacket(&data); return; } } // grab the item Item * item = objmgr.LoadItem( *itr ); if(item == 0) { // doesn't exist data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } // find a free bag slot SlotResult result = _player->GetItemInterface()->FindFreeInventorySlot(item->GetProto()); if(result.Result == 0) { // no free slots left! data << uint32(MAIL_ERR_BAG_FULL); SendPacket(&data); delete item; return; } item->m_isDirty = true; if( !_player->GetItemInterface()->SafeAddItem(item, result.ContainerSlot, result.Slot) ) { if( !_player->GetItemInterface()->AddItemToFreeSlot(item) ) { // no free slots left! data << uint32(MAIL_ERR_BAG_FULL); SendPacket(&data); delete item; return; } } else // true so it waitexecute's item->SaveToDB(result.ContainerSlot, result.Slot, true, NULL); // send complete packet data << uint32(MAIL_OK); data << item->GetUInt32Value(OBJECT_FIELD_GUID); data << item->GetUInt32Value(ITEM_FIELD_STACK_COUNT); message->items.erase( itr ); // re-save (update the items field) sMailSystem.SaveMessageToSQL( message); SendPacket(&data); if( message->cod > 0 ) { _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -int32(message->cod)); string subject = "COD Payment: "; subject += message->subject; sMailSystem.SendAutomatedMessage(NORMAL, message->player_guid, message->sender_guid, subject, "", message->cod, 0, 0, 1); message->cod = 0; CharacterDatabase.Execute("UPDATE mailbox SET cod = 0 WHERE message_id = %u", message->message_id); } // prolly need to send an item push here }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+8+4+4+4); uint64 auctioneer, item; uint32 etime, bid, buyout; recv_data >> auctioneer >> item; recv_data >> bid >> buyout >> etime; Player *pl = GetPlayer(); if (!item || !bid || !etime) return; //check for cheaters Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, auctioneer,UNIT_NPC_FLAG_AUCTIONEER); if (!pCreature) { sLog.outDebug( "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer)) ); return; } // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid( item ); //do not allow to sell already auctioned items if(objmgr.GetAItem(GUID_LOPART(item))) { sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) if(!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if(!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } uint32 location = AuctioneerFactionToLocation(pCreature->getFaction()); AuctionHouseObject * mAuctions; mAuctions = objmgr.GetAuctionsMap( location ); //we have to take deposit : uint32 deposit = objmgr.GetAuctionDeposit( location, etime, it ); if ( pl->GetMoney() < deposit ) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount()); } pl->ModifyMoney( -int32(deposit) ); uint32 auction_time = uint32(etime * sWorld.getRate(RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = objmgr.GenerateAuctionID(); AH->auctioneer = GUID_LOPART(auctioneer); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->time = time(NULL) + auction_time; AH->deposit = deposit; AH->location = location; sLog.outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in location: %u", GUID_LOPART(item), GUID_LOPART(auctioneer), bid, buyout, auction_time, location); mAuctions->AddAuction(AH); objmgr.AddAItem(it); pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true); CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(); it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone CharacterDatabase.PExecute("INSERT INTO auctionhouse (id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location) " "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u')", AH->Id, AH->auctioneer, AH->item_guidlow, AH->item_template, AH->owner, AH->buyout, (uint64)AH->time, AH->bidder, AH->bid, AH->startbid, AH->deposit, AH->location); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); }
void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) { sLog->outDetail("AchievementMgr::CompletedAchievement(%u)", achievement->ID); // disable for gamemasters with GM-mode enabled if (_player->isGameMaster()) return; if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) return; SendAchievementEarned(achievement); CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; ca.date = time(NULL); ca.changed = true; // don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement // TODO: where do set this instead? if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) sAchievementMgr->SetRealmCompleted(achievement); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, _player); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, _player, achievement->points); m_achievementPoints += achievement->points; // reward items and titles if any AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement); // no rewards if (!reward) return; // titles //! Currently there's only one achievement that deals with gender-specific titles. //! Since no common attributes were found, (not even in titleRewardFlags field) //! we explicitly check by ID. Maybe in the future we could move the achievement_reward //! condition fields to the condition system. if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetPlayer()->getGender() : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) GetPlayer()->SetTitle(titleEntry); // mail if (reward->sender) { Item* item = reward->itemId ? Item::CreateItem(reward->itemId, 1, GetPlayer ()) : NULL; int loc_idx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex(); // subject and text std::string subject = reward->subject; std::string text = reward->text; if (loc_idx >= 0) { if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement)) { ObjectMgr::GetLocaleString(loc->subject, loc_idx, subject); ObjectMgr::GetLocaleString(loc->text, loc_idx, text); } } MailDraft draft(subject, text); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (item) { // save new item before send item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted // item draft.AddItem(item); } draft.SendMailTo(trans, GetPlayer(), MailSender(MAIL_CREATURE, reward->sender)); CharacterDatabase.CommitTransaction(trans); } }
// $req will be deleted by the caller. void WorldSession::HandleSendMailCallback(WorldSession::AsyncMailSendRequest* req) { MasterPlayer* pl = GetMasterPlayer(); Player* loadedPlayer = GetPlayer(); ASSERT(pl); uint32 reqmoney = req->money + 30; // Check for overflow if (reqmoney < req->money) { ProcessAnticheatAction("MailCheck", "Attempt to send free mails with money overflow", CHEAT_ACTION_LOG); pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } if (reqmoney && (!loadedPlayer || loadedPlayer->GetMoney() < reqmoney)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (req->mailsCount > 100) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // check the receiver's Faction... if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != req->rcTeam && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } uint32 rc_account = sObjectMgr.GetPlayerAccountIdByGUID(req->receiver); Item* item = NULL; if (req->itemGuid) { item = loadedPlayer->GetItemByGuid(req->itemGuid); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item || !item->IsInWorld()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if ((item->GetProto()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (req->COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } } // Antispam checks if (loadedPlayer->getLevel() < sWorld.getConfig(CONFIG_UINT32_MAILSPAM_LEVEL) && req->money < sWorld.getConfig(CONFIG_UINT32_MAILSPAM_MONEY) && (sWorld.getConfig(CONFIG_BOOL_MAILSPAM_ITEM) && !req->itemGuid)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); return; } AccountPersistentData& data = sAccountMgr.GetAccountPersistentData(GetAccountId()); if (!data.CanMail(rc_account)) { std::stringstream details; std::string from = ChatHandler(this).playerLink(GetMasterPlayer()->GetName()); std::string to = ChatHandler(this).playerLink(req->receiverName); details << from << " -> " << to << "\n"; details << req->subject << "\n"; details << req->body << "\n"; if (req->COD) details << "COD: " << req->COD << " coppers\n"; uint32 logId = sWorld.InsertLog(details.str(), SEC_GAMEMASTER); std::stringstream oss; oss << "Mail limit reached (\"" << req->body.substr(0, 30) << "...\") [log #" << logId << "]"; ProcessAnticheatAction("ChatSpam", oss.str().c_str(), CHEAT_ACTION_LOG | CHEAT_ACTION_REPORT_GMS); pl->SendMailResult(0, MAIL_SEND, MAIL_OK); return; } data.JustMailed(rc_account); pl->SendMailResult(0, MAIL_SEND, MAIL_OK); loadedPlayer->ModifyMoney(-int32(reqmoney)); bool needItemDelay = false; MailDraft draft(req->subject, req->body); if (!req->COD && (req->money || item)) { PlayerTransactionData data; data.type = "Mail"; data.parts[0].lowGuid = pl->GetGUIDLow(); if (item) { data.parts[0].itemsEntries[0] = item->GetEntry(); data.parts[0].itemsCount[0] = item->GetCount(); } data.parts[0].money = req->money; data.parts[1].lowGuid = req->receiver.GetCounter(); sWorld.LogTransaction(data); } if (req->itemGuid || req->money > 0) { if (item) { if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), req->receiver.GetString().c_str(), rc_account); } loadedPlayer->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); // deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", req->receiver.GetCounter(), item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); draft.AddItem(item); // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (req->money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), req->money, req->receiver.GetString().c_str(), rc_account); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY) : 0; if (!item && req->COD) { req->COD = 0; ProcessAnticheatAction("MailCheck", "Attempt to send COD mail without any item", CHEAT_ACTION_LOG); } // will delete item or place to receiver mail list draft .SetMoney(req->money) .SetCOD(req->COD) .SendMailTo(MailReceiver(req->receiverPtr, req->receiver), loadedPlayer, req->body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); CharacterDatabase.BeginTransaction(); loadedPlayer->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) { sLog.outDetail("AchievementMgr::CompletedAchievement(%u)", achievement->ID); if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER || m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end()) return; SendAchievementEarned(achievement); CompletedAchievementData& ca = m_completedAchievements[achievement->ID]; ca.date = time(NULL); ca.changed = true; // don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement // TODO: where do set this instead? if(!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) achievementmgr.SetRealmCompleted(achievement); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT); // reward items and titles if any AchievementReward const* reward = achievementmgr.GetAchievementReward(achievement); // no rewards if(!reward) return; // titles if(uint32 titleId = reward->titleId[GetPlayer()->GetTeam() == HORDE?0:1]) { if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) GetPlayer()->SetTitle(titleEntry); } // mail if(reward->sender) { Item* item = reward->itemId ? Item::CreateItem(reward->itemId,1,GetPlayer ()) : NULL; MailItemsInfo mi; if(item) { // save new item before send item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted // item mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); } int loc_idx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex(); // subject and text std::string subject = reward->subject; std::string text = reward->text; if ( loc_idx >= 0 ) { if(AchievementRewardLocale const* loc = achievementmgr.GetAchievementRewardLocale(achievement)) { if (loc->subject.size() > size_t(loc_idx) && !loc->subject[loc_idx].empty()) subject = loc->subject[loc_idx]; if (loc->text.size() > size_t(loc_idx) && !loc->text[loc_idx].empty()) text = loc->text[loc_idx]; } } uint32 itemTextId = objmgr.CreateItemText( text ); WorldSession::SendMailTo(GetPlayer(), MAIL_CREATURE, MAIL_STATIONERY_NORMAL, reward->sender, GetPlayer()->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE); } }
void PlayerAchievementMgr::CompletedAchievement(AchievementEntry const* achievement, Player* referencePlayer) { // disable for gamemasters with GM-mode enabled if (_owner->IsGameMaster()) return; if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && referencePlayer->GetTeam() != HORDE) || (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && referencePlayer->GetTeam() != ALLIANCE)) return; if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) return; if (achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_NEWS) if (Guild* guild = referencePlayer->GetGuild()) guild->AddGuildNews(GUILD_NEWS_PLAYER_ACHIEVEMENT, referencePlayer->GetGUID(), achievement->Flags & ACHIEVEMENT_FLAG_SHOW_IN_GUILD_HEADER, achievement->ID); if (!_owner->GetSession()->PlayerLoading()) SendAchievementEarned(achievement); TC_LOG_INFO("criteria.achievement", "PlayerAchievementMgr::CompletedAchievement(%u). %s", achievement->ID, GetOwnerInfo().c_str()); CompletedAchievementData& ca = _completedAchievements[achievement->ID]; ca.Date = time(NULL); ca.Changed = true; if (achievement->Flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) sAchievementMgr->SetRealmCompleted(achievement); if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) _achievementPoints += achievement->Points; UpdateCriteria(CRITERIA_TYPE_COMPLETE_ACHIEVEMENT, 0, 0, 0, NULL, referencePlayer); UpdateCriteria(CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS, achievement->Points, 0, 0, NULL, referencePlayer); // reward items and titles if any AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement); // no rewards if (!reward) return; // titles //! Currently there's only one achievement that deals with gender-specific titles. //! Since no common attributes were found, (not even in titleRewardFlags field) //! we explicitly check by ID. Maybe in the future we could move the achievement_reward //! condition fields to the condition system. if (uint32 titleId = reward->TitleId[achievement->ID == 1793 ? _owner->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) : (_owner->GetTeam() == ALLIANCE ? 0 : 1)]) if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId)) _owner->SetTitle(titleEntry); // mail if (reward->SenderCreatureId) { MailDraft draft(uint16(reward->MailTemplateId)); if (!reward->MailTemplateId) { // subject and text std::string subject = reward->Subject; std::string text = reward->Body; LocaleConstant localeConstant = _owner->GetSession()->GetSessionDbLocaleIndex(); if (localeConstant != LOCALE_enUS) { if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement)) { ObjectMgr::GetLocaleString(loc->Subject, localeConstant, subject); ObjectMgr::GetLocaleString(loc->Body, localeConstant, text); } } draft = MailDraft(subject, text); } SQLTransaction trans = CharacterDatabase.BeginTransaction(); Item* item = reward->ItemId ? Item::CreateItem(reward->ItemId, 1, _owner) : NULL; if (item) { // save new item before send item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted // item draft.AddItem(item); } draft.SendMailTo(trans, _owner, MailSender(MAIL_CREATURE, uint64(reward->SenderCreatureId))); CharacterDatabase.CommitTransaction(trans); } }
/** * Handles the Packet sent by the client when sending a mail. * * This methods takes the packet sent by the client and performs the following actions: * - Checks whether the mail is valid: i.e. can he send the selected items, * does he have enough money, etc. * - Creates a MailDraft and adds the needed items, money, cost data. * - Sends the mail. * * Depending on the outcome of the checks performed the player will recieve a different * MailResponseResult. * * @see MailResponseResult * @see SendMailResult() * * @param recv_data the WorldPacket containing the data sent by the client. */ void WorldSession::HandleSendMail(WorldPacket& recv_data) { ObjectGuid mailboxGuid; ObjectGuid itemGuid; uint64 unk3; std::string receiver, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; recv_data >> mailboxGuid; recv_data >> receiver; recv_data >> subject; recv_data >> body; recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 recv_data >> itemGuid; recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 // packet read complete, now do check if (!CheckMailBox(mailboxGuid)) return; if (receiver.empty()) return; Player* pl = _player; ObjectGuid rc; if (normalizePlayerName(receiver)) rc = sObjectMgr.GetPlayerGuidByName(receiver); if (!rc) { DETAIL_LOG("%s is sending mail to %s (GUID: nonexistent!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGuidStr().c_str(), receiver.c_str(), subject.c_str(), body.c_str(), itemGuid ? 1 : 0, money, COD, unk1, unk2); pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } DETAIL_LOG("%s is sending mail to %s with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGuidStr().c_str(), rc.GetString().c_str(), subject.c_str(), body.c_str(), itemGuid ? 1 : 0, money, COD, unk1, unk2); if (pl->GetObjectGuid() == rc) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 reqmoney = money + 30; if (pl->GetMoney() < reqmoney) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receive = sObjectMgr.GetPlayer(rc); Team rc_team; uint8 mails_count = 0; // do not allow to send to one player more than 100 mails if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); } else { rc_team = sObjectMgr.GetPlayerTeamByGUID(rc); if (QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", rc.GetCounter())) { Field* fields = result->Fetch(); mails_count = fields[0].GetUInt32(); delete result; } } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // check the receiver's Faction... if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(rc); Item* item = nullptr; if (itemGuid) { item = pl->GetItemByGuid(itemGuid); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if ((item->GetProto()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); pl->ModifyMoney(-int32(reqmoney)); bool needItemDelay = false; MailDraft draft(subject, body); if (itemGuid || money > 0) { uint32 rc_account = 0; if (receive) rc_account = receive->GetSession()->GetAccountId(); else rc_account = sObjectMgr.GetPlayerAccountIdByGUID(rc); if (item) { if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } pl->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); // deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", rc.GetCounter(), item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); draft.AddItem(item); // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list draft .SetMoney(money) .SetCOD(COD) .SendMailTo(MailReceiver(receive, rc), pl, body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
void WorldSession::HandleSendMail(WorldPacket & recv_data ) { MailMessage msg; uint64 gameobject; uint32 unk2; uint8 itemcount; uint8 itemslot; uint8 i; uint64 itemguid; vector< Item* > items; vector< Item* >::iterator itr; string recepient; Item * pItem; //uint32 err = MAIL_OK; recv_data >> gameobject >> recepient; recv_data >> msg.subject >> msg.body >> msg.stationary; recv_data >> unk2 >> itemcount; //he simply ads ' ' after each '%' to string so that vsnprintf function would not find tokens in string char *t=(char*)msg.subject.c_str(); if( t[0] != 0 ) //if not an empty string { int ind=1; //make sure we do not have any recognizable tokens here while(t[ind]!=0 && ind<5000) { if(t[ind-1]=='%') t[ind]=' ';//just remove chars that could be interpreted ind++; } } msg.subject = t; t=(char*)msg.body.c_str(); if( t[0] != 0 ) //if not an empty string { int ind=1; while(t[ind]!=0 && ind<5000) { if(t[ind-1]=='%') t[ind]=' ';//just remove chars that could be interpreted ind++; } } msg.body = t; if( itemcount > 12 ) { //SystemMessage("Sorry, Ascent does not support sending multiple items at this time. (don't want to lose your item do you) Remove some items, and try again."); SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } for( i = 0; i < itemcount; ++i ) { recv_data >> itemslot; recv_data >> itemguid; pItem = _player->GetItemInterface()->GetItemByGUID( itemguid ); if( pItem == NULL || pItem->IsSoulbound() || pItem->HasFlag( ITEM_FIELD_FLAGS, ITEM_FLAG_CONJURED ) ) { SendMailError( MAIL_ERR_INTERNAL_ERROR ); return; } items.push_back( pItem ); } recv_data >> msg.money; recv_data >> msg.cod; // left over: (TODO- FIX ME BURLEX!) // uint32 // uint32 // uint8 // Search for the recipient PlayerInfo* player = ObjectMgr::getSingleton().GetPlayerInfoByName(recepient.c_str()); if( player == NULL ) { SendMailError( MAIL_ERR_RECIPIENT_NOT_FOUND ); return; } bool interfaction = false; if( sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION ) || (HasGMPermissions() && sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM ) ) ) { interfaction = true; } // Check we're sending to the same faction (disable this for testing) if( player->team != _player->GetTeam() && !interfaction ) { SendMailError( MAIL_ERR_NOT_YOUR_ALLIANCE ); return; } // Check if we're sending mail to ourselves if( strcmp(player->name, _player->GetName()) == 0 && !GetPermissionCount()) { SendMailError(MAIL_ERR_CANNOT_SEND_TO_SELF); return; } if( msg.stationary == 0x3d || msg.stationary == 0x3d && !HasGMPermissions()) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } // Instant delivery time by default. msg.delivery_time = (uint32)UNIXTIME; // Set up the cost int32 cost = 0; if( !sMailSystem.MailOption( MAIL_FLAG_DISABLE_POSTAGE_COSTS ) && !( GetPermissionCount() && sMailSystem.MailOption( MAIL_FLAG_NO_COST_FOR_GM ) ) ) { cost = 30; } // Check for attached money if( msg.money > 0 ) cost += msg.money; if( cost < 0 ) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } // check that we have enough in our backpack if( (int32)_player->GetUInt32Value( PLAYER_FIELD_COINAGE ) < cost ) { SendMailError( MAIL_ERR_NOT_ENOUGH_MONEY ); return; } // Check for the item, and required item. if( !items.empty( ) ) { for( itr = items.begin(); itr != items.end(); ++itr ) { pItem = *itr; if( _player->GetItemInterface()->SafeRemoveAndRetreiveItemByGuid(pItem->GetGUID(), false) != pItem ) continue; // should never be hit. pItem->RemoveFromWorld(); pItem->SetOwner( NULL ); pItem->SaveToDB( INVENTORY_SLOT_NOT_SET, 0, true, NULL ); msg.items.push_back( pItem->GetUInt32Value(OBJECT_FIELD_GUID) ); if( GetPermissionCount() > 0 ) { /* log the message */ sGMLog.writefromsession(this, "sent mail with item entry %u to %s, with gold %u.", pItem->GetEntry(), player->name, msg.money); } pItem->DeleteMe(); } } if(msg.money != 0 || msg.cod != 0 || !msg.items.size() && player->acct != _player->GetSession()->GetAccountId()) { if(!sMailSystem.MailOption(MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS)) msg.delivery_time += 3600; // 1hr } // take the money _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -cost); // Fill in the rest of the info msg.player_guid = player->guid; msg.sender_guid = _player->GetGUID(); // 30 day expiry time for unread mail mail if(!sMailSystem.MailOption(MAIL_FLAG_NO_EXPIRY)) msg.expire_time = (uint32)UNIXTIME + (TIME_DAY * MAIL_DEFAULT_EXPIRATION_TIME); else msg.expire_time = 0; msg.copy_made = false; msg.read_flag = false; msg.deleted_flag = false; msg.message_type = 0; // Great, all our info is filled in. Now we can add it to the other players mailbox. sMailSystem.DeliverMessage(player->guid, &msg); // Success packet :) SendMailError(MAIL_OK); }
void WorldSession::SendExternalMails() { sLog->outString("EXTERNAL MAIL> Sending mails in queue..."); QueryResult result = CharacterDatabase.Query("SELECT id,receiver,subject,message,money,item,item_count FROM mail_external"); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if(!result) { sLog->outString("EXTERNAL MAIL> No mails in queue..."); // delete result; return; } else { uint32 last_id = 0; MailDraft* mail = NULL; uint32 last_receiver_guid; do { Field *fields = result->Fetch(); uint32 id = fields[0].GetUInt32(); uint64 receiver_guid = fields[1].GetUInt64(); std::string subject = fields[2].GetString(); std::string body = fields[3].GetString(); uint32 money = fields[4].GetUInt32(); uint32 itemId = fields[5].GetUInt32(); uint32 itemCount = fields[6].GetUInt32(); Player *receiver = sObjectMgr->GetPlayer( receiver_guid ); if (id != last_id) { // send mail if (last_id != 0) { sLog->outString("EXTERNAL MAIL> Sending mail to character with guid %d", last_receiver_guid); mail->SendMailTo(trans,MailReceiver(last_receiver_guid), MailSender(MAIL_NORMAL, 0, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_RETURNED); delete mail; CharacterDatabase.PExecute("DELETE FROM mail_external WHERE id=%u", last_id); sLog->outString("EXTERNAL MAIL> Mail sent"); } //Create the maildraft mail = new MailDraft( subject, body ); if(money) { sLog->outString("EXTERNAL MAIL> Adding money"); mail->AddMoney(money); } } if (itemId) { sLog->outString("EXTERNAL MAIL> Adding %u of item with id %u", itemCount, itemId); Item* mailItem = Item::CreateItem( itemId, itemCount, receiver ); mailItem->SaveToDB(trans); mail->AddItem(mailItem); } last_id = id; last_receiver_guid = receiver_guid; } while( result->NextRow() ); // we only send a mail when mail_id!=last_mail_id, so we need to send the very last mail here: if (last_id != 0) { // send last mail sLog->outString("EXTERNAL MAIL> Sending mail to character with guid %d", last_receiver_guid); mail->SendMailTo(trans,MailReceiver(last_receiver_guid), MailSender(MAIL_NORMAL, 0, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_RETURNED); delete mail; CharacterDatabase.PExecute("DELETE FROM mail_external WHERE id=%u", last_id); sLog->outString("EXTERNAL MAIL> Mail sent"); } } CharacterDatabase.CommitTransaction(trans); sLog->outString("EXTERNAL MAIL> All Mails Sent..."); }
// this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: HandleAuctionSellItem"); ObjectGuid auctioneerGuid; uint64 item; uint32 etime, bid, buyout; recv_data >> auctioneerGuid; recv_data.read_skip<uint32>(); // const 1? recv_data >> item; recv_data.read_skip<uint32>(); // stack size recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!item || !bid || !etime) return; // check for cheaters Player *pl = GetPlayer(); AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid( item ); // do not allow to sell already auctioned items if(sAuctionMgr.GetAItem(GUID_LOPART(item))) { sLog.outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to auction) if(!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if(!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if ((it->GetProto()->Flags & ITEM_FLAG_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } //we have to take deposit : uint32 deposit = AuctionHouseMgr::GetAuctionDeposit( auctionHouseEntry, etime, it ); if ( pl->GetMoney() < deposit ) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE) ) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), it->GetCount()); } pl->ModifyMoney( -int32(deposit) ); uint32 auction_time = uint32(etime * sWorld.getConfig(CONFIG_FLOAT_RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = sObjectMgr.GenerateAuctionID(); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auction_time; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; DETAIL_LOG("selling item %u to auctioneer %s with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), auctioneerGuid.GetString().c_str(), bid, buyout, auction_time, AH->GetHouseId()); auctionHouse->AddAuction(AH); sAuctionMgr.AddAItem(it); pl->MoveItemFromInventory( it->GetBagSlot(), it->GetSlot(), true); CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(); it->SaveToDB(); // recursive and not have transaction guard into self, not in inventiory and can be save standalone AH->SaveToDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) { uint64 auctioneer, item; uint32 etime, bid, buyout, count; recv_data >> auctioneer; recv_data.read_skip<uint32>(); // const 1? recv_data >> item; recv_data >> count; // 3.2.2, number of items being auctioned recv_data >> bid; recv_data >> buyout; recv_data >> etime; Player* pl = GetPlayer(); if(!item || !bid || !etime) return; //check for cheaters Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if(!pCreature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(pCreature->getFaction()); if(!auctionHouseEntry) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); return; } // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item *it = pl->GetItemByGuid(item); //do not allow to sell already auctioned items if(sAuctionMgr->GetAItem(GUID_LOPART(item))) { sLog->outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", pl->GetName(), GUID_LOPART(item)); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) if(!it) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); return; } if(!it->CanBeTraded()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if(it->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if(it->IsNotEmptyBag()) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(pCreature->getFaction()); //we have to take deposit : uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, it, count); if(!pl->HasEnoughMoney(deposit)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); return; } if(GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), count); } pl->ModifyMoney(-int32(deposit)); uint32 auction_time = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = sObjectMgr->GenerateAuctionID(); if(sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) AH->auctioneer = 23442; else AH->auctioneer = GUID_LOPART(auctioneer); AH->item_guidlow = GUID_LOPART(item); AH->item_template = it->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expire_time = time(NULL) + auction_time; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; sLog->outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); sAuctionMgr->AddAItem(it); auctionHouse->AddAuction(AH); pl->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); SQLTransaction trans = CharacterDatabase.BeginTransaction(); it->DeleteFromInventoryDB(trans); it->SaveToDB(trans); // recursive and not have transaction guard into self, not in inventiory and can be save standalone AH->SaveToDB(trans); pl->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); }
void WorldSession::HandleSendMail(WorldPacket & recv_data) { CHECK_PACKET_SIZE(recv_data,8+1+1+1+4+4+1+4+4+8+1); ObjectGuid mailboxGuid; uint64 unk3; std::string receiver, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; recv_data >> mailboxGuid; recv_data >> receiver; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+1+1+4+4+1+4+4+8+1); recv_data >> subject; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+1+4+4+1+4+4+8+1); recv_data >> body; // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+(body.size()+1)+4+4+1+4+4+8+1); recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 uint8 items_count; recv_data >> items_count; // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam return; } // recheck CHECK_PACKET_SIZE(recv_data, 8+(receiver.size()+1)+(subject.size()+1)+(body.size()+1)+4+4+1+items_count*(1+8)+4+4+8+1); ObjectGuid itemGuids[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { recv_data.read_skip<uint8>(); // item slot in mail, not used recv_data >> itemGuids[i]; } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 // packet read complete, now do check if (!CheckMailBox(mailboxGuid)) return; items_count = 0; // remove duplicates, after this items_count will contains real items count { ObjectGuid tmpItemGuids[MAX_MAIL_ITEMS]; bool inTable = false; for (uint8 i = 0; i < MAX_MAIL_ITEMS; ++i) { if (itemGuids[i].IsEmpty()) continue; inTable = false; for (uint8 j = 0; j < MAX_MAIL_ITEMS; ++j) { if (tmpItemGuids[j].IsEmpty()) break; if (tmpItemGuids[j] == itemGuids[i]) { inTable = true; break; } } if (!inTable) { tmpItemGuids[items_count] = itemGuids[i]; ++items_count; } itemGuids[i].Clear(); } for (uint8 i = 0; i < items_count; ++i) itemGuids[i] = tmpItemGuids[i]; } if (receiver.empty()) return; Player* pl = _player; ObjectGuid rc; if (normalizePlayerName(receiver)) rc = sObjectMgr.GetPlayerGUIDByName(receiver); if (!rc) { sLog.outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); pl->SendMailResult(0, 0, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } sLog.outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (pl->GetGUID() == rc) { pl->SendMailResult(0, 0, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 reqmoney = money + 30; if (items_count) reqmoney = money + (30 * items_count); if (pl->GetMoney() < reqmoney) { pl->SendMailResult(0, 0, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player *receive = sObjectMgr.GetPlayer(rc); uint32 rc_team = 0; uint8 mails_count = 0; //do not allow to send to one player more than 100 mails if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); } else { rc_team = sObjectMgr.GetPlayerTeamByGUID(rc); QueryResultAutoPtr result = RealmDataDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc)); if (result) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); } } //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } // test the receiver's Faction... if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && !HasPermissions(PERM_GMT)) { pl->SendMailResult(0, 0, MAIL_ERR_NOT_YOUR_TEAM); return; } Item* items[MAX_MAIL_ITEMS]; for(uint8 i = 0; i < items_count; ++i) { if (!itemGuids[i].IsItem()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!itemGuids[i].GetCounter()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } Item* item = pl->GetItemByGuid(itemGuids[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if(!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if ((item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsBag() && !((Bag*)item)->IsEmpty()) { pl->SendMailResult(0, 0, MAIL_ERR_INTERNAL_ERROR); return; } items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); pl->ModifyMoney(-int32(reqmoney)); bool needItemDelay = false; MailDraft draft(subject, body); uint32 rc_account = 0; if (receive) rc_account = receive->GetSession()->GetAccountId(); else rc_account = sObjectMgr.GetPlayerAccountIdByGUID(rc); if (items_count > 0 || money > 0) { if (items_count > 0) { for(uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (!item) continue; if (HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } sLog.outLog(LOG_TRADE, "Player %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); pl->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); RealmDataDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); //deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting RealmDataDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", rc.GetCounter(), item->GetGUIDLow()); RealmDataDatabase.CommitTransaction(); draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0) { if (HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } if (_player->GetSession()->IsAccountFlagged(ACC_SPECIAL_LOG)) { sLog.outLog(LOG_SPECIAL, "Player %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } sLog.outLog(LOG_TRADE, "Player %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } sLog.outLog(LOG_MAIL, "Player %s (Account: %u) sent mail to player: %s (Account: %u) with subject: %s and body: %s", GetPlayerName(), GetAccountId(), receiver.c_str(), rc_account, subject.c_str(), body.c_str()); // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // If GM sends mail to player - deliver_delay must be zero if (deliver_delay && HasPermissions(PERM_GMT) && sWorld.getConfig(CONFIG_GM_MAIL)) deliver_delay = 0; // will delete item or place to receiver mail list draft .SetMoney(money) .SetCOD(COD) .SendMailTo(MailReceiver(receive, rc), pl, body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); RealmDataDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); RealmDataDatabase.CommitTransaction(); }
// this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) { DEBUG_LOG("WORLD: HandleAuctionSellItem"); ObjectGuid auctioneerGuid; uint32 etime, bid, buyout, itemCount; std::vector<ObjectGuid> guids; std::vector<uint32> stackSizes; recv_data >> auctioneerGuid; recv_data >> itemCount; if(itemCount > MAX_BAG_SIZE * 5) { recv_data.rpos(recv_data.wpos()); // should not happen return; } guids.resize(itemCount); stackSizes.resize(itemCount); for(uint32 i = 0; i < itemCount; ++i) { recv_data >> guids[i]; // item guid recv_data >> stackSizes[i]; // stack size } recv_data >> bid; recv_data >> buyout; recv_data >> etime; if (!bid || !etime) return; // check for cheaters Player *pl = GetPlayer(); AuctionHouseEntry const* auctionHouseEntry = GetCheckedAuctionHouseForAuctioneer(auctioneerGuid); if (!auctionHouseEntry) return; // always return pointer AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(auctionHouseEntry); // client send time in minutes, convert to common used sec time etime *= MINUTE; // client understand only 3 auction time switch(etime) { case 1*MIN_AUCTION_TIME: case 2*MIN_AUCTION_TIME: case 4*MIN_AUCTION_TIME: break; default: return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); for(uint32 i = 0; i < itemCount; ++i) { ObjectGuid itemGuid = guids[i]; if(itemGuid.IsEmpty()) continue; uint32 stackSize = stackSizes[i]; Item *it = pl->GetItemByGuid(itemGuid); // do not allow to sell already auctioned items if (sAuctionMgr.GetAItem(itemGuid.GetCounter())) { sLog.outError("AuctionError, %s is sending %s, but item is already in another auction", pl->GetGuidStr().c_str(), itemGuid.GetString().c_str()); SendAuctionCommandResult(NULL, AUCTION_STARTED, AUCTION_ERR_INVENTORY, EQUIP_ERR_ITEM_NOT_FOUND); continue; } // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to auction) if(!it) { SendAuctionCommandResult(NULL, AUCTION_STARTED, AUCTION_ERR_INVENTORY, EQUIP_ERR_ITEM_NOT_FOUND); continue; } if(!it->CanBeTraded()) { SendAuctionCommandResult(NULL, AUCTION_STARTED, AUCTION_ERR_INVENTORY, EQUIP_ERR_CANNOT_TRADE_THAT); continue; } if ((it->GetProto()->Flags & ITEM_FLAG_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(NULL, AUCTION_STARTED, AUCTION_ERR_INVENTORY, EQUIP_ERR_CANNOT_TRADE_THAT); continue; } // check money for deposit uint32 deposit = AuctionHouseMgr::GetAuctionDeposit( auctionHouseEntry, etime, it ); if ( pl->GetMoney() < deposit ) { SendAuctionCommandResult(NULL, AUCTION_STARTED, AUCTION_ERR_NOT_ENOUGH_MONEY); continue; } if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE) ) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), it->GetCount()); } if(stackSize == 0) stackSize = 1; if(stackSize > it->GetMaxStackCount()) // too big stack size stackSize = it->GetMaxStackCount(); if(!pl->HasItemCount(it->GetEntry(), stackSize)) // not enough items continue; Item *newItem = it->CloneItem(stackSize, pl); pl->DestroyItemCount(it, stackSize, true); pl->ModifyMoney( -int32(deposit) ); uint32 auction_time = uint32(etime * sWorld.getConfig(CONFIG_FLOAT_RATE_AUCTION_TIME)); AuctionEntry *AH = new AuctionEntry; AH->Id = sObjectMgr.GenerateAuctionID(); AH->itemGuidLow = newItem->GetObjectGuid().GetCounter(); AH->itemTemplate = newItem->GetEntry(); AH->owner = pl->GetGUIDLow(); AH->startbid = bid; AH->bidder = 0; AH->bid = 0; AH->buyout = buyout; AH->expireTime = time(NULL) + auction_time; AH->moneyDeliveryTime = 0; AH->deposit = deposit; AH->auctionHouseEntry = auctionHouseEntry; DETAIL_LOG("selling %s to auctioneer %s with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", itemGuid.GetString().c_str(), auctioneerGuid.GetString().c_str(), bid, buyout, auction_time, AH->GetHouseId()); auctionHouse->AddAuction(AH); sAuctionMgr.AddAItem(newItem); CharacterDatabase.BeginTransaction(); newItem->SaveToDB(); AH->SaveToDB(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); if (sIRC.BOTMASK & 1024) sIRC.AHFunc(it->GetEntry(), it->GetProto()->Name1, pl->GetName()); SendAuctionCommandResult(AH, AUCTION_STARTED, AUCTION_OK); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); } }
void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) { if (packet.Inv.Items.size() != 2) { TC_LOG_ERROR("network", "HandleWrapItem - Invalid itemCount (" SZFMTD ")", packet.Inv.Items.size()); return; } /// @todo: 6.x find better way for read // Gift uint8 giftContainerSlot = packet.Inv.Items[0].ContainerSlot; uint8 giftSlot = packet.Inv.Items[0].Slot; // Item uint8 itemContainerSlot = packet.Inv.Items[1].ContainerSlot; uint8 itemSlot = packet.Inv.Items[1].Slot; TC_LOG_DEBUG("network", "HandleWrapItem - Receive giftContainerSlot = %u, giftSlot = %u, itemContainerSlot = %u, itemSlot = %u", giftContainerSlot, giftSlot, itemContainerSlot, itemSlot); Item* gift = _player->GetItemByPos(giftContainerSlot, giftSlot); if (!gift) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); return; } if (!(gift->GetTemplate()->GetFlags() & ITEM_FLAG_IS_WRAPPER)) // cheating: non-wrapper wrapper { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); return; } Item* item = _player->GetItemByPos(itemContainerSlot, itemSlot); if (!item) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); return; } if (item == gift) // not possable with pacjket from real client { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_WRAPPED, item, NULL); return; } if (item->IsEquipped()) { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_EQUIPPED, item, NULL); return; } if (!item->GetGuidValue(ITEM_FIELD_GIFTCREATOR).IsEmpty()) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_WRAPPED, item, NULL); return; } if (item->IsBag()) { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_BAGS, item, NULL); return; } if (item->IsSoulBound()) { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_BOUND, item, NULL); return; } if (item->GetMaxStackCount() != 1) { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_STACKABLE, item, NULL); return; } // maybe not correct check (it is better than nothing) if (item->GetTemplate()->GetMaxCount() > 0) { _player->SendEquipError(EQUIP_ERR_CANT_WRAP_UNIQUE, item, NULL); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GIFT); stmt->setUInt64(0, item->GetOwnerGUID().GetCounter()); stmt->setUInt64(1, item->GetGUID().GetCounter()); stmt->setUInt32(2, item->GetEntry()); stmt->setUInt32(3, item->GetUInt32Value(ITEM_FIELD_FLAGS)); trans->Append(stmt); item->SetEntry(gift->GetEntry()); switch (item->GetEntry()) { case 5042: item->SetEntry(5043); break; case 5048: item->SetEntry(5044); break; case 17303: item->SetEntry(17302); break; case 17304: item->SetEntry(17305); break; case 17307: item->SetEntry(17308); break; case 21830: item->SetEntry(21831); break; } item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED); item->SetState(ITEM_CHANGED, _player); if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` { // after save it will be impossible to remove the item from the queue item->RemoveFromUpdateQueueOf(_player); item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone } CharacterDatabase.CommitTransaction(trans); uint32 count = 1; _player->DestroyItemCount(gift, count, true); }
void WorldSession::HandleSendMail(WorldPacket & recv_data) { uint64 mailbox, unk3, money, COD; std::string receiver, subject, body; uint32 unk1, unk2; uint8 unk4; recv_data >> mailbox; recv_data >> receiver; recv_data >> subject; recv_data >> body; recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 uint8 items_count; recv_data >> items_count; // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam return; } uint64 itemGUIDs[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { recv_data.read_skip<uint8>(); // item slot in mail, not used recv_data >> itemGUIDs[i]; } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 // packet read complete, now do check if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; if (receiver.empty()) return; Player* pl = _player; if (pl->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetSkyFireString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } uint64 rc = 0; if (normalizePlayerName(receiver)) rc = sObjectMgr->GetPlayerGUIDByName(receiver); if (!rc) { sLog->outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, "UI64FMTD" copper and "UI64FMTD" COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } sLog->outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, "UI64FMTD" copper and "UI64FMTD" COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (pl->GetGUID() == rc) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client uint64 reqmoney = cost + money; if (!pl->HasEnoughMoney(uint32(reqmoney))) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player *receive = sObjectMgr->GetPlayer(rc); uint32 rc_team = 0; uint8 mails_count = 0; //do not allow to send to one player more than 100 mails uint8 receiveLevel = 0; if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); receiveLevel = receive->getLevel(); } else { rc_team = sObjectMgr->GetPlayerTeamByGUID(rc); if (QueryResult result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); } if (QueryResult result = CharacterDatabase.PQuery("SELECT level FROM characters WHERE guid = '%u'", GUID_LOPART(rc))) { Field *fields = result->Fetch(); receiveLevel = fields[0].GetUInt8(); } } //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... or all items are account bound bool accountBound = items_count ? true : false; for (uint8 i = 0; i < items_count; ++i) { Item* item = pl->GetItemByGuid(itemGUIDs[i]); if (item) { ItemPrototype const* itemProto = item->GetProto(); if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiveLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetSkyFireString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(rc); Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { if (!itemGUIDs[i]) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = pl->GetItemByGuid(itemGUIDs[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; } if (item->GetProto()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsBag() && !((Bag*)item)->IsEmpty()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS); return; } items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); pl->ModifyMoney(-int32(reqmoney)); pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (items_count > 0 || money > 0) { if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_ITEM_OWNER); stmt->setUInt32(0, GUID_LOPART(rc)); stmt->setUInt32(1, item->GetGUIDLow()); trans->Append(stmt); draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail money: "UI64FMTD" to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list draft .AddMoney(money) .AddCOD(COD) .SendMailTo(trans, MailReceiver(receive, GUID_LOPART(rc)), MailSender(pl), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); pl->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandleSendMail(WorldPacket& recv_data) { CHECK_INWORLD_RETURN MailMessage msg; uint64 gameobject; uint32 unk2; uint8 itemcount; uint8 itemslot; uint8 i; uint64 itemguid; std::vector< Item* > items; std::vector< Item* >::iterator itr; std::string recepient; Item* pItem; //uint32 err = MAIL_OK; recv_data >> gameobject >> recepient; recv_data >> msg.subject >> msg.body >> msg.stationery; recv_data >> unk2 >> itemcount; if (itemcount > MAIL_MAX_ITEM_SLOT || msg.body.find("%") != std::string::npos || msg.subject.find("%") != std::string::npos) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } // Search for the recipient PlayerInfo* player = ObjectMgr::getSingleton().GetPlayerInfoByName(recepient.c_str()); if (player == NULL) { SendMailError(MAIL_ERR_RECIPIENT_NOT_FOUND); return; } for (i = 0; i < itemcount; ++i) { recv_data >> itemslot; recv_data >> itemguid; pItem = _player->GetItemInterface()->GetItemByGUID(itemguid); if (pItem == NULL || pItem->IsSoulbound() || pItem->IsConjured()) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } if (pItem->IsAccountbound() && GetAccountId() != player->acct) // don't mail account-bound items to another account { WorldPacket data(SMSG_SEND_MAIL_RESULT, 16); data << uint32(0); data << uint32(0); data << uint32(MAIL_ERR_BAG_FULL); data << uint32(INV_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); SendPacket(&data); return; } items.push_back(pItem); } recv_data >> msg.money; recv_data >> msg.cod; ///\todo left over: (TODO- FIX ME BURLEX!) // uint32 // uint32 // uint8 bool interfaction = false; if (sMailSystem.MailOption(MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION) || (HasGMPermissions() && sMailSystem.MailOption(MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM))) { interfaction = true; } // Check we're sending to the same faction (disable this for testing) if (player->team != _player->GetTeam() && !interfaction) { SendMailError(MAIL_ERR_NOT_YOUR_ALLIANCE); return; } // Check if we're sending mail to ourselves if (strcmp(player->name, _player->GetName()) == 0 && !GetPermissionCount()) { SendMailError(MAIL_ERR_CANNOT_SEND_TO_SELF); return; } if (msg.stationery == MAIL_STATIONERY_GM && !HasGMPermissions()) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } // Instant delivery time by default. msg.delivery_time = (uint32)UNIXTIME; // Set up the cost int32 cost = 0; // Check for attached money if (msg.money > 0) cost += msg.money; if (!sMailSystem.MailOption(MAIL_FLAG_DISABLE_POSTAGE_COSTS) && !(GetPermissionCount() && sMailSystem.MailOption(MAIL_FLAG_NO_COST_FOR_GM))) { cost += 30; } // check that we have enough in our backpack if (!_player->HasGold(cost)) { SendMailError(MAIL_ERR_NOT_ENOUGH_MONEY); return; } // Check for the item, and required item. if (!items.empty()) { for (itr = items.begin(); itr != items.end(); ++itr) { pItem = *itr; if (_player->GetItemInterface()->SafeRemoveAndRetreiveItemByGuid(pItem->GetGUID(), false) != pItem) continue; // should never be hit. pItem->RemoveFromWorld(); pItem->SetOwner(NULL); pItem->SaveToDB(INVENTORY_SLOT_NOT_SET, 0, true, NULL); msg.items.push_back(pItem->GetLowGUID()); if (GetPermissionCount() > 0) { /* log the message */ sGMLog.writefromsession(this, "sent mail with item entry %u to %s, with gold %u.", pItem->GetEntry(), player->name, msg.money); } pItem->DeleteMe(); } } if (msg.money != 0 || msg.cod != 0 || (!msg.items.size() && player->acct != _player->GetSession()->GetAccountId())) { if (!sMailSystem.MailOption(MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS)) msg.delivery_time += 3600; // 1hr } // take the money _player->ModGold(-cost); // Fill in the rest of the info msg.player_guid = player->guid; msg.sender_guid = _player->GetGUID(); // 30 day expiry time for unread mail if (!sMailSystem.MailOption(MAIL_FLAG_NO_EXPIRY)) msg.expire_time = (uint32)UNIXTIME + (TIME_DAY * MAIL_DEFAULT_EXPIRATION_TIME); else msg.expire_time = 0; msg.deleted_flag = false; msg.message_type = 0; msg.checked_flag = msg.body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY; // Great, all our info is filled in. Now we can add it to the other players mailbox. sMailSystem.DeliverMessage(player->guid, &msg); // Save/Update character's gold if they've received gold that is. This prevents a rollback. CharacterDatabase.Execute("UPDATE characters SET gold = %u WHERE guid = %u", _player->GetGold(), _player->m_playerInfo->guid); // Success packet :) SendMailError(MAIL_OK); }
void WorldSession::HandleSendMail(WorldPacket & recv_data ) { uint64 mailbox, unk3; std::string receiver, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; recv_data >> mailbox; recv_data >> receiver; recv_data >> subject; recv_data >> body; recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 uint8 items_count; recv_data >> items_count; // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam return; } uint64 itemGUIDs[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { recv_data.read_skip<uint8>(); // item slot in mail, not used recv_data >> itemGUIDs[i]; } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 // packet read complete, now do check if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; if (receiver.empty()) return; Player* pl = _player; uint64 rc = 0; if (normalizePlayerName(receiver)) rc = objmgr.GetPlayerGUIDByName(receiver); if (!rc) { sLog.outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } sLog.outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (pl->GetGUID() == rc) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client uint32 reqmoney = cost + money; if (pl->GetMoney() < reqmoney) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player *receive = objmgr.GetPlayer(rc); uint32 rc_team = 0; uint8 mails_count = 0; //do not allow to send to one player more than 100 mails if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); } else { rc_team = objmgr.GetPlayerTeamByGUID(rc); if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); } } //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : objmgr.GetPlayerAccountIdByGUID(rc); Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { if (!itemGUIDs[i]) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = pl->GetItemByGuid(itemGUIDs[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; } if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); uint32 itemTextId = !body.empty() ? objmgr.CreateItemText( body ) : 0; pl->ModifyMoney( -int32(reqmoney) ); pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, itemTextId); if (items_count > 0 || money > 0) { if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); // deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", GUID_LOPART(rc), item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list draft .AddMoney(money) .AddCOD(COD) .SendMailTo(MailReceiver(receive, GUID_LOPART(rc)), pl, MAIL_CHECK_MASK_NONE, deliver_delay); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
void WorldSession::HandleTakeItem(WorldPacket& recv_data) { CHECK_INWORLD_RETURN uint64 mailbox; uint32 message_id; uint32 lowguid; std::vector< uint32 >::iterator itr; recv_data >> mailbox >> message_id >> lowguid; WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); data << message_id << uint32(MAIL_RES_ITEM_TAKEN); MailMessage* message = _player->m_mailBox.GetMessage(message_id); if (message == 0 || message->items.empty()) { data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } for (itr = message->items.begin(); itr != message->items.end(); ++itr) { if ((*itr) == lowguid) break; } if (itr == message->items.end()) { data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } // check for cod credit if (message->cod > 0) { if (!_player->HasGold(message->cod)) { data << uint32(MAIL_ERR_NOT_ENOUGH_MONEY); SendPacket(&data); return; } } // grab the item Item* item = objmgr.LoadItem(*itr); if (item == 0) { // doesn't exist data << uint32(MAIL_ERR_INTERNAL_ERROR); SendPacket(&data); return; } //Find free slot SlotResult result = _player->GetItemInterface()->FindFreeInventorySlot(item->GetProto()); if (result.Result == 0) { //End of slots data << uint32(MAIL_ERR_BAG_FULL); SendPacket(&data); item->DeleteMe(); return; } item->m_isDirty = true; if (!_player->GetItemInterface()->SafeAddItem(item, result.ContainerSlot, result.Slot)) { if (!_player->GetItemInterface()->AddItemToFreeSlot(item)) { //End of slots data << uint32(MAIL_ERR_BAG_FULL); SendPacket(&data); item->DeleteMe(); return; } } else item->SaveToDB(result.ContainerSlot, result.Slot, true, NULL); // send complete packet data << uint32(MAIL_OK); data << item->GetLowGUID(); data << item->GetStackCount(); message->items.erase(itr); // re-save (update the items field) sMailSystem.SaveMessageToSQL(message); SendPacket(&data); if (message->cod > 0) { _player->ModGold(-(int32)message->cod); std::string subject = "COD Payment: "; subject += message->subject; sMailSystem.SendAutomatedMessage(NORMAL, message->player_guid, message->sender_guid, subject, "", message->cod, 0, 0, MAIL_STATIONERY_TEST1, MAIL_CHECK_MASK_COD_PAYMENT); message->cod = 0; CharacterDatabase.Execute("UPDATE mailbox SET cod = 0 WHERE message_id = %u", message->message_id); } // probably need to send an item push here }
/** * Handles the Packet sent by the client when sending a mail. * * This methods takes the packet sent by the client and performs the following actions: * - Checks whether the mail is valid: i.e. can he send the selected items, * does he have enough money, etc. * - Creates a MailDraft and adds the needed items, money, cost data. * - Sends the mail. * * Depending on the outcome of the checks performed the player will recieve a different * MailResponseResult. * * @see MailResponseResult * @see SendMailResult() * * @param recv_data the WorldPacket containing the data sent by the client. */ void WorldSession::HandleSendMail(WorldPacket& recv_data) { sLog.outError("WORLD: CMSG_SEND_MAIL"); ObjectGuid mailboxGuid; uint64 money, COD; std::string receiver, subject, body; uint8 receiverLen, subjectLen, bodyLen; uint32 unk1, unk2; recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 recv_data >> COD >> money; // cod and money bodyLen = recv_data.ReadBits(12); subjectLen = recv_data.ReadBits(9); uint8 items_count = recv_data.ReadBits(5); // attached items count if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rfinish(); // set to end to avoid warnings spam return; } recv_data.ReadGuidMask<0>(mailboxGuid); ObjectGuid itemGuids[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) recv_data.ReadGuidMask<2, 6, 3, 7, 1, 0, 4, 5>(itemGuids[i]); recv_data.ReadGuidMask<3, 4>(mailboxGuid); receiverLen = recv_data.ReadBits(7); recv_data.ReadGuidMask<2, 6, 1, 7, 5>(mailboxGuid); recv_data.ReadGuidBytes<4>(mailboxGuid); for (uint8 i = 0; i < items_count; ++i) { recv_data.ReadGuidBytes<6, 1, 7, 2>(itemGuids[i]); recv_data.read_skip<uint8>(); // item slot in mail, not used recv_data.ReadGuidBytes<3, 0, 4, 5>(itemGuids[i]); } recv_data.ReadGuidBytes<7, 3, 6, 5>(mailboxGuid); subject = recv_data.ReadString(subjectLen); receiver = recv_data.ReadString(receiverLen); recv_data.ReadGuidBytes<2, 0>(mailboxGuid); body = recv_data.ReadString(bodyLen); recv_data.ReadGuidBytes<1>(mailboxGuid); DEBUG_LOG("WORLD: CMSG_SEND_MAIL receiver '%s' subject '%s' body '%s' mailbox " UI64FMTD " money " UI64FMTD " COD " UI64FMTD " unkt1 %u unk2 %u", receiver.c_str(), subject.c_str(), body.c_str(), mailboxGuid.GetRawValue(), money, COD, unk1, unk2); // packet read complete, now do check if (!CheckMailBox(mailboxGuid)) return; if (receiver.empty()) return; Player* pl = _player; ObjectGuid rc; if (normalizePlayerName(receiver)) rc = sObjectMgr.GetPlayerGuidByName(receiver); if (!rc) { DEBUG_LOG("%s is sending mail to %s (GUID: nonexistent!) with subject %s and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", pl->GetGuidStr().c_str(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } DEBUG_LOG("%s is sending mail to %s with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGuidStr().c_str(), rc.GetString().c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (pl->GetObjectGuid() == rc) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client uint64 reqmoney = cost + money; if (pl->GetMoney() < reqmoney) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receive = sObjectMgr.GetPlayer(rc); Team rc_team; uint8 mails_count = 0; // do not allow to send to one player more than 100 mails if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); } else { rc_team = sObjectMgr.GetPlayerTeamByGUID(rc); if (QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", rc.GetCounter())) { Field* fields = result->Fetch(); mails_count = fields[0].GetUInt32(); delete result; } } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mails_count > 100) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // check the receiver's Faction... if (!sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } uint32 rc_account = receive ? receive->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(rc); Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) { if (!itemGuids[i].IsItem()) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = pl->GetItemByGuid(itemGuids[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; } if ((item->GetProto()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); pl->ModifyMoney(-int64(reqmoney)); pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, body); if (items_count > 0 || money > 0) { if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); CharacterDatabase.BeginTransaction(); item->DeleteFromInventoryDB(); // deletes item from character's inventory item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", rc.GetCounter(), item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail money: " UI64FMTD " to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list draft .SetMoney(money) .SetCOD(COD) .SendMailTo(MailReceiver(receive, rc), pl, body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); }
static void addNewAuctions(Player *AHBplayer, AHBConfig *config) { if (!AHBSeller) return; AuctionHouseObject* auctionHouse = objmgr.GetAuctionsMap(config->GetAHID()); uint32 items = 0; uint32 minItems = config->GetMinItems(); uint32 maxItems = config->GetMaxItems(); uint32 auctions = auctionHouse->Getcount(); if (auctions >= minItems) return; if (auctions <= maxItems) { if ((maxItems - auctions) > ItemsPerCycle) items = ItemsPerCycle; else items = (maxItems - auctions); } uint32 wtgbin = config->GetPercents(AHB_WHITE_TG); uint32 gtgbin = config->GetPercents(AHB_GREEN_TG); uint32 btgbin = config->GetPercents(AHB_BLUE_TG); uint32 ptgbin = config->GetPercents(AHB_PURPLE_TG); uint32 wibin = config->GetPercents(AHB_WHITE_I); uint32 gibin = config->GetPercents(AHB_GREEN_I); uint32 bibin = config->GetPercents(AHB_BLUE_I); uint32 pibin = config->GetPercents(AHB_PURPLE_I); uint32 total = wtgbin + gtgbin + btgbin + ptgbin + wibin + gibin + bibin + pibin; uint32 pItems = 0; uint32 bItems = 0; uint32 gItems = 0; uint32 wItems = 0; uint32 pTGoods = 0; uint32 bTGoods = 0; uint32 gTGoods = 0; uint32 wTGoods = 0; for (AuctionHouseObject::AuctionEntryMap::iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr) { AuctionEntry *Aentry = itr->second; Item *item = objmgr.GetAItem(Aentry->item_guidlow); if( item ) { ItemPrototype const *prototype = item->GetProto(); if( prototype ) { switch (prototype->Quality) { case 0: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) wTGoods = wTGoods + 1; else wItems = wItems + 1; break; case 1: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) wTGoods = wTGoods + 1; else wItems = wItems + 1; break; case 2: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) gTGoods = gTGoods + 1; else gItems = gItems + 1; break; case 3: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) bTGoods = bTGoods + 1; else bItems = bItems + 1; break; case 4: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) pTGoods = pTGoods + 1; else pItems = pItems + 1; break; } } } } // only insert a few at a time, so as not to peg the processor for (uint32 cnt = 1;cnt <= items;cnt++) { uint32 itemID = 0; while (itemID == 0) { uint32 choice = urand(1, 8); switch (choice) { case 1: { if ((purpleItems.size() > 0) && (pItems < pibin)) { itemID = purpleItems[urand(0, purpleItems.size() - 1)]; pItems = pItems + 1; break; } } case 2: { if ((blueItems.size() > 0) && (bItems < bibin)) { itemID = blueItems[urand(0, blueItems.size() - 1)]; bItems = bItems + 1; break; } } case 3: { if ((greenItems.size() > 0) && (gItems < gibin)) { itemID = greenItems[urand(0, greenItems.size() - 1)]; gItems = gItems + 1; break; } } case 4: { if ((whiteItems.size() > 0) && (wItems < wibin)) { itemID = whiteItems[urand(0, whiteItems.size() - 1)]; wItems = wItems + 1; break; } } case 5: { if ((purpleTradeGoods.size() > 0) && (pTGoods < ptgbin)) { itemID = purpleTradeGoods[urand(0, purpleTradeGoods.size() - 1)]; pTGoods = pTGoods + 1; break; } } case 6: { if ((blueTradeGoods.size() > 0) && (bTGoods < btgbin)) { itemID = blueTradeGoods[urand(0, blueTradeGoods.size() - 1)]; bTGoods = bTGoods + 1; break; } } case 7: { if ((greenTradeGoods.size() > 0) && (gTGoods < gtgbin)) { itemID = greenTradeGoods[urand(0, greenTradeGoods.size() - 1)]; gTGoods = gTGoods + 1; break; } } case 8: { if ((whiteTradeGoods.size() > 0) && (wTGoods < wtgbin)) { itemID = whiteTradeGoods[urand(0, whiteTradeGoods.size() - 1)]; wTGoods = wTGoods + 1; break; } } default: { break; } } } ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); if (prototype == NULL) { sLog.outString("AuctionHouseBot: Huh?!?! prototype == NULL"); continue; } Item* item = Item::CreateItem(itemID, 1, AHBplayer); item->AddToUpdateQueueOf(AHBplayer); if (item == NULL) { sLog.outString("AuctionHouseBot: Item::CreateItem() returned NULL"); break; } uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); if (randomPropertyId != 0) item->SetItemRandomProperties(randomPropertyId); uint32 buyoutPrice = prototype->BuyPrice * item->GetCount(); uint32 bidPrice = 0; uint32 stackCount = urand(1, item->GetMaxStackCount()); switch (prototype->Quality) { case 1: if (config->GetMaxStack(AHB_WHITE) != 0) { stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_WHITE))); } buyoutPrice *= urand(config->GetMinPrice(AHB_WHITE), config->GetMaxPrice(AHB_WHITE)) * stackCount; buyoutPrice /= 100; bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_WHITE), config->GetMaxBidPrice(AHB_WHITE)); bidPrice /= 100; break; case 2: if (config->GetMaxStack(AHB_GREEN) != 0) { stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREEN))); } buyoutPrice *= urand(config->GetMinPrice(AHB_GREEN), config->GetMaxPrice(AHB_GREEN)) * stackCount; buyoutPrice /= 100; bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREEN), config->GetMaxBidPrice(AHB_GREEN)); bidPrice /= 100; break; case 3: if (config->GetMaxStack(AHB_BLUE) != 0) { stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_BLUE))); } buyoutPrice *= urand(config->GetMinPrice(AHB_BLUE), config->GetMaxPrice(AHB_BLUE)) * stackCount; buyoutPrice /= 100; bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_BLUE), config->GetMaxBidPrice(AHB_BLUE)); bidPrice /= 100; break; case 4: if (config->GetMaxStack(AHB_PURPLE) != 0) { stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_PURPLE))); } buyoutPrice *= urand(config->GetMinPrice(AHB_PURPLE), config->GetMaxPrice(AHB_PURPLE)) * stackCount; buyoutPrice /= 100; bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_PURPLE), config->GetMaxBidPrice(AHB_PURPLE)); bidPrice /= 100; break; } item->SetCount(stackCount); AuctionEntry* auctionEntry = new AuctionEntry; auctionEntry->Id = objmgr.GenerateAuctionID(); auctionEntry->auctioneer = 0; auctionEntry->item_guidlow = item->GetGUIDLow(); auctionEntry->item_template = item->GetEntry(); auctionEntry->owner = AHBplayer->GetGUIDLow(); auctionEntry->startbid = bidPrice; auctionEntry->buyout = buyoutPrice; auctionEntry->bidder = 0; auctionEntry->bid = 0; auctionEntry->deposit = 0; auctionEntry->location = config->GetAHID(); auctionEntry->time = (time_t) (urand(config->GetMinTime(), config->GetMaxTime()) * 60 * 60 + time(NULL)); item->SaveToDB(); item->RemoveFromUpdateQueueOf(AHBplayer); objmgr.AddAItem(item); auctionHouse->AddAuction(auctionEntry); CharacterDatabase.PExecute("INSERT INTO `auctionhouse` (`id`," "`auctioneerguid`,`itemguid`,`item_template`," "`itemowner`,`buyoutprice`,`time`,`buyguid`," "`lastbid`,`startbid`,`deposit`,`location`) " "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', " "'" I64FMTD "', '%u', '%u', '%u', '%u', '%u')", auctionEntry->Id, auctionEntry->auctioneer, auctionEntry->item_guidlow, auctionEntry->item_template, auctionEntry->owner, auctionEntry->buyout, (uint64) auctionEntry->time, auctionEntry->bidder, auctionEntry->bid, auctionEntry->startbid, auctionEntry->deposit, auctionEntry->location); } }