/** * MaNGOS is a full featured server for World of Warcraft, supporting * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 * * Copyright (C) 2005-2020 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * World of Warcraft, and all World of Warcraft or Warcraft art, images, * and lore are copyrighted by Blizzard Entertainment, Inc. */ #include "Chat.h" #include "Language.h" #include "Database/DatabaseEnv.h" #include "WorldPacket.h" #include "WorldSession.h" #include "Opcodes.h" #include "Log.h" #include "World.h" #include "ObjectMgr.h" #include "ObjectGuid.h" #include "Player.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "AccountMgr.h" #include "SpellMgr.h" #include "PoolManager.h" #include "GameEventMgr.h" #include "AuctionHouseBot/AuctionHouseBot.h" #include "CommandMgr.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ // Supported shift-links (client generated and server side) // |color|Harea:area_id|h[name]|h|r // |color|Hareatrigger:id|h[name]|h|r // |color|Hareatrigger_target:id|h[name]|h|r // |color|Hcreature:creature_guid|h[name]|h|r // |color|Hcreature_entry:creature_id|h[name]|h|r // |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog // |color|Hgameevent:id|h[name]|h|r // |color|Hgameobject:go_guid|h[name]|h|r // |color|Hgameobject_entry:go_id|h[name]|h|r // |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:0:0:0|h[name]|h|r - client, item icon shift click // |color|Hitemset:itemset_id|h[name]|h|r // |color|Hplayer:name|h[name]|h|r - client, in some messages, at click copy only name instead link, so no way generate it in client string send to server // |color|Hpool:pool_id|h[name]|h|r // |color|Hquest:quest_id:quest_level|h[name]|h|r - client, quest list name shift-click // |color|Hskill:skill_id|h[name]|h|r // |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click // |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click rank==-1 if shift-copy unlearned talent // |color|Htaxinode:id|h[name]|h|r // |color|Htele:id|h[name]|h|r bool ChatHandler::load_command_table = true; ChatCommand* ChatHandler::getCommandTable() { static ChatCommand accountSetCommandTable[] = { { "addon", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountSetAddonCommand, "", NULL }, { "gmlevel", SEC_CONSOLE, true, &ChatHandler::HandleAccountSetGmLevelCommand, "", NULL }, { "password", SEC_CONSOLE, true, &ChatHandler::HandleAccountSetPasswordCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand accountCommandTable[] = { { "characters", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountCharactersCommand, "", NULL }, { "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL }, { "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL }, { "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL }, { "lock", SEC_PLAYER, true, &ChatHandler::HandleAccountLockCommand, "", NULL }, { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable }, { "password", SEC_PLAYER, true, &ChatHandler::HandleAccountPasswordCommand, "", NULL }, { "", SEC_PLAYER, true, &ChatHandler::HandleAccountCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand ahbotItemsAmountCommandTable[] = { { "grey", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "white", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "green", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "blue", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "purple", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "orange", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "yellow", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand, "", NULL }, { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountCommand, "", NULL }, { NULL, 0, true, NULL, "", NULL } }; static ChatCommand ahbotItemsRatioCommandTable[] = { { "alliance", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand, "", NULL }, { "horde", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand, "", NULL }, { "neutral", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand, "", NULL }, { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioCommand, "", NULL }, { NULL, 0, true, NULL, "", NULL } }; static ChatCommand ahbotItemsCommandTable[] = { { "amount", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsAmountCommandTable}, { "ratio", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsRatioCommandTable}, { NULL, 0, true, NULL, "", NULL } }; static ChatCommand ahbotCommandTable[] = { { "items", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsCommandTable}, { "rebuild", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotRebuildCommand, "", NULL }, { "reload", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotReloadCommand, "", NULL }, { "status", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotStatusCommand, "", NULL }, { NULL, 0, true, NULL, "", NULL } }; static ChatCommand auctionCommandTable[] = { { "alliance", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionAllianceCommand, "", NULL }, { "goblin", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionGoblinCommand, "", NULL }, { "horde", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionHordeCommand, "", NULL }, { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAuctionItemCommand, "", NULL }, { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand banCommandTable[] = { { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanAccountCommand, "", NULL }, { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanCharacterCommand, "", NULL }, { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanIPCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand baninfoCommandTable[] = { { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoAccountCommand, "", NULL }, { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoCharacterCommand, "", NULL }, { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoIPCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand banlistCommandTable[] = { { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListAccountCommand, "", NULL }, { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListCharacterCommand, "", NULL }, { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListIPCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand castCommandTable[] = { { "back", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastBackCommand, "", NULL }, { "dist", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastDistCommand, "", NULL }, { "self", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastSelfCommand, "", NULL }, { "target", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastTargetCommand, "", NULL }, { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand characterDeletedCommandTable[] = { { "delete", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeletedDeleteCommand, "", NULL }, { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterDeletedListCommand, "", NULL }, { "restore", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterDeletedRestoreCommand, "", NULL }, { "old", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeletedOldCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand characterCommandTable[] = { { "deleted", SEC_GAMEMASTER, true, NULL, "", characterDeletedCommandTable}, { "erase", SEC_CONSOLE, true, &ChatHandler::HandleCharacterEraseCommand, "", NULL }, { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterLevelCommand, "", NULL }, { "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterRenameCommand, "", NULL }, { "reputation", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterReputationCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand debugPlayCommandTable[] = { { "cinematic", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlayCinematicCommand, "", NULL }, { "sound", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlaySoundCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand debugSendCommandTable[] = { { "buyerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendBuyErrorCommand, "", NULL }, { "channelnotify", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChannelNotifyCommand, "", NULL }, { "chatmmessage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChatMsgCommand, "", NULL }, { "equiperror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendEquipErrorCommand, "", NULL }, { "opcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendOpcodeCommand, "", NULL }, { "poi", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendPoiCommand, "", NULL }, { "qpartymsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestPartyMsgCommand, "", NULL }, { "qinvalidmsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestInvalidMsgCommand, "", NULL }, { "sellerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSellErrorCommand, "", NULL }, { "spellfail", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSpellFailCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand debugCommandTable[] = { { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL }, { "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL }, { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemStateCommand, "", NULL }, { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipientCommand, "", NULL }, { "getitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemValueCommand, "", NULL }, { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValueCommand, "", NULL }, { "moditemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugModItemValueCommand, "", NULL }, { "modvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugModValueCommand, "", NULL }, { "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable }, { "recv", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugRecvOpcodeCommand, "", NULL }, { "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable }, { "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL }, { "setitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemValueCommand, "", NULL }, { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL }, { "spellcheck", SEC_CONSOLE, true, &ChatHandler::HandleDebugSpellCheckCommand, "", NULL }, { "spellcoefs", SEC_ADMINISTRATOR, true, &ChatHandler::HandleDebugSpellCoefsCommand, "", NULL }, { "spellmods", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpellModsCommand, "", NULL }, { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateWorldStateCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand eventCommandTable[] = { { "list", SEC_GAMEMASTER, true, &ChatHandler::HandleEventListCommand, "", NULL }, { "start", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStartCommand, "", NULL }, { "stop", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStopCommand, "", NULL }, { "", SEC_GAMEMASTER, true, &ChatHandler::HandleEventInfoCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand gmCommandTable[] = { { "chat", SEC_MODERATOR, false, &ChatHandler::HandleGMChatCommand, "", NULL }, { "fly", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGMFlyCommand, "", NULL }, { "ingame", SEC_PLAYER, true, &ChatHandler::HandleGMListIngameCommand, "", NULL }, { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMListFullCommand, "", NULL }, { "visible", SEC_MODERATOR, false, &ChatHandler::HandleGMVisibleCommand, "", NULL }, { "setview", SEC_MODERATOR, false, &ChatHandler::HandleSetViewCommand, "", NULL }, { "", SEC_MODERATOR, false, &ChatHandler::HandleGMCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand goCommandTable[] = { { "creature", SEC_MODERATOR, false, &ChatHandler::HandleGoCreatureCommand, "", NULL }, { "graveyard", SEC_MODERATOR, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL }, { "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL }, { "object", SEC_MODERATOR, false, &ChatHandler::HandleGoObjectCommand, "", NULL }, { "taxinode", SEC_MODERATOR, false, &ChatHandler::HandleGoTaxinodeCommand, "", NULL }, { "trigger", SEC_MODERATOR, false, &ChatHandler::HandleGoTriggerCommand, "", NULL }, { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL }, { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL }, { "xyz", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL }, { "", SEC_MODERATOR, false, &ChatHandler::HandleGoCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand gobjectCommandTable[] = { { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectAddCommand, "", NULL }, { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectAnimationCommand, "", NULL }, { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectDeleteCommand, "", NULL }, { "lootstate", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectLootstateCommand, "", NULL }, { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectMoveCommand, "", NULL }, { "near", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectNearCommand, "", NULL }, { "state", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectStateCommand, "", NULL }, { "target", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTargetCommand, "", NULL }, { "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTurnCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand guildCommandTable[] = { { "create", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildCreateCommand, "", NULL }, { "delete", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildDeleteCommand, "", NULL }, { "invite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildInviteCommand, "", NULL }, { "uninvite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildUninviteCommand, "", NULL }, { "rank", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildRankCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand honorCommandTable[] = { { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddCommand, "", NULL }, { "addkill", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddKillCommand, "", NULL }, { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorShow, "", NULL }, { "update", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorUpdateCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand instanceCommandTable[] = { { "listbinds", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceListBindsCommand, "", NULL }, { "unbind", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceUnbindCommand, "", NULL }, { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleInstanceStatsCommand, "", NULL }, { "savedata", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand learnCommandTable[] = { { "all", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllCommand, "", NULL }, { "all_gm", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllGMCommand, "", NULL }, { "all_crafts", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllCraftsCommand, "", NULL }, { "all_default", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllDefaultCommand, "", NULL }, { "all_lang", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllLangCommand, "", NULL }, { "all_myclass", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyClassCommand, "", NULL }, { "all_myspells", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMySpellsCommand, "", NULL }, { "all_mytalents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyTalentsCommand, "", NULL }, { "all_recipes", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllRecipesCommand, "", NULL }, { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand listCommandTable[] = { { "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL }, { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListCreatureCommand, "", NULL }, { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListItemCommand, "", NULL }, { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListObjectCommand, "", NULL }, { "talents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListTalentsCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand lookupAccountCommandTable[] = { { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountEmailCommand, "", NULL }, { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountIpCommand, "", NULL }, { "name", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountNameCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand lookupPlayerCommandTable[] = { { "account", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL }, { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL }, { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand lookupCommandTable[] = { { "account", SEC_GAMEMASTER, true, NULL, "", lookupAccountCommandTable }, { "area", SEC_MODERATOR, true, &ChatHandler::HandleLookupAreaCommand, "", NULL }, { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupCreatureCommand, "", NULL }, { "event", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupEventCommand, "", NULL }, { "faction", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupFactionCommand, "", NULL }, { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemCommand, "", NULL }, { "itemset", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemSetCommand, "", NULL }, { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupObjectCommand, "", NULL }, { "quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupQuestCommand, "", NULL }, { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable }, { "pool", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPoolCommand, "", NULL }, { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL }, { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL }, { "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL }, { "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand mmapCommandTable[] = { { "path", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapPathCommand, "", NULL }, { "loc", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLocCommand, "", NULL }, { "loadedtiles", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLoadedTilesCommand, "", NULL }, { "stats", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapStatsCommand, "", NULL }, { "testarea", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestArea, "", NULL }, { "testheight", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestHeight, "", NULL }, { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMmap, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand modifyCommandTable[] = { { "hp", SEC_MODERATOR, false, &ChatHandler::HandleModifyHPCommand, "", NULL }, { "mana", SEC_MODERATOR, false, &ChatHandler::HandleModifyManaCommand, "", NULL }, { "rage", SEC_MODERATOR, false, &ChatHandler::HandleModifyRageCommand, "", NULL }, { "energy", SEC_MODERATOR, false, &ChatHandler::HandleModifyEnergyCommand, "", NULL }, { "money", SEC_MODERATOR, false, &ChatHandler::HandleModifyMoneyCommand, "", NULL }, { "speed", SEC_MODERATOR, false, &ChatHandler::HandleModifySpeedCommand, "", NULL }, { "swim", SEC_MODERATOR, false, &ChatHandler::HandleModifySwimCommand, "", NULL }, { "scale", SEC_MODERATOR, false, &ChatHandler::HandleModifyScaleCommand, "", NULL }, { "bwalk", SEC_MODERATOR, false, &ChatHandler::HandleModifyBWalkCommand, "", NULL }, { "aspeed", SEC_MODERATOR, false, &ChatHandler::HandleModifyASpeedCommand, "", NULL }, { "faction", SEC_MODERATOR, false, &ChatHandler::HandleModifyFactionCommand, "", NULL }, { "tp", SEC_MODERATOR, false, &ChatHandler::HandleModifyTalentCommand, "", NULL }, { "mount", SEC_MODERATOR, false, &ChatHandler::HandleModifyMountCommand, "", NULL }, { "honor", SEC_MODERATOR, false, &ChatHandler::HandleModifyHonorCommand, "", NULL }, { "rep", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyRepCommand, "", NULL }, { "drunk", SEC_MODERATOR, false, &ChatHandler::HandleModifyDrunkCommand, "", NULL }, { "standstate", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyStandStateCommand, "", NULL }, { "morph", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyMorphCommand, "", NULL }, { "gender", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyGenderCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand npcCommandTable[] = { { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL }, { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL }, { "aiinfo", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAIInfoCommand, "", NULL }, { "allowmove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAllowMovementCommand, "", NULL }, { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL }, { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL }, { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL }, { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorItemCommand, "", NULL }, { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL }, { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL }, { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL }, { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL }, { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL }, { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL }, { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL }, { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL }, { "spawndist", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnDistCommand, "", NULL }, { "spawntime", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnTimeCommand, "", NULL }, { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL }, { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL }, { "unfollow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcUnFollowCommand, "", NULL }, { "whisper", SEC_MODERATOR, false, &ChatHandler::HandleNpcWhisperCommand, "", NULL }, { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL }, { "tame", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTameCommand, "", NULL }, { "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL }, //{ TODO: fix or remove this commands { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL }, { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcNameCommand, "", NULL }, { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSubNameCommand, "", NULL }, //} { NULL, 0, false, NULL, "", NULL } }; static ChatCommand pdumpCommandTable[] = { { "load", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpLoadCommand, "", NULL }, { "write", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpWriteCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand poolCommandTable[] = { { "list", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolListCommand, "", NULL }, { "spawns", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolSpawnsCommand, "", NULL }, { "", SEC_GAMEMASTER, true, &ChatHandler::HandlePoolInfoCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand questCommandTable[] = { { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestAddCommand, "", NULL }, { "complete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestCompleteCommand, "", NULL }, { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestRemoveCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand reloadCommandTable[] = { { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllCommand, "", NULL }, { "all_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAreaCommand, "", NULL }, { "all_eventai", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllEventAICommand, "", NULL }, { "all_gossips", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllGossipsCommand, "", NULL }, { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL }, { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL }, { "all_loot", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLootCommand, "", NULL }, { "all_npc", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllNpcCommand, "", NULL }, { "all_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllQuestCommand, "", NULL }, { "all_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL }, { "all_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllSpellCommand, "", NULL }, { "config", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConfigCommand, "", NULL }, { "areatrigger_quest_end", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL }, { "areatrigger_tavern", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL }, { "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL }, { "autobroadcast", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAutoBroadcastCommand, "", NULL }, { "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL }, { "conditions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConditionsCommand, "", NULL }, { "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL }, { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL }, { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL }, { "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL }, { "creature_quest_end", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand, "", NULL }, { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_quest_start", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, { "creature_template_classlevelstats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreaturesStatsCommand, "", NULL }, { "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL }, { "dbscripts_on_creature_death", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnCreatureDeathCommand, "", NULL }, { "dbscripts_on_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnEventCommand, "", NULL }, { "dbscripts_on_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnGossipCommand, "", NULL }, { "dbscripts_on_go_use", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnGoUseCommand, "", NULL }, { "dbscripts_on_quest_end", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnQuestEndCommand, "", NULL }, { "dbscripts_on_quest_start", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnQuestStartCommand, "", NULL }, { "dbscripts_on_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDBScriptsOnSpellCommand, "", NULL }, { "disables", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDisablesCommand, "", NULL }, { "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL }, { "fishing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL }, { "game_graveyard_zone", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL }, { "game_tele", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameTeleCommand, "", NULL }, { "gameobject_quest_end", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestInvRelationsCommand, "", NULL }, { "gameobject_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesGameobjectCommand, "", NULL }, { "gameobject_quest_start", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL }, { "gameobject_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL }, { "gossip_menu", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuCommand, "", NULL }, { "gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuCommand, "", NULL }, { "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, { "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL }, { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL }, { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL }, { "locales_gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGossipMenuOptionCommand, "", NULL }, { "locales_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesItemCommand, "", NULL }, { "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL }, { "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL }, { "locales_points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPointsOfInterestCommand, "", NULL }, { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL }, { "locales_command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCommandHelpCommand, "", NULL }, { "mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMailCommand, "", NULL }, { "mangos_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMangosStringCommand, "", NULL }, { "npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTextCommand, "", NULL }, { "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, { "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, { "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, { "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand, "", NULL}, { "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "", NULL }, { "quest_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL }, { "reference_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL }, { "reserved_name", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReservedNameCommand, "", NULL }, { "reputation_reward_rate", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationRewardRateCommand, "", NULL }, { "reputation_spillover_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationSpilloverTemplateCommand, "", NULL }, { "script_binding", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadScriptBindingCommand, "", NULL }, { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, { "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, { "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL }, { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL }, { "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL }, { "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL }, { "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL }, { "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL }, { "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL }, { "spell_proc_item_enchant", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcItemEnchantCommand, "", NULL }, { "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL }, { "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand resetCommandTable[] = { { "honor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetHonorCommand, "", NULL }, { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetLevelCommand, "", NULL }, { "spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetSpellsCommand, "", NULL }, { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetStatsCommand, "", NULL }, { "talents", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetTalentsCommand, "", NULL }, { "items", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetItemsCommand, "", NULL }, { "mail", SEC_ADMINISTRATOR, false, &ChatHandler::HandleResetMailCommand, "", NULL }, { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetAllCommand, "", NULL }, { 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 }, { "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverIdleRestartCommandTable[] = { { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL }, { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleRestartCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverIdleShutdownCommandTable[] = { { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL }, { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleShutDownCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverRestartCommandTable[] = { { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL }, { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerRestartCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverShutdownCommandTable[] = { { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL }, { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverLogCommandTable[] = { { "filter", SEC_CONSOLE, true, &ChatHandler::HandleServerLogFilterCommand, "", NULL }, { "level", SEC_CONSOLE, true, &ChatHandler::HandleServerLogLevelCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverSetCommandTable[] = { { "motd", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetMotdCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand serverCommandTable[] = { { "corpses", SEC_GAMEMASTER, true, &ChatHandler::HandleServerCorpsesCommand, "", NULL }, { "exit", SEC_CONSOLE, true, &ChatHandler::HandleServerExitCommand, "", NULL }, { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable }, { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverIdleShutdownCommandTable }, { "info", SEC_PLAYER, true, &ChatHandler::HandleServerInfoCommand, "", NULL }, { "log", SEC_CONSOLE, true, NULL, "", serverLogCommandTable }, { "motd", SEC_PLAYER, true, &ChatHandler::HandleServerMotdCommand, "", NULL }, { "plimit", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerPLimitCommand, "", NULL }, { "resetallraid", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerResetAllRaidCommand, "", NULL }, { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable }, { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable }, { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand teleCommandTable[] = { { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleTeleAddCommand, "", NULL }, { "del", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTeleDelCommand, "", NULL }, { "name", SEC_MODERATOR, true, &ChatHandler::HandleTeleNameCommand, "", NULL }, { "group", SEC_MODERATOR, false, &ChatHandler::HandleTeleGroupCommand, "", NULL }, { "", SEC_MODERATOR, false, &ChatHandler::HandleTeleCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand ticketCommandTable[] = { { "accept", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTicketAcceptCommand, "", NULL }, { "close", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketCloseCommand, "", NULL }, { "delete", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTicketDeleteCommand, "", NULL }, { "info", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketInfoCommand, "", NULL }, { "list", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketListCommand, "", NULL }, { "meaccept", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketMeAcceptCommand, "", NULL }, { "onlinelist", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketOnlineListCommand, "", NULL }, { "respond", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketRespondCommand, "", NULL }, { "show", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketShowCommand, "", NULL }, { "surveyclose", SEC_GAMEMASTER, true, &ChatHandler::HandleTickerSurveyClose, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand triggerCommandTable[] = { { "active", SEC_GAMEMASTER, false, &ChatHandler::HandleTriggerActiveCommand, "", NULL }, { "near", SEC_GAMEMASTER, false, &ChatHandler::HandleTriggerNearCommand, "", NULL }, { "", SEC_GAMEMASTER, true, &ChatHandler::HandleTriggerCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand unbanCommandTable[] = { { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanAccountCommand, "", NULL }, { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanCharacterCommand, "", NULL }, { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanIPCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand wpCommandTable[] = { { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL }, { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL }, { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL }, { "export", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpExportCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = { { "account", SEC_PLAYER, true, NULL, "", accountCommandTable }, { "auction", SEC_ADMINISTRATOR, false, NULL, "", auctionCommandTable }, { "ahbot", SEC_ADMINISTRATOR, true, NULL, "", ahbotCommandTable }, { "cast", SEC_ADMINISTRATOR, false, NULL, "", castCommandTable }, { "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable}, { "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable }, { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable }, { "gm", SEC_PLAYER, true, NULL, "", gmCommandTable }, { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable }, { "go", SEC_MODERATOR, false, NULL, "", goCommandTable }, { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable }, { "guild", SEC_GAMEMASTER, true, NULL, "", guildCommandTable }, { "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable }, { "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable }, { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable }, { "lookup", SEC_MODERATOR, true, NULL, "", lookupCommandTable }, { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable }, { "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable }, { "pool", SEC_GAMEMASTER, true, NULL, "", poolCommandTable }, { "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable }, { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable }, { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable }, { "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable }, { "server", SEC_PLAYER, true, NULL, "", serverCommandTable }, { "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable }, { "trigger", SEC_GAMEMASTER, false, NULL, "", triggerCommandTable }, { "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable }, { "aura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuraCommand, "", NULL }, { "unaura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnAuraCommand, "", NULL }, { "announce", SEC_MODERATOR, true, &ChatHandler::HandleAnnounceCommand, "", NULL }, { "notify", SEC_MODERATOR, true, &ChatHandler::HandleNotifyCommand, "", NULL }, { "appear", SEC_MODERATOR, false, &ChatHandler::HandleAppearCommand, "", NULL }, { "summon", SEC_MODERATOR, false, &ChatHandler::HandleSummonCommand, "", NULL }, { "groupgo", SEC_MODERATOR, false, &ChatHandler::HandleGroupgoCommand, "", NULL }, { "commands", SEC_PLAYER, true, &ChatHandler::HandleCommandsCommand, "", NULL }, { "demorph", SEC_GAMEMASTER, false, &ChatHandler::HandleDeMorphCommand, "", NULL }, { "die", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDieCommand, "", NULL }, { "revive", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReviveCommand, "", NULL }, { "dismount", SEC_PLAYER, false, &ChatHandler::HandleDismountCommand, "", NULL }, { "gps", SEC_MODERATOR, false, &ChatHandler::HandleGPSCommand, "", NULL }, { "guid", SEC_GAMEMASTER, false, &ChatHandler::HandleGUIDCommand, "", NULL }, { "help", SEC_PLAYER, true, &ChatHandler::HandleHelpCommand, "", NULL }, { "itemmove", SEC_GAMEMASTER, false, &ChatHandler::HandleItemMoveCommand, "", NULL }, { "cooldown", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCooldownCommand, "", NULL }, { "unlearn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnLearnCommand, "", NULL }, { "distance", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGetDistanceCommand, "", NULL }, { "recall", SEC_MODERATOR, false, &ChatHandler::HandleRecallCommand, "", NULL }, { "save", SEC_PLAYER, false, &ChatHandler::HandleSaveCommand, "", NULL }, { "saveall", SEC_MODERATOR, true, &ChatHandler::HandleSaveAllCommand, "", NULL }, { "kick", SEC_GAMEMASTER, true, &ChatHandler::HandleKickPlayerCommand, "", NULL }, { "ban", SEC_ADMINISTRATOR, true, NULL, "", banCommandTable }, { "unban", SEC_ADMINISTRATOR, true, NULL, "", unbanCommandTable }, { "baninfo", SEC_ADMINISTRATOR, false, NULL, "", baninfoCommandTable }, { "banlist", SEC_ADMINISTRATOR, true, NULL, "", banlistCommandTable }, { "start", SEC_PLAYER, false, &ChatHandler::HandleStartCommand, "", NULL }, { "taxicheat", SEC_MODERATOR, false, &ChatHandler::HandleTaxiCheatCommand, "", NULL }, { "linkgrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLinkGraveCommand, "", NULL }, { "neargrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNearGraveCommand, "", NULL }, { "explorecheat", SEC_ADMINISTRATOR, false, &ChatHandler::HandleExploreCheatCommand, "", NULL }, { "levelup", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLevelUpCommand, "", NULL }, { "showarea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowAreaCommand, "", NULL }, { "hidearea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleHideAreaCommand, "", NULL }, { "additem", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddItemCommand, "", NULL }, { "additemset", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddItemSetCommand, "", NULL }, { "bank", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBankCommand, "", NULL }, { "wchange", SEC_ADMINISTRATOR, false, &ChatHandler::HandleChangeWeatherCommand, "", NULL }, { "ticket", SEC_GAMEMASTER, false, NULL, "", ticketCommandTable }, { "maxskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMaxSkillCommand, "", NULL }, { "setskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetSkillCommand, "", NULL }, { "whispers", SEC_MODERATOR, false, &ChatHandler::HandleWhispersCommand, "", NULL }, { "pinfo", SEC_GAMEMASTER, true, &ChatHandler::HandlePInfoCommand, "", NULL }, { "respawn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleRespawnCommand, "", NULL }, { "send", SEC_MODERATOR, true, NULL, "", sendCommandTable }, { "loadscripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadScriptsCommand, "", NULL }, { "mute", SEC_MODERATOR, true, &ChatHandler::HandleMuteCommand, "", NULL }, { "unmute", SEC_MODERATOR, true, &ChatHandler::HandleUnmuteCommand, "", NULL }, { "movegens", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMovegensCommand, "", NULL }, { "cometome", SEC_ADMINISTRATOR, false, &ChatHandler::HandleComeToMeCommand, "", NULL }, { "damage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDamageCommand, "", NULL }, { "combatstop", SEC_GAMEMASTER, false, &ChatHandler::HandleCombatStopCommand, "", NULL }, { "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL }, { "stable", SEC_ADMINISTRATOR, false, &ChatHandler::HandleStableCommand, "", NULL }, { "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL }, { "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL }, { "mmap", SEC_GAMEMASTER, false, NULL, "", mmapCommandTable }, { "spell_linked", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedCommand, "", NULL }, #ifdef ENABLE_PLAYERBOTS { "bot", SEC_PLAYER, false, &ChatHandler::HandlePlayerbotCommand, "", NULL }, { "rndbot", SEC_CONSOLE, true, &ChatHandler::HandlePlayerbotConsoleCommand, "", NULL }, { "ahbot", SEC_GAMEMASTER, true, &ChatHandler::HandleAhBotCommand, "", NULL }, #endif { NULL, 0, false, NULL, "", NULL } }; if (load_command_table) { load_command_table = false; // check hardcoded part integrity CheckIntegrity(commandTable, NULL); QueryResult* result = WorldDatabase.Query("SELECT `id`, `command_text`,`security`,`help_text` FROM `command`"); if (result) { do { Field* fields = result->Fetch(); uint32 id = fields[0].GetUInt32(); std::string name = fields[1].GetCppString(); SetDataForCommandInTable(commandTable, id, name.c_str(), fields[2].GetUInt16(), fields[3].GetCppString()); } while (result->NextRow()); delete result; } } return commandTable; } ChatHandler::ChatHandler(WorldSession* session) : m_session(session) {} ChatHandler::ChatHandler(Player* player) : m_session(player->GetSession()) {} ChatHandler::~ChatHandler() {} const char* ChatHandler::GetMangosString(int32 entry) const { return m_session->GetMangosString(entry); } const char* ChatHandler::GetOnOffStr(bool value) const { return value ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF); } uint32 ChatHandler::GetAccountId() const { return m_session->GetAccountId(); } AccountTypes ChatHandler::GetAccessLevel() const { return m_session->GetSecurity(); } bool ChatHandler::isAvailable(ChatCommand const& cmd) const { // check security level only for simple command (without child commands) return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel; } std::string ChatHandler::GetNameLink() const { return GetNameLink(m_session->GetPlayer()); } bool ChatHandler::HasLowerSecurity(Player* target, ObjectGuid guid, bool strong) { WorldSession* target_session = NULL; uint32 target_account = 0; if (target) { target_session = target->GetSession(); } else { target_account = sObjectMgr.GetPlayerAccountIdByGUID(guid); } if (!target_session && !target_account) { SendSysMessage(LANG_PLAYER_NOT_FOUND); SetSentErrorMessage(true); return true; } return HasLowerSecurityAccount(target_session, target_account, strong); } bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_account, bool strong) { AccountTypes target_sec; // ignore only for non-players for non strong checks (when allow apply command at least to same sec level) if (GetAccessLevel() > SEC_PLAYER && !strong && !sWorld.getConfig(CONFIG_BOOL_GM_LOWER_SECURITY)) { return false; } if (target) { target_sec = target->GetSecurity(); } else if (target_account) { target_sec = sAccountMgr.GetSecurity(target_account); } else { return true; } // caller must report error for (target==NULL && target_account==0) if (GetAccessLevel() < target_sec || (strong && GetAccessLevel() <= target_sec)) { SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); SetSentErrorMessage(true); return true; } return false; } bool ChatHandler::hasStringAbbr(const char* name, const char* part) { // non "" command if (*name) { // "" part from non-"" command if (!*part) { return false; } for (;;) { if (!*part) { return true; } else if (!*name) { return false; } else if (tolower(*name) != tolower(*part)) { return false; } ++name; ++part; } } // allow with any for "" return true; } void ChatHandler::SendSysMessage(const char* str) { WorldPacket data; // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = mangos_strdup(str); char* pos = buf; while (char* line = LineFromMessage(pos)) { // m_session == null when we're accessing these command from the console. ObjectGuid senderGuid; if (m_session) senderGuid = m_session->GetPlayer()->GetObjectGuid(); ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, senderGuid); m_session->SendPacket(&data); } delete[] buf; } void ChatHandler::SendGlobalSysMessage(const char* str, AccountTypes minSec) { // Chat output WorldPacket data; // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = mangos_strdup(str); char* pos = buf; ObjectGuid senderGuid = m_session ? m_session->GetPlayer()->GetObjectGuid() : ObjectGuid(); while (char* line = LineFromMessage(pos)) { ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, senderGuid); sWorld.SendGlobalMessage(&data, minSec); } delete[] buf; } void ChatHandler::SendSysMessage(int32 entry) { SendSysMessage(GetMangosString(entry)); } void ChatHandler::PSendSysMessage(int32 entry, ...) { const char* format = GetMangosString(entry); va_list ap; char str [2048]; va_start(ap, entry); vsnprintf(str, 2048, format, ap); va_end(ap); SendSysMessage(str); } void ChatHandler::PSendSysMessageMultiline(int32 entry, ...) { uint32 linecount = 0; const char* format = GetMangosString(entry); va_list ap; char str[2048]; va_start(ap, entry); vsnprintf(str, 2048, format, ap); va_end(ap); std::string mangosString(str); /* Used for tracking our position within the string while iterating through it */ std::string::size_type pos = 0, nextpos; /* Find the next occurance of @ in the string * This is how newlines are represented */ while ((nextpos = mangosString.find("@@", pos)) != std::string::npos) { /* If these are not equal, it means a '@@' was found * These are used to represent newlines in the string * It is set by the code above here */ if (nextpos != pos) { /* Send the player a system message containing the substring from pos to nextpos - pos */ PSendSysMessage("%s", mangosString.substr(pos, nextpos - pos).c_str()); ++linecount; } pos = nextpos + 2; // +2 because there are two @ as delimiter } /* There are no more newlines in our mangosString, so we send whatever is left */ if (pos < mangosString.length()) { PSendSysMessage("%s", mangosString.substr(pos).c_str()); } } void ChatHandler::PSendSysMessage(const char* format, ...) { va_list ap; char str [2048]; va_start(ap, format); vsnprintf(str, 2048, format, ap); va_end(ap); SendSysMessage(str); } void ChatHandler::CheckIntegrity(ChatCommand* table, ChatCommand* parentCommand) { for (uint32 i = 0; table[i].Name != NULL; ++i) { ChatCommand* command = &table[i]; if (parentCommand && command->SecurityLevel < parentCommand->SecurityLevel) sLog.outError("Subcommand '%s' of command '%s' have less access level (%u) that parent (%u)", command->Name, parentCommand->Name, command->SecurityLevel, parentCommand->SecurityLevel); if (!parentCommand && strlen(command->Name) == 0) { sLog.outError("Subcommand '' at top level"); } if (command->ChildCommands) { if (command->Handler) { if (parentCommand) sLog.outError("Subcommand '%s' of command '%s' have handler and subcommands in same time, must be used '' subcommand for handler instead.", command->Name, parentCommand->Name); else sLog.outError("First level command '%s' have handler and subcommands in same time, must be used '' subcommand for handler instead.", command->Name); } if (parentCommand && strlen(command->Name) == 0) { sLog.outError("Subcommand '' of command '%s' have subcommands", parentCommand->Name); } CheckIntegrity(command->ChildCommands, command); } else if (!command->Handler) { if (parentCommand) sLog.outError("Subcommand '%s' of command '%s' not have handler and subcommands in same time. Must have some from its!", command->Name, parentCommand->Name); else sLog.outError("First level command '%s' not have handler and subcommands in same time. Must have some from its!", command->Name); } } } /** * Search (sub)command for command line available for chat handler access level * * @param text Command line string that will parsed for (sub)command search * * @return Pointer to found command structure or NULL if appropriate command not found */ ChatCommand const* ChatHandler::FindCommand(char const* text) { ChatCommand* command = NULL; char const* textPtr = text; return FindCommand(getCommandTable(), textPtr, command) == CHAT_COMMAND_OK ? command : NULL; } /** * Search (sub)command for command line available for chat handler access level with options and fail case additional info * * @param table Pointer to command C-style array first level command where will be searched * @param text Command line string that will parsed for (sub)command search, * it modified at return from function and pointed to not parsed tail * @param command At success this is found command, at other cases this is last found parent command * before subcommand search fail * @param parentCommand Output arg for optional return parent command for command arg. * @param cmdNamePtr Output arg for optional return last parsed command name. * @param allAvailable Optional arg (with false default value) control use command access level checks while command search. * @param exactlyName Optional arg (with false default value) control use exactly name in checks while command search. * * @return one from enum value of ChatCommandSearchResult. Output args return values highly dependent from this return result: * * CHAT_COMMAND_OK - Command found! * text point to non parsed tail with possible command specific data, command store found command pointer, * parentCommand have parent of found command or NULL if command found in table array directly * cmdNamePtr store found command name in original form from command line * CHAT_COMMAND_UNKNOWN - Command not found in table directly * text only skip possible whitespaces, * command is NULL * parentCommand is NULL * cmdNamePtr store command name that not found as it extracted from command line * CHAT_COMMAND_UNKNOWN_SUBCOMMAND - Subcommand not found in some deed subcomand lists * text point to non parsed tail including not found command name in command line, * command store last found parent command if any * parentCommand have parent of command in command arg or NULL * cmdNamePtr store command name that not found as it extracted from command line */ ChatCommandSearchResult ChatHandler::FindCommand(ChatCommand* table, char const*& text, ChatCommand*& command, ChatCommand** parentCommand /*= NULL*/, std::string* cmdNamePtr /*= NULL*/, bool allAvailable /*= false*/, bool exactlyName /*= false*/) { std::string cmd = ""; // skip whitespaces while (*text != ' ' && *text != '\0') { cmd += *text; ++text; } while (*text == ' ') { ++text; } // search first level command in table for (uint32 i = 0; table[i].Name != NULL; ++i) { if (exactlyName) { size_t len = strlen(table[i].Name); if (strncmp(table[i].Name, cmd.c_str(), len + 1) != 0) { continue; } } else { if (!hasStringAbbr(table[i].Name, cmd.c_str())) { continue; } } // select subcommand from child commands list if (table[i].ChildCommands != NULL) { char const* oldchildtext = text; ChatCommand* parentSubcommand = NULL; ChatCommandSearchResult res = FindCommand(table[i].ChildCommands, text, command, &parentSubcommand, cmdNamePtr, allAvailable, exactlyName); switch (res) { case CHAT_COMMAND_OK: { // if subcommand success search not return parent command, then this parent command is owner of child commands if (parentCommand) { *parentCommand = parentSubcommand ? parentSubcommand : &table[i]; } // Name == "" is special case: restore original command text for next level "" (where parentSubcommand==NULL) if (strlen(command->Name) == 0 && !parentSubcommand) { text = oldchildtext; } return CHAT_COMMAND_OK; } case CHAT_COMMAND_UNKNOWN: { // command not found directly in child command list, return child command list owner command = &table[i]; if (parentCommand) { *parentCommand = NULL; } // we don't known parent of table list at this point text = oldchildtext; // restore text to stated just after parse found parent command return CHAT_COMMAND_UNKNOWN_SUBCOMMAND; // we not found subcommand for table[i] } case CHAT_COMMAND_UNKNOWN_SUBCOMMAND: default: { // some deep subcommand not found, if this second level subcommand then parentCommand can be NULL, use known value for it if (parentCommand) { *parentCommand = parentSubcommand ? parentSubcommand : &table[i]; } return res; } } } // must be available (not checked for subcommands case because parent command expected have most low access that all subcommands always if (!allAvailable && !isAvailable(table[i])) { continue; } // must be have handler is explicitly selected if (!table[i].Handler) { continue; } // command found directly in to table command = &table[i]; // unknown table owner at this point if (parentCommand) { *parentCommand = NULL; } if (cmdNamePtr) { *cmdNamePtr = cmd; } return CHAT_COMMAND_OK; } // command not found in table directly command = NULL; // unknown table owner at this point if (parentCommand) { *parentCommand = NULL; } if (cmdNamePtr) { *cmdNamePtr = cmd; } return CHAT_COMMAND_UNKNOWN; } /** * Execute (sub)command available for chat handler access level with options in command line string * * @param text Command line string that will parsed for (sub)command search and command specific data * * Command output and errors in command execution will send to chat handler. */ void ChatHandler::ExecuteCommand(const char* text) { std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing. ChatCommand* command = NULL; ChatCommand* parentCommand = NULL; ChatCommandSearchResult res = FindCommand(getCommandTable(), text, command, &parentCommand); switch (res) { case CHAT_COMMAND_OK: { SetSentErrorMessage(false); if ((this->*(command->Handler))((char*)text)) // text content destroyed at call { if (command->SecurityLevel > SEC_PLAYER) { LogCommand(fullcmd.c_str()); } } // some commands have custom error messages. Don't send the default one in these cases. else if (!HasSentErrorMessage()) { if (!command->Help.empty()) { std::string helpText = command->Help; // Attemp to localize help text if not in CLI mode if (m_session) { int loc_idx = m_session->GetSessionDbLocaleIndex(); sCommandMgr.GetCommandHelpLocaleString(command->Id, loc_idx, &helpText); } SendSysMessage(helpText.c_str()); } else { SendSysMessage(LANG_CMD_SYNTAX); } if (ChatCommand* showCommand = (strlen(command->Name) == 0 && parentCommand ? parentCommand : command)) if (ChatCommand* childs = showCommand->ChildCommands) { ShowHelpForSubCommands(childs, showCommand->Name); } SetSentErrorMessage(true); } break; } case CHAT_COMMAND_UNKNOWN_SUBCOMMAND: { #ifdef ENABLE_ELUNA if (!sEluna->OnCommand(m_session ? m_session->GetPlayer() : NULL, fullcmd.c_str())) { return; } #endif /* ENABLE_ELUNA */ SendSysMessage(LANG_NO_SUBCMD); ShowHelpForCommand(command->ChildCommands, text); SetSentErrorMessage(true); break; } case CHAT_COMMAND_UNKNOWN: { #ifdef ENABLE_ELUNA if (!sEluna->OnCommand(m_session ? m_session->GetPlayer() : NULL, fullcmd.c_str())) { return; } #endif /* ENABLE_ELUNA */ SendSysMessage(LANG_NO_CMD); SetSentErrorMessage(true); break; } } } /** * Function find appropriate command and update command security level and help text * * @param commandTable Table for first level command search * @param text Command line string that will parsed for (sub)command search * @param security New security level for command * @param help New help text for command * * @return true if command has been found, and false in other case * * All problems found while command search and updated output as to DB errors log */ bool ChatHandler::SetDataForCommandInTable(ChatCommand* commandTable, uint32 id, const char* text, uint32 security, std::string const& help) { std::string fullcommand = text; // original `text` can't be used. It content destroyed in command code processing. ChatCommand* command = NULL; std::string cmdName; ChatCommandSearchResult res = FindCommand(commandTable, text, command, NULL, &cmdName, true, true); switch (res) { case CHAT_COMMAND_OK: { if (command->SecurityLevel != security) DETAIL_LOG("Table `command` overwrite for command '%s' default security (%u) by %u", fullcommand.c_str(), command->SecurityLevel, security); command->Id = id; command->SecurityLevel = security; command->Help = help; return true; } case CHAT_COMMAND_UNKNOWN_SUBCOMMAND: { // command have subcommands, but not '' subcommand and then any data in `command` useless for it. if (cmdName.empty()) { sLog.outErrorDb("Table `command` have command '%s' that only used with some subcommand selection, it can't have help or overwritten access level, skip.", cmdName.c_str()); } else { sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.", cmdName.c_str(), fullcommand.c_str()); } return false; } case CHAT_COMMAND_UNKNOWN: { sLog.outErrorDb("Table `command` have nonexistent command '%s', skip.", cmdName.c_str()); return false; } } return false; } bool ChatHandler::ParseCommands(const char* text) { MANGOS_ASSERT(text); MANGOS_ASSERT(*text); /// chat case (.command or !command format) if (m_session) { if (m_session->GetSecurity() == SEC_PLAYER && !sWorld.getConfig(CONFIG_BOOL_PLAYER_COMMANDS)) { return false; } if (text[0] != '!' && text[0] != '.') { return false; } /// ignore single . and ! in line if (strlen(text) < 2) { return false; } } /// ignore messages staring from many dots. if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!')) { return false; } /// skip first . or ! (in console allowed use command with . and ! and without its) if (text[0] == '!' || text[0] == '.') { ++text; } ExecuteCommand(text); return true; } bool ChatHandler::ShowHelpForSubCommands(ChatCommand* table, char const* cmd) { std::string list; for (uint32 i = 0; table[i].Name != NULL; ++i) { // must be available (ignore handler existence for show command with possible available subcommands if (!isAvailable(table[i])) { continue; } if (m_session) { list += "\n "; } else { list += "\n\r "; } list += table[i].Name; if (table[i].ChildCommands) { list += " ..."; } } if (list.empty()) { return false; } if (table == getCommandTable()) { SendSysMessage(LANG_AVIABLE_CMD); SendSysMessage(list.c_str()); } else { PSendSysMessage(LANG_SUBCMDS_LIST, cmd); SendSysMessage(list.c_str()); } return true; } bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd) { char const* oldCmd = cmd; ChatCommand* command = NULL; ChatCommand* parentCommand = NULL; ChatCommand* showCommand = NULL; ChatCommand* childCommands = NULL; ChatCommandSearchResult res = FindCommand(table, cmd, command, &parentCommand); switch (res) { case CHAT_COMMAND_OK: { // for "" subcommand use parent command if any for subcommands list output if (strlen(command->Name) == 0 && parentCommand) { showCommand = parentCommand; cmd = ""; } else { showCommand = command; } childCommands = showCommand->ChildCommands; break; } case CHAT_COMMAND_UNKNOWN_SUBCOMMAND: showCommand = command; childCommands = showCommand->ChildCommands; break; case CHAT_COMMAND_UNKNOWN: // not show command list at error in first level command find fail childCommands = table != getCommandTable() || strlen(oldCmd) == 0 ? table : NULL; command = NULL; break; } if (command && !command->Help.empty()) { std::string helpText = command->Help; // Attemp to localize help text if not in CLI mode if (m_session) { int loc_idx = m_session->GetSessionDbLocaleIndex(); sCommandMgr.GetCommandHelpLocaleString(command->Id, loc_idx, &helpText); } SendSysMessage(helpText.c_str()); } if (childCommands) if (ShowHelpForSubCommands(childCommands, showCommand ? showCommand->Name : "")) { return true; } if (command && command->Help.empty()) { SendSysMessage(LANG_NO_HELP_CMD); } return command || childCommands; } bool ChatHandler::isValidChatMessage(const char* message) { /* valid examples: |cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r |cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r |cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r |cff71d5ff|Hspell:21563|h[Command]|h|r |cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r | will be escaped to || */ if (strlen(message) > 255) { return false; } const char validSequence[6] = "cHhhr"; const char* validSequenceIterator = validSequence; // more simple checks if (sWorld.getConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3) { const std::string validCommands = "cHhr|"; while (*message) { // find next pipe command message = strchr(message, '|'); if (!message) { return true; } ++message; char commandChar = *message; if (validCommands.find(commandChar) == std::string::npos) { return false; } ++message; // validate sequence if (sWorld.getConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2) { if (commandChar == *validSequenceIterator) { if (validSequenceIterator == validSequence + 4) { validSequenceIterator = validSequence; } else { ++validSequenceIterator; } } else if (commandChar != '|') { return false; } } } return true; } std::istringstream reader(message); char buffer[256]; uint32 color = 0; ItemPrototype const* linkedItem = NULL; Quest const* linkedQuest = NULL; SpellEntry const* linkedSpell = NULL; ItemRandomPropertiesEntry const* itemProperty = NULL; while (!reader.eof()) { if (validSequence == validSequenceIterator) { linkedItem = NULL; linkedQuest = NULL; linkedSpell = NULL; itemProperty = NULL; reader.ignore(255, '|'); } else if (reader.get() != '|') { DEBUG_LOG("ChatHandler::isValidChatMessage sequence aborted unexpectedly"); return false; } // pipe has always to be followed by at least one char if (reader.peek() == '\0') { DEBUG_LOG("ChatHandler::isValidChatMessage pipe followed by \\0"); return false; } // no further pipe commands if (reader.eof()) { break; } char commandChar; reader >> commandChar; // | in normal messages is escaped by || if (commandChar != '|') { if (commandChar == *validSequenceIterator) { if (validSequenceIterator == validSequence + 4) { validSequenceIterator = validSequence; } else { ++validSequenceIterator; } } else { DEBUG_LOG("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar); return false; } } else if (validSequence != validSequenceIterator) { // no escaped pipes in sequences DEBUG_LOG("ChatHandler::isValidChatMessage got escaped pipe in sequence"); return false; } switch (commandChar) { case 'c': color = 0; // validate color, expect 8 hex chars for (int i = 0; i < 8; ++i) { char c; reader >> c; if (!c) { DEBUG_LOG("ChatHandler::isValidChatMessage got \\0 while reading color in |c command"); return false; } color <<= 4; // check for hex char if (c >= '0' && c <= '9') { color |= c - '0'; continue; } if (c >= 'a' && c <= 'f') { color |= 10 + c - 'a'; continue; } DEBUG_LOG("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c); return false; } break; case 'H': // read chars up to colon = link type reader.getline(buffer, 256, ':'); if (reader.eof()) // : must be { return false; } if (strcmp(buffer, "item") == 0) { // read item entry reader.getline(buffer, 256, ':'); if (reader.eof()) // : must be { return false; } linkedItem = ObjectMgr::GetItemPrototype(atoi(buffer)); if (!linkedItem) { DEBUG_LOG("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer)); return false; } if (color != ItemQualityColors[linkedItem->Quality]) { DEBUG_LOG("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality], color); return false; } // the itementry is followed by several integers which describe an instance of this item // position relative after itemEntry const uint8 randomPropertyPosition = 6; int32 propertyId = 0; bool negativeNumber = false; char c; for (uint8 i = 0; i < randomPropertyPosition; ++i) { propertyId = 0; negativeNumber = false; while ((c = reader.get()) != ':') { if (c >= '0' && c <= '9') { propertyId *= 10; propertyId += c - '0'; } else if (c == '-') { negativeNumber = true; } else { return false; } } } if (negativeNumber) { propertyId *= -1; } if (propertyId > 0) { itemProperty = sItemRandomPropertiesStore.LookupEntry(propertyId); if (!itemProperty) { return false; } } // ignore other integers while ((c >= '0' && c <= '9') || c == ':') { reader.ignore(1); c = reader.peek(); } } else if (strcmp(buffer, "quest") == 0) { // no color check for questlinks, each client will adapt it anyway uint32 questid = 0; // read questid char c = reader.peek(); while (c >= '0' && c <= '9') { reader.ignore(1); questid *= 10; questid += c - '0'; c = reader.peek(); } linkedQuest = sObjectMgr.GetQuestTemplate(questid); if (!linkedQuest) { DEBUG_LOG("ChatHandler::isValidChatMessage Questtemplate %u not found", questid); return false; } if (c != ':') { DEBUG_LOG("ChatHandler::isValidChatMessage Invalid quest link structure"); return false; } reader.ignore(1); c = reader.peek(); // level uint32 questlevel = 0; while (c >= '0' && c <= '9') { reader.ignore(1); questlevel *= 10; questlevel += c - '0'; c = reader.peek(); } if (questlevel >= STRONG_MAX_LEVEL) { DEBUG_LOG("ChatHandler::isValidChatMessage Quest level %u too big", questlevel); return false; } if (c != '|') { DEBUG_LOG("ChatHandler::isValidChatMessage Invalid quest link structure"); return false; } } else if (strcmp(buffer, "talent") == 0) { // talent links are always supposed to be blue if (color != CHAT_LINK_COLOR_TALENT) { return false; } // read talent entry reader.getline(buffer, 256, ':'); if (reader.eof()) // : must be { return false; } TalentEntry const* talentInfo = sTalentStore.LookupEntry(atoi(buffer)); if (!talentInfo) { return false; } linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]); if (!linkedSpell) { return false; } char c = reader.peek(); // skillpoints? whatever, drop it while (c != '|' && c != '\0') { reader.ignore(1); c = reader.peek(); } } else if (strcmp(buffer, "spell") == 0) { if (color != CHAT_LINK_COLOR_SPELL) { return false; } uint32 spellid = 0; // read spell entry char c = reader.peek(); while (c >= '0' && c <= '9') { reader.ignore(1); spellid *= 10; spellid += c - '0'; c = reader.peek(); } linkedSpell = sSpellStore.LookupEntry(spellid); if (!linkedSpell) { return false; } } else if (strcmp(buffer, "enchant") == 0) { if (color != CHAT_LINK_COLOR_ENCHANT) { return false; } uint32 spellid = 0; // read spell entry char c = reader.peek(); while (c >= '0' && c <= '9') { reader.ignore(1); spellid *= 10; spellid += c - '0'; c = reader.peek(); } linkedSpell = sSpellStore.LookupEntry(spellid); if (!linkedSpell) { return false; } } else { DEBUG_LOG("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer); return false; } break; case 'h': // if h is next element in sequence, this one must contain the linked text :) if (*validSequenceIterator == 'h') { // links start with '[' if (reader.get() != '[') { DEBUG_LOG("ChatHandler::isValidChatMessage link caption doesn't start with '['"); return false; } reader.getline(buffer, 256, ']'); if (reader.eof()) // ] must be { return false; } // verify the link name if (linkedSpell) { // spells with that flag have a prefix of "$PROFESSION: " if (linkedSpell->HasAttribute(SPELL_ATTR_TRADESPELL)) { // lookup skillid SkillLineAbilityMapBounds bounds = sSpellMgr.GetSkillLineAbilityMapBounds(linkedSpell->Id); if (bounds.first == bounds.second) { return false; } SkillLineAbilityEntry const* skillInfo = bounds.first->second; if (!skillInfo) { return false; } SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId); if (!skillLine) { return false; } for (uint8 i = 0; i < MAX_LOCALE; ++i) { uint32 skillLineNameLength = strlen(skillLine->name[i]); if (skillLineNameLength > 0 && strncmp(skillLine->name[i], buffer, skillLineNameLength) == 0) { // found the prefix, remove it to perform spellname validation below // -2 = strlen(": ") uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2; memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1); } } } bool foundName = false; for (uint8 i = 0; i < MAX_LOCALE; ++i) { if (*linkedSpell->SpellName[i] && strcmp(linkedSpell->SpellName[i], buffer) == 0) { foundName = true; break; } } if (!foundName) { return false; } } else if (linkedQuest) { if (linkedQuest->GetTitle() != buffer) { QuestLocale const* ql = sObjectMgr.GetQuestLocale(linkedQuest->GetQuestId()); if (!ql) { DEBUG_LOG("ChatHandler::isValidChatMessage default questname didn't match and there is no locale"); return false; } bool foundName = false; for (uint8 i = 0; i < ql->Title.size(); ++i) { if (ql->Title[i] == buffer) { foundName = true; break; } } if (!foundName) { DEBUG_LOG("ChatHandler::isValidChatMessage no quest locale title matched"); return false; } } } else if (linkedItem) { std::string expectedName = std::string(linkedItem->Name1); if (expectedName != buffer) { ItemLocale const* il = sObjectMgr.GetItemLocale(linkedItem->ItemId); bool foundName = false; for (uint8 i = LOCALE_koKR; i < MAX_LOCALE; ++i) { int8 dbIndex = sObjectMgr.GetIndexForLocale(LocaleConstant(i)); if (dbIndex == -1 || il == NULL || (size_t)dbIndex >= il->Name.size()) // using strange database/client combinations can lead to this case { expectedName = linkedItem->Name1; } else { expectedName = il->Name[dbIndex]; } if (expectedName == buffer) { foundName = true; break; } } if (!foundName) { DEBUG_LOG("ChatHandler::isValidChatMessage linked item name wasn't found in any localization"); return false; } } } // that place should never be reached - if nothing linked has been set in |H // it will return false before else { return false; } } break; case 'r': case '|': // no further payload break; default: DEBUG_LOG("ChatHandler::isValidChatMessage got invalid command |%c", commandChar); return false; } } // check if every opened sequence was also closed properly if (validSequence != validSequenceIterator) { DEBUG_LOG("ChatHandler::isValidChatMessage EOF in active sequence"); } return validSequence == validSequenceIterator; } Player* ChatHandler::getSelectedPlayer() { if (!m_session) { return NULL; } ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid(); if (!guid) { return m_session->GetPlayer(); } return sObjectMgr.GetPlayer(guid); } Unit* ChatHandler::getSelectedUnit() { if (!m_session) { return NULL; } ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid(); if (!guid) { return m_session->GetPlayer(); } // can be selected player at another map return sObjectAccessor.GetUnit(*m_session->GetPlayer(), guid); } Creature* ChatHandler::getSelectedCreature() { if (!m_session) { return NULL; } return m_session->GetPlayer()->GetMap()->GetAnyTypeCreature(m_session->GetPlayer()->GetSelectionGuid()); } /** * Function skip all whitespaces in args string * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * allowed NULL string pointer stored in *args */ void ChatHandler::SkipWhiteSpaces(char** args) { if (!*args) { return; } while (isWhiteSpace(**args)) { ++(*args); } } /** * Function extract to val arg signed integer value or fail * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @return true if value extraction successful */ bool ChatHandler::ExtractInt32(char** args, int32& val) { if (!*args || !** args) { return false; } char* tail = *args; long valRaw = strtol(*args, &tail, 10); if (tail != *args && isWhiteSpace(*tail)) { *(tail++) = '\0'; } else if (tail && *tail) // some not whitespace symbol { return false; } // args not modified and can be re-parsed if (valRaw < std::numeric_limits::min() || valRaw > std::numeric_limits::max()) { return false; } // value successfully extracted val = int32(valRaw); *args = tail; return true; } /** * Function extract to val arg optional signed integer value or use default value. Fail if extracted not signed integer. * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @param defVal default value used if no data for extraction in args * @return true if value extraction successful */ bool ChatHandler::ExtractOptInt32(char** args, int32& val, int32 defVal) { if (!*args || !** args) { val = defVal; return true; } return ExtractInt32(args, val); } /** * Function extract to val arg unsigned integer value or fail * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @param base set used base for extracted value format (10 for decimal, 16 for hex, etc), 0 let auto select by system internal function * @return true if value extraction successful */ bool ChatHandler::ExtractUInt32Base(char** args, uint32& val, uint32 base) { if (!*args || !** args) { return false; } char* tail = *args; unsigned long valRaw = strtoul(*args, &tail, base); if (tail != *args && isWhiteSpace(*tail)) { *(tail++) = '\0'; } else if (tail && *tail) // some not whitespace symbol { return false; } // args not modified and can be re-parsed if (valRaw > std::numeric_limits::max()) { return false; } // value successfully extracted val = uint32(valRaw); *args = tail; SkipWhiteSpaces(args); return true; } /** * Function extract to val arg optional unsigned integer value or use default value. Fail if extracted not unsigned integer. * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @param defVal default value used if no data for extraction in args * @return true if value extraction successful */ bool ChatHandler::ExtractOptUInt32(char** args, uint32& val, uint32 defVal) { if (!*args || !** args) { val = defVal; return true; } return ExtractUInt32(args, val); } /** * Function extract to val arg float value or fail * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @return true if value extraction successful */ bool ChatHandler::ExtractFloat(char** args, float& val) { if (!*args || !** args) { return false; } char* tail = *args; double valRaw = strtod(*args, &tail); if (tail != *args && isWhiteSpace(*tail)) { *(tail++) = '\0'; } else if (tail && *tail) // some not whitespace symbol { return false; } // args not modified and can be re-parsed // value successfully extracted val = float(valRaw); *args = tail; SkipWhiteSpaces(args); return true; } /** * Function extract to val arg optional float value or use default value. Fail if extracted not float. * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @param defVal default value used if no data for extraction in args * @return true if value extraction successful */ bool ChatHandler::ExtractOptFloat(char** args, float& val, float defVal) { if (!*args || !** args) { val = defVal; return true; } return ExtractFloat(args, val); } /** * Function extract name-like string (from non-numeric or special symbol until whitespace) * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param lit optional explicit literal requirement. function fail if literal is not starting substring of lit. * Note: function in same way fail if no any literal or literal not fit in this case. Need additional check for select specific fail case * @return name/number-like string without whitespaces, or NULL if args empty or not appropriate content. */ char* ChatHandler::ExtractLiteralArg(char** args, char const* lit /*= NULL*/) { if (!*args || !** args) { return NULL; } char* head = *args; // reject quoted string or link (|-started text) switch (head[0]) { // reject quoted string case '[': case '\'': case '"': return NULL; // reject link (|-started text) case '|': // client replace all | by || in raw text if (head[1] != '|') { return NULL; } ++head; // skip one | break; default: break; } if (lit) { int l = strlen(lit); int largs = 0; while (head[largs] && !isWhiteSpace(head[largs])) { ++largs; } if (largs < l) { l = largs; } int diff = strncmp(head, lit, l); if (diff != 0) { return NULL; } if (head[l] && !isWhiteSpace(head[l])) { return NULL; } char* arg = head; if (head[l]) { head[l] = '\0'; head += l + 1; *args = head; } else { *args = head + l; } SkipWhiteSpaces(args); return arg; } char* name = strtok(head, " "); char* tail = strtok(NULL, ""); *args = tail ? tail : (char*)""; // *args don't must be NULL SkipWhiteSpaces(args); return name; } /** * Function extract quote-like string (any characters guarded by some special character, in our cases ['") * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param asis control save quote string wrappers * @return quote-like string, or NULL if args empty or not appropriate content. */ char* ChatHandler::ExtractQuotedArg(char** args, bool asis /*= false*/) { if (!*args || !** args) { return NULL; } if (**args != '\'' &&** args != '"' &&** args != '[') { return NULL; } char guard = (*args)[0]; if (guard == '[') { guard = ']'; } char* tail = (*args) + 1; // start scan after first quote symbol char* head = asis ? *args : tail; // start arg while (*tail && *tail != guard) { ++tail; } if (!*tail || (tail[1] && !isWhiteSpace(tail[1]))) // fail { return NULL; } if (!tail[1]) // quote is last char in string { if (!asis) { *tail = '\0'; } } else // quote isn't last char { if (asis) { ++tail; } *tail = '\0'; } *args = tail + 1; SkipWhiteSpaces(args); return head; } /** * Function extract quote-like string or literal if quote not detected * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param asis control save quote string wrappers * @return quote/literal string, or NULL if args empty or not appropriate content. */ char* ChatHandler::ExtractQuotedOrLiteralArg(char** args, bool asis /*= false*/) { char* arg = ExtractQuotedArg(args, asis); if (!arg) { arg = ExtractLiteralArg(args); } return arg; } /** * Function extract on/off literals as boolean values * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param val return extracted value if function success, in fail case original value unmodified * @return true at success */ bool ChatHandler::ExtractOnOff(char** args, bool& value) { char* arg = ExtractLiteralArg(args); if (!arg) { return false; } if (strncmp(arg, "on", 3) == 0) { value = true; } else if (strncmp(arg, "off", 4) == 0) { value = false; } else { return false; } return true; } /** * Function extract shift-link-like string (any characters guarded by | and |h|r with some additional internal structure check) * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * * @param linkTypes optional NULL-terminated array of link types, shift-link must fit one from link type from array if provided or extraction fail * * @param found_idx if not NULL then at return index in linkTypes that fit shift-link type, if extraction fail then non modified * * @param keyPair if not NULL then pointer to 2-elements array for return start and end pointer for found key * if extraction fail then non modified * * @param somethingPair then pointer to 2-elements array for return start and end pointer if found. * if not NULL then shift-link must have data field, if extraction fail then non modified * * @return shift-link-like string, or NULL if args empty or not appropriate content. */ char* ChatHandler::ExtractLinkArg(char** args, char const* const* linkTypes /*= NULL*/, int* foundIdx /*= NULL*/, char** keyPair /*= NULL*/, char** somethingPair /*= NULL*/) { if (!*args || !** args) { return NULL; } // skip if not linked started or encoded single | (doubled by client) if ((*args)[0] != '|' || (*args)[1] == '|') { return NULL; } // |color|Hlinktype:key:data...|h[name]|h|r char* head = *args; // [name] Shift-click form |color|linkType:key|h[name]|h|r // or // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r // or // [name] Shift-click form |linkType:key|h[name]|h|r // |color|Hlinktype:key:data...|h[name]|h|r char* tail = (*args) + 1; // skip | if (*tail != 'H') // skip color part, some links can not have color part { while (*tail && *tail != '|') { ++tail; } if (!*tail) { return NULL; } // |Hlinktype:key:data...|h[name]|h|r ++tail; // skip | } // Hlinktype:key:data...|h[name]|h|r if (*tail != 'H') { return NULL; } int linktype_idx = 0; if (linkTypes) // check link type if provided { // check linktypes (its include H in name) for (; linkTypes[linktype_idx]; ++linktype_idx) { // exactly string with follow : or | int l = strlen(linkTypes[linktype_idx]); if (strncmp(tail, linkTypes[linktype_idx], l) == 0 && (tail[l] == ':' || tail[l] == '|')) { break; } } // is search fail? if (!linkTypes[linktype_idx]) // NULL terminator in last element { return NULL; } tail += strlen(linkTypes[linktype_idx]); // skip linktype string // :key:data...|h[name]|h|r if (*tail != ':') { return NULL; } } else { while (*tail && *tail != ':') // skip linktype string { ++tail; } if (!*tail) { return NULL; } } ++tail; // key:data...|h[name]|h|r char* keyStart = tail; // remember key start for return while (*tail && *tail != '|' && *tail != ':') { ++tail; } if (!*tail) { return NULL; } char* keyEnd = tail; // remember key end for truncate // |h[name]|h|r or :something...|h[name]|h|r char* somethingStart = tail + 1; char* somethingEnd = tail + 1; // will updated later if need if (*tail == ':' && somethingPair) // optional data extraction { // :something...|h[name]|h|r ++tail; // something|h[name]|h|r or something:something2...|h[name]|h|r while (*tail && *tail != '|' && *tail != ':') { ++tail; } if (!*tail) { return NULL; } somethingEnd = tail; // remember data end for truncate } // |h[name]|h|r or :something2...|h[name]|h|r while (*tail && (*tail != '|' || *(tail + 1) != 'h')) // skip ... part if exist { ++tail; } if (!*tail) { return NULL; } // |h[name]|h|r tail += 2; // skip |h // [name]|h|r if (!*tail || *tail != '[') { return NULL; } while (*tail && (*tail != ']' || *(tail + 1) != '|')) // skip name part { ++tail; } tail += 2; // skip ]| // h|r if (!*tail || *tail != 'h' || *(tail + 1) != '|') { return NULL; } tail += 2; // skip h| // r if (!*tail || *tail != 'r' || (*(tail + 1) && !isWhiteSpace(*(tail + 1)))) { return NULL; } ++tail; // skip r // success if (*tail) // truncate all link string { *(tail++) = '\0'; } if (foundIdx) { *foundIdx = linktype_idx; } if (keyPair) { keyPair[0] = keyStart; keyPair[1] = keyEnd; } if (somethingPair) { somethingPair[0] = somethingStart; somethingPair[1] = somethingEnd; } *args = tail; SkipWhiteSpaces(args); return head; } /** * Function extract name/number/quote/shift-link-like string * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * @param asis control save quote string wrappers * @return extracted arg string, or NULL if args empty or not appropriate content. */ char* ChatHandler::ExtractArg(char** args, bool asis /*= false*/) { if (!*args || !** args) { return NULL; } char* arg = ExtractQuotedOrLiteralArg(args, asis); if (!arg) { arg = ExtractLinkArg(args); } return arg; } /** * Function extract name/quote/number/shift-link-like string, and return it if args have more non-whitespace data * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * if args have only single arg then args still pointing to this arg (unmodified pointer) * @return extracted string, or NULL if args empty or not appropriate content or have single arg totally. */ char* ChatHandler::ExtractOptNotLastArg(char** args) { char* arg = ExtractArg(args, true); // have more data if (*args &&** args) { return arg; } // optional name not found *args = arg ? arg : (char*)""; // *args don't must be NULL return NULL; } /** * Function extract data from shift-link "|color|LINKTYPE:RETURN:SOMETHING1|h[name]|h|r if linkType == LINKTYPE * It also extract literal/quote if not shift-link in args * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer) * * @param linkType shift-link must fit by link type to this arg value or extraction fail * * @param something1 if not NULL then shift-link must have data field and it returned into this arg * if extraction fail then non modified * * @return extracted key, or NULL if args empty or not appropriate content or not fit to linkType. */ char* ChatHandler::ExtractKeyFromLink(char** text, char const* linkType, char** something1 /*= NULL*/) { char const* linkTypes[2]; linkTypes[0] = linkType; linkTypes[1] = NULL; int foundIdx; return ExtractKeyFromLink(text, linkTypes, &foundIdx, something1); } /** * Function extract data from shift-link "|color|LINKTYPE:RETURN:SOMETHING1|h[name]|h|r if LINKTYPE in linkTypes array * It also extract literal/quote if not shift-link in args * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer) * * @param linkTypes NULL-terminated array of link types, shift-link must fit one from link type from array or extraction fail * * @param found_idx if not NULL then at return index in linkTypes that fit shift-link type, for non-link case return -1 * if extraction fail then non modified * * @param something1 if not NULL then shift-link must have data field and it returned into this arg * if extraction fail then non modified * * @return extracted key, or NULL if args empty or not appropriate content or not fit to linkType. */ char* ChatHandler::ExtractKeyFromLink(char** text, char const* const* linkTypes, int* found_idx, char** something1 /*= NULL*/) { // skip empty if (!*text || !** text) { return NULL; } // return non link case char* arg = ExtractQuotedOrLiteralArg(text); if (arg) { if (found_idx) { *found_idx = -1; } // special index case return arg; } char* keyPair[2]; char* somethingPair[2]; arg = ExtractLinkArg(text, linkTypes, found_idx, keyPair, something1 ? somethingPair : NULL); if (!arg) { return NULL; } *keyPair[1] = '\0'; // truncate key string if (something1) { *somethingPair[1] = '\0'; // truncate data string *something1 = somethingPair[0]; } return keyPair[0]; } /** * Function extract uint32 key from shift-link "|color|LINKTYPE:RETURN|h[name]|h|r if linkType == LINKTYPE * It also extract direct number if not shift-link in args * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer) * * @param linkType shift-link must fit by link type to this arg value or extraction fail * * @param value store result value at success return, not modified at fail * * @return true if extraction succesful */ bool ChatHandler::ExtractUint32KeyFromLink(char** text, char const* linkType, uint32& value) { char* arg = ExtractKeyFromLink(text, linkType); if (!arg) { return false; } return ExtractUInt32(&arg, value); } GameObject* ChatHandler::GetGameObjectWithGuid(uint32 lowguid, uint32 entry) { if (!m_session) { return NULL; } Player* pl = m_session->GetPlayer(); return pl->GetMap()->GetGameObject(ObjectGuid(HIGHGUID_GAMEOBJECT, entry, lowguid)); } enum SpellLinkType { SPELL_LINK_RAW = -1, // non-link case SPELL_LINK_SPELL = 0, SPELL_LINK_TALENT = 1, SPELL_LINK_ENCHANT = 2, }; static char const* const spellKeys[] = { "Hspell", // normal spell "Htalent", // talent spell "Henchant", // enchanting recipe spell NULL }; uint32 ChatHandler::ExtractSpellIdFromLink(char** text) { // number or [name] Shift-click form |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r // number or [name] Shift-click form |color|Htalent:talent_id,rank|h[name]|h|r int type; char* param1_str = NULL; char* idS = ExtractKeyFromLink(text, spellKeys, &type, ¶m1_str); if (!idS) { return 0; } uint32 id; if (!ExtractUInt32(&idS, id)) { return 0; } switch (type) { case SPELL_LINK_RAW: case SPELL_LINK_SPELL: case SPELL_LINK_ENCHANT: return id; case SPELL_LINK_TALENT: { // talent TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); if (!talentEntry) { return 0; } int32 rank; if (!ExtractInt32(¶m1_str, rank)) { return 0; } if (rank < 0) // unlearned talent have in shift-link field -1 as rank { rank = 0; } return rank < MAX_TALENT_RANK ? talentEntry->RankID[rank] : 0; } } // unknown type? return 0; } GameTele const* ChatHandler::ExtractGameTeleFromLink(char** text) { // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r char* cId = ExtractKeyFromLink(text, "Htele"); if (!cId) { return NULL; } // id case (explicit or from shift link) uint32 id; if (ExtractUInt32(&cId, id)) { return sObjectMgr.GetGameTele(id); } else { return sObjectMgr.GetGameTele(cId); } } enum GuidLinkType { GUID_LINK_RAW = -1, // non-link case GUID_LINK_PLAYER = 0, GUID_LINK_CREATURE = 1, GUID_LINK_GAMEOBJECT = 2, }; static char const* const guidKeys[] = { "Hplayer", "Hcreature", "Hgameobject", NULL }; ObjectGuid ChatHandler::ExtractGuidFromLink(char** text) { int type = 0; // |color|Hcreature:creature_guid|h[name]|h|r // |color|Hgameobject:go_guid|h[name]|h|r // |color|Hplayer:name|h[name]|h|r char* idS = ExtractKeyFromLink(text, guidKeys, &type); if (!idS) { return ObjectGuid(); } switch (type) { case GUID_LINK_RAW: case GUID_LINK_PLAYER: { std::string name = idS; if (!normalizePlayerName(name)) { return ObjectGuid(); } if (Player* player = sObjectMgr.GetPlayer(name.c_str())) { return player->GetObjectGuid(); } return sObjectMgr.GetPlayerGuidByName(name); } case GUID_LINK_CREATURE: { uint32 lowguid; if (!ExtractUInt32(&idS, lowguid)) { return ObjectGuid(); } if (CreatureData const* data = sObjectMgr.GetCreatureData(lowguid)) { return data->GetObjectGuid(lowguid); } else { return ObjectGuid(); } } case GUID_LINK_GAMEOBJECT: { uint32 lowguid; if (!ExtractUInt32(&idS, lowguid)) { return ObjectGuid(); } if (GameObjectData const* data = sObjectMgr.GetGOData(lowguid)) { return ObjectGuid(HIGHGUID_GAMEOBJECT, data->id, lowguid); } else { return ObjectGuid(); } } } // unknown type? return ObjectGuid(); } enum LocationLinkType { LOCATION_LINK_RAW = -1, // non-link case LOCATION_LINK_PLAYER = 0, LOCATION_LINK_TELE = 1, LOCATION_LINK_TAXINODE = 2, LOCATION_LINK_CREATURE = 3, LOCATION_LINK_GAMEOBJECT = 4, LOCATION_LINK_CREATURE_ENTRY = 5, LOCATION_LINK_GAMEOBJECT_ENTRY = 6, LOCATION_LINK_AREATRIGGER = 7, LOCATION_LINK_AREATRIGGER_TARGET = 8, }; static char const* const locationKeys[] = { "Htele", "Htaxinode", "Hplayer", "Hcreature", "Hgameobject", "Hcreature_entry", "Hgameobject_entry", "Hareatrigger", "Hareatrigger_target", NULL }; bool ChatHandler::ExtractLocationFromLink(char** text, uint32& mapid, float& x, float& y, float& z) { int type = 0; // |color|Hplayer:name|h[name]|h|r // |color|Htele:id|h[name]|h|r // |color|Htaxinode:id|h[name]|h|r // |color|Hcreature:creature_guid|h[name]|h|r // |color|Hgameobject:go_guid|h[name]|h|r // |color|Hcreature_entry:creature_id|h[name]|h|r // |color|Hgameobject_entry:go_id|h[name]|h|r // |color|Hareatrigger:id|h[name]|h|r // |color|Hareatrigger_target:id|h[name]|h|r char* idS = ExtractKeyFromLink(text, locationKeys, &type); if (!idS) { return false; } switch (type) { case LOCATION_LINK_RAW: case LOCATION_LINK_PLAYER: { std::string name = idS; if (!normalizePlayerName(name)) { return false; } if (Player* player = sObjectMgr.GetPlayer(name.c_str())) { mapid = player->GetMapId(); x = player->GetPositionX(); y = player->GetPositionY(); z = player->GetPositionZ(); return true; } if (ObjectGuid guid = sObjectMgr.GetPlayerGuidByName(name)) { // to point where player stay (if loaded) float o; bool in_flight; return Player::LoadPositionFromDB(guid, mapid, x, y, z, o, in_flight); } return false; } case LOCATION_LINK_TELE: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } GameTele const* tele = sObjectMgr.GetGameTele(id); if (!tele) { return false; } mapid = tele->mapId; x = tele->position_x; y = tele->position_y; z = tele->position_z; return true; } case LOCATION_LINK_TAXINODE: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); if (!node) { return false; } mapid = node->map_id; x = node->x; y = node->y; z = node->z; return true; } case LOCATION_LINK_CREATURE: { uint32 lowguid; if (!ExtractUInt32(&idS, lowguid)) { return false; } if (CreatureData const* data = sObjectMgr.GetCreatureData(lowguid)) { mapid = data->mapid; x = data->posX; y = data->posY; z = data->posZ; return true; } else { return false; } } case LOCATION_LINK_GAMEOBJECT: { uint32 lowguid; if (!ExtractUInt32(&idS, lowguid)) { return false; } if (GameObjectData const* data = sObjectMgr.GetGOData(lowguid)) { mapid = data->mapid; x = data->posX; y = data->posY; z = data->posZ; return true; } else { return false; } } case LOCATION_LINK_CREATURE_ENTRY: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } if (ObjectMgr::GetCreatureTemplate(id)) { FindCreatureData worker(id, m_session ? m_session->GetPlayer() : NULL); sObjectMgr.DoCreatureData(worker); if (CreatureDataPair const* dataPair = worker.GetResult()) { mapid = dataPair->second.mapid; x = dataPair->second.posX; y = dataPair->second.posY; z = dataPair->second.posZ; return true; } else { return false; } } else { return false; } } case LOCATION_LINK_GAMEOBJECT_ENTRY: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } if (ObjectMgr::GetGameObjectInfo(id)) { FindGOData worker(id, m_session ? m_session->GetPlayer() : NULL); sObjectMgr.DoGOData(worker); if (GameObjectDataPair const* dataPair = worker.GetResult()) { mapid = dataPair->second.mapid; x = dataPair->second.posX; y = dataPair->second.posY; z = dataPair->second.posZ; return true; } else { return false; } } else { return false; } } case LOCATION_LINK_AREATRIGGER: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(id); if (!atEntry) { PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND, id); SetSentErrorMessage(true); return false; } mapid = atEntry->mapid; x = atEntry->x; y = atEntry->y; z = atEntry->z; return true; } case LOCATION_LINK_AREATRIGGER_TARGET: { uint32 id; if (!ExtractUInt32(&idS, id)) { return false; } if (!sAreaTriggerStore.LookupEntry(id)) { PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND, id); SetSentErrorMessage(true); return false; } AreaTrigger const* at = sObjectMgr.GetAreaTrigger(id); if (!at) { PSendSysMessage(LANG_AREATRIGER_NOT_HAS_TARGET, id); SetSentErrorMessage(true); return false; } mapid = at->target_mapId; x = at->target_X; y = at->target_Y; z = at->target_Z; return true; } } // unknown type? return false; } std::string ChatHandler::ExtractPlayerNameFromLink(char** text) { // |color|Hplayer:name|h[name]|h|r char* name_str = ExtractKeyFromLink(text, "Hplayer"); if (!name_str) { return ""; } std::string name = name_str; if (!normalizePlayerName(name)) { return ""; } return name; } /** * Function extract at least one from request player data (pointer/guid/name) from args name/shift-link or selected player if no args * * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces) * * @param player optional arg One from 3 optional args must be provided at least (or more). * @param player_guid optional arg For function success only one from provided args need get result * @param player_name optional arg But if early arg get value then all later args will have its (if requested) * if player_guid requested and not found then name also will not found * So at success can be returned 2 cases: (player/guid/name) or (guid/name) * * @return true if extraction successful */ bool ChatHandler::ExtractPlayerTarget(char** args, Player** player /*= NULL*/, ObjectGuid* player_guid /*= NULL*/, std::string* player_name /*= NULL*/) { if (*args &&** args) { std::string name = ExtractPlayerNameFromLink(args); if (name.empty()) { SendSysMessage(LANG_PLAYER_NOT_FOUND); SetSentErrorMessage(true); return false; } Player* pl = sObjectMgr.GetPlayer(name.c_str()); // if allowed player pointer if (player) { *player = pl; } // if need guid value from DB (in name case for check player existence) ObjectGuid guid = !pl && (player_guid || player_name) ? sObjectMgr.GetPlayerGuidByName(name) : ObjectGuid(); // if allowed player guid (if no then only online players allowed) if (player_guid) { *player_guid = pl ? pl->GetObjectGuid() : guid; } if (player_name) { *player_name = pl || guid ? name : ""; } } else { Player* pl = getSelectedPlayer(); // if allowed player pointer if (player) { *player = pl; } // if allowed player guid (if no then only online players allowed) if (player_guid) { *player_guid = pl ? pl->GetObjectGuid() : ObjectGuid(); } if (player_name) { *player_name = pl ? pl->GetName() : ""; } } // some from req. data must be provided (note: name is empty if player not exist) if ((!player || !*player) && (!player_guid || !*player_guid) && (!player_name || player_name->empty())) { SendSysMessage(LANG_PLAYER_NOT_FOUND); SetSentErrorMessage(true); return false; } return true; } uint32 ChatHandler::ExtractAccountId(char** args, std::string* accountName /*= NULL*/, Player** targetIfNullArg /*= NULL*/) { uint32 account_id = 0; ///- Get the account name from the command line char* account_str = ExtractLiteralArg(args); if (!account_str) { if (!targetIfNullArg) { return 0; } /// only target player different from self allowed (if targetPlayer!=NULL then not console) Player* targetPlayer = getSelectedPlayer(); if (!targetPlayer) { return 0; } account_id = targetPlayer->GetSession()->GetAccountId(); if (accountName) { sAccountMgr.GetName(account_id, *accountName); } if (targetIfNullArg) { *targetIfNullArg = targetPlayer; } return account_id; } std::string account_name; if (ExtractUInt32(&account_str, account_id)) { if (!sAccountMgr.GetName(account_id, account_name)) { PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_str); SetSentErrorMessage(true); return 0; } } else { account_name = account_str; if (!AccountMgr::normalizeString(account_name)) { PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str()); SetSentErrorMessage(true); return 0; } account_id = sAccountMgr.GetId(account_name); if (!account_id) { PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str()); SetSentErrorMessage(true); return 0; } } if (accountName) { *accountName = account_name; } if (targetIfNullArg) { *targetIfNullArg = NULL; } 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)) }, // 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()); } bool ChatHandler::needReportToTarget(Player* chr) const { Player* pl = m_session->GetPlayer(); return pl != chr && pl->IsVisibleGloballyFor(chr); } LocaleConstant ChatHandler::GetSessionDbcLocale() const { return m_session->GetSessionDbcLocale(); } int ChatHandler::GetSessionDbLocaleIndex() const { return m_session->GetSessionDbLocaleIndex(); } const char* CliHandler::GetMangosString(int32 entry) const { return sObjectMgr.GetMangosStringForDBCLocale(entry); } uint32 CliHandler::GetAccountId() const { return m_accountId; } AccountTypes CliHandler::GetAccessLevel() const { return m_loginAccessLevel; } bool CliHandler::isAvailable(ChatCommand const& cmd) const { // skip non-console commands in console case if (!cmd.AllowConsole) { return false; } // normal case return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel; } void CliHandler::SendSysMessage(const char* str) { m_print(m_callbackArg, str); m_print(m_callbackArg, "\r\n"); } std::string CliHandler::GetNameLink() const { return GetMangosString(LANG_CONSOLE_COMMAND); } bool CliHandler::needReportToTarget(Player* /*chr*/) const { return true; } LocaleConstant CliHandler::GetSessionDbcLocale() const { return sWorld.GetDefaultDbcLocale(); } int CliHandler::GetSessionDbLocaleIndex() const { return sObjectMgr.GetDBCLocaleIndex(); } // Check/ Output if a NPC or GO (by guid) is part of a pool or game event template void ChatHandler::ShowNpcOrGoSpawnInformation(uint32 guid) { if (uint16 pool_id = sPoolMgr.IsPartOfAPool(guid)) { uint16 top_pool_id = sPoolMgr.IsPartOfTopPool(pool_id); if (!top_pool_id || top_pool_id == pool_id) { PSendSysMessage(LANG_NPC_GO_INFO_POOL, pool_id); } else { PSendSysMessage(LANG_NPC_GO_INFO_TOP_POOL, pool_id, top_pool_id); } if (int16 event_id = sGameEventMgr.GetGameEventId(top_pool_id)) { GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap(); GameEventData const& eventData = events[std::abs(event_id)]; if (event_id > 0) { PSendSysMessage(LANG_NPC_GO_INFO_POOL_GAME_EVENT_S, top_pool_id, std::abs(event_id), eventData.description.c_str()); } else { PSendSysMessage(LANG_NPC_GO_INFO_POOL_GAME_EVENT_D, top_pool_id, std::abs(event_id), eventData.description.c_str()); } } } else if (int16 event_id = sGameEventMgr.GetGameEventId(guid)) { GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap(); GameEventData const& eventData = events[std::abs(event_id)]; if (event_id > 0) { PSendSysMessage(LANG_NPC_GO_INFO_GAME_EVENT_S, std::abs(event_id), eventData.description.c_str()); } else { PSendSysMessage(LANG_NPC_GO_INFO_GAME_EVENT_D, std::abs(event_id), eventData.description.c_str()); } } } // Prepare ShortString for a NPC or GO (by guid) with pool or game event IDs template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation(uint32 guid) { std::string str = ""; if (uint16 pool_id = sPoolMgr.IsPartOfAPool(guid)) { uint16 top_pool_id = sPoolMgr.IsPartOfTopPool(guid); if (int16 event_id = sGameEventMgr.GetGameEventId(top_pool_id)) { char buffer[100]; const char* format = GetMangosString(LANG_NPC_GO_INFO_POOL_EVENT_STRING); sprintf(buffer, format, pool_id, event_id); str = buffer; } else { char buffer[100]; const char* format = GetMangosString(LANG_NPC_GO_INFO_POOL_STRING); sprintf(buffer, format, pool_id); str = buffer; } } else if (int16 event_id = sGameEventMgr.GetGameEventId(guid)) { char buffer[100]; const char* format = GetMangosString(LANG_NPC_GO_INFO_EVENT_STRING); sprintf(buffer, format, event_id); str = buffer; } return str; } void ChatHandler::LogCommand(char const* fullcmd) { // chat case if (m_session) { Player* p = m_session->GetPlayer(); ObjectGuid sel_guid = p->GetSelectionGuid(); sLog.outCommand(GetAccountId(), "Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s]", fullcmd, p->GetName(), GetAccountId(), p->GetPositionX(), p->GetPositionY(), p->GetPositionZ(), p->GetMapId(), sel_guid.GetString().c_str()); } else // 0 account -> console { sLog.outCommand(GetAccountId(), "Command: %s [Account: %u from %s]", fullcmd, GetAccountId(), GetAccountId() ? "RA-connection" : "Console"); } } void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language /*= LANG_UNIVERSAL*/, ChatTagFlags chatTag /*= CHAT_TAG_NONE*/, ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= NULL*/, ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* /*targetName*/ /*= NULL*/, char const* channelName /*= NULL*/, uint8 playerRank /*= 0*/) { data.Initialize(SMSG_MESSAGECHAT); data << uint8(msgtype); data << uint32(language); switch (msgtype) { case CHAT_MSG_MONSTER_WHISPER: case CHAT_MSG_RAID_BOSS_WHISPER: case CHAT_MSG_RAID_BOSS_EMOTE: case CHAT_MSG_MONSTER_EMOTE: MANGOS_ASSERT(senderName); data << uint32(strlen(senderName) + 1); data << senderName; data << ObjectGuid(targetGuid); // Unit Target break; case CHAT_MSG_SAY: case CHAT_MSG_PARTY: case CHAT_MSG_YELL: data << ObjectGuid(senderGuid); data << ObjectGuid(senderGuid); break; case CHAT_MSG_MONSTER_SAY: case CHAT_MSG_MONSTER_YELL: MANGOS_ASSERT(senderName); data << ObjectGuid(senderGuid); data << uint32(strlen(senderName) + 1); data << senderName; data << ObjectGuid(targetGuid); // Unit Target break; case CHAT_MSG_CHANNEL: MANGOS_ASSERT(channelName); data << channelName; data << uint32(playerRank); data << ObjectGuid(senderGuid); break; default: data << ObjectGuid(senderGuid); break; } MANGOS_ASSERT(message); data << uint32(strlen(message) + 1); data << message; data << uint8(chatTag); } // Shared Helpers between command implementation files void ChatHandler::ShowFactionListHelper(FactionEntry const* factionEntry, LocaleConstant loc, FactionState const* repState /*= NULL*/, Player* target /*= NULL */) { std::string name = factionEntry->name[loc]; // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format // or "id - [faction] [no reputation]" format std::ostringstream ss; if (m_session) { ss << factionEntry->ID << " - |cffffffff|Hfaction:" << factionEntry->ID << "|h[" << name << " " << localeNames[loc] << "]|h|r"; } else { ss << factionEntry->ID << " - " << name << " " << localeNames[loc]; } if (repState) // and then target!=NULL also { ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; if (repState->Flags & FACTION_FLAG_VISIBLE) { ss << GetMangosString(LANG_FACTION_VISIBLE); } if (repState->Flags & FACTION_FLAG_AT_WAR) { ss << GetMangosString(LANG_FACTION_ATWAR); } if (repState->Flags & FACTION_FLAG_PEACE_FORCED) { ss << GetMangosString(LANG_FACTION_PEACE_FORCED); } if (repState->Flags & FACTION_FLAG_HIDDEN) { ss << GetMangosString(LANG_FACTION_HIDDEN); } if (repState->Flags & FACTION_FLAG_INVISIBLE_FORCED) { ss << GetMangosString(LANG_FACTION_INVISIBLE_FORCED); } if (repState->Flags & FACTION_FLAG_INACTIVE) { ss << GetMangosString(LANG_FACTION_INACTIVE); } } else if (target) { ss << GetMangosString(LANG_FACTION_NOREPUTATION); } SendSysMessage(ss.str().c_str()); } void ChatHandler::ShowSpellListHelper(Player* target, SpellEntry const* spellInfo, LocaleConstant loc) { uint32 id = spellInfo->Id; bool known = target && target->HasSpell(id); bool learn = (spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_LEARN_SPELL); uint32 talentCost = GetTalentSpellCost(id); bool talent = (talentCost > 0); bool passive = IsPassiveSpell(spellInfo); bool active = target && target->HasAura(id); // unit32 used to prevent interpreting uint8 as char at output // find rank of learned spell for learning spell, or talent rank uint32 rank = talentCost ? talentCost : sSpellMgr.GetSpellRank(learn ? spellInfo->EffectTriggerSpell[EFFECT_INDEX_0] : id); // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format std::ostringstream ss; if (m_session) { ss << id << " - |cffffffff|Hspell:" << id << "|h[" << spellInfo->SpellName[loc]; } else { ss << id << " - " << spellInfo->SpellName[loc]; } // include rank in link name if (rank) { ss << GetMangosString(LANG_SPELL_RANK) << rank; } if (m_session) { ss << " " << localeNames[loc] << "]|h|r"; } else { ss << " " << localeNames[loc]; } if (talent) { ss << GetMangosString(LANG_TALENT); } if (passive) { ss << GetMangosString(LANG_PASSIVE); } if (learn) { ss << GetMangosString(LANG_LEARN); } if (known) { ss << GetMangosString(LANG_KNOWN); } if (active) { ss << GetMangosString(LANG_ACTIVE); } SendSysMessage(ss.str().c_str()); } bool ChatHandler::ShowPlayerListHelper(QueryResult* result, uint32* limit, bool title, bool error) { if (!result) { if (error) { PSendSysMessage(LANG_NO_PLAYERS_FOUND); SetSentErrorMessage(true); } return false; } if (!m_session && title) { SendSysMessage(LANG_CHARACTERS_LIST_BAR); SendSysMessage(LANG_CHARACTERS_LIST_HEADER); SendSysMessage(LANG_CHARACTERS_LIST_BAR); } if (result) { ///- Circle through them. Display username and GM level do { // check limit if (limit) { if (*limit == 0) { break; } --* limit; } Field* fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); std::string name = fields[1].GetCppString(); uint8 race = fields[2].GetUInt8(); uint8 class_ = fields[3].GetUInt8(); uint32 level = fields[4].GetUInt32(); ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race); ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); char const* race_name = raceEntry ? raceEntry->name[GetSessionDbcLocale()] : ""; char const* class_name = classEntry ? classEntry->name[GetSessionDbcLocale()] : ""; if (!m_session) { PSendSysMessage(LANG_CHARACTERS_LIST_LINE_CONSOLE, guid, name.c_str(), race_name, class_name, level); } else { PSendSysMessage(LANG_CHARACTERS_LIST_LINE_CHAT, guid, name.c_str(), name.c_str(), race_name, class_name, level); } } while (result->NextRow()); delete result; } if (!m_session) { SendSysMessage(LANG_CHARACTERS_LIST_BAR); } return true; } // Instantiate template for helper function template void ChatHandler::ShowNpcOrGoSpawnInformation(uint32 guid); template void ChatHandler::ShowNpcOrGoSpawnInformation(uint32 guid); template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation(uint32 guid); template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation(uint32 guid);