
* Update timestamp format * shutdown / restart notifications * other time formats core side * Remove Whitespace
1202 lines
31 KiB
C++
1202 lines
31 KiB
C++
/**
|
|
* MaNGOS is a full featured server for World of Warcraft, supporting
|
|
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
|
*
|
|
* Copyright (C) 2005-2021 MaNGOS <https://getmangos.eu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
|
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
|
*/
|
|
|
|
#include "Chat.h"
|
|
#include "Language.h"
|
|
#include "World.h"
|
|
#include "GridNotifiersImpl.h"
|
|
#include "CellImpl.h"
|
|
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
|
#include "TemporarySummon.h"
|
|
#include "WaypointManager.h"
|
|
#include "PathFinder.h" // for mmap commands
|
|
#include "Totem.h"
|
|
|
|
#ifdef _DEBUG_VMAPS
|
|
#include "VMapFactory.h"
|
|
#endif
|
|
|
|
/**********************************************************************
|
|
CommandTable : commandTable
|
|
/***********************************************************************/
|
|
|
|
/*
|
|
ComeToMe command REQUIRED for 3rd party scripting library to have access to PointMovementGenerator
|
|
Without this function 3rd party scripting library will get linking errors (unresolved external)
|
|
when attempting to use the PointMovementGenerator
|
|
*/
|
|
bool ChatHandler::HandleComeToMeCommand(char* /*args*/)
|
|
{
|
|
Creature* caster = getSelectedCreature();
|
|
|
|
if (!caster)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Player* pl = m_session->GetPlayer();
|
|
|
|
caster->GetMotionMaster()->MovePoint(0, pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ());
|
|
return true;
|
|
}
|
|
|
|
bool ChatHandler::HandleRespawnCommand(char* /*args*/)
|
|
{
|
|
Player* pl = m_session->GetPlayer();
|
|
|
|
// accept only explicitly selected target (not implicitly self targeting case)
|
|
Unit* target = getSelectedUnit();
|
|
if (pl->GetSelectionGuid() && target)
|
|
{
|
|
if (target->GetTypeId() != TYPEID_UNIT)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (target->IsDead())
|
|
{
|
|
((Creature*)target)->Respawn();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MaNGOS::RespawnDo u_do;
|
|
MaNGOS::WorldObjectWorker<MaNGOS::RespawnDo> worker(u_do);
|
|
Cell::VisitGridObjects(pl, worker, pl->GetMap()->GetVisibilityDistance());
|
|
return true;
|
|
}
|
|
|
|
// Edit Creature Faction
|
|
bool ChatHandler::HandleModifyFactionCommand(char* args)
|
|
{
|
|
Creature* chr = getSelectedCreature();
|
|
if (!chr)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (!*args)
|
|
{
|
|
if (chr)
|
|
{
|
|
uint32 factionid = chr->getFaction();
|
|
uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS);
|
|
uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS);
|
|
uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS);
|
|
PSendSysMessage(LANG_CURRENT_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (!chr)
|
|
{
|
|
SendSysMessage(LANG_NO_CHAR_SELECTED);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 factionid;
|
|
if (!ExtractUint32KeyFromLink(&args, "Hfaction", factionid))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!sFactionTemplateStore.LookupEntry(factionid))
|
|
{
|
|
PSendSysMessage(LANG_WRONG_FACTION, factionid);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 flag;
|
|
if (!ExtractOptUInt32(&args, flag, chr->GetUInt32Value(UNIT_FIELD_FLAGS)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 npcflag;
|
|
if (!ExtractOptUInt32(&args, npcflag, chr->GetUInt32Value(UNIT_NPC_FLAGS)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 dyflag;
|
|
if (!ExtractOptUInt32(&args, dyflag, chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag);
|
|
|
|
chr->setFaction(factionid);
|
|
chr->SetUInt32Value(UNIT_FIELD_FLAGS, flag);
|
|
chr->SetUInt32Value(UNIT_NPC_FLAGS, npcflag);
|
|
chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS, dyflag);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------Npc Commands-----------------------
|
|
// add spawn of creature
|
|
bool ChatHandler::HandleNpcAddCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 id;
|
|
if (!ExtractUint32KeyFromLink(&args, "Hcreature_entry", id))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(id);
|
|
if (!cinfo)
|
|
{
|
|
PSendSysMessage(LANG_COMMAND_INVALIDCREATUREID, id);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Player* chr = m_session->GetPlayer();
|
|
CreatureCreatePos pos(chr, chr->GetOrientation());
|
|
Map* map = chr->GetMap();
|
|
|
|
Creature* pCreature = new Creature;
|
|
|
|
// used guids from specially reserved range (can be 0 if no free values)
|
|
uint32 lowguid = sObjectMgr.GenerateStaticCreatureLowGuid();
|
|
if (!lowguid)
|
|
{
|
|
SendSysMessage(LANG_NO_FREE_STATIC_GUID_FOR_SPAWN);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (!pCreature->Create(lowguid, pos, cinfo))
|
|
{
|
|
delete pCreature;
|
|
return false;
|
|
}
|
|
|
|
pCreature->SaveToDB(map->GetId());
|
|
|
|
uint32 db_guid = pCreature->GetGUIDLow();
|
|
|
|
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
|
|
pCreature->LoadFromDB(db_guid, map);
|
|
|
|
return true;
|
|
}
|
|
|
|
// add item in vendorlist
|
|
bool ChatHandler::HandleNpcAddVendorItemCommand(char* args)
|
|
{
|
|
uint32 itemId;
|
|
if (!ExtractUint32KeyFromLink(&args, "Hitem", itemId))
|
|
{
|
|
SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 maxcount;
|
|
if (!ExtractOptUInt32(&args, maxcount, 0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 incrtime;
|
|
if (!ExtractOptUInt32(&args, incrtime, 0))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Creature* vendor = getSelectedCreature();
|
|
|
|
uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
|
|
|
|
if (!sObjectMgr.IsVendorItemValid(false, "npc_vendor", vendor_entry, itemId, maxcount, incrtime, 0, m_session->GetPlayer()))
|
|
{
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
sObjectMgr.AddVendorItem(vendor_entry, itemId, maxcount, incrtime);
|
|
|
|
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId);
|
|
|
|
PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, pProto->Name1, maxcount, incrtime);
|
|
return true;
|
|
}
|
|
|
|
// del item from vendor list
|
|
bool ChatHandler::HandleNpcDelVendorItemCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Creature* vendor = getSelectedCreature();
|
|
if (!vendor || !vendor->IsVendor())
|
|
{
|
|
SendSysMessage(LANG_COMMAND_VENDORSELECTION);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 itemId;
|
|
if (!ExtractUint32KeyFromLink(&args, "Hitem", itemId))
|
|
{
|
|
SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (!sObjectMgr.RemoveVendorItem(vendor->GetEntry(), itemId))
|
|
{
|
|
PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId);
|
|
|
|
PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, pProto->Name1);
|
|
return true;
|
|
}
|
|
|
|
// show info about AI
|
|
bool ChatHandler::HandleNpcAIInfoCommand(char* /*args*/)
|
|
{
|
|
Creature* pTarget = getSelectedCreature();
|
|
|
|
if (!pTarget)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
PSendSysMessage(LANG_NPC_AI_HEADER, pTarget->GetEntry());
|
|
|
|
std::string strScript = pTarget->GetScriptName();
|
|
std::string strAI = pTarget->GetAIName();
|
|
char const* cstrAIClass = pTarget->AI() ? typeid(*pTarget->AI()).name() : " - ";
|
|
|
|
PSendSysMessage(LANG_NPC_AI_NAMES,
|
|
strAI.empty() ? " - " : strAI.c_str(),
|
|
cstrAIClass ? cstrAIClass : " - ",
|
|
strScript.empty() ? " - " : strScript.c_str());
|
|
PSendSysMessage("Motion Type: %u", pTarget->GetMotionMaster()->GetCurrentMovementGeneratorType());
|
|
PSendSysMessage("Casting Spell: %s", pTarget->IsNonMeleeSpellCasted(true) ? "yes" : "no");
|
|
|
|
if (pTarget->AI())
|
|
{
|
|
pTarget->AI()->GetAIInformation(*this);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// change level of creature or pet
|
|
bool ChatHandler::HandleNpcChangeLevelCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint8 lvl = (uint8)atoi(args);
|
|
if (lvl < 1 || lvl > sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL) + 3)
|
|
{
|
|
SendSysMessage(LANG_BAD_VALUE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
if (!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (pCreature->IsPet())
|
|
{
|
|
((Pet*)pCreature)->GivePetLevel(lvl);
|
|
}
|
|
else
|
|
{
|
|
pCreature->SetMaxHealth(100 + 30 * lvl);
|
|
pCreature->SetHealth(100 + 30 * lvl);
|
|
pCreature->SetLevel(lvl);
|
|
|
|
if (pCreature->HasStaticDBSpawnData())
|
|
{
|
|
pCreature->SaveToDB();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// set npcflag of creature
|
|
bool ChatHandler::HandleNpcFlagCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 npcFlags = (uint32)atoi(args);
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
|
|
if (!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
|
|
|
|
WorldDatabase.PExecuteLog("UPDATE `creature_template` SET `NpcFlags` = '%u' WHERE `entry` = '%u'", npcFlags, pCreature->GetEntry());
|
|
|
|
SendSysMessage(LANG_VALUE_SAVED_REJOIN);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ChatHandler::HandleNpcDeleteCommand(char* args)
|
|
{
|
|
Creature* unit = NULL;
|
|
|
|
if (*args)
|
|
{
|
|
// number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
|
|
uint32 lowguid;
|
|
if (!ExtractUint32KeyFromLink(&args, "Hcreature", lowguid))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!lowguid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (CreatureData const* data = sObjectMgr.GetCreatureData(lowguid))
|
|
{
|
|
unit = m_session->GetPlayer()->GetMap()->GetCreature(data->GetObjectGuid(lowguid));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unit = getSelectedCreature();
|
|
}
|
|
|
|
if (!unit)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
switch (unit->GetSubtype())
|
|
{
|
|
case CREATURE_SUBTYPE_GENERIC:
|
|
{
|
|
unit->CombatStop();
|
|
if (CreatureData const* data = sObjectMgr.GetCreatureData(unit->GetGUIDLow()))
|
|
{
|
|
Creature::AddToRemoveListInMaps(unit->GetGUIDLow(), data);
|
|
Creature::DeleteFromDB(unit->GetGUIDLow(), data);
|
|
}
|
|
else
|
|
{
|
|
unit->AddObjectToRemoveList();
|
|
}
|
|
break;
|
|
}
|
|
case CREATURE_SUBTYPE_PET:
|
|
((Pet*)unit)->Unsummon(PET_SAVE_AS_CURRENT);
|
|
break;
|
|
case CREATURE_SUBTYPE_TOTEM:
|
|
((Totem*)unit)->UnSummon();
|
|
break;
|
|
case CREATURE_SUBTYPE_TEMPORARY_SUMMON:
|
|
((TemporarySummon*)unit)->UnSummon();
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
|
|
|
|
return true;
|
|
}
|
|
|
|
// move selected creature
|
|
bool ChatHandler::HandleNpcMoveCommand(char* args)
|
|
{
|
|
uint32 lowguid = 0;
|
|
Player* player = m_session->GetPlayer();
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
if (!pCreature)
|
|
{
|
|
// number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
|
|
if (!ExtractUint32KeyFromLink(&args, "Hcreature", lowguid))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CreatureData const* data = sObjectMgr.GetCreatureData(lowguid);
|
|
if (!data)
|
|
{
|
|
PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (player->GetMapId() != data->mapid)
|
|
{
|
|
PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
pCreature = player->GetMap()->GetCreature(data->GetObjectGuid(lowguid));
|
|
}
|
|
else
|
|
{
|
|
lowguid = pCreature->GetGUIDLow();
|
|
}
|
|
|
|
float x = player->GetPositionX();
|
|
float y = player->GetPositionY();
|
|
float z = player->GetPositionZ();
|
|
float o = player->GetOrientation();
|
|
|
|
if (pCreature)
|
|
{
|
|
if (CreatureData const* data = sObjectMgr.GetCreatureData(pCreature->GetGUIDLow()))
|
|
{
|
|
const_cast<CreatureData*>(data)->posX = x;
|
|
const_cast<CreatureData*>(data)->posY = y;
|
|
const_cast<CreatureData*>(data)->posZ = z;
|
|
const_cast<CreatureData*>(data)->orientation = o;
|
|
}
|
|
pCreature->GetMap()->CreatureRelocation(pCreature, x, y, z, o);
|
|
pCreature->GetMotionMaster()->Initialize();
|
|
if (pCreature->IsAlive()) // dead creature will reset movement generator at respawn
|
|
{
|
|
pCreature->SetDeathState(JUST_DIED);
|
|
pCreature->Respawn();
|
|
}
|
|
}
|
|
|
|
WorldDatabase.PExecuteLog("UPDATE `creature` SET `position_x` = '%f', `position_y` = '%f', `position_z` = '%f', `orientation` = '%f' WHERE `guid` = '%u'", x, y, z, o, lowguid);
|
|
PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
|
|
return true;
|
|
}
|
|
|
|
/**HandleNpcSetMoveTypeCommand
|
|
* Set the movement type for an NPC.<br/>
|
|
* <br/>
|
|
* Valid movement types are:
|
|
* <ul>
|
|
* <li> stay - NPC wont move </li>
|
|
* <li> random - NPC will move randomly according to the spawndist </li>
|
|
* <li> way - NPC will move with given waypoints set </li>
|
|
* </ul>
|
|
* additional parameter: NODEL - so no waypoints are deleted, if you
|
|
* change the movement type
|
|
*/
|
|
bool ChatHandler::HandleNpcSetMoveTypeCommand(char* args)
|
|
{
|
|
// 3 arguments:
|
|
// GUID (optional - you can also select the creature)
|
|
// stay|random|way (determines the kind of movement)
|
|
// NODEL (optional - tells the system NOT to delete any waypoints)
|
|
// this is very handy if you want to do waypoints, that are
|
|
// later switched on/off according to special events (like escort
|
|
// quests, etc)
|
|
|
|
uint32 lowguid;
|
|
Creature* pCreature;
|
|
if (!ExtractUInt32(&args, lowguid)) // case .setmovetype $move_type (with selected creature)
|
|
{
|
|
pCreature = getSelectedCreature();
|
|
if (!pCreature || !pCreature->HasStaticDBSpawnData())
|
|
{
|
|
return false;
|
|
}
|
|
lowguid = pCreature->GetGUIDLow();
|
|
}
|
|
else // case .setmovetype #creature_guid $move_type (with guid)
|
|
{
|
|
CreatureData const* data = sObjectMgr.GetCreatureData(lowguid);
|
|
if (!data)
|
|
{
|
|
PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Player* player = m_session->GetPlayer();
|
|
|
|
if (player->GetMapId() != data->mapid)
|
|
{
|
|
PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
pCreature = player->GetMap()->GetCreature(data->GetObjectGuid(lowguid));
|
|
}
|
|
|
|
MovementGeneratorType move_type;
|
|
char* type_str = ExtractLiteralArg(&args);
|
|
if (!type_str)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (strncmp(type_str, "stay", strlen(type_str)) == 0)
|
|
{
|
|
move_type = IDLE_MOTION_TYPE;
|
|
}
|
|
else if (strncmp(type_str, "random", strlen(type_str)) == 0)
|
|
{
|
|
move_type = RANDOM_MOTION_TYPE;
|
|
}
|
|
else if (strncmp(type_str, "way", strlen(type_str)) == 0)
|
|
{
|
|
move_type = WAYPOINT_MOTION_TYPE;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool doNotDelete = ExtractLiteralArg(&args, "NODEL") != NULL;
|
|
if (!doNotDelete && *args) // need fail if false in result wrong literal
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// now lowguid is low guid really existing creature
|
|
// and pCreature point (maybe) to this creature or NULL
|
|
|
|
// update movement type
|
|
if (!doNotDelete)
|
|
{
|
|
sWaypointMgr.DeletePath(lowguid);
|
|
}
|
|
|
|
if (pCreature)
|
|
{
|
|
pCreature->SetDefaultMovementType(move_type);
|
|
pCreature->GetMotionMaster()->Initialize();
|
|
if (pCreature->IsAlive()) // dead creature will reset movement generator at respawn
|
|
{
|
|
pCreature->SetDeathState(JUST_DIED);
|
|
pCreature->Respawn();
|
|
}
|
|
pCreature->SaveToDB();
|
|
}
|
|
|
|
if (doNotDelete)
|
|
{
|
|
PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, type_str);
|
|
}
|
|
else
|
|
{
|
|
PSendSysMessage(LANG_MOVE_TYPE_SET, type_str);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// set model of creature
|
|
bool ChatHandler::HandleNpcSetModelCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 displayId = (uint32)atoi(args);
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
|
|
if (!pCreature || pCreature->IsPet())
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (!sCreatureDisplayInfoStore.LookupEntry(displayId))
|
|
{
|
|
SendSysMessage(LANG_BAD_VALUE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
pCreature->SetDisplayId(displayId);
|
|
pCreature->SetNativeDisplayId(displayId);
|
|
|
|
if (pCreature->HasStaticDBSpawnData())
|
|
{
|
|
pCreature->SaveToDB();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// set faction of creature
|
|
bool ChatHandler::HandleNpcFactionIdCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 factionId = (uint32)atoi(args);
|
|
|
|
if (!sFactionTemplateStore.LookupEntry(factionId))
|
|
{
|
|
PSendSysMessage(LANG_WRONG_FACTION, factionId);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
|
|
if (!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
pCreature->setFaction(factionId);
|
|
|
|
// faction is set in creature_template - not inside creature
|
|
|
|
// update in memory
|
|
if (CreatureInfo const* cinfo = pCreature->GetCreatureInfo())
|
|
{
|
|
const_cast<CreatureInfo*>(cinfo)->FactionAlliance = factionId;
|
|
const_cast<CreatureInfo*>(cinfo)->FactionHorde = factionId;
|
|
}
|
|
|
|
// and DB
|
|
WorldDatabase.PExecuteLog("UPDATE `creature_template` SET `FactionAlliance` = '%u', `FactionHorde` = '%u' WHERE `entry` = '%u'", factionId, factionId, pCreature->GetEntry());
|
|
|
|
return true;
|
|
}
|
|
|
|
// set spawn dist of creature
|
|
bool ChatHandler::HandleNpcSpawnDistCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float option = (float)atof(args);
|
|
if (option < 0.0f)
|
|
{
|
|
SendSysMessage(LANG_BAD_VALUE);
|
|
return false;
|
|
}
|
|
|
|
MovementGeneratorType mtype = IDLE_MOTION_TYPE;
|
|
if (option > 0.0f)
|
|
{
|
|
mtype = RANDOM_MOTION_TYPE;
|
|
}
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
|
|
if (!pCreature)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pCreature->SetRespawnRadius((float)option);
|
|
pCreature->SetDefaultMovementType(mtype);
|
|
pCreature->GetMotionMaster()->Initialize();
|
|
if (pCreature->IsAlive()) // dead creature will reset movement generator at respawn
|
|
{
|
|
pCreature->SetDeathState(JUST_DIED);
|
|
pCreature->Respawn();
|
|
}
|
|
|
|
WorldDatabase.PExecuteLog("UPDATE `creature` SET `spawndist`=%f, `MovementType`=%i WHERE `guid`=%u", option, mtype, pCreature->GetGUIDLow());
|
|
PSendSysMessage(LANG_COMMAND_SPAWNDIST, option);
|
|
return true;
|
|
}
|
|
// spawn time handling
|
|
bool ChatHandler::HandleNpcSpawnTimeCommand(char* args)
|
|
{
|
|
uint32 stime;
|
|
if (!ExtractUInt32(&args, stime))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
if (!pCreature)
|
|
{
|
|
PSendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 u_guidlow = pCreature->GetGUIDLow();
|
|
|
|
WorldDatabase.PExecuteLog("UPDATE `creature` SET `spawntimesecs`=%i WHERE `guid`=%u", stime, u_guidlow);
|
|
pCreature->SetRespawnDelay(stime);
|
|
PSendSysMessage(LANG_COMMAND_SPAWNTIME, stime);
|
|
|
|
return true;
|
|
}
|
|
// npc follow handling
|
|
bool ChatHandler::HandleNpcFollowCommand(char* /*args*/)
|
|
{
|
|
Player* player = m_session->GetPlayer();
|
|
Creature* creature = getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
PSendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
// Follow player - Using pet's default dist and angle
|
|
creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
|
|
|
PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
|
|
return true;
|
|
}
|
|
// npc unfollow handling
|
|
bool ChatHandler::HandleNpcUnFollowCommand(char* /*args*/)
|
|
{
|
|
Player* player = m_session->GetPlayer();
|
|
Creature* creature = getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
PSendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
MotionMaster* creatureMotion = creature->GetMotionMaster();
|
|
if (creatureMotion->empty() ||
|
|
creatureMotion->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE)
|
|
{
|
|
PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>(creatureMotion->top());
|
|
|
|
if (mgen->GetTarget() != player)
|
|
{
|
|
PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
// reset movement
|
|
creatureMotion->MovementExpired(true);
|
|
|
|
PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
|
|
return true;
|
|
}
|
|
// npc tame handling
|
|
bool ChatHandler::HandleNpcTameCommand(char* /*args*/)
|
|
{
|
|
Creature* creatureTarget = getSelectedCreature();
|
|
|
|
if (!creatureTarget || creatureTarget->IsPet())
|
|
{
|
|
PSendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Player* player = m_session->GetPlayer();
|
|
|
|
if (player->GetPetGuid())
|
|
{
|
|
SendSysMessage(LANG_YOU_ALREADY_HAVE_PET);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
player->CastSpell(creatureTarget, 13481, true); // Tame Beast, triggered effect
|
|
return true;
|
|
}
|
|
|
|
// npc deathstate handling
|
|
bool ChatHandler::HandleNpcSetDeathStateCommand(char* args)
|
|
{
|
|
bool value;
|
|
if (!ExtractOnOff(&args, value))
|
|
{
|
|
SendSysMessage(LANG_USE_BOL);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
Creature* pCreature = getSelectedCreature();
|
|
if (!pCreature || !pCreature->HasStaticDBSpawnData())
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
if (value)
|
|
{
|
|
pCreature->SetDeadByDefault(true);
|
|
}
|
|
else
|
|
{
|
|
pCreature->SetDeadByDefault(false);
|
|
}
|
|
|
|
pCreature->SaveToDB();
|
|
pCreature->Respawn();
|
|
|
|
return true;
|
|
}
|
|
|
|
// TODO: NpcCommands that need to be fixed :
|
|
|
|
bool ChatHandler::HandleNpcNameCommand(char* /*args*/)
|
|
{
|
|
/* Temp. disabled
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (strlen((char*)args)>75)
|
|
{
|
|
PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
|
|
return true;
|
|
}
|
|
|
|
for (uint8 i = 0; i < strlen(args); ++i)
|
|
{
|
|
if (!isalpha(args[i]) && args[i]!=' ')
|
|
{
|
|
SendSysMessage(LANG_CHARS_ONLY);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid();
|
|
if (guid.IsEmpty())
|
|
{
|
|
SendSysMessage(LANG_NO_SELECTION);
|
|
return true;
|
|
}
|
|
|
|
Creature* pCreature = sObjectAccessor.GetCreature(*m_session->GetPlayer(), guid);
|
|
|
|
if (!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
return true;
|
|
}
|
|
|
|
pCreature->SetName(args);
|
|
uint32 idname = sObjectMgr.AddCreatureTemplate(pCreature->GetName());
|
|
pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
|
|
|
|
pCreature->SaveToDB();
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ChatHandler::HandleNpcSubNameCommand(char* /*args*/)
|
|
{
|
|
/* Temp. disabled
|
|
|
|
if (!*args)
|
|
{
|
|
args = "";
|
|
}
|
|
|
|
if (strlen((char*)args)>75)
|
|
{
|
|
PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
|
|
return true;
|
|
}
|
|
|
|
for (uint8 i = 0; i < strlen(args); ++i)
|
|
{
|
|
if (!isalpha(args[i]) && args[i]!=' ')
|
|
{
|
|
SendSysMessage(LANG_CHARS_ONLY);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid();
|
|
if (guid.IsEmpty())
|
|
{
|
|
SendSysMessage(LANG_NO_SELECTION);
|
|
return true;
|
|
}
|
|
|
|
Creature* pCreature = sObjectAccessor.GetCreature(*m_session->GetPlayer(), guid);
|
|
|
|
if (!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
return true;
|
|
}
|
|
|
|
uint32 idname = sObjectMgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
|
|
pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
|
|
|
|
pCreature->SaveToDB();
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
//-----------------------Npc Commands-----------------------
|
|
bool ChatHandler::HandleNpcAllowMovementCommand(char* /*args*/)
|
|
{
|
|
if (sWorld.getAllowMovement())
|
|
{
|
|
sWorld.SetAllowMovement(false);
|
|
SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
|
|
}
|
|
else
|
|
{
|
|
sWorld.SetAllowMovement(true);
|
|
SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ChatHandler::HandleNpcChangeEntryCommand(char* args)
|
|
{
|
|
if (!*args)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 newEntryNum = atoi(args);
|
|
if (!newEntryNum)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Unit* unit = getSelectedUnit();
|
|
if (!unit || unit->GetTypeId() != TYPEID_UNIT)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
Creature* creature = (Creature*)unit;
|
|
if (creature->UpdateEntry(newEntryNum))
|
|
{
|
|
SendSysMessage(LANG_DONE);
|
|
}
|
|
else
|
|
{
|
|
SendSysMessage(LANG_ERROR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
|
|
{
|
|
Creature* target = getSelectedCreature();
|
|
|
|
if (!target)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
uint32 faction = target->getFaction();
|
|
uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS);
|
|
uint32 displayid = target->GetDisplayId();
|
|
uint32 nativeid = target->GetNativeDisplayId();
|
|
uint32 Entry = target->GetEntry();
|
|
CreatureInfo const* cInfo = target->GetCreatureInfo();
|
|
|
|
time_t curRespawnDelay = target->GetRespawnTimeEx() - time(NULL);
|
|
if (curRespawnDelay < 0)
|
|
{
|
|
curRespawnDelay = 0;
|
|
}
|
|
std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay, TimeFormat::ShortText);
|
|
std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(), TimeFormat::ShortText);
|
|
|
|
PSendSysMessage(LANG_NPCINFO_CHAR, target->GetGuidStr().c_str(), faction, npcflags, Entry, displayid, nativeid);
|
|
PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
|
|
PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
|
|
PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction());
|
|
PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str());
|
|
PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->LootId, cInfo->PickpocketLootId, cInfo->SkinningLootId);
|
|
PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
|
|
PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ()));
|
|
|
|
if ((npcflags & UNIT_NPC_FLAG_VENDOR))
|
|
{
|
|
SendSysMessage(LANG_NPCINFO_VENDOR);
|
|
}
|
|
if ((npcflags & UNIT_NPC_FLAG_TRAINER))
|
|
{
|
|
SendSysMessage(LANG_NPCINFO_TRAINER);
|
|
}
|
|
|
|
ShowNpcOrGoSpawnInformation<Creature>(target->GetGUIDLow());
|
|
return true;
|
|
}
|
|
|
|
// play npc emote
|
|
bool ChatHandler::HandleNpcPlayEmoteCommand(char* args)
|
|
{
|
|
uint32 emote = atoi(args);
|
|
|
|
Creature* target = getSelectedCreature();
|
|
if (!target)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
target->HandleEmote(emote);
|
|
|
|
return true;
|
|
}
|
|
|
|
// TODO: NpcCommands that needs to be fixed :
|
|
bool ChatHandler::HandleNpcAddWeaponCommand(char* /*args*/)
|
|
{
|
|
/*if (!*args)
|
|
return false;
|
|
|
|
ObjectGuid guid = m_session->GetPlayer()->GetSelectionGuid();
|
|
if (guid.IsEmpty())
|
|
{
|
|
SendSysMessage(LANG_NO_SELECTION);
|
|
return true;
|
|
}
|
|
|
|
Creature *pCreature = sObjectAccessor.GetCreature(*m_session->GetPlayer(), guid);
|
|
|
|
if(!pCreature)
|
|
{
|
|
SendSysMessage(LANG_SELECT_CREATURE);
|
|
return true;
|
|
}
|
|
|
|
char* pSlotID = strtok((char*)args, " ");
|
|
if (!pSlotID)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
char* pItemID = strtok(NULL, " ");
|
|
if (!pItemID)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32 ItemID = atoi(pItemID);
|
|
uint32 SlotID = atoi(pSlotID);
|
|
|
|
ItemPrototype* tmpItem = ObjectMgr::GetItemPrototype(ItemID);
|
|
|
|
bool added = false;
|
|
if(tmpItem)
|
|
{
|
|
switch(SlotID)
|
|
{
|
|
case 1:
|
|
pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
|
|
added = true;
|
|
break;
|
|
case 2:
|
|
pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
|
|
added = true;
|
|
break;
|
|
case 3:
|
|
pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
|
|
added = true;
|
|
break;
|
|
default:
|
|
PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID);
|
|
added = false;
|
|
break;
|
|
}
|
|
|
|
if(added)
|
|
{
|
|
PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID);
|
|
return true;
|
|
}
|
|
*/
|
|
return true;
|
|
}
|
|
//----------------------------------------------------------
|