Core/Conditions: Implemented conditions for spawn groups
This commit is contained in:
1 parent
740fa9e65a
commit
cbd46b7664
7 files changed
+181
-68
No files matched your search
@@ -66,7 +66,12 @@ char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX]
|
||||
"Terrain Swap",
|
||||
"Phase",
|
||||
"Graveyard",
|
||||
"Spell Area"
|
||||
"Spell Area",
|
||||
"ConversationLine",
|
||||
"AreaTrigger Client Triggered",
|
||||
"Trainer Spell",
|
||||
"Object Visibility (by ID)",
|
||||
"Spawn Group"
|
||||
};
|
||||
|
||||
ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[CONDITION_MAX] =
|
||||
@@ -121,24 +126,97 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
|
||||
{ "Quest state mask", true, true, 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 = sWorldStateMgr->GetValue(ConditionValue1, map) == int32(ConditionValue2);
|
||||
break;
|
||||
}
|
||||
case CONDITION_REALM_ACHIEVEMENT:
|
||||
{
|
||||
AchievementEntry const* achievement = sAchievementStore.LookupEntry(ConditionValue1);
|
||||
if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
|
||||
condMeets = true;
|
||||
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())
|
||||
@@ -248,38 +326,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;
|
||||
@@ -409,11 +455,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 = sWorldStateMgr->GetValue(ConditionValue1, object->GetMap()) == int32(ConditionValue2);
|
||||
break;
|
||||
}
|
||||
case CONDITION_PHASEID:
|
||||
{
|
||||
condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
|
||||
@@ -447,13 +488,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1);
|
||||
break;
|
||||
}
|
||||
case CONDITION_REALM_ACHIEVEMENT:
|
||||
{
|
||||
AchievementEntry const* achievement = sAchievementMgr->GetAchievement(ConditionValue1);
|
||||
if (achievement && sAchievementMgr->IsRealmCompleted(achievement))
|
||||
condMeets = true;
|
||||
break;
|
||||
}
|
||||
case CONDITION_IN_WATER:
|
||||
{
|
||||
if (Unit* unit = object->ToUnit())
|
||||
@@ -514,7 +548,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
|
||||
break;
|
||||
}
|
||||
default:
|
||||
condMeets = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -909,6 +942,30 @@ 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:
|
||||
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)
|
||||
@@ -930,6 +987,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)
|
||||
@@ -1900,6 +1963,21 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const
|
||||
return false;
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <vector>
|
||||
|
||||
class Creature;
|
||||
class Map;
|
||||
class Player;
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
@@ -144,7 +145,12 @@ enum ConditionSourceType
|
||||
CONDITION_SOURCE_TYPE_PHASE = 26,
|
||||
CONDITION_SOURCE_TYPE_GRAVEYARD = 27,
|
||||
CONDITION_SOURCE_TYPE_SPELL_AREA = 28,
|
||||
CONDITION_SOURCE_TYPE_MAX = 29 // MAX
|
||||
//CONDITION_SOURCE_TYPE_CONVERSATION_LINE = 29, // master only
|
||||
//CONDITION_SOURCE_TYPE_AREATRIGGER_CLIENT_TRIGGERED = 30, // master only
|
||||
//CONDITION_SOURCE_TYPE_TRAINER_SPELL = 31, // master only
|
||||
//CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY = 32, // master only
|
||||
CONDITION_SOURCE_TYPE_SPAWN_GROUP = 33,
|
||||
CONDITION_SOURCE_TYPE_MAX = 34 // MAX
|
||||
};
|
||||
|
||||
enum RelationType
|
||||
@@ -174,14 +180,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
|
||||
@@ -254,8 +256,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;
|
||||
|
||||
@@ -2670,7 +2670,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,%u) has map id %u - spawn NOT added to group!", groupId, groupTemplate.mapId, uint32(spawnType), spawnId, data->mapId);
|
||||
|
||||
@@ -1308,6 +1308,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* GetSpawnGroupsForInstance(uint32 instanceId) const { auto it = _instanceSpawnGroupStore.find(instanceId); return it != _instanceSpawnGroupStore.end() ? &it->second : nullptr; }
|
||||
|
||||
MailLevelReward const* GetMailLevelReward(uint32 level, uint32 raceMask) const
|
||||
@@ -1758,6 +1759,7 @@ class TC_GAME_API ObjectMgr
|
||||
GameObjectTemplateContainer _gameObjectTemplateStore;
|
||||
GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore;
|
||||
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
|
||||
|
||||
@@ -624,6 +624,7 @@ void Map::Update(uint32 t_diff)
|
||||
if (_respawnCheckTimer <= t_diff)
|
||||
{
|
||||
ProcessRespawns();
|
||||
UpdateSpawnGroupConditions();
|
||||
_respawnCheckTimer = sWorld->getIntConfig(CONFIG_RESPAWN_MINCHECKINTERVALMS);
|
||||
}
|
||||
else
|
||||
@@ -2191,6 +2192,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)));
|
||||
|
||||
@@ -707,6 +707,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
}
|
||||
|
||||
void SetSpawnGroupActive(uint32 groupId, bool state);
|
||||
void UpdateSpawnGroupConditions();
|
||||
std::unordered_set<uint32> _toggledSpawnGroupIds;
|
||||
|
||||
uint32 _respawnCheckTimer;
|
||||
|
||||
@@ -45,14 +45,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