1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System.Collections.Generic;
13 using OpenRA.Support;
14 using OpenRA.Traits;
15 
16 namespace OpenRA.Mods.Common.Traits
17 {
18 	/// <summary>Use as base class for *Info to subclass of PausableConditionalTrait. (See PausableConditionalTrait.)</summary>
19 	public abstract class PausableConditionalTraitInfo : ConditionalTraitInfo
20 	{
21 		[ConsumedConditionReference]
22 		[Desc("Boolean expression defining the condition to pause this trait.")]
23 		public readonly BooleanExpression PauseOnCondition = null;
24 
25 		public bool PausedByDefault { get; private set; }
26 
RulesetLoaded(Ruleset rules, ActorInfo ai)27 		public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
28 		{
29 			base.RulesetLoaded(rules, ai);
30 			PausedByDefault = PauseOnCondition != null && PauseOnCondition.Evaluate(VariableExpression.NoVariables);
31 		}
32 	}
33 
34 	/// <summary>
35 	/// Abstract base for enabling and disabling trait using conditions.
36 	/// Requires basing *Info on PausableConditionalTraitInfo and using base(info) constructor.
37 	/// TraitResumed will be called at creation if the trait starts not paused or does not have a pause condition.
38 	/// </summary>
39 	public abstract class PausableConditionalTrait<InfoType> : ConditionalTrait<InfoType> where InfoType : PausableConditionalTraitInfo
40 	{
41 		[Sync]
42 		public bool IsTraitPaused { get; private set; }
43 
PausableConditionalTrait(InfoType info)44 		protected PausableConditionalTrait(InfoType info)
45 			: base(info)
46 		{
47 			IsTraitPaused = info.PausedByDefault;
48 		}
49 
Created(Actor self)50 		protected override void Created(Actor self)
51 		{
52 			base.Created(self);
53 			if (Info.PauseOnCondition == null)
54 				TraitResumed(self);
55 		}
56 
57 		// Overrides must call `base.GetVariableObservers()` to avoid breaking RequiresCondition or PauseOnCondition.
GetVariableObservers()58 		public override IEnumerable<VariableObserver> GetVariableObservers()
59 		{
60 			foreach (var observer in base.GetVariableObservers())
61 				yield return observer;
62 
63 			if (Info.PauseOnCondition != null)
64 				yield return new VariableObserver(PauseConditionsChanged, Info.PauseOnCondition.Variables);
65 		}
66 
PauseConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions)67 		void PauseConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
68 		{
69 			var wasPaused = IsTraitPaused;
70 			IsTraitPaused = Info.PauseOnCondition.Evaluate(conditions);
71 
72 			if (IsTraitPaused != wasPaused)
73 			{
74 				if (wasPaused)
75 					TraitResumed(self);
76 				else
77 					TraitPaused(self);
78 			}
79 		}
80 
81 		// Subclasses can add pause support by querying IsTraitPaused and/or overriding these methods.
TraitResumed(Actor self)82 		protected virtual void TraitResumed(Actor self) { }
TraitPaused(Actor self)83 		protected virtual void TraitPaused(Actor self) { }
84 	}
85 }
86