mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
1290 lines
46 KiB
C++
1290 lines
46 KiB
C++
/*
|
|
* This file is part of the AzerothCore 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 Affero General Public License as published by the
|
|
* Free Software Foundation; either version 3 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 Affero 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/>.
|
|
*/
|
|
|
|
#include "Chat.h"
|
|
#include "CommandScript.h"
|
|
#include "CreatureAI.h"
|
|
#include "CreatureGroups.h"
|
|
#include "GameTime.h"
|
|
#include "Language.h"
|
|
#include "ObjectMgr.h"
|
|
#include "Pet.h"
|
|
#include "Player.h"
|
|
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
|
#include "Transport.h"
|
|
#include <string>
|
|
|
|
using namespace Acore::ChatCommands;
|
|
|
|
using CreatureSpawnId = Variant<Hyperlink<creature>, ObjectGuid::LowType>;
|
|
using CreatureEntry = Variant<Hyperlink<creature_entry>, uint32>;
|
|
|
|
struct NpcFlagText
|
|
{
|
|
uint32 flag;
|
|
int32 text;
|
|
};
|
|
|
|
#define NPCFLAG_COUNT 24
|
|
|
|
NpcFlagText const npcFlagTexts[NPCFLAG_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 }
|
|
};
|
|
|
|
struct MechanicImmune
|
|
{
|
|
uint32 flag;
|
|
char const* text;
|
|
};
|
|
|
|
MechanicImmune const mechanicImmunes[MAX_MECHANIC] =
|
|
{
|
|
{ MECHANIC_NONE, "MECHANIC_NONE" },
|
|
{ MECHANIC_CHARM, "MECHANIC_CHARM" },
|
|
{ MECHANIC_DISORIENTED, "MECHANIC_DISORIENTED" },
|
|
{ MECHANIC_DISARM, "MECHANIC_DISARM" },
|
|
{ MECHANIC_DISTRACT, "MECHANIC_DISTRACT" },
|
|
{ MECHANIC_FEAR, "MECHANIC_FEAR" },
|
|
{ MECHANIC_GRIP, "MECHANIC_GRIP" },
|
|
{ MECHANIC_ROOT, "MECHANIC_ROOT" },
|
|
{ MECHANIC_SLOW_ATTACK, "MECHANIC_SLOW_ATTACK" },
|
|
{ MECHANIC_SILENCE, "MECHANIC_SILENCE" },
|
|
{ MECHANIC_SLEEP, "MECHANIC_SLEEP" },
|
|
{ MECHANIC_SNARE, "MECHANIC_SNARE" },
|
|
{ MECHANIC_STUN, "MECHANIC_STUN" },
|
|
{ MECHANIC_FREEZE, "MECHANIC_FREEZE" },
|
|
{ MECHANIC_KNOCKOUT, "MECHANIC_KNOCKOUT" },
|
|
{ MECHANIC_BLEED, "MECHANIC_BLEED" },
|
|
{ MECHANIC_BANDAGE, "MECHANIC_BANDAGE" },
|
|
{ MECHANIC_POLYMORPH, "MECHANIC_POLYMORPH" },
|
|
{ MECHANIC_BANISH, "MECHANIC_BANISH" },
|
|
{ MECHANIC_SHIELD, "MECHANIC_SHIELD" },
|
|
{ MECHANIC_SHACKLE, "MECHANIC_SHACKLE" },
|
|
{ MECHANIC_MOUNT, "MECHANIC_MOUNT" },
|
|
{ MECHANIC_INFECTED, "MECHANIC_INFECTED" },
|
|
{ MECHANIC_TURN, "MECHANIC_TURN" },
|
|
{ MECHANIC_HORROR, "MECHANIC_HORROR" },
|
|
{ MECHANIC_INVULNERABILITY, "MECHANIC_INVULNERABILITY" },
|
|
{ MECHANIC_INTERRUPT, "MECHANIC_INTERRUPT" },
|
|
{ MECHANIC_DAZE, "MECHANIC_DAZE" },
|
|
{ MECHANIC_DISCOVERY, "MECHANIC_DISCOVERY" },
|
|
{ MECHANIC_IMMUNE_SHIELD, "MECHANIC_IMMUNE_SHIELD" },
|
|
{ MECHANIC_SAPPED, "MECHANIC_SAPPED" },
|
|
{ MECHANIC_ENRAGED, "MECHANIC_ENRAGED" },
|
|
};
|
|
|
|
struct SpellSchoolImmune
|
|
{
|
|
uint32 flag;
|
|
char const* text;
|
|
};
|
|
|
|
SpellSchoolImmune const spellSchoolImmunes[MAX_SPELL_SCHOOL] =
|
|
{
|
|
{ SPELL_SCHOOL_NORMAL, "SPELL_SCHOOL_NORMAL" },
|
|
{ SPELL_SCHOOL_HOLY, "SPELL_SCHOOL_HOLY" },
|
|
{ SPELL_SCHOOL_FIRE, "SPELL_SCHOOL_FIRE" },
|
|
{ SPELL_SCHOOL_NATURE, "SPELL_SCHOOL_NATURE" },
|
|
{ SPELL_SCHOOL_FROST, "SPELL_SCHOOL_FROST" },
|
|
{ SPELL_SCHOOL_SHADOW, "SPELL_SCHOOL_SHADOW" },
|
|
{ SPELL_SCHOOL_ARCANE, "SPELL_SCHOOL_ARCANE" },
|
|
};
|
|
|
|
class npc_commandscript : public CommandScript
|
|
{
|
|
public:
|
|
npc_commandscript() : CommandScript("npc_commandscript") { }
|
|
|
|
ChatCommandTable GetCommands() const override
|
|
{
|
|
static ChatCommandTable npcAddCommandTable =
|
|
{
|
|
{ "formation", HandleNpcAddFormationCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "item", HandleNpcAddVendorItemCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "move", HandleNpcAddMoveCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "temp", HandleNpcAddTempSpawnCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "", HandleNpcAddCommand, SEC_ADMINISTRATOR, Console::No }
|
|
};
|
|
static ChatCommandTable npcDeleteCommandTable =
|
|
{
|
|
{ "item", HandleNpcDeleteVendorItemCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "", HandleNpcDeleteCommand, SEC_ADMINISTRATOR, Console::No }
|
|
};
|
|
static ChatCommandTable npcFollowCommandTable =
|
|
{
|
|
{ "stop", HandleNpcUnFollowCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "", HandleNpcFollowCommand, SEC_GAMEMASTER, Console::No }
|
|
};
|
|
|
|
static ChatCommandTable npcFactionCommandTable =
|
|
{
|
|
{ "permanent", HandleNpcSetFactionIdCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "temp", HandleNpcSetFactionTempIdCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "original", HandleNpcSetOriginalFaction, SEC_ADMINISTRATOR, Console::No }
|
|
};
|
|
|
|
static ChatCommandTable npcSetCommandTable =
|
|
{
|
|
{ "allowmove", HandleNpcSetAllowMovementCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "entry", HandleNpcSetEntryCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "faction", npcFactionCommandTable},
|
|
{ "flag", HandleNpcSetFlagCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "level", HandleNpcSetLevelCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "link", HandleNpcSetLinkCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "model", HandleNpcSetModelCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "movetype", HandleNpcSetMoveTypeCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "phase", HandleNpcSetPhaseCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "wanderdistance", HandleNpcSetWanderDistanceCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "spawntime", HandleNpcSetSpawnTimeCommand, SEC_ADMINISTRATOR, Console::No },
|
|
{ "data", HandleNpcSetDataCommand, SEC_ADMINISTRATOR, Console::No }
|
|
};
|
|
static ChatCommandTable npcCommandTable =
|
|
{
|
|
{ "info", HandleNpcInfoCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "guid", HandleNpcGuidCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "near", HandleNpcNearCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "move", HandleNpcMoveCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "playemote", HandleNpcPlayEmoteCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "say", HandleNpcSayCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "textemote", HandleNpcTextEmoteCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "whisper", HandleNpcWhisperCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "yell", HandleNpcYellCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "tame", HandleNpcTameCommand, SEC_GAMEMASTER, Console::No },
|
|
{ "add", npcAddCommandTable },
|
|
{ "delete", npcDeleteCommandTable },
|
|
{ "follow", npcFollowCommandTable },
|
|
{ "set", npcSetCommandTable }
|
|
};
|
|
static ChatCommandTable commandTable =
|
|
{
|
|
{ "npc", npcCommandTable }
|
|
};
|
|
return commandTable;
|
|
}
|
|
|
|
//add spawn of creature
|
|
static bool HandleNpcAddCommand(ChatHandler* handler, CreatureEntry id)
|
|
{
|
|
if (!sObjectMgr->GetCreatureTemplate(id))
|
|
return false;
|
|
|
|
Player* chr = handler->GetSession()->GetPlayer();
|
|
float x = chr->GetPositionX();
|
|
float y = chr->GetPositionY();
|
|
float z = chr->GetPositionZ();
|
|
float o = chr->GetOrientation();
|
|
Map* map = chr->GetMap();
|
|
|
|
if (Transport* tt = chr->GetTransport())
|
|
if (MotionTransport* trans = tt->ToMotionTransport())
|
|
{
|
|
ObjectGuid::LowType guid = sObjectMgr->GenerateCreatureSpawnId();
|
|
CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
|
|
data.id1 = id;
|
|
data.phaseMask = chr->GetPhaseMaskForSpawn();
|
|
data.posX = chr->GetTransOffsetX();
|
|
data.posY = chr->GetTransOffsetY();
|
|
data.posZ = chr->GetTransOffsetZ();
|
|
data.orientation = chr->GetTransOffsetO();
|
|
|
|
Creature* creature = trans->CreateNPCPassenger(guid, &data);
|
|
|
|
creature->SaveToDB(trans->GetGOInfo()->moTransport.mapID, 1 << map->GetSpawnMode(), chr->GetPhaseMaskForSpawn());
|
|
|
|
sObjectMgr->AddCreatureToGrid(guid, &data);
|
|
return true;
|
|
}
|
|
|
|
Creature* creature = new Creature();
|
|
if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, 0, x, y, z, o))
|
|
{
|
|
delete creature;
|
|
return false;
|
|
}
|
|
|
|
creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
|
|
|
|
ObjectGuid::LowType spawnId = 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 = new Creature();
|
|
if (!creature->LoadCreatureFromDB(spawnId, map, true, true))
|
|
{
|
|
delete creature;
|
|
return false;
|
|
}
|
|
|
|
sObjectMgr->AddCreatureToGrid(spawnId, sObjectMgr->GetCreatureData(spawnId));
|
|
return true;
|
|
}
|
|
|
|
//add item in vendorlist
|
|
static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, ItemTemplate const* item, Optional<uint32> mc, Optional<uint32> it, Optional<uint32> ec, Optional<bool> addMulti)
|
|
{
|
|
if (!item)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_NEEDITEMSEND);
|
|
return false;
|
|
}
|
|
|
|
Creature* vendor = handler->getSelectedCreature();
|
|
if (!vendor)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
uint32 itemId = item->ItemId;
|
|
uint32 maxcount = mc.value_or(0);
|
|
uint32 incrtime = it.value_or(0);
|
|
uint32 extendedcost = ec.value_or(0);
|
|
uint32 vendor_entry = addMulti.value_or(false) ? handler->GetSession()->GetCurrentVendor() : vendor->GetEntry();
|
|
|
|
if (!sObjectMgr->IsVendorItemValid(vendor_entry, itemId, maxcount, incrtime, extendedcost, handler->GetSession()->GetPlayer()))
|
|
{
|
|
handler->SetSentErrorMessage(true);
|
|
return false;
|
|
}
|
|
|
|
sObjectMgr->AddVendorItem(vendor_entry, itemId, maxcount, incrtime, extendedcost);
|
|
|
|
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, item->Name1, maxcount, incrtime, extendedcost);
|
|
return true;
|
|
}
|
|
|
|
//add move for creature
|
|
static bool HandleNpcAddMoveCommand(ChatHandler* handler, CreatureSpawnId lowGuid)
|
|
{
|
|
// attempt check creature existence by DB data
|
|
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
|
|
if (!data)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_CREATGUIDNOTFOUND, uint32(lowGuid));
|
|
return false;
|
|
}
|
|
|
|
// Update movement type
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE);
|
|
stmt->SetData(0, uint8(WAYPOINT_MOTION_TYPE));
|
|
stmt->SetData(1, uint32(lowGuid));
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler)
|
|
{
|
|
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, CreatureEntry newEntryNum)
|
|
{
|
|
if (!newEntryNum)
|
|
return false;
|
|
|
|
Unit* unit = handler->getSelectedUnit();
|
|
if (!unit || !unit->IsCreature())
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
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, uint8 lvl)
|
|
{
|
|
if (lvl < 1 || lvl > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
|
|
{
|
|
handler->SendErrorMessage(LANG_BAD_VALUE);
|
|
return false;
|
|
}
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature || creature->IsPet())
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->SetMaxHealth(100 + 30*lvl);
|
|
creature->SetHealth(100 + 30*lvl);
|
|
creature->SetLevel(lvl);
|
|
creature->SaveToDB();
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcDeleteCommand(ChatHandler* handler, Optional<ObjectGuid::LowType> lowGuid)
|
|
{
|
|
Creature* creature;
|
|
if (lowGuid.has_value())
|
|
creature = handler->GetCreatureFromPlayerMapByDbGuid(*lowGuid);
|
|
else
|
|
creature = handler->getSelectedCreature();
|
|
|
|
if (!creature || creature->IsPet() || creature->IsTotem())
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
// Delete the creature
|
|
creature->CombatStop();
|
|
creature->DeleteFromDB();
|
|
creature->AddObjectToRemoveList();
|
|
|
|
handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
|
|
|
|
return true;
|
|
}
|
|
|
|
//del item from vendor list
|
|
static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, ItemTemplate const* item, Optional<bool> addMulti)
|
|
{
|
|
Creature* vendor = handler->getSelectedCreature();
|
|
if (!vendor || !vendor->IsVendor())
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_VENDORSELECTION);
|
|
return false;
|
|
}
|
|
|
|
if (!item)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_NEEDITEMSEND);
|
|
return false;
|
|
}
|
|
|
|
uint32 itemId = item->ItemId;
|
|
if (!sObjectMgr->RemoveVendorItem(addMulti.value_or(false) ? handler->GetSession()->GetCurrentVendor() : vendor->GetEntry(), itemId))
|
|
{
|
|
handler->SendErrorMessage(LANG_ITEM_NOT_IN_LIST, itemId);
|
|
return false;
|
|
}
|
|
|
|
handler->PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST, itemId, item->Name1);
|
|
return true;
|
|
}
|
|
|
|
//set faction of creature
|
|
static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, uint32 factionId)
|
|
{
|
|
if (!sFactionTemplateStore.LookupEntry(factionId))
|
|
{
|
|
handler->SendErrorMessage(LANG_WRONG_FACTION, factionId);
|
|
return false;
|
|
}
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
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
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION);
|
|
|
|
stmt->SetData(0, uint16(factionId));
|
|
stmt->SetData(1, creature->GetEntry());
|
|
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
return true;
|
|
}
|
|
|
|
//set tempfaction for creature
|
|
static bool HandleNpcSetFactionTempIdCommand(ChatHandler* handler, uint32 tempfaction)
|
|
{
|
|
Player* player = handler->GetSession()->GetPlayer();
|
|
Unit* unit = player->GetSelectedUnit();
|
|
|
|
if (!unit)
|
|
return false;
|
|
|
|
Creature* creature = unit->ToCreature();
|
|
|
|
if (!creature)
|
|
return false;
|
|
|
|
creature->SetFaction(tempfaction);
|
|
|
|
return true;
|
|
}
|
|
|
|
//set orginal faction for npc
|
|
static bool HandleNpcSetOriginalFaction(ChatHandler* handler)
|
|
{
|
|
Player* player = handler->GetSession()->GetPlayer();
|
|
|
|
if (!player)
|
|
return false;
|
|
|
|
if (!player->GetSelectedUnit())
|
|
return false;
|
|
|
|
Creature* creature = player->GetSelectedUnit()->ToCreature();
|
|
|
|
if (!creature)
|
|
return false;
|
|
|
|
creature->RestoreFaction();
|
|
|
|
return true;
|
|
}
|
|
|
|
//set npcflag of creature
|
|
static bool HandleNpcSetFlagCommand(ChatHandler* handler, uint32 npcFlags)
|
|
{
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->ReplaceAllNpcFlags(NPCFlags(npcFlags));
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG);
|
|
|
|
stmt->SetData(0, NPCFlags(npcFlags));
|
|
stmt->SetData(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, uint32 data_1, uint32 data_2)
|
|
{
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
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(), creature->GetEntry(), creature->GetName(), data_1, data_2, AIorScript);
|
|
return true;
|
|
}
|
|
|
|
//npc follow handling
|
|
static bool HandleNpcFollowCommand(ChatHandler* handler)
|
|
{
|
|
Player* player = handler->GetSession()->GetPlayer();
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
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());
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcInfoCommand(ChatHandler* handler)
|
|
{
|
|
Creature* target = handler->getSelectedCreature();
|
|
|
|
if (!target)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
CreatureTemplate const* cInfo = target->GetCreatureTemplate();
|
|
uint32 faction = target->GetFaction();
|
|
uint32 npcflags = target->GetNpcFlags();
|
|
uint32 mechanicImmuneMask = cInfo->MechanicImmuneMask;
|
|
uint32 spellSchoolImmuneMask = cInfo->SpellSchoolImmuneMask;
|
|
uint32 displayid = target->GetDisplayId();
|
|
uint32 nativeid = target->GetNativeDisplayId();
|
|
uint32 entry = target->GetEntry();
|
|
uint32 id1 = 0;
|
|
uint32 id2 = 0;
|
|
uint32 id3 = 0;
|
|
if (CreatureData const* cData = target->GetCreatureData())
|
|
{
|
|
id1 = cData->id1;
|
|
id2 = cData->id2;
|
|
id3 = cData->id3;
|
|
}
|
|
|
|
int64 curRespawnDelay = target->GetRespawnTimeEx() - GameTime::GetGameTime().count();
|
|
if (curRespawnDelay < 0)
|
|
curRespawnDelay = 0;
|
|
std::string curRespawnDelayStr = secsToTimeString(uint64(curRespawnDelay), true);
|
|
std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(), true);
|
|
|
|
handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetSpawnId(), target->GetGUID().ToString(), entry, id1, id2, id3, displayid, nativeid, faction, npcflags);
|
|
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->GetLevel());
|
|
handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId());
|
|
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
|
|
handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUnitFlags(), target->GetUnitFlags2(), target->GetDynamicFlags(), target->GetFaction());
|
|
handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr, curRespawnDelayStr);
|
|
handler->PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId);
|
|
handler->PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId());
|
|
handler->PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask());
|
|
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
|
|
handler->PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ()));
|
|
handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName(), target->GetScriptName());
|
|
|
|
for (uint8 i = 0; i < NPCFLAG_COUNT; i++)
|
|
{
|
|
if (npcflags & npcFlagTexts[i].flag)
|
|
{
|
|
handler->PSendSysMessage(npcFlagTexts[i].text, npcFlagTexts[i].flag);
|
|
}
|
|
}
|
|
|
|
handler->PSendSysMessage(LANG_NPCINFO_MECHANIC_IMMUNE, mechanicImmuneMask);
|
|
for (uint8 i = 1; i < MAX_MECHANIC; ++i)
|
|
{
|
|
if (mechanicImmuneMask & (1 << (mechanicImmunes[i].flag - 1)))
|
|
{
|
|
handler->PSendSysMessage(mechanicImmunes[i].text, mechanicImmunes[i].flag);
|
|
}
|
|
}
|
|
|
|
handler->PSendSysMessage(LANG_NPCINFO_SPELL_SCHOOL_IMMUNE, spellSchoolImmuneMask);
|
|
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
|
{
|
|
if (spellSchoolImmuneMask & (1 << spellSchoolImmunes[i].flag))
|
|
{
|
|
handler->PSendSysMessage(spellSchoolImmunes[i].text, spellSchoolImmunes[i].flag);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static bool HandleNpcGuidCommand(ChatHandler* handler)
|
|
{
|
|
Creature* target = handler->getSelectedCreature();
|
|
|
|
if (!target)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
uint32 faction = target->GetFaction();
|
|
uint32 npcflags = target->GetNpcFlags();
|
|
uint32 displayid = target->GetDisplayId();
|
|
uint32 nativeid = target->GetNativeDisplayId();
|
|
uint32 entry = target->GetEntry();
|
|
uint32 id1 = 0;
|
|
uint32 id2 = 0;
|
|
uint32 id3 = 0;
|
|
if (CreatureData const* cData = target->GetCreatureData())
|
|
{
|
|
id1 = cData->id1;
|
|
id2 = cData->id2;
|
|
id3 = cData->id3;
|
|
}
|
|
|
|
handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetSpawnId(), target->GetGUID().ToString(), entry, id1, id2, id3, displayid, nativeid, faction, npcflags);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcNearCommand(ChatHandler* handler, Optional<float> dist)
|
|
{
|
|
float distance = dist.value_or(10.0f);
|
|
uint32 count = 0;
|
|
|
|
Player* player = handler->GetSession()->GetPlayer();
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_NEAREST);
|
|
stmt->SetData(0, player->GetPositionX());
|
|
stmt->SetData(1, player->GetPositionY());
|
|
stmt->SetData(2, player->GetPositionZ());
|
|
stmt->SetData(3, player->GetMapId());
|
|
stmt->SetData(4, player->GetPositionX());
|
|
stmt->SetData(5, player->GetPositionY());
|
|
stmt->SetData(6, player->GetPositionZ());
|
|
stmt->SetData(7, distance * distance);
|
|
stmt->SetData(8, player->GetPhaseMask());
|
|
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
|
|
|
if (result)
|
|
{
|
|
do
|
|
{
|
|
Field* fields = result->Fetch();
|
|
ObjectGuid::LowType guid = fields[0].Get<uint32>();
|
|
uint32 entry = fields[1].Get<uint32>();
|
|
//uint32 entry2 = fields[2].Get<uint32>();
|
|
//uint32 entry3 = fields[3].Get<uint32>();
|
|
float x = fields[4].Get<float>();
|
|
float y = fields[5].Get<float>();
|
|
float z = fields[6].Get<float>();
|
|
uint16 mapId = fields[7].Get<uint16>();
|
|
|
|
CreatureTemplate const* creatureTemplate = sObjectMgr->GetCreatureTemplate(entry);
|
|
if (!creatureTemplate)
|
|
continue;
|
|
|
|
handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, entry, guid, creatureTemplate->Name, 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, Optional<ObjectGuid::LowType> guid)
|
|
{
|
|
Creature* creature;
|
|
if (guid.has_value())
|
|
creature = handler->GetCreatureFromPlayerMapByDbGuid(*guid);
|
|
else
|
|
creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
return false;
|
|
|
|
ObjectGuid::LowType lowGuid;
|
|
if (guid.has_value())
|
|
lowGuid = *guid;
|
|
else
|
|
lowGuid = creature->GetSpawnId();
|
|
|
|
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
|
|
if (!data)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
|
|
return false;
|
|
}
|
|
|
|
if (handler->GetSession()->GetPlayer()->GetMapId() != data->mapid)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowGuid);
|
|
return false;
|
|
}
|
|
|
|
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(DeathState::JustDied);
|
|
creature->Respawn();
|
|
}
|
|
}
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION);
|
|
stmt->SetData(0, x);
|
|
stmt->SetData(1, y);
|
|
stmt->SetData(2, z);
|
|
stmt->SetData(3, o);
|
|
stmt->SetData(4, lowGuid);
|
|
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
|
|
return true;
|
|
}
|
|
|
|
//play npc emote
|
|
static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, uint32 emote)
|
|
{
|
|
Creature* target = handler->getSelectedCreature();
|
|
if (!target)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote);
|
|
|
|
return true;
|
|
}
|
|
|
|
//set model of creature
|
|
static bool HandleNpcSetModelCommand(ChatHandler* handler, uint32 displayId)
|
|
{
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature || creature->IsPet())
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
if (!sCreatureDisplayInfoStore.LookupEntry(displayId))
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, Acore::ToString(displayId).c_str());
|
|
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 wander_distance </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, Optional<CreatureSpawnId> lowGuid, Variant<EXACT_SEQUENCE("stay"), EXACT_SEQUENCE("random"), EXACT_SEQUENCE("way")> type, Optional<EXACT_SEQUENCE("nodel")> nodel)
|
|
{
|
|
// 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)
|
|
|
|
bool doNotDelete = nodel.has_value();
|
|
|
|
ObjectGuid::LowType lowguid = 0;
|
|
Creature* creature = nullptr;
|
|
|
|
if (!lowGuid) // case .setmovetype $move_type (with selected creature)
|
|
{
|
|
creature = handler->getSelectedCreature();
|
|
if (!creature || creature->IsPet())
|
|
return false;
|
|
lowguid = creature->GetSpawnId();
|
|
}
|
|
else // case .setmovetype #creature_guid $move_type (with selected creature)
|
|
{
|
|
lowguid = *lowGuid;
|
|
|
|
if (lowguid)
|
|
creature = handler->GetCreatureFromPlayerMapByDbGuid(lowguid);
|
|
|
|
// attempt check creature existence by DB data
|
|
if (!creature)
|
|
{
|
|
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
|
|
if (!data)
|
|
{
|
|
handler->SendErrorMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
|
|
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;
|
|
switch (type.index())
|
|
{
|
|
case 0:
|
|
move_type = IDLE_MOTION_TYPE;
|
|
break;
|
|
case 1:
|
|
move_type = RANDOM_MOTION_TYPE;
|
|
break;
|
|
case 2:
|
|
move_type = WAYPOINT_MOTION_TYPE;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
// update movement type
|
|
//if (doNotDelete == false)
|
|
// WaypointMgr.DeletePath(lowguid);
|
|
|
|
if (creature)
|
|
{
|
|
// update movement type
|
|
if (!doNotDelete)
|
|
creature->LoadPath(0);
|
|
|
|
creature->SetDefaultMovementType(move_type);
|
|
creature->GetMotionMaster()->Initialize();
|
|
|
|
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
|
|
{
|
|
creature->setDeathState(DeathState::JustDied);
|
|
creature->Respawn();
|
|
}
|
|
|
|
creature->SaveToDB();
|
|
}
|
|
|
|
if (!doNotDelete)
|
|
{
|
|
handler->PSendSysMessage(LANG_MOVE_TYPE_SET, move_type);
|
|
}
|
|
else
|
|
{
|
|
handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, move_type);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//npc phasemask handling
|
|
//change phasemask of creature or pet
|
|
static bool HandleNpcSetPhaseCommand(ChatHandler* handler, uint32 phasemask)
|
|
{
|
|
if (phasemask == 0)
|
|
{
|
|
handler->SendErrorMessage(LANG_BAD_VALUE);
|
|
return false;
|
|
}
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->SetPhaseMask(phasemask, true);
|
|
|
|
if (!creature->IsPet())
|
|
creature->SaveToDB();
|
|
|
|
return true;
|
|
}
|
|
|
|
//set spawn dist of creature
|
|
static bool HandleNpcSetWanderDistanceCommand(ChatHandler* handler, float option)
|
|
{
|
|
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 = 0;
|
|
|
|
if (creature)
|
|
guidLow = creature->GetSpawnId();
|
|
else
|
|
return false;
|
|
|
|
creature->SetWanderDistance((float)option);
|
|
creature->SetDefaultMovementType(mtype);
|
|
creature->GetMotionMaster()->Initialize();
|
|
|
|
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
|
|
{
|
|
creature->setDeathState(DeathState::JustDied);
|
|
creature->Respawn();
|
|
}
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_WANDER_DISTANCE);
|
|
|
|
stmt->SetData(0, option);
|
|
stmt->SetData(1, uint8(mtype));
|
|
stmt->SetData(2, guidLow);
|
|
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
handler->PSendSysMessage(LANG_COMMAND_WANDER_DISTANCE, option);
|
|
return true;
|
|
}
|
|
|
|
//spawn time handling
|
|
static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, std::string spawnTimeStr)
|
|
{
|
|
if (spawnTimeStr.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Acore::StringTo<int32>(spawnTimeStr).value_or(0) < 0)
|
|
{
|
|
handler->SendErrorMessage(LANG_BAD_VALUE);
|
|
return false;
|
|
}
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature)
|
|
return false;
|
|
|
|
int32 spawnTime = TimeStringToSecs(spawnTimeStr);
|
|
if (spawnTime <= 0)
|
|
{
|
|
spawnTime = Acore::StringTo<int32>(spawnTimeStr).value_or(0);
|
|
}
|
|
|
|
if (spawnTime <= 0)
|
|
{
|
|
handler->SendErrorMessage(LANG_BAD_VALUE);
|
|
return false;
|
|
}
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS);
|
|
stmt->SetData(0, spawnTime);
|
|
stmt->SetData(1, creature->GetSpawnId());
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
creature->SetRespawnDelay(spawnTime);
|
|
handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, secsToTimeString(spawnTime, true));
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcSayCommand(ChatHandler* handler, Tail text)
|
|
{
|
|
if (text.empty())
|
|
return false;
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->Say(text, LANG_UNIVERSAL);
|
|
|
|
// make some emotes
|
|
switch (text.back())
|
|
{
|
|
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, Tail text)
|
|
{
|
|
if (text.empty())
|
|
return false;
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->TextEmote(text);
|
|
|
|
return true;
|
|
}
|
|
|
|
//npc unfollow handling
|
|
static bool HandleNpcUnFollowCommand(ChatHandler* handler)
|
|
{
|
|
Player* player = handler->GetSession()->GetPlayer();
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
if (/*creature->GetMotionMaster()->empty() ||*/
|
|
creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE)
|
|
{
|
|
handler->SendErrorMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
|
|
return false;
|
|
}
|
|
|
|
FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
|
|
|
|
if (mgen->GetTarget() != player)
|
|
{
|
|
handler->SendErrorMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName().c_str());
|
|
return false;
|
|
}
|
|
|
|
// reset movement
|
|
creature->GetMotionMaster()->MovementExpired(true);
|
|
|
|
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
|
|
return true;
|
|
}
|
|
|
|
// make npc whisper to player
|
|
static bool HandleNpcWhisperCommand(ChatHandler* handler, std::string const& recv, Tail text)
|
|
{
|
|
if (text.empty())
|
|
return false;
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
// check online security
|
|
Player* receiver = ObjectAccessor::FindPlayerByName(recv);
|
|
if (handler->HasLowerSecurity(receiver, ObjectGuid::Empty))
|
|
return false;
|
|
|
|
creature->Whisper(text, LANG_UNIVERSAL, receiver);
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcYellCommand(ChatHandler* handler, Tail text)
|
|
{
|
|
if (text.empty())
|
|
return false;
|
|
|
|
Creature* creature = handler->getSelectedCreature();
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
creature->Yell(text, LANG_UNIVERSAL);
|
|
|
|
// make an emote
|
|
creature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT);
|
|
|
|
return true;
|
|
}
|
|
|
|
// add creature, temp only
|
|
static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, CreatureEntry id)
|
|
{
|
|
Player* chr = handler->GetSession()->GetPlayer();
|
|
|
|
if (!id)
|
|
return false;
|
|
|
|
chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120);
|
|
|
|
return true;
|
|
}
|
|
|
|
//npc tame handling
|
|
static bool HandleNpcTameCommand(ChatHandler* handler)
|
|
{
|
|
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->IsExistPet())
|
|
{
|
|
handler->SendErrorMessage(LANG_YOU_ALREADY_HAVE_PET);
|
|
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;
|
|
}
|
|
|
|
if (!player->CreatePet(creatureTarget))
|
|
{
|
|
handler->SendErrorMessage(LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcAddFormationCommand(ChatHandler* handler, ObjectGuid::LowType leaderGUID)
|
|
{
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature || !creature->GetSpawnId())
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
ObjectGuid::LowType lowguid = creature->GetSpawnId();
|
|
if (creature->GetFormation())
|
|
{
|
|
handler->PSendSysMessage("Selected creature is already member of group {}", creature->GetFormation()->GetId());
|
|
return false;
|
|
}
|
|
|
|
if (!lowguid)
|
|
return false;
|
|
|
|
Player* chr = handler->GetSession()->GetPlayer();
|
|
FormationInfo group_member;
|
|
group_member.follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI;
|
|
group_member.follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - creature->GetPositionY(), int(2)));
|
|
group_member.leaderGUID = leaderGUID;
|
|
group_member.groupAI = 0;
|
|
|
|
sFormationMgr->CreatureGroupMap[lowguid] = group_member;
|
|
creature->SearchFormation();
|
|
|
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
|
|
stmt->SetData(0, leaderGUID);
|
|
stmt->SetData(1, lowguid);
|
|
stmt->SetData(2, group_member.follow_dist);
|
|
stmt->SetData(3, group_member.follow_angle);
|
|
stmt->SetData(4, uint32(group_member.groupAI));
|
|
|
|
WorldDatabase.Execute(stmt);
|
|
|
|
handler->PSendSysMessage("Creature {} added to formation with leader {}", lowguid, leaderGUID);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool HandleNpcSetLinkCommand(ChatHandler* handler, ObjectGuid::LowType linkguid)
|
|
{
|
|
Creature* creature = handler->getSelectedCreature();
|
|
|
|
if (!creature)
|
|
{
|
|
handler->SendErrorMessage(LANG_SELECT_CREATURE);
|
|
return false;
|
|
}
|
|
|
|
if (!creature->GetSpawnId())
|
|
{
|
|
handler->SendErrorMessage("Selected creature {} isn't in creature table", creature->GetGUID().ToString());
|
|
return false;
|
|
}
|
|
|
|
if (!sObjectMgr->SetCreatureLinkedRespawn(creature->GetSpawnId(), linkguid))
|
|
{
|
|
handler->SendErrorMessage("Selected creature can't link with guid '{}'", linkguid);
|
|
return false;
|
|
}
|
|
|
|
handler->PSendSysMessage("LinkGUID '{}' added to creature with DBTableGUID: '{}'", linkguid, creature->GetSpawnId());
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void AddSC_npc_commandscript()
|
|
{
|
|
new npc_commandscript();
|
|
}
|