From 2f17dbe01788289143b8e805a16d2d10d16ed98b Mon Sep 17 00:00:00 2001 From: Olion17 Date: Sat, 19 Mar 2016 22:23:31 +0000 Subject: [PATCH] [GM] .ticket command rework Including ticket numbering fix (now real ticket IDs throughout) Closing tickets for offline players --- src/game/ChatCommands/Level2.cpp | 492 ++++++++++++++++++------------- src/game/Object/GMTicketMgr.cpp | 12 +- src/game/Object/GMTicketMgr.h | 41 +-- src/game/Tools/Language.h | 7 +- src/game/WorldHandlers/Chat.cpp | 18 +- src/game/WorldHandlers/Chat.h | 13 +- src/game/WorldHandlers/World.cpp | 12 +- src/game/WorldHandlers/World.h | 3 +- src/mangosd/mangosd.conf.dist.in | 35 ++- src/shared/SystemConfig.h.in | 2 +- src/shared/revision.h | 6 +- 11 files changed, 390 insertions(+), 251 deletions(-) diff --git a/src/game/ChatCommands/Level2.cpp b/src/game/ChatCommands/Level2.cpp index 89b9c8d9..0b640da9 100644 --- a/src/game/ChatCommands/Level2.cpp +++ b/src/game/ChatCommands/Level2.cpp @@ -2410,7 +2410,7 @@ bool ChatHandler::HandlePInfoCommand(char* args) return true; } -// show tickets +// show ticket (helper) void ChatHandler::ShowTicket(GMTicket const* ticket) { std::string lastupdated = TimeToTimestampStr(ticket->GetLastUpdate()); @@ -2429,238 +2429,88 @@ void ChatHandler::ShowTicket(GMTicket const* ticket) } // ticket commands -bool ChatHandler::HandleTicketCommand(char* args) +bool ChatHandler::HandleTicketAcceptCommand(char* args) { char* px = ExtractLiteralArg(&args); - // ticket - if (!px) - { - size_t count = sTicketMgr.GetTicketCount(); - - if (m_session) - { - bool accept = m_session->GetPlayer()->isAcceptTickets(); - - PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, GetOnOffStr(accept)); - } - else - { PSendSysMessage(LANG_COMMAND_TICKETCOUNT_CONSOLE, count); } - - return true; - } - - if (strncmp(px, "system_on", 10) == 0) + if (strncmp(px, "on", 3) == 0) { sTicketMgr.SetAcceptTickets(true); SendSysMessage(LANG_COMMAND_TICKETS_SYSTEM_ON); - return true; } - - if (strncmp(px, "system_off", 11) == 0) + else if (strncmp(px, "off", 4) == 0) { sTicketMgr.SetAcceptTickets(false); SendSysMessage(LANG_COMMAND_TICKETS_SYSTEM_OFF); - return true; } - - // ticket on - if (strncmp(px, "on", 3) == 0) - { - if (!m_session) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } + else + return false; - m_session->GetPlayer()->SetAcceptTicket(true); - SendSysMessage(LANG_COMMAND_TICKETON); - return true; - } + return true; +} - // ticket off - if (strncmp(px, "off", 4) == 0) - { - if (!m_session) - { - SendSysMessage(LANG_PLAYER_NOT_FOUND); - SetSentErrorMessage(true); - return false; - } +bool ChatHandler::HandleTicketCloseCommand(char* args) +{ + GMTicket* ticket = NULL; - m_session->GetPlayer()->SetAcceptTicket(false); - SendSysMessage(LANG_COMMAND_TICKETOFF); - return true; - } - - //TODO: Break both of these out into extract functions - // ticket close, can show them a gm-survey - if (strncmp(px, "close", 6) == 0 || strncmp(px, "close_survey", 13) == 0) - { - GMTicket* ticket = NULL; - - uint32 num; - if (ExtractUInt32(&args, num)) - { - if (num == 0) - return false; - - ticket = sTicketMgr.GetGMTicketByOrderPos(num - 1); - - if (!ticket) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); - SetSentErrorMessage(true); - return false; - } - } - else - { - ObjectGuid target_guid; - std::string target_name; - if (!ExtractPlayerTarget(&args, NULL, &target_guid, &target_name)) - return false; - - // ticket respond $char_name - ticket = sTicketMgr.GetGMTicket(target_guid); - - if (!ticket) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - if (strncmp(px, "close_survey", 13) == 0) - ticket->CloseWithSurvey(); - else - ticket->Close(); - - //This needs to be before we delete the ticket - Player* pPlayer = sObjectMgr.GetPlayer(ticket->GetPlayerGuid()); - - //For now we can't close tickets for offline players, TODO - if (!pPlayer) - { - SendSysMessage(LANG_COMMAND_TICKET_CANT_CLOSE); - return false; - } - - //This logic feels misplaced, but you can't have it in GMTicket? - sTicketMgr.Delete(ticket->GetPlayerGuid()); - ticket = NULL; - - PSendSysMessage(LANG_COMMAND_TICKETCLOSED_NAME, pPlayer->GetName()); - - return true; - } - - // ticket respond - if (strncmp(px, "respond", 8) == 0 || strncmp(px, "response", 9) == 0 - || strncmp(px, "whisper", 8) == 0) - { - GMTicket* ticket = NULL; - - // ticket respond #num - uint32 num; - if (ExtractUInt32(&args, num)) - { - if (num == 0) - { return false; } - - // mgr numbering tickets start from 0 - ticket = sTicketMgr.GetGMTicketByOrderPos(num - 1); - - if (!ticket) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); - SetSentErrorMessage(true); - return false; - } - } - else - { - ObjectGuid target_guid; - std::string target_name; - if (!ExtractPlayerTarget(&args, NULL, &target_guid, &target_name)) - { return false; } - - // ticket respond $char_name - ticket = sTicketMgr.GetGMTicket(target_guid); - - if (!ticket) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); - SetSentErrorMessage(true); - return false; - } - } - - // no response text? - if (!*args) - { return false; } - ticket->SetResponseText(args); - - if (Player* pl = sObjectMgr.GetPlayer(ticket->GetPlayerGuid())) - { - pl->GetSession()->SendGMTicketGetTicket(0x06, ticket); - //How should we error here? - if (m_session) - m_session->GetPlayer()->Whisper(args, LANG_UNIVERSAL, pl->GetObjectGuid()); - } - - return true; - } - - // ticket #num uint32 num; - if (ExtractUInt32(&px, num)) + if (ExtractUInt32(&args, num)) { if (num == 0) - { return false; } + return false; + + ticket = sTicketMgr.GetGMTicket(num); - // mgr numbering tickets start from 0 - GMTicket* ticket = sTicketMgr.GetGMTicketByOrderPos(num - 1); if (!ticket) { PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); SetSentErrorMessage(true); return false; } + } + else + { + ObjectGuid target_guid; + std::string target_name; + if (!ExtractPlayerTarget(&args, NULL, &target_guid, &target_name)) + return false; - ShowTicket(ticket); - return true; + // ticket respond $char_name + ticket = sTicketMgr.GetGMTicket(target_guid); + + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); + SetSentErrorMessage(true); + return false; + } } - ObjectGuid target_guid; - std::string target_name; - if (!ExtractPlayerTarget(&px, NULL, &target_guid, &target_name)) - { return false; } + Player* pPlayer = sObjectMgr.GetPlayer(ticket->GetPlayerGuid()); - // ticket $char_name - GMTicket* ticket = sTicketMgr.GetGMTicket(target_guid); - if (!ticket) + if (!pPlayer && !sWorld.getConfig(CONFIG_BOOL_GM_TICKET_OFFLINE_CLOSING)) { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); - SetSentErrorMessage(true); + SendSysMessage(LANG_COMMAND_TICKET_CANT_CLOSE); return false; } - ShowTicket(ticket); + ticket->Close(); + + //This logic feels misplaced, but you can't have it in GMTicket? + sTicketMgr.Delete(ticket->GetPlayerGuid()); // here, ticket become invalidated and should not be used below + + PSendSysMessage(LANG_COMMAND_TICKETCLOSED_NAME, pPlayer ? pPlayer->GetName() : "an offline player"); return true; } -// dell all tickets -bool ChatHandler::HandleDelTicketCommand(char* args) +bool ChatHandler::HandleTicketDeleteCommand(char* args) { char* px = ExtractLiteralArg(&args); if (!px) - { return false; } + return false; - // delticket all + // ticket delete all if (strncmp(px, "all", 4) == 0) { sTicketMgr.DeleteAll(); @@ -2670,14 +2520,14 @@ bool ChatHandler::HandleDelTicketCommand(char* args) uint32 num; - // delticket #num + // ticket delete #id if (ExtractUInt32(&px, num)) { if (num == 0) - { return false; } + return false; // mgr numbering tickets start from 0 - GMTicket* ticket = sTicketMgr.GetGMTicketByOrderPos(num - 1); + GMTicket* ticket = sTicketMgr.GetGMTicket(num); if (!ticket) { @@ -2697,23 +2547,23 @@ bool ChatHandler::HandleDelTicketCommand(char* args) PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL, GetNameLink(pl).c_str()); } else - { PSendSysMessage(LANG_COMMAND_TICKETDEL); } + PSendSysMessage(LANG_COMMAND_TICKETDEL); return true; } + // ticket delete $charName Player* target; ObjectGuid target_guid; std::string target_name; if (!ExtractPlayerTarget(&px, &target, &target_guid, &target_name)) - { return false; } + return false; - // delticket $char_name sTicketMgr.Delete(target_guid); // notify players about ticket deleting if (target) - { target->GetSession()->SendGMTicketGetTicket(0x0A); } + target->GetSession()->SendGMTicketGetTicket(0x0A); std::string nameLink = playerLink(target_name); @@ -2721,6 +2571,248 @@ bool ChatHandler::HandleDelTicketCommand(char* args) return true; } +bool ChatHandler::HandleTicketInfoCommand(char *args) +{ + char* px = ExtractLiteralArg(&args); + + size_t count = sTicketMgr.GetTicketCount(); + + if (m_session) + PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, GetOnOffStr(m_session->GetPlayer()->isAcceptTickets())); + else + PSendSysMessage(LANG_COMMAND_TICKETCOUNT_CONSOLE, count); + + return true; +} + +bool ChatHandler::HandleTicketListCommand(char* args) +{ + uint16 numToShow = std::min(uint16(sTicketMgr.GetTicketCount()), uint16(sWorld.getConfig(CONFIG_UINT32_GM_TICKET_LIST_SIZE))); + for (uint16 i = 0; i < numToShow; ++i) + { + GMTicket* ticket = sTicketMgr.GetGMTicketByOrderPos(i); + time_t lastChanged = time_t(ticket->GetLastUpdate()); + PSendSysMessage(LANG_COMMAND_TICKET_OFFLINE_INFO, ticket->GetId(), ticket->GetPlayerGuid().GetCounter(), ticket->HasResponse() ? "+" : "-", ctime(&lastChanged)); + } + + PSendSysMessage(LANG_COMMAND_TICKET_COUNT_ALL, numToShow, sTicketMgr.GetTicketCount()); + return true; +} + +bool ChatHandler::HandleTicketOnlineListCommand(char* args) +{ + uint16 count = 0; + for (uint16 i = 0; i < sTicketMgr.GetTicketCount(); ++i) + { + GMTicket* ticket = sTicketMgr.GetGMTicketByOrderPos(i); + if (Player* player = sObjectMgr.GetPlayer(ticket->GetPlayerGuid(), true)) + { + ++count; + if (i < sWorld.getConfig(CONFIG_UINT32_GM_TICKET_LIST_SIZE)) + { + time_t lastChanged = time_t(ticket->GetLastUpdate()); + PSendSysMessage(LANG_COMMAND_TICKET_BRIEF_INFO, ticket->GetId(), player->GetName(), ticket->HasResponse() ? "+" : "-", ctime(&lastChanged)); + } + } + } + + PSendSysMessage(LANG_COMMAND_TICKET_COUNT_ONLINE, std::min(count, uint16(sWorld.getConfig(CONFIG_UINT32_GM_TICKET_LIST_SIZE))), count); + return true; +} + +bool ChatHandler::HandleTicketMeAcceptCommand(char* args) +{ + char* px = ExtractLiteralArg(&args); + if (!px) + { + PSendSysMessage(LANG_COMMAND_TICKET_ACCEPT_STATE, m_session->GetPlayer()->isAcceptTickets() ? "on" : "off"); + return true; + } + + if (!m_session) + { + SendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + // ticket on + if (strncmp(px, "on", 3) == 0) + { + m_session->GetPlayer()->SetAcceptTicket(true); + SendSysMessage(LANG_COMMAND_TICKETON); + } + // ticket off + else if (strncmp(px, "off", 4) == 0) + { + m_session->GetPlayer()->SetAcceptTicket(false); + SendSysMessage(LANG_COMMAND_TICKETOFF); + } + else + return false; + + return true; +} + +bool ChatHandler::HandleTicketRespondCommand(char* args) +{ + GMTicket* ticket = NULL; + + // ticket respond #num + uint32 num; + if (ExtractUInt32(&args, num)) + { + if (num == 0) + return false; + + // mgr numbering tickets start from 0 + ticket = sTicketMgr.GetGMTicket(num); + + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); + SetSentErrorMessage(true); + return false; + } + } + else + { + ObjectGuid target_guid; + std::string target_name; + if (!ExtractPlayerTarget(&args, NULL, &target_guid, &target_name)) + return false; + + // ticket respond $char_name + ticket = sTicketMgr.GetGMTicket(target_guid); + + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + // no response text? + if (!*args) + return false; + + ticket->SetResponseText(args); + + if (Player* pl = sObjectMgr.GetPlayer(ticket->GetPlayerGuid())) + { + pl->GetSession()->SendGMTicketGetTicket(0x06, ticket); + //How should we error here? + if (m_session) + m_session->GetPlayer()->Whisper(args, LANG_UNIVERSAL, pl->GetObjectGuid()); + } + + return true; +} + +bool ChatHandler::HandleTicketShowCommand(char *args) +{ + // ticket #num + char* px = ExtractLiteralArg(&args); + if (!px) + return false; + + uint32 num; + if (ExtractUInt32(&px, num)) + { + if (num == 0) + return false; + + // mgr numbering tickets start from 0 + GMTicket* ticket = sTicketMgr.GetGMTicket(num); + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); + SetSentErrorMessage(true); + return false; + } + + ShowTicket(ticket); + return true; + } + + ObjectGuid target_guid; + std::string target_name; + if (!ExtractPlayerTarget(&px, NULL, &target_guid, &target_name)) + return false; + + // ticket $char_name + GMTicket* ticket = sTicketMgr.GetGMTicket(target_guid); + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); + SetSentErrorMessage(true); + return false; + } + + ShowTicket(ticket); + + return true; +} + +bool ChatHandler::HandleTickerSurveyClose(char *args) +{ + GMTicket* ticket = NULL; + + uint32 num; + if (ExtractUInt32(&args, num)) + { + if (num == 0) + return false; + + ticket = sTicketMgr.GetGMTicket(num); + + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST, num); + SetSentErrorMessage(true); + return false; + } + } + else + { + ObjectGuid target_guid; + std::string target_name; + if (!ExtractPlayerTarget(&args, NULL, &target_guid, &target_name)) + return false; + + // ticket respond $char_name + ticket = sTicketMgr.GetGMTicket(target_guid); + + if (!ticket) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST_NAME, target_name.c_str()); + SetSentErrorMessage(true); + return false; + } + } + + ticket->CloseWithSurvey(); + + //This needs to be before we delete the ticket + Player* pPlayer = sObjectMgr.GetPlayer(ticket->GetPlayerGuid()); + + //For now we can't close tickets for offline players, TODO + if (!pPlayer) + { + SendSysMessage(LANG_COMMAND_TICKET_CANT_CLOSE); + return false; + } + + //This logic feels misplaced, but you can't have it in GMTicket? + sTicketMgr.Delete(ticket->GetPlayerGuid()); + ticket = NULL; + + PSendSysMessage(LANG_COMMAND_TICKETCLOSED_NAME, pPlayer->GetName()); + + return true; +} + /// Helper function inline Creature* Helper_CreateWaypointFor(Creature* wpOwner, WaypointPathOrigin wpOrigin, int32 pathId, uint32 wpId, WaypointNode const* wpNode, CreatureInfo const* waypointInfo) { diff --git a/src/game/Object/GMTicketMgr.cpp b/src/game/Object/GMTicketMgr.cpp index 15fb5e82..e9e6b8d5 100644 --- a/src/game/Object/GMTicketMgr.cpp +++ b/src/game/Object/GMTicketMgr.cpp @@ -116,15 +116,13 @@ void GMTicket::Close() const void GMTicket::_Close(GMTicketStatus statusCode) const { Player* pPlayer = sObjectMgr.GetPlayer(m_guid); - if (!pPlayer) - return; CharacterDatabase.PExecute("UPDATE character_ticket " "SET resolved = 1 " "WHERE guid = %u AND resolved = 0", m_guid.GetCounter()); - if (statusCode != GM_TICKET_STATUS_DO_NOTHING) + if (pPlayer && statusCode != GM_TICKET_STATUS_DO_NOTHING) { pPlayer->GetSession()->SendGMTicketStatusUpdate(statusCode); } } @@ -164,7 +162,7 @@ void GMTicketMgr::LoadGMTickets() GMTicket& ticket = m_GMTicketMap[guid]; ticket.Init(guid, fields[1].GetCppString(), fields[2].GetCppString(), time_t(fields[3].GetUInt64()), fields[4].GetUInt32()); - m_GMTicketListByCreatingOrder.push_back(&ticket); + m_GMTicketIdMap[ticket.GetId()] = &ticket; } while (result->NextRow()); delete result; @@ -202,11 +200,11 @@ void GMTicketMgr::Create(ObjectGuid guid, const char* text) //This implicitly creates a new instance since we're using operator[] GMTicket& ticket = m_GMTicketMap[guid]; if (ticket.GetPlayerGuid()) - m_GMTicketListByCreatingOrder.remove(&ticket); + m_GMTicketIdMap.erase(ticketId); //Lets reinitialize with new data ticket.Init(guid, text, "", time(NULL), ticketId); - m_GMTicketListByCreatingOrder.push_back(&ticket); + m_GMTicketIdMap[ticketId] = &ticket; } void GMTicketMgr::DeleteAll() @@ -217,6 +215,6 @@ void GMTicketMgr::DeleteAll() { owner->GetSession()->SendGMTicketGetTicket(0x0A); } } CharacterDatabase.Execute("DELETE FROM character_ticket"); - m_GMTicketListByCreatingOrder.clear(); + m_GMTicketIdMap.clear(); m_GMTicketMap.clear(); } diff --git a/src/game/Object/GMTicketMgr.h b/src/game/Object/GMTicketMgr.h index 948fbfd7..3860efff 100644 --- a/src/game/Object/GMTicketMgr.h +++ b/src/game/Object/GMTicketMgr.h @@ -57,31 +57,30 @@ * care of what needs to be done by giving back a \ref GMTicket. The database table interesting * in this case is character_ticket in the characaters database. * - * Theres also some handling of tickets in \ref ChatHandler::HandleTicketCommand where + * Theres also some handling of tickets in \ref ChatHandler::HandleTicketAcceptCommand where * you can turn on/off accepting tickets with your current GM char. You can also turn * off tickets globally, this will show the client a message about tickets not being * available at the moment. The commands that can be used are: *
- *
.ticket on/off
+ *
.ticket meaccept on/off
*
Turns on/off showing new incoming tickets for you character
- *
.ticket system_on/off
+ *
.ticket accept on/off
*
Will turn the whole ticket reporting system on/off, ie: if it's off the clients * will get a message that the system is unavailable when trying to submit a ticket
*
.ticket close $character_name/.ticket close #num_of_ticket
*
Will close a ticket for the given character name or the given number of the ticket, * this will make the little icon in the top right go away for the player
- *
.ticket close_survey $character_name/.ticket close_survey #num_of_ticket
+ *
.ticket surveyclose $character_name/.ticket surveyclose #num_of_ticket
*
Does the same as .ticket close but instead of just closing it it also asks the \ref Player * to answer a survey about how please they were with the experience
*
.ticket respond $character_name/.ticket respond #num_of_ticket
*
Will respond to a ticket, this will whisper the \ref Player who asked the question and from * there on you will have to explain the solution etc. and then close the ticket again.
- *
.ticket
+ *
.ticket info
*
Shows the number of currently active tickets
- *
.ticket $character_name/.ticket #num_of_ticket
+ *
.ticket show $character_name/.ticket show #num_of_ticket
*
Will show the question and name of the character for the given ticket
* - * \todo Do not remove tickets from db when closing but mark them as solved instead. * \todo Log conversations between GM and the player receiving help. */ class GMTicket @@ -144,7 +143,7 @@ class GMTicket * \deprecated * \todo Change to resolved/not resolved instead, via the check in db */ - bool HasResponse() { return !m_responseText.empty(); }; + bool HasResponse() { return !m_responseText.empty(); } /** * This will take care of a \ref OpcodesList::CMSG_GMSURVEY_SUBMIT packet @@ -179,7 +178,7 @@ class GMTicket time_t m_lastUpdate; }; typedef std::map GMTicketMap; -typedef std::list GMTicketList; // for creating order access +typedef std::map GMTicketIdMap; // for creating order access class GMTicketMgr { @@ -198,7 +197,15 @@ class GMTicketMgr { return NULL; } return &(itr->second); } - + + GMTicket* GetGMTicket(uint32 id) + { + GMTicketIdMap::iterator itr = m_GMTicketIdMap.find(id); + if (itr == m_GMTicketIdMap.end()) + return NULL; + return itr->second; + } + size_t GetTicketCount() const { return m_GMTicketMap.size(); @@ -209,11 +216,11 @@ class GMTicketMgr if (pos >= GetTicketCount()) { return NULL; } - GMTicketList::iterator itr = m_GMTicketListByCreatingOrder.begin(); + GMTicketMap::iterator itr = m_GMTicketMap.begin(); std::advance(itr, pos); - if (itr == m_GMTicketListByCreatingOrder.end()) + if (itr == m_GMTicketMap.end()) { return NULL; } - return *itr; + return &(itr->second); } /** @@ -229,7 +236,7 @@ class GMTicketMgr GMTicketMap::iterator itr = m_GMTicketMap.find(guid); if (itr == m_GMTicketMap.end()) { return; } - m_GMTicketListByCreatingOrder.remove(&itr->second); + m_GMTicketIdMap.erase(itr->second.GetId()); m_GMTicketMap.erase(itr); } @@ -255,17 +262,17 @@ class GMTicketMgr * file a ticket. * @param accept true means that we accept tickets, false means that we don't */ - void SetAcceptTickets(bool accept) { m_TicketSystemOn = accept; }; + void SetAcceptTickets(bool accept) { m_TicketSystemOn = accept; } /** * Checks if we accept tickets globally (see \ref GMTicketMgr::SetAcceptTickets) * @return true if we are accepting tickets globally, false otherwise * \todo Perhaps rename to IsAcceptingTickets? */ - bool WillAcceptTickets() { return m_TicketSystemOn; }; + bool WillAcceptTickets() { return m_TicketSystemOn; } private: bool m_TicketSystemOn; GMTicketMap m_GMTicketMap; - GMTicketList m_GMTicketListByCreatingOrder; + GMTicketIdMap m_GMTicketIdMap; }; #define sTicketMgr MaNGOS::Singleton::Instance() diff --git a/src/game/Tools/Language.h b/src/game/Tools/Language.h index 570b1e45..335862ab 100644 --- a/src/game/Tools/Language.h +++ b/src/game/Tools/Language.h @@ -1029,7 +1029,12 @@ enum MangosStrings LANG_COMMAND_TICKETS_SYSTEM_ON = 1511, LANG_COMMAND_TICKETS_SYSTEM_OFF = 1512, LANG_COMMAND_TICKET_CANT_CLOSE = 1513, - // Room for more Level 2 1514-1599 not used + LANG_COMMAND_TICKET_BRIEF_INFO = 1514, + LANG_COMMAND_TICKET_COUNT_ONLINE = 1515, + LANG_COMMAND_TICKET_OFFLINE_INFO = 1516, + LANG_COMMAND_TICKET_COUNT_ALL = 1517, + LANG_COMMAND_TICKET_ACCEPT_STATE = 1518, + // Room for more Level 2 1519-1599 not used // Outdoor PvP LANG_OPVP_EP_CAPTURE_NPT_H = 1600, diff --git a/src/game/WorldHandlers/Chat.cpp b/src/game/WorldHandlers/Chat.cpp index 1c4ea363..4c4a604c 100644 --- a/src/game/WorldHandlers/Chat.cpp +++ b/src/game/WorldHandlers/Chat.cpp @@ -661,6 +661,21 @@ ChatCommand* ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; + static ChatCommand ticketCommandTable[] = + { + { "accept", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTicketAcceptCommand, "", NULL }, + { "close", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketCloseCommand, "", NULL }, + { "delete", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTicketDeleteCommand, "", NULL }, + { "info", SEC_MODERATOR, true, &ChatHandler::HandleTicketInfoCommand, "", NULL }, + { "list", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketListCommand, "", NULL }, + { "meaccept", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketMeAcceptCommand, "", NULL }, + { "onlinelist", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketOnlineListCommand, "", NULL }, + { "respond", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketRespondCommand, "", NULL }, + { "show", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketShowCommand, "", NULL }, + { "surveyclose", SEC_GAMEMASTER, true, &ChatHandler::HandleTickerSurveyClose, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand triggerCommandTable[] = { { "active", SEC_GAMEMASTER, false, &ChatHandler::HandleTriggerActiveCommand, "", NULL }, @@ -755,8 +770,7 @@ ChatCommand* ChatHandler::getCommandTable() { "additemset", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddItemSetCommand, "", NULL }, { "bank", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBankCommand, "", NULL }, { "wchange", SEC_ADMINISTRATOR, false, &ChatHandler::HandleChangeWeatherCommand, "", NULL }, - { "ticket", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketCommand, "", NULL }, - { "delticket", SEC_GAMEMASTER, true, &ChatHandler::HandleDelTicketCommand, "", NULL }, + { "ticket", SEC_GAMEMASTER, true, NULL, "", ticketCommandTable }, { "maxskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMaxSkillCommand, "", NULL }, { "setskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetSkillCommand, "", NULL }, { "whispers", SEC_MODERATOR, false, &ChatHandler::HandleWhispersCommand, "", NULL }, diff --git a/src/game/WorldHandlers/Chat.h b/src/game/WorldHandlers/Chat.h index 7c42876b..52839f51 100644 --- a/src/game/WorldHandlers/Chat.h +++ b/src/game/WorldHandlers/Chat.h @@ -574,8 +574,17 @@ class ChatHandler bool HandleChangeWeatherCommand(char* args); bool HandleKickPlayerCommand(char* args); - bool HandleTicketCommand(char* args); - bool HandleDelTicketCommand(char* args); + bool HandleTicketAcceptCommand(char* args); + bool HandleTicketCloseCommand(char* args); + bool HandleTicketDeleteCommand(char* args); + bool HandleTicketInfoCommand(char* args); + bool HandleTicketListCommand(char* args); + bool HandleTicketMeAcceptCommand(char* args); + bool HandleTicketOnlineListCommand(char* args); + bool HandleTicketRespondCommand(char* args); + bool HandleTicketShowCommand(char* args); + bool HandleTickerSurveyClose(char* args); + bool HandleMaxSkillCommand(char* args); bool HandleSetSkillCommand(char* args); bool HandleRespawnCommand(char* args); diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index c8483561..980b294e 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -589,11 +589,13 @@ void World::LoadConfigSettings(bool reload) setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS, "MinPetitionSigns", 9, 0, 9); - setConfig(CONFIG_UINT32_GM_LOGIN_STATE, "GM.LoginState", 2); - setConfig(CONFIG_UINT32_GM_VISIBLE_STATE, "GM.Visible", 2); - setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "GM.AcceptTickets", 2); - setConfig(CONFIG_UINT32_GM_CHAT, "GM.Chat", 2); - setConfig(CONFIG_UINT32_GM_WISPERING_TO, "GM.WhisperingTo", 2); + setConfig(CONFIG_UINT32_GM_LOGIN_STATE, "GM.LoginState", 2); + setConfig(CONFIG_UINT32_GM_VISIBLE_STATE, "GM.Visible", 2); + setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "GM.AcceptTickets", 2); + setConfig(CONFIG_UINT32_GM_TICKET_LIST_SIZE, "GM.TicketListSize", 30); + setConfig(CONFIG_BOOL_GM_TICKET_OFFLINE_CLOSING, "GM.TicketOfflineClosing", false); + setConfig(CONFIG_UINT32_GM_CHAT, "GM.Chat", 2); + setConfig(CONFIG_UINT32_GM_WISPERING_TO, "GM.WhisperingTo", 2); setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST, "GM.InGMList.Level", SEC_ADMINISTRATOR); setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST, "GM.InWhoList.Level", SEC_ADMINISTRATOR); diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index e078cfb3..8dc1562e 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -128,6 +128,7 @@ enum eConfigUInt32Values CONFIG_UINT32_GM_LOGIN_STATE, CONFIG_UINT32_GM_VISIBLE_STATE, CONFIG_UINT32_GM_ACCEPT_TICKETS, + CONFIG_UINT32_GM_TICKET_LIST_SIZE, CONFIG_UINT32_GM_CHAT, CONFIG_UINT32_GM_WISPERING_TO, CONFIG_UINT32_GM_LEVEL_IN_GM_LIST, @@ -362,6 +363,7 @@ enum eConfigBoolValues #endif CONFIG_BOOL_WARDEN_WIN_ENABLED, CONFIG_BOOL_WARDEN_OSX_ENABLED, + CONFIG_BOOL_GM_TICKET_OFFLINE_CLOSING, CONFIG_BOOL_VALUE_COUNT }; @@ -412,7 +414,6 @@ enum RealmZone REALM_ZONE_CN9 = 29 // basic-Latin at create, any at login }; - /// Storage class for commands issued for delayed execution struct CliCommandHolder { diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index fa53fdf5..448c0544 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -3,7 +3,7 @@ ################################################################################ [MangosdConf] -ConfVersion=2015082701 +ConfVersion=2016031901 ################################################################################ # CONNECTIONS AND DIRECTORIES @@ -1088,6 +1088,15 @@ Channel.SilentlyGMJoin = 0 # 0 (disable) # 1 (enable) # +# GM.TicketListSize +# Number of tickets shown to a GM by .ticket list/onlinelist. +# Default: 30 +# +# GM.TicketOfflineClosing +# Is GM ticket close available for teh offline players or not. +# Default: 0 (false) closing denied +# 1 (true) closing enabled +# # GM.Chat # GM chat mode at login # Default: 2 (last save state) @@ -1135,17 +1144,19 @@ Channel.SilentlyGMJoin = 0 # ################################################################################ -GM.LoginState = 2 -GM.Visible = 2 -GM.AcceptTickets = 2 -GM.Chat = 2 -GM.WhisperingTo = 2 -GM.InGMList.Level = 3 -GM.InWhoList.Level = 3 -GM.LogTrade = 1 -GM.StartLevel = 1 -GM.LowerSecurity = 0 -GM.InvisibleAura = 31748 +GM.LoginState = 2 +GM.Visible = 2 +GM.AcceptTickets = 2 +GM.TicketListSize = 30 +GM.TicketOfflineClosing = 1 +GM.Chat = 2 +GM.WhisperingTo = 2 +GM.InGMList.Level = 3 +GM.InWhoList.Level = 3 +GM.LogTrade = 1 +GM.StartLevel = 1 +GM.LowerSecurity = 0 +GM.InvisibleAura = 31748 ################################################################################ # VISIBILITY AND RADIUSES diff --git a/src/shared/SystemConfig.h.in b/src/shared/SystemConfig.h.in index 12561a56..b3c53580 100644 --- a/src/shared/SystemConfig.h.in +++ b/src/shared/SystemConfig.h.in @@ -42,7 +42,7 @@ // Format is YYYYMMDDRR where RR is the change in the conf file // for that day. #ifndef MANGOSD_CONFIG_VERSION -# define MANGOSD_CONFIG_VERSION 2015082701 +# define MANGOSD_CONFIG_VERSION 2016031901 #endif #ifndef REALMD_CONFIG_VERSION # define REALMD_CONFIG_VERSION 2010062001 diff --git a/src/shared/revision.h b/src/shared/revision.h index bf57255b..3c759b50 100644 --- a/src/shared/revision.h +++ b/src/shared/revision.h @@ -37,7 +37,7 @@ #define CHAR_DB_UPDATE_DESCRIPTION "Fix SoR paladin" #define WORLD_DB_VERSION_NR 21 - #define WORLD_DB_STRUCTURE_NR 5 - #define WORLD_DB_CONTENT_NR 2 - #define WORLD_DB_UPDATE_DESCRIPTION "BG template addition" + #define WORLD_DB_STRUCTURE_NR 6 + #define WORLD_DB_CONTENT_NR 1 + #define WORLD_DB_UPDATE_DESCRIPTION "GM Ticket Additions" #endif // __REVISION_H__