/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "ScriptMgr.h"
#include "AccountMgr.h"
#include "ArenaTeamMgr.h"
#include "CellImpl.h"
#include "CharacterCache.h"
#include "Chat.h"
#include "ChatCommand.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "DisableMgr.h"
#include "GridNotifiers.h"
#include "Group.h"
#include "IPLocation.h"
#include "Item.h"
#include "ItemBonusMgr.h"
#include "Language.h"
#include "MiscPackets.h"
#include "MMapFactory.h"
#include "MotionMaster.h"
#include "MovementDefines.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "PhasingHandler.h"
#include "Player.h"
#include "RealmList.h"
#include "SpellAuras.h"
#include "SpellHistory.h"
#include "SpellMgr.h"
#include "TerrainMgr.h"
#include "Transport.h"
#include "Weather.h"
#include "World.h"
#include "WorldSession.h"
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
using namespace Trinity::ChatCommands;
class misc_commandscript : public CommandScript
{
public:
misc_commandscript() : CommandScript("misc_commandscript") { }
ChatCommandTable GetCommands() const override
{
static ChatCommandTable commandTable =
{
{ "additem", HandleAddItemCommand, rbac::RBAC_PERM_COMMAND_ADDITEM, Console::No },
{ "additem to", HandleAddItemToCommand, rbac::RBAC_PERM_COMMAND_ADDITEM, Console::No },
{ "additem set", HandleAddItemSetCommand, rbac::RBAC_PERM_COMMAND_ADDITEMSET, Console::No },
{ "appear", HandleAppearCommand, rbac::RBAC_PERM_COMMAND_APPEAR, Console::No },
{ "aura", HandleAuraCommand, rbac::RBAC_PERM_COMMAND_AURA, Console::No },
{ "bank", HandleBankCommand, rbac::RBAC_PERM_COMMAND_BANK, Console::No },
{ "bindsight", HandleBindSightCommand, rbac::RBAC_PERM_COMMAND_BINDSIGHT, Console::No },
{ "combatstop", HandleCombatStopCommand, rbac::RBAC_PERM_COMMAND_COMBATSTOP, Console::Yes },
{ "cometome", HandleComeToMeCommand, rbac::RBAC_PERM_COMMAND_COMETOME, Console::No },
{ "commands", HandleCommandsCommand, rbac::RBAC_PERM_COMMAND_COMMANDS, Console::Yes },
{ "cooldown", HandleCooldownCommand, rbac::RBAC_PERM_COMMAND_COOLDOWN, Console::No },
{ "damage", HandleDamageCommand, rbac::RBAC_PERM_COMMAND_DAMAGE, Console::No },
{ "damage go", HandleDamageGoCommand, rbac::RBAC_PERM_COMMAND_DAMAGE, Console::No },
{ "dev", HandleDevCommand, rbac::RBAC_PERM_COMMAND_DEV, Console::No },
{ "die", HandleDieCommand, rbac::RBAC_PERM_COMMAND_DIE, Console::No },
{ "dismount", HandleDismountCommand, rbac::RBAC_PERM_COMMAND_DISMOUNT, Console::No },
{ "distance", HandleGetDistanceCommand, rbac::RBAC_PERM_COMMAND_DISTANCE, Console::No },
{ "freeze", HandleFreezeCommand, rbac::RBAC_PERM_COMMAND_FREEZE, Console::No },
{ "gps", HandleGPSCommand, rbac::RBAC_PERM_COMMAND_GPS, Console::No },
{ "guid", HandleGUIDCommand, rbac::RBAC_PERM_COMMAND_GUID, Console::No },
{ "help", HandleHelpCommand, rbac::RBAC_PERM_COMMAND_HELP, Console::Yes },
{ "hidearea", HandleHideAreaCommand, rbac::RBAC_PERM_COMMAND_HIDEAREA, Console::No },
{ "itemmove", HandleItemMoveCommand, rbac::RBAC_PERM_COMMAND_ITEMMOVE, Console::No },
{ "kick", HandleKickPlayerCommand, rbac::RBAC_PERM_COMMAND_KICK, Console::Yes },
{ "linkgrave", HandleLinkGraveCommand, rbac::RBAC_PERM_COMMAND_LINKGRAVE, Console::No },
{ "listfreeze", HandleListFreezeCommand, rbac::RBAC_PERM_COMMAND_LISTFREEZE, Console::No },
{ "movegens", HandleMovegensCommand, rbac::RBAC_PERM_COMMAND_MOVEGENS, Console::No },
{ "mute", HandleMuteCommand, rbac::RBAC_PERM_COMMAND_MUTE, Console::Yes },
{ "mutehistory", HandleMuteHistoryCommand, rbac::RBAC_PERM_COMMAND_MUTEHISTORY, Console::Yes },
{ "neargrave", HandleNearGraveCommand, rbac::RBAC_PERM_COMMAND_NEARGRAVE, Console::No },
{ "pinfo", HandlePInfoCommand, rbac::RBAC_PERM_COMMAND_PINFO, Console::Yes },
{ "playall", HandlePlayAllCommand, rbac::RBAC_PERM_COMMAND_PLAYALL, Console::No },
{ "possess", HandlePossessCommand, rbac::RBAC_PERM_COMMAND_POSSESS, Console::No },
{ "pvpstats", HandlePvPstatsCommand, rbac::RBAC_PERM_COMMAND_PVPSTATS, Console::Yes },
{ "recall", HandleRecallCommand, rbac::RBAC_PERM_COMMAND_RECALL, Console::No },
{ "repairitems", HandleRepairitemsCommand, rbac::RBAC_PERM_COMMAND_REPAIRITEMS, Console::Yes },
{ "respawn", HandleRespawnCommand, rbac::RBAC_PERM_COMMAND_RESPAWN, Console::No },
{ "revive", HandleReviveCommand, rbac::RBAC_PERM_COMMAND_REVIVE, Console::Yes },
{ "saveall", HandleSaveAllCommand, rbac::RBAC_PERM_COMMAND_SAVEALL, Console::Yes },
{ "save", HandleSaveCommand, rbac::RBAC_PERM_COMMAND_SAVE, Console::No },
{ "setskill", HandleSetSkillCommand, rbac::RBAC_PERM_COMMAND_SETSKILL, Console::No },
{ "showarea", HandleShowAreaCommand, rbac::RBAC_PERM_COMMAND_SHOWAREA, Console::No },
{ "summon", HandleSummonCommand, rbac::RBAC_PERM_COMMAND_SUMMON, Console::No },
{ "unaura", HandleUnAuraCommand, rbac::RBAC_PERM_COMMAND_UNAURA, Console::No },
{ "unbindsight", HandleUnbindSightCommand, rbac::RBAC_PERM_COMMAND_UNBINDSIGHT, Console::No },
{ "unfreeze", HandleUnFreezeCommand, rbac::RBAC_PERM_COMMAND_UNFREEZE, Console::No },
{ "unmute", HandleUnmuteCommand, rbac::RBAC_PERM_COMMAND_UNMUTE, Console::Yes },
{ "unpossess", HandleUnPossessCommand, rbac::RBAC_PERM_COMMAND_UNPOSSESS, Console::No },
{ "unstuck", HandleUnstuckCommand, rbac::RBAC_PERM_COMMAND_UNSTUCK, Console::Yes },
{ "wchange", HandleChangeWeather, rbac::RBAC_PERM_COMMAND_WCHANGE, Console::No },
{ "mailbox", HandleMailBoxCommand, rbac::RBAC_PERM_COMMAND_MAILBOX, Console::No },
};
return commandTable;
}
static bool HandlePvPstatsCommand(ChatHandler* handler)
{
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_FACTIONS_OVERALL);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result)
{
Field* fields = result->Fetch();
uint32 horde_victories = fields[1].GetUInt32();
if (!(result->NextRow()))
return false;
fields = result->Fetch();
uint32 alliance_victories = fields[1].GetUInt32();
handler->PSendSysMessage(LANG_PVPSTATS, alliance_victories, horde_victories);
}
else
return false;
}
else
handler->PSendSysMessage(LANG_PVPSTATS_DISABLED);
return true;
}
static bool HandleDevCommand(ChatHandler* handler, Optional enableArg)
{
Player* player = handler->GetSession()->GetPlayer();
if (!enableArg)
{
handler->GetSession()->SendNotification(player->IsDeveloper() ? LANG_DEV_ON : LANG_DEV_OFF);
return true;
}
if (*enableArg)
{
player->SetDeveloper(true);
handler->GetSession()->SendNotification(LANG_DEV_ON);
}
else
{
player->SetDeveloper(false);
handler->GetSession()->SendNotification(LANG_DEV_OFF);
}
return true;
}
static bool HandleGPSCommand(ChatHandler* handler, char const* args)
{
WorldObject* object = nullptr;
if (*args)
{
HighGuid guidHigh;
ObjectGuid::LowType guidLow = handler->extractLowGuidFromLink((char*)args, guidHigh);
if (!guidLow)
return false;
switch (guidHigh)
{
case HighGuid::Player:
{
object = ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create(guidLow));
if (!object)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
}
break;
}
case HighGuid::Creature:
{
object = handler->GetCreatureFromPlayerMapByDbGuid(guidLow);
if (!object)
{
handler->SendSysMessage(LANG_COMMAND_NOCREATUREFOUND);
handler->SetSentErrorMessage(true);
}
break;
}
case HighGuid::GameObject:
{
object = handler->GetObjectFromPlayerMapByDbGuid(guidLow);
if (!object)
{
handler->SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND);
handler->SetSentErrorMessage(true);
}
break;
}
default:
return false;
}
if (!object)
return false;
}
else
{
object = handler->getSelectedUnit();
if (!object)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
}
CellCoord cellCoord = Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY());
Cell cell(cellCoord);
uint32 zoneId, areaId;
object->GetZoneAndAreaId(zoneId, areaId);
uint32 mapId = object->GetMapId();
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
float zoneX = object->GetPositionX();
float zoneY = object->GetPositionY();
sDB2Manager.Map2ZoneCoordinates(zoneId, zoneX, zoneY);
Map* map = object->GetMap();
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
GridCoord gridCoord = Trinity::ComputeGridCoord(object->GetPositionX(), object->GetPositionY());
int gridX = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord;
int gridY = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord;
uint32 haveMap = TerrainInfo::ExistMap(mapId, gridX, gridY) ? 1 : 0;
uint32 haveVMap = TerrainInfo::ExistVMap(mapId, gridX, gridY) ? 1 : 0;
uint32 haveMMap = (DisableMgr::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0;
if (haveVMap)
{
if (object->IsOutdoors())
handler->PSendSysMessage(LANG_GPS_POSITION_OUTDOORS);
else
handler->PSendSysMessage(LANG_GPS_POSITION_INDOORS);
}
else
handler->PSendSysMessage(LANG_GPS_NO_VMAP);
char const* unknown = handler->GetTrinityString(LANG_UNKNOWN);
handler->PSendSysMessage(LANG_MAP_POSITION,
mapId, (mapEntry ? mapEntry->MapName[handler->GetSessionDbcLocale()] : unknown),
zoneId, (zoneEntry ? zoneEntry->AreaName[handler->GetSessionDbcLocale()] : unknown),
areaId, (areaEntry ? areaEntry->AreaName[handler->GetSessionDbcLocale()] : unknown),
object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation());
if (Transport* transport = dynamic_cast(object->GetTransport()))
handler->PSendSysMessage(LANG_TRANSPORT_POSITION,
transport->GetGOInfo()->moTransport.SpawnMap, object->GetTransOffsetX(), object->GetTransOffsetY(), object->GetTransOffsetZ(), object->GetTransOffsetO(),
transport->GetEntry(), transport->GetName().c_str());
handler->PSendSysMessage(LANG_GRID_POSITION,
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
zoneX, zoneY, groundZ, floorZ, map->GetMinHeight(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY()), haveMap, haveVMap, haveMMap);
LiquidData liquidStatus;
ZLiquidStatus status = map->GetLiquidStatus(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), {}, &liquidStatus);
if (status)
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, uint32(liquidStatus.type_flags.AsUnderlyingType()), status);
PhasingHandler::PrintToChat(handler, object);
return true;
}
static bool HandleAuraCommand(ChatHandler* handler, SpellInfo const* spell)
{
Unit* target = handler->getSelectedUnit();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (!spell)
return false;
target->AddAura(spell, MAX_EFFECT_MASK, target);
return true;
}
static bool HandleUnAuraCommand(ChatHandler* handler, Variant spellArg)
{
Unit* target = handler->getSelectedUnit();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (spellArg.holds_alternative())
{
target->RemoveAllAuras();
return true;
}
if (SpellInfo const* spellInfo = spellArg.get())
{
target->RemoveAurasDueToSpell(spellInfo->Id);
return true;
}
return false;
}
// Teleport to Player
static bool HandleAppearCommand(ChatHandler* handler, char const* args)
{
Player* target;
ObjectGuid targetGuid;
std::string targetName;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
return false;
Player* _player = handler->GetSession()->GetPlayer();
if (target == _player || targetGuid == _player->GetGUID())
{
handler->SendSysMessage(LANG_CANT_TELEPORT_SELF);
handler->SetSentErrorMessage(true);
return false;
}
if (target)
{
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
std::string chrNameLink = handler->playerLink(targetName);
Map* map = target->GetMap();
if (map->IsBattlegroundOrArena())
{
// only allow if gm mode is on
if (!_player->IsGameMaster())
{
handler->PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM, chrNameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
// if both players are in different bgs
else if (_player->GetBattlegroundId() && _player->GetBattlegroundId() != target->GetBattlegroundId())
_player->LeaveBattleground(false); // Note: should be changed so _player gets no Deserter debuff
// all's well, set bg id
// when porting out from the bg, it will be reset to 0
_player->SetBattlegroundId(target->GetBattlegroundId(), target->GetBattlegroundTypeId(), BATTLEGROUND_QUEUE_NONE); // unsure
// remember current position as entry point for return at bg end teleportation
if (!_player->GetMap()->IsBattlegroundOrArena())
_player->SetBattlegroundEntryPoint();
}
else if (map->IsDungeon())
{
// we have to go to instance, and can go to player only if:
// 1) we are in his group (either as leader or as member)
// 2) we are not bound to any group and have GM mode on
if (_player->GetGroup())
{
// we are in group, we can go only if we are in the player group
if (_player->GetGroup() != target->GetGroup())
{
handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY, chrNameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
// we are not in group, let's verify our GM mode
if (!_player->IsGameMaster())
{
handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM, chrNameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
}
if (map->IsRaid())
{
_player->SetRaidDifficultyID(target->GetRaidDifficultyID());
_player->SetLegacyRaidDifficultyID(target->GetLegacyRaidDifficultyID());
}
else
_player->SetDungeonDifficultyID(target->GetDungeonDifficultyID());
}
handler->PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str());
// stop flight if need
if (_player->IsInFlight())
_player->FinishTaxiFlight();
else
_player->SaveRecallPosition(); // save only in non-flight case
// to point to see at target with same orientation
float x, y, z;
target->GetClosePoint(x, y, z, _player->GetCombatReach(), 1.0f);
_player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAbsoluteAngle(target), TELE_TO_GM_MODE, target->GetInstanceId());
PhasingHandler::InheritPhaseShift(_player, target);
_player->UpdateObjectVisibility();
}
else
{
// check offline security
if (handler->HasLowerSecurity(nullptr, targetGuid))
return false;
std::string nameLink = handler->playerLink(targetName);
handler->PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str());
// to point where player stay (if loaded)
float x, y, z, o;
uint32 map;
bool in_flight;
if (!Player::LoadPositionFromDB(map, x, y, z, o, in_flight, targetGuid))
return false;
// stop flight if need
if (_player->IsInFlight())
_player->FinishTaxiFlight();
else
_player->SaveRecallPosition(); // save only in non-flight case
_player->TeleportTo(map, x, y, z, _player->GetOrientation());
}
return true;
}
// Summon Player
static bool HandleSummonCommand(ChatHandler* handler, char const* args)
{
Player* target;
ObjectGuid targetGuid;
std::string targetName;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
return false;
Player* _player = handler->GetSession()->GetPlayer();
if (target == _player || targetGuid == _player->GetGUID())
{
handler->PSendSysMessage(LANG_CANT_TELEPORT_SELF);
handler->SetSentErrorMessage(true);
return false;
}
if (target)
{
std::string nameLink = handler->playerLink(targetName);
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
if (target->IsBeingTeleported())
{
handler->PSendSysMessage(LANG_IS_TELEPORTED, nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
Map* map = _player->GetMap();
if (map->IsBattlegroundOrArena())
{
// only allow if gm mode is on
if (!_player->IsGameMaster())
{
handler->PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM, nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
// if both players are in different bgs
else if (target->GetBattlegroundId() && _player->GetBattlegroundId() != target->GetBattlegroundId())
target->LeaveBattleground(false); // Note: should be changed so target gets no Deserter debuff
// all's well, set bg id
// when porting out from the bg, it will be reset to 0
target->SetBattlegroundId(_player->GetBattlegroundId(), _player->GetBattlegroundTypeId(), BATTLEGROUND_QUEUE_NONE); // unsure about this
// remember current position as entry point for return at bg end teleportation
if (!target->GetMap()->IsBattlegroundOrArena())
target->SetBattlegroundEntryPoint();
}
else if (map->IsDungeon())
{
Map* targetMap = target->GetMap();
Player* targetGroupLeader = nullptr;
if (Group* targetGroup = target->GetGroup())
targetGroupLeader = ObjectAccessor::GetPlayer(map, targetGroup->GetLeaderGUID());
// check if far teleport is allowed
if (!targetGroupLeader || (targetGroupLeader->GetMapId() != map->GetId()) || (targetGroupLeader->GetInstanceId() != map->GetInstanceId()))
if ((targetMap->GetId() != map->GetId()) || (targetMap->GetInstanceId() != map->GetInstanceId()))
{
handler->PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST);
handler->SetSentErrorMessage(true);
return false;
}
// check if we're already in a different instance of the same map
if ((targetMap->GetId() == map->GetId()) && (targetMap->GetInstanceId() != map->GetInstanceId()))
{
handler->PSendSysMessage(LANG_CANNOT_SUMMON_INST_INST, nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
}
handler->PSendSysMessage(LANG_SUMMONING, nameLink.c_str(), "");
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_SUMMONED_BY, handler->playerLink(_player->GetName()).c_str());
// stop flight if need
if (_player->IsInFlight())
_player->FinishTaxiFlight();
else
_player->SaveRecallPosition(); // save only in non-flight case
// before GM
float x, y, z;
_player->GetClosePoint(x, y, z, target->GetCombatReach());
target->TeleportTo(_player->GetMapId(), x, y, z, target->GetOrientation(), TELE_TO_NONE, map->GetInstanceId());
PhasingHandler::InheritPhaseShift(target, _player);
target->UpdateObjectVisibility();
}
else
{
// check offline security
if (handler->HasLowerSecurity(nullptr, targetGuid))
return false;
std::string nameLink = handler->playerLink(targetName);
handler->PSendSysMessage(LANG_SUMMONING, nameLink.c_str(), handler->GetTrinityString(LANG_OFFLINE));
// in point where GM stay
Player::SavePositionInDB(WorldLocation(_player->GetMapId(),
_player->GetPositionX(),
_player->GetPositionY(),
_player->GetPositionZ(),
_player->GetOrientation()),
_player->GetZoneId(),
targetGuid, nullptr);
}
return true;
}
static bool HandleCommandsCommand(ChatHandler* handler)
{
Trinity::ChatCommands::SendCommandHelpFor(*handler, "");
return true;
}
static bool HandleDieCommand(ChatHandler* handler)
{
Unit* target = handler->getSelectedUnit();
if (!target || !handler->GetSession()->GetPlayer()->GetTarget())
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (Player* player = target->ToPlayer())
if (handler->HasLowerSecurity(player, ObjectGuid::Empty, false))
return false;
if (target->IsAlive())
{
if (sWorld->getBoolConfig(CONFIG_DIE_COMMAND_MODE))
Unit::Kill(handler->GetSession()->GetPlayer(), target);
else
Unit::DealDamage(handler->GetSession()->GetPlayer(), target, target->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
}
return true;
}
static bool HandleReviveCommand(ChatHandler* handler, char const* args)
{
Player* target;
ObjectGuid targetGuid;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid))
return false;
if (target)
{
target->ResurrectPlayer(target->GetSession()->HasPermission(rbac::RBAC_PERM_RESURRECT_WITH_FULL_HPS) ? 1.0f : 0.5f);
target->SpawnCorpseBones();
target->SaveToDB();
}
else
{
CharacterDatabaseTransaction trans(nullptr);
Player::OfflineResurrect(targetGuid, trans);
}
return true;
}
static bool HandleDismountCommand(ChatHandler* handler)
{
Player* player = handler->getSelectedPlayerOrSelf();
// If player is not mounted, so go out :)
if (!player->IsMounted())
{
handler->SendSysMessage(LANG_CHAR_NON_MOUNTED);
handler->SetSentErrorMessage(true);
return false;
}
if (player->IsInFlight())
{
handler->SendSysMessage(LANG_CHAR_IN_FLIGHT);
handler->SetSentErrorMessage(true);
return false;
}
player->Dismount();
player->RemoveAurasByType(SPELL_AURA_MOUNTED);
return true;
}
static bool HandleGUIDCommand(ChatHandler* handler)
{
ObjectGuid guid = handler->GetSession()->GetPlayer()->GetTarget();
if (guid.IsEmpty())
{
handler->SendSysMessage(LANG_NO_SELECTION);
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage(LANG_OBJECT_GUID, guid.ToString().c_str());
return true;
}
static bool HandleHelpCommand(ChatHandler* handler, Tail cmd)
{
Trinity::ChatCommands::SendCommandHelpFor(*handler, cmd);
if (cmd.empty())
Trinity::ChatCommands::SendCommandHelpFor(*handler, "help");
return true;
}
// move item to other slot
static bool HandleItemMoveCommand(ChatHandler* handler, uint8 srcSlot, uint8 dstSlot)
{
if (srcSlot == dstSlot)
return true;
if (!handler->GetSession()->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0, srcSlot, true))
return false;
if (!handler->GetSession()->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0, dstSlot, false))
return false;
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcSlot);
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstSlot);
handler->GetSession()->GetPlayer()->SwapItem(src, dst);
return true;
}
static bool HandleCooldownCommand(ChatHandler* handler, Optional spellArg)
{
Unit* target = handler->getSelectedUnit();
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
Player* owner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!owner)
{
owner = handler->GetSession()->GetPlayer();
target = owner;
}
std::string nameLink = handler->GetNameLink(owner);
if (!spellArg)
{
target->GetSpellHistory()->ResetAllCooldowns();
target->GetSpellHistory()->ResetAllCharges();
handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str());
}
else
{
if (!*spellArg)
{
handler->PSendSysMessage(LANG_UNKNOWN_SPELL, owner == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
handler->SetSentErrorMessage(true);
return false;
}
target->GetSpellHistory()->ResetCooldown((*spellArg)->Id, true);
target->GetSpellHistory()->ResetCharges((*spellArg)->ChargeCategoryId);
handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, (*spellArg)->Id, owner == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str());
}
return true;
}
static bool HandleGetDistanceCommand(ChatHandler* handler, char const* args)
{
WorldObject* object = nullptr;
if (*args)
{
HighGuid guidHigh;
ObjectGuid::LowType guidLow = handler->extractLowGuidFromLink((char*)args, guidHigh);
if (!guidLow)
return false;
switch (guidHigh)
{
case HighGuid::Player:
{
object = ObjectAccessor::GetPlayer(*handler->GetSession()->GetPlayer(), ObjectGuid::Create(guidLow));
if (!object)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
}
break;
}
case HighGuid::Creature:
{
object = handler->GetCreatureFromPlayerMapByDbGuid(guidLow);
if (!object)
{
handler->SendSysMessage(LANG_COMMAND_NOCREATUREFOUND);
handler->SetSentErrorMessage(true);
}
break;
}
case HighGuid::GameObject:
{
object = handler->GetObjectFromPlayerMapByDbGuid(guidLow);
if (!object)
{
handler->SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND);
handler->SetSentErrorMessage(true);
}
break;
}
default:
return false;
}
if (!object)
return false;
}
else
{
object = handler->getSelectedUnit();
if (!object)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
}
handler->PSendSysMessage(LANG_DISTANCE, handler->GetSession()->GetPlayer()->GetDistance(object), handler->GetSession()->GetPlayer()->GetDistance2d(object), handler->GetSession()->GetPlayer()->GetExactDist(object), handler->GetSession()->GetPlayer()->GetExactDist2d(object));
return true;
}
// Teleport player to last position
static bool HandleRecallCommand(ChatHandler* handler, char const* args)
{
Player* target;
if (!handler->extractPlayerTarget((char*)args, &target))
return false;
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
if (target->IsBeingTeleported())
{
handler->PSendSysMessage(LANG_IS_TELEPORTED, handler->GetNameLink(target).c_str());
handler->SetSentErrorMessage(true);
return false;
}
target->FinishTaxiFlight();
target->Recall();
return true;
}
static bool HandleSaveCommand(ChatHandler* handler)
{
Player* player = handler->GetSession()->GetPlayer();
// save GM account without delay and output message
if (handler->GetSession()->HasPermission(rbac::RBAC_PERM_COMMANDS_SAVE_WITHOUT_DELAY))
{
if (Player* target = handler->getSelectedPlayer())
target->SaveToDB();
else
player->SaveToDB();
handler->SendSysMessage(LANG_PLAYER_SAVED);
return true;
}
// save if the player has last been saved over 20 seconds ago
uint32 saveInterval = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE);
if (saveInterval == 0 || (saveInterval > 20 * IN_MILLISECONDS && player->GetSaveTimer() <= saveInterval - 20 * IN_MILLISECONDS))
player->SaveToDB();
return true;
}
// Save all players in the world
static bool HandleSaveAllCommand(ChatHandler* handler)
{
ObjectAccessor::SaveAllPlayers();
handler->SendSysMessage(LANG_PLAYERS_SAVED);
return true;
}
// kick player
static bool HandleKickPlayerCommand(ChatHandler* handler, char const* args)
{
Player* target = nullptr;
std::string playerName;
if (!handler->extractPlayerTarget((char*)args, &target, nullptr, &playerName))
return false;
if (handler->GetSession() && target == handler->GetSession()->GetPlayer())
{
handler->SendSysMessage(LANG_COMMAND_KICKSELF);
handler->SetSentErrorMessage(true);
return false;
}
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
std::string kickReasonStr = handler->GetTrinityString(LANG_NO_REASON);
if (*args != '\0')
{
char const* kickReason = strtok(nullptr, "\r");
if (kickReason != nullptr)
kickReasonStr = kickReason;
}
if (sWorld->getBoolConfig(CONFIG_SHOW_KICK_IN_WORLD))
sWorld->SendWorldText(LANG_COMMAND_KICKMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), playerName.c_str(), kickReasonStr.c_str());
else
handler->PSendSysMessage(LANG_COMMAND_KICKMESSAGE, playerName.c_str());
target->GetSession()->KickPlayer("HandleKickPlayerCommand GM Command");
return true;
}
static bool HandleUnstuckCommand(ChatHandler* handler, char const* args)
{
#define SPELL_UNSTUCK_ID 7355
#define SPELL_UNSTUCK_VISUAL 2683
// No args required for players
if (handler->GetSession() && !handler->GetSession()->HasPermission(rbac::RBAC_PERM_COMMANDS_USE_UNSTUCK_WITH_ARGS))
{
// 7355: "Stuck"
if (Player* player = handler->GetSession()->GetPlayer())
player->CastSpell(player, SPELL_UNSTUCK_ID, false);
return true;
}
if (!*args)
return false;
char* player_str = strtok((char*)args, " ");
if (!player_str)
return false;
std::string location_str = "inn";
if (char const* loc = strtok(nullptr, " "))
location_str = loc;
Player* player = nullptr;
ObjectGuid targetGUID;
if (!handler->extractPlayerTarget(player_str, &player, &targetGUID))
return false;
if (!player)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND);
stmt->setUInt64(0, targetGUID.GetCounter());
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result)
{
Field* fields = result->Fetch();
CharacterDatabaseTransaction dummy;
Player::SavePositionInDB(WorldLocation(fields[0].GetUInt16(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat(), 0.0f), fields[1].GetUInt16(), targetGUID, dummy);
return true;
}
return false;
}
if (player->IsInFlight() || player->IsInCombat())
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_UNSTUCK_ID, DIFFICULTY_NONE);
if (!spellInfo)
return false;
if (Player* caster = handler->GetSession()->GetPlayer())
caster->SendDirectMessage(WorldPackets::Misc::DisplayGameError(GameError::ERR_CLIENT_LOCKED_OUT).Write());
return false;
}
if (location_str == "inn")
{
player->TeleportTo(player->m_homebind);
return true;
}
if (location_str == "graveyard")
{
player->RepopAtGraveyard();
return true;
}
//Not a supported argument
return false;
}
static bool HandleLinkGraveCommand(ChatHandler* handler, uint32 graveyardId, Optional teamArg)
{
uint32 team;
if (!teamArg)
team = 0;
else if (StringEqualI(*teamArg, "horde"))
team = HORDE;
else if (StringEqualI(*teamArg, "alliance"))
team = ALLIANCE;
else
return false;
WorldSafeLocsEntry const* graveyard = sObjectMgr->GetWorldSafeLoc(graveyardId);
if (!graveyard)
{
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST, graveyardId);
handler->SetSentErrorMessage(true);
return false;
}
Player* player = handler->GetSession()->GetPlayer();
uint32 zoneId = player->GetZoneId();
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
if (!areaEntry || areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
{
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId);
handler->SetSentErrorMessage(true);
return false;
}
if (sObjectMgr->AddGraveyardLink(graveyardId, zoneId, team, true))
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, graveyardId, zoneId);
else
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, graveyardId, zoneId);
return true;
}
static bool HandleNearGraveCommand(ChatHandler* handler, Optional teamArg)
{
uint32 team;
if (!teamArg)
team = 0;
else if (StringEqualI(*teamArg, "horde"))
team = HORDE;
else if (StringEqualI(*teamArg, "alliance"))
team = ALLIANCE;
else
return false;
Player* player = handler->GetSession()->GetPlayer();
uint32 zone_id = player->GetZoneId();
WorldSafeLocsEntry const* graveyard = sObjectMgr->GetClosestGraveyard(*player, team, nullptr);
if (graveyard)
{
uint32 graveyardId = graveyard->ID;
GraveyardData const* data = sObjectMgr->FindGraveyardData(graveyardId, zone_id);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR, graveyardId);
handler->SetSentErrorMessage(true);
return false;
}
std::string team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_NOTEAM);
if (team == 0)
team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_ANY);
else if (team == HORDE)
team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE);
else if (team == ALLIANCE)
team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE);
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, graveyardId, team_name.c_str(), zone_id);
}
else
{
std::string team_name;
if (team == HORDE)
team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_HORDE);
else if (team == ALLIANCE)
team_name = handler->GetTrinityString(LANG_COMMAND_GRAVEYARD_ALLIANCE);
if (!team)
handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id);
else
handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id, team_name.c_str());
}
return true;
}
static bool HandleShowAreaCommand(ChatHandler* handler, uint32 areaId)
{
Player* playerTarget = handler->getSelectedPlayer();
if (!playerTarget)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
handler->SetSentErrorMessage(true);
return false;
}
AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
if (!area)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
if (area->AreaBit < 0)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 offset = area->AreaBit / PLAYER_EXPLORED_ZONES_BITS;
uint64 val = UI64LIT(1) << (area->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
playerTarget->AddExploredZones(offset, val);
handler->SendSysMessage(LANG_EXPLORE_AREA);
return true;
}
static bool HandleHideAreaCommand(ChatHandler* handler, uint32 areaId)
{
Player* playerTarget = handler->getSelectedPlayer();
if (!playerTarget)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
handler->SetSentErrorMessage(true);
return false;
}
AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
if (!area)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
if (area->AreaBit < 0)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 offset = area->AreaBit / PLAYER_EXPLORED_ZONES_BITS;
uint64 val = UI64LIT(1) << (area->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
playerTarget->RemoveExploredZones(offset, val);
handler->SendSysMessage(LANG_UNEXPLORE_AREA);
return true;
}
static bool HandleAddItemCommandHelper(ChatHandler* handler, Player* player, Player* playerTarget,
Variant, uint32, std::string_view> const& itemArg, Optional countArg,
Optional const& bonusListIdString, Optional itemContextArg)
{
uint32 itemId = 0;
std::vector bonusListIDs;
ItemContext itemContext = ItemContext::NONE;
if (Hyperlink<::item> const* itemLinkData = std::get_if>(&itemArg))
{
itemId = (*itemLinkData)->Item->GetId();
bonusListIDs = (*itemLinkData)->ItemBonusListIDs;
itemContext = static_cast((*itemLinkData)->Context);
}
else if (uint32 const* itemIdPtr = std::get_if(&itemArg))
itemId = *itemIdPtr;
else if (std::string_view const* itemNameText = std::get_if(&itemArg))
{
std::string itemName(*itemNameText);
if (itemName.starts_with('['))
itemName.erase(0, 1);
if (itemName.ends_with(']'))
itemName.pop_back();
auto itr = std::ranges::find_if(sItemSparseStore, [&itemName](ItemSparseEntry const* sparse)
{
for (LocaleConstant i = LOCALE_enUS; i < TOTAL_LOCALES; i = LocaleConstant(i + 1))
if (itemName == sparse->Display[i])
return true;
return false;
});
if (itr == sItemSparseStore.end())
{
handler->PSendSysMessage(LANG_COMMAND_COULDNOTFIND, itemName.c_str());
handler->SetSentErrorMessage(true);
return false;
}
itemId = itr->ID;
}
int32 count = countArg.value_or(1);
if (count == 0)
count = 1;
// semicolon separated bonuslist ids (parse them after all arguments are extracted by strtok!)
if (bonusListIdString)
for (std::string_view token : Trinity::Tokenize(*bonusListIdString, ';', false))
if (Optional bonusListId = Trinity::StringTo(token); bonusListId && *bonusListId)
bonusListIDs.push_back(*bonusListId);
if (itemContextArg)
{
itemContext = ItemContext(*itemContextArg);
if (itemContext < ItemContext::Max)
{
std::vector contextBonuses = ItemBonusMgr::GetBonusListsForItem(itemId, itemContext);
bonusListIDs.insert(bonusListIDs.begin(), contextBonuses.begin(), contextBonuses.end());
std::ranges::sort(bonusListIDs);
bonusListIDs.erase(std::unique(bonusListIDs.begin(), bonusListIDs.end()), bonusListIDs.end());
}
}
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
if (!itemTemplate)
{
handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId);
handler->SetSentErrorMessage(true);
return false;
}
// Subtract
if (count < 0)
{
uint32 destroyedItemCount = playerTarget->DestroyItemCount(itemId, -count, true, false);
if (destroyedItemCount > 0)
{
// output the amount of items successfully destroyed
handler->PSendSysMessage(LANG_REMOVEITEM, itemId, destroyedItemCount, handler->GetNameLink(playerTarget).c_str());
// check to see if we were unable to destroy all of the amount requested.
uint32 unableToDestroyItemCount = -count - destroyedItemCount;
if (unableToDestroyItemCount > 0)
{
// output message for the amount of items we couldn't destroy
handler->PSendSysMessage(LANG_REMOVEITEM_FAILURE, itemId, unableToDestroyItemCount, handler->GetNameLink(playerTarget).c_str());
}
}
else
{
// failed to destroy items of the amount requested
handler->PSendSysMessage(LANG_REMOVEITEM_FAILURE, itemId, -count, handler->GetNameLink(playerTarget).c_str());
}
return true;
}
// Adding items
uint32 noSpaceForCount = 0;
// check space and find places
ItemPosCountVec dest;
InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount);
if (msg != EQUIP_ERR_OK) // convert to possible store amount
count -= noSpaceForCount;
if (count == 0 || dest.empty()) // can't add any
{
handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount);
handler->SetSentErrorMessage(true);
return false;
}
Item* item = playerTarget->StoreNewItem(dest, itemId, true, GenerateItemRandomBonusListId(itemId), GuidSet(), itemContext,
bonusListIDs.empty() ? nullptr : &bonusListIDs);
// remove binding (let GM give it to another player later)
if (player == playerTarget)
for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr)
if (Item* item1 = player->GetItemByPos(itr->pos))
item1->SetBinding(false);
if (count > 0 && item)
{
player->SendNewItem(item, count, false, true);
handler->PSendSysMessage(LANG_ADDITEM, itemId, count, handler->GetNameLink(playerTarget).c_str());
if (player != playerTarget)
playerTarget->SendNewItem(item, count, true, false);
}
if (noSpaceForCount > 0)
handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount);
return true;
}
static bool HandleAddItemCommand(ChatHandler* handler,
Variant, uint32, std::string_view> const& item, Optional countArg,
Optional const& bonusListIdString, Optional itemContextArg)
{
Player* player = handler->GetSession()->GetPlayer();
Player* playerTarget = handler->getSelectedPlayerOrSelf();
return HandleAddItemCommandHelper(handler, player, playerTarget, item, countArg, bonusListIdString, itemContextArg);
}
static bool HandleAddItemToCommand(ChatHandler* handler, PlayerIdentifier const& target,
Variant, uint32, std::string_view> const& item, Optional countArg,
Optional const& bonusListIdString, Optional itemContextArg)
{
Player* player = handler->GetSession()->GetPlayer();
if (!target.IsConnected())
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
return HandleAddItemCommandHelper(handler, player, target.GetConnectedPlayer(), item, countArg, bonusListIdString, itemContextArg);
}
static bool HandleAddItemSetCommand(ChatHandler* handler, Variant, uint32> itemSetId, Optional bonuses, Optional context)
{
// prevent generation all items with itemset field value '0'
if (*itemSetId == 0)
{
handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, *itemSetId);
handler->SetSentErrorMessage(true);
return false;
}
std::vector bonusListIDs;
// semicolon separated bonuslist ids (parse them after all arguments are extracted by strtok!)
if (bonuses)
for (std::string_view token : Trinity::Tokenize(*bonuses, ';', false))
if (Optional bonusListId = Trinity::StringTo(token); bonusListId && *bonusListId)
bonusListIDs.push_back(*bonusListId);
ItemContext itemContext = ItemContext::NONE;
if (context)
itemContext = ItemContext(*context);
Player* player = handler->GetSession()->GetPlayer();
Player* playerTarget = handler->getSelectedPlayer();
if (!playerTarget)
playerTarget = player;
bool found = false;
ItemTemplateContainer const& its = sObjectMgr->GetItemTemplateStore();
for (auto const& itemTemplatePair : its)
{
if (itemTemplatePair.second.GetItemSet() != *itemSetId)
continue;
found = true;
ItemPosCountVec dest;
InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemTemplatePair.first, 1);
if (msg == EQUIP_ERR_OK)
{
std::vector bonusListIDsForItem = bonusListIDs; // copy, bonuses for each depending on context might be different for each item
if (itemContext < ItemContext::Max)
{
std::vector contextBonuses = ItemBonusMgr::GetBonusListsForItem(itemTemplatePair.first, itemContext);
bonusListIDsForItem.insert(bonusListIDsForItem.begin(), contextBonuses.begin(), contextBonuses.end());
}
Item* item = playerTarget->StoreNewItem(dest, itemTemplatePair.first, true, {}, GuidSet(), itemContext,
bonusListIDsForItem.empty() ? nullptr : &bonusListIDsForItem);
if (!item)
continue;
// remove binding (let GM give it to another player later)
if (player == playerTarget)
item->SetBinding(false);
player->SendNewItem(item, 1, false, true);
if (player != playerTarget)
playerTarget->SendNewItem(item, 1, true, false);
}
else
{
player->SendEquipError(msg, nullptr, nullptr, itemTemplatePair.first);
handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemTemplatePair.first, 1);
}
}
if (!found)
{
handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, *itemSetId);
handler->SetSentErrorMessage(true);
return false;
}
return true;
}
static bool HandleBankCommand(ChatHandler* handler)
{
handler->GetSession()->SendShowBank(handler->GetSession()->GetPlayer()->GetGUID(), PlayerInteractionType::Banker);
return true;
}
static bool HandleChangeWeather(ChatHandler* handler, WeatherType type, float intensity)
{
// Weather is OFF
if (!sWorld->getBoolConfig(CONFIG_WEATHER))
{
handler->SendSysMessage(LANG_WEATHER_DISABLED);
handler->SetSentErrorMessage(true);
return false;
}
Player* player = handler->GetSession()->GetPlayer();
uint32 zoneid = player->GetZoneId();
Weather* weather = player->GetMap()->GetOrGenerateZoneDefaultWeather(zoneid);
if (!weather)
{
handler->SendSysMessage(LANG_NO_WEATHER);
handler->SetSentErrorMessage(true);
return false;
}
weather->SetWeather(type, intensity);
return true;
}
static bool HandleSetSkillCommand(ChatHandler* handler, Variant, uint32> skillId, uint32 level, Optional maxSkillArg)
{
Player* target = handler->getSelectedPlayerOrSelf();
if (!target)
{
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
handler->SetSentErrorMessage(true);
return false;
}
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillId);
if (!skillLine)
{
handler->PSendSysMessage(LANG_INVALID_SKILL_ID, *skillId);
handler->SetSentErrorMessage(true);
return false;
}
bool targetHasSkill = target->GetSkillValue(skillId) != 0;
// If our target does not yet have the skill they are trying to add to them, the chosen level also becomes
// the max level of the new profession.
uint16 max = maxSkillArg.value_or(targetHasSkill ? target->GetPureMaxSkillValue(skillId) : level);
if (level == 0 || level > max)
return false;
// If the player has the skill, we get the current skill step. If they don't have the skill, we
// add the skill to the player's book with step 1 (which is the first rank, in most cases something
// like 'Apprentice '.
target->SetSkill(skillId, targetHasSkill ? target->GetSkillStep(skillId) : 1, level, max);
handler->PSendSysMessage(LANG_SET_SKILL, *skillId, skillLine->DisplayName[handler->GetSessionDbcLocale()], handler->GetNameLink(target).c_str(), level, max);
return true;
}
/**
* @name Player command: .pinfo
* @date 05/19/2013
*
* @brief Prints information about a character and it's linked account to the commander
*
* Non-applying information, e.g. a character that is not in gm mode right now or
* that is not banned/muted, is not printed
*
* This can be done either by giving a name or by targeting someone, else, it'll use the commander
*
* @param args name Prints information according to the given name to the commander
* target Prints information on the target to the commander
* none No given args results in printing information on the commander
*
* @return Several pieces of information about the character and the account
**/
static bool HandlePInfoCommand(ChatHandler* handler, Optional arg)
{
if (!arg)
arg = PlayerIdentifier::FromTargetOrSelf(handler);
if (!arg)
return false;
// Define ALL the player variables!
Player* target = arg->GetConnectedPlayer();
ObjectGuid targetGuid = arg->GetGUID();
std::string targetName = arg->GetName();
CharacterDatabasePreparedStatement* stmt = nullptr;
/* The variables we extract for the command. They are
* default as "does not exist" to prevent problems
* The output is printed in the follow manner:
*
* Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER
* ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM)
* ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned)
* ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted)
* * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT
* * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN
* * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS
* * Registration Email: %s - Email: %s - VIII. LANG_PINFO_ACC_REGMAILS
* * Last IP: %u (Locked: %s) - IX. LANG_PINFO_ACC_IP
* * Level: %u (%u/%u XP (%u XP left) - X. LANG_PINFO_CHR_LEVEL
* * Race: %s %s, Class %s - XI. LANG_PINFO_CHR_RACE
* * Alive ?: %s - XII. LANG_PINFO_CHR_ALIVE
* * Phases: %s - XIII. LANG_PINFO_CHR_PHASE (if not GM)
* * Money: %ug%us%uc - XIV. LANG_PINFO_CHR_MONEY
* * Map: %s, Area: %s - XV. LANG_PINFO_CHR_MAP
* * Guild: %s (Id: %s) - XVI. LANG_PINFO_CHR_GUILD (if in guild)
* ** Rank: %s, ID: %u - XVII. LANG_PINFO_CHR_GUILD_RANK (if in guild)
* ** Note: %s - XVIII.LANG_PINFO_CHR_GUILD_NOTE (if in guild and has note)
* ** O. Note: %s - XVIX. LANG_PINFO_CHR_GUILD_ONOTE (if in guild and has officer note)
* * Played time: %s - XX. LANG_PINFO_CHR_PLAYEDTIME
* * Mails: %u Read/%u Total - XXI. LANG_PINFO_CHR_MAILS (if has mails)
*
* Not all of them can be moved to the top. These should
* place the most important ones to the head, though.
*
* For a cleaner overview, I segment each output in Roman numerals
*/
// Account data print variables
std::string userName = handler->GetTrinityString(LANG_ERROR);
uint32 accId = 0;
ObjectGuid::LowType lowguid = targetGuid.GetCounter();
std::string eMail = handler->GetTrinityString(LANG_ERROR);
std::string regMail = handler->GetTrinityString(LANG_ERROR);
uint32 security = 0;
std::string lastIp = handler->GetTrinityString(LANG_ERROR);
uint8 locked = 0;
std::string lastLogin = handler->GetTrinityString(LANG_ERROR);
uint32 failedLogins = 0;
uint32 latency = 0;
std::string OS = handler->GetTrinityString(LANG_UNKNOWN);
// Mute data print variables
int64 muteTime = -1;
std::string muteReason = handler->GetTrinityString(LANG_NO_REASON);
std::string muteBy = handler->GetTrinityString(LANG_UNKNOWN);
// Ban data print variables
int64 banTime = -1;
std::string banType = handler->GetTrinityString(LANG_UNKNOWN);
std::string banReason = handler->GetTrinityString(LANG_NO_REASON);
std::string bannedBy = handler->GetTrinityString(LANG_UNKNOWN);
// Character data print variables
uint8 raceid, classid = 0; //RACE_NONE, CLASS_NONE
std::string raceStr, classStr = handler->GetTrinityString(LANG_UNKNOWN);
uint8 gender = 0;
LocaleConstant locale = handler->GetSessionDbcLocale();
uint32 totalPlayerTime = 0;
uint8 level = 0;
std::string alive = handler->GetTrinityString(LANG_ERROR);
uint64 money = 0;
uint32 xp = 0;
uint32 xptotal = 0;
// Position data print
uint32 mapId;
uint32 areaId;
char const* areaName = nullptr;
char const* zoneName = nullptr;
// Guild data print variables defined so that they exist, but are not necessarily used
ObjectGuid::LowType guildId = UI64LIT(0);
uint8 guildRankId = 0;
std::string guildName;
std::string guildRank;
std::string note;
std::string officeNote;
// Mail data print is only defined if you have a mail
if (target)
{
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
accId = target->GetSession()->GetAccountId();
money = target->GetMoney();
totalPlayerTime = target->GetTotalPlayedTime();
level = target->GetLevel();
latency = target->GetSession()->GetLatency();
raceid = target->GetRace();
classid = target->GetClass();
muteTime = target->GetSession()->m_muteTime;
mapId = target->GetMapId();
areaId = target->GetAreaId();
alive = target->IsAlive() ? handler->GetTrinityString(LANG_YES) : handler->GetTrinityString(LANG_NO);
gender = target->GetNativeGender();
}
// get additional information from DB
else
{
// check offline security
if (handler->HasLowerSecurity(nullptr, targetGuid))
return false;
// Query informations from the DB
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PINFO);
stmt->setUInt64(0, lowguid);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
return false;
Field* fields = result->Fetch();
totalPlayerTime = fields[0].GetUInt32();
level = fields[1].GetUInt8();
money = fields[2].GetUInt64();
accId = fields[3].GetUInt32();
raceid = fields[4].GetUInt8();
classid = fields[5].GetUInt8();
mapId = fields[6].GetUInt16();
areaId = fields[7].GetUInt16();
gender = fields[8].GetUInt8();
uint32 health = fields[9].GetUInt32();
uint32 playerFlags = fields[10].GetUInt32();
if (!health || playerFlags & PLAYER_FLAGS_GHOST)
alive = handler->GetTrinityString(LANG_NO);
else
alive = handler->GetTrinityString(LANG_YES);
}
// Query the prepared statement for login data
LoginDatabasePreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO);
stmt2->setInt32(0, int32(sRealmList->GetCurrentRealmId().Realm));
stmt2->setUInt32(1, accId);
PreparedQueryResult result = LoginDatabase.Query(stmt2);
if (result)
{
Field* fields = result->Fetch();
userName = fields[0].GetString();
security = fields[1].GetUInt8();
// Only fetch these fields if commander has sufficient rights)
if (handler->HasPermission(rbac::RBAC_PERM_COMMANDS_PINFO_CHECK_PERSONAL_DATA) && // RBAC Perm. 48, Role 39
(!handler->GetSession() || handler->GetSession()->GetSecurity() >= AccountTypes(security)))
{
eMail = fields[2].GetString();
regMail = fields[3].GetString();
lastIp = fields[4].GetString();
lastLogin = fields[5].GetString();
if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(lastIp))
{
lastIp.append(" (");
lastIp.append(location->CountryName);
lastIp.append(")");
}
}
else
{
eMail = handler->GetTrinityString(LANG_UNAUTHORIZED);
regMail = handler->GetTrinityString(LANG_UNAUTHORIZED);
lastIp = handler->GetTrinityString(LANG_UNAUTHORIZED);
lastLogin = handler->GetTrinityString(LANG_UNAUTHORIZED);
}
muteTime = fields[6].GetUInt64();
muteReason = fields[7].GetString();
muteBy = fields[8].GetString();
failedLogins = fields[9].GetUInt32();
locked = fields[10].GetUInt8();
OS = fields[11].GetString();
}
// Creates a chat link to the character. Returns nameLink
std::string nameLink = handler->playerLink(targetName);
// Returns banType, banTime, bannedBy, banreason
stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS);
stmt2->setUInt32(0, accId);
PreparedQueryResult result2 = LoginDatabase.Query(stmt2);
if (!result2)
{
banType = handler->GetTrinityString(LANG_CHARACTER);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_BANS);
stmt->setUInt64(0, lowguid);
result2 = CharacterDatabase.Query(stmt);
}
else
banType = handler->GetTrinityString(LANG_ACCOUNT);
if (result2)
{
Field* fields = result2->Fetch();
bool permanent = fields[1].GetUInt64() != 0;
banTime = !permanent ? int64(fields[0].GetUInt32()) : 0;
bannedBy = fields[2].GetString();
banReason = fields[3].GetString();
}
// Can be used to query data from Characters database
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_XP);
stmt->setUInt64(0, lowguid);
PreparedQueryResult result4 = CharacterDatabase.Query(stmt);
if (result4)
{
Field* fields = result4->Fetch();
xp = fields[0].GetUInt32(); // Used for "current xp" output and "%u XP Left" calculation
ObjectGuid::LowType gguid = fields[1].GetUInt64(); // We check if have a guild for the person, so we might not require to query it at all
xptotal = sObjectMgr->GetXPForLevel(level);
if (gguid)
{
// Guild Data - an own query, because it may not happen.
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED);
stmt->setUInt64(0, lowguid);
PreparedQueryResult result5 = CharacterDatabase.Query(stmt);
if (result5)
{
Field* fields5 = result5->Fetch();
guildId = fields5[0].GetUInt64();
guildName = fields5[1].GetString();
guildRank = fields5[2].GetString();
guildRankId = fields5[3].GetUInt8();
note = fields5[4].GetString();
officeNote = fields5[5].GetString();
}
}
}
// Initiate output
// Output I. LANG_PINFO_PLAYER
handler->PSendSysMessage(LANG_PINFO_PLAYER, target ? "" : handler->GetTrinityString(LANG_OFFLINE), nameLink.c_str(), targetGuid.ToString().c_str());
// Output II. LANG_PINFO_GM_ACTIVE if character is gamemaster
if (target && target->IsGameMaster())
handler->PSendSysMessage(LANG_PINFO_GM_ACTIVE);
// Output III. LANG_PINFO_BANNED if ban exists and is applied
if (banTime >= 0)
handler->PSendSysMessage(LANG_PINFO_BANNED, banType.c_str(), banReason.c_str(), banTime > 0 ? secsToTimeString(banTime - GameTime::GetGameTime(), TimeFormat::ShortText).c_str() : handler->GetTrinityString(LANG_PERMANENTLY), bannedBy.c_str());
// Output IV. LANG_PINFO_MUTED if mute is applied
if (muteTime > 0)
handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - GameTime::GetGameTime(), TimeFormat::ShortText).c_str(), muteBy.c_str());
// Output V. LANG_PINFO_ACC_ACCOUNT
handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security);
// Output VI. LANG_PINFO_ACC_LASTLOGIN
handler->PSendSysMessage(LANG_PINFO_ACC_LASTLOGIN, lastLogin.c_str(), failedLogins);
// Output VII. LANG_PINFO_ACC_OS
handler->PSendSysMessage(LANG_PINFO_ACC_OS, OS.c_str(), latency);
// Output VIII. LANG_PINFO_ACC_REGMAILS
handler->PSendSysMessage(LANG_PINFO_ACC_REGMAILS, regMail.c_str(), eMail.c_str());
// Output IX. LANG_PINFO_ACC_IP
handler->PSendSysMessage(LANG_PINFO_ACC_IP, lastIp.c_str(), locked ? handler->GetTrinityString(LANG_YES) : handler->GetTrinityString(LANG_NO));
// Output X. LANG_PINFO_CHR_LEVEL
if (level != sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
handler->PSendSysMessage(LANG_PINFO_CHR_LEVEL_LOW, level, xp, xptotal, (xptotal - xp));
else
handler->PSendSysMessage(LANG_PINFO_CHR_LEVEL_HIGH, level);
// Output XI. LANG_PINFO_CHR_RACE
raceStr = DB2Manager::GetChrRaceName(raceid, locale);
classStr = DB2Manager::GetChrClassName(classid, locale);
handler->PSendSysMessage(LANG_PINFO_CHR_RACE, (gender == 0 ? handler->GetTrinityString(LANG_CHARACTER_GENDER_MALE) : handler->GetTrinityString(LANG_CHARACTER_GENDER_FEMALE)), raceStr.c_str(), classStr.c_str());
// Output XII. LANG_PINFO_CHR_ALIVE
handler->PSendSysMessage(LANG_PINFO_CHR_ALIVE, alive.c_str());
// Output XIII. phases
if (target)
PhasingHandler::PrintToChat(handler, target);
// Output XIV. LANG_PINFO_CHR_MONEY
uint32 gold = money / GOLD;
uint32 silv = (money % GOLD) / SILVER;
uint32 copp = (money % GOLD) % SILVER;
handler->PSendSysMessage(LANG_PINFO_CHR_MONEY, gold, silv, copp);
// Position data
MapEntry const* map = sMapStore.LookupEntry(mapId);
AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
if (area)
{
zoneName = area->AreaName[locale];
if (area->GetFlags().HasFlag(AreaFlags::IsSubzone))
{
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID);
if (zone)
{
areaName = zoneName;
zoneName = zone->AreaName[locale];
}
}
}
if (!zoneName)
zoneName = handler->GetTrinityString(LANG_UNKNOWN);
if (areaName)
handler->PSendSysMessage(LANG_PINFO_CHR_MAP_WITH_AREA, map->MapName[locale], zoneName, areaName);
else
handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->MapName[locale], zoneName);
// Output XVII. - XVIX. if they are not empty
if (!guildName.empty())
{
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD, guildName.c_str(), std::to_string(guildId).c_str());
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_RANK, guildRank.c_str(), uint32(guildRankId));
if (!note.empty())
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_NOTE, note.c_str());
if (!officeNote.empty())
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_ONOTE, officeNote.c_str());
}
// Output XX. LANG_PINFO_CHR_PLAYEDTIME
handler->PSendSysMessage(LANG_PINFO_CHR_PLAYEDTIME, (secsToTimeString(totalPlayerTime, TimeFormat::ShortText, true)).c_str());
// Mail Data - an own query, because it may or may not be useful.
// SQL: "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?"
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_MAILS);
stmt->setUInt64(0, lowguid);
PreparedQueryResult result6 = CharacterDatabase.Query(stmt);
if (result6)
{
Field* fields = result6->Fetch();
uint32 readmail = uint32(fields[0].GetDouble());
uint32 totalmail = uint32(fields[1].GetUInt64());
// Output XXI. LANG_INFO_CHR_MAILS if at least one mail is given
if (totalmail >= 1)
handler->PSendSysMessage(LANG_PINFO_CHR_MAILS, readmail, totalmail);
}
return true;
}
static bool HandleRespawnCommand(ChatHandler* handler)
{
Player* player = handler->GetSession()->GetPlayer();
// accept only explicitly selected target (not implicitly self targeting case)
Creature* target = !player->GetTarget().IsEmpty() ? handler->getSelectedCreature() : nullptr;
if (target)
{
if (target->IsPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (target->isDead())
target->Respawn();
return true;
}
// First handle any creatures that still have a corpse around
Trinity::RespawnDo u_do;
Trinity::WorldObjectWorker worker(player, u_do);
Cell::VisitGridObjects(player, worker, player->GetGridActivationRange());
// Now handle any that had despawned, but had respawn time logged.
std::vector data;
player->GetMap()->GetRespawnInfo(data, SPAWN_TYPEMASK_ALL);
if (!data.empty())
{
uint32 const gridId = Trinity::ComputeGridCoord(player->GetPositionX(), player->GetPositionY()).GetId();
for (RespawnInfo const* info : data)
if (info->gridId == gridId)
player->GetMap()->Respawn(info->type, info->spawnId);
}
return true;
}
// mute player for the specified duration
static bool HandleMuteCommand(ChatHandler* handler, Optional player, uint32 muteTime, Tail muteReason)
{
std::string muteReasonStr{ muteReason };
if (muteReason.empty())
muteReasonStr = handler->GetTrinityString(LANG_NO_REASON);
if (!player)
player = PlayerIdentifier::FromTarget(handler);
if (!player)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
Player* target = player->GetConnectedPlayer();
uint32 accountId = target ? target->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(*player);
// find only player from same account if any
if (!target)
if (WorldSession* session = sWorld->FindSession(accountId))
target = session->GetPlayer();
// must have strong lesser security level
if (handler->HasLowerSecurity(target, player->GetGUID(), true))
return false;
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME);
std::string muteBy = "";
if (Player* gmPlayer = handler->GetPlayer())
muteBy = gmPlayer->GetName();
else
muteBy = handler->GetTrinityString(LANG_CONSOLE);
if (target)
{
// Target is online, mute will be in effect right away.
int64 mutedUntil = GameTime::GetGameTime() + static_cast(muteTime) * MINUTE;
target->GetSession()->m_muteTime = mutedUntil;
stmt->setInt64(0, mutedUntil);
}
else
{
// Target is offline, mute will be in effect starting from the next login.
stmt->setInt64(0, -static_cast(muteTime) * MINUTE);
}
stmt->setString(1, muteReasonStr);
stmt->setString(2, muteBy);
stmt->setUInt32(3, accountId);
LoginDatabase.Execute(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_MUTE);
stmt->setUInt32(0, accountId);
stmt->setUInt32(1, muteTime);
stmt->setString(2, muteBy);
stmt->setString(3, muteReasonStr);
LoginDatabase.Execute(stmt);
std::string nameLink = handler->playerLink(*player);
if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD))
sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), muteTime, muteReasonStr.c_str());
if (target)
{
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, muteTime, muteBy.c_str(), muteReasonStr.c_str());
handler->PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), muteTime, muteReasonStr.c_str());
}
else
{
handler->PSendSysMessage(LANG_COMMAND_DISABLE_CHAT_DELAYED, nameLink.c_str(), muteTime, muteReasonStr.c_str());
}
return true;
}
// unmute player
static bool HandleUnmuteCommand(ChatHandler* handler, char const* args)
{
Player* target;
ObjectGuid targetGuid;
std::string targetName;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
return false;
uint32 accountId = target ? target->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(targetGuid);
// find only player from same account if any
if (!target)
if (WorldSession* session = sWorld->FindSession(accountId))
target = session->GetPlayer();
// must have strong lesser security level
if (handler->HasLowerSecurity (target, targetGuid, true))
return false;
if (target)
{
if (target->GetSession()->CanSpeak())
{
handler->SendSysMessage(LANG_CHAT_ALREADY_ENABLED);
handler->SetSentErrorMessage(true);
return false;
}
target->GetSession()->m_muteTime = 0;
}
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME);
stmt->setInt64(0, 0);
stmt->setString(1, ""sv);
stmt->setString(2, ""sv);
stmt->setUInt32(3, accountId);
LoginDatabase.Execute(stmt);
if (target)
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
std::string nameLink = handler->playerLink(targetName);
handler->PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str());
return true;
}
// mutehistory command
static bool HandleMuteHistoryCommand(ChatHandler* handler, std::string accountName)
{
if (!Utf8ToUpperOnlyLatin(accountName))
{
handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
handler->SetSentErrorMessage(true);
return false;
}
uint32 accountId = AccountMgr::GetId(accountName);
if (!accountId)
{
handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
return false;
}
return HandleMuteHistoryHelper(accountId, accountName.c_str(), handler);
}
// helper for mutehistory
static bool HandleMuteHistoryHelper(uint32 accountId, char const* accountName, ChatHandler *handler)
{
LoginDatabasePreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO);
stmt->setUInt32(0, accountId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY_EMPTY, accountName);
return true;
}
handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY, accountName);
do
{
Field* fields = result->Fetch();
// we have to manually set the string for mutedate
time_t sqlTime = fields[0].GetUInt32();
tm timeinfo;
char buffer[80];
// set it to string
localtime_r(&sqlTime, &timeinfo);
strftime(buffer, sizeof(buffer),"%Y-%m-%d %I:%M%p", &timeinfo);
handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY_OUTPUT, buffer, fields[1].GetUInt32(), fields[2].GetCString(), fields[3].GetCString());
} while (result->NextRow());
return true;
}
static bool HandleMovegensCommand(ChatHandler* handler)
{
Unit* unit = handler->getSelectedUnit();
if (!unit)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage(LANG_MOVEGENS_LIST, (unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), unit->GetGUID().ToString().c_str());
if (unit->GetMotionMaster()->Empty())
{
handler->SendSysMessage("Empty");
return true;
}
float x, y, z;
unit->GetMotionMaster()->GetDestination(x, y, z);
std::vector const list = unit->GetMotionMaster()->GetMovementGeneratorsInformation();
for (MovementGeneratorInformation const& info : list)
{
switch (info.Type)
{
case IDLE_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_IDLE);
break;
case RANDOM_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_RANDOM);
break;
case WAYPOINT_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_WAYPOINT);
break;
case CONFUSED_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_CONFUSED);
break;
case CHASE_MOTION_TYPE:
if (info.TargetGUID.IsEmpty())
handler->SendSysMessage(LANG_MOVEGENS_CHASE_NULL);
else if (info.TargetGUID.IsPlayer())
handler->PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, info.TargetName.c_str(), info.TargetGUID.ToString().c_str());
else
handler->PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, info.TargetName.c_str(), info.TargetGUID.ToString().c_str());
break;
case FOLLOW_MOTION_TYPE:
if (info.TargetGUID.IsEmpty())
handler->SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL);
else if (info.TargetGUID.IsPlayer())
handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, info.TargetName.c_str(), info.TargetGUID.ToString().c_str());
else
handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, info.TargetName.c_str(), info.TargetGUID.ToString().c_str());
break;
case HOME_MOTION_TYPE:
if (unit->GetTypeId() == TYPEID_UNIT)
handler->PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z);
else
handler->SendSysMessage(LANG_MOVEGENS_HOME_PLAYER);
break;
case FLIGHT_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_FLIGHT);
break;
case POINT_MOTION_TYPE:
handler->PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z);
break;
case FLEEING_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_FEAR);
break;
case DISTRACT_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_DISTRACT);
break;
case EFFECT_MOTION_TYPE:
handler->SendSysMessage(LANG_MOVEGENS_EFFECT);
break;
default:
handler->PSendSysMessage(LANG_MOVEGENS_UNKNOWN, info.Type);
break;
}
}
return true;
}
static bool HandleComeToMeCommand(ChatHandler* handler)
{
Creature* caster = handler->getSelectedCreature();
if (!caster)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
Player* player = handler->GetSession()->GetPlayer();
caster->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
return true;
}
static bool HandleDamageCommand(ChatHandler* handler, uint32 damage, Optional school, Optional spellInfo)
{
Unit* target = handler->getSelectedUnit();
if (!target || !handler->GetSession()->GetPlayer()->GetTarget())
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (Player* player = target->ToPlayer())
if (handler->HasLowerSecurity(player, ObjectGuid::Empty, false))
return false;
if (!target->IsAlive())
return true;
// flat melee damage without resistence/etc reduction
if (!school)
{
Unit::DealDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
if (target != handler->GetSession()->GetPlayer())
handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0, 0);
return true;
}
SpellSchoolMask schoolmask = SpellSchoolMask(1 << *school);
if (Unit::IsDamageReducedByArmor(schoolmask))
damage = Unit::CalcArmorReducedDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, BASE_ATTACK);
Player* attacker = handler->GetSession()->GetPlayer();
// melee damage by specific school
if (!spellInfo)
{
DamageInfo dmgInfo(attacker, target, damage, nullptr, schoolmask, SPELL_DIRECT_DAMAGE, BASE_ATTACK);
Unit::CalcAbsorbResist(dmgInfo);
if (!dmgInfo.GetDamage())
return true;
damage = dmgInfo.GetDamage();
uint32 absorb = dmgInfo.GetAbsorb();
uint32 resist = dmgInfo.GetResist();
Unit::DealDamageMods(attacker, target, damage, &absorb);
Unit::DealDamage(attacker, target, damage, nullptr, DIRECT_DAMAGE, schoolmask, nullptr, false);
attacker->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 0, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0, 0);
return true;
}
// non-melee damage
SpellNonMeleeDamage damageInfo(attacker, target, *spellInfo, { (*spellInfo)->GetSpellXSpellVisualId(handler->GetSession()->GetPlayer()), 0 }, (*spellInfo)->SchoolMask);
damageInfo.damage = damage;
Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb);
target->DealSpellDamage(&damageInfo, true);
target->SendSpellNonMeleeDamageLog(&damageInfo);
return true;
}
static bool HandleDamageGoCommand(ChatHandler* handler, Variant, ObjectGuid::LowType> spawnId, int32 damage)
{
GameObject* go = handler->GetObjectFromPlayerMapByDbGuid(*spawnId);
if (!go)
{
handler->PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, std::to_string(*spawnId).c_str());
handler->SetSentErrorMessage(true);
return false;
}
if (!go->IsDestructibleBuilding())
{
handler->SendSysMessage(LANG_INVALID_GAMEOBJECT_TYPE);
handler->SetSentErrorMessage(true);
return false;
}
go->ModifyHealth(-damage, handler->GetSession()->GetPlayer());
handler->PSendSysMessage(LANG_GAMEOBJECT_DAMAGED, go->GetName().c_str(), std::to_string(*spawnId).c_str(), -damage, go->GetGOValue()->Building.Health);
return true;
}
static bool HandleCombatStopCommand(ChatHandler* handler, char const* args)
{
Player* target = nullptr;
if (args && args[0] != '\0')
{
target = ObjectAccessor::FindPlayerByName(args);
if (!target)
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
}
if (!target)
{
if (!handler->extractPlayerTarget((char*)args, &target))
return false;
}
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
target->CombatStop();
return true;
}
static bool HandleRepairitemsCommand(ChatHandler* handler, char const* args)
{
Player* target;
if (!handler->extractPlayerTarget((char*)args, &target))
return false;
// check online security
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
// Repair items
target->DurabilityRepairAll(false, 0, false);
handler->PSendSysMessage(LANG_YOU_REPAIR_ITEMS, handler->GetNameLink(target).c_str());
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, handler->GetNameLink().c_str());
return true;
}
static bool HandleFreezeCommand(ChatHandler* handler, char const* args)
{
Player* player = handler->getSelectedPlayer(); // Selected player, if any. Might be null.
uint32 freezeDuration = 0; // Freeze Duration (in seconds)
bool canApplyFreeze = false; // Determines if every possible argument is set so Freeze can be applied
bool getDurationFromConfig = false; // If there's no given duration, we'll retrieve the world cfg value later
/*
Possible Freeze Command Scenarios:
case 1 - .freeze (without args and a selected player)
case 2 - .freeze duration (with a selected player)
case 3 - .freeze player duration
case 4 - .freeze player (without specifying duration)
*/
// case 1: .freeze
if (!*args)
{
// Might have a selected player. We'll check it later
// Get the duration from world cfg
getDurationFromConfig = true;
}
else
{
// Get the args that we might have (up to 2)
char const* arg1 = strtok((char*)args, " ");
char const* arg2 = strtok(nullptr, " ");
// Analyze them to see if we got either a playerName or duration or both
if (arg1)
{
if (isNumeric(arg1))
{
// case 2: .freeze duration
// We have a selected player. We'll check him later
freezeDuration = uint32(atoi(arg1));
canApplyFreeze = true;
}
else
{
// case 3 or 4: .freeze player duration | .freeze player
// find the player
std::string name = arg1;
normalizePlayerName(name);
player = ObjectAccessor::FindPlayerByName(name);
// Check if we have duration set
if (arg2 && isNumeric(arg2))
{
freezeDuration = uint32(atoi(arg2));
canApplyFreeze = true;
}
else
getDurationFromConfig = true;
}
}
}
// Check if duration needs to be retrieved from config
if (getDurationFromConfig)
{
freezeDuration = sWorld->getIntConfig(CONFIG_GM_FREEZE_DURATION);
canApplyFreeze = true;
}
// Player and duration retrieval is over
if (canApplyFreeze)
{
if (!player) // can be null if some previous selection failed
{
handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
return true;
}
else if (player == handler->GetSession()->GetPlayer())
{
// Can't freeze himself
handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR);
return true;
}
else // Apply the effect
{
// Add the freeze aura and set the proper duration
// Player combat status and flags are now handled
// in Freeze Spell AuraScript (OnApply)
Aura* freeze = player->AddAura(9454, player);
if (freeze)
{
if (freezeDuration)
freeze->SetDuration(freezeDuration * IN_MILLISECONDS);
handler->PSendSysMessage(LANG_COMMAND_FREEZE, player->GetName().c_str());
// save player
player->SaveToDB();
return true;
}
}
}
return false;
}
static bool HandleUnFreezeCommand(ChatHandler* handler, Optional targetNameArg)
{
std::string name;
Player* player;
if (targetNameArg)
{
name = *targetNameArg;
normalizePlayerName(name);
player = ObjectAccessor::FindPlayerByName(name);
}
else // If no name was entered - use target
{
player = handler->getSelectedPlayer();
if (player)
name = player->GetName();
}
if (player)
{
handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str());
// Remove Freeze spell (allowing movement and spells)
// Player Flags + Neutral faction removal is now
// handled on the Freeze Spell AuraScript (OnRemove)
player->RemoveAurasDueToSpell(9454);
}
else
{
if (targetNameArg)
{
// Check for offline players
ObjectGuid guid = sCharacterCache->GetCharacterGuidByName(name);
if (guid.IsEmpty())
{
handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
return true;
}
// If player found: delete his freeze aura
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN);
stmt->setUInt64(0, guid.GetCounter());
CharacterDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str());
return true;
}
else
{
handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
return true;
}
}
return true;
}
static bool HandleListFreezeCommand(ChatHandler* handler)
{
// Get names from DB
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURA_FROZEN);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
{
handler->SendSysMessage(LANG_COMMAND_NO_FROZEN_PLAYERS);
return true;
}
// Header of the names
handler->PSendSysMessage(LANG_COMMAND_LIST_FREEZE);
// Output of the results
do
{
Field* fields = result->Fetch();
std::string player = fields[0].GetString();
int32 remaintime = fields[1].GetInt32();
// Save the frozen player to update remaining time in case of future .listfreeze uses
// before the frozen state expires
if (Player* frozen = ObjectAccessor::FindPlayerByName(player))
frozen->SaveToDB();
// Notify the freeze duration
if (remaintime == -1) // Permanent duration
handler->PSendSysMessage(LANG_COMMAND_PERMA_FROZEN_PLAYER, player.c_str());
else
// show time left (seconds)
handler->PSendSysMessage(LANG_COMMAND_TEMP_FROZEN_PLAYER, player.c_str(), remaintime / IN_MILLISECONDS);
}
while (result->NextRow());
return true;
}
static bool HandlePlayAllCommand(ChatHandler* handler, uint32 soundId, Optional broadcastTextId)
{
if (!sSoundKitStore.LookupEntry(soundId))
{
handler->PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId);
handler->SetSentErrorMessage(true);
return false;
}
sWorld->SendGlobalMessage(WorldPackets::Misc::PlaySound(handler->GetSession()->GetPlayer()->GetGUID(), soundId, broadcastTextId.value_or(0)).Write());
handler->PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId);
return true;
}
static bool HandlePossessCommand(ChatHandler* handler)
{
Unit* unit = handler->getSelectedUnit();
if (!unit)
return false;
handler->GetSession()->GetPlayer()->CastSpell(unit, 530, true);
return true;
}
static bool HandleUnPossessCommand(ChatHandler* handler)
{
Unit* unit = handler->getSelectedUnit();
if (!unit)
unit = handler->GetSession()->GetPlayer();
unit->RemoveCharmAuras();
return true;
}
static bool HandleBindSightCommand(ChatHandler* handler)
{
Unit* unit = handler->getSelectedUnit();
if (!unit)
return false;
handler->GetSession()->GetPlayer()->CastSpell(unit, 6277, true);
return true;
}
static bool HandleUnbindSightCommand(ChatHandler* handler)
{
Player* player = handler->GetSession()->GetPlayer();
if (player->isPossessing())
return false;
player->StopCastingBindSight();
return true;
}
static bool HandleMailBoxCommand(ChatHandler* handler)
{
Player* player = handler->GetSession()->GetPlayer();
handler->GetSession()->SendShowMailBox(player->GetGUID());
return true;
}
};
void AddSC_misc_commandscript()
{
new misc_commandscript();
}