aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts/Commands
diff options
context:
space:
mode:
authorr00ty-tc <r00ty-tc@users.noreply.github.com>2017-05-07 21:48:41 +0100
committerShauren <shauren.trinity@gmail.com>2020-08-22 12:59:57 +0200
commit03b125e6d1947258316c931499746696a95aded2 (patch)
tree34d7ebc57cd3669d6d1a118e1491d3ecf353470a /src/server/scripts/Commands
parentbf5be2839652e038eeb87c9fa301fd9dd6de8982 (diff)
Dynamic Creature/Go spawning:
- True blizzlike creature spawn/respawn behavior - new creature = new object - Toggleable spawn groups (with C++/SAI/command options to use them) - Custom feature: dynamic spawn rate scaling. Accelerates respawn rate based on players in the zone. - Backward compatibility mode (set via group and for summons) to support creatures/gos that currently don't work well with this (this should be removed once the exceptions are fixed) Fixes and closes #2858 Tags #8661 as fixable. Fixes and closes #13787 Fixes #15222. (cherry picked from commit 59db2eeea0a35028779fd76372ae06cc98c8086f)
Diffstat (limited to 'src/server/scripts/Commands')
-rw-r--r--src/server/scripts/Commands/cs_go.cpp23
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp59
-rw-r--r--src/server/scripts/Commands/cs_list.cpp141
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp12
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp184
-rw-r--r--src/server/scripts/Commands/cs_wp.cpp8
6 files changed, 338 insertions, 89 deletions
diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp
index ec7b3e83cd0..1793cfdfbf8 100644
--- a/src/server/scripts/Commands/cs_go.cpp
+++ b/src/server/scripts/Commands/cs_go.cpp
@@ -161,7 +161,6 @@ public:
player->SaveRecallPosition();
player->TeleportTo(mapId, x, y, z, o);
-
return true;
}
@@ -272,28 +271,18 @@ public:
if (!guidLow)
return false;
- float x, y, z, o;
- uint32 mapId;
-
// by DB guid
- if (GameObjectData const* goData = sObjectMgr->GetGOData(guidLow))
- {
- x = goData->posX;
- y = goData->posY;
- z = goData->posZ;
- o = goData->orientation;
- mapId = goData->mapid;
- }
- else
+ GameObjectData const* goData = sObjectMgr->GetGameObjectData(guidLow);
+ if (!goData)
{
handler->SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND);
handler->SetSentErrorMessage(true);
return false;
}
-
- if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId))
+
+ if (!MapManager::IsValidMapCoord(goData->spawnPoint) || sObjectMgr->IsTransportMap(goData->spawnPoint.GetMapId()))
{
- handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId);
+ handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, goData->spawnPoint.GetPositionX(), goData->spawnPoint.GetPositionY(), goData->spawnPoint.GetMapId());
handler->SetSentErrorMessage(true);
return false;
}
@@ -308,7 +297,7 @@ public:
else
player->SaveRecallPosition();
- player->TeleportTo(mapId, x, y, z, o);
+ player->TeleportTo(goData->spawnPoint);
return true;
}
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 1a27c3f88f0..3160e659082 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -41,6 +41,10 @@ EndScriptData */
#include "WorldSession.h"
#include <sstream>
+// definitions are over in cs_npc.cpp
+bool HandleNpcSpawnGroup(ChatHandler* handler, char const* args);
+bool HandleNpcDespawnGroup(ChatHandler* handler, char const* args);
+
class gobject_commandscript : public CommandScript
{
public:
@@ -60,15 +64,17 @@ public:
};
static std::vector<ChatCommand> gobjectCommandTable =
{
- { "activate", rbac::RBAC_PERM_COMMAND_GOBJECT_ACTIVATE, false, &HandleGameObjectActivateCommand, "" },
- { "delete", rbac::RBAC_PERM_COMMAND_GOBJECT_DELETE, false, &HandleGameObjectDeleteCommand, "" },
- { "info", rbac::RBAC_PERM_COMMAND_GOBJECT_INFO, false, &HandleGameObjectInfoCommand, "" },
- { "move", rbac::RBAC_PERM_COMMAND_GOBJECT_MOVE, false, &HandleGameObjectMoveCommand, "" },
- { "near", rbac::RBAC_PERM_COMMAND_GOBJECT_NEAR, false, &HandleGameObjectNearCommand, "" },
- { "target", rbac::RBAC_PERM_COMMAND_GOBJECT_TARGET, false, &HandleGameObjectTargetCommand, "" },
- { "turn", rbac::RBAC_PERM_COMMAND_GOBJECT_TURN, false, &HandleGameObjectTurnCommand, "" },
- { "add", rbac::RBAC_PERM_COMMAND_GOBJECT_ADD, false, nullptr, "", gobjectAddCommandTable },
- { "set", rbac::RBAC_PERM_COMMAND_GOBJECT_SET, false, nullptr, "", gobjectSetCommandTable },
+ { "activate", rbac::RBAC_PERM_COMMAND_GOBJECT_ACTIVATE, false, &HandleGameObjectActivateCommand, "" },
+ { "delete", rbac::RBAC_PERM_COMMAND_GOBJECT_DELETE, false, &HandleGameObjectDeleteCommand, "" },
+ { "info", rbac::RBAC_PERM_COMMAND_GOBJECT_INFO, false, &HandleGameObjectInfoCommand, "" },
+ { "move", rbac::RBAC_PERM_COMMAND_GOBJECT_MOVE, false, &HandleGameObjectMoveCommand, "" },
+ { "near", rbac::RBAC_PERM_COMMAND_GOBJECT_NEAR, false, &HandleGameObjectNearCommand, "" },
+ { "target", rbac::RBAC_PERM_COMMAND_GOBJECT_TARGET, false, &HandleGameObjectTargetCommand, "" },
+ { "turn", rbac::RBAC_PERM_COMMAND_GOBJECT_TURN, false, &HandleGameObjectTurnCommand, "" },
+ { "spawngroup", rbac::RBAC_PERM_COMMAND_GOBJECT_SPAWNGROUP, false, &HandleNpcSpawnGroup, "" },
+ { "despawngroup", rbac::RBAC_PERM_COMMAND_GOBJECT_DESPAWNGROUP, false, &HandleNpcDespawnGroup,""},
+ { "add", rbac::RBAC_PERM_COMMAND_GOBJECT_ADD, false, nullptr, "", gobjectAddCommandTable },
+ { "set", rbac::RBAC_PERM_COMMAND_GOBJECT_SET, false, nullptr, "", gobjectSetCommandTable },
};
static std::vector<ChatCommand> commandTable =
{
@@ -172,7 +178,7 @@ public:
return false;
/// @todo is it really necessary to add both the real and DB table guid here ?
- sObjectMgr->AddGameobjectToGrid(spawnId, ASSERT_NOTNULL(sObjectMgr->GetGOData(spawnId)));
+ sObjectMgr->AddGameobjectToGrid(spawnId, ASSERT_NOTNULL(sObjectMgr->GetGameObjectData(spawnId)));
handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), std::to_string(spawnId).c_str(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
return true;
@@ -569,7 +575,7 @@ public:
if (!gameObjectInfo)
continue;
- handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gameObjectInfo->name.c_str(), x, y, z, mapId);
+ handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gameObjectInfo->name.c_str(), x, y, z, mapId, "", "");
++count;
} while (result->NextRow());
@@ -602,7 +608,7 @@ public:
if (!cValue)
return false;
ObjectGuid::LowType guidLow = atoull(cValue);
- const GameObjectData* data = sObjectMgr->GetGOData(guidLow);
+ GameObjectData const* data = sObjectMgr->GetGameObjectData(guidLow);
if (!data)
return false;
entry = data->id;
@@ -614,18 +620,47 @@ public:
GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate(entry);
+ GameObject* thisGO = nullptr;
+
if (!gameObjectInfo)
return false;
+ if (*args && handler->GetSession()->GetPlayer())
+ thisGO = handler->GetSession()->GetPlayer()->FindNearestGameObject(entry, 30);
+ else if (handler->getSelectedObject() && handler->getSelectedObject()->GetTypeId() == TYPEID_GAMEOBJECT)
+ thisGO = handler->getSelectedObject()->ToGameObject();
+
type = gameObjectInfo->type;
displayId = gameObjectInfo->displayId;
name = gameObjectInfo->name;
lootId = gameObjectInfo->GetLootId();
+ // If we have a real object, send some info about it
+ if (thisGO)
+ {
+ handler->PSendSysMessage(LANG_SPAWNINFO_GUIDINFO, thisGO->GetGUID().ToString().c_str());
+ handler->PSendSysMessage(LANG_SPAWNINFO_SPAWNID_LOCATION, std::to_string(thisGO->GetSpawnId()).c_str(), thisGO->GetPositionX(), thisGO->GetPositionY(), thisGO->GetPositionZ());
+ if (Player* player = handler->GetSession()->GetPlayer())
+ {
+ Position playerPos = player->GetPosition();
+ float dist = thisGO->GetExactDist(&playerPos);
+ handler->PSendSysMessage(LANG_SPAWNINFO_DISTANCEFROMPLAYER, dist);
+ }
+ }
handler->PSendSysMessage(LANG_GOINFO_ENTRY, entry);
handler->PSendSysMessage(LANG_GOINFO_TYPE, type);
handler->PSendSysMessage(LANG_GOINFO_LOOTID, lootId);
handler->PSendSysMessage(LANG_GOINFO_DISPLAYID, displayId);
+ if (WorldObject* object = handler->getSelectedObject())
+ {
+ if (object->ToGameObject() && object->ToGameObject()->GetGameObjectData() && object->ToGameObject()->GetGameObjectData()->spawnGroupData->groupId)
+ {
+ SpawnGroupTemplateData const* groupData = object->ToGameObject()->GetGameObjectData()->spawnGroupData;
+ handler->PSendSysMessage(LANG_SPAWNINFO_GROUP_ID, groupData->name.c_str(), groupData->groupId, groupData->flags, groupData->isActive);
+ }
+ if (object->ToGameObject())
+ handler->PSendSysMessage(LANG_SPAWNINFO_COMPATIBILITY_MODE, object->ToGameObject()->GetRespawnCompatibilityMode());
+ }
handler->PSendSysMessage(LANG_GOINFO_NAME, name.c_str());
handler->PSendSysMessage(LANG_GOINFO_SIZE, gameObjectInfo->size);
diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp
index 94e22efc94a..b332543864b 100644
--- a/src/server/scripts/Commands/cs_list.cpp
+++ b/src/server/scripts/Commands/cs_list.cpp
@@ -25,8 +25,12 @@ EndScriptData */
#include "ScriptMgr.h"
#include "CharacterCache.h"
#include "Chat.h"
+#include "Creature.h"
#include "DatabaseEnv.h"
+#include "DB2Stores.h"
+#include "GameObject.h"
#include "Language.h"
+#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
@@ -49,6 +53,7 @@ public:
{ "object", rbac::RBAC_PERM_COMMAND_LIST_OBJECT, true, &HandleListObjectCommand, "" },
{ "auras", rbac::RBAC_PERM_COMMAND_LIST_AURAS, false, &HandleListAurasCommand, "" },
{ "mail", rbac::RBAC_PERM_COMMAND_LIST_MAIL, true, &HandleListMailCommand, "" },
+ { "respawns", rbac::RBAC_PERM_COMMAND_LIST_MAIL, false, &HandleListRespawnsCommand, "" },
{ "scenes", rbac::RBAC_PERM_COMMAND_LIST_SCENES, false, &HandleListScenesCommand, "" },
};
static std::vector<ChatCommand> commandTable =
@@ -117,11 +122,40 @@ public:
float y = fields[2].GetFloat();
float z = fields[3].GetFloat();
uint16 mapId = fields[4].GetUInt16();
+ bool liveFound = false;
+ // Get map (only support base map from console)
+ Map* thisMap;
if (handler->GetSession())
- handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId);
+ thisMap = handler->GetSession()->GetPlayer()->GetMap();
else
- handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId);
+ thisMap = sMapMgr->FindBaseNonInstanceMap(mapId);
+
+ // If map found, try to find active version of this creature
+ if (thisMap)
+ {
+ auto const creBounds = thisMap->GetCreatureBySpawnIdStore().equal_range(guid);
+ if (creBounds.first != creBounds.second)
+ {
+ for (std::unordered_multimap<ObjectGuid::LowType, Creature*>::const_iterator itr = creBounds.first; itr != creBounds.second;)
+ {
+ if (handler->GetSession())
+ handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->IsAlive() ? "*" : " ");
+ else
+ handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->IsAlive() ? "*" : " ");
+ ++itr;
+ }
+ liveFound = true;
+ }
+ }
+
+ if (!liveFound)
+ {
+ if (handler->GetSession())
+ handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, std::to_string(guid).c_str(), std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, "", "");
+ else
+ handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, std::to_string(guid).c_str(), cInfo->Name.c_str(), x, y, z, mapId, "", "");
+ }
}
while (result->NextRow());
}
@@ -407,11 +441,40 @@ public:
float z = fields[3].GetFloat();
uint16 mapId = fields[4].GetUInt16();
uint32 entry = fields[5].GetUInt32();
+ bool liveFound = false;
+ // Get map (only support base map from console)
+ Map* thisMap;
if (handler->GetSession())
- handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId);
+ thisMap = handler->GetSession()->GetPlayer()->GetMap();
else
- handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId);
+ thisMap = sMapMgr->FindBaseNonInstanceMap(mapId);
+
+ // If map found, try to find active version of this object
+ if (thisMap)
+ {
+ auto const goBounds = thisMap->GetGameObjectBySpawnIdStore().equal_range(guid);
+ if (goBounds.first != goBounds.second)
+ {
+ for (std::unordered_multimap<ObjectGuid::LowType, GameObject*>::const_iterator itr = goBounds.first; itr != goBounds.second;)
+ {
+ if (handler->GetSession())
+ handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->isSpawned() ? "*" : " ");
+ else
+ handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->isSpawned() ? "*" : " ");
+ ++itr;
+ }
+ liveFound = true;
+ }
+ }
+
+ if (!liveFound)
+ {
+ if (handler->GetSession())
+ handler->PSendSysMessage(LANG_GO_LIST_CHAT, std::to_string(guid).c_str(), entry, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, "", "");
+ else
+ handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, std::to_string(guid).c_str(), gInfo->name.c_str(), x, y, z, mapId, "", "");
+ }
}
while (result->NextRow());
}
@@ -582,6 +645,76 @@ public:
return true;
}
+ static char const* GetZoneName(uint32 zoneId, LocaleConstant locale)
+ {
+ AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
+ return zoneEntry ? zoneEntry->AreaName[locale] : "<unknown zone>";
+ }
+ static bool HandleListRespawnsCommand(ChatHandler* handler, char const* args)
+ {
+ // We need a player
+ Player const* player = handler->GetSession()->GetPlayer();
+ if (!player)
+ return false;
+ // And we need a map
+ Map const* map = player->GetMap();
+ if (!map)
+ return false;
+
+ uint32 range = 0;
+ if (*args)
+ range = atoi((char*)args);
+
+ RespawnVector respawns;
+ LocaleConstant locale = handler->GetSession()->GetSessionDbcLocale();
+ char const* stringOverdue = sObjectMgr->GetTrinityString(LANG_LIST_RESPAWNS_OVERDUE, locale);
+ char const* stringCreature = sObjectMgr->GetTrinityString(LANG_LIST_RESPAWNS_CREATURES, locale);
+ char const* stringGameobject = sObjectMgr->GetTrinityString(LANG_LIST_RESPAWNS_GAMEOBJECTS, locale);
+
+ uint32 zoneId = player->GetZoneId();
+ if (range)
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_RANGE, stringCreature, range);
+ else
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_ZONE, stringCreature, GetZoneName(zoneId, handler->GetSessionDbcLocale()), zoneId);
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_LISTHEADER);
+ map->GetRespawnInfo(respawns, SPAWN_TYPEMASK_CREATURE, range ? 0 : zoneId);
+ for (RespawnInfo* ri : respawns)
+ {
+ CreatureData const* data = sObjectMgr->GetCreatureData(ri->spawnId);
+ if (!data)
+ continue;
+ if (range && !player->IsInDist(data->spawnPoint, range))
+ continue;
+ uint32 gridY = ri->gridId / MAX_NUMBER_OF_GRIDS;
+ uint32 gridX = ri->gridId % MAX_NUMBER_OF_GRIDS;
+
+ std::string respawnTime = ri->respawnTime > time(NULL) ? secsToTimeString(uint64(ri->respawnTime - time(NULL)), true) : stringOverdue;
+ handler->PSendSysMessage(UI64FMTD " | %u | [%02u,%02u] | %s (%u) | %s", ri->spawnId, ri->entry, gridX, gridY, GetZoneName(ri->zoneId, handler->GetSessionDbcLocale()), ri->zoneId, data->spawnGroupData->isActive ? respawnTime.c_str() : "inactive");
+ }
+
+ respawns.clear();
+ if (range)
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_RANGE, stringGameobject, range);
+ else
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_ZONE, stringGameobject, GetZoneName(zoneId, handler->GetSessionDbcLocale()), zoneId);
+ handler->PSendSysMessage(LANG_LIST_RESPAWNS_LISTHEADER);
+ map->GetRespawnInfo(respawns, SPAWN_TYPEMASK_GAMEOBJECT, range ? 0 : zoneId);
+ for (RespawnInfo* ri : respawns)
+ {
+ GameObjectData const* data = sObjectMgr->GetGameObjectData(ri->spawnId);
+ if (!data)
+ continue;
+ if (range && !player->IsInDist(data->spawnPoint, range))
+ continue;
+ uint32 gridY = ri->gridId / MAX_NUMBER_OF_GRIDS;
+ uint32 gridX = ri->gridId % MAX_NUMBER_OF_GRIDS;
+
+ std::string respawnTime = ri->respawnTime > time(NULL) ? secsToTimeString(uint64(ri->respawnTime - time(NULL)), true) : stringOverdue;
+ handler->PSendSysMessage(UI64FMTD " | %u | [% 02u, % 02u] | %s (%u) | %s", ri->spawnId, ri->entry, gridX, gridY, GetZoneName(ri->zoneId, handler->GetSessionDbcLocale()), ri->zoneId, data->spawnGroupData->isActive ? respawnTime.c_str() : "inactive");
+ }
+ return true;
+ }
+
static bool HandleListScenesCommand(ChatHandler* handler, char const* /*args*/)
{
Player* target = handler->getSelectedPlayer();
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 28e74d257d6..801d1da66e9 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -1958,10 +1958,22 @@ public:
return true;
}
+ // First handle any creatures that still have a corpse around
Trinity::RespawnDo u_do;
Trinity::WorldObjectWorker<Trinity::RespawnDo> worker(player, u_do);
Cell::VisitGridObjects(player, worker, player->GetGridActivationRange());
+ // Now handle any that had despawned, but had respawn time logged.
+ RespawnVector data;
+ player->GetMap()->GetRespawnInfo(data, SPAWN_TYPEMASK_ALL, 0);
+ if (!data.empty())
+ {
+ uint32 const gridId = Trinity::ComputeGridCoord(player->GetPositionX(), player->GetPositionY()).GetId();
+ for (RespawnInfo* info : data)
+ if (info->gridId == gridId)
+ player->GetMap()->RemoveRespawnTime(info, true);
+ }
+
return true;
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 7b59f796c40..2ccbb67f26a 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -206,6 +206,86 @@ EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
};
+bool HandleNpcSpawnGroup(ChatHandler* handler, char const* args)
+{
+ if (!*args)
+ return false;
+
+ bool ignoreRespawn = false;
+ bool force = false;
+ uint32 groupId = 0;
+
+ // Decode arguments
+ char* arg = strtok((char*)args, " ");
+ while (arg)
+ {
+ std::string thisArg = arg;
+ std::transform(thisArg.begin(), thisArg.end(), thisArg.begin(), ::tolower);
+ if (thisArg == "ignorerespawn")
+ ignoreRespawn = true;
+ else if (thisArg == "force")
+ force = true;
+ else if (thisArg.empty() || !(std::count_if(thisArg.begin(), thisArg.end(), ::isdigit) == (int)thisArg.size()))
+ return false;
+ else
+ groupId = atoi(thisArg.c_str());
+
+ arg = strtok(NULL, " ");
+ }
+
+ Player* player = handler->GetSession()->GetPlayer();
+
+ std::vector <WorldObject*> creatureList;
+ if (!sObjectMgr->SpawnGroupSpawn(groupId, player->GetMap(), ignoreRespawn, force, &creatureList))
+ {
+ handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_SPAWNGROUP_SPAWNCOUNT, creatureList.size());
+ for (WorldObject* obj : creatureList)
+ handler->PSendSysMessage("%s (%s)", obj->GetName(), obj->GetGUID().ToString().c_str());
+
+ return true;
+}
+
+bool HandleNpcDespawnGroup(ChatHandler* handler, char const* args)
+{
+ if (!*args)
+ return false;
+
+ bool deleteRespawnTimes = false;
+ uint32 groupId = 0;
+
+ // Decode arguments
+ char* arg = strtok((char*)args, " ");
+ while (arg)
+ {
+ std::string thisArg = arg;
+ std::transform(thisArg.begin(), thisArg.end(), thisArg.begin(), ::tolower);
+ if (thisArg == "removerespawntime")
+ deleteRespawnTimes = true;
+ else if (thisArg.empty() || !(std::count_if(thisArg.begin(), thisArg.end(), ::isdigit) == (int)thisArg.size()))
+ return false;
+ else
+ groupId = atoi(thisArg.c_str());
+
+ arg = strtok(nullptr, " ");
+ }
+
+ Player* player = handler->GetSession()->GetPlayer();
+
+ if (!sObjectMgr->SpawnGroupDespawn(groupId, player->GetMap(), deleteRespawnTimes))
+ {
+ handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+}
+
class npc_commandscript : public CommandScript
{
public:
@@ -250,21 +330,23 @@ public:
};
static std::vector<ChatCommand> npcCommandTable =
{
- { "info", rbac::RBAC_PERM_COMMAND_NPC_INFO, false, &HandleNpcInfoCommand, "" },
- { "near", rbac::RBAC_PERM_COMMAND_NPC_NEAR, false, &HandleNpcNearCommand, "" },
- { "move", rbac::RBAC_PERM_COMMAND_NPC_MOVE, false, &HandleNpcMoveCommand, "" },
- { "playemote", rbac::RBAC_PERM_COMMAND_NPC_PLAYEMOTE, false, &HandleNpcPlayEmoteCommand, "" },
- { "say", rbac::RBAC_PERM_COMMAND_NPC_SAY, false, &HandleNpcSayCommand, "" },
- { "textemote", rbac::RBAC_PERM_COMMAND_NPC_TEXTEMOTE, false, &HandleNpcTextEmoteCommand, "" },
- { "whisper", rbac::RBAC_PERM_COMMAND_NPC_WHISPER, false, &HandleNpcWhisperCommand, "" },
- { "yell", rbac::RBAC_PERM_COMMAND_NPC_YELL, false, &HandleNpcYellCommand, "" },
- { "tame", rbac::RBAC_PERM_COMMAND_NPC_TAME, false, &HandleNpcTameCommand, "" },
- { "add", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, nullptr, "", npcAddCommandTable },
- { "delete", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, nullptr, "", npcDeleteCommandTable },
- { "follow", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, nullptr, "", npcFollowCommandTable },
- { "set", rbac::RBAC_PERM_COMMAND_NPC_SET, false, nullptr, "", npcSetCommandTable },
- { "evade", rbac::RBAC_PERM_COMMAND_NPC_EVADE, false, &HandleNpcEvadeCommand, "" },
- { "showloot", rbac::RBAC_PERM_COMMAND_NPC_SHOWLOOT, false, &HandleNpcShowLootCommand, "" },
+ { "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, "" },
+ { "spawngroup", rbac::RBAC_PERM_COMMAND_NPC_SPAWNGROUP, false, &HandleNpcSpawnGroup, "" },
+ { "despawngroup", rbac::RBAC_PERM_COMMAND_NPC_DESPAWNGROUP, false, &HandleNpcDespawnGroup, "" },
+ { "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<ChatCommand> commandTable =
{
@@ -294,11 +376,9 @@ public:
{
ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Creature>();
CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
+ data.spawnId = guid;
data.id = id;
- data.posX = chr->GetTransOffsetX();
- data.posY = chr->GetTransOffsetY();
- data.posZ = chr->GetTransOffsetZ();
- data.orientation = chr->GetTransOffsetO();
+ data.spawnPoint.Relocate(chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO());
/// @todo: add phases
Creature* creature = trans->CreateNPCPassenger(guid, &data);
@@ -323,7 +403,7 @@ public:
creature->CleanupsBeforeDelete();
delete creature;
- creature = Creature::CreateCreatureFromDB(db_guid, map);
+ creature = Creature::CreateCreatureFromDB(db_guid, map, true, true);
if (!creature)
return false;
@@ -511,7 +591,7 @@ public:
static bool HandleNpcDeleteCommand(ChatHandler* handler, char const* args)
{
- Creature* unit = nullptr;
+ Creature* creature = nullptr;
if (*args)
{
@@ -523,22 +603,27 @@ public:
ObjectGuid::LowType lowguid = atoull(cId);
if (!lowguid)
return false;
- unit = handler->GetCreatureFromPlayerMapByDbGuid(lowguid);
+ creature = handler->GetCreatureFromPlayerMapByDbGuid(lowguid);
}
else
- unit = handler->getSelectedCreature();
+ creature = handler->getSelectedCreature();
- if (!unit || unit->IsPet() || unit->IsTotem())
+ if (!creature || creature->IsPet() || creature->IsTotem())
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
- // Delete the creature
- unit->CombatStop();
- unit->DeleteFromDB();
- unit->AddObjectToRemoveList();
+ if (TempSummon* summon = creature->ToTempSummon())
+ summon->UnSummon();
+ else
+ {
+ // Delete the creature
+ creature->CombatStop();
+ creature->DeleteFromDB();
+ creature->AddObjectToRemoveList();
+ }
handler->SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
@@ -734,13 +819,20 @@ public:
uint32 nativeid = target->GetNativeDisplayId();
uint32 Entry = target->GetEntry();
- int64 curRespawnDelay = target->GetRespawnTimeEx()-time(nullptr);
+ int64 curRespawnDelay = target->GetRespawnCompatibilityMode() ? target->GetRespawnTimeEx() - time(nullptr) : target->GetMap()->GetCreatureRespawnTime(target->GetSpawnId()) - time(nullptr);
+
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);
+ if (target->GetCreatureData() && target->GetCreatureData()->spawnGroupData->groupId)
+ {
+ if (SpawnGroupTemplateData const* groupData = target->GetCreatureData()->spawnGroupData)
+ handler->PSendSysMessage(LANG_SPAWNINFO_GROUP_ID, groupData->name.c_str(), groupData->groupId, groupData->flags, groupData->isActive);
+ }
+ handler->PSendSysMessage(LANG_SPAWNINFO_COMPATIBILITY_MODE, target->GetRespawnCompatibilityMode());
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());
@@ -827,7 +919,7 @@ public:
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);
+ 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;
}
@@ -845,6 +937,9 @@ public:
ObjectGuid::LowType lowguid = UI64LIT(0);
Creature* creature = handler->getSelectedCreature();
+ Player const* player = handler->GetSession()->GetPlayer();
+ if (!player)
+ return false;
if (!creature)
{
@@ -864,9 +959,7 @@ public:
return false;
}
- uint32 map_id = data->mapid;
-
- if (handler->GetSession()->GetPlayer()->GetMapId() != map_id)
+ if (player->GetMapId() != data->spawnPoint.GetMapId())
{
handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, std::to_string(lowguid).c_str());
handler->SetSentErrorMessage(true);
@@ -874,25 +967,12 @@ public:
}
}
else
- {
lowguid = creature->GetSpawnId();
- }
-
- float x = handler->GetSession()->GetPlayer()->GetPositionX();
- float y = handler->GetSession()->GetPlayer()->GetPositionY();
- float z = handler->GetSession()->GetPlayer()->GetPositionZ();
- float o = handler->GetSession()->GetPlayer()->GetOrientation();
if (creature)
{
- if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetSpawnId()))
- {
- const_cast<CreatureData*>(data)->posX = x;
- const_cast<CreatureData*>(data)->posY = y;
- const_cast<CreatureData*>(data)->posZ = z;
- const_cast<CreatureData*>(data)->orientation = o;
- }
- creature->UpdatePosition(x, y, z, o);
+ sObjectMgr->NewOrExistCreatureData(creature->GetSpawnId()).spawnPoint.Relocate(*player);
+ creature->UpdatePosition(*player);
creature->GetMotionMaster()->Initialize();
if (creature->IsAlive()) // dead creature will reset movement generator at respawn
{
@@ -903,10 +983,10 @@ public:
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->setFloat(0, player->GetPositionX());
+ stmt->setFloat(1, player->GetPositionY());
+ stmt->setFloat(2, player->GetPositionZ());
+ stmt->setFloat(3, player->GetOrientation());
stmt->setUInt64(4, lowguid);
WorldDatabase.Execute(stmt);
diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp
index 61c6c43d2b5..124708ffa24 100644
--- a/src/server/scripts/Commands/cs_wp.cpp
+++ b/src/server/scripts/Commands/cs_wp.cpp
@@ -683,7 +683,7 @@ public:
delete wpCreature;
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- wpCreature = Creature::CreateCreatureFromDB(dbGuid, map);
+ wpCreature = Creature::CreateCreatureFromDB(dbGuid, map, true, true);
if (!wpCreature)
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
@@ -901,7 +901,7 @@ public:
delete wpCreature;
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- wpCreature = Creature::CreateCreatureFromDB(dbGuid, map);
+ wpCreature = Creature::CreateCreatureFromDB(dbGuid, map, true, true);
if (!wpCreature)
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
@@ -969,7 +969,7 @@ public:
creature->CleanupsBeforeDelete();
delete creature;
- creature = Creature::CreateCreatureFromDB(dbGuid, map);
+ creature = Creature::CreateCreatureFromDB(dbGuid, map, true, true);
if (!creature)
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
@@ -1026,7 +1026,7 @@ public:
creature->CleanupsBeforeDelete();
delete creature;
- creature = Creature::CreateCreatureFromDB(dbGuid, map);
+ creature = Creature::CreateCreatureFromDB(dbGuid, map, true, true);
if (!creature)
{
handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);