/*
* Copyright (C) 2008-2010 TrinityCore
* Copyright (C) 2005-2009 MaNGOS
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "Common.h"
#include "ObjectMgr.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "DatabaseEnv.h"
#include "AccountMgr.h"
#include "CellImpl.h"
#include "Chat.h"
#include "GridNotifiersImpl.h"
#include "Language.h"
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
#include "UpdateMask.h"
#include "SpellMgr.h"
#include "ScriptMgr.h"
// Supported shift-links (client generated and server side)
// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
// - client, item icon shift click, not used in server currently
// |color|Harea:area_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|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r - client, at shift click in glyphs dialog, GlyphSlot.dbc, GlyphProperties.dbc
// |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:0:0:0:reporter_level|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
// |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
// |color|Htaxinode:id|h[name]|h|r
// |color|Htele:id|h[name]|h|r
// |color|Htitle:id|h[name]|h|r
// |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click
bool ChatHandler::load_command_table = true;
// wrapper for old-style handlers
template
bool OldHandler(ChatHandler* chatHandler, const char* args)
{
return (chatHandler->*F)(args);
}
// get number of commands in table
static size_t getCommandTableSize(const ChatCommand* commands)
{
if (!commands)
return 0;
size_t count = 0;
while (commands[count].Name != NULL)
count++;
return count;
}
// append source command table to target, return number of appended commands
static size_t appendCommandTable(ChatCommand* target, const ChatCommand* source)
{
const size_t count = getCommandTableSize(source);
if (count)
memcpy(target, source, count * sizeof(ChatCommand));
return count;
}
ChatCommand * ChatHandler::getCommandTable()
{
static ChatCommand banCommandTable[] =
{
{ "account", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanAccountCommand>, "", NULL },
{ "character", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanCharacterCommand>, "", NULL },
{ "playeraccount", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanAccountByCharCommand>, "", NULL },
{ "ip", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanIPCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand baninfoCommandTable[] =
{
{ "account", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanInfoAccountCommand>, "", NULL },
{ "character", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanInfoCharacterCommand>, "", NULL },
{ "ip", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanInfoIPCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand banlistCommandTable[] =
{
{ "account", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanListAccountCommand>, "", NULL },
{ "character", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanListCharacterCommand>, "", NULL },
{ "ip", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleBanListIPCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand castCommandTable[] =
{
{ "back", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCastBackCommand>, "", NULL },
{ "dist", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCastDistCommand>, "", NULL },
{ "self", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCastSelfCommand>, "", NULL },
{ "target", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCastTargetCommand>, "", NULL },
{ "", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCastCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand characterDeletedCommandTable[] =
{
{ "delete", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleCharacterDeletedDeleteCommand>, "", NULL },
{ "list", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleCharacterDeletedListCommand>, "", NULL },
{ "restore", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleCharacterDeletedRestoreCommand>, "", NULL },
{ "old", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleCharacterDeletedOldCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand characterCommandTable[] =
{
{ "customize", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterCustomizeCommand>, "", NULL },
{ "changefaction", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterChangeFactionCommand>, "", NULL },
{ "changerace", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterChangeRaceCommand>, "", NULL },
{ "deleted", SEC_GAMEMASTER, true, NULL, "", characterDeletedCommandTable},
{ "erase", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleCharacterEraseCommand>, "", NULL },
{ "level", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleCharacterLevelCommand>, "", NULL },
{ "rename", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterRenameCommand>, "", NULL },
{ "reputation", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterReputationCommand>, "", NULL },
{ "titles", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleCharacterTitlesCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand channelSetCommandTable[] =
{
{ "ownership", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleChannelSetOwnership>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand channelCommandTable[] =
{
{ "set", SEC_ADMINISTRATOR, true, NULL, "", channelSetCommandTable },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand groupCommandTable[] =
{
{ "leader", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGroupLeaderCommand>, "", NULL },
{ "disband", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGroupDisbandCommand>, "", NULL },
{ "remove", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGroupRemoveCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand guildCommandTable[] =
{
{ "create", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGuildCreateCommand>, "", NULL },
{ "delete", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGuildDeleteCommand>, "", NULL },
{ "invite", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGuildInviteCommand>, "", NULL },
{ "uninvite", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGuildUninviteCommand>, "", NULL },
{ "rank", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGuildRankCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand instanceCommandTable[] =
{
{ "listbinds", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleInstanceListBindsCommand>, "", NULL },
{ "unbind", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleInstanceUnbindCommand>, "", NULL },
{ "stats", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleInstanceStatsCommand>, "", NULL },
{ "savedata", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleInstanceSaveDataCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand listCommandTable[] =
{
{ "creature", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleListCreatureCommand>, "", NULL },
{ "item", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleListItemCommand>, "", NULL },
{ "object", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleListObjectCommand>, "", NULL },
{ "auras", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleListAurasCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand lookupPlayerCommandTable[] =
{
{ "ip", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleLookupPlayerIpCommand>, "", NULL },
{ "account", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleLookupPlayerAccountCommand>, "", NULL },
{ "email", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleLookupPlayerEmailCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand lookupCommandTable[] =
{
{ "area", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleLookupAreaCommand>, "", NULL },
{ "creature", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupCreatureCommand>, "", NULL },
{ "event", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleLookupEventCommand>, "", NULL },
{ "faction", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupFactionCommand>, "", NULL },
{ "item", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupItemCommand>, "", NULL },
{ "itemset", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupItemSetCommand>, "", NULL },
{ "object", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupObjectCommand>, "", NULL },
{ "quest", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupQuestCommand>, "", NULL },
{ "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable },
{ "skill", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupSkillCommand>, "", NULL },
{ "spell", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupSpellCommand>, "", NULL },
{ "taxinode", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupTaxiNodeCommand>, "", NULL },
{ "tele", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleLookupTeleCommand>, "", NULL },
{ "title", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleLookupTitleCommand>, "", NULL },
{ "map", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleLookupMapCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand petCommandTable[] =
{
{ "create", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleCreatePetCommand>, "", NULL },
{ "learn", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandlePetLearnCommand>, "", NULL },
{ "unlearn", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandlePetUnlearnCommand>, "", NULL },
{ "tp", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandlePetTpCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand pdumpCommandTable[] =
{
{ "load", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandlePDumpLoadCommand>, "", NULL },
{ "write", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandlePDumpWriteCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand resetCommandTable[] =
{
{ "achievements", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetAchievementsCommand>, "", NULL },
{ "honor", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetHonorCommand>, "", NULL },
{ "level", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetLevelCommand>, "", NULL },
{ "spells", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetSpellsCommand>, "", NULL },
{ "stats", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetStatsCommand>, "", NULL },
{ "talents", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetTalentsCommand>, "", NULL },
{ "all", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleResetAllCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand sendCommandTable[] =
{
{ "items", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleSendItemsCommand>, "", NULL },
{ "mail", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleSendMailCommand>, "", NULL },
{ "message", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleSendMessageCommand>, "", NULL },
{ "money", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleSendMoneyCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverIdleRestartCommandTable[] =
{
{ "cancel", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerShutDownCancelCommand>,"", NULL },
{ "" , SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerIdleRestartCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverIdleShutdownCommandTable[] =
{
{ "cancel", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerShutDownCancelCommand>,"", NULL },
{ "" , SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerIdleShutDownCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverRestartCommandTable[] =
{
{ "cancel", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerShutDownCancelCommand>,"", NULL },
{ "" , SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerRestartCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverShutdownCommandTable[] =
{
{ "cancel", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerShutDownCancelCommand>,"", NULL },
{ "" , SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerShutDownCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverSetCommandTable[] =
{
{ "difftime", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleServerSetDiffTimeCommand>, "", NULL },
{ "loglevel", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleServerSetLogLevelCommand>, "", NULL },
{ "logfilelevel", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleServerSetLogFileLevelCommand>, "", NULL },
{ "motd", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerSetMotdCommand>, "", NULL },
{ "closed", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerSetClosedCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand serverCommandTable[] =
{
{ "corpses", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleServerCorpsesCommand>, "", NULL },
{ "exit", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleServerExitCommand>, "", NULL },
{ "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable },
{ "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
{ "info", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleServerInfoCommand>, "", NULL },
{ "motd", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleServerMotdCommand>, "", NULL },
{ "plimit", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleServerPLimitCommand>, "", NULL },
{ "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable },
{ "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
{ "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable },
{ "togglequerylog", SEC_CONSOLE, true, OldHandler<&ChatHandler::HandleServerToggleQueryLogging>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand unbanCommandTable[] =
{
{ "account", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleUnBanAccountCommand>, "", NULL },
{ "character", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleUnBanCharacterCommand>, "", NULL },
{ "playeraccount", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleUnBanAccountByCharCommand>, "", NULL },
{ "ip", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleUnBanIPCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand ticketResponseCommandTable[] =
{
{ "append", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketResponseAppendCommand>, "", NULL },
{ "appendln", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketResponseAppendLnCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand ticketCommandTable[] =
{
{ "list", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListCommand>, "", NULL },
{ "onlinelist", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListOnlineCommand>, "", NULL },
{ "viewname", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketGetByNameCommand>, "", NULL },
{ "viewid", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketGetByIdCommand>, "", NULL },
{ "close", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCloseByIdCommand>, "", NULL },
{ "closedlist", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListClosedCommand>, "", NULL },
{ "escalatedlist", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketListEscalatedCommand>, "", NULL },
{ "delete", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGMTicketDeleteByIdCommand>, "", NULL },
{ "assign", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketAssignToCommand>, "", NULL },
{ "unassign", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketUnAssignCommand>, "", NULL },
{ "comment", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCommentCommand>, "", NULL },
{ "togglesystem", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleToggleGMTicketSystem>, "", NULL },
{ "escalate", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketEscalateCommand>, "", NULL },
{ "response", SEC_MODERATOR, false, NULL, "", ticketResponseCommandTable },
{ "complete", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCompleteCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
{
{ "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable},
{ "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
{ "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable },
{ "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
{ "guild", SEC_ADMINISTRATOR, true, NULL, "", guildCommandTable },
{ "cast", SEC_ADMINISTRATOR, false, NULL, "", castCommandTable },
{ "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable },
{ "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable },
{ "server", SEC_ADMINISTRATOR, true, NULL, "", serverCommandTable },
{ "channel", SEC_ADMINISTRATOR, true, NULL, "", channelCommandTable },
{ "pet", SEC_GAMEMASTER, false, NULL, "", petCommandTable },
{ "ticket", SEC_MODERATOR, false, NULL, "", ticketCommandTable },
{ "aura", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleAuraCommand>, "", NULL },
{ "unaura", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleUnAuraCommand>, "", NULL },
{ "nameannounce", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleNameAnnounceCommand>, "", NULL },
{ "gmnameannounce", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMNameAnnounceCommand>, "", NULL },
{ "announce", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleAnnounceCommand>, "", NULL },
{ "gmannounce", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMAnnounceCommand>, "", NULL },
{ "notify", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleNotifyCommand>, "", NULL },
{ "gmnotify", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMNotifyCommand>, "", NULL },
{ "appear", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleAppearCommand>, "", NULL },
{ "summon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleSummonCommand>, "", NULL },
{ "groupsummon", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGroupSummonCommand>, "", NULL },
{ "commands", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleCommandsCommand>, "", NULL },
{ "demorph", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleDeMorphCommand>, "", NULL },
{ "die", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleDieCommand>, "", NULL },
{ "revive", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleReviveCommand>, "", NULL },
{ "dismount", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleDismountCommand>, "", NULL },
{ "gps", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGPSCommand>, "", NULL },
{ "guid", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGUIDCommand>, "", NULL },
{ "help", SEC_PLAYER, true, OldHandler<&ChatHandler::HandleHelpCommand>, "", NULL },
{ "itemmove", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleItemMoveCommand>, "", NULL },
{ "cooldown", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleCooldownCommand>, "", NULL },
{ "unlearn", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleUnLearnCommand>, "", NULL },
{ "distance", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGetDistanceCommand>, "", NULL },
{ "recall", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleRecallCommand>, "", NULL },
{ "save", SEC_PLAYER, false, OldHandler<&ChatHandler::HandleSaveCommand>, "", NULL },
{ "saveall", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleSaveAllCommand>, "", NULL },
{ "kick", SEC_GAMEMASTER, true, OldHandler<&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, OldHandler<&ChatHandler::HandleStartCommand>, "", NULL },
{ "taxicheat", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleTaxiCheatCommand>, "", NULL },
{ "linkgrave", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleLinkGraveCommand>, "", NULL },
{ "neargrave", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleNearGraveCommand>, "", NULL },
{ "explorecheat", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleExploreCheatCommand>, "", NULL },
{ "hover", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleHoverCommand>, "", NULL },
{ "levelup", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleLevelUpCommand>, "", NULL },
{ "showarea", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleShowAreaCommand>, "", NULL },
{ "hidearea", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleHideAreaCommand>, "", NULL },
{ "additem", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleAddItemCommand>, "", NULL },
{ "additemset", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleAddItemSetCommand>, "", NULL },
{ "bank", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleBankCommand>, "", NULL },
{ "wchange", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleChangeWeather>, "", NULL },
{ "maxskill", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleMaxSkillCommand>, "", NULL },
{ "setskill", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleSetSkillCommand>, "", NULL },
{ "whispers", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleWhispersCommand>, "", NULL },
{ "pinfo", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandlePInfoCommand>, "", NULL },
{ "respawn", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleRespawnCommand>, "", NULL },
{ "send", SEC_MODERATOR, true, NULL, "", sendCommandTable },
{ "mute", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleMuteCommand>, "", NULL },
{ "unmute", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleUnmuteCommand>, "", NULL },
{ "movegens", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleMovegensCommand>, "", NULL },
{ "cometome", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleComeToMeCommand>, "", NULL },
{ "damage", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleDamageCommand>, "", NULL },
{ "combatstop", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleCombatStopCommand>, "", NULL },
{ "flusharenapoints",SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleFlushArenaPointsCommand>, "", NULL },
{ "repairitems", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleRepairitemsCommand>, "", NULL },
{ "waterwalk", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleWaterwalkCommand>, "", NULL },
{ "freeze", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleFreezeCommand>, "", NULL },
{ "unfreeze", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleUnFreezeCommand>, "", NULL },
{ "listfreeze", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleListFreezeCommand>, "", NULL },
{ "possess", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandlePossessCommand>, "", NULL },
{ "unpossess", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleUnPossessCommand>, "", NULL },
{ "bindsight", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleBindSightCommand>, "", NULL },
{ "unbindsight", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleUnbindSightCommand>, "", NULL },
{ "playall", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandlePlayAllCommand>, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
// cache for commands, needed because some commands are loaded dynamically through ScriptMgr
// cache is never freed and will show as a memory leak in diagnostic tools
// can't use vector as vector storage is implementation-dependent, eg, there can be alignment gaps between elements
static ChatCommand* commandTableCache = 0;
if (LoadCommandTable())
{
SetLoadCommandTable(false);
{
// count total number of top-level commands
size_t total = getCommandTableSize(commandTable);
std::vector const& dynamic = sScriptMgr->GetChatCommands();
for (std::vector::const_iterator it = dynamic.begin(); it != dynamic.end(); ++it)
total += getCommandTableSize(*it);
total += 1; // ending zero
// cache top-level commands
commandTableCache = (ChatCommand*)malloc(sizeof(ChatCommand) * total);
memset(commandTableCache, 0, sizeof(ChatCommand) * total);
ACE_ASSERT(commandTableCache);
size_t added = appendCommandTable(commandTableCache, commandTable);
for (std::vector::const_iterator it = dynamic.begin(); it != dynamic.end(); ++it)
added += appendCommandTable(commandTableCache + added, *it);
}
QueryResult result = WorldDatabase.Query("SELECT name,security,help FROM command");
if (result)
{
do
{
Field *fields = result->Fetch();
std::string name = fields[0].GetString();
SetDataForCommandInTable(commandTableCache, name.c_str(), fields[1].GetUInt16(), fields[2].GetString(), name);
} while (result->NextRow());
}
}
return commandTableCache;
}
const char *ChatHandler::GetTrinityString(int32 entry) const
{
return m_session->GetTrinityString(entry);
}
bool ChatHandler::isAvailable(ChatCommand const& cmd) const
{
// check security level only for simple command (without child commands)
return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel);
}
bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong)
{
WorldSession* target_session = NULL;
uint32 target_account = 0;
if (target)
target_session = target->GetSession();
else if (guid)
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)
{
uint32 target_sec;
// allow everything from console and RA console
if (!m_session)
return false;
// ignore only for non-players for non strong checks (when allow apply command at least to same sec level)
if (m_session->GetSecurity() > SEC_PLAYER && !strong && !sWorld.getBoolConfig(CONFIG_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)
AccountTypes target_ac_sec = AccountTypes(target_sec);
if (m_session->GetSecurity() < target_ac_sec || (strong && m_session->GetSecurity() <= target_ac_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 = strdup(str);
char* pos = buf;
while (char* line = LineFromMessage(pos))
{
FillSystemMessageData(&data, line);
m_session->SendPacket(&data);
}
free(buf);
}
void ChatHandler::SendGlobalSysMessage(const char *str)
{
// Chat output
WorldPacket data;
// need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = strdup(str);
char* pos = buf;
while (char* line = LineFromMessage(pos))
{
FillSystemMessageData(&data, line);
sWorld.SendGlobalMessage(&data);
}
free(buf);
}
void ChatHandler::SendGlobalGMSysMessage(const char *str)
{
// Chat output
WorldPacket data;
// need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = strdup(str);
char* pos = buf;
while (char* line = LineFromMessage(pos))
{
FillSystemMessageData(&data, line);
sWorld.SendGlobalGMMessage(&data);
}
free(buf);
}
void ChatHandler::SendSysMessage(int32 entry)
{
SendSysMessage(GetTrinityString(entry));
}
void ChatHandler::PSendSysMessage(int32 entry, ...)
{
const char *format = GetTrinityString(entry);
va_list ap;
char str [2048];
va_start(ap, entry);
vsnprintf(str,2048,format, ap);
va_end(ap);
SendSysMessage(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);
}
bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcmd)
{
char const* oldtext = text;
std::string cmd = "";
while (*text != ' ' && *text != '\0')
{
cmd += *text;
++text;
}
while (*text == ' ') ++text;
for (uint32 i = 0; table[i].Name != NULL; ++i)
{
if (!hasStringAbbr(table[i].Name, cmd.c_str()))
continue;
bool match = false;
if (strlen(table[i].Name) > strlen(cmd.c_str()))
{
for (uint32 j = 0; table[j].Name != NULL; ++j)
{
if (!hasStringAbbr(table[j].Name, cmd.c_str()))
continue;
if (strcmp(table[j].Name,cmd.c_str()) != 0)
continue;
else
{
match = true;
break;
}
}
}
if (match)
continue;
// select subcommand from child commands list
if (table[i].ChildCommands != NULL)
{
if (!ExecuteCommandInTable(table[i].ChildCommands, text, fullcmd))
{
if (text && text[0] != '\0')
SendSysMessage(LANG_NO_SUBCMD);
else
SendSysMessage(LANG_CMD_SYNTAX);
ShowHelpForCommand(table[i].ChildCommands,text);
}
return true;
}
// must be available and have handler
if (!table[i].Handler || !isAvailable(table[i]))
continue;
SetSentErrorMessage(false);
// table[i].Name == "" is special case: send original command to handler
if ((table[i].Handler)(this, strlen(table[i].Name) != 0 ? text : oldtext))
{
if (table[i].SecurityLevel > SEC_PLAYER)
{
// chat case
if (m_session)
{
Player* p = m_session->GetPlayer();
uint64 sel_guid = p->GetSelection();
sLog.outCommand(m_session->GetAccountId(),"Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected %s: %s (GUID: %u)]",
fullcmd.c_str(),p->GetName(),m_session->GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(),
GetLogNameForGuid(sel_guid), (p->GetSelectedUnit()) ? p->GetSelectedUnit()->GetName() : "", GUID_LOPART(sel_guid));
}
}
}
// some commands have custom error messages. Don't send the default one in these cases.
else if (!HasSentErrorMessage())
{
if (!table[i].Help.empty())
SendSysMessage(table[i].Help.c_str());
else
SendSysMessage(LANG_CMD_SYNTAX);
}
return true;
}
return false;
}
bool ChatHandler::SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand)
{
std::string cmd = "";
while (*text != ' ' && *text != '\0')
{
cmd += *text;
++text;
}
while (*text == ' ') ++text;
for (uint32 i = 0; table[i].Name != NULL; i++)
{
// for data fill use full explicit command names
if (table[i].Name != cmd)
continue;
// select subcommand from child commands list (including "")
if (table[i].ChildCommands != NULL)
{
if (SetDataForCommandInTable(table[i].ChildCommands, text, security, help, fullcommand))
return true;
else if (*text)
return false;
// fail with "" subcommands, then use normal level up command instead
}
// expected subcommand by full name DB content
else if (*text)
{
sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.",text,fullcommand.c_str());
return false;
}
if (table[i].SecurityLevel != security)
sLog.outDetail("Table `command` overwrite for command '%s' default security (%u) by %u",fullcommand.c_str(),table[i].SecurityLevel,security);
table[i].SecurityLevel = security;
table[i].Help = help;
return true;
}
// in case "" command let process by caller
if (!cmd.empty())
{
if (table == getCommandTable())
sLog.outErrorDb("Table `command` have not existed command '%s', skip.",cmd.c_str());
else
sLog.outErrorDb("Table `command` have not existed subcommand '%s' in command '%s', skip.",cmd.c_str(),fullcommand.c_str());
}
return false;
}
int ChatHandler::ParseCommands(const char* text)
{
ASSERT(text);
ASSERT(*text);
std::string fullcmd = text;
if (m_session && m_session->GetSecurity() <= SEC_PLAYER && sWorld.getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS) == 0)
return 0;
/// chat case (.command or !command format)
if (m_session)
{
if (text[0] != '!' && text[0] != '.')
return 0;
}
/// ignore single . and ! in line
if (strlen(text) < 2)
return 0;
// original `text` can't be used. It content destroyed in command code processing.
/// ignore messages staring from many dots.
if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
return 0;
/// skip first . or ! (in console allowed use command with . and ! and without its)
if (text[0] == '!' || text[0] == '.')
++text;
if (!ExecuteCommandInTable(getCommandTable(), text, fullcmd))
{
if (m_session && m_session->GetSecurity() == SEC_PLAYER)
return 0;
SendSysMessage(LANG_NO_CMD);
}
return 1;
}
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
|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|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
|cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
|cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|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.getIntConfig(CONFIG_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.getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2)
{
if (commandChar == *validSequenceIterator)
{
if (validSequenceIterator == validSequence+4)
validSequenceIterator = validSequence;
else
++validSequenceIterator;
}
else
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;
AchievementEntry const* linkedAchievement = NULL;
ItemRandomPropertiesEntry const* itemProperty = NULL;
ItemRandomSuffixEntry const* itemSuffix = NULL;
while (!reader.eof())
{
if (validSequence == validSequenceIterator)
{
linkedItem = NULL;
linkedQuest = NULL;
linkedSpell = NULL;
linkedAchievement = NULL;
itemProperty = NULL;
itemSuffix = NULL;
reader.ignore(255, '|');
}
else if (reader.get() != '|')
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage sequence aborted unexpectedly");
#endif
return false;
}
// pipe has always to be followed by at least one char
if (reader.peek() == '\0')
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage pipe followed by \\0");
#endif
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
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar);
#endif
return false;
}
}
else if (validSequence != validSequenceIterator)
{
// no escaped pipes in sequences
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got escaped pipe in sequence");
#endif
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)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got \\0 while reading color in |c command");
#endif
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;
}
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c);
#endif
return false;
}
break;
case 'H':
// read chars up to colon = link type
reader.getline(buffer, 256, ':');
if (strcmp(buffer, "item") == 0)
{
// read item entry
reader.getline(buffer, 256, ':');
linkedItem= ObjectMgr::GetItemPrototype(atoi(buffer));
if (!linkedItem)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer));
#endif
return false;
}
if (color != ItemQualityColors[linkedItem->Quality])
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality],
color);
#endif
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 = '\0';
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;
}
else if (propertyId < 0)
{
itemSuffix = sItemRandomSuffixStore.LookupEntry(-propertyId);
if (!itemSuffix)
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)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage Questtemplate %u not found", questid);
#endif
return false;
}
c = reader.peek();
// level
while (c !='|' && c != '\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if (strcmp(buffer, "trade") == 0)
{
if (color != CHAT_LINK_COLOR_TRADE)
return false;
// read spell entry
reader.getline(buffer, 256, ':');
linkedSpell = sSpellStore.LookupEntry(atoi(buffer));
if (!linkedSpell)
return false;
char c = reader.peek();
// base64 encoded stuff
while (c !='|' && c != '\0')
{
reader.ignore(1);
c = reader.peek();
}
}
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, ':');
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 if (strcmp(buffer, "achievement") == 0)
{
if (color != CHAT_LINK_COLOR_ACHIEVEMENT)
return false;
reader.getline(buffer, 256, ':');
uint32 achievementId = atoi(buffer);
linkedAchievement = sAchievementStore.LookupEntry(achievementId);
if (!linkedAchievement)
return false;
char c = reader.peek();
// skip progress
while (c !='|' && c != '\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if (strcmp(buffer, "glyph") == 0)
{
if (color != CHAT_LINK_COLOR_GLYPH)
return false;
// first id is slot, drop it
reader.getline(buffer, 256, ':');
uint32 glyphId = 0;
char c = reader.peek();
while (c >= '0' && c <= '9')
{
glyphId *= 10;
glyphId += c-'0';
reader.ignore(1);
c = reader.peek();
}
GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
if (!glyph)
return false;
linkedSpell = sSpellStore.LookupEntry(glyph->SpellId);
if (!linkedSpell)
return false;
}
else
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer);
#endif
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() != '[')
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage link caption doesn't start with '['");
#endif
return false;
}
reader.getline(buffer, 256, ']');
// verify the link name
if (linkedSpell)
{
// spells with that flag have a prefix of "$PROFESSION: "
if (linkedSpell->Attributes & SPELL_ATTR0_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 < TOTAL_LOCALES; ++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 < TOTAL_LOCALES; ++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)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage default questname didn't match and there is no locale");
#endif
return false;
}
bool foundName = false;
for (uint8 i=0; iTitle.size(); i++)
{
if (ql->Title[i] == buffer)
{
foundName = true;
break;
}
}
if (!foundName)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage no quest locale title matched");
#endif
return false;
}
}
}
else if (linkedItem)
{
char* const* suffix = itemSuffix?itemSuffix->nameSuffix:(itemProperty?itemProperty->nameSuffix:NULL);
std::string expectedName = std::string(linkedItem->Name1);
if (suffix)
{
expectedName += " ";
expectedName += suffix[LOCALE_enUS];
}
if (expectedName != buffer)
{
ItemLocale const *il = sObjectMgr->GetItemLocale(linkedItem->ItemId);
bool foundName = false;
for (uint8 dbIndex = LOCALE_koKR; dbIndex < TOTAL_LOCALES; ++dbIndex)
{
if (il == NULL || dbIndex >= il->Name.size())
// using strange database/client combinations can lead to this case
expectedName = linkedItem->Name1;
else
expectedName = il->Name[dbIndex];
if (suffix)
{
expectedName += " ";
expectedName += suffix[dbIndex];
}
if (expectedName == buffer)
{
foundName = true;
break;
}
}
if (!foundName)
{
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage linked item name wasn't found in any localization");
#endif
return false;
}
}
}
else if (linkedAchievement)
{
bool foundName = false;
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
if (*linkedAchievement->name[i] && strcmp(linkedAchievement->name[i], buffer) == 0)
{
foundName = true;
break;
}
}
if (!foundName)
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:
#ifdef TRINITY_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got invalid command |%c", commandChar);
#endif
return false;
}
}
// check if every opened sequence was also closed properly
#ifdef TRINITY_DEBUG
if (validSequence != validSequenceIterator)
sLog.outBasic("ChatHandler::isValidChatMessage EOF in active sequence");
#endif
return validSequence == validSequenceIterator;
}
bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd)
{
std::string list;
for (uint32 i = 0; table[i].Name != NULL; ++i)
{
// must be available (ignore handler existence for show command with possibe avalable subcomands
if (!isAvailable(table[i]))
continue;
/// for empty subcmd show all available
if (*subcmd && !hasStringAbbr(table[i].Name, subcmd))
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);
PSendSysMessage("%s",list.c_str());
}
else
PSendSysMessage(LANG_SUBCMDS_LIST,cmd,list.c_str());
return true;
}
bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd)
{
if (*cmd)
{
for (uint32 i = 0; table[i].Name != NULL; ++i)
{
// must be available (ignore handler existence for show command with possibe avalable subcomands
if (!isAvailable(table[i]))
continue;
if (!hasStringAbbr(table[i].Name, cmd))
continue;
// have subcommand
char const* subcmd = (*cmd) ? strtok(NULL, " ") : "";
if (table[i].ChildCommands && subcmd && *subcmd)
{
if (ShowHelpForCommand(table[i].ChildCommands, subcmd))
return true;
}
if (!table[i].Help.empty())
SendSysMessage(table[i].Help.c_str());
if (table[i].ChildCommands)
if (ShowHelpForSubCommands(table[i].ChildCommands,table[i].Name,subcmd ? subcmd : ""))
return true;
return !table[i].Help.empty();
}
}
else
{
for (uint32 i = 0; table[i].Name != NULL; ++i)
{
// must be available (ignore handler existence for show command with possibe avalable subcomands
if (!isAvailable(table[i]))
continue;
if (strlen(table[i].Name))
continue;
if (!table[i].Help.empty())
SendSysMessage(table[i].Help.c_str());
if (table[i].ChildCommands)
if (ShowHelpForSubCommands(table[i].ChildCommands,"",""))
return true;
return !table[i].Help.empty();
}
}
return ShowHelpForSubCommands(table,"",cmd);
}
//Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored)
void ChatHandler::FillMessageData(WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker)
{
uint32 messageLength = (message ? strlen(message) : 0) + 1;
data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
*data << uint8(type);
if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON)
*data << uint32(language);
else
*data << uint32(LANG_UNIVERSAL);
switch(type)
{
case CHAT_MSG_SAY:
case CHAT_MSG_PARTY:
case CHAT_MSG_PARTY_LEADER:
case CHAT_MSG_RAID:
case CHAT_MSG_GUILD:
case CHAT_MSG_OFFICER:
case CHAT_MSG_YELL:
case CHAT_MSG_WHISPER:
case CHAT_MSG_CHANNEL:
case CHAT_MSG_RAID_LEADER:
case CHAT_MSG_RAID_WARNING:
case CHAT_MSG_BG_SYSTEM_NEUTRAL:
case CHAT_MSG_BG_SYSTEM_ALLIANCE:
case CHAT_MSG_BG_SYSTEM_HORDE:
case CHAT_MSG_BATTLEGROUND:
case CHAT_MSG_BATTLEGROUND_LEADER:
target_guid = session ? session->GetPlayer()->GetGUID() : 0;
break;
case CHAT_MSG_MONSTER_SAY:
case CHAT_MSG_MONSTER_PARTY:
case CHAT_MSG_MONSTER_YELL:
case CHAT_MSG_MONSTER_WHISPER:
case CHAT_MSG_MONSTER_EMOTE:
case CHAT_MSG_RAID_BOSS_WHISPER:
case CHAT_MSG_RAID_BOSS_EMOTE:
case CHAT_MSG_BATTLENET:
{
*data << uint64(speaker->GetGUID());
*data << uint32(0); // 2.1.0
*data << uint32(strlen(speaker->GetName()) + 1);
*data << speaker->GetName();
uint64 listener_guid = 0;
*data << uint64(listener_guid);
if (listener_guid && !IS_PLAYER_GUID(listener_guid))
{
*data << uint32(1); // string listener_name_length
*data << uint8(0); // string listener_name
}
*data << uint32(messageLength);
*data << message;
*data << uint8(0);
return;
}
default:
if (type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
target_guid = 0; // only for CHAT_MSG_WHISPER_INFORM used original value target_guid
break;
}
*data << uint64(target_guid); // there 0 for BG messages
*data << uint32(0); // can be chat msg group or something
if (type == CHAT_MSG_CHANNEL)
{
ASSERT(channelName);
*data << channelName;
}
*data << uint64(target_guid);
*data << uint32(messageLength);
*data << message;
if (session != 0 && type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
*data << uint8(session->GetPlayer()->chatTag());
else
*data << uint8(0);
}
Player * ChatHandler::getSelectedPlayer()
{
if (!m_session)
return NULL;
uint64 guid = m_session->GetPlayer()->GetSelection();
if (guid == 0)
return m_session->GetPlayer();
return sObjectMgr->GetPlayer(guid);
}
Unit* ChatHandler::getSelectedUnit()
{
if (!m_session)
return NULL;
uint64 guid = m_session->GetPlayer()->GetSelection();
if (guid == 0)
return m_session->GetPlayer();
return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid);
}
WorldObject *ChatHandler::getSelectedObject()
{
if (!m_session)
return NULL;
uint64 guid = m_session->GetPlayer()->GetSelection();
if (guid == 0)
return GetNearbyGameObject();
return ObjectAccessor::GetUnit(*m_session->GetPlayer(),guid);
}
Creature* ChatHandler::getSelectedCreature()
{
if (!m_session)
return NULL;
return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(),m_session->GetPlayer()->GetSelection());
}
char* ChatHandler::extractKeyFromLink(char* text, char const* linkType, char** something1)
{
// skip empty
if (!text)
return NULL;
// skip spaces
while (*text == ' '||*text == '\t'||*text == '\b')
++text;
if (!*text)
return NULL;
// return non link case
if (text[0] != '|')
return strtok(text, " ");
// [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
char* check = strtok(text, "|"); // skip color
if (!check)
return NULL; // end of data
char* cLinkType = strtok(NULL, ":"); // linktype
if (!cLinkType)
return NULL; // end of data
if (strcmp(cLinkType,linkType) != 0)
{
strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after retturn from function
SendSysMessage(LANG_WRONG_LINK_TYPE);
return NULL;
}
char* cKeys = strtok(NULL, "|"); // extract keys and values
char* cKeysTail = strtok(NULL, "");
char* cKey = strtok(cKeys, ":|"); // extract key
if (something1)
*something1 = strtok(NULL, ":|"); // extract something
strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces
strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function
return cKey;
}
char* ChatHandler::extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1)
{
// skip empty
if (!text)
return NULL;
// skip spaces
while (*text == ' '||*text == '\t'||*text == '\b')
++text;
if (!*text)
return NULL;
// return non link case
if (text[0] != '|')
return strtok(text, " ");
// [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
char* tail;
if (text[1] == 'c')
{
char* check = strtok(text, "|"); // skip color
if (!check)
return NULL; // end of data
tail = strtok(NULL, ""); // tail
}
else
tail = text+1; // skip first |
char* cLinkType = strtok(tail, ":"); // linktype
if (!cLinkType)
return NULL; // end of data
for (int i = 0; linkTypes[i]; ++i)
{
if (strcmp(cLinkType,linkTypes[i]) == 0)
{
char* cKeys = strtok(NULL, "|"); // extract keys and values
char* cKeysTail = strtok(NULL, "");
char* cKey = strtok(cKeys, ":|"); // extract key
if (something1)
*something1 = strtok(NULL, ":|"); // extract something
strtok(cKeysTail, "]"); // restart scan tail and skip name with possible spaces
strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function
if (found_idx)
*found_idx = i;
return cKey;
}
}
strtok(NULL, " "); // skip link tail (to allow continue strtok(NULL,s) use after return from function
SendSysMessage(LANG_WRONG_LINK_TYPE);
return NULL;
}
char const *fmtstring(char const *format, ...)
{
va_list argptr;
#define MAX_FMT_STRING 32000
static char temp_buffer[MAX_FMT_STRING];
static char string[MAX_FMT_STRING];
static int index = 0;
char *buf;
int len;
va_start(argptr, format);
vsnprintf(temp_buffer,MAX_FMT_STRING, format, argptr);
va_end(argptr);
len = strlen(temp_buffer);
if (len >= MAX_FMT_STRING)
return "ERROR";
if (len + index >= MAX_FMT_STRING-1)
{
index = 0;
}
buf = &string[index];
memcpy(buf, temp_buffer, len+1);
index += len + 1;
return buf;
}
GameObject* ChatHandler::GetNearbyGameObject()
{
if (!m_session)
return NULL;
Player* pl = m_session->GetPlayer();
GameObject* obj = NULL;
Trinity::NearestGameObjectCheck check(*pl);
Trinity::GameObjectLastSearcher searcher(pl, obj, check);
pl->VisitNearbyGridObject(999, searcher);
return obj;
}
GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry)
{
if (!m_session)
return NULL;
Player* pl = m_session->GetPlayer();
GameObject* obj = pl->GetMap()->GetGameObject(MAKE_NEW_GUID(lowguid, entry, HIGHGUID_GAMEOBJECT));
if (!obj && sObjectMgr->GetGOData(lowguid)) // guid is DB guid of object
{
// search near player then
CellPair p(Trinity::ComputeCellPair(pl->GetPositionX(), pl->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::GameObjectWithDbGUIDCheck go_check(*pl,lowguid);
Trinity::GameObjectSearcher checker(pl,obj,go_check);
TypeContainerVisitor, GridTypeMapContainer > object_checker(checker);
cell.Visit(p, object_checker, *pl->GetMap());
}
return obj;
}
enum SpellLinkType
{
SPELL_LINK_SPELL = 0,
SPELL_LINK_TALENT = 1,
SPELL_LINK_ENCHANT = 2,
SPELL_LINK_TRADE = 3,
SPELL_LINK_GLYPH = 4
};
static char const* const spellKeys[] =
{
"Hspell", // normal spell
"Htalent", // talent spell
"Henchant", // enchanting recipe spell
"Htrade", // profession/skill spell
"Hglyph", // glyph
0
};
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|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|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
// number or [name] Shift-click form |color|Htrade:spell_id,skill_id,max_value,cur_value|h[name]|h|r
int type = 0;
char* param1_str = NULL;
char* idS = extractKeyFromLink(text,spellKeys,&type,¶m1_str);
if (!idS)
return 0;
uint32 id = (uint32)atol(idS);
switch(type)
{
case SPELL_LINK_SPELL:
return id;
case SPELL_LINK_TALENT:
{
// talent
TalentEntry const* talentEntry = sTalentStore.LookupEntry(id);
if (!talentEntry)
return 0;
int32 rank = param1_str ? (uint32)atol(param1_str) : 0;
if (rank >= MAX_TALENT_RANK)
return 0;
if (rank < 0)
rank = 0;
return talentEntry->RankID[rank];
}
case SPELL_LINK_ENCHANT:
case SPELL_LINK_TRADE:
return id;
case SPELL_LINK_GLYPH:
{
uint32 glyph_prop_id = param1_str ? (uint32)atol(param1_str) : 0;
GlyphPropertiesEntry const* glyphPropEntry = sGlyphPropertiesStore.LookupEntry(glyph_prop_id);
if (!glyphPropEntry)
return 0;
return glyphPropEntry->SpellId;
}
}
// 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 false;
// id case (explicit or from shift link)
if (cId[0] >= '0' || cId[0] >= '9')
if (uint32 id = atoi(cId))
return sObjectMgr->GetGameTele(id);
return sObjectMgr->GetGameTele(cId);
}
enum GuidLinkType
{
SPELL_LINK_PLAYER = 0, // must be first for selection in not link case
SPELL_LINK_CREATURE = 1,
SPELL_LINK_GAMEOBJECT = 2
};
static char const* const guidKeys[] =
{
"Hplayer",
"Hcreature",
"Hgameobject",
0
};
uint64 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 0;
switch(type)
{
case SPELL_LINK_PLAYER:
{
std::string name = idS;
if (!normalizePlayerName(name))
return 0;
if (Player* player = sObjectMgr->GetPlayer(name.c_str()))
return player->GetGUID();
if (uint64 guid = sObjectMgr->GetPlayerGUIDByName(name))
return guid;
return 0;
}
case SPELL_LINK_CREATURE:
{
uint32 lowguid = (uint32)atol(idS);
if (CreatureData const* data = sObjectMgr->GetCreatureData(lowguid))
return MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT);
else
return 0;
}
case SPELL_LINK_GAMEOBJECT:
{
uint32 lowguid = (uint32)atol(idS);
if (GameObjectData const* data = sObjectMgr->GetGOData(lowguid))
return MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_GAMEOBJECT);
else
return 0;
}
}
// unknown type?
return 0;
}
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;
}
bool ChatHandler::extractPlayerTarget(char* args, Player** player, uint64* 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)
uint64 guid = !pl && (player_guid || player_name) ? sObjectMgr->GetPlayerGUIDByName(name) : 0;
// if allowed player guid (if no then only online players allowed)
if (player_guid)
*player_guid = pl ? pl->GetGUID() : 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->GetGUID() : 0;
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;
}
void ChatHandler::extractOptFirstArg(char* args, char** arg1, char** arg2)
{
char* p1 = strtok(args, " ");
char* p2 = strtok(NULL, " ");
if (!p2)
{
p2 = p1;
p1 = NULL;
}
if (arg1)
*arg1 = p1;
if (arg2)
*arg2 = p2;
}
char* ChatHandler::extractQuotedArg(char* args)
{
if (!*args)
return NULL;
if (*args == '"')
return strtok(args+1, "\"");
else
{
char* space = strtok(args, "\"");
if (!space)
return false;
return strtok(NULL, "\"");
}
}
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::GetTrinityString(int32 entry) const
{
return sObjectMgr->GetTrinityStringForDBCLocale(entry);
}
bool CliHandler::isAvailable(ChatCommand const& cmd) const
{
// skip non-console commands in console case
return cmd.AllowConsole;
}
void CliHandler::SendSysMessage(const char *str)
{
m_print(m_callbackArg, str);
m_print(m_callbackArg, "\r\n");
}
std::string CliHandler::GetNameLink() const
{
return GetTrinityString(LANG_CONSOLE_COMMAND);
}
bool CliHandler::needReportToTarget(Player* /*chr*/) const
{
return true;
}
bool ChatHandler::GetPlayerGroupAndGUIDByName(const char* cname, Player* &plr, Group* &group, uint64 &guid, bool offline)
{
plr = NULL;
guid = 0;
if (cname)
{
std::string name = cname;
if (!name.empty())
{
if (!normalizePlayerName(name))
{
PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
plr = sObjectMgr->GetPlayer(name.c_str());
if (offline)
guid = sObjectMgr->GetPlayerGUIDByName(name.c_str());
}
}
if (plr)
{
group = plr->GetGroup();
if (!guid || !offline)
guid = plr->GetGUID();
}
else
{
if (getSelectedPlayer())
plr = getSelectedPlayer();
else
plr = m_session->GetPlayer();
if (!guid || !offline)
guid = plr->GetGUID();
group = plr->GetGroup();
}
return true;
}
LocaleConstant CliHandler::GetSessionDbcLocale() const
{
return sWorld.GetDefaultDbcLocale();
}
int CliHandler::GetSessionDbLocaleIndex() const
{
return sObjectMgr->GetDBCLocaleIndex();
}