diff options
| author | r00ty-tc <r00ty-tc@users.noreply.github.com> | 2017-05-07 21:48:41 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2020-08-22 12:59:57 +0200 |
| commit | 03b125e6d1947258316c931499746696a95aded2 (patch) | |
| tree | 34d7ebc57cd3669d6d1a118e1491d3ecf353470a /src/server/scripts/Commands | |
| parent | bf5be2839652e038eeb87c9fa301fd9dd6de8982 (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.cpp | 23 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_gobject.cpp | 59 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_list.cpp | 141 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 12 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_npc.cpp | 184 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_wp.cpp | 8 |
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); |
