aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Spells/Spell.cpp69
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp7
3 files changed, 72 insertions, 6 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index c7bae4c17c8..66ec7cbad4d 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -8613,6 +8613,75 @@ bool WorldObjectSpellLineTargetCheck::operator()(WorldObject* target) const
return WorldObjectSpellTargetCheck::operator ()(target);
}
+void SelectRandomInjuredTargets(std::list<WorldObject*>& targets, size_t maxTargets, bool prioritizePlayers)
+{
+ if (targets.size() <= maxTargets)
+ return;
+
+ std::vector<WorldObject*> tempTargets(targets.begin(), targets.end());
+
+ auto begin = tempTargets.begin();
+ auto end = tempTargets.end();
+
+ if (prioritizePlayers)
+ {
+ auto playersEnd = std::stable_partition(begin, end, [](WorldObject const* target)
+ {
+ return target->IsPlayer();
+ });
+
+ size_t playerCount = std::distance(begin, playersEnd);
+ if (playerCount < maxTargets)
+ {
+ // not enough players, add nonplayer targets
+ // prioritize injured nonplayers over full health nonplayers
+ auto injuredNonPlayersEnd = std::stable_partition(playersEnd, end, [](WorldObject const* target)
+ {
+ return target->IsUnit() && !target->ToUnit()->IsFullHealth();
+ });
+
+ size_t injuredNonPlayersCount = std::distance(playersEnd, injuredNonPlayersEnd);
+ if (playerCount + injuredNonPlayersCount < maxTargets)
+ {
+ // not enough players + injured nonplayers
+ // fill remainder with random full health nonplayers
+ Containers::RandomShuffle(injuredNonPlayersEnd, end);
+ }
+ else if (playerCount + injuredNonPlayersCount > maxTargets)
+ {
+ // randomize injured nonplayers order
+ // final list will contain all players + random injured nonplayers
+ Containers::RandomShuffle(playersEnd, injuredNonPlayersEnd);
+ }
+
+ targets.assign(tempTargets.begin(), tempTargets.begin() + maxTargets);
+ return;
+ }
+
+ // We have more players than we requested, proceed checking injured targets
+ end = playersEnd;
+ }
+
+ auto injuredUnitsEnd = std::stable_partition(begin, end, [](WorldObject const* target)
+ {
+ return target->IsUnit() && !target->ToUnit()->IsFullHealth();
+ });
+
+ size_t injuredUnitsCount = std::distance(begin, injuredUnitsEnd);
+ if (injuredUnitsCount < maxTargets)
+ {
+ // not enough injured units
+ // fill remainder with full health units
+ Containers::RandomShuffle(injuredUnitsEnd, end);
+ }
+ else if (injuredUnitsCount > maxTargets)
+ {
+ // select random injured units
+ Containers::RandomShuffle(begin, injuredUnitsEnd);
+ }
+
+ targets.assign(tempTargets.begin(), tempTargets.begin() + maxTargets);
+}
} //namespace Trinity
CastSpellTargetArg::CastSpellTargetArg(WorldObject* target)
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 69fd9d2026d..8601e1d5042 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -933,6 +933,8 @@ namespace Trinity
bool operator()(WorldObject* target) const;
};
+
+ TC_GAME_API void SelectRandomInjuredTargets(std::list<WorldObject*>& targets, size_t maxTargets, bool prioritizePlayers);
}
using SpellEffectHandlerFn = void(Spell::*)();
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index 1ed37c14a58..1cc2cfca560 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -324,12 +324,7 @@ class spell_sha_downpour : public SpellScript
void FilterTargets(std::list<WorldObject*>& targets)
{
- uint32 const maxTargets = 6;
- if (targets.size() > maxTargets)
- {
- targets.sort(Trinity::HealthPctOrderPred());
- targets.resize(maxTargets);
- }
+ Trinity::SelectRandomInjuredTargets(targets, 6, true);
}
void CountEffectivelyHealedTarget()