Files
TCPlayerbotCore/src/game/Mail.cpp
T

1022 lines
37 KiB
C++
Raw Normal View History

2008-10-02 16:23:55 -05:00
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Mail.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "World.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "UpdateMask.h"
#include "Unit.h"
#include "Language.h"
#include "AuctionHouseBot.h"
#include "DBCStores.h"
2009-12-16 18:58:36 +02:00
#include "BattleGroundMgr.h"
#include "Item.h"
#include "AuctionHouseMgr.h"
2009-10-17 15:51:44 -07:00
2009-07-12 17:55:57 +08:00
enum MailShowFlags
{
MAIL_SHOW_UNK0 = 0x0001,
MAIL_SHOW_DELETE = 0x0002, // forced show delete button instead return button
MAIL_SHOW_AUCTION = 0x0004, // from old comment
MAIL_SHOW_UNK2 = 0x0008, // unknown, COD will be shown even without that flag
MAIL_SHOW_RETURN = 0x0010,
2009-07-12 17:55:57 +08:00
};
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession::HandleSendMail(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox, unk3;
std::string receiver, subject, body;
uint32 unk1, unk2, money, COD;
uint8 unk4;
recv_data >> mailbox;
recv_data >> receiver;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> subject;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> body;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> unk1; // stationery?
recv_data >> unk2; // 0x00000000
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint8 items_count;
recv_data >> items_count; // attached items count
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (items_count > MAX_MAIL_ITEMS) // client limit
{
GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS);
2009-12-16 18:58:36 +02:00
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
2008-10-02 16:23:55 -05:00
return;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
uint64 itemGUIDs[MAX_MAIL_ITEMS];
for (uint8 i = 0; i < items_count; ++i)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
recv_data.read_skip<uint8>(); // item slot in mail, not used
recv_data >> itemGUIDs[i];
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> money >> COD; // money and cod
recv_data >> unk3; // const 0
recv_data >> unk4; // const 0
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
// packet read complete, now do check
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if (receiver.empty())
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player* pl = _player;
2009-10-17 15:51:44 -07:00
2010-03-09 12:58:48 +01:00
if (pl->getLevel() < sWorld.getConfig(CONFIG_MAIL_LEVEL_REQ))
{
SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld.getConfig(CONFIG_MAIL_LEVEL_REQ));
return;
}
2008-10-02 16:23:55 -05:00
uint64 rc = 0;
2009-12-16 18:58:36 +02:00
if (normalizePlayerName(receiver))
2008-10-02 16:23:55 -05:00
rc = objmgr.GetPlayerGUIDByName(receiver);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
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);
2008-10-02 16:23:55 -05:00
return;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
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);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (pl->GetGUID() == rc)
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF);
2008-10-02 16:23:55 -05:00
return;
}
2009-10-17 15:51:44 -07:00
uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
2009-10-17 15:51:44 -07:00
uint32 reqmoney = cost + money;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if (pl->GetMoney() < reqmoney)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY);
2008-10-02 16:23:55 -05:00
return;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player *receive = objmgr.GetPlayer(rc);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 rc_team = 0;
uint8 mails_count = 0; //do not allow to send to one player more than 100 mails
2010-03-09 12:58:48 +01:00
uint8 receiveLevel = 0;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (receive)
2008-10-02 16:23:55 -05:00
{
rc_team = receive->GetTeam();
mails_count = receive->GetMailSize();
2010-03-09 12:58:48 +01:00
receiveLevel = receive->getLevel();
2008-10-02 16:23:55 -05:00
}
else
{
rc_team = objmgr.GetPlayerTeamByGUID(rc);
if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc)))
2008-10-02 16:23:55 -05:00
{
Field *fields = result->Fetch();
mails_count = fields[0].GetUInt32();
}
2010-03-09 12:58:48 +01:00
if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT level FROM characters WHERE guid = '%u'", GUID_LOPART(rc)))
{
Field *fields = result->Fetch();
receiveLevel = fields[0].GetUInt8();
}
2008-10-02 16:23:55 -05:00
}
//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);
2008-10-02 16:23:55 -05:00
return;
}
// test the receiver's Faction...
if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && pl->GetTeam() != rc_team && GetSecurity() == SEC_PLAYER)
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM);
2008-10-02 16:23:55 -05:00
return;
}
2009-10-17 15:51:44 -07:00
2010-03-09 12:58:48 +01:00
if (receiveLevel < sWorld.getConfig(CONFIG_MAIL_LEVEL_REQ))
{
SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld.getConfig(CONFIG_MAIL_LEVEL_REQ));
return;
}
2009-12-16 18:58:36 +02:00
uint32 rc_account = receive
? receive->GetSession()->GetAccountId()
: objmgr.GetPlayerAccountIdByGUID(rc);
Item* items[MAX_MAIL_ITEMS];
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
for (uint8 i = 0; i < items_count; ++i)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
if (!itemGUIDs[i])
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID);
return;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
Item* item = pl->GetItemByGuid(itemGUIDs[i]);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
// 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;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (!item->CanBeTraded(true))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
return;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
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;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
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;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD);
return;
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
items[i] = item;
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
pl->SendMailResult(0, MAIL_SEND, MAIL_OK);
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
pl->ModifyMoney(-int32(reqmoney));
pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
bool needItemDelay = false;
2009-10-17 15:51:44 -07:00
MailDraft draft(subject, body);
2009-12-16 18:58:36 +02:00
if (items_count > 0 || money > 0)
2008-10-02 16:23:55 -05:00
{
if (items_count > 0)
{
2009-12-16 18:58:36 +02:00
for (uint8 i = 0; i < items_count; ++i)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
Item* item = items[i];
if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2008-10-02 16:23:55 -05:00
{
2008-11-25 16:36:50 -06:00
sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)",
2009-12-16 18:58:36 +02:00
GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-03-19 13:36:54 +01:00
item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable
2009-12-16 18:58:36 +02:00
pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true);
2008-10-02 16:23:55 -05:00
CharacterDatabase.BeginTransaction();
2009-12-16 18:58:36 +02:00
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
2008-10-02 16:23:55 -05:00
// owner in data will set at mail receive and item extracting
2009-12-16 18:58:36 +02:00
CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", GUID_LOPART(rc), item->GetGUIDLow());
2008-10-02 16:23:55 -05:00
CharacterDatabase.CommitTransaction();
2009-12-16 18:58:36 +02:00
draft.AddItem(item);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// if item send to character at another account, then apply item delivery delay
needItemDelay = pl->GetSession()->GetAccountId() != rc_account;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2008-10-02 16:23:55 -05:00
{
2008-11-25 16:36:50 -06:00
sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)",
2008-10-02 16:23:55 -05:00
GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account);
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// 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;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// will delete item or place to receiver mail list
2009-12-16 18:58:36 +02:00
draft
.AddMoney(money)
.AddCOD(COD)
.SendMailTo(MailReceiver(receive, GUID_LOPART(rc)), MailSender(pl), body.empty() ? MailCheckMask(MAIL_CHECK_MASK_NONE | MAIL_CHECK_MASK_COPIED) : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
CharacterDatabase.BeginTransaction();
pl->SaveInventoryAndGoldToDB();
CharacterDatabase.CommitTransaction();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//called when mail is read
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailMarkAsRead(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
2009-12-16 18:58:36 +02:00
recv_data >> mailId;
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player *pl = _player;
Mail *m = pl->GetMail(mailId);
if (m)
{
if (pl->unReadMails)
--pl->unReadMails;
m->checked = m->checked | MAIL_CHECK_MASK_READ;
pl->m_mailsUpdated = true;
m->state = MAIL_STATE_CHANGED;
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//called when client deletes mail
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailDelete(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
recv_data >> mailId;
2009-12-16 18:58:36 +02:00
recv_data.read_skip<uint32>(); // mailTemplateId
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2009-08-14 19:00:12 -05:00
Mail *m = _player->GetMail(mailId);
Player* pl = _player;
pl->m_mailsUpdated = true;
2009-12-16 18:58:36 +02:00
if (m)
2009-08-14 19:00:12 -05:00
{
// delete shouldn't show up for COD mails
if (m->COD)
{
pl->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR);
2009-08-14 19:00:12 -05:00
return;
}
2009-10-17 15:51:44 -07:00
m->state = MAIL_STATE_DELETED;
}
pl->SendMailResult(mailId, MAIL_DELETED, MAIL_OK);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
2009-12-16 18:58:36 +02:00
recv_data >> mailId;
recv_data.read_skip<uint64>(); // original sender GUID for return to, not used
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player *pl = _player;
Mail *m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR);
return;
}
//we can return mail now
//so firstly delete the old one
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mailId);
// needed?
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mailId);
CharacterDatabase.CommitTransaction();
pl->RemoveMail(mailId);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
// send back only to players and simple drop for other cases
if (m->messageType == MAIL_NORMAL)
2008-10-02 16:23:55 -05:00
{
MailDraft draft(m->subject, m->body);
2009-12-16 18:58:36 +02:00
if (m->mailTemplateId)
draft = MailDraft(m->mailTemplateId, false); // items already included
if (m->HasItems())
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
for (std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
Item *item = pl->GetMItem(itr2->item_guid);
if (item)
draft.AddItem(item);
else
{
//WTF?
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
pl->RemoveMItem(itr2->item_guid);
}
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
if (m->sender == auctionbot.GetAHBplayerGUID())
draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, auctionbot.GetAHBplayerGUID());
else
draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, m->sender);
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
delete m; //we can deallocate old mail
pl->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//called when player takes item attached in mail
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailTakeItem(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
uint32 itemId;
recv_data >> mailbox;
2009-12-16 18:58:36 +02:00
recv_data >> mailId;
recv_data >> itemId; // item guid low
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player* pl = _player;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Mail* m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// prevent cheating with skip client money check
2009-12-16 18:58:36 +02:00
if (pl->GetMoney() < m->COD)
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY);
return;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Item *it = pl->GetMItem(itemId);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
ItemPosCountVec dest;
2010-04-07 22:59:46 +02:00
uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false);
2009-12-16 18:58:36 +02:00
if (msg == EQUIP_ERR_OK)
2008-10-02 16:23:55 -05:00
{
m->RemoveItem(itemId);
m->removedItems.push_back(itemId);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
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 = objmgr.GetPlayer(sender_guid);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 sender_accId = 0;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2008-10-02 16:23:55 -05:00
{
std::string sender_name;
2009-12-16 18:58:36 +02:00
if (receive)
2008-10-02 16:23:55 -05:00
{
sender_accId = receive->GetSession()->GetAccountId();
sender_name = receive->GetName();
}
else
{
// can be calculated early
sender_accId = objmgr.GetPlayerAccountIdByGUID(sender_guid);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (!objmgr.GetPlayerNameByGUID(sender_guid,sender_name))
2008-10-14 11:57:03 -05:00
sender_name = objmgr.GetTrinityStringForDBCLocale(LANG_UNKNOWN);
2008-10-02 16:23:55 -05:00
}
2008-11-25 16:36:50 -06:00
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)",
2008-10-02 16:23:55 -05:00
GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount(),m->COD,sender_name.c_str(),sender_accId);
}
2009-12-16 18:58:36 +02:00
else if (!receive)
2008-10-02 16:23:55 -05:00
sender_accId = objmgr.GetPlayerAccountIdByGUID(sender_guid);
2009-10-17 15:51:44 -07:00
2008-11-14 16:28:45 -06:00
// check player existence
2009-12-16 18:58:36 +02:00
if (receive || sender_accId)
2008-10-02 16:23:55 -05:00
{
MailDraft(m->subject, "")
2009-12-16 18:58:36 +02:00
.AddMoney(m->COD)
.SendMailTo(MailReceiver(receive, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
pl->ModifyMoney(-int32(m->COD));
2008-10-02 16:23:55 -05:00
}
m->COD = 0;
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
pl->RemoveMItem(it->GetGUIDLow());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 count = it->GetCount(); // save counts before store and possible merge with deleting
pl->MoveItemToInventory(dest,it,true);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
CharacterDatabase.BeginTransaction();
pl->SaveInventoryAndGoldToDB();
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count);
}
else
pl->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailTakeMoney(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
recv_data >> mailbox;
recv_data >> mailId;
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player *pl = _player;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Mail* m = pl->GetMail(mailId);
if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
2009-10-17 15:51:44 -07:00
pl->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
pl->ModifyMoney(m->money);
m->money = 0;
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// save money and mail to prevent cheating
CharacterDatabase.BeginTransaction();
2009-06-27 17:39:51 -05:00
pl->SaveGoldToDB();
2008-10-02 16:23:55 -05:00
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//called when player lists his received mails
2010-04-07 22:59:46 +02:00
void WorldSession::HandleGetMailList(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
recv_data >> mailbox;
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player* pl = _player;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//load players mails, and mailed items
2009-12-16 18:58:36 +02:00
if (!pl->m_mailsLoaded)
2008-10-02 16:23:55 -05:00
pl ->_LoadMail();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// client can't work with packets > max int16 value
const uint32 maxPacketSize = 32767;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
uint32 mailsCount = 0; // real send to client mails amount
2009-12-18 10:18:09 +01:00
uint32 realCount = 0; // real mails amount
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size
2009-12-18 10:18:09 +01:00
data << uint32(0); // real mail's count
2008-10-02 16:23:55 -05:00
data << uint8(0); // mail's count
time_t cur_time = time(NULL);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
for (PlayerMails::iterator itr = pl->GetMailBegin(); itr != pl->GetMailEnd(); ++itr)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
// packet send mail count as uint8, prevent overflow
if (mailsCount >= 254)
2009-12-18 10:18:09 +01:00
{
realCount += 1;
continue;
}
2009-12-16 18:58:36 +02:00
2008-10-02 16:23:55 -05:00
// skip deleted or not delivered (deliver delay not expired) mails
if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time)
continue;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12)
2009-10-17 15:51:44 -07:00
size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+4+4+7*3*4+4+4+4+4+4+4+1);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (data.wpos()+next_mail_size > maxPacketSize)
2009-12-18 10:18:09 +01:00
{
realCount += 1;
continue;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
data << uint16(next_mail_size); // Message size
data << uint32((*itr)->messageID); // Message ID
data << uint8((*itr)->messageType); // Message Type
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
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:
2009-12-16 18:58:36 +02:00
data << uint32((*itr)->sender); // creature/gameobject entry, auction id
2008-10-02 16:23:55 -05:00
break;
case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI
2009-12-18 10:18:09 +01:00
data << uint32(0); // item entry
2008-10-02 16:23:55 -05:00
break;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
data << uint32((*itr)->COD); // COD
data << uint32(0); // probably changed in 3.3.3
2009-12-16 18:58:36 +02:00
data << uint32((*itr)->stationery); // stationery (Stationery.dbc)
data << uint32((*itr)->money); // Gold
data << uint32((*itr)->checked); // flags
data << float(((*itr)->expire_time-time(NULL))/DAY); // Time
2009-12-16 18:58:36 +02:00
data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc)
2010-04-11 20:20:38 +02:00
data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256
data << (*itr)->body; // message? max 8000
2009-12-16 18:58:36 +02:00
data << uint8(item_count); // client limit is 0x10
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for (uint8 i = 0; i < item_count; ++i)
2008-10-02 16:23:55 -05:00
{
Item *item = pl->GetMItem((*itr)->items[i].item_guid);
// item index (0-6?)
2009-12-16 18:58:36 +02:00
data << uint8(i);
2008-10-02 16:23:55 -05:00
// item guid low?
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetGUIDLow() : 0));
2008-10-02 16:23:55 -05:00
// entry
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetEntry() : 0));
2009-10-17 16:20:24 -07:00
for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0));
2010-03-13 17:22:42 +01:00
data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0));
data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0));
2008-10-02 16:23:55 -05:00
}
// can be negative
data << int32((item ? item->GetItemRandomPropertyId() : 0));
2008-10-02 16:23:55 -05:00
// unk
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetItemSuffixFactor() : 0));
2008-10-02 16:23:55 -05:00
// stack count
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetCount() : 0));
2008-10-02 16:23:55 -05:00
// charges
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetSpellCharges() : 0));
2008-10-02 16:23:55 -05:00
// durability
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0));
2008-10-02 16:23:55 -05:00
// durability
2009-12-16 18:58:36 +02:00
data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0));
// unknown wotlk
2009-12-16 18:58:36 +02:00
data << uint8(0);
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-18 10:18:09 +01:00
realCount += 1;
2009-12-16 18:58:36 +02:00
mailsCount += 1;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-18 10:18:09 +01:00
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
2008-10-02 16:23:55 -05:00
SendPacket(&data);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// recalculate m_nextMailDelivereTime and unReadMails
_player->UpdateNextMailTimeAndUnreads();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///this function is called when client needs mail message body, or when player clicks on item which has ITEM_FIELD_ITEM_TEXT_ID > 0
2010-04-07 22:59:46 +02:00
void WorldSession::HandleItemTextQuery(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
2010-04-11 20:20:38 +02:00
uint64 itemGuid;
recv_data >> itemGuid;
2009-10-17 15:51:44 -07:00
sLog.outDebug("CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid));
2009-10-17 15:51:44 -07:00
2010-04-11 20:20:38 +02:00
WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size
if (Item *item = _player->GetItemByGuid(itemGuid))
{
data << uint8(0); // has text
data << uint64(itemGuid); // item guid
data << objmgr.GetItemText(item->GetGUIDLow()); // max 8000
}
2010-04-11 20:20:38 +02:00
else
{
2010-04-11 20:20:38 +02:00
data << uint8(1); // no text
}
2008-10-02 16:23:55 -05:00
SendPacket(&data);
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//used when player copies mail body to his inventory
2010-04-07 22:59:46 +02:00
void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data)
2008-10-02 16:23:55 -05:00
{
uint64 mailbox;
uint32 mailId;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
recv_data >> mailbox;
recv_data >> mailId;
2009-10-17 15:51:44 -07:00
if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX))
return;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Player *pl = _player;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Mail* m = pl->GetMail(mailId);
if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
2008-10-02 16:23:55 -05:00
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
2009-10-17 15:51:44 -07:00
2010-04-11 20:20:38 +02:00
Item *bodyItem = new Item; // This is not bag and then can be used new Item.
if (!bodyItem->Create(objmgr.GenerateLowGuid(HIGHGUID_ITEM), MAIL_BODY_ITEM_TEMPLATE, pl))
2010-04-11 20:20:38 +02:00
{
delete bodyItem;
2010-04-11 20:20:38 +02:00
return;
}
2009-12-16 18:58:36 +02:00
// in mail template case we need create new item text
if(m->mailTemplateId)
2009-12-16 18:58:36 +02:00
{
MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId);
if (!mailTemplateEntry)
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
objmgr.CreateItemText(bodyItem->GetGUIDLow(), mailTemplateEntry->content[GetSessionDbcLocale()]);
2009-12-16 18:58:36 +02:00
}
2010-04-11 20:20:38 +02:00
else
objmgr.CreateItemText(bodyItem->GetGUIDLow(), m->body);
2009-12-16 18:58:36 +02:00
2010-04-11 20:20:38 +02:00
bodyItem->SetUInt32Value(ITEM_FIELD_CREATOR, m->sender);
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER | ITEM_FLAGS_REFUNDABLE_2 | ITEM_FLAGS_UNK1);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
sLog.outDetail("HandleMailCreateTextItem mailid=%u",mailId);
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
ItemPosCountVec dest;
2009-12-16 18:58:36 +02:00
uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false);
if (msg == EQUIP_ERR_OK)
2008-10-02 16:23:55 -05:00
{
m->checked = m->checked | MAIL_CHECK_MASK_COPIED;
2008-10-02 16:23:55 -05:00
m->state = MAIL_STATE_CHANGED;
pl->m_mailsUpdated = true;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
pl->StoreItem(dest, bodyItem, true);
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK);
2008-10-02 16:23:55 -05:00
}
else
{
pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg);
2008-10-02 16:23:55 -05:00
delete bodyItem;
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//TODO Fix me! ... this void has probably bad condition, but good data are sent
2010-04-07 22:59:46 +02:00
void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/)
2008-10-02 16:23:55 -05:00
{
WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (!_player->m_mailsLoaded)
2008-10-02 16:23:55 -05:00
_player->_LoadMail();
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (_player->unReadMails > 0)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
data << uint32(0); // float
data << uint32(0); // count
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 count = 0;
time_t now = time(NULL);
2009-12-16 18:58:36 +02:00
for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr)
2008-10-02 16:23:55 -05:00
{
Mail *m = (*itr);
// must be not checked yet
2009-12-16 18:58:36 +02:00
if (m->checked & MAIL_CHECK_MASK_READ)
continue;
2009-10-17 15:51:44 -07:00
// and already delivered
2009-12-16 18:58:36 +02:00
if (now < m->deliver_time)
continue;
2009-10-17 15:51:44 -07:00
if (m->messageType)
data << uint64(m->sender); // player guid
else
data << uint32(m->sender); // creature entry
2009-10-17 15:51:44 -07:00
switch(m->messageType)
{
case MAIL_AUCTION:
2009-12-16 18:58:36 +02:00
data << uint32(2);
data << uint32(2);
data << uint32(m->stationery);
break;
default:
2009-12-16 18:58:36 +02:00
data << uint32(0);
data << uint32(0);
data << uint32(m->stationery);
break;
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
data << uint32(0xC6000000); // float unk, time or something
2009-10-17 15:51:44 -07:00
++count;
2009-12-16 18:58:36 +02:00
if (count == 2) // do not display more than 2 mails
break;
2008-10-02 16:23:55 -05:00
}
data.put<uint32>(4, count);
}
else
{
2009-12-16 18:58:36 +02:00
data << uint32(0xC7A8C000);
data << uint32(0x00000000);
2008-10-02 16:23:55 -05:00
}
SendPacket(&data);
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
MailSender::MailSender(Object* sender, MailStationery stationery) : m_stationery(stationery)
2009-12-16 18:58:36 +02:00
{
switch(sender->GetTypeId())
{
case TYPEID_UNIT:
m_messageType = MAIL_CREATURE;
m_senderId = sender->GetEntry();
break;
case TYPEID_GAMEOBJECT:
m_messageType = MAIL_GAMEOBJECT;
m_senderId = sender->GetEntry();
break;
case TYPEID_ITEM:
m_messageType = MAIL_ITEM;
m_senderId = sender->GetEntry();
break;
case TYPEID_PLAYER:
m_messageType = MAIL_NORMAL;
m_senderId = sender->GetGUIDLow();
break;
default:
m_messageType = MAIL_NORMAL;
m_senderId = 0; // will show mail from not existed player
sLog.outError("MailSender::MailSender - Mail have unexpected sender typeid (%u)", sender->GetTypeId());
break;
}
}
2010-04-07 22:59:46 +02:00
MailSender::MailSender(AuctionEntry* sender)
2009-12-16 18:58:36 +02:00
: m_messageType(MAIL_AUCTION), m_senderId(sender->GetHouseId()), m_stationery(MAIL_STATIONERY_AUCTION)
{
}
2010-04-07 22:59:46 +02:00
MailReceiver::MailReceiver(Player* receiver) : m_receiver(receiver), m_receiver_lowguid(receiver->GetGUIDLow())
2009-12-16 18:58:36 +02:00
{
}
2010-04-07 22:59:46 +02:00
MailReceiver::MailReceiver(Player* receiver,uint32 receiver_lowguid) : m_receiver(receiver), m_receiver_lowguid(receiver_lowguid)
2009-12-16 18:58:36 +02:00
{
ASSERT(!receiver || receiver->GetGUIDLow() == receiver_lowguid);
}
2010-04-07 22:59:46 +02:00
MailDraft& MailDraft::AddItem(Item* item)
2009-12-16 18:58:36 +02:00
{
m_items[item->GetGUIDLow()] = item; return *this;
}
void MailDraft::prepareItems(Player* receiver)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
if (!m_mailTemplateId || !m_mailTemplateItemsNeed)
return;
m_mailTemplateItemsNeed = false;
Loot mailLoot;
// can be empty
mailLoot.FillLoot(m_mailTemplateId, LootTemplates_Mail, receiver, true, true);
uint32 max_slot = mailLoot.GetMaxSlotInLootFor(receiver);
for (uint32 i = 0; m_items.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
2009-12-16 18:58:36 +02:00
if (LootItem* lootitem = mailLoot.LootItemInSlot(i,receiver))
{
2009-12-16 18:58:36 +02:00
if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,receiver))
{
item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
AddItem(item);
}
}
2009-12-16 18:58:36 +02:00
}
}
2010-04-07 22:59:46 +02:00
void MailDraft::deleteIncludedItems(bool inDB /*= false*/)
2009-12-16 18:58:36 +02:00
{
for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
if (inDB)
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", item->GetGUIDLow());
delete item;
}
m_items.clear();
}
2010-04-07 22:59:46 +02:00
void MailDraft::SendReturnToSender(uint32 sender_acc, uint32 sender_guid, uint32 receiver_guid)
2009-12-16 18:58:36 +02:00
{
Player *receiver = objmgr.GetPlayer(MAKE_NEW_GUID(receiver_guid, 0, HIGHGUID_PLAYER));
uint32 rc_account = 0;
if (!receiver)
rc_account = objmgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(receiver_guid, 0, HIGHGUID_PLAYER));
if (!receiver && !rc_account) // sender not exist
{
deleteIncludedItems(true);
return;
}
2009-12-16 18:58:36 +02:00
// prepare mail and send in other case
bool needItemDelay = false;
if (!m_items.empty())
{
// if item send to character at another account, then apply item delivery delay
needItemDelay = sender_acc != rc_account;
// set owner to new receiver (to prevent delete item with sender char deleting)
CharacterDatabase.BeginTransaction();
for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
item->SaveToDB(); // 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'", receiver_guid, item->GetGUIDLow());
}
CharacterDatabase.CommitTransaction();
}
// If theres is an item, there is a one hour delivery delay.
uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0;
// will delete item or place to receiver mail list
SendMailTo(MailReceiver(receiver,receiver_guid), MailSender(MAIL_NORMAL, sender_guid), MAIL_CHECK_MASK_RETURNED, deliver_delay);
}
void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay)
{
Player* pReceiver = receiver.GetPlayer(); // can be NULL
2009-12-16 18:58:36 +02:00
if (pReceiver)
prepareItems(pReceiver); // generate mail template items
2008-10-02 16:23:55 -05:00
uint32 mailId = objmgr.GenerateMailID();
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (receiver.GetPlayerGUIDLow() == auctionbot.GetAHBplayerGUID())
{
if (sender.GetMailMessageType() == MAIL_AUCTION) // auction mail with items
deleteIncludedItems(true);
return;
}
time_t deliver_time = time(NULL) + deliver_delay;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//expire time if COD 3 days, if no COD 30 days, if auction sale pending 1 hour
uint32 expire_delay;
2009-12-16 18:58:36 +02:00
// auction mail without any items and money
if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money)
2009-08-19 15:20:10 -04:00
expire_delay = sWorld.getConfig(CONFIG_MAIL_DELIVERY_DELAY);
2009-12-16 18:58:36 +02:00
// 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
2008-10-02 16:23:55 -05:00
else
2009-12-16 18:58:36 +02:00
expire_delay = (m_COD > 0) ? 3 * DAY : 30 * DAY;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
time_t expire_time = deliver_time + expire_delay;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
// Add to DB
std::string safe_subject = GetSubject();
CharacterDatabase.BeginTransaction();
CharacterDatabase.escape_string(safe_subject);
2010-04-11 20:20:38 +02:00
std::string safe_body = GetBody();
CharacterDatabase.BeginTransaction();
CharacterDatabase.escape_string(safe_body);
2010-04-11 20:20:38 +02:00
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', '%d')",
mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGUIDLow(), safe_subject.c_str(), safe_body.c_str(),(m_items.empty() ? 0 : 1), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked);
2009-12-16 18:58:36 +02:00
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
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());
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
CharacterDatabase.CommitTransaction();
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
// For online receiver update in game mail status and data
if (pReceiver)
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
pReceiver->AddNewMailDeliverTime(deliver_time);
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (pReceiver->IsMailsLoaded())
2008-10-02 16:23:55 -05:00
{
Mail * m = new Mail;
m->messageID = mailId;
2009-12-16 18:58:36 +02:00
m->mailTemplateId = GetMailTemplateId();
m->subject = GetSubject();
m->body = GetBody();
2009-12-16 18:58:36 +02:00
m->money = GetMoney();
m->COD = GetCOD();
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
m->AddItem(item->GetGUIDLow(), item->GetEntry());
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
m->messageType = sender.GetMailMessageType();
m->stationery = sender.GetStationery();
m->sender = sender.GetSenderId();
m->receiver = receiver.GetPlayerGUIDLow();
2008-10-02 16:23:55 -05:00
m->expire_time = expire_time;
m->deliver_time = deliver_time;
m->checked = checked;
m->state = MAIL_STATE_UNCHANGED;
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
pReceiver->AddMail(m); // to insert new mail to beginning of maillist
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
if (!m_items.empty())
2008-10-02 16:23:55 -05:00
{
2009-12-16 18:58:36 +02:00
for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
pReceiver->AddMItem(mailItemIter->second);
2008-10-02 16:23:55 -05:00
}
}
2009-12-16 18:58:36 +02:00
else if (!m_items.empty())
deleteIncludedItems();
2008-10-02 16:23:55 -05:00
}
2009-12-16 18:58:36 +02:00
else if (!m_items.empty())
deleteIncludedItems();
2008-10-02 16:23:55 -05:00
}