diff --git a/OpenRA.Mods.Common/Traits/Health.cs b/OpenRA.Mods.Common/Traits/Health.cs index f4f18da151..6dcc4d4347 100644 --- a/OpenRA.Mods.Common/Traits/Health.cs +++ b/OpenRA.Mods.Common/Traits/Health.cs @@ -32,9 +32,16 @@ namespace OpenRA.Mods.Common.Traits } } - public class Health : IHealth, ISync, ITick + public class Health : IHealth, ISync, ITick, INotifyCreated, INotifyOwnerChanged { public readonly HealthInfo Info; + INotifyDamageStateChanged[] notifyDamageStateChanged; + INotifyDamage[] notifyDamage; + INotifyDamage[] notifyDamagePlayer; + IDamageModifier[] damageModifiers; + IDamageModifier[] damageModifiersPlayer; + INotifyKilled[] notifyKilled; + INotifyKilled[] notifyKilledPlayer; [Sync] int hp; @@ -80,6 +87,24 @@ namespace OpenRA.Mods.Common.Traits } } + void INotifyCreated.Created(Actor self) + { + notifyDamageStateChanged = self.TraitsImplementing().ToArray(); + notifyDamage = self.TraitsImplementing().ToArray(); + notifyDamagePlayer = self.Owner.PlayerActor.TraitsImplementing().ToArray(); + damageModifiers = self.TraitsImplementing().ToArray(); + damageModifiersPlayer = self.Owner.PlayerActor.TraitsImplementing().ToArray(); + notifyKilled = self.TraitsImplementing().ToArray(); + notifyKilledPlayer = self.Owner.PlayerActor.TraitsImplementing().ToArray(); + } + + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + notifyDamagePlayer = newOwner.PlayerActor.TraitsImplementing().ToArray(); + damageModifiersPlayer = newOwner.PlayerActor.TraitsImplementing().ToArray(); + notifyKilledPlayer = newOwner.PlayerActor.TraitsImplementing().ToArray(); + } + public void Resurrect(Actor self, Actor repairer) { if (!IsDead) @@ -95,17 +120,21 @@ namespace OpenRA.Mods.Common.Traits PreviousDamageState = DamageState.Dead, }; - foreach (var nd in self.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing())) + foreach (var nd in notifyDamage) + nd.Damaged(self, ai); + foreach (var nd in notifyDamagePlayer) nd.Damaged(self, ai); - foreach (var nd in self.TraitsImplementing()) + foreach (var nd in notifyDamageStateChanged) nd.DamageStateChanged(self, ai); if (Info.NotifyAppliedDamage && repairer != null && repairer.IsInWorld && !repairer.IsDead) - foreach (var nd in repairer.TraitsImplementing() - .Concat(repairer.Owner.PlayerActor.TraitsImplementing())) + { + foreach (var nd in repairer.TraitsImplementing()) nd.AppliedDamage(repairer, self, ai); + foreach (var nd in repairer.Owner.PlayerActor.TraitsImplementing()) + nd.AppliedDamage(repairer, self, ai); + } } public void InflictDamage(Actor self, Actor attacker, Damage damage, bool ignoreModifiers) @@ -119,8 +148,8 @@ namespace OpenRA.Mods.Common.Traits // Apply any damage modifiers if (!ignoreModifiers && damage.Value > 0) { - var modifiers = self.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing()) + var modifiers = damageModifiers + .Concat(damageModifiersPlayer) .Select(t => t.GetDamageModifier(attacker, damage)); damage = new Damage(Util.ApplyPercentageModifiers(damage.Value, modifiers), damage.DamageTypes); @@ -136,23 +165,28 @@ namespace OpenRA.Mods.Common.Traits PreviousDamageState = oldState, }; - foreach (var nd in self.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing())) + foreach (var nd in notifyDamage) + nd.Damaged(self, ai); + foreach (var nd in notifyDamagePlayer) nd.Damaged(self, ai); if (DamageState != oldState) - foreach (var nd in self.TraitsImplementing()) + foreach (var nd in notifyDamageStateChanged) nd.DamageStateChanged(self, ai); if (Info.NotifyAppliedDamage && attacker != null && attacker.IsInWorld && !attacker.IsDead) - foreach (var nd in attacker.TraitsImplementing() - .Concat(attacker.Owner.PlayerActor.TraitsImplementing())) + { + foreach (var nd in attacker.TraitsImplementing()) nd.AppliedDamage(attacker, self, ai); + foreach (var nd in attacker.Owner.PlayerActor.TraitsImplementing()) + nd.AppliedDamage(attacker, self, ai); + } if (hp == 0) { - foreach (var nd in self.TraitsImplementing() - .Concat(self.Owner.PlayerActor.TraitsImplementing())) + foreach (var nd in notifyKilled) + nd.Killed(self, ai); + foreach (var nd in notifyKilledPlayer) nd.Killed(self, ai); if (RemoveOnDeath)