Files
Viano-Core/src/server/scripts/Commands/cs_npc.cpp
T
Machiavelli dbbac0bdaa Core/Movement: Implement spline movement subsystem.
Spline movement controls movements of server-side controlled units (monster movement, taxi movement, etc).
Proper implementation of effects such as charge, jump, cyclic movement will rely on it.
However, need improve our states system before.

Technical changes:

* Added linear, catmullrom and bezier3 splines which based on client's algorthims. They can be reused for proper transport position interpolation.
* Precission increased. There are no more position desync issues since client's position calculation formulas used.
* Now possible to move by paths with multiple points, send whole path to client.

--
Original author of research and implementation: SilverIce. Massive kudos.
Original port for Trinity (ref #4629) Chaplain and Venugh
With the following incremental fixes during my review:

- Restore flightmaster end grid pre-loading
- Fix uninitialized Creature::m_path_id
- Add missing trinity_string entries for .movegens command
- Fix a bug in WaypointMovementGenerator that would trigger unexpected pausing at waypoints for various amounts of time

Known issues:
- Errors like WaypointMovementGenerator::LoadPath creature XXX (Entry: YYYYY GUID: ZZZZZZ) doesn't have waypoint path id: 0.
This is caused by bad DB data. This commit didn't "break" it.

Do not forget to re-run CMake before compiling.
2012-01-14 15:36:07 +01:00

1450 lines
48 KiB
C++

/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
Name: npc_commandscript
%Complete: 100
Comment: All npc related commands
Category: commandscripts
EndScriptData */
#include "ScriptMgr.h"
#include "ObjectMgr.h"
#include "Chat.h"
#include "Transport.h"
#include "CreatureGroups.h"
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
class npc_commandscript : public CommandScript
{
public:
npc_commandscript() : CommandScript("npc_commandscript") { }
ChatCommand* GetCommands() const
{
static ChatCommand npcAddCommandTable[] =
{
{ "formation", SEC_MODERATOR, false, &HandleNpcAddFormationCommand, "", NULL },
{ "item", SEC_GAMEMASTER, false, &HandleNpcAddVendorItemCommand, "", NULL },
{ "move", SEC_GAMEMASTER, false, &HandleNpcAddMoveCommand, "", NULL },
{ "temp", SEC_GAMEMASTER, false, &HandleNpcAddTempSpawnCommand, "", NULL },
//{ TODO: fix or remove this command
{ "weapon", SEC_ADMINISTRATOR, false, &HandleNpcAddWeaponCommand, "", NULL },
//}
{ "", SEC_GAMEMASTER, false, &HandleNpcAddCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand npcDeleteCommandTable[] =
{
{ "item", SEC_GAMEMASTER, false, &HandleNpcDeleteVendorItemCommand, "", NULL },
{ "", SEC_GAMEMASTER, false, &HandleNpcDeleteCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand npcFollowCommandTable[] =
{
{ "stop", SEC_GAMEMASTER, false, &HandleNpcUnFollowCommand, "", NULL },
{ "", SEC_GAMEMASTER, false, &HandleNpcFollowCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand npcSetCommandTable[] =
{
{ "allowmove", SEC_ADMINISTRATOR, false, &HandleNpcSetAllowMovementCommand, "", NULL },
{ "entry", SEC_ADMINISTRATOR, false, &HandleNpcSetEntryCommand, "", NULL },
{ "factionid", SEC_GAMEMASTER, false, &HandleNpcSetFactionIdCommand, "", NULL },
{ "flag", SEC_GAMEMASTER, false, &HandleNpcSetFlagCommand, "", NULL },
{ "level", SEC_GAMEMASTER, false, &HandleNpcSetLevelCommand, "", NULL },
{ "link", SEC_GAMEMASTER, false, &HandleNpcSetLinkCommand, "", NULL },
{ "model", SEC_GAMEMASTER, false, &HandleNpcSetModelCommand, "", NULL },
{ "movetype", SEC_GAMEMASTER, false, &HandleNpcSetMoveTypeCommand, "", NULL },
{ "phase", SEC_GAMEMASTER, false, &HandleNpcSetPhaseCommand, "", NULL },
{ "spawndist", SEC_GAMEMASTER, false, &HandleNpcSetSpawnDistCommand, "", NULL },
{ "spawntime", SEC_GAMEMASTER, false, &HandleNpcSetSpawnTimeCommand, "", NULL },
//{ TODO: fix or remove these commands
{ "name", SEC_GAMEMASTER, false, &HandleNpcSetNameCommand, "", NULL },
{ "subname", SEC_GAMEMASTER, false, &HandleNpcSetSubNameCommand, "", NULL },
//}
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand npcCommandTable[] =
{
{ "info", SEC_ADMINISTRATOR, false, &HandleNpcInfoCommand, "", NULL },
{ "move", SEC_GAMEMASTER, false, &HandleNpcMoveCommand, "", NULL },
{ "playemote", SEC_ADMINISTRATOR, false, &HandleNpcPlayEmoteCommand, "", NULL },
{ "say", SEC_MODERATOR, false, &HandleNpcSayCommand, "", NULL },
{ "textemote", SEC_MODERATOR, false, &HandleNpcTextEmoteCommand, "", NULL },
{ "whisper", SEC_MODERATOR, false, &HandleNpcWhisperCommand, "", NULL },
{ "yell", SEC_MODERATOR, false, &HandleNpcYellCommand, "", NULL },
{ "tame", SEC_GAMEMASTER, false, &HandleNpcTameCommand, "", NULL },
{ "add", SEC_GAMEMASTER, false, NULL, "", npcAddCommandTable },
{ "delete", SEC_GAMEMASTER, false, NULL, "", npcDeleteCommandTable },
{ "follow", SEC_GAMEMASTER, false, NULL, "", npcFollowCommandTable },
{ "set", SEC_GAMEMASTER, false, NULL, "", npcSetCommandTable },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
{
{ "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
{ NULL, 0, false, NULL, "", NULL }
};
return commandTable;
}
//add spawn of creature
static bool HandleNpcAddCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry");
if (!charID)
return false;
char* team = strtok(NULL, " ");
int32 teamval = 0;
if (team) { teamval = atoi(team); }
if (teamval < 0) { teamval = 0; }
uint32 id = atoi(charID);
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 (chr->GetTransport())
{
uint32 tguid = chr->GetTransport()->AddNPCPassenger(0, id, chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());
if (tguid > 0)
WorldDatabase.PQuery("INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (%u, %u, %f, %f, %f, %f, %u)", tguid, id, chr->GetTransport()->GetEntry(), chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());
return true;
}
Creature* creature = new Creature;
if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o))
{
delete creature;
return false;
}
creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn());
uint32 db_guid = creature->GetDBTableGUIDLow();
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
if (!creature->LoadCreatureFromDB(db_guid, map))
{
delete 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;
char* pitem = handler->extractKeyFromLink((char*)args, "Hitem");
if (!pitem)
{
handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
handler->SetSentErrorMessage(true);
return false;
}
int32 item_int = atol(pitem);
if (item_int <= 0)
return false;
uint32 itemId = item_int;
char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0
uint32 maxcount = 0;
if (fmaxcount)
maxcount = atol(fmaxcount);
char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0
uint32 incrtime = 0;
if (fincrtime)
incrtime = atol(fincrtime);
char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0
uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0;
Creature* vendor = handler->getSelectedCreature();
if (!vendor)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
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);
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_LIST, itemId, itemTemplate->Name1.c_str(), maxcount, incrtime, extendedcost);
return true;
}
//add move for creature
static bool HandleNpcAddMoveCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
char* guidStr = strtok((char*)args, " ");
char* waitStr = strtok((char*)NULL, " ");
uint32 lowGuid = atoi((char*)guidStr);
Creature* creature = NULL;
/* FIXME: impossible without entry
if (lowguid)
creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
*/
// attempt check creature existence by DB data
if (!creature)
{
CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid);
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
// obtain real GUID for DB operations
lowGuid = creature->GetDBTableGUIDLow();
}
int wait = waitStr ? atoi(waitStr) : 0;
if (wait < 0)
wait = 0;
// Update movement type
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE);
stmt->setUInt8(0, uint8(WAYPOINT_MOTION_TYPE));
stmt->setUInt32(1, lowGuid);
WorldDatabase.Execute(stmt);
if (creature && creature->GetWaypointPath())
{
creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
creature->GetMotionMaster()->Initialize();
if (creature->isAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn(true);
}
creature->SaveToDB();
}
handler->SendSysMessage(LANG_WAYPOINT_ADDED);
return true;
}
static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler, const char* /*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, const char* args)
{
if (!*args)
return false;
uint32 newEntryNum = atoi(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, const char* args)
{
if (!*args)
return false;
uint8 lvl = (uint8) atoi((char*)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)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (creature->isPet())
{
if (((Pet*)creature)->getPetType() == HUNTER_PET)
{
creature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr->GetXPForLevel(lvl)/4);
creature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
}
((Pet*)creature)->GivePetLevel(lvl);
}
else
{
creature->SetMaxHealth(100 + 30*lvl);
creature->SetHealth(100 + 30*lvl);
creature->SetLevel(lvl);
creature->SaveToDB();
}
return true;
}
static bool HandleNpcDeleteCommand(ChatHandler* handler, const char* args)
{
Creature* unit = NULL;
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;
uint32 lowguid = atoi(cId);
if (!lowguid)
return false;
if (CreatureData const* cr_data = sObjectMgr->GetCreatureData(lowguid))
unit = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
}
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, const char* 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 = atol(pitem);
if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId))
{
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->Name1.c_str());
return true;
}
//set faction of creature
static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 factionId = (uint32) atoi((char*)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->GetCreatureInfo())
{
const_cast<CreatureTemplate*>(cinfo)->faction_A = factionId;
const_cast<CreatureTemplate*>(cinfo)->faction_H = factionId;
}
// ..and DB
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_FACTION);
stmt->setUInt16(0, uint16(factionId));
stmt->setUInt16(1, uint16(factionId));
stmt->setUInt32(2, creature->GetEntry());
WorldDatabase.Execute(stmt);
return true;
}
//set npcflag of creature
static bool HandleNpcSetFlagCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 npcFlags = (uint32) atoi((char*)args);
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG);
stmt->setUInt32(0, npcFlags);
stmt->setUInt32(1, creature->GetEntry());
WorldDatabase.Execute(stmt);
handler->SendSysMessage(LANG_VALUE_SAVED_REJOIN);
return true;
}
//npc follow handling
static bool HandleNpcFollowCommand(ChatHandler* handler, const char* /*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());
return true;
}
static bool HandleNpcInfoCommand(ChatHandler* handler, const char* /*args*/)
{
Creature* target = handler->getSelectedCreature();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 faction = target->getFaction();
uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS);
uint32 displayid = target->GetDisplayId();
uint32 nativeid = target->GetNativeDisplayId();
uint32 Entry = target->GetEntry();
CreatureTemplate const* cInfo = target->GetCreatureInfo();
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, target->GetDBTableGUIDLow(), target->GetGUIDLow(), faction, npcflags, Entry, displayid, nativeid);
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel());
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction());
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());
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().c_str(), target->GetScriptName().c_str());
if (npcflags & UNIT_NPC_FLAG_VENDOR)
handler->SendSysMessage(LANG_NPCINFO_VENDOR);
if (npcflags & UNIT_NPC_FLAG_TRAINER)
handler->SendSysMessage(LANG_NPCINFO_TRAINER);
return true;
}
//move selected creature
static bool HandleNpcMoveCommand(ChatHandler* handler, const char* args)
{
uint32 lowguid = 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 = atoi(cId);
/* FIXME: impossible without entry
if (lowguid)
creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
*/
// Attempting creature load from DB data
if (!creature)
{
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
handler->SetSentErrorMessage(true);
return false;
}
uint32 map_id = data->mapid;
if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
{
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
lowguid = creature->GetDBTableGUIDLow();
}
}
else
{
lowguid = creature->GetDBTableGUIDLow();
}
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->GetDBTableGUIDLow()))
{
const_cast<CreatureData*>(data)->posX = x;
const_cast<CreatureData*>(data)->posY = y;
const_cast<CreatureData*>(data)->posZ = z;
const_cast<CreatureData*>(data)->orientation = o;
}
creature->SetPosition(x, y, z, o);
creature->GetMotionMaster()->Initialize();
if (creature->isAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn();
}
}
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_POSITION);
stmt->setFloat(0, x);
stmt->setFloat(1, y);
stmt->setFloat(2, z);
stmt->setFloat(3, o);
stmt->setUInt32(4, lowguid);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
return true;
}
//play npc emote
static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, const char* args)
{
uint32 emote = atoi((char*)args);
Creature* target = handler->getSelectedCreature();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (target->GetTransport())
if (target->GetGUIDTransport())
WorldDatabase.PQuery("UPDATE creature_transport SET emote=%u WHERE transport_entry=%u AND guid=%u", emote, target->GetTransport()->GetEntry(), target->GetGUIDTransport());
target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote);
return true;
}
//set model of creature
static bool HandleNpcSetModelCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 displayId = (uint32) atoi((char*)args);
Creature* creature = handler->getSelectedCreature();
if (!creature || creature->isPet())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetDisplayId(displayId);
creature->SetNativeDisplayId(displayId);
creature->SaveToDB();
return true;
}
/**HandleNpcSetMoveTypeCommand
* Set the movement type for an NPC.<br/>
* <br/>
* Valid movement types are:
* <ul>
* <li> stay - NPC wont move </li>
* <li> random - NPC will move randomly according to the spawndist </li>
* <li> way - NPC will move with given waypoints set </li>
* </ul>
* additional parameter: NODEL - so no waypoints are deleted, if you
* change the movement type
*/
static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, const char* 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*)NULL, " ");
char* dontdel_str = strtok((char*)NULL, " ");
bool doNotDelete = false;
if (!guid_str)
return false;
uint32 lowguid = 0;
Creature* creature = NULL;
if (dontdel_str)
{
//sLog->outError("DEBUG: All 3 params are set");
// All 3 params are set
// GUID
// type
// doNotDEL
if (stricmp(dontdel_str, "NODEL") == 0)
{
//sLog->outError("DEBUG: doNotDelete = true;");
doNotDelete = true;
}
}
else
{
// Only 2 params - but maybe NODEL is set
if (type_str)
{
sLog->outError("DEBUG: Only 2 params ");
if (stricmp(type_str, "NODEL") == 0)
{
//sLog->outError("DEBUG: type_str, NODEL ");
doNotDelete = true;
type_str = NULL;
}
}
}
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->GetDBTableGUIDLow();
}
else // case .setmovetype #creature_guid $move_type (with selected creature)
{
lowguid = atoi((char*)guid_str);
/* impossible without entry
if (lowguid)
creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT));
*/
// attempt check creature existence by DB data
if (!creature)
{
CreatureData const* data = sObjectMgr->GetCreatureData(lowguid);
if (!data)
{
handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
handler->SetSentErrorMessage(true);
return false;
}
}
else
{
lowguid = creature->GetDBTableGUIDLow();
}
}
// now lowguid is low guid really existed creature
// and creature point (maybe) to this creature or NULL
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 phasemask handling
//change phasemask of creature or pet
static bool HandleNpcSetPhaseCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 phasemask = (uint32) atoi((char*)args);
if (phasemask == 0)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->SetPhaseMask(phasemask, true);
if (!creature->isPet())
creature->SaveToDB();
return true;
}
//set spawn dist of creature
static bool HandleNpcSetSpawnDistCommand(ChatHandler* handler, const char* 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();
uint32 guidLow = 0;
if (creature)
guidLow = creature->GetDBTableGUIDLow();
else
return false;
creature->SetRespawnRadius((float)option);
creature->SetDefaultMovementType(mtype);
creature->GetMotionMaster()->Initialize();
if (creature->isAlive()) // dead creature will reset movement generator at respawn
{
creature->setDeathState(JUST_DIED);
creature->Respawn();
}
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE);
stmt->setFloat(0, option);
stmt->setUInt8(1, uint8(mtype));
stmt->setUInt32(2, guidLow);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_SPAWNDIST, option);
return true;
}
//spawn time handling
static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
char* stime = strtok((char*)args, " ");
if (!stime)
return false;
int spawnTime = atoi((char*)stime);
if (spawnTime < 0)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
Creature* creature = handler->getSelectedCreature();
uint32 guidLow = 0;
if (creature)
guidLow = creature->GetDBTableGUIDLow();
else
return false;
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS);
stmt->setUInt32(0, uint32(spawnTime));
stmt->setUInt32(1, guidLow);
WorldDatabase.Execute(stmt);
creature->SetRespawnDelay((uint32)spawnTime);
handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, spawnTime);
return true;
}
static bool HandleNpcSayCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->MonsterSay(args, LANG_UNIVERSAL, 0);
// 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, const char* args)
{
if (!*args)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->MonsterTextEmote(args, 0);
return true;
}
//npc unfollow handling
static bool HandleNpcUnFollowCommand(ChatHandler* handler, const char* /*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());
handler->SetSentErrorMessage(true);
return false;
}
FollowMovementGenerator<Creature> const* mgen = static_cast<FollowMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
if (mgen->GetTarget() != player)
{
handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName());
handler->SetSentErrorMessage(true);
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, const char* args)
{
if (!*args)
return false;
char* receiver_str = strtok((char*)args, " ");
char* text = strtok(NULL, "");
uint64 guid = handler->GetSession()->GetPlayer()->GetSelection();
Creature* creature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(guid);
if (!creature || !receiver_str || !text)
{
return false;
}
uint64 receiver_guid= atol(receiver_str);
// check online security
if (handler->HasLowerSecurity(ObjectAccessor::FindPlayer(receiver_guid), 0))
return false;
creature->MonsterWhisper(text, receiver_guid);
return true;
}
static bool HandleNpcYellCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
creature->MonsterYell(args, LANG_UNIVERSAL, 0);
// make an emote
creature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT);
return true;
}
// add creature, temp only
static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
char* charID = strtok((char*)args, " ");
if (!charID)
return false;
Player* chr = handler->GetSession()->GetPlayer();
uint32 id = atoi(charID);
if (!id)
return false;
chr->SummonCreature(id, *chr, TEMPSUMMON_CORPSE_DESPAWN, 120);
return true;
}
//npc tame handling
static bool HandleNpcTameCommand(ChatHandler* handler, const char* /*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 ())
{
handler->SendSysMessage (LANG_YOU_ALREADY_HAVE_PET);
handler->SetSentErrorMessage (true);
return false;
}
CreatureTemplate const* cInfo = creatureTarget->GetCreatureInfo();
if (!cInfo->isTameable (player->CanTameExoticPets()))
{
handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
handler->SetSentErrorMessage (true);
return false;
}
// Everything looks OK, create new pet
Pet* pet = player->CreateTamedPetFrom(creatureTarget);
if (!pet)
{
handler->PSendSysMessage (LANG_CREATURE_NON_TAMEABLE, cInfo->Entry);
handler->SetSentErrorMessage (true);
return false;
}
// place pet before player
float x, y, z;
player->GetClosePoint (x, y, z, creatureTarget->GetObjectSize (), CONTACT_DISTANCE);
pet->Relocate (x, y, z, M_PI-player->GetOrientation ());
// set pet to defensive mode by default (some classes can't control controlled pets in fact).
pet->SetReactState(REACT_DEFENSIVE);
// calculate proper level
uint8 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel();
// prepare visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
// add to world
pet->GetMap()->AddToMap(pet->ToCreature());
// visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
// caster have pet now
player->SetMinion(pet, true);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
player->PetSpellInitialize();
return true;
}
static bool HandleNpcAddFormationCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 leaderGUID = (uint32) atoi((char*)args);
Creature* creature = handler->getSelectedCreature();
if (!creature || !creature->GetDBTableGUIDLow())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 lowguid = creature->GetDBTableGUIDLow();
if (creature->GetFormation())
{
handler->PSendSysMessage("Selected creature is already member of group %u", 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 / 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;
CreatureGroupMap[lowguid] = group_member;
creature->SearchFormation();
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION);
stmt->setUInt32(0, leaderGUID);
stmt->setUInt32(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 %u added to formation with leader %u", lowguid, leaderGUID);
return true;
}
static bool HandleNpcSetLinkCommand(ChatHandler* handler, const char* args)
{
if (!*args)
return false;
uint32 linkguid = (uint32) atoi((char*)args);
Creature* creature = handler->getSelectedCreature();
if (!creature)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
if (!creature->GetDBTableGUIDLow())
{
handler->PSendSysMessage("Selected creature %u isn't in creature table", creature->GetGUIDLow());
handler->SetSentErrorMessage(true);
return false;
}
if (!sObjectMgr->SetCreatureLinkedRespawn(creature->GetDBTableGUIDLow(), linkguid))
{
handler->PSendSysMessage("Selected creature can't link with guid '%u'", linkguid);
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage("LinkGUID '%u' added to creature with DBTableGUID: '%u'", linkguid, creature->GetDBTableGUIDLow());
return true;
}
//TODO: NpcCommands that need to be fixed :
static bool HandleNpcAddWeaponCommand(ChatHandler* /*handler*/, const char* /*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(NULL, " ");
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;
}
static bool HandleNpcSetNameCommand(ChatHandler* /*handler*/, const char* /*args*/)
{
/* Temp. disabled
if (!*args)
return false;
if (strlen((char*)args)>75)
{
handler->PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
return true;
}
for (uint8 i = 0; i < strlen(args); ++i)
{
if (!isalpha(args[i]) && args[i] != ' ')
{
handler->SendSysMessage(LANG_CHARS_ONLY);
return false;
}
}
uint64 guid;
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;
}
creature->SetName(args);
uint32 idname = sObjectMgr->AddCreatureTemplate(creature->GetName());
creature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
creature->SaveToDB();
*/
return true;
}
static bool HandleNpcSetSubNameCommand(ChatHandler* /*handler*/, const char* /*args*/)
{
/* Temp. disabled
if (!*args)
args = "";
if (strlen((char*)args)>75)
{
handler->PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
return true;
}
for (uint8 i = 0; i < strlen(args); i++)
{
if (!isalpha(args[i]) && args[i] != ' ')
{
handler->SendSysMessage(LANG_CHARS_ONLY);
return false;
}
}
uint64 guid;
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;
}
uint32 idname = sObjectMgr->AddCreatureSubName(creature->GetName(), args, creature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
creature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
creature->SaveToDB();
*/
return true;
}
};
void AddSC_npc_commandscript()
{
new npc_commandscript();
}