Files
TrinityCore/src/server/game/Handlers/QuestHandler.cpp
Spp 55ce180f28 Core/Logging: Add Asyncronous logging with Loggers ("What to log") and Appenders ("Where to log") system. Will allow to select to full log some parts of core while others are not even logged.
- Logging System is asyncronous to improve performance.
- Each msg and Logger has a Log Type and Log Level assigned. Each msg is assigned the Logger of same Log Type or "root" Logger is selected if there is no Logger configured for the given Log Type
- Loggers have a list of Appenders to send the msg to. The Msg in the Logger is not sent to Appenders if the msg LogLevel is lower than Logger LogLevel.
- There are three (at the moment) types of Appenders: Console, File or DB (this is WIP, not working ATM). Msg is not written to the resource if msg LogLevel is lower than Appender LogLevel.
- Appender and Console Log levels can be changed while server is active with command '.set loglevel (a/l) name level'

Explanation of use with Sample config:

Appender.Console.Type=1       (1 = Console)
Appender.Console.Level=2      (2 = Debug)

Appender.Server.Type=2        (2 = File)
Appender.Server.Level=3       (3 = Info)
Appender.Server.File=Server.log

Appender.SQL.Type=2           (2 = File)
Appender.SQL.Level=1          (1 = Trace)
Appender.SQL.File=sql.log

Appenders=Console Server      (NOTE: SQL has not been included here... that will make core ignore the config for "SQL" as it's not in this list)

Logger.root.Type=0            (0 = Default - if it's not created by config, server will create it with LogLevel = DISABLED)
Logger.root.Level=5           (5 = Error)
Logger.root.Appenders=Console

Logger.SQL.Type=26            (26 = SQL)
Logger.SQL.Level=3            (2 = Debug)
Logger.SQL.Appenders=Console Server SQL

Logger.SomeRandomName.Type=24 (24 = Guild)
Logger.SomeRandomName.Level=5 (5 = Error)
Loggers=root SQL SomeRandomName

* At loading Appender SQL will be ignored, as it's not present on "Appenders"

* sLog->outDebug(LOG_FILTER_GUILD, "Some log msg related to Guilds")
  - Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomName is found but it's LogLevel = 5 and Msg LogLevel=2... Msg is not logged

* sLog->outError(LOG_FILTER_GUILD, "Some error log msg related to Guilds")
  - Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomeName is found with proper LogLevel but Logger does not have any Appenders assigned to that logger... Msg is not logged

* sLog->outDebug(LOG_FILTER_SQL, "Some msg related to SQLs")
  - Msg is sent to Logger SQL (matches type), as it matches LogLevel the msg is sent to Appenders Console, Server and SQL
    - Appender Console has lower Log Level: Msg is logged to Console
    - Appender Server has higher Log Level: Msg is not logged to file
    - Appender SQL has lower Log Level: Msg is logged to file sql.log

* sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Some msg related to Battelgrounds")
  - Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). As Logger has higher LogLevel msg is not sent to any appender

* sLog->outError(LOG_FILTER_BATTLEGROUND, "Some error msg related to Battelgrounds")
  - Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). Msg has lower LogLevel and is sent to Appender Console
    - Appender Console has lower LogLevel: Msg is logged to Console
2012-08-03 14:20:18 +02:00

776 lines
29 KiB
C++
Executable File

/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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"
#include "GameObjectAI.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->outInfo(LOG_FILTER_NETWORKIO, "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(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u", uint32(GUID_LOPART(guid)));
Creature* cr_questgiver=questgiver->ToCreature();
if (!cr_questgiver->IsHostileTo(_player)) // do not show quest status to enemies
{
questStatus = sScriptMgr->GetDialogStatus(_player, cr_questgiver);
if (questStatus > 6)
questStatus = getDialogStatus(_player, cr_questgiver, defstatus);
}
break;
}
case TYPEID_GAMEOBJECT:
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u", uint32(GUID_LOPART(guid)));
GameObject* go_questgiver=(GameObject*)questgiver;
questStatus = sScriptMgr->GetDialogStatus(_player, go_questgiver);
if (questStatus > 6)
questStatus = getDialogStatus(_player, go_questgiver, defstatus);
break;
}
default:
sLog->outError(LOG_FILTER_NETWORKIO, "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(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid));
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!creature)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "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_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
// Stop the npc if moving
creature->StopMoving();
if (sScriptMgr->OnGossipHello(_player, creature))
return;
_player->PrepareGossipMenu(creature, creature->GetCreatureTemplate()->GossipMenuId, true);
_player->SendPreparedGossip(creature);
creature->AI()->sGossipHello(_player);
}
void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data)
{
uint64 guid;
uint32 questId;
uint32 unk1;
recv_data >> guid >> questId >> unk1;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), questId, unk1);
Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER);
// no or incorrect quest giver
if (!object || (object->GetTypeId() != TYPEID_PLAYER && !object->hasQuest(questId)) ||
(object->GetTypeId() == TYPEID_PLAYER && !object->ToPlayer()->CanShareQuest(questId)))
{
_player->PlayerTalkClass->SendCloseGossip();
_player->SetDivider(0);
return;
}
// some kind of WPE protection
if (!_player->CanInteractWithQuestGiver(object))
return;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
// prevent cheating
if (!GetPlayer()->CanTakeQuest(quest, true))
{
_player->PlayerTalkClass->SendCloseGossip();
_player->SetDivider(0);
return;
}
if (_player->GetDivider() != 0)
{
Player* player = ObjectAccessor::FindPlayer(_player->GetDivider());
if (player)
{
player->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST);
_player->SetDivider(0);
}
}
if (_player->CanAddQuest(quest, true))
{
_player->AddQuest(quest, object);
if (quest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT))
{
if (Group* group = _player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* player = itr->getSource();
if (!player || player == _player) // not self
continue;
if (player->CanTakeQuest(quest, true))
{
player->SetDivider(_player->GetGUID());
//need confirmation that any gossip window will close
player->PlayerTalkClass->SendCloseGossip();
_player->SendQuestConfirmAccept(quest, player);
}
}
}
}
if (_player->CanCompleteQuest(questId))
_player->CompleteQuest(questId);
switch (object->GetTypeId())
{
case TYPEID_UNIT:
sScriptMgr->OnQuestAccept(_player, (object->ToCreature()), quest);
(object->ToCreature())->AI()->sQuestAccept(_player, quest);
break;
case TYPEID_ITEM:
case TYPEID_CONTAINER:
{
sScriptMgr->OnQuestAccept(_player, ((Item*)object), quest);
// destroy not required for quest finish quest starting item
bool destroyItem = true;
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
{
if ((quest->RequiredItemId[i] == ((Item*)object)->GetEntry()) && (((Item*)object)->GetTemplate()->MaxCount > 0))
{
destroyItem = false;
break;
}
}
if (destroyItem)
_player->DestroyItem(((Item*)object)->GetBagSlot(), ((Item*)object)->GetSlot(), true);
break;
}
case TYPEID_GAMEOBJECT:
sScriptMgr->OnQuestAccept(_player, ((GameObject*)object), quest);
(object->ToGameObject())->AI()->QuestAccept(_player, quest);
break;
default:
break;
}
_player->PlayerTalkClass->SendCloseGossip();
if (quest->GetSrcSpell() > 0)
_player->CastSpell(_player, quest->GetSrcSpell(), true);
return;
}
}
_player->PlayerTalkClass->SendCloseGossip();
}
void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data)
{
uint64 guid;
uint32 questId;
uint8 unk1;
recv_data >> guid >> questId >> unk1;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), questId, unk1);
// Verify that the guid is valid and is a questgiver or involved in the requested quest
Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);
if (!object || (!object->hasQuest(questId) && !object->hasInvolvedQuest(questId)))
{
_player->PlayerTalkClass->SendCloseGossip();
return;
}
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
// not sure here what should happen to quests with QUEST_FLAGS_AUTOCOMPLETE
// if this breaks them, add && object->GetTypeId() == TYPEID_ITEM to this check
// item-started quests never have that flag
if (!_player->CanTakeQuest(quest, true))
return;
if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true))
{
_player->AddQuest(quest, object);
if (_player->CanCompleteQuest(questId))
_player->CompleteQuest(questId);
}
if (quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
_player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true);
else
_player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true);
}
}
void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data)
{
if (!_player)
return;
uint32 questId;
recv_data >> questId;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_QUERY quest = %u", questId);
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
_player->PlayerTalkClass->SendQuestQueryResponse(quest);
}
void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data)
{
uint32 questId, reward;
uint64 guid;
recv_data >> guid >> questId >> reward;
if (reward >= QUEST_REWARD_CHOICES_COUNT)
{
sLog->outError(LOG_FILTER_NETWORKIO, "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;
}
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u", uint32(GUID_LOPART(guid)), questId, reward);
Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if (!object || !object->hasInvolvedQuest(questId))
return;
// some kind of WPE protection
if (!_player->CanInteractWithQuestGiver(object))
return;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) ||
(_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete()))
{
sLog->outError(LOG_FILTER_NETWORKIO, "HACK ALERT: Player %s (guid: %u) is trying to complete quest (id: %u) but he has no right to do it!",
_player->GetName(), _player->GetGUIDLow(), questId);
return;
}
if (_player->CanRewardQuest(quest, reward, true))
{
_player->RewardQuest(quest, reward, object);
switch (object->GetTypeId())
{
case TYPEID_UNIT:
if (!(sScriptMgr->OnQuestReward(_player, (object->ToCreature()), quest, reward)))
{
// Send next quest
if (Quest const* nextQuest = _player->GetNextQuest(guid, quest))
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
_player->AddQuest(nextQuest, object);
if (_player->CanCompleteQuest(nextQuest->GetQuestId()))
_player->CompleteQuest(nextQuest->GetQuestId());
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
}
(object->ToCreature())->AI()->sQuestReward(_player, quest, reward);
}
break;
case TYPEID_GAMEOBJECT:
if (!sScriptMgr->OnQuestReward(_player, ((GameObject*)object), quest, reward))
{
// Send next quest
if (Quest const* nextQuest = _player->GetNextQuest(guid, quest))
{
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(nextQuest, true))
{
_player->AddQuest(nextQuest, object);
if (_player->CanCompleteQuest(nextQuest->GetQuestId()))
_player->CompleteQuest(nextQuest->GetQuestId());
}
_player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
}
object->ToGameObject()->AI()->QuestReward(_player, quest, reward);
}
break;
default:
break;
}
}
else
_player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
}
}
void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data)
{
uint32 questId;
uint64 guid;
recv_data >> guid >> questId;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u", uint32(GUID_LOPART(guid)), questId);
Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if (!object || !object->hasInvolvedQuest(questId))
return;
// some kind of WPE protection
if (!_player->CanInteractWithQuestGiver(object))
return;
if (_player->CanCompleteQuest(questId))
_player->CompleteQuest(questId);
if (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE)
return;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
_player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
}
void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CANCEL");
_player->PlayerTalkClass->SendCloseGossip();
}
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(LOG_FILTER_NETWORKIO, "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(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u", slot);
if (slot < MAX_QUEST_LOG_SIZE)
{
if (uint32 questId = _player->GetQuestSlotQuestId(slot))
{
if (!_player->TakeQuestSourceItem(questId, true))
return; // can't un-equip some items, reject quest cancel
if (const Quest *quest = sObjectMgr->GetQuestTemplate(questId))
{
if (quest->HasFlag(QUEST_TRINITY_FLAGS_TIMED))
_player->RemoveTimedQuest(questId);
}
_player->TakeQuestSourceItem(questId, true); // remove quest src item from player
_player->RemoveActiveQuest(questId);
_player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, questId);
sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u abandoned quest %u", _player->GetGUIDLow(), questId);
}
_player->SetQuestSlot(slot, 0);
_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1);
}
}
void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data)
{
uint32 questId;
recv_data >> questId;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", questId);
if (const Quest* quest = sObjectMgr->GetQuestTemplate(questId))
{
if (!quest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT))
return;
Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider());
if (!pOriginalPlayer)
return;
if (quest->IsRaidQuest())
{
if (!_player->IsInSameRaidWith(pOriginalPlayer))
return;
}
else
{
if (!_player->IsInSameGroupWith(pOriginalPlayer))
return;
}
if (_player->CanAddQuest(quest, true))
_player->AddQuest(quest, NULL); // NULL, this prevent DB script from duplicate running
_player->SetDivider(0);
}
}
void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data)
{
uint32 questId;
uint64 guid;
recv_data >> guid >> questId;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u", uint32(GUID_LOPART(guid)), questId);
Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if (!object || !object->hasInvolvedQuest(questId))
return;
// some kind of WPE protection
if (!_player->CanInteractWithQuestGiver(object))
return;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
if (!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE)
{
sLog->outError(LOG_FILTER_NETWORKIO, "Possible hacking attempt: Player %s [guid: %u] tried to complete quest [entry: %u] without being in possession of the quest!",
_player->GetName(), _player->GetGUIDLow(), questId);
return;
}
// TODO: need a virtual function
if (_player->InBattleground())
if (Battleground* bg = _player->GetBattleground())
if (bg->GetTypeID() == BATTLEGROUND_AV)
((BattlegroundAV*)bg)->HandleQuestComplete(questId, _player);
if (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE)
{
if (quest->IsRepeatable())
_player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanCompleteRepeatableQuest(quest), false);
else
_player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
}
else
{
if (quest->GetReqItemsCount()) // some items required
_player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
else // no items required
_player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
}
}
}
void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/)
{
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH");
}
void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket)
{
uint32 questId;
recvPacket >> questId;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId);
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
{
if (Group* group = _player->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* player = itr->getSource();
if (!player || player == _player) // skip self
continue;
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_SHARING_QUEST);
if (!player->SatisfyQuestStatus(quest, false))
{
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_HAVE_QUEST);
continue;
}
if (player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
{
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_FINISH_QUEST);
continue;
}
if (!player->CanTakeQuest(quest, false))
{
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_CANT_TAKE_QUEST);
continue;
}
if (!player->SatisfyQuestLog(false))
{
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_LOG_FULL);
continue;
}
if (player->GetDivider() != 0)
{
_player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_BUSY);
continue;
}
player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, _player->GetGUID(), true);
player->SetDivider(_player->GetGUID());
}
}
}
}
void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket)
{
uint64 guid;
uint8 msg;
recvPacket >> guid >> msg;
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_QUEST_PUSH_RESULT");
if (_player->GetDivider() != 0)
{
Player* player = ObjectAccessor::FindPlayer(_player->GetDivider());
if (player)
{
WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1));
data << uint64(guid);
data << uint8(msg); // valid values: 0-8
player->GetSession()->SendPacket(&data);
_player->SetDivider(0);
}
}
}
uint32 WorldSession::getDialogStatus(Player* player, Object* questgiver, uint32 defstatus)
{
uint32 result = defstatus;
QuestRelationBounds qr;
QuestRelationBounds qir;
switch (questgiver->GetTypeId())
{
case TYPEID_GAMEOBJECT:
{
qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry());
qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry());
break;
}
case TYPEID_UNIT:
{
qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry());
qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry());
break;
}
default:
//its imposible, but check ^)
sLog->outError(LOG_FILTER_NETWORKIO, "Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId());
return DIALOG_STATUS_NONE;
}
for (QuestRelations::const_iterator i = qir.first; i != qir.second; ++i)
{
uint32 result2 = 0;
uint32 quest_id = i->second;
Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
if (!quest)
continue;
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, quest->GetQuestId());
if (!sConditionMgr->IsObjectMeetToConditions(player, conditions))
continue;
QuestStatus status = player->GetQuestStatus(quest_id);
if ((status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(quest_id)) ||
(quest->IsAutoComplete() && player->CanTakeQuest(quest, false)))
{
if (quest->IsAutoComplete() && quest->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.first; i != qr.second; ++i)
{
uint32 result2 = 0;
uint32 quest_id = i->second;
Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
if (!quest)
continue;
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, quest->GetQuestId());
if (!sConditionMgr->IsObjectMeetToConditions(player, conditions))
continue;
QuestStatus status = player->GetQuestStatus(quest_id);
if (status == QUEST_STATUS_NONE)
{
if (player->CanSeeStartQuest(quest))
{
if (player->SatisfyQuestLevel(quest, false))
{
if (quest->IsAutoComplete() || (quest->IsRepeatable() && player->IsQuestRewarded(quest_id)))
result2 = DIALOG_STATUS_REWARD_REP;
else if (player->getLevel() <= ((player->GetQuestLevel(quest) == -1) ? player->getLevel() : player->GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF)))
{
if (quest->HasFlag(QUEST_FLAGS_DAILY) || quest->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(LOG_FILTER_NETWORKIO, "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->GetDialogStatus(_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->GetDialogStatus(_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*/)
{
size_t rew_count = _player->GetRewardedQuestCount();
WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4 + 4 * rew_count);
data << uint32(rew_count);
const RewardedQuestSet &rewQuests = _player->getRewardedQuests();
for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr)
data << uint32(*itr);
SendPacket(&data);
}