/* * Copyright (C) 2008-2010 TrinityCore * Copyright (C) 2005-2009 MaNGOS * * 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, see . */ #include "DatabaseEnv.h" #include "Mail.h" #include "Log.h" #include "World.h" #include "ObjectMgr.h" #include "Player.h" #include "Unit.h" #include "BattlegroundMgr.h" #include "Item.h" #include "AuctionHouseMgr.h" 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, SQLTransaction& trans) { 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) { if (LootItem* lootitem = mailLoot.LootItemInSlot(i,receiver)) { if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,receiver)) { item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted AddItem(item); } } } } void MailDraft::deleteIncludedItems(SQLTransaction& trans, bool inDB /*= false*/ ) { for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; if (inDB) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt32(0, item->GetGUIDLow()); trans->Append(stmt); } delete item; } m_items.clear(); } void MailDraft::SendReturnToSender(uint32 sender_acc, uint32 sender_guid, uint32 receiver_guid) { Player *receiver = sObjectMgr.GetPlayer(MAKE_NEW_GUID(receiver_guid, 0, HIGHGUID_PLAYER)); uint32 rc_account = 0; if (!receiver) rc_account = sObjectMgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(receiver_guid, 0, HIGHGUID_PLAYER)); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (!receiver && !rc_account) // sender not exist { deleteIncludedItems(trans, 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) for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; item->SaveToDB(trans); // item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting trans->PAppend("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", receiver_guid, item->GetGUIDLow()); } } // If theres is an item, there is a one hour delivery delay. uint32 deliver_delay = needItemDelay ? sWorld.getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // will delete item or place to receiver mail list SendMailTo(trans,MailReceiver(receiver,receiver_guid), MailSender(MAIL_NORMAL, sender_guid), MAIL_CHECK_MASK_RETURNED, deliver_delay); CharacterDatabase.CommitTransaction(trans); } void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL if (pReceiver) prepareItems(pReceiver, trans); // generate mail template items uint32 mailId = sObjectMgr.GenerateMailID(); time_t deliver_time = time(NULL) + deliver_delay; //expire time if COD 3 days, if no COD 30 days, if auction sale pending 1 hour uint32 expire_delay; // auction mail without any items and money if (sender.GetMailMessageType() == MAIL_AUCTION && m_items.empty() && !m_money) expire_delay = sWorld.getIntConfig(CONFIG_MAIL_DELIVERY_DELAY); // mail from battlemaster (rewardmarks) should last only one day else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattlegroundMgr.GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE) expire_delay = DAY; // default case: expire time if COD 3 days, if no COD 30 days 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(); std::string safe_body = GetBody(); CharacterDatabase.escape_string(safe_subject); CharacterDatabase.escape_string(safe_body); trans->PAppend("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); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; trans->PAppend("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')", mailId, item->GetGUIDLow(), item->GetEntry(), receiver.GetPlayerGUIDLow()); } // For online receiver update in game mail status and data if (pReceiver) { pReceiver->AddNewMailDeliverTime(deliver_time); if (pReceiver->IsMailsLoaded()) { Mail * m = new Mail; m->messageID = mailId; m->mailTemplateId = GetMailTemplateId(); m->subject = GetSubject(); m->body = GetBody(); m->money = GetMoney(); m->COD = GetCOD(); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { Item* item = mailItemIter->second; m->AddItem(item->GetGUIDLow(), item->GetEntry()); } m->messageType = sender.GetMailMessageType(); m->stationery = sender.GetStationery(); m->sender = sender.GetSenderId(); m->receiver = receiver.GetPlayerGUIDLow(); m->expire_time = expire_time; m->deliver_time = deliver_time; m->checked = checked; m->state = MAIL_STATE_UNCHANGED; pReceiver->AddMail(m); // to insert new mail to beginning of maillist if (!m_items.empty()) { for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) pReceiver->AddMItem(mailItemIter->second); } } else if (!m_items.empty()) { SQLTransaction temp = SQLTransaction(NULL); deleteIncludedItems(temp); } } else if (!m_items.empty()) { SQLTransaction temp = SQLTransaction(NULL); deleteIncludedItems(temp); } }