Files
TrinityCore/src/server/scripts/Commands/cs_npc.cpp

1688 lines
60 KiB
C++

/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* ScriptData
Name: npc_commandscript
%Complete: 100
Comment: All npc related commands
Category: commandscripts
EndScriptData */
#include "ScriptMgr.h"
#include "Chat.h"
#include "CreatureAI.h"
#include "CreatureGroups.h"
#include "DatabaseEnv.h"
#include "Language.h"
#include "Log.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
#include "Transport.h"
#include "World.h"
#include "WorldSession.h"
template<typename E, typename T = char const*>
struct EnumName
{
E Value;
T Name;
};
#define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) }
#define NPC_FLAG_COUNT 24
#define FLAGS_EXTRA_COUNT 20
EnumName<NPCFlags, uint32> const npcFlagTexts[NPC_FLAG_COUNT] =
{
{ UNIT_NPC_FLAG_AUCTIONEER, LANG_NPCINFO_AUCTIONEER },
{ UNIT_NPC_FLAG_BANKER, LANG_NPCINFO_BANKER },
{ UNIT_NPC_FLAG_BATTLEMASTER, LANG_NPCINFO_BATTLEMASTER },
{ UNIT_NPC_FLAG_FLIGHTMASTER, LANG_NPCINFO_FLIGHTMASTER },
{ UNIT_NPC_FLAG_GOSSIP, LANG_NPCINFO_GOSSIP },
{ UNIT_NPC_FLAG_GUILD_BANKER, LANG_NPCINFO_GUILD_BANKER },
{ UNIT_NPC_FLAG_INNKEEPER, LANG_NPCINFO_INNKEEPER },
{ UNIT_NPC_FLAG_PETITIONER, LANG_NPCINFO_PETITIONER },
{ UNIT_NPC_FLAG_PLAYER_VEHICLE, LANG_NPCINFO_PLAYER_VEHICLE },
{ UNIT_NPC_FLAG_QUESTGIVER, LANG_NPCINFO_QUESTGIVER },
{ UNIT_NPC_FLAG_REPAIR, LANG_NPCINFO_REPAIR },
{ UNIT_NPC_FLAG_SPELLCLICK, LANG_NPCINFO_SPELLCLICK },
{ UNIT_NPC_FLAG_SPIRITGUIDE, LANG_NPCINFO_SPIRITGUIDE },
{ UNIT_NPC_FLAG_SPIRITHEALER, LANG_NPCINFO_SPIRITHEALER },
{ UNIT_NPC_FLAG_STABLEMASTER, LANG_NPCINFO_STABLEMASTER },
{ UNIT_NPC_FLAG_TABARDDESIGNER, LANG_NPCINFO_TABARDDESIGNER },
{ UNIT_NPC_FLAG_TRAINER, LANG_NPCINFO_TRAINER },
{ UNIT_NPC_FLAG_TRAINER_CLASS, LANG_NPCINFO_TRAINER_CLASS },
{ UNIT_NPC_FLAG_TRAINER_PROFESSION, LANG_NPCINFO_TRAINER_PROFESSION },
{ UNIT_NPC_FLAG_VENDOR, LANG_NPCINFO_VENDOR },
{ UNIT_NPC_FLAG_VENDOR_AMMO, LANG_NPCINFO_VENDOR_AMMO },
{ UNIT_NPC_FLAG_VENDOR_FOOD, LANG_NPCINFO_VENDOR_FOOD },
{ UNIT_NPC_FLAG_VENDOR_POISON, LANG_NPCINFO_VENDOR_POISON },
{ UNIT_NPC_FLAG_VENDOR_REAGENT, LANG_NPCINFO_VENDOR_REAGENT }
};
EnumName<Mechanics> const mechanicImmunes[MAX_MECHANIC] =
{
CREATE_NAMED_ENUM(MECHANIC_NONE),
CREATE_NAMED_ENUM(MECHANIC_CHARM),
CREATE_NAMED_ENUM(MECHANIC_DISORIENTED),
CREATE_NAMED_ENUM(MECHANIC_DISARM),
CREATE_NAMED_ENUM(MECHANIC_DISTRACT),
CREATE_NAMED_ENUM(MECHANIC_FEAR),
CREATE_NAMED_ENUM(MECHANIC_GRIP),
CREATE_NAMED_ENUM(MECHANIC_ROOT),
CREATE_NAMED_ENUM(MECHANIC_SLOW_ATTACK),
CREATE_NAMED_ENUM(MECHANIC_SILENCE),
CREATE_NAMED_ENUM(MECHANIC_SLEEP),
CREATE_NAMED_ENUM(MECHANIC_SNARE),
CREATE_NAMED_ENUM(MECHANIC_STUN),
CREATE_NAMED_ENUM(MECHANIC_FREEZE),
CREATE_NAMED_ENUM(MECHANIC_KNOCKOUT),
CREATE_NAMED_ENUM(MECHANIC_BLEED),
CREATE_NAMED_ENUM(MECHANIC_BANDAGE),
CREATE_NAMED_ENUM(MECHANIC_POLYMORPH),
CREATE_NAMED_ENUM(MECHANIC_BANISH),
CREATE_NAMED_ENUM(MECHANIC_SHIELD),
CREATE_NAMED_ENUM(MECHANIC_SHACKLE),
CREATE_NAMED_ENUM(MECHANIC_MOUNT),
CREATE_NAMED_ENUM(MECHANIC_INFECTED),
CREATE_NAMED_ENUM(MECHANIC_TURN),
CREATE_NAMED_ENUM(MECHANIC_HORROR),
CREATE_NAMED_ENUM(MECHANIC_INVULNERABILITY),
CREATE_NAMED_ENUM(MECHANIC_INTERRUPT),
CREATE_NAMED_ENUM(MECHANIC_DAZE),
CREATE_NAMED_ENUM(MECHANIC_DISCOVERY),
CREATE_NAMED_ENUM(MECHANIC_IMMUNE_SHIELD),
CREATE_NAMED_ENUM(MECHANIC_SAPPED),
CREATE_NAMED_ENUM(MECHANIC_ENRAGED),
CREATE_NAMED_ENUM(MECHANIC_WOUNDED)
};
EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] =
{
CREATE_NAMED_ENUM(UNIT_FLAG_SERVER_CONTROLLED),
CREATE_NAMED_ENUM(UNIT_FLAG_NON_ATTACKABLE),
CREATE_NAMED_ENUM(UNIT_FLAG_REMOVE_CLIENT_CONTROL),
CREATE_NAMED_ENUM(UNIT_FLAG_PVP_ATTACKABLE),
CREATE_NAMED_ENUM(UNIT_FLAG_RENAME),
CREATE_NAMED_ENUM(UNIT_FLAG_PREPARATION),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_6),
CREATE_NAMED_ENUM(UNIT_FLAG_NOT_ATTACKABLE_1),
CREATE_NAMED_ENUM(UNIT_FLAG_IMMUNE_TO_PC),
CREATE_NAMED_ENUM(UNIT_FLAG_IMMUNE_TO_NPC),
CREATE_NAMED_ENUM(UNIT_FLAG_LOOTING),
CREATE_NAMED_ENUM(UNIT_FLAG_PET_IN_COMBAT),
CREATE_NAMED_ENUM(UNIT_FLAG_PVP),
CREATE_NAMED_ENUM(UNIT_FLAG_SILENCED),
CREATE_NAMED_ENUM(UNIT_FLAG_CANNOT_SWIM),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_15),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_16),
CREATE_NAMED_ENUM(UNIT_FLAG_PACIFIED),
CREATE_NAMED_ENUM(UNIT_FLAG_STUNNED),
CREATE_NAMED_ENUM(UNIT_FLAG_IN_COMBAT),
CREATE_NAMED_ENUM(UNIT_FLAG_TAXI_FLIGHT),
CREATE_NAMED_ENUM(UNIT_FLAG_DISARMED),
CREATE_NAMED_ENUM(UNIT_FLAG_CONFUSED),
CREATE_NAMED_ENUM(UNIT_FLAG_FLEEING),
CREATE_NAMED_ENUM(UNIT_FLAG_PLAYER_CONTROLLED),
CREATE_NAMED_ENUM(UNIT_FLAG_NOT_SELECTABLE),
CREATE_NAMED_ENUM(UNIT_FLAG_SKINNABLE),
CREATE_NAMED_ENUM(UNIT_FLAG_MOUNT),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_28),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_29),
CREATE_NAMED_ENUM(UNIT_FLAG_SHEATHE),
CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31)
};
EnumName<UnitFlags2> const unitFlags2[MAX_UNIT_FLAGS_2] =
{
CREATE_NAMED_ENUM(UNIT_FLAG2_FEIGN_DEATH),
CREATE_NAMED_ENUM(UNIT_FLAG2_UNK1),
CREATE_NAMED_ENUM(UNIT_FLAG2_IGNORE_REPUTATION),
CREATE_NAMED_ENUM(UNIT_FLAG2_COMPREHEND_LANG),
CREATE_NAMED_ENUM(UNIT_FLAG2_MIRROR_IMAGE),
CREATE_NAMED_ENUM(UNIT_FLAG2_INSTANTLY_APPEAR_MODEL),
CREATE_NAMED_ENUM(UNIT_FLAG2_FORCE_MOVEMENT),
CREATE_NAMED_ENUM(UNIT_FLAG2_DISARM_OFFHAND),
CREATE_NAMED_ENUM(UNIT_FLAG2_DISABLE_PRED_STATS),
CREATE_NAMED_ENUM(UNIT_FLAG2_DISARM_RANGED),
CREATE_NAMED_ENUM(UNIT_FLAG2_REGENERATE_POWER),
CREATE_NAMED_ENUM(UNIT_FLAG2_RESTRICT_PARTY_INTERACTION),
CREATE_NAMED_ENUM(UNIT_FLAG2_PREVENT_SPELL_CLICK),
CREATE_NAMED_ENUM(UNIT_FLAG2_ALLOW_ENEMY_INTERACT),
CREATE_NAMED_ENUM(UNIT_FLAG2_DISABLE_TURN),
CREATE_NAMED_ENUM(UNIT_FLAG2_UNK2),
CREATE_NAMED_ENUM(UNIT_FLAG2_PLAY_DEATH_ANIM),
CREATE_NAMED_ENUM(UNIT_FLAG2_ALLOW_CHEAT_SPELLS),
CREATE_NAMED_ENUM(UNIT_FLAG2_NO_ACTIONS)
};
EnumName<UnitFlags3> const unitFlags3[MAX_UNIT_FLAGS_3] =
{
CREATE_NAMED_ENUM(UNIT_FLAG3_UNK1)
};
EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
{
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
};
class npc_commandscript : public CommandScript
{
public:
npc_commandscript() : CommandScript("npc_commandscript") { }
std::vector<ChatCommand> GetCommands() const override
{
static std::vector<ChatCommand> npcAddCommandTable =
{
{ "formation", rbac::RBAC_PERM_COMMAND_NPC_ADD_FORMATION, false, &HandleNpcAddFormationCommand, "" },
{ "item", rbac::RBAC_PERM_COMMAND_NPC_ADD_ITEM, false, &HandleNpcAddVendorItemCommand, "" },
{ "move", rbac::RBAC_PERM_COMMAND_NPC_ADD_MOVE, false, &HandleNpcAddMoveCommand, "" },
{ "temp", rbac::RBAC_PERM_COMMAND_NPC_ADD_TEMP, false, &HandleNpcAddTempSpawnCommand, "" },
//{ "weapon", rbac::RBAC_PERM_COMMAND_NPC_ADD_WEAPON, false, &HandleNpcAddWeaponCommand, "" },
{ "", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, &HandleNpcAddCommand, "" },
};
static std::vector<ChatCommand> npcDeleteCommandTable =
{
{ "item", rbac::RBAC_PERM_COMMAND_NPC_DELETE_ITEM, false, &HandleNpcDeleteVendorItemCommand, "" },
{ "", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, &HandleNpcDeleteCommand, "" },
};
static std::vector<ChatCommand> npcFollowCommandTable =
{
{ "stop", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW_STOP, false, &HandleNpcUnFollowCommand, "" },
{ "", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, &HandleNpcFollowCommand, "" },
};
static std::vector<ChatCommand> npcSetCommandTable =
{
{ "allowmove", rbac::RBAC_PERM_COMMAND_NPC_SET_ALLOWMOVE, false, &HandleNpcSetAllowMovementCommand, "" },
{ "entry", rbac::RBAC_PERM_COMMAND_NPC_SET_ENTRY, false, &HandleNpcSetEntryCommand, "" },
{ "factionid", rbac::RBAC_PERM_COMMAND_NPC_SET_FACTIONID, false, &HandleNpcSetFactionIdCommand, "" },
{ "flag", rbac::RBAC_PERM_COMMAND_NPC_SET_FLAG, false, &HandleNpcSetFlagCommand, "" },
{ "level", rbac::RBAC_PERM_COMMAND_NPC_SET_LEVEL, false, &HandleNpcSetLevelCommand, "" },
{ "link", rbac::RBAC_PERM_COMMAND_NPC_SET_LINK, false, &HandleNpcSetLinkCommand, "" },
{ "model", rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, false, &HandleNpcSetModelCommand, "" },
{ "movetype", rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, false, &HandleNpcSetMoveTypeCommand, "" },
{ "phase", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseCommand, "" },
{ "phasegroup", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseGroup, "" },
{ "spawndist", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, false, &HandleNpcSetSpawnDistCommand, "" },
{ "spawntime", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, false, &HandleNpcSetSpawnTimeCommand, "" },
{ "data", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetDataCommand, "" },
};
static std::vector<ChatCommand> npcCommandTable =
{
{ "info", rbac::RBAC_PERM_COMMAND_NPC_INFO, false, &HandleNpcInfoCommand, "" },
{ "near", rbac::RBAC_PERM_COMMAND_NPC_NEAR, false, &HandleNpcNearCommand, "" },
{ "move", rbac::RBAC_PERM_COMMAND_NPC_MOVE, false, &HandleNpcMoveCommand, "" },
{ "playemote", rbac::RBAC_PERM_COMMAND_NPC_PLAYEMOTE, false, &HandleNpcPlayEmoteCommand, "" },
{ "say", rbac::RBAC_PERM_COMMAND_NPC_SAY, false, &HandleNpcSayCommand, "" },
{ "textemote", rbac::RBAC_PERM_COMMAND_NPC_TEXTEMOTE, false, &HandleNpcTextEmoteCommand, "" },
{ "whisper", rbac::RBAC_PERM_COMMAND_NPC_WHISPER, false, &HandleNpcWhisperCommand, "" },
{ "yell", rbac::RBAC_PERM_COMMAND_NPC_YELL, false, &HandleNpcYellCommand, "" },
{ "tame", rbac::RBAC_PERM_COMMAND_NPC_TAME, false, &HandleNpcTameCommand, "" },
{ "add", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, nullptr, "", npcAddCommandTable },
{ "delete", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, nullptr, "", npcDeleteCommandTable },
{ "follow", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, nullptr, "", npcFollowCommandTable },
{ "set", rbac::RBAC_PERM_COMMAND_NPC_SET, false, nullptr, "", npcSetCommandTable },
{ "evade", rbac::RBAC_PERM_COMMAND_NPC_EVADE, false, &HandleNpcEvadeCommand, "" },
};
static std::vector<ChatCommand> commandTable =
{
{ "npc", rbac::RBAC_PERM_COMMAND_NPC, false, nullptr, "", npcCommandTable },
};
return commandTable;
}
//add spawn of creature
static bool HandleNpcAddCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry");
if (!charID)
return false;
uint32 id = atoul(charID);
if (!sObjectMgr->GetCreatureTemplate(id))
return false;
Player* chr = handler->GetSession()->GetPlayer();
Map* map = chr->GetMap();
if (Transport* trans = chr->GetTransport())
{
ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Creature>();
CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
data.id = id;
data.posX = chr->GetTransOffsetX();
data.posY = chr->GetTransOffsetY();
data.posZ = chr->GetTransOffsetZ();
data.orientation = chr->GetTransOffsetO();
/// @todo: add phases
Creature* creature = trans->CreateNPCPassenger(guid, &data);
creature->SaveToDB(trans->GetGOInfo()->moTransport.SpawnMap, { map->GetDifficultyID() });
sObjectMgr->AddCreatureToGrid(guid, &data);
return true;
}
Creature* creature = Creature::CreateCreature(id, map, chr->GetPosition());
if (!creature)
return false;
PhasingHandler::InheritPhaseShift(creature, chr);
creature->SaveToDB(map->GetId(), { map->GetDifficultyID() });
ObjectGuid::LowType db_guid = creature->GetSpawnId();
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells()
// current "creature" variable is deleted and created fresh new, otherwise old values might trigger asserts or cause undefined behavior
creature->CleanupsBeforeDelete();
delete creature;
creature = Creature::CreateCreatureFromDB(db_guid, map);
if (!creature)
return false;
sObjectMgr->AddCreatureToGrid(db_guid, sObjectMgr->GetCreatureData(db_guid));
return true;
}
//add item in vendorlist
static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument
char* pitem = handler->extractKeyFromLink((char*)args, "Hitem");
if (!pitem)
{
handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
handler->SetSentErrorMessage(true);
return false;
}
uint32 itemId = atoull(pitem);
if (!itemId)
return false;
char* fmaxcount = strtok(nullptr, " "); //add maxcount, default: 0
uint32 maxcount = 0;
if (fmaxcount)
maxcount = atoul(fmaxcount);
char* fincrtime = strtok(nullptr, " "); //add incrtime, default: 0
uint32 incrtime = 0;
if (fincrtime)
incrtime = atoul(fincrtime);
char* fextendedcost = strtok(nullptr, " "); //add ExtendedCost, default: 0
uint32 extendedcost = fextendedcost ? atoul(fextendedcost) : 0;
char const* fbonuslist = strtok(nullptr, " ");
Creature* vendor = handler->getSelectedCreature();
if (!vendor)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 vendor_entry = vendor->GetEntry();
VendorItem vItem;
vItem.item = itemId;
vItem.maxcount = maxcount;
vItem.incrtime = incrtime;
vItem.ExtendedCost = extendedcost;
vItem.Type = type;
if (fbonuslist)
{
Tokenizer bonusListIDsTok(fbonuslist, ';');
for (char const* token : bonusListIDsTok)
vItem.BonusListIDs.push_back(int32(atol(token)));
}
if (!sObjectMgr->IsVendorItemValid(vendor_entry, vItem, handler->GetSession()->GetPlayer()))
{
handler->SetSentErrorMessage(true);
return false;
}
sObjectMgr->AddVendorItem(vendor_entry, vItem);
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, itemTemplate->GetDefaultLocaleName(), maxcount, incrtime, extendedcost);
return true;
}
//add move for creature
static bool HandleNpcAddMoveCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
char* guidStr = strtok((char*)args, " ");
char* waitStr = strtok((char*)nullptr, " ");
ObjectGuid::LowType lowGuid = atoull(guidStr);
// attempt check creature existence by DB data
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, std::to_string(lowGuid).c_str());
handler->SetSentErrorMessage(true);
return false;
}
int wait = waitStr ? atoi(waitStr) : 0;
if (wait < 0)
wait = 0;
// Update movement type
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE);
stmt->setUInt8(0, uint8(WAYPOINT_MOTION_TYPE));
stmt->setUInt64(1, lowGuid);
WorldDatabase.Execute(stmt);
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
return true;
}
static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler, char const* /*args*/)
{
if (sWorld->getAllowMovement())
{
sWorld->SetAllowMovement(false);
handler->SendSysMessage(LANG_CREATURE_MOVE_DISABLED);
}
else
{
sWorld->SetAllowMovement(true);
handler->SendSysMessage(LANG_CREATURE_MOVE_ENABLED);
}
return true;
}
static bool HandleNpcSetEntryCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint32 newEntryNum = atoul(args);
if (!newEntryNum)
return false;
Unit* unit = handler->getSelectedUnit();
if (!unit || unit->GetTypeId() != TYPEID_UNIT)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = unit->ToCreature();
if (creature->UpdateEntry(newEntryNum))
handler->SendSysMessage(LANG_DONE);
else
handler->SendSysMessage(LANG_ERROR);
return true;
}
//change level of creature or pet
static bool HandleNpcSetLevelCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint8 lvl = (uint8) atoi(args);
if (lvl < 1 || lvl > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature || creature->IsPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetMaxHealth(100 + 30*lvl);
creature->SetHealth(100 + 30*lvl);
creature->SetLevel(lvl);
creature->SaveToDB();
return true;
}
static bool HandleNpcDeleteCommand(ChatHandler* handler, char const* args)
{
Creature* unit = nullptr;
if (*args)
{
// number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
char* cId = handler->extractKeyFromLink((char*)args, "Hcreature");
if (!cId)
return false;
ObjectGuid::LowType lowguid = atoull(cId);
if (!lowguid)
return false;
unit = handler->GetCreatureFromPlayerMapByDbGuid(lowguid);
}
else
unit = handler->getSelectedCreature();
if (!unit || unit->IsPet() || unit->IsTotem())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
// Delete the creature
unit->CombatStop();
unit->DeleteFromDB();
unit->AddObjectToRemoveList();
handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
return true;
}
//del item from vendor list
static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
Creature* vendor = handler->getSelectedCreature();
if (!vendor || !vendor->IsVendor())
{
handler->SendSysMessage(LANG_COMMAND_VENDORSELECTION);
handler->SetSentErrorMessage(true);
return false;
}
char* pitem = handler->extractKeyFromLink((char*)args, "Hitem");
if (!pitem)
{
handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
handler->SetSentErrorMessage(true);
return false;
}
uint32 itemId = atoul(pitem);
const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument
if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId, type))
{
handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId);
handler->SetSentErrorMessage(true);
return false;
}
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, itemTemplate->GetDefaultLocaleName());
return true;
}
//set faction of creature
static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint32 factionId = atoul(args);
if (!sFactionTemplateStore.LookupEntry(factionId))
{
handler->PSendSysMessage(LANG_WRONG_FACTION, factionId);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->setFaction(factionId);
// Faction is set in creature_template - not inside creature
// Update in memory..
if (CreatureTemplate const* cinfo = creature->GetCreatureTemplate())
const_cast<CreatureTemplate*>(cinfo)->faction = factionId;
// ..and DB
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION);
stmt->setUInt16(0, uint16(factionId));
stmt->setUInt32(1, creature->GetEntry());
WorldDatabase.Execute(stmt);
return true;
}
//set npcflag of creature
static bool HandleNpcSetFlagCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint64 npcFlags = atoull(args);
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetUInt64Value(UNIT_NPC_FLAGS, npcFlags);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG);
stmt->setUInt64(0, npcFlags);
stmt->setUInt32(1, creature->GetEntry());
WorldDatabase.Execute(stmt);
handler->SendSysMessage(LANG_VALUE_SAVED_REJOIN);
return true;
}
//set data of creature for testing scripting
static bool HandleNpcSetDataCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
char* arg1 = strtok((char*)args, " ");
char* arg2 = strtok((char*)nullptr, "");
if (!arg1 || !arg2)
return false;
uint32 data_1 = (uint32)atoi(arg1);
uint32 data_2 = (uint32)atoi(arg2);
if (!data_1 || !data_2)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->AI()->SetData(data_1, data_2);
std::string AIorScript = !creature->GetAIName().empty() ? "AI type: " + creature->GetAIName() : (!creature->GetScriptName().empty() ? "Script Name: " + creature->GetScriptName() : "No AI or Script Name Set");
handler->PSendSysMessage(LANG_NPC_SETDATA, creature->GetGUID().ToString().c_str(), creature->GetName().c_str(), data_1, data_2, AIorScript.c_str());
return true;
}
//npc follow handling
static bool HandleNpcFollowCommand(ChatHandler* handler, char const* /*args*/)
{
Player* player = handler->GetSession()->GetPlayer();
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->PSendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
// Follow player - Using pet's default dist and angle
creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle());
handler->PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName().c_str());
return true;
}
static bool HandleNpcInfoCommand(ChatHandler* handler, char const* /*args*/)
{
Creature* target = handler->getSelectedCreature();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
CreatureTemplate const* cInfo = target->GetCreatureTemplate();
uint32 faction = target->getFaction();
uint64 npcflags = target->GetUInt64Value(UNIT_NPC_FLAGS);
uint32 mechanicImmuneMask = cInfo->MechanicImmuneMask;
uint32 displayid = target->GetDisplayId();
uint32 nativeid = target->GetNativeDisplayId();
uint32 Entry = target->GetEntry();
int64 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
if (curRespawnDelay < 0)
curRespawnDelay = 0;
std::string curRespawnDelayStr = secsToTimeString(uint64(curRespawnDelay), true);
std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(), true);
handler->PSendSysMessage(LANG_NPCINFO_CHAR, std::to_string(target->GetSpawnId()).c_str(), target->GetGUID().ToString().c_str(), faction, std::to_string(npcflags).c_str(), Entry, displayid, nativeid);
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId());
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), std::to_string(target->GetMaxHealth()).c_str(), std::to_string(target->GetHealth()).c_str());
handler->PSendSysMessage(LANG_NPCINFO_INHABIT_TYPE, cInfo->InhabitType);
handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS));
for (uint8 i = 0; i < MAX_UNIT_FLAGS; ++i)
if (target->GetUInt32Value(UNIT_FIELD_FLAGS) & unitFlags[i].Value)
handler->PSendSysMessage("%s (0x%X)", unitFlags[i].Name, unitFlags[i].Value);
handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS_2, target->GetUInt32Value(UNIT_FIELD_FLAGS_2));
for (uint8 i = 0; i < MAX_UNIT_FLAGS_2; ++i)
if (target->GetUInt32Value(UNIT_FIELD_FLAGS_2) & unitFlags2[i].Value)
handler->PSendSysMessage("%s (0x%X)", unitFlags2[i].Name, unitFlags2[i].Value);
handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS_3, target->GetUInt32Value(UNIT_FIELD_FLAGS_3));
for (uint8 i = 0; i < MAX_UNIT_FLAGS_3; ++i)
if (target->GetUInt32Value(UNIT_FIELD_FLAGS_3) & unitFlags3[i].Value)
handler->PSendSysMessage("%s (0x%X)", unitFlags3[i].Name, unitFlags3[i].Value);
handler->PSendSysMessage(LANG_NPCINFO_DYNAMIC_FLAGS, target->GetUInt32Value(OBJECT_DYNAMIC_FLAGS));
handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str());
handler->PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId);
handler->PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
if (CreatureData const* data = sObjectMgr->GetCreatureData(target->GetSpawnId()))
{
handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseId, data->phaseGroup);
PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
}
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str());
handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra);
for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i)
if (cInfo->flags_extra & flagsExtra[i].Value)
handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value);
handler->PSendSysMessage(LANG_NPCINFO_NPC_FLAGS, npcflags);
for (uint8 i = 0; i < NPC_FLAG_COUNT; i++)
if (npcflags & npcFlagTexts[i].Value)
handler->PSendSysMessage(npcFlagTexts[i].Name, npcFlagTexts[i].Value);
handler->PSendSysMessage(LANG_NPCINFO_MECHANIC_IMMUNE, mechanicImmuneMask);
for (uint8 i = 1; i < MAX_MECHANIC; ++i)
if (mechanicImmuneMask & (1 << (mechanicImmunes[i].Value - 1)))
handler->PSendSysMessage("%s (0x%X)", mechanicImmunes[i].Name, mechanicImmunes[i].Value);
return true;
}
static bool HandleNpcNearCommand(ChatHandler* handler, char const* args)
{
float distance = (!*args) ? 10.0f : float((atof(args)));
uint32 count = 0;
Player* player = handler->GetSession()->GetPlayer();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_NEAREST);
stmt->setFloat(0, player->GetPositionX());
stmt->setFloat(1, player->GetPositionY());
stmt->setFloat(2, player->GetPositionZ());
stmt->setUInt32(3, player->GetMapId());
stmt->setFloat(4, player->GetPositionX());
stmt->setFloat(5, player->GetPositionY());
stmt->setFloat(6, player->GetPositionZ());
stmt->setFloat(7, distance * distance);
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (result)
{
do
{
Field* fields = result->Fetch();
ObjectGuid::LowType guid = fields[0].GetUInt64();
uint32 entry = fields[1].GetUInt32();
float x = fields[2].GetFloat();
float y = fields[3].GetFloat();
float z = fields[4].GetFloat();
uint16 mapId = fields[5].GetUInt16();
CreatureTemplate const* creatureTemplate = sObjectMgr->GetCreatureTemplate(entry);
if (!creatureTemplate)
continue;
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), creatureTemplate->Name.c_str(), x, y, z, mapId);
++count;
}
while (result->NextRow());
}
handler->PSendSysMessage(LANG_COMMAND_NEAR_NPC_MESSAGE, distance, count);
return true;
}
//move selected creature
static bool HandleNpcMoveCommand(ChatHandler* handler, char const* args)
{
ObjectGuid::LowType lowguid = UI64LIT(0);
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
// number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
char* cId = handler->extractKeyFromLink((char*)args, "Hcreature");
if (!cId)
return false;
lowguid = atoull(cId);
// Attempting creature load from DB data
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, std::to_string(lowguid).c_str());
handler->SetSentErrorMessage(true);
return false;
}
uint32 map_id = data->mapid;
if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
{
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, std::to_string(lowguid).c_str());
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
lowguid = creature->GetSpawnId();
}
float x = handler->GetSession()->GetPlayer()->GetPositionX();
float y = handler->GetSession()->GetPlayer()->GetPositionY();
float z = handler->GetSession()->GetPlayer()->GetPositionZ();
float o = handler->GetSession()->GetPlayer()->GetOrientation();
if (creature)
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetSpawnId()))
{
const_cast<CreatureData*>(data)->posX = x;
const_cast<CreatureData*>(data)->posY = y;
const_cast<CreatureData*>(data)->posZ = z;
const_cast<CreatureData*>(data)->orientation = o;
}
creature->SetPosition(x, y, z, o);
creature->GetMotionMaster()->Initialize();
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn();
}
}
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION);
stmt->setFloat(0, x);
stmt->setFloat(1, y);
stmt->setFloat(2, z);
stmt->setFloat(3, o);
stmt->setUInt64(4, lowguid);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
return true;
}
//play npc emote
static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, char const* args)
{
uint32 emote = atoi((char*)args);
Creature* target = handler->getSelectedCreature();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote);
return true;
}
//set model of creature
static bool HandleNpcSetModelCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint32 displayId = atoul(args);
Creature* creature = handler->getSelectedCreature();
if (!creature || creature->IsPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetDisplayId(displayId);
creature->SetNativeDisplayId(displayId);
creature->SaveToDB();
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
*/
static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
// 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)
char* guid_str = strtok((char*)args, " ");
char* type_str = strtok((char*)nullptr, " ");
char* dontdel_str = strtok((char*)nullptr, " ");
bool doNotDelete = false;
if (!guid_str)
return false;
ObjectGuid::LowType lowguid = UI64LIT(0);
Creature* creature = nullptr;
if (dontdel_str)
{
//TC_LOG_ERROR("misc", "DEBUG: All 3 params are set");
// All 3 params are set
// GUID
// type
// doNotDEL
if (stricmp(dontdel_str, "NODEL") == 0)
{
//TC_LOG_ERROR("misc", "DEBUG: doNotDelete = true;");
doNotDelete = true;
}
}
else
{
// Only 2 params - but maybe NODEL is set
if (type_str)
{
TC_LOG_ERROR("misc", "DEBUG: Only 2 params ");
if (stricmp(type_str, "NODEL") == 0)
{
//TC_LOG_ERROR("misc", "DEBUG: type_str, NODEL ");
doNotDelete = true;
type_str = nullptr;
}
}
}
if (!type_str) // case .setmovetype $move_type (with selected creature)
{
type_str = guid_str;
creature = handler->getSelectedCreature();
if (!creature || creature->IsPet())
return false;
lowguid = creature->GetSpawnId();
}
else // case .setmovetype #creature_guid $move_type (with selected creature)
{
lowguid = atoull(guid_str);
if (lowguid)
creature = handler->GetCreatureFromPlayerMapByDbGuid(lowguid);
// attempt check creature existence by DB data
if (!creature)
{
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, std::to_string(lowguid).c_str());
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
lowguid = creature->GetSpawnId();
}
}
// now lowguid is low guid really existed creature
// and creature point (maybe) to this creature or nullptr
MovementGeneratorType move_type;
std::string type = type_str;
if (type == "stay")
move_type = IDLE_MOTION_TYPE;
else if (type == "random")
move_type = RANDOM_MOTION_TYPE;
else if (type == "way")
move_type = WAYPOINT_MOTION_TYPE;
else
return false;
// update movement type
//if (doNotDelete == false)
// WaypointMgr.DeletePath(lowguid);
if (creature)
{
// update movement type
if (doNotDelete == false)
creature->LoadPath(0);
creature->SetDefaultMovementType(move_type);
creature->GetMotionMaster()->Initialize();
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn();
}
creature->SaveToDB();
}
if (doNotDelete == false)
{
handler->PSendSysMessage(LANG_MOVE_TYPE_SET, type_str);
}
else
{
handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, type_str);
}
return true;
}
//npc phase handling
//change phase of creature
static bool HandleNpcSetPhaseGroup(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
int32 phaseGroupId = atoi(args);
Creature* creature = handler->getSelectedCreature();
if (!creature || creature->IsPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
PhasingHandler::ResetPhaseShift(creature);
PhasingHandler::AddPhaseGroup(creature, phaseGroupId, true);
creature->SetDBPhase(-phaseGroupId);
creature->SaveToDB();
return true;
}
//npc phase handling
//change phase of creature
static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
uint32 phaseID = atoul(args);
if (!sPhaseStore.LookupEntry(phaseID))
{
handler->SendSysMessage(LANG_PHASE_NOTFOUND);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature || creature->IsPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
PhasingHandler::ResetPhaseShift(creature);
PhasingHandler::AddPhase(creature, phaseID, true);
creature->SetDBPhase(phaseID);
creature->SaveToDB();
return true;
}
//set spawn dist of creature
static bool HandleNpcSetSpawnDistCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
float option = (float)(atof((char*)args));
if (option < 0.0f)
{
handler->SendSysMessage(LANG_BAD_VALUE);
return false;
}
MovementGeneratorType mtype = IDLE_MOTION_TYPE;
if (option >0.0f)
mtype = RANDOM_MOTION_TYPE;
Creature* creature = handler->getSelectedCreature();
ObjectGuid::LowType guidLow = UI64LIT(0);
if (creature)
guidLow = creature->GetSpawnId();
else
return false;
creature->SetRespawnRadius(option);
creature->SetDefaultMovementType(mtype);
creature->GetMotionMaster()->Initialize();
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn();
}
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE);
stmt->setFloat(0, option);
stmt->setUInt8(1, uint8(mtype));
stmt->setUInt64(2, guidLow);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_SPAWNDIST, option);
return true;
}
//spawn time handling
static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
char* stime = strtok((char*)args, " ");
if (!stime)
return false;
uint32 spawnTime = atoul(stime);
Creature* creature = handler->getSelectedCreature();
if (!creature)
return false;
ObjectGuid::LowType guidLow = creature->GetSpawnId();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS);
stmt->setUInt32(0, spawnTime);
stmt->setUInt64(1, guidLow);
WorldDatabase.Execute(stmt);
creature->SetRespawnDelay(spawnTime);
handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, spawnTime);
return true;
}
static bool HandleNpcSayCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->Say(args, LANG_UNIVERSAL);
// make some emotes
char lastchar = args[strlen(args) - 1];
switch (lastchar)
{
case '?': creature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break;
case '!': creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break;
default: creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break;
}
return true;
}
//show text emote by creature in chat
static bool HandleNpcTextEmoteCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->TextEmote(args);
return true;
}
//npc unfollow handling
static bool HandleNpcUnFollowCommand(ChatHandler* handler, char const* /*args*/)
{
Player* player = handler->GetSession()->GetPlayer();
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->PSendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (/*creature->GetMotionMaster()->empty() ||*/
creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE)
{
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
handler->SetSentErrorMessage(true);
return false;
}
FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
if (mgen->GetTarget() != player)
{
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
handler->SetSentErrorMessage(true);
return false;
}
// reset movement
creature->GetMotionMaster()->MovementExpired(true);
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName().c_str());
return true;
}
// make npc whisper to player
static bool HandleNpcWhisperCommand(ChatHandler* handler, char const* args)
{
if (!*args)
{
handler->SendSysMessage(LANG_CMD_SYNTAX);
handler->SetSentErrorMessage(true);
return false;
}
char* receiver_str = strtok((char*)args, " ");
char* text = strtok(nullptr, "");
if (!receiver_str || !text)
{
handler->SendSysMessage(LANG_CMD_SYNTAX);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
ObjectGuid receiver_guid = ObjectGuid::Create<HighGuid::Player>(strtoull(receiver_str, nullptr, 10));
// check online security
Player* receiver = ObjectAccessor::FindPlayer(receiver_guid);
if (handler->HasLowerSecurity(receiver, ObjectGuid::Empty))
return false;
creature->Whisper(text, LANG_UNIVERSAL, receiver);
return true;
}
static bool HandleNpcYellCommand(ChatHandler* handler, char const* args)
{
if (!*args)
{
handler->SendSysMessage(LANG_CMD_SYNTAX);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->Yell(args, LANG_UNIVERSAL);
// make an emote
creature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT);
return true;
}
// add creature, temp only
static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
bool loot = false;
char const* spawntype_str = strtok((char*)args, " ");
char const* entry_str = strtok(nullptr, "");
if (stricmp(spawntype_str, "LOOT") == 0)
loot = true;
else if (stricmp(spawntype_str, "NOLOOT") == 0)
loot = false;
else
entry_str = args;
char* charID = handler->extractKeyFromLink((char*)entry_str, "Hcreature_entry");
if (!charID)
return false;
Player* chr = handler->GetSession()->GetPlayer();
uint32 id = atoul(charID);
if (!id)
return false;
if (!sObjectMgr->GetCreatureTemplate(id))
return false;
chr->SummonCreature(id, *chr, loot ? TEMPSUMMON_CORPSE_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN, 30 * IN_MILLISECONDS);
return true;
}
//npc tame handling
static bool HandleNpcTameCommand(ChatHandler* handler, char const* /*args*/)
{
Creature* creatureTarget = handler->getSelectedCreature();
if (!creatureTarget || creatureTarget->IsPet())
{
handler->PSendSysMessage (LANG_SELECT_CREATURE);
handler->SetSentErrorMessage (true);
return false;
}
Player* player = handler->GetSession()->GetPlayer();
if (!player->GetPetGUID().IsEmpty())
{
handler->SendSysMessage (LANG_YOU_ALREADY_HAVE_PET);
handler->SetSentErrorMessage (true);
return false;
}
CreatureTemplate const* cInfo = creatureTarget->GetCreatureTemplate();
if (!cInfo->IsTameable (player->CanTameExoticPets()))
{
handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
handler->SetSentErrorMessage (true);
return false;
}
// Everything looks OK, create new pet
Pet* pet = player->CreateTamedPetFrom(creatureTarget);
if (!pet)
{
handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
handler->SetSentErrorMessage (true);
return false;
}
// place pet before player
float x, y, z;
player->GetClosePoint (x, y, z, creatureTarget->GetObjectSize(), CONTACT_DISTANCE);
pet->Relocate(x, y, z, float(M_PI) - player->GetOrientation());
// set pet to defensive mode by default (some classes can't control controlled pets in fact).
pet->SetReactState(REACT_DEFENSIVE);
// calculate proper level
uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel();
// prepare visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
// add to world
pet->GetMap()->AddToMap(pet->ToCreature());
// visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
// caster have pet now
player->SetMinion(pet, true);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
player->PetSpellInitialize();
return true;
}
static bool HandleNpcEvadeCommand(ChatHandler* handler, char const* args)
{
Creature* creatureTarget = handler->getSelectedCreature();
if (!creatureTarget || creatureTarget->IsPet())
{
handler->PSendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (!creatureTarget->IsAIEnabled)
{
handler->PSendSysMessage(LANG_CREATURE_NOT_AI_ENABLED);
handler->SetSentErrorMessage(true);
return false;
}
char* type_str = args ? strtok((char*)args, " ") : nullptr;
char* force_str = args ? strtok(nullptr, " ") : nullptr;
CreatureAI::EvadeReason why = CreatureAI::EVADE_REASON_OTHER;
bool force = false;
if (type_str)
{
if (stricmp(type_str, "NO_HOSTILES") == 0 || stricmp(type_str, "EVADE_REASON_NO_HOSTILES") == 0)
why = CreatureAI::EVADE_REASON_NO_HOSTILES;
else if (stricmp(type_str, "BOUNDARY") == 0 || stricmp(type_str, "EVADE_REASON_BOUNDARY") == 0)
why = CreatureAI::EVADE_REASON_BOUNDARY;
else if (stricmp(type_str, "SEQUENCE_BREAK") == 0 || stricmp(type_str, "EVADE_REASON_SEQUENCE_BREAK") == 0)
why = CreatureAI::EVADE_REASON_SEQUENCE_BREAK;
else if (stricmp(type_str, "FORCE") == 0)
force = true;
if (!force && force_str)
if (stricmp(force_str, "FORCE") == 0)
force = true;
}
if (force)
creatureTarget->ClearUnitState(UNIT_STATE_EVADE);
creatureTarget->AI()->EnterEvadeMode(why);
return true;
}
static bool HandleNpcAddFormationCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
ObjectGuid::LowType leaderGUID = atoull(args);
Creature* creature = handler->getSelectedCreature();
if (!creature || !creature->GetSpawnId())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
ObjectGuid::LowType lowguid = creature->GetSpawnId();
if (creature->GetFormation())
{
handler->PSendSysMessage("Selected creature is already member of group " UI64FMTD, creature->GetFormation()->GetId());
return false;
}
if (!lowguid)
return false;
Player* chr = handler->GetSession()->GetPlayer();
FormationInfo* group_member;
group_member = new FormationInfo;
group_member->follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / float(M_PI);
group_member->follow_dist = std::sqrt(std::pow(chr->GetPositionX() - creature->GetPositionX(), 2.f) + std::pow(chr->GetPositionY() - creature->GetPositionY(), 2.f));
group_member->leaderGUID = leaderGUID;
group_member->groupAI = 0;
sFormationMgr->CreatureGroupMap[lowguid] = group_member;
creature->SearchFormation();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
stmt->setUInt64(0, leaderGUID);
stmt->setUInt64(1, lowguid);
stmt->setFloat(2, group_member->follow_dist);
stmt->setFloat(3, group_member->follow_angle);
stmt->setUInt32(4, uint32(group_member->groupAI));
WorldDatabase.Execute(stmt);
handler->PSendSysMessage("Creature " UI64FMTD " added to formation with leader " UI64FMTD, lowguid, leaderGUID);
return true;
}
static bool HandleNpcSetLinkCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
ObjectGuid::LowType linkguid = atoull(args);
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (!creature->GetSpawnId())
{
handler->PSendSysMessage("Selected %s isn't in creature table", creature->GetGUID().ToString().c_str());
handler->SetSentErrorMessage(true);
return false;
}
if (!sObjectMgr->SetCreatureLinkedRespawn(creature->GetSpawnId(), linkguid))
{
handler->PSendSysMessage("Selected creature can't link with guid '" UI64FMTD "'", linkguid);
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage("LinkGUID '" UI64FMTD "' added to creature with DBTableGUID: '" UI64FMTD "'", linkguid, creature->GetSpawnId());
return true;
}
/// @todo NpcCommands that need to be fixed :
static bool HandleNpcAddWeaponCommand(ChatHandler* /*handler*/, char const* /*args*/)
{
/*if (!*args)
return false;
uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
if (guid == 0)
{
handler->SendSysMessage(LANG_NO_SELECTION);
return true;
}
Creature* creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid);
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
return true;
}
char* pSlotID = strtok((char*)args, " ");
if (!pSlotID)
return false;
char* pItemID = strtok(nullptr, " ");
if (!pItemID)
return false;
uint32 ItemID = atoi(pItemID);
uint32 SlotID = atoi(pSlotID);
ItemTemplate* tmpItem = sObjectMgr->GetItemTemplate(ItemID);
bool added = false;
if (tmpItem)
{
switch (SlotID)
{
case 1:
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID);
added = true;
break;
case 2:
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
added = true;
break;
case 3:
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
added = true;
break;
default:
handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, SlotID);
added = false;
break;
}
if (added)
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, ItemID, tmpItem->Name1, SlotID);
}
else
{
handler->PSendSysMessage(LANG_ITEM_NOT_FOUND, ItemID);
return true;
}
*/
return true;
}
};
void AddSC_npc_commandscript()
{
new npc_commandscript();
}