diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index b292906005..b9e1fe0516 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -777,7 +777,7 @@
-
+
diff --git a/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs
index 46f4872fb4..71d7b22894 100644
--- a/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs
+++ b/OpenRA.Mods.Common/Scripting/Properties/ConditionProperties.cs
@@ -20,15 +20,16 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Scripting
{
[ScriptPropertyGroup("General")]
- public class ConditionProperties : ScriptActorProperties, Requires
+ public class ConditionProperties : ScriptActorProperties, Requires
{
- readonly ConditionManager conditionManager;
+ readonly ExternalCondition[] externalConditions;
+
readonly Dictionary> legacyShim = new Dictionary>();
public ConditionProperties(ScriptContext context, Actor self)
: base(context, self)
{
- conditionManager = self.Trait();
+ externalConditions = self.TraitsImplementing().ToArray();
}
[Desc("Grant an external condition on this actor and return the revocation token.",
@@ -36,22 +37,27 @@ namespace OpenRA.Mods.Common.Scripting
"If duration > 0 the condition will be automatically revoked after the defined number of ticks")]
public int GrantCondition(string condition, int duration = 0)
{
- if (!conditionManager.AcceptsExternalCondition(Self, condition, duration > 0))
- throw new InvalidDataException("Condition `{0}` has not been listed on an ExternalConditions trait".F(condition));
+ var external = externalConditions
+ .FirstOrDefault(t => t.Info.Condition == condition && t.CanGrantCondition(Self, this));
- return conditionManager.GrantCondition(Self, condition, true, duration);
+ if (external == null)
+ throw new InvalidDataException("Condition `{0}` has not been listed on an enabled ExternalCondition trait".F(condition));
+
+ return external.GrantCondition(Self, this, duration);
}
[Desc("Revoke a condition using the token returned by GrantCondition.")]
public void RevokeCondition(int token)
{
- conditionManager.RevokeCondition(Self, token);
+ foreach (var external in externalConditions)
+ external.TryRevokeCondition(Self, this, token);
}
[Desc("Check whether this actor accepts a specific external condition.")]
- public bool AcceptsCondition(string condition, bool timed = false)
+ public bool AcceptsCondition(string condition)
{
- return conditionManager.AcceptsExternalCondition(Self, condition, timed);
+ return externalConditions
+ .Any(t => t.Info.Condition == condition && t.CanGrantCondition(Self, this));
}
[Desc("Grant an upgrade to this actor. DEPRECATED! Will be removed.")]
diff --git a/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs b/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs
index 805756aaf5..b70f5460ae 100644
--- a/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs
+++ b/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs
@@ -63,9 +63,6 @@ namespace OpenRA.Mods.Common.Traits
/// Each granted condition receives a unique token that is used when revoking.
Dictionary tokens = new Dictionary();
- /// Set of whitelisted externally grantable conditions cached from ExternalConditions traits.
- string[] externalConditions = { };
-
/// Set of conditions that are monitored for stacked bonuses, and the bonus conditions that they grant.
readonly Dictionary stackedConditions = new Dictionary();
@@ -114,12 +111,6 @@ namespace OpenRA.Mods.Common.Traits
conditionCache[kv.Value] = conditionState.Tokens.Count > 0;
}
- // Build external condition whitelist
- externalConditions = self.Info.TraitInfos()
- .SelectMany(t => t.Conditions)
- .Distinct()
- .ToArray();
-
foreach (var sc in self.Info.TraitInfos())
{
stackedConditions[sc.Condition] = sc.StackedConditions;
@@ -172,11 +163,8 @@ namespace OpenRA.Mods.Common.Traits
/// The token that is used to revoke this condition.
/// Validate against the external condition whitelist.
/// Automatically revoke condition after this delay if non-zero.
- public int GrantCondition(Actor self, string condition, bool external = false, int duration = 0)
+ public int GrantCondition(Actor self, string condition, int duration = 0)
{
- if (external && !externalConditions.Contains(condition))
- return InvalidConditionToken;
-
var token = nextToken++;
tokens.Add(token, condition);
@@ -218,26 +206,6 @@ namespace OpenRA.Mods.Common.Traits
return InvalidConditionToken;
}
- /// Returns true if the given external condition will have an effect on this actor.
- public bool AcceptsExternalCondition(Actor self, string condition, bool timed = false)
- {
- if (state == null)
- throw new InvalidOperationException("AcceptsExternalCondition cannot be queried before the actor has been fully created.");
-
- if (!externalConditions.Contains(condition))
- return false;
-
- // A timed condition can always replace an existing timed condition (resetting its duration)
- if (timed && timers.ContainsKey(condition))
- return true;
-
- string[] sc;
- if (stackedConditions.TryGetValue(condition, out sc))
- return stackedTokens[condition].Count < sc.Length;
-
- return !conditionCache[condition];
- }
-
/// Returns whether the specified token is valid for RevokeCondition
public bool TokenValid(Actor self, int token)
{
diff --git a/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs
new file mode 100644
index 0000000000..8e9c0ab91d
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Conditions/ExternalCondition.cs
@@ -0,0 +1,142 @@
+#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;
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ [Desc("Allows a condition to be granted from an external source (Lua, warheads, etc).")]
+ public class ExternalConditionInfo : ITraitInfo, Requires
+ {
+ [GrantedConditionReference]
+ [FieldLoader.Require]
+ public readonly string Condition = null;
+
+ [Desc("If > 0, restrict the number of times that this condition can be granted by a single source.")]
+ public readonly int SourceCap = 0;
+
+ [Desc("If > 0, restrict the number of times that this condition can be granted by any source.")]
+ public readonly int TotalCap = 0;
+
+ public object Create(ActorInitializer init) { return new ExternalCondition(init.Self, this); }
+ }
+
+ public class ExternalCondition
+ {
+ class TimedToken
+ {
+ public int Token;
+ public int Expires;
+ }
+
+ public readonly ExternalConditionInfo Info;
+ readonly ConditionManager conditionManager;
+ readonly Dictionary