Updated Copyright year to 2013
[getmangos.git] / src / game / Chat.cpp
blobaf209c0120c93a1c61232537a0f7b767865c3774
1 /*
2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Chat.h"
20 #include "Language.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "World.h"
27 #include "ObjectMgr.h"
28 #include "ObjectGuid.h"
29 #include "Player.h"
30 #include "UpdateMask.h"
31 #include "GridNotifiersImpl.h"
32 #include "CellImpl.h"
33 #include "AccountMgr.h"
34 #include "SpellMgr.h"
35 #include "PoolManager.h"
36 #include "GameEventMgr.h"
37 #include "AuctionHouseBot/AuctionHouseBot.h"
39 // Supported shift-links (client generated and server side)
40 // |color|Hachievement:achievement_id:player_guid_hex:completed_0_1:mm:dd:yy_from_2000:criteriaMask1:criteriaMask2:criteriaMask3:criteriaMask4|h[name]|h|r
41 // - client, item icon shift click, not used in server currently
42 // |color|Hachievement_criteria:criteria_id|h[name]|h|r
43 // |color|Harea:area_id|h[name]|h|r
44 // |color|Hareatrigger:id|h[name]|h|r
45 // |color|Hareatrigger_target:id|h[name]|h|r
46 // |color|Hcreature:creature_guid|h[name]|h|r
47 // |color|Hcreature_entry:creature_id|h[name]|h|r
48 // |color|Hcurrency:currency_id||h[name]|h|r
49 // |color|Hinstancelock:player_guid:map_id:is_completed:encounter_mask|h[instance_name]|h|r
50 // |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r - client, at shift click in recipes list dialog
51 // |color|Hgameevent:id|h[name]|h|r
52 // |color|Hgameobject:go_guid|h[name]|h|r
53 // |color|Hgameobject_entry:go_id|h[name]|h|r
54 // |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r - client, at shift click in glyphs dialog, GlyphSlot.dbc, GlyphProperties.dbc
55 // |color|Hitem:item_id:perm_ench_id:gem1:gem2:gem3:0:0:0:0:reporter_level|h[name]|h|r
56 // - client, item icon shift click
57 // |color|Hitemset:itemset_id|h[name]|h|r
58 // |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
59 // |color|Hpool:pool_id|h[name]|h|r
60 // |color|Hquest:quest_id:quest_level|h[name]|h|r - client, quest list name shift-click
61 // |color|Hskill:skill_id|h[name]|h|r
62 // |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click
63 // |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click rank==-1 if shift-copy unlearned talent
64 // |color|Htaxinode:id|h[name]|h|r
65 // |color|Htele:id|h[name]|h|r
66 // |color|Htitle:id|h[name]|h|r
67 // |color|Htrade:spell_id:cur_value:max_value:unk3int:unk3str|h[name]|h|r - client, spellbook profession icon shift-click
69 bool ChatHandler::load_command_table = true;
71 ChatCommand* ChatHandler::getCommandTable()
73 static ChatCommand accountSetCommandTable[] =
75 { "addon", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountSetAddonCommand, "", NULL },
76 { "gmlevel", SEC_CONSOLE, true, &ChatHandler::HandleAccountSetGmLevelCommand, "", NULL },
77 { "password", SEC_CONSOLE, true, &ChatHandler::HandleAccountSetPasswordCommand, "", NULL },
78 { NULL, 0, false, NULL, "", NULL }
81 static ChatCommand accountCommandTable[] =
83 { "characters", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountCharactersCommand, "", NULL },
84 { "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL },
85 { "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL },
86 { "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL },
87 { "lock", SEC_PLAYER, true, &ChatHandler::HandleAccountLockCommand, "", NULL },
88 { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable },
89 { "password", SEC_PLAYER, true, &ChatHandler::HandleAccountPasswordCommand, "", NULL },
90 { "", SEC_PLAYER, true, &ChatHandler::HandleAccountCommand, "", NULL },
91 { NULL, 0, false, NULL, "", NULL }
94 static ChatCommand achievementCriteriaCommandTable[] =
96 { "add", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAchievementCriteriaAddCommand, "", NULL },
97 { "remove", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAchievementCriteriaRemoveCommand, "", NULL },
98 { NULL, 0, true, NULL, "", NULL }
101 static ChatCommand achievementCommandTable[] =
103 { "criteria", SEC_ADMINISTRATOR, true, NULL, "", achievementCriteriaCommandTable },
104 { "add", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAchievementAddCommand, "", NULL },
105 { "remove", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAchievementRemoveCommand, "", NULL },
106 { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAchievementCommand, "", NULL },
107 { NULL, 0, true, NULL, "", NULL }
110 static ChatCommand ahbotItemsAmountCommandTable[] =
112 { "grey", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GREY>, "", NULL },
113 { "white", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_WHITE>, "", NULL },
114 { "green", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GREEN>, "", NULL },
115 { "blue", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_BLUE>, "", NULL },
116 { "purple", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_PURPLE>, "", NULL },
117 { "orange", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_ORANGE>, "", NULL },
118 { "yellow", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_YELLOW>, "", NULL },
119 { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsAmountCommand, "", NULL },
120 { NULL, 0, true, NULL, "", NULL }
123 static ChatCommand ahbotItemsRatioCommandTable[] =
125 { "alliance", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_ALLIANCE>, "", NULL },
126 { "horde", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_HORDE>, "", NULL },
127 { "neutral", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_NEUTRAL>, "", NULL },
128 { "", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotItemsRatioCommand, "", NULL },
129 { NULL, 0, true, NULL, "", NULL }
132 static ChatCommand ahbotItemsCommandTable[] =
134 { "amount", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsAmountCommandTable},
135 { "ratio", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsRatioCommandTable},
136 { NULL, 0, true, NULL, "", NULL }
139 static ChatCommand ahbotCommandTable[] =
141 { "items", SEC_ADMINISTRATOR, true, NULL, "", ahbotItemsCommandTable},
142 { "rebuild", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotRebuildCommand, "", NULL },
143 { "reload", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotReloadCommand, "", NULL },
144 { "status", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAHBotStatusCommand, "", NULL },
145 { NULL, 0, true, NULL, "", NULL }
148 static ChatCommand auctionCommandTable[] =
150 { "alliance", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionAllianceCommand, "", NULL },
151 { "goblin", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionGoblinCommand, "", NULL },
152 { "horde", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionHordeCommand, "", NULL },
153 { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAuctionItemCommand, "", NULL },
154 { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuctionCommand, "", NULL },
155 { NULL, 0, false, NULL, "", NULL }
158 static ChatCommand banCommandTable[] =
160 { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanAccountCommand, "", NULL },
161 { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanCharacterCommand, "", NULL },
162 { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanIPCommand, "", NULL },
163 { NULL, 0, false, NULL, "", NULL }
166 static ChatCommand baninfoCommandTable[] =
168 { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoAccountCommand, "", NULL },
169 { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoCharacterCommand, "", NULL },
170 { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanInfoIPCommand, "", NULL },
171 { NULL, 0, false, NULL, "", NULL }
174 static ChatCommand banlistCommandTable[] =
176 { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListAccountCommand, "", NULL },
177 { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListCharacterCommand, "", NULL },
178 { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleBanListIPCommand, "", NULL },
179 { NULL, 0, false, NULL, "", NULL }
182 static ChatCommand castCommandTable[] =
184 { "back", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastBackCommand, "", NULL },
185 { "dist", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastDistCommand, "", NULL },
186 { "self", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastSelfCommand, "", NULL },
187 { "target", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastTargetCommand, "", NULL },
188 { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCastCommand, "", NULL },
189 { NULL, 0, false, NULL, "", NULL }
192 static ChatCommand characterDeletedCommandTable[] =
194 { "delete", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeletedDeleteCommand, "", NULL },
195 { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterDeletedListCommand, "", NULL },
196 { "restore", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterDeletedRestoreCommand, "", NULL },
197 { "old", SEC_CONSOLE, true, &ChatHandler::HandleCharacterDeletedOldCommand, "", NULL },
198 { NULL, 0, false, NULL, "", NULL }
201 static ChatCommand characterCommandTable[] =
203 { "achievements", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterAchievementsCommand, "", NULL },
204 { "customize", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterCustomizeCommand, "", NULL },
205 { "deleted", SEC_GAMEMASTER, true, NULL, "", characterDeletedCommandTable},
206 { "erase", SEC_CONSOLE, true, &ChatHandler::HandleCharacterEraseCommand, "", NULL },
207 { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleCharacterLevelCommand, "", NULL },
208 { "rename", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterRenameCommand, "", NULL },
209 { "reputation", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterReputationCommand, "", NULL },
210 { "titles", SEC_GAMEMASTER, true, &ChatHandler::HandleCharacterTitlesCommand, "", NULL },
211 { NULL, 0, false, NULL, "", NULL }
214 static ChatCommand debugPlayCommandTable[] =
216 { "cinematic", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlayCinematicCommand, "", NULL },
217 { "movie", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlayMovieCommand, "", NULL },
218 { "sound", SEC_MODERATOR, false, &ChatHandler::HandleDebugPlaySoundCommand, "", NULL },
219 { NULL, 0, false, NULL, "", NULL }
222 static ChatCommand debugSendCommandTable[] =
224 { "buyerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendBuyErrorCommand, "", NULL },
225 { "channelnotify", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChannelNotifyCommand, "", NULL },
226 { "chatmmessage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendChatMsgCommand, "", NULL },
227 { "equiperror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendEquipErrorCommand, "", NULL },
228 { "largepacket", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendLargePacketCommand, "", NULL },
229 { "opcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendOpcodeCommand, "", NULL },
230 { "poi", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendPoiCommand, "", NULL },
231 { "qpartymsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestPartyMsgCommand, "", NULL },
232 { "qinvalidmsg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendQuestInvalidMsgCommand, "", NULL },
233 { "sellerror", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSellErrorCommand, "", NULL },
234 { "setphaseshift", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSetPhaseShiftCommand, "", NULL },
235 { "spellfail", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSendSpellFailCommand, "", NULL },
236 { NULL, 0, false, NULL, "", NULL }
239 static ChatCommand debugCommandTable[] =
241 { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL },
242 { "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL },
243 { "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL },
244 { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemStateCommand, "", NULL },
245 { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipientCommand, "", NULL },
246 { "getitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemValueCommand, "", NULL },
247 { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValueCommand, "", NULL },
248 { "moditemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugModItemValueCommand, "", NULL },
249 { "modvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugModValueCommand, "", NULL },
250 { "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable },
251 { "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable },
252 { "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL },
253 { "setitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemValueCommand, "", NULL },
254 { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL },
255 { "spellcheck", SEC_CONSOLE, true, &ChatHandler::HandleDebugSpellCheckCommand, "", NULL },
256 { "spellcoefs", SEC_ADMINISTRATOR, true, &ChatHandler::HandleDebugSpellCoefsCommand, "", NULL },
257 { "spellmods", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpellModsCommand, "", NULL },
258 { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateWorldStateCommand, "", NULL },
259 { NULL, 0, false, NULL, "", NULL }
262 static ChatCommand eventCommandTable[] =
264 { "list", SEC_GAMEMASTER, true, &ChatHandler::HandleEventListCommand, "", NULL },
265 { "start", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStartCommand, "", NULL },
266 { "stop", SEC_GAMEMASTER, true, &ChatHandler::HandleEventStopCommand, "", NULL },
267 { "", SEC_GAMEMASTER, true, &ChatHandler::HandleEventInfoCommand, "", NULL },
268 { NULL, 0, false, NULL, "", NULL }
271 static ChatCommand gmCommandTable[] =
273 { "chat", SEC_MODERATOR, false, &ChatHandler::HandleGMChatCommand, "", NULL },
274 { "fly", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGMFlyCommand, "", NULL },
275 { "ingame", SEC_PLAYER, true, &ChatHandler::HandleGMListIngameCommand, "", NULL },
276 { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMListFullCommand, "", NULL },
277 { "visible", SEC_MODERATOR, false, &ChatHandler::HandleGMVisibleCommand, "", NULL },
278 { "setview", SEC_MODERATOR, false, &ChatHandler::HandleSetViewCommand, "", NULL },
279 { "", SEC_MODERATOR, false, &ChatHandler::HandleGMCommand, "", NULL },
280 { NULL, 0, false, NULL, "", NULL }
283 static ChatCommand goCommandTable[] =
285 { "creature", SEC_MODERATOR, false, &ChatHandler::HandleGoCreatureCommand, "", NULL },
286 { "graveyard", SEC_MODERATOR, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL },
287 { "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL },
288 { "object", SEC_MODERATOR, false, &ChatHandler::HandleGoObjectCommand, "", NULL },
289 { "taxinode", SEC_MODERATOR, false, &ChatHandler::HandleGoTaxinodeCommand, "", NULL },
290 { "trigger", SEC_MODERATOR, false, &ChatHandler::HandleGoTriggerCommand, "", NULL },
291 { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL },
292 { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL },
293 { "xyz", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL },
294 { "", SEC_MODERATOR, false, &ChatHandler::HandleGoCommand, "", NULL },
295 { NULL, 0, false, NULL, "", NULL }
298 static ChatCommand gobjectCommandTable[] =
300 { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectAddCommand, "", NULL },
301 { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectDeleteCommand, "", NULL },
302 { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectMoveCommand, "", NULL },
303 { "near", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectNearCommand, "", NULL },
304 { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectPhaseCommand, "", NULL },
305 { "target", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTargetCommand, "", NULL },
306 { "turn", SEC_GAMEMASTER, false, &ChatHandler::HandleGameObjectTurnCommand, "", NULL },
307 { NULL, 0, false, NULL, "", NULL }
310 static ChatCommand guildCommandTable[] =
312 { "create", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildCreateCommand, "", NULL },
313 { "delete", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildDeleteCommand, "", NULL },
314 { "invite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildInviteCommand, "", NULL },
315 { "uninvite", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildUninviteCommand, "", NULL },
316 { "rank", SEC_GAMEMASTER, true, &ChatHandler::HandleGuildRankCommand, "", NULL },
317 { NULL, 0, false, NULL, "", NULL }
320 static ChatCommand honorCommandTable[] =
322 { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddCommand, "", NULL },
323 { "addkill", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorAddKillCommand, "", NULL },
324 { "updatekills", SEC_GAMEMASTER, false, &ChatHandler::HandleHonorKillsUpdateCommand, "", NULL },
325 { NULL, 0, false, NULL, "", NULL }
328 static ChatCommand instanceCommandTable[] =
330 { "listbinds", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceListBindsCommand, "", NULL },
331 { "unbind", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceUnbindCommand, "", NULL },
332 { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleInstanceStatsCommand, "", NULL },
333 { "savedata", SEC_ADMINISTRATOR, false, &ChatHandler::HandleInstanceSaveDataCommand, "", NULL },
334 { NULL, 0, false, NULL, "", NULL }
337 static ChatCommand learnCommandTable[] =
339 { "all", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllCommand, "", NULL },
340 { "all_gm", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllGMCommand, "", NULL },
341 { "all_crafts", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllCraftsCommand, "", NULL },
342 { "all_default", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllDefaultCommand, "", NULL },
343 { "all_lang", SEC_MODERATOR, false, &ChatHandler::HandleLearnAllLangCommand, "", NULL },
344 { "all_myclass", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyClassCommand, "", NULL },
345 { "all_mypettalents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyPetTalentsCommand, "", NULL },
346 { "all_myspells", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMySpellsCommand, "", NULL },
347 { "all_mytalents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnAllMyTalentsCommand, "", NULL },
348 { "all_recipes", SEC_GAMEMASTER, false, &ChatHandler::HandleLearnAllRecipesCommand, "", NULL },
349 { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLearnCommand, "", NULL },
350 { NULL, 0, false, NULL, "", NULL }
353 static ChatCommand listCommandTable[] =
355 { "auras", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListAurasCommand, "", NULL },
356 { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListCreatureCommand, "", NULL },
357 { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListItemCommand, "", NULL },
358 { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleListObjectCommand, "", NULL },
359 { "talents", SEC_ADMINISTRATOR, false, &ChatHandler::HandleListTalentsCommand, "", NULL },
360 { NULL, 0, false, NULL, "", NULL }
363 static ChatCommand lookupAccountCommandTable[] =
365 { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountEmailCommand, "", NULL },
366 { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountIpCommand, "", NULL },
367 { "name", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAccountNameCommand, "", NULL },
368 { NULL, 0, false, NULL, "", NULL }
371 static ChatCommand lookupPlayerCommandTable[] =
373 { "account", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL },
374 { "email", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL },
375 { "ip", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL },
376 { NULL, 0, false, NULL, "", NULL }
379 static ChatCommand lookupCommandTable[] =
381 { "account", SEC_GAMEMASTER, true, NULL, "", lookupAccountCommandTable },
382 { "achievement", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupAchievementCommand, "", NULL },
383 { "area", SEC_MODERATOR, true, &ChatHandler::HandleLookupAreaCommand, "", NULL },
384 { "creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupCreatureCommand, "", NULL },
385 { "currency", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupCurrencyCommand, "", NULL },
386 { "event", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupEventCommand, "", NULL },
387 { "faction", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupFactionCommand, "", NULL },
388 { "item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemCommand, "", NULL },
389 { "itemset", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupItemSetCommand, "", NULL },
390 { "object", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupObjectCommand, "", NULL },
391 { "quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupQuestCommand, "", NULL },
392 { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable },
393 { "pool", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupPoolCommand, "", NULL },
394 { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL },
395 { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL },
396 { "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL },
397 { "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL },
398 { "title", SEC_GAMEMASTER, true, &ChatHandler::HandleLookupTitleCommand, "", NULL },
399 { NULL, 0, false, NULL, "", NULL }
402 static ChatCommand mmapCommandTable[] =
404 { "path", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapPathCommand, "", NULL },
405 { "loc", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLocCommand, "", NULL },
406 { "loadedtiles", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapLoadedTilesCommand, "", NULL },
407 { "stats", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapStatsCommand, "", NULL },
408 { "testarea", SEC_GAMEMASTER, false, &ChatHandler::HandleMmapTestArea, "", NULL },
409 { "", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMmap, "", NULL },
410 { NULL, 0, false, NULL, "", NULL }
413 static ChatCommand modifyCommandTable[] =
415 { "currency", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyCurrencyCommand, "", NULL },
416 { "holypower", SEC_MODERATOR, false, &ChatHandler::HandleModifyHolyPowerCommand, "", NULL },
417 { "hp", SEC_MODERATOR, false, &ChatHandler::HandleModifyHPCommand, "", NULL },
418 { "mana", SEC_MODERATOR, false, &ChatHandler::HandleModifyManaCommand, "", NULL },
419 { "rage", SEC_MODERATOR, false, &ChatHandler::HandleModifyRageCommand, "", NULL },
420 { "runicpower", SEC_MODERATOR, false, &ChatHandler::HandleModifyRunicPowerCommand, "", NULL },
421 { "energy", SEC_MODERATOR, false, &ChatHandler::HandleModifyEnergyCommand, "", NULL },
422 { "money", SEC_MODERATOR, false, &ChatHandler::HandleModifyMoneyCommand, "", NULL },
423 { "speed", SEC_MODERATOR, false, &ChatHandler::HandleModifySpeedCommand, "", NULL },
424 { "swim", SEC_MODERATOR, false, &ChatHandler::HandleModifySwimCommand, "", NULL },
425 { "scale", SEC_MODERATOR, false, &ChatHandler::HandleModifyScaleCommand, "", NULL },
426 { "bwalk", SEC_MODERATOR, false, &ChatHandler::HandleModifyBWalkCommand, "", NULL },
427 { "fly", SEC_MODERATOR, false, &ChatHandler::HandleModifyFlyCommand, "", NULL },
428 { "aspeed", SEC_MODERATOR, false, &ChatHandler::HandleModifyASpeedCommand, "", NULL },
429 { "faction", SEC_MODERATOR, false, &ChatHandler::HandleModifyFactionCommand, "", NULL },
430 { "tp", SEC_MODERATOR, false, &ChatHandler::HandleModifyTalentCommand, "", NULL },
431 { "mount", SEC_MODERATOR, false, &ChatHandler::HandleModifyMountCommand, "", NULL },
432 { "rep", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyRepCommand, "", NULL },
433 { "drunk", SEC_MODERATOR, false, &ChatHandler::HandleModifyDrunkCommand, "", NULL },
434 { "standstate", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyStandStateCommand, "", NULL },
435 { "morph", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyMorphCommand, "", NULL },
436 { "phase", SEC_ADMINISTRATOR, false, &ChatHandler::HandleModifyPhaseCommand, "", NULL },
437 { "gender", SEC_GAMEMASTER, false, &ChatHandler::HandleModifyGenderCommand, "", NULL },
438 { NULL, 0, false, NULL, "", NULL }
441 static ChatCommand npcCommandTable[] =
443 { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL },
444 { "addcurrency", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorCurrencyCommand,"", NULL },
445 { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL },
446 { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL },
447 { "aiinfo", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAIInfoCommand, "", NULL },
448 { "allowmove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAllowMovementCommand, "", NULL },
449 { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL },
450 { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL },
451 { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL },
452 { "delcurrency", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorCurrencyCommand,"", NULL },
453 { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDelVendorItemCommand, "", NULL },
454 { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL },
455 { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL },
456 { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL },
457 { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL },
458 { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL },
459 { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL },
460 { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL },
461 { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL },
462 { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetPhaseCommand, "", NULL },
463 { "spawndist", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnDistCommand, "", NULL },
464 { "spawntime", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnTimeCommand, "", NULL },
465 { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL },
466 { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL },
467 { "unfollow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcUnFollowCommand, "", NULL },
468 { "whisper", SEC_MODERATOR, false, &ChatHandler::HandleNpcWhisperCommand, "", NULL },
469 { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL },
470 { "tame", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTameCommand, "", NULL },
471 { "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL },
473 //{ TODO: fix or remove this commands
474 { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL },
475 { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcNameCommand, "", NULL },
476 { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSubNameCommand, "", NULL },
479 { NULL, 0, false, NULL, "", NULL }
482 static ChatCommand pdumpCommandTable[] =
484 { "load", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpLoadCommand, "", NULL },
485 { "write", SEC_ADMINISTRATOR, true, &ChatHandler::HandlePDumpWriteCommand, "", NULL },
486 { NULL, 0, false, NULL, "", NULL }
489 static ChatCommand poolCommandTable[] =
491 { "list", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolListCommand, "", NULL },
492 { "spawns", SEC_GAMEMASTER, false, &ChatHandler::HandlePoolSpawnsCommand, "", NULL },
493 { "", SEC_GAMEMASTER, true, &ChatHandler::HandlePoolInfoCommand, "", NULL },
494 { NULL, 0, false, NULL, "", NULL }
497 static ChatCommand questCommandTable[] =
499 { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestAddCommand, "", NULL },
500 { "complete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestCompleteCommand, "", NULL },
501 { "remove", SEC_ADMINISTRATOR, false, &ChatHandler::HandleQuestRemoveCommand, "", NULL },
502 { NULL, 0, false, NULL, "", NULL }
505 static ChatCommand reloadCommandTable[] =
507 { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllCommand, "", NULL },
508 { "all_achievement", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAchievementCommand, "", NULL },
509 { "all_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllAreaCommand, "", NULL },
510 { "all_eventai", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllEventAICommand, "", NULL },
511 { "all_gossips", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllGossipsCommand, "", NULL },
512 { "all_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllItemCommand, "", NULL },
513 { "all_locales", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLocalesCommand, "", NULL },
514 { "all_loot", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllLootCommand, "", NULL },
515 { "all_npc", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllNpcCommand, "", NULL },
516 { "all_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllQuestCommand, "", NULL },
517 { "all_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL },
518 { "all_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAllSpellCommand, "", NULL },
520 { "config", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConfigCommand, "", NULL },
522 { "achievement_criteria_requirement", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementCriteriaRequirementCommand, "", NULL },
523 { "achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAchievementRewardCommand, "", NULL },
524 { "areatrigger_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestAreaTriggersCommand, "", NULL },
525 { "areatrigger_tavern", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTavernCommand, "", NULL },
526 { "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL },
527 { "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL },
528 { "conditions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConditionsCommand, "", NULL },
529 { "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL },
530 { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL },
531 { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL },
532 { "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL },
533 { "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand, "", NULL },
534 { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
535 { "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
536 { "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL },
537 { "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL },
538 { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
539 { "fishing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL },
540 { "game_graveyard_zone", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL },
541 { "game_tele", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameTeleCommand, "", NULL },
542 { "gameobject_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestInvRelationsCommand, "", NULL },
543 { "gameobject_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesGameobjectCommand, "", NULL },
544 { "gameobject_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGOQuestRelationsCommand, "", NULL },
545 { "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
546 { "gameobject_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL },
547 { "gossip_menu", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuCommand, "", NULL },
548 { "gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuCommand, "", NULL },
549 { "gossip_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipScriptsCommand, "", NULL },
550 { "item_convert", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemConvertCommand, "", NULL },
551 { "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
552 { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
553 { "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL },
554 { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand, "", NULL },
555 { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
556 { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
557 { "locales_gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGossipMenuOptionCommand, "", NULL },
558 { "locales_item", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesItemCommand, "", NULL },
559 { "locales_npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesNpcTextCommand, "", NULL },
560 { "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL },
561 { "locales_points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPointsOfInterestCommand, "", NULL },
562 { "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL },
563 { "mail_level_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMailLevelRewardCommand, "", NULL },
564 { "mail_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMailCommand, "", NULL },
565 { "mangos_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadMangosStringCommand, "", NULL },
566 { "milling_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesMillingCommand, "", NULL },
567 { "npc_gossip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL },
568 { "npc_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTextCommand, "", NULL },
569 { "npc_spellclick_spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellClickSpellsCommand, "", NULL },
570 { "npc_trainer", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL },
571 { "npc_vendor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL },
572 { "page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPageTextsCommand, "", NULL },
573 { "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand, "", NULL},
574 { "points_of_interest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadPointsOfInterestCommand, "", NULL },
575 { "prospecting_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesProspectingCommand, "", NULL },
576 { "quest_end_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestEndScriptsCommand, "", NULL },
577 { "quest_poi", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestPOICommand, "", NULL },
578 { "quest_start_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestStartScriptsCommand, "", NULL },
579 { "quest_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadQuestTemplateCommand, "", NULL },
580 { "reference_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesReferenceCommand, "", NULL },
581 { "reserved_name", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReservedNameCommand, "", NULL },
582 { "reputation_reward_rate", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationRewardRateCommand, "", NULL },
583 { "reputation_spillover_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadReputationSpilloverTemplateCommand, "", NULL },
584 { "skill_discovery_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillDiscoveryTemplateCommand, "", NULL },
585 { "skill_extra_item_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL },
586 { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL },
587 { "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
588 { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
589 { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL },
590 { "spell_chain", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellChainCommand, "", NULL },
591 { "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
592 { "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
593 { "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
594 { "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
595 { "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
596 { "spell_proc_item_enchant", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcItemEnchantCommand, "", NULL },
597 { "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL },
598 { "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
599 { "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
600 { "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL },
602 { NULL, 0, false, NULL, "", NULL }
605 static ChatCommand resetCommandTable[] =
607 { "achievements", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetAchievementsCommand, "", NULL },
608 { "honor", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetHonorCommand, "", NULL },
609 { "level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetLevelCommand, "", NULL },
610 { "specs", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetSpecsCommand, "", NULL },
611 { "spells", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetSpellsCommand, "", NULL },
612 { "stats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetStatsCommand, "", NULL },
613 { "talents", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetTalentsCommand, "", NULL },
614 { "all", SEC_ADMINISTRATOR, true, &ChatHandler::HandleResetAllCommand, "", NULL },
615 { NULL, 0, false, NULL, "", NULL }
618 static ChatCommand sendMassCommandTable[] =
620 { "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassItemsCommand, "", NULL },
621 { "mail", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMailCommand, "", NULL },
622 { "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMoneyCommand, "", NULL },
623 { NULL, 0, false, NULL, "", NULL }
626 static ChatCommand sendCommandTable[] =
628 { "mass", SEC_ADMINISTRATOR, true, NULL, "", sendMassCommandTable },
630 { "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL },
631 { "mail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
632 { "message", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL },
633 { "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMoneyCommand, "", NULL },
634 { NULL, 0, false, NULL, "", NULL }
637 static ChatCommand serverIdleRestartCommandTable[] =
639 { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL },
640 { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleRestartCommand, "", NULL },
641 { NULL, 0, false, NULL, "", NULL }
644 static ChatCommand serverIdleShutdownCommandTable[] =
646 { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL },
647 { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerIdleShutDownCommand, "", NULL },
648 { NULL, 0, false, NULL, "", NULL }
651 static ChatCommand serverRestartCommandTable[] =
653 { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL },
654 { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerRestartCommand, "", NULL },
655 { NULL, 0, false, NULL, "", NULL }
658 static ChatCommand serverShutdownCommandTable[] =
660 { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand, "", NULL },
661 { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL },
662 { NULL, 0, false, NULL, "", NULL }
665 static ChatCommand serverLogCommandTable[] =
667 { "filter", SEC_CONSOLE, true, &ChatHandler::HandleServerLogFilterCommand, "", NULL },
668 { "level", SEC_CONSOLE, true, &ChatHandler::HandleServerLogLevelCommand, "", NULL },
669 { NULL, 0, false, NULL, "", NULL }
672 static ChatCommand serverSetCommandTable[] =
674 { "motd", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerSetMotdCommand, "", NULL },
675 { NULL, 0, false, NULL, "", NULL }
678 static ChatCommand serverCommandTable[] =
680 { "corpses", SEC_GAMEMASTER, true, &ChatHandler::HandleServerCorpsesCommand, "", NULL },
681 { "exit", SEC_CONSOLE, true, &ChatHandler::HandleServerExitCommand, "", NULL },
682 { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable },
683 { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
684 { "info", SEC_PLAYER, true, &ChatHandler::HandleServerInfoCommand, "", NULL },
685 { "log", SEC_CONSOLE, true, NULL, "", serverLogCommandTable },
686 { "motd", SEC_PLAYER, true, &ChatHandler::HandleServerMotdCommand, "", NULL },
687 { "plimit", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerPLimitCommand, "", NULL },
688 { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable },
689 { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable },
690 { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable },
691 { NULL, 0, false, NULL, "", NULL }
694 static ChatCommand teleCommandTable[] =
696 { "add", SEC_ADMINISTRATOR, false, &ChatHandler::HandleTeleAddCommand, "", NULL },
697 { "del", SEC_ADMINISTRATOR, true, &ChatHandler::HandleTeleDelCommand, "", NULL },
698 { "name", SEC_MODERATOR, true, &ChatHandler::HandleTeleNameCommand, "", NULL },
699 { "group", SEC_MODERATOR, false, &ChatHandler::HandleTeleGroupCommand, "", NULL },
700 { "", SEC_MODERATOR, false, &ChatHandler::HandleTeleCommand, "", NULL },
701 { NULL, 0, false, NULL, "", NULL }
704 static ChatCommand titlesCommandTable[] =
706 { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleTitlesAddCommand, "", NULL },
707 { "current", SEC_GAMEMASTER, false, &ChatHandler::HandleTitlesCurrentCommand, "", NULL },
708 { "remove", SEC_GAMEMASTER, false, &ChatHandler::HandleTitlesRemoveCommand, "", NULL },
709 { "setmask", SEC_GAMEMASTER, false, &ChatHandler::HandleTitlesSetMaskCommand, "", NULL },
710 { NULL, 0, false, NULL, "", NULL }
713 static ChatCommand triggerCommandTable[] =
715 { "active", SEC_GAMEMASTER, false, &ChatHandler::HandleTriggerActiveCommand, "", NULL },
716 { "near", SEC_GAMEMASTER, false, &ChatHandler::HandleTriggerNearCommand, "", NULL },
717 { "", SEC_GAMEMASTER, true, &ChatHandler::HandleTriggerCommand, "", NULL },
718 { NULL, 0, false, NULL, "", NULL }
721 static ChatCommand unbanCommandTable[] =
723 { "account", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanAccountCommand, "", NULL },
724 { "character", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanCharacterCommand, "", NULL },
725 { "ip", SEC_ADMINISTRATOR, true, &ChatHandler::HandleUnBanIPCommand, "", NULL },
726 { NULL, 0, false, NULL, "", NULL }
729 static ChatCommand wpCommandTable[] =
731 { "show", SEC_GAMEMASTER, false, &ChatHandler::HandleWpShowCommand, "", NULL },
732 { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleWpAddCommand, "", NULL },
733 { "modify", SEC_GAMEMASTER, false, &ChatHandler::HandleWpModifyCommand, "", NULL },
734 { "export", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpExportCommand, "", NULL },
735 { "import", SEC_ADMINISTRATOR, false, &ChatHandler::HandleWpImportCommand, "", NULL },
736 { NULL, 0, false, NULL, "", NULL }
739 static ChatCommand commandTable[] =
741 { "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
742 { "achievement", SEC_ADMINISTRATOR, true, NULL, "", achievementCommandTable },
743 { "auction", SEC_ADMINISTRATOR, false, NULL, "", auctionCommandTable },
744 { "ahbot", SEC_ADMINISTRATOR, true, NULL, "", ahbotCommandTable },
745 { "cast", SEC_ADMINISTRATOR, false, NULL, "", castCommandTable },
746 { "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable},
747 { "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable },
748 { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
749 { "gm", SEC_PLAYER, true, NULL, "", gmCommandTable },
750 { "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
751 { "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
752 { "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
753 { "guild", SEC_GAMEMASTER, true, NULL, "", guildCommandTable },
754 { "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable },
755 { "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
756 { "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
757 { "lookup", SEC_MODERATOR, true, NULL, "", lookupCommandTable },
758 { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
759 { "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
760 { "pool", SEC_GAMEMASTER, true, NULL, "", poolCommandTable },
761 { "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
762 { "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
763 { "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
764 { "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable },
765 { "server", SEC_PLAYER, true, NULL, "", serverCommandTable },
766 { "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
767 { "titles", SEC_GAMEMASTER, false, NULL, "", titlesCommandTable },
768 { "trigger", SEC_GAMEMASTER, false, NULL, "", triggerCommandTable },
769 { "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
771 { "aura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAuraCommand, "", NULL },
772 { "unaura", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnAuraCommand, "", NULL },
773 { "announce", SEC_MODERATOR, true, &ChatHandler::HandleAnnounceCommand, "", NULL },
774 { "notify", SEC_MODERATOR, true, &ChatHandler::HandleNotifyCommand, "", NULL },
775 { "goname", SEC_MODERATOR, false, &ChatHandler::HandleGonameCommand, "", NULL },
776 { "namego", SEC_MODERATOR, false, &ChatHandler::HandleNamegoCommand, "", NULL },
777 { "groupgo", SEC_MODERATOR, false, &ChatHandler::HandleGroupgoCommand, "", NULL },
778 { "commands", SEC_PLAYER, true, &ChatHandler::HandleCommandsCommand, "", NULL },
779 { "demorph", SEC_GAMEMASTER, false, &ChatHandler::HandleDeMorphCommand, "", NULL },
780 { "die", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDieCommand, "", NULL },
781 { "revive", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReviveCommand, "", NULL },
782 { "dismount", SEC_PLAYER, false, &ChatHandler::HandleDismountCommand, "", NULL },
783 { "gps", SEC_MODERATOR, false, &ChatHandler::HandleGPSCommand, "", NULL },
784 { "guid", SEC_GAMEMASTER, false, &ChatHandler::HandleGUIDCommand, "", NULL },
785 { "help", SEC_PLAYER, true, &ChatHandler::HandleHelpCommand, "", NULL },
786 { "itemmove", SEC_GAMEMASTER, false, &ChatHandler::HandleItemMoveCommand, "", NULL },
787 { "cooldown", SEC_ADMINISTRATOR, false, &ChatHandler::HandleCooldownCommand, "", NULL },
788 { "unlearn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUnLearnCommand, "", NULL },
789 { "distance", SEC_ADMINISTRATOR, false, &ChatHandler::HandleGetDistanceCommand, "", NULL },
790 { "recall", SEC_MODERATOR, false, &ChatHandler::HandleRecallCommand, "", NULL },
791 { "save", SEC_PLAYER, false, &ChatHandler::HandleSaveCommand, "", NULL },
792 { "saveall", SEC_MODERATOR, true, &ChatHandler::HandleSaveAllCommand, "", NULL },
793 { "kick", SEC_GAMEMASTER, true, &ChatHandler::HandleKickPlayerCommand, "", NULL },
794 { "ban", SEC_ADMINISTRATOR, true, NULL, "", banCommandTable },
795 { "unban", SEC_ADMINISTRATOR, true, NULL, "", unbanCommandTable },
796 { "baninfo", SEC_ADMINISTRATOR, false, NULL, "", baninfoCommandTable },
797 { "banlist", SEC_ADMINISTRATOR, true, NULL, "", banlistCommandTable },
798 { "start", SEC_PLAYER, false, &ChatHandler::HandleStartCommand, "", NULL },
799 { "taxicheat", SEC_MODERATOR, false, &ChatHandler::HandleTaxiCheatCommand, "", NULL },
800 { "linkgrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLinkGraveCommand, "", NULL },
801 { "neargrave", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNearGraveCommand, "", NULL },
802 { "explorecheat", SEC_ADMINISTRATOR, false, &ChatHandler::HandleExploreCheatCommand, "", NULL },
803 { "levelup", SEC_ADMINISTRATOR, false, &ChatHandler::HandleLevelUpCommand, "", NULL },
804 { "showarea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowAreaCommand, "", NULL },
805 { "hidearea", SEC_ADMINISTRATOR, false, &ChatHandler::HandleHideAreaCommand, "", NULL },
806 { "additem", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddItemCommand, "", NULL },
807 { "additemset", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddItemSetCommand, "", NULL },
808 { "bank", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBankCommand, "", NULL },
809 { "mailbox", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMailBoxCommand, "", NULL },
810 { "wchange", SEC_ADMINISTRATOR, false, &ChatHandler::HandleChangeWeatherCommand, "", NULL },
811 { "ticket", SEC_GAMEMASTER, true, &ChatHandler::HandleTicketCommand, "", NULL },
812 { "delticket", SEC_GAMEMASTER, true, &ChatHandler::HandleDelTicketCommand, "", NULL },
813 { "maxskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMaxSkillCommand, "", NULL },
814 { "setskill", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSetSkillCommand, "", NULL },
815 { "whispers", SEC_MODERATOR, false, &ChatHandler::HandleWhispersCommand, "", NULL },
816 { "pinfo", SEC_GAMEMASTER, true, &ChatHandler::HandlePInfoCommand, "", NULL },
817 { "respawn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleRespawnCommand, "", NULL },
818 { "send", SEC_MODERATOR, true, NULL, "", sendCommandTable },
819 { "loadscripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLoadScriptsCommand, "", NULL },
820 { "mute", SEC_MODERATOR, true, &ChatHandler::HandleMuteCommand, "", NULL },
821 { "unmute", SEC_MODERATOR, true, &ChatHandler::HandleUnmuteCommand, "", NULL },
822 { "movegens", SEC_ADMINISTRATOR, false, &ChatHandler::HandleMovegensCommand, "", NULL },
823 { "cometome", SEC_ADMINISTRATOR, false, &ChatHandler::HandleComeToMeCommand, "", NULL },
824 { "damage", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDamageCommand, "", NULL },
825 { "combatstop", SEC_GAMEMASTER, false, &ChatHandler::HandleCombatStopCommand, "", NULL },
826 { "repairitems", SEC_GAMEMASTER, true, &ChatHandler::HandleRepairitemsCommand, "", NULL },
827 { "stable", SEC_ADMINISTRATOR, false, &ChatHandler::HandleStableCommand, "", NULL },
828 { "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL },
829 { "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL },
830 { "gearscore", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowGearScoreCommand, "", NULL },
831 { "mmap", SEC_GAMEMASTER, false, NULL, "", mmapCommandTable },
833 { NULL, 0, false, NULL, "", NULL }
836 if (load_command_table)
838 load_command_table = false;
840 // check hardcoded part integrity
841 CheckIntegrity(commandTable, NULL);
843 QueryResult* result = WorldDatabase.Query("SELECT name,security,help FROM command");
844 if (result)
848 Field* fields = result->Fetch();
849 std::string name = fields[0].GetCppString();
851 SetDataForCommandInTable(commandTable, name.c_str(), fields[1].GetUInt16(), fields[2].GetCppString());
854 while (result->NextRow());
855 delete result;
859 return commandTable;
862 ChatHandler::ChatHandler(WorldSession* session) : m_session(session) {}
864 ChatHandler::ChatHandler(Player* player) : m_session(player->GetSession()) {}
866 ChatHandler::~ChatHandler() {}
868 const char* ChatHandler::GetMangosString(int32 entry) const
870 return m_session->GetMangosString(entry);
873 const char* ChatHandler::GetOnOffStr(bool value) const
875 return value ? GetMangosString(LANG_ON) : GetMangosString(LANG_OFF);
878 uint32 ChatHandler::GetAccountId() const
880 return m_session->GetAccountId();
883 AccountTypes ChatHandler::GetAccessLevel() const
885 return m_session->GetSecurity();
888 bool ChatHandler::isAvailable(ChatCommand const& cmd) const
890 // check security level only for simple command (without child commands)
891 return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel;
894 std::string ChatHandler::GetNameLink() const
896 return GetNameLink(m_session->GetPlayer());
899 bool ChatHandler::HasLowerSecurity(Player* target, ObjectGuid guid, bool strong)
901 WorldSession* target_session = NULL;
902 uint32 target_account = 0;
904 if (target)
905 target_session = target->GetSession();
906 else
907 target_account = sObjectMgr.GetPlayerAccountIdByGUID(guid);
909 if (!target_session && !target_account)
911 SendSysMessage(LANG_PLAYER_NOT_FOUND);
912 SetSentErrorMessage(true);
913 return true;
916 return HasLowerSecurityAccount(target_session, target_account, strong);
919 bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_account, bool strong)
921 AccountTypes target_sec;
923 // ignore only for non-players for non strong checks (when allow apply command at least to same sec level)
924 if (GetAccessLevel() > SEC_PLAYER && !strong && !sWorld.getConfig(CONFIG_BOOL_GM_LOWER_SECURITY))
925 return false;
927 if (target)
928 target_sec = target->GetSecurity();
929 else if (target_account)
930 target_sec = sAccountMgr.GetSecurity(target_account);
931 else
932 return true; // caller must report error for (target==NULL && target_account==0)
934 if (GetAccessLevel() < target_sec || (strong && GetAccessLevel() <= target_sec))
936 SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
937 SetSentErrorMessage(true);
938 return true;
941 return false;
944 bool ChatHandler::hasStringAbbr(const char* name, const char* part)
946 // non "" command
947 if (*name)
949 // "" part from non-"" command
950 if (!*part)
951 return false;
953 for (;;)
955 if (!*part)
956 return true;
957 else if (!*name)
958 return false;
959 else if (tolower(*name) != tolower(*part))
960 return false;
961 ++name; ++part;
964 // allow with any for ""
966 return true;
969 void ChatHandler::SendSysMessage(const char* str)
971 WorldPacket data;
973 // need copy to prevent corruption by strtok call in LineFromMessage original string
974 char* buf = mangos_strdup(str);
975 char* pos = buf;
977 while (char* line = LineFromMessage(pos))
979 FillSystemMessageData(&data, line);
980 m_session->SendPacket(&data);
983 delete[] buf;
986 void ChatHandler::SendGlobalSysMessage(const char* str)
988 // Chat output
989 WorldPacket data;
991 // need copy to prevent corruption by strtok call in LineFromMessage original string
992 char* buf = mangos_strdup(str);
993 char* pos = buf;
995 while (char* line = LineFromMessage(pos))
997 FillSystemMessageData(&data, line);
998 sWorld.SendGlobalMessage(&data);
1001 delete[] buf;
1004 void ChatHandler::SendSysMessage(int32 entry)
1006 SendSysMessage(GetMangosString(entry));
1009 void ChatHandler::PSendSysMessage(int32 entry, ...)
1011 const char* format = GetMangosString(entry);
1012 va_list ap;
1013 char str [2048];
1014 va_start(ap, entry);
1015 vsnprintf(str, 2048, format, ap);
1016 va_end(ap);
1017 SendSysMessage(str);
1020 void ChatHandler::PSendSysMessage(const char* format, ...)
1022 va_list ap;
1023 char str [2048];
1024 va_start(ap, format);
1025 vsnprintf(str, 2048, format, ap);
1026 va_end(ap);
1027 SendSysMessage(str);
1030 void ChatHandler::CheckIntegrity(ChatCommand* table, ChatCommand* parentCommand)
1032 for (uint32 i = 0; table[i].Name != NULL; ++i)
1034 ChatCommand* command = &table[i];
1036 if (parentCommand && command->SecurityLevel < parentCommand->SecurityLevel)
1037 sLog.outError("Subcommand '%s' of command '%s' have less access level (%u) that parent (%u)",
1038 command->Name, parentCommand->Name, command->SecurityLevel, parentCommand->SecurityLevel);
1040 if (!parentCommand && strlen(command->Name) == 0)
1041 sLog.outError("Subcommand '' at top level");
1043 if (command->ChildCommands)
1045 if (command->Handler)
1047 if (parentCommand)
1048 sLog.outError("Subcommand '%s' of command '%s' have handler and subcommands in same time, must be used '' subcommand for handler instead.",
1049 command->Name, parentCommand->Name);
1050 else
1051 sLog.outError("First level command '%s' have handler and subcommands in same time, must be used '' subcommand for handler instead.",
1052 command->Name);
1055 if (parentCommand && strlen(command->Name) == 0)
1056 sLog.outError("Subcommand '' of command '%s' have subcommands", parentCommand->Name);
1058 CheckIntegrity(command->ChildCommands, command);
1060 else if (!command->Handler)
1062 if (parentCommand)
1063 sLog.outError("Subcommand '%s' of command '%s' not have handler and subcommands in same time. Must have some from its!",
1064 command->Name, parentCommand->Name);
1065 else
1066 sLog.outError("First level command '%s' not have handler and subcommands in same time. Must have some from its!",
1067 command->Name);
1073 * Search (sub)command for command line available for chat handler access level
1075 * @param text Command line string that will parsed for (sub)command search
1077 * @return Pointer to found command structure or NULL if appropriate command not found
1079 ChatCommand const* ChatHandler::FindCommand(char const* text)
1081 ChatCommand* command = NULL;
1082 char const* textPtr = text;
1084 return FindCommand(getCommandTable(), textPtr, command) == CHAT_COMMAND_OK ? command : NULL;
1088 * Search (sub)command for command line available for chat handler access level with options and fail case additional info
1090 * @param table Pointer to command C-style array first level command where will be searched
1091 * @param text Command line string that will parsed for (sub)command search,
1092 * it modified at return from function and pointed to not parsed tail
1093 * @param command At success this is found command, at other cases this is last found parent command
1094 * before subcommand search fail
1095 * @param parentCommand Output arg for optional return parent command for command arg.
1096 * @param cmdNamePtr Output arg for optional return last parsed command name.
1097 * @param allAvailable Optional arg (with false default value) control use command access level checks while command search.
1098 * @param exactlyName Optional arg (with false default value) control use exactly name in checks while command search.
1100 * @return one from enum value of ChatCommandSearchResult. Output args return values highly dependent from this return result:
1102 * CHAT_COMMAND_OK - Command found!
1103 * text point to non parsed tail with possible command specific data, command store found command pointer,
1104 * parentCommand have parent of found command or NULL if command found in table array directly
1105 * cmdNamePtr store found command name in original form from command line
1106 * CHAT_COMMAND_UNKNOWN - Command not found in table directly
1107 * text only skip possible whitespaces,
1108 * command is NULL
1109 * parentCommand is NULL
1110 * cmdNamePtr store command name that not found as it extracted from command line
1111 * CHAT_COMMAND_UNKNOWN_SUBCOMMAND - Subcommand not found in some deed subcomand lists
1112 * text point to non parsed tail including not found command name in command line,
1113 * command store last found parent command if any
1114 * parentCommand have parent of command in command arg or NULL
1115 * cmdNamePtr store command name that not found as it extracted from command line
1117 ChatCommandSearchResult ChatHandler::FindCommand(ChatCommand* table, char const*& text, ChatCommand*& command, ChatCommand** parentCommand /*= NULL*/, std::string* cmdNamePtr /*= NULL*/, bool allAvailable /*= false*/, bool exactlyName /*= false*/)
1119 std::string cmd = "";
1121 // skip whitespaces
1122 while (*text != ' ' && *text != '\0')
1124 cmd += *text;
1125 ++text;
1128 while (*text == ' ') ++text;
1130 // search first level command in table
1131 for (uint32 i = 0; table[i].Name != NULL; ++i)
1133 if (exactlyName)
1135 size_t len = strlen(table[i].Name);
1136 if (strncmp(table[i].Name, cmd.c_str(), len + 1) != 0)
1137 continue;
1139 else
1141 if (!hasStringAbbr(table[i].Name, cmd.c_str()))
1142 continue;
1144 // select subcommand from child commands list
1145 if (table[i].ChildCommands != NULL)
1147 char const* oldchildtext = text;
1148 ChatCommand* parentSubcommand = NULL;
1149 ChatCommandSearchResult res = FindCommand(table[i].ChildCommands, text, command, &parentSubcommand, cmdNamePtr, allAvailable, exactlyName);
1151 switch (res)
1153 case CHAT_COMMAND_OK:
1155 // if subcommand success search not return parent command, then this parent command is owner of child commands
1156 if (parentCommand)
1157 *parentCommand = parentSubcommand ? parentSubcommand : &table[i];
1159 // Name == "" is special case: restore original command text for next level "" (where parentSubcommand==NULL)
1160 if (strlen(command->Name) == 0 && !parentSubcommand)
1161 text = oldchildtext;
1163 return CHAT_COMMAND_OK;
1165 case CHAT_COMMAND_UNKNOWN:
1167 // command not found directly in child command list, return child command list owner
1168 command = &table[i];
1169 if (parentCommand)
1170 *parentCommand = NULL; // we don't known parent of table list at this point
1172 text = oldchildtext; // restore text to stated just after parse found parent command
1173 return CHAT_COMMAND_UNKNOWN_SUBCOMMAND; // we not found subcommand for table[i]
1175 case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
1176 default:
1178 // some deep subcommand not found, if this second level subcommand then parentCommand can be NULL, use known value for it
1179 if (parentCommand)
1180 *parentCommand = parentSubcommand ? parentSubcommand : &table[i];
1181 return res;
1186 // must be available (not checked for subcommands case because parent command expected have most low access that all subcommands always
1187 if (!allAvailable && !isAvailable(table[i]))
1188 continue;
1190 // must be have handler is explicitly selected
1191 if (!table[i].Handler)
1192 continue;
1194 // command found directly in to table
1195 command = &table[i];
1197 // unknown table owner at this point
1198 if (parentCommand)
1199 *parentCommand = NULL;
1201 if (cmdNamePtr)
1202 *cmdNamePtr = cmd;
1204 return CHAT_COMMAND_OK;
1207 // command not found in table directly
1208 command = NULL;
1210 // unknown table owner at this point
1211 if (parentCommand)
1212 *parentCommand = NULL;
1214 if (cmdNamePtr)
1215 *cmdNamePtr = cmd;
1217 return CHAT_COMMAND_UNKNOWN;
1221 * Execute (sub)command available for chat handler access level with options in command line string
1223 * @param text Command line string that will parsed for (sub)command search and command specific data
1225 * Command output and errors in command execution will send to chat handler.
1227 void ChatHandler::ExecuteCommand(const char* text)
1229 std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing.
1231 ChatCommand* command = NULL;
1232 ChatCommand* parentCommand = NULL;
1234 ChatCommandSearchResult res = FindCommand(getCommandTable(), text, command, &parentCommand);
1236 switch (res)
1238 case CHAT_COMMAND_OK:
1240 SetSentErrorMessage(false);
1241 if ((this->*(command->Handler))((char*)text)) // text content destroyed at call
1243 if (command->SecurityLevel > SEC_PLAYER)
1244 LogCommand(fullcmd.c_str());
1246 // some commands have custom error messages. Don't send the default one in these cases.
1247 else if (!HasSentErrorMessage())
1249 if (!command->Help.empty())
1250 SendSysMessage(command->Help.c_str());
1251 else
1252 SendSysMessage(LANG_CMD_SYNTAX);
1254 if (ChatCommand* showCommand = (strlen(command->Name) == 0 && parentCommand ? parentCommand : command))
1255 if (ChatCommand* childs = showCommand->ChildCommands)
1256 ShowHelpForSubCommands(childs, showCommand->Name);
1258 SetSentErrorMessage(true);
1260 break;
1262 case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
1264 SendSysMessage(LANG_NO_SUBCMD);
1265 ShowHelpForCommand(command->ChildCommands, text);
1266 SetSentErrorMessage(true);
1267 break;
1269 case CHAT_COMMAND_UNKNOWN:
1271 SendSysMessage(LANG_NO_CMD);
1272 SetSentErrorMessage(true);
1273 break;
1279 * Function find appropriate command and update command security level and help text
1281 * @param commandTable Table for first level command search
1282 * @param text Command line string that will parsed for (sub)command search
1283 * @param security New security level for command
1284 * @param help New help text for command
1286 * @return true if command has been found, and false in other case
1288 * All problems found while command search and updated output as to DB errors log
1290 bool ChatHandler::SetDataForCommandInTable(ChatCommand* commandTable, const char* text, uint32 security, std::string const& help)
1292 std::string fullcommand = text; // original `text` can't be used. It content destroyed in command code processing.
1294 ChatCommand* command = NULL;
1295 std::string cmdName;
1297 ChatCommandSearchResult res = FindCommand(commandTable, text, command, NULL, &cmdName, true, true);
1299 switch (res)
1301 case CHAT_COMMAND_OK:
1303 if (command->SecurityLevel != security)
1304 DETAIL_LOG("Table `command` overwrite for command '%s' default security (%u) by %u",
1305 fullcommand.c_str(), command->SecurityLevel, security);
1307 command->SecurityLevel = security;
1308 command->Help = help;
1309 return true;
1311 case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
1313 // command have subcommands, but not '' subcommand and then any data in `command` useless for it.
1314 if (cmdName.empty())
1315 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());
1316 else
1317 sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.", cmdName.c_str(), fullcommand.c_str());
1318 return false;
1320 case CHAT_COMMAND_UNKNOWN:
1322 sLog.outErrorDb("Table `command` have nonexistent command '%s', skip.", cmdName.c_str());
1323 return false;
1327 return false;
1330 bool ChatHandler::ParseCommands(const char* text)
1332 MANGOS_ASSERT(text);
1333 MANGOS_ASSERT(*text);
1335 // if(m_session->GetSecurity() == SEC_PLAYER)
1336 // return false;
1338 /// chat case (.command or !command format)
1339 if (m_session)
1341 if (text[0] != '!' && text[0] != '.')
1342 return false;
1344 /// ignore single . and ! in line
1345 if (strlen(text) < 2)
1346 return false;
1349 /// ignore messages staring from many dots.
1350 if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
1351 return false;
1353 /// skip first . or ! (in console allowed use command with . and ! and without its)
1354 if (text[0] == '!' || text[0] == '.')
1355 ++text;
1357 ExecuteCommand(text);
1359 return true;
1362 bool ChatHandler::ShowHelpForSubCommands(ChatCommand* table, char const* cmd)
1364 std::string list;
1365 for (uint32 i = 0; table[i].Name != NULL; ++i)
1367 // must be available (ignore handler existence for show command with possible available subcommands
1368 if (!isAvailable(table[i]))
1369 continue;
1371 if (m_session)
1372 list += "\n ";
1373 else
1374 list += "\n\r ";
1376 list += table[i].Name;
1378 if (table[i].ChildCommands)
1379 list += " ...";
1382 if (list.empty())
1383 return false;
1385 if (table == getCommandTable())
1387 SendSysMessage(LANG_AVIABLE_CMD);
1388 SendSysMessage(list.c_str());
1390 else
1392 PSendSysMessage(LANG_SUBCMDS_LIST, cmd);
1393 SendSysMessage(list.c_str());
1395 return true;
1398 bool ChatHandler::ShowHelpForCommand(ChatCommand* table, const char* cmd)
1400 char const* oldCmd = cmd;
1401 ChatCommand* command = NULL;
1402 ChatCommand* parentCommand = NULL;
1404 ChatCommand* showCommand = NULL;
1405 ChatCommand* childCommands = NULL;
1407 ChatCommandSearchResult res = FindCommand(table, cmd, command, &parentCommand);
1409 switch (res)
1411 case CHAT_COMMAND_OK:
1413 // for "" subcommand use parent command if any for subcommands list output
1414 if (strlen(command->Name) == 0 && parentCommand)
1416 showCommand = parentCommand;
1417 cmd = "";
1419 else
1420 showCommand = command;
1422 childCommands = showCommand->ChildCommands;
1423 break;
1425 case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
1426 showCommand = command;
1427 childCommands = showCommand->ChildCommands;
1428 break;
1429 case CHAT_COMMAND_UNKNOWN:
1430 // not show command list at error in first level command find fail
1431 childCommands = table != getCommandTable() || strlen(oldCmd) == 0 ? table : NULL;
1432 command = NULL;
1433 break;
1436 if (command && !command->Help.empty())
1437 SendSysMessage(command->Help.c_str());
1439 if (childCommands)
1440 if (ShowHelpForSubCommands(childCommands, showCommand ? showCommand->Name : ""))
1441 return true;
1443 if (command && command->Help.empty())
1444 SendSysMessage(LANG_NO_HELP_CMD);
1446 return command || childCommands;
1449 bool ChatHandler::isValidChatMessage(const char* message)
1453 valid examples:
1454 |cff00aa00|Hcurrency:391|h[Ðåêîìåíäàòåëüíûé çíà÷îê Òîë Áàðàäà]|h|r
1455 |cffff8000|Hinstancelock:070000000177AF81:532:0:1|h[Êàðàæàí]|h|r NYI
1456 |cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
1457 |cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
1458 |cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
1459 |cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
1460 |cff71d5ff|Hspell:21563|h[Command]|h|r
1461 |cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
1462 |cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
1463 |cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
1465 | will be escaped to ||
1468 if (strlen(message) > 255)
1469 return false;
1471 const char validSequence[6] = "cHhhr";
1472 const char* validSequenceIterator = validSequence;
1474 // more simple checks
1475 if (sWorld.getConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3)
1477 const std::string validCommands = "cHhr|";
1479 while (*message)
1481 // find next pipe command
1482 message = strchr(message, '|');
1484 if (!message)
1485 return true;
1487 ++message;
1488 char commandChar = *message;
1489 if (validCommands.find(commandChar) == std::string::npos)
1490 return false;
1492 ++message;
1493 // validate sequence
1494 if (sWorld.getConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2)
1496 if (commandChar == *validSequenceIterator)
1498 if (validSequenceIterator == validSequence + 4)
1499 validSequenceIterator = validSequence;
1500 else
1501 ++validSequenceIterator;
1503 else if (commandChar != '|')
1504 return false;
1507 return true;
1510 std::istringstream reader(message);
1511 char buffer[256];
1513 uint32 color = 0;
1515 CurrencyTypesEntry const* linkedCurrency = NULL;
1516 ItemPrototype const* linkedItem = NULL;
1517 Quest const* linkedQuest = NULL;
1518 SpellEntry const* linkedSpell = NULL;
1519 AchievementEntry const* linkedAchievement = NULL;
1520 ItemRandomPropertiesEntry const* itemProperty = NULL;
1521 ItemRandomSuffixEntry const* itemSuffix = NULL;
1523 while (!reader.eof())
1525 if (validSequence == validSequenceIterator)
1527 linkedCurrency = NULL;
1528 linkedItem = NULL;
1529 linkedQuest = NULL;
1530 linkedSpell = NULL;
1531 linkedAchievement = NULL;
1532 itemProperty = NULL;
1533 itemSuffix = NULL;
1535 reader.ignore(255, '|');
1537 else if (reader.get() != '|')
1539 DEBUG_LOG("ChatHandler::isValidChatMessage sequence aborted unexpectedly");
1540 return false;
1543 // pipe has always to be followed by at least one char
1544 if (reader.peek() == '\0')
1546 DEBUG_LOG("ChatHandler::isValidChatMessage pipe followed by \\0");
1547 return false;
1550 // no further pipe commands
1551 if (reader.eof())
1552 break;
1554 char commandChar;
1555 reader >> commandChar;
1557 // | in normal messages is escaped by ||
1558 if (commandChar != '|')
1560 if (commandChar == *validSequenceIterator)
1562 if (validSequenceIterator == validSequence + 4)
1563 validSequenceIterator = validSequence;
1564 else
1565 ++validSequenceIterator;
1567 else
1569 DEBUG_LOG("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar);
1570 return false;
1573 else if (validSequence != validSequenceIterator)
1575 // no escaped pipes in sequences
1576 DEBUG_LOG("ChatHandler::isValidChatMessage got escaped pipe in sequence");
1577 return false;
1580 switch (commandChar)
1582 case 'c':
1583 color = 0;
1584 // validate color, expect 8 hex chars
1585 for (int i = 0; i < 8; ++i)
1587 char c;
1588 reader >> c;
1589 if (!c)
1591 DEBUG_LOG("ChatHandler::isValidChatMessage got \\0 while reading color in |c command");
1592 return false;
1595 color <<= 4;
1596 // check for hex char
1597 if (c >= '0' && c <= '9')
1599 color |= c - '0';
1600 continue;
1602 if (c >= 'a' && c <= 'f')
1604 color |= 10 + c - 'a';
1605 continue;
1607 DEBUG_LOG("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c);
1608 return false;
1610 break;
1611 case 'H':
1612 // read chars up to colon = link type
1613 reader.getline(buffer, 256, ':');
1614 if (reader.eof()) // : must be
1615 return false;
1617 if (strcmp(buffer, "currency") == 0)
1619 if (color != CHAT_LINK_COLOR_CURRENCY)
1620 return false;
1622 uint32 currencyEntry = 0;
1623 // read currency entry
1624 char c = reader.peek();
1625 while (c >= '0' && c <= '9')
1627 reader.ignore(1);
1628 currencyEntry *= 10;
1629 currencyEntry += c - '0';
1630 c = reader.peek();
1632 linkedCurrency = sCurrencyTypesStore.LookupEntry(currencyEntry);
1633 if (!linkedCurrency)
1634 return false;
1636 else if (strcmp(buffer, "item") == 0)
1638 // read item entry
1639 reader.getline(buffer, 256, ':');
1640 if (reader.eof()) // : must be
1641 return false;
1643 linkedItem = ObjectMgr::GetItemPrototype(atoi(buffer));
1644 if (!linkedItem)
1646 DEBUG_LOG("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer));
1647 return false;
1650 if (color != ItemQualityColors[linkedItem->Quality])
1652 DEBUG_LOG("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality],
1653 color);
1654 return false;
1657 // the itementry is followed by several integers which describe an instance of this item
1659 // position relative after itemEntry
1660 const uint8 randomPropertyPosition = 6;
1662 int32 propertyId = 0;
1663 bool negativeNumber = false;
1664 char c;
1665 for (uint8 i = 0; i < randomPropertyPosition; ++i)
1667 propertyId = 0;
1668 negativeNumber = false;
1669 while ((c = reader.get()) != ':')
1671 if (c >= '0' && c <= '9')
1673 propertyId *= 10;
1674 propertyId += c - '0';
1676 else if (c == '-')
1677 negativeNumber = true;
1678 else
1679 return false;
1682 if (negativeNumber)
1683 propertyId *= -1;
1685 if (propertyId > 0)
1687 itemProperty = sItemRandomPropertiesStore.LookupEntry(propertyId);
1688 if (!itemProperty)
1689 return false;
1691 else if (propertyId < 0)
1693 itemSuffix = sItemRandomSuffixStore.LookupEntry(-propertyId);
1694 if (!itemSuffix)
1695 return false;
1698 // ignore other integers
1699 while ((c >= '0' && c <= '9') || c == ':')
1701 reader.ignore(1);
1702 c = reader.peek();
1705 else if (strcmp(buffer, "quest") == 0)
1707 // no color check for questlinks, each client will adapt it anyway
1708 uint32 questid = 0;
1709 // read questid
1710 char c = reader.peek();
1711 while (c >= '0' && c <= '9')
1713 reader.ignore(1);
1714 questid *= 10;
1715 questid += c - '0';
1716 c = reader.peek();
1719 linkedQuest = sObjectMgr.GetQuestTemplate(questid);
1721 if (!linkedQuest)
1723 DEBUG_LOG("ChatHandler::isValidChatMessage Questtemplate %u not found", questid);
1724 return false;
1727 if (c != ':')
1729 DEBUG_LOG("ChatHandler::isValidChatMessage Invalid quest link structure");
1730 return false;
1733 reader.ignore(1);
1734 c = reader.peek();
1735 // level
1736 uint32 questlevel = 0;
1737 while (c >= '0' && c <= '9')
1739 reader.ignore(1);
1740 questlevel *= 10;
1741 questlevel += c - '0';
1742 c = reader.peek();
1745 if (questlevel >= STRONG_MAX_LEVEL)
1747 DEBUG_LOG("ChatHandler::isValidChatMessage Quest level %u too big", questlevel);
1748 return false;
1751 if (c != '|')
1753 DEBUG_LOG("ChatHandler::isValidChatMessage Invalid quest link structure");
1754 return false;
1757 else if (strcmp(buffer, "trade") == 0)
1759 if (color != CHAT_LINK_COLOR_TRADE)
1760 return false;
1762 // read spell entry
1763 reader.getline(buffer, 256, ':');
1764 if (reader.eof()) // : must be
1765 return false;
1767 linkedSpell = sSpellStore.LookupEntry(atoi(buffer));
1768 if (!linkedSpell)
1769 return false;
1771 char c = reader.peek();
1772 // base64 encoded stuff
1773 while (c != '|' && c != '\0')
1775 reader.ignore(1);
1776 c = reader.peek();
1779 else if (strcmp(buffer, "talent") == 0)
1781 // talent links are always supposed to be blue
1782 if (color != CHAT_LINK_COLOR_TALENT)
1783 return false;
1785 // read talent entry
1786 reader.getline(buffer, 256, ':');
1787 if (reader.eof()) // : must be
1788 return false;
1790 TalentEntry const* talentInfo = sTalentStore.LookupEntry(atoi(buffer));
1791 if (!talentInfo)
1792 return false;
1794 linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]);
1795 if (!linkedSpell)
1796 return false;
1798 char c = reader.peek();
1799 // skillpoints? whatever, drop it
1800 while (c != '|' && c != '\0')
1802 reader.ignore(1);
1803 c = reader.peek();
1806 else if (strcmp(buffer, "spell") == 0)
1808 if (color != CHAT_LINK_COLOR_SPELL)
1809 return false;
1811 uint32 spellid = 0;
1812 // read spell entry
1813 char c = reader.peek();
1814 while (c >= '0' && c <= '9')
1816 reader.ignore(1);
1817 spellid *= 10;
1818 spellid += c - '0';
1819 c = reader.peek();
1821 linkedSpell = sSpellStore.LookupEntry(spellid);
1822 if (!linkedSpell)
1823 return false;
1825 else if (strcmp(buffer, "enchant") == 0)
1827 if (color != CHAT_LINK_COLOR_ENCHANT)
1828 return false;
1830 uint32 spellid = 0;
1831 // read spell entry
1832 char c = reader.peek();
1833 while (c >= '0' && c <= '9')
1835 reader.ignore(1);
1836 spellid *= 10;
1837 spellid += c - '0';
1838 c = reader.peek();
1840 linkedSpell = sSpellStore.LookupEntry(spellid);
1841 if (!linkedSpell)
1842 return false;
1844 else if (strcmp(buffer, "achievement") == 0)
1846 if (color != CHAT_LINK_COLOR_ACHIEVEMENT)
1847 return false;
1849 reader.getline(buffer, 256, ':');
1850 if (reader.eof()) // : must be
1851 return false;
1853 uint32 achievementId = atoi(buffer);
1854 linkedAchievement = sAchievementStore.LookupEntry(achievementId);
1856 if (!linkedAchievement)
1857 return false;
1859 char c = reader.peek();
1860 // skip progress
1861 while (c != '|' && c != '\0')
1863 reader.ignore(1);
1864 c = reader.peek();
1867 else if (strcmp(buffer, "glyph") == 0)
1869 if (color != CHAT_LINK_COLOR_GLYPH)
1870 return false;
1872 // first id is slot, drop it
1873 reader.getline(buffer, 256, ':');
1874 if (reader.eof()) // : must be
1875 return false;
1877 uint32 glyphId = 0;
1878 char c = reader.peek();
1879 while (c >= '0' && c <= '9')
1881 glyphId *= 10;
1882 glyphId += c - '0';
1883 reader.ignore(1);
1884 c = reader.peek();
1886 GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
1887 if (!glyph)
1888 return false;
1890 linkedSpell = sSpellStore.LookupEntry(glyph->SpellId);
1892 if (!linkedSpell)
1893 return false;
1895 else
1897 DEBUG_LOG("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer);
1898 return false;
1900 break;
1901 case 'h':
1902 // if h is next element in sequence, this one must contain the linked text :)
1903 if (*validSequenceIterator == 'h')
1905 // links start with '['
1906 if (reader.get() != '[')
1908 DEBUG_LOG("ChatHandler::isValidChatMessage link caption doesn't start with '['");
1909 return false;
1911 reader.getline(buffer, 256, ']');
1912 if (reader.eof()) // ] must be
1913 return false;
1915 // verify the link name
1916 if (linkedCurrency)
1918 if (linkedCurrency->ID == CURRENCY_CONQUEST_ARENA_META || linkedCurrency->ID == CURRENCY_CONQUEST_BG_META)
1919 return false;
1921 bool foundName = false;
1922 for (uint8 i = 0; i < MAX_LOCALE; ++i)
1924 if (*linkedCurrency->name[i] && strcmp(linkedCurrency->name[i], buffer) == 0)
1926 foundName = true;
1927 break;
1930 if (!foundName)
1931 return false;
1933 else if (linkedSpell)
1935 // spells with that flag have a prefix of "$PROFESSION: "
1936 if (linkedSpell->HasAttribute(SPELL_ATTR_TRADESPELL))
1938 // lookup skillid
1939 SkillLineAbilityMapBounds bounds = sSpellMgr.GetSkillLineAbilityMapBounds(linkedSpell->Id);
1940 if (bounds.first == bounds.second)
1942 return false;
1945 SkillLineAbilityEntry const* skillInfo = bounds.first->second;
1947 if (!skillInfo)
1949 return false;
1952 SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId);
1953 if (!skillLine)
1955 return false;
1958 for (uint8 i = 0; i < MAX_LOCALE; ++i)
1960 uint32 skillLineNameLength = strlen(skillLine->name[i]);
1961 if (skillLineNameLength > 0 && strncmp(skillLine->name[i], buffer, skillLineNameLength) == 0)
1963 // found the prefix, remove it to perform spellname validation below
1964 // -2 = strlen(": ")
1965 uint32 spellNameLength = strlen(buffer) - skillLineNameLength - 2;
1966 memmove(buffer, buffer + skillLineNameLength + 2, spellNameLength + 1);
1970 bool foundName = false;
1971 for (uint8 i = 0; i < MAX_LOCALE; ++i)
1973 if (*linkedSpell->SpellName[i] && strcmp(linkedSpell->SpellName[i], buffer) == 0)
1975 foundName = true;
1976 break;
1979 if (!foundName)
1980 return false;
1982 else if (linkedQuest)
1984 if (linkedQuest->GetTitle() != buffer)
1986 QuestLocale const* ql = sObjectMgr.GetQuestLocale(linkedQuest->GetQuestId());
1988 if (!ql)
1990 DEBUG_LOG("ChatHandler::isValidChatMessage default questname didn't match and there is no locale");
1991 return false;
1994 bool foundName = false;
1995 for (uint8 i = 0; i < ql->Title.size(); ++i)
1997 if (ql->Title[i] == buffer)
1999 foundName = true;
2000 break;
2003 if (!foundName)
2005 DEBUG_LOG("ChatHandler::isValidChatMessage no quest locale title matched");
2006 return false;
2010 else if (linkedItem)
2012 DBCString suffix = itemSuffix?itemSuffix->nameSuffix:(itemProperty?itemProperty->nameSuffix:NULL);
2014 std::string expectedName = std::string(linkedItem->Name1);
2015 if (suffix)
2017 expectedName += " ";
2018 expectedName += suffix[LOCALE_enUS];
2021 if (expectedName != buffer)
2023 ItemLocale const* il = sObjectMgr.GetItemLocale(linkedItem->ItemId);
2025 bool foundName = false;
2026 for (uint8 i = LOCALE_koKR; i < MAX_LOCALE; ++i)
2028 int8 dbIndex = sObjectMgr.GetIndexForLocale(LocaleConstant(i));
2029 if (dbIndex == -1 || il == NULL || (size_t)dbIndex >= il->Name.size())
2030 // using strange database/client combinations can lead to this case
2031 expectedName = linkedItem->Name1;
2032 else
2033 expectedName = il->Name[dbIndex];
2034 if (suffix)
2036 expectedName += " ";
2037 expectedName += suffix[i];
2039 if (expectedName == buffer)
2041 foundName = true;
2042 break;
2045 if (!foundName)
2047 DEBUG_LOG("ChatHandler::isValidChatMessage linked item name wasn't found in any localization");
2048 return false;
2052 else if (linkedAchievement)
2054 bool foundName = false;
2055 for (uint8 i = 0; i < MAX_LOCALE; ++i)
2057 if (*linkedAchievement->name[i] && strcmp(linkedAchievement->name[i], buffer) == 0)
2059 foundName = true;
2060 break;
2063 if (!foundName)
2064 return false;
2066 // that place should never be reached - if nothing linked has been set in |H
2067 // it will return false before
2068 else
2069 return false;
2071 break;
2072 case 'r':
2073 case '|':
2074 // no further payload
2075 break;
2076 default:
2077 DEBUG_LOG("ChatHandler::isValidChatMessage got invalid command |%c", commandChar);
2078 return false;
2082 // check if every opened sequence was also closed properly
2083 if (validSequence != validSequenceIterator)
2084 DEBUG_LOG("ChatHandler::isValidChatMessage EOF in active sequence");
2086 return validSequence == validSequenceIterator;
2089 // Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored)
2090 void ChatHandler::FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* channelName, ObjectGuid targetGuid, const char* message, Unit* speaker, const char* addonPrefix /*= NULL*/)
2092 uint32 messageLength = (message ? strlen(message) : 0) + 1;
2094 data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
2095 *data << uint8(type);
2096 if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON)
2097 *data << uint32(language);
2098 else
2099 *data << uint32(LANG_UNIVERSAL);
2101 switch (type)
2103 case CHAT_MSG_SAY:
2104 case CHAT_MSG_PARTY:
2105 case CHAT_MSG_PARTY_LEADER:
2106 case CHAT_MSG_RAID:
2107 case CHAT_MSG_GUILD:
2108 case CHAT_MSG_OFFICER:
2109 case CHAT_MSG_YELL:
2110 case CHAT_MSG_WHISPER:
2111 case CHAT_MSG_CHANNEL:
2112 case CHAT_MSG_RAID_LEADER:
2113 case CHAT_MSG_RAID_WARNING:
2114 case CHAT_MSG_BG_SYSTEM_NEUTRAL:
2115 case CHAT_MSG_BG_SYSTEM_ALLIANCE:
2116 case CHAT_MSG_BG_SYSTEM_HORDE:
2117 case CHAT_MSG_BATTLEGROUND:
2118 case CHAT_MSG_BATTLEGROUND_LEADER:
2119 targetGuid = session ? session->GetPlayer()->GetObjectGuid() : ObjectGuid();
2120 break;
2121 case CHAT_MSG_MONSTER_SAY:
2122 case CHAT_MSG_MONSTER_PARTY:
2123 case CHAT_MSG_MONSTER_YELL:
2124 case CHAT_MSG_MONSTER_WHISPER:
2125 case CHAT_MSG_MONSTER_EMOTE:
2126 case CHAT_MSG_RAID_BOSS_WHISPER:
2127 case CHAT_MSG_RAID_BOSS_EMOTE:
2128 case CHAT_MSG_BATTLENET:
2130 *data << ObjectGuid(speaker->GetObjectGuid());
2131 *data << uint32(0); // 2.1.0
2132 *data << uint32(strlen(speaker->GetName()) + 1);
2133 *data << speaker->GetName();
2134 ObjectGuid listener_guid;
2135 *data << listener_guid;
2136 if (listener_guid && !listener_guid.IsPlayer())
2138 *data << uint32(1); // string listener_name_length
2139 *data << uint8(0); // string listener_name
2141 *data << uint32(messageLength);
2142 *data << message;
2143 *data << uint8(0);
2145 if (type == CHAT_MSG_RAID_BOSS_WHISPER || type == CHAT_MSG_RAID_BOSS_EMOTE)
2147 *data << float(0.0f); // Added in 4.2.0, unk
2148 *data << uint8(0); // Added in 4.2.0, unk
2150 return;
2152 default:
2153 if (type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
2154 targetGuid.Clear(); // only for CHAT_MSG_WHISPER_INFORM used original value target_guid
2155 break;
2158 *data << ObjectGuid(targetGuid); // there 0 for BG messages
2159 *data << uint32(0); // can be chat msg group or something
2161 if (type == CHAT_MSG_CHANNEL)
2163 MANGOS_ASSERT(channelName);
2164 *data << channelName;
2165 *data << ObjectGuid(targetGuid);
2167 else if (type == CHAT_MSG_ADDON)
2169 MANGOS_ASSERT(addonPrefix);
2170 *data << addonPrefix;
2172 else
2173 *data << ObjectGuid(targetGuid);
2175 *data << uint32(messageLength);
2176 *data << message;
2177 if (session != 0 && type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_DND && type != CHAT_MSG_AFK)
2178 *data << uint8(session->GetPlayer()->GetChatTag());
2179 else
2180 *data << uint8(0);
2183 Player* ChatHandler::getSelectedPlayer()
2185 if (!m_session)
2186 return NULL;
2188 ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid();
2190 if (!guid)
2191 return m_session->GetPlayer();
2193 return sObjectMgr.GetPlayer(guid);
2196 Unit* ChatHandler::getSelectedUnit()
2198 if (!m_session)
2199 return NULL;
2201 ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid();
2203 if (!guid)
2204 return m_session->GetPlayer();
2206 // can be selected player at another map
2207 return ObjectAccessor::GetUnit(*m_session->GetPlayer(), guid);
2210 Creature* ChatHandler::getSelectedCreature()
2212 if (!m_session)
2213 return NULL;
2215 return m_session->GetPlayer()->GetMap()->GetAnyTypeCreature(m_session->GetPlayer()->GetSelectionGuid());
2219 * Function skip all whitespaces in args string
2221 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2222 * allowed NULL string pointer stored in *args
2224 void ChatHandler::SkipWhiteSpaces(char** args)
2226 if (!*args)
2227 return;
2229 while (isWhiteSpace(**args))
2230 ++(*args);
2234 * Function extract to val arg signed integer value or fail
2236 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2237 * @param val return extracted value if function success, in fail case original value unmodified
2238 * @return true if value extraction successful
2240 bool ChatHandler::ExtractInt32(char** args, int32& val)
2242 if (!*args || !** args)
2243 return false;
2245 char* tail = *args;
2247 long valRaw = strtol(*args, &tail, 10);
2249 if (tail != *args && isWhiteSpace(*tail))
2250 *(tail++) = '\0';
2251 else if (tail && *tail) // some not whitespace symbol
2252 return false; // args not modified and can be re-parsed
2254 if (valRaw < std::numeric_limits<int32>::min() || valRaw > std::numeric_limits<int32>::max())
2255 return false;
2257 // value successfully extracted
2258 val = int32(valRaw);
2259 *args = tail;
2260 return true;
2264 * Function extract to val arg optional signed integer value or use default value. Fail if extracted not signed integer.
2266 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2267 * @param val return extracted value if function success, in fail case original value unmodified
2268 * @param defVal default value used if no data for extraction in args
2269 * @return true if value extraction successful
2271 bool ChatHandler::ExtractOptInt32(char** args, int32& val, int32 defVal)
2273 if (!*args || !** args)
2275 val = defVal;
2276 return true;
2279 return ExtractInt32(args, val);
2283 * Function extract to val arg unsigned integer value or fail
2285 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2286 * @param val return extracted value if function success, in fail case original value unmodified
2287 * @param base set used base for extracted value format (10 for decimal, 16 for hex, etc), 0 let auto select by system internal function
2288 * @return true if value extraction successful
2290 bool ChatHandler::ExtractUInt32Base(char** args, uint32& val, uint32 base)
2292 if (!*args || !** args)
2293 return false;
2295 char* tail = *args;
2297 unsigned long valRaw = strtoul(*args, &tail, base);
2299 if (tail != *args && isWhiteSpace(*tail))
2300 *(tail++) = '\0';
2301 else if (tail && *tail) // some not whitespace symbol
2302 return false; // args not modified and can be re-parsed
2304 if (valRaw > std::numeric_limits<uint32>::max())
2305 return false;
2307 // value successfully extracted
2308 val = uint32(valRaw);
2309 *args = tail;
2311 SkipWhiteSpaces(args);
2312 return true;
2316 * Function extract to val arg unsigned long value or fail
2318 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2319 * @param val return extracted value if function success, in fail case original value unmodified
2320 * @return true if value extraction successful
2322 bool ChatHandler::ExtractUInt64(char** args, uint64& val)
2324 if (!*args || !** args)
2325 return false;
2327 char* tail = *args;
2329 unsigned long valRaw = strtoul(*args, &tail, 10);
2331 if (tail != *args && isWhiteSpace(*tail))
2332 *(tail++) = '\0';
2333 else if (tail && *tail) // some not whitespace symbol
2334 return false; // args not modified and can be re-parsed
2336 if (valRaw > std::numeric_limits<uint64>::max())
2337 return false;
2339 // value successfully extracted
2340 val = uint64(valRaw);
2341 *args = tail;
2343 SkipWhiteSpaces(args);
2344 return true;
2348 * Function extract to val arg signed long value or fail
2350 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2351 * @param val return extracted value if function success, in fail case original value unmodified
2352 * @return true if value extraction successful
2354 bool ChatHandler::ExtractInt64(char** args, int64& val)
2356 if (!*args || !** args)
2357 return false;
2359 char* tail = *args;
2361 long valRaw = strtol(*args, &tail, 10);
2363 if (tail != *args && isWhiteSpace(*tail))
2364 *(tail++) = '\0';
2365 else if (tail && *tail) // some not whitespace symbol
2366 return false; // args not modified and can be re-parsed
2368 if (valRaw < std::numeric_limits<int64>::min() || valRaw > std::numeric_limits<int64>::max())
2369 return false;
2371 // value successfully extracted
2372 val = int64(valRaw);
2373 *args = tail;
2374 return true;
2378 * Function extract to val arg optional unsigned integer value or use default value. Fail if extracted not unsigned integer.
2380 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2381 * @param val return extracted value if function success, in fail case original value unmodified
2382 * @param defVal default value used if no data for extraction in args
2383 * @return true if value extraction successful
2385 bool ChatHandler::ExtractOptUInt32(char** args, uint32& val, uint32 defVal)
2387 if (!*args || !** args)
2389 val = defVal;
2390 return true;
2393 return ExtractUInt32(args, val);
2397 * Function extract to val arg float value or fail
2399 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2400 * @param val return extracted value if function success, in fail case original value unmodified
2401 * @return true if value extraction successful
2403 bool ChatHandler::ExtractFloat(char** args, float& val)
2405 if (!*args || !** args)
2406 return false;
2408 char* tail = *args;
2410 double valRaw = strtod(*args, &tail);
2412 if (tail != *args && isWhiteSpace(*tail))
2413 *(tail++) = '\0';
2414 else if (tail && *tail) // some not whitespace symbol
2415 return false; // args not modified and can be re-parsed
2417 // value successfully extracted
2418 val = float(valRaw);
2419 *args = tail;
2421 SkipWhiteSpaces(args);
2422 return true;
2426 * Function extract to val arg optional float value or use default value. Fail if extracted not float.
2428 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2429 * @param val return extracted value if function success, in fail case original value unmodified
2430 * @param defVal default value used if no data for extraction in args
2431 * @return true if value extraction successful
2433 bool ChatHandler::ExtractOptFloat(char** args, float& val, float defVal)
2435 if (!*args || !** args)
2437 val = defVal;
2438 return true;
2441 return ExtractFloat(args, val);
2445 * Function extract name-like string (from non-numeric or special symbol until whitespace)
2447 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2448 * @param lit optional explicit literal requirement. function fail if literal is not starting substring of lit.
2449 * 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
2450 * @return name/number-like string without whitespaces, or NULL if args empty or not appropriate content.
2452 char* ChatHandler::ExtractLiteralArg(char** args, char const* lit /*= NULL*/)
2454 if (!*args || !** args)
2455 return NULL;
2457 char* head = *args;
2459 // reject quoted string or link (|-started text)
2460 switch (head[0])
2462 // reject quoted string
2463 case '[': case '\'': case '"':
2464 return NULL;
2465 // reject link (|-started text)
2466 case '|':
2467 // client replace all | by || in raw text
2468 if (head[1] != '|')
2469 return NULL;
2470 ++head; // skip one |
2471 break;
2472 default: break;
2475 if (lit)
2477 int l = strlen(lit);
2479 int largs = 0;
2480 while (head[largs] && !isWhiteSpace(head[largs]))
2481 ++largs;
2483 if (largs < l)
2484 l = largs;
2486 int diff = strncmp(head, lit, l);
2488 if (diff != 0)
2489 return NULL;
2491 if (head[l] && !isWhiteSpace(head[l]))
2492 return NULL;
2494 char* arg = head;
2496 if (head[l])
2498 head[l] = '\0';
2500 head += l + 1;
2502 *args = head;
2504 else
2505 *args = head + l;
2507 SkipWhiteSpaces(args);
2508 return arg;
2511 char* name = strtok(head, " ");
2513 char* tail = strtok(NULL, "");
2515 *args = tail ? tail : (char*)""; // *args don't must be NULL
2517 SkipWhiteSpaces(args);
2519 return name;
2523 * Function extract quote-like string (any characters guarded by some special character, in our cases ['")
2525 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2526 * @param asis control save quote string wrappers
2527 * @return quote-like string, or NULL if args empty or not appropriate content.
2529 char* ChatHandler::ExtractQuotedArg(char** args, bool asis /*= false*/)
2531 if (!*args || !** args)
2532 return NULL;
2534 if (**args != '\'' &&** args != '"' &&** args != '[')
2535 return NULL;
2537 char guard = (*args)[0];
2539 if (guard == '[')
2540 guard = ']';
2542 char* tail = (*args) + 1; // start scan after first quote symbol
2543 char* head = asis ? *args : tail; // start arg
2545 while (*tail && *tail != guard)
2546 ++tail;
2548 if (!*tail || (tail[1] && !isWhiteSpace(tail[1]))) // fail
2549 return NULL;
2551 if (!tail[1]) // quote is last char in string
2553 if (!asis)
2554 *tail = '\0';
2556 else // quote isn't last char
2558 if (asis)
2559 ++tail;
2561 *tail = '\0';
2564 *args = tail + 1;
2566 SkipWhiteSpaces(args);
2568 return head;
2572 * Function extract quote-like string or literal if quote not detected
2574 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2575 * @param asis control save quote string wrappers
2576 * @return quote/literal string, or NULL if args empty or not appropriate content.
2578 char* ChatHandler::ExtractQuotedOrLiteralArg(char** args, bool asis /*= false*/)
2580 char* arg = ExtractQuotedArg(args, asis);
2581 if (!arg)
2582 arg = ExtractLiteralArg(args);
2583 return arg;
2587 * Function extract on/off literals as boolean values
2589 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2590 * @param val return extracted value if function success, in fail case original value unmodified
2591 * @return true at success
2593 bool ChatHandler::ExtractOnOff(char** args, bool& value)
2595 char* arg = ExtractLiteralArg(args);
2596 if (!arg)
2597 return false;
2599 if (strncmp(arg, "on", 3) == 0)
2600 value = true;
2601 else if (strncmp(arg, "off", 4) == 0)
2602 value = false;
2603 else
2604 return false;
2606 return true;
2610 * Function extract shift-link-like string (any characters guarded by | and |h|r with some additional internal structure check)
2612 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2614 * @param linkTypes optional NULL-terminated array of link types, shift-link must fit one from link type from array if provided or extraction fail
2616 * @param found_idx if not NULL then at return index in linkTypes that fit shift-link type, if extraction fail then non modified
2618 * @param keyPair if not NULL then pointer to 2-elements array for return start and end pointer for found key
2619 * if extraction fail then non modified
2621 * @param somethingPair then pointer to 2-elements array for return start and end pointer if found.
2622 * if not NULL then shift-link must have data field, if extraction fail then non modified
2624 * @return shift-link-like string, or NULL if args empty or not appropriate content.
2626 char* ChatHandler::ExtractLinkArg(char** args, char const* const* linkTypes /*= NULL*/, int* foundIdx /*= NULL*/, char** keyPair /*= NULL*/, char** somethingPair /*= NULL*/)
2628 if (!*args || !** args)
2629 return NULL;
2631 // skip if not linked started or encoded single | (doubled by client)
2632 if ((*args)[0] != '|' || (*args)[1] == '|')
2633 return NULL;
2635 // |color|Hlinktype:key:data...|h[name]|h|r
2637 char* head = *args;
2639 // [name] Shift-click form |color|linkType:key|h[name]|h|r
2640 // or
2641 // [name] Shift-click form |color|linkType:key:something1:...:somethingN|h[name]|h|r
2642 // or
2643 // [name] Shift-click form |linkType:key|h[name]|h|r
2645 // |color|Hlinktype:key:data...|h[name]|h|r
2647 char* tail = (*args) + 1; // skip |
2649 if (*tail != 'H') // skip color part, some links can not have color part
2651 while (*tail && *tail != '|')
2652 ++tail;
2654 if (!*tail)
2655 return NULL;
2657 // |Hlinktype:key:data...|h[name]|h|r
2659 ++tail; // skip |
2662 // Hlinktype:key:data...|h[name]|h|r
2664 if (*tail != 'H')
2665 return NULL;
2667 int linktype_idx = 0;
2669 if (linkTypes) // check link type if provided
2671 // check linktypes (its include H in name)
2672 for (; linkTypes[linktype_idx]; ++linktype_idx)
2674 // exactly string with follow : or |
2675 int l = strlen(linkTypes[linktype_idx]);
2676 if (strncmp(tail, linkTypes[linktype_idx], l) == 0 &&
2677 (tail[l] == ':' || tail[l] == '|'))
2678 break;
2681 // is search fail?
2682 if (!linkTypes[linktype_idx]) // NULL terminator in last element
2683 return NULL;
2685 tail += strlen(linkTypes[linktype_idx]); // skip linktype string
2687 // :key:data...|h[name]|h|r
2689 if (*tail != ':')
2690 return NULL;
2692 else
2694 while (*tail && *tail != ':') // skip linktype string
2695 ++tail;
2697 if (!*tail)
2698 return NULL;
2701 ++tail;
2703 // key:data...|h[name]|h|r
2704 char* keyStart = tail; // remember key start for return
2705 char* keyEnd = tail; // key end for truncate, will updated
2707 while (*tail && *tail != '|' && *tail != ':')
2708 ++tail;
2710 if (!*tail)
2711 return NULL;
2713 keyEnd = tail; // remember key end for truncate
2715 // |h[name]|h|r or :something...|h[name]|h|r
2717 char* somethingStart = tail + 1;
2718 char* somethingEnd = tail + 1; // will updated later if need
2720 if (*tail == ':' && somethingPair) // optional data extraction
2722 // :something...|h[name]|h|r
2724 if (*tail == ':')
2725 ++tail;
2727 // something|h[name]|h|r or something:something2...|h[name]|h|r
2729 while (*tail && *tail != '|' && *tail != ':')
2730 ++tail;
2732 if (!*tail)
2733 return NULL;
2735 somethingEnd = tail; // remember data end for truncate
2738 // |h[name]|h|r or :something2...|h[name]|h|r
2740 while (*tail && (*tail != '|' || *(tail + 1) != 'h')) // skip ... part if exist
2741 ++tail;
2743 if (!*tail)
2744 return NULL;
2746 // |h[name]|h|r
2748 tail += 2; // skip |h
2750 // [name]|h|r
2751 if (!*tail || *tail != '[')
2752 return NULL;
2754 while (*tail && (*tail != ']' || *(tail + 1) != '|')) // skip name part
2755 ++tail;
2757 tail += 2; // skip ]|
2759 // h|r
2760 if (!*tail || *tail != 'h' || *(tail + 1) != '|')
2761 return NULL;
2763 tail += 2; // skip h|
2765 // r
2766 if (!*tail || *tail != 'r' || (*(tail + 1) && !isWhiteSpace(*(tail + 1))))
2767 return NULL;
2769 ++tail; // skip r
2771 // success
2773 if (*tail) // truncate all link string
2774 *(tail++) = '\0';
2776 if (foundIdx)
2777 *foundIdx = linktype_idx;
2779 if (keyPair)
2781 keyPair[0] = keyStart;
2782 keyPair[1] = keyEnd;
2785 if (somethingPair)
2787 somethingPair[0] = somethingStart;
2788 somethingPair[1] = somethingEnd;
2791 *args = tail;
2793 SkipWhiteSpaces(args);
2795 return head;
2799 * Function extract name/number/quote/shift-link-like string
2801 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2802 * @param asis control save quote string wrappers
2803 * @return extracted arg string, or NULL if args empty or not appropriate content.
2805 char* ChatHandler::ExtractArg(char** args, bool asis /*= false*/)
2807 if (!*args || !** args)
2808 return NULL;
2810 char* arg = ExtractQuotedOrLiteralArg(args, asis);
2811 if (!arg)
2812 arg = ExtractLinkArg(args);
2814 return arg;
2818 * Function extract name/quote/number/shift-link-like string, and return it if args have more non-whitespace data
2820 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2821 * if args have only single arg then args still pointing to this arg (unmodified pointer)
2822 * @return extracted string, or NULL if args empty or not appropriate content or have single arg totally.
2824 char* ChatHandler::ExtractOptNotLastArg(char** args)
2826 char* arg = ExtractArg(args, true);
2828 // have more data
2829 if (*args &&** args)
2830 return arg;
2832 // optional name not found
2833 *args = arg ? arg : (char*)""; // *args don't must be NULL
2835 return NULL;
2839 * Function extract data from shift-link "|color|LINKTYPE:RETURN:SOMETHING1|h[name]|h|r if linkType == LINKTYPE
2840 * It also extract literal/quote if not shift-link in args
2842 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2843 * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer)
2845 * @param linkType shift-link must fit by link type to this arg value or extraction fail
2847 * @param something1 if not NULL then shift-link must have data field and it returned into this arg
2848 * if extraction fail then non modified
2850 * @return extracted key, or NULL if args empty or not appropriate content or not fit to linkType.
2852 char* ChatHandler::ExtractKeyFromLink(char** text, char const* linkType, char** something1 /*= NULL*/)
2854 char const* linkTypes[2];
2855 linkTypes[0] = linkType;
2856 linkTypes[1] = NULL;
2858 int foundIdx;
2860 return ExtractKeyFromLink(text, linkTypes, &foundIdx, something1);
2864 * Function extract data from shift-link "|color|LINKTYPE:RETURN:SOMETHING1|h[name]|h|r if LINKTYPE in linkTypes array
2865 * It also extract literal/quote if not shift-link in args
2867 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2868 * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer)
2870 * @param linkTypes NULL-terminated array of link types, shift-link must fit one from link type from array or extraction fail
2872 * @param found_idx if not NULL then at return index in linkTypes that fit shift-link type, for non-link case return -1
2873 * if extraction fail then non modified
2875 * @param something1 if not NULL then shift-link must have data field and it returned into this arg
2876 * if extraction fail then non modified
2878 * @return extracted key, or NULL if args empty or not appropriate content or not fit to linkType.
2880 char* ChatHandler::ExtractKeyFromLink(char** text, char const* const* linkTypes, int* found_idx, char** something1 /*= NULL*/)
2882 // skip empty
2883 if (!*text || !** text)
2884 return NULL;
2886 // return non link case
2887 char* arg = ExtractQuotedOrLiteralArg(text);
2888 if (arg)
2890 if (found_idx)
2891 *found_idx = -1; // special index case
2893 return arg;
2896 char* keyPair[2];
2897 char* somethingPair[2];
2899 arg = ExtractLinkArg(text, linkTypes, found_idx, keyPair, something1 ? somethingPair : NULL);
2900 if (!arg)
2901 return NULL;
2903 *keyPair[1] = '\0'; // truncate key string
2905 if (something1)
2907 *somethingPair[1] = '\0'; // truncate data string
2908 *something1 = somethingPair[0];
2911 return keyPair[0];
2915 * Function extract uint32 key from shift-link "|color|LINKTYPE:RETURN|h[name]|h|r if linkType == LINKTYPE
2916 * It also extract direct number if not shift-link in args
2918 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
2919 * if args have sift link with linkType != LINKTYPE then args still pointing to this arg (unmodified pointer)
2921 * @param linkType shift-link must fit by link type to this arg value or extraction fail
2923 * @param value store result value at success return, not modified at fail
2925 * @return true if extraction succesful
2927 bool ChatHandler::ExtractUint32KeyFromLink(char** text, char const* linkType, uint32& value)
2929 char* arg = ExtractKeyFromLink(text, linkType);
2930 if (!arg)
2931 return false;
2933 return ExtractUInt32(&arg, value);
2936 GameObject* ChatHandler::GetGameObjectWithGuid(uint32 lowguid, uint32 entry)
2938 if (!m_session)
2939 return NULL;
2941 Player* pl = m_session->GetPlayer();
2943 return pl->GetMap()->GetGameObject(ObjectGuid(HIGHGUID_GAMEOBJECT, entry, lowguid));
2946 enum SpellLinkType
2948 SPELL_LINK_RAW = -1, // non-link case
2949 SPELL_LINK_SPELL = 0,
2950 SPELL_LINK_TALENT = 1,
2951 SPELL_LINK_ENCHANT = 2,
2952 SPELL_LINK_TRADE = 3,
2953 SPELL_LINK_GLYPH = 4,
2956 static char const* const spellKeys[] =
2958 "Hspell", // normal spell
2959 "Htalent", // talent spell
2960 "Henchant", // enchanting recipe spell
2961 "Htrade", // profession/skill spell
2962 "Hglyph", // glyph
2963 NULL
2966 uint32 ChatHandler::ExtractSpellIdFromLink(char** text)
2968 // number or [name] Shift-click form |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r
2969 // number or [name] Shift-click form |color|Hglyph:glyph_slot_id:glyph_prop_id|h[%s]|h|r
2970 // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
2971 // number or [name] Shift-click form |color|Htalent:talent_id,rank|h[name]|h|r
2972 // number or [name] Shift-click form |color|Htrade:spell_id,skill_id,max_value,cur_value|h[name]|h|r
2973 int type;
2974 char* param1_str = NULL;
2975 char* idS = ExtractKeyFromLink(text, spellKeys, &type, &param1_str);
2976 if (!idS)
2977 return 0;
2979 uint32 id;
2980 if (!ExtractUInt32(&idS, id))
2981 return 0;
2983 switch (type)
2985 case SPELL_LINK_RAW:
2986 case SPELL_LINK_SPELL:
2987 case SPELL_LINK_ENCHANT:
2988 case SPELL_LINK_TRADE:
2989 return id;
2990 case SPELL_LINK_TALENT:
2992 // talent
2993 TalentEntry const* talentEntry = sTalentStore.LookupEntry(id);
2994 if (!talentEntry)
2995 return 0;
2997 int32 rank;
2998 if (!ExtractInt32(&param1_str, rank))
2999 return 0;
3001 if (rank < 0) // unlearned talent have in shift-link field -1 as rank
3002 rank = 0;
3004 return rank < MAX_TALENT_RANK ? talentEntry->RankID[rank] : 0;
3006 case SPELL_LINK_GLYPH:
3008 uint32 glyph_prop_id;
3010 if (!ExtractUInt32(&param1_str, glyph_prop_id))
3011 return 0;
3013 GlyphPropertiesEntry const* glyphPropEntry = sGlyphPropertiesStore.LookupEntry(glyph_prop_id);
3014 return glyphPropEntry ? glyphPropEntry->SpellId : 0;
3018 // unknown type?
3019 return 0;
3022 GameTele const* ChatHandler::ExtractGameTeleFromLink(char** text)
3024 // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r
3025 char* cId = ExtractKeyFromLink(text, "Htele");
3026 if (!cId)
3027 return NULL;
3029 // id case (explicit or from shift link)
3030 uint32 id;
3031 if (ExtractUInt32(&cId, id))
3032 return sObjectMgr.GetGameTele(id);
3033 else
3034 return sObjectMgr.GetGameTele(cId);
3037 enum GuidLinkType
3039 GUID_LINK_RAW = -1, // non-link case
3040 GUID_LINK_PLAYER = 0,
3041 GUID_LINK_CREATURE = 1,
3042 GUID_LINK_GAMEOBJECT = 2,
3045 static char const* const guidKeys[] =
3047 "Hplayer",
3048 "Hcreature",
3049 "Hgameobject",
3050 NULL
3053 ObjectGuid ChatHandler::ExtractGuidFromLink(char** text)
3055 int type = 0;
3057 // |color|Hcreature:creature_guid|h[name]|h|r
3058 // |color|Hgameobject:go_guid|h[name]|h|r
3059 // |color|Hplayer:name|h[name]|h|r
3060 char* idS = ExtractKeyFromLink(text, guidKeys, &type);
3061 if (!idS)
3062 return ObjectGuid();
3064 switch (type)
3066 case GUID_LINK_RAW:
3067 case GUID_LINK_PLAYER:
3069 std::string name = idS;
3070 if (!normalizePlayerName(name))
3071 return ObjectGuid();
3073 if (Player* player = sObjectMgr.GetPlayer(name.c_str()))
3074 return player->GetObjectGuid();
3076 return sObjectMgr.GetPlayerGuidByName(name);
3078 case GUID_LINK_CREATURE:
3080 uint32 lowguid;
3081 if (!ExtractUInt32(&idS, lowguid))
3082 return ObjectGuid();
3084 if (CreatureData const* data = sObjectMgr.GetCreatureData(lowguid))
3085 return data->GetObjectGuid(lowguid);
3086 else
3087 return ObjectGuid();
3089 case GUID_LINK_GAMEOBJECT:
3091 uint32 lowguid;
3092 if (!ExtractUInt32(&idS, lowguid))
3093 return ObjectGuid();
3095 if (GameObjectData const* data = sObjectMgr.GetGOData(lowguid))
3096 return ObjectGuid(HIGHGUID_GAMEOBJECT, data->id, lowguid);
3097 else
3098 return ObjectGuid();
3102 // unknown type?
3103 return ObjectGuid();
3106 enum LocationLinkType
3108 LOCATION_LINK_RAW = -1, // non-link case
3109 LOCATION_LINK_PLAYER = 0,
3110 LOCATION_LINK_TELE = 1,
3111 LOCATION_LINK_TAXINODE = 2,
3112 LOCATION_LINK_CREATURE = 3,
3113 LOCATION_LINK_GAMEOBJECT = 4,
3114 LOCATION_LINK_CREATURE_ENTRY = 5,
3115 LOCATION_LINK_GAMEOBJECT_ENTRY = 6,
3116 LOCATION_LINK_AREATRIGGER = 7,
3117 LOCATION_LINK_AREATRIGGER_TARGET = 8,
3120 static char const* const locationKeys[] =
3122 "Htele",
3123 "Htaxinode",
3124 "Hplayer",
3125 "Hcreature",
3126 "Hgameobject",
3127 "Hcreature_entry",
3128 "Hgameobject_entry",
3129 "Hareatrigger",
3130 "Hareatrigger_target",
3131 NULL
3134 bool ChatHandler::ExtractLocationFromLink(char** text, uint32& mapid, float& x, float& y, float& z)
3136 int type = 0;
3138 // |color|Hplayer:name|h[name]|h|r
3139 // |color|Htele:id|h[name]|h|r
3140 // |color|Htaxinode:id|h[name]|h|r
3141 // |color|Hcreature:creature_guid|h[name]|h|r
3142 // |color|Hgameobject:go_guid|h[name]|h|r
3143 // |color|Hcreature_entry:creature_id|h[name]|h|r
3144 // |color|Hgameobject_entry:go_id|h[name]|h|r
3145 // |color|Hareatrigger:id|h[name]|h|r
3146 // |color|Hareatrigger_target:id|h[name]|h|r
3147 char* idS = ExtractKeyFromLink(text, locationKeys, &type);
3148 if (!idS)
3149 return false;
3151 switch (type)
3153 case LOCATION_LINK_RAW:
3154 case LOCATION_LINK_PLAYER:
3156 std::string name = idS;
3157 if (!normalizePlayerName(name))
3158 return false;
3160 if (Player* player = sObjectMgr.GetPlayer(name.c_str()))
3162 mapid = player->GetMapId();
3163 x = player->GetPositionX();
3164 y = player->GetPositionY();
3165 z = player->GetPositionZ();
3166 return true;
3169 if (ObjectGuid guid = sObjectMgr.GetPlayerGuidByName(name))
3171 // to point where player stay (if loaded)
3172 float o;
3173 bool in_flight;
3174 return Player::LoadPositionFromDB(guid, mapid, x, y, z, o, in_flight);
3177 return false;
3179 case LOCATION_LINK_TELE:
3181 uint32 id;
3182 if (!ExtractUInt32(&idS, id))
3183 return false;
3185 GameTele const* tele = sObjectMgr.GetGameTele(id);
3186 if (!tele)
3187 return false;
3188 mapid = tele->mapId;
3189 x = tele->position_x;
3190 y = tele->position_y;
3191 z = tele->position_z;
3192 return true;
3194 case LOCATION_LINK_TAXINODE:
3196 uint32 id;
3197 if (!ExtractUInt32(&idS, id))
3198 return false;
3200 TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
3201 if (!node)
3202 return false;
3203 mapid = node->map_id;
3204 x = node->x;
3205 y = node->y;
3206 z = node->z;
3207 return true;
3209 case LOCATION_LINK_CREATURE:
3211 uint32 lowguid;
3212 if (!ExtractUInt32(&idS, lowguid))
3213 return false;
3215 if (CreatureData const* data = sObjectMgr.GetCreatureData(lowguid))
3217 mapid = data->mapid;
3218 x = data->posX;
3219 y = data->posY;
3220 z = data->posZ;
3221 return true;
3223 else
3224 return false;
3226 case LOCATION_LINK_GAMEOBJECT:
3228 uint32 lowguid;
3229 if (!ExtractUInt32(&idS, lowguid))
3230 return false;
3232 if (GameObjectData const* data = sObjectMgr.GetGOData(lowguid))
3234 mapid = data->mapid;
3235 x = data->posX;
3236 y = data->posY;
3237 z = data->posZ;
3238 return true;
3240 else
3241 return false;
3243 case LOCATION_LINK_CREATURE_ENTRY:
3245 uint32 id;
3246 if (!ExtractUInt32(&idS, id))
3247 return false;
3249 if (ObjectMgr::GetCreatureTemplate(id))
3251 FindCreatureData worker(id, m_session ? m_session->GetPlayer() : NULL);
3253 sObjectMgr.DoCreatureData(worker);
3255 if (CreatureDataPair const* dataPair = worker.GetResult())
3257 mapid = dataPair->second.mapid;
3258 x = dataPair->second.posX;
3259 y = dataPair->second.posY;
3260 z = dataPair->second.posZ;
3261 return true;
3263 else
3264 return false;
3266 else
3267 return false;
3269 case LOCATION_LINK_GAMEOBJECT_ENTRY:
3271 uint32 id;
3272 if (!ExtractUInt32(&idS, id))
3273 return false;
3275 if (ObjectMgr::GetGameObjectInfo(id))
3277 FindGOData worker(id, m_session ? m_session->GetPlayer() : NULL);
3279 sObjectMgr.DoGOData(worker);
3281 if (GameObjectDataPair const* dataPair = worker.GetResult())
3283 mapid = dataPair->second.mapid;
3284 x = dataPair->second.posX;
3285 y = dataPair->second.posY;
3286 z = dataPair->second.posZ;
3287 return true;
3289 else
3290 return false;
3292 else
3293 return false;
3295 case LOCATION_LINK_AREATRIGGER:
3297 uint32 id;
3298 if (!ExtractUInt32(&idS, id))
3299 return false;
3301 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(id);
3302 if (!atEntry)
3304 PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND, id);
3305 SetSentErrorMessage(true);
3306 return false;
3309 mapid = atEntry->mapid;
3310 x = atEntry->x;
3311 y = atEntry->y;
3312 z = atEntry->z;
3313 return true;
3315 case LOCATION_LINK_AREATRIGGER_TARGET:
3317 uint32 id;
3318 if (!ExtractUInt32(&idS, id))
3319 return false;
3321 if (!sAreaTriggerStore.LookupEntry(id))
3323 PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND, id);
3324 SetSentErrorMessage(true);
3325 return false;
3328 AreaTrigger const* at = sObjectMgr.GetAreaTrigger(id);
3329 if (!at)
3331 PSendSysMessage(LANG_AREATRIGER_NOT_HAS_TARGET, id);
3332 SetSentErrorMessage(true);
3333 return false;
3336 mapid = at->target_mapId;
3337 x = at->target_X;
3338 y = at->target_Y;
3339 z = at->target_Z;
3340 return true;
3344 // unknown type?
3345 return false;
3348 std::string ChatHandler::ExtractPlayerNameFromLink(char** text)
3350 // |color|Hplayer:name|h[name]|h|r
3351 char* name_str = ExtractKeyFromLink(text, "Hplayer");
3352 if (!name_str)
3353 return "";
3355 std::string name = name_str;
3356 if (!normalizePlayerName(name))
3357 return "";
3359 return name;
3363 * Function extract at least one from request player data (pointer/guid/name) from args name/shift-link or selected player if no args
3365 * @param args variable pointer to non parsed args string, updated at function call to new position (with skipped white spaces)
3367 * @param player optional arg One from 3 optional args must be provided at least (or more).
3368 * @param player_guid optional arg For function success only one from provided args need get result
3369 * @param player_name optional arg But if early arg get value then all later args will have its (if requested)
3370 * if player_guid requested and not found then name also will not found
3371 * So at success can be returned 2 cases: (player/guid/name) or (guid/name)
3373 * @return true if extraction successful
3375 bool ChatHandler::ExtractPlayerTarget(char** args, Player** player /*= NULL*/, ObjectGuid* player_guid /*= NULL*/, std::string* player_name /*= NULL*/)
3377 if (*args &&** args)
3379 std::string name = ExtractPlayerNameFromLink(args);
3380 if (name.empty())
3382 SendSysMessage(LANG_PLAYER_NOT_FOUND);
3383 SetSentErrorMessage(true);
3384 return false;
3387 Player* pl = sObjectMgr.GetPlayer(name.c_str());
3389 // if allowed player pointer
3390 if (player)
3391 *player = pl;
3393 // if need guid value from DB (in name case for check player existence)
3394 ObjectGuid guid = !pl && (player_guid || player_name) ? sObjectMgr.GetPlayerGuidByName(name) : ObjectGuid();
3396 // if allowed player guid (if no then only online players allowed)
3397 if (player_guid)
3398 *player_guid = pl ? pl->GetObjectGuid() : guid;
3400 if (player_name)
3401 *player_name = pl || guid ? name : "";
3403 else
3405 Player* pl = getSelectedPlayer();
3406 // if allowed player pointer
3407 if (player)
3408 *player = pl;
3409 // if allowed player guid (if no then only online players allowed)
3410 if (player_guid)
3411 *player_guid = pl ? pl->GetObjectGuid() : ObjectGuid();
3413 if (player_name)
3414 *player_name = pl ? pl->GetName() : "";
3417 // some from req. data must be provided (note: name is empty if player not exist)
3418 if ((!player || !*player) && (!player_guid || !*player_guid) && (!player_name || player_name->empty()))
3420 SendSysMessage(LANG_PLAYER_NOT_FOUND);
3421 SetSentErrorMessage(true);
3422 return false;
3425 return true;
3428 uint32 ChatHandler::ExtractAccountId(char** args, std::string* accountName /*= NULL*/, Player** targetIfNullArg /*= NULL*/)
3430 uint32 account_id = 0;
3432 ///- Get the account name from the command line
3433 char* account_str = ExtractLiteralArg(args);
3435 if (!account_str)
3437 if (!targetIfNullArg)
3438 return 0;
3440 /// only target player different from self allowed (if targetPlayer!=NULL then not console)
3441 Player* targetPlayer = getSelectedPlayer();
3442 if (!targetPlayer)
3443 return 0;
3445 account_id = targetPlayer->GetSession()->GetAccountId();
3447 if (accountName)
3448 sAccountMgr.GetName(account_id, *accountName);
3450 if (targetIfNullArg)
3451 *targetIfNullArg = targetPlayer;
3453 return account_id;
3456 std::string account_name;
3458 if (ExtractUInt32(&account_str, account_id))
3460 if (!sAccountMgr.GetName(account_id, account_name))
3462 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_str);
3463 SetSentErrorMessage(true);
3464 return 0;
3467 else
3469 account_name = account_str;
3470 if (!AccountMgr::normalizeString(account_name))
3472 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
3473 SetSentErrorMessage(true);
3474 return 0;
3477 account_id = sAccountMgr.GetId(account_name);
3478 if (!account_id)
3480 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
3481 SetSentErrorMessage(true);
3482 return 0;
3486 if (accountName)
3487 *accountName = account_name;
3489 if (targetIfNullArg)
3490 *targetIfNullArg = NULL;
3492 return account_id;
3495 struct RaceMaskName
3497 char const* literal;
3498 uint32 raceMask;
3501 static RaceMaskName const raceMaskNames[] =
3503 // races
3504 { "human", (1 << (RACE_HUMAN - 1)) },
3505 { "orc", (1 << (RACE_ORC - 1)) },
3506 { "dwarf", (1 << (RACE_DWARF - 1)) },
3507 { "nightelf", (1 << (RACE_NIGHTELF - 1))},
3508 { "undead", (1 << (RACE_UNDEAD - 1)) },
3509 { "tauren", (1 << (RACE_TAUREN - 1)) },
3510 { "gnome", (1 << (RACE_GNOME - 1)) },
3511 { "troll", (1 << (RACE_TROLL - 1)) },
3512 { "bloodelf", (1 << (RACE_BLOODELF - 1))},
3513 { "draenei", (1 << (RACE_DRAENEI - 1)) },
3515 // masks
3516 { "alliance", RACEMASK_ALLIANCE },
3517 { "horde", RACEMASK_HORDE },
3518 { "all", RACEMASK_ALL_PLAYABLE },
3520 // terminator
3521 { NULL, 0 }
3524 bool ChatHandler::ExtractRaceMask(char** text, uint32& raceMask, char const** maskName /*=NULL*/)
3526 if (ExtractUInt32(text, raceMask))
3528 if (maskName)
3529 *maskName = "custom mask";
3531 else
3533 for (RaceMaskName const* itr = raceMaskNames; itr->literal; ++itr)
3535 if (ExtractLiteralArg(text, itr->literal))
3537 raceMask = itr->raceMask;
3539 if (maskName)
3540 *maskName = itr->literal;
3541 break;
3545 if (!raceMask)
3546 return false;
3549 return true;
3552 std::string ChatHandler::GetNameLink(Player* chr) const
3554 return playerLink(chr->GetName());
3557 bool ChatHandler::needReportToTarget(Player* chr) const
3559 Player* pl = m_session->GetPlayer();
3560 return pl != chr && pl->IsVisibleGloballyFor(chr);
3563 LocaleConstant ChatHandler::GetSessionDbcLocale() const
3565 return m_session->GetSessionDbcLocale();
3568 int ChatHandler::GetSessionDbLocaleIndex() const
3570 return m_session->GetSessionDbLocaleIndex();
3573 const char* CliHandler::GetMangosString(int32 entry) const
3575 return sObjectMgr.GetMangosStringForDBCLocale(entry);
3578 uint32 CliHandler::GetAccountId() const
3580 return m_accountId;
3583 AccountTypes CliHandler::GetAccessLevel() const
3585 return m_loginAccessLevel;
3588 bool CliHandler::isAvailable(ChatCommand const& cmd) const
3590 // skip non-console commands in console case
3591 if (!cmd.AllowConsole)
3592 return false;
3594 // normal case
3595 return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel;
3598 void CliHandler::SendSysMessage(const char* str)
3600 m_print(m_callbackArg, str);
3601 m_print(m_callbackArg, "\r\n");
3604 std::string CliHandler::GetNameLink() const
3606 return GetMangosString(LANG_CONSOLE_COMMAND);
3609 bool CliHandler::needReportToTarget(Player* /*chr*/) const
3611 return true;
3614 LocaleConstant CliHandler::GetSessionDbcLocale() const
3616 return sWorld.GetDefaultDbcLocale();
3619 int CliHandler::GetSessionDbLocaleIndex() const
3621 return sObjectMgr.GetDBCLocaleIndex();
3624 // Check/ Output if a NPC or GO (by guid) is part of a pool or game event
3625 template <typename T>
3626 void ChatHandler::ShowNpcOrGoSpawnInformation(uint32 guid)
3628 if (uint16 pool_id = sPoolMgr.IsPartOfAPool<T>(guid))
3630 uint16 top_pool_id = sPoolMgr.IsPartOfTopPool<Pool>(pool_id);
3631 if (!top_pool_id || top_pool_id == pool_id)
3632 PSendSysMessage(LANG_NPC_GO_INFO_POOL, pool_id);
3633 else
3634 PSendSysMessage(LANG_NPC_GO_INFO_TOP_POOL, pool_id, top_pool_id);
3636 if (int16 event_id = sGameEventMgr.GetGameEventId<Pool>(top_pool_id))
3638 GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap();
3639 GameEventData const& eventData = events[std::abs(event_id)];
3641 if (event_id > 0)
3642 PSendSysMessage(LANG_NPC_GO_INFO_POOL_GAME_EVENT_S, top_pool_id, std::abs(event_id), eventData.description.c_str());
3643 else
3644 PSendSysMessage(LANG_NPC_GO_INFO_POOL_GAME_EVENT_D, top_pool_id, std::abs(event_id), eventData.description.c_str());
3647 else if (int16 event_id = sGameEventMgr.GetGameEventId<T>(guid))
3649 GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap();
3650 GameEventData const& eventData = events[std::abs(event_id)];
3652 if (event_id > 0)
3653 PSendSysMessage(LANG_NPC_GO_INFO_GAME_EVENT_S, std::abs(event_id), eventData.description.c_str());
3654 else
3655 PSendSysMessage(LANG_NPC_GO_INFO_GAME_EVENT_D, std::abs(event_id), eventData.description.c_str());
3659 // Prepare ShortString for a NPC or GO (by guid) with pool or game event IDs
3660 template <typename T>
3661 std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation(uint32 guid)
3663 std::string str = "";
3664 if (uint16 pool_id = sPoolMgr.IsPartOfAPool<T>(guid))
3666 uint16 top_pool_id = sPoolMgr.IsPartOfTopPool<T>(guid);
3667 if (int16 event_id = sGameEventMgr.GetGameEventId<Pool>(top_pool_id))
3669 char buffer[100];
3670 const char* format = GetMangosString(LANG_NPC_GO_INFO_POOL_EVENT_STRING);
3671 sprintf(buffer, format, pool_id, event_id);
3672 str = buffer;
3674 else
3676 char buffer[100];
3677 const char* format = GetMangosString(LANG_NPC_GO_INFO_POOL_STRING);
3678 sprintf(buffer, format, pool_id);
3679 str = buffer;
3682 else if (int16 event_id = sGameEventMgr.GetGameEventId<T>(guid))
3684 char buffer[100];
3685 const char* format = GetMangosString(LANG_NPC_GO_INFO_EVENT_STRING);
3686 sprintf(buffer, format, event_id);
3687 str = buffer;
3690 return str;
3693 void ChatHandler::LogCommand(char const* fullcmd)
3695 // chat case
3696 if (m_session)
3698 Player* p = m_session->GetPlayer();
3699 ObjectGuid sel_guid = p->GetSelectionGuid();
3700 sLog.outCommand(GetAccountId(), "Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s]",
3701 fullcmd, p->GetName(), GetAccountId(), p->GetPositionX(), p->GetPositionY(), p->GetPositionZ(), p->GetMapId(),
3702 sel_guid.GetString().c_str());
3704 else // 0 account -> console
3706 sLog.outCommand(GetAccountId(), "Command: %s [Account: %u from %s]",
3707 fullcmd, GetAccountId(), GetAccountId() ? "RA-connection" : "Console");
3711 // Instantiate template for helper function
3712 template void ChatHandler::ShowNpcOrGoSpawnInformation<Creature>(uint32 guid);
3713 template void ChatHandler::ShowNpcOrGoSpawnInformation<GameObject>(uint32 guid);
3715 template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation<Creature>(uint32 guid);
3716 template std::string ChatHandler::PrepareStringNpcOrGoSpawnInformation<GameObject>(uint32 guid);