diff options
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 204 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 16 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 1 | ||||
-rw-r--r-- | src/server/game/Maps/SpawnData.h | 18 |
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 |