From f8af51643dc34850fa8845de5b36430fb0ed9549 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 27 Mar 2017 17:20:54 +0000 Subject: [PATCH] Add LineBuildSegmentExternalCondition. --- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + .../LineBuildSegmentExternalCondition.cs | 88 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 61f03891a0..1d672dff30 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -800,6 +800,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs b/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs new file mode 100644 index 0000000000..c78414ef0d --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Conditions/LineBuildSegmentExternalCondition.cs @@ -0,0 +1,88 @@ +#region Copyright & License Information +/* + * Copyright 2007-2017 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Applies a condition to connected line build segments.")] + public class LineBuildSegmentExternalConditionInfo : ConditionalTraitInfo, Requires + { + [FieldLoader.Require] + [Desc("The condition to apply. Must be included in the target actor's ExternalConditions list.")] + public readonly string Condition = null; + + public override object Create(ActorInitializer init) { return new LineBuildSegmentExternalCondition(init.Self, this); } + } + + public class LineBuildSegmentExternalCondition : ConditionalTrait, INotifyLineBuildSegmentsChanged + { + readonly HashSet segments = new HashSet(); + readonly Dictionary tokens = new Dictionary(); + + public LineBuildSegmentExternalCondition(Actor self, LineBuildSegmentExternalConditionInfo info) + : base(info) { } + + void GrantCondition(Actor self, Actor segment) + { + if (tokens.ContainsKey(segment)) + return; + + var external = segment.TraitsImplementing() + .FirstOrDefault(t => t.Info.Condition == Info.Condition && t.CanGrantCondition(segment, self)); + + if (external != null) + tokens[segment] = external.GrantCondition(segment, self); + } + + void RevokeCondition(Actor self, Actor segment) + { + int token; + if (!tokens.TryGetValue(segment, out token)) + return; + + tokens.Remove(segment); + if (segment.Disposed) + return; + + foreach (var external in segment.TraitsImplementing()) + external.TryRevokeCondition(segment, self, token); + } + + void INotifyLineBuildSegmentsChanged.SegmentAdded(Actor self, Actor segment) + { + segments.Add(segment); + if (!IsTraitDisabled) + GrantCondition(self, segment); + } + + void INotifyLineBuildSegmentsChanged.SegmentRemoved(Actor self, Actor segment) + { + if (!IsTraitDisabled) + RevokeCondition(self, segment); + segments.Remove(segment); + } + + protected override void TraitEnabled(Actor self) + { + foreach (var s in segments) + GrantCondition(self, s); + } + + protected override void TraitDisabled(Actor self) + { + foreach (var s in segments) + RevokeCondition(self, s); + } + } +}