diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 69 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_shaman.cpp | 7 |
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() |