diff --git a/sql/mangos.sql b/sql/mangos.sql index 3714f7ee7..2bd318691 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_10951_01_mangos_spell_proc_event` bit(1) default NULL + `required_10972_01_mangos_command` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -738,6 +738,9 @@ INSERT INTO `command` VALUES ('saveall',1,'Syntax: .saveall\r\n\r\nSave all characters in game.'), ('send items',3,'Syntax: .send items #playername "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'), ('send mail',1,'Syntax: .send mail #playername "#subject" "#text"\r\n\r\nSend a mail to a player. Subject and mail text must be in "".'), +('send mass items',3,'Syntax: .send mass items #racemask|$racename|alliance|horde|all "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to players. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'), +('send mass mail',1,'Syntax: .send mass mail #racemask|$racename|alliance|horde|all "#subject" "#text"\r\n\r\nSend a mail to players. Subject and mail text must be in "".'), +('send mass money','3','Syntax: .send mass money #racemask|$racename|alliance|horde|all "#subject" "#text" #money\r\n\r\nSend mail with money to players. Subject and mail text must be in "".'), ('send message',3,'Syntax: .send message $playername $message\r\n\r\nSend screen message to player from ADMINISTRATOR.'), ('send money','3','Syntax: .send money #playername "#subject" "#text" #money\r\n\r\nSend mail with money to a player. Subject and mail text must be in "".'), ('server corpses',2,'Syntax: .server corpses\r\n\r\nTriggering corpses expire check in world.'), diff --git a/sql/updates/10972_01_mangos_command.sql b/sql/updates/10972_01_mangos_command.sql new file mode 100644 index 000000000..64b6362f8 --- /dev/null +++ b/sql/updates/10972_01_mangos_command.sql @@ -0,0 +1,9 @@ +ALTER TABLE db_version CHANGE COLUMN required_10951_01_mangos_spell_proc_event required_10972_01_mangos_command bit; + +DELETE FROM command WHERE name IN ('send mass items','send mass mail','send mass money'); + +INSERT INTO command (name, security, help) VALUES +('send mass items',3,'Syntax: .send mass items #racemask|$racename|alliance|horde|all "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to players. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'), +('send mass mail',1,'Syntax: .send mass mail #racemask|$racename|alliance|horde|all "#subject" "#text"\r\n\r\nSend a mail to players. Subject and mail text must be in "".'), +('send mass money','3','Syntax: .send mass money #racemask|$racename|alliance|horde|all "#subject" "#text" #money\r\n\r\nSend mail with money to players. Subject and mail text must be in "".'); + diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 3ce51b3d9..5251ceb62 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -144,6 +144,7 @@ pkgdata_DATA = \ 10949_01_mangos_mangos_string.sql \ 10950_01_mangos_mangos_string.sql \ 10951_01_mangos_spell_proc_event.sql \ + 10972_01_mangos_command.sql \ README ## Additional files to include when running 'make dist' @@ -268,4 +269,5 @@ EXTRA_DIST = \ 10949_01_mangos_mangos_string.sql \ 10950_01_mangos_mangos_string.sql \ 10951_01_mangos_spell_proc_event.sql \ + 10972_01_mangos_command.sql \ README diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 7eb26f568..a0f62f9f7 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -546,8 +546,18 @@ ChatCommand * ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; + static ChatCommand sendMassCommandTable[] = + { + { "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassItemsCommand, "", NULL }, + { "mail", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMailCommand, "", NULL }, + { "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMoneyCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand sendCommandTable[] = { + { "mass", SEC_ADMINISTRATOR, true, NULL, "", sendMassCommandTable }, + { "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL }, { "mail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL }, { "message", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL }, @@ -3264,6 +3274,63 @@ uint32 ChatHandler::ExtractAccountId(char** args, std::string* accountName /*= N return account_id; } +struct RaceMaskName +{ + char const* literal; + uint32 raceMask; +}; + +static RaceMaskName const raceMaskNames[] = +{ + // races + { "human", (1<<(RACE_HUMAN-1)) }, + { "orc", (1<<(RACE_ORC-1)) }, + { "dwarf", (1<<(RACE_DWARF-1)) }, + { "nightelf", (1<<(RACE_NIGHTELF-1))}, + { "undead", (1<<(RACE_UNDEAD-1)) }, + { "tauren", (1<<(RACE_TAUREN-1)) }, + { "gnome", (1<<(RACE_GNOME-1)) }, + { "troll", (1<<(RACE_TROLL-1)) }, + { "bloodelf", (1<<(RACE_BLOODELF-1))}, + { "draenei", (1<<(RACE_DRAENEI-1)) }, + + // masks + { "alliance", RACEMASK_ALLIANCE }, + { "horde", RACEMASK_HORDE }, + { "all", RACEMASK_ALL_PLAYABLE }, + + // terminator + { NULL, 0 } +}; + +bool ChatHandler::ExtractRaceMask(char** text, uint32& raceMask, char const** maskName /*=NULL*/) +{ + if (ExtractUInt32(text, raceMask)) + { + if (maskName) + *maskName = "custom mask"; + } + else + { + for (RaceMaskName const* itr = raceMaskNames; itr->literal; ++itr) + { + if (ExtractLiteralArg(text, itr->literal)) + { + raceMask = itr->raceMask; + + if (maskName) + *maskName = itr->literal; + break; + } + } + + if (!raceMask) + return false; + } + + return true; +} + std::string ChatHandler::GetNameLink(Player* chr) const { return playerLink(chr->GetName()); diff --git a/src/game/Chat.h b/src/game/Chat.h index 7db3af4d2..93a6fb1ba 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -37,6 +37,7 @@ class ChatHandler; class WorldSession; class WorldPacket; class GMTicket; +class MailDraft; class Object; class GameObject; class Creature; @@ -462,6 +463,10 @@ class ChatHandler bool HandleSendMessageCommand(char* args); bool HandleSendMoneyCommand(char* args); + bool HandleSendMassItemsCommand(char* args); + bool HandleSendMassMailCommand(char* args); + bool HandleSendMassMoneyCommand(char* args); + bool HandleServerCorpsesCommand(char* args); bool HandleServerExitCommand(char* args); bool HandleServerIdleRestartCommand(char* args); @@ -601,6 +606,7 @@ class ChatHandler ObjectGuid ExtractGuidFromLink(char** text); GameTele const* ExtractGameTeleFromLink(char** text); bool ExtractLocationFromLink(char** text, uint32& mapid, float& x, float& y, float& z); + bool ExtractRaceMask(char** text, uint32& raceMask, char const** maskName = NULL); std::string ExtractPlayerNameFromLink(char** text); bool ExtractPlayerTarget(char** args, Player** player, ObjectGuid* player_guid = NULL, std::string* player_name = NULL); // select by arg (name/link) or in-game selection online/offline player @@ -633,6 +639,11 @@ class ChatHandler bool HandleGetValueHelper(Object* target, uint32 field, char* typeStr); bool HandlerDebugModValueHelper(Object* target, uint32 field, char* typeStr, char* valStr); bool HandleSetValueHelper(Object* target, uint32 field, char* typeStr, char* valStr); + + bool HandleSendItemsHelper(MailDraft& draft, char* args); + bool HandleSendMailHelper(MailDraft& draft, char* args); + bool HandleSendMoneyHelper(MailDraft& draft, char* args); + template void ShowNpcOrGoSpawnInformation(uint32 guid); template diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index a98a524ca..7eb336903 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -1755,19 +1755,16 @@ bool ChatHandler::HandleSendMailCommand(char* args) if (!ExtractPlayerTarget(&args, &target, &target_guid, &target_name)) return false; - char* msgSubject = ExtractQuotedArg(&args); - if (!msgSubject) - return false; + MailDraft draft; - char* msgText = ExtractQuotedArg(&args); - if (!msgText) + // fill draft + if (!HandleSendMailHelper(draft, args)) return false; // from console show nonexistent sender MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); - MailDraft(msgSubject, msgText) - .SendMailTo(MailReceiver(target, target_guid),sender); + draft.SendMailTo(MailReceiver(target, target_guid),sender); std::string nameLink = playerLink(target_name); PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 21551dc2a..ca37a1c7c 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -33,6 +33,7 @@ #include "Guild.h" #include "ObjectAccessor.h" #include "MapManager.h" +#include "MassMailMgr.h" #include "ScriptMgr.h" #include "Language.h" #include "GridNotifiersImpl.h" @@ -6496,16 +6497,56 @@ bool ChatHandler::HandleAccountSetAddonCommand(char* args) return true; } -//Send items by mail -bool ChatHandler::HandleSendItemsCommand(char* args) +bool ChatHandler::HandleSendMailHelper(MailDraft& draft, char* args) { - // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] - Player* receiver; - ObjectGuid receiver_guid; - std::string receiver_name; - if (!ExtractPlayerTarget(&args, &receiver, &receiver_guid, &receiver_name)) + // format: "subject text" "mail text" + char* msgSubject = ExtractQuotedArg(&args); + if (!msgSubject) return false; + char* msgText = ExtractQuotedArg(&args); + if (!msgText) + return false; + + // msgSubject, msgText isn't NUL after prev. check + draft.SetSubjectAndBody(msgSubject, msgText); + + return true; +} + +bool ChatHandler::HandleSendMassMailCommand(char* args) +{ + // format: raceMask "subject text" "mail text" + uint32 raceMask = 0; + char const* name = NULL; + + if (!ExtractRaceMask(&args, raceMask, &name)) + return false; + + // need dynamic object because it trasfered to mass mailer + MailDraft* draft = new MailDraft; + + // fill mail + if (!HandleSendMailHelper(*draft, args)) + { + delete draft; + return false; + } + + // from console show nonexistent sender + MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); + + sMassMailMgr.AddMassMailTask(draft, sender, raceMask); + + PSendSysMessage(LANG_MAIL_SENT, name); + return true; +} + + + +bool ChatHandler::HandleSendItemsHelper(MailDraft& draft, char* args) +{ + // format: "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] char* msgSubject = ExtractQuotedArg(&args); if (!msgSubject) return false; @@ -6567,11 +6608,8 @@ bool ChatHandler::HandleSendItemsCommand(char* args) } } - // from console show nonexistent sender - MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); - // fill mail - MailDraft draft(msgSubject, msgText); + draft.SetSubjectAndBody(msgSubject, msgText); for(ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr) { @@ -6582,6 +6620,27 @@ bool ChatHandler::HandleSendItemsCommand(char* args) } } + return true; +} + +bool ChatHandler::HandleSendItemsCommand(char* args) +{ + // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] + Player* receiver; + ObjectGuid receiver_guid; + std::string receiver_name; + if (!ExtractPlayerTarget(&args, &receiver, &receiver_guid, &receiver_name)) + return false; + + MailDraft draft; + + // fill mail + if (!HandleSendItemsHelper(draft, args)) + return false; + + // from console show nonexistent sender + MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); + draft.SendMailTo(MailReceiver(receiver, receiver_guid), sender); std::string nameLink = playerLink(receiver_name); @@ -6589,17 +6648,40 @@ bool ChatHandler::HandleSendItemsCommand(char* args) return true; } -///Send money by mail -bool ChatHandler::HandleSendMoneyCommand(char* args) +bool ChatHandler::HandleSendMassItemsCommand(char* args) { - /// format: name "subject text" "mail text" money + // format: racemask "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] - Player* receiver; - ObjectGuid receiver_guid; - std::string receiver_name; - if (!ExtractPlayerTarget(&args, &receiver, &receiver_guid, &receiver_name)) + uint32 raceMask = 0; + char const* name = NULL; + + if (!ExtractRaceMask(&args, raceMask, &name)) return false; + // need dynamic object because it trasfered to mass mailer + MailDraft* draft = new MailDraft; + + + // fill mail + if (!HandleSendItemsHelper(*draft, args)) + { + delete draft; + return false; + } + + // from console show nonexistent sender + MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); + + sMassMailMgr.AddMassMailTask(draft, sender, raceMask); + + PSendSysMessage(LANG_MAIL_SENT, name); + return true; +} + +bool ChatHandler::HandleSendMoneyHelper(MailDraft& draft, char* args) +{ + /// format: "subject text" "mail text" money + char* msgSubject = ExtractQuotedArg(&args); if (!msgSubject) return false; @@ -6615,18 +6697,67 @@ bool ChatHandler::HandleSendMoneyCommand(char* args) if (money <= 0) return false; + // msgSubject, msgText isn't NUL after prev. check + draft.SetSubjectAndBody(msgSubject, msgText).SetMoney(money); + + return true; +} + +bool ChatHandler::HandleSendMoneyCommand(char* args) +{ + /// format: name "subject text" "mail text" money + + Player* receiver; + ObjectGuid receiver_guid; + std::string receiver_name; + if (!ExtractPlayerTarget(&args, &receiver, &receiver_guid, &receiver_name)) + return false; + + MailDraft draft; + + // fill mail + if (!HandleSendMoneyHelper(draft, args)) + return false; + // from console show nonexistent sender MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); - MailDraft(msgSubject, msgText) - .SetMoney(money) - .SendMailTo(MailReceiver(receiver, receiver_guid),sender); + draft.SendMailTo(MailReceiver(receiver, receiver_guid),sender); std::string nameLink = playerLink(receiver_name); PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); return true; } +bool ChatHandler::HandleSendMassMoneyCommand(char* args) +{ + /// format: raceMask "subject text" "mail text" money + + uint32 raceMask = 0; + char const* name = NULL; + + if (!ExtractRaceMask(&args, raceMask, &name)) + return false; + + // need dynamic object because it trasfered to mass mailer + MailDraft* draft = new MailDraft; + + // fill mail + if (!HandleSendMoneyHelper(*draft, args)) + { + delete draft; + return false; + } + + // from console show nonexistent sender + MailSender sender(MAIL_NORMAL, m_session ? m_session->GetPlayer()->GetObjectGuid().GetCounter() : 0, MAIL_STATIONERY_GM); + + sMassMailMgr.AddMassMailTask(draft, sender, raceMask); + + PSendSysMessage(LANG_MAIL_SENT, name); + return true; +} + /// Send a message to a player in game bool ChatHandler::HandleSendMessageCommand(char* args) { diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 2ec9f7410..dc44215fc 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -64,7 +64,16 @@ enum Races ((1<<(RACE_HUMAN-1)) |(1<<(RACE_ORC-1)) |(1<<(RACE_DWARF-1)) | \ (1<<(RACE_NIGHTELF-1)) |(1<<(RACE_UNDEAD-1)) |(1<<(RACE_TAUREN-1)) | \ (1<<(RACE_GNOME-1)) |(1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))| \ - (1<<(RACE_DRAENEI-1)) ) + (1<<(RACE_DRAENEI-1))) + +// for most cases batter use ChrRace data for team check as more safe, but when need full mask of team can be use this defines. +#define RACEMASK_ALLIANCE \ + ((1<<(RACE_HUMAN-1)) |(1<<(RACE_DWARF-1)) |(1<<(RACE_NIGHTELF-1))| \ + (1<<(RACE_GNOME-1)) |(1<<(RACE_DRAENEI-1))) + +#define RACEMASK_HORDE \ + ((1<<(RACE_ORC-1)) |(1<<(RACE_UNDEAD-1)) |(1<<(RACE_TAUREN-1)) | \ + (1<<(RACE_TROLL-1)) |(1<<(RACE_BLOODELF-1))) // Class value is index in ChrClasses.dbc enum Classes diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 2104bc029..371723cbb 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10971" + #define REVISION_NR "10972" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index f6b0cb6fd..53e6e956a 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_10862_01_characters_mail" - #define REVISION_DB_MANGOS "required_10951_01_mangos_spell_proc_event" + #define REVISION_DB_MANGOS "required_10972_01_mangos_command" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__