mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 15:40:45 +01:00
Core/Conditions: Implemented conditions for spawn groups
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#include "GameObject.h"
|
||||
#include "GameTime.h"
|
||||
#include "Group.h"
|
||||
#include "InstanceScenario.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Item.h"
|
||||
#include "LanguageMgr.h"
|
||||
@@ -43,7 +44,6 @@
|
||||
#include "RaceMask.h"
|
||||
#include "Realm.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "Scenario.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellAuras.h"
|
||||
@@ -88,7 +88,8 @@ char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX]
|
||||
"ConversationLine",
|
||||
"AreaTrigger Client Triggered",
|
||||
"Trainer Spell",
|
||||
"Object Visibility (by ID)"
|
||||
"Object Visibility (by ID)",
|
||||
"Spawn Group"
|
||||
};
|
||||
|
||||
ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[CONDITION_MAX] =
|
||||
@@ -151,24 +152,109 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
|
||||
{ "Scene In Progress", true, false, false },
|
||||
};
|
||||
|
||||
ConditionSourceInfo::ConditionSourceInfo(WorldObject* target0, WorldObject* target1, WorldObject* target2)
|
||||
{
|
||||
mConditionTargets[0] = target0;
|
||||
mConditionTargets[1] = target1;
|
||||
mConditionTargets[2] = target2;
|
||||
mConditionMap = target0 ? target0->GetMap() : nullptr;
|
||||
mLastFailedCondition = nullptr;
|
||||
}
|
||||
|
||||
ConditionSourceInfo::ConditionSourceInfo(Map const* map)
|
||||
{
|
||||
std::fill(std::begin(mConditionTargets), std::end(mConditionTargets), nullptr);
|
||||
mConditionMap = map;
|
||||
mLastFailedCondition = nullptr;
|
||||
}
|
||||
|
||||
// Checks if object meets the condition
|
||||
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI)
|
||||
bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
{
|
||||
ASSERT(ConditionTarget < MAX_CONDITION_TARGETS);
|
||||
WorldObject* object = sourceInfo.mConditionTargets[ConditionTarget];
|
||||
// object not present, return false
|
||||
if (!object)
|
||||
{
|
||||
TC_LOG_DEBUG("condition", "Condition object not found for %s", ToString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
Map const* map = sourceInfo.mConditionMap;
|
||||
bool condMeets = false;
|
||||
bool needsObject = false;
|
||||
switch (ConditionType)
|
||||
{
|
||||
case CONDITION_NONE:
|
||||
condMeets = true; // empty condition, always met
|
||||
break;
|
||||
case CONDITION_ACTIVE_EVENT:
|
||||
condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1);
|
||||
break;
|
||||
case CONDITION_INSTANCE_INFO:
|
||||
{
|
||||
if (map->IsDungeon())
|
||||
{
|
||||
if (InstanceScript const* instance = ((InstanceMap*)map)->GetInstanceScript())
|
||||
{
|
||||
switch (ConditionValue3)
|
||||
{
|
||||
case INSTANCE_INFO_DATA:
|
||||
condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
|
||||
break;
|
||||
//case INSTANCE_INFO_GUID_DATA:
|
||||
// condMeets = instance->GetGuidData(ConditionValue1) == ObjectGuid(uint64(ConditionValue2));
|
||||
// break;
|
||||
case INSTANCE_INFO_BOSS_STATE:
|
||||
condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
|
||||
break;
|
||||
case INSTANCE_INFO_DATA64:
|
||||
condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
|
||||
break;
|
||||
default:
|
||||
condMeets = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_MAPID:
|
||||
condMeets = map->GetId() == ConditionValue1;
|
||||
break;
|
||||
case CONDITION_WORLD_STATE:
|
||||
{
|
||||
condMeets = ConditionValue2 == sWorld->getWorldState(ConditionValue1);
|
||||
break;
|
||||
}
|
||||
case CONDITION_REALM_ACHIEVEMENT:
|
||||
{
|
||||
AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
|
||||
if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
|
||||
condMeets = true;
|
||||
break;
|
||||
}
|
||||
case CONDITION_DIFFICULTY_ID:
|
||||
{
|
||||
condMeets = map->GetDifficultyID() == ConditionValue1;
|
||||
break;
|
||||
}
|
||||
case CONDITION_SCENARIO_STEP:
|
||||
{
|
||||
if (InstanceMap const* instanceMap = map->ToInstanceMap())
|
||||
if (Scenario const* scenario = instanceMap->GetInstanceScenario())
|
||||
if (ScenarioStepEntry const* step = scenario->GetStep())
|
||||
condMeets = step->ID == ConditionValue1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
needsObject = true;
|
||||
break;
|
||||
}
|
||||
|
||||
WorldObject* object = sourceInfo.mConditionTargets[ConditionTarget];
|
||||
// object not present, return false
|
||||
if (needsObject && !object)
|
||||
{
|
||||
TC_LOG_DEBUG("condition", "Condition object not found for %s", ToString().c_str());
|
||||
return false;
|
||||
}
|
||||
switch (ConditionType)
|
||||
{
|
||||
case CONDITION_AURA:
|
||||
{
|
||||
if (Unit* unit = object->ToUnit())
|
||||
@@ -273,38 +359,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_ACTIVE_EVENT:
|
||||
condMeets = sGameEventMgr->IsActiveEvent(ConditionValue1);
|
||||
break;
|
||||
case CONDITION_INSTANCE_INFO:
|
||||
{
|
||||
Map* map = object->GetMap();
|
||||
if (map->IsDungeon())
|
||||
{
|
||||
if (InstanceScript const* instance = ((InstanceMap*)map)->GetInstanceScript())
|
||||
{
|
||||
switch (ConditionValue3)
|
||||
{
|
||||
case INSTANCE_INFO_DATA:
|
||||
condMeets = instance->GetData(ConditionValue1) == ConditionValue2;
|
||||
break;
|
||||
//case INSTANCE_INFO_GUID_DATA:
|
||||
// condMeets = instance->GetGuidData(ConditionValue1) == ObjectGuid(uint64(ConditionValue2));
|
||||
// break;
|
||||
case INSTANCE_INFO_BOSS_STATE:
|
||||
condMeets = instance->GetBossState(ConditionValue1) == EncounterState(ConditionValue2);
|
||||
break;
|
||||
case INSTANCE_INFO_DATA64:
|
||||
condMeets = instance->GetData64(ConditionValue1) == ConditionValue2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_MAPID:
|
||||
condMeets = object->GetMapId() == ConditionValue1;
|
||||
break;
|
||||
case CONDITION_AREAID:
|
||||
condMeets = object->GetAreaId() == ConditionValue1;
|
||||
break;
|
||||
@@ -434,11 +488,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
condMeets = CompareValues(static_cast<ComparisionType>(ConditionValue2), unit->GetHealthPct(), static_cast<float>(ConditionValue1));
|
||||
break;
|
||||
}
|
||||
case CONDITION_WORLD_STATE:
|
||||
{
|
||||
condMeets = ConditionValue2 == sWorld->getWorldState(ConditionValue1);
|
||||
break;
|
||||
}
|
||||
case CONDITION_PHASEID:
|
||||
{
|
||||
condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
|
||||
@@ -462,13 +511,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
condMeets = creature->GetCreatureTemplate()->type == ConditionValue1;
|
||||
break;
|
||||
}
|
||||
case CONDITION_REALM_ACHIEVEMENT:
|
||||
{
|
||||
AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
|
||||
if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
|
||||
condMeets = true;
|
||||
break;
|
||||
}
|
||||
case CONDITION_IN_WATER:
|
||||
{
|
||||
if (Unit* unit = object->ToUnit())
|
||||
@@ -553,11 +595,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_DIFFICULTY_ID:
|
||||
{
|
||||
condMeets = object->GetMap()->GetDifficultyID() == ConditionValue1;
|
||||
break;
|
||||
}
|
||||
case CONDITION_GAMEMASTER:
|
||||
{
|
||||
if (Player* player = object->ToPlayer())
|
||||
@@ -577,13 +614,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
static_cast<uint8>(ConditionValue2));
|
||||
break;
|
||||
}
|
||||
case CONDITION_SCENARIO_STEP:
|
||||
{
|
||||
if (Scenario const* scenario = object->GetScenario())
|
||||
if (ScenarioStepEntry const* step = scenario->GetStep())
|
||||
condMeets = step->ID == ConditionValue1;
|
||||
break;
|
||||
}
|
||||
case CONDITION_SCENE_IN_PROGRESS:
|
||||
{
|
||||
if (Player* player = object->ToPlayer())
|
||||
@@ -591,7 +621,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
break;
|
||||
}
|
||||
default:
|
||||
condMeets = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1002,6 +1031,32 @@ bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType)
|
||||
return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
|
||||
}
|
||||
|
||||
bool ConditionMgr::CanHaveConditionType(ConditionSourceType sourceType, ConditionTypes conditionType)
|
||||
{
|
||||
switch (sourceType)
|
||||
{
|
||||
case CONDITION_SOURCE_TYPE_SPAWN_GROUP:
|
||||
switch (conditionType)
|
||||
{
|
||||
case CONDITION_NONE:
|
||||
case CONDITION_ACTIVE_EVENT:
|
||||
case CONDITION_INSTANCE_INFO:
|
||||
case CONDITION_MAPID:
|
||||
case CONDITION_WORLD_STATE:
|
||||
case CONDITION_REALM_ACHIEVEMENT:
|
||||
case CONDITION_DIFFICULTY_ID:
|
||||
case CONDITION_SCENARIO_STEP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, ConditionSourceInfo& sourceInfo) const
|
||||
{
|
||||
if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
|
||||
@@ -1023,6 +1078,12 @@ bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourc
|
||||
return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
|
||||
}
|
||||
|
||||
bool ConditionMgr::IsMapMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, Map const* map) const
|
||||
{
|
||||
ConditionSourceInfo conditionSource(map);
|
||||
return IsObjectMeetingNotGroupedConditions(sourceType, entry, conditionSource);
|
||||
}
|
||||
|
||||
bool ConditionMgr::HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const
|
||||
{
|
||||
if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
|
||||
@@ -2097,6 +2158,21 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_SPAWN_GROUP:
|
||||
{
|
||||
SpawnGroupTemplateData const* spawnGroup = sObjectMgr->GetSpawnGroupData(cond->SourceEntry);
|
||||
if (!spawnGroup)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in `spawn_group_template`, ignoring.", cond->ToString().c_str());
|
||||
return false;
|
||||
}
|
||||
if (spawnGroup->flags & (SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_MANUAL_SPAWN))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "%s in `spawn_group_template` table cannot have SPAWNGROUP_FLAG_SYSTEM or SPAWNGROUP_FLAG_MANUAL_SPAWN flags, ignoring.", cond->ToString().c_str());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TC_LOG_ERROR("sql.sql", "%s Invalid ConditionSourceType in `condition` table, ignoring.", cond->ToString().c_str());
|
||||
return false;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <vector>
|
||||
|
||||
class Creature;
|
||||
class Map;
|
||||
class Player;
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
@@ -179,7 +180,8 @@ enum ConditionSourceType
|
||||
CONDITION_SOURCE_TYPE_AREATRIGGER_CLIENT_TRIGGERED = 30,
|
||||
CONDITION_SOURCE_TYPE_TRAINER_SPELL = 31,
|
||||
CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY = 32,
|
||||
CONDITION_SOURCE_TYPE_MAX = 33 // MAX
|
||||
CONDITION_SOURCE_TYPE_SPAWN_GROUP = 33,
|
||||
CONDITION_SOURCE_TYPE_MAX = 34 // MAX
|
||||
};
|
||||
|
||||
enum RelationType
|
||||
@@ -209,14 +211,10 @@ enum MaxConditionTargets
|
||||
struct TC_GAME_API ConditionSourceInfo
|
||||
{
|
||||
WorldObject* mConditionTargets[MAX_CONDITION_TARGETS]; // an array of targets available for conditions
|
||||
Map const* mConditionMap;
|
||||
Condition const* mLastFailedCondition;
|
||||
ConditionSourceInfo(WorldObject* target0, WorldObject* target1 = nullptr, WorldObject* target2 = nullptr)
|
||||
{
|
||||
mConditionTargets[0] = target0;
|
||||
mConditionTargets[1] = target1;
|
||||
mConditionTargets[2] = target2;
|
||||
mLastFailedCondition = nullptr;
|
||||
}
|
||||
ConditionSourceInfo(WorldObject* target0, WorldObject* target1 = nullptr, WorldObject* target2 = nullptr);
|
||||
ConditionSourceInfo(Map const* map);
|
||||
};
|
||||
|
||||
struct TC_GAME_API Condition
|
||||
@@ -290,8 +288,10 @@ class TC_GAME_API ConditionMgr
|
||||
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionContainer const& conditions) const;
|
||||
static bool CanHaveSourceGroupSet(ConditionSourceType sourceType);
|
||||
static bool CanHaveSourceIdSet(ConditionSourceType sourceType);
|
||||
static bool CanHaveConditionType(ConditionSourceType sourceType, ConditionTypes conditionType);
|
||||
bool IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, ConditionSourceInfo& sourceInfo) const;
|
||||
bool IsObjectMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, WorldObject* target0, WorldObject* target1 = nullptr, WorldObject* target2 = nullptr) const;
|
||||
bool IsMapMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, Map const* map) const;
|
||||
bool HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const;
|
||||
bool IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject* clicker, WorldObject* target) const;
|
||||
ConditionContainer const* GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const;
|
||||
|
||||
@@ -2885,7 +2885,10 @@ void ObjectMgr::LoadSpawnGroups()
|
||||
{
|
||||
SpawnGroupTemplateData& groupTemplate = it->second;
|
||||
if (groupTemplate.mapId == SPAWNGROUP_MAP_UNSET)
|
||||
{
|
||||
groupTemplate.mapId = data->mapId;
|
||||
_spawnGroupsByMap[data->mapId].push_back(groupId);
|
||||
}
|
||||
else if (groupTemplate.mapId != data->mapId && !(groupTemplate.flags & SPAWNGROUP_FLAG_SYSTEM))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Spawn group %u has map ID %u, but spawn (%u," UI64FMTD ") has map id %u - spawn NOT added to group!", groupId, groupTemplate.mapId, uint32(spawnType), spawnId, data->mapId);
|
||||
|
||||
@@ -1455,6 +1455,7 @@ class TC_GAME_API ObjectMgr
|
||||
SpawnGroupTemplateData const* GetDefaultSpawnGroup() const { return &_spawnGroupDataStore.at(0); }
|
||||
SpawnGroupTemplateData const* GetLegacySpawnGroup() const { return &_spawnGroupDataStore.at(1); }
|
||||
Trinity::IteratorPair<SpawnGroupLinkContainer::const_iterator> GetSpawnMetadataForGroup(uint32 groupId) const { return Trinity::Containers::MapEqualRange(_spawnGroupMapStore, groupId); }
|
||||
std::vector<uint32> const* GetSpawnGroupsForMap(uint32 mapId) const { auto it = _spawnGroupsByMap.find(mapId); return it != _spawnGroupsByMap.end() ? &it->second : nullptr; }
|
||||
std::vector<InstanceSpawnGroupInfo> const* GetInstanceSpawnGroupsForMap(uint32 mapId) const { auto it = _instanceSpawnGroupStore.find(mapId); return it != _instanceSpawnGroupStore.end() ? &it->second : nullptr; }
|
||||
|
||||
MailLevelReward const* GetMailLevelReward(uint8 level, uint8 race) const
|
||||
@@ -1922,6 +1923,7 @@ class TC_GAME_API ObjectMgr
|
||||
GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore;
|
||||
GameObjectOverrideContainer _gameObjectOverrideStore;
|
||||
SpawnGroupDataContainer _spawnGroupDataStore;
|
||||
std::unordered_map<uint32, std::vector<uint32>> _spawnGroupsByMap;
|
||||
SpawnGroupLinkContainer _spawnGroupMapStore;
|
||||
InstanceSpawnGroupContainer _instanceSpawnGroupStore;
|
||||
/// Stores temp summon data grouped by summoner's entry, summoner's type and group id
|
||||
|
||||
@@ -853,6 +853,7 @@ void Map::Update(uint32 t_diff)
|
||||
if (_respawnCheckTimer <= t_diff)
|
||||
{
|
||||
ProcessRespawns();
|
||||
UpdateSpawnGroupConditions();
|
||||
_respawnCheckTimer = sWorld->getIntConfig(CONFIG_RESPAWN_MINCHECKINTERVALMS);
|
||||
}
|
||||
else
|
||||
@@ -3640,6 +3641,28 @@ bool Map::IsSpawnGroupActive(uint32 groupId) const
|
||||
return (_toggledSpawnGroupIds.find(groupId) != _toggledSpawnGroupIds.end()) != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN);
|
||||
}
|
||||
|
||||
void Map::UpdateSpawnGroupConditions()
|
||||
{
|
||||
std::vector<uint32> const* spawnGroups = sObjectMgr->GetSpawnGroupsForMap(GetId());
|
||||
if (!spawnGroups)
|
||||
return;
|
||||
|
||||
for (uint32 spawnGroupId : *spawnGroups)
|
||||
{
|
||||
bool isActive = IsSpawnGroupActive(spawnGroupId);
|
||||
bool shouldBeActive = sConditionMgr->IsMapMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPAWN_GROUP, spawnGroupId, this);
|
||||
if (isActive == shouldBeActive)
|
||||
continue;
|
||||
|
||||
if (shouldBeActive)
|
||||
SpawnGroupSpawn(spawnGroupId);
|
||||
else if (ASSERT_NOTNULL(GetSpawnGroupData(spawnGroupId))->flags & SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE)
|
||||
SpawnGroupDespawn(spawnGroupId);
|
||||
else
|
||||
SetSpawnGroupInactive(spawnGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::AddFarSpellCallback(FarSpellCallback&& callback)
|
||||
{
|
||||
_farSpellCallbacks.Enqueue(new FarSpellCallback(std::move(callback)));
|
||||
|
||||
@@ -876,6 +876,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
}
|
||||
|
||||
void SetSpawnGroupActive(uint32 groupId, bool state);
|
||||
void UpdateSpawnGroupConditions();
|
||||
std::unordered_set<uint32> _toggledSpawnGroupIds;
|
||||
|
||||
uint32 _respawnCheckTimer;
|
||||
|
||||
@@ -50,14 +50,16 @@ enum SpawnObjectTypeMask
|
||||
|
||||
enum SpawnGroupFlags
|
||||
{
|
||||
SPAWNGROUP_FLAG_NONE = 0x00,
|
||||
SPAWNGROUP_FLAG_SYSTEM = 0x01,
|
||||
SPAWNGROUP_FLAG_COMPATIBILITY_MODE = 0x02,
|
||||
SPAWNGROUP_FLAG_MANUAL_SPAWN = 0x04,
|
||||
SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE = 0x08,
|
||||
SPAWNGROUP_FLAG_ESCORTQUESTNPC = 0x10,
|
||||
SPAWNGROUP_FLAG_NONE = 0x00,
|
||||
SPAWNGROUP_FLAG_SYSTEM = 0x01,
|
||||
SPAWNGROUP_FLAG_COMPATIBILITY_MODE = 0x02,
|
||||
SPAWNGROUP_FLAG_MANUAL_SPAWN = 0x04,
|
||||
SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE = 0x08,
|
||||
SPAWNGROUP_FLAG_ESCORTQUESTNPC = 0x10,
|
||||
SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE = 0x20,
|
||||
|
||||
SPAWNGROUP_FLAGS_ALL = (SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_COMPATIBILITY_MODE | SPAWNGROUP_FLAG_MANUAL_SPAWN | SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE | SPAWNGROUP_FLAG_ESCORTQUESTNPC)
|
||||
SPAWNGROUP_FLAGS_ALL = (SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_COMPATIBILITY_MODE | SPAWNGROUP_FLAG_MANUAL_SPAWN
|
||||
| SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE | SPAWNGROUP_FLAG_ESCORTQUESTNPC | SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE)
|
||||
};
|
||||
|
||||
struct SpawnGroupTemplateData
|
||||
|
||||
Reference in New Issue
Block a user