diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 3a646f5ebc..c06017d596 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -493,7 +493,7 @@
-
+
diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeActorsNear.cs b/OpenRA.Mods.Common/Traits/Upgrades/ProximityExternalCondition.cs
similarity index 76%
rename from OpenRA.Mods.Common/Traits/Upgrades/UpgradeActorsNear.cs
rename to OpenRA.Mods.Common/Traits/Upgrades/ProximityExternalCondition.cs
index ec0c19ad0d..3bfea5b832 100644
--- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeActorsNear.cs
+++ b/OpenRA.Mods.Common/Traits/Upgrades/ProximityExternalCondition.cs
@@ -9,16 +9,17 @@
*/
#endregion
+using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Applies an upgrade to actors within a specified range.")]
- public class UpgradeActorsNearInfo : ITraitInfo
+ public class ProximityExternalConditionInfo : ITraitInfo
{
- [UpgradeGrantedReference, FieldLoader.Require]
- [Desc("The upgrades to grant.")]
- public readonly string[] Upgrades = { };
+ [FieldLoader.Require]
+ [Desc("The condition to apply. Must be included in the target actor's ExternalConditions list.")]
+ public readonly string Condition = null;
[Desc("The range to search for actors to upgrade.")]
public readonly WDist Range = WDist.FromCells(3);
@@ -36,14 +37,16 @@ namespace OpenRA.Mods.Common.Traits
public readonly string EnableSound = null;
public readonly string DisableSound = null;
- public object Create(ActorInitializer init) { return new UpgradeActorsNear(init.Self, this); }
+ public object Create(ActorInitializer init) { return new ProximityExternalCondition(init.Self, this); }
}
- public class UpgradeActorsNear : ITick, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOtherProduction
+ public class ProximityExternalCondition : ITick, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyOtherProduction
{
- readonly UpgradeActorsNearInfo info;
+ readonly ProximityExternalConditionInfo info;
readonly Actor self;
+ readonly Dictionary tokens = new Dictionary();
+
int proximityTrigger;
WPos cachedPosition;
WDist cachedRange;
@@ -53,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits
bool cachedDisabled = true;
- public UpgradeActorsNear(Actor self, UpgradeActorsNearInfo info)
+ public ProximityExternalCondition(Actor self, ProximityExternalConditionInfo info)
{
this.info = info;
this.self = self;
@@ -106,9 +109,8 @@ namespace OpenRA.Mods.Common.Traits
return;
var um = a.TraitOrDefault();
- if (um != null)
- foreach (var u in info.Upgrades)
- um.GrantUpgrade(a, u, this);
+ if (um != null && !tokens.ContainsKey(a) && um.AcceptsExternalCondition(a, info.Condition))
+ tokens[a] = um.GrantCondition(a, info.Condition, true);
}
public void UnitProducedByOther(Actor self, Actor producer, Actor produced)
@@ -129,26 +131,24 @@ namespace OpenRA.Mods.Common.Traits
return;
var um = produced.TraitOrDefault();
- if (um != null)
- foreach (var u in info.Upgrades)
- if (um.AcknowledgesUpgrade(produced, u))
- um.GrantTimedUpgrade(produced, u, 1);
+ if (um != null && um.AcceptsExternalCondition(produced, info.Condition))
+ tokens[produced] = um.GrantCondition(produced, info.Condition, true);
}
}
void ActorExited(Actor a)
{
- if (a == self || a.Disposed || self.Disposed)
+ if (a.Disposed)
return;
- var stance = self.Owner.Stances[a.Owner];
- if (!info.ValidStances.HasStance(stance))
+ int token;
+ if (!tokens.TryGetValue(a, out token))
return;
+ tokens.Remove(a);
var um = a.TraitOrDefault();
if (um != null)
- foreach (var u in info.Upgrades)
- um.RevokeUpgrade(a, u, this);
+ um.RevokeCondition(a, token);
}
}
}
diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
index ec4e4e25fc..fec57ffaac 100644
--- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
+++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
@@ -567,6 +567,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
+ if (engineVersion < 20161212)
+ {
+ if (node.Key.StartsWith("UpgradeActorsNear", StringComparison.Ordinal))
+ {
+ RenameNodeKey(node, "ProximityExternalCondition");
+ ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition");
+ }
+ }
+
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
}
diff --git a/mods/ra/maps/allies-03a/rules.yaml b/mods/ra/maps/allies-03a/rules.yaml
index 2955853830..308bad527b 100644
--- a/mods/ra/maps/allies-03a/rules.yaml
+++ b/mods/ra/maps/allies-03a/rules.yaml
@@ -34,6 +34,8 @@ HACKE6:
CaptureTypes: building
Targetable:
RequiresCondition: !jail
+ ExternalConditions@JAIL:
+ Conditions: jail
Targetable@PRISONER:
TargetTypes: Prisoner
RenderSprites:
@@ -42,6 +44,8 @@ HACKE6:
MEDI:
Targetable:
RequiresCondition: !jail
+ ExternalConditions@JAIL:
+ Conditions: jail
Targetable@PRISONER:
TargetTypes: Prisoner
@@ -50,8 +54,8 @@ PRISON:
Type: CenterPosition
Immobile:
OccupiesSpace: false
- UpgradeActorsNear:
- Upgrades: jail
+ ProximityExternalCondition:
+ Condition: jail
Range: 1c0
CAMERA:
diff --git a/mods/ra/maps/allies-03b/rules.yaml b/mods/ra/maps/allies-03b/rules.yaml
index 530c8d2656..78d533e0c0 100644
--- a/mods/ra/maps/allies-03b/rules.yaml
+++ b/mods/ra/maps/allies-03b/rules.yaml
@@ -35,6 +35,8 @@ HACKE6:
WithInfantryBody:
Targetable:
RequiresCondition: !jail
+ ExternalConditions@JAIL:
+ Conditions: jail
Targetable@PRISONER:
TargetTypes: Prisoner
RenderSprites:
@@ -43,6 +45,8 @@ HACKE6:
MEDI:
Targetable:
RequiresCondition: !jail
+ ExternalConditions@JAIL:
+ Conditions: jail
Targetable@PRISONER:
TargetTypes: Prisoner
@@ -51,8 +55,8 @@ PRISON:
Type: CenterPosition
Immobile:
OccupiesSpace: false
- UpgradeActorsNear:
- Upgrades: jail
+ ProximityExternalCondition:
+ Condition: jail
Range: 1c0
CAMERA:
diff --git a/mods/ts/rules/civilian-structures.yaml b/mods/ts/rules/civilian-structures.yaml
index e6ece37203..8ea04c9022 100644
--- a/mods/ts/rules/civilian-structures.yaml
+++ b/mods/ts/rules/civilian-structures.yaml
@@ -1263,7 +1263,7 @@ GALITE:
Prerequisites: ~disabled
SelectionDecorations:
VisualBounds: 25, 35, 0, -12
- -Cloak@CLOAKGENERATOR:
+ -Cloak@EXTERNALCLOAK:
TSTLAMP:
Inherits: GALITE
diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml
index 92e305909a..e5d7fde952 100644
--- a/mods/ts/rules/defaults.yaml
+++ b/mods/ts/rules/defaults.yaml
@@ -94,7 +94,7 @@
RequiresCondition: !empdisable && !deployed && !loading
^Cloakable:
- Cloak@CLOAKGENERATOR:
+ Cloak@EXTERNALCLOAK:
RequiresCondition: cloakgenerator || crate-cloak
InitialDelay: 0
CloakDelay: 90
@@ -102,6 +102,8 @@
CloakSound: cloak5.aud
UncloakSound: cloak5.aud
UncloakOn: Attack, Unload, Infiltrate, Demolish, Damage
+ ExternalConditions@EXTERNALCLOAK:
+ Conditions: cloakgenerator, crate-cloak
^BasicBuilding:
Inherits@1: ^ExistsInWorld
diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml
index c1d8a21afa..e2346a6604 100644
--- a/mods/ts/rules/nod-structures.yaml
+++ b/mods/ts/rules/nod-structures.yaml
@@ -396,8 +396,8 @@ NASTLH:
PowerupSpeech: EnablePower
PowerdownSpeech: DisablePower
IndicatorPalette: mouse
- UpgradeActorsNear:
- Upgrades: cloakgenerator
+ ProximityExternalCondition:
+ Condition: cloakgenerator
Range: 12c0
EnableSound: cloak5.aud
DisableSound: cloak5.aud