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