[2390] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Mail.cpp
blob86cb846c4189bc63a8d19d64b5939a0c47e64783
1 /*
2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "WorldPacket.h"
20 #include "WorldSession.h"
21 #include "Opcodes.h"
22 #include "Log.h"
23 #include "Chat.h"
24 #include "World.h"
25 #include "ObjectMgr.h"
26 #include "Player.h"
27 #include "UpdateMask.h"
28 #include "Unit.h"
30 void WorldSession::HandleSendMail(WorldPacket & recv_data )
32 time_t base = time(NULL);
33 WorldPacket data;
34 uint64 sender,item;
35 std::string receiver,subject,body;
36 uint32 unk1,unk2,money,COD,mID;
37 recv_data >> sender;
38 recv_data >> receiver >> subject >> body;
39 recv_data >> unk1 >> unk2;
40 recv_data >> item;
41 recv_data >> money >> COD;
43 sLog.outDetail("Player %u is sending mail to %s with subject %s and body %s includes item %u and %u copper and %u COD copper",GUID_LOPART(sender),receiver.c_str(),subject.c_str(),body.c_str(),GUID_LOPART(item),money,COD);
44 mID = objmgr.GenerateMailID();
46 Player* pl = _player;
48 WorldPacket tmpData;
50 uint64 rc = objmgr.GetPlayerGUIDByName(receiver.c_str());
51 if(pl->GetGUID() == rc)
53 tmpData.Initialize(SMSG_SEND_MAIL_RESULT);
54 tmpData << uint32(0);
55 tmpData << uint32(0);
56 tmpData << uint32(MAIL_ERR_CANNOT_SEND_TO_SELF);
57 SendPacket(&tmpData);
58 return;
61 if (pl->GetMoney() < money + 30)
63 tmpData.Initialize(SMSG_SEND_MAIL_RESULT);
64 tmpData << uint32(0);
65 tmpData << uint32(0);
66 tmpData << uint32(MAIL_ERR_NOT_ENOUGH_MONEY);
67 SendPacket(&tmpData);
68 return;
71 if (!rc)
73 data.Initialize(SMSG_SEND_MAIL_RESULT);
74 data << uint32(0);
75 data << uint32(0);
76 data << uint32(MAIL_ERR_RECIPIENT_NOT_FOUND);
77 SendPacket(&data);
78 return;
81 Player *receive = objmgr.GetPlayer(rc);
83 uint32 rc_team = 0;
85 if(receive)
86 rc_team = receive->GetTeam();
87 else
88 rc_team = objmgr.GetPlayerTeamByGUID(rc);
90 // test the receiver's Faction...
91 if (pl->GetTeam() != rc_team)
93 data.Initialize(SMSG_SEND_MAIL_RESULT);
94 data << uint32(0);
95 data << uint32(0);
96 data << uint32(MAIL_ERR_NOT_YOUR_TEAM);
97 SendPacket(&data);
98 return;
101 uint16 item_pos;
102 Item *it = 0;
104 if (item != 0)
106 item_pos = pl->GetPosByGuid(item);
107 it = pl->GetItemByPos( item_pos );
109 // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to mail)
110 if(it->IsBag() && !((Bag*)it)->IsEmpty())
112 data.Initialize(SMSG_SEND_MAIL_RESULT);
113 data << uint32(0);
114 data << uint32(0);
115 data << uint32(MAIL_ERR_INTERNAL_ERROR);
116 SendPacket(&data);
117 return;
121 data.Initialize(SMSG_SEND_MAIL_RESULT);
122 data << uint32(0);
123 data << uint32(0);
124 data << uint32(MAIL_OK);
125 SendPacket(&data);
127 if (item != 0)
129 //item reminds in item_instance table already, used it in mail now
130 pl->RemoveItem( (item_pos >> 8), (item_pos & 255), true );
132 pl->ModifyMoney( -30 - money );
134 time_t etime = base + 3600 * ((COD > 0)? 3 : 30); //time if COD 3 days, if no COD 30 days
135 if (receive)
137 Mail* m = new Mail;
138 m->messageID = mID;
139 m->sender = pl->GetGUIDLow();
140 m->receiver = GUID_LOPART(rc);
141 m->subject = subject;
142 m->body = body;
143 m->item = GUID_LOPART(item);
144 m->time = etime;
145 m->money = money;
146 m->COD = COD;
147 m->checked = 0;
149 receive->AddMail(m);
150 if (it)
151 receive->AddMItem(it);
154 sDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'",mID);
155 // there was (long)etime ;-) COD added
156 sDatabase.PExecute("INSERT INTO `mail` (`id`,`sender`,`receiver`,`subject`,`body`,`item`,`time`,`money`,`cod`,`checked`) VALUES ('%u', '%u', '%u', '%s', '%s', '%u', '" I64FMTD "', '%u', '%u', '%u')", mID, pl->GetGUIDLow(), GUID_LOPART(rc), subject.c_str(), body.c_str(), GUID_LOPART(item), (uint64)etime, money, COD, 0);
159 void WorldSession::HandleMarkAsRead(WorldPacket & recv_data )
161 uint64 mailbox;
162 uint32 message;
163 recv_data >> mailbox;
164 recv_data >> message;
165 Player *pl = _player;
166 Mail *m = pl->GetMail(message);
167 if (m)
169 if (pl->unReadMails)
170 pl->unReadMails--;
171 m->checked = 1;
172 m->time = time(NULL) + (3 * 3600);
173 pl->m_mailsUpdated = true;
174 pl->SetMail(m);
178 void WorldSession::HandleMailDelete(WorldPacket & recv_data )
180 uint64 mailbox;
181 uint32 message;
182 WorldPacket data;
183 recv_data >> mailbox;
184 recv_data >> message;
185 Player *pl = _player;
186 // pl->m_mailsUpdated = true; there 's no need to change it .. because query deletes mail from DB...
187 Mail *m = pl->GetMail(message);
188 if(m)
190 //begin Transaction
191 sDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'", m->messageID);
192 /*if (m->item) //player cannot delete mail, when it has money , or item, that mail can be returned
193 sDatabase.PExecute("DELETE FROM `item_instance` WHERE `guid` = '%u'", m->item);*/
194 //commit Transaction
196 pl->RemoveMail(message);
198 data.Initialize(SMSG_SEND_MAIL_RESULT);
199 data << uint32(message);
200 data << uint32(MAIL_DELETED);
201 data << uint32(0);
202 SendPacket(&data);
205 void WorldSession::HandleReturnToSender(WorldPacket & recv_data )
207 uint64 mailbox;
208 uint32 message;
209 WorldPacket data;
210 recv_data >> mailbox;
211 recv_data >> message;
212 Player *pl = _player;
213 Mail *m = pl->GetMail(message);
215 if(!m)
216 return;
218 m->receiver = m->sender;
219 m->sender = pl->GetGUIDLow();
220 m->time = time(NULL) + (30 * 3600);
221 m->COD = 0;
222 m->checked = 0;
223 uint64 rc = m->receiver;
224 Player *receive = objmgr.GetPlayer(rc);
225 if(receive)
227 if (m->item)
229 Item *pItem = pl->GetMItem(m->item);
230 receive->AddMItem(pItem);
231 pl->RemoveMItem(m->item);
233 receive->AddMail(m);
235 //pl->m_mailsUpdated = true; - not needed, query does all we need
237 data.Initialize(SMSG_SEND_MAIL_RESULT);
238 data << uint32(message);
239 data << uint32(MAIL_RETURNED_TO_SENDER);
240 data << uint32(0);
241 SendPacket(&data);
243 sDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'", message);
244 sDatabase.PExecute("INSERT INTO `mail` (`id`,`sender`,`receiver`,`subject`,`body`,`item`,`time`,`money`,`cod`,`checked`) VALUES ('%u', '%u','%u', '%s', '%s', '%u','" I64FMTD "','%u','%u','%u')", m->messageID, pl->GetGUIDLow(), m->receiver, m->subject.c_str(), m->body.c_str(), m->item, (uint64)m->time, m->money, 0, 0);
246 pl->RemoveMail(message);
249 void WorldSession::HandleTakeItem(WorldPacket & recv_data )
251 uint64 mailbox;
252 uint32 message;
253 uint16 dest;
254 WorldPacket data;
255 recv_data >> mailbox;
256 recv_data >> message;
257 Player* pl = _player;
259 Mail* m = pl->GetMail(message);
260 if (!m)
261 return;
263 Item *it = pl->GetMItem(m->item);
265 uint8 msg = _player->CanStoreItem( 0, NULL_SLOT, dest, it, false );
266 if( msg == EQUIP_ERR_OK )
268 m->item = 0;
270 if (m->COD > 0)
272 Mail* mn = new Mail;
273 mn->messageID = objmgr.GenerateMailID();
274 mn->sender = m->receiver;
275 mn->receiver = m->sender;
276 mn->subject = m->subject;
277 mn->body = "Your item sold, player paid a COD";
278 mn->item = 0;
279 mn->time = time(NULL) + (30 * 3600);
280 mn->money = m->COD;
281 mn->COD = 0;
282 mn->checked = 0;
284 Player *receive = objmgr.GetPlayer((uint64)m->sender);
286 if (receive)
287 receive->AddMail(mn);
289 sDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'",mn->messageID);
290 //added
291 sDatabase.PExecute("INSERT INTO `mail` (`id`,`sender`,`receiver`,`subject`,`body`,`item`,`time`,`money`,`cod`,`checked`) VALUES ('%u', '%u', '%u', '%s', '%s', '%u', '" I64FMTD "', '%u', '%u', '%u')", mn->messageID, mn->sender, mn->receiver, mn->subject.c_str(), mn->body.c_str(), 0, (uint64)mn->time, mn->money, 0, 0);
292 // client tests, if player has enought money !!!
293 pl->ModifyMoney( -int32(m->COD) );
295 m->COD = 0;
296 pl->SetMail(m);
298 uint32 it_guidlow = it->GetGUIDLow();
299 _player->StoreItem( dest, it, true); // item can be remove at adding to existed item stack
300 pl->RemoveMItem(it_guidlow);
302 data.Initialize(SMSG_SEND_MAIL_RESULT);
303 data << uint32(message);
304 data << uint32(MAIL_ITEM_TAKEN);
305 data << uint32(0);
306 SendPacket(&data);
308 else
310 data.Initialize(SMSG_SEND_MAIL_RESULT);
311 data << uint32(message);
312 data << uint32(0);
313 data << uint32(MAIL_ERR_BAG_FULL);
314 SendPacket(&data);
318 void WorldSession::HandleTakeMoney(WorldPacket & recv_data )
320 WorldPacket data;
321 uint64 mailbox;
322 uint32 id;
323 recv_data >> mailbox;
324 recv_data >> id;
325 Player *pl = _player;
327 Mail* m = pl->GetMail(id);
328 if(!m)
329 return;
331 data.Initialize(SMSG_SEND_MAIL_RESULT);
332 data << uint32(id);
333 data << uint32(MAIL_MONEY_TAKEN);
334 data << uint32(0);
335 SendPacket(&data);
337 pl->ModifyMoney(m->money);
338 m->money = 0;
340 pl->m_mailsUpdated = true;
341 pl->SetMail(m);
344 void WorldSession::HandleGetMail(WorldPacket & recv_data )
346 uint64 mailbox;
347 recv_data >> mailbox; // from mailbox in Storm near bank it was 0x000068A2 (dec 26786) and 0xF0004000 (dec 4026548224)
349 WorldPacket data;
350 Player* pl = _player;
352 //load players mails, and mailed items
353 if(!pl->m_mailsLoaded)
354 pl ->_LoadMail();
356 data.Initialize(SMSG_MAIL_LIST_RESULT);
357 data << uint8(pl->GetMailSize());
358 std::list<Mail*>::iterator itr;
359 for (itr = pl->GetmailBegin(); itr != pl->GetmailEnd();itr++)
361 data << uint32((*itr)->messageID); // Correct..., also message id , if you change it, server crashes
362 data << uint8(0); // Message Type 0 = Default, maybe there will be also Reply
363 data << uint32((*itr)->sender); // SenderID
364 data << uint32(0); // Constant
366 data << (*itr)->subject.c_str(); // Subject string
367 if((*itr)->body.c_str()!=NULL)
368 data << uint32((*itr)->messageID); // MessageID!!
369 else
370 data << uint32(0); // No messageID
371 data << uint32(0); // Unknown - 0x00000029
372 data << uint32(0); // Unknown
373 if ((*itr)->item != 0)
375 if(Item* i = pl->GetMItem((*itr)->item))
376 data << uint32(i->GetUInt32Value(OBJECT_FIELD_ENTRY));
377 else
379 sLog.outError("Mail to %s marked as having item (mail item idx: %u), but item not found.",pl->GetName(),(*itr)->item);
380 data << uint32(0);
383 else
384 data << uint32(0);
386 data << uint32(0); // Unknown
387 data << uint32(0); // Unknown
388 data << uint32(0); // Unknown
389 data << uint8(1); // Unknown - Count
390 data << uint32(0xFFFFFFFF); // Unknown - Charges
391 data << uint32(0); // Unknown - MaxDurability
392 data << uint32(0); // Unknown - Durability
393 data << uint32((*itr)->money); // Gold
394 data << uint32((*itr)->COD); // COD
395 data << uint32((*itr)->checked); // flags 0: not checked 1: checked 8: COD Payment: "Subject"
396 data << float(((*itr)->time - time(NULL)) / 3600); // Time
397 data << uint32(0); // Unknown
400 SendPacket(&data);
403 extern char *fmtstring( char *format, ... );
405 uint32 GetItemGuidFromDisplayID ( uint32 displayID, Player* pl )
408 uint8 i = 0;
409 Item * srcitem;
411 for (i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; i++)
413 srcitem = pl->GetItemByPos( INVENTORY_SLOT_BAG_0, i );
415 if (srcitem)
417 if (srcitem->GetProto()->DisplayInfoID == displayID)
419 break;
424 if( i >= BANK_SLOT_BAG_END )
426 QueryResult *result = sDatabase.PQuery( "SELECT `entry` FROM `item_template` WHERE `displayid`='%u'", displayID );
428 if( !result )
430 return (uint8)-1;
433 uint32 id = (*result)[0].GetUInt32();
434 return id;
435 delete result;
438 return srcitem->GetProto()->ItemId;
441 bool WorldSession::SendItemInfo( uint32 itemid, WorldPacket data )
443 // int i;
444 uint32 realID = GetItemGuidFromDisplayID(itemid, _player);
445 char const *itemInfo;
447 if (realID < 0)
449 sLog.outError( "WORLD: Unknown item id 0x%.8X", realID );
450 return false;
453 ItemPrototype const *itemProto = objmgr.GetItemPrototype(realID);
455 if(!itemProto)
457 sLog.outError( "WORLD: Unknown item id 0x%.8X", realID );
458 return false;
461 sLog.outDebug( "WORLD: Real item id is %u. Name %s.", realID, itemProto->Name1 );
463 data.Initialize(SMSG_ITEM_TEXT_QUERY_RESPONSE);
464 data << itemid;
466 itemInfo = fmtstring("<HTML>\n<BODY>\n");
468 itemInfo = fmtstring("%s</P></BODY>\n</HTML>\n", itemInfo);
470 data << itemInfo;
471 data << uint32(0);
472 SendPacket(&data);
474 return true;
477 void WorldSession::HandleItemTextQuery(WorldPacket & recv_data )
479 WorldPacket data;
480 uint32 mailguid;
481 uint64 unk1;
483 recv_data >> mailguid >> unk1;
485 Player* pl = _player;
487 Mail *itr;
489 itr = pl->GetMail(mailguid);
490 if(itr)
492 sLog.outDebug("We got mailguid: %u with unk: %u", mailguid, unk1);
494 data.Initialize(SMSG_ITEM_TEXT_QUERY_RESPONSE);
495 data << mailguid;
496 data << itr->body.c_str();
497 data << uint32(0);
498 SendPacket(&data);
501 else
503 QueryResult *result = sDatabase.PQuery( "SELECT `text`,`next_page` FROM `item_page` WHERE `id` = '%u'", mailguid );
505 if( result )
507 data.Initialize(SMSG_ITEM_TEXT_QUERY_RESPONSE);
508 data << mailguid;
510 uint32 nextpage = mailguid;
512 while (nextpage)
514 data << (*result)[0].GetString();
515 nextpage = (*result)[1].GetUInt32();
516 data << nextpage;
519 data << uint32(0);
520 SendPacket(&data);
521 delete result;
522 return;
525 if (!SendItemInfo( mailguid, data ))
527 data.Initialize(SMSG_ITEM_TEXT_QUERY_RESPONSE);
528 data << mailguid;
530 data << "There is no info for this item.";
532 data << uint32(0);
533 SendPacket(&data);
538 void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data )
540 uint32 unk1,unk2,mailid;
542 recv_data >> unk1 >> unk2 >> mailid;
544 sLog.outDetail("HandleMailCreateTextItem unk1=%u,unk2=%u,mailid=%u",unk1,unk2,mailid);
546 Item *item = new Item();
548 if(!item->Create(objmgr.GenerateLowGuid(HIGHGUID_ITEM), 889, _player))
550 delete item;
551 return;
553 item->SetUInt32Value( ITEM_FIELD_ITEM_TEXT_ID , mailid );
555 WorldPacket data;
556 data.Initialize(SMSG_SEND_MAIL_RESULT);
558 uint16 dest;
559 uint8 msg = _player->CanStoreItem( 0, NULL_SLOT, dest, item, false );
560 if( msg == EQUIP_ERR_OK )
562 _player->StoreItem(dest, item, true);
563 data << uint32(mailid);
564 data << uint32(MAIL_MADE_PERMANENT);
565 data << uint32(0);
567 else
569 delete item;
570 _player->SendEquipError( msg, item, NULL );
571 data << uint32(mailid);
572 data << uint32(0);
573 data << uint32(MAIL_ERR_INTERNAL_ERROR);
576 SendPacket(&data);
579 void WorldSession::HandleMsgQueryNextMailtime(WorldPacket & recv_data )
582 WorldPacket Data;
584 if( _player->unReadMails > 0 )
586 Data.Initialize(MSG_QUERY_NEXT_MAIL_TIME);
587 Data << uint32(0);
588 SendPacket(&Data);
590 else
592 Data.Initialize(MSG_QUERY_NEXT_MAIL_TIME);
593 Data << uint8(0x00);
594 Data << uint8(0xC0);
595 Data << uint8(0xA8);
596 Data << uint8(0xC7);
597 SendPacket(&Data);