Core/Spells: Rewrite SelectRandomInjuredTargets to make extending it with additional requirements easier and allow it to prioritize group members
Port From (https://github.com/TrinityCore/TrinityCore/commit/d4d28d27f8322d6c07a6c384de1b4aecd1bb8a92)
This commit is contained in:
@@ -120,6 +120,18 @@ namespace System.Collections.Generic
|
|||||||
list.Resize(size);
|
list.Resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RandomShuffle<T>(this IList<T> array, int first, int count)
|
||||||
|
{
|
||||||
|
for (int n = count; n > 1;)
|
||||||
|
{
|
||||||
|
int k = (int)RandomHelper.Rand32(n);
|
||||||
|
--n;
|
||||||
|
T temp = array[n + first];
|
||||||
|
array[n + first] = array[k + first];
|
||||||
|
array[k + first] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static T SelectRandom<T>(this IEnumerable<T> source)
|
public static T SelectRandom<T>(this IEnumerable<T> source)
|
||||||
{
|
{
|
||||||
return source.SelectRandom(1).Single();
|
return source.SelectRandom(1).Single();
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace Game.Scripting
|
|||||||
_callImpl(victim, ref damageOrHealing, ref flatMod, ref pctMod);
|
_callImpl(victim, ref damageOrHealing, ref flatMod, ref pctMod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnCalculateResistAbsorbHandler
|
public class OnCalculateResistAbsorbHandler
|
||||||
{
|
{
|
||||||
SpellOnResistAbsorbCalculateFnType _callImpl;
|
SpellOnResistAbsorbCalculateFnType _callImpl;
|
||||||
@@ -1025,63 +1025,65 @@ namespace Game.Scripting
|
|||||||
m_spell.m_customError = result;
|
m_spell.m_customError = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectRandomInjuredTargets(List<WorldObject> targets, uint maxTargets, bool prioritizePlayers)
|
public void SelectRandomInjuredTargets(List<WorldObject> targets, uint maxTargets, bool prioritizePlayers, Unit prioritizeGroupMembersOf = null)
|
||||||
{
|
{
|
||||||
if (targets.Count <= maxTargets)
|
if (targets.Count <= maxTargets)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//List of all player targets.
|
// Target priority states (bit indices)
|
||||||
var tempPlayers = targets.Where(p => p.IsPlayer()).ToList();
|
// higher value means lower selection priority
|
||||||
|
// current list:
|
||||||
|
// * injured player group members
|
||||||
|
// * injured other players
|
||||||
|
// * injured pets of group members
|
||||||
|
// * injured other pets
|
||||||
|
// * full health player group members
|
||||||
|
// * full health other players
|
||||||
|
// * full health pets of group members
|
||||||
|
// * full health other pets
|
||||||
|
int NOT_GROUPED = 0;
|
||||||
|
int NOT_PLAYER = 1;
|
||||||
|
int NOT_INJURED = 2;
|
||||||
|
int END = 3;
|
||||||
|
|
||||||
//List of all injured non player targets.
|
int[] countsByPriority = new int[1 << END];
|
||||||
var tempInjuredUnits = targets.Where(target => target.IsUnit() && !target.ToUnit().IsFullHealth()).ToList();
|
|
||||||
|
|
||||||
//List of all none injured non player targets.
|
// categorize each target
|
||||||
var tempNoneInjuredUnits = targets.Where(target => target.IsUnit() && target.ToUnit().IsFullHealth()).ToList();
|
var tempTargets = targets.Select<WorldObject, (WorldObject, int)>(target =>
|
||||||
|
{
|
||||||
|
int negativePoints = 0;
|
||||||
|
if (prioritizeGroupMembersOf && (!target.IsUnit() || target.ToUnit().IsInRaidWith(prioritizeGroupMembersOf)))
|
||||||
|
negativePoints |= 1 << NOT_GROUPED;
|
||||||
|
|
||||||
|
if (prioritizePlayers && !target.IsPlayer() && (!target.IsCreature() || !target.ToCreature().HasFlag(CreatureStaticFlags4.TreatAsRaidUnitForHelpfulSpells)))
|
||||||
|
negativePoints |= 1 << NOT_PLAYER;
|
||||||
|
|
||||||
|
if (!target.IsUnit() || target.ToUnit().IsFullHealth())
|
||||||
|
negativePoints |= 1 << NOT_INJURED;
|
||||||
|
|
||||||
|
++countsByPriority[negativePoints];
|
||||||
|
return (target, negativePoints);
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
tempTargets.OrderBy(pair => pair.Item2);
|
||||||
|
|
||||||
|
int foundTargets = 0;
|
||||||
|
foreach (int countForPriority in countsByPriority)
|
||||||
|
{
|
||||||
|
if (foundTargets + countForPriority >= maxTargets)
|
||||||
|
{
|
||||||
|
// shuffle only the lower priority extras
|
||||||
|
// example: our initial target list had 5 injured and 5 full health units and we want to select 7 targets
|
||||||
|
// we always want to select 5 injured and 2 random full health ones
|
||||||
|
tempTargets.RandomShuffle(foundTargets, foundTargets + countForPriority);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foundTargets += countForPriority;
|
||||||
|
}
|
||||||
|
|
||||||
targets.Clear();
|
targets.Clear();
|
||||||
if (prioritizePlayers)
|
targets.AddRange(tempTargets.Select(pair => pair.Item1));
|
||||||
{
|
|
||||||
if (tempPlayers.Count < maxTargets)
|
|
||||||
{
|
|
||||||
// not enough players, add nonplayer targets
|
|
||||||
// prioritize injured nonplayers over full health nonplayers
|
|
||||||
|
|
||||||
if (tempPlayers.Count + tempInjuredUnits.Count < maxTargets)
|
|
||||||
{
|
|
||||||
// not enough players + injured nonplayers
|
|
||||||
// fill remainder with random full health nonplayers
|
|
||||||
targets.AddRange(tempPlayers);
|
|
||||||
targets.AddRange(tempInjuredUnits);
|
|
||||||
targets.AddRange(tempNoneInjuredUnits.Shuffle());
|
|
||||||
}
|
|
||||||
else if (tempPlayers.Count + tempInjuredUnits.Count > maxTargets)
|
|
||||||
{
|
|
||||||
// randomize injured nonplayers order
|
|
||||||
// final list will contain all players + random injured nonplayers
|
|
||||||
targets.AddRange(tempPlayers);
|
|
||||||
targets.AddRange(tempInjuredUnits.Shuffle());
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.Resize(maxTargets);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var lookupPlayers = tempPlayers.ToLookup(target => !target.ToUnit().IsFullHealth());
|
|
||||||
if (lookupPlayers[true].Count() < maxTargets)
|
|
||||||
{
|
|
||||||
// not enough injured units
|
|
||||||
// fill remainder with full health units
|
|
||||||
targets.AddRange(lookupPlayers[true]);
|
|
||||||
targets.AddRange(lookupPlayers[false].Shuffle());
|
|
||||||
}
|
|
||||||
else if (lookupPlayers[true].Count() > maxTargets)
|
|
||||||
{
|
|
||||||
// select random injured units
|
|
||||||
targets.AddRange(lookupPlayers[true].Shuffle());
|
|
||||||
}
|
|
||||||
|
|
||||||
targets.Resize(maxTargets);
|
targets.Resize(maxTargets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user