diff options
Diffstat (limited to 'src/server/scripts')
14 files changed, 359 insertions, 126 deletions
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 69f7ecb3f9a..a7ac9028bc8 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -972,7 +972,7 @@ public: Map* map = handler->GetSession()->GetPlayer()->GetMap(); - if (!v->Create(map->GenerateLowGuid<HighGuid::Vehicle>(), map, handler->GetSession()->GetPlayer()->GetPhaseMask(), entry, x, y, z, o, nullptr, id)) + if (!v->Create(map->GenerateLowGuid<HighGuid::Vehicle>(), map, handler->GetSession()->GetPlayer()->GetPhaseMask(), entry, { x, y, z, o }, nullptr, id)) { delete v; return false; diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index 6a27060c2ed..2b8f89da7ac 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -138,8 +138,6 @@ public: float o = fields[3].GetFloat(); uint32 mapId = fields[4].GetUInt16(); - Transport* transport = nullptr; - if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); @@ -157,11 +155,7 @@ public: else player->SaveRecallPosition(); - if (player->TeleportTo(mapId, x, y, z, o)) - { - if (transport) - transport->AddPassenger(player); - } + player->TeleportTo(mapId, x, y, z, o); return true; } @@ -272,28 +266,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 +292,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 a315355ff44..46927a1c8f6 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -38,6 +38,10 @@ EndScriptData */ #include "RBAC.h" #include "WorldSession.h" +// 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: @@ -57,15 +61,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 = { @@ -169,14 +175,14 @@ public: object = new GameObject(); // this will generate a new guid if the object is in an instance - if (!object->LoadGameObjectFromDB(guidLow, map)) + if (!object->LoadFromDB(guidLow, map, true)) { delete object; return false; } /// @todo is it really necessary to add both the real and DB table guid here ? - sObjectMgr->AddGameobjectToGrid(guidLow, sObjectMgr->GetGOData(guidLow)); + sObjectMgr->AddGameobjectToGrid(guidLow, sObjectMgr->GetGameObjectData(guidLow)); handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), guidLow, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); return true; @@ -430,7 +436,7 @@ public: object->Delete(); object = new GameObject(); - if (!object->LoadGameObjectFromDB(guidLow, map)) + if (!object->LoadFromDB(guidLow, map, true)) { delete object; return false; @@ -499,7 +505,7 @@ public: object->Delete(); object = new GameObject(); - if (!object->LoadGameObjectFromDB(guidLow, map)) + if (!object->LoadFromDB(guidLow, map, true)) { delete object; return false; @@ -578,7 +584,7 @@ public: if (!gameObjectInfo) continue; - handler->PSendSysMessage(LANG_GO_LIST_CHAT, guid, entry, guid, gameObjectInfo->name.c_str(), x, y, z, mapId); + handler->PSendSysMessage(LANG_GO_LIST_CHAT, guid, entry, guid, gameObjectInfo->name.c_str(), x, y, z, mapId, "", ""); ++count; } while (result->NextRow()); @@ -611,7 +617,7 @@ public: if (!cValue) return false; ObjectGuid::LowType guidLow = atoul(cValue); - GameObjectData const* data = sObjectMgr->GetGOData(guidLow); + GameObjectData const* data = sObjectMgr->GetGameObjectData(guidLow); if (!data) return false; entry = data->id; @@ -623,9 +629,16 @@ 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; @@ -634,10 +647,32 @@ public: else if (type == GAMEOBJECT_TYPE_FISHINGHOLE) lootId = gameObjectInfo->fishinghole.lootId; + // 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, thisGO->GetSpawnId(), 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 8b502f60e11..ea57f29a771 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -27,7 +27,9 @@ EndScriptData */ #include "Chat.h" #include "DatabaseEnv.h" #include "DBCStores.h" +#include "GameObject.h" #include "Language.h" +#include "MapManager.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" @@ -50,6 +52,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, "" }, }; static std::vector<ChatCommand> commandTable = { @@ -117,11 +120,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, guid, guid, cInfo->Name.c_str(), x, y, z, mapId); + thisMap = handler->GetSession()->GetPlayer()->GetMap(); else - handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, guid, 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<uint32, Creature*>::const_iterator itr = creBounds.first; itr != creBounds.second;) + { + if (handler->GetSession()) + handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, cInfo->Name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->IsAlive() ? "*" : " "); + else + handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, guid, 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, guid, guid, cInfo->Name.c_str(), x, y, z, mapId, "", ""); + else + handler->PSendSysMessage(LANG_CREATURE_LIST_CONSOLE, guid, cInfo->Name.c_str(), x, y, z, mapId, "", ""); + } } while (result->NextRow()); } @@ -407,11 +439,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, guid, entry, guid, gInfo->name.c_str(), x, y, z, mapId); + thisMap = handler->GetSession()->GetPlayer()->GetMap(); else - handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, guid, 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<uint32, GameObject*>::const_iterator itr = goBounds.first; itr != goBounds.second;) + { + if (handler->GetSession()) + handler->PSendSysMessage(LANG_GO_LIST_CHAT, guid, entry, guid, gInfo->name.c_str(), x, y, z, mapId, itr->second->GetGUID().ToString().c_str(), itr->second->isSpawned() ? "*" : " "); + else + handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, guid, 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, guid, entry, guid, gInfo->name.c_str(), x, y, z, mapId, "", ""); + else + handler->PSendSysMessage(LANG_GO_LIST_CONSOLE, guid, gInfo->name.c_str(), x, y, z, mapId, "", ""); + } } while (result->NextRow()); } @@ -581,8 +642,79 @@ public: handler->PSendSysMessage(LANG_LIST_MAIL_NOT_FOUND); return true; } + + static char const* GetZoneName(uint32 zoneId, LocaleConstant locale) + { + AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId); + return zoneEntry ? zoneEntry->area_name[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("%u | %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("%u | %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; + } }; + void AddSC_list_commandscript() { new list_commandscript(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index f57d960d08a..dbf50d65640 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1911,10 +1911,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 dfb9ddb66a6..cf63419303d 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -176,6 +176,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: @@ -219,21 +299,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 = { @@ -257,22 +339,16 @@ public: return false; Player* chr = handler->GetSession()->GetPlayer(); - float x = chr->GetPositionX(); - float y = chr->GetPositionY(); - float z = chr->GetPositionZ(); - float o = chr->GetOrientation(); Map* map = chr->GetMap(); if (Transport* trans = chr->GetTransport()) { ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Unit>(); CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid); + data.spawnId = guid; data.id = id; data.phaseMask = chr->GetPhaseMaskForSpawn(); - 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()); Creature* creature = trans->CreateNPCPassenger(guid, &data); @@ -283,7 +359,7 @@ public: } Creature* creature = new Creature(); - if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, x, y, z, o)) + if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, *chr)) { delete creature; return false; @@ -298,7 +374,7 @@ public: creature->CleanupsBeforeDelete(); delete creature; creature = new Creature(); - if (!creature->LoadCreatureFromDB(db_guid, map)) + if (!creature->LoadFromDB(db_guid, map, true, true)) { delete creature; return false; @@ -473,7 +549,7 @@ public: static bool HandleNpcDeleteCommand(ChatHandler* handler, char const* args) { - Creature* unit = nullptr; + Creature* creature = nullptr; if (*args) { @@ -485,22 +561,27 @@ public: ObjectGuid::LowType lowguid = atoul(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); @@ -690,13 +771,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, target->GetSpawnId(), target->GetGUID().GetCounter(), faction, npcflags, 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(), target->GetMaxHealth(), target->GetHealth()); @@ -766,7 +854,7 @@ public: if (!creatureTemplate) continue; - handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, creatureTemplate->Name.c_str(), x, y, z, mapId); + handler->PSendSysMessage(LANG_CREATURE_LIST_CHAT, guid, guid, creatureTemplate->Name.c_str(), x, y, z, mapId, "", ""); ++count; } @@ -784,6 +872,9 @@ public: ObjectGuid::LowType lowguid = 0; Creature* creature = handler->getSelectedCreature(); + Player const* player = handler->GetSession()->GetPlayer(); + if (!player) + return false; if (!creature) { @@ -803,9 +894,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, lowguid); handler->SetSentErrorMessage(true); @@ -813,25 +902,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 { @@ -842,10 +918,10 @@ public: 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->setFloat(0, player->GetPositionX()); + stmt->setFloat(1, player->GetPositionY()); + stmt->setFloat(2, player->GetPositionZ()); + stmt->setFloat(3, player->GetOrientation()); stmt->setUInt32(4, lowguid); WorldDatabase.Execute(stmt); @@ -1529,13 +1605,13 @@ public: handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player quest items"); _IterateNotNormalLootMap(handler, loot.GetPlayerQuestItems(), loot.quest_items); } - + if (!loot.GetPlayerFFAItems().empty()) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "FFA items per allowed player"); _IterateNotNormalLootMap(handler, loot.GetPlayerFFAItems(), loot.items); } - + if (!loot.GetPlayerNonQuestNonFFAConditionalItems().empty()) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player conditional items"); diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index efd02314d0e..6298a34644f 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -662,7 +662,7 @@ public: // re-create Creature* wpCreature = new Creature(); - if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) + if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, *chr)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); delete wpCreature; @@ -671,8 +671,7 @@ public: wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - /// @todo Should we first use "Create" then use "LoadFromDB"? - if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map)) + if (!wpCreature->LoadFromDB(wpCreature->GetSpawnId(), map, true, true)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); delete wpCreature; @@ -874,7 +873,7 @@ public: float o = chr->GetOrientation(); Creature* wpCreature = new Creature(); - if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, x, y, z, o)) + if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, { x, y, z, o })) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete wpCreature; @@ -891,7 +890,7 @@ public: WorldDatabase.Execute(stmt); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map)) + if (!wpCreature->LoadFromDB(wpCreature->GetSpawnId(), map, true, true)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete wpCreature; @@ -937,7 +936,7 @@ public: Map* map = chr->GetMap(); Creature* creature = new Creature(); - if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, x, y, z, o)) + if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, { x, y, z, o })) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete creature; @@ -945,7 +944,7 @@ public: } creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - if (!creature->LoadCreatureFromDB(creature->GetSpawnId(), map)) + if (!creature->LoadFromDB(creature->GetSpawnId(), map, true, true)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete creature; @@ -986,7 +985,7 @@ public: Map* map = chr->GetMap(); Creature* creature = new Creature(); - if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, x, y, z, o)) + if (!creature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMaskForSpawn(), id, { x, y, z, o })) { handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); delete creature; @@ -994,7 +993,7 @@ public: } creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); - if (!creature->LoadCreatureFromDB(creature->GetSpawnId(), map)) + if (!creature->LoadFromDB(creature->GetSpawnId(), map, true, true)) { handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); delete creature; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 89bc369fd6f..d2cc08dcc6e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -264,7 +264,7 @@ class ValithriaDespawner : public BasicEvent creature->SetRespawnDelay(10); if (CreatureData const* data = creature->GetCreatureData()) - creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation); + creature->UpdatePosition(data->spawnPoint); creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index ed85ee3fa17..90d764cd9db 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -354,7 +354,7 @@ class FrostwingGauntletRespawner creature->SetRespawnDelay(2); if (CreatureData const* data = creature->GetCreatureData()) - creature->UpdatePosition(data->posX, data->posY, data->posZ, data->orientation); + creature->UpdatePosition(data->spawnPoint); creature->DespawnOrUnsummon(); creature->SetCorpseDelay(corpseDelay); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 53caf9fda7a..c98b086b203 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -392,13 +392,13 @@ class instance_icecrown_citadel : public InstanceMapScript break; case NPC_ZAFOD_BOOMBOX: if (GameObjectTemplate const* go = sObjectMgr->GetGameObjectTemplate(GO_THE_SKYBREAKER_A)) - if ((TeamInInstance == ALLIANCE && data->mapid == go->moTransport.mapID) || - (TeamInInstance == HORDE && data->mapid != go->moTransport.mapID)) + if ((TeamInInstance == ALLIANCE && data->spawnPoint.GetMapId() == go->moTransport.mapID) || + (TeamInInstance == HORDE && data->spawnPoint.GetMapId() != go->moTransport.mapID)) return entry; return 0; case NPC_IGB_MURADIN_BRONZEBEARD: - if ((TeamInInstance == ALLIANCE && data->posX > 10.0f) || - (TeamInInstance == HORDE && data->posX < 10.0f)) + if ((TeamInInstance == ALLIANCE && data->spawnPoint.GetPositionX() > 10.0f) || + (TeamInInstance == HORDE && data->spawnPoint.GetPositionX() < 10.0f)) return entry; return 0; default: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 5454ff7c848..cb04d154f8a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -96,7 +96,7 @@ public: void InitializeAI() override { - if (!me->isDead()) + if (!me->isDead() && instance->GetBossState(BOSS_ANUBREKHAN) != DONE) { Reset(); SummonGuards(); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index da3d95a5173..65d70f1e398 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -83,7 +83,7 @@ class boss_faerlina : public CreatureScript void InitializeAI() override { - if (!me->isDead()) + if (!me->isDead() && instance->GetBossState(BOSS_FAERLINA) != DONE) { Reset(); SummonAdds(); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index 0fb00d18fd3..51deb5b4375 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -265,14 +265,9 @@ struct boss_four_horsemen_baseAI : public BossAI for (Horseman boss : horsemen) { if (Creature* cBoss = getHorsemanHandle(boss)) - { - cBoss->DespawnOrUnsummon(); - cBoss->SetRespawnTime(15); - } + cBoss->DespawnOrUnsummon(0, Seconds(15)); else - { TC_LOG_WARN("scripts", "FourHorsemenAI: Encounter resetting but horseman with id %u is not present", uint32(boss)); - } } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index 58da5a92295..ac27c44d1de 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -79,7 +79,7 @@ public: void InitializeAI() override { - if (!me->isDead()) + if (!me->isDead() && instance->GetBossState(BOSS_RAZUVIOUS) != DONE) { Reset(); SummonAdds(); |