aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp204
-rw-r--r--src/server/game/Conditions/ConditionMgr.h16
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp3
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Maps/Map.cpp23
-rw-r--r--src/server/game/Maps/Map.h1
-rw-r--r--src/server/game/Maps/SpawnData.h18
7 files changed, 187 insertions, 80 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 9377b4ff214..24d2a6b9260 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -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);
+
+ 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 (!object)
+ if (needsObject && !object)
{
TC_LOG_DEBUG("condition", "Condition object not found for %s", ToString().c_str());
return false;
}
- bool condMeets = false;
switch (ConditionType)
{
- case CONDITION_NONE:
- condMeets = true; // empty condition, always met
- break;
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;
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 1408bbe77f5..a1047e57428 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -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;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 7324e9e05b1..de8e1092919 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -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);
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index b02afbba37a..9a93903ebc3 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -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
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 174b3fda99a..e9fe8caffc3 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -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)));
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index d4b7b5c1c10..f589ce9e0e3 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -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;
diff --git a/src/server/game/Maps/SpawnData.h b/src/server/game/Maps/SpawnData.h
index c672ec528ad..9f25655e46e 100644
--- a/src/server/game/Maps/SpawnData.h
+++ b/src/server/game/Maps/SpawnData.h
@@ -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_FLAGS_ALL = (SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_COMPATIBILITY_MODE | SPAWNGROUP_FLAG_MANUAL_SPAWN | SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE | SPAWNGROUP_FLAG_ESCORTQUESTNPC)
+ 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_FLAG_DESPAWN_ON_CONDITION_FAILURE)
};
struct SpawnGroupTemplateData