server/src/game/Mail.cpp
Schmoozerd 8068dcf6dd [11875] Update Copyright notice to year 2012
Start timemachine and a Happy new year to all!
2012-01-16 17:43:59 +01:00

380 lines
13 KiB
C++

/*
* Copyright (C) 2005-2012 MaNGOS <http://getmangos.com/>
*
* 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
* 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
*/
/**
* @addtogroup mailing
* @{
*
* @file Mail.cpp
* This file contains the code needed for MaNGOS to handle mails.
*
*/
#include "Mail.h"
#include "Log.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "Item.h"
#include "Player.h"
#include "World.h"
/**
* Creates a new MailSender object.
*
* @param sender The object/player sending this mail.
* @param stationery The stationary associated with this sender.
*/
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:
case TYPEID_CONTAINER:
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 nonexistent player
sLog.outError( "MailSender::MailSender - Mail have unexpected sender typeid (%u)", sender->GetTypeId());
break;
}
}
/**
* Creates a new MailSender object from an AuctionEntry.
*
* @param sender the AuctionEntry from which this mail is generated.
*/
MailSender::MailSender( AuctionEntry* sender )
: m_messageType(MAIL_AUCTION), m_senderId(sender->GetHouseId()), m_stationery(MAIL_STATIONERY_AUCTION)
{
}
/**
* Creates a new MailReceiver object.
*
* @param receiver The player receiving the mail.
*/
MailReceiver::MailReceiver(Player* receiver) : m_receiver(receiver), m_receiver_guid(receiver->GetObjectGuid())
{
}
/**
* Creates a new MailReceiver object with a specified GUID.
*
* @param receiver The player receiving the mail.
* @param receiver_lowguid The GUID to use instead of the receivers.
*/
MailReceiver::MailReceiver(Player* receiver, ObjectGuid receiver_guid) : m_receiver(receiver), m_receiver_guid(receiver_guid)
{
MANGOS_ASSERT(!receiver || receiver->GetObjectGuid() == receiver_guid);
}
/**
* Adds an item to the MailDraft.
*
* @param item The item to be added to the MailDraft.
* @returns the MailDraft the item was added to.
*/
MailDraft& MailDraft::AddItem( Item* item )
{
m_items[item->GetGUIDLow()] = item;
return *this;
}
/**
* Prepares the items in a MailDraft.
*/
bool MailDraft::prepareItems(Player* receiver)
{
if (!m_mailTemplateId || !m_mailTemplateItemsNeed)
return false;
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)
{
if (LootItem* lootitem = mailLoot.LootItemInSlot(i, receiver))
{
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);
}
}
}
return true;
}
/**
* Deletes the items included in a MailDraft.
*
* @param inDB A boolean specifying whether the change should be saved to the database or not.
*/
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();
}
/**
* Clone MailDraft from another MailDraft.
*
* @param draft Point to source for draft cloning.
*/
void MailDraft::CloneFrom(MailDraft const& draft)
{
m_mailTemplateId = draft.GetMailTemplateId();
m_mailTemplateItemsNeed = draft.m_mailTemplateItemsNeed;
m_subject = draft.GetSubject();
m_body = draft.GetBody();
m_money = draft.GetMoney();
m_COD = draft.GetCOD();
for(MailItemMap::const_iterator mailItemIter = draft.m_items.begin(); mailItemIter != draft.m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
if(Item* newitem = item->CloneItem(item->GetCount()))
{
newitem->SaveToDB();
AddItem(newitem);
}
}
}
/*
* Returns a mail to its sender.
* @param sender_acc The id of the account of the sender.
* @param sender_guid The low part of the GUID of the sender.
* @param receiver_guid The low part of the GUID of the receiver.
*/
void MailDraft::SendReturnToSender(uint32 sender_acc, ObjectGuid sender_guid, ObjectGuid receiver_guid)
{
Player *receiver = sObjectMgr.GetPlayer(receiver_guid);
uint32 rc_account = 0;
if (!receiver)
rc_account = sObjectMgr.GetPlayerAccountIdByGUID(receiver_guid);
if (!receiver && !rc_account) // sender not exist
{
deleteIncludedItems(true);
return;
}
// 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.GetCounter(), item->GetGUIDLow());
}
CharacterDatabase.CommitTransaction();
}
// If theres is an item, there is a one hour delivery delay.
uint32 deliver_delay = needItemDelay ? sWorld.getConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY) : 0;
// will delete item or place to receiver mail list
SendMailTo(MailReceiver(receiver,receiver_guid), MailSender(MAIL_NORMAL, sender_guid.GetCounter()), MAIL_CHECK_MASK_RETURNED, deliver_delay);
}
/**
* Sends a mail.
*
* @param receiver The MailReceiver to which this mail is sent.
* @param sender The MailSender from which this mail is originated.
* @param checked The mask used to specify the mail.
* @param deliver_delay The delay after which the mail is delivered in seconds
*/
void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay)
{
Player* pReceiver = receiver.GetPlayer(); // can be NULL
uint32 pReceiverAccount = 0;
if (!pReceiver)
pReceiverAccount = sObjectMgr.GetPlayerAccountIdByGUID(receiver.GetPlayerGuid());
if (!pReceiver && !pReceiverAccount) // receiver not exist
{
deleteIncludedItems(true);
return;
}
bool has_items = !m_items.empty();
// generate mail template items for online player, for offline player items will generated at open
if (pReceiver)
{
if (prepareItems(pReceiver))
has_items = true;
}
uint32 mailId = sObjectMgr.GenerateMailID();
time_t deliver_time = time(NULL) + deliver_delay;
uint32 expire_delay;
// auction mail without any items and money (auction sale note) pending 1 hour
if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money)
expire_delay = HOUR;
// default case: expire time if COD 3 days, if no COD 30 days
else
expire_delay = (m_COD > 0) ? 3 * DAY : 30 * DAY;
time_t expire_time = deliver_time + expire_delay;
// Add to DB
std::string safe_subject = GetSubject();
CharacterDatabase.escape_string(safe_subject);
std::string safe_body = GetBody();
CharacterDatabase.escape_string(safe_body);
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("INSERT INTO mail (id,messageType,stationery,mailTemplateId,sender,receiver,subject,body,has_items,expire_time,deliver_time,money,cod,checked) "
"VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%s', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%u')",
mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGuid().GetCounter(), safe_subject.c_str(), safe_body.c_str(), (has_items ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked);
for(MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')",
mailId, item->GetGUIDLow(), item->GetEntry(), receiver.GetPlayerGuid().GetCounter());
}
CharacterDatabase.CommitTransaction();
// For online receiver update in game mail status and data
if (pReceiver)
{
pReceiver->AddNewMailDeliverTime(deliver_time);
Mail *m = new Mail;
m->messageID = mailId;
m->mailTemplateId = GetMailTemplateId();
m->subject = GetSubject();
m->body = GetBody();
m->money = GetMoney();
m->COD = GetCOD();
for(MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
{
Item* item = mailItemIter->second;
m->AddItem(item->GetGUIDLow(), item->GetEntry());
}
m->messageType = sender.GetMailMessageType();
m->stationery = sender.GetStationery();
m->sender = sender.GetSenderId();
m->receiverGuid = receiver.GetPlayerGuid();
m->expire_time = expire_time;
m->deliver_time = deliver_time;
m->checked = checked;
m->state = MAIL_STATE_UNCHANGED;
pReceiver->AddMail(m); // to insert new mail to beginning of maillist
if (!m_items.empty())
{
for(MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
pReceiver->AddMItem(mailItemIter->second);
}
}
else if (!m_items.empty())
deleteIncludedItems();
}
/**
* Generate items from template at mails loading (this happens when mail with mail template items send in time when receiver has been offline)
*
* @param receiver reciver of mail
*/
void Mail::prepareTemplateItems( Player* receiver )
{
if (!mailTemplateId || !items.empty())
return;
has_items = true;
Loot mailLoot;
// can be empty
mailLoot.FillLoot(mailTemplateId, LootTemplates_Mail, receiver, true, true);
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("UPDATE mail SET has_items = 1 WHERE id = %u", messageID);
uint32 max_slot = mailLoot.GetMaxSlotInLootFor(receiver);
for(uint32 i = 0; items.size() < MAX_MAIL_ITEMS && i < max_slot; ++i)
{
if (LootItem* lootitem = mailLoot.LootItemInSlot(i, receiver))
{
if (Item* item = Item::CreateItem(lootitem->itemid, lootitem->count, receiver))
{
item->SaveToDB();
AddItem(item->GetGUIDLow(), item->GetEntry());
receiver->AddMItem(item);
CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')",
messageID, item->GetGUIDLow(), item->GetEntry(), receiver->GetGUIDLow());
}
}
}
CharacterDatabase.CommitTransaction();
}
/*! @} */