/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 . */ #include "SupportMgr.h" #include "CharacterCache.h" #include "Chat.h" #include "DatabaseEnv.h" #include "GameTime.h" #include "Language.h" #include "Log.h" #include "ObjectAccessor.h" #include "Player.h" #include "Timer.h" #include "World.h" #include inline time_t GetAge(uint64 t) { return (GameTime::GetGameTime() - t) / DAY; } Ticket::Ticket() : _id(0), _mapId(0), _createTime(0) { } Ticket::Ticket(Player* player) : _id(0), _mapId(0), _createTime(GameTime::GetGameTime()) { _playerGuid = player->GetGUID(); } Ticket::~Ticket() { } Player* Ticket::GetPlayer() const { return ObjectAccessor::FindConnectedPlayer(_playerGuid); } std::string Ticket::GetPlayerName() const { std::string name; if (!_playerGuid.IsEmpty()) sCharacterCache->GetCharacterNameByGuid(_playerGuid, name); return name; } Player* Ticket::GetAssignedPlayer() const { return ObjectAccessor::FindConnectedPlayer(_assignedTo); } std::string Ticket::GetAssignedToName() const { std::string name; if (!_assignedTo.IsEmpty()) sCharacterCache->GetCharacterNameByGuid(_assignedTo, name); return name; } void Ticket::TeleportTo(Player* player) const { player->TeleportTo(_mapId, _pos.GetPositionX(), _pos.GetPositionY(), _pos.GetPositionZ(), 0.0f); } std::string Ticket::FormatViewMessageString(ChatHandler& handler, char const* closedName, char const* assignedToName, char const* unassignedName, char const* deletedName) const { std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); if (closedName) ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, closedName); if (assignedToName) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, assignedToName); if (unassignedName) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, unassignedName); if (deletedName) ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, deletedName); return ss.str(); } BugTicket::BugTicket() { } BugTicket::BugTicket(Player* player) : Ticket(player) { _id = sSupportMgr->GenerateBugId(); } BugTicket::~BugTicket() { } void BugTicket::LoadFromDB(Field* fields) { uint8 idx = 0; _id = fields[ idx].GetUInt32(); _playerGuid = ObjectGuid::Create(fields[++idx].GetUInt64()); _note = fields[++idx].GetString(); _createTime = fields[++idx].GetInt64(); _mapId = fields[++idx].GetUInt16(); _pos.m_positionX = fields[++idx].GetFloat(); _pos.m_positionY = fields[++idx].GetFloat(); _pos.m_positionZ = fields[++idx].GetFloat(); _pos.SetOrientation(fields[++idx].GetFloat()); int64 closedBy = fields[++idx].GetInt64(); if (closedBy == 0) _closedBy = ObjectGuid::Empty; else if (closedBy < 0) _closedBy.SetRawValue(0, uint64(closedBy)); else _closedBy = ObjectGuid::Create(uint64(closedBy)); uint64 assignedTo = fields[++idx].GetUInt64(); if (assignedTo == 0) _assignedTo = ObjectGuid::Empty; else _assignedTo = ObjectGuid::Create(assignedTo); _comment = fields[++idx].GetString(); } void BugTicket::SaveToDB() const { uint8 idx = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_BUG); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); stmt->setInt64(++idx, _createTime); stmt->setUInt16(++idx, _mapId); stmt->setFloat(++idx, _pos.GetPositionX()); stmt->setFloat(++idx, _pos.GetPositionY()); stmt->setFloat(++idx, _pos.GetPositionZ()); stmt->setFloat(++idx, _pos.GetOrientation()); stmt->setInt64(++idx, _closedBy.GetCounter()); stmt->setUInt64(++idx, _assignedTo.GetCounter()); stmt->setString(++idx, _comment); CharacterDatabase.Execute(stmt); } void BugTicket::DeleteFromDB() { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_BUG); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); } std::string BugTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const { time_t curTime = GameTime::GetGameTime(); std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, TimeFormat::ShortText)).c_str()); if (!_assignedTo.IsEmpty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); if (!_comment.empty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); } return ss.str(); } ComplaintTicket::ComplaintTicket() : _reportType(ReportType::Chat), _majorCategory(ReportMajorCategory::InappropriateCommunication), _minorCategoryFlags(ReportMinorCategory::TextChat) { } ComplaintTicket::ComplaintTicket(Player* player) : Ticket(player), _reportType(ReportType::Chat), _majorCategory(ReportMajorCategory::InappropriateCommunication), _minorCategoryFlags(ReportMinorCategory::TextChat) { _id = sSupportMgr->GenerateComplaintId(); } ComplaintTicket::~ComplaintTicket() = default; void ComplaintTicket::LoadFromDB(Field* fields) { uint8 idx = 0; _id = fields[ idx].GetUInt32(); _playerGuid = ObjectGuid::Create(fields[++idx].GetUInt64()); _note = fields[++idx].GetString(); _createTime = fields[++idx].GetInt64(); _mapId = fields[++idx].GetUInt16(); _pos.m_positionX = fields[++idx].GetFloat(); _pos.m_positionY = fields[++idx].GetFloat(); _pos.m_positionZ = fields[++idx].GetFloat(); _pos.SetOrientation(fields[++idx].GetFloat()); _targetCharacterGuid = ObjectGuid::Create(fields[++idx].GetUInt64()); _reportType = ReportType(fields[++idx].GetInt32()); _majorCategory = ReportMajorCategory(fields[++idx].GetInt32()); _minorCategoryFlags = ReportMinorCategory(fields[++idx].GetInt32()); int32 reportLineIndex = fields[++idx].GetInt32(); if (reportLineIndex != -1) _chatLog.ReportLineIndex = reportLineIndex; int64 closedBy = fields[++idx].GetInt64(); if (closedBy == 0) _closedBy = ObjectGuid::Empty; else if (closedBy < 0) _closedBy.SetRawValue(0, uint64(closedBy)); else _closedBy = ObjectGuid::Create(uint64(closedBy)); uint64 assignedTo = fields[++idx].GetUInt64(); if (assignedTo == 0) _assignedTo = ObjectGuid::Empty; else _assignedTo = ObjectGuid::Create(assignedTo); _comment = fields[++idx].GetString(); } void ComplaintTicket::LoadChatLineFromDB(Field* fields) { _chatLog.Lines.emplace_back(fields[0].GetInt64(), fields[1].GetStringView()); } void ComplaintTicket::SaveToDB() const { CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); uint8 idx = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_COMPLAINT); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); stmt->setInt64(++idx, _createTime); stmt->setUInt16(++idx, _mapId); stmt->setFloat(++idx, _pos.GetPositionX()); stmt->setFloat(++idx, _pos.GetPositionY()); stmt->setFloat(++idx, _pos.GetPositionZ()); stmt->setFloat(++idx, _pos.GetOrientation()); stmt->setUInt64(++idx, _targetCharacterGuid.GetCounter()); stmt->setInt32(++idx, AsUnderlyingType(_reportType)); stmt->setInt32(++idx, AsUnderlyingType(_majorCategory)); stmt->setInt32(++idx, AsUnderlyingType(_minorCategoryFlags)); if (_chatLog.ReportLineIndex) stmt->setInt32(++idx, *_chatLog.ReportLineIndex); else stmt->setInt32(++idx, -1); // empty ReportLineIndex stmt->setInt64(++idx, _closedBy.GetCounter()); stmt->setUInt64(++idx, _assignedTo.GetCounter()); stmt->setString(++idx, _comment); trans->Append(stmt); uint32 lineIndex = 0; for (auto const& c : _chatLog.Lines) { idx = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_COMPLAINT_CHATLINE); stmt->setUInt32(idx, _id); stmt->setUInt32(++idx, lineIndex); stmt->setInt64(++idx, c.Timestamp); stmt->setString(++idx, c.Text); trans->Append(stmt); ++lineIndex; } CharacterDatabase.CommitTransaction(trans); } void ComplaintTicket::DeleteFromDB() { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT_CHATLOG); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); } std::string ComplaintTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const { time_t curTime = GameTime::GetGameTime(); std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, TimeFormat::ShortText)).c_str()); if (!_assignedTo.IsEmpty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); if (!_comment.empty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); } return ss.str(); } SuggestionTicket::SuggestionTicket() { } SuggestionTicket::SuggestionTicket(Player* player) : Ticket(player) { _id = sSupportMgr->GenerateSuggestionId(); } SuggestionTicket::~SuggestionTicket() { } void SuggestionTicket::LoadFromDB(Field* fields) { uint8 idx = 0; _id = fields[ idx].GetUInt32(); _playerGuid = ObjectGuid::Create(fields[++idx].GetUInt64()); _note = fields[++idx].GetString(); _createTime = fields[++idx].GetInt64(); _mapId = fields[++idx].GetUInt16(); _pos.m_positionX = fields[++idx].GetFloat(); _pos.m_positionY = fields[++idx].GetFloat(); _pos.m_positionZ = fields[++idx].GetFloat(); _pos.SetOrientation(fields[++idx].GetFloat()); int64 closedBy = fields[++idx].GetInt64(); if (closedBy == 0) _closedBy = ObjectGuid::Empty; else if (closedBy < 0) _closedBy.SetRawValue(0, uint64(closedBy)); else _closedBy = ObjectGuid::Create(uint64(closedBy)); uint64 assignedTo = fields[++idx].GetUInt64(); if (assignedTo == 0) _assignedTo = ObjectGuid::Empty; else _assignedTo = ObjectGuid::Create(assignedTo); _comment = fields[++idx].GetString(); } void SuggestionTicket::SaveToDB() const { uint8 idx = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_SUGGESTION); stmt->setUInt32(idx, _id); stmt->setUInt64(++idx, _playerGuid.GetCounter()); stmt->setString(++idx, _note); stmt->setInt64(++idx, _createTime); stmt->setUInt16(++idx, _mapId); stmt->setFloat(++idx, _pos.GetPositionX()); stmt->setFloat(++idx, _pos.GetPositionY()); stmt->setFloat(++idx, _pos.GetPositionZ()); stmt->setFloat(++idx, _pos.GetOrientation()); stmt->setInt64(++idx, _closedBy.GetCounter()); stmt->setUInt64(++idx, _assignedTo.GetCounter()); stmt->setString(++idx, _comment); CharacterDatabase.Execute(stmt); } void SuggestionTicket::DeleteFromDB() { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_SUGGESTION); stmt->setUInt32(0, _id); CharacterDatabase.Execute(stmt); } std::string SuggestionTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const { time_t curTime = GameTime::GetGameTime(); std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, TimeFormat::ShortText)).c_str()); if (!_assignedTo.IsEmpty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); if (!_comment.empty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); } return ss.str(); } SupportMgr::SupportMgr() : _supportSystemStatus(false), _ticketSystemStatus(false), _bugSystemStatus(false), _complaintSystemStatus(false), _suggestionSystemStatus(false), _lastBugId(0), _lastComplaintId(0), _lastSuggestionId(0), _lastChange(0), _openBugTicketCount(0), _openComplaintTicketCount(0), _openSuggestionTicketCount(0) { } SupportMgr::~SupportMgr() { for (auto const& b : _bugTicketList) delete b.second; for (auto const& c : _complaintTicketList) delete c.second; for (auto const& s : _suggestionTicketList) delete s.second; } SupportMgr* SupportMgr::instance() { static SupportMgr instance; return &instance; } template<> TC_GAME_API BugTicket* SupportMgr::GetTicket(uint32 bugId) { BugTicketList::const_iterator itr = _bugTicketList.find(bugId); if (itr != _bugTicketList.end()) return itr->second; return nullptr; } template<> TC_GAME_API ComplaintTicket* SupportMgr::GetTicket(uint32 complaintId) { ComplaintTicketList::const_iterator itr = _complaintTicketList.find(complaintId); if (itr != _complaintTicketList.end()) return itr->second; return nullptr; } template<> TC_GAME_API SuggestionTicket* SupportMgr::GetTicket(uint32 suggestionId) { SuggestionTicketList::const_iterator itr = _suggestionTicketList.find(suggestionId); if (itr != _suggestionTicketList.end()) return itr->second; return nullptr; } ComplaintTicketList SupportMgr::GetComplaintsByPlayerGuid(ObjectGuid playerGuid) const { ComplaintTicketList ret; for (auto const& c : _complaintTicketList) if (c.second->GetPlayerGuid() == playerGuid) ret.insert(c); return ret; } void SupportMgr::Initialize() { SetSupportSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_ENABLED)); SetTicketSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED)); SetBugSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED)); SetComplaintSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED)); SetSuggestionSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED)); } template<> TC_GAME_API uint32 SupportMgr::GetOpenTicketCount() const { return _openBugTicketCount; } template<> TC_GAME_API uint32 SupportMgr::GetOpenTicketCount() const { return _openComplaintTicketCount; } template<> TC_GAME_API uint32 SupportMgr::GetOpenTicketCount() const { return _openSuggestionTicketCount; } void SupportMgr::LoadBugTickets() { uint32 oldMSTime = getMSTime(); for (auto const& c : _bugTicketList) delete c.second; _bugTicketList.clear(); _lastBugId = 0; _openBugTicketCount = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_BUGS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 GM bugs. DB table `gm_bug` is empty!"); return; } uint32 count = 0; do { Field* fields = result->Fetch(); BugTicket* bug = new BugTicket(); bug->LoadFromDB(fields); if (!bug->IsClosed()) ++_openBugTicketCount; uint32 id = bug->GetId(); if (_lastBugId < id) _lastBugId = id; _bugTicketList[id] = bug; ++count; } while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded {} GM bugs in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SupportMgr::LoadComplaintTickets() { uint32 oldMSTime = getMSTime(); for (auto const& c : _complaintTicketList) delete c.second; _complaintTicketList.clear(); _lastComplaintId = 0; _openComplaintTicketCount = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINTS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 GM complaints. DB table `gm_complaint` is empty!"); return; } uint32 count = 0; CharacterDatabasePreparedStatement* chatLogStmt; PreparedQueryResult chatLogResult; do { Field* fields = result->Fetch(); ComplaintTicket* complaint = new ComplaintTicket(); complaint->LoadFromDB(fields); if (!complaint->IsClosed()) ++_openComplaintTicketCount; uint32 id = complaint->GetId(); if (_lastComplaintId < id) _lastComplaintId = id; chatLogStmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINT_CHATLINES); chatLogStmt->setUInt32(0, id); chatLogResult = CharacterDatabase.Query(chatLogStmt); if (chatLogResult) { do { Field* chatLineFields = chatLogResult->Fetch(); complaint->LoadChatLineFromDB(chatLineFields); } while (chatLogResult->NextRow()); } _complaintTicketList[id] = complaint; ++count; } while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded {} GM complaints in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SupportMgr::LoadSuggestionTickets() { uint32 oldMSTime = getMSTime(); for (auto const& c : _suggestionTicketList) delete c.second; _suggestionTicketList.clear(); _lastSuggestionId = 0; _openSuggestionTicketCount = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_SUGGESTIONS); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 GM suggestions. DB table `gm_suggestion` is empty!"); return; } uint32 count = 0; do { Field* fields = result->Fetch(); SuggestionTicket* suggestion = new SuggestionTicket(); suggestion->LoadFromDB(fields); if (!suggestion->IsClosed()) ++_openSuggestionTicketCount; uint32 id = suggestion->GetId(); if (_lastSuggestionId < id) _lastSuggestionId = id; _suggestionTicketList[id] = suggestion; ++count; } while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded {} GM suggestions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SupportMgr::AddTicket(BugTicket* ticket) { _bugTicketList[ticket->GetId()] = ticket; if (!ticket->IsClosed()) ++_openBugTicketCount; ticket->SaveToDB(); } void SupportMgr::AddTicket(ComplaintTicket* ticket) { _complaintTicketList[ticket->GetId()] = ticket; if (!ticket->IsClosed()) ++_openComplaintTicketCount; ticket->SaveToDB(); } void SupportMgr::AddTicket(SuggestionTicket* ticket) { _suggestionTicketList[ticket->GetId()] = ticket; if (!ticket->IsClosed()) ++_openSuggestionTicketCount; ticket->SaveToDB(); } template<> TC_GAME_API void SupportMgr::RemoveTicket(uint32 ticketId) { if (BugTicket* ticket = GetTicket(ticketId)) { ticket->DeleteFromDB(); _bugTicketList.erase(ticketId); delete ticket; } } template<> TC_GAME_API void SupportMgr::RemoveTicket(uint32 ticketId) { if (ComplaintTicket* ticket = GetTicket(ticketId)) { ticket->DeleteFromDB(); _complaintTicketList.erase(ticketId); delete ticket; } } template<> TC_GAME_API void SupportMgr::RemoveTicket(uint32 ticketId) { if (SuggestionTicket* ticket = GetTicket(ticketId)) { ticket->DeleteFromDB(); _suggestionTicketList.erase(ticketId); delete ticket; } } template<> TC_GAME_API void SupportMgr::CloseTicket(uint32 ticketId, ObjectGuid closedBy) { if (BugTicket* ticket = GetTicket(ticketId)) { ticket->SetClosedBy(closedBy); if (!closedBy.IsEmpty()) --_openBugTicketCount; ticket->SaveToDB(); } } template<> TC_GAME_API void SupportMgr::CloseTicket(uint32 ticketId, ObjectGuid closedBy) { if (ComplaintTicket* ticket = GetTicket(ticketId)) { ticket->SetClosedBy(closedBy); if (!closedBy.IsEmpty()) --_openComplaintTicketCount; ticket->SaveToDB(); } } template<> TC_GAME_API void SupportMgr::CloseTicket(uint32 ticketId, ObjectGuid closedBy) { if (SuggestionTicket* ticket = GetTicket(ticketId)) { ticket->SetClosedBy(closedBy); if (!closedBy.IsEmpty()) --_openSuggestionTicketCount; ticket->SaveToDB(); } } template<> TC_GAME_API void SupportMgr::ResetTickets() { for (auto const& c : _bugTicketList) delete c.second; _bugTicketList.clear(); _lastBugId = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_BUGS); CharacterDatabase.Execute(stmt); } template<> TC_GAME_API void SupportMgr::ResetTickets() { for (auto const& c : _complaintTicketList) delete c.second; _complaintTicketList.clear(); _lastComplaintId = 0; CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINTS)); trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS)); CharacterDatabase.CommitTransaction(trans); } template<> TC_GAME_API void SupportMgr::ResetTickets() { for (auto const& c : _suggestionTicketList) delete c.second; _suggestionTicketList.clear(); _lastSuggestionId = 0; CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_SUGGESTIONS); CharacterDatabase.Execute(stmt); } template<> TC_GAME_API void SupportMgr::ShowList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr) if (!itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } template<> TC_GAME_API void SupportMgr::ShowList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr) if (!itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } template<> TC_GAME_API void SupportMgr::ShowList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr) if (!itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } template<> TC_GAME_API void SupportMgr::ShowClosedList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr) if (itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } template<> TC_GAME_API void SupportMgr::ShowClosedList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr) if (itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } template<> TC_GAME_API void SupportMgr::ShowClosedList(ChatHandler& handler) const { handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr) if (itr->second->IsClosed()) handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); } void SupportMgr::UpdateLastChange() { _lastChange = GameTime::GetGameTime(); }