diff options
33 files changed, 3475 insertions, 1350 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 9b6c41ad7d5..6fba92991d9 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -496,7 +496,7 @@ CREATE TABLE `rbac_linked_permissions` ( LOCK TABLES `rbac_linked_permissions` WRITE; /*!40000 ALTER TABLE `rbac_linked_permissions` DISABLE KEYS */; -INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(192,778),(192,779),(192,780),(192,781),(192,782),(192,783),(192,784),(192,785),(192,786),(192,787),(192,788),(192,789),(192,790),(192,791),(192,792),(192,793),(192,794),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,51),(194,195),(194,198),(194,632),(194,798),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,208),(196,212),(196,213),(196,214),(196,215),(196,216),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,622),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,631),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(199,207),(199,209),(199,210),(199,211),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534),(199,797); +INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(192,778),(192,779),(192,780),(192,781),(192,782),(192,783),(192,784),(192,785),(192,786),(192,787),(192,788),(192,789),(192,790),(192,791),(192,792),(192,793),(192,794),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,51),(194,195),(194,198),(194,632),(194,798),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,208),(196,212),(196,213),(196,214),(196,215),(196,216),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,631),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(196,809),(196,817),(196,825),(196,829),(196,830),(196,831),(196,832),(196,833),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(197,805),(197,811),(197,813),(197,819),(197,821),(197,827),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(198,799),(198,800),(198,801),(198,802),(198,803),(198,804),(198,806),(198,807),(198,808),(198,810),(198,812),(198,814),(198,815),(198,816),(198,818),(198,820),(198,822),(198,823),(198,824),(198,826),(198,828),(199,207),(199,209),(199,210),(199,211),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534),(199,797); /*!40000 ALTER TABLE `rbac_linked_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -520,7 +520,7 @@ CREATE TABLE `rbac_permissions` ( LOCK TABLES `rbac_permissions` WRITE; /*!40000 ALTER TABLE `rbac_permissions` DISABLE KEYS */; -INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(51,'Allow trading between factions'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(207,'Command: battlenetaccount'),(208,'Command: battlenetaccount create'),(209,'Command: battlenetaccount lock country'),(210,'Command: battlenetaccount lock ip'),(211,'Command: battlenetaccount password'),(212,'Command: battlenetaccount set'),(213,'Command: battlenetaccount set password'),(214,'Command: bnetaccount link'),(215,'Command: bnetaccount unlink'),(216,'Command: bnetaccount gameaccountcreate'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(622,'Command: reload all spell'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(631,'Command: reload battleground_template'),(632,'Command: .mutehistory'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload gm_tickets'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'),(778,'Command: ahbot'),(779,'Command: ahbot items'),(780,'Command: ahbot items gray'),(781,'Command: ahbot items white'),(782,'Command: ahbot items green'),(783,'Command: ahbot items blue'),(784,'Command: ahbot items purple'),(785,'Command: ahbot items orange'),(786,'Command: ahbot items yellow'),(787,'Command: ahbot ratio'),(788,'Command: ahbot ratio alliance'),(789,'Command: ahbot ratio horde'),(790,'Command: ahbot ratio neutral'),(791,'Command: ahbot rebuild'),(792,'Command: ahbot reload'),(793,'Command: ahbot status'),(794,'Command: .guild info'),(797,'Command: pvpstats'),(798,'Command: .mod xp'); +INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(51,'Allow trading between factions'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(207,'Command: battlenetaccount'),(208,'Command: battlenetaccount create'),(209,'Command: battlenetaccount lock country'),(210,'Command: battlenetaccount lock ip'),(211,'Command: battlenetaccount password'),(212,'Command: battlenetaccount set'),(213,'Command: battlenetaccount set password'),(214,'Command: bnetaccount link'),(215,'Command: bnetaccount unlink'),(216,'Command: bnetaccount gameaccountcreate'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(631,'Command: reload battleground_template'),(632,'Command: .mutehistory'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload support'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'),(778,'Command: ahbot'),(779,'Command: ahbot items'),(780,'Command: ahbot items gray'),(781,'Command: ahbot items white'),(782,'Command: ahbot items green'),(783,'Command: ahbot items blue'),(784,'Command: ahbot items purple'),(785,'Command: ahbot items orange'),(786,'Command: ahbot items yellow'),(787,'Command: ahbot ratio'),(788,'Command: ahbot ratio alliance'),(789,'Command: ahbot ratio horde'),(790,'Command: ahbot ratio neutral'),(791,'Command: ahbot rebuild'),(792,'Command: ahbot reload'),(793,'Command: ahbot status'),(794,'Command: .guild info'),(797,'Command: pvpstats'),(798,'Command: .mod xp'),(799,'Command: .go bugticket'),(800,'Command: .go complaintticket'),(801,'Command: .go suggestionticket'),(802,'Command: .ticket bug'),(803,'Command: .ticket complaint'),(804,'Command: .ticket suggestion'),(805,'Command: .ticket bug assign'),(806,'Command: .ticket bug close'),(807,'Command: .ticket bug closedlist'),(808,'Command: .ticket bug comment'),(809,'Command: .ticket bug delete'),(810,'Command: .ticket bug list'),(811,'Command: .ticket bug unassign'),(812,'Command: .ticket bug view'),(813,'Command: .ticket complaint assign'),(814,'Command: .ticket complaint close'),(815,'Command: .ticket complaint closedlist'),(816,'Command: .ticket complaint comment'),(817,'Command: .ticket complaint delete'),(818,'Command: .ticket complaint list'),(819,'Command: .ticket complaint unassign'),(820,'Command: .ticket complaint view'),(821,'Command: .ticket suggestion assign'),(822,'Command: .ticket suggestion close'),(823,'Command: .ticket suggestion closedlist'),(824,'Command: .ticket suggestion comment'),(825,'Command: .ticket suggestion delete'),(826,'Command: .ticket suggestion list'),(827,'Command: .ticket suggestion unassign'),(828,'Command: .ticket suggestion view'),(829,'Command: .ticket reset all'),(830,'Command: .ticket reset gm'),(831,'Command: .ticket reset bug'),(832,'Command: .ticket reset complaint'),(833,'Command: .ticket reset suggestion'); /*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index b920bcba8cd..b37dd5dffac 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1619,93 +1619,218 @@ LOCK TABLES `gameobject_respawn` WRITE; UNLOCK TABLES; -- --- Table structure for table `gm_subsurveys` +-- Table structure for table `gm_bug` -- -DROP TABLE IF EXISTS `gm_subsurveys`; +DROP TABLE IF EXISTS `gm_bug`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `gm_subsurveys` ( - `surveyId` int(10) unsigned NOT NULL AUTO_INCREMENT, - `subsurveyId` int(10) unsigned NOT NULL DEFAULT '0', - `rank` int(10) unsigned NOT NULL DEFAULT '0', - `comment` text NOT NULL, - PRIMARY KEY (`surveyId`,`subsurveyId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System'; +CREATE TABLE `gm_bug` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) COLLATE='utf8_general_ci' ENGINE=InnoDB; /*!40101 SET character_set_client = @saved_cs_client */; -- --- Dumping data for table `gm_subsurveys` +-- Dumping data for table `gm_bug` -- -LOCK TABLES `gm_subsurveys` WRITE; -/*!40000 ALTER TABLE `gm_subsurveys` DISABLE KEYS */; -/*!40000 ALTER TABLE `gm_subsurveys` ENABLE KEYS */; +LOCK TABLES `gm_bug` WRITE; +/*!40000 ALTER TABLE `gm_bug` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_bug` ENABLE KEYS */; UNLOCK TABLES; -- --- Table structure for table `gm_surveys` +-- Table structure for table `gm_complaint` -- -DROP TABLE IF EXISTS `gm_surveys`; +DROP TABLE IF EXISTS `gm_complaint`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `gm_surveys` ( - `surveyId` int(10) unsigned NOT NULL AUTO_INCREMENT, - `guid` bigint(20) unsigned NOT NULL DEFAULT '0', - `mainSurvey` int(10) unsigned NOT NULL DEFAULT '0', - `overallComment` longtext NOT NULL, - `createTime` int(10) unsigned NOT NULL DEFAULT '0', +CREATE TABLE `gm_complaint` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `targetCharacterGuid` BIGINT(20) UNSIGNED NOT NULL, + `complaintType` SMALLINT(5) UNSIGNED NOT NULL, + `reportLineIndex` INT(10) NOT NULL, + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) COLLATE='utf8_general_ci' ENGINE=InnoDB; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_complaint` +-- + +LOCK TABLES `gm_complaint` WRITE; +/*!40000 ALTER TABLE `gm_complaint` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_complaint` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gm_complaint_chatlog` +-- + +DROP TABLE IF EXISTS `gm_complaint_chatlog`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_complaint_chatlog` ( + `complaintId` INT(10) UNSIGNED NOT NULL, + `lineId` INT(10) UNSIGNED NOT NULL, + `timestamp` INT(10) UNSIGNED NOT NULL, + `text` TEXT NOT NULL, + PRIMARY KEY (`complaintId`, `lineId`) +) COLLATE='utf8_general_ci' ENGINE=InnoDB; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_complaint_chatlog` +-- + +LOCK TABLES `gm_complaint_chatlog` WRITE; +/*!40000 ALTER TABLE `gm_complaint_chatlog` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_complaint_chatlog` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gm_subsurvey` +-- + +DROP TABLE IF EXISTS `gm_subsurvey`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_subsurvey` ( + `surveyId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `questionId` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `answer` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `answerComment` TEXT NOT NULL, + PRIMARY KEY (`surveyId`, `questionId`) +) COMMENT='Player System' COLLATE='utf8_general_ci' ENGINE=InnoDB; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_subsurvey` +-- + +LOCK TABLES `gm_subsurvey` WRITE; +/*!40000 ALTER TABLE `gm_subsurvey` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_subsurvey` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gm_suggestion` +-- +DROP TABLE IF EXISTS `gm_suggestion`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_suggestion` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) COLLATE='utf8_general_ci' ENGINE=InnoDB; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `gm_suggestion` +-- + +LOCK TABLES `gm_suggestion` WRITE; +/*!40000 ALTER TABLE `gm_suggestion` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_suggestion` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `gm_survey` +-- + +DROP TABLE IF EXISTS `gm_survey`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gm_survey` ( + `surveyId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `guid` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', + `mainSurvey` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `comment` LONGTEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`surveyId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System'; +) COMMENT='Player System' COLLATE='utf8_general_ci' ENGINE=InnoDB; /*!40101 SET character_set_client = @saved_cs_client */; -- --- Dumping data for table `gm_surveys` +-- Dumping data for table `gm_survey` -- -LOCK TABLES `gm_surveys` WRITE; -/*!40000 ALTER TABLE `gm_surveys` DISABLE KEYS */; -/*!40000 ALTER TABLE `gm_surveys` ENABLE KEYS */; +LOCK TABLES `gm_survey` WRITE; +/*!40000 ALTER TABLE `gm_survey` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_survey` ENABLE KEYS */; UNLOCK TABLES; -- --- Table structure for table `gm_tickets` +-- Table structure for table `gm_ticket` -- -DROP TABLE IF EXISTS `gm_tickets`; +DROP TABLE IF EXISTS `gm_ticket`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `gm_tickets` ( - `ticketId` int(10) unsigned NOT NULL AUTO_INCREMENT, - `guid` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier of ticket creator', - `name` varchar(12) NOT NULL COMMENT 'Name of ticket creator', - `message` text NOT NULL, - `createTime` int(10) unsigned NOT NULL DEFAULT '0', - `mapId` smallint(5) unsigned NOT NULL DEFAULT '0', - `posX` float NOT NULL DEFAULT '0', - `posY` float NOT NULL DEFAULT '0', - `posZ` float NOT NULL DEFAULT '0', - `lastModifiedTime` int(10) unsigned NOT NULL DEFAULT '0', - `closedBy` bigint(20) NOT NULL DEFAULT '0', - `assignedTo` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', - `comment` text NOT NULL, - `response` text NOT NULL, - `completed` tinyint(3) unsigned NOT NULL DEFAULT '0', - `escalated` tinyint(3) unsigned NOT NULL DEFAULT '0', - `viewed` tinyint(3) unsigned NOT NULL DEFAULT '0', - `haveTicket` tinyint(3) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`ticketId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System'; +CREATE TABLE `gm_ticket` ( + `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier of ticket creator', + `description` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `lastModifiedTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', + `comment` TEXT NOT NULL, + `response` TEXT NOT NULL, + `completed` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `escalated` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `viewed` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `needMoreHelp` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) COMMENT='Player System' COLLATE='utf8_general_ci' ENGINE=InnoDB; /*!40101 SET character_set_client = @saved_cs_client */; -- --- Dumping data for table `gm_tickets` +-- Dumping data for table `gm_ticket` -- -LOCK TABLES `gm_tickets` WRITE; -/*!40000 ALTER TABLE `gm_tickets` DISABLE KEYS */; -/*!40000 ALTER TABLE `gm_tickets` ENABLE KEYS */; +LOCK TABLES `gm_ticket` WRITE; +/*!40000 ALTER TABLE `gm_ticket` DISABLE KEYS */; +/*!40000 ALTER TABLE `gm_ticket` ENABLE KEYS */; UNLOCK TABLES; -- @@ -2401,36 +2526,6 @@ LOCK TABLES `item_soulbound_trade_data` 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` ( - `reportId` int(10) unsigned NOT NULL AUTO_INCREMENT, - `guid` bigint(20) unsigned NOT NULL DEFAULT '0', - `lagType` tinyint(3) unsigned NOT NULL DEFAULT '0', - `mapId` smallint(5) unsigned NOT NULL DEFAULT '0', - `posX` float NOT NULL DEFAULT '0', - `posY` float NOT NULL DEFAULT '0', - `posZ` float NOT NULL DEFAULT '0', - `latency` int(10) unsigned NOT NULL DEFAULT '0', - `createTime` int(10) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`reportId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 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 `lfg_data` -- diff --git a/sql/updates/auth/2015_03_10_00_auth.sql b/sql/updates/auth/2015_03_10_00_auth.sql new file mode 100644 index 00000000000..3206edcbd8d --- /dev/null +++ b/sql/updates/auth/2015_03_10_00_auth.sql @@ -0,0 +1,77 @@ +UPDATE `rbac_permissions` SET `name`='Command: reload support' WHERE `id`=650; + +DELETE FROM `rbac_permissions` WHERE `id` IN (799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833); +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(799, 'Command: .go bugticket'), +(800, 'Command: .go complaintticket'), +(801, 'Command: .go suggestionticket'), +(802, 'Command: .ticket bug'), +(803, 'Command: .ticket complaint'), +(804, 'Command: .ticket suggestion'), +(805, 'Command: .ticket bug assign'), +(806, 'Command: .ticket bug close'), +(807, 'Command: .ticket bug closedlist'), +(808, 'Command: .ticket bug comment'), +(809, 'Command: .ticket bug delete'), +(810, 'Command: .ticket bug list'), +(811, 'Command: .ticket bug unassign'), +(812, 'Command: .ticket bug view'), +(813, 'Command: .ticket complaint assign'), +(814, 'Command: .ticket complaint close'), +(815, 'Command: .ticket complaint closedlist'), +(816, 'Command: .ticket complaint comment'), +(817, 'Command: .ticket complaint delete'), +(818, 'Command: .ticket complaint list'), +(819, 'Command: .ticket complaint unassign'), +(820, 'Command: .ticket complaint view'), +(821, 'Command: .ticket suggestion assign'), +(822, 'Command: .ticket suggestion close'), +(823, 'Command: .ticket suggestion closedlist'), +(824, 'Command: .ticket suggestion comment'), +(825, 'Command: .ticket suggestion delete'), +(826, 'Command: .ticket suggestion list'), +(827, 'Command: .ticket suggestion unassign'), +(828, 'Command: .ticket suggestion view'), +(829, 'Command: .ticket reset all'), +(830, 'Command: .ticket reset gm'), +(831, 'Command: .ticket reset bug'), +(832, 'Command: .ticket reset complaint'), +(833, 'Command: .ticket reset suggestion'); + +DELETE FROM `rbac_linked_permissions` WHERE `id` = 198 AND `linkedId` IN (799,800,801,892,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833); +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(198, 799), +(198, 800), +(198, 801), +(198, 802), +(198, 803), +(198, 804), +(197, 805), +(198, 806), +(198, 807), +(198, 808), +(196, 809), +(198, 810), +(197, 811), +(198, 812), +(197, 813), +(198, 814), +(198, 815), +(198, 816), +(196, 817), +(198, 818), +(197, 819), +(198, 820), +(197, 821), +(198, 822), +(198, 823), +(198, 824), +(196, 825), +(198, 826), +(197, 827), +(198, 828), +(196, 829), +(196, 830), +(196, 831), +(196, 832), +(196, 833); diff --git a/sql/updates/characters/2015_03_10_00_characters.sql b/sql/updates/characters/2015_03_10_00_characters.sql new file mode 100644 index 00000000000..ce55b3b35cc --- /dev/null +++ b/sql/updates/characters/2015_03_10_00_characters.sql @@ -0,0 +1,95 @@ +DROP TABLE IF EXISTS `lag_reports`; + +ALTER TABLE `gm_surveys` + RENAME TO `gm_survey`, + CHANGE COLUMN `overallComment` `comment` LONGTEXT NOT NULL AFTER `mainSurvey`; + +ALTER TABLE `gm_subsurveys` + RENAME TO `gm_subsurvey`, + CHANGE COLUMN `subsurveyId` `questionId` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `surveyId`, + CHANGE COLUMN `rank` `answer` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `questionId`, + CHANGE COLUMN `comment` `answerComment` TEXT NOT NULL AFTER `answer`; + + +ALTER TABLE `gm_tickets` + RENAME TO `gm_ticket`, + CHANGE COLUMN `ticketId` `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT FIRST, + CHANGE COLUMN `guid` `playerGuid` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier of ticket creator' AFTER `id`, + CHANGE COLUMN `message` `description` TEXT NOT NULL AFTER `playerGuid`, + CHANGE COLUMN `haveTicket` `needMoreHelp` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `viewed`, + DROP COLUMN `name`; + +DROP TABLE IF EXISTS `gm_bug`; +CREATE TABLE `gm_bug` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + +DROP TABLE IF EXISTS `gm_complaint`; +CREATE TABLE `gm_complaint` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `targetCharacterGuid` BIGINT(20) UNSIGNED NOT NULL, + `complaintType` SMALLINT(5) UNSIGNED NOT NULL, + `reportLineIndex` INT(10) NOT NULL, + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + +DROP TABLE IF EXISTS `gm_complaint_chatlog`; +CREATE TABLE `gm_complaint_chatlog` ( + `complaintId` INT(10) UNSIGNED NOT NULL, + `lineId` INT(10) UNSIGNED NOT NULL, + `timestamp` INT(10) UNSIGNED NOT NULL, + `text` TEXT NOT NULL, + PRIMARY KEY (`complaintId`, `lineId`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + +DROP TABLE IF EXISTS `gm_suggestion`; +CREATE TABLE `gm_suggestion` ( + `id` INT(10) UNSIGNED NOT NULL, + `playerGuid` BIGINT(20) UNSIGNED NOT NULL, + `note` TEXT NOT NULL, + `createTime` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `mapId` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `posX` FLOAT NOT NULL DEFAULT '0', + `posY` FLOAT NOT NULL DEFAULT '0', + `posZ` FLOAT NOT NULL DEFAULT '0', + `facing` FLOAT NOT NULL DEFAULT '0', + `closedBy` BIGINT(20) NOT NULL DEFAULT '0', + `assignedTo` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned', + `comment` TEXT NOT NULL, + PRIMARY KEY (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; diff --git a/sql/updates/world/2015_03_10_00_world.sql b/sql/updates/world/2015_03_10_00_world.sql new file mode 100644 index 00000000000..befd7f94145 --- /dev/null +++ b/sql/updates/world/2015_03_10_00_world.sql @@ -0,0 +1,36 @@ +DELETE FROM `trinity_string` WHERE `entry` = 1190; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES (1190, 'Ticket system is disabled. You can\'t change its status.'); + +UPDATE `command` SET `name`='reload support', `help`='Syntax: .reload support\r\nReload support system tables.' WHERE `name`='reload gm_tickets'; + +DELETE FROM `command` WHERE `name` IN ('ticket bug assign', 'ticket bug close', 'ticket bug closedlist', 'ticket bug comment', 'ticket bug delete', 'ticket bug list', 'ticket bug unassign', 'ticket bug view', 'ticket complaint assign', 'ticket complaint close', 'ticket complaint closedlist', 'ticket complaint comment', 'ticket complaint delete', 'ticket complaint list', 'ticket complaint unassign', 'ticket complaint view', 'ticket suggestion assign', 'ticket suggestion close', 'ticket suggestion closedlist', 'ticket suggestion comment', 'ticket suggestion delete', 'ticket suggestion list', 'ticket suggestion unassign', 'ticket suggestion view', 'ticket reset all', 'ticket reset gm', 'ticket reset bug', 'ticket reset complaint', 'ticket reset suggestion'); +INSERT INTO `command` (`name`, `permission`, `help`) VALUES +('ticket bug assign', 805, 'Usage: .ticket bug assign $ticketid $gmname.\r\nAssigns the specified ticket to the specified Game Master.'), +('ticket bug close', 806, 'Usage: .ticket bug close $ticketid.\r\nCloses the specified ticket. Does not delete permanently.'), +('ticket bug closedlist', 807, 'Usage: Displays a list of closed bug tickets.'), +('ticket bug comment', 808, 'Usage: .ticket bug comment $ticketid $comment.\r\nAllows the adding or modifying of a comment to the specified ticket.'), +('ticket bug delete', 809, 'Usage: .ticket bug delete $ticketid.\r\nDeletes the specified ticket permanently. Ticket must be closed first.'), +('ticket bug list', 810, 'Usage: Displays a list of open bug tickets.'), +('ticket bug unassign', 811, 'Usage: .ticket bug unassign $ticketid.\r\nUnassigns the specified ticket from the current assigned Game Master.'), +('ticket bug view', 812, 'Usage: .ticket bug view $ticketid.\r\nReturns details about specified ticket. Ticket must be open and not deleted.'), +('ticket complaint assign', 813, 'Usage: .ticket complaint assign $ticketid $gmname.\r\nAssigns the specified ticket to the specified Game Master.'), +('ticket complaint close', 814, 'Usage: .ticket complaint close $ticketid.\r\nCloses the specified ticket. Does not delete permanently.'), +('ticket complaint closedlist', 815, 'Usage: Displays a list of closed complaint tickets.'), +('ticket complaint comment', 816, 'Usage: .ticket complaint comment $ticketid $comment.\r\nAllows the adding or modifying of a comment to the specified ticket.'), +('ticket complaint delete', 817, 'Usage: .ticket complaint delete $ticketid.\r\nDeletes the specified ticket permanently. Ticket must be closed first.'), +('ticket complaint list', 818, 'Usage: Displays a list of open complaint tickets.'), +('ticket complaint unassign', 819, 'Usage: .ticket complaint unassign $ticketid.\r\nUnassigns the specified ticket from the current assigned Game Master.'), +('ticket complaint view', 820, 'Usage: .ticket complaint view $ticketid.\r\nReturns details about specified ticket. Ticket must be open and not deleted.'), +('ticket suggestion assign', 821, 'Usage: .ticket suggestion assign $ticketid $gmname.Assigns the specified ticket to the specified Game Master.'), +('ticket suggestion close', 822, 'Usage: .ticket suggestion close $ticketid.\r\nCloses the specified ticket. Does not delete permanently.'), +('ticket suggestion closedlist', 823, 'Usage: Displays a list of closed suggestion tickets.'), +('ticket suggestion comment', 824, 'Usage: .ticket suggestion comment $ticketid $comment.\r\nAllows the adding or modifying of a comment to the specified ticket.'), +('ticket suggestion delete', 825, 'Usage: .ticket suggestion delete $ticketid.\r\nDeletes the specified ticket permanently. Ticket must be closed first.'), +('ticket suggestion list', 826, 'Usage: Displays a list of open suggestion tickets.'), +('ticket suggestion unassign', 827, 'Usage: .ticket suggestion unassign $ticketid.\r\nUnassigns the specified ticket from the current assigned Game Master.'), +('ticket suggestion view', 828, 'Usage: .ticket suggestion view $ticketid.\r\nReturns details about specified ticket. Ticket must be open and not deleted.'), +('ticket reset all', 829, 'Usage: Removes all closed tickets and resets the counter, if no pending open tickets exist.'), +('ticket reset gm', 830, 'Usage: Removes all closed GM tickets and resets the counter, if no pending open tickets exist.'), +('ticket reset bug', 831, 'Usage: Removes all closed bug tickets and resets the counter, if no pending open tickets exist.'), +('ticket reset complaint', 832, 'Usage: Removes all closed complaint tickets and resets the counter, if no pending open tickets exist.'), +('ticket reset suggestion', 833, 'Usage: Removes all closed suggestion tickets and resets the counter, if no pending open tickets exist.'); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 3f5a21f2888..e700a8b1708 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -554,7 +554,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER = 647, RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE = 648, RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER = 649, - RBAC_PERM_COMMAND_RELOAD_GM_TICKETS = 650, + RBAC_PERM_COMMAND_RELOAD_SUPPORT_SYSTEM = 650, RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU = 651, RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION = 652, RBAC_PERM_COMMAND_RELOAD_ITEM_ENCHANTMENT_TEMPLATE = 653, @@ -703,6 +703,41 @@ enum RBACPermissions RBAC_PERM_COMMAND_INSTANCE_GET_BOSS_STATE = 796, RBAC_PERM_COMMAND_PVPSTATS = 797, RBAC_PERM_COMMAND_MODIFY_XP = 798, + RBAC_PERM_COMMAND_GO_BUG_TICKET = 799, + RBAC_PERM_COMMAND_GO_COMPLAINT_TICKET = 800, + RBAC_PERM_COMMAND_GO_SUGGESTION_TICKET = 801, + RBAC_PERM_COMMAND_TICKET_BUG = 802, + RBAC_PERM_COMMAND_TICKET_COMPLAINT = 803, + RBAC_PERM_COMMAND_TICKET_SUGGESTION = 804, + RBAC_PERM_COMMAND_TICKET_BUG_ASSIGN = 805, + RBAC_PERM_COMMAND_TICKET_BUG_CLOSE = 806, + RBAC_PERM_COMMAND_TICKET_BUG_CLOSEDLIST = 807, + RBAC_PERM_COMMAND_TICKET_BUG_COMMENT = 808, + RBAC_PERM_COMMAND_TICKET_BUG_DELETE = 809, + RBAC_PERM_COMMAND_TICKET_BUG_LIST = 810, + RBAC_PERM_COMMAND_TICKET_BUG_UNASSIGN = 811, + RBAC_PERM_COMMAND_TICKET_BUG_VIEW = 812, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_ASSIGN = 813, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSE = 814, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSEDLIST = 815, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_COMMENT = 816, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_DELETE = 817, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_LIST = 818, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_UNASSIGN = 819, + RBAC_PERM_COMMAND_TICKET_COMPLAINT_VIEW = 820, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_ASSIGN = 821, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSE = 822, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSEDLIST = 823, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_COMMENT = 824, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_DELETE = 825, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_LIST = 826, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_UNASSIGN = 827, + RBAC_PERM_COMMAND_TICKET_SUGGESTION_VIEW = 828, + RBAC_PERM_COMMAND_TICKET_RESET_ALL = 829, + RBAC_PERM_COMMAND_TICKET_RESET_GM = 830, + RBAC_PERM_COMMAND_TICKET_RESET_BUG = 831, + RBAC_PERM_COMMAND_TICKET_RESET_COMPLAINT = 832, + RBAC_PERM_COMMAND_TICKET_RESET_SUGGESTION = 833, // custom permissions 1000+ RBAC_PERM_MAX diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 2773178da08..18c710c2a20 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -43,9 +43,9 @@ file(GLOB_RECURSE sources_Scripting Scripting/*.cpp Scripting/*.h) 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_Support Support/*.cpp Support/*.h) file(GLOB_RECURSE sources_Texts Texts/*.cpp Texts/*.h) file(GLOB_RECURSE sources_Tools Tools/*.cpp Tools/*.h) -file(GLOB_RECURSE sources_Tickets Tickets/*.cpp Tickets/*.h) file(GLOB_RECURSE sources_Warden Warden/*.cpp Warden/*.h) file(GLOB_RECURSE sources_Weather Weather/*.cpp Weather/*.h) file(GLOB_RECURSE sources_World World/*.cpp World/*.h) @@ -94,9 +94,9 @@ set(game_STAT_SRCS ${sources_Server} ${sources_Skills} ${sources_Spells} + ${sources_Support} ${sources_Texts} ${sources_Tools} - ${sources_Tickets} ${sources_Warden} ${sources_Weather} ${sources_World} @@ -198,9 +198,9 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Skills ${CMAKE_CURRENT_SOURCE_DIR}/Spells ${CMAKE_CURRENT_SOURCE_DIR}/Spells/Auras + ${CMAKE_CURRENT_SOURCE_DIR}/Support ${CMAKE_CURRENT_SOURCE_DIR}/Texts ${CMAKE_CURRENT_SOURCE_DIR}/Tools - ${CMAKE_CURRENT_SOURCE_DIR}/Tickets ${CMAKE_CURRENT_SOURCE_DIR}/Warden ${CMAKE_CURRENT_SOURCE_DIR}/Warden/Modules ${CMAKE_CURRENT_SOURCE_DIR}/Weather diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a25111df730..b46783deffb 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3243,17 +3243,12 @@ void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResp result.Command = mailAction; result.ErrorCode = mailError; - switch (mailError) + if (mailError == MAIL_ERR_EQUIP_ERROR) + result.BagResult = equipError; + else if (mailAction == MAIL_ITEM_TAKEN) { - case MAIL_ERR_EQUIP_ERROR: - result.BagResult = equipError; - break; - case MAIL_ITEM_TAKEN: - result.AttachID = item_guid; - result.QtyInInventory = item_count; - break; - default: - break; + result.AttachID = item_guid; + result.QtyInInventory = item_count; } GetSession()->SendPacket(result.Write()); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ba6b064d2f3..7a63d38f4fa 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1096,14 +1096,20 @@ void WorldSession::SendFeatureSystemStatus() features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened features.EuropaTicketSystemStatus.HasValue = true; - features.EuropaTicketSystemStatus.Value.ThrottleState.MaxTries = 5; - features.EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds = 5; - features.EuropaTicketSystemStatus.Value.ThrottleState.TryCount = 0; - features.EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow = time(nullptr) - 5000; + features.EuropaTicketSystemStatus.Value.ThrottleState.MaxTries = 10; + features.EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds = 60000; + features.EuropaTicketSystemStatus.Value.ThrottleState.TryCount = 1; + features.EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow = 111111; + features.ComplaintStatus = 0; + features.TutorialsEnabled = true; + features.UnkBit90 = true; /// END OF DUMMY VALUES - features.EuropaTicketSystemStatus.Value.SubmitBugEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_BUG); - features.EuropaTicketSystemStatus.Value.TicketSystemEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_TICKET); + features.EuropaTicketSystemStatus.Value.TicketsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED); + features.EuropaTicketSystemStatus.Value.BugsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED); + features.EuropaTicketSystemStatus.Value.ComplaintsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED); + features.EuropaTicketSystemStatus.Value.SuggestionsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED); + features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED); features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED); diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index 5b2e197ae7a..55bbe96f15c 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -22,17 +22,17 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" -#include "TicketMgr.h" +#include "SupportMgr.h" #include "TicketPackets.h" #include "Util.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData) +void WorldSession::HandleGMTicketCreateOpcode(WorldPackets::Ticket::GMTicketCreate& packet) { // Don't accept tickets if the ticket queue is disabled. (Ticket UI is greyed out but not fully dependable) - if (sTicketMgr->GetStatus() == GMTICKET_QUEUE_STATUS_DISABLED) + if (sSupportMgr->GetSupportSystemStatus() == GMTICKET_QUEUE_STATUS_DISABLED) return; if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ)) @@ -42,140 +42,101 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData) } GMTicketResponse response = GMTICKET_RESPONSE_CREATE_ERROR; - GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()); + GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID()); if (ticket && ticket->IsCompleted()) - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); + sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID()); // Player must not have ticket if (!ticket || ticket->IsClosed()) { - uint32 mapId; - float x, y, z; - std::string message; - uint32 needResponse; - bool needMoreHelp; - uint32 count; - std::list<uint32> times; - uint32 decompressedSize; std::string chatLog; - recvData >> mapId; - recvData >> x >> y >> z; - recvData >> message; - - recvData >> needResponse; - recvData >> needMoreHelp; - - recvData >> count; - - for (uint32 i = 0; i < count; i++) + if (packet.DataLength > 0 && packet.ChatHistoryData.DecompressedSize < 0xFFFF) { - uint32 time; - recvData >> time; - times.push_back(time); - } - - recvData >> decompressedSize; - - if (count && decompressedSize && decompressedSize < 0xFFFF) - { - uint32 pos = recvData.rpos(); ByteBuffer dest; - dest.resize(decompressedSize); + dest.resize(size_t(packet.ChatHistoryData.DecompressedSize)); - uLongf realSize = decompressedSize; - if (uncompress(dest.contents(), &realSize, recvData.contents() + pos, recvData.size() - pos) == Z_OK) - { + uLongf realSize = packet.ChatHistoryData.DecompressedSize; + + if (uncompress(dest.contents(), &realSize, packet.ChatHistoryData.Data.contents(), packet.ChatHistoryData.Data.size()) == Z_OK) dest >> chatLog; - } else { TC_LOG_ERROR("network", "CMSG_GM_TICKET_CREATE possibly corrupt. Uncompression failed."); - recvData.rfinish(); return; } - - recvData.rfinish(); // Will still have compressed data in buffer. } ticket = new GmTicket(GetPlayer()); - ticket->SetPosition(mapId, x, y, z); - ticket->SetMessage(message); - ticket->SetGmAction(needResponse, needMoreHelp); + ticket->SetPosition(packet.Map, packet.Pos); + ticket->SetDescription(packet.Description); + ticket->SetGmAction(packet.NeedResponse, packet.NeedMoreHelp); - if (!chatLog.empty()) - ticket->SetChatLog(times, chatLog); + //TODO: more reasearch needed + //if (!chatLog.empty()) + //ticket->SetChatLog(times, chatLog); - sTicketMgr->AddTicket(ticket); - sTicketMgr->UpdateLastChange(); + sSupportMgr->AddTicket(ticket); + sSupportMgr->UpdateLastChange(); sWorld->SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName().c_str(), ticket->GetId()); response = GMTICKET_RESPONSE_CREATE_SUCCESS; } - - WorldPacket data(SMSG_GM_TICKET_UPDATE, 4); - data << uint32(response); - SendPacket(&data); + sSupportMgr->SendGmTicketUpdate(this, response); } -void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket& recvData) +void WorldSession::HandleGMTicketUpdateTextOpcode(WorldPackets::Ticket::GMTicketUpdateText& packet) { - std::string message; - recvData >> message; - GMTicketResponse response = GMTICKET_RESPONSE_UPDATE_ERROR; - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID())) { SQLTransaction trans = SQLTransaction(NULL); - ticket->SetMessage(message); + ticket->SetDescription(packet.Description); ticket->SaveToDB(trans); sWorld->SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName().c_str(), ticket->GetId()); response = GMTICKET_RESPONSE_UPDATE_SUCCESS; } - - WorldPacket data(SMSG_GM_TICKET_UPDATE, 4); - data << uint32(response); - SendPacket(&data); + sSupportMgr->SendGmTicketUpdate(this, response); } -void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleGMTicketDeleteOpcode(WorldPackets::Ticket::GMTicketDelete& /*packet*/) { - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID())) { - WorldPacket data(SMSG_GM_TICKET_UPDATE, 4); - data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - SendPacket(&data); + sSupportMgr->SendGmTicketUpdate(this, GMTICKET_RESPONSE_TICKET_DELETED); sWorld->SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName().c_str(), ticket->GetId()); - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); - sTicketMgr->SendTicket(this, NULL); + sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID()); + sSupportMgr->SendGmTicket(this, NULL); } } void WorldSession::HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& /*packet*/) { - // TODO: Implement GmCase and handle this packet correctly + // TODO: Implement GmCase and handle this packet properly + WorldPackets::Ticket::GMTicketCaseStatus status; + status.OldestTicketTime = time(nullptr); + SendPacket(status.Write()); } void WorldSession::HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& /*packet*/) { SendQueryTimeResponse(); - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID())) { if (ticket->IsCompleted()) - // TODO: Update SMSG_GM_TICKET_RESPONSE ticket->SendResponse(this); else - sTicketMgr->SendTicket(this, ticket); + sSupportMgr->SendGmTicket(this, ticket); } else - sTicketMgr->SendTicket(this, NULL); + sSupportMgr->SendGmTicket(this, NULL); } void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& /*packet*/) @@ -183,100 +144,93 @@ void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTick // Note: This only disables the ticket UI at client side and is not fully reliable // Note: This disables the whole customer support UI after trying to send a ticket in disabled state (MessageBox: "GM Help Tickets are currently unavaiable."). UI remains disabled until the character relogs. WorldPackets::Ticket::GMTicketSystemStatus response; - response.Status = sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED; + response.Status = sSupportMgr->GetSupportSystemStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED; SendPacket(response.Write()); } -void WorldSession::HandleGMSurveySubmit(WorldPacket& recvData) +void WorldSession::HandleGMSurveySubmit(WorldPackets::Ticket::GMSurveySubmit& /*packet*/) { - uint32 nextSurveyID = sTicketMgr->GetNextSurveyID(); - // just put the survey into the database - uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc - recvData >> mainSurvey; + /*uint32 nextSurveyID = sSupportMgr->GetNextSurveyID(); std::unordered_set<uint32> surveyIds; SQLTransaction trans = CharacterDatabase.BeginTransaction(); - // 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 < 15; i++) + + for (auto const& q : packet.SurveyQuestion) { - uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) - recvData >> subSurveyId; - if (!subSurveyId) + if (!q.QuestionID) break; - uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc - recvData >> rank; - std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") - recvData >> comment; - // make sure the same sub survey is not added to DB twice - if (!surveyIds.insert(subSurveyId).second) + if (!surveyIds.insert(q.QuestionID).second) continue; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SUBSURVEY); stmt->setUInt32(0, nextSurveyID); - stmt->setUInt32(1, subSurveyId); - stmt->setUInt32(2, rank); - stmt->setString(3, comment); + stmt->setUInt32(1, q.QuestionID); // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) + stmt->setUInt32(2, q.Answer); // probably some sort of ref to GMSurveyAnswers.dbc + stmt->setString(3, q.AnswerComment); // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") trans->Append(stmt); } - std::string comment; // just a guess - recvData >> comment; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SURVEY); stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); stmt->setUInt32(1, nextSurveyID); - stmt->setUInt32(2, mainSurvey); - stmt->setString(3, comment); - + stmt->setUInt32(2, packet.SurveyID); // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc + stmt->setString(3, packet.Comment); trans->Append(stmt); - CharacterDatabase.CommitTransaction(trans); + CharacterDatabase.CommitTransaction(trans);*/ } -void WorldSession::HandleReportLag(WorldPacket& recvData) +void WorldSession::HandleGMResponseResolve(WorldPackets::Ticket::GMTicketResponseResolve& /*packet*/) { - // just put the lag report into the database... - // can't think of anything else to do with it - uint32 lagType, mapId; - recvData >> lagType; - recvData >> mapId; - float x, y, z; - recvData >> x; - recvData >> y; - recvData >> z; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LAG_REPORT); - stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter()); - stmt->setUInt8 (1, lagType); - stmt->setUInt16(2, mapId); - stmt->setFloat (3, x); - stmt->setFloat (4, y); - stmt->setFloat (5, z); - stmt->setUInt32(6, GetLatency()); - stmt->setUInt32(7, time(NULL)); - CharacterDatabase.Execute(stmt); -} - -void WorldSession::HandleGMResponseResolve(WorldPacket& /*recvPacket*/) -{ - // empty packet - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID())) { - uint8 getSurvey = 0; + bool showSurvey = false; if (float(rand_chance()) < sWorld->getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY)) - getSurvey = 1; + showSurvey = true; - WorldPacket data(SMSG_GM_TICKET_STATUS_UPDATE, 4); - data << uint8(getSurvey); - SendPacket(&data); + WorldPackets::Ticket::GMTicketResolveResponse response; + response.ShowSurvey = showSurvey; + SendPacket(response.Write()); - WorldPacket data2(SMSG_GM_TICKET_UPDATE, 4); - data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - SendPacket(&data2); + sSupportMgr->SendGmTicketUpdate(this, GMTICKET_RESPONSE_TICKET_DELETED); - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); - sTicketMgr->SendTicket(this, NULL); + sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID()); + sSupportMgr->SendGmTicket(this, NULL); } } + +void WorldSession::HandleSupportTicketSubmitBug(WorldPackets::Ticket::SupportTicketSubmitBug& packet) +{ + BugTicket* ticket = new BugTicket(GetPlayer()); + ticket->SetPosition(packet.Header.MapID, packet.Header.Position); + ticket->SetFacing(packet.Header.Facing); + ticket->SetNote(packet.Note); + + sSupportMgr->AddTicket(ticket); +} + +void WorldSession::HandleSupportTicketSubmitSuggestion(WorldPackets::Ticket::SupportTicketSubmitSuggestion& packet) +{ + SuggestionTicket* ticket = new SuggestionTicket(GetPlayer()); + ticket->SetPosition(packet.Header.MapID, packet.Header.Position); + ticket->SetFacing(packet.Header.Facing); + ticket->SetNote(packet.Note); + + sSupportMgr->AddTicket(ticket); +} + +void WorldSession::HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet) +{ + ComplaintTicket* comp = new ComplaintTicket(GetPlayer()); + comp->SetPosition(packet.Header.MapID, packet.Header.Position); + comp->SetFacing(packet.Header.Facing); + comp->SetChatLog(packet.ChatLog); + comp->SetTargetCharacterGuid(packet.TargetCharacterGUID); + comp->SetComplaintType(GMSupportComplaintType(packet.ComplaintType)); + comp->SetNote(packet.Note); + + sSupportMgr->AddTicket(comp); + +} diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index ef4035469a9..446ee2606e1 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -985,7 +985,8 @@ enum TrinityStrings LANG_ACCOUNT_ALREADY_LINKED = 1187, LANG_ACCOUNT_BNET_UNLINKED = 1188, LANG_ACCOUNT_BNET_NOT_LINKED = 1189, - // Room for more level 3 1190-1199 not used + LANG_DISALLOW_TICKETS_CONFIG = 1190, + // Room for more level 3 1191-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/server/game/Server/Packets/LFGPackets.cpp b/src/server/game/Server/Packets/LFGPackets.cpp new file mode 100644 index 00000000000..4e7bc35b55a --- /dev/null +++ b/src/server/game/Server/Packets/LFGPackets.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <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, see <http://www.gnu.org/licenses/>. + */ + +#include "LFGPackets.h" + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::LFG::RideTicket& ticket) +{ + data >> ticket.RequesterGuid; + data >> ticket.Id; + data >> ticket.Type; + data >> ticket.Time; + + return data; +} diff --git a/src/server/game/Server/Packets/LFGPackets.h b/src/server/game/Server/Packets/LFGPackets.h new file mode 100644 index 00000000000..e62cb47b41a --- /dev/null +++ b/src/server/game/Server/Packets/LFGPackets.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LFGPackets_h__ +#define LFGPackets_h__ + +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace LFG + { + struct RideTicket + { + ObjectGuid RequesterGuid; + int32 Id = 0; + int32 Type = 0; + time_t Time = 0; + }; + } +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::LFG::RideTicket& ticket); + +#endif // LFGPackets_h__ diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp index 1a01c2d28c6..a88895fb35c 100644 --- a/src/server/game/Server/Packets/SystemPackets.cpp +++ b/src/server/game/Server/Packets/SystemPackets.cpp @@ -39,18 +39,20 @@ WorldPacket const* WorldPackets::System::FeatureSystemStatus::Write() _worldPacket.WriteBit(SessionAlert.HasValue); _worldPacket.WriteBit(RecruitAFriendSendingEnabled); _worldPacket.WriteBit(CharUndeleteEnabled); - _worldPacket.WriteBit(UnkBit21); - _worldPacket.WriteBit(UnkBit22); + _worldPacket.WriteBit(RestrictedAccount); + _worldPacket.WriteBit(TutorialsEnabled); _worldPacket.WriteBit(UnkBit90); _worldPacket.WriteBit(TwitterEnabled); _worldPacket.WriteBit(UnkBit61); + _worldPacket.FlushBits(); + if (EuropaTicketSystemStatus.HasValue) { - _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit0); - _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit1); - _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.TicketSystemEnabled); - _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.SubmitBugEnabled); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.TicketsEnabled); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.BugsEnabled); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.ComplaintsEnabled); + _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.SuggestionsEnabled); _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.MaxTries); _worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds); diff --git a/src/server/game/Server/Packets/SystemPackets.h b/src/server/game/Server/Packets/SystemPackets.h index 897726575a4..d20d35649fb 100644 --- a/src/server/game/Server/Packets/SystemPackets.h +++ b/src/server/game/Server/Packets/SystemPackets.h @@ -37,10 +37,10 @@ namespace WorldPackets struct EuropaTicketConfig { - bool UnkBit0 = false; - bool UnkBit1 = false; - bool TicketSystemEnabled = false; - bool SubmitBugEnabled = false; + bool TicketsEnabled = false; + bool BugsEnabled = false; + bool ComplaintsEnabled = false; + bool SuggestionsEnabled = false; SavedThrottleObjectState ThrottleState; }; @@ -76,8 +76,8 @@ namespace WorldPackets bool BpayStoreDisabledByParentalControls = false; bool TwitterEnabled = false; - bool UnkBit21 = false; - bool UnkBit22 = false; + bool RestrictedAccount = false; + bool TutorialsEnabled = false; bool UnkBit90 = false; bool UnkBit61 = false; }; diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index 8567cebd736..1a4d4d00c0a 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -15,8 +15,21 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "LFGPackets.h" +#include "PacketUtilities.h" #include "TicketPackets.h" +using namespace WorldPackets; + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketHeader& header) +{ + data >> header.MapID; + data >> header.Position; + data >> header.Facing; + + return data; +} + WorldPacket const* WorldPackets::Ticket::GMTicketSystemStatus::Write() { _worldPacket << int32(Status); @@ -80,3 +93,281 @@ WorldPacket const* WorldPackets::Ticket::GMTicketGetTicketResponse::Write() return &_worldPacket; } + +void WorldPackets::Ticket::GMTicketCreate::Read() +{ + _worldPacket >> Map; + _worldPacket >> Pos; + _worldPacket >> Flags; + + uint16 descLength = _worldPacket.ReadBits(11); + Description = _worldPacket.ReadString(descLength); + _worldPacket.ResetBitPos(); + + NeedMoreHelp = _worldPacket.ReadBit(); + NeedResponse = _worldPacket.ReadBit(); + _worldPacket >> DataLength; + + if (DataLength > 0) + { + _worldPacket >> ChatHistoryData.TextCount; + for (uint8 i = 0; i < ChatHistoryData.TextCount; ++i) + ChatHistoryData.Sent.push_back(_worldPacket.read<uint32>()); + + _worldPacket >> ChatHistoryData.DecompressedSize; + + //Note: don't ask why, but it works... + uint32 realLength = DataLength - ((ChatHistoryData.TextCount * 4) + 5); + ChatHistoryData.Data.resize(realLength); + _worldPacket.read(ChatHistoryData.Data.contents(), realLength); + } +} + +void WorldPackets::Ticket::GMTicketUpdateText::Read() +{ + uint16 descLength = _worldPacket.ReadBits(11); + Description = _worldPacket.ReadString(descLength); +} + +WorldPacket const* WorldPackets::Ticket::GMTicketUpdate::Write() +{ + _worldPacket << uint8(Result); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Ticket::GMTicketStatusUpdate::Write() +{ + _worldPacket << int32(StatusInt); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Ticket::GMTicketResponse::Write() +{ + _worldPacket << uint32(TicketID); + _worldPacket << uint32(ResponseID); + + _worldPacket.WriteBits(Description.size(), 11); + _worldPacket.WriteBits(ResponseText.size(), 14); + _worldPacket.FlushBits(); + + _worldPacket.WriteString(Description); + _worldPacket.WriteString(ResponseText); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Ticket::GMTicketResolveResponse::Write() +{ + _worldPacket.WriteBit(ShowSurvey); + + _worldPacket.FlushBits(); + return &_worldPacket; +} + +void WorldPackets::Ticket::GMSurveySubmit::Read() +{ + _worldPacket >> SurveyID; + + SurveyQuestion.resize(_worldPacket.ReadBits(4)); + uint16 commentLength = _worldPacket.ReadBits(11); + + for (auto& q : SurveyQuestion) + { + _worldPacket >> q.QuestionID; + _worldPacket >> q.Answer; + q.AnswerComment = _worldPacket.ReadString(_worldPacket.ReadBits(11)); + } + + Comment = _worldPacket.ReadString(commentLength); +} + +void WorldPackets::Ticket::SupportTicketSubmitBug::Read() +{ + _worldPacket >> Header; + Note = _worldPacket.ReadString(_worldPacket.ReadBits(10)); +} + +void WorldPackets::Ticket::SupportTicketSubmitSuggestion::Read() +{ + _worldPacket >> Header; + Note = _worldPacket.ReadString(_worldPacket.ReadBits(10)); +} + +WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine::SupportTicketChatLine(ByteBuffer& data) +{ + data >> Timestamp; + uint16 textLength = data.ReadBits(12); + data.ResetBitPos(); + Text = data.ReadString(textLength); +} + +WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine::SupportTicketChatLine(uint32 timestamp, std::string const& text) +{ + Timestamp = timestamp; + Text = text; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine& line) +{ + data >> line.Timestamp; + uint16 textLength = data.ReadBits(12); + data.ResetBitPos(); + line.Text = data.ReadString(textLength); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLog& chatlog) +{ + uint32 linesCount = data.read<uint32>(); + + for (uint32 i = 0; i < linesCount; i++) + chatlog.Lines.emplace_back(data); + + bool hasReportLineIndex = data.ReadBit(); + if (hasReportLineIndex) + chatlog.ReportLineIndex.Set(data.read<uint32>()); + + data.ResetBitPos(); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketMailInfo& mail) +{ + data >> mail.MailID; + uint16 bodyLength = data.ReadBits(13); + uint16 subjectLength = data.ReadBits(9); + + mail.MailBody = data.ReadString(bodyLength); + mail.MailSubject = data.ReadString(subjectLength); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketCalendarEventInfo& event) +{ + data >> event.EventID; + data >> event.InviteID; + uint8 titleLength = data.ReadBits(8); + + event.EventTitle = data.ReadString(titleLength); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketPetInfo& pet) +{ + data >> pet.PetID; + uint8 nameLength = data.ReadBits(8); + + pet.PetName = data.ReadString(nameLength); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketGuildInfo& guild) +{ + data >> guild.GuildID; + uint8 nameLength = data.ReadBits(8); + + guild.GuildName = data.ReadString(nameLength); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::Struct5E4383& str) +{ + data >> str.RideTicket; + data >> str._40; + data >> str._56; + data >> str._72; + + uint8 _88Length = data.ReadBits(8); + uint8 _217Length = data.ReadBits(8); + uint8 _1242Length = data.ReadBits(8); + + str._88 = data.ReadString(_88Length); + str._217 = data.ReadString(_217Length); + str._1242 = data.ReadString(_1242Length); + + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::Struct5E3DFB& str) +{ + data >> str.RideTicket; + + uint16 _32Length = data.ReadBits(9); + data.ResetBitPos(); + + str._32 = data.ReadString(_32Length); + + return data; +} + +void WorldPackets::Ticket::SupportTicketSubmitComplaint::Read() +{ + _worldPacket >> Header; + _worldPacket >> ChatLog; + _worldPacket >> TargetCharacterGUID; + ComplaintType = _worldPacket.ReadBits(5); + + uint16 noteLength = _worldPacket.ReadBits(10); + bool hasMailInfo = _worldPacket.ReadBit(); + bool hasCalendarInfo = _worldPacket.ReadBit(); + bool hasPetInfo = _worldPacket.ReadBit(); + bool hasGuildInfo = _worldPacket.ReadBit(); + bool has5E4383 = _worldPacket.ReadBit(); + bool has5E3DFB = _worldPacket.ReadBit(); + + _worldPacket.ResetBitPos(); + + Note = _worldPacket.ReadString(noteLength); + + if (hasMailInfo) + { + _worldPacket >> MailInfo.Value; + MailInfo.HasValue = true; + } + + if (hasCalendarInfo) + { + _worldPacket >> CalenderInfo.Value; + CalenderInfo.HasValue = true; + } + + if (hasPetInfo) + { + _worldPacket >> PetInfo.Value; + PetInfo.HasValue = true; + } + + if (hasGuildInfo) + { + _worldPacket >> GuildInfo.Value; + GuildInfo.HasValue = true; + } + + if (has5E4383) + { + _worldPacket >> _5E4383.Value; + _5E4383.HasValue = true; + } + + if (has5E3DFB) + { + _worldPacket >> _5E3DFB.Value; + _5E3DFB.HasValue = true; + } +} + +WorldPacket const* WorldPackets::Ticket::ComplaintResult::Write() +{ + _worldPacket << uint32(ComplaintType); + _worldPacket << uint8(Result); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/TicketPackets.h b/src/server/game/Server/Packets/TicketPackets.h index 8a5ae862f84..e11adf912ed 100644 --- a/src/server/game/Server/Packets/TicketPackets.h +++ b/src/server/game/Server/Packets/TicketPackets.h @@ -19,11 +19,20 @@ #define TicketPackets_h__ #include "Packet.h" +#include "LFGPackets.h" +#include <G3D/Vector3.h> namespace WorldPackets { namespace Ticket { + struct SupportTicketHeader + { + int32 MapID = 0; + G3D::Vector3 Position; + float Facing = 0.0f; + }; + class GMTicketGetSystemStatus final : public ClientPacket { public: @@ -107,6 +116,120 @@ namespace WorldPackets Optional<GMTicketInfo> Info; }; + class GMTicketCreate final : public ClientPacket + { + public: + struct ChatHistoryData + { + uint8 TextCount = 0; + std::vector<uint32> Sent; + uint32 DecompressedSize = 0; + ByteBuffer Data; + }; + + GMTicketCreate(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_CREATE, std::move(packet)) { } + + void Read() override; + + int32 Map = 0; + G3D::Vector3 Pos; + uint8 Flags = 0; + std::string Description; + bool NeedMoreHelp = false; + bool NeedResponse = false; + uint32 DataLength = 0; + ChatHistoryData ChatHistoryData; ///< Compressed Data + }; + + class GMTicketUpdateText final : public ClientPacket + { + public: + GMTicketUpdateText(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_UPDATE_TEXT, std::move(packet)) { } + + void Read() override; + + std::string Description; + }; + + class GMTicketUpdate final : public ServerPacket + { + public: + GMTicketUpdate() : ServerPacket(SMSG_GM_TICKET_UPDATE, 1) { } + + WorldPacket const* Write() override; + + uint8 Result = 0; + }; + + class GMTicketStatusUpdate final : public ServerPacket + { + public: + GMTicketStatusUpdate() : ServerPacket(SMSG_GM_TICKET_STATUS_UPDATE, 4) { } + + WorldPacket const* Write() override; + + int32 StatusInt = 0; + }; + + class GMTicketDelete final : public ClientPacket + { + public: + GMTicketDelete(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_DELETE_TICKET, std::move(packet)) { } + + void Read() override { } + }; + + class GMTicketResponse final : public ServerPacket + { + public: + GMTicketResponse() : ServerPacket(SMSG_GM_TICKET_RESPONSE, 12) { } + + WorldPacket const* Write() override; + + uint32 TicketID = 0; + uint32 ResponseID = 0; + std::string Description; + std::string ResponseText; + }; + + class GMTicketResponseResolve final : public ClientPacket + { + public: + GMTicketResponseResolve(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_RESPONSE_RESOLVE, std::move(packet)) { } + + void Read() override { } + }; + + class GMTicketResolveResponse final : public ServerPacket + { + public: + GMTicketResolveResponse() : ServerPacket(SMSG_GM_TICKET_RESOLVE_RESPONSE, 1) { } + + WorldPacket const* Write() override; + + bool ShowSurvey = false; + }; + + class GMSurveySubmit final : public ClientPacket + { + public: + struct GMSurveyQuestion + { + int32 QuestionID = 0; + uint8 Answer = 0; + std::string AnswerComment; + }; + + GMSurveySubmit(WorldPacket&& packet) : ClientPacket(CMSG_GM_SURVEY_SUBMIT, std::move(packet)) { } + + void Read() override; + + int32 SurveyID = 0; + std::vector<GMSurveyQuestion> SurveyQuestion; + std::string Comment; + + }; + class GMTicketAcknowledgeSurvey final : public ClientPacket { public: @@ -124,6 +247,118 @@ namespace WorldPackets WorldPacket const* Write() { return &_worldPacket; } }; + + class SupportTicketSubmitBug final : public ClientPacket + { + public: + SupportTicketSubmitBug(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_BUG, std::move(packet)) { } + + void Read() override; + + SupportTicketHeader Header; + std::string Note; + }; + + class SupportTicketSubmitSuggestion final : public ClientPacket + { + public: + SupportTicketSubmitSuggestion(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, std::move(packet)) { } + + void Read() override; + + SupportTicketHeader Header; + std::string Note; + }; + + class SupportTicketSubmitComplaint final : public ClientPacket + { + public: + struct SupportTicketChatLine + { + SupportTicketChatLine(ByteBuffer& data); + SupportTicketChatLine(uint32 timestamp, std::string const& text); + + uint32 Timestamp = 0; + std::string Text; + }; + + struct SupportTicketChatLog + { + std::vector<SupportTicketChatLine> Lines; + Optional<uint32> ReportLineIndex; + }; + + struct SupportTicketMailInfo + { + int32 MailID = 0; + std::string MailSubject; + std::string MailBody; + }; + + struct SupportTicketCalendarEventInfo + { + ObjectGuid EventID; + ObjectGuid InviteID; + std::string EventTitle; + }; + + struct SupportTicketPetInfo + { + ObjectGuid PetID; + std::string PetName; + }; + + struct SupportTicketGuildInfo + { + ObjectGuid GuildID; + std::string GuildName; + }; + + struct Struct5E4383 + { + WorldPackets::LFG::RideTicket RideTicket; + ObjectGuid _40; + ObjectGuid _56; + ObjectGuid _72; + std::string _88; + std::string _217; + std::string _1242; + }; + + struct Struct5E3DFB + { + WorldPackets::LFG::RideTicket RideTicket; + std::string _32; + }; + + SupportTicketSubmitComplaint(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, std::move(packet)) { } + + void Read() override; + + SupportTicketHeader Header; + SupportTicketChatLog ChatLog; + ObjectGuid TargetCharacterGUID; + uint8 ComplaintType = 0; + std::string Note; + Optional<SupportTicketMailInfo> MailInfo; + Optional<SupportTicketCalendarEventInfo> CalenderInfo; + Optional<SupportTicketPetInfo> PetInfo; + Optional<SupportTicketGuildInfo> GuildInfo; + Optional<Struct5E4383> _5E4383; + Optional<Struct5E3DFB> _5E3DFB; + + }; + + class ComplaintResult final : public ServerPacket + { + public: + ComplaintResult() : ServerPacket(SMSG_COMPLAINT_RESULT, 9) { } + + WorldPacket const* Write() override; + + uint32 ComplaintType = 0; + uint8 Result = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index de285fb1ed6..43ffe3e223e 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -379,20 +379,19 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_GET_UNDELETE_COOLDOWN_STATUS, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GetUndeleteCooldownStatus, &WorldSession::HandleGetUndeleteCooldownStatus); DEFINE_OPCODE_HANDLER_OLD(CMSG_GHOST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_INVIS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_LAG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReportLag ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_LAG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_NUKE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SET_SECURITY_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit ); + DEFINE_HANDLER(CMSG_GM_SURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMSurveySubmit, &WorldSession::HandleGMSurveySubmit); DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_HANDLER(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketAcknowledgeSurvey, &WorldSession::HandleGMTicketAcknowledgeSurveyOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_CREATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketCreateOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_DELETE_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketDeleteOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - //DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketGetCaseStatus, &WorldSession::HandleGMTicketGetCaseStatusOpcode); - DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetSystemStatus, &WorldSession::HandleGMTicketSystemStatusOpcode); - DEFINE_HANDLER(CMSG_GM_TICKET_GET_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetTicket, &WorldSession::HandleGMTicketGetTicketOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_RESPONSE_RESOLVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_UPDATE_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode ); + DEFINE_HANDLER(CMSG_GM_TICKET_CREATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketCreate, &WorldSession::HandleGMTicketCreateOpcode); + DEFINE_HANDLER(CMSG_GM_TICKET_DELETE_TICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketDelete, &WorldSession::HandleGMTicketDeleteOpcode); + DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketGetCaseStatus, &WorldSession::HandleGMTicketGetCaseStatusOpcode); + DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetSystemStatus, &WorldSession::HandleGMTicketSystemStatusOpcode); + DEFINE_HANDLER(CMSG_GM_TICKET_GET_TICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetTicket, &WorldSession::HandleGMTicketGetTicketOpcode); + DEFINE_HANDLER(CMSG_GM_TICKET_RESPONSE_RESOLVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketResponseResolve, &WorldSession::HandleGMResponseResolve); + DEFINE_HANDLER(CMSG_GM_TICKET_UPDATE_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketUpdateText, &WorldSession::HandleGMTicketUpdateTextOpcode); DEFINE_HANDLER(CMSG_GOSSIP_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode); DEFINE_HANDLER(CMSG_GOSSIP_SELECT_OPTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::NPC::GossipSelectOption, &WorldSession::HandleGossipSelectOptionOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_GRANT_LEVEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel ); @@ -804,9 +803,9 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_STOP_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_STORE_LOOT_IN_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUMMON_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_BUG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_BUG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitBug, &WorldSession::HandleSupportTicketSubmitBug); + DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitComplaint, &WorldSession::HandleSupportTicketSubmitComplaint); + DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitSuggestion, &WorldSession::HandleSupportTicketSubmitSuggestion); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_COMMS_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode); @@ -1239,14 +1238,14 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_MESSAGECHAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESOLVE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESOLVE_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 7bc9488dd26..f4bfac9225e 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -292,13 +292,13 @@ enum OpcodeClient : uint32 CMSG_GM_SET_SECURITY_GROUP = 0xBADD, CMSG_GM_SURVEY_SUBMIT = 0xBADD, CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY = 0xBADD, - CMSG_GM_TICKET_CREATE = 0xBADD, - CMSG_GM_TICKET_DELETE_TICKET = 0xBADD, - CMSG_GM_TICKET_GET_CASE_STATUS = 0xBADD, - CMSG_GM_TICKET_GET_SYSTEM_STATUS = 0xBADD, - CMSG_GM_TICKET_GET_TICKET = 0xBADD, - CMSG_GM_TICKET_RESPONSE_RESOLVE = 0xBADD, - CMSG_GM_TICKET_UPDATE_TEXT = 0xBADD, + CMSG_GM_TICKET_CREATE = 0x19A4, + CMSG_GM_TICKET_DELETE_TICKET = 0x1B39, + CMSG_GM_TICKET_GET_CASE_STATUS = 0x17E1, + CMSG_GM_TICKET_GET_SYSTEM_STATUS = 0x1BB9, + CMSG_GM_TICKET_GET_TICKET = 0x1939, + CMSG_GM_TICKET_RESPONSE_RESOLVE = 0x19FB, + CMSG_GM_TICKET_UPDATE_TEXT = 0x19EB, CMSG_GOSSIP_HELLO = 0x0483, CMSG_GOSSIP_SELECT_OPTION = 0xBADD, CMSG_GRANT_LEVEL = 0xBADD, @@ -712,9 +712,9 @@ enum OpcodeClient : uint32 CMSG_STOP_DANCE = 0xBADD, CMSG_STORE_LOOT_IN_SLOT = 0xBADD, CMSG_SUMMON_RESPONSE = 0xBADD, - CMSG_SUPPORT_TICKET_SUBMIT_BUG = 0xBADD, - CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT = 0xBADD, - CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION = 0xBADD, + CMSG_SUPPORT_TICKET_SUBMIT_BUG = 0x11BB, + CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT = 0x1BB1, + CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION = 0x1B63, CMSG_SUSPEND_COMMS_ACK = 0x123C, CMSG_SUSPEND_TOKEN_RESPONSE = 0x1273, CMSG_SWAP_INV_ITEM = 0x00C5, @@ -1171,14 +1171,14 @@ enum OpcodeServer : uint32 SMSG_GM_PLAYER_INFO = 0xBADD, SMSG_GM_REQUEST_PLAYER_INFO = 0xBADD, SMSG_GM_SUMMON = 0xBADD, - SMSG_GM_TICKET_CASE_STATUS = 0xBADD, - SMSG_GM_TICKET_GET_TICKET_RESPONSE = 0xBADD, - SMSG_GM_TICKET_RESOLVE_RESPONSE = 0xBADD, - SMSG_GM_TICKET_RESPONSE = 0xBADD, - SMSG_GM_TICKET_RESPONSE_ERROR = 0xBADD, - SMSG_GM_TICKET_STATUS_UPDATE = 0xBADD, - SMSG_GM_TICKET_SYSTEM_STATUS = 0xBADD, - SMSG_GM_TICKET_UPDATE = 0xBADD, + SMSG_GM_TICKET_CASE_STATUS = 0x086B, + SMSG_GM_TICKET_GET_TICKET_RESPONSE = 0x0183, + SMSG_GM_TICKET_RESOLVE_RESPONSE = 0x0869, + SMSG_GM_TICKET_RESPONSE = 0x1729, + SMSG_GM_TICKET_RESPONSE_ERROR = 0x0A33, + SMSG_GM_TICKET_STATUS_UPDATE = 0x0B74, + SMSG_GM_TICKET_SYSTEM_STATUS = 0x134C, + SMSG_GM_TICKET_UPDATE = 0x193A, SMSG_GOD_MODE = 0xBADD, SMSG_GOSSIP_COMPLETE = 0xBADD, SMSG_GOSSIP_MESSAGE = 0x0117, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 54c995589a4..c7ea26b7adf 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -358,10 +358,18 @@ namespace WorldPackets namespace Ticket { + class GMSurveySubmit; + class GMTicketAcknowledgeSurvey; + class GMTicketCreate; + class GMTicketDelete; class GMTicketGetSystemStatus; class GMTicketGetCaseStatus; class GMTicketGetTicket; - class GMTicketAcknowledgeSurvey; + class GMTicketResponseResolve; + class GMTicketUpdateText; + class SupportTicketSubmitBug; + class SupportTicketSubmitSuggestion; + class SupportTicketSubmitComplaint; } namespace Trade @@ -840,15 +848,17 @@ class WorldSession void HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCancel& logoutCancel); // GM Ticket opcodes - void HandleGMTicketCreateOpcode(WorldPacket& recvPacket); - void HandleGMTicketUpdateOpcode(WorldPacket& recvPacket); - void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket); + void HandleGMTicketCreateOpcode(WorldPackets::Ticket::GMTicketCreate& packet); + void HandleGMTicketUpdateTextOpcode(WorldPackets::Ticket::GMTicketUpdateText& packet); + void HandleGMTicketDeleteOpcode(WorldPackets::Ticket::GMTicketDelete& packet); void HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& packet); void HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& packet); void HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& packet); - void HandleGMSurveySubmit(WorldPacket& recvPacket); - void HandleReportLag(WorldPacket& recvPacket); - void HandleGMResponseResolve(WorldPacket& recvPacket); + void HandleGMSurveySubmit(WorldPackets::Ticket::GMSurveySubmit& packet); + void HandleGMResponseResolve(WorldPackets::Ticket::GMTicketResponseResolve& packet); + void HandleSupportTicketSubmitBug(WorldPackets::Ticket::SupportTicketSubmitBug& packet); + void HandleSupportTicketSubmitSuggestion(WorldPackets::Ticket::SupportTicketSubmitSuggestion& packet); + void HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet); void HandleTogglePvP(WorldPacket& recvPacket); diff --git a/src/server/game/Support/SupportMgr.cpp b/src/server/game/Support/SupportMgr.cpp new file mode 100644 index 00000000000..9183c2f7fde --- /dev/null +++ b/src/server/game/Support/SupportMgr.cpp @@ -0,0 +1,1088 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <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, see <http://www.gnu.org/licenses/>. + */ +#include "Chat.h" +#include "Language.h" +#include "SupportMgr.h" + +inline time_t GetAge(uint64 t) { return (time(nullptr) - t) / DAY; } + +Ticket::Ticket() : _id(0), _mapId(0), _createTime(0) { } + +Ticket::Ticket(Player* player) : _id(0), _mapId(0), _createTime(time(nullptr)) +{ + _playerGuid = player->GetGUID(); +} + +Ticket::~Ticket() { } + +void Ticket::TeleportTo(Player* player) const +{ + player->TeleportTo(_mapId, _pos.x, _pos.y, _pos.z, 0.0f, 0); +} + +std::string Ticket::FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const +{ + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + if (szClosedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName); + if (szAssignedToName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName); + if (szUnassignedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName); + if (szDeletedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName); + return ss.str(); +} + +GmTicket::GmTicket() : _lastModifiedTime(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), _needResponse(false), _needMoreHelp(false) { } + +GmTicket::GmTicket(Player* player) : Ticket(player), _lastModifiedTime(time(nullptr)), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), +_viewed(false), _needResponse(false), _needMoreHelp(false) +{ + _id = sSupportMgr->GenerateGmTicketId(); +} + +GmTicket::~GmTicket() { } + +void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp) +{ + _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default) + _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket" +} + +void GmTicket::SetUnassigned() +{ + _assignedTo.Clear(); + switch (_escalatedStatus) + { + case TICKET_ASSIGNED: _escalatedStatus = TICKET_UNASSIGNED; + break; + case TICKET_ESCALATED_ASSIGNED: _escalatedStatus = TICKET_IN_ESCALATION_QUEUE; + break; + case TICKET_UNASSIGNED: + case TICKET_IN_ESCALATION_QUEUE: + default: + break; + } +} + +void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log) +{ + std::stringstream ss(log); + std::stringstream newss; + std::string line; + while (std::getline(ss, line) && !time.empty()) + { + newss << secsToTimeString(time.front()) << ": " << line << "\n"; + time.pop_front(); + } + + _chatLog = newss.str(); +} + +void GmTicket::SendResponse(WorldSession* session) const +{ + WorldPackets::Ticket::GMTicketResponse resp; + resp.TicketID = GetId(); + resp.ResponseID = 2; //TODO : research + resp.Description = GetDescription(); + resp.ResponseText = GetResponse(); + + session->SendPacket(resp.Write()); +} + +void GmTicket::LoadFromDB(Field* fields) +{ + uint8 idx = 0; + _id = fields[ idx].GetUInt32(); + _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64()); + _description = fields[++idx].GetString(); + _createTime = fields[++idx].GetUInt32(); + _mapId = fields[++idx].GetUInt16(); + _pos.x = fields[++idx].GetFloat(); + _pos.y = fields[++idx].GetFloat(); + _pos.z = fields[++idx].GetFloat(); + _lastModifiedTime = fields[++idx].GetUInt32(); + + int64 closedBy = fields[++idx].GetInt64(); + if (closedBy == 0) + _closedBy = ObjectGuid::Empty; + else if (closedBy < 0) + _closedBy.SetRawValue(0, uint64(closedBy)); + else + _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy)); + + uint64 assignedTo = fields[++idx].GetUInt64(); + if (assignedTo == 0) + _assignedTo = ObjectGuid::Empty; + else + _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo); + + _comment = fields[++idx].GetString(); + _response = fields[++idx].GetString(); + _completed = fields[++idx].GetBool(); + _escalatedStatus = GMTicketEscalationStatus(fields[++idx].GetUInt8()); + _viewed = fields[++idx].GetBool(); + _needMoreHelp = fields[++idx].GetBool(); +} + +void GmTicket::SaveToDB(SQLTransaction& trans) const +{ + uint8 idx = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET); + stmt->setUInt32(idx, _id); + stmt->setUInt64(++idx, _playerGuid.GetCounter()); + stmt->setString(++idx, _description); + stmt->setUInt32(++idx, _createTime); + stmt->setUInt16(++idx, _mapId); + stmt->setFloat(++idx, _pos.x); + stmt->setFloat(++idx, _pos.y); + stmt->setFloat(++idx, _pos.z); + stmt->setUInt32(++idx, uint32(_lastModifiedTime)); + stmt->setInt64(++idx, int64(_closedBy.GetCounter())); + stmt->setUInt64(++idx, _assignedTo.GetCounter()); + stmt->setString(++idx, _comment); + stmt->setString(++idx, _response); + stmt->setBool(++idx, _completed); + stmt->setUInt8(++idx, uint8(_escalatedStatus)); + stmt->setBool(++idx, _viewed); + stmt->setBool(++idx, _needMoreHelp); + + CharacterDatabase.ExecuteOrAppend(trans, stmt); +} + +void GmTicket::DeleteFromDB() +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_TICKET); + stmt->setUInt32(0, _id); + CharacterDatabase.Execute(stmt); +} + +std::string GmTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const +{ + time_t curTime = time(nullptr); + + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(curTime - _lastModifiedTime, true, false)).c_str()); + + std::string name; + if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + + if (detailed) + { + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _description.c_str()); + if (!_comment.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); + if (!_response.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, _response.c_str()); + } + return ss.str(); +} + +std::string GmTicket::FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const +{ + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + if (szClosedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName); + if (szAssignedToName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName); + if (szUnassignedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName); + if (szDeletedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName); + if (szCompletedName) + ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName); + return ss.str(); +} + +BugTicket::BugTicket() : _facing(0.0f) { } + +BugTicket::BugTicket(Player* player) : Ticket(player) +{ + _id = sSupportMgr->GenerateBugId(); +} + +BugTicket::~BugTicket() { } + +void BugTicket::LoadFromDB(Field* fields) +{ + uint8 idx = 0; + _id = fields[ idx].GetUInt32(); + _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64()); + _note = fields[++idx].GetString(); + _createTime = fields[++idx].GetUInt32(); + _mapId = fields[++idx].GetUInt32(); + _pos.x = fields[++idx].GetFloat(); + _pos.y = fields[++idx].GetFloat(); + _pos.z = fields[++idx].GetFloat(); + _facing = fields[++idx].GetFloat(); + + int64 closedBy = fields[++idx].GetInt64(); + if (closedBy == 0) + _closedBy = ObjectGuid::Empty; + else if (closedBy < 0) + _closedBy.SetRawValue(0, uint64(closedBy)); + else + _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy)); + + uint64 assignedTo = fields[++idx].GetUInt64(); + if (assignedTo == 0) + _assignedTo = ObjectGuid::Empty; + else + _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo); + + _comment = fields[++idx].GetString(); +} + +void BugTicket::SaveToDB(SQLTransaction& trans) const +{ + uint8 idx = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_BUG); + stmt->setUInt32(idx, _id); + stmt->setUInt64(++idx, _playerGuid.GetCounter()); + stmt->setString(++idx, _note); + stmt->setUInt32(++idx, _mapId); + stmt->setFloat(++idx, _pos.x); + stmt->setFloat(++idx, _pos.y); + stmt->setFloat(++idx, _pos.z); + stmt->setFloat(++idx, _facing); + stmt->setInt64(++idx, _closedBy.GetCounter()); + stmt->setUInt64(++idx, _assignedTo.GetCounter()); + stmt->setString(++idx, _comment); + + CharacterDatabase.ExecuteOrAppend(trans, stmt); +} + +void BugTicket::DeleteFromDB() +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_BUG); + stmt->setUInt32(0, _id); + CharacterDatabase.Execute(stmt); +} + +std::string BugTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const +{ + time_t curTime = time(nullptr); + + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); + + std::string name; + if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + + if (detailed) + { + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); + if (!_comment.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); + } + return ss.str(); +} + +ComplaintTicket::ComplaintTicket() : _facing(0.0f), _complaintType(GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE) { } + +ComplaintTicket::ComplaintTicket(Player* player) : Ticket(player), _facing(0.0f), _complaintType(GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE) +{ + _id = sSupportMgr->GenerateComplaintId(); +} + +ComplaintTicket::~ComplaintTicket() { } + +void ComplaintTicket::LoadFromDB(Field* fields) +{ + uint8 idx = 0; + _id = fields[ idx].GetUInt32(); + _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64()); + _note = fields[++idx].GetString(); + _createTime = fields[++idx].GetUInt32(); + _mapId = fields[++idx].GetUInt32(); + _pos.x = fields[++idx].GetFloat(); + _pos.y = fields[++idx].GetFloat(); + _pos.z = fields[++idx].GetFloat(); + _facing = fields[++idx].GetFloat(); + _targetCharacterGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64()); + _complaintType = GMSupportComplaintType(fields[++idx].GetUInt8()); + int32 reportLineIndex = fields[++idx].GetInt32(); + if (reportLineIndex != -1) + _chatLog.ReportLineIndex.Set(reportLineIndex); + + int64 closedBy = fields[++idx].GetInt64(); + if (closedBy == 0) + _closedBy = ObjectGuid::Empty; + else if (closedBy < 0) + _closedBy.SetRawValue(0, uint64(closedBy)); + else + _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy)); + + uint64 assignedTo = fields[++idx].GetUInt64(); + if (assignedTo == 0) + _assignedTo = ObjectGuid::Empty; + else + _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo); + + _comment = fields[++idx].GetString(); +} + +void ComplaintTicket::LoadChatLineFromDB(Field* fields) +{ + _chatLog.Lines.emplace_back(fields[0].GetUInt32(), fields[1].GetString()); +} + +void ComplaintTicket::SaveToDB(SQLTransaction& trans) const +{ + bool isInTransaction = bool(trans); + if (!isInTransaction) + trans = CharacterDatabase.BeginTransaction(); + + uint8 idx = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_COMPLAINT); + stmt->setUInt32(idx, _id); + stmt->setUInt64(++idx, _playerGuid.GetCounter()); + stmt->setString(++idx, _note); + stmt->setUInt32(++idx, _mapId); + stmt->setFloat(++idx, _pos.x); + stmt->setFloat(++idx, _pos.y); + stmt->setFloat(++idx, _pos.z); + stmt->setFloat(++idx, _facing); + stmt->setUInt64(++idx, _targetCharacterGuid.GetCounter()); + stmt->setUInt8(++idx, _complaintType); + if (_chatLog.ReportLineIndex.HasValue) + stmt->setInt32(++idx, _chatLog.ReportLineIndex.Value); + else + stmt->setInt32(++idx, -1); // empty ReportLineIndex + stmt->setInt64(++idx, _closedBy.GetCounter()); + stmt->setUInt64(++idx, _assignedTo.GetCounter()); + stmt->setString(++idx, _comment); + trans->Append(stmt); + + uint32 lineIndex = 0; + for (auto const& c : _chatLog.Lines) + { + idx = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_COMPLAINT_CHATLINE); + stmt->setUInt32(idx, _id); + stmt->setUInt32(++idx, lineIndex); + stmt->setUInt32(++idx, c.Timestamp); + stmt->setString(++idx, c.Text); + + trans->Append(stmt); + ++lineIndex; + } + + if (!isInTransaction) + CharacterDatabase.CommitTransaction(trans); +} + +void ComplaintTicket::DeleteFromDB() +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT); + stmt->setUInt32(0, _id); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT_CHATLOG); + stmt->setUInt32(0, _id); +} + +std::string ComplaintTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const +{ + time_t curTime = time(nullptr); + + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); + + std::string name; + if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + + if (detailed) + { + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); + if (!_comment.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); + } + return ss.str(); +} + +SuggestionTicket::SuggestionTicket() : _facing(0.0f) { } + +SuggestionTicket::SuggestionTicket(Player* player) : Ticket(player) +{ + _id = sSupportMgr->GenerateSuggestionId(); +} + +SuggestionTicket::~SuggestionTicket() { } + +void SuggestionTicket::LoadFromDB(Field* fields) +{ + uint8 idx = 0; + _id = fields[ idx].GetUInt32(); + _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64()); + _note = fields[++idx].GetString(); + _createTime = fields[++idx].GetUInt32(); + _mapId = fields[++idx].GetUInt32(); + _pos.x = fields[++idx].GetFloat(); + _pos.y = fields[++idx].GetFloat(); + _pos.z = fields[++idx].GetFloat(); + _facing = fields[++idx].GetFloat(); + + int64 closedBy = fields[++idx].GetInt64(); + if (closedBy == 0) + _closedBy = ObjectGuid::Empty; + else if (closedBy < 0) + _closedBy.SetRawValue(0, uint64(closedBy)); + else + _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy)); + + uint64 assignedTo = fields[++idx].GetUInt64(); + if (assignedTo == 0) + _assignedTo = ObjectGuid::Empty; + else + _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo); + + _comment = fields[++idx].GetString(); +} + +void SuggestionTicket::SaveToDB(SQLTransaction& trans) const +{ + uint8 idx = 0; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_SUGGESTION); + stmt->setUInt32(idx, _id); + stmt->setUInt64(++idx, _playerGuid.GetCounter()); + stmt->setString(++idx, _note); + stmt->setUInt32(++idx, _mapId); + stmt->setFloat(++idx, _pos.x); + stmt->setFloat(++idx, _pos.y); + stmt->setFloat(++idx, _pos.z); + stmt->setFloat(++idx, _facing); + stmt->setInt64(++idx, _closedBy.GetCounter()); + stmt->setUInt64(++idx, _assignedTo.GetCounter()); + stmt->setString(++idx, _comment); + + CharacterDatabase.ExecuteOrAppend(trans, stmt); +} + +void SuggestionTicket::DeleteFromDB() +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_SUGGESTION); + stmt->setUInt32(0, _id); + CharacterDatabase.Execute(stmt); +} + +std::string SuggestionTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const +{ + time_t curTime = time(nullptr); + + std::stringstream ss; + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); + + std::string name; + if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + + if (detailed) + { + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str()); + if (!_comment.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); + } + return ss.str(); +} + +SupportMgr::SupportMgr() : _lastGmTicketId(0), _lastBugId(0), _lastComplaintId(0), _lastSuggestionId(0), _openGmTicketCount(0), +_openBugTicketCount(0), _openComplaintTicketCount(0), _openSuggestionTicketCount(0) { } + +SupportMgr::~SupportMgr() +{ + for (auto const& t : _gmTicketList) + delete t.second; + + for (auto const& b : _bugTicketList) + delete b.second; + + for (auto const& c : _complaintTicketList) + delete c.second; + + for (auto const& s : _suggestionTicketList) + delete s.second; +} + +void SupportMgr::Initialize() +{ + SetSupportSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_ENABLED)); + SetTicketSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED)); + SetBugSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED)); + SetComplaintSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED)); + SetSuggestionSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED)); +} + +template<> +GmTicket* SupportMgr::GetTicket<GmTicket>(uint32 ticketId) +{ + GmTicketList::const_iterator itr = _gmTicketList.find(ticketId); + if (itr != _gmTicketList.end()) + return itr->second; + + return nullptr; + +} + +template<> +BugTicket* SupportMgr::GetTicket<BugTicket>(uint32 bugId) +{ + BugTicketList::const_iterator itr = _bugTicketList.find(bugId); + if (itr != _bugTicketList.end()) + return itr->second; + + return nullptr; + +} + +template<> +ComplaintTicket* SupportMgr::GetTicket<ComplaintTicket>(uint32 complaintId) +{ + ComplaintTicketList::const_iterator itr = _complaintTicketList.find(complaintId); + if (itr != _complaintTicketList.end()) + return itr->second; + + return nullptr; +} + +template<> +SuggestionTicket* SupportMgr::GetTicket<SuggestionTicket>(uint32 suggestionId) +{ + SuggestionTicketList::const_iterator itr = _suggestionTicketList.find(suggestionId); + if (itr != _suggestionTicketList.end()) + return itr->second; + + return nullptr; + +} + +template<> +uint32 SupportMgr::GetOpenTicketCount<GmTicket>() const { return _openGmTicketCount; } + +template<> +uint32 SupportMgr::GetOpenTicketCount<BugTicket>() const { return _openBugTicketCount; } + +template<> +uint32 SupportMgr::GetOpenTicketCount<ComplaintTicket>() const { return _openComplaintTicketCount; } + +template<> +uint32 SupportMgr::GetOpenTicketCount<SuggestionTicket>() const { return _openSuggestionTicketCount; } + +void SupportMgr::LoadGmTickets() +{ + uint32 oldMSTime = getMSTime(); + + for (auto const& c : _gmTicketList) + delete c.second; + _gmTicketList.clear(); + + _lastGmTicketId = 0; + _openGmTicketCount = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_TICKETS); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_ticket` is empty!"); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + GmTicket* ticket = new GmTicket(); + ticket->LoadFromDB(fields); + + if (!ticket->IsClosed()) + ++_openGmTicketCount; + + uint32 id = ticket->GetId(); + if (_lastGmTicketId < id) + _lastGmTicketId = id; + + _gmTicketList[id] = ticket; + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u GM tickets in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void SupportMgr::LoadBugTickets() +{ + uint32 oldMSTime = getMSTime(); + + for (auto const& c : _bugTicketList) + delete c.second; + _bugTicketList.clear(); + + _lastBugId = 0; + _openBugTicketCount = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_BUGS); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 GM bugs. DB table `gm_bug` is empty!"); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + BugTicket* bug = new BugTicket(); + bug->LoadFromDB(fields); + + if (!bug->IsClosed()) + ++_openBugTicketCount; + + uint32 id = bug->GetId(); + if (_lastBugId < id) + _lastBugId = id; + + _bugTicketList[id] = bug; + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u GM bugs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void SupportMgr::LoadComplaintTickets() +{ + uint32 oldMSTime = getMSTime(); + + for (auto const& c : _complaintTicketList) + delete c.second; + _complaintTicketList.clear(); + + _lastComplaintId = 0; + _openComplaintTicketCount = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINTS); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 GM complaints. DB table `gm_complaint` is empty!"); + return; + } + + uint32 count = 0; + PreparedStatement* chatLogStmt; + PreparedQueryResult chatLogResult; + do + { + Field* fields = result->Fetch(); + ComplaintTicket* complaint = new ComplaintTicket(); + complaint->LoadFromDB(fields); + + if (!complaint->IsClosed()) + ++_openComplaintTicketCount; + + uint32 id = complaint->GetId(); + if (_lastComplaintId < id) + _lastComplaintId = id; + + chatLogStmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINT_CHATLINES); + chatLogResult = CharacterDatabase.Query(stmt); + + if (chatLogResult) + { + do + { + Field* chatLineFields = chatLogResult->Fetch(); + complaint->LoadChatLineFromDB(chatLineFields); + } while (chatLogResult->NextRow()); + } + + _complaintTicketList[id] = complaint; + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u GM complaints in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void SupportMgr::LoadSuggestionTickets() +{ + uint32 oldMSTime = getMSTime(); + + for (auto const& c : _suggestionTicketList) + delete c.second; + _suggestionTicketList.clear(); + + _lastSuggestionId = 0; + _openSuggestionTicketCount = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_SUGGESTIONS); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 GM suggestions. DB table `gm_suggestion` is empty!"); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + SuggestionTicket* suggestion = new SuggestionTicket(); + suggestion->LoadFromDB(fields); + + if (!suggestion->IsClosed()) + ++_openSuggestionTicketCount; + + uint32 id = suggestion->GetId(); + if (_lastSuggestionId < id) + _lastSuggestionId = id; + + _suggestionTicketList[id] = suggestion; + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u GM suggestions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void SupportMgr::AddTicket(GmTicket* ticket) +{ + _gmTicketList[ticket->GetId()] = ticket; + if (!ticket->IsClosed()) + ++_openGmTicketCount; + + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SaveToDB(trans); +} + +void SupportMgr::AddTicket(BugTicket* ticket) +{ + _bugTicketList[ticket->GetId()] = ticket; + if (!ticket->IsClosed()) + ++_openBugTicketCount; + + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SaveToDB(trans); +} + +void SupportMgr::AddTicket(ComplaintTicket* ticket) +{ + _complaintTicketList[ticket->GetId()] = ticket; + if (!ticket->IsClosed()) + ++_openComplaintTicketCount; + + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SaveToDB(trans); +} + +void SupportMgr::AddTicket(SuggestionTicket* ticket) +{ + _suggestionTicketList[ticket->GetId()] = ticket; + if (!ticket->IsClosed()) + ++_openSuggestionTicketCount; + + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SaveToDB(trans); +} + +template<> +void SupportMgr::RemoveTicket<GmTicket>(uint32 ticketId) +{ + if (GmTicket* ticket = GetTicket<GmTicket>(ticketId)) + { + ticket->DeleteFromDB(); + _gmTicketList.erase(ticketId); + delete ticket; + } +} + +template<> +void SupportMgr::RemoveTicket<BugTicket>(uint32 ticketId) +{ + if (BugTicket* ticket = GetTicket<BugTicket>(ticketId)) + { + ticket->DeleteFromDB(); + _bugTicketList.erase(ticketId); + delete ticket; + } +} + +template<> +void SupportMgr::RemoveTicket<ComplaintTicket>(uint32 ticketId) +{ + if (ComplaintTicket* ticket = GetTicket<ComplaintTicket>(ticketId)) + { + ticket->DeleteFromDB(); + _complaintTicketList.erase(ticketId); + delete ticket; + } +} + +template<> +void SupportMgr::RemoveTicket<SuggestionTicket>(uint32 ticketId) +{ + if (SuggestionTicket* ticket = GetTicket<SuggestionTicket>(ticketId)) + { + ticket->DeleteFromDB(); + _suggestionTicketList.erase(ticketId); + delete ticket; + } +} + +template<> +void SupportMgr::CloseTicket<GmTicket>(uint32 ticketId, ObjectGuid closedBy) +{ + if (GmTicket* ticket = GetTicket<GmTicket>(ticketId)) + { + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetClosedBy(closedBy); + if (!closedBy.IsEmpty()) + --_openGmTicketCount; + ticket->SaveToDB(trans); + } +} + +template<> +void SupportMgr::CloseTicket<BugTicket>(uint32 ticketId, ObjectGuid closedBy) +{ + if (BugTicket* ticket = GetTicket<BugTicket>(ticketId)) + { + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetClosedBy(closedBy); + if (!closedBy.IsEmpty()) + --_openBugTicketCount; + ticket->SaveToDB(trans); + } +} + +template<> +void SupportMgr::CloseTicket<ComplaintTicket>(uint32 ticketId, ObjectGuid closedBy) +{ + if (ComplaintTicket* ticket = GetTicket<ComplaintTicket>(ticketId)) + { + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetClosedBy(closedBy); + if (!closedBy.IsEmpty()) + --_openComplaintTicketCount; + ticket->SaveToDB(trans); + } +} + +template<> +void SupportMgr::CloseTicket<SuggestionTicket>(uint32 ticketId, ObjectGuid closedBy) +{ + if (SuggestionTicket* ticket = GetTicket<SuggestionTicket>(ticketId)) + { + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetClosedBy(closedBy); + if (!closedBy.IsEmpty()) + --_openSuggestionTicketCount; + ticket->SaveToDB(trans); + } +} + +template<> +void SupportMgr::ResetTickets<GmTicket>() +{ + for (auto const& c : _gmTicketList) + delete c.second; + _gmTicketList.clear(); + + _lastGmTicketId = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_TICKETS); + CharacterDatabase.Execute(stmt); +} + +template<> +void SupportMgr::ResetTickets<BugTicket>() +{ + for (auto const& c : _bugTicketList) + delete c.second; + _bugTicketList.clear(); + + _lastBugId = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_BUGS); + CharacterDatabase.Execute(stmt); +} + +template<> +void SupportMgr::ResetTickets<ComplaintTicket>() +{ + for (auto const& c : _complaintTicketList) + delete c.second; + _complaintTicketList.clear(); + + _lastComplaintId = 0; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINTS)); + trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS)); + CharacterDatabase.CommitTransaction(trans); +} + +template<> +void SupportMgr::ResetTickets<SuggestionTicket>() +{ + for (auto const& c : _suggestionTicketList) + delete c.second; + _suggestionTicketList.clear(); + + _lastSuggestionId = 0; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_SUGGESTIONS); + CharacterDatabase.Execute(stmt); +} + +template<> +void SupportMgr::ShowList<GmTicket>(ChatHandler& handler, bool onlineOnly) const +{ + handler.SendSysMessage(onlineOnly ? LANG_COMMAND_TICKETSHOWONLINELIST : LANG_COMMAND_TICKETSHOWLIST); + for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr) + if (!itr->second->IsClosed() && !itr->second->IsCompleted()) + if (!onlineOnly || itr->second->GetPlayer()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowList<GmTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr) + if (!itr->second->IsClosed() && !itr->second->IsCompleted()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowList<BugTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr) + if (!itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowList<ComplaintTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr) + if (!itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowList<SuggestionTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST); + for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr) + if (!itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowClosedList<GmTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr) + if (itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowClosedList<BugTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr) + if (itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowClosedList<ComplaintTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr) + if (itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +template<> +void SupportMgr::ShowClosedList<SuggestionTicket>(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); + for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr) + if (itr->second->IsClosed()) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +void SupportMgr::ShowGmEscalatedList(ChatHandler& handler) const +{ + handler.SendSysMessage(LANG_COMMAND_TICKETSHOWESCALATEDLIST); + for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr) + if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE) + handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str()); +} + +void SupportMgr::SendGmTicket(WorldSession* session, GmTicket* ticket) const +{ + WorldPackets::Ticket::GMTicketGetTicketResponse response; + + if (ticket) + { + response.Result = GMTICKET_STATUS_HASTEXT; + response.Info.HasValue = true; + + response.Info.Value.TicketID = ticket->GetId(); + response.Info.Value.TicketDescription = ticket->GetDescription(); + response.Info.Value.Category = ticket->GetEscalatedStatus(); + response.Info.Value.TicketOpenTime = GetAge(ticket->GetLastModifiedTime()); + response.Info.Value.OldestTicketTime = sSupportMgr->GetOldestOpenTicket() ? GetAge(sSupportMgr->GetOldestOpenTicket()->GetLastModifiedTime()) : float(0); + response.Info.Value.UpdateTime = GetAge(sSupportMgr->GetLastChange()); + response.Info.Value.AssignedToGM = ticket->IsAssigned(); + response.Info.Value.OpenedByGM = ticket->IsViewed(); + response.Info.Value.WaitTimeOverrideMessage = ""; + response.Info.Value.WaitTimeOverrideMinutes = 0; + } + else + response.Result = GMTICKET_STATUS_DEFAULT; + + session->SendPacket(response.Write()); +} + +void SupportMgr::SendGmTicketUpdate(WorldSession* session, GMTicketResponse response) const +{ + WorldPackets::Ticket::GMTicketUpdate update; + update.Result = response; + + session->SendPacket(update.Write()); +} diff --git a/src/server/game/Support/SupportMgr.h b/src/server/game/Support/SupportMgr.h new file mode 100644 index 00000000000..eddb3cebf75 --- /dev/null +++ b/src/server/game/Support/SupportMgr.h @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SupportMgr_h__ +#define SupportMgr_h__ + +#include "ObjectMgr.h" +#include "Player.h" +#include "TicketPackets.h" + +class ChatHandler; + +// from blizzard lua +enum GMTicketSystemStatus +{ + GMTICKET_QUEUE_STATUS_DISABLED = 0, + GMTICKET_QUEUE_STATUS_ENABLED = 1 +}; + +enum GMTicketStatus +{ + GMTICKET_STATUS_HASTEXT = 0x06, + GMTICKET_STATUS_DEFAULT = 0x0A +}; + +enum GMTicketResponse +{ + GMTICKET_RESPONSE_ALREADY_EXIST = 1, + GMTICKET_RESPONSE_CREATE_SUCCESS = 2, + GMTICKET_RESPONSE_CREATE_ERROR = 3, + GMTICKET_RESPONSE_UPDATE_SUCCESS = 4, + GMTICKET_RESPONSE_UPDATE_ERROR = 5, + GMTICKET_RESPONSE_TICKET_DELETED = 9 +}; + +// 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 +}; + +// 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 +}; + +enum GMSupportComplaintType +{ + GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE = 0, + GMTICKET_SUPPORT_COMPLAINT_TYPE_LANGUAGE = 2, + GMTICKET_SUPPORT_COMPLAINT_TYPE_PLAYERNAME = 4, + GMTICKET_SUPPORT_COMPLAINT_TYPE_CHEAT = 15, + GMTICKET_SUPPORT_COMPLAINT_TYPE_GUILDNAME = 23, + GMTICKET_SUPPORT_COMPLAINT_TYPE_SPAMMING = 24 +}; + +using ChatLog = WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLog; + +class Ticket +{ +public: + Ticket(); + Ticket(Player* player); + virtual ~Ticket(); + + bool IsClosed() const { return !_closedBy.IsEmpty(); } + bool IsFromPlayer(ObjectGuid guid) const { return guid == _playerGuid; } + bool IsAssigned() const { return !_assignedTo.IsEmpty(); } + bool IsAssignedTo(ObjectGuid guid) const { return guid == _assignedTo; } + bool IsAssignedNotTo(ObjectGuid guid) const { return IsAssigned() && !IsAssignedTo(guid); } + + uint32 GetId() const { return _id; } + ObjectGuid GetPlayerGuid() const { return _playerGuid; } + Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); } + Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); } + ObjectGuid GetAssignedToGUID() const { return _assignedTo; } + std::string GetAssignedToName() const + { + std::string name; + if (!_assignedTo.IsEmpty()) + ObjectMgr::GetPlayerNameByGUID(_assignedTo, name); + + return name; + } + std::string const& GetComment() { return _comment; } + + virtual void SetAssignedTo(ObjectGuid guid) { _assignedTo = guid; } + virtual void SetAssignedTo(ObjectGuid /*guid*/, bool /*isAdmin*/) { } + virtual void SetUnassigned() { _assignedTo.Clear(); } + void SetClosedBy(ObjectGuid value) { _closedBy = value; } + void SetComment(std::string const& comment) { _comment = comment; } + void SetPosition(uint32 mapId, G3D::Vector3& pos) + { + _mapId = mapId; + _pos = pos; + } + + virtual void LoadFromDB(Field* fields) = 0; + virtual void SaveToDB(SQLTransaction& trans) const = 0; + virtual void DeleteFromDB() = 0; + + void TeleportTo(Player* player) const; + + virtual std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const = 0; + virtual std::string FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const; + +protected: + uint32 _id; + ObjectGuid _playerGuid; + uint16 _mapId; + G3D::Vector3 _pos; + uint64 _createTime; + ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. + ObjectGuid _assignedTo; + std::string _comment; +}; + + +class GmTicket : public Ticket +{ +public: + GmTicket(); + GmTicket(Player* player); + ~GmTicket(); + + bool IsCompleted() const { return _completed; } + bool IsViewed() const { return _viewed; } + + bool GetNeedMoreHelp() const { return _needMoreHelp; } + std::string const& GetDescription() const { return _description; } + uint64 GetLastModifiedTime() const { return _lastModifiedTime; } + GMTicketEscalationStatus GetEscalatedStatus() const { return _escalatedStatus; } + std::string const& GetResponse() const { return _response; } + + void SetAssignedTo(ObjectGuid guid, bool isAdmin) override + { + _assignedTo = guid; + if (isAdmin && _escalatedStatus == TICKET_IN_ESCALATION_QUEUE) + _escalatedStatus = TICKET_ESCALATED_ASSIGNED; + else if (_escalatedStatus == TICKET_UNASSIGNED) + _escalatedStatus = TICKET_ASSIGNED; + } + void SetEscalatedStatus(GMTicketEscalationStatus escalatedStatus) { _escalatedStatus = escalatedStatus; } + void SetCompleted() { _completed = true; } + void SetDescription(std::string const& description) + { + _description = description; + _lastModifiedTime = uint64(time(NULL)); + } + void SetViewed() { _viewed = true; } + void SetGmAction(uint32 needResponse, bool needMoreHelp); + void SetUnassigned() override; + + void AppendResponse(std::string const& response) { _response += response; } + + void SetChatLog(std::list<uint32> time, std::string const& log); + std::string const& GetChatLog() const { return _chatLog; } + + void SendResponse(WorldSession* session) const; + + void LoadFromDB(Field* fields) override; + void SaveToDB(SQLTransaction& trans) const override; + void DeleteFromDB() override; + + std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override; + std::string FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const override; + +private: + std::string _description; + uint64 _lastModifiedTime; + bool _completed; + GMTicketEscalationStatus _escalatedStatus; + bool _viewed; + bool _needResponse; /// @todo find out the use of this, and then store it in DB + bool _needMoreHelp; + std::string _response; + std::string _chatLog; // No need to store in db, will be refreshed every session client side +}; + +class BugTicket : public Ticket +{ +public: + BugTicket(); + BugTicket(Player* player); + ~BugTicket(); + + std::string const& GetNote() const { return _note; } + + void SetFacing(float facing) { _facing = facing; } + void SetNote(std::string const& note) { _note = note; } + + void LoadFromDB(Field* fields) override; + void SaveToDB(SQLTransaction& trans) const override; + void DeleteFromDB() override; + + using Ticket::FormatViewMessageString; + std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override; + +private: + float _facing; + std::string _note; +}; + +class ComplaintTicket : public Ticket +{ +public: + ComplaintTicket(); + ComplaintTicket(Player* player); + ~ComplaintTicket(); + + ObjectGuid GetTargetCharacterGuid() const { return _targetCharacterGuid; } + GMSupportComplaintType GetComplaintType() const { return _complaintType; } + std::string const& GetNote() const { return _note; } + + void SetFacing(float facing) { _facing = facing; } + void SetTargetCharacterGuid(ObjectGuid targetCharacterGuid) + { + _targetCharacterGuid = targetCharacterGuid; + } + void SetComplaintType(GMSupportComplaintType type) { _complaintType = type; } + void SetChatLog(ChatLog const& log) { _chatLog = log; } + void SetNote(std::string const& note) { _note = note; } + + void LoadFromDB(Field* fields) override; + void LoadChatLineFromDB(Field* fields); + void SaveToDB(SQLTransaction& trans) const override; + void DeleteFromDB() override; + + using Ticket::FormatViewMessageString; + std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override; + +private: + float _facing; + ObjectGuid _targetCharacterGuid; + GMSupportComplaintType _complaintType; + ChatLog _chatLog; + std::string _note; +}; + +class SuggestionTicket : public Ticket +{ +public: + SuggestionTicket(); + SuggestionTicket(Player* player); + ~SuggestionTicket(); + + std::string const& GetNote() const { return _note; } + void SetNote(std::string const& note) { _note = note; } + + void SetFacing(float facing) { _facing = facing; } + + void LoadFromDB(Field* fields) override; + void SaveToDB(SQLTransaction& trans) const override; + void DeleteFromDB() override; + + using Ticket::FormatViewMessageString; + std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override; + +private: + float _facing; + std::string _note; +}; + +typedef std::map<uint32, BugTicket*> BugTicketList; +typedef std::map<uint32, ComplaintTicket*> ComplaintTicketList; +typedef std::map<uint32, SuggestionTicket*> SuggestionTicketList; +typedef std::map<uint32, GmTicket*> GmTicketList; + +class SupportMgr +{ +private: + SupportMgr(); + ~SupportMgr(); + +public: + static SupportMgr* instance() + { + static SupportMgr instance; + return &instance; + } + + template<typename T> + T* GetTicket(uint32 ticketId); + + GmTicket* GetGmTicketByPlayerGuid(ObjectGuid playerGuid) const + { + for (auto const& c : _gmTicketList) + if (c.second->GetPlayerGuid() == playerGuid && !c.second->IsClosed()) + return c.second; + + return nullptr; + } + + ComplaintTicketList GetComplaintsByPlayerGuid(ObjectGuid playerGuid) const + { + ComplaintTicketList ret; + for (auto const& c : _complaintTicketList) + if (c.second->GetPlayerGuid() == playerGuid) + ret.insert(c); + + return ret; + } + + GmTicket* GetOldestOpenTicket() + { + for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr) + if (itr->second && !itr->second->IsClosed() && !itr->second->IsCompleted()) + return itr->second; + + return nullptr; + } + + void Initialize(); + + bool GetSupportSystemStatus() { return _supportSystemStatus; } + bool GetTicketSystemStatus() { return _supportSystemStatus && _ticketSystemStatus; } + bool GetBugSystemStatus() { return _supportSystemStatus && _bugSystemStatus; } + bool GetComplaintSystemStatus() { return _supportSystemStatus && _complaintSystemStatus; } + bool GetSuggestionSystemStatus() { return _supportSystemStatus && _suggestionSystemStatus; } + uint64 GetLastChange() const { return _lastChange; } + template<typename T> + uint32 GetOpenTicketCount() const; + + void SetSupportSystemStatus(bool status) { _supportSystemStatus = status; } + void SetTicketSystemStatus(bool status) { _ticketSystemStatus = status; } + void SetBugSystemStatus(bool status) { _bugSystemStatus = status; } + void SetComplaintSystemStatus(bool status) { _complaintSystemStatus = status; } + void SetSuggestionSystemStatus(bool status) { _suggestionSystemStatus = status; } + + void LoadGmTickets(); + void LoadBugTickets(); + void LoadComplaintTickets(); + void LoadSuggestionTickets(); + + void AddTicket(GmTicket* ticket); + void AddTicket(BugTicket* ticket); + void AddTicket(ComplaintTicket* ticket); + void AddTicket(SuggestionTicket* ticket); + + template<typename T> + void RemoveTicket(uint32 ticketId); + + template<typename T> + void CloseTicket(uint32 ticketId, ObjectGuid closedBy); + + template<typename T> + void ResetTickets(); + + template<typename T> + void ShowList(ChatHandler& handler) const; + + template<typename T> + void ShowList(ChatHandler& handler, bool onlineOnly) const; + + template<typename T> + void ShowClosedList(ChatHandler& handler) const; + + void ShowGmEscalatedList(ChatHandler& handler) const; + + void UpdateLastChange() { _lastChange = uint64(time(nullptr)); } + + void SendGmTicket(WorldSession* session, GmTicket* ticket) const; + void SendGmTicketUpdate(WorldSession* session, GMTicketResponse response) const; + + uint32 GenerateGmTicketId() { return ++_lastGmTicketId; } + uint32 GenerateBugId() { return ++_lastBugId; } + uint32 GenerateComplaintId() { return ++_lastComplaintId; } + uint32 GenerateSuggestionId() { return ++_lastSuggestionId; } + +private: + bool _supportSystemStatus; + bool _ticketSystemStatus; + bool _bugSystemStatus; + bool _complaintSystemStatus; + bool _suggestionSystemStatus; + GmTicketList _gmTicketList; + BugTicketList _bugTicketList; + ComplaintTicketList _complaintTicketList; + SuggestionTicketList _suggestionTicketList; + uint32 _lastGmTicketId; + uint32 _lastBugId; + uint32 _lastComplaintId; + uint32 _lastSuggestionId; + uint32 _openGmTicketCount; + uint32 _openBugTicketCount; + uint32 _openComplaintTicketCount; + uint32 _openSuggestionTicketCount; + uint64 _lastChange; +}; + +#define sSupportMgr SupportMgr::instance() + +#endif // SupportMgr_h__ diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp deleted file mode 100644 index 84dac6cc175..00000000000 --- a/src/server/game/Tickets/TicketMgr.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "Common.h" -#include "TicketMgr.h" -#include "TicketPackets.h" -#include "DatabaseEnv.h" -#include "Log.h" -#include "Language.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Chat.h" -#include "World.h" -#include "Player.h" -#include "Opcodes.h" - -inline time_t GetAge(uint64 t) { return (time(NULL) - t) / DAY; } - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// GM ticket -GmTicket::GmTicket() : _id(0), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0), - _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), - _needResponse(false), _needMoreHelp(false) { } - -GmTicket::GmTicket(Player* player) : _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(time(NULL)), _lastModifiedTime(time(NULL)), - _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), - _needResponse(false), _needMoreHelp(false) -{ - _id = sTicketMgr->GenerateTicketId(); - _playerName = player->GetName(); - _playerGuid = player->GetGUID(); -} - -GmTicket::~GmTicket() { } - -bool GmTicket::LoadFromDB(Field* fields) -{ - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket - uint8 index = 0; - _id = fields[ index].GetUInt32(); - _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt64()); - _playerName = fields[++index].GetString(); - _message = fields[++index].GetString(); - _createTime = fields[++index].GetUInt32(); - _mapId = fields[++index].GetUInt16(); - _posX = fields[++index].GetFloat(); - _posY = fields[++index].GetFloat(); - _posZ = fields[++index].GetFloat(); - _lastModifiedTime = fields[++index].GetUInt32(); - int64 closedBy = fields[++index].GetInt64(); - if (closedBy < 0) - _closedBy.SetRawValue(0, uint64(closedBy)); - else - _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy)); - - _assignedTo = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt64()); - _comment = fields[++index].GetString(); - _response = fields[++index].GetString(); - _completed = fields[++index].GetBool(); - _escalatedStatus = GMTicketEscalationStatus(fields[++index].GetUInt8()); - _viewed = fields[++index].GetBool(); - _needMoreHelp = fields[++index].GetBool(); - return true; -} - -void GmTicket::SaveToDB(SQLTransaction& trans) const -{ - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, completed, escalated, viewed - uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET); - stmt->setUInt32( index, _id); - stmt->setUInt64(++index, _playerGuid.GetCounter()); - stmt->setString(++index, _playerName); - stmt->setString(++index, _message); - stmt->setUInt32(++index, uint32(_createTime)); - stmt->setUInt16(++index, _mapId); - stmt->setFloat (++index, _posX); - stmt->setFloat (++index, _posY); - stmt->setFloat (++index, _posZ); - stmt->setUInt32(++index, uint32(_lastModifiedTime)); - stmt->setInt64 (++index, int64(_closedBy.GetCounter())); - stmt->setUInt64(++index, _assignedTo.GetCounter()); - stmt->setString(++index, _comment); - stmt->setString(++index, _response); - stmt->setBool (++index, _completed); - stmt->setUInt8 (++index, uint8(_escalatedStatus)); - stmt->setBool (++index, _viewed); - stmt->setBool (++index, _needMoreHelp); - - CharacterDatabase.ExecuteOrAppend(trans, stmt); -} - -void GmTicket::DeleteFromDB() -{ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_TICKET); - stmt->setUInt32(0, _id); - CharacterDatabase.Execute(stmt); -} - -void GmTicket::SendResponse(WorldSession* session) const -{ - WorldPacket data(SMSG_GM_TICKET_RESPONSE); - data << uint32(1); // responseID - data << uint32(_id); // ticketID - data << _message.c_str(); - - size_t len = _response.size(); - char const* s = _response.c_str(); - - for (int i = 0; i < 4; i++) - { - if (len) - { - size_t writeLen = std::min<size_t>(len, 3999); - data.append(s, writeLen); - - len -= writeLen; - s += writeLen; - } - - data << uint8(0); - } - - session->SendPacket(&data); -} - -std::string GmTicket::FormatMessageString(ChatHandler& handler, bool detailed) const -{ - time_t curTime = time(NULL); - - std::stringstream ss; - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, _playerName.c_str()); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(curTime - _lastModifiedTime, true, false)).c_str()); - - std::string name; - if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); - - if (detailed) - { - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _message.c_str()); - if (!_comment.empty()) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); - if (!_response.empty()) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, _response.c_str()); - } - return ss.str(); -} - -std::string GmTicket::FormatMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const -{ - std::stringstream ss; - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, _playerName.c_str()); - if (szClosedName) - ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName); - if (szAssignedToName) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName); - if (szUnassignedName) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName); - if (szDeletedName) - ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName); - if (szCompletedName) - ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName); - return ss.str(); -} - -void GmTicket::SetUnassigned() -{ - _assignedTo.Clear(); - switch (_escalatedStatus) - { - case TICKET_ASSIGNED: _escalatedStatus = TICKET_UNASSIGNED; break; - case TICKET_ESCALATED_ASSIGNED: _escalatedStatus = TICKET_IN_ESCALATION_QUEUE; break; - case TICKET_UNASSIGNED: - case TICKET_IN_ESCALATION_QUEUE: - default: - break; - } -} - -void GmTicket::SetPosition(uint32 mapId, float x, float y, float z) -{ - _mapId = mapId; - _posX = x; - _posY = y; - _posZ = z; -} - -void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp) -{ - _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default) - _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket" -} - -void GmTicket::TeleportTo(Player* player) const -{ - player->TeleportTo(_mapId, _posX, _posY, _posZ, 0.0f, 0); -} - -void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log) -{ - std::stringstream ss(log); - std::stringstream newss; - std::string line; - while (std::getline(ss, line) && !time.empty()) - { - newss << secsToTimeString(time.front()) << ": " << line << "\n"; - time.pop_front(); - } - - _chatLog = newss.str(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Ticket manager -TicketMgr::TicketMgr() : _status(true), _lastTicketId(0), _lastSurveyId(0), _openTicketCount(0), - _lastChange(time(NULL)) { } - -TicketMgr::~TicketMgr() -{ - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - delete itr->second; -} - -void TicketMgr::Initialize() -{ - SetStatus(sWorld->getBoolConfig(CONFIG_TICKET_SYSTEM_STATUS)); -} - -void TicketMgr::ResetTickets() -{ - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end();) - { - if (itr->second->IsClosed()) - { - uint32 ticketId = itr->second->GetId(); - ++itr; - sTicketMgr->RemoveTicket(ticketId); - } - else - ++itr; - } - - _lastTicketId = 0; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_TICKETS); - - CharacterDatabase.Execute(stmt); -} - -void TicketMgr::LoadTickets() -{ - uint32 oldMSTime = getMSTime(); - - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - delete itr->second; - _ticketList.clear(); - - _lastTicketId = 0; - _openTicketCount = 0; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_TICKETS); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_tickets` is empty!"); - - return; - } - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - GmTicket* ticket = new GmTicket(); - if (!ticket->LoadFromDB(fields)) - { - delete ticket; - continue; - } - if (!ticket->IsClosed()) - ++_openTicketCount; - - // Update max ticket id if necessary - uint32 id = ticket->GetId(); - if (_lastTicketId < id) - _lastTicketId = id; - - _ticketList[id] = ticket; - ++count; - } while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u GM tickets in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - -} - -void TicketMgr::LoadSurveys() -{ - // we don't actually load anything into memory here as there's no reason to - _lastSurveyId = 0; - - uint32 oldMSTime = getMSTime(); - if (QueryResult result = CharacterDatabase.Query("SELECT MAX(surveyId) FROM gm_surveys")) - _lastSurveyId = (*result)[0].GetUInt32(); - - TC_LOG_INFO("server.loading", ">> Loaded GM Survey count from database in %u ms", GetMSTimeDiffToNow(oldMSTime)); - -} - -void TicketMgr::AddTicket(GmTicket* ticket) -{ - _ticketList[ticket->GetId()] = ticket; - if (!ticket->IsClosed()) - ++_openTicketCount; - SQLTransaction trans = SQLTransaction(NULL); - ticket->SaveToDB(trans); -} - -void TicketMgr::CloseTicket(uint32 ticketId, ObjectGuid source) -{ - if (GmTicket* ticket = GetTicket(ticketId)) - { - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetClosedBy(source); - if (!source.IsEmpty()) - --_openTicketCount; - ticket->SaveToDB(trans); - } -} - -void TicketMgr::RemoveTicket(uint32 ticketId) -{ - if (GmTicket* ticket = GetTicket(ticketId)) - { - ticket->DeleteFromDB(); - _ticketList.erase(ticketId); - delete ticket; - } -} - -void TicketMgr::ShowList(ChatHandler& handler, bool onlineOnly) const -{ - handler.SendSysMessage(onlineOnly ? LANG_COMMAND_TICKETSHOWONLINELIST : LANG_COMMAND_TICKETSHOWLIST); - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - if (!itr->second->IsClosed() && !itr->second->IsCompleted()) - if (!onlineOnly || itr->second->GetPlayer()) - handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str()); -} - -void TicketMgr::ShowClosedList(ChatHandler& handler) const -{ - handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST); - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - if (itr->second->IsClosed()) - handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str()); -} - -void TicketMgr::ShowEscalatedList(ChatHandler& handler) const -{ - handler.SendSysMessage(LANG_COMMAND_TICKETSHOWESCALATEDLIST); - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE) - handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str()); -} - -void TicketMgr::SendTicket(WorldSession* session, GmTicket* ticket) const -{ - WorldPackets::Ticket::GMTicketGetTicketResponse response; - - if (ticket) - { - response.Result = GMTICKET_STATUS_HASTEXT; - response.Info.HasValue = true; - - response.Info.Value.TicketID = ticket->GetId(); - response.Info.Value.TicketDescription = ticket->GetMessage(); - response.Info.Value.Category = ticket->GetNeedMoreHelp(); - response.Info.Value.TicketOpenTime = GetAge(ticket->GetLastModifiedTime()); - response.Info.Value.OldestTicketTime = sTicketMgr->GetOldestOpenTicket() ? GetAge(sTicketMgr->GetOldestOpenTicket()->GetLastModifiedTime()) : float(0); - response.Info.Value.UpdateTime = GetAge(sTicketMgr->GetLastChange()); - response.Info.Value.AssignedToGM = ticket->IsAssigned(); - response.Info.Value.OpenedByGM = ticket->IsViewed(); - response.Info.Value.WaitTimeOverrideMessage = ""; - response.Info.Value.WaitTimeOverrideMinutes = 0; - } - else - response.Result = GMTICKET_STATUS_DEFAULT; - - session->SendPacket(response.Write()); -} diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h deleted file mode 100644 index 577f29062b8..00000000000 --- a/src/server/game/Tickets/TicketMgr.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2008-2015 TrinityCore <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, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _TICKETMGR_H -#define _TICKETMGR_H - -#include <string> - -#include "ObjectMgr.h" - -class ChatHandler; - -// from blizzard lua -enum GMTicketSystemStatus -{ - GMTICKET_QUEUE_STATUS_DISABLED = 0, - GMTICKET_QUEUE_STATUS_ENABLED = 1 -}; - -enum GMTicketStatus -{ - GMTICKET_STATUS_HASTEXT = 0x06, - GMTICKET_STATUS_DEFAULT = 0x0A -}; - -enum GMTicketResponse -{ - GMTICKET_RESPONSE_ALREADY_EXIST = 1, - GMTICKET_RESPONSE_CREATE_SUCCESS = 2, - GMTICKET_RESPONSE_CREATE_ERROR = 3, - GMTICKET_RESPONSE_UPDATE_SUCCESS = 4, - GMTICKET_RESPONSE_UPDATE_ERROR = 5, - 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 -}; - -class GmTicket -{ -public: - GmTicket(); - GmTicket(Player* player); - ~GmTicket(); - - bool IsClosed() const { return !_closedBy.IsEmpty(); } - bool IsCompleted() const { return _completed; } - bool IsFromPlayer(ObjectGuid guid) const { return guid == _playerGuid; } - bool IsAssigned() const { return !_assignedTo.IsEmpty(); } - bool IsAssignedTo(ObjectGuid guid) const { return guid == _assignedTo; } - bool IsAssignedNotTo(ObjectGuid guid) const { return IsAssigned() && !IsAssignedTo(guid); } - bool IsViewed() const { return _viewed; } - - uint32 GetId() const { return _id; } - Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); } - std::string const& GetPlayerName() const { return _playerName; } - std::string const& GetMessage() const { return _message; } - bool GetNeedMoreHelp() const { return _needMoreHelp; } - Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); } - ObjectGuid GetAssignedToGUID() const { return _assignedTo; } - std::string GetAssignedToName() const - { - std::string name; - // save queries if ticket is not assigned - if (!_assignedTo.IsEmpty()) - ObjectMgr::GetPlayerNameByGUID(_assignedTo, name); - - return name; - } - uint64 GetLastModifiedTime() const { return _lastModifiedTime; } - GMTicketEscalationStatus GetEscalatedStatus() const { return _escalatedStatus; } - - void SetEscalatedStatus(GMTicketEscalationStatus escalatedStatus) { _escalatedStatus = escalatedStatus; } - void SetAssignedTo(ObjectGuid guid, bool isAdmin) - { - _assignedTo = guid; - if (isAdmin && _escalatedStatus == TICKET_IN_ESCALATION_QUEUE) - _escalatedStatus = TICKET_ESCALATED_ASSIGNED; - else if (_escalatedStatus == TICKET_UNASSIGNED) - _escalatedStatus = TICKET_ASSIGNED; - } - void SetClosedBy(ObjectGuid value) { _closedBy = value; } - void SetCompleted() { _completed = true; } - void SetMessage(std::string const& message) - { - _message = message; - _lastModifiedTime = uint64(time(NULL)); - } - void SetComment(std::string const& comment) { _comment = comment; } - void SetViewed() { _viewed = true; } - void SetUnassigned(); - void SetPosition(uint32 mapId, float x, float y, float z); - void SetGmAction(uint32 needResponse, bool needMoreHelp); - - void AppendResponse(std::string const& response) { _response += response; } - - bool LoadFromDB(Field* fields); - void SaveToDB(SQLTransaction& trans) const; - void DeleteFromDB(); - - void WritePacket(WorldPacket& data) const; - void SendResponse(WorldSession* session) const; - - void TeleportTo(Player* player) const; - std::string FormatMessageString(ChatHandler& handler, bool detailed = false) const; - std::string FormatMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const; - - void SetChatLog(std::list<uint32> time, std::string const& log); - std::string const& GetChatLog() const { return _chatLog; } - -private: - uint32 _id; - ObjectGuid _playerGuid; - std::string _playerName; - float _posX; - float _posY; - float _posZ; - uint16 _mapId; - std::string _message; - uint64 _createTime; - uint64 _lastModifiedTime; - ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it. - ObjectGuid _assignedTo; - std::string _comment; - bool _completed; - GMTicketEscalationStatus _escalatedStatus; - bool _viewed; - bool _needResponse; /// @todo find out the use of this, and then store it in DB - bool _needMoreHelp; - std::string _response; - std::string _chatLog; // No need to store in db, will be refreshed every session client side -}; -typedef std::map<uint32, GmTicket*> GmTicketList; - -class TicketMgr -{ -private: - TicketMgr(); - ~TicketMgr(); - -public: - static TicketMgr* instance() - { - static TicketMgr instance; - return &instance; - } - - void LoadTickets(); - void LoadSurveys(); - - GmTicket* GetTicket(uint32 ticketId) - { - GmTicketList::iterator itr = _ticketList.find(ticketId); - if (itr != _ticketList.end()) - return itr->second; - - return NULL; - } - - GmTicket* GetTicketByPlayer(ObjectGuid playerGuid) - { - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - if (itr->second && itr->second->IsFromPlayer(playerGuid) && !itr->second->IsClosed()) - return itr->second; - - return NULL; - } - - GmTicket* GetOldestOpenTicket() - { - for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr) - if (itr->second && !itr->second->IsClosed() && !itr->second->IsCompleted()) - return itr->second; - - return NULL; - } - - void AddTicket(GmTicket* ticket); - void CloseTicket(uint32 ticketId, ObjectGuid source); - void RemoveTicket(uint32 ticketId); - - bool GetStatus() const { return _status; } - void SetStatus(bool status) { _status = status; } - - uint64 GetLastChange() const { return _lastChange; } - void UpdateLastChange() { _lastChange = uint64(time(NULL)); } - - uint32 GenerateTicketId() { return ++_lastTicketId; } - uint32 GetOpenTicketCount() const { return _openTicketCount; } - uint32 GetNextSurveyID() { return ++_lastSurveyId; } - - void Initialize(); - void ResetTickets(); - - void ShowList(ChatHandler& handler, bool onlineOnly) const; - void ShowClosedList(ChatHandler& handler) const; - void ShowEscalatedList(ChatHandler& handler) const; - - void SendTicket(WorldSession* session, GmTicket* ticket) const; - -protected: - void _RemoveTicket(uint32 ticketId, int64 source = -1, bool permanently = false); - - GmTicketList _ticketList; - - bool _status; - uint32 _lastTicketId; - uint32 _lastSurveyId; - uint32 _openTicketCount; - uint64 _lastChange; -}; - -#define sTicketMgr TicketMgr::instance() - -#endif // _TICKETMGR_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c51c9e3ecc4..561cd5bb3a0 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -57,7 +57,7 @@ #include "SkillExtraItems.h" #include "SmartAI.h" #include "SystemConfig.h" -#include "TicketMgr.h" +#include "SupportMgr.h" #include "TransportMgr.h" #include "Unit.h" #include "VMapFactory.h" @@ -427,12 +427,22 @@ void World::LoadConfigSettings(bool reload) SetPlayerAmountLimit(sConfigMgr->GetIntDefault("PlayerLimit", 100)); SetMotd(sConfigMgr->GetStringDefault("Motd", "Welcome to a Trinity Core Server.")); - ///- Read ticket system setting from the config file - m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS] = sConfigMgr->GetBoolDefault("Ticket.SystemStatus", true); + ///- Read support system setting from the config file + m_bool_configs[CONFIG_SUPPORT_ENABLED] = sConfigMgr->GetBoolDefault("Support.Enabled", true); + m_bool_configs[CONFIG_SUPPORT_TICKETS_ENABLED] = sConfigMgr->GetBoolDefault("Support.TicketsEnabled", false); + m_bool_configs[CONFIG_SUPPORT_BUGS_ENABLED] = sConfigMgr->GetBoolDefault("Support.BugsEnabled", false); + m_bool_configs[CONFIG_SUPPORT_COMPLAINTS_ENABLED] = sConfigMgr->GetBoolDefault("Support.ComplaintsEnabled", false); + m_bool_configs[CONFIG_SUPPORT_SUGGESTIONS_ENABLED] = sConfigMgr->GetBoolDefault("Support.SuggestionsEnabled", false); if (reload) - sTicketMgr->SetStatus(m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS]); - m_bool_configs[CONFIG_TICKET_SUBMIT_TICKET] = sConfigMgr->GetBoolDefault("Ticket.SubmitTicket", false); - m_bool_configs[CONFIG_TICKET_SUBMIT_BUG] = sConfigMgr->GetBoolDefault("Ticket.SubmitBug", false); + { + sSupportMgr->SetSupportSystemStatus(m_bool_configs[CONFIG_SUPPORT_ENABLED]); + sSupportMgr->SetTicketSystemStatus(m_bool_configs[CONFIG_SUPPORT_TICKETS_ENABLED]); + sSupportMgr->SetBugSystemStatus(m_bool_configs[CONFIG_SUPPORT_BUGS_ENABLED]); + sSupportMgr->SetComplaintSystemStatus(m_bool_configs[CONFIG_SUPPORT_COMPLAINTS_ENABLED]); + sSupportMgr->SetSuggestionSystemStatus(m_bool_configs[CONFIG_SUPPORT_SUGGESTIONS_ENABLED]); + } + m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfigMgr->GetFloatDefault("Support.ChanceOfGMSurvey", 50.0f); + ///- Get string for new logins (newly created characters) SetNewCharString(sConfigMgr->GetStringDefault("PlayerStart.String", "")); @@ -954,7 +964,6 @@ void World::LoadConfigSettings(bool reload) } m_bool_configs[CONFIG_ALLOW_GM_GROUP] = sConfigMgr->GetBoolDefault("GM.AllowInvite", false); m_bool_configs[CONFIG_GM_LOWER_SECURITY] = sConfigMgr->GetBoolDefault("GM.LowerSecurity", false); - m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfigMgr->GetFloatDefault("GM.TicketSystem.ChanceOfGMSurvey", 50.0f); m_int_configs[CONFIG_GROUP_VISIBILITY] = sConfigMgr->GetIntDefault("Visibility.GroupMode", 1); @@ -1814,10 +1823,19 @@ void World::SetInitialWorldSettings() sObjectMgr->LoadFactionChangeTitles(); TC_LOG_INFO("server.loading", "Loading GM tickets..."); - sTicketMgr->LoadTickets(); + sSupportMgr->LoadGmTickets(); + + TC_LOG_INFO("server.loading", "Loading GM bugs..."); + sSupportMgr->LoadBugTickets(); + + TC_LOG_INFO("server.loading", "Loading GM complaints..."); + sSupportMgr->LoadComplaintTickets(); + + TC_LOG_INFO("server.loading", "Loading GM suggestions..."); + sSupportMgr->LoadSuggestionTickets(); - TC_LOG_INFO("server.loading", "Loading GM surveys..."); - sTicketMgr->LoadSurveys(); + /*TC_LOG_INFO("server.loading", "Loading GM surveys..."); + sSupportMgr->LoadSurveys();*/ TC_LOG_INFO("server.loading", "Loading client addons..."); AddonMgr::LoadFromDB(); @@ -1916,7 +1934,7 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Starting Arena Season..."); sGameEventMgr->StartArenaSeason(); - sTicketMgr->Initialize(); + sSupportMgr->Initialize(); ///- Initialize Battlegrounds TC_LOG_INFO("server.loading", "Starting Battleground System"); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 847ca687112..f0cfcb37969 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -151,9 +151,11 @@ enum WorldBoolConfigs CONFIG_SHOW_MUTE_IN_WORLD, CONFIG_SHOW_BAN_IN_WORLD, CONFIG_AUTOBROADCAST, - CONFIG_TICKET_SYSTEM_STATUS, - CONFIG_TICKET_SUBMIT_TICKET, - CONFIG_TICKET_SUBMIT_BUG, + CONFIG_SUPPORT_ENABLED, + CONFIG_SUPPORT_TICKETS_ENABLED, + CONFIG_SUPPORT_BUGS_ENABLED, + CONFIG_SUPPORT_COMPLAINTS_ENABLED, + CONFIG_SUPPORT_SUGGESTIONS_ENABLED, CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES, CONFIG_PRESERVE_CUSTOM_CHANNELS, CONFIG_PDUMP_NO_PATHS, diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 1d441339df6..7df42e158de 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -131,12 +131,13 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Reputation ${CMAKE_SOURCE_DIR}/src/server/game/Scripting ${CMAKE_SOURCE_DIR}/src/server/game/Server + ${CMAKE_SOURCE_DIR}/src/server/game/Server/Packets ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol ${CMAKE_SOURCE_DIR}/src/server/game/Skills ${CMAKE_SOURCE_DIR}/src/server/game/Spells ${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras + ${CMAKE_SOURCE_DIR}/src/server/game/Support ${CMAKE_SOURCE_DIR}/src/server/game/Texts - ${CMAKE_SOURCE_DIR}/src/server/game/Tickets ${CMAKE_SOURCE_DIR}/src/server/game/Tools ${CMAKE_SOURCE_DIR}/src/server/game/Warden ${CMAKE_SOURCE_DIR}/src/server/game/Warden/Modules diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index b2256ba962b..cae6765ad3e 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -25,7 +25,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ObjectMgr.h" #include "MapManager.h" -#include "TicketMgr.h" +#include "SupportMgr.h" #include "Chat.h" #include "Language.h" #include "Player.h" @@ -40,23 +40,26 @@ public: { static ChatCommand goCommandTable[] = { - { "creature", rbac::RBAC_PERM_COMMAND_GO_CREATURE, false, &HandleGoCreatureCommand, "", NULL }, - { "graveyard", rbac::RBAC_PERM_COMMAND_GO_GRAVEYARD, false, &HandleGoGraveyardCommand, "", NULL }, - { "grid", rbac::RBAC_PERM_COMMAND_GO_GRID, false, &HandleGoGridCommand, "", NULL }, - { "object", rbac::RBAC_PERM_COMMAND_GO_OBJECT, false, &HandleGoObjectCommand, "", NULL }, - { "taxinode", rbac::RBAC_PERM_COMMAND_GO_TAXINODE, false, &HandleGoTaxinodeCommand, "", NULL }, - { "trigger", rbac::RBAC_PERM_COMMAND_GO_TRIGGER, false, &HandleGoTriggerCommand, "", NULL }, - { "zonexy", rbac::RBAC_PERM_COMMAND_GO_ZONEXY, false, &HandleGoZoneXYCommand, "", NULL }, - { "xyz", rbac::RBAC_PERM_COMMAND_GO_XYZ, false, &HandleGoXYZCommand, "", NULL }, - { "ticket", rbac::RBAC_PERM_COMMAND_GO_TICKET, false, &HandleGoTicketCommand, "", NULL }, - { "", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoXYZCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { "creature", rbac::RBAC_PERM_COMMAND_GO_CREATURE, false, &HandleGoCreatureCommand, "", NULL }, + { "graveyard", rbac::RBAC_PERM_COMMAND_GO_GRAVEYARD, false, &HandleGoGraveyardCommand, "", NULL }, + { "grid", rbac::RBAC_PERM_COMMAND_GO_GRID, false, &HandleGoGridCommand, "", NULL }, + { "object", rbac::RBAC_PERM_COMMAND_GO_OBJECT, false, &HandleGoObjectCommand, "", NULL }, + { "taxinode", rbac::RBAC_PERM_COMMAND_GO_TAXINODE, false, &HandleGoTaxinodeCommand, "", NULL }, + { "trigger", rbac::RBAC_PERM_COMMAND_GO_TRIGGER, false, &HandleGoTriggerCommand, "", NULL }, + { "zonexy", rbac::RBAC_PERM_COMMAND_GO_ZONEXY, false, &HandleGoZoneXYCommand, "", NULL }, + { "xyz", rbac::RBAC_PERM_COMMAND_GO_XYZ, false, &HandleGoXYZCommand, "", NULL }, + { "ticket", rbac::RBAC_PERM_COMMAND_GO_TICKET, false, &HandleGoTicketCommand<GmTicket>, "", NULL }, + { "bugticket", rbac::RBAC_PERM_COMMAND_GO_BUG_TICKET, false, &HandleGoTicketCommand<BugTicket>, "", NULL }, + { "complaintticket", rbac::RBAC_PERM_COMMAND_GO_COMPLAINT_TICKET, false, &HandleGoTicketCommand<ComplaintTicket>, "", NULL }, + { "suggestionticket", rbac::RBAC_PERM_COMMAND_GO_SUGGESTION_TICKET, false, &HandleGoTicketCommand<SuggestionTicket>, "", NULL }, + { "", rbac::RBAC_PERM_COMMAND_GO, false, &HandleGoXYZCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = { { "go", rbac::RBAC_PERM_COMMAND_GO, false, NULL, "", goCommandTable }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; return commandTable; } @@ -544,6 +547,7 @@ public: return true; } + template<typename T> static bool HandleGoTicketCommand(ChatHandler* handler, char const* args) { if (!*args) @@ -557,7 +561,7 @@ public: if (!ticketId) return false; - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); + T* ticket = sSupportMgr->GetTicket<T>(ticketId); if (!ticket) { handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index df6010ac3ae..99cec7bed95 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -38,7 +38,7 @@ EndScriptData */ #include "SkillExtraItems.h" #include "SmartAI.h" #include "SpellMgr.h" -#include "TicketMgr.h" +#include "SupportMgr.h" #include "WardenCheckMgr.h" #include "WaypointManager.h" @@ -96,7 +96,6 @@ public: { "gameobject_questender", rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER, true, &HandleReloadGOQuestEnderCommand, "", NULL }, { "gameobject_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesGameobjectCommand, "", NULL }, { "gameobject_queststarter", rbac::RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER, true, &HandleReloadGOQuestStarterCommand, "", NULL }, - { "gm_tickets", rbac::RBAC_PERM_COMMAND_RELOAD_GM_TICKETS, true, &HandleReloadGMTicketsCommand, "", NULL }, { "gossip_menu", rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU, true, &HandleReloadGossipMenuCommand, "", NULL }, { "gossip_menu_option", rbac::RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION, true, &HandleReloadGossipMenuOptionCommand, "", NULL }, { "item_enchantment_template", rbac::RBAC_PERM_COMMAND_RELOAD_ITEM_ENCHANTMENT_TEMPLATE, true, &HandleReloadItemEnchantementsCommand, "", NULL }, @@ -146,6 +145,7 @@ public: { "spell_target_position", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, true, &HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_threats", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS, true, &HandleReloadSpellThreatsCommand, "", NULL }, { "spell_group_stack_rules", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES, true, &HandleReloadSpellGroupStackRulesCommand, "", NULL }, + { "support", rbac::RBAC_PERM_COMMAND_RELOAD_SUPPORT_SYSTEM, true, &HandleReloadSupportSystemCommand, "", NULL }, { "trinity_string", rbac::RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING, true, &HandleReloadTrinityStringCommand, "", NULL }, { "warden_action", rbac::RBAC_PERM_COMMAND_RELOAD_WARDEN_ACTION, true, &HandleReloadWardenactionCommand, "", NULL }, { "waypoint_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS, true, &HandleReloadWpScriptsCommand, "", NULL }, @@ -163,9 +163,14 @@ public: } //reload commands - static bool HandleReloadGMTicketsCommand(ChatHandler* /*handler*/, const char* /*args*/) - { - sTicketMgr->LoadTickets(); + static bool HandleReloadSupportSystemCommand(ChatHandler* handler, const char* /*args*/) + { + TC_LOG_INFO("misc", "Re-Loading Support System Tables..."); + sSupportMgr->LoadGmTickets(); + sSupportMgr->LoadBugTickets(); + sSupportMgr->LoadComplaintTickets(); + sSupportMgr->LoadSuggestionTickets(); + handler->SendGlobalGMSysMessage("DB tables `gm_*` reloaded."); return true; } diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index 98d1b2c7192..7af67902711 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -24,202 +24,45 @@ EndScriptData */ #include "AccountMgr.h" #include "Chat.h" +#include "Config.h" #include "Language.h" #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" -#include "TicketMgr.h" #include "ScriptMgr.h" +#include "SupportMgr.h" class ticket_commandscript : public CommandScript { public: ticket_commandscript() : CommandScript("ticket_commandscript") { } - ChatCommand* GetCommands() const override - { - static ChatCommand ticketResponseCommandTable[] = - { - { "append", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPEND, true, &HandleGMTicketResponseAppendCommand, "", NULL }, - { "appendln", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPENDLN, true, &HandleGMTicketResponseAppendLnCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } - }; - static ChatCommand ticketCommandTable[] = - { - { "assign", rbac::RBAC_PERM_COMMAND_TICKET_ASSIGN, true, &HandleGMTicketAssignToCommand, "", NULL }, - { "close", rbac::RBAC_PERM_COMMAND_TICKET_CLOSE, true, &HandleGMTicketCloseByIdCommand, "", NULL }, - { "closedlist", rbac::RBAC_PERM_COMMAND_TICKET_CLOSEDLIST, true, &HandleGMTicketListClosedCommand, "", NULL }, - { "comment", rbac::RBAC_PERM_COMMAND_TICKET_COMMENT, true, &HandleGMTicketCommentCommand, "", NULL }, - { "complete", rbac::RBAC_PERM_COMMAND_TICKET_COMPLETE, true, &HandleGMTicketCompleteCommand, "", NULL }, - { "delete", rbac::RBAC_PERM_COMMAND_TICKET_DELETE, true, &HandleGMTicketDeleteByIdCommand, "", NULL }, - { "escalate", rbac::RBAC_PERM_COMMAND_TICKET_ESCALATE, true, &HandleGMTicketEscalateCommand, "", NULL }, - { "escalatedlist", rbac::RBAC_PERM_COMMAND_TICKET_ESCALATEDLIST, true, &HandleGMTicketListEscalatedCommand, "", NULL }, - { "list", rbac::RBAC_PERM_COMMAND_TICKET_LIST, true, &HandleGMTicketListCommand, "", NULL }, - { "onlinelist", rbac::RBAC_PERM_COMMAND_TICKET_ONLINELIST, true, &HandleGMTicketListOnlineCommand, "", NULL }, - { "reset", rbac::RBAC_PERM_COMMAND_TICKET_RESET, true, &HandleGMTicketResetCommand, "", NULL }, - { "response", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE, true, NULL, "", ticketResponseCommandTable }, - { "togglesystem", rbac::RBAC_PERM_COMMAND_TICKET_TOGGLESYSTEM, true, &HandleToggleGMTicketSystem, "", NULL }, - { "unassign", rbac::RBAC_PERM_COMMAND_TICKET_UNASSIGN, true, &HandleGMTicketUnAssignCommand, "", NULL }, - { "viewid", rbac::RBAC_PERM_COMMAND_TICKET_VIEWID, true, &HandleGMTicketGetByIdCommand, "", NULL }, - { "viewname", rbac::RBAC_PERM_COMMAND_TICKET_VIEWNAME, true, &HandleGMTicketGetByNameCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } - }; - static ChatCommand commandTable[] = - { - { "ticket", rbac::RBAC_PERM_COMMAND_TICKET, false, NULL, "", ticketCommandTable }, - { NULL, 0, false, NULL, "", NULL } - }; - return commandTable; - } - - static bool HandleGMTicketAssignToCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - char* ticketIdStr = strtok((char*)args, " "); - uint32 ticketId = atoi(ticketIdStr); - - char* targetStr = strtok(NULL, " "); - if (!targetStr) - return false; - - std::string target(targetStr); - if (!normalizePlayerName(target)) - return false; - - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket || ticket->IsClosed()) - { - handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - ObjectGuid targetGuid = ObjectMgr::GetPlayerGUIDByName(target); - uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(targetGuid); - // Target must exist and have administrative rights - if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmHandle.Index)) - { - handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); - return true; - } - - // If already assigned, leave - if (ticket->IsAssignedTo(targetGuid)) - { - handler->PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->GetId()); - return true; - } - - // If assigned to different player other than current, leave - //! Console can override though - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; - if (player && ticket->IsAssignedNotTo(player->GetGUID())) - { - handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId(), target.c_str()); - return true; - } - - // Assign ticket - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmHandle.Index))); - ticket->SaveToDB(trans); - sTicketMgr->UpdateLastChange(); - - std::string msg = ticket->FormatMessageString(*handler, NULL, target.c_str(), NULL, NULL, NULL); - handler->SendGlobalGMSysMessage(msg.c_str()); - return true; - } - - static bool HandleGMTicketCloseByIdCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) - { - handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - // Ticket should be assigned to the player who tries to close it. - // Console can override though - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; - if (player && ticket->IsAssignedNotTo(player->GetGUID())) - { - handler->PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->GetId()); - return true; - } + template<typename T> + static bool HandleTicketAssignToCommand(ChatHandler* handler, char const* args); - ObjectGuid closedByGuid; - if (player) - closedByGuid = player->GetGUID(); - else - closedByGuid.SetRawValue(0, uint64(-1)); - - sTicketMgr->CloseTicket(ticket->GetId(), closedByGuid); - sTicketMgr->UpdateLastChange(); - - std::string msg = ticket->FormatMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL, NULL); - handler->SendGlobalGMSysMessage(msg.c_str()); - - // Inform player, who submitted this ticket, that it is closed - if (Player* submitter = ticket->GetPlayer()) - { - WorldPacket data(SMSG_GM_TICKET_UPDATE, 4); - data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - submitter->GetSession()->SendPacket(&data); - } - return true; - } - - static bool HandleGMTicketCommentCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; + template<typename T> + static bool HandleTicketCloseByIdCommand(ChatHandler* handler, char const* args); - char* ticketIdStr = strtok((char*)args, " "); - uint32 ticketId = atoi(ticketIdStr); + template<typename T> + static bool HandleTicketCommentCommand(ChatHandler* handler, char const* args); - char* comment = strtok(NULL, "\n"); - if (!comment) - return false; + template<typename T> + static bool HandleTicketDeleteByIdCommand(ChatHandler* handler, char const* args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket || ticket->IsClosed()) - { - handler->PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } + template<typename T> + static bool HandleTicketListCommand(ChatHandler* handler, char const* /*args*/); - // Cannot comment ticket assigned to someone else - //! Console excluded - Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL; - if (player && ticket->IsAssignedNotTo(player->GetGUID())) - { - handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); - return true; - } + template<typename T> + static bool HandleTicketListClosedCommand(ChatHandler* handler, char const* /*args*/); - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetComment(comment); - ticket->SaveToDB(trans); - sTicketMgr->UpdateLastChange(); + template<typename T> + static bool HandleTicketResetCommand(ChatHandler* handler, char const* /*args*/); - std::string msg = ticket->FormatMessageString(*handler, NULL, ticket->GetAssignedToName().c_str(), NULL, NULL, NULL); - msg += handler->PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, player ? player->GetName().c_str() : "Console", comment); - handler->SendGlobalGMSysMessage(msg.c_str()); + template<typename T> + static bool HandleTicketUnAssignCommand(ChatHandler* handler, char const* args); - return true; - } - - static bool HandleGMTicketListClosedCommand(ChatHandler* handler, char const* /*args*/) - { - sTicketMgr->ShowClosedList(*handler); - return true; - } + template<typename T> + static bool HandleTicketGetByIdCommand(ChatHandler* handler, char const* args); static bool HandleGMTicketCompleteCommand(ChatHandler* handler, char const* args) { @@ -227,7 +70,7 @@ public: return false; uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) { handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); @@ -241,46 +84,9 @@ public: ticket->SetCompleted(); ticket->SaveToDB(trans); - std::string msg = ticket->FormatMessageString(*handler, NULL, NULL, - NULL, NULL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console"); - handler->SendGlobalGMSysMessage(msg.c_str()); - sTicketMgr->UpdateLastChange(); - return true; - } - - static bool HandleGMTicketDeleteByIdCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket) - { - handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - if (!ticket->IsClosed()) - { - handler->SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); - return true; - } - - std::string msg = ticket->FormatMessageString(*handler, NULL, NULL, NULL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL); + std::string msg = ticket->FormatViewMessageString(*handler, NULL, NULL, NULL, NULL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console"); handler->SendGlobalGMSysMessage(msg.c_str()); - - sTicketMgr->RemoveTicket(ticket->GetId()); - sTicketMgr->UpdateLastChange(); - - if (Player* player = ticket->GetPlayer()) - { - // Force abandon ticket - WorldPacket data(SMSG_GM_TICKET_UPDATE, 4); - data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - player->GetSession()->SendPacket(&data); - } - + sSupportMgr->UpdateLastChange(); return true; } @@ -290,7 +96,7 @@ public: return false; uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); if (!ticket || ticket->IsClosed() || ticket->IsCompleted() || ticket->GetEscalatedStatus() != TICKET_UNASSIGNED) { handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); @@ -300,125 +106,54 @@ public: ticket->SetEscalatedStatus(TICKET_IN_ESCALATION_QUEUE); if (Player* player = ticket->GetPlayer()) - sTicketMgr->SendTicket(player->GetSession(), ticket); + sSupportMgr->SendGmTicket(player->GetSession(), ticket); - sTicketMgr->UpdateLastChange(); + sSupportMgr->UpdateLastChange(); return true; } static bool HandleGMTicketListEscalatedCommand(ChatHandler* handler, char const* /*args*/) { - sTicketMgr->ShowEscalatedList(*handler); - return true; - } - - static bool HandleGMTicketListCommand(ChatHandler* handler, char const* /*args*/) - { - sTicketMgr->ShowList(*handler, false); + sSupportMgr->ShowGmEscalatedList(*handler); return true; } static bool HandleGMTicketListOnlineCommand(ChatHandler* handler, char const* /*args*/) { - sTicketMgr->ShowList(*handler, true); + sSupportMgr->ShowList<GmTicket>(*handler, true); return true; } - static bool HandleGMTicketResetCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleTicketResetAllCommand(ChatHandler* handler, char const* /*args*/) { - if (sTicketMgr->GetOpenTicketCount()) + if (sSupportMgr->GetOpenTicketCount<GmTicket>() || sSupportMgr->GetOpenTicketCount<BugTicket>() + || sSupportMgr->GetOpenTicketCount<ComplaintTicket>() || sSupportMgr->GetOpenTicketCount<SuggestionTicket>()) { handler->SendSysMessage(LANG_COMMAND_TICKETPENDING); return true; } else { - sTicketMgr->ResetTickets(); + sSupportMgr->ResetTickets<GmTicket>(); + sSupportMgr->ResetTickets<BugTicket>(); + sSupportMgr->ResetTickets<ComplaintTicket>(); + sSupportMgr->ResetTickets<SuggestionTicket>(); handler->SendSysMessage(LANG_COMMAND_TICKETRESET); } - return true; } static bool HandleToggleGMTicketSystem(ChatHandler* handler, char const* /*args*/) { - bool status = !sTicketMgr->GetStatus(); - sTicketMgr->SetStatus(status); - handler->PSendSysMessage(status ? LANG_ALLOW_TICKETS : LANG_DISALLOW_TICKETS); - return true; - } - - static bool HandleGMTicketUnAssignCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket || ticket->IsClosed()) - { - handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - // Ticket must be assigned - if (!ticket->IsAssigned()) + if (!sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED)) { - handler->PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->GetId()); + handler->SendSysMessage(LANG_DISALLOW_TICKETS_CONFIG); return true; } - // Get security level of player, whom this ticket is assigned to - uint32 security = SEC_PLAYER; - Player* assignedPlayer = ticket->GetAssignedPlayer(); - if (assignedPlayer) - security = assignedPlayer->GetSession()->GetSecurity(); - else - { - ObjectGuid guid = ticket->GetAssignedToGUID(); - uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(guid); - security = AccountMgr::GetSecurity(accountId, realmHandle.Index); - } - - // Check security - //! If no m_session present it means we're issuing this command from the console - uint32 mySecurity = handler->GetSession() ? handler->GetSession()->GetSecurity() : SEC_CONSOLE; - if (security > mySecurity) - { - handler->SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); - return true; - } - - std::string assignedTo = ticket->GetAssignedToName(); // copy assignedto name because we need it after the ticket has been unnassigned - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetUnassigned(); - ticket->SaveToDB(trans); - sTicketMgr->UpdateLastChange(); - - std::string msg = ticket->FormatMessageString(*handler, NULL, assignedTo.c_str(), - handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL, NULL); - handler->SendGlobalGMSysMessage(msg.c_str()); - - return true; - } - - static bool HandleGMTicketGetByIdCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - uint32 ticketId = atoi(args); - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); - if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) - { - handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); - return true; - } - - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetViewed(); - ticket->SaveToDB(trans); - - handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str()); + bool status = !sSupportMgr->GetSupportSystemStatus(); + sSupportMgr->SetSupportSystemStatus(status); + handler->PSendSysMessage(status ? LANG_ALLOW_TICKETS : LANG_DISALLOW_TICKETS); return true; } @@ -446,7 +181,7 @@ public: } // Ticket must exist - GmTicket* ticket = sTicketMgr->GetTicketByPlayer(guid); + GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(guid); if (!ticket) { handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); @@ -457,7 +192,7 @@ public: ticket->SetViewed(); ticket->SaveToDB(trans); - handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str()); + handler->SendSysMessage(ticket->FormatViewMessageString(*handler, true).c_str()); return true; } @@ -473,7 +208,7 @@ public: if (!response) return false; - GmTicket* ticket = sTicketMgr->GetTicket(ticketId); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); if (!ticket || ticket->IsClosed()) { handler->PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); @@ -507,8 +242,571 @@ public: { return _HandleGMTicketResponseAppendCommand(args, true, handler); } + + ChatCommand* GetCommands() const override; }; +template<typename T> +bool ticket_commandscript::HandleTicketAssignToCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + char* ticketIdStr = strtok((char*)args, " "); + uint32 ticketId = atoi(ticketIdStr); + + char* targetStr = strtok(NULL, " "); + if (!targetStr) + return false; + + std::string target(targetStr); + if (!normalizePlayerName(target)) + return false; + + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + ObjectGuid targetGuid = ObjectMgr::GetPlayerGUIDByName(target); + uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(targetGuid); + // Target must exist and have administrative rights + if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmHandle.Index)) + { + handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); + return true; + } + + // If already assigned, leave + if (ticket->IsAssignedTo(targetGuid)) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->GetId()); + return true; + } + + // If assigned to different player other than current, leave + //! Console can override though + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId(), target.c_str()); + return true; + } + + // Assign ticket + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SetAssignedTo(targetGuid); + + ticket->SaveToDB(trans); + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, target.c_str(), NULL, NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + return true; +} + +template<> +bool ticket_commandscript::HandleTicketAssignToCommand<GmTicket>(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + char* ticketIdStr = strtok((char*)args, " "); + uint32 ticketId = atoi(ticketIdStr); + + char* targetStr = strtok(NULL, " "); + if (!targetStr) + return false; + + std::string target(targetStr); + if (!normalizePlayerName(target)) + return false; + + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + ObjectGuid targetGuid = ObjectMgr::GetPlayerGUIDByName(target); + uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(targetGuid); + // Target must exist and have administrative rights + if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmHandle.Index)) + { + handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); + return true; + } + + // If already assigned, leave + if (ticket->IsAssignedTo(targetGuid)) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->GetId()); + return true; + } + + // If assigned to different player other than current, leave + //! Console can override though + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId(), target.c_str()); + return true; + } + + // Assign ticket + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmHandle.Index))); + sSupportMgr->UpdateLastChange(); + + ticket->SaveToDB(trans); + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, target.c_str(), NULL, NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketCloseByIdCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + // Ticket should be assigned to the player who tries to close it. + // Console can override though + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->GetId()); + return true; + } + + ObjectGuid closedByGuid; + if (player) + closedByGuid = player->GetGUID(); + else + closedByGuid.SetRawValue(0, uint64(-1)); + + sSupportMgr->CloseTicket<T>(ticket->GetId(), closedByGuid); + + std::string msg = ticket->FormatViewMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + return true; +} + +template<> +bool ticket_commandscript::HandleTicketCloseByIdCommand<GmTicket>(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); + if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + // Ticket should be assigned to the player who tries to close it. + // Console can override though + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->GetId()); + return true; + } + + ObjectGuid closedByGuid; + if (player) + closedByGuid = player->GetGUID(); + else + closedByGuid.SetRawValue(0, uint64(-1)); + + std::string msg = ticket->FormatViewMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + + sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), closedByGuid); + sSupportMgr->UpdateLastChange(); + + // Inform player, who submitted this ticket, that it is closed + if (Player* submitter = ticket->GetPlayer()) + sSupportMgr->SendGmTicketUpdate(submitter->GetSession(), GMTICKET_RESPONSE_TICKET_DELETED); + + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketCommentCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + char* ticketIdStr = strtok((char*)args, " "); + uint32 ticketId = atoi(ticketIdStr); + + char* comment = strtok(NULL, "\n"); + if (!comment) + return false; + + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + // Cannot comment ticket assigned to someone else + //! Console excluded + Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); + return true; + } + + SQLTransaction trans = SQLTransaction(nullptr); + ticket->SetComment(comment); + ticket->SaveToDB(trans); + sSupportMgr->UpdateLastChange(); + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, ticket->GetAssignedToName().c_str(), NULL, NULL, NULL); + msg += handler->PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, player ? player->GetName().c_str() : "Console", comment); + handler->SendGlobalGMSysMessage(msg.c_str()); + + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketListCommand(ChatHandler* handler, char const* /*args*/) +{ + sSupportMgr->ShowList<T>(*handler); + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketListClosedCommand(ChatHandler* handler, char const* /*args*/) +{ + sSupportMgr->ShowClosedList<T>(*handler); + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketDeleteByIdCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + if (!ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); + return true; + } + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, NULL, NULL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + sSupportMgr->RemoveTicket<T>(ticket->GetId()); + + return true; +} + +template<> +bool ticket_commandscript::HandleTicketDeleteByIdCommand<GmTicket>(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); + if (!ticket) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + if (!ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); + return true; + } + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, NULL, NULL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + sSupportMgr->RemoveTicket<GmTicket>(ticket->GetId()); + sSupportMgr->UpdateLastChange(); + + if (Player* player = ticket->GetPlayer()) + sSupportMgr->SendGmTicketUpdate(player->GetSession(), GMTICKET_RESPONSE_TICKET_DELETED); + + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketResetCommand(ChatHandler* handler, char const* /*args*/) +{ + if (sSupportMgr->GetOpenTicketCount<T>()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETPENDING); + return true; + } + else + { + sSupportMgr->ResetTickets<T>(); + handler->SendSysMessage(LANG_COMMAND_TICKETRESET); + } + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketUnAssignCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + // Ticket must be assigned + if (!ticket->IsAssigned()) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->GetId()); + return true; + } + + // Get security level of player, whom this ticket is assigned to + uint32 security = SEC_PLAYER; + Player* assignedPlayer = ticket->GetAssignedPlayer(); + if (assignedPlayer) + security = assignedPlayer->GetSession()->GetSecurity(); + else + { + ObjectGuid guid = ticket->GetAssignedToGUID(); + uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(guid); + security = AccountMgr::GetSecurity(accountId, realmHandle.Index); + } + + // Check security + //! If no m_session present it means we're issuing this command from the console + uint32 mySecurity = handler->GetSession() ? handler->GetSession()->GetSecurity() : SEC_CONSOLE; + if (security > mySecurity) + { + handler->SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); + return true; + } + + std::string assignedTo = ticket->GetAssignedToName(); // copy assignedto name because we need it after the ticket has been unnassigned + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetUnassigned(); + ticket->SaveToDB(trans); + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, assignedTo.c_str(), handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + return true; +} + +template<> +bool ticket_commandscript::HandleTicketUnAssignCommand<GmTicket>(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + // Ticket must be assigned + if (!ticket->IsAssigned()) + { + handler->PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->GetId()); + return true; + } + + // Get security level of player, whom this ticket is assigned to + uint32 security = SEC_PLAYER; + Player* assignedPlayer = ticket->GetAssignedPlayer(); + if (assignedPlayer) + security = assignedPlayer->GetSession()->GetSecurity(); + else + { + ObjectGuid guid = ticket->GetAssignedToGUID(); + uint32 accountId = ObjectMgr::GetPlayerAccountIdByGUID(guid); + security = AccountMgr::GetSecurity(accountId, realmHandle.Index); + } + + // Check security + //! If no m_session present it means we're issuing this command from the console + uint32 mySecurity = handler->GetSession() ? handler->GetSession()->GetSecurity() : SEC_CONSOLE; + if (security > mySecurity) + { + handler->SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); + return true; + } + + std::string assignedTo = ticket->GetAssignedToName(); // copy assignedto name because we need it after the ticket has been unnassigned + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetUnassigned(); + ticket->SaveToDB(trans); + sSupportMgr->UpdateLastChange(); + + std::string msg = ticket->FormatViewMessageString(*handler, NULL, assignedTo.c_str(), handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL, NULL); + handler->SendGlobalGMSysMessage(msg.c_str()); + + return true; +} + +template<typename T> +bool ticket_commandscript::HandleTicketGetByIdCommand(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + T* ticket = sSupportMgr->GetTicket<T>(ticketId); + if (!ticket || ticket->IsClosed()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + handler->SendSysMessage(ticket->FormatViewMessageString(*handler, true).c_str()); + return true; +} + +template<> +bool ticket_commandscript::HandleTicketGetByIdCommand<GmTicket>(ChatHandler* handler, char const* args) +{ + if (!*args) + return false; + + uint32 ticketId = atoi(args); + GmTicket* ticket = sSupportMgr->GetTicket<GmTicket>(ticketId); + if (!ticket || ticket->IsClosed() || ticket->IsCompleted()) + { + handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); + return true; + } + + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetViewed(); + ticket->SaveToDB(trans); + + handler->SendSysMessage(ticket->FormatViewMessageString(*handler, true).c_str()); + return true; +} + +ChatCommand* ticket_commandscript::GetCommands() const +{ + static ChatCommand ticketBugCommandTable[] = + { + { "assign", rbac::RBAC_PERM_COMMAND_TICKET_BUG_ASSIGN, true, &HandleTicketAssignToCommand<BugTicket>, "", NULL }, + { "close", rbac::RBAC_PERM_COMMAND_TICKET_BUG_CLOSE, true, &HandleTicketCloseByIdCommand<BugTicket>, "", NULL }, + { "closedlist", rbac::RBAC_PERM_COMMAND_TICKET_BUG_CLOSEDLIST, true, &HandleTicketListClosedCommand<BugTicket>, "", NULL }, + { "comment", rbac::RBAC_PERM_COMMAND_TICKET_BUG_COMMENT, true, &HandleTicketCommentCommand<BugTicket>, "", NULL }, + { "delete", rbac::RBAC_PERM_COMMAND_TICKET_BUG_DELETE, true, &HandleTicketDeleteByIdCommand<BugTicket>, "", NULL }, + { "list", rbac::RBAC_PERM_COMMAND_TICKET_BUG_LIST, true, &HandleTicketListCommand<BugTicket>, "", NULL }, + { "unassign", rbac::RBAC_PERM_COMMAND_TICKET_BUG_UNASSIGN, true, &HandleTicketUnAssignCommand<BugTicket>, "", NULL }, + { "view", rbac::RBAC_PERM_COMMAND_TICKET_BUG_VIEW, true, &HandleTicketGetByIdCommand<BugTicket>, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketComplaintCommandTable[] = + { + { "assign", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_ASSIGN, true, &HandleTicketAssignToCommand<ComplaintTicket>, "", NULL }, + { "close", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSE, true, &HandleTicketCloseByIdCommand<ComplaintTicket>, "", NULL }, + { "closedlist", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSEDLIST, true, &HandleTicketListClosedCommand<ComplaintTicket>, "", NULL }, + { "comment", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_COMMENT, true, &HandleTicketCommentCommand<ComplaintTicket>, "", NULL }, + { "delete", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_DELETE, true, &HandleTicketDeleteByIdCommand<ComplaintTicket>, "", NULL }, + { "list", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_LIST, true, &HandleTicketListCommand<ComplaintTicket>, "", NULL }, + { "unassign", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_UNASSIGN, true, &HandleTicketUnAssignCommand<ComplaintTicket>, "", NULL }, + { "view", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT_VIEW, true, &HandleTicketGetByIdCommand<ComplaintTicket>, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketSuggestionCommandTable[] = + { + { "assign", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_ASSIGN, true, &HandleTicketAssignToCommand<SuggestionTicket>, "", NULL }, + { "close", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSE, true, &HandleTicketCloseByIdCommand<SuggestionTicket>, "", NULL }, + { "closedlist", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSEDLIST, true, &HandleTicketListClosedCommand<SuggestionTicket>, "", NULL }, + { "comment", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_COMMENT, true, &HandleTicketCommentCommand<SuggestionTicket>, "", NULL }, + { "delete", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_DELETE, true, &HandleTicketDeleteByIdCommand<SuggestionTicket>, "", NULL }, + { "list", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_LIST, true, &HandleTicketListCommand<SuggestionTicket>, "", NULL }, + { "unassign", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_UNASSIGN, true, &HandleTicketUnAssignCommand<SuggestionTicket>, "", NULL }, + { "view", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION_VIEW, true, &HandleTicketGetByIdCommand<SuggestionTicket>, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketResetCommandTable[] = + { + { "all", rbac::RBAC_PERM_COMMAND_TICKET_RESET_ALL, true, &HandleTicketResetAllCommand, "", NULL }, + { "gm", rbac::RBAC_PERM_COMMAND_TICKET_RESET_GM, true, &HandleTicketResetCommand<GmTicket>, "", NULL }, + { "bug", rbac::RBAC_PERM_COMMAND_TICKET_RESET_BUG, true, &HandleTicketResetCommand<BugTicket>, "", NULL }, + { "complaint", rbac::RBAC_PERM_COMMAND_TICKET_RESET_COMPLAINT, true, &HandleTicketResetCommand<ComplaintTicket>, "", NULL }, + { "suggestion", rbac::RBAC_PERM_COMMAND_TICKET_RESET_SUGGESTION, true, &HandleTicketResetCommand<SuggestionTicket>, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketResponseCommandTable[] = + { + { "append", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPEND, true, &HandleGMTicketResponseAppendCommand, "", NULL }, + { "appendln", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE_APPENDLN, true, &HandleGMTicketResponseAppendLnCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand ticketCommandTable[] = + { + { "assign", rbac::RBAC_PERM_COMMAND_TICKET_ASSIGN, true, &HandleTicketAssignToCommand<GmTicket>, "", NULL }, + { "bug", rbac::RBAC_PERM_COMMAND_TICKET_BUG, true, NULL, "", ticketBugCommandTable }, + { "close", rbac::RBAC_PERM_COMMAND_TICKET_CLOSE, true, &HandleTicketCloseByIdCommand<GmTicket>, "", NULL }, + { "closedlist", rbac::RBAC_PERM_COMMAND_TICKET_CLOSEDLIST, true, &HandleTicketListClosedCommand<GmTicket>, "", NULL }, + { "comment", rbac::RBAC_PERM_COMMAND_TICKET_COMMENT, true, &HandleTicketCommentCommand<GmTicket>, "", NULL }, + { "complaint", rbac::RBAC_PERM_COMMAND_TICKET_COMPLAINT, true, NULL, "", ticketComplaintCommandTable }, + { "complete", rbac::RBAC_PERM_COMMAND_TICKET_COMPLETE, true, &HandleGMTicketCompleteCommand, "", NULL }, + { "delete", rbac::RBAC_PERM_COMMAND_TICKET_DELETE, true, &HandleTicketDeleteByIdCommand<GmTicket>, "", NULL }, + { "escalate", rbac::RBAC_PERM_COMMAND_TICKET_ESCALATE, true, &HandleGMTicketEscalateCommand, "", NULL }, + { "escalatedlist", rbac::RBAC_PERM_COMMAND_TICKET_ESCALATEDLIST, true, &HandleGMTicketListEscalatedCommand, "", NULL }, + { "list", rbac::RBAC_PERM_COMMAND_TICKET_LIST, true, &HandleTicketListCommand<GmTicket>, "", NULL }, + { "onlinelist", rbac::RBAC_PERM_COMMAND_TICKET_ONLINELIST, true, &HandleGMTicketListOnlineCommand, "", NULL }, + { "reset", rbac::RBAC_PERM_COMMAND_TICKET_RESET, true, NULL, "", ticketResetCommandTable }, + { "response", rbac::RBAC_PERM_COMMAND_TICKET_RESPONSE, true, NULL, "", ticketResponseCommandTable }, + { "suggestion", rbac::RBAC_PERM_COMMAND_TICKET_SUGGESTION, true, NULL, "", ticketSuggestionCommandTable }, + { "togglesystem", rbac::RBAC_PERM_COMMAND_TICKET_TOGGLESYSTEM, true, &HandleToggleGMTicketSystem, "", NULL }, + { "unassign", rbac::RBAC_PERM_COMMAND_TICKET_UNASSIGN, true, &HandleTicketUnAssignCommand<GmTicket>, "", NULL }, + { "viewid", rbac::RBAC_PERM_COMMAND_TICKET_VIEWID, true, &HandleTicketGetByIdCommand<GmTicket>, "", NULL }, + { "viewname", rbac::RBAC_PERM_COMMAND_TICKET_VIEWNAME, true, &HandleGMTicketGetByNameCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand commandTable[] = + { + { "ticket", rbac::RBAC_PERM_COMMAND_TICKET, false, NULL, "", ticketCommandTable }, + { NULL, 0, false, NULL, "", NULL } + }; + return commandTable; +} + void AddSC_ticket_commandscript() { new ticket_commandscript(); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 012d1cc3938..6369429236f 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -356,15 +356,37 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC); // GM Tickets - PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket FROM gm_tickets", CONNECTION_SYNCH); - PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_tickets (ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_tickets WHERE ticketId = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_tickets WHERE guid = ?", CONNECTION_ASYNC); - - // GM Survey/subsurvey/lag report - PrepareStatement(CHAR_INS_GM_SURVEY, "INSERT INTO gm_surveys (guid, surveyId, mainSurvey, overallComment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_GM_SUBSURVEY, "INSERT INTO gm_subsurveys (surveyId, subsurveyId, rank, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_LAG_REPORT, "INSERT INTO lag_reports (guid, lagType, mapId, posX, posY, posZ, latency, createTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, playerGuid, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, playerGuid, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_ticket WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_ticket WHERE playerGuid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_ticket", CONNECTION_ASYNC); + + // GM Survey/subsurvey + PrepareStatement(CHAR_INS_GM_SURVEY, "INSERT INTO gm_survey (guid, surveyId, mainSurvey, comment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GM_SUBSURVEY, "INSERT INTO gm_subsurvey (surveyId, questionID, answer, answerComment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + + // GM Bug + PrepareStatement(CHAR_SEL_GM_BUGS, "SELECT id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, closedBy, assignedTo, comment FROM gm_bug", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_GM_BUG, "REPLACE INTO gm_bug (id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, closedBy, assignedTo, comment) VALUES (?, ?, ?, UNIX_TIMESTAMP(NOW()), ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GM_BUG, "DELETE FROM gm_bug WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_GM_BUGS, "TRUNCATE TABLE gm_bug", CONNECTION_ASYNC); + + // GM Complaint + PrepareStatement(CHAR_SEL_GM_COMPLAINTS, "SELECT id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, targetCharacterGuid, complaintType, reportLineIndex, assignedTo, closedBy, comment FROM gm_complaint", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_GM_COMPLAINT, "REPLACE INTO gm_complaint (id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, targetCharacterGuid, complaintType, reportLineIndex, assignedTo, closedBy, comment) VALUES (?, ?, ?, UNIX_TIMESTAMP(NOW()), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GM_COMPLAINT, "DELETE FROM gm_complaint WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_GM_COMPLAINT_CHATLINES, "SELECT timestamp, text FROM gm_complaint_chatlog WHERE complaintId = ? ORDER BY lineId ASC", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_GM_COMPLAINT_CHATLINE, "INSERT INTO gm_complaint_chatlog (complaintId, lineId, timestamp, text) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GM_COMPLAINT_CHATLOG, "DELETE FROM gm_complaint_chatlog WHERE complaintId = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_GM_COMPLAINTS, "TRUNCATE TABLE gm_complaint", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS, "TRUNCATE TABLE gm_complaint_chatlog", CONNECTION_ASYNC); + + // GM Suggestion + PrepareStatement(CHAR_SEL_GM_SUGGESTIONS, "SELECT id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, closedBy, assignedTo, comment FROM gm_suggestion", CONNECTION_SYNCH); + PrepareStatement(CHAR_REP_GM_SUGGESTION, "REPLACE INTO gm_suggestion (id, playerGuid, note, createTime, mapId, posX, posY, posZ, facing, closedBy, assignedTo, comment) VALUES (?, ?, ?, UNIX_TIMESTAMP(NOW()), ?, ?, ?, ?, ?, ? ,? ,?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_GM_SUGGESTION, "DELETE FROM gm_suggestion WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ALL_GM_SUGGESTIONS, "TRUNCATE TABLE gm_suggestion", CONNECTION_ASYNC); // LFG Data PrepareStatement(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC); @@ -405,7 +427,6 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_GROUP_DIFFICULTY, "UPDATE groups SET difficulty = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY, "UPDATE groups SET raidDifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GROUP_LEGACY_RAID_DIFFICULTY, "UPDATE groups SET legacyRaidDifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_tickets", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_TALENTS, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index 6a9dc813386..b10591f0e5f 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -314,7 +314,25 @@ enum CharacterDatabaseStatements CHAR_INS_GM_SURVEY, CHAR_INS_GM_SUBSURVEY, - CHAR_INS_LAG_REPORT, + + CHAR_SEL_GM_BUGS, + CHAR_REP_GM_BUG, + CHAR_DEL_GM_BUG, + CHAR_DEL_ALL_GM_BUGS, + + CHAR_SEL_GM_COMPLAINTS, + CHAR_REP_GM_COMPLAINT, + CHAR_DEL_GM_COMPLAINT, + CHAR_SEL_GM_COMPLAINT_CHATLINES, + CHAR_INS_GM_COMPLAINT_CHATLINE, + CHAR_DEL_GM_COMPLAINT_CHATLOG, + CHAR_DEL_ALL_GM_COMPLAINTS, + CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS, + + CHAR_SEL_GM_SUGGESTIONS, + CHAR_REP_GM_SUGGESTION, + CHAR_DEL_GM_SUGGESTION, + CHAR_DEL_ALL_GM_SUGGESTIONS, CHAR_INS_CHARACTER, CHAR_UPD_CHARACTER, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index b64393508fe..86d9dac2946 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -16,6 +16,7 @@ # CREATURE SETTINGS # CHAT SETTINGS # GAME MASTER SETTINGS +# SUPPORT SETTINGS # VISIBILITY AND DISTANCES # SERVER RATES # STATS LIMITS @@ -1060,33 +1061,6 @@ Server.LoginInfo = 0 Command.LookupMaxResults = 0 # -# Ticket.SystemStatus -# Description: Enable/disable the ticket system. This disables the whole customer -# support UI after trying to send a ticket in disabled state -# (MessageBox: "GM Help Tickets are currently unavailable."). -# UI remains disabled until the character relogs. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -Ticket.SystemStatus = 1 - -# -# Ticket.SubmitTicket -# Description: Allow/disallow opening new tickets. -# Default: 0 - (Disabled) -# 1 - (Enabled, Experimental) - -Ticket.SubmitTicket = 0 - -# -# Ticket.SubmitBug -# Description: Allow/disallow opening new bug reports. -# Default: 0 - (Disabled) -# 1 - (Enabled, Experimental) - -Ticket.SubmitBug = 0 - -# # DungeonFinder.OptionsMask # Description: Dungeon and raid finder system. # Value is a bitmask consisting of: @@ -1662,12 +1636,60 @@ GM.AllowInvite = 0 GM.LowerSecurity = 0 # -# GM.TicketSystem.ChanceOfGMSurvey +################################################################################################### + +################################################################################################### +# SUPPORT SETTINGS +# +# Support.Enabled +# Description: Enable/disable the ticket system. This disables the whole customer +# support UI after trying to send a ticket in disabled state +# (MessageBox: "GM Help Tickets are currently unavailable."). +# UI remains disabled until the character relogs. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +Support.Enabled = 1 + +# +# Support.TicketsEnabled +# Description: Allow/disallow opening new tickets. +# Default: 0 - (Disabled) +# 1 - (Enabled, Experimental) + +Support.TicketsEnabled = 0 + +# +# Support.BugsEnabled +# Description: Allow/disallow opening new bug reports. +# Default: 0 - (Disabled) +# 1 - (Enabled, Experimental) + +Support.BugsEnabled = 0 + +# +# Support.ComplaintsEnabled +# Description: Allow/disallow creating new player complaints. +# Default: 0 - (Disabled) +# 1 - (Enabled, Experimental) + +Support.ComplaintsEnabled = 0 + +# +# Support.SuggestionsEnabled +# Description: Allow/disallow opening new suggestion reports. +# Default: 0 - (Disabled) +# 1 - (Enabled, Experimental) + +Support.SuggestionsEnabled = 0 + +# +# Support.ChanceOfGMSurvey # Description: Chance of sending a GM survey after ticket completion. # Default: 50 - (Enabled) # 0 - (Disabled) -GM.TicketSystem.ChanceOfGMSurvey = 50 +Support.ChanceOfGMSurvey = 50 # ################################################################################################### |