* Even more restructuring of the game library.
--HG-- branch : trunk
This commit is contained in:
@@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Language.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Database/DatabaseImpl.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 "NPCHandler.h"
|
||||
#include "Pet.h"
|
||||
#include "MapManager.h"
|
||||
|
||||
void WorldSession::SendNameQueryOpcode(Player *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
// guess size
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10));
|
||||
data.append(p->GetPackGUID()); // player guid
|
||||
data << uint8(0); // added in 3.1
|
||||
data << p->GetName(); // played name
|
||||
data << uint8(0); // realm name for cross realm BG usage
|
||||
data << uint8(p->getRace());
|
||||
data << uint8(p->getGender());
|
||||
data << uint8(p->getClass());
|
||||
if (DeclinedName const* names = p->GetDeclinedNames())
|
||||
{
|
||||
data << uint8(1); // is declined
|
||||
for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
||||
data << names->name[i];
|
||||
}
|
||||
else
|
||||
data << uint8(0); // is not declined
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid)
|
||||
{
|
||||
CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(),
|
||||
!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ?
|
||||
// ------- Query Without Declined Names --------
|
||||
// 0 1 2 3 4
|
||||
"SELECT guid, name, race, gender, class "
|
||||
"FROM characters WHERE guid = '%u'"
|
||||
:
|
||||
// --------- Query With Declined Names ---------
|
||||
// 0 1 2 3 4
|
||||
"SELECT characters.guid, name, race, gender, class, "
|
||||
// 5 6 7 8 9
|
||||
"genitive, dative, accusative, instrumental, prepositional "
|
||||
"FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'",
|
||||
GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult_AutoPtr result, uint32 accountId)
|
||||
{
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
WorldSession * session = sWorld.FindSession(accountId);
|
||||
if (!session)
|
||||
return;
|
||||
|
||||
Field *fields = result->Fetch();
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
std::string name = fields[1].GetCppString();
|
||||
uint8 pRace = 0, pGender = 0, pClass = 0;
|
||||
if (name == "")
|
||||
name = session->GetTrinityString(LANG_NON_EXIST_CHARACTER);
|
||||
else
|
||||
{
|
||||
pRace = fields[2].GetUInt8();
|
||||
pGender = fields[3].GetUInt8();
|
||||
pClass = fields[4].GetUInt8();
|
||||
}
|
||||
// guess size
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10));
|
||||
data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
|
||||
data << uint8(0); // added in 3.1
|
||||
data << name;
|
||||
data << uint8(0); // realm name for cross realm BG usage
|
||||
data << uint8(pRace); // race
|
||||
data << uint8(pGender); // gender
|
||||
data << uint8(pClass); // class
|
||||
|
||||
// if the first declined name field (5) is empty, the rest must be too
|
||||
if (sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetCppString() != "")
|
||||
{
|
||||
data << uint8(1); // is declined
|
||||
for (int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i)
|
||||
data << fields[i].GetCppString();
|
||||
}
|
||||
else
|
||||
data << uint8(0); // is not declined
|
||||
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleNameQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
Player *pChar = objmgr.GetPlayer(guid);
|
||||
|
||||
if (pChar)
|
||||
SendNameQueryOpcode(pChar);
|
||||
else
|
||||
SendNameQueryOpcodeFromDB(guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
SendQueryTimeResponse();
|
||||
}
|
||||
|
||||
void WorldSession::SendQueryTimeResponse()
|
||||
{
|
||||
WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4);
|
||||
data << uint32(time(NULL));
|
||||
data << uint32(sWorld.GetNextDailyQuestsResetTime() - time(NULL));
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
/// Only _static_ data send in this packet !!!
|
||||
void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 entry;
|
||||
recv_data >> entry;
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry);
|
||||
if (ci)
|
||||
{
|
||||
|
||||
std::string Name, SubName;
|
||||
Name = ci->Name;
|
||||
SubName = ci->SubName;
|
||||
|
||||
int loc_idx = GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
CreatureLocale const *cl = objmgr.GetCreatureLocale(entry);
|
||||
if (cl)
|
||||
{
|
||||
if (cl->Name.size() > size_t(loc_idx) && !cl->Name[loc_idx].empty())
|
||||
Name = cl->Name[loc_idx];
|
||||
if (cl->SubName.size() > size_t(loc_idx) && !cl->SubName[loc_idx].empty())
|
||||
SubName = cl->SubName[loc_idx];
|
||||
}
|
||||
}
|
||||
sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name, entry);
|
||||
// guess size
|
||||
WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100);
|
||||
data << uint32(entry); // creature entry
|
||||
data << Name;
|
||||
data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
|
||||
data << SubName;
|
||||
data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0
|
||||
data << uint32(ci->type_flags); // flags
|
||||
data << uint32(ci->type); // CreatureType.dbc
|
||||
data << uint32(ci->family); // CreatureFamily.dbc
|
||||
data << uint32(ci->rank); // Creature Rank (elite, boss, etc)
|
||||
data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit
|
||||
data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit
|
||||
data << uint32(ci->Modelid1); // Modelid1
|
||||
data << uint32(ci->Modelid2); // Modelid2
|
||||
data << uint32(ci->Modelid3); // Modelid3
|
||||
data << uint32(ci->Modelid4); // Modelid4
|
||||
data << float(ci->ModHealth); // dmg/hp modifier
|
||||
data << float(ci->ModMana); // dmg/mana modifier
|
||||
data << uint8(ci->RacialLeader);
|
||||
for (uint32 i = 0; i < 6; ++i)
|
||||
data << uint32(ci->questItems[i]); // itemId[6], quest drop
|
||||
data << uint32(ci->movementId); // CreatureMovementInfo.dbc
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)",
|
||||
GUID_LOPART(guid), entry);
|
||||
WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4);
|
||||
data << uint32(entry | 0x80000000);
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
||||
}
|
||||
}
|
||||
|
||||
/// Only _static_ data send in this packet !!!
|
||||
void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 entryID;
|
||||
recv_data >> entryID;
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
const GameObjectInfo *info = objmgr.GetGameObjectInfo(entryID);
|
||||
if (info)
|
||||
{
|
||||
std::string Name;
|
||||
std::string IconName;
|
||||
std::string CastBarCaption;
|
||||
|
||||
Name = info->name;
|
||||
IconName = info->IconName;
|
||||
CastBarCaption = info->castBarCaption;
|
||||
|
||||
int loc_idx = GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
GameObjectLocale const *gl = objmgr.GetGameObjectLocale(entryID);
|
||||
if (gl)
|
||||
{
|
||||
if (gl->Name.size() > size_t(loc_idx) && !gl->Name[loc_idx].empty())
|
||||
Name = gl->Name[loc_idx];
|
||||
if (gl->CastBarCaption.size() > size_t(loc_idx) && !gl->CastBarCaption[loc_idx].empty())
|
||||
CastBarCaption = gl->CastBarCaption[loc_idx];
|
||||
}
|
||||
}
|
||||
sLog.outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name, entryID);
|
||||
WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150);
|
||||
data << uint32(entryID);
|
||||
data << uint32(info->type);
|
||||
data << uint32(info->displayId);
|
||||
data << Name;
|
||||
data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
|
||||
data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
|
||||
data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
|
||||
data << info->unk1; // 2.0.3, string
|
||||
data.append(info->raw.data, 24);
|
||||
data << float(info->size); // go size
|
||||
for (uint32 i = 0; i < 6; ++i)
|
||||
data << uint32(info->questItems[i]); // itemId[6], quest drop
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outDebug("WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)",
|
||||
GUID_LOPART(guid), entryID);
|
||||
WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4);
|
||||
data << uint32(entryID | 0x80000000);
|
||||
SendPacket(&data);
|
||||
sLog.outDebug("WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
sLog.outDetail("WORLD: Received MSG_CORPSE_QUERY");
|
||||
|
||||
Corpse *corpse = GetPlayer()->GetCorpse();
|
||||
|
||||
if (!corpse)
|
||||
{
|
||||
WorldPacket data(MSG_CORPSE_QUERY, 1);
|
||||
data << uint8(0); // corpse not found
|
||||
SendPacket(&data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 mapid = corpse->GetMapId();
|
||||
float x = corpse->GetPositionX();
|
||||
float y = corpse->GetPositionY();
|
||||
float z = corpse->GetPositionZ();
|
||||
uint32 corpsemapid = mapid;
|
||||
|
||||
// if corpse at different map
|
||||
if (mapid != _player->GetMapId())
|
||||
{
|
||||
// search entrance map for proper show entrance
|
||||
if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid))
|
||||
{
|
||||
if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0)
|
||||
{
|
||||
// if corpse map have entrance
|
||||
if (Map const* entranceMap = MapManager::Instance().CreateBaseMap(corpseMapEntry->entrance_map))
|
||||
{
|
||||
mapid = corpseMapEntry->entrance_map;
|
||||
x = corpseMapEntry->entrance_x;
|
||||
y = corpseMapEntry->entrance_y;
|
||||
z = entranceMap->GetHeight(x, y, MAX_HEIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4));
|
||||
data << uint8(1); // corpse found
|
||||
data << int32(mapid);
|
||||
data << float(x);
|
||||
data << float(y);
|
||||
data << float(z);
|
||||
data << int32(corpsemapid);
|
||||
data << uint32(0); // unknown
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleNpcTextQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 textID;
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> textID;
|
||||
sLog.outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID);
|
||||
|
||||
recv_data >> guid;
|
||||
GetPlayer()->SetUInt64Value(UNIT_FIELD_TARGET, guid);
|
||||
|
||||
GossipText const* pGossip = objmgr.GetGossipText(textID);
|
||||
|
||||
WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size
|
||||
data << textID;
|
||||
|
||||
if (!pGossip)
|
||||
{
|
||||
for (uint32 i = 0; i < 8; ++i)
|
||||
{
|
||||
data << float(0);
|
||||
data << "Greetings $N";
|
||||
data << "Greetings $N";
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
data << uint32(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string Text_0[8], Text_1[8];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
Text_0[i]=pGossip->Options[i].Text_0;
|
||||
Text_1[i]=pGossip->Options[i].Text_1;
|
||||
}
|
||||
|
||||
int loc_idx = GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);
|
||||
if (nl)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (nl->Text_0[i].size() > size_t(loc_idx) && !nl->Text_0[i][loc_idx].empty())
|
||||
Text_0[i]=nl->Text_0[i][loc_idx];
|
||||
if (nl->Text_1[i].size() > size_t(loc_idx) && !nl->Text_1[i][loc_idx].empty())
|
||||
Text_1[i]=nl->Text_1[i][loc_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
data << pGossip->Options[i].Probability;
|
||||
|
||||
if (Text_0[i].empty())
|
||||
data << Text_1[i];
|
||||
else
|
||||
data << Text_0[i];
|
||||
|
||||
if (Text_1[i].empty())
|
||||
data << Text_0[i];
|
||||
else
|
||||
data << Text_1[i];
|
||||
|
||||
data << pGossip->Options[i].Language;
|
||||
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
data << pGossip->Options[i].Emotes[j]._Delay;
|
||||
data << pGossip->Options[i].Emotes[j]._Emote;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_NPC_TEXT_UPDATE");
|
||||
}
|
||||
|
||||
void WorldSession::HandlePageTextQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY");
|
||||
recv_data.hexlike();
|
||||
|
||||
uint32 pageID;
|
||||
recv_data >> pageID;
|
||||
recv_data.read_skip<uint64>(); // guid
|
||||
|
||||
while (pageID)
|
||||
{
|
||||
PageText const *pPage = sPageTextStore.LookupEntry<PageText>(pageID);
|
||||
// guess size
|
||||
WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50);
|
||||
data << pageID;
|
||||
|
||||
if (!pPage)
|
||||
{
|
||||
data << "Item page missing.";
|
||||
data << uint32(0);
|
||||
pageID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string Text = pPage->Text;
|
||||
|
||||
int loc_idx = GetSessionDbLocaleIndex();
|
||||
if (loc_idx >= 0)
|
||||
{
|
||||
PageTextLocale const *pl = objmgr.GetPageTextLocale(pageID);
|
||||
if (pl)
|
||||
{
|
||||
if (pl->Text.size() > size_t(loc_idx) && !pl->Text[loc_idx].empty())
|
||||
Text = pl->Text[loc_idx];
|
||||
}
|
||||
}
|
||||
|
||||
data << Text;
|
||||
data << uint32(pPage->Next_Page);
|
||||
pageID = pPage->Next_Page;
|
||||
}
|
||||
SendPacket(&data);
|
||||
|
||||
sLog.outDebug("WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE");
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleCorpseMapPositionQuery(WorldPacket & recv_data)
|
||||
{
|
||||
sLog.outDebug("WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY");
|
||||
|
||||
uint32 unk;
|
||||
recv_data >> unk;
|
||||
|
||||
WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4);
|
||||
data << float(0);
|
||||
data << float(0);
|
||||
data << float(0);
|
||||
data << float(0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data)
|
||||
{
|
||||
uint32 count;
|
||||
recv_data >> count; // quest count, max=25
|
||||
|
||||
if (count >= MAX_QUEST_LOG_SIZE)
|
||||
return;
|
||||
|
||||
WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count);
|
||||
data << uint32(count); // count
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
uint32 questId;
|
||||
recv_data >> questId; // quest id
|
||||
|
||||
bool questOk = false;
|
||||
|
||||
uint16 questSlot = _player->FindQuestSlot(questId);
|
||||
|
||||
if (questSlot != MAX_QUEST_LOG_SIZE)
|
||||
questOk =_player->GetQuestSlotQuestId(questSlot) == questId;
|
||||
|
||||
if (questOk)
|
||||
{
|
||||
QuestPOIVector const *POI = objmgr.GetQuestPOIVector(questId);
|
||||
|
||||
if (POI)
|
||||
{
|
||||
data << uint32(questId); // quest ID
|
||||
data << uint32(POI->size()); // POI count
|
||||
|
||||
for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr)
|
||||
{
|
||||
data << uint32(itr->Id); // POI index
|
||||
data << int32(itr->ObjectiveIndex); // objective index
|
||||
data << uint32(itr->MapId); // mapid
|
||||
data << uint32(itr->AreaId); // areaid
|
||||
data << uint32(itr->Unk2); // unknown
|
||||
data << uint32(itr->Unk3); // unknown
|
||||
data << uint32(itr->Unk4); // unknown
|
||||
data << uint32(itr->points.size()); // POI points count
|
||||
|
||||
for (std::vector<QuestPOIPoint>::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2)
|
||||
{
|
||||
data << int32(itr2->x); // POI point x
|
||||
data << int32(itr2->y); // POI point y
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(questId); // quest ID
|
||||
data << uint32(0); // POI count
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(questId); // quest ID
|
||||
data << uint32(0); // POI count
|
||||
}
|
||||
}
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
@@ -1,721 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "Log.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "World.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "GossipDef.h"
|
||||
#include "QuestDef.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Group.h"
|
||||
#include "BattleGround.h"
|
||||
#include "BattleGroundAV.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
uint8 questStatus = DIALOG_STATUS_NONE;
|
||||
uint8 defstatus = DIALOG_STATUS_NONE;
|
||||
|
||||
Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
|
||||
if (!questgiver)
|
||||
{
|
||||
sLog.outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)",GuidHigh2TypeId(GUID_HIPART(guid)),GUID_LOPART(guid));
|
||||
return;
|
||||
}
|
||||
|
||||
switch(questgiver->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u",uint32(GUID_LOPART(guid)));
|
||||
Creature* cr_questgiver=questgiver->ToCreature();
|
||||
if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies
|
||||
{
|
||||
questStatus = sScriptMgr.NPCDialogStatus(_player, cr_questgiver);
|
||||
if (questStatus > 6)
|
||||
questStatus = getDialogStatus(_player, cr_questgiver, defstatus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u",uint32(GUID_LOPART(guid)));
|
||||
GameObject* go_questgiver=(GameObject*)questgiver;
|
||||
questStatus = sScriptMgr.GODialogStatus(_player, go_questgiver);
|
||||
if (questStatus > 6)
|
||||
questStatus = getDialogStatus(_player, go_questgiver, defstatus);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sLog.outError("QuestGiver called for unexpected type %u", questgiver->GetTypeId());
|
||||
break;
|
||||
}
|
||||
|
||||
//inform client about status of quest
|
||||
_player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
recv_data >> guid;
|
||||
|
||||
sLog.outDebug ("WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid));
|
||||
|
||||
Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid,UNIT_NPC_FLAG_NONE);
|
||||
if (!pCreature)
|
||||
{
|
||||
sLog.outDebug ("WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.",
|
||||
GUID_LOPART(guid));
|
||||
return;
|
||||
}
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
// Stop the npc if moving
|
||||
pCreature->StopMoving();
|
||||
|
||||
if (sScriptMgr.GossipHello(_player, pCreature))
|
||||
return;
|
||||
|
||||
_player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId, true);
|
||||
_player->SendPreparedGossip(pCreature);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
uint32 quest;
|
||||
uint32 unk1;
|
||||
recv_data >> guid >> quest >> unk1;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1);
|
||||
|
||||
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER);
|
||||
|
||||
// no or incorrect quest giver
|
||||
if (!pObject
|
||||
|| (pObject->GetTypeId() != TYPEID_PLAYER && !pObject->hasQuest(quest))
|
||||
|| (pObject->GetTypeId() == TYPEID_PLAYER && !pObject->ToPlayer()->CanShareQuest(quest))
|
||||
)
|
||||
{
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
_player->SetDivider(0);
|
||||
return;
|
||||
}
|
||||
|
||||
Quest const* qInfo = objmgr.GetQuestTemplate(quest);
|
||||
if (qInfo)
|
||||
{
|
||||
// prevent cheating
|
||||
if (!GetPlayer()->CanTakeQuest(qInfo,true))
|
||||
{
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
_player->SetDivider(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->GetDivider() != 0)
|
||||
{
|
||||
Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider());
|
||||
if (pPlayer)
|
||||
{
|
||||
pPlayer->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST);
|
||||
_player->SetDivider(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (_player->CanAddQuest(qInfo, true))
|
||||
{
|
||||
_player->AddQuest(qInfo, pObject);
|
||||
|
||||
if (qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT))
|
||||
{
|
||||
if (Group* pGroup = _player->GetGroup())
|
||||
{
|
||||
for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player* pPlayer = itr->getSource();
|
||||
|
||||
if (!pPlayer || pPlayer == _player) // not self
|
||||
continue;
|
||||
|
||||
if (pPlayer->CanTakeQuest(qInfo, true))
|
||||
{
|
||||
pPlayer->SetDivider(_player->GetGUID());
|
||||
|
||||
//need confirmation that any gossip window will close
|
||||
pPlayer->PlayerTalkClass->CloseGossip();
|
||||
|
||||
_player->SendQuestConfirmAccept(qInfo, pPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_player->CanCompleteQuest(quest))
|
||||
_player->CompleteQuest(quest);
|
||||
|
||||
switch(pObject->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
sScriptMgr.QuestAccept(_player, (pObject->ToCreature()), qInfo);
|
||||
break;
|
||||
case TYPEID_ITEM:
|
||||
case TYPEID_CONTAINER:
|
||||
{
|
||||
sScriptMgr.ItemQuestAccept(_player, ((Item*)pObject), qInfo);
|
||||
|
||||
// destroy not required for quest finish quest starting item
|
||||
bool destroyItem = true;
|
||||
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount > 0))
|
||||
{
|
||||
destroyItem = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (destroyItem)
|
||||
_player->DestroyItem(((Item*)pObject)->GetBagSlot(),((Item*)pObject)->GetSlot(),true);
|
||||
|
||||
break;
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
sScriptMgr.GOQuestAccept(_player, ((GameObject*)pObject), qInfo);
|
||||
break;
|
||||
}
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
|
||||
if (qInfo->GetSrcSpell() > 0)
|
||||
_player->CastSpell(_player, qInfo->GetSrcSpell(), true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
uint32 quest;
|
||||
uint8 unk1;
|
||||
recv_data >> guid >> quest >> unk1;
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1);
|
||||
|
||||
// Verify that the guid is valid and is a questgiver or involved in the requested quest
|
||||
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM);
|
||||
if (!pObject||!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest))
|
||||
{
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
return;
|
||||
}
|
||||
|
||||
Quest const* pQuest = objmgr.GetQuestTemplate(quest);
|
||||
if (pQuest)
|
||||
{
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_AUTO_ACCEPT) && _player->CanAddQuest(pQuest, true))
|
||||
{
|
||||
_player->AddQuest(pQuest, pObject);
|
||||
if (_player->CanCompleteQuest(quest))
|
||||
_player->CompleteQuest(quest);
|
||||
}
|
||||
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
|
||||
_player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, pObject->GetGUID(), _player->CanCompleteQuest(pQuest->GetQuestId()), true);
|
||||
else
|
||||
_player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 quest;
|
||||
recv_data >> quest;
|
||||
sLog.outDebug("WORLD: Received CMSG_QUEST_QUERY quest = %u",quest);
|
||||
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(quest);
|
||||
if (pQuest)
|
||||
{
|
||||
_player->PlayerTalkClass->SendQuestQueryResponse(pQuest);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 quest, reward;
|
||||
uint64 guid;
|
||||
recv_data >> guid >> quest >> reward;
|
||||
|
||||
if (reward >= QUEST_REWARD_CHOICES_COUNT)
|
||||
{
|
||||
sLog.outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName(), _player->GetGUIDLow(), reward);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u",uint32(GUID_LOPART(guid)),quest,reward);
|
||||
|
||||
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
|
||||
if (!pObject)
|
||||
return;
|
||||
|
||||
if (!pObject->hasInvolvedQuest(quest))
|
||||
return;
|
||||
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(quest);
|
||||
if (pQuest)
|
||||
{
|
||||
if (_player->CanRewardQuest(pQuest, reward, true))
|
||||
{
|
||||
_player->RewardQuest(pQuest, reward, pObject);
|
||||
|
||||
switch(pObject->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
if (!(sScriptMgr.ChooseReward(_player, (pObject->ToCreature()), pQuest, reward)))
|
||||
{
|
||||
// Send next quest
|
||||
if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest))
|
||||
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true);
|
||||
}
|
||||
break;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
if (!sScriptMgr.GOChooseReward(_player, ((GameObject*)pObject), pQuest, reward))
|
||||
{
|
||||
// Send next quest
|
||||
if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest))
|
||||
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextquest,guid,true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
_player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data)
|
||||
{
|
||||
uint32 quest;
|
||||
uint64 guid;
|
||||
recv_data >> guid >> quest;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest);
|
||||
|
||||
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid,TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
|
||||
if (!pObject||!pObject->hasInvolvedQuest(quest))
|
||||
return;
|
||||
|
||||
if (_player->CanCompleteQuest(quest))
|
||||
_player->CompleteQuest(quest);
|
||||
|
||||
if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE)
|
||||
return;
|
||||
|
||||
if (Quest const *pQuest = objmgr.GetQuestTemplate(quest))
|
||||
_player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_CANCEL");
|
||||
|
||||
_player->PlayerTalkClass->CloseGossip();
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestLogSwapQuest(WorldPacket& recv_data)
|
||||
{
|
||||
uint8 slot1, slot2;
|
||||
recv_data >> slot1 >> slot2;
|
||||
|
||||
if (slot1 == slot2 || slot1 >= MAX_QUEST_LOG_SIZE || slot2 >= MAX_QUEST_LOG_SIZE)
|
||||
return;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1, slot2);
|
||||
|
||||
GetPlayer()->SwapQuestSlot(slot1,slot2);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data)
|
||||
{
|
||||
uint8 slot;
|
||||
recv_data >> slot;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u",slot);
|
||||
|
||||
if (slot < MAX_QUEST_LOG_SIZE)
|
||||
{
|
||||
if (uint32 quest = _player->GetQuestSlotQuestId(slot))
|
||||
{
|
||||
if (!_player->TakeQuestSourceItem(quest, true))
|
||||
return; // can't un-equip some items, reject quest cancel
|
||||
|
||||
if (const Quest *pQuest = objmgr.GetQuestTemplate(quest))
|
||||
{
|
||||
if (pQuest->HasFlag(QUEST_TRINITY_FLAGS_TIMED))
|
||||
_player->RemoveTimedQuest(quest);
|
||||
}
|
||||
|
||||
_player->TakeQuestSourceItem(quest, true); // remove quest src item from player
|
||||
_player->SetQuestStatus(quest, QUEST_STATUS_NONE);
|
||||
_player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest);
|
||||
}
|
||||
|
||||
_player->SetQuestSlot(slot, 0);
|
||||
|
||||
_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data)
|
||||
{
|
||||
uint32 quest;
|
||||
recv_data >> quest;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest);
|
||||
|
||||
if (const Quest* pQuest = objmgr.GetQuestTemplate(quest))
|
||||
{
|
||||
if (!pQuest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT))
|
||||
return;
|
||||
|
||||
Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider());
|
||||
|
||||
if (!pOriginalPlayer)
|
||||
return;
|
||||
|
||||
if (pQuest->GetType() == QUEST_TYPE_RAID)
|
||||
{
|
||||
if (!_player->IsInSameRaidWith(pOriginalPlayer))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_player->IsInSameGroupWith(pOriginalPlayer))
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->CanAddQuest(pQuest, true))
|
||||
_player->AddQuest(pQuest, NULL); // NULL, this prevent DB script from duplicate running
|
||||
|
||||
_player->SetDivider(0);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data)
|
||||
{
|
||||
uint32 quest;
|
||||
uint64 guid;
|
||||
recv_data >> guid >> quest;
|
||||
|
||||
if (!GetPlayer()->isAlive())
|
||||
return;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u",uint32(GUID_LOPART(guid)),quest);
|
||||
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(quest);
|
||||
if (pQuest)
|
||||
{
|
||||
// TODO: need a virtual function
|
||||
if (GetPlayer()->InBattleGround())
|
||||
if (BattleGround* bg = GetPlayer()->GetBattleGround())
|
||||
if (bg->GetTypeID() == BATTLEGROUND_AV)
|
||||
((BattleGroundAV*)bg)->HandleQuestComplete(quest, GetPlayer());
|
||||
|
||||
if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE)
|
||||
{
|
||||
if (pQuest->IsRepeatable())
|
||||
_player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanCompleteRepeatableQuest(pQuest), false);
|
||||
else
|
||||
_player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pQuest->GetReqItemsCount()) // some items required
|
||||
_player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest,false), false);
|
||||
else // no items required
|
||||
_player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH");
|
||||
}
|
||||
|
||||
void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket)
|
||||
{
|
||||
uint32 questId;
|
||||
recvPacket >> questId;
|
||||
|
||||
sLog.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId);
|
||||
|
||||
if (Quest const *pQuest = objmgr.GetQuestTemplate(questId))
|
||||
{
|
||||
if (Group* pGroup = _player->GetGroup())
|
||||
{
|
||||
for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player *pPlayer = itr->getSource();
|
||||
|
||||
if (!pPlayer || pPlayer == _player) // skip self
|
||||
continue;
|
||||
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST);
|
||||
|
||||
if (!pPlayer->SatisfyQuestStatus(pQuest, false))
|
||||
{
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_HAVE_QUEST);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pPlayer->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
|
||||
{
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_FINISH_QUEST);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pPlayer->CanTakeQuest(pQuest, false))
|
||||
{
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pPlayer->SatisfyQuestLog(false))
|
||||
{
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_LOG_FULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pPlayer->GetDivider() != 0)
|
||||
{
|
||||
_player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_BUSY);
|
||||
continue;
|
||||
}
|
||||
|
||||
pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true);
|
||||
pPlayer->SetDivider(_player->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket)
|
||||
{
|
||||
uint64 guid;
|
||||
uint8 msg;
|
||||
recvPacket >> guid >> msg;
|
||||
|
||||
sLog.outDebug("WORLD: Received MSG_QUEST_PUSH_RESULT");
|
||||
|
||||
if (_player->GetDivider() != 0)
|
||||
{
|
||||
Player *pPlayer = ObjectAccessor::FindPlayer(_player->GetDivider());
|
||||
if (pPlayer)
|
||||
{
|
||||
WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1));
|
||||
data << uint64(guid);
|
||||
data << uint8(msg); // valid values: 0-8
|
||||
pPlayer->GetSession()->SendPacket(&data);
|
||||
_player->SetDivider(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 WorldSession::getDialogStatus(Player *pPlayer, Object* questgiver, uint32 defstatus)
|
||||
{
|
||||
uint32 result = defstatus;
|
||||
|
||||
QuestRelations const* qir;
|
||||
QuestRelations const* qr;
|
||||
|
||||
switch(questgiver->GetTypeId())
|
||||
{
|
||||
case TYPEID_GAMEOBJECT:
|
||||
{
|
||||
qir = &objmgr.mGOQuestInvolvedRelations;
|
||||
qr = &objmgr.mGOQuestRelations;
|
||||
break;
|
||||
}
|
||||
case TYPEID_UNIT:
|
||||
{
|
||||
qir = &objmgr.mCreatureQuestInvolvedRelations;
|
||||
qr = &objmgr.mCreatureQuestRelations;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//its imposible, but check ^)
|
||||
sLog.outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId());
|
||||
return DIALOG_STATUS_NONE;
|
||||
}
|
||||
|
||||
for (QuestRelations::const_iterator i = qir->lower_bound(questgiver->GetEntry()); i != qir->upper_bound(questgiver->GetEntry()); ++i)
|
||||
{
|
||||
uint32 result2 = 0;
|
||||
uint32 quest_id = i->second;
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(quest_id);
|
||||
if (!pQuest) continue;
|
||||
|
||||
QuestStatus status = pPlayer->GetQuestStatus(quest_id);
|
||||
if ((status == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(quest_id)) ||
|
||||
(pQuest->IsAutoComplete() && pPlayer->CanTakeQuest(pQuest, false)))
|
||||
{
|
||||
if (pQuest->IsAutoComplete() && pQuest->IsRepeatable())
|
||||
result2 = DIALOG_STATUS_REWARD_REP;
|
||||
else
|
||||
result2 = DIALOG_STATUS_REWARD;
|
||||
}
|
||||
else if (status == QUEST_STATUS_INCOMPLETE)
|
||||
result2 = DIALOG_STATUS_INCOMPLETE;
|
||||
|
||||
if (result2 > result)
|
||||
result = result2;
|
||||
}
|
||||
|
||||
for (QuestRelations::const_iterator i = qr->lower_bound(questgiver->GetEntry()); i != qr->upper_bound(questgiver->GetEntry()); ++i)
|
||||
{
|
||||
uint32 result2 = 0;
|
||||
uint32 quest_id = i->second;
|
||||
Quest const *pQuest = objmgr.GetQuestTemplate(quest_id);
|
||||
if (!pQuest)
|
||||
continue;
|
||||
|
||||
QuestStatus status = pPlayer->GetQuestStatus(quest_id);
|
||||
if (status == QUEST_STATUS_NONE)
|
||||
{
|
||||
if (pPlayer->CanSeeStartQuest(pQuest))
|
||||
{
|
||||
if (pPlayer->SatisfyQuestLevel(pQuest, false))
|
||||
{
|
||||
if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded))
|
||||
result2 = DIALOG_STATUS_REWARD_REP;
|
||||
else if (pPlayer->getLevel() <= ((pPlayer->GetQuestLevel(pQuest) == -1) ? pPlayer->getLevel() : pPlayer->GetQuestLevel(pQuest) + sWorld.getConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF)))
|
||||
{
|
||||
if (pQuest->HasFlag(QUEST_FLAGS_DAILY) || pQuest->HasFlag(QUEST_FLAGS_WEEKLY))
|
||||
result2 = DIALOG_STATUS_AVAILABLE_REP;
|
||||
else
|
||||
result2 = DIALOG_STATUS_AVAILABLE;
|
||||
}
|
||||
else
|
||||
result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE;
|
||||
}
|
||||
else
|
||||
result2 = DIALOG_STATUS_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (result2 > result)
|
||||
result = result2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/)
|
||||
{
|
||||
sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY");
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
|
||||
data << uint32(count); // placeholder
|
||||
|
||||
for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr)
|
||||
{
|
||||
uint8 questStatus = DIALOG_STATUS_NONE;
|
||||
uint8 defstatus = DIALOG_STATUS_NONE;
|
||||
|
||||
if (IS_CRE_OR_VEH_OR_PET_GUID(*itr))
|
||||
{
|
||||
// need also pet quests case support
|
||||
Creature *questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(),*itr);
|
||||
if (!questgiver || questgiver->IsHostileTo(_player))
|
||||
continue;
|
||||
if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER))
|
||||
continue;
|
||||
questStatus = sScriptMgr.NPCDialogStatus(_player, questgiver);
|
||||
if (questStatus > 6)
|
||||
questStatus = getDialogStatus(_player, questgiver, defstatus);
|
||||
|
||||
data << uint64(questgiver->GetGUID());
|
||||
data << uint8(questStatus);
|
||||
++count;
|
||||
}
|
||||
else if (IS_GAMEOBJECT_GUID(*itr))
|
||||
{
|
||||
GameObject *questgiver = GetPlayer()->GetMap()->GetGameObject(*itr);
|
||||
if (!questgiver)
|
||||
continue;
|
||||
if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
|
||||
continue;
|
||||
questStatus = sScriptMgr.GODialogStatus(_player, questgiver);
|
||||
if (questStatus > 6)
|
||||
questStatus = getDialogStatus(_player, questgiver, defstatus);
|
||||
|
||||
data << uint64(questgiver->GetGUID());
|
||||
data << uint8(questStatus);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
data.put<uint32>(0, count); // write real count
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
uint32 count = 0;
|
||||
|
||||
WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4+4*count);
|
||||
data << uint32(count);
|
||||
|
||||
for (QuestStatusMap::const_iterator itr = _player->getQuestStatusMap().begin(); itr != _player->getQuestStatusMap().end(); ++itr)
|
||||
{
|
||||
if (itr->second.m_rewarded)
|
||||
{
|
||||
data << uint32(itr->first);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
data.put<uint32>(0, count);
|
||||
SendPacket(&data);
|
||||
}
|
||||
Reference in New Issue
Block a user