From ae45707c8473966824af56fbc7f1ba61fbfcecbb Mon Sep 17 00:00:00 2001 From: Gustas <37534529+PunkPun@users.noreply.github.com> Date: Mon, 5 Dec 2022 17:08:14 +0200 Subject: [PATCH] Fix ProximityExternalCondition ignoring the owner change event --- .../Traits/Conditions/ExternalCondition.cs | 8 +++- .../Conditions/ProximityExternalCondition.cs | 42 ++++++++++++++++--- OpenRA.Mods.Common/TraitsInterfaces.cs | 1 + 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs index da293509fa..1306228f75 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits public override object Create(ActorInitializer init) { return new ExternalCondition(this); } } - public class ExternalCondition : ITick, INotifyCreated + public class ExternalCondition : ITick, INotifyCreated, INotifyOwnerChanged { readonly struct TimedToken { @@ -222,6 +222,12 @@ namespace OpenRA.Mods.Common.Traits bool Notifies(IConditionTimerWatcher watcher) { return watcher.Condition == Info.Condition; } + void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) + { + foreach (var pair in self.World.ActorsWithTrait()) + pair.Trait.OnProximityOwnerChanged(self, oldOwner, newOwner); + } + void INotifyCreated.Created(Actor self) { watchers = self.TraitsImplementing().Where(Notifies).ToArray(); diff --git a/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs b/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs index 7d1b6410a5..c4c1377b0a 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/ProximityExternalCondition.cs @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits public override object Create(ActorInitializer init) { return new ProximityExternalCondition(init.Self, this); } } - public class ProximityExternalCondition : ConditionalTrait, ITick, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOtherProduction + public class ProximityExternalCondition : ConditionalTrait, ITick, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOtherProduction, INotifyProximityOwnerChanged { readonly Actor self; @@ -123,19 +123,18 @@ namespace OpenRA.Mods.Common.Traits public void UnitProducedByOther(Actor self, Actor producer, Actor produced, string productionType, TypeDictionary init) { - // If the produced Actor doesn't occupy space, it can't be in range + // If the produced Actor doesn't occupy space, it can't be in range. if (produced.OccupiesSpace == null) return; - // We don't grant conditions when disabled + // We don't grant conditions when disabled. if (IsTraitDisabled) return; - // Work around for actors produced within the region not triggering until the second tick + // Work around for actors produced within the region not triggering until the second tick. if ((produced.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= Info.Range.LengthSquared) { - var stance = self.Owner.RelationshipWith(produced.Owner); - if (!Info.ValidRelationships.HasRelationship(stance)) + if (!Info.ValidRelationships.HasRelationship(self.Owner.RelationshipWith(produced.Owner))) return; var external = produced.TraitsImplementing() @@ -159,5 +158,36 @@ namespace OpenRA.Mods.Common.Traits if (external.TryRevokeCondition(a, self, token)) break; } + + void INotifyProximityOwnerChanged.OnProximityOwnerChanged(Actor actor, Player oldOwner, Player newOwner) + { + // If the Actor doesn't occupy space, it can't be in range. + if (actor.OccupiesSpace == null) + return; + + // We don't grant conditions when disabled. + if (IsTraitDisabled) + return; + + // Work around for actors changin owner within the region. + if ((actor.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= Info.Range.LengthSquared) + { + var hasRelationship = Info.ValidRelationships.HasRelationship(self.Owner.RelationshipWith(actor.Owner)); + var contains = tokens.TryGetValue(actor, out var token); + if (hasRelationship && !contains) + { + var external = actor.TraitsImplementing().FirstOrDefault(t => t.Info.Condition == Info.Condition && t.CanGrantCondition(self)); + if (external != null) + tokens[actor] = external.GrantCondition(actor, self); + } + else if (!hasRelationship && contains) + { + tokens.Remove(actor); + foreach (var external in actor.TraitsImplementing()) + if (external.TryRevokeCondition(actor, self, token)) + break; + } + } + } } } diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index f352636ec0..5f57f28b76 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -183,6 +183,7 @@ namespace OpenRA.Mods.Common.Traits [RequireExplicitImplementation] public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet captureTypes); } + public interface INotifyProximityOwnerChanged { void OnProximityOwnerChanged(Actor actor, Player oldOwner, Player newOwner); } public interface INotifyDiscovered { void OnDiscovered(Actor self, Player discoverer, bool playNotification); } public interface IRenderActorPreviewInfo : ITraitInfoInterface { IEnumerable RenderPreview(ActorPreviewInitializer init); } public interface ICruiseAltitudeInfo : ITraitInfoInterface { WDist GetCruiseAltitude(); }