diff options
23 files changed, 1311 insertions, 624 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index d2efb12900a..1299a9a698f 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1311,6 +1311,55 @@ LOCK TABLES `game_event_save` WRITE; UNLOCK TABLES; -- +-- Table structure for table `gm_subsurveys` +-- +DROP TABLE IF EXISTS `gm_subsurveys`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_subsurveys` ( + `surveyid` int(10) NOT NULL, + `subsurveyid` int(11) UNSIGNED NOT NULL DEFAULT '0', + `rank` int(11) UNSIGNED NOT NULL DEFAULT '0', + `comment` longtext NOT NULL DEFAULT '', + PRIMARY KEY (`surveyid`,`subsurveyid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_subsurveys` +-- + +LOCK TABLES `gm_subsurveys` WRITE; +/*!40000 ALTER TABLE `gm_subsurveys` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_subsurveys` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gm_surveys` +-- +DROP TABLE IF EXISTS `gm_surveys`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_surveys` ( + `surveyid` int(10) NOT NULL auto_increment, + `player` int(11) UNSIGNED NOT NULL DEFAULT '0', + `mainSurvey` int(11) UNSIGNED NOT NULL DEFAULT '0', + `overall_comment` longtext NOT NULL DEFAULT '', + `timestamp` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`surveyid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_surveys` +-- + +LOCK TABLES `gm_surveys` WRITE; +/*!40000 ALTER TABLE `gm_surveys` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_surveys` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `gm_tickets` -- @@ -1331,6 +1380,9 @@ CREATE TABLE `gm_tickets` ( `closed` int(10) NOT NULL default '0', `assignedto` int(10) NOT NULL default '0', `comment` text NOT NULL, + `completed` int(11) NOT NULL DEFAULT '0', + `escalated` int(11) NOT NULL DEFAULT '0', + `viewed` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`guid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1792,6 +1844,34 @@ LOCK TABLES `item_refund_instance` WRITE; UNLOCK TABLES; -- +-- Table structure for table `lag_reports` +-- + +DROP TABLE IF EXISTS `lag_reports`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `lag_reports` ( + `report_id` int(10) NOT NULL auto_increment, + `player` int(11) UNSIGNED NOT NULL DEFAULT '0', + `lag_type` int(10) NOT NULL DEFAULT '0', + `map` int(11) NOT NULL DEFAULT '0', + `posX` float NOT NULL default '0', + `posY` float NOT NULL default '0', + `posZ` float NOT NULL default '0', + PRIMARY KEY (`report_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `lag_reports` +-- + +LOCK TABLES `lag_reports` WRITE; +/*!40000 ALTER TABLE `lag_reports` DISABLE KEYS */; +/*!40000 ALTER TABLE `lag_reports` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `mail` -- diff --git a/sql/updates/9668_characters_gm_subsurveys.sql b/sql/updates/9668_characters_gm_subsurveys.sql new file mode 100644 index 00000000000..4dae1442a3d --- /dev/null +++ b/sql/updates/9668_characters_gm_subsurveys.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS `gm_subsurveys`; +CREATE TABLE `gm_subsurveys` ( + `surveyid` int(10) NOT NULL auto_increment, + `subsurveyid` int(11) UNSIGNED NOT NULL DEFAULT '0', + `rank` int(11) UNSIGNED NOT NULL DEFAULT '0', + `comment` longtext NOT NULL DEFAULT '', + PRIMARY KEY (`surveyid`,`subsurveyid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; diff --git a/sql/updates/9668_characters_gm_surveys.sql b/sql/updates/9668_characters_gm_surveys.sql new file mode 100644 index 00000000000..4f7aa5a6c91 --- /dev/null +++ b/sql/updates/9668_characters_gm_surveys.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS `gm_surveys`; +CREATE TABLE `gm_surveys` ( + `surveyid` int(10) NOT NULL auto_increment, + `player` int(11) UNSIGNED NOT NULL DEFAULT '0', + `mainSurvey` int(11) UNSIGNED NOT NULL DEFAULT '0', + `overall_comment` longtext NOT NULL DEFAULT '', + `timestamp` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`surveyid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; diff --git a/sql/updates/9668_characters_gm_tickets.sql b/sql/updates/9668_characters_gm_tickets.sql new file mode 100644 index 00000000000..71f13206f72 --- /dev/null +++ b/sql/updates/9668_characters_gm_tickets.sql @@ -0,0 +1,3 @@ +ALTER TABLE `gm_tickets` ADD COLUMN `completed` int(11) NOT NULL DEFAULT '0' AFTER `comment`; +ALTER TABLE `gm_tickets` ADD COLUMN `escalated` int(11) NOT NULL DEFAULT '0' AFTER `completed`; +ALTER TABLE `gm_tickets` ADD COLUMN `viewed` int(11) NOT NULL DEFAULT '0' AFTER `escalated`; diff --git a/sql/updates/9668_characters_lag_reports.sql b/sql/updates/9668_characters_lag_reports.sql new file mode 100644 index 00000000000..956bccba8f3 --- /dev/null +++ b/sql/updates/9668_characters_lag_reports.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS `lag_reports`; +CREATE TABLE `lag_reports` ( + `report_id` int(10) NOT NULL auto_increment, + `player` int(11) UNSIGNED NOT NULL DEFAULT '0', + `lag_type` int(10) NOT NULL DEFAULT '0', + `map` int(11) NOT NULL DEFAULT '0', + `posX` float NOT NULL default '0', + `posY` float NOT NULL default '0', + `posZ` float NOT NULL default '0', + PRIMARY KEY (`report_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 679210778f1..4fbdc53c420 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -907,7 +907,7 @@ bool AuthSocket::_HandleXferResume() uint64 start; socket().recv_skip(1); socket().recv((char*)&start,sizeof(start)); - fseek(pPatch, start, 0); + fseek(pPatch, long(start), 0); ACE_Based::Thread u(new PatcherRunnable(this)); return true; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 9a9342d97c4..37108c64e9e 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -45,6 +45,7 @@ file(GLOB_RECURSE sources_Server Server/*.cpp Server/*.h) file(GLOB_RECURSE sources_Skills Skills/*.cpp Skills/*.h) file(GLOB_RECURSE sources_Spells Spells/*.cpp Spells/*.h) file(GLOB_RECURSE sources_Tools Tools/*.cpp Tools/*.h) +file(GLOB_RECURSE sources_Tickets Tickets/*.cpp Tickets/*.h) file(GLOB_RECURSE sources_Weather Weather/*.cpp Weather/*.h) file(GLOB_RECURSE sources_World World/*.cpp World/*.h) @@ -92,6 +93,7 @@ set(game_STAT_SRCS ${sources_Skills} ${sources_Spells} ${sources_Tools} + ${sources_Tickets} ${sources_Weather} ${sources_World} ) @@ -181,6 +183,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Spells ${CMAKE_CURRENT_SOURCE_DIR}/Spells/Auras ${CMAKE_CURRENT_SOURCE_DIR}/Tools + ${CMAKE_CURRENT_SOURCE_DIR}/Tickets ${CMAKE_CURRENT_SOURCE_DIR}/Weather ${CMAKE_CURRENT_SOURCE_DIR}/World ${CMAKE_SOURCE_DIR}/src/server/scripts/PrecompiledHeaders diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 373559b73cc..9ff18aba367 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -659,6 +659,13 @@ ChatCommand * ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; + static ChatCommand ticketResponseCommandTable[] = + { + { "append", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketResponseAppendCommand, "", NULL }, + { "appendln", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketResponseAppendLnCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketCommandTable[] = { { "list", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketListCommand, "", NULL }, @@ -667,10 +674,15 @@ ChatCommand * ChatHandler::getCommandTable() { "viewid", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketGetByIdCommand, "", NULL }, { "close", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketCloseByIdCommand, "", NULL }, { "closedlist", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketListClosedCommand, "", NULL }, + { "escalatedlist", SEC_GAMEMASTER, false, &ChatHandler::HandleGMTicketListEscalatedCommand, "", NULL }, { "delete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGMTicketDeleteByIdCommand, "", NULL }, - { "assign", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketAssignToCommand, "", NULL }, - { "unassign", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketUnAssignCommand, "", NULL }, + { "assign", SEC_GAMEMASTER, false, &ChatHandler::HandleGMTicketAssignToCommand, "", NULL }, + { "unassign", SEC_GAMEMASTER, false, &ChatHandler::HandleGMTicketUnAssignCommand, "", NULL }, { "comment", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketCommentCommand, "", NULL }, + { "togglesystem", SEC_ADMINISTRATOR, false, &ChatHandler::HandleToggleGMTicketSystem, "", NULL }, + { "escalate", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketEscalateCommand, "", NULL }, + { "response", SEC_MODERATOR, false, NULL, "", ticketResponseCommandTable }, + { "complete", SEC_MODERATOR, false, &ChatHandler::HandleGMTicketCompleteCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 913e9b71360..6e84ae67511 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -566,6 +566,7 @@ class ChatHandler bool HandleGMTicketListCommand(const char* args); bool HandleGMTicketListOnlineCommand(const char* args); bool HandleGMTicketListClosedCommand(const char* args); + bool HandleGMTicketListEscalatedCommand(const char* args); bool HandleGMTicketGetByIdCommand(const char* args); bool HandleGMTicketGetByNameCommand(const char* args); bool HandleGMTicketCloseByIdCommand(const char* args); @@ -574,6 +575,11 @@ class ChatHandler bool HandleGMTicketCommentCommand(const char* args); bool HandleGMTicketDeleteByIdCommand(const char* args); bool HandleGMTicketReloadCommand(const char*); + bool HandleToggleGMTicketSystem(const char* args); + bool HandleGMTicketEscalateCommand(const char* args); + bool HandleGMTicketCompleteCommand(const char* args); + bool HandleGMTicketResponseAppendCommand(const char* args); + bool HandleGMTicketResponseAppendLnCommand(const char* args); bool HandleMaxSkillCommand(const char* args); bool HandleSetSkillCommand(const char* args); diff --git a/src/server/game/Chat/Commands/Level1.cpp b/src/server/game/Chat/Commands/Level1.cpp index c9ef15c50ad..3f50ec762cb 100644 --- a/src/server/game/Chat/Commands/Level1.cpp +++ b/src/server/game/Chat/Commands/Level1.cpp @@ -24,6 +24,7 @@ #include "WorldSession.h" #include "World.h" #include "ObjectMgr.h" +#include "TicketMgr.h" #include "Player.h" #include "AccountMgr.h" #include "Opcodes.h" @@ -288,377 +289,6 @@ bool ChatHandler::HandleGMChatCommand(const char* args) return false; } -std::string ChatHandler::PGetParseString(int32 entry, ...) -{ - const char *format = GetTrinityString(entry); - va_list ap; - char str [1024]; - va_start(ap, entry); - vsnprintf(str,1024,format, ap); - va_end(ap); - return (std::string)str; -} - -bool ChatHandler::HandleGMTicketListCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); - for (GmTicketList::iterator itr = sObjectMgr.m_GMTicketList.begin(); itr != sObjectMgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed != 0) - continue; - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketListOnlineCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWONLINELIST); - for (GmTicketList::iterator itr = sObjectMgr.m_GMTicketList.begin(); itr != sObjectMgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed != 0 || !sObjectMgr.GetPlayer((*itr)->playerGuid)) - continue; - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketListClosedCommand(const char* /*args*/) -{ - SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); - for (GmTicketList::iterator itr = sObjectMgr.m_GMTicketList.begin(); itr != sObjectMgr.m_GMTicketList.end(); ++itr) - { - if ((*itr)->closed == 0) - continue; - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); - if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - SendSysMessage(ss.str().c_str()); - } - return true; -} - -bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args) -{ - if (!*args) - return false; - - uint64 tguid = atoi(args); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(tguid); - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); - if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); - if (ticket->comment != "") - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); - } - SendSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) -{ - if (!*args) - return false; - - std::string name = (char*)args; - normalizePlayerName(name); - - Player *plr = sObjectMgr.GetPlayer(name.c_str()); - if (!plr) - { - SendSysMessage(LANG_NO_PLAYERS_FOUND); - return true; - } - - GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(plr->GetGUID()); - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - std::string gmname; - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); - if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); - if (ticket->comment != "") - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); - } - SendSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args) -{ - if (!*args) - return false; - - uint64 tguid = atoi(args); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(tguid); - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket && ticket->assignedToGM != 0 && ticket->assignedToGM != m_session->GetPlayer()->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->guid); - return true; - } - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETCLOSED, m_session->GetPlayer()->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); - sObjectMgr.RemoveGMTicket(ticket, m_session->GetPlayer()->GetGUID()); - - if (!plr || !plr->IsInWorld()) - return true; - - // send abandon ticket - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); - plr->GetSession()->SendPacket(&data); - return true; -} - -bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) -{ - if (!*args) - return false; - - char* tguid = strtok((char*)args, " "); - uint64 ticketGuid = atoi(tguid); - char* targetgm = strtok(NULL, " "); - - if (!targetgm) - return false; - - std::string targm = targetgm; - if (!normalizePlayerName(targm)) - return false; - - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(ticketGuid); - - if (!ticket || ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - uint64 tarGUID = sObjectMgr.GetPlayerGUIDByName(targm.c_str()); - uint64 accid = sObjectMgr.GetPlayerAccountIdByGUID(tarGUID); - uint32 gmlevel = sAccountMgr.GetSecurity(accid, realmID); - - if (!tarGUID || gmlevel == SEC_PLAYER) - { - SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); - return true; - } - - if (ticket->assignedToGM == tarGUID) - { - PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->guid); - return true; - } - - std::string gmname; - sObjectMgr.GetPlayerNameByGUID(tarGUID, gmname); - if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str()); - return true; - } - - ticket->assignedToGM = tarGUID; - sObjectMgr.AddOrUpdateGMTicket(*ticket); - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - SendGlobalGMSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) -{ - if (!*args) - return false; - - uint64 ticketGuid = atoi(args); - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(ticketGuid); - - if (!ticket|| ticket->closed != 0) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->assignedToGM == 0) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->guid); - return true; - } - - std::string gmname; - sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); - Player *plr = sObjectMgr.GetPlayer(ticket->assignedToGM); - if (plr && plr->IsInWorld() && plr->GetSession()->GetSecurity() > cplr->GetSession()->GetSecurity()) - { - SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); - return true; - } - - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, cplr->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - ticket->assignedToGM = 0; - sObjectMgr.AddOrUpdateGMTicket(*ticket); - return true; -} - -bool ChatHandler::HandleGMTicketCommentCommand(const char* args) -{ - if (!*args) - return false; - - char* tguid = strtok((char*)args, " "); - uint64 ticketGuid = atoi(tguid); - char* comment = strtok(NULL, "\n"); - - if (!comment) - return false; - - Player *cplr = m_session->GetPlayer(); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(ticketGuid); - - if (!ticket || ticket->closed != 0) - { - PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) - { - PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); - return true; - } - - std::string gmname; - sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); - ticket->comment = comment; - sObjectMgr.AddOrUpdateGMTicket(*ticket); - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) - { - ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); - } - ss << PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, cplr->GetName(), ticket->comment.c_str()); - SendGlobalGMSysMessage(ss.str().c_str()); - return true; -} - -bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) -{ - if (!*args) - return false; - uint64 ticketGuid = atoi(args); - GM_Ticket *ticket = sObjectMgr.GetGMTicket(ticketGuid); - - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - if (ticket->closed == 0) - { - SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); - return true; - } - - std::stringstream ss; - ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); - ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); - ss << PGetParseString(LANG_COMMAND_TICKETDELETED, m_session->GetPlayer()->GetName()); - SendGlobalGMSysMessage(ss.str().c_str()); - Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); - sObjectMgr.RemoveGMTicket(ticket, -1, true); - if (plr && plr->IsInWorld()) - { - // Force abandon ticket - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); - plr->GetSession()->SendPacket(&data); - } - - ticket = NULL; - return true; -} - -bool ChatHandler::HandleGMTicketReloadCommand(const char*) -{ - sObjectMgr.LoadGMTickets(); - return true; -} - //Enable\Dissable Invisible mode bool ChatHandler::HandleGMVisibleCommand(const char* args) { diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp index 3074a842990..c89be230a93 100644 --- a/src/server/game/Chat/Commands/Level2.cpp +++ b/src/server/game/Chat/Commands/Level2.cpp @@ -138,48 +138,6 @@ bool ChatHandler::HandleUnmuteCommand(const char* args) return true; } -bool ChatHandler::HandleGoTicketCommand(const char * args) -{ - if (!*args) - return false; - - char *cstrticket_id = strtok((char*)args, " "); - - if (!cstrticket_id) - return false; - - uint64 ticket_id = atoi(cstrticket_id); - if (!ticket_id) - return false; - - GM_Ticket *ticket = sObjectMgr.GetGMTicket(ticket_id); - if (!ticket) - { - SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - float x, y, z; - int mapid; - - x = ticket->pos_x; - y = ticket->pos_y; - z = ticket->pos_z; - mapid = ticket->map; - - Player* _player = m_session->GetPlayer(); - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, 1, 0); - return true; -} - bool ChatHandler::HandleGoTriggerCommand(const char* args) { Player* _player = m_session->GetPlayer(); diff --git a/src/server/game/Chat/Commands/TicketCommands.cpp b/src/server/game/Chat/Commands/TicketCommands.cpp new file mode 100644 index 00000000000..fc1db823a68 --- /dev/null +++ b/src/server/game/Chat/Commands/TicketCommands.cpp @@ -0,0 +1,596 @@ +/* + * 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 "DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectMgr.h" +#include "TicketMgr.h" +#include "AccountMgr.h" +#include "Chat.h" +#include "Player.h" + +std::string ChatHandler::PGetParseString(int32 entry, ...) +{ + const char *format = GetTrinityString(entry); + va_list ap; + char str [1024]; + va_start(ap, entry); + vsnprintf(str,1024,format, ap); + va_end(ap); + return (std::string)str; +} + +bool ChatHandler::HandleGMTicketListCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (GmTicketList::iterator itr = sTicketMgr.m_GMTicketList.begin(); itr != sTicketMgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed != 0 || (*itr)->completed) + continue; + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + + if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketListOnlineCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWONLINELIST); + for (GmTicketList::iterator itr = sTicketMgr.m_GMTicketList.begin(); itr != sTicketMgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed != 0 || (*itr)->completed || !sObjectMgr.GetPlayer((*itr)->playerGuid)) + continue; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketListClosedCommand(const char* /*args*/) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (GmTicketList::iterator itr = sTicketMgr.m_GMTicketList.begin(); itr != sTicketMgr.m_GMTicketList.end(); ++itr) + { + if ((*itr)->closed == 0) + continue; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + if (sObjectMgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketListEscalatedCommand(const char* args) +{ + SendSysMessage(LANG_COMMAND_TICKETSHOWESCALATEDLIST); + for (GmTicketList::iterator itr = sTicketMgr.m_GMTicketList.begin(); itr != sTicketMgr.m_GMTicketList.end(); ++itr) + { + if (!((*itr)->escalated == TICKET_IN_ESCALATION_QUEUE) || (*itr)->closed != 0) + continue; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, (*itr)->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, (*itr)->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - (*itr)->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - (*itr)->timestamp, true, false)).c_str()); + SendSysMessage(ss.str().c_str()); + } + return true; +} + +bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0 || ticket->completed) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + ticket->viewed = true; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); + + if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + + ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); + + if (strlen(ticket->comment.c_str()) != 0) + ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); + + SendSysMessage(ss.str().c_str()); + return true; +} + +bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) +{ + if (!*args) + return false; + + std::string name = (char*)args; + normalizePlayerName(name); + + Player *plr = sObjectMgr.GetPlayer(name.c_str()); + if (!plr) + { + SendSysMessage(LANG_NO_PLAYERS_FOUND); + return true; + } + + GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(plr->GetGUID()); + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + ticket->viewed = true; + + std::string gmname; + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(time(NULL) - ticket->createtime, true, false)).c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(time(NULL) - ticket->timestamp, true, false)).c_str()); + + if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + + ss << PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, ticket->message.c_str()); + + if (strlen(ticket->comment.c_str()) != 0) + ss << PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, ticket->comment.c_str()); + + SendSysMessage(ss.str().c_str()); + + return true; +} + +bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0 || ticket->completed) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + if (ticket && ticket->assignedToGM != 0 && ticket->assignedToGM != m_session->GetPlayer()->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->guid); + return true; + } + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETCLOSED, m_session->GetPlayer()->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); + sTicketMgr.RemoveGMTicket(ticket, m_session->GetPlayer()->GetGUID()); + + if (!plr || !plr->IsInWorld()) + return true; + + // send abandon ticket + WorldPacket deleteTicket(SMSG_GMTICKET_DELETETICKET, 4); + deleteTicket << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + plr->GetSession()->SendPacket(&deleteTicket); + + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* targetgm = strtok(NULL, " "); + + if (!targetgm) + return false; + + std::string targm = targetgm; + if (!normalizePlayerName(targm)) + return false; + + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + + if (!ticket || ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + uint64 tarGUID = sObjectMgr.GetPlayerGUIDByName(targm.c_str()); + uint64 accid = sObjectMgr.GetPlayerAccountIdByGUID(tarGUID); + uint32 gmlevel = sAccountMgr.GetSecurity(accid, realmID); + + if (!tarGUID || gmlevel == SEC_PLAYER) + { + SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); + return true; + } + + if (ticket->assignedToGM == tarGUID) + { + PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->guid); + return true; + } + + std::string gmname; + sObjectMgr.GetPlayerNameByGUID(tarGUID, gmname); + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str()); + return true; + } + + ticket->assignedToGM = tarGUID; + + if (gmlevel == SEC_ADMINISTRATOR && ticket->escalated == TICKET_IN_ESCALATION_QUEUE) + ticket->escalated = TICKET_ESCALATED_ASSIGNED; + else if (ticket->escalated == TICKET_UNASSIGNED) + ticket->escalated = TICKET_ASSIGNED; + + sTicketMgr.AddOrUpdateGMTicket(*ticket); + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + SendGlobalGMSysMessage(ss.str().c_str()); + + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) +{ + if (!*args) + return false; + + uint64 ticketGuid = atoi(args); + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + + if (!ticket|| ticket->closed != 0) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->assignedToGM == 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->guid); + return true; + } + + std::string gmname; + sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); + Player *plr = sObjectMgr.GetPlayer(ticket->assignedToGM); + if (plr && plr->IsInWorld() && plr->GetSession()->GetSecurity() > cplr->GetSession()->GetSecurity()) + { + SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); + return true; + } + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, cplr->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + ticket->assignedToGM = 0; + if (ticket->escalated != TICKET_UNASSIGNED && ticket->escalated != TICKET_IN_ESCALATION_QUEUE) + ticket->escalated--; + sTicketMgr.AddOrUpdateGMTicket(*ticket); + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketCommentCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* comment = strtok(NULL, "\n"); + + if (!comment) + return false; + + Player *cplr = m_session->GetPlayer(); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + + if (!ticket || ticket->closed != 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); + return true; + } + + std::string gmname; + sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname); + ticket->comment = comment; + sTicketMgr.AddOrUpdateGMTicket(*ticket); + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + + if (sObjectMgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname)) + ss << PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, gmname.c_str()); + + ss << PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, cplr->GetName(), ticket->comment.c_str()); + SendGlobalGMSysMessage(ss.str().c_str()); + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) +{ + if (!*args) + return false; + uint64 ticketGuid = atoi(args); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + if (ticket->closed == 0) + { + SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); + return true; + } + + std::stringstream ss; + ss << PGetParseString(LANG_COMMAND_TICKETLISTGUID, ticket->guid); + ss << PGetParseString(LANG_COMMAND_TICKETLISTNAME, ticket->name.c_str()); + ss << PGetParseString(LANG_COMMAND_TICKETDELETED, m_session->GetPlayer()->GetName()); + SendGlobalGMSysMessage(ss.str().c_str()); + Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); + sTicketMgr.RemoveGMTicket(ticket, -1, true); // we don't need to care about who deleted it... + if (plr && plr->IsInWorld()) + { + // Force abandon ticket + WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); + data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + plr->GetSession()->SendPacket(&data); + } + + ticket = NULL; + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketReloadCommand(const char* /* args */) +{ + sTicketMgr.LoadGMTickets(); + return true; +} + +bool ChatHandler::HandleToggleGMTicketSystem(const char* /* args */) +{ + sTicketMgr.SetStatus(!sTicketMgr.GetStatus()); + return true; +} + +bool ChatHandler::HandleGoTicketCommand(const char * args) +{ + if (!*args) + return false; + + char *cstrticket_id = strtok((char*)args, " "); + + if (!cstrticket_id) + return false; + + uint64 ticket_id = atoi(cstrticket_id); + if (!ticket_id) + return false; + + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticket_id); + if (!ticket) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + float x, y, z; + int mapid; + + x = ticket->pos_x; + y = ticket->pos_y; + z = ticket->pos_z; + mapid = ticket->map; + + Player* _player = m_session->GetPlayer(); + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + else + _player->SaveRecallPosition(); + + _player->TeleportTo(mapid, x, y, z, 1, 0); + return true; +} + +bool ChatHandler::HandleGMTicketEscalateCommand(const char *args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0 || ticket->completed || ticket->escalated != TICKET_UNASSIGNED) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + ticket->escalated = TICKET_IN_ESCALATION_QUEUE; + + Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); + if (plr && plr->IsInWorld()) + plr->GetSession()->SendGMTicketGetTicket(GMTICKET_STATUS_HASTEXT, ticket->message.c_str(), ticket); + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketCompleteCommand(const char* args) +{ + if (!*args) + return false; + + uint64 tguid = atoi(args); + GM_Ticket *ticket = sTicketMgr.GetGMTicket(tguid); + if (!ticket || ticket->closed != 0 || ticket->completed) + { + SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + Player *plr = sObjectMgr.GetPlayer(ticket->playerGuid); + if (plr && plr->IsInWorld()) + plr->GetSession()->SendGMTicketResponse(ticket); + sTicketMgr.UpdateLastChange(); + return true; +} + +bool ChatHandler::HandleGMTicketResponseAppendCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* response = strtok(NULL, "\n"); + + if (!response) + return false; + + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + Player *cplr = m_session->GetPlayer(); + + if (!ticket || ticket->closed != 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); + return true; + } + + std::stringstream ss; + ss << ticket->response; + ss << response; + ticket->response = ss.str(); + sTicketMgr.AddOrUpdateGMTicket(*ticket); + return true; +} + +bool ChatHandler::HandleGMTicketResponseAppendLnCommand(const char* args) +{ + if (!*args) + return false; + + char* tguid = strtok((char*)args, " "); + uint64 ticketGuid = atoi(tguid); + char* response = strtok(NULL, "\n"); + + if (!response) + return false; + + GM_Ticket *ticket = sTicketMgr.GetGMTicket(ticketGuid); + Player *cplr = m_session->GetPlayer(); + + if (!ticket || ticket->closed != 0) + { + PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + if (ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID()) + { + PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid); + return true; + } + + std::stringstream ss; + ss << ticket->response; + ss << response; + ss << "\n"; + ticket->response = ss.str(); + sTicketMgr.AddOrUpdateGMTicket(*ticket); + return true; +} diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index aecf48a4f1a..e9fec505d22 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -8816,129 +8816,6 @@ Quest const* GetQuestTemplateStore(uint32 entry) return sObjectMgr.GetQuestTemplate(entry); } -uint64 ObjectMgr::GenerateGMTicketId() -{ - return ++m_GMticketid; -} - -void ObjectMgr::LoadGMTickets() -{ - if (!m_GMTicketList.empty()) - { - for (GmTicketList::const_iterator itr = m_GMTicketList.begin(); itr != m_GMTicketList.end(); ++itr) - delete *itr; - } - m_GMTicketList.clear(); - m_GMticketid = 0; - - QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment FROM gm_tickets"); - - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outString(">> GM Tickets table is empty, no tickets were loaded."); - return; - } - - uint16 count = 0; - barGoLink bar ((*result).GetRowCount()); - GM_Ticket *ticket; - do - { - Field *fields = result->Fetch(); - ticket = new GM_Ticket; - ticket->guid = fields[0].GetUInt64(); - ticket->playerGuid = fields[1].GetUInt64(); - ticket->name = fields[2].GetCppString(); - ticket->message = fields[3].GetCppString(); - ticket->createtime = fields[4].GetUInt64(); - ticket->map = fields[5].GetUInt32(); - ticket->pos_x = fields[6].GetFloat(); - ticket->pos_y = fields[7].GetFloat(); - ticket->pos_z = fields[8].GetFloat(); - ticket->timestamp = fields[9].GetUInt64(); - ticket->closed = fields[10].GetUInt64(); - ticket->assignedToGM = fields[11].GetUInt64(); - ticket->comment = fields[12].GetCppString(); - ++count; - bar.step(); - - m_GMTicketList.push_back(ticket); - - } while (result->NextRow()); - - result = CharacterDatabase.Query("SELECT MAX(guid) from gm_tickets"); - - if (result) - { - Field *fields = result->Fetch(); - m_GMticketid = fields[0].GetUInt64(); - } - - sLog.outString(">> Loaded %u GM Tickets from the database.", count); -} - -void ObjectMgr::AddOrUpdateGMTicket(GM_Ticket &ticket, bool create) -{ - if (create) - m_GMTicketList.push_back(&ticket); - - _AddOrUpdateGMTicket(ticket); -} - -void ObjectMgr::_AddOrUpdateGMTicket(GM_Ticket &ticket) -{ - std::string msg(ticket.message), name(ticket.name), comment(ticket.comment); - CharacterDatabase.escape_string(msg); - CharacterDatabase.escape_string(name); - CharacterDatabase.escape_string(comment); - std::ostringstream ss; - ss << "REPLACE INTO gm_tickets (guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment) VALUES('"; - ss << ticket.guid << "', '"; - ss << ticket.playerGuid << "', '"; - ss << name << "', '"; - ss << msg << "', '" ; - ss << ticket.createtime << "', '"; - ss << ticket.map << "', '"; - ss << ticket.pos_x << "', '"; - ss << ticket.pos_y << "', '"; - ss << ticket.pos_z << "', '"; - ss << ticket.timestamp << "', '"; - ss << ticket.closed << "', '"; - ss << ticket.assignedToGM << "', '"; - ss << comment << "');"; - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->Append(ss.str().c_str()); - CharacterDatabase.CommitTransaction(trans); -} - -void ObjectMgr::RemoveGMTicket(GM_Ticket *ticket, int64 source, bool permanently) -{ - for (GmTicketList::iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i)->guid == ticket->guid) - { - if (permanently) - { - CharacterDatabase.PExecute("DELETE FROM gm_tickets WHERE guid = '%u'", ticket->guid); - i = m_GMTicketList.erase(i); - ticket = NULL; - return; - } - (*i)->closed = source; - _AddOrUpdateGMTicket(*(*i)); - } -} - -void ObjectMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently) -{ - GM_Ticket *ticket = GetGMTicket(ticketGuid); - ASSERT(ticket); - RemoveGMTicket(ticket, source, permanently); -} - CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unitClass) { CreatureBaseStatsMap::const_iterator it = m_creatureBaseStatsMap.find(MAKE_PAIR16(level,unitClass)); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index fab85d8678f..389b017b959 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -337,23 +337,6 @@ enum SkillRangeType SKILL_RANGE_NONE, // 0..0 always }; -struct GM_Ticket -{ - uint64 guid; - uint64 playerGuid; - std::string name; - float pos_x; - float pos_y; - float pos_z; - uint32 map; - std::string message; - uint64 createtime; - uint64 timestamp; - int64 closed; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. - uint64 assignedToGM; - std::string comment; -}; -typedef std::list<GM_Ticket*> GmTicketList; SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); #define MAX_PLAYER_NAME 12 // max allowed by client name length @@ -713,7 +696,6 @@ class ObjectMgr void LoadTrainerSpell(); bool AddSpellToTrainer(uint32 entry, uint32 spell, Field *fields, std::set<uint32> *skip_trainers, std::set<uint32> *talentIds); int LoadReferenceTrainer(uint32 trainer, int32 spell, std::set<uint32> *skip_trainers, std::set<uint32> *talentIds); - void LoadGMTickets(); std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); @@ -950,23 +932,6 @@ class ObjectMgr return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id)); } - GM_Ticket *GetGMTicket(uint64 ticketGuid) - { - for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i) && (*i)->guid == ticketGuid) - return (*i); - - return NULL; - } - GM_Ticket *GetGMTicketByPlayer(uint64 playerGuid) - { - for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if ((*i) && (*i)->playerGuid == playerGuid && (*i)->closed == 0) - return (*i); - - return NULL; - } - GossipMenusMapBounds GetGossipMenusMapBounds(uint32 uiMenuId) const { return GossipMenusMapBounds(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId)); @@ -986,13 +951,6 @@ class ObjectMgr return GossipMenuItemsMapBoundsNonConst(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId)); } - void AddOrUpdateGMTicket(GM_Ticket &ticket, bool create = false); - void _AddOrUpdateGMTicket(GM_Ticket &ticket); - void RemoveGMTicket(uint64 ticketGuid, int64 source = -1, bool permanently = false); - void RemoveGMTicket(GM_Ticket *ticket, int64 source = -1, bool permanently = false); - GmTicketList m_GMTicketList; - uint64 GenerateGMTicketId(); - // for wintergrasp only GraveYardMap mGraveYardMap; @@ -1013,7 +971,6 @@ class ObjectMgr uint32 m_ItemTextId; uint32 m_mailid; uint32 m_hiPetNumber; - uint64 m_GMticketid; // first free low guid for seelcted guid type uint32 m_hiCharGuid; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 91cd6e29310..d9d7b4fb3eb 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -869,6 +869,7 @@ enum TrinityStrings LANG_COMMAND_TICKETLISTCOMMENT = 2023, LANG_COMMAND_TICKETLISTADDCOMMENT = 2024, LANG_COMMAND_TICKETLISTAGECREATE = 2025, + LANG_COMMAND_TICKETSHOWESCALATEDLIST = 2026, // Trinity strings 5000-9999 LANG_COMMAND_FREEZE = 5000, diff --git a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp index 7ddf3ca6c91..8d6f8a13294 100644 --- a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp @@ -22,8 +22,11 @@ #include "WorldPacket.h" #include "Common.h" #include "ObjectMgr.h" +#include "TicketMgr.h" #include "Player.h" #include "World.h" +#include "WorldSession.h" +#include "Util.h" void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) { @@ -33,31 +36,32 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) return; } - if (GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) + if (GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) { WorldPacket data(SMSG_GMTICKET_CREATE, 4); - data << uint32(1); // 1 - You already have GM ticket + data << uint32(GMTICKET_RESPONSE_FAILURE); // You already have GM ticket SendPacket(&data); return; } - uint32 map; + uint32 map, unk1; + uint8 needResponse; // ignored float x, y, z; std::string ticketText, ticketText2; SendQueryTimeResponse(); - WorldPacket data(SMSG_GMTICKET_CREATE, 4); recv_data >> map; recv_data >> x; recv_data >> y; recv_data >> z; recv_data >> ticketText; - recv_data >> ticketText2; + recv_data >> unk1; // not sure what this is... replyTo? + recv_data >> needResponse; // always 1/0 -- not sure what retail does with this GM_Ticket *ticket = new GM_Ticket; ticket->name = GetPlayer()->GetName(); - ticket->guid = sObjectMgr.GenerateGMTicketId(); + ticket->guid = sTicketMgr.GenerateGMTicketId(); ticket->playerGuid = GetPlayer()->GetGUID(); ticket->message = ticketText; ticket->createtime = time(NULL); @@ -69,27 +73,29 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) ticket->closed = 0; ticket->assignedToGM = 0; ticket->comment = ""; + ticket->completed = false; + ticket->escalated = TICKET_UNASSIGNED; + ticket->response = ""; - sObjectMgr.AddOrUpdateGMTicket(*ticket, true); + sTicketMgr.AddOrUpdateGMTicket(*ticket, true); - data << uint32(2); + WorldPacket data(SMSG_GMTICKET_CREATE, 4); + data << uint32(GMTICKET_RESPONSE_SUCCESS); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid); - } void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) { - WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); - std::string message; recv_data >> message; - GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); if (!ticket) { - data << uint32(1); + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + data << uint32(GMTICKET_RESPONSE_FAILURE); SendPacket(&data); return; } @@ -97,28 +103,28 @@ void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) ticket->message = message; ticket->timestamp = time(NULL); - sObjectMgr.AddOrUpdateGMTicket(*ticket); + sTicketMgr.AddOrUpdateGMTicket(*ticket); - data << uint32(2); + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + data << uint32(GMTICKET_RESPONSE_SUCCESS); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid); - } void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) { - GM_Ticket* ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + GM_Ticket* ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); if (ticket) { WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); + data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid); - sObjectMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); - SendGMTicketGetTicket(0x0A, 0); + sTicketMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); } } @@ -126,36 +132,184 @@ void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) { SendQueryTimeResponse(); - GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); - if (ticket) - SendGMTicketGetTicket(0x06, ticket->message.c_str()); + if (GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) + { + if (ticket->completed) + SendGMTicketResponse(ticket); + else + SendGMTicketGetTicket(GMTICKET_STATUS_HASTEXT, ticket->message.c_str(), ticket); + } else - SendGMTicketGetTicket(0x0A, 0); - + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); } void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) { WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); - data << uint32(1); + // are we sure this is a uint32? Should ask Zor + data << uint32(sTicketMgr.GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED); SendPacket(&data); } -void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text) +void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text, GM_Ticket *ticket /* = NULL */) { int len = text ? strlen(text) : 0; - WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4)); + WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+4+((status == GMTICKET_STATUS_HASTEXT) ? (len+1+4+4+4+1+1) : 0))); data << uint32(status); // standard 0x0A, 0x06 if text present - data << uint32(1); // unk flags, if 0, can't edit the ticket - if (status == 6) + data << uint32(1); // g_HasActiveGMTicket -- not a flag + + if (status == GMTICKET_STATUS_HASTEXT) { data << text; // ticket text - data << uint8(0x7); // ticket category - data << float(0); // tickets in queue? - data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions." - data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable" - data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated" - data << uint8(0); // const + data << uint8(0x7); // ticket category; why is this hardcoded? does it make a diff re: client? + + // we've got the easy stuff done by now. + // Now we need to go through the client logic for displaying various levels of ticket load + if (ticket) + { + // get ticketage, but it's stored in seconds so we have to do it in days + float ticketAge = (float)time(NULL) - (float)ticket->timestamp; + ticketAge /= DAY; + + data << float(ticketAge); // ticketAge (days) + if (GM_Ticket *oldestTicket = sTicketMgr.GetOldestOpenGMTicket()) + { + // get ticketage, but it's stored in seconds so we have to do it in days + float oldestTicketAge = (float)time(NULL) - (float)oldestTicket->timestamp; + oldestTicketAge /= DAY; + data << float(oldestTicketAge); + } + else + data << float(0); + + // I am not sure how blizzlike this is, and we don't really have a way to find out + int64 lastChange = int64(sTicketMgr.GetLastChange()); + float timeDiff = float(int64(time(NULL)) - lastChange); + timeDiff /= DAY; + data << float(timeDiff); + + data << uint8(std::min(ticket->escalated, uint8(TICKET_IN_ESCALATION_QUEUE))); // escalated data + data << uint8(ticket->viewed ? GMTICKET_OPENEDBYGM_STATUS_OPENED : GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED); // whether or not it has been viewed + } + else + { + // we can't actually get any numbers here... + data << float(0); + data << float(0); + data << float(1); + data << uint8(0); + data << uint8(0); + } } + + SendPacket(&data); +} + +void WorldSession::SendGMTicketResponse(GM_Ticket *ticket) +{ + if (!ticket) + return; + + WorldPacket data(SMSG_GMRESPONSE_RECEIVED); + data << uint32(1); // unk? Zor says "hasActiveTicket" + data << uint32(0); // can-edit - always 1 or 0, not flags + data << ticket->message.c_str(); + data << ticket->response.c_str(); + for (int8 j = 0; j < 3; j++) + data << uint8(0); // 3 null strings SendPacket(&data); } + +void WorldSession::HandleGMSurveySubmit(WorldPacket& recv_data) +{ + uint64 nextSurveyID = sTicketMgr.GetNextSurveyID(); + // just put the survey into the database + std::ostringstream ss; + uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc + recv_data >> mainSurvey; + + ss << "INSERT INTO gm_surveys (player, surveyid, mainSurvey, overall_comment, timestamp) VALUES ("; + ss << GetPlayer()->GetGUID() << ", "; + ss << nextSurveyID << ", "; + ss << mainSurvey << ", "; + + // sub_survey1, r1, comment1, sub_survey2, r2, comment2, sub_survey3, r3, comment3, sub_survey4, r4, comment4, sub_survey5, r5, comment5, sub_survey6, r6, comment6, sub_survey7, r7, comment7, sub_survey8, r8, comment8, sub_survey9, r9, comment9, sub_survey10, r10, comment10, + + for (uint8 i = 0; i < 10; i++) + { + std::ostringstream os; + os << "INSERT INTO gm_subsurveys (surveyid, subsurveyid, rank, comment) VALUES ("; + uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) + recv_data >> subSurveyId; + if(!subSurveyId) + break; + + uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc + std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") + recv_data >> rank; + recv_data >> comment; + + os << nextSurveyID << " "; + os << subSurveyId << ", "; + os << rank << ", '"; + CharacterDatabase.escape_string(comment); + os << comment << "');"; + CharacterDatabase.PExecute(os.str().c_str()); + } + + std::string comment; // just a guess + recv_data >> comment; + CharacterDatabase.escape_string(comment); + ss << "'" << comment << "', "; + ss << int64(time_t(NULL)) << ");"; + + CharacterDatabase.PExecute(ss.str().c_str()); +} + +void WorldSession::HandleReportLag(WorldPacket& recv_data) +{ + // just put the lag report into the database... + // can't think of anything else to do with it + uint32 lagType, mapId; + float x, y, z; + recv_data >> lagType; + recv_data >> mapId; + recv_data >> x; + recv_data >> y; + recv_data >> z; + + // build and execute query + std::ostringstream os; + os << "INSERT INTO lag_reports (player, lag_type, map, x, y, z) VALUES ("; + os << GetPlayer()->GetGUID() << ", "; + os << lagType << ", "; + os << mapId << ", "; + os << x << ", "; + os << y << ", "; + os << z << ");"; + + CharacterDatabase.Execute(os.str().c_str()); +} + +void WorldSession::HandleGMResponseResolve(WorldPacket& recvPacket) +{ + // empty packet + GM_Ticket* ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + + if (ticket) + { + uint8 getSurvey = 0; + if ((float)rand_chance() < sWorld.getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY)) + getSurvey = 1; + + WorldPacket data(SMSG_GMRESPONSE_STATUS_UPDATE, 4); + data << uint8(getSurvey); + SendPacket(&data); + + WorldPacket data2(SMSG_GMTICKET_DELETETICKET, 4); + data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + SendPacket(&data2); + sTicketMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), true); + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); + } +} diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c22148ab96b..f86a7ccba94 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -838,7 +838,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetDungeonDifficultyOpcode}, - /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_NEVER, &WorldSession::Handle_NULL },//LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, + /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -1292,7 +1292,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4EE*/ { "SMSG_GMRESPONSE_DB_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4EF*/ { "SMSG_GMRESPONSE_RECEIVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_LOGGEDIN, &WorldSession::HandleGMResponseResolve }, /*0x4F1*/ { "SMSG_GMRESPONSE_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4F2*/ { "UMSG_UNKNOWN_1266", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4F3*/ { "UMSG_UNKNOWN_1267", STATUS_NEVER, &WorldSession::Handle_NULL }, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index ccc97fad75b..f4fa9922b05 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -50,6 +50,8 @@ class CharacterHandler; class SpellCastTargets; struct AreaTableEntry; +struct GM_Ticket; + enum AccountDataType { GLOBAL_CONFIG_CACHE = 0, // 0x01 g @@ -375,9 +377,11 @@ class WorldSession void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket); void HandleGMTicketGetTicketOpcode(WorldPacket& recvPacket); void HandleGMTicketSystemStatusOpcode(WorldPacket& recvPacket); - void SendGMTicketGetTicket(uint32 status, char const* text); - - //void HandleGMSurveySubmit(WorldPacket& recvPacket); + void SendGMTicketGetTicket(uint32 status, char const* text, GM_Ticket *ticket = NULL); + void SendGMTicketResponse(GM_Ticket *ticket); + void HandleGMSurveySubmit(WorldPacket& recvPacket); + void HandleReportLag(WorldPacket& recvPacket); + void HandleGMResponseResolve(WorldPacket& recvPacket); void HandleTogglePvP(WorldPacket& recvPacket); diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp new file mode 100644 index 00000000000..205cf45dfd4 --- /dev/null +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -0,0 +1,193 @@ +/* + * 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 "DatabaseEnv.h" +#include "SQLStorage.h" +#include "ProgressBar.h" +#include "Log.h" +#include "TicketMgr.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +TicketMgr::TicketMgr() +{ + m_GMticketid = 0; // this is initialized in LoadGMTickets() but it's best to be safe + m_GMSurveyID = 0; + m_openTickets = 0; + lastChange = time(NULL); + status = true; +} + +uint64 TicketMgr::GenerateGMTicketId() +{ + return ++m_GMticketid; +} + +void TicketMgr::LoadGMTickets() +{ + if (!m_GMTicketList.empty()) + { + for (GmTicketList::const_iterator itr = m_GMTicketList.begin(); itr != m_GMTicketList.end(); ++itr) + delete *itr; + } + m_GMTicketList.clear(); + m_GMticketid = 0; + m_openTickets = 0; + + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment, completed, escalated, viewed FROM gm_tickets"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outString(">> GM Tickets table is empty, no tickets were loaded."); + return; + } + + uint16 count = 0; + barGoLink bar ((*result).GetRowCount()); + GM_Ticket *ticket; + do + { + Field *fields = result->Fetch(); + ticket = new GM_Ticket; + ticket->guid = fields[0].GetUInt64(); + ticket->playerGuid = fields[1].GetUInt64(); + ticket->name = fields[2].GetCppString(); + ticket->message = fields[3].GetCppString(); + ticket->createtime = fields[4].GetUInt64(); + ticket->map = fields[5].GetUInt32(); + ticket->pos_x = fields[6].GetFloat(); + ticket->pos_y = fields[7].GetFloat(); + ticket->pos_z = fields[8].GetFloat(); + ticket->timestamp = fields[9].GetUInt64(); + ticket->closed = fields[10].GetUInt64(); + if (ticket->closed == 0) + m_openTickets++; + + ticket->assignedToGM = fields[11].GetUInt64(); + ticket->comment = fields[12].GetCppString(); + ticket->completed = fields[13].GetBool(); + ticket->escalated = fields[14].GetUInt8(); + ticket->viewed = fields[15].GetBool(); + ++count; + bar.step(); + + m_GMTicketList.push_back(ticket); + + } while (result->NextRow()); + + result = CharacterDatabase.Query("SELECT MAX(guid) from gm_tickets"); + + if (result) + { + Field *fields = result->Fetch(); + m_GMticketid = fields[0].GetUInt64(); + } + + sLog.outString(">> Loaded %u GM Tickets from the database.", count); +} + +void TicketMgr::LoadGMSurveys() +{ + // we don't actually load anything into memory here as there's no reason to + QueryResult_AutoPtr result = CharacterDatabase.Query("SELECT MAX(surveyid) FROM gm_surveys"); + if (result) + { + Field *fields = result->Fetch(); + m_GMSurveyID = fields[0].GetUInt64(); + } + else + m_GMSurveyID = 0; + + sLog.outString(">> Loaded GM Survey count from database."); +} + +void TicketMgr::AddOrUpdateGMTicket(GM_Ticket &ticket, bool create) +{ + if (create) + { + m_GMTicketList.push_back(&ticket); + if (ticket.closed == 0) + m_openTickets++; + } + + _AddOrUpdateGMTicket(ticket); +} + +void TicketMgr::_AddOrUpdateGMTicket(GM_Ticket &ticket) +{ + std::string msg(ticket.message), name(ticket.name), comment(ticket.comment); + CharacterDatabase.escape_string(msg); + CharacterDatabase.escape_string(name); + CharacterDatabase.escape_string(comment); + std::ostringstream ss; + ss << "REPLACE INTO gm_tickets (guid, playerGuid, name, message, createtime, map, posX, posY, posZ, timestamp, closed, assignedto, comment, completed, escalated, viewed) VALUES ("; + ss << ticket.guid << ", "; + ss << ticket.playerGuid << ", '"; + ss << name << "', '"; + ss << msg << "', " ; + ss << ticket.createtime << ", "; + ss << ticket.map << ", "; + ss << ticket.pos_x << ", "; + ss << ticket.pos_y << ", "; + ss << ticket.pos_z << ", "; + ss << ticket.timestamp << ", "; + ss << ticket.closed << ", "; + ss << ticket.assignedToGM << ", '"; + ss << comment << "', "; + ss << (ticket.completed ? 1 : 0) << ", "; + ss << ticket.escalated << ", "; + ss << (ticket.viewed ? 1 : 0) << ");"; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->Append(ss.str().c_str()); + CharacterDatabase.CommitTransaction(trans); +} + +void TicketMgr::RemoveGMTicket(GM_Ticket *ticket, int64 source, bool permanently) +{ + for (GmTicketList::iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i)->guid == ticket->guid) + { + if (permanently) + { + CharacterDatabase.PExecute("DELETE FROM gm_tickets WHERE guid = '%u'", ticket->guid); + i = m_GMTicketList.erase(i); + ticket = NULL; + return; + } + (*i)->closed = source; + + if (source != 0) + m_openTickets--; + + _AddOrUpdateGMTicket(*(*i)); + } +} + +void TicketMgr::RemoveGMTicket(uint64 ticketGuid, int64 source, bool permanently) +{ + GM_Ticket *ticket = GetGMTicket(ticketGuid); + ASSERT(ticket); // hmm + RemoveGMTicket(ticket, source, permanently); +} diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h new file mode 100644 index 00000000000..44a20f07da7 --- /dev/null +++ b/src/server/game/Tickets/TicketMgr.h @@ -0,0 +1,173 @@ +/* + * 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 _TICKETMGR_H +#define _TICKETMGR_H + +#include <string> +#include <ace/Singleton.h> +#include "Common.h" +#include "DatabaseEnv.h" +#include "SQLStorage.h" +#include "SQLStorageImpl.h" + +// from blizzard lua +enum GMTicketSystemStatus +{ + GMTICKET_QUEUE_STATUS_DISABLED = -1, + GMTICKET_QUEUE_STATUS_ENABLED = 1, +}; + +enum GMTicketStatus +{ + GMTICKET_STATUS_HASTEXT = 0x06, + GMTICKET_STATUS_DEFAULT = 0x0A, +}; + +enum GMTicketResponse +{ + GMTICKET_RESPONSE_FAILURE = 1, + GMTICKET_RESPONSE_SUCCESS = 2, + GMTICKET_RESPONSE_TICKET_DELETED = 9, +}; + +// from Blizzard LUA: +// GMTICKET_ASSIGNEDTOGM_STATUS_NOT_ASSIGNED = 0; -- ticket is not currently assigned to a gm +// GMTICKET_ASSIGNEDTOGM_STATUS_ASSIGNED = 1; -- ticket is assigned to a normal gm +// GMTICKET_ASSIGNEDTOGM_STATUS_ESCALATED = 2; -- ticket is in the escalation queue +// 3 is a custom value and should never actually be sent +enum GMTicketEscalationStatus +{ + TICKET_UNASSIGNED = 0, + TICKET_ASSIGNED = 1, + TICKET_IN_ESCALATION_QUEUE = 2, + TICKET_ESCALATED_ASSIGNED = 3, +}; + +// from blizzard lua +enum GMTicketOpenedByGMStatus +{ + GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED = 0, // ticket has never been opened by a gm + GMTICKET_OPENEDBYGM_STATUS_OPENED = 1, // ticket has been opened by a gm +}; + +enum LagReportType +{ + LAG_REPORT_TYPE_LOOT = 1, + LAG_REPORT_TYPE_AUCTION_HOUSE = 2, + LAG_REPORT_TYPE_MAIL = 3, + LAG_REPORT_TYPE_CHAT = 4, + LAG_REPORT_TYPE_MOVEMENT = 5, + LAG_REPORT_TYPE_SPELL = 6 +}; + +struct GM_Ticket +{ + uint64 guid; + uint64 playerGuid; + std::string name; + float pos_x; + float pos_y; + float pos_z; + uint32 map; + std::string message; + uint64 createtime; + uint64 timestamp; + int64 closed; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. + uint64 assignedToGM; + std::string comment; + bool completed; + uint8 escalated; + bool viewed; + std::string response; +}; +typedef std::list<GM_Ticket*> GmTicketList; + +class TicketMgr +{ + TicketMgr(); + friend class ACE_Singleton<TicketMgr, ACE_Null_Mutex>; + +public: + void LoadGMTickets(); + void LoadGMSurveys(); + + GM_Ticket *GetGMTicket(uint64 ticketGuid) + { + for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i) && (*i)->guid == ticketGuid) + return (*i); + + return NULL; + } + + GM_Ticket *GetGMTicketByPlayer(uint64 playerGuid) + { + for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i) && (*i)->playerGuid == playerGuid && (*i)->closed == 0) + return (*i); + + return NULL; + } + + void AddOrUpdateGMTicket(GM_Ticket &ticket, bool create = false); + void _AddOrUpdateGMTicket(GM_Ticket &ticket); + void RemoveGMTicket(uint64 ticketGuid, int64 source = -1, bool permanently = false); + void RemoveGMTicket(GM_Ticket *ticket, int64 source = -1, bool permanently = false); + uint64 GenerateGMTicketId(); + bool GetStatus() const { return status; } + void SetStatus(bool newStatus) { status = newStatus; } + uint64 GetOpenTicketCount() { return m_openTickets; } + uint64 GetNextSurveyID() + { + return ++m_GMSurveyID; + } + + GM_Ticket *GetOldestOpenGMTicket() + { + for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) + if ((*i) && (*i)->closed == 0 && !(*i)->completed) + return (*i); + + return NULL; + } + + time_t GetLastChange() + { + return lastChange; + } + + void UpdateLastChange() + { + lastChange = time(NULL); + } + + GmTicketList m_GMTicketList; + +protected: + uint64 m_GMticketid; + uint64 m_GMSurveyID; + bool status; + uint64 m_openTickets; + uint32 m_gmCount; + time_t lastChange; +}; + +#define sTicketMgr (*ACE_Singleton<TicketMgr, ACE_Null_Mutex>::instance()) + +#endif // _TICKETMGR_H
\ No newline at end of file diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index cc5391fc9a9..660fc88679f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -39,6 +39,7 @@ #include "AchievementMgr.h" #include "AuctionHouseMgr.h" #include "ObjectMgr.h" +#include "TicketMgr.h" #include "CreatureEventAIMgr.h" #include "SpellMgr.h" #include "Chat.h" @@ -886,6 +887,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_ALLOW_GM_FRIEND] = sConfig.GetBoolDefault("GM.AllowFriend", false); m_bool_configs[CONFIG_GM_LOWER_SECURITY] = sConfig.GetBoolDefault("GM.LowerSecurity", false); m_bool_configs[CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS] = sConfig.GetBoolDefault("GM.AllowAchievementGain", true); + m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfig.GetFloatDefault("GM.TicketSystem.ChanceOfGMSurvey", 50.0f); m_int_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode", 1); @@ -1566,7 +1568,10 @@ void World::SetInitialWorldSettings() sConditionMgr.LoadConditions(); sLog.outString("Loading GM tickets..."); - sObjectMgr.LoadGMTickets(); + sTicketMgr.LoadGMTickets(); + + sLog.outString("Loading GM surveys..."); + sTicketMgr.LoadGMSurveys(); sLog.outString("Loading client addons..."); sAddonMgr.LoadFromDB(); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index d3c4ab5d32e..cb54ee406be 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -177,6 +177,7 @@ enum WorldFloatConfigs CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS, CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS, CONFIG_THREAT_RADIUS, + CONFIG_CHANCE_OF_GM_SURVEY, FLOAT_CONFIG_VALUE_COUNT }; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index ecc03f4a491..0a55f3c8cc1 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1354,6 +1354,11 @@ AllowPlayerCommands = 1 # Default: 1 (enable) # 0 (disable) # +# GM.TicketSystem.ChanceOfGMSurvey +# Chance of sending a GM survey with every ticket completion. +# Default: 50 +# 0 (disables surveys) +# ############################################################################### GM.LoginState = 2 @@ -1369,6 +1374,7 @@ GM.AllowInvite = 0 GM.AllowFriend = 0 GM.LowerSecurity = 0 GM.AllowAchievementGain = 1 +GM.TicketSystem.ChanceOfGMSurvey = 50 ############################################################################### # VISIBILITY AND RADIUSES |