Updated Copyright year to 2013
[getmangos.git] / src / game / QueryHandler.cpp
blob25fa4d065256c0764ec4bb78985424957ac87235
1 /*
2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
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 "Common.h"
20 #include "Language.h"
21 #include "Database/DatabaseEnv.h"
22 #include "Database/DatabaseImpl.h"
23 #include "WorldPacket.h"
24 #include "WorldSession.h"
25 #include "Opcodes.h"
26 #include "Log.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "ObjectGuid.h"
30 #include "Player.h"
31 #include "UpdateMask.h"
32 #include "NPCHandler.h"
33 #include "Pet.h"
34 #include "MapManager.h"
35 #include "SQLStorages.h"
37 void WorldSession::SendNameQueryOpcode(Player* p)
39 if (!p)
40 return;
41 // guess size
42 WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10));
43 data << p->GetPackGUID(); // player guid
44 data << uint8(0); // added in 3.1; if > 1, then end of packet
45 data << p->GetName(); // played name
46 data << uint8(0); // realm name for cross realm BG usage
47 data << uint8(p->getRace());
48 data << uint8(p->getGender());
49 data << uint8(p->getClass());
50 if (DeclinedName const* names = p->GetDeclinedNames())
52 data << uint8(1); // is declined
53 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
54 data << names->name[i];
56 else
57 data << uint8(0); // is not declined
59 SendPacket(&data);
62 void WorldSession::SendNameQueryOpcodeFromDB(ObjectGuid guid)
64 CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(),
65 !sWorld.getConfig(CONFIG_BOOL_DECLINED_NAMES_USED) ?
66 // ------- Query Without Declined Names --------
67 // 0 1 2 3 4
68 "SELECT guid, name, race, gender, class "
69 "FROM characters WHERE guid = '%u'"
71 // --------- Query With Declined Names ---------
72 // 0 1 2 3 4
73 "SELECT characters.guid, name, race, gender, class, "
74 // 5 6 7 8 9
75 "genitive, dative, accusative, instrumental, prepositional "
76 "FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'",
77 guid.GetCounter());
80 void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult* result, uint32 accountId)
82 if (!result)
83 return;
85 WorldSession* session = sWorld.FindSession(accountId);
86 if (!session)
88 delete result;
89 return;
92 Field* fields = result->Fetch();
93 uint32 lowguid = fields[0].GetUInt32();
94 std::string name = fields[1].GetCppString();
95 uint8 pRace = 0, pGender = 0, pClass = 0;
96 if (name == "")
97 name = session->GetMangosString(LANG_NON_EXIST_CHARACTER);
98 else
100 pRace = fields[2].GetUInt8();
101 pGender = fields[3].GetUInt8();
102 pClass = fields[4].GetUInt8();
104 // guess size
105 WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 1 + 10));
106 data << ObjectGuid(HIGHGUID_PLAYER, lowguid).WriteAsPacked();
107 data << uint8(0); // added in 3.1; if > 1, then end of packet
108 data << name;
109 data << uint8(0); // realm name for cross realm BG usage
110 data << uint8(pRace); // race
111 data << uint8(pGender); // gender
112 data << uint8(pClass); // class
114 // if the first declined name field (5) is empty, the rest must be too
115 if (sWorld.getConfig(CONFIG_BOOL_DECLINED_NAMES_USED) && fields[5].GetCppString() != "")
117 data << uint8(1); // is declined
118 for (int i = 5; i < MAX_DECLINED_NAME_CASES + 5; ++i)
119 data << fields[i].GetCppString();
121 else
122 data << uint8(0); // is not declined
124 session->SendPacket(&data);
125 delete result;
128 void WorldSession::HandleNameQueryOpcode(WorldPacket& recv_data)
130 ObjectGuid guid;
132 recv_data >> guid;
134 Player* pChar = sObjectMgr.GetPlayer(guid);
136 if (pChar)
137 SendNameQueryOpcode(pChar);
138 else
139 SendNameQueryOpcodeFromDB(guid);
142 void WorldSession::HandleQueryTimeOpcode(WorldPacket& /*recv_data*/)
144 SendQueryTimeResponse();
147 /// Only _static_ data send in this packet !!!
148 void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data)
150 uint32 entry;
151 recv_data >> entry;
152 ObjectGuid guid;
153 recv_data >> guid;
155 CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(entry);
156 if (ci)
158 int loc_idx = GetSessionDbLocaleIndex();
160 char const* name = ci->Name;
161 char const* subName = ci->SubName;
162 sObjectMgr.GetCreatureLocaleStrings(entry, loc_idx, &name, &subName);
164 DETAIL_LOG("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name, entry);
165 // guess size
166 WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100);
167 data << uint32(entry); // creature entry
168 data << name;
170 for (uint8 i = 0; i < 7; ++i)
171 data << uint8(0); // name2, name3, name4, always empty
173 data << subName;
174 data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0
175 data << uint32(ci->type_flags); // flags
176 data << uint32(0); // unk
177 data << uint32(ci->type); // CreatureType.dbc
178 data << uint32(ci->family); // CreatureFamily.dbc
179 data << uint32(ci->rank); // Creature Rank (elite, boss, etc)
180 data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit
181 data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit
183 for (int i = 0; i < MAX_CREATURE_MODEL; ++i)
184 data << uint32(ci->ModelId[i]);
186 data << float(ci->healthModifier); // health modifier
187 data << float(ci->powerModifier); // power modifier
188 data << uint8(ci->RacialLeader);
189 for (uint32 i = 0; i < 6; ++i)
190 data << uint32(ci->questItems[i]); // itemId[6], quest drop
191 data << uint32(ci->movementId); // CreatureMovementInfo.dbc
192 data << uint32(0); //unk
193 SendPacket(&data);
194 DEBUG_LOG("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
196 else
198 DEBUG_LOG("WORLD: CMSG_CREATURE_QUERY - Guid: %s Entry: %u NO CREATURE INFO!",
199 guid.GetString().c_str(), entry);
200 WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4);
201 data << uint32(entry | 0x80000000);
202 SendPacket(&data);
203 DEBUG_LOG("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
207 /// Only _static_ data send in this packet !!!
208 void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recv_data)
210 uint32 entryID;
211 recv_data >> entryID;
212 ObjectGuid guid;
213 recv_data >> guid;
215 const GameObjectInfo* info = ObjectMgr::GetGameObjectInfo(entryID);
216 if (info)
218 std::string Name;
219 std::string IconName;
220 std::string CastBarCaption;
222 Name = info->name;
223 IconName = info->IconName;
224 CastBarCaption = info->castBarCaption;
226 int loc_idx = GetSessionDbLocaleIndex();
227 if (loc_idx >= 0)
229 GameObjectLocale const* gl = sObjectMgr.GetGameObjectLocale(entryID);
230 if (gl)
232 if (gl->Name.size() > size_t(loc_idx) && !gl->Name[loc_idx].empty())
233 Name = gl->Name[loc_idx];
234 if (gl->CastBarCaption.size() > size_t(loc_idx) && !gl->CastBarCaption[loc_idx].empty())
235 CastBarCaption = gl->CastBarCaption[loc_idx];
238 DETAIL_LOG("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name, entryID);
239 WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 150);
240 data << uint32(entryID);
241 data << uint32(info->type);
242 data << uint32(info->displayId);
243 data << Name;
244 data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
245 data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
246 data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
247 data << info->unk1; // 2.0.3, string
248 data.append(info->raw.data, 24);
249 data << float(info->size); // go size
250 for (uint32 i = 0; i < 6; ++i)
251 data << uint32(info->questItems[i]); // itemId[6], quest drop
252 SendPacket(&data);
253 DEBUG_LOG("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
255 else
257 DEBUG_LOG("WORLD: CMSG_GAMEOBJECT_QUERY - Guid: %s Entry: %u Missing gameobject info!",
258 guid.GetString().c_str(), entryID);
259 WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 4);
260 data << uint32(entryID | 0x80000000);
261 SendPacket(&data);
262 DEBUG_LOG("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
266 void WorldSession::HandleCorpseQueryOpcode(WorldPacket& /*recv_data*/)
268 DETAIL_LOG("WORLD: Received MSG_CORPSE_QUERY");
270 Corpse* corpse = GetPlayer()->GetCorpse();
272 if (!corpse)
274 WorldPacket data(MSG_CORPSE_QUERY, 1);
275 data << uint8(0); // corpse not found
276 SendPacket(&data);
277 return;
280 uint32 corpsemapid = corpse->GetMapId();
281 float x = corpse->GetPositionX();
282 float y = corpse->GetPositionY();
283 float z = corpse->GetPositionZ();
284 int32 mapid = corpsemapid;
286 // if corpse at different map
287 if (corpsemapid != _player->GetMapId())
289 // search entrance map for proper show entrance
290 if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(corpsemapid))
292 if (corpseMapEntry->IsDungeon() && corpseMapEntry->ghost_entrance_map >= 0)
294 // if corpse map have entrance
295 if (TerrainInfo const* entranceMap = sTerrainMgr.LoadTerrain(corpseMapEntry->ghost_entrance_map))
297 mapid = corpseMapEntry->ghost_entrance_map;
298 x = corpseMapEntry->ghost_entrance_x;
299 y = corpseMapEntry->ghost_entrance_y;
300 z = entranceMap->GetHeight(x, y, MAX_HEIGHT);
306 WorldPacket data(MSG_CORPSE_QUERY, 1 + (6 * 4));
307 data << uint8(1); // corpse found
308 data << int32(mapid);
309 data << float(x);
310 data << float(y);
311 data << float(z);
312 data << uint32(corpsemapid);
313 data << uint32(0); // unknown
314 SendPacket(&data);
317 void WorldSession::HandleNpcTextQueryOpcode(WorldPacket& recv_data)
319 uint32 textID;
320 ObjectGuid guid;
322 recv_data >> textID;
323 recv_data >> guid;
325 DETAIL_LOG("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID);
327 _player->SetTargetGuid(guid);
329 GossipText const* pGossip = sObjectMgr.GetGossipText(textID);
331 WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size
332 data << textID;
334 if (!pGossip)
336 for (uint32 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i)
338 data << float(0);
339 data << "Greetings $N";
340 data << "Greetings $N";
341 data << uint32(0);
342 data << uint32(0);
343 data << uint32(0);
344 data << uint32(0);
345 data << uint32(0);
346 data << uint32(0);
347 data << uint32(0);
350 else
352 std::string Text_0[MAX_GOSSIP_TEXT_OPTIONS], Text_1[MAX_GOSSIP_TEXT_OPTIONS];
353 for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i)
355 Text_0[i] = pGossip->Options[i].Text_0;
356 Text_1[i] = pGossip->Options[i].Text_1;
359 int loc_idx = GetSessionDbLocaleIndex();
361 sObjectMgr.GetNpcTextLocaleStringsAll(textID, loc_idx, &Text_0, &Text_1);
363 for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i)
365 data << pGossip->Options[i].Probability;
367 if (Text_0[i].empty())
368 data << Text_1[i];
369 else
370 data << Text_0[i];
372 if (Text_1[i].empty())
373 data << Text_0[i];
374 else
375 data << Text_1[i];
377 data << pGossip->Options[i].Language;
379 for (int j = 0; j < 3; ++j)
381 data << pGossip->Options[i].Emotes[j]._Delay;
382 data << pGossip->Options[i].Emotes[j]._Emote;
387 SendPacket(&data);
389 DEBUG_LOG("WORLD: Sent SMSG_NPC_TEXT_UPDATE");
392 void WorldSession::HandlePageTextQueryOpcode(WorldPacket& recv_data)
394 DETAIL_LOG("WORLD: Received CMSG_PAGE_TEXT_QUERY");
395 recv_data.hexlike();
397 uint32 pageID;
398 recv_data >> pageID;
399 recv_data.read_skip<uint64>(); // guid
401 while (pageID)
403 PageText const* pPage = sPageTextStore.LookupEntry<PageText>(pageID);
404 // guess size
405 WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50);
406 data << pageID;
408 if (!pPage)
410 data << "Item page missing.";
411 data << uint32(0);
412 pageID = 0;
414 else
416 std::string Text = pPage->Text;
418 int loc_idx = GetSessionDbLocaleIndex();
419 if (loc_idx >= 0)
421 PageTextLocale const* pl = sObjectMgr.GetPageTextLocale(pageID);
422 if (pl)
424 if (pl->Text.size() > size_t(loc_idx) && !pl->Text[loc_idx].empty())
425 Text = pl->Text[loc_idx];
429 data << Text;
430 data << uint32(pPage->Next_Page);
431 pageID = pPage->Next_Page;
433 SendPacket(&data);
435 DEBUG_LOG("WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE");
439 void WorldSession::HandleCorpseMapPositionQueryOpcode(WorldPacket& recv_data)
441 DEBUG_LOG("WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY");
443 uint32 unk;
444 recv_data >> unk;
446 WorldPacket data(SMSG_CORPSE_TRANSPORT_QUERY, 4 + 4 + 4 + 4);
447 data << float(0);
448 data << float(0);
449 data << float(0);
450 data << float(0);
451 SendPacket(&data);
454 void WorldSession::HandleQueryQuestsCompletedOpcode(WorldPacket& /*recv_data */)
456 uint32 count = 0;
458 WorldPacket data(SMSG_ALL_QUESTS_COMPLETED, 4 + 4 * count);
459 data << uint32(count);
461 for (QuestStatusMap::const_iterator itr = _player->getQuestStatusMap().begin(); itr != _player->getQuestStatusMap().end(); ++itr)
463 if (itr->second.m_rewarded)
465 data << uint32(itr->first);
466 ++count;
469 data.put<uint32>(0, count);
470 SendPacket(&data);
473 void WorldSession::HandleQuestPOIQueryOpcode(WorldPacket& recv_data)
475 uint32 count;
476 recv_data >> count; // quest count, max=25
478 if (count > MAX_QUEST_LOG_SIZE)
480 recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
481 return;
484 WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4)*count);
485 data << uint32(count); // count
487 for (uint32 i = 0; i < count; ++i)
489 uint32 questId;
490 recv_data >> questId; // quest id
492 bool questOk = false;
494 uint16 questSlot = _player->FindQuestSlot(questId);
496 if (questSlot != MAX_QUEST_LOG_SIZE)
497 questOk = _player->GetQuestSlotQuestId(questSlot) == questId;
499 if (questOk)
501 QuestPOIVector const* POI = sObjectMgr.GetQuestPOIVector(questId);
503 if (POI)
505 data << uint32(questId); // quest ID
506 data << uint32(POI->size()); // POI count
508 for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr)
510 data << uint32(itr->PoiId); // POI index
511 data << int32(itr->ObjectiveIndex); // objective index
512 data << uint32(itr->MapId); // mapid
513 data << uint32(itr->MapAreaId); // world map area id
514 data << uint32(itr->FloorId); // floor id
515 data << uint32(itr->Unk3); // unknown
516 data << uint32(itr->Unk4); // unknown
517 data << uint32(itr->points.size()); // POI points count
519 for (std::vector<QuestPOIPoint>::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2)
521 data << int32(itr2->x); // POI point x
522 data << int32(itr2->y); // POI point y
526 else
528 data << uint32(questId); // quest ID
529 data << uint32(0); // POI count
532 else
534 data << uint32(questId); // quest ID
535 data << uint32(0); // POI count
539 SendPacket(&data);
542 void WorldSession::SendQueryTimeResponse()
544 WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4 + 4);
545 data << uint32(time(NULL));
546 data << uint32(sWorld.GetNextDailyQuestsResetTime() - time(NULL));
547 SendPacket(&data);