diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index 3a5c3b180911f5..ca89e7de0921b6 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -138,18 +138,28 @@ namespace Acore::Containers } /* - * Select a random element from a container. + * @brief Selects a random element from a container that matches the given predicate + * + * @param container Source container to select from + * @param predicate Unary predicate to filter elements + * @return Iterator to the randomly selected element, or end iterator if no elements match the predicate * * Note: container cannot be empty */ template - inline auto SelectRandomContainerElementIf(C const& container, Predicate&& predicate) -> typename std::add_const::type& + inline auto SelectRandomContainerElementIf(C const& container, Predicate&& predicate) -> decltype(std::begin(container)) { - C containerCopy; - std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate); - auto it = std::begin(containerCopy); - std::advance(it, urand(0, uint32(std::size(containerCopy)) - 1)); - return *it; + std::vector matchingElements; + + for (auto it = std::begin(container); it != std::end(container); ++it) + if (predicate(*it)) + matchingElements.push_back(it); + + if (matchingElements.empty()) + return std::end(container); + + auto randomIt = matchingElements[urand(0, matchingElements.size() - 1)]; + return randomIt; } /* diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index d44da6547afe70..39751a12a8a760 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -64,6 +64,11 @@ struct Position return !(operator==(a)); } + inline bool operator!=(Position const& a) const + { + return !(operator==(a)); + } + operator G3D::Vector3() const { return { m_positionX, m_positionY, m_positionZ }; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp index 3946eca1fcc4e3..1551eefbdb7959 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp @@ -205,10 +205,12 @@ class instance_the_black_morass : public InstanceMapScript { if (_availableRiftPositions.size() > 1) { - spawnPos = Acore::Containers::SelectRandomContainerElementIf(_availableRiftPositions, [&](Position pos) -> bool + auto spawnPosItr = Acore::Containers::SelectRandomContainerElementIf(_availableRiftPositions, [&](Position const& pos) -> bool { return pos != lastPosition; }); + if (spawnPosItr != _availableRiftPositions.end()) + spawnPos = *spawnPosItr; } else { diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp index aea7b72d38373d..4864540216c633 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp @@ -93,10 +93,13 @@ struct boss_laj : public BossAI ScheduleTimedEvent(30s, [&] { me->RemoveAurasDueToSpell(_lastTransform.spellId); - _lastTransform = Acore::Containers::SelectRandomContainerElementIf(_transformContainer, [&](LajTransformData data) -> bool + auto lastTransformItr = Acore::Containers::SelectRandomContainerElementIf(_transformContainer, [&](LajTransformData const& data) -> bool { return data.spellId != _lastTransform.spellId; }); + if (lastTransformItr == _transformContainer.end()) + return; + _lastTransform = *lastTransformItr; me->SetDisplayId(_lastTransform.modelId); DoCastSelf(_lastTransform.spellId, true); }, 35s);