/* * 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 . */ /* 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 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 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 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 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 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 const unitFlags3[MAX_UNIT_FLAGS_3] = { CREATE_NAMED_ENUM(UNIT_FLAG3_UNK1) }; EnumName 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 GetCommands() const override { static std::vector 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 npcDeleteCommandTable = { { "item", rbac::RBAC_PERM_COMMAND_NPC_DELETE_ITEM, false, &HandleNpcDeleteVendorItemCommand, "" }, { "", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, &HandleNpcDeleteCommand, "" }, }; static std::vector npcFollowCommandTable = { { "stop", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW_STOP, false, &HandleNpcUnFollowCommand, "" }, { "", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, &HandleNpcFollowCommand, "" }, }; static std::vector 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 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, "" }, { "showloot", rbac::RBAC_PERM_COMMAND_NPC_SHOWLOOT, false, &HandleNpcShowLootCommand, "" }, }; static std::vector 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(); 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 WorldDatabasePreparedStatement* 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(cinfo)->faction = factionId; // ..and DB WorldDatabasePreparedStatement* 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; } uint32 raw[2]; memcpy(raw, &npcFlags, sizeof(raw)); creature->SetNpcFlags(NPCFlags(raw[0])); creature->SetNpcFlags2(NPCFlags2(raw[1])); WorldDatabasePreparedStatement* 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; memcpy(&npcflags, target->m_unitData->NpcFlags.begin(), sizeof(npcflags)); 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->m_unitData->Flags); for (uint8 i = 0; i < MAX_UNIT_FLAGS; ++i) if (target->HasUnitFlag(unitFlags[i].Value)) handler->PSendSysMessage("%s (0x%X)", unitFlags[i].Name, unitFlags[i].Value); handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS_2, *target->m_unitData->Flags2); for (uint8 i = 0; i < MAX_UNIT_FLAGS_2; ++i) if (target->HasUnitFlag2(unitFlags2[i].Value)) handler->PSendSysMessage("%s (0x%X)", unitFlags2[i].Name, unitFlags2[i].Value); handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS_3, *target->m_unitData->Flags3); for (uint8 i = 0; i < MAX_UNIT_FLAGS_3; ++i) if (target->HasUnitFlag3(unitFlags3[i].Value)) handler->PSendSysMessage("%s (0x%X)", unitFlags3[i].Name, unitFlags3[i].Value); handler->PSendSysMessage(LANG_NPCINFO_DYNAMIC_FLAGS, target->GetDynamicFlags()); 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(); WorldDatabasePreparedStatement* 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(data)->posX = x; const_cast(data)->posY = y; const_cast(data)->posZ = z; const_cast(data)->orientation = o; } creature->UpdatePosition(x, y, z, o); creature->GetMotionMaster()->Initialize(); if (creature->IsAlive()) // dead creature will reset movement generator at respawn { creature->setDeathState(JUST_DIED); creature->Respawn(); } } WorldDatabasePreparedStatement* 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->SetEmoteState(Emote(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.
*
* Valid movement types are: *
    *
  • stay - NPC wont move
  • *
  • random - NPC will move randomly according to the spawndist
  • *
  • way - NPC will move with given waypoints set
  • *
* 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(); } WorldDatabasePreparedStatement* 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(); WorldDatabasePreparedStatement* 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 const* mgen = static_cast 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(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->GetCombatReach(), 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 = std::max(player->getLevel()-5, creatureTarget->getLevel()); // prepare visual effect for levelup pet->SetLevel(level - 1); // add to world pet->GetMap()->AddToMap(pet->ToCreature()); // visual effect for levelup pet->SetLevel(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 void _ShowLootEntry(ChatHandler* handler, uint32 itemId, uint8 itemCount, bool alternateString = false) { ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId); char const* name = nullptr; if (!itemTemplate) name = itemTemplate->GetName(handler->GetSessionDbcLocale()); if (!name) name = "Unknown item"; handler->PSendSysMessage(alternateString ? LANG_COMMAND_NPC_SHOWLOOT_ENTRY_2 : LANG_COMMAND_NPC_SHOWLOOT_ENTRY, itemCount, ItemQualityColors[itemTemplate ? static_cast(itemTemplate->GetQuality()) : ITEM_QUALITY_POOR], itemId, name, itemId); } static void _IterateNotNormalLootMap(ChatHandler* handler, NotNormalLootItemMap const& map, std::vector const& items) { for (NotNormalLootItemMap::value_type const& pair : map) { if (!pair.second) continue; Player const* player = ObjectAccessor::FindConnectedPlayer(pair.first); handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_SUBLABEL, player ? player->GetName() : Trinity::StringFormat("Offline player (GUID %s)", pair.first.ToString()).c_str(), pair.second->size()); for (auto it = pair.second->cbegin(); it != pair.second->cend(); ++it) { LootItem const& item = items[it->index]; if (!(it->is_looted) && !item.is_looted) _ShowLootEntry(handler, item.itemid, item.count, true); } } } static bool HandleNpcShowLootCommand(ChatHandler* handler, char const* args) { Creature* creatureTarget = handler->getSelectedCreature(); if (!creatureTarget || creatureTarget->IsPet()) { handler->PSendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } Loot const& loot = creatureTarget->loot; if (!creatureTarget->isDead() || loot.empty()) { handler->PSendSysMessage(LANG_COMMAND_NOT_DEAD_OR_NO_LOOT, creatureTarget->GetName()); handler->SetSentErrorMessage(true); return false; } handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_HEADER, creatureTarget->GetName(), creatureTarget->GetEntry()); handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_MONEY, loot.gold / GOLD, (loot.gold%GOLD) / SILVER, loot.gold%SILVER); if (strcmp(args, "all")) // nonzero from strcmp <-> not equal { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot.items.size()); for (LootItem const& item : loot.items) if (!item.is_looted) _ShowLootEntry(handler, item.itemid, item.count); handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Quest items", loot.quest_items.size()); for (LootItem const& item : loot.quest_items) if (!item.is_looted) _ShowLootEntry(handler, item.itemid, item.count); } else { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot.items.size()); for (LootItem const& item : loot.items) if (!item.is_looted && !item.freeforall && item.conditions.empty()) _ShowLootEntry(handler, item.itemid, item.count); if (!loot.GetPlayerQuestItems().empty()) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player quest items"); _IterateNotNormalLootMap(handler, loot.GetPlayerQuestItems(), loot.quest_items); } if (!loot.GetPlayerFFAItems().empty()) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "FFA items per allowed player"); _IterateNotNormalLootMap(handler, loot.GetPlayerFFAItems(), loot.items); } if (!loot.GetPlayerNonQuestNonFFAConditionalItems().empty()) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player conditional items"); _IterateNotNormalLootMap(handler, loot.GetPlayerNonQuestNonFFAConditionalItems(), loot.items); } } 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(); WorldDatabasePreparedStatement* 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(); }