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.
This commit is contained in:
r00ty-tc
2017-05-07 21:48:41 +01:00
committed by Treeston
parent d24ce1739a
commit 59db2eeea0
59 changed files with 2709 additions and 771 deletions
+50 -15
View File
@@ -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);