//called when mail is read void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) { ObjectGuid mailbox; uint32 mailId; recvData >> mailId; recvData.ReadGuidMask(mailbox, 0, 2, 3); recvData.ReadBit(); recvData.ReadGuidMask(mailbox, 4, 6, 7, 1, 5); recvData.FlushBits(); recvData.ReadGuidBytes(mailbox, 1, 7, 2, 5, 6, 3, 4, 0); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; if (Mail* mail = _player->GetMail(mailId)) { if (_player->unReadMails) --_player->unReadMails; mail->checked |= MAIL_CHECK_MASK_READ; mail->state = MAIL_STATE_CHANGED; _player->m_mailsUpdated = true; } }
void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData) { uint32 proposalID; // Proposal ID bool accept; ObjectGuid guid1; ObjectGuid guid2; recvData >> proposalID; recvData.read_skip<uint32>(); recvData.read_skip<uint32>(); recvData.read_skip<uint32>(); recvData.ReadGuidMask(guid2, 4, 5, 0, 6, 2, 7, 1, 3); recvData.ReadGuidBytes(guid2, 7, 4, 3, 2, 6, 0, 1, 5); guid1[7] = recvData.ReadBit(); accept = recvData.ReadBit(); recvData.ReadGuidMask(guid1, 1, 3, 0, 5, 4, 6, 2); recvData.ReadGuidBytes(guid1, 7, 1, 5, 6, 3, 4, 0, 2); TC_LOG_DEBUG("lfg", "CMSG_LFG_PROPOSAL_RESULT %s proposal: %u accept: %u", GetPlayerInfo().c_str(), proposalID, accept ? 1 : 0); sLFGMgr->UpdateProposal(proposalID, GetPlayer()->GetGUID(), accept); }
void WorldSession::HandleRepairItemOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_REPAIR_ITEM"); ObjectGuid npcGuid, itemGuid; bool guildBank; // new in 2.3.2, bool that means from guild bank money recvData.ReadGuidMask(itemGuid, 2, 5); npcGuid[3] = recvData.ReadBit(); guildBank = recvData.ReadBit(); npcGuid[7] = recvData.ReadBit(); itemGuid[4] = recvData.ReadBit(); npcGuid[2] = recvData.ReadBit(); recvData.ReadGuidMask(itemGuid, 0, 3); recvData.ReadGuidMask(npcGuid, 6, 1, 4); itemGuid[6] = recvData.ReadBit(); recvData.ReadGuidMask(npcGuid, 5, 0); recvData.ReadGuidMask(itemGuid, 7, 1); recvData.ReadByteSeq(itemGuid[2]); recvData.ReadByteSeq(npcGuid[1]); recvData.ReadByteSeq(itemGuid[1]); recvData.ReadGuidBytes(npcGuid, 4, 7, 3, 2); recvData.ReadByteSeq(itemGuid[7]); recvData.ReadGuidBytes(npcGuid, 5, 0); recvData.ReadGuidBytes(itemGuid, 5, 3, 4, 6); recvData.ReadByteSeq(npcGuid[6]); recvData.ReadByteSeq(itemGuid[0]); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_REPAIR); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGuid))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // reputation discount float discountMod = _player->GetReputationPriceDiscount(unit); if (itemGuid) { TC_LOG_DEBUG("network", "ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGuid), GUID_LOPART(npcGuid)); Item* item = _player->GetItemByGuid(itemGuid); if (item) _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); } else { TC_LOG_DEBUG("network", "ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGuid)); _player->DurabilityRepairAll(true, discountMod, guildBank); } }
void WorldSession::HandlePetitionDeclineOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode MSG_PETITION_DECLINE"); // ok ObjectGuid petitionGuid; uint64 ownerGuid; recvData.ReadGuidMask(petitionGuid, 5, 6, 4, 3, 1, 7, 0, 2); recvData.ReadGuidBytes(petitionGuid, 6, 2, 1, 5, 0, 7, 4, 3); TC_LOG_DEBUG("network", "Petition %u declined by %u", GUID_LOPART(petitionGuid), _player->GetGUIDLow()); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_OWNER_BY_GUID); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) return; Field* fields = result->Fetch(); ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); Player* owner = ObjectAccessor::FindPlayer(ownerGuid); if (owner) // petition owner online owner->GetSession()->SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_OK); }
void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) { ObjectGuid mailbox; uint32 mailId; recvData >> mailId; recvData.ReadGuidMask(mailbox, 2, 0, 4, 6, 3, 1, 7, 5); recvData.ReadGuidBytes(mailbox, 5, 6, 2, 0, 3, 1, 4, 7); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; Mail* m = player->GetMail(mailId); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); return; } //we can return mail now, so firstly delete the old one SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); stmt->setUInt32(0, mailId); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); stmt->setUInt32(0, mailId); trans->Append(stmt); player->RemoveMail(mailId); // only return mail if the player exists (and delete if not existing) if (m->messageType == MAIL_NORMAL && m->sender) { MailDraft draft(m->subject, m->body); if (m->mailTemplateId) draft = MailDraft(m->mailTemplateId, false); // items already included if (m->HasItems()) { for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) { if (Item* const item = player->GetMItem(itr2->item_guid)) draft.AddItem(item); player->RemoveMItem(itr2->item_guid); } } draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, m->sender, trans); } CharacterDatabase.CommitTransaction(trans); delete m; //we can deallocate old mail player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); }
void WorldSession::HandleTrainerListOpcode(WorldPacket& recvData) { ObjectGuid guid; recvData.ReadGuidMask(guid, 0, 2, 7, 6, 1, 4, 5, 3); recvData.ReadGuidBytes(guid, 3, 6, 7, 5, 1, 0, 2, 4); SendTrainerList(guid); }
void WorldSession::HandleGuildFinderDeclineRecruit(WorldPacket& recvPacket) { SF_LOG_DEBUG("network", "WORLD: Received CMSG_LF_GUILD_DECLINE_RECRUIT"); ObjectGuid RecruitGUID; recvPacket.ReadGuidMask(RecruitGUID, 6, 7, 3, 1, 2, 0, 4, 5); recvPacket.ReadGuidBytes(RecruitGUID, 0, 7, 1, 6, 4, 3, 5, 2); if (!IS_PLAYER_GUID(RecruitGUID)) return; sGuildFinderMgr->RemoveMembershipRequest(GUID_LOPART(RecruitGUID), GetPlayer()->GetGuildId()); }
void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_GOSSIP_HELLO"); ObjectGuid guid; recvData.ReadGuidMask(guid, 2, 4, 0, 3, 6, 7, 5, 1); recvData.ReadGuidBytes(guid, 4, 7, 1, 0, 5, 3, 6, 2); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); return; } // set faction visible if needed if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); // remove fake death //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard()) unit->StopMoving(); // If spiritguide, no need for gossip menu, just put player into resurrect queue if (unit->IsSpiritGuide()) { Battleground* bg = _player->GetBattleground(); if (bg) { bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); return; } } if (!sScriptMgr->OnGossipHello(_player, unit)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); _player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true); _player->SendPreparedGossip(unit); } unit->AI()->sGossipHello(_player); }
void WorldSession::HandlePetitionQueryOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_QUERY"); // ok uint32 guildguid; ObjectGuid petitionGuid; recvData >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid) recvData.ReadGuidMask(petitionGuid, 2, 3, 1, 0, 4, 7, 6, 5); recvData.ReadGuidBytes(petitionGuid, 0, 4, 7, 5, 1, 6, 3, 2); TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionGuid), guildguid); SendPetitionQueryOpcode(petitionGuid); }
void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) { ObjectGuid mailbox; uint64 money; uint32 mailId; recvData >> mailId; recvData >> money; recvData.ReadGuidMask(mailbox, 7, 6, 3, 2, 4, 5, 0, 1); recvData.ReadGuidBytes(mailbox, 7, 1, 4, 0, 3, 2, 6, 5); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; Mail* m = player->GetMail(mailId); if ((!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) || (money > 0 && m->money != money)) { player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } if (!player->ModifyMoney(m->money, false)) { player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); return; } m->money = 0; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); // save money and mail to prevent cheating SQLTransaction trans = CharacterDatabase.BeginTransaction(); player->SaveGoldToDB(trans); player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandlePetitionShowListOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received CMSG_PETITION_SHOWLIST"); ObjectGuid guid; recvData.ReadGuidMask(guid, 1, 7, 2, 5, 4, 0, 3, 6); recvData.ReadGuidBytes(guid, 6, 3, 2, 4, 1, 7, 5, 0); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandlePetitionerShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); return; } SendPetitionShowList(guid); }
void WorldSession::HandleAttackSwingOpcode(WorldPacket& recvData) { ObjectGuid guid; recvData.ReadGuidMask(guid, 6, 5, 7, 0, 3, 1, 4, 2); recvData.ReadGuidBytes(guid, 6, 7, 1, 3, 2, 0, 4, 5); TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_ATTACK_SWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); Unit* pEnemy = ObjectAccessor::GetUnit(*_player, guid); if (!pEnemy) { // stop attack state at client SendAttackStop(NULL); return; } if (!_player->IsValidAttackTarget(pEnemy)) { // stop attack state at client SendAttackStop(pEnemy); return; } //! Client explicitly checks the following before sending CMSG_ATTACK_SWING packet, //! so we'll place the same check here. Note that it might be possible to reuse this snippet //! in other places as well. if (Vehicle* vehicle = _player->GetVehicle()) { VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(_player); ASSERT(seat); if (!(seat->m_flags & VEHICLE_SEAT_FLAG_CAN_ATTACK)) { SendAttackStop(pEnemy); return; } } _player->Attack(pEnemy, true); }
void WorldSession::HandleEnterPlayerVehicle(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_PLAYER_VEHICLE_ENTER"); ObjectGuid guid; recvData.ReadGuidMask(guid, 5, 7, 3, 0, 2, 4, 6, 1); recvData.ReadGuidBytes(guid, 5, 3, 1, 2, 7, 0, 6, 4); /*uint64 guid; recvData >> guid;*/ //TODO: this does not work, the guid obtained is wrong if (Player* player = ObjectAccessor::FindPlayer(guid)) { if (!player->GetVehicleKit()){ return; } if (!player->IsInRaidWith(_player)){ return; } if (!player->IsWithinDistInMap(_player, INTERACTION_DISTANCE)){ return; } _player->EnterVehicle(player); } }
void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); ObjectGuid guid; recvData.ReadGuidMask(guid, 2, 7, 6, 0, 5, 4, 1, 3); recvData.ReadGuidBytes(guid, 1, 5, 6, 3, 2, 0, 7, 4); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); SendSpiritResurrect(); }
void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recv MSG_LIST_STABLED_PETS"); ObjectGuid npcGUID; recvData.ReadGuidMask(npcGUID, 0, 5, 1, 3, 6, 7, 2, 4); recvData.ReadGuidBytes(npcGUID, 0, 5, 7, 1, 2, 3, 4, 6); if (!CheckStableMaster(npcGUID)) return; // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // remove mounts this fix bug where getting pet from stable while mounted deletes pet. if (GetPlayer()->IsMounted()) GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); SendStablePetCallback(NULL, npcGUID); }
void WorldSession::HandleBankerActivateOpcode(WorldPacket& recvData) { ObjectGuid guid; TC_LOG_DEBUG("network", "WORLD: Received CMSG_BANKER_ACTIVATE"); recvData.ReadGuidMask(guid, 4, 5, 0, 6, 1, 2, 7, 3); recvData.ReadGuidBytes(guid, 1, 7, 2, 5, 6, 3, 0, 4); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); SendShowBank(guid); }
void WorldSession::HandleLfgLeaveOpcode(WorldPacket& recvData) { ObjectGuid leaveGuid; Group* group = GetPlayer()->GetGroup(); uint64 guid = GetPlayer()->GetGUID(); uint64 gguid = group ? group->GetGUID() : guid; recvData.read_skip<uint32>(); // Always 8 recvData.read_skip<uint32>(); // Join date recvData.read_skip<uint32>(); // Always 3 recvData.read_skip<uint32>(); // Queue Id recvData.ReadGuidMask(leaveGuid, 0, 1, 6, 7, 3, 5, 2, 4); recvData.ReadGuidBytes(leaveGuid, 1, 5, 6, 7, 4, 2, 3, 0); TC_LOG_DEBUG("lfg", "CMSG_LFG_LEAVE %s in group: %u sent guid " UI64FMTD ".", GetPlayerInfo().c_str(), group ? 1 : 0, uint64(leaveGuid)); // Check cheating - only leader can leave the queue if (!group || group->GetLeaderGUID() == guid) sLFGMgr->LeaveLfg(gguid); }
void WorldSession::HandleBinderActivateOpcode(WorldPacket& recvData) { ObjectGuid npcGuid; recvData.ReadGuidMask(npcGuid, 0, 5, 4, 7, 6, 2, 1, 3); recvData.ReadGuidBytes(npcGuid, 0, 4, 2, 3, 7, 1, 5, 6); if (!GetPlayer()->IsInWorld() || !GetPlayer()->IsAlive()) return; Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_INNKEEPER); if (!unit) { TC_LOG_DEBUG("network", "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGuid))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); SendBindPoint(unit); }
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_SHOW_SIGNATURES"); uint8 playerCount = 0; ObjectGuid petitionGuid; recvData.ReadGuidMask(petitionGuid, 3, 7, 2, 4, 5, 6, 0, 1); recvData.ReadGuidBytes(petitionGuid, 2, 4, 5, 7, 1, 0, 3, 6); // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) uint32 petitionGuidLow = GUID_LOPART(petitionGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, petitionGuidLow); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_DEBUG("entities.player.items", "Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName().c_str()); return; } Field* fields = result->Fetch(); uint32 type = fields[0].GetUInt8(); // if guild petition and has guild => error, return; if (type == GUILD_CHARTER_TYPE && _player->GetGuildId()) return; stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, petitionGuidLow); result = CharacterDatabase.Query(stmt); // result == NULL also correct in case no sign yet if (result) playerCount = uint8(result->GetRowCount()); TC_LOG_DEBUG("network", "CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionGuidLow); ObjectGuid playerGuid = _player->GetGUID(); ObjectGuid* playerGuids = new ObjectGuid[playerCount]; for (uint8 i = 0; i < playerCount; ++i) { Field* fields2 = result->Fetch(); uint32 lowGuid = fields2[0].GetUInt32(); playerGuids[i] = MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); result->NextRow(); } WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (9 + 9 + 3 + 4 + playerCount * (9 + 4))); data.WriteBit(playerGuid[1]); data.WriteBit(petitionGuid[3]); data.WriteBit(playerGuid[3]); data.WriteGuidMask(petitionGuid, 4, 0); data.WriteGuidMask(playerGuid, 7, 5); data.WriteGuidMask(petitionGuid, 1, 5, 7); data.WriteGuidMask(playerGuid, 0, 6); data.WriteBit(petitionGuid[6]); data.WriteGuidMask(playerGuid, 2, 4); data.WriteBits(playerCount, 21); for (int i = 0; i < playerCount; i++) { data.WriteGuidMask(playerGuids[i], 2, 0, 4, 7, 5, 1, 6, 3); } data.WriteBit(petitionGuid[2]); data.FlushBits(); for (int i = 0; i < playerCount; i++) { data.WriteGuidBytes(playerGuids[i], 6, 0, 1, 3, 2, 5, 7, 4); data << uint32(1); // Choice ??? Blizzard also stores declined players ??? } data.WriteGuidBytes(petitionGuid, 6, 5, 4); data.WriteByteSeq(playerGuid[4]); data.WriteByteSeq(petitionGuid[1]); data << uint32(petitionGuidLow); // guildID data.WriteGuidBytes(petitionGuid, 2, 3, 7); data.WriteGuidBytes(playerGuid, 5, 6, 3, 7, 1, 0); data.WriteByteSeq(petitionGuid[0]); data.WriteByteSeq(playerGuid[2]); delete[] playerGuids; SendPacket(&data); }
void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_TURN_IN_PETITION"); // Get petition guid from packet WorldPacket data; ObjectGuid petitionGuid; recvData.ReadGuidMask(petitionGuid, 1, 2, 3, 0, 5, 7, 4, 6); recvData.ReadGuidBytes(petitionGuid, 2, 1, 4, 6, 0, 7, 5, 3); // Check if player really has the required petition charter Item* item = _player->GetItemByGuid(petitionGuid); if (!item) return; TC_LOG_DEBUG("network", "Petition %u turned in by %u", GUID_LOPART(petitionGuid), _player->GetGUIDLow()); // Get petition data from db uint32 ownerguidlo; uint32 type; std::string name; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); ownerguidlo = fields[0].GetUInt32(); name = fields[1].GetString(); type = fields[2].GetUInt8(); } else { TC_LOG_ERROR("network", "Player %s (guid: %u) tried to turn in petition (guid: %u) that is not present in the database", _player->GetName().c_str(), _player->GetGUIDLow(), GUID_LOPART(petitionGuid)); return; } // Only the petition owner can turn in the petition if (_player->GetGUIDLow() != ownerguidlo) return; // Petition type (guild/arena) specific checks // Check if player is already in a guild if (_player->GetGuildId()) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_ALREADY_IN_GUILD, 4); data.FlushBits(); _player->GetSession()->SendPacket(&data); return; } // Check if guild name is already taken if (sGuildMgr->GetGuildByName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, name); return; } // Get petition signatures from db uint8 signatures; stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); if (result) signatures = uint8(result->GetRowCount()); else signatures = 0; uint32 requiredSignatures; if (type == GUILD_CHARTER_TYPE) requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS); else requiredSignatures = type-1; // Notify player if signatures are missing if (signatures < requiredSignatures) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_NEED_MORE_SIGNATURES, 4); data.FlushBits(); SendPacket(&data); return; } // Proceed with guild/arena team creation // Delete charter item _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); // Create guild Guild* guild = new Guild; if (!guild->Create(_player, name)) { delete guild; return; } // Register guild and add guild master sGuildMgr->AddGuild(guild); Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_COMMAND_SUCCESS, name); // Add members from signatures for (uint8 i = 0; i < signatures; ++i) { Field* fields = result->Fetch(); guild->AddMember(MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER)); result->NextRow(); } SQLTransaction trans = CharacterDatabase.BeginTransaction(); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_GUID); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE_BY_GUID); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); // created TC_LOG_DEBUG("network", "TURN IN PETITION GUID %u", GUID_LOPART(petitionGuid)); data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_OK, 4); data.FlushBits(); SendPacket(&data); }
void WorldSession::HandleOfferPetitionOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_OFFER_PETITION"); // ok uint8 playerCount = 0; ObjectGuid petitionGuid, playerGuid; uint32 type; Player* player; recvData.read_skip<uint32>(); recvData.ReadGuidMask(playerGuid, 4, 1); petitionGuid[2] = recvData.ReadBit(); playerGuid[6] = recvData.ReadBit(); petitionGuid[1] = recvData.ReadBit(); playerGuid[2] = recvData.ReadBit(); petitionGuid[4] = recvData.ReadBit(); recvData.ReadGuidMask(playerGuid, 3, 7); recvData.ReadGuidMask(petitionGuid, 0, 6); recvData.ReadGuidMask(playerGuid, 5, 0); recvData.ReadGuidMask(petitionGuid, 3, 5, 7); recvData.ReadByteSeq(playerGuid[7]); recvData.ReadGuidBytes(petitionGuid, 1, 4, 2); recvData.ReadByteSeq(playerGuid[6]); recvData.ReadGuidBytes(petitionGuid, 3, 0, 5); recvData.ReadGuidBytes(playerGuid, 0, 2, 5, 3, 4); recvData.ReadByteSeq(petitionGuid[7]); recvData.ReadByteSeq(playerGuid[1]); recvData.ReadByteSeq(petitionGuid[6]); player = ObjectAccessor::FindPlayer(playerGuid); if (!player) return; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) return; Field* fields = result->Fetch(); type = fields[0].GetUInt8(); TC_LOG_DEBUG("network", "OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionGuid), GUID_LOPART(playerGuid)); if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); return; } if (player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (player->GetGuildIdInvited()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); // result == NULL also correct charter without signs if (result) playerCount = uint8(result->GetRowCount()); ObjectGuid* playerGuids = new ObjectGuid[playerCount]; for (uint8 i = 0; i < playerCount; ++i) { Field* fields2 = result->Fetch(); uint32 lowGuid = fields2[0].GetUInt32(); playerGuids[i] = MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); result->NextRow(); } WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (9 + 9 + 3 + 4 + playerCount * (9 + 4))); data.WriteBit(playerGuid[1]); data.WriteBit(petitionGuid[3]); data.WriteBit(playerGuid[3]); data.WriteGuidMask(petitionGuid, 4, 0); data.WriteGuidMask(playerGuid, 7, 5); data.WriteGuidMask(petitionGuid, 1, 5, 7); data.WriteGuidMask(playerGuid, 0, 6); data.WriteBit(petitionGuid[6]); data.WriteGuidMask(playerGuid, 2, 4); data.WriteBits(playerCount, 21); for (int i = 0; i < playerCount; i++) { data.WriteGuidMask(playerGuids[i], 2, 0, 4, 7, 5, 1, 6, 3); } data.WriteBit(petitionGuid[2]); data.FlushBits(); for (int i = 0; i < playerCount; i++) { data.WriteGuidBytes(playerGuids[i], 6, 0, 1, 3, 2, 5, 7, 4); data << uint32(1); // Choice ??? Blizzard also stores declined players ??? } data.WriteGuidBytes(petitionGuid, 6, 5, 4); data.WriteByteSeq(playerGuid[4]); data.WriteByteSeq(petitionGuid[1]); data << uint32(GUID_LOPART(petitionGuid)); // guildID data.WriteGuidBytes(petitionGuid, 2, 3, 7); data.WriteGuidBytes(playerGuid, 5, 6, 3, 7, 1, 0); data.WriteByteSeq(petitionGuid[0]); data.WriteByteSeq(playerGuid[2]); delete[] playerGuids; player->GetSession()->SendPacket(&data); }
void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_BUY"); ObjectGuid guid; recvData.ReadGuidMask(guid, 5, 2, 3); uint8 nameLength = recvData.ReadBits(7); recvData.ReadGuidMask(guid, 4, 1, 7, 0, 6); std::string name = recvData.ReadString(nameLength); recvData.ReadGuidBytes(guid, 1, 7, 4, 6, 0, 5, 2, 3); TC_LOG_DEBUG("network", "Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guid), name.c_str()); // prevent cheating Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guid)); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); uint32 charterid = 0; uint32 cost = 0; uint32 type = 0; // if tabard designer, then trying to buy a guild charter. // do not let if already in guild. if (_player->GetGuildId()) return; charterid = GUILD_CHARTER; cost = GUILD_CHARTER_COST; type = GUILD_CHARTER_TYPE; if (sGuildMgr->GetGuildByName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, name); return; } if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, name); return; } ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterid); if (!pProto) { _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); return; } if (!_player->HasEnoughMoney(uint64(cost))) { //player hasn't got enough money _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterid, 0); return; } ItemPosCountVec dest; InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); if (msg != EQUIP_ERR_OK) { _player->SendEquipError(msg, NULL, NULL, charterid); return; } _player->ModifyMoney(-(int32)cost); Item* charter = _player->StoreNewItem(dest, charterid, true); if (!charter) return; //I think this has changed charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow()); // ITEM_FIELD_ENCHANTMENT is guild/arenateam id // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item) charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); // a petition is invalid, if both the owner and the type matches // we checked above, if this player is in an arenateam, so this must be // datacorruption PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_BY_OWNER); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt8(1, type); PreparedQueryResult result = CharacterDatabase.Query(stmt); std::ostringstream ssInvalidPetitionGUIDs; if (result) { do { Field* fields = result->Fetch(); ssInvalidPetitionGUIDs << '\'' << fields[0].GetUInt32() << "', "; } while (result->NextRow()); } // delete petitions with the same guid as this one ssInvalidPetitionGUIDs << '\'' << charter->GetGUIDLow() << '\''; //Probably DB Charter Petitions has changed too TC_LOG_DEBUG("network", "Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.EscapeString(name); SQLTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); trans->PAppend("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt32(1, charter->GetGUIDLow()); stmt->setString(2, name); stmt->setUInt8(3, uint8(type)); //Type no needed anymore trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_SIGN"); // ok Field* fields; ObjectGuid petitionGuid; recvData.read_skip<uint8>(); recvData.ReadGuidMask(petitionGuid, 4, 2, 0, 1, 5, 3, 6, 7); recvData.ReadGuidBytes(petitionGuid, 6, 1, 7, 2, 5, 3, 0, 4); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURES); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_ERROR("network", "Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName().c_str()); return; } fields = result->Fetch(); uint64 ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); uint64 signs = fields[1].GetUInt64(); uint8 type = fields[2].GetUInt8(); uint32 playerGuid = _player->GetGUIDLow(); if (GUID_LOPART(ownerGuid) == playerGuid) return; // not let enemies sign guild charter if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerGuid)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); return; } if (_player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (_player->GetGuildIdInvited()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } if (++signs > type) // client signs maximum return; // Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account // not allow sign another player from already sign player account stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIG_BY_ACCOUNT); stmt->setUInt32(0, GetAccountId()); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); if (result) { // close at signer side SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_ALREADY_SIGNED); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(ownerGuid)); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); stmt->setUInt32(2, playerGuid); stmt->setUInt32(3, GetAccountId()); CharacterDatabase.Execute(stmt); TC_LOG_DEBUG("network", "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionGuid), _player->GetName().c_str(), playerGuid, GetAccountId()); // close at signer side SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_OK); // update signs count on charter, required testing... //Item* item = _player->GetItemByGuid(petitionguid)); //if (item) // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs); // update for owner if online if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) owner->GetSession()->SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_OK); }
void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_RENAME"); ObjectGuid petitionGuid; uint32 type; uint8 nameLen; std::string newName; nameLen = recvData.ReadBits(7); recvData.ReadGuidMask(petitionGuid, 7, 4, 6, 2, 0, 5, 3, 1); recvData.ReadGuidBytes(petitionGuid, 4, 1, 7); newName = recvData.ReadString(nameLen); recvData.ReadGuidBytes(petitionGuid, 0, 3, 2, 6, 5); Item* item = _player->GetItemByGuid(petitionGuid); if (!item) return; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); type = fields[0].GetUInt8(); } else { TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); return; } if (sGuildMgr->GetGuildByName(newName)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, newName); return; } if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, newName); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); stmt->setString(0, newName); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); CharacterDatabase.Execute(stmt); TC_LOG_DEBUG("network", "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionGuid), newName.c_str()); WorldPacket data(SMSG_PETITION_RENAME_RESULT, (9 + 1 + newName.size())); data.WriteBits(newName.length(), 7); data.WriteGuidMask(petitionGuid, 0, 3, 4, 2, 6, 5, 7, 1); data.WriteGuidBytes(petitionGuid, 4, 3, 6, 0, 5, 2, 1, 7); data.WriteString(newName); SendPacket(&data); }
//used when player copies mail body to his inventory void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) { ObjectGuid mailbox; uint32 mailId; recvData >> mailId; recvData.ReadGuidMask(mailbox, 4, 1, 6, 2, 5, 3, 0, 7); recvData.ReadGuidBytes(mailbox, 6, 5, 4, 3, 0, 7, 2, 1); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; Mail* m = player->GetMail(mailId); if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } Item* bodyItem = new Item; // This is not bag and then can be used new Item. if (!bodyItem->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), MAIL_BODY_ITEM_TEMPLATE, player)) { delete bodyItem; return; } // in mail template case we need create new item text if (m->mailTemplateId) { MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); if (!mailTemplateEntry) { player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } bodyItem->SetText(mailTemplateEntry->content); } else bodyItem->SetText(m->body); bodyItem->SetUInt32Value(ITEM_FIELD_CREATOR, m->sender); bodyItem->SetFlag(ITEM_FIELD_DYNAMIC_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); TC_LOG_INFO("network", "HandleMailCreateTextItem mailid=%u", mailId); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); if (msg == EQUIP_ERR_OK) { m->checked = m->checked | MAIL_CHECK_MASK_COPIED; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; player->StoreItem(dest, bodyItem, true); player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); } else { player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); delete bodyItem; } }
//called when player lists his received mails void WorldSession::HandleGetMailList(WorldPacket& recvData) { ObjectGuid mailbox; recvData.ReadGuidMask(mailbox, 6, 3, 7, 5, 4, 1, 2, 0); recvData.ReadGuidBytes(mailbox, 7, 1, 6, 5, 4, 2, 3, 0); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; //load players mails, and mailed items if (!player->m_mailsLoaded) player->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailCount = 0; uint32 realCount = 0; // true mail count (includes any skipped mail) time_t cur_time = time(NULL); ByteBuffer mailData; WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size data << uint32(0); // placeholder size_t mailCountPos = data.bitwpos(); data.WriteBits(0, 18); // placeholder for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) { Mail* mail = *itr; // Only first 50 mails are displayed if (mailCount >= 50) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if (mail->state == MAIL_STATE_DELETED || cur_time < mail->deliver_time) continue; // skip mail with more than MAX_MAIL_ITEMS items (should not occur) uint8 itemCount = mail->items.size(); if (itemCount > MAX_MAIL_ITEMS) { realCount += 1; continue; } // skip mail if the packet has become too large (should not occur) size_t nextMailSize = 6 + 1 + 8 + itemCount * (4 + 4 + 4 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * (4 + 4 + 4) + 4 + 4 + 4 + 4 + 1 + 4) + mail->body.size() + mail->subject.size() + 4 + 4 + 8 + 4 + 8 + 4 + 4 + 1 + 4; if (data.wpos() + nextMailSize > maxPacketSize) { realCount += 1; continue; } data.WriteBit(mail->messageType != MAIL_NORMAL ? 1 : 0); data.WriteBits(mail->subject.size(), 8); data.WriteBits(mail->body.size(), 13); data.WriteBit(0); data.WriteBit(0); size_t itemCountPos = data.bitwpos(); data.WriteBits(0, 17); // placeholder data.WriteBit(1); // has guid ObjectGuid guid = mail->messageType == MAIL_NORMAL ? MAKE_NEW_GUID(mail->sender, 0, HIGHGUID_PLAYER) : 0; data.WriteGuidMask(guid, 2, 6, 7, 0, 5, 3, 1, 4); uint8 trueItemCount = 0; for (uint8 i = 0; i < itemCount; i++) { Item* item = player->GetMItem(mail->items[i].item_guid); if (!item) continue; data.WriteBit(0); mailData << uint32(item->GetGUIDLow()); mailData << uint32(4); // unknown mailData << uint32(item->GetSpellCharges()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); mailData << uint32(0); // unknown for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; j++) { mailData << uint32(item->GetEnchantmentCharges((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentDuration((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentId((EnchantmentSlot)j)); } mailData << uint32(item->GetItemSuffixFactor()); mailData << int32(item->GetItemRandomPropertyId()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_MAX_DURABILITY)); mailData << uint32(item->GetCount()); mailData << uint8(i); mailData << uint32(item->GetEntry()); trueItemCount++; } data.PutBits(itemCountPos, trueItemCount, 17); mailData.WriteString(mail->body); mailData << uint32(mail->messageID); mailData.WriteGuidBytes(guid, 4, 0, 5, 3, 1, 7, 2, 6); mailData << uint32(mail->mailTemplateId); mailData << uint64(mail->COD); mailData.WriteString(mail->subject); mailData << uint32(mail->stationery); mailData << float(float(mail->expire_time - time(NULL)) / DAY); mailData << uint64(mail->money); mailData << uint32(mail->checked); if (mail->messageType != MAIL_NORMAL) mailData << uint32(mail->sender); mailData << uint8(mail->messageType); mailData << uint32(0); // unknown realCount++; mailCount++; } data.FlushBits(); data.append(mailData); data.put<uint32>(0, realCount); data.PutBits(mailCountPos, mailCount, 18); SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
void WorldSession::HandleVoidStorageTransfer(WorldPacket& recvData) { SF_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_STORAGE_TRANSFER"); Player* player = GetPlayer(); ObjectGuid npcGuid; recvData.ReadGuidMask(npcGuid, 7, 4); uint32 countDeposit = recvData.ReadBits(24); //40 if (countDeposit > 9) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit more than 9 items (%u).", player->GetGUIDLow(), player->GetName().c_str(), countDeposit); return; } std::vector<ObjectGuid> itemGuids(countDeposit); for (uint32 i = 0; i < countDeposit; ++i) { recvData.ReadGuidMask(itemGuids[i], 0, 3, 6, 5, 4, 2, 1, 7); } uint32 countWithdraw = recvData.ReadBits(24); if (countWithdraw > 9) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to withdraw more than 9 items (%u).", player->GetGUIDLow(), player->GetName().c_str(), countWithdraw); return; } std::vector<ObjectGuid> itemIds(countWithdraw); for (uint32 i = 0; i < countWithdraw; ++i) { recvData.ReadGuidMask(itemIds[i], 4, 0, 5, 7, 6, 1, 2, 3); } recvData.ReadGuidMask(npcGuid, 6, 0, 3, 1, 2, 5); for (uint32 i = 0; i < countDeposit; ++i) { recvData.ReadGuidBytes(itemGuids[i], 5, 6, 3, 4, 1, 7, 2, 0); } recvData.ReadGuidBytes(npcGuid, 5); for (uint32 i = 0; i < countWithdraw; ++i) { recvData.ReadGuidBytes(itemIds[i], 0, 4, 1, 2, 6, 3, 7, 5); } recvData.ReadGuidBytes(npcGuid, 1, 7, 4, 3, 2, 0, 6); Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); if (!unit) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); return; } if (!player->IsVoidStorageUnlocked()) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName().c_str()); return; } if (itemGuids.size() > player->GetNumOfVoidStorageFreeSlots()) { SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); return; } uint32 freeBagSlots = 0; if (itemIds.size() != 0) { // make this a Player function for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) if (Bag* bag = player->GetBagByPos(i)) freeBagSlots += bag->GetFreeSlots(); for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) if (!player->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) ++freeBagSlots; } if (itemIds.size() > freeBagSlots) { SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); return; } if (!player->HasEnoughMoney(uint64(itemGuids.size() * VOID_STORAGE_STORE_ITEM))) { SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NOT_ENOUGH_MONEY); return; } std::pair<VoidStorageItem, uint8> depositItems[VOID_STORAGE_MAX_DEPOSIT]; uint8 depositCount = 0; for (std::vector<ObjectGuid>::iterator itr = itemGuids.begin(); itr != itemGuids.end(); ++itr) { Item* item = player->GetItemByGuid(*itr); if (!item) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit an invalid item (item guid: " UI64FMTD ").", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); continue; } VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetUInt64Value(ITEM_FIELD_CREATOR), item->GetItemRandomPropertyId(), item->GetItemSuffixFactor()); uint8 slot = player->AddVoidStorageItem(itemVS); depositItems[depositCount++] = std::make_pair(itemVS, slot); player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); } int64 cost = depositCount * VOID_STORAGE_STORE_ITEM; player->ModifyMoney(-cost); VoidStorageItem withdrawItems[VOID_STORAGE_MAX_WITHDRAW]; uint8 withdrawCount = 0; for (std::vector<ObjectGuid>::iterator itr = itemIds.begin(); itr != itemIds.end(); ++itr) { uint8 slot; VoidStorageItem* itemVS = player->GetVoidStorageItem(*itr, slot); if (!itemVS) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) tried to withdraw an invalid item (id: " UI64FMTD ")", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); continue; } ItemPosCountVec dest; InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemVS->ItemEntry, 1); if (msg != EQUIP_ERR_OK) { SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) couldn't withdraw item id " UI64FMTD " because inventory was full.", player->GetGUIDLow(), player->GetName().c_str(), uint64(*itr)); return; } Item* item = player->StoreNewItem(dest, itemVS->ItemEntry, true, itemVS->ItemRandomPropertyId); item->SetUInt64Value(ITEM_FIELD_CREATOR, uint64(itemVS->CreatorGuid)); item->SetBinding(true); player->SendNewItem(item, 1, false, false, false); withdrawItems[withdrawCount++] = *itemVS; player->DeleteVoidStorageItem(slot); } WorldPacket data(SMSG_VOID_STORAGE_TRANSFER_CHANGES, ((5 + 5 + (7 + 7) * depositCount + 7 * withdrawCount) / 8) + 7 * withdrawCount + (7 + 7 + 4 * 4) * depositCount); data.WriteBits(withdrawCount, 4); for (uint8 i = 0; i < withdrawCount; ++i) { ObjectGuid itemId = withdrawItems[i].ItemId; data.WriteGuidMask(itemId, 1, 6, 7, 3, 2, 0, 4, 5); } data.WriteBits(depositCount, 4); for (uint8 i = 0; i < depositCount; ++i) { ObjectGuid itemId = depositItems[i].first.ItemId; ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; data.WriteGuidMask(itemId, 0); data.WriteGuidMask(creatorGuid, 6, 4); data.WriteGuidMask(itemId, 3); data.WriteGuidMask(creatorGuid, 3); data.WriteGuidMask(itemId, 5, 7); data.WriteGuidMask(creatorGuid, 0, 5, 7); data.WriteGuidMask(itemId, 6, 4); data.WriteGuidMask(creatorGuid, 1); data.WriteGuidMask(itemId, 1); data.WriteGuidMask(creatorGuid, 2); } data.FlushBits(); for (uint8 i = 0; i < depositCount; ++i) { ObjectGuid itemId = depositItems[i].first.ItemId; ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; data << uint32(depositItems[i].second); // slot data.WriteGuidBytes(creatorGuid, 5); data << uint32(depositItems[i].first.ItemEntry); data.WriteGuidBytes(creatorGuid, 6, 3); data << uint32(depositItems[i].first.ItemSuffixFactor); data.WriteGuidBytes(creatorGuid, 2); data.WriteGuidBytes(itemId, 5); data << uint32(depositItems[i].first.ItemRandomPropertyId); data.WriteGuidBytes(itemId, 3); data.WriteGuidBytes(creatorGuid, 7, 4, 1); data.WriteGuidBytes(itemId, 0, 4, 6); data << uint32(0); // unk data.WriteGuidBytes(itemId, 1, 2); data.WriteGuidBytes(creatorGuid, 0); data.WriteGuidBytes(itemId, 7); } for (uint8 i = 0; i < withdrawCount; ++i) { ObjectGuid itemId = withdrawItems[i].ItemId; data.WriteGuidBytes(itemId, 7, 3, 1, 5, 4, 0, 6, 2); } SendPacket(&data); SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NO_ERROR); }
void WorldSession::HandleSendMail(WorldPacket& recvData) { ObjectGuid mailbox; uint64 money, COD; std::string receiverName, subject, body; uint32 bodyLength, subjectLength, receiverLength; uint32 unk1, unk2; uint8 itemCount; recvData >> unk1 >> unk2; // both unknown recvData >> COD >> money; // money and cod recvData.ReadGuidMask(mailbox, 0, 6, 4, 1); bodyLength = recvData.ReadBits(11); mailbox[3] = recvData.ReadBit(); receiverLength = recvData.ReadBits(9); recvData.ReadGuidMask(mailbox, 7, 5); itemCount = recvData.ReadBits(5); // attached items count if (itemCount > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recvData.rfinish(); // set to end to avoid warnings spam return; } ObjectGuid itemGuids[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < itemCount; ++i) { recvData.ReadGuidMask(itemGuids[i], 1, 7, 2, 5, 0, 6, 3, 4); } subjectLength = recvData.ReadBits(9); mailbox[2] = recvData.ReadBit(); for (uint8 i = 0; i < itemCount; ++i) { recvData.read_skip<uint8>(); // item slot in mail, not used recvData.ReadGuidBytes(itemGuids[i], 3, 0, 2, 1, 6, 5, 7, 4); } recvData.ReadByteSeq(mailbox[1]); body = recvData.ReadString(bodyLength); recvData.ReadByteSeq(mailbox[0]); subject = recvData.ReadString(subjectLength); recvData.ReadGuidBytes(mailbox, 2, 6, 5, 7, 3, 4); receiverName = recvData.ReadString(receiverLength); // packet read complete, now do check if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; if (receiverName.empty()) return; Player* player = _player; if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } uint64 receiverGuid = 0; if (normalizePlayerName(receiverName)) receiverGuid = sObjectMgr->GetPlayerGUIDByName(receiverName); if (!receiverGuid) { TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: not existed!) with subject %s " "and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), subject.c_str(), body.c_str(), itemCount, money, COD, unk1, unk2); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: %u) with subject %s and body %s " "includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiverName.c_str(), GUID_LOPART(receiverGuid), subject.c_str(), body.c_str(), itemCount, money, COD, unk1, unk2); if (player->GetGUID() == receiverGuid) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = itemCount ? 30 * itemCount : 30; // price hardcoded in client uint64 reqmoney = cost + money; if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receiver = ObjectAccessor::FindPlayer(receiverGuid); uint32 receiverTeam = 0; uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; if (receiver) { receiverTeam = receiver->GetTeam(); mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); } else { receiverTeam = sObjectMgr->GetPlayerTeamByGUID(receiverGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt32(0, GUID_LOPART(receiverGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); mailsCount = fields[0].GetUInt64(); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); stmt->setUInt32(0, GUID_LOPART(receiverGuid)); result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); receiverLevel = fields[0].GetUInt8(); } receiverAccountId = sObjectMgr->GetPlayerAccountIdByGUID(receiverGuid); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mailsCount > 100) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... or all items are account bound bool accountBound = itemCount ? true : false; for (uint8 i = 0; i < itemCount; ++i) { if (Item* item = player->GetItemByGuid(itemGuids[i])) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < itemCount; ++i) { if (!itemGuids[i]) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } Item* item = player->GetItemByGuid(itemGuids[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); return; } if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_EXPIRATION)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (COD && item->HasFlag(ITEM_FIELD_DYNAMIC_FLAGS, ITEM_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsNotEmptyBag()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_DESTROY_NONEMPTY_BAG); return; } items[i] = item; } player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-int64(reqmoney)); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(subject, body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (itemCount > 0 || money > 0) { bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE); if (itemCount > 0) { for (uint8 i = 0; i < itemCount; ++i) { Item* item = items[i]; if (log) { sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail item: %s (Entry: %u Count: %u) " "to player: %s (GUID: %u) (Account: %u)", GetPlayerName().c_str(), GetGuidLow(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiverName.c_str(), GUID_LOPART(receiverGuid), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SetOwnerGUID(receiverGuid); item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } if (log && money > 0) { sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail money: " UI64FMTD " to player: %s (GUID: %u) (Account: %u)", GetPlayerName().c_str(), GetGuidLow(), GetAccountId(), money, receiverName.c_str(), GUID_LOPART(receiverGuid), receiverAccountId); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // Mail sent between guild members arrives instantly if they have the guild perk "Guild Mail" if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) if (guild->GetLevel() >= 17 && guild->IsMember(receiverGuid)) deliver_delay = 0; // will delete item or place to receiver mail list draft .AddMoney(money) .AddCOD(COD) .SendMailTo(trans, MailReceiver(receiver, GUID_LOPART(receiverGuid)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandleVoidStorageQuery(WorldPacket& recvData) { SF_LOG_DEBUG("network", "WORLD: Received CMSG_VOID_STORAGE_QUERY"); Player* player = GetPlayer(); ObjectGuid npcGuid; recvData.ReadGuidMask(npcGuid, 1, 5, 6, 0, 7, 2, 3, 4); recvData.ReadGuidBytes(npcGuid, 1, 6, 4, 3, 7, 0, 2, 5); Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); if (!unit) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageQuery - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); return; } if (!player->IsVoidStorageUnlocked()) { SF_LOG_DEBUG("network", "WORLD: HandleVoidStorageQuery - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName().c_str()); return; } uint8 count = 0; for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) if (player->GetVoidStorageItem(i)) ++count; WorldPacket data(SMSG_VOID_STORAGE_CONTENTS, 2 * count + (14 + 4 + 4 + 4 + 4) * count); data.WriteBits(count, 7); ByteBuffer itemData((14 + 4 + 4 + 4 + 4) * count); for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) { VoidStorageItem* item = player->GetVoidStorageItem(i); if (!item) continue; ObjectGuid itemId = item->ItemId; ObjectGuid creatorGuid = item->CreatorGuid; data.WriteBit(creatorGuid[1]); data.WriteBit(creatorGuid[3]); data.WriteBit(itemId[1]); data.WriteBit(creatorGuid[2]); data.WriteBit(itemId[2]); data.WriteBit(creatorGuid[5]); data.WriteBit(creatorGuid[0]); data.WriteBit(itemId[6]); data.WriteBit(itemId[5]); data.WriteBit(creatorGuid[4]); data.WriteBit(itemId[7]); data.WriteBit(itemId[3]); data.WriteBit(itemId[4]); data.WriteBit(itemId[0]); data.WriteBit(creatorGuid[6]); data.WriteBit(creatorGuid[7]); itemData.WriteByteSeq(creatorGuid[4]); itemData.WriteByteSeq(creatorGuid[7]); itemData.WriteByteSeq(itemId[6]); itemData.WriteByteSeq(creatorGuid[6]); itemData.WriteByteSeq(itemId[2]); itemData << uint32(item->ItemSuffixFactor); //= 32 itemData.WriteByteSeq(itemId[7]); itemData.WriteByteSeq(itemId[3]); itemData.WriteByteSeq(creatorGuid[0]); itemData << uint32(0); //= 20 itemData.WriteByteSeq(itemId[0]); itemData << uint32(item->ItemRandomPropertyId); //= 24 itemData.WriteByteSeq(creatorGuid[2]); itemData.WriteByteSeq(creatorGuid[5]); itemData.WriteByteSeq(creatorGuid[3]); itemData << uint32(item->ItemEntry); //= 28 itemData.WriteByteSeq(itemId[5]); itemData.WriteByteSeq(itemId[1]); itemData << uint32(i); //= 16 itemData.WriteByteSeq(itemId[4]); itemData.WriteByteSeq(creatorGuid[1]); } data.FlushBits(); data.append(itemData); SendPacket(&data); }
//called when player takes item attached in mail void WorldSession::HandleMailTakeItem(WorldPacket& recvData) { ObjectGuid mailbox; uint32 mailId; uint32 itemId; recvData >> mailId; recvData >> itemId; recvData.ReadGuidMask(mailbox, 6, 5, 2, 3, 0, 1, 4, 7); recvData.ReadGuidBytes(mailbox, 0, 1, 4, 2, 5, 6, 3, 7); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; Mail* m = player->GetMail(mailId); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if (!player->HasEnoughMoney(uint64(m->COD))) { player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Item* it = player->GetMItem(itemId); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); if (msg == EQUIP_ERR_OK) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); 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* receiver = ObjectAccessor::FindPlayer(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 = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); if (!sObjectMgr->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()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); } else if (!receiver) sender_accId = sObjectMgr->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->GetGUIDLow()); 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(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); } else player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); }