diff options
| author | Rat <none@none> | 2010-06-05 23:40:08 +0200 |
|---|---|---|
| committer | Rat <none@none> | 2010-06-05 23:40:08 +0200 |
| commit | 75b80d9f5b02a643c983b2fb1ededed79fd5d133 (patch) | |
| tree | ebd1c2cc12a2715909dd04c1ed147a260c6ceb14 /src/server/game/Quests | |
| parent | 6a9357b13d7ea6bd7d77dbfc6587af9028caa401 (diff) | |
rearranged core files
--HG--
branch : trunk
Diffstat (limited to 'src/server/game/Quests')
| -rw-r--r-- | src/server/game/Quests/QueryHandler.cpp | 539 | ||||
| -rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 206 | ||||
| -rw-r--r-- | src/server/game/Quests/QuestDef.h | 372 | ||||
| -rw-r--r-- | src/server/game/Quests/QuestHandler.cpp | 721 |
4 files changed, 1838 insertions, 0 deletions
diff --git a/src/server/game/Quests/QueryHandler.cpp b/src/server/game/Quests/QueryHandler.cpp new file mode 100644 index 00000000000..1067ad49bc4 --- /dev/null +++ b/src/server/game/Quests/QueryHandler.cpp @@ -0,0 +1,539 @@ +/* + * 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); +}
\ No newline at end of file diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp new file mode 100644 index 00000000000..2fdd1c58e9b --- /dev/null +++ b/src/server/game/Quests/QuestDef.cpp @@ -0,0 +1,206 @@ +/* + * 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 "QuestDef.h" +#include "Player.h" +#include "World.h" + +Quest::Quest(Field * questRecord) +{ + QuestId = questRecord[0].GetUInt32(); + QuestMethod = questRecord[1].GetUInt32(); + ZoneOrSort = questRecord[2].GetInt32(); + SkillOrClassMask = questRecord[3].GetInt32(); + MinLevel = questRecord[4].GetUInt32(); + MaxLevel = questRecord[5].GetUInt32(); + QuestLevel = questRecord[6].GetInt32(); + Type = questRecord[7].GetUInt32(); + RequiredRaces = questRecord[8].GetUInt32(); + RequiredSkillValue = questRecord[9].GetUInt32(); + RepObjectiveFaction = questRecord[10].GetUInt32(); + RepObjectiveValue = questRecord[11].GetInt32(); + RepObjectiveFaction2 = questRecord[12].GetUInt32(); + RepObjectiveValue2 = questRecord[13].GetInt32(); + RequiredMinRepFaction = questRecord[14].GetUInt32(); + RequiredMinRepValue = questRecord[15].GetInt32(); + RequiredMaxRepFaction = questRecord[16].GetUInt32(); + RequiredMaxRepValue = questRecord[17].GetInt32(); + SuggestedPlayers = questRecord[18].GetUInt32(); + LimitTime = questRecord[19].GetUInt32(); + QuestFlags = questRecord[20].GetUInt32(); + uint32 SpecialFlags = questRecord[21].GetUInt16(); + CharTitleId = questRecord[22].GetUInt32(); + PlayersSlain = questRecord[23].GetUInt32(); + BonusTalents = questRecord[24].GetUInt32(); + RewArenaPoints = questRecord[25].GetInt32(); + PrevQuestId = questRecord[26].GetInt32(); + NextQuestId = questRecord[27].GetInt32(); + ExclusiveGroup = questRecord[28].GetInt32(); + NextQuestInChain = questRecord[29].GetUInt32(); + XPId = questRecord[30].GetUInt32(); + SrcItemId = questRecord[31].GetUInt32(); + SrcItemCount = questRecord[32].GetUInt32(); + SrcSpell = questRecord[33].GetUInt32(); + Title = questRecord[34].GetCppString(); + Details = questRecord[35].GetCppString(); + Objectives = questRecord[36].GetCppString(); + OfferRewardText = questRecord[37].GetCppString(); + RequestItemsText = questRecord[38].GetCppString(); + EndText = questRecord[39].GetCppString(); + CompletedText = questRecord[40].GetCppString(); + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + ObjectiveText[i] = questRecord[41+i].GetCppString(); + + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + ReqItemId[i] = questRecord[45+i].GetUInt32(); + + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + ReqItemCount[i] = questRecord[51+i].GetUInt32(); + + for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) + ReqSourceId[i] = questRecord[57+i].GetUInt32(); + + for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) + ReqSourceCount[i] = questRecord[61+i].GetUInt32(); + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + ReqCreatureOrGOId[i] = questRecord[65+i].GetInt32(); + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + ReqCreatureOrGOCount[i] = questRecord[69+i].GetUInt32(); + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + ReqSpell[i] = questRecord[73+i].GetUInt32(); + + for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + RewChoiceItemId[i] = questRecord[77+i].GetUInt32(); + + for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + RewChoiceItemCount[i] = questRecord[83+i].GetUInt32(); + + for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) + RewItemId[i] = questRecord[89+i].GetUInt32(); + + for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) + RewItemCount[i] = questRecord[93+i].GetUInt32(); + + for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + RewRepFaction[i] = questRecord[97+i].GetUInt32(); + + for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + RewRepValueId[i] = questRecord[102+i].GetInt32(); + + for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + RewRepValue[i] = questRecord[107+i].GetInt32(); + + RewHonorableKills = questRecord[112].GetUInt32(); + RewHonorMultiplier = questRecord[113].GetFloat(); + RewOrReqMoney = questRecord[114].GetInt32(); + RewMoneyMaxLevel = questRecord[115].GetUInt32(); + RewSpell = questRecord[116].GetUInt32(); + RewSpellCast = questRecord[117].GetInt32(); + RewMailTemplateId = questRecord[118].GetUInt32(); + RewMailDelaySecs = questRecord[119].GetUInt32(); + PointMapId = questRecord[120].GetUInt32(); + PointX = questRecord[121].GetFloat(); + PointY = questRecord[122].GetFloat(); + PointOpt = questRecord[123].GetUInt32(); + + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + DetailsEmote[i] = questRecord[124+i].GetUInt32(); + + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + DetailsEmoteDelay[i] = questRecord[128+i].GetUInt32(); + + IncompleteEmote = questRecord[132].GetUInt32(); + CompleteEmote = questRecord[133].GetUInt32(); + + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + OfferRewardEmote[i] = questRecord[134+i].GetInt32(); + + for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) + OfferRewardEmoteDelay[i] = questRecord[138+i].GetInt32(); + + QuestStartScript = questRecord[142].GetUInt32(); + QuestCompleteScript = questRecord[143].GetUInt32(); + + QuestFlags |= SpecialFlags << 20; + + m_reqitemscount = 0; + m_reqCreatureOrGOcount = 0; + m_rewitemscount = 0; + m_rewchoiceitemscount = 0; + + for (int i=0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + if (ReqItemId[i]) + ++m_reqitemscount; + + for (int i=0; i < QUEST_OBJECTIVES_COUNT; ++i) + if (ReqCreatureOrGOId[i]) + ++m_reqCreatureOrGOcount; + + for (int i=0; i < QUEST_REWARDS_COUNT; ++i) + if (RewItemId[i]) + ++m_rewitemscount; + + for (int i=0; i < QUEST_REWARD_CHOICES_COUNT; ++i) + if (RewChoiceItemId[i]) + ++m_rewchoiceitemscount; +} + +uint32 Quest::XPValue(Player *pPlayer) const +{ + if (pPlayer) + { + int32 quest_level = (QuestLevel == -1 ? pPlayer->getLevel() : QuestLevel); + const QuestXPEntry *xpentry = sQuestXPStore.LookupEntry(quest_level); + if (!xpentry) + return 0; + + int diffFactor = 2 * (quest_level - pPlayer->getLevel()) + 20; + if (diffFactor < 1) + diffFactor = 1; + else if (diffFactor > 10) + diffFactor = 10; + + uint32 xp = diffFactor * xpentry->Exp[XPId] / 10; + if (xp <= 100) + xp = 5 * ((xp + 2) / 5); + else if (xp <= 500) + xp = 10 * ((xp + 5) / 10); + else if (xp <= 1000) + xp = 25 * ((xp + 12) / 25); + else + xp = 50 * ((xp + 25) / 50); + + return xp; + } + + return 0; +} + +int32 Quest::GetRewOrReqMoney() const +{ + if (RewOrReqMoney <= 0) + return RewOrReqMoney; + + return int32(RewOrReqMoney * sWorld.getRate(RATE_DROP_MONEY)); +} diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h new file mode 100644 index 00000000000..20d4ca3d28d --- /dev/null +++ b/src/server/game/Quests/QuestDef.h @@ -0,0 +1,372 @@ +/* + * 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 + */ + +#ifndef TRINITYCORE_QUEST_H +#define TRINITYCORE_QUEST_H + +#include "Platform/Define.h" +#include "Database/DatabaseEnv.h" + +#include <string> +#include <vector> + +class Player; + +class ObjectMgr; + +#define MAX_QUEST_LOG_SIZE 25 + +#define QUEST_OBJECTIVES_COUNT 4 +#define QUEST_ITEM_OBJECTIVES_COUNT 6 +#define QUEST_SOURCE_ITEM_IDS_COUNT 4 +#define QUEST_REWARD_CHOICES_COUNT 6 +#define QUEST_REWARDS_COUNT 4 +#define QUEST_DEPLINK_COUNT 10 +#define QUEST_REPUTATIONS_COUNT 5 +#define QUEST_EMOTE_COUNT 4 + +enum QuestFailedReasons +{ + INVALIDREASON_DONT_HAVE_REQ = 0, + INVALIDREASON_QUEST_FAILED_LOW_LEVEL = 1, // You are not high enough level for that quest. + INVALIDREASON_QUEST_FAILED_WRONG_RACE = 6, // That quest is not available to your race. + INVALIDREASON_QUEST_ALREADY_DONE = 7, // You have completed that quest. + INVALIDREASON_QUEST_ONLY_ONE_TIMED = 12, // You can only be on one timed quest at a time. + INVALIDREASON_QUEST_ALREADY_ON = 13, // You are already on that quest. + INVALIDREASON_QUEST_FAILED_EXPANSION = 16, // This quest requires an expansion enabled account. + INVALIDREASON_QUEST_ALREADY_ON2 = 18, // You are already on that quest. + INVALIDREASON_QUEST_FAILED_MISSING_ITEMS = 21, // You don't have the required items with you. Check storage. + INVALIDREASON_QUEST_FAILED_NOT_ENOUGH_MONEY = 23, // You don't have enough money for that quest. + INVALIDREASON_DAILY_QUESTS_REMAINING = 26, // You have already completed 25 daily quests today. + INVALIDREASON_QUEST_FAILED_CAIS = 27, // You cannot complete quests once you have reached tired time. + INVALIDREASON_DAILY_QUEST_COMPLETED_TODAY = 29 // You have completed that daily quest today. +}; + +enum QuestShareMessages +{ + QUEST_PARTY_MSG_SHARING_QUEST = 0, + QUEST_PARTY_MSG_CANT_TAKE_QUEST = 1, + QUEST_PARTY_MSG_ACCEPT_QUEST = 2, + QUEST_PARTY_MSG_DECLINE_QUEST = 3, + QUEST_PARTY_MSG_BUSY = 4, + QUEST_PARTY_MSG_LOG_FULL = 5, + QUEST_PARTY_MSG_HAVE_QUEST = 6, + QUEST_PARTY_MSG_FINISH_QUEST = 7, + QUEST_PARTY_MSG_CANT_BE_SHARED_TODAY = 8, + QUEST_PARTY_MSG_SHARING_TIMER_EXPIRED = 9, + QUEST_PARTY_MSG_NOT_IN_PARTY = 10 +}; + +enum __QuestTradeSkill +{ + QUEST_TRSKILL_NONE = 0, + QUEST_TRSKILL_ALCHEMY = 1, + QUEST_TRSKILL_BLACKSMITHING = 2, + QUEST_TRSKILL_COOKING = 3, + QUEST_TRSKILL_ENCHANTING = 4, + QUEST_TRSKILL_ENGINEERING = 5, + QUEST_TRSKILL_FIRSTAID = 6, + QUEST_TRSKILL_HERBALISM = 7, + QUEST_TRSKILL_LEATHERWORKING = 8, + QUEST_TRSKILL_POISONS = 9, + QUEST_TRSKILL_TAILORING = 10, + QUEST_TRSKILL_MINING = 11, + QUEST_TRSKILL_FISHING = 12, + QUEST_TRSKILL_SKINNING = 13, + QUEST_TRSKILL_JEWELCRAFTING = 14, +}; + +enum QuestStatus +{ + QUEST_STATUS_NONE = 0, + QUEST_STATUS_COMPLETE = 1, + //QUEST_STATUS_UNAVAILABLE = 2, + QUEST_STATUS_INCOMPLETE = 3, + //QUEST_STATUS_AVAILABLE = 4, + QUEST_STATUS_FAILED = 5, + MAX_QUEST_STATUS +}; + +enum __QuestGiverStatus +{ + DIALOG_STATUS_NONE = 0, + DIALOG_STATUS_UNAVAILABLE = 1, + DIALOG_STATUS_LOW_LEVEL_AVAILABLE = 2, + DIALOG_STATUS_LOW_LEVEL_REWARD_REP = 3, + DIALOG_STATUS_LOW_LEVEL_AVAILABLE_REP = 4, + DIALOG_STATUS_INCOMPLETE = 5, + DIALOG_STATUS_REWARD_REP = 6, + DIALOG_STATUS_AVAILABLE_REP = 7, + DIALOG_STATUS_AVAILABLE = 8, + DIALOG_STATUS_REWARD2 = 9, // no yellow dot on minimap + DIALOG_STATUS_REWARD = 10 // yellow dot on minimap +}; + +enum __QuestFlags +{ + // Flags used at server and sent to client + QUEST_FLAGS_NONE = 0x00000000, + QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently + QUEST_FLAGS_PARTY_ACCEPT = 0x00000002, // Not used currently. If player in party, all players that can accept this quest will receive confirmation box to accept quest CMSG_QUEST_CONFIRM_ACCEPT/SMSG_QUEST_CONFIRM_ACCEPT + QUEST_FLAGS_EXPLORATION = 0x00000004, // Not used currently + QUEST_FLAGS_SHARABLE = 0x00000008, // Can be shared: Player::CanShareQuest() + //QUEST_FLAGS_NONE2 = 0x00000010, // Not used currently + QUEST_FLAGS_EPIC = 0x00000020, // Not used currently: Unsure of content + QUEST_FLAGS_RAID = 0x00000040, // Not used currently + QUEST_FLAGS_TBC = 0x00000080, // Not used currently: Available if TBC expansion enabled only + QUEST_FLAGS_UNK2 = 0x00000100, // Not used currently: _DELIVER_MORE Quest needs more than normal _q-item_ drops from mobs + QUEST_FLAGS_HIDDEN_REWARDS = 0x00000200, // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUESTGIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE)) + QUEST_FLAGS_AUTO_REWARDED = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. + QUEST_FLAGS_TBC_RACES = 0x00000800, // Not used currently: Blood elf/Draenei starting zone quests + QUEST_FLAGS_DAILY = 0x00001000, // Used to know quest is Daily one + QUEST_FLAGS_WEEKLY = 0x00008000, + QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // auto complete + QUEST_FLAGS_UNK5 = 0x00020000, // has something to do with ReqItemId and SrcItemId + QUEST_FLAGS_UNK6 = 0x00040000, // use Objective text as Complete text + QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // quests in starting areas + + // Trinity flags for set SpecialFlags in DB if required but used only at server + QUEST_TRINITY_FLAGS_REPEATABLE = 0x00100000, // Set by 1 in SpecialFlags from DB + QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT = 0x00200000, // Set by 2 in SpecialFlags from DB (if reequired area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script) + QUEST_TRINITY_FLAGS_DB_ALLOWED = 0xFFFFF | QUEST_TRINITY_FLAGS_REPEATABLE | QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT, + + // Trinity flags for internal use only + QUEST_TRINITY_FLAGS_DELIVER = 0x04000000, // Internal flag computed only + QUEST_TRINITY_FLAGS_SPEAKTO = 0x08000000, // Internal flag computed only + QUEST_TRINITY_FLAGS_KILL_OR_CAST = 0x10000000, // Internal flag computed only + QUEST_TRINITY_FLAGS_TIMED = 0x20000000, // Internal flag computed only +}; + +struct QuestLocale +{ + QuestLocale() { ObjectiveText.resize(QUEST_OBJECTIVES_COUNT); } + + std::vector<std::string> Title; + std::vector<std::string> Details; + std::vector<std::string> Objectives; + std::vector<std::string> OfferRewardText; + std::vector<std::string> RequestItemsText; + std::vector<std::string> EndText; + std::vector<std::string> CompletedText; + std::vector< std::vector<std::string> > ObjectiveText; +}; + +// This Quest class provides a convenient way to access a few pretotaled (cached) quest details, +// all base quest information, and any utility functions such as generating the amount of +// xp to give +class Quest +{ + friend class ObjectMgr; + public: + Quest(Field * questRecord); + uint32 XPValue(Player *pPlayer) const; + + bool HasFlag(uint32 flag) const { return (QuestFlags & flag) != 0; } + void SetFlag(uint32 flag) { QuestFlags |= flag; } + + // table data accessors: + uint32 GetQuestId() const { return QuestId; } + uint32 GetQuestMethod() const { return QuestMethod; } + int32 GetZoneOrSort() const { return ZoneOrSort; } + int32 GetSkillOrClassMask() const { return SkillOrClassMask; } + uint32 GetMinLevel() const { return MinLevel; } + uint32 GetMaxLevel() const { return MaxLevel; } + uint32 GetQuestLevel() const { return QuestLevel; } + uint32 GetType() const { return Type; } + uint32 GetRequiredRaces() const { return RequiredRaces; } + uint32 GetRequiredSkillValue() const { return RequiredSkillValue; } + uint32 GetRepObjectiveFaction() const { return RepObjectiveFaction; } + int32 GetRepObjectiveValue() const { return RepObjectiveValue; } + uint32 GetRepObjectiveFaction2() const { return RepObjectiveFaction2; } + int32 GetRepObjectiveValue2() const { return RepObjectiveValue2; } + uint32 GetRequiredMinRepFaction() const { return RequiredMinRepFaction; } + int32 GetRequiredMinRepValue() const { return RequiredMinRepValue; } + uint32 GetRequiredMaxRepFaction() const { return RequiredMaxRepFaction; } + int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; } + uint32 GetSuggestedPlayers() const { return SuggestedPlayers; } + uint32 GetLimitTime() const { return LimitTime; } + int32 GetPrevQuestId() const { return PrevQuestId; } + int32 GetNextQuestId() const { return NextQuestId; } + int32 GetExclusiveGroup() const { return ExclusiveGroup; } + uint32 GetNextQuestInChain() const { return NextQuestInChain; } + uint32 GetCharTitleId() const { return CharTitleId; } + uint32 GetPlayersSlain() const { return PlayersSlain; } + uint32 GetBonusTalents() const { return BonusTalents; } + int32 GetRewArenaPoints() const {return RewArenaPoints; } + uint32 GetXPId() const { return XPId; } + uint32 GetSrcItemId() const { return SrcItemId; } + uint32 GetSrcItemCount() const { return SrcItemCount; } + uint32 GetSrcSpell() const { return SrcSpell; } + std::string GetTitle() const { return Title; } + std::string GetDetails() const { return Details; } + std::string GetObjectives() const { return Objectives; } + std::string GetOfferRewardText() const { return OfferRewardText; } + std::string GetRequestItemsText() const { return RequestItemsText; } + std::string GetEndText() const { return EndText; } + std::string GetCompletedText() const { return CompletedText; } + int32 GetRewOrReqMoney() const; + uint32 GetRewHonorableKills() const { return RewHonorableKills; } + uint32 GetRewMoneyMaxLevel() const { return RewMoneyMaxLevel; } + // use in XP calculation at client + uint32 GetRewSpell() const { return RewSpell; } + int32 GetRewSpellCast() const { return RewSpellCast; } + uint32 GetRewMailTemplateId() const { return RewMailTemplateId; } + uint32 GetRewMailDelaySecs() const { return RewMailDelaySecs; } + uint32 GetPointMapId() const { return PointMapId; } + float GetPointX() const { return PointX; } + float GetPointY() const { return PointY; } + uint32 GetPointOpt() const { return PointOpt; } + uint32 GetIncompleteEmote() const { return IncompleteEmote; } + uint32 GetCompleteEmote() const { return CompleteEmote; } + uint32 GetQuestStartScript() const { return QuestStartScript; } + uint32 GetQuestCompleteScript() const { return QuestCompleteScript; } + bool IsRepeatable() const { return QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE; } + bool IsAutoComplete() const { return QuestMethod ? false : true; } + uint32 GetFlags() const { return QuestFlags; } + bool IsDaily() const { return QuestFlags & QUEST_FLAGS_DAILY; } + bool IsWeekly() const { return QuestFlags & QUEST_FLAGS_WEEKLY; } + bool IsDailyOrWeekly() const { return QuestFlags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); } + bool IsAutoAccept() const { return QuestFlags & QUEST_FLAGS_AUTO_ACCEPT; } + + // multiple values + std::string ObjectiveText[QUEST_OBJECTIVES_COUNT]; + uint32 ReqItemId[QUEST_ITEM_OBJECTIVES_COUNT]; + uint32 ReqItemCount[QUEST_ITEM_OBJECTIVES_COUNT]; + uint32 ReqSourceId[QUEST_SOURCE_ITEM_IDS_COUNT]; + uint32 ReqSourceCount[QUEST_SOURCE_ITEM_IDS_COUNT]; + int32 ReqCreatureOrGOId[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject + uint32 ReqCreatureOrGOCount[QUEST_OBJECTIVES_COUNT]; + uint32 ReqSpell[QUEST_OBJECTIVES_COUNT]; + uint32 RewChoiceItemId[QUEST_REWARD_CHOICES_COUNT]; + uint32 RewChoiceItemCount[QUEST_REWARD_CHOICES_COUNT]; + uint32 RewItemId[QUEST_REWARDS_COUNT]; + uint32 RewItemCount[QUEST_REWARDS_COUNT]; + uint32 RewRepFaction[QUEST_REPUTATIONS_COUNT]; + int32 RewRepValueId[QUEST_REPUTATIONS_COUNT]; + int32 RewRepValue[QUEST_REPUTATIONS_COUNT]; + uint32 DetailsEmote[QUEST_EMOTE_COUNT]; + uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT]; + uint32 OfferRewardEmote[QUEST_EMOTE_COUNT]; + uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT]; + + uint32 GetReqItemsCount() const { return m_reqitemscount; } + uint32 GetReqCreatureOrGOcount() const { return m_reqCreatureOrGOcount; } + uint32 GetRewChoiceItemsCount() const { return m_rewchoiceitemscount; } + uint32 GetRewItemsCount() const { return m_rewitemscount; } + + typedef std::vector<int32> PrevQuests; + PrevQuests prevQuests; + typedef std::vector<uint32> PrevChainQuests; + PrevChainQuests prevChainQuests; + + // cached data + private: + uint32 m_reqitemscount; + uint32 m_reqCreatureOrGOcount; + uint32 m_rewchoiceitemscount; + uint32 m_rewitemscount; + + // table data + protected: + uint32 QuestId; + uint32 QuestMethod; + int32 ZoneOrSort; + int32 SkillOrClassMask; + uint32 MinLevel; + uint32 MaxLevel; + int32 QuestLevel; + uint32 Type; + uint32 RequiredRaces; + uint32 RequiredSkillValue; + uint32 RepObjectiveFaction; + int32 RepObjectiveValue; + uint32 RepObjectiveFaction2; + int32 RepObjectiveValue2; + uint32 RequiredMinRepFaction; + int32 RequiredMinRepValue; + uint32 RequiredMaxRepFaction; + int32 RequiredMaxRepValue; + uint32 SuggestedPlayers; + uint32 LimitTime; + uint32 QuestFlags; + uint32 CharTitleId; + uint32 PlayersSlain; + uint32 BonusTalents; + int32 RewArenaPoints; + int32 PrevQuestId; + int32 NextQuestId; + int32 ExclusiveGroup; + uint32 NextQuestInChain; + uint32 XPId; + uint32 SrcItemId; + uint32 SrcItemCount; + uint32 SrcSpell; + std::string Title; + std::string Details; + std::string Objectives; + std::string OfferRewardText; + std::string RequestItemsText; + std::string EndText; + std::string CompletedText; + uint32 RewHonorableKills; + float RewHonorMultiplier; + int32 RewOrReqMoney; + uint32 RewMoneyMaxLevel; + uint32 RewSpell; + int32 RewSpellCast; + uint32 RewMailTemplateId; + uint32 RewMailDelaySecs; + uint32 PointMapId; + float PointX; + float PointY; + uint32 PointOpt; + uint32 IncompleteEmote; + uint32 CompleteEmote; + uint32 QuestStartScript; + uint32 QuestCompleteScript; +}; + +enum QuestUpdateState +{ + QUEST_UNCHANGED = 0, + QUEST_CHANGED = 1, + QUEST_NEW = 2 +}; + +struct QuestStatusData +{ + QuestStatusData() + : m_status(QUEST_STATUS_NONE),m_rewarded(false), + m_explored(false), m_timer(0), uState(QUEST_NEW) + { + memset(m_itemcount, 0, QUEST_ITEM_OBJECTIVES_COUNT * sizeof(uint32)); + memset(m_creatureOrGOcount, 0, QUEST_OBJECTIVES_COUNT * sizeof(uint32)); + } + + QuestStatus m_status; + bool m_rewarded; + bool m_explored; + uint32 m_timer; + QuestUpdateState uState; + + uint32 m_itemcount[ QUEST_ITEM_OBJECTIVES_COUNT ]; + uint32 m_creatureOrGOcount[ QUEST_OBJECTIVES_COUNT ]; +}; +#endif diff --git a/src/server/game/Quests/QuestHandler.cpp b/src/server/game/Quests/QuestHandler.cpp new file mode 100644 index 00000000000..8043f5ed149 --- /dev/null +++ b/src/server/game/Quests/QuestHandler.cpp @@ -0,0 +1,721 @@ +/* + * 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); +} |
