Elmsroth 0f53874d1f
Implement .reset mail command + Increase max bags slots to 36 (#102)
Default behaviour :
       -------------------
        - delete checked mails (even if its is GM stationery and if it contains items in it, but not deleted COD)

       Options :
       ---------
        - cod : delete only cod mail (even if it is unchecked)
            TODO -> to improve => return cod to sender instead of delete
        - gm : delete only GM stationery emails (even if it is unchecked)
        - all : delete all mails (even if it is unchecked)
        - from XXXX : delete all mails from specific sender in the slected player mailbox, name or guid
          TODO  -> to improve, if unchecked return letter to sender to inform it was not read and purged by GM for tech. reason.

        TODO : future => handle reset mail for Offline char ?
2020-06-17 07:50:54 +01:00

4046 lines
164 KiB
C++

/**
* 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 <https://getmangos.eu>
*
* 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<AUCTION_QUALITY_GREY>, "", NULL },
{ "white", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_WHITE>, "", NULL },
{ "green", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GREEN>, "", NULL },
{ "blue", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_BLUE>, "", NULL },
{ "purple", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_PURPLE>, "", NULL },
{ "orange", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_ORANGE>, "", NULL },
{ "yellow", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_YELLOW>, "", NULL },
{ "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountCommand, "", NULL },
{ NULL, 0, true, NULL, "", NULL }
};
static ChatCommand ahbotItemsRatioCommandTable[] =
{
{ "alliance", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_ALLIANCE>, "", NULL },
{ "horde", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_HORDE>, "", NULL },
{ "neutral", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_NEUTRAL>, "", 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<int32>::min() || valRaw > std::numeric_limits<int32>::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<uint32>::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, &param1_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(&param1_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 <typename T>
void ChatHandler::ShowNpcOrGoSpawnInformation(uint32 guid)
{
if (uint16 pool_id = sPoolMgr.IsPartOfAPool<T>(guid))
{
uint16 top_pool_id = sPoolMgr.IsPartOfTopPool<Pool>(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<Pool>(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<T>(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 <typename T>
std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation(uint32 guid)
{
std::string str = "";
if (uint16 pool_id = sPoolMgr.IsPartOfAPool<T>(guid))
{
uint16 top_pool_id = sPoolMgr.IsPartOfTopPool<T>(guid);
if (int16 event_id = sGameEventMgr.GetGameEventId<Pool>(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<T>(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<Creature>(uint32 guid);
template void ChatHandler::ShowNpcOrGoSpawnInformation<GameObject>(uint32 guid);
template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation<Creature>(uint32 guid);
template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation<GameObject>(uint32 guid);