2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01: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
2008-11-20 16:16:57 -06:00
* 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
2008-11-20 16:16:57 -06:00
* 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"
2009-01-20 16:44:05 -06:00
#include "AuctionHouseBot.h"
2009-03-27 09:58:20 -06:00
#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
2009-09-01 17:09:39 -05:00
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
2008-10-02 16:23:55 -05:00
void WorldSession :: HandleSendMail ( WorldPacket & recv_data )
{
uint64 mailbox , unk3 ;
std :: string receiver , subject , body ;
uint32 unk1 , unk2 , money , COD ;
uint8 unk4 ;
recv_data >> mailbox ;
recv_data >> receiver ;
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
2009-05-27 16:38:50 -05:00
{
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-05-27 16:38:50 -05:00
}
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
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 );
2009-05-27 16:38:50 -05:00
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
{
2009-05-27 16:38:50 -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
2009-03-06 15:22:19 -06:00
uint32 cost = items_count ? 30 * items_count : 30 ; // price hardcoded in client
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06: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 )
{
2009-05-27 16:38:50 -05:00
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
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 ();
}
else
{
rc_team = objmgr . GetPlayerTeamByGUID ( rc );
2010-01-23 14:45:58 +01:00
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 ();
}
}
//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 )
{
2009-05-27 16:38:50 -05:00
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 )
{
2009-05-27 16:38:50 -05:00
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
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
2009-05-27 16:38:50 -05:00
pl -> SendMailResult ( 0 , MAIL_SEND , MAIL_OK );
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
uint32 itemTextId = ! body . empty () ? objmgr . CreateItemText ( body ) : 0 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
pl -> ModifyMoney ( - int32 ( reqmoney ) );
2009-03-05 09:22:43 -06:00
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
2009-12-16 18:58:36 +02:00
MailDraft draft ( subject , itemTextId );
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
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 )), pl , MAIL_CHECK_MASK_NONE , 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
2009-05-31 15:56:51 -05: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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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 ;
2009-12-24 10:20:15 +01:00
// m->expire_time = time(NULL) + (30 * DAY); // Expire time do not change at reading mail
2008-10-02 16:23:55 -05:00
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
void WorldSession :: HandleMailDelete ( WorldPacket & recv_data )
{
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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-08-14 19:00:12 -05:00
Mail * m = _player -> GetMail ( mailId );
2009-09-01 17:21:22 -05:00
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
{
2009-09-01 17:09:39 -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-09-01 17:09:39 -05:00
}
2009-10-17 15:51:44 -07:00
2009-09-01 17:09:39 -05:00
m -> state = MAIL_STATE_DELETED ;
}
2009-05-27 16:38:50 -05:00
pl -> SendMailResult ( mailId , MAIL_DELETED , MAIL_OK );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-05-31 15:56:51 -05: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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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 );
2009-12-24 10:20:15 +01:00
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
{
2009-12-16 18:58:36 +02:00
MailDraft draft ( m -> subject , m -> itemTextId );
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-01-20 16:44:05 -06:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
delete m ; //we can deallocate old mail
2009-05-27 16:38:50 -05:00
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
2009-05-31 15:56:51 -05: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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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 );
2009-12-24 10:20:15 +01:00
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 ;
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
{
2009-12-16 18:58:36 +02:00
MailDraft ( m -> subject )
. 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
2008-10-02 16:23:55 -05:00
pl -> ModifyMoney ( - int32 ( m -> COD ) );
}
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
2009-05-27 16:38:50 -05:00
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
2009-05-31 15:56:51 -05: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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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 );
2009-12-24 10:20:15 +01:00
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
2009-05-27 16:38:50 -05: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
2009-05-31 15:56:51 -05: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
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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
2009-12-24 10:20:15 +01:00
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
2010-02-14 19:13:14 -07:00
size_t next_mail_size = 2 + 4 + 1 + (( * itr ) -> messageType == MAIL_NORMAL ? 8 : 4 ) + 4 * 8 + (( * itr ) -> subject . size () + 1 ) + 1 + item_count * ( 1 + 4 + 4 + 7 * 3 * 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1 );
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-07-12 17:55:57 +08:00
uint32 show_flags = 0 ;
if (( * itr ) -> messageType != MAIL_NORMAL )
show_flags |= MAIL_SHOW_DELETE ;
if (( * itr ) -> messageType == MAIL_AUCTION )
show_flags |= MAIL_SHOW_AUCTION ;
2009-09-01 17:09:39 -05:00
if (( * itr ) -> HasItems () && ( * itr ) -> messageType == MAIL_NORMAL )
show_flags |= MAIL_SHOW_RETURN ;
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 (( * itr ) -> itemTextId ); // sure about this
data << uint32 ( 0 ); // unknown
data << uint32 (( * itr ) -> stationery ); // stationery (Stationery.dbc)
data << uint32 (( * itr ) -> money ); // Gold
data << uint32 ( show_flags ); // unknown, 0x4 - auction, 0x10 - normal
2009-12-24 10:20:15 +01:00
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)
data << ( * itr ) -> subject ; // Subject string - once 00, when mail type = 3
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
{
// unsure
2009-12-16 18:58:36 +02:00
data << uint32 (( item ? item -> GetEnchantmentCharges (( EnchantmentSlot ) j ) : 0 ));
2008-10-02 16:23:55 -05:00
// unsure
2009-12-16 18:58:36 +02:00
data << uint32 (( item ? item -> GetEnchantmentDuration (( EnchantmentSlot ) j ) : 0 ));
2008-10-02 16:23:55 -05:00
// unsure
2009-12-16 18:58:36 +02:00
data << uint32 (( item ? item -> GetEnchantmentId (( EnchantmentSlot ) j ) : 0 ));
2008-10-02 16:23:55 -05:00
}
// can be negative
2009-12-21 14:48:30 -07:00
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 ));
2008-12-24 09:58:26 -06:00
// 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
void WorldSession :: HandleItemTextQuery ( WorldPacket & recv_data )
{
uint32 itemTextId ;
uint32 mailId ; //this value can be item id in bag, but it is also mail id
uint32 unk ; //maybe something like state - 0x70000000
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
recv_data >> itemTextId >> mailId >> unk ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//some check needed, if player has item with guid mailId, or has mail with id mailId
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
sLog . outDebug ( "CMSG_ITEM_TEXT_QUERY itemguid: %u, mailId: %u, unk: %u" , itemTextId , mailId , unk );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
WorldPacket data ( SMSG_ITEM_TEXT_QUERY_RESPONSE , ( 4 + 10 )); // guess size
data << itemTextId ;
data << objmgr . GetItemText ( itemTextId );
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
void WorldSession :: HandleMailCreateTextItem ( WorldPacket & recv_data )
{
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 ;
recv_data . read_skip < uint32 > (); // mailTemplateId, non need, Mail store own 100% correct value anyway
2009-10-17 15:51:44 -07:00
2009-04-19 18:23:10 -05:00
if ( ! GetPlayer () -> GetGameObjectIfCanInteractWith ( mailbox , GAMEOBJECT_TYPE_MAILBOX ))
2009-04-13 17:21:59 -05:00
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 );
2009-12-24 10:20:15 +01:00
if ( ! m || ! m -> itemTextId && ! 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
2009-12-16 18:58:36 +02:00
uint32 itemTextId = m -> itemTextId ;
// in mail template case we need create new text id
if ( ! itemTextId )
{
MailTemplateEntry const * mailTemplateEntry = sMailTemplateStore . LookupEntry ( m -> mailTemplateId );
if ( ! mailTemplateEntry )
{
pl -> SendMailResult ( mailId , MAIL_MADE_PERMANENT , MAIL_ERR_INTERNAL_ERROR );
return ;
}
itemTextId = objmgr . CreateItemText ( mailTemplateEntry -> content [ GetSessionDbcLocale ()]);
}
2008-10-02 16:23:55 -05:00
Item * bodyItem = new Item ; // This is not bag and then can be used new Item.
2009-12-16 18:58:36 +02:00
if ( ! bodyItem -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_ITEM ), MAIL_BODY_ITEM_TEMPLATE , pl ))
2008-10-02 16:23:55 -05:00
{
delete bodyItem ;
return ;
}
2009-10-17 15:51:44 -07:00
2009-12-16 18:58:36 +02:00
bodyItem -> SetUInt32Value ( ITEM_FIELD_ITEM_TEXT_ID , itemTextId );
bodyItem -> SetUInt32Value ( ITEM_FIELD_CREATOR , m -> sender );
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 -> itemTextId = 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
pl -> StoreItem ( dest , bodyItem , true );
//bodyItem->SetState(ITEM_NEW, pl); is set automatically
2009-05-27 16:38:50 -05:00
pl -> SendMailResult ( mailId , MAIL_MADE_PERMANENT , MAIL_OK );
2008-10-02 16:23:55 -05:00
}
else
{
2009-05-27 16:38:50 -05:00
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
2009-05-31 15:56:51 -05: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 ;
2009-12-24 10:20:15 +01:00
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 );
2009-07-10 08:38:35 +08:00
// must be not checked yet
2009-12-16 18:58:36 +02:00
if ( m -> checked & MAIL_CHECK_MASK_READ )
2009-07-10 08:38:35 +08:00
continue ;
2009-10-17 15:51:44 -07:00
2009-07-10 08:38:35 +08:00
// and already delivered
2009-12-16 18:58:36 +02:00
if ( now < m -> deliver_time )
2009-07-10 08:38:35 +08:00
continue ;
2009-10-17 15:51:44 -07:00
2010-02-15 10:17:33 +01: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
2009-07-10 08:38:35 +08: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 );
2009-07-10 08:38:35 +08:00
break ;
default :
2009-12-16 18:58:36 +02:00
data << uint32 ( 0 );
data << uint32 ( 0 );
data << uint32 ( m -> stationery );
2009-07-10 08:38:35 +08:00
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
2009-07-10 08:38:35 +08:00
++ count ;
2009-12-16 18:58:36 +02:00
if ( count == 2 ) // do not display more than 2 mails
2009-07-10 08:38:35 +08:00
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
2009-12-16 18:58:36 +02:00
MailSender :: MailSender ( Object * sender , MailStationery stationery ) : m_stationery ( stationery )
{
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 ;
}
}
MailSender :: MailSender ( AuctionEntry * sender )
: m_messageType ( MAIL_AUCTION ), m_senderId ( sender -> GetHouseId ()), m_stationery ( MAIL_STATIONERY_AUCTION )
{
}
MailReceiver :: MailReceiver ( Player * receiver ) : m_receiver ( receiver ), m_receiver_lowguid ( receiver -> GetGUIDLow ())
{
}
MailReceiver :: MailReceiver ( Player * receiver , uint32 receiver_lowguid ) : m_receiver ( receiver ), m_receiver_lowguid ( receiver_lowguid )
{
ASSERT ( ! receiver || receiver -> GetGUIDLow () == receiver_lowguid );
}
MailDraft & MailDraft :: AddItem ( Item * item )
{
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-01-20 16:44:05 -06:00
{
2009-12-16 18:58:36 +02:00
if ( LootItem * lootitem = mailLoot . LootItemInSlot ( i , receiver ))
2009-01-20 16:44:05 -06:00
{
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-01-20 16:44:05 -06:00
}
2009-12-16 18:58:36 +02:00
}
}
void MailDraft :: deleteIncludedItems ( bool inDB /*= false*/ )
{
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 ();
}
void MailDraft :: SendReturnToSender ( uint32 sender_acc , uint32 sender_guid , uint32 receiver_guid )
{
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 );
2009-01-20 16:44:05 -06:00
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-18 13:41:30 -08:00
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 ;
}
2009-12-24 10:20:15 +01:00
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 );
CharacterDatabase . PExecute ( "INSERT INTO mail (id,messageType,stationery,mailTemplateId,sender,receiver,subject,itemTextId,has_items,expire_time,deliver_time,money,cod,checked) "
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%u', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%d')" ,
mailId , sender . GetMailMessageType (), sender . GetStationery (), GetMailTemplateId (), sender . GetSenderId (), receiver . GetPlayerGUIDLow (), safe_subject . c_str (), GetBodyId (), ( m_items . empty () ? 0 : 1 ), ( uint64 ) expire_time , ( uint64 ) deliver_time , m_money , m_COD , checked );
for ( MailItemMap :: const_iterator mailItemIter = m_items . begin (); mailItemIter != m_items . end (); ++ mailItemIter )
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 -> itemTextId = GetBodyId ();
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
}