void WorldSession::HandleTransmogrifyItems(WorldPackets::Item::TransmogrifyItems& transmogrifyItems) { Player* player = GetPlayer(); // Validate if (!player->GetNPCIfCanInteractWith(transmogrifyItems.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER)) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - %s not found or player can't interact with it.", transmogrifyItems.Npc.ToString().c_str()); return; } int64 cost = 0; std::unordered_map<Item*, Item*> transmogItems; std::unordered_map<Item*, std::pair<VoidStorageItem*, BonusData>> transmogVoidItems; std::vector<Item*> resetAppearanceItems; for (WorldPackets::Item::TransmogrifyItem const& transmogItem : transmogrifyItems.Items) { // slot of the transmogrified item if (transmogItem.Slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify wrong slot (%u) when transmogrifying items.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, transmogItem.Slot); if (!itemTransmogrified) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.Slot); return; } WorldPackets::Item::ItemInstance itemInstance; BonusData const* bonus = nullptr; if (transmogItem.SrcItemGUID) { // guid of the transmogrifier item Item* itemTransmogrifier = player->GetItemByGuid(*transmogItem.SrcItemGUID); if (!itemTransmogrifier) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } itemInstance.Initialize(itemTransmogrifier); bonus = itemTransmogrifier->GetBonus(); transmogItems[itemTransmogrified] = itemTransmogrifier; } else if (transmogItem.SrcVoidItemGUID) { // guid of the transmogrifier item uint8 slot; VoidStorageItem* itemTransmogrifier = player->GetVoidStorageItem(transmogItem.SrcVoidItemGUID->GetCounter(), slot); if (!itemTransmogrifier) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid void storage item (%s).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcVoidItemGUID->ToString().c_str()); return; } itemInstance.Initialize(itemTransmogrifier); std::pair<VoidStorageItem*, BonusData>& transmogData = transmogVoidItems[itemTransmogrified]; transmogData.first = itemTransmogrifier; transmogData.second.Initialize(itemInstance); bonus = &transmogData.second; } else { resetAppearanceItems.push_back(itemTransmogrified); continue; } // entry of transmogrifier and from packet if (itemInstance != transmogItem.Item) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) tried to transmogrify with an invalid item instance data for %s.", player->GetGUID().ToString().c_str(), player->GetName().c_str(), transmogItem.SrcItemGUID->ToString().c_str()); return; } // validity of the transmogrification items if (!Item::CanTransmogrifyItemWithItem(itemTransmogrified, transmogItem.Item, bonus)) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (%s, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUID().ToString().c_str(), player->GetName().c_str(), itemTransmogrified->GetEntry(), transmogItem.Item.ItemID); return; } // add cost cost += itemTransmogrified->GetSpecialPrice(); } if (cost) // 0 cost if reverting look { if (!player->HasEnoughMoney(cost)) return; player->ModifyMoney(-cost); } // Everything is fine, proceed for (auto& transmogPair : transmogItems) { Item* transmogrified = transmogPair.first; Item* transmogrifier = transmogPair.second; transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->GetEntry()); transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, transmogrifier->GetAppearanceModId()); player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); transmogrified->SetNotRefundable(player); transmogrified->ClearSoulboundTradeable(player); transmogrifier->SetNotRefundable(player); transmogrifier->ClearSoulboundTradeable(player); if (transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_EQUIPED || transmogrifier->GetTemplate()->GetBonding() == BIND_WHEN_USE) transmogrifier->SetBinding(true); } for (auto& transmogVoirPair : transmogVoidItems) { Item* transmogrified = transmogVoirPair.first; VoidStorageItem* transmogrifier = transmogVoirPair.second.first; BonusData& bonus = transmogVoirPair.second.second; transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, transmogrifier->ItemEntry); transmogrified->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, bonus.AppearanceModID); player->SetVisibleItemSlot(transmogrified->GetSlot(), transmogrified); transmogrified->SetNotRefundable(player); transmogrified->ClearSoulboundTradeable(player); } for (Item* item : resetAppearanceItems) { item->SetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID, 0); item->SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD, 0); player->SetVisibleItemSlot(item->GetSlot(), item); } }
void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) { DEBUG_LOG("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 DEBUG_LOG("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, nullptr); return; } // cheating: non-wrapper wrapper (all empty wrappers is stackable) if (!(gift->GetProto()->Flags & ITEM_FLAG_IS_WRAPPER) || gift->GetMaxStackCount() == 1) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, nullptr); return; } Item* item = _player->GetItemByPos(item_bag, item_slot); if (!item) { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, nullptr); return; } if (item == gift) // not possible with packet from real client { _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, nullptr); return; } if (item->IsEquipped()) { _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, nullptr); return; } if (item->GetGuidValue(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED); { _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, nullptr); return; } if (item->IsBag()) { _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, nullptr); return; } if (item->IsSoulBound()) { _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, nullptr); return; } if (item->GetMaxStackCount() != 1) { _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, nullptr); return; } // maybe not correct check (it is better than nothing) if (item->GetProto()->MaxCount > 0) { _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, nullptr); return; } CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", item->GetOwnerGuid().GetCounter(), 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->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetObjectGuid()); item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_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(); // item gave inventory record unchanged and can be save standalone } CharacterDatabase.CommitTransaction(); uint32 count = 1; _player->DestroyItemCount(gift, count, true); }
void LootRoll::Finalize() { if( !mLootLock.AttemptAcquire() ) // only one finalization, please. players on different maps can roll, too, so this is needed. { sEventMgr.RemoveEvents(this); return; } sEventMgr.RemoveEvents(this); // this we will have to finalize with groups types.. for now // we'll just assume need before greed. person with highest roll // in need gets the item. uint32 highest = 0; int8 hightype = -1; uint64 player = 0; WorldPacket data(34); for(std::map<uint32, uint32>::iterator itr = m_NeedRolls.begin(); itr != m_NeedRolls.end(); itr++) { if(itr->second > highest) { highest = itr->second; player = itr->first; hightype = NEED; } } if(!highest) { for(std::map<uint32, uint32>::iterator itr = m_GreedRolls.begin(); itr != m_GreedRolls.end(); itr++) { if(itr->second > highest) { highest = itr->second; player = itr->first; hightype = GREED; } } for(std::map<uint32, uint32>::iterator itr = m_DisenchantRolls.begin(); itr != m_DisenchantRolls.end(); itr++) { if(itr->second > highest) { highest = itr->second; player = itr->first; hightype = DISENCHANT; } } } Loot * pLoot = 0; uint32 guidtype = GET_TYPE_FROM_GUID(_guid); if( guidtype == HIGHGUID_TYPE_CREATURE ) { Creature* pc = _mgr->GetCreature(GET_LOWGUID_PART(_guid)); if(pc) pLoot = &pc->m_loot; } else if( guidtype == HIGHGUID_TYPE_GAMEOBJECT ) { GameObject* go = _mgr->GetGameObject(GET_LOWGUID_PART(_guid)); if(go) pLoot = &go->m_loot; } if(!pLoot) { delete this; return; } if(_slotid >= pLoot->items.size()) { delete this; return; } pLoot->items.at(_slotid).roll = NULLROLL; uint32 itemid = pLoot->items.at(_slotid).item.itemproto->ItemId; uint32 amt = pLoot->items.at(_slotid).StackSize; if(!amt) { delete this; return; } Player* _player = (player) ? _mgr->GetPlayer((uint32)player) : NULLPLR; if(!player || !_player) { /* all passed */ data.Initialize(SMSG_LOOT_ALL_PASSED); data << _guid << _groupcount << _itemid << _randomsuffixid << _randompropertyid; set<uint32>::iterator pitr = m_passRolls.begin(); while(_player == NULL && pitr != m_passRolls.end()) { _player = _mgr->GetPlayer( (*(pitr)) ); ++pitr; } if( _player != NULL ) { if(_player->InGroup()) _player->GetGroup()->SendPacketToAll(&data); else _player->GetSession()->SendPacket(&data); } /* item can now be looted by anyone :) */ pLoot->items.at(_slotid).passed = true; delete this; return; } pLoot->items.at(_slotid).roll = 0; data.Initialize(SMSG_LOOT_ROLL_WON); data << _guid << _slotid << _itemid << _randomsuffixid << _randompropertyid; data << _player->GetGUID() << uint8(highest) << uint8(hightype); if(_player->InGroup()) _player->GetGroup()->SendPacketToAll(&data); else _player->GetSession()->SendPacket(&data); if(hightype == DISENCHANT) { //generate Disenchantingloot Item * pItem = objmgr.CreateItem( itemid, _player); lootmgr.FillItemLoot(&pItem->m_loot, pItem->GetEntry(), _player->GetTeam()); //add loot for(std::vector<__LootItem>::iterator iter=pItem->m_loot.items.begin();iter != pItem->m_loot.items.end();iter++) { itemid =iter->item.itemproto->ItemId; Item * Titem = objmgr.CreateItem( itemid, _player); if( Titem == NULLITEM ) continue; if( !_player->GetItemInterface()->AddItemToFreeSlot(Titem) ) { _player->GetSession()->SendNotification("No free slots were found in your inventory, item has been mailed."); sMailSystem.DeliverMessage(MAILTYPE_NORMAL, _player->GetGUID(), _player->GetGUID(), "Loot Roll", "Here is your reward.", 0, 0, itemid, 1, true); } Titem->DeleteMe(); Titem = NULLITEM; } pItem->DeleteMe(); pItem = NULLITEM; // Set a looter, doesn't matter who. pLoot->items.at(_slotid).has_looted.insert(_player->GetLowGUID()); //Send "finish" packet data.Initialize(SMSG_LOOT_REMOVED); data << uint8(_slotid); Player* plr; for(LooterSet::iterator itr = pLoot->looters.begin(); itr != pLoot->looters.end(); itr++) { if((plr = _player->GetMapMgr()->GetPlayer(*itr))) plr->GetSession()->SendPacket(&data); } delete this; //end here and skip the rest return; } ItemPrototype* it = ItemPrototypeStorage.LookupEntry(itemid); int8 error; if((error = _player->GetItemInterface()->CanReceiveItem(it, 1, NULL))) { _player->GetItemInterface()->BuildInventoryChangeError(NULLITEM, NULLITEM, error); return; } Item* add = _player->GetItemInterface()->FindItemLessMax(itemid, amt, false); if (!add) { SlotResult slotresult = _player->GetItemInterface()->FindFreeInventorySlot(it); if(!slotresult.Result) { _player->GetSession()->SendNotification("No free slots were found in your inventory, item has been mailed."); sMailSystem.DeliverMessage(MAILTYPE_NORMAL, _player->GetGUID(), _player->GetGUID(), "Loot Roll", "Here is your reward.", 0, 0, it->ItemId, 1, true); data.Initialize(SMSG_LOOT_REMOVED); data << uint8(_slotid); Player* plr; for(LooterSet::iterator itr = pLoot->looters.begin(); itr != pLoot->looters.end(); itr++) { if((plr = _player->GetMapMgr()->GetPlayer(*itr))) plr->GetSession()->SendPacket(&data); } delete this; return; } DEBUG_LOG("HandleAutostoreItem","AutoLootItem %u",itemid); Item* item = objmgr.CreateItem( itemid, _player); item->SetUInt32Value(ITEM_FIELD_STACK_COUNT,amt); if(pLoot->items.at(_slotid).iRandomProperty!=NULL) { item->SetRandomProperty(pLoot->items.at(_slotid).iRandomProperty->ID); item->ApplyRandomProperties(false); } else if(pLoot->items.at(_slotid).iRandomSuffix != NULL) { item->SetRandomSuffix(pLoot->items.at(_slotid).iRandomSuffix->id); item->ApplyRandomProperties(false); } if( _player->GetItemInterface()->SafeAddItem(item,slotresult.ContainerSlot, slotresult.Slot) ) { _player->GetSession()->SendItemPushResult(item,false,true,true,true,slotresult.ContainerSlot,slotresult.Slot,1); sQuestMgr.OnPlayerItemPickup(_player,item); } else { item->DeleteMe(); item = NULLITEM; } } else { add->SetCount(add->GetUInt32Value(ITEM_FIELD_STACK_COUNT) + amt); add->m_isDirty = true; sQuestMgr.OnPlayerItemPickup(_player,add); _player->GetSession()->SendItemPushResult(add, false, true, true, false, _player->GetItemInterface()->GetBagSlotByGuid(add->GetGUID()), 0xFFFFFFFF, 1); } // Set a looter, doesn't matter who. pLoot->items.at(_slotid).has_looted.insert(_player->GetLowGUID()); // this gets sent to all looters data.Initialize(SMSG_LOOT_REMOVED); data << uint8(_slotid); Player* plr; for(LooterSet::iterator itr = pLoot->looters.begin(); itr != pLoot->looters.end(); itr++) { if((plr = _player->GetMapMgr()->GetPlayer(*itr))) plr->GetSession()->SendPacket(&data); } delete this; }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { uint8 bagIndex, slot; uint8 unk_flags; // flags (if 0x02 - some additional data are received) uint8 cast_count; // next cast if exists (single or not) uint64 item_guid; uint32 glyphIndex; // something to do with glyphs? uint32 spellid; // casted spell id recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; // TODO: add targets.read() check Player* pUser = _player; // ignore for remote control state if (!pUser->IsSelfMover()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail return; } // reject fake data if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } Item *pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if (pItem->GetGUID() != item_guid) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } DETAIL_LOG("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (uint32)recvPacket.size()); ItemPrototype const *proto = pItem->GetProto(); if (!proto) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // some item classes can be used only in equipped state if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } uint8 msg = pUser->CanUseItem(pItem); if (msg != EQUIP_ERR_OK) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError( msg, pItem, NULL ); return; } // not allow use item from trade (cheat way only) if (pItem->IsInTrade()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); return; } if (pUser->isInCombat()) { for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { if (IsNonCombatSpell(spellInfo)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); return; } } } // Prevent potion drink if another potion in processing (client have potions disabled in like case) if (pItem->IsPotion() && pUser->GetLastPotionId()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_OBJECT_IS_BUSY,pItem,NULL); return; } } // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM ) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding( true ); } } SpellCastTargets targets; recvPacket >> targets.ReadForCaster(pUser); targets.Update(pUser); if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) { // free gray item after use fail pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); // send spell error if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) { // for implicit area/coord target spells if (IsPointEffectTarget(Targets(spellInfo->EffectImplicitTargetA[EFFECT_INDEX_0])) || IsAreaEffectTarget(Targets(spellInfo->EffectImplicitTargetA[EFFECT_INDEX_0]))) Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS); // for explicit target spells else Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_BAD_TARGETS); } return; } //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. if(!Script->ItemUse(pUser,pItem,targets)) { // no script or script not process request by self pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); } }
//this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) { uint64 auctioneer; uint32 itemsCount, etime, bid, buyout; recvData >> auctioneer; recvData >> 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, ERR_AUCTION_DATABASE_ERROR); return; } for (uint32 i = 0; i < itemsCount; ++i) { recvData >> itemGUIDs[i]; recvData >> count[i]; if (!itemGUIDs[i] || !count[i] || count[i] > 1000 ) return; } recvData >> bid; recvData >> buyout; recvData >> 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, 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_DURATION) || item->GetCount() < count[i]) { 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; } 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; } } 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, ERR_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); // Required stack size of auction matches to current item stack size, just move item to auctionhouse 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().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); } 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; sLog->outInfo(LOG_FILTER_NETWORKIO, "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().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->Id, AUCTION_SELL_ITEM, ERR_AUCTION_OK); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); return; } 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) { sLog->outError(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_SELL_ITEM: Could not create clone of item %u", item->GetEntry()); SendAuctionCommandResult(0, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_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().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); } 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; sLog->outInfo(LOG_FILTER_NETWORKIO, "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().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 < 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); } 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); return; } } }
//called when player lists his received mails void WorldSession::HandleGetMailList(WorldPacket & recv_data ) { uint64 mailbox; recv_data >> mailbox; if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // send to client mails amount uint32 realCount = 0; // real mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size data << uint32(0); // real mail's count data << uint8(0); // mail's count time_t cur_time = time(NULL); for(PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if(mailsCount >= 254) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+1+item_count*(1+4+4+7*3*4+4+4+4+4+4+4+1); if(data.wpos()+next_mail_size > maxPacketSize) { realCount += 1; continue; } uint32 show_flags = 0; if ((*itr)->messageType != MAIL_NORMAL) show_flags |= MAIL_SHOW_DELETE; if ((*itr)->messageType == MAIL_AUCTION) show_flags |= MAIL_SHOW_AUCTION; if ((*itr)->HasItems() && (*itr)->messageType == MAIL_NORMAL) show_flags |= MAIL_SHOW_RETURN; data << uint16(next_mail_size); // Message size data << uint32((*itr)->messageID); // Message ID data << uint8((*itr)->messageType); // Message Type switch((*itr)->messageType) { case MAIL_NORMAL: // sender guid data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << uint32((*itr)->sender); // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI data << uint32(0); // item entry break; } data << uint32((*itr)->COD); // COD data << uint32((*itr)->itemTextId); // sure about this data << uint32(0); // unknown data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32((*itr)->money); // Gold data << uint32(show_flags); // unknown, 0x4 - auction, 0x10 - normal data << float(((*itr)->expire_time-time(NULL))/DAY);// Time data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) data << (*itr)->subject; // Subject string - once 00, when mail type = 3 data << uint8(item_count); // client limit is 0x10 for(uint8 i = 0; i < item_count; ++i) { Item *item = _player->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << uint8(i); // item guid low? data << uint32(item ? item->GetGUIDLow() : 0); // entry data << uint32(item ? item->GetEntry() : 0); for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) { // unsure data << uint32(item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0); } // can be negative data << uint32(item ? item->GetItemRandomPropertyId() : 0); // unk data << uint32(item ? item->GetItemSuffixFactor() : 0); // stack count data << uint32(item ? item->GetCount() : 0); // charges data << uint32(item ? item->GetSpellCharges() : 0); // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0); // durability data << uint32(item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0); // unknown wotlk data << uint8(0); } mailsCount += 1; realCount += 1; } data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount data.put<uint8>(4, mailsCount); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
TransmogTrinityStrings Transmogrification::Transmogrify(Player* player, uint64 itemGUID, uint8 slot, /*uint32 newEntry, */bool no_cost) { int32 cost = 0; // slot of the transmogrified item if (slot >= EQUIPMENT_SLOT_END) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an item (lowguid: %u) with a wrong slot (%u) when transmogrifying items.", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID), slot); return LANG_ERR_TRANSMOG_INVALID_SLOT; } /* // GET FROM itemTransmogrifier // entry of the transmogrifier item, if it's not 0 if (newEntry) { ItemTemplate const* proto = sObjectMgr->GetItemTemplate(newEntry); if (!proto) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify to an invalid item (entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), newEntry); return LANG_ERR_TRANSMOG_INVALID_SRC_ENTRY; } } */ Item* itemTransmogrifier = NULL; // guid of the transmogrifier item, if it's not 0 if (itemGUID) { itemTransmogrifier = player->GetItemByGuid(itemGUID); if (!itemTransmogrifier) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify with an invalid item (lowguid: %u).", player->GetGUIDLow(), player->GetName().c_str(), GUID_LOPART(itemGUID)); return LANG_ERR_TRANSMOG_MISSING_SRC_ITEM; } } // transmogrified item Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); if (!itemTransmogrified) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot); return LANG_ERR_TRANSMOG_MISSING_DEST_ITEM; } // uint16 tempDest; //// has to be able to equip item transmogrified item //if (!player->CanEquipItem(slot, tempDest, itemTransmogrified, true, true)) //{ // TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the item to be transmogrified (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot, itemTransmogrified->GetEntry()); // return; //} // //// has to be able to equip item transmogrifier item //if (!player->CanEquipItem(slot, tempDest, itemTransmogrifier, true, true)) //{ // TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) can't equip the transmogrifier item (slot: %u, entry: %u).", player->GetGUIDLow(), player->GetName().c_str(), slot, itemTransmogrifier->GetEntry()); // return; //} if (!itemTransmogrifier) // reset look newEntry { // itemTransmogrified->ClearEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT); // player->SetVisibleItemSlot(slot, itemTransmogrified); // Custom DeleteFakeEntry(player, slot, itemTransmogrified); } else { if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier->GetTemplate())) { TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - Player (GUID: %u, name: %s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetGUIDLow(), player->GetName().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry()); return LANG_ERR_TRANSMOG_INVALID_ITEMS; } if (!no_cost) { cost = GetSpecialPrice(itemTransmogrified->GetTemplate()); cost *= ScaledCostModifier; cost += CopperCost; if (!player->HasEnoughMoney(cost)) return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY; if (RequireToken) { if (player->HasItemCount(TokenEntry, TokenAmount)) player->DestroyItemCount(TokenEntry, TokenAmount, true); else return LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS; } } // All okay, proceed // itemTransmogrified->SetEnchantment(TRANSMOGRIFY_ENCHANTMENT_SLOT, newEntry, 0, 0); // player->SetVisibleItemSlot(slot, itemTransmogrified); // Custom SetFakeEntry(player, itemTransmogrifier->GetEntry(), slot, itemTransmogrified); // newEntry itemTransmogrified->UpdatePlayedTime(player); itemTransmogrified->SetOwnerGUID(player->GetGUID()); itemTransmogrified->SetNotRefundable(player); itemTransmogrified->ClearSoulboundTradeable(player); if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE) itemTransmogrifier->SetBinding(true); itemTransmogrifier->SetOwnerGUID(player->GetGUID()); itemTransmogrifier->SetNotRefundable(player); itemTransmogrifier->ClearSoulboundTradeable(player); //cost += GetSpecialPrice(itemTransmogrified->GetTemplate()); //cost *= GetScaledCostModifier(); //cost += sT->GetCopperCost(); } // trusting the client, if it got here it has to have enough money // ... unless client was modified if (cost) // 0 cost if reverting look player->ModifyMoney(-1*cost, false); return LANG_ERR_TRANSMOG_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.rfinish(); // 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* player = _player; if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } if (player->GetSession()->GetSecurity() == 2 || player->GetSession()->GetSecurity() == 3 || player->GetSession()->GetSecurity() == 4 || player->GetSession()->GetSecurity() == 5 || player->GetSession()->GetSecurity() == 6 || player->GetSession()->GetSecurity() == 7 || player->GetSession()->GetSecurity() == 8) { SendNotification("Gamemasters are not allowed to send mails."); 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, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiver.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->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", player->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); if (player->GetGUID() == rc) { 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; if (!player->HasEnoughMoney(reqmoney)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receive = ObjectAccessor::FindPlayer(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); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt32(0, GUID_LOPART(rc)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); mails_count = fields[0].GetUInt64(); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); stmt->setUInt32(0, GUID_LOPART(rc)); result = CharacterDatabase.Query(stmt); if (result) { 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) { 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) { Item* item = player->GetItemByGuid(itemGUIDs[i]); if (item) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeam() != rc_team && AccountMgr::IsPlayerAccount(GetSecurity())) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiveLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(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]) { 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() != rc_account) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); 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_CAN_ONLY_DO_WITH_EMPTY_BAGS); return; } items[i] = item; } player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-int32(reqmoney)); player->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 (!AccountMgr::IsPlayerAccount(GetSecurity()) && 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->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } 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(rc); 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() != rc_account; } if (money > 0 && !AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(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->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(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
//does not clear ram void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans) { Item* pItem = GetAItem(auction->itemGUIDLow); if (!pItem) return; uint32 bidderAccId = 0; uint64 bidderGuid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); Player* bidder = ObjectAccessor::FindPlayer(bidderGuid); // data for gm.log std::string bidderName; bool logGmTrade = false; if (bidder) { bidderAccId = bidder->GetSession()->GetAccountId(); bidderName = bidder->GetName(); logGmTrade = bidder->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE); } else { bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid); logGmTrade = AccountMgr::HasPermission(bidderAccId, RBAC_PERM_LOG_GM_TRADE, realmID); if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName)) bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); } if (logGmTrade) { std::string ownerName; if (!sObjectMgr->GetPlayerNameByGUID(auction->owner, ownerName)) ownerName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); uint32 ownerAccId = sObjectMgr->GetPlayerAccountIdByGUID(auction->owner); sLog->outCommand(bidderAccId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", bidderName.c_str(), bidderAccId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId); } // receiver exist if (bidder || bidderAccId) { // set owner to bidder (to prevent delete item with sender char deleting) // owner in `data` will set at mail receive and item extracting PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); stmt->setUInt32(0, auction->bidder); stmt->setUInt32(1, pItem->GetGUIDLow()); trans->Append(stmt); if (bidder) { bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidderGuid, 0, 0, auction->itemEntry); // FIXME: for offline player need also bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1); } MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, 0, 0)) .AddItem(pItem) .SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); } }
bool Mailbox::AddMessageToListingPacket(WorldPacket& data,MailMessage *msg) { uint8 i = 0; uint32 j; size_t pos; vector<uint64>::iterator itr; Item* pItem; // add stuff if(msg->deleted_flag || msg->Expired() || (uint32)UNIXTIME < msg->delivery_time) return false; uint8 guidsize; if( msg->message_type ) guidsize = 4; else guidsize = 8; size_t msize = 2 + 4 + 1 + guidsize + 7 * 4 + ( msg->subject.size() + 1 ) + ( msg->body.size() + 1 ) + 1 + ( msg->items.size() * ( 1 + 2*4 + 7 * ( 3*4 ) + 6*4 + 1 ) ); data << uint16(msize); data << msg->message_id; data << uint8(msg->message_type); if(msg->message_type) data << uint32(msg->sender_guid); else data << msg->sender_guid; data << msg->cod; data << uint32(0); data << msg->stationary; data << msg->money; // money data << uint32(0x10); data << float((msg->expire_time - uint32(UNIXTIME)) / 86400.0f); data << uint32( 0 ); // mail template data << msg->subject; data << msg->body; // subjectbody pos = data.wpos(); data << uint8(0); // item count if( !msg->items.empty( ) ) { for( itr = msg->items.begin( ); itr != msg->items.end( ); itr++ ) { pItem = objmgr.LoadItem( *itr ); if( pItem == NULL ) continue; data << uint8(i++); data << pItem->GetLowGUID(); data << pItem->GetEntry(); for( j = 0; j < 7; ++j ) { data << pItem->GetUInt32Value( ITEM_FIELD_ENCHANTMENT_1_1 + ( j * 3 ) ); data << pItem->GetUInt32Value( (ITEM_FIELD_ENCHANTMENT_1_1 + 1) + ( j * 3 ) ); data << pItem->GetUInt32Value( ITEM_FIELD_ENCHANTMENT_1_3 + ( j * 3 ) ); } data << pItem->GetUInt32Value( ITEM_FIELD_RANDOM_PROPERTIES_ID ); if( ( (int32)pItem->GetUInt32Value( ITEM_FIELD_RANDOM_PROPERTIES_ID ) ) < 0 ) data << pItem->GetItemRandomSuffixFactor(); else data << uint32( 0 ); data << uint32( pItem->GetUInt32Value(ITEM_FIELD_STACK_COUNT) ); data << uint32( pItem->GetChargesLeft() ); data << pItem->GetUInt32Value( ITEM_FIELD_MAXDURABILITY ); data << pItem->GetUInt32Value( ITEM_FIELD_DURABILITY ); data << uint8(0); pItem->DeleteMe(); pItem = NULLITEM; } data.put< uint8 >( pos, i ); } return true; }
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; int8 real_item_slot; recv_data >> gameobject >> recepient; // Search for the recipient PlayerInfo* player = ObjectMgr::getSingleton().GetPlayerInfoByName(recepient.c_str()); if( player == NULL ) { SendMailError(MAIL_ERR_RECIPIENT_NOT_FOUND); return; } msg.player_guid = player->guid; msg.sender_guid = _player->GetGUID(); recv_data >> msg.subject >> msg.body >> msg.stationary; // Check attached items recv_data >> unk2 >> itemcount; for( i = 0; i < itemcount; i++ ) { recv_data >> itemslot; recv_data >> itemguid; pItem = _player->GetItemInterface()->GetItemByGUID( itemguid ); real_item_slot = _player->GetItemInterface()->GetInventorySlotByGuid( itemguid ); if( pItem == NULL || pItem->HasFlag( ITEM_FIELD_FLAGS, ITEM_FLAG_CONJURED ) ) { SendMailError(MAIL_ERR_BAG_FULL, INV_ERR_CANNOT_TRADE_THAT); return; } if( ( pItem->IsContainer() && (TO_CONTAINER( pItem ))->HasItems() ) || real_item_slot >= 0 && real_item_slot < INVENTORY_SLOT_ITEM_START ) { SendMailError(MAIL_ERR_BAG_FULL, INV_ERR_CANT_TRADE_EQUIP_BAGS); return; } if(pItem->IsAccountbound()) // don't mail account-bound items to another account { if(GetAccountId() != player->acct) { SendMailError(MAIL_ERR_BAG_FULL, INV_ERR_ACCOUNT_BOUND); return; } } else if(pItem->IsSoulbound()) { SendMailError(MAIL_ERR_BAG_FULL, INV_ERR_CANNOT_TRADE_THAT); return; } items.push_back( pItem ); } if( items.size() > 12 || msg.body.find("%") != string::npos || msg.subject.find("%") != string::npos) { SendMailError(MAIL_ERR_INTERNAL_ERROR); return; } recv_data >> msg.money; recv_data >> msg.cod; // left over: (TODO- FIX ME BURLEX!) // uint32 // uint32 // uint8 // Check if we're sending mail to ourselves if(msg.player_guid == msg.sender_guid && !GetPermissionCount()) { SendMailError(MAIL_ERR_CANNOT_SEND_TO_SELF); return; } // Check stationary if(msg.stationary != STATIONERY_GM && HasGMPermissions()) { msg.stationary = STATIONERY_GM; // GM mail always has GM Stationary. } if( msg.stationary == STATIONERY_GM && !HasGMPermissions()) { msg.stationary = STATIONERY_NORMAL; // Send stationary as normal instead. } // 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 we're sending to the same faction (disable this for testing) bool interfaction = (sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION ) || (HasGMPermissions() && sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM ) )); if(!interfaction) { if(player->team != _player->GetTeam()) { SendMailError( MAIL_ERR_NOT_YOUR_ALLIANCE ); return; } } msg.message_id = 0; msg.message_type = 0; msg.copy_made = false; msg.read_flag = false; msg.deleted_flag = false; msg.returned_flag = false; msg.delivery_time = (uint32)UNIXTIME; if(msg.money != 0 || msg.cod != 0 || !items.size() && player->acct != _player->GetSession()->GetAccountId()) { if(!sMailSystem.MailOption(MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS)) msg.delivery_time += 3600; // +1hr } msg.expire_time = 0; if(!sMailSystem.MailOption(MAIL_FLAG_NO_EXPIRY)) { msg.expire_time = (uint32)UNIXTIME + (TIME_DAY * 30); } if (items.empty() && msg.money != 0 && HasGMPermissions()) sWorld.LogGM(this, "sent mail with %u gold to %s (Acct: %u, Charid: %u).", msg.money, player->name, player->acct, player->guid); // Sending Message // take the money _player->ModUnsigned32Value(PLAYER_FIELD_COINAGE, -cost); // 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. sQuestMgr.OnPlayerDropItem(_player, pItem->GetEntry()); pItem->RemoveFromWorld(); pItem->SetOwner( NULLPLR ); pItem->SaveToDB( INVENTORY_SLOT_NOT_SET, 0, true, NULL ); msg.items.push_back( pItem->GetUInt32Value(OBJECT_FIELD_GUID) ); if( HasGMPermissions() ) sWorld.LogGM(this, "sent mail with item entry %u to %s, with gold %u.", pItem->GetEntry(), player->name, msg.money); pItem->DeleteMe(); pItem = NULLITEM; } } // Great, all our info is filled in. Now we can add it to the other players mailbox. sMailSystem.DeliverMessage(&msg); // Success packet :) SendMailError(MAIL_OK); }
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_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::HandleSellItemOpcode(WorldPackets::Item::SellItem& packet) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_SELL_ITEM: Vendor %s, Item %s, Amount: %u", packet.VendorGUID.ToString().c_str(), packet.ItemGUID.ToString().c_str(), packet.Amount); if (packet.ItemGUID.IsEmpty()) return; Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.VendorGUID, UNIT_NPC_FLAG_VENDOR); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - %s not found or you can not interact with him.", packet.VendorGUID.ToString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, packet.ItemGUID); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item* pItem = _player->GetItemByGuid(packet.ItemGUID); if (pItem) { // prevent sell not owner item if (_player->GetGUID() != pItem->GetOwnerGUID()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem->IsNotEmptyBag()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } // prevent sell currently looted item if (_player->GetLootGUID() == pItem->GetGUID()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } // prevent selling item for sellprice when the item is still refundable // this probably happens when right clicking a refundable item, the client sends both // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) return; // Therefore, no feedback to client // special case at auto sell (sell all) if (packet.Amount == 0) packet.Amount = pItem->GetCount(); else { // prevent sell more items that exist in stack (possible only not from client) if (packet.Amount > pItem->GetCount()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } } ItemTemplate const* pProto = pItem->GetTemplate(); if (pProto) { if (pProto->GetSellPrice() > 0) { if (packet.Amount < pItem->GetCount()) // need split items { Item* pNewItem = pItem->CloneItem(packet.Amount, _player); if (!pNewItem) { TC_LOG_ERROR("network", "WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), packet.Amount); _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } pItem->SetCount(pItem->GetCount() - packet.Amount); _player->ItemRemovedQuestCheck(pItem->GetEntry(), packet.Amount); if (_player->IsInWorld()) pItem->SendUpdateToPlayer(_player); pItem->SetState(ITEM_CHANGED, _player); _player->AddItemToBuyBackSlot(pNewItem); if (_player->IsInWorld()) pNewItem->SendUpdateToPlayer(_player); } else { _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); pItem->RemoveFromUpdateQueueOf(_player); _player->AddItemToBuyBackSlot(pItem); } uint32 money = pProto->GetSellPrice() * packet.Amount; _player->ModifyMoney(money); _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); } else _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGUID); return; } } _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, packet.ItemGUID); return; }
void WorldSession::HandleUseCritterItem(WorldPackets::Item::UseCritterItem& useCritterItem) { Item* item = _player->GetItemByGuid(useCritterItem.ItemGuid); if (!item) return; ItemToBattlePetSpeciesEntry const* itemToBattlePetSpecies = sItemToBattlePetSpeciesStore.LookupEntry(item->GetEntry()); if (!itemToBattlePetSpecies) return; BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(itemToBattlePetSpecies->BattlePetSpeciesID); if (!battlePetSpecies) return; GetBattlePetMgr()->AddPet(battlePetSpecies->ID, battlePetSpecies->CreatureID, BattlePetMgr::RollPetBreed(battlePetSpecies->ID), BattlePetMgr::GetDefaultPetQuality(battlePetSpecies->ID)); _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); }
//called when player takes item attached in mail void WorldSession::HandleMailTakeItem(WorldPacket & recv_data ) { uint64 mailbox; uint32 mailId; uint32 itemId; recv_data >> mailbox; recv_data >> mailId; recv_data >> itemId; // item guid low if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* pl = _player; Mail* m = pl->GetMail(mailId); if(!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if(pl->GetMoney() < m->COD) { pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Item *it = pl->GetMItem(itemId); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem( NULL_BAG, NULL_SLOT, dest, it, false ); if( msg == EQUIP_ERR_OK ) { m->RemoveItem(itemId); m->removedItems.push_back(itemId); if (m->COD > 0) // if there is COD, take COD money from player and send them to sender by mail { uint64 sender_guid = MAKE_NEW_GUID(m->sender, 0, HIGHGUID_PLAYER); Player *receive = sObjectMgr.GetPlayer(sender_guid); uint32 sender_accId = 0; if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) { std::string sender_name; if(receive) { sender_accId = receive->GetSession()->GetAccountId(); sender_name = receive->GetName(); } else { // can be calculated early sender_accId = sObjectMgr.GetPlayerAccountIdByGUID(sender_guid); if(!sObjectMgr.GetPlayerNameByGUID(sender_guid, sender_name)) sender_name = sObjectMgr.GetMangosStringForDBCLocale(LANG_UNKNOWN); } sLog.outCommand(GetAccountId(), "GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), it->GetProto()->Name1, it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); } else if(!receive) sender_accId = sObjectMgr.GetPlayerAccountIdByGUID(sender_guid); // check player existence if(receive || sender_accId) { MailDraft(m->subject) .AddMoney(m->COD) .SendMailTo(MailReceiver(receive,m->sender),MailSender(MAIL_NORMAL,m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); } pl->ModifyMoney( -int32(m->COD) ); } m->COD = 0; m->state = MAIL_STATE_CHANGED; pl->m_mailsUpdated = true; pl->RemoveMItem(it->GetGUIDLow()); uint32 count = it->GetCount(); // save counts before store and possible merge with deleting pl->MoveItemToInventory(dest, it, true); CharacterDatabase.BeginTransaction(); pl->SaveInventoryAndGoldToDB(); pl->_SaveMail(); CharacterDatabase.CommitTransaction(); pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); } else pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { uint8 bagIndex, slot; uint8 spell_count; // number of spells at item, not used uint8 cast_count; // next cast if exists (single or not) ObjectGuid itemGuid; recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> itemGuid; // TODO: add targets.read() check Player* pUser = _player; // ignore for remote control state if (!pUser->IsSelfMover()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail return; } Item* pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } if (pItem->GetObjectGuid() != itemGuid) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } DETAIL_LOG("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), (uint32)recvPacket.size()); ItemPrototype const* proto = pItem->GetProto(); if (!proto) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } // some item classes can be used only in equipped state if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } InventoryResult msg = pUser->CanUseItem(pItem); if (msg != EQUIP_ERR_OK) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(msg, pItem, NULL); return; } // not allow use item from trade (cheat way only) if (pItem->IsInTrade()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAG_USEABLE_IN_ARENA) && pUser->InArena()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); return; } if (pUser->isInCombat()) { for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { if (IsNonCombatSpell(spellInfo)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT, pItem, NULL); return; } } } } // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) if (pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding(true); } } SpellCastTargets targets; recvPacket >> targets.ReadForCaster(pUser); targets.Update(pUser); if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) { // free gray item after use fail pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); // search spell for spell error uint32 spellid = 0; for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE) { spellid = proto->Spells[i].SpellId; break; } } // send spell error if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) Spell::SendCastResult(_player, spellInfo, cast_count, SPELL_FAILED_BAD_TARGETS); return; } //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. if (!sScriptMgr.OnItemUse(pUser, pItem, targets)) { // no script or script not process request by self pUser->CastItemUseSpell(pItem, targets, cast_count); } }
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 = 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, 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 = 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); if (QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) { 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_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]) { 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() ? sObjectMgr.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 FlanisSwiftwing_Gossip::GossipSelectOption(Object* pObject, Player* plr, uint32 Id, uint32 IntId, const char* Code) { Creature* pCreature = (pObject->IsCreature()) ? TO_CREATURE(pObject) : NULL; if(pCreature == NULL) return; if(IntId == 1) { Item* item; item = objmgr.CreateItem(30658 , plr); item->SetStackCount(1); if(!plr->GetItemInterface()->AddItemToFreeSlot(item)) { plr->GetSession()->SendNotification("No free slots were found in your inventory!"); item->DeleteMe(); } else { plr->SendItemPushResult(false, true, false, true, plr->GetItemInterface()->LastSearchResult()->ContainerSlot, plr->GetItemInterface()->LastSearchResult()->Slot, 1, item->GetEntry(), item->GetItemRandomSuffixFactor(), item->GetItemRandomPropertyId(), item->GetStackCount()); } } };
void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL if (pReceiver) prepareItems(pReceiver); // generate mail template items uint32 mailId = sObjectMgr.GenerateMailID(); time_t deliver_time = time(NULL) + deliver_delay; uint32 expire_delay; // auction mail without any items and money (auction sale note) pending 1 hour if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money) expire_delay = HOUR; // mail from battlemaster (rewardmarks) should last only one day else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattleGroundMgr.GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE) expire_delay = DAY; // default case: expire time if COD 3 days, if no COD 30 days else expire_delay = (m_COD > 0) ? 3 * DAY : 30 * DAY; time_t expire_time = deliver_time + expire_delay; // Add to DB std::string safe_subject = GetSubject(); CharacterDatabase.BeginTransaction(); CharacterDatabase.escape_string(safe_subject); CharacterDatabase.PExecute("INSERT INTO mail (id,messageType,stationery,mailTemplateId,sender,receiver,subject,itemTextId,has_items,expire_time,deliver_time,money,cod,checked) " "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%u', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%d')", mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGUIDLow(), safe_subject.c_str(), GetBodyId(), (m_items.empty() ? 0 : 1), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked); for(MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')", mailId, item->GetGUIDLow(), item->GetEntry(), receiver.GetPlayerGUIDLow()); } CharacterDatabase.CommitTransaction(); // For online receiver update in game mail status and data if (pReceiver) { pReceiver->AddNewMailDeliverTime(deliver_time); Mail *m = new Mail; m->messageID = mailId; m->mailTemplateId = GetMailTemplateId(); m->subject = GetSubject(); m->itemTextId = GetBodyId(); m->money = GetMoney(); m->COD = GetCOD(); for(MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; m->AddItem(item->GetGUIDLow(), item->GetEntry()); } m->messageType = sender.GetMailMessageType(); m->stationery = sender.GetStationery(); m->sender = sender.GetSenderId(); m->receiver = receiver.GetPlayerGUIDLow(); m->expire_time = expire_time; m->deliver_time = deliver_time; m->checked = checked; m->state = MAIL_STATE_UNCHANGED; pReceiver->AddMail(m); // to insert new mail to beginning of maillist if (!m_items.empty()) { for(MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) pReceiver->AddMItem(mailItemIter->second); } } else if (!m_items.empty()) deleteIncludedItems(); }
//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("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); }
//called when player takes item attached in mail void WorldSession::HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& packet) { uint32 AttachID = packet.AttachID; if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; Mail* m = player->GetMail(packet.MailID); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr)) { player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // verify that the mail has the item to avoid cheaters taking COD items without paying if (std::find_if(m->items.begin(), m->items.end(), [AttachID](MailItemInfo info){ return info.item_guid == AttachID; }) == m->items.end()) { player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if (!player->HasEnoughMoney(uint64(m->COD))) { player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Item* it = player->GetMItem(packet.AttachID); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); if (msg == EQUIP_ERR_OK) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); m->RemoveItem(packet.AttachID); m->removedItems.push_back(packet.AttachID); if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail { ObjectGuid sender_guid = ObjectGuid::Create<HighGuid::Player>(m->sender); Player* receiver = ObjectAccessor::FindConnectedPlayer(sender_guid); uint32 sender_accId = 0; if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { std::string sender_name; if (receiver) { sender_accId = receiver->GetSession()->GetAccountId(); sender_name = receiver->GetName(); } else { // can be calculated early sender_accId = ObjectMgr::GetPlayerAccountIdByGUID(sender_guid); if (!ObjectMgr::GetPlayerNameByGUID(sender_guid, sender_name)) sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); } sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receiver mail item: %s (Entry: %u Count: %u) and send COD money: " UI64FMTD " to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), it->GetTemplate()->GetDefaultLocaleName(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); } else if (!receiver) sender_accId = ObjectMgr::GetPlayerAccountIdByGUID(sender_guid); // check player existence if (receiver || sender_accId) { MailDraft(m->subject, "") .AddMoney(m->COD) .SendMailTo(trans, MailReceiver(receiver, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); } player->ModifyMoney(-int32(m->COD)); } m->COD = 0; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; player->RemoveMItem(it->GetGUID().GetCounter()); uint32 count = it->GetCount(); // save counts before store and possible merge with deleting it->SetState(ITEM_UNCHANGED); // need to set this state, otherwise item cannot be removed later, if neccessary player->MoveItemToInventory(dest, it, true); player->SaveInventoryAndGoldToDB(trans); player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_OK, 0, packet.AttachID, count); } else player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); }
void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL Player* pSender = sObjectMgr->GetPlayerByLowGUID(sender.GetSenderId()); if (pReceiver) prepareItems(pReceiver, trans); // generate mail template items uint32 mailId = sObjectMgr->GenerateMailID(); if (receiver.GetPlayerGUIDLow() == auctionbot.GetAHBplayerGUID()) { if (sender.GetMailMessageType() == MAIL_AUCTION) // auction mail with items deleteIncludedItems(trans, true); return; } time_t deliver_time = time(NULL) + deliver_delay; //expire time if COD 3 days, if no COD 30 days, if auction sale pending 1 hour uint32 expire_delay; // auction mail without any items and money if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money) expire_delay = sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY); // mail from battlemaster (rewardmarks) should last only one day else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattlegroundMgr->GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE) expire_delay = DAY; // default case: expire time if COD 3 days, if no COD 30 days (or 90 days if sender is a game master) else { if (m_COD) expire_delay = 3 * DAY; else expire_delay = pSender && pSender->IsGameMaster() ? 90 * DAY : 30 * DAY; } time_t expire_time = deliver_time + expire_delay; // Add to DB uint8 index = 0; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL); stmt->setUInt32( index, mailId); stmt->setUInt8 (++index, uint8(sender.GetMailMessageType())); stmt->setInt8 (++index, int8(sender.GetStationery())); stmt->setUInt16(++index, GetMailTemplateId()); stmt->setUInt32(++index, sender.GetSenderId()); stmt->setUInt32(++index, receiver.GetPlayerGUIDLow()); stmt->setString(++index, GetSubject()); stmt->setString(++index, GetBody()); stmt->setBool (++index, !m_items.empty()); stmt->setUInt64(++index, uint64(expire_time)); stmt->setUInt64(++index, uint64(deliver_time)); stmt->setUInt32(++index, m_money); stmt->setUInt32(++index, m_COD); stmt->setUInt8 (++index, uint8(checked)); trans->Append(stmt); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* pItem = mailItemIter->second; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL_ITEM); stmt->setUInt32(0, mailId); stmt->setUInt32(1, pItem->GetGUIDLow()); stmt->setUInt32(2, receiver.GetPlayerGUIDLow()); trans->Append(stmt); } // For online receiver update in game mail status and data if (pReceiver) { pReceiver->AddNewMailDeliverTime(deliver_time); if (pReceiver->IsMailsLoaded()) { Mail* m = new Mail; m->messageID = mailId; m->mailTemplateId = GetMailTemplateId(); m->subject = GetSubject(); m->body = GetBody(); m->money = GetMoney(); m->COD = GetCOD(); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; m->AddItem(item->GetGUIDLow(), item->GetEntry()); } m->messageType = sender.GetMailMessageType(); m->stationery = sender.GetStationery(); m->sender = sender.GetSenderId(); m->receiver = receiver.GetPlayerGUIDLow(); m->expire_time = expire_time; m->deliver_time = deliver_time; m->checked = checked; m->state = MAIL_STATE_UNCHANGED; pReceiver->AddMail(m); // to insert new mail to beginning of maillist if (!m_items.empty()) { for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) pReceiver->AddMItem(mailItemIter->second); } } else if (!m_items.empty()) { SQLTransaction temp = SQLTransaction(NULL); deleteIncludedItems(temp); } } else if (!m_items.empty()) { SQLTransaction temp = SQLTransaction(NULL); deleteIncludedItems(temp); } }
/** * Sends a mail. * * @param receiver The MailReceiver to which this mail is sent. * @param sender The MailSender from which this mail is originated. * @param checked The mask used to specify the mail. * @param deliver_delay The delay after which the mail is delivered in seconds */ void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL uint32 pReceiverAccount = 0; if (!pReceiver) pReceiverAccount = sObjectMgr.GetPlayerAccountIdByGUID(receiver.GetPlayerGuid()); if (!pReceiver && !pReceiverAccount) // receiver not exist { deleteIncludedItems(true); return; } bool has_items = !m_items.empty(); // generate mail template items for online player, for offline player items will generated at open if (pReceiver) { if (prepareItems(pReceiver)) has_items = true; } uint32 mailId = sObjectMgr.GenerateMailID(); time_t deliver_time = time(NULL) + deliver_delay; uint32 expire_delay; // auction mail without any items and money (auction sale note) pending 1 hour if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money) expire_delay = HOUR; // default case: expire time if COD 3 days, if no COD 30 days else expire_delay = (m_COD > 0) ? 3 * DAY : 30 * DAY; time_t expire_time = deliver_time + expire_delay; // Add to DB std::string safe_subject = GetSubject(); CharacterDatabase.escape_string(safe_subject); std::string safe_body = GetBody(); CharacterDatabase.escape_string(safe_body); CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("INSERT INTO mail (id,messageType,stationery,mailTemplateId,sender,receiver,subject,body,has_items,expire_time,deliver_time,money,cod,checked) " "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%s', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%u')", mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGuid().GetCounter(), safe_subject.c_str(), safe_body.c_str(), (has_items ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')", mailId, item->GetGUIDLow(), item->GetEntry(), receiver.GetPlayerGuid().GetCounter()); } CharacterDatabase.CommitTransaction(); // For online receiver update in game mail status and data if (pReceiver) { pReceiver->AddNewMailDeliverTime(deliver_time); Mail* m = new Mail; m->messageID = mailId; m->mailTemplateId = GetMailTemplateId(); m->subject = GetSubject(); m->body = GetBody(); m->money = GetMoney(); m->COD = GetCOD(); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; m->AddItem(item->GetGUIDLow(), item->GetEntry()); } m->messageType = sender.GetMailMessageType(); m->stationery = sender.GetStationery(); m->sender = sender.GetSenderId(); m->receiverGuid = receiver.GetPlayerGuid(); m->expire_time = expire_time; m->deliver_time = deliver_time; m->checked = checked; m->state = MAIL_STATE_UNCHANGED; pReceiver->AddMail(m); // to insert new mail to beginning of maillist if (!m_items.empty()) { for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) pReceiver->AddMItem(mailItemIter->second); } } else if (!m_items.empty()) deleteIncludedItems(); }
void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket &recv_data) { uint64 guid; uint32 quest; uint32 unk1; recv_data >> guid >> quest >> unk1; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER); #define CLOSE_GOSSIP_CLEAR_DIVIDER() \ do { \ _player->PlayerTalkClass->SendCloseGossip(); \ _player->SetDivider(0); \ } while (0) // no or incorrect quest giver if(!pObject) { CLOSE_GOSSIP_CLEAR_DIVIDER(); return; } if(Player* playerQuestObject = pObject->ToPlayer()) { if((_player->GetDivider() && _player->GetDivider() != guid) || ((pObject != _player && !playerQuestObject->CanShareQuest(quest)))) { CLOSE_GOSSIP_CLEAR_DIVIDER(); return; } } else { if(!pObject->hasQuest(quest)) { CLOSE_GOSSIP_CLEAR_DIVIDER(); return; } } // some kind of WPE protection if(!_player->CanInteractWithQuestGiver(pObject)) return; Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest); if(qInfo) { // prevent cheating if(!GetPlayer()->CanTakeQuest(qInfo, true)) { CLOSE_GOSSIP_CLEAR_DIVIDER(); return; } if(_player->GetDivider() != 0) { Player* pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); if(pPlayer) { pPlayer->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST); _player->SetDivider(0); } } if(_player->CanAddQuest(qInfo, true)) { _player->AddQuest(qInfo, pObject); if(qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) { if(Group* pGroup = _player->GetGroup()) { for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* pPlayer = itr->getSource(); if(!pPlayer || pPlayer == _player) // not self continue; if(pPlayer->CanTakeQuest(qInfo, true)) { pPlayer->SetDivider(_player->GetGUID()); //need confirmation that any gossip window will close pPlayer->PlayerTalkClass->SendCloseGossip(); _player->SendQuestConfirmAccept(qInfo, pPlayer); } } } } if(_player->CanCompleteQuest(quest)) _player->CompleteQuest(quest); switch(pObject->GetTypeId()) { case TYPEID_UNIT: sScriptMgr->OnQuestAccept(_player, (pObject->ToCreature()), qInfo); pObject->ToCreature()->AI()->sQuestAccept(_player, qInfo); break; case TYPEID_ITEM: case TYPEID_CONTAINER: { Item* item = (Item*)pObject; sScriptMgr->OnQuestAccept(_player, item, qInfo); // destroy not required for quest finish quest starting item bool destroyItem = true; for(int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { if((qInfo->ReqItemId[i] == item->GetEntry()) && (item->GetTemplate()->MaxCount > 0)) { destroyItem = false; break; } } if(destroyItem) _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); break; } case TYPEID_GAMEOBJECT: sScriptMgr->OnQuestAccept(_player, ((GameObject*)pObject), qInfo); pObject->ToGameObject()->AI()->QuestAccept(_player, qInfo); break; default: break; } _player->PlayerTalkClass->SendCloseGossip(); if(qInfo->GetSrcSpell() > 0) _player->CastSpell(_player, qInfo->GetSrcSpell(), true); return; } #undef CLOSE_GOSSIP_CLEAR_DIVIDER } _player->PlayerTalkClass->SendCloseGossip(); }
// does not clear ram void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction) { Item* pItem = GetAItem(auction->item_guidlow); if (!pItem) return; uint32 bidder_accId = 0; uint32 bidder_security = 0; uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); Player* bidder = sObjectMgr.GetPlayer(bidder_guid); // data for gm.log if (sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { std::string bidder_name; if (bidder) { bidder_accId = bidder->GetSession()->GetAccountId(); bidder_security = bidder->GetSession()->GetSecurity(); bidder_name = bidder->GetName(); } else { bidder_accId = sObjectMgr.GetPlayerAccountIdByGUID(bidder_guid); bidder_security = sAccountMgr->GetSecurity(bidder_accId); if (bidder_security > SEC_PLAYER) // not do redundant DB requests { if (!sObjectMgr.GetPlayerNameByGUID(bidder_guid, bidder_name)) bidder_name = sObjectMgr.GetOregonStringForDBCLocale(LANG_UNKNOWN); } } if (bidder_security > SEC_PLAYER) { std::string owner_name; if (!sObjectMgr.GetPlayerNameByGUID(auction->owner, owner_name)) owner_name = sObjectMgr.GetOregonStringForDBCLocale(LANG_UNKNOWN); uint32 owner_accid = sObjectMgr.GetPlayerAccountIdByGUID(auction->owner); sLog.outCommand(bidder_accId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", bidder_name.c_str(), bidder_accId, pItem->GetProto()->Name1, pItem->GetEntry(), pItem->GetCount(), auction->bid, owner_name.c_str(), owner_accid); } } // receiver exist if (bidder || bidder_accId) { std::ostringstream msgAuctionWonSubject; msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON; std::ostringstream msgAuctionWonBody; msgAuctionWonBody.width(16); msgAuctionWonBody << std::right << std::hex << auction->owner; msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout; sLog.outDebug("AuctionWon body string : %s", msgAuctionWonBody.str().c_str()); // prepare mail data... : uint32 itemTextId = sObjectMgr.CreateItemText(msgAuctionWonBody.str()); // set owner to bidder (to prevent delete item with sender char deleting) // owner in data will set at mail receive and item extracting CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", auction->bidder, pItem->GetGUIDLow()); if (bidder) bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidder_guid, 0, 0, auction->item_template); MailDraft(msgAuctionWonSubject.str(), itemTextId) .AddItem(pItem) .SendMailTo(MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); } }
void WorldSession::HandleSellItemOpcode(WorldPacket & recv_data) { sLog->outDebug("WORLD: Received CMSG_SELL_ITEM"); uint64 vendorguid, itemguid; uint32 count; recv_data >> vendorguid >> itemguid >> count; if (!itemguid) return; Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); if (!pCreature) { sLog->outDebug("WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); Item *pItem = _player->GetItemByGuid(itemguid); if (pItem) { // prevent sell not owner item if (_player->GetGUID() != pItem->GetOwnerGUID()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // prevent sell currently looted item if (_player->GetLootGUID() == pItem->GetGUID()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } // prevent selling item for sellprice when the item is still refundable // this probably happens when right clicking a refundable item, the client sends both // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) return; // Therefore, no feedback to client // special case at auto sell (sell all) if (count == 0) { count = pItem->GetCount(); } else { // prevent sell more items that exist in stack (possible only not from client) if (count > pItem->GetCount()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } } ItemTemplate const *pProto = pItem->GetTemplate(); if (pProto) { if (pProto->SellPrice > 0) { if (count < pItem->GetCount()) // need split items { Item *pNewItem = pItem->CloneItem(count, _player); if (!pNewItem) { sLog->outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } pItem->SetCount(pItem->GetCount() - count); _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); if (_player->IsInWorld()) pItem->SendUpdateToPlayer(_player); pItem->SetState(ITEM_CHANGED, _player); _player->AddItemToBuyBackSlot(pNewItem); if (_player->IsInWorld()) pNewItem->SendUpdateToPlayer(_player); } else { _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); pItem->RemoveFromUpdateQueueOf(_player); _player->AddItemToBuyBackSlot(pItem); } uint32 money = pProto->SellPrice * count; _player->ModifyMoney(money); _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); } else _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemguid, 0); return; } } _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, pCreature, itemguid, 0); return; }
void WorldSession::HandleSellItemOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: Received opcode CMSG_SELL_ITEM"); ObjectGuid vendorGuid; ObjectGuid itemGuid; uint8 _count; recv_data >> vendorGuid; recv_data >> itemGuid; recv_data >> _count; // prevent possible overflow, as mangos uses uint32 for item count uint32 count = _count; if (!itemGuid) return; Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: HandleSellItemOpcode - %s not found or you can't interact with him.", vendorGuid.GetString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, itemGuid, 0); return; } Item* pItem = _player->GetItemByGuid(itemGuid); if (!pItem) return; // prevent sell not owner item if (_player->GetObjectGuid() != pItem->GetOwnerGuid()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } // prevent sell currently looted item if (_player->GetLootGuid() == pItem->GetObjectGuid()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } // special case at auto sell (sell all) if (count == 0) { count = pItem->GetCount(); } else { // prevent sell more items that exist in stack (possible only not from client) if (count > pItem->GetCount()) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } } ItemPrototype const* pProto = pItem->GetProto(); if (!pProto) { _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, pCreature, itemGuid, 0); return; } if (pProto->SellPrice == 0) { _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } uint32 money = pProto->SellPrice * count; for (auto i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { auto const &spell = pProto->Spells[i]; // if spell charges for this item are negative, it means that the item should be destroyed once the charges are consumed. // it also means that the value of this item is relative to how many charges are remaining. if (spell.SpellId != 0 && spell.SpellCharges < 0) { auto const multiplier = static_cast<float>(pItem->GetSpellCharges(i)) / spell.SpellCharges; money *= multiplier; break; } } if (count < pItem->GetCount()) // need split items { Item* pNewItem = pItem->CloneItem(count, _player); if (!pNewItem) { sLog.outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return; } pItem->SetCount(pItem->GetCount() - count); _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); if (_player->IsInWorld()) pItem->SendCreateUpdateToPlayer(_player); pItem->SetState(ITEM_CHANGED, _player); _player->AddItemToBuyBackSlot(pNewItem, money); if (_player->IsInWorld()) pNewItem->SendCreateUpdateToPlayer(_player); } else { _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); pItem->RemoveFromUpdateQueueOf(_player); _player->AddItemToBuyBackSlot(pItem, money); } _player->ModifyMoney(money); }
// 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) 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->DestroyItemCount(it, stackSize, true); pl->ModifyMoney(-int32(deposit)); AuctionEntry* AH = auctionHouse->AddAuction(auctionHouseEntry, newItem, etime, bid, buyout, deposit, pl); 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, etime, auctionHouseEntry->houseId); SendAuctionCommandResult(AH, AUCTION_STARTED, 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("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("WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); return; } sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); // client send time in minutes, convert to common used sec time etime *= MINUTE; sLog.outDebug("WORLD: HandleAuctionSellItem - ETIME: %u", etime); // 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->GetProto()->Flags & ITEM_PROTO_FLAG_CONJURED || it->GetUInt32Value(ITEM_FIELD_DURATION)) { SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); return; } if (it->IsBag() && !((Bag*)it)->IsEmpty()) { 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->GetProto()->Name1,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); }
bool CPlayer::SellItemToMultiVendor(ObjectGuid itemGuid, uint8 _count) { DEBUG_LOG("WORLD: SellItemToMultiVendor"); // prevent possible overflow, as mangos uses uint32 for item count uint32 count = _count; uint32 entry; ObjectGuid guid; GetMultiVendor(entry, guid); if (!itemGuid) return false; Creature* pCreature = GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!pCreature) { DEBUG_LOG("WORLD: SellItemToMultiVendor - %s not found or you can't interact with him.", guid.GetString().c_str()); SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemGuid, 0); return false; } // remove fake death if (hasUnitState(UNIT_STAT_DIED)) RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); Item* pItem = GetItemByGuid(itemGuid); if (pItem) { // prevent sell not owner item if (GetObjectGuid() != pItem->GetOwnerGuid()) { SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return false; } // prevent sell non empty bag by drag-and-drop at vendor's item list if (pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) { SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return false; } // prevent sell currently looted item if (GetLootGuid() == pItem->GetObjectGuid()) { SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return false; } // special case at auto sell (sell all) if (count == 0) { count = pItem->GetCount(); } else { // prevent sell more items that exist in stack (possible only not from client) if (count > pItem->GetCount()) { SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return false; } } ItemPrototype const* pProto = pItem->GetProto(); if (pProto) { if (pProto->SellPrice > 0) { if (count < pItem->GetCount()) // need split items { Item* pNewItem = pItem->CloneItem(count, ToPlayer()); if (!pNewItem) { sLog.outError("WORLD: SellItemToMultiVendor - could not create clone of item %u; count = %u", pItem->GetEntry(), count); SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return false; } pItem->SetCount(pItem->GetCount() - count); ItemRemovedQuestCheck(pItem->GetEntry(), count); if (IsInWorld()) pItem->SendCreateUpdateToPlayer(ToPlayer()); pItem->SetState(ITEM_CHANGED, ToPlayer()); AddItemToBuyBackSlot(pNewItem); if (IsInWorld()) pNewItem->SendCreateUpdateToPlayer(ToPlayer()); } else { ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); pItem->RemoveFromUpdateQueueOf(ToPlayer()); AddItemToBuyBackSlot(pItem); } uint32 money = pProto->SellPrice * count; ModifyMoney(money); } else SendSellError(SELL_ERR_CANT_SELL_ITEM, pCreature, itemGuid, 0); return true; } } SendSellError(SELL_ERR_CANT_FIND_ITEM, pCreature, itemGuid, 0); return false; }