diff --git a/OpenRA.Mods.Common/Activities/Parachute.cs b/OpenRA.Mods.Common/Activities/Parachute.cs index 834e63f721..009171fad9 100644 --- a/OpenRA.Mods.Common/Activities/Parachute.cs +++ b/OpenRA.Mods.Common/Activities/Parachute.cs @@ -17,7 +17,6 @@ namespace OpenRA.Mods.Common.Activities { public class Parachute : Activity { - readonly UpgradeManager um; readonly IPositionable pos; readonly ParachutableInfo para; readonly WVec fallVector; @@ -29,7 +28,6 @@ namespace OpenRA.Mods.Common.Activities public Parachute(Actor self, WPos dropPosition, Actor ignoreActor = null) { - um = self.TraitOrDefault(); pos = self.TraitOrDefault(); ignore = ignoreActor; @@ -44,9 +42,8 @@ namespace OpenRA.Mods.Common.Activities { triggered = true; - if (um != null) - foreach (var u in para.ParachuteUpgrade) - um.GrantUpgrade(self, u, this); + foreach (var np in self.TraitsImplementing()) + np.OnParachute(self); // Place the actor and retrieve its visual position (CenterPosition) pos.SetPosition(self, dropPosition); @@ -60,12 +57,8 @@ namespace OpenRA.Mods.Common.Activities var dat = self.World.Map.DistanceAboveTerrain(currentPosition); pos.SetPosition(self, currentPosition - new WVec(WDist.Zero, WDist.Zero, dat)); - if (um != null) - foreach (var u in para.ParachuteUpgrade) - um.RevokeUpgrade(self, u, this); - - foreach (var npl in self.TraitsImplementing()) - npl.OnLanded(ignore); + foreach (var np in self.TraitsImplementing()) + np.OnLanded(self, ignore); return NextActivity; } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index c06017d596..3dfe883214 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -331,7 +331,7 @@ - + @@ -373,7 +373,7 @@ - + @@ -490,13 +490,13 @@ - - + + - - - + + + diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index c43946e7f8..8b19fe40df 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -53,12 +53,12 @@ namespace OpenRA.Mods.Common.Traits [VoiceReference] public readonly string Voice = "Action"; [UpgradeGrantedReference] - [Desc("The upgrades to grant to self while airborne.")] - public readonly string[] AirborneUpgrades = { }; + [Desc("The condition to grant to self while airborne.")] + public readonly string AirborneCondition = null; [UpgradeGrantedReference] - [Desc("The upgrades to grant to self while at cruise altitude.")] - public readonly string[] CruisingUpgrades = { }; + [Desc("The condition to grant to self while at cruise altitude.")] + public readonly string CruisingCondition = null; [Desc("Can the actor hover in place mid-air? If not, then the actor will have to remain in motion (circle around).")] public readonly bool CanHover = false; @@ -119,6 +119,8 @@ namespace OpenRA.Mods.Common.Traits bool airborne; bool cruising; bool firstTick = true; + int airborneToken = UpgradeManager.InvalidConditionToken; + int cruisingToken = UpgradeManager.InvalidConditionToken; bool isMoving; bool isMovingVertically; @@ -656,20 +658,20 @@ namespace OpenRA.Mods.Common.Traits { if (airborne) return; + airborne = true; - if (um != null) - foreach (var u in Info.AirborneUpgrades) - um.GrantUpgrade(self, u, this); + if (um != null && !string.IsNullOrEmpty(Info.AirborneCondition) && airborneToken == UpgradeManager.InvalidConditionToken) + airborneToken = um.GrantCondition(self, Info.AirborneCondition); } void OnAirborneAltitudeLeft() { if (!airborne) return; + airborne = false; - if (um != null) - foreach (var u in Info.AirborneUpgrades) - um.RevokeUpgrade(self, u, this); + if (um != null && airborneToken != UpgradeManager.InvalidConditionToken) + airborneToken = um.RevokeCondition(self, airborneToken); } #endregion @@ -680,10 +682,10 @@ namespace OpenRA.Mods.Common.Traits { if (cruising) return; + cruising = true; - if (um != null) - foreach (var u in Info.CruisingUpgrades) - um.GrantUpgrade(self, u, this); + if (um != null && !string.IsNullOrEmpty(Info.CruisingCondition) && cruisingToken == UpgradeManager.InvalidConditionToken) + cruisingToken = um.GrantCondition(self, Info.CruisingCondition); } void OnCruisingAltitudeLeft() @@ -691,9 +693,8 @@ namespace OpenRA.Mods.Common.Traits if (!cruising) return; cruising = false; - if (um != null) - foreach (var u in Info.CruisingUpgrades) - um.RevokeUpgrade(self, u, this); + if (um != null && cruisingToken != UpgradeManager.InvalidConditionToken) + cruisingToken = um.RevokeCondition(self, cruisingToken); } #endregion diff --git a/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs b/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs index ba9c11adea..25fda44e21 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/PrimaryBuilding.cs @@ -26,10 +26,11 @@ namespace OpenRA.Mods.Common.Traits } [Desc("Used together with ClassicProductionQueue.")] - public class PrimaryBuildingInfo : ITraitInfo, Requires + public class PrimaryBuildingInfo : ITraitInfo { - [UpgradeGrantedReference, Desc("The upgrades to grant while the primary building.")] - public readonly string[] Upgrades = { "primary" }; + [UpgradeGrantedReference] + [Desc("The condition to grant to self while this is the primary building.")] + public readonly string PrimaryCondition = null; [Desc("The speech notification to play when selecting a primary building.")] public readonly string SelectionNotification = "PrimaryBuildingSelected"; @@ -37,25 +38,30 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new PrimaryBuilding(init.Self, this); } } - public class PrimaryBuilding : IIssueOrder, IResolveOrder + public class PrimaryBuilding : INotifyCreated, IIssueOrder, IResolveOrder { readonly PrimaryBuildingInfo info; - readonly UpgradeManager manager; + UpgradeManager um; + int primaryToken = UpgradeManager.InvalidConditionToken; public bool IsPrimary { get; private set; } public PrimaryBuilding(Actor self, PrimaryBuildingInfo info) { this.info = info; - manager = self.Trait(); } - public IEnumerable Orders + void INotifyCreated.Created(Actor self) + { + um = self.TraitOrDefault(); + } + + IEnumerable IIssueOrder.Orders { get { yield return new DeployOrderTargeter("PrimaryProducer", 1); } } - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) { if (order.OrderID == "PrimaryProducer") return new Order(order.OrderID, self, false); @@ -63,41 +69,39 @@ namespace OpenRA.Mods.Common.Traits return null; } - public void ResolveOrder(Actor self, Order order) + void IResolveOrder.ResolveOrder(Actor self, Order order) { if (order.OrderString == "PrimaryProducer") SetPrimaryProducer(self, !IsPrimary); } - public void SetPrimaryProducer(Actor self, bool state) + public void SetPrimaryProducer(Actor self, bool isPrimary) { - if (state == false) + IsPrimary = isPrimary; + + if (isPrimary) { - IsPrimary = false; - foreach (var up in info.Upgrades) - manager.RevokeUpgrade(self, up, this); - return; + // Cancel existing primaries + // TODO: THIS IS SHIT + foreach (var p in self.Info.TraitInfo().Produces) + { + foreach (var b in self.World + .ActorsWithTrait() + .Where(a => + a.Actor != self && + a.Actor.Owner == self.Owner && + a.Trait.IsPrimary && + a.Actor.Info.TraitInfo().Produces.Contains(p))) + b.Trait.SetPrimaryProducer(b.Actor, false); + } + + if (um != null && primaryToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(info.PrimaryCondition)) + primaryToken = um.GrantCondition(self, info.PrimaryCondition); + + Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SelectionNotification, self.Owner.Faction.InternalName); } - - // TODO: THIS IS SHIT - // Cancel existing primaries - foreach (var p in self.Info.TraitInfo().Produces) - { - var productionType = p; // benign closure hazard - foreach (var b in self.World - .ActorsWithTrait() - .Where(a => - a.Actor.Owner == self.Owner && - a.Trait.IsPrimary && - a.Actor.Info.TraitInfo().Produces.Contains(productionType))) - b.Trait.SetPrimaryProducer(b.Actor, false); - } - - IsPrimary = true; - foreach (var up in info.Upgrades) - manager.GrantUpgrade(self, up, this); - - Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SelectionNotification, self.Owner.Faction.InternalName); + else if (primaryToken != UpgradeManager.InvalidConditionToken) + primaryToken = um.RevokeCondition(self, primaryToken); } } } diff --git a/OpenRA.Mods.Common/Traits/Cloak.cs b/OpenRA.Mods.Common/Traits/Cloak.cs index b875ef056a..3e5706a8b8 100644 --- a/OpenRA.Mods.Common/Traits/Cloak.cs +++ b/OpenRA.Mods.Common/Traits/Cloak.cs @@ -54,8 +54,8 @@ namespace OpenRA.Mods.Common.Traits public readonly HashSet CloakTypes = new HashSet { "Cloak" }; [UpgradeGrantedReference] - [Desc("The upgrades to grant to self while cloaked.")] - public readonly string[] WhileCloakedUpgrades = { }; + [Desc("The condition to grant to self while cloaked.")] + public readonly string CloakedCondition = null; public override object Create(ActorInitializer init) { return new Cloak(this); } } @@ -70,6 +70,7 @@ namespace OpenRA.Mods.Common.Traits CPos? lastPos; bool wasCloaked = false; + int cloakedToken = UpgradeManager.InvalidConditionToken; public Cloak(CloakInfo info) : base(info) @@ -81,12 +82,11 @@ namespace OpenRA.Mods.Common.Traits { upgradeManager = self.TraitOrDefault(); - // The upgrade manager exists, but may not have finished being created yet. - // We'll defer the upgrades until the end of the tick, at which point it will be ready. if (Cloaked) { wasCloaked = true; - self.World.AddFrameEndTask(_ => GrantUpgrades(self)); + if (upgradeManager != null && cloakedToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CloakedCondition)) + cloakedToken = upgradeManager.GrantCondition(self, Info.CloakedCondition); } } @@ -144,13 +144,17 @@ namespace OpenRA.Mods.Common.Traits var isCloaked = Cloaked; if (isCloaked && !wasCloaked) { - GrantUpgrades(self); + if (upgradeManager != null && cloakedToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.CloakedCondition)) + cloakedToken = upgradeManager.GrantCondition(self, Info.CloakedCondition); + if (!self.TraitsImplementing().Any(a => a != this && a.Cloaked)) Game.Sound.Play(Info.CloakSound, self.CenterPosition); } else if (!isCloaked && wasCloaked) { - RevokeUpgrades(self); + if (cloakedToken != UpgradeManager.InvalidConditionToken) + cloakedToken = upgradeManager.RevokeCondition(self, cloakedToken); + if (!self.TraitsImplementing().Any(a => a != this && a.Cloaked)) Game.Sound.Play(Info.UncloakSound, self.CenterPosition); } @@ -176,20 +180,6 @@ namespace OpenRA.Mods.Common.Traits return color; } - void GrantUpgrades(Actor self) - { - if (upgradeManager != null) - foreach (var u in Info.WhileCloakedUpgrades) - upgradeManager.GrantUpgrade(self, u, this); - } - - void RevokeUpgrades(Actor self) - { - if (upgradeManager != null) - foreach (var u in Info.WhileCloakedUpgrades) - upgradeManager.RevokeUpgrade(self, u, this); - } - void INotifyHarvesterAction.MovingToResources(Actor self, CPos targetCell, Activity next) { } void INotifyHarvesterAction.MovingToRefinery(Actor self, CPos targetCell, Activity next) { } diff --git a/OpenRA.Mods.Common/Traits/Crates/Crate.cs b/OpenRA.Mods.Common/Traits/Crates/Crate.cs index 422ef39c3c..4ab79c1f7d 100644 --- a/OpenRA.Mods.Common/Traits/Crates/Crate.cs +++ b/OpenRA.Mods.Common/Traits/Crates/Crate.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits } class Crate : ITick, IPositionable, ICrushable, ISync, - INotifyParachuteLanded, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyCrushed + INotifyParachute, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyCrushed { readonly Actor self; readonly CrateInfo info; @@ -70,7 +70,8 @@ namespace OpenRA.Mods.Common.Traits OnCrushInner(crusher); } - void INotifyParachuteLanded.OnLanded(Actor ignore) + void INotifyParachute.OnParachute(Actor self) { } + void INotifyParachute.OnLanded(Actor self, Actor ignore) { // Check whether the crate landed on anything var landedOn = self.World.ActorMap.GetActorsAt(self.Location) diff --git a/OpenRA.Mods.Common/Traits/GainsExperience.cs b/OpenRA.Mods.Common/Traits/GainsExperience.cs index 7c0a55c7f9..c0deb86f02 100644 --- a/OpenRA.Mods.Common/Traits/GainsExperience.cs +++ b/OpenRA.Mods.Common/Traits/GainsExperience.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Mods.Common.Effects; using OpenRA.Primitives; using OpenRA.Traits; @@ -18,13 +19,13 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor's experience increases when it has killed a GivesExperience actor.")] - public class GainsExperienceInfo : ITraitInfo, Requires, Requires + public class GainsExperienceInfo : ITraitInfo, Requires { [FieldLoader.Require] - [Desc("Upgrades to grant at each level.", + [Desc("Condition to grant at each level.", "Key is the XP requirements for each level as a percentage of our own value.", "Value is a list of the upgrade types to grant")] - public readonly Dictionary Upgrades = null; + public readonly Dictionary Conditions = null; [Desc("Palette for the level up sprite.")] [PaletteReference] public readonly string LevelUpPalette = "effect"; @@ -35,13 +36,14 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new GainsExperience(init, this); } } - public class GainsExperience : ISync, IResolveOrder + public class GainsExperience : INotifyCreated, ISync, IResolveOrder { readonly Actor self; readonly GainsExperienceInfo info; - readonly UpgradeManager um; + readonly int initialExperience; - readonly List> nextLevel = new List>(); + readonly List> nextLevel = new List>(); + UpgradeManager um; // Stored as a percentage of our value [Sync] int experience = 0; @@ -54,16 +56,20 @@ namespace OpenRA.Mods.Common.Traits self = init.Self; this.info = info; - MaxLevel = info.Upgrades.Count; - + MaxLevel = info.Conditions.Count; var cost = self.Info.TraitInfo().Cost; - foreach (var kv in info.Upgrades) + foreach (var kv in info.Conditions) nextLevel.Add(Pair.New(kv.Key * cost, kv.Value)); if (init.Contains()) - GiveExperience(init.Get(), info.SuppressLevelupAnimation); + initialExperience = init.Get(); + } - um = self.Trait(); + void INotifyCreated.Created(Actor self) + { + um = self.TraitOrDefault(); + if (initialExperience > 0) + GiveExperience(initialExperience, info.SuppressLevelupAnimation); } public bool CanGainLevel { get { return Level < MaxLevel; } } @@ -76,17 +82,18 @@ namespace OpenRA.Mods.Common.Traits public void GiveExperience(int amount, bool silent = false) { + if (amount < 0) + throw new ArgumentException("Revoking experience is not implemented.", "amount"); + experience += amount; while (Level < MaxLevel && experience >= nextLevel[Level].First) { - var upgrades = nextLevel[Level].Second; + if (um != null) + um.GrantCondition(self, nextLevel[Level].Second); Level++; - foreach (var u in upgrades) - um.GrantUpgrade(self, u, this); - if (!silent) { Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", "LevelUp", self.Owner.Faction.InternalName); diff --git a/OpenRA.Mods.Common/Traits/GlobalUpgradable.cs b/OpenRA.Mods.Common/Traits/GlobalUpgradable.cs deleted file mode 100644 index c9f9a3c652..0000000000 --- a/OpenRA.Mods.Common/Traits/GlobalUpgradable.cs +++ /dev/null @@ -1,72 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 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.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - [Desc("Grants upgrades to the actor this is attached to when prerequisites are available.")] - public class GlobalUpgradableInfo : ITraitInfo, Requires - { - [UpgradeGrantedReference, FieldLoader.Require] - [Desc("List of upgrades to apply.")] - public readonly string[] Upgrades = { }; - - [FieldLoader.Require] - [Desc("List of required prerequisites.")] - public readonly string[] Prerequisites = { }; - - public object Create(ActorInitializer init) { return new GlobalUpgradable(init.Self, this); } - } - - public class GlobalUpgradable : INotifyAddedToWorld, INotifyRemovedFromWorld - { - readonly GlobalUpgradableInfo info; - readonly GlobalUpgradeManager globalManager; - readonly UpgradeManager manager; - bool wasAvailable; - - public GlobalUpgradable(Actor self, GlobalUpgradableInfo info) - { - this.info = info; - globalManager = self.Owner.PlayerActor.Trait(); - manager = self.Trait(); - } - - public void AddedToWorld(Actor self) - { - if (info.Prerequisites.Any()) - globalManager.Register(self, this, info.Prerequisites); - } - - public void RemovedFromWorld(Actor self) - { - if (info.Prerequisites.Any()) - globalManager.Unregister(self, this, info.Prerequisites); - } - - public void PrerequisitesUpdated(Actor self, bool available) - { - if (available == wasAvailable) - return; - - if (available) - foreach (var u in info.Upgrades) - manager.GrantUpgrade(self, u, this); - else - foreach (var u in info.Upgrades) - manager.RevokeUpgrade(self, u, this); - - wasAvailable = available; - } - } -} diff --git a/OpenRA.Mods.Common/Traits/GrantConditionOnPrerequisite.cs b/OpenRA.Mods.Common/Traits/GrantConditionOnPrerequisite.cs new file mode 100644 index 0000000000..77b01d7f7c --- /dev/null +++ b/OpenRA.Mods.Common/Traits/GrantConditionOnPrerequisite.cs @@ -0,0 +1,78 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Grants a condition to the actor this is attached to when prerequisites are available.")] + public class GrantConditionOnPrerequisiteInfo : ITraitInfo + { + [FieldLoader.Require] + [UpgradeGrantedReference] + [Desc("The condition to grant.")] + public readonly string Condition = null; + + [FieldLoader.Require] + [Desc("List of required prerequisites.")] + public readonly string[] Prerequisites = { }; + + public object Create(ActorInitializer init) { return new GrantConditionOnPrerequisite(init.Self, this); } + } + + public class GrantConditionOnPrerequisite : INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld + { + readonly GrantConditionOnPrerequisiteInfo info; + readonly GrantConditionOnPrerequisiteManager globalManager; + + UpgradeManager manager; + int conditionToken = UpgradeManager.InvalidConditionToken; + + bool wasAvailable; + + public GrantConditionOnPrerequisite(Actor self, GrantConditionOnPrerequisiteInfo info) + { + this.info = info; + globalManager = self.Owner.PlayerActor.Trait(); + } + + void INotifyCreated.Created(Actor self) + { + manager = self.TraitOrDefault(); + } + + void INotifyAddedToWorld.AddedToWorld(Actor self) + { + if (info.Prerequisites.Any()) + globalManager.Register(self, this, info.Prerequisites); + } + + void INotifyRemovedFromWorld.RemovedFromWorld(Actor self) + { + if (info.Prerequisites.Any()) + globalManager.Unregister(self, this, info.Prerequisites); + } + + public void PrerequisitesUpdated(Actor self, bool available) + { + if (available == wasAvailable || manager == null) + return; + + if (available && conditionToken == UpgradeManager.InvalidConditionToken) + conditionToken = manager.GrantCondition(self, info.Condition); + else if (!available && conditionToken != UpgradeManager.InvalidConditionToken) + conditionToken = manager.RevokeCondition(self, conditionToken); + + wasAvailable = available; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Parachutable.cs b/OpenRA.Mods.Common/Traits/Parachutable.cs index 3901f6d350..7301c197ef 100644 --- a/OpenRA.Mods.Common/Traits/Parachutable.cs +++ b/OpenRA.Mods.Common/Traits/Parachutable.cs @@ -39,27 +39,42 @@ namespace OpenRA.Mods.Common.Traits public readonly int FallRate = 13; [UpgradeGrantedReference] - [Desc("Upgrade to grant to this actor when parachuting. Normally used to render the parachute using the WithParachute trait.")] - public readonly string[] ParachuteUpgrade = { "parachute" }; + [Desc("The condition to grant to self while parachuting.")] + public readonly string ParachutingCondition = null; - public object Create(ActorInitializer init) { return new Parachutable(init, this); } + public object Create(ActorInitializer init) { return new Parachutable(init.Self, this); } } - class Parachutable : INotifyParachuteLanded + class Parachutable : INotifyCreated, INotifyParachute { - readonly Actor self; readonly ParachutableInfo info; readonly IPositionable positionable; - public Parachutable(ActorInitializer init, ParachutableInfo info) + UpgradeManager um; + int parachutingToken = UpgradeManager.InvalidConditionToken; + + public Parachutable(Actor self, ParachutableInfo info) { - self = init.Self; this.info = info; positionable = self.Trait(); } - void INotifyParachuteLanded.OnLanded(Actor ignore) + void INotifyCreated.Created(Actor self) { + um = self.TraitOrDefault(); + } + + void INotifyParachute.OnParachute(Actor self) + { + if (um != null && parachutingToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(info.ParachutingCondition)) + parachutingToken = um.GrantCondition(self, info.ParachutingCondition); + } + + void INotifyParachute.OnLanded(Actor self, Actor ignore) + { + if (parachutingToken != UpgradeManager.InvalidConditionToken) + parachutingToken = um.RevokeCondition(self, parachutingToken); + if (!info.KilledOnImpassableTerrain) return; diff --git a/OpenRA.Mods.Common/Traits/Player/GlobalUpgradeManager.cs b/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs similarity index 68% rename from OpenRA.Mods.Common/Traits/Player/GlobalUpgradeManager.cs rename to OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs index 30159665b1..5328c3ec1b 100644 --- a/OpenRA.Mods.Common/Traits/Player/GlobalUpgradeManager.cs +++ b/OpenRA.Mods.Common/Traits/Player/GrantConditionOnPrerequisiteManager.cs @@ -17,18 +17,18 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Attach this to the player actor.")] - public class GlobalUpgradeManagerInfo : ITraitInfo, Requires + public class GrantConditionOnPrerequisiteManagerInfo : ITraitInfo, Requires { - public object Create(ActorInitializer init) { return new GlobalUpgradeManager(init); } + public object Create(ActorInitializer init) { return new GrantConditionOnPrerequisiteManager(init); } } - public class GlobalUpgradeManager : ITechTreeElement + public class GrantConditionOnPrerequisiteManager : ITechTreeElement { readonly Actor self; - readonly Dictionary>> upgradables = new Dictionary>>(); + readonly Dictionary>> upgradables = new Dictionary>>(); readonly TechTree techTree; - public GlobalUpgradeManager(ActorInitializer init) + public GrantConditionOnPrerequisiteManager(ActorInitializer init) { self = init.Self; techTree = self.Trait(); @@ -39,12 +39,12 @@ namespace OpenRA.Mods.Common.Traits return "upgrade_" + string.Join("_", prerequisites.OrderBy(a => a)); } - public void Register(Actor actor, GlobalUpgradable u, string[] prerequisites) + public void Register(Actor actor, GrantConditionOnPrerequisite u, string[] prerequisites) { var key = MakeKey(prerequisites); if (!upgradables.ContainsKey(key)) { - upgradables.Add(key, new List>()); + upgradables.Add(key, new List>()); techTree.Add(key, prerequisites, 0, this); } @@ -54,7 +54,7 @@ namespace OpenRA.Mods.Common.Traits u.PrerequisitesUpdated(actor, techTree.HasPrerequisites(prerequisites)); } - public void Unregister(Actor actor, GlobalUpgradable u, string[] prerequisites) + public void Unregister(Actor actor, GrantConditionOnPrerequisite u, string[] prerequisites) { var key = MakeKey(prerequisites); var list = upgradables[key]; @@ -69,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits public void PrerequisitesAvailable(string key) { - List> list; + List> list; if (!upgradables.TryGetValue(key, out list)) return; @@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Traits public void PrerequisitesUnavailable(string key) { - List> list; + List> list; if (!upgradables.TryGetValue(key, out list)) return; diff --git a/OpenRA.Mods.Common/Traits/Pluggable.cs b/OpenRA.Mods.Common/Traits/Pluggable.cs index e27ec24929..d1214be5b6 100644 --- a/OpenRA.Mods.Common/Traits/Pluggable.cs +++ b/OpenRA.Mods.Common/Traits/Pluggable.cs @@ -14,13 +14,15 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class PluggableInfo : ITraitInfo, Requires, UsesInit + public class PluggableInfo : ITraitInfo, UsesInit { [Desc("Footprint cell offset where a plug can be placed.")] public readonly CVec Offset = CVec.Zero; - [FieldLoader.Require, Desc("Upgrades to grant for each accepted plug type.")] - public readonly Dictionary Upgrades = null; + [FieldLoader.Require] + [UpgradeGrantedReference] + [Desc("Conditions to grant for each accepted plug type.")] + public readonly Dictionary Conditions = null; public object Create(ActorInitializer init) { return new Pluggable(init, this); } } @@ -30,14 +32,14 @@ namespace OpenRA.Mods.Common.Traits public readonly PluggableInfo Info; readonly string initialPlug; - readonly UpgradeManager upgradeManager; + UpgradeManager upgradeManager; + int conditionToken = UpgradeManager.InvalidConditionToken; string active; public Pluggable(ActorInitializer init, PluggableInfo info) { Info = info; - upgradeManager = init.Self.Trait(); var plugInit = init.Contains() ? init.Get>() : new Dictionary(); if (plugInit.ContainsKey(Info.Offset)) @@ -46,24 +48,24 @@ namespace OpenRA.Mods.Common.Traits public void Created(Actor self) { + upgradeManager = self.TraitOrDefault(); + if (!string.IsNullOrEmpty(initialPlug)) EnablePlug(self, initialPlug); } public bool AcceptsPlug(Actor self, string type) { - return active == null && Info.Upgrades.ContainsKey(type); + return active == null && Info.Conditions.ContainsKey(type); } public void EnablePlug(Actor self, string type) { - string[] upgrades; - if (!Info.Upgrades.TryGetValue(type, out upgrades)) + string condition; + if (!Info.Conditions.TryGetValue(type, out condition)) return; - foreach (var u in upgrades) - upgradeManager.GrantUpgrade(self, u, this); - + conditionToken = upgradeManager.GrantCondition(self, condition); active = type; } @@ -72,8 +74,10 @@ namespace OpenRA.Mods.Common.Traits if (type != active) return; - foreach (var u in Info.Upgrades[type]) - upgradeManager.RevokeUpgrade(self, u, this); + if (conditionToken != UpgradeManager.InvalidConditionToken) + conditionToken = upgradeManager.RevokeCondition(self, conditionToken); + + active = null; } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs b/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs index a111d68e91..54dc53808d 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits.Render } } - class WithCrateBody : INotifyParachuteLanded, INotifyAddedToWorld + class WithCrateBody : INotifyParachute, INotifyAddedToWorld { readonly Actor self; readonly Animation anim; @@ -70,7 +70,9 @@ namespace OpenRA.Mods.Common.Traits.Render PlaySequence(); } - void INotifyParachuteLanded.OnLanded(Actor ignore) + void INotifyParachute.OnParachute(Actor self) { } + + void INotifyParachute.OnLanded(Actor self, Actor ignore) { PlaySequence(); } diff --git a/OpenRA.Mods.Common/Traits/Upgrades/DisableOnUpgrade.cs b/OpenRA.Mods.Common/Traits/Upgrades/DisableOnCondition.cs similarity index 75% rename from OpenRA.Mods.Common/Traits/Upgrades/DisableOnUpgrade.cs rename to OpenRA.Mods.Common/Traits/Upgrades/DisableOnCondition.cs index b15e2debd6..225fd5d461 100644 --- a/OpenRA.Mods.Common/Traits/Upgrades/DisableOnUpgrade.cs +++ b/OpenRA.Mods.Common/Traits/Upgrades/DisableOnCondition.cs @@ -14,14 +14,14 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Disable the actor when this trait is enabled by an upgrade.")] - public class DisableOnUpgradeInfo : UpgradableTraitInfo + public class DisableOnConditionInfo : UpgradableTraitInfo { - public override object Create(ActorInitializer init) { return new DisableOnUpgrade(this); } + public override object Create(ActorInitializer init) { return new DisableOnCondition(this); } } - public class DisableOnUpgrade : UpgradableTrait, IDisable + public class DisableOnCondition : UpgradableTrait, IDisable { - public DisableOnUpgrade(DisableOnUpgradeInfo info) + public DisableOnCondition(DisableOnConditionInfo info) : base(info) { } public bool Disabled { get { return !IsTraitDisabled; } } diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnDamageState.cs b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDamageState.cs similarity index 57% rename from OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnDamageState.cs rename to OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDamageState.cs index 0fd2711631..630d5d372d 100644 --- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnDamageState.cs +++ b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDamageState.cs @@ -14,11 +14,12 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Applies an upgrade to the actor at specified damage states.")] - public class UpgradeOnDamageStateInfo : ITraitInfo, Requires, Requires + public class GrantConditionOnDamageStateInfo : ITraitInfo, Requires { - [UpgradeGrantedReference, FieldLoader.Require] - [Desc("The upgrades to grant.")] - public readonly string[] Upgrades = { }; + [FieldLoader.Require] + [UpgradeGrantedReference] + [Desc("Condition to grant.")] + public readonly string Condition = null; [Desc("Play a random sound from this list when enabled.")] public readonly string[] EnabledSounds = { }; @@ -29,59 +30,57 @@ namespace OpenRA.Mods.Common.Traits [Desc("Levels of damage at which to grant upgrades.")] public readonly DamageState ValidDamageStates = DamageState.Heavy | DamageState.Critical; - [Desc("Are upgrades irrevocable once the conditions have been met?")] + [Desc("Is the condition irrevocable once it has been activated?")] public readonly bool GrantPermanently = false; - public object Create(ActorInitializer init) { return new UpgradeOnDamageState(init.Self, this); } + public object Create(ActorInitializer init) { return new GrantConditionOnDamageState(init.Self, this); } } - public class UpgradeOnDamageState : INotifyDamageStateChanged, INotifyCreated + public class GrantConditionOnDamageState : INotifyDamageStateChanged, INotifyCreated { - readonly UpgradeOnDamageStateInfo info; - readonly UpgradeManager um; + readonly GrantConditionOnDamageStateInfo info; readonly Health health; - bool granted; - public UpgradeOnDamageState(Actor self, UpgradeOnDamageStateInfo info) + UpgradeManager manager; + int conditionToken = UpgradeManager.InvalidConditionToken; + + public GrantConditionOnDamageState(Actor self, GrantConditionOnDamageStateInfo info) { this.info = info; - um = self.Trait(); health = self.Trait(); } void INotifyCreated.Created(Actor self) { + manager = self.TraitOrDefault(); GrantUpgradeOnValidDamageState(self, health.DamageState); } void GrantUpgradeOnValidDamageState(Actor self, DamageState state) { - if (!info.ValidDamageStates.HasFlag(state)) + if (!info.ValidDamageStates.HasFlag(state) || conditionToken != UpgradeManager.InvalidConditionToken) return; - granted = true; - var rand = Game.CosmeticRandom; - var sound = info.EnabledSounds.RandomOrDefault(rand); + conditionToken = manager.GrantCondition(self, info.Condition); + + var sound = info.EnabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(sound, self.CenterPosition); - foreach (var u in info.Upgrades) - um.GrantUpgrade(self, u, this); } void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) { - if (granted && info.GrantPermanently) + var granted = conditionToken != UpgradeManager.InvalidConditionToken; + if ((granted && info.GrantPermanently) || manager == null) return; if (!granted && !info.ValidDamageStates.HasFlag(e.PreviousDamageState)) GrantUpgradeOnValidDamageState(self, health.DamageState); else if (granted && !info.ValidDamageStates.HasFlag(e.DamageState) && info.ValidDamageStates.HasFlag(e.PreviousDamageState)) { - granted = false; - var rand = Game.CosmeticRandom; - var sound = info.DisabledSounds.RandomOrDefault(rand); + conditionToken = manager.RevokeCondition(self, conditionToken); + + var sound = info.DisabledSounds.RandomOrDefault(Game.CosmeticRandom); Game.Sound.Play(sound, self.CenterPosition); - foreach (var u in info.Upgrades) - um.RevokeUpgrade(self, u, this); } } } diff --git a/OpenRA.Mods.Common/Traits/Upgrades/DeployToUpgrade.cs b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDeploy.cs similarity index 82% rename from OpenRA.Mods.Common/Traits/Upgrades/DeployToUpgrade.cs rename to OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDeploy.cs index 317b303c69..3272deeb24 100644 --- a/OpenRA.Mods.Common/Traits/Upgrades/DeployToUpgrade.cs +++ b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnDeploy.cs @@ -19,15 +19,15 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class DeployToUpgradeInfo : ITraitInfo, Requires + public class GrantConditionOnDeployInfo : ITraitInfo { [UpgradeGrantedReference] - [Desc("The upgrades to grant while the actor is undeployed.")] - public readonly string[] UndeployedUpgrades = { }; + [Desc("The condition to grant while the actor is undeployed.")] + public readonly string UndeployedCondition = null; [UpgradeGrantedReference, FieldLoader.Require] - [Desc("The upgrades to grant after deploying and revoke before undeploying.")] - public readonly string[] DeployedUpgrades = { }; + [Desc("The condition to grant after deploying and revoke before undeploying.")] + public readonly string DeployedCondition = null; [Desc("The terrain types that this actor can deploy on to receive these upgrades. " + "Leave empty to allow any.")] @@ -57,27 +57,28 @@ namespace OpenRA.Mods.Common.Traits [Desc("Can this actor undeploy?")] public readonly bool CanUndeploy = true; - public object Create(ActorInitializer init) { return new DeployToUpgrade(init, this); } + public object Create(ActorInitializer init) { return new GrantConditionOnDeploy(init, this); } } public enum DeployState { Undeployed, Deploying, Deployed, Undeploying } - public class DeployToUpgrade : IResolveOrder, IIssueOrder, INotifyCreated + public class GrantConditionOnDeploy : IResolveOrder, IIssueOrder, INotifyCreated { readonly Actor self; - readonly DeployToUpgradeInfo info; - readonly UpgradeManager manager; + readonly GrantConditionOnDeployInfo info; readonly bool checkTerrainType; readonly bool canTurn; readonly Lazy body; DeployState deployState; + UpgradeManager manager; + int deployedToken = UpgradeManager.InvalidConditionToken; + int undeployedToken = UpgradeManager.InvalidConditionToken; - public DeployToUpgrade(ActorInitializer init, DeployToUpgradeInfo info) + public GrantConditionOnDeploy(ActorInitializer init, GrantConditionOnDeployInfo info) { self = init.Self; this.info = info; - manager = self.Trait(); checkTerrainType = info.AllowedTerrainTypes.Count > 0; canTurn = self.Info.HasTraitInfo(); body = Exts.Lazy(self.TraitOrDefault); @@ -87,6 +88,8 @@ namespace OpenRA.Mods.Common.Traits public void Created(Actor self) { + manager = self.TraitOrDefault(); + switch (deployState) { case DeployState.Undeployed: @@ -239,32 +242,32 @@ namespace OpenRA.Mods.Common.Traits void OnDeployStarted() { - foreach (var up in info.UndeployedUpgrades) - manager.RevokeUpgrade(self, up, this); + if (undeployedToken != UpgradeManager.InvalidConditionToken) + undeployedToken = manager.RevokeCondition(self, undeployedToken); deployState = DeployState.Deploying; } void OnDeployCompleted() { - foreach (var up in info.DeployedUpgrades) - manager.GrantUpgrade(self, up, this); + if (manager != null && !string.IsNullOrEmpty(info.DeployedCondition) && deployedToken == UpgradeManager.InvalidConditionToken) + deployedToken = manager.GrantCondition(self, info.DeployedCondition); deployState = DeployState.Deployed; } void OnUndeployStarted() { - foreach (var up in info.DeployedUpgrades) - manager.RevokeUpgrade(self, up, this); + if (deployedToken != UpgradeManager.InvalidConditionToken) + deployedToken = manager.RevokeCondition(self, deployedToken); deployState = DeployState.Deploying; } void OnUndeployCompleted() { - foreach (var up in info.UndeployedUpgrades) - manager.GrantUpgrade(self, up, this); + if (manager != null && !string.IsNullOrEmpty(info.UndeployedCondition) && undeployedToken == UpgradeManager.InvalidConditionToken) + undeployedToken = manager.GrantCondition(self, info.UndeployedCondition); deployState = DeployState.Undeployed; } diff --git a/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnMovement.cs b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnMovement.cs new file mode 100644 index 0000000000..b9137d48c1 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnMovement.cs @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + public class GrantConditionOnMovementInfo : UpgradableTraitInfo, Requires + { + [FieldLoader.Require] + [UpgradeGrantedReference] + [Desc("Condition to grant.")] + public readonly string Condition = null; + + [Desc("Apply upgrades on straight vertical movement as well.")] + public readonly bool ConsiderVerticalMovement = false; + + public override object Create(ActorInitializer init) { return new GrantConditionOnMovement(init.Self, this); } + } + + public class GrantConditionOnMovement : UpgradableTrait, ITick + { + readonly IMove movement; + + UpgradeManager manager; + int conditionToken = UpgradeManager.InvalidConditionToken; + + public GrantConditionOnMovement(Actor self, GrantConditionOnMovementInfo info) + : base(info) + { + movement = self.Trait(); + } + + protected override void Created(Actor self) + { + manager = self.TraitOrDefault(); + base.Created(self); + } + + void ITick.Tick(Actor self) + { + if (manager == null) + return; + + var isMovingVertically = Info.ConsiderVerticalMovement ? movement.IsMovingVertically : false; + var isMoving = !IsTraitDisabled && !self.IsDead && (movement.IsMoving || isMovingVertically); + if (isMoving && conditionToken == UpgradeManager.InvalidConditionToken) + conditionToken = manager.GrantCondition(self, Info.Condition); + else if (!isMoving && conditionToken != UpgradeManager.InvalidConditionToken) + conditionToken = manager.RevokeCondition(self, conditionToken); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnTerrain.cs b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnTerrain.cs new file mode 100644 index 0000000000..d00d8a581f --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Upgrades/GrantConditionOnTerrain.cs @@ -0,0 +1,67 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + public class GrantConditionOnTerrainInfo : ITraitInfo + { + [FieldLoader.Require] + [UpgradeGrantedReference] + [Desc("Condition to grant.")] + public readonly string Condition = null; + + [FieldLoader.Require] + [Desc("Terrain names to trigger the upgrade.")] + public readonly string[] TerrainTypes = { }; + + public object Create(ActorInitializer init) { return new GrantConditionOnTerrain(init, this); } + } + + public class GrantConditionOnTerrain : INotifyCreated, ITick + { + readonly GrantConditionOnTerrainInfo info; + + UpgradeManager manager; + int conditionToken = UpgradeManager.InvalidConditionToken; + string previousTerrain; + + public GrantConditionOnTerrain(ActorInitializer init, GrantConditionOnTerrainInfo info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + manager = self.TraitOrDefault(); + } + + public void Tick(Actor self) + { + if (manager == null) + return; + + var currentTerrain = self.World.Map.GetTerrainInfo(self.Location).Type; + var wantsGranted = info.TerrainTypes.Contains(currentTerrain); + if (currentTerrain != previousTerrain) + { + if (wantsGranted && conditionToken == UpgradeManager.InvalidConditionToken) + conditionToken = manager.GrantCondition(self, info.Condition); + else if (!wantsGranted && conditionToken != UpgradeManager.InvalidConditionToken) + conditionToken = manager.RevokeCondition(self, conditionToken); + } + + previousTerrain = currentTerrain; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnMovement.cs b/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnMovement.cs deleted file mode 100644 index a39e9eacae..0000000000 --- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnMovement.cs +++ /dev/null @@ -1,75 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 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.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - public class UpgradeOnMovementInfo : UpgradableTraitInfo, Requires, Requires - { - [UpgradeGrantedReference, FieldLoader.Require] - [Desc("The upgrades to grant.")] - public readonly string[] Upgrades = { }; - - [Desc("Apply upgrades on straight vertical movement as well.")] - public readonly bool ConsiderVerticalMovement = false; - - public override object Create(ActorInitializer init) { return new UpgradeOnMovement(init.Self, this); } - } - - public class UpgradeOnMovement : UpgradableTrait, ITick - { - readonly UpgradeManager manager; - readonly IMove movement; - - bool granted; - - public UpgradeOnMovement(Actor self, UpgradeOnMovementInfo info) - : base(info) - { - manager = self.Trait(); - movement = self.Trait(); - } - - void Revoke(Actor self) - { - if (!granted) - return; - - foreach (var up in Info.Upgrades) - manager.RevokeUpgrade(self, up, this); - - granted = false; - } - - void ITick.Tick(Actor self) - { - if (IsTraitDisabled) - { - Revoke(self); - return; - } - - var isMovingVertically = Info.ConsiderVerticalMovement ? movement.IsMovingVertically : false; - var isMoving = !self.IsDead && (movement.IsMoving || isMovingVertically); - if (isMoving && !granted) - { - foreach (var up in Info.Upgrades) - manager.GrantUpgrade(self, up, this); - - granted = true; - } - else if (!isMoving) - Revoke(self); - } - } -} diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnTerrain.cs b/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnTerrain.cs deleted file mode 100644 index 3e89ec7ef2..0000000000 --- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradeOnTerrain.cs +++ /dev/null @@ -1,69 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 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.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - public class UpgradeOnTerrainInfo : ITraitInfo, Requires - { - [UpgradeGrantedReference] - public readonly string[] Upgrades = { "terrain" }; - - [Desc("Terrain names to trigger the upgrade.")] - public readonly string[] TerrainTypes = { }; - - public object Create(ActorInitializer init) { return new UpgradeOnTerrain(init, this); } - } - - public class UpgradeOnTerrain : ITick - { - readonly Actor self; - readonly UpgradeOnTerrainInfo info; - readonly UpgradeManager manager; - - bool granted; - string previousTerrain; - - public UpgradeOnTerrain(ActorInitializer init, UpgradeOnTerrainInfo info) - { - self = init.Self; - this.info = info; - manager = self.Trait(); - } - - public void Tick(Actor self) - { - var currentTerrain = self.World.Map.GetTerrainInfo(self.Location).Type; - var wantsGranted = info.TerrainTypes.Contains(currentTerrain); - if (currentTerrain != previousTerrain) - { - if (wantsGranted && !granted) - { - foreach (var up in info.Upgrades) - manager.GrantUpgrade(self, up, this); - - granted = true; - } - else if (!wantsGranted && granted) - { - foreach (var up in info.Upgrades) - manager.RevokeUpgrade(self, up, this); - - granted = false; - } - } - - previousTerrain = currentTerrain; - } - } -} diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 9a003670d4..51550be498 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -87,7 +87,7 @@ namespace OpenRA.Mods.Common.Traits public interface INotifyOtherProduction { void UnitProducedByOther(Actor self, Actor producer, Actor produced); } public interface INotifyDelivery { void IncomingDelivery(Actor self); void Delivered(Actor self); } public interface INotifyDocking { void Docked(Actor self, Actor harvester); void Undocked(Actor self, Actor harvester); } - public interface INotifyParachuteLanded { void OnLanded(Actor ignore); } + public interface INotifyParachute { void OnParachute(Actor self); void OnLanded(Actor self, Actor ignore); } public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyDiscovered { void OnDiscovered(Actor self, Player discoverer, bool playNotification); } public interface IRenderActorPreviewInfo : ITraitInfo { IEnumerable RenderPreview(ActorPreviewInitializer init); } diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 739f454fff..5d3b98b58e 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -586,6 +586,115 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + if (engineVersion < 20161213) + { + if (node.Key == "Aircraft") + { + ConvertUpgradesToCondition(parent, node, "AirborneUpgrades", "AirborneCondition"); + ConvertUpgradesToCondition(parent, node, "CruisingUpgrades", "CruisingCondition"); + } + + if (node.Key.StartsWith("Cloak", StringComparison.Ordinal)) + ConvertUpgradesToCondition(parent, node, "WhileCloakedUpgrades", "CloakedCondition"); + + if (node.Key == "Disguise") + { + ConvertUpgradesToCondition(parent, node, "Upgrades", "DisguisedCondition"); + if (!node.Value.Nodes.Any(n => n.Key == "DisguisedCondition")) + node.Value.Nodes.Add(new MiniYamlNode("DisguisedCondition", "disguise")); + } + + if (node.Key == "Parachutable") + { + ConvertUpgradesToCondition(parent, node, "ParachuteUpgrade", "ParachutingCondition"); + if (!node.Value.Nodes.Any(n => n.Key == "ParachutingCondition")) + node.Value.Nodes.Add(new MiniYamlNode("ParachutingCondition", "parachute")); + } + + if (node.Key == "PrimaryBuilding") + { + ConvertUpgradesToCondition(parent, node, "Upgrades", "PrimaryCondition"); + if (!node.Value.Nodes.Any(n => n.Key == "PrimaryCondition")) + node.Value.Nodes.Add(new MiniYamlNode("PrimaryCondition", "primary")); + } + + if (node.Key.StartsWith("UpgradeOnDamageState", StringComparison.Ordinal)) + { + RenameNodeKey(node, "GrantConditionOnDamageState"); + ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition"); + } + + if (node.Key.StartsWith("UpgradeOnMovement", StringComparison.Ordinal)) + { + RenameNodeKey(node, "GrantConditionOnMovement"); + ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition"); + } + + if (node.Key.StartsWith("UpgradeOnTerrain", StringComparison.Ordinal)) + { + RenameNodeKey(node, "GrantConditionOnTerrain"); + ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition"); + if (!node.Value.Nodes.Any(n => n.Key == "Condition")) + node.Value.Nodes.Add(new MiniYamlNode("Condition", "terrain")); + } + + if (node.Key == "AttackSwallow") + { + ConvertUpgradesToCondition(parent, node, "AttackingUpgrades", "AttackingCondition"); + if (!node.Value.Nodes.Any(n => n.Key == "AttackingCondition")) + node.Value.Nodes.Add(new MiniYamlNode("AttackingCondition", "attacking")); + } + + if (node.Key.StartsWith("Pluggable", StringComparison.Ordinal)) + { + var upgrades = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades"); + if (upgrades != null) + { + upgrades.Key = "Conditions"; + foreach (var n in upgrades.Value.Nodes) + { + var conditions = FieldLoader.GetValue("", n.Value.Value); + if (conditions.Length > 1) + Console.WriteLine("Unable to automatically migrate multiple Pluggable upgrades to a condition. This must be corrected manually"); + } + } + } + + if (node.Key.StartsWith("GlobalUpgradable", StringComparison.Ordinal)) + { + RenameNodeKey(node, "GrantConditionOnPrerequisite"); + ConvertUpgradesToCondition(parent, node, "Upgrades", "Condition"); + } + + if (node.Key.StartsWith("GlobalUpgradeManager", StringComparison.Ordinal)) + RenameNodeKey(node, "GrantConditionOnPrerequisiteManager"); + + if (node.Key.StartsWith("DeployToUpgrade", StringComparison.Ordinal)) + { + RenameNodeKey(node, "GrantConditionOnDeploy"); + ConvertUpgradesToCondition(parent, node, "UndeployedUpgrades", "UndeployedCondition"); + ConvertUpgradesToCondition(parent, node, "DeployedUpgrades", "DeployedCondition"); + } + + if (node.Key == "GainsExperience") + { + var upgrades = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades"); + if (upgrades != null) + { + upgrades.Key = "Conditions"; + foreach (var n in upgrades.Value.Nodes) + { + var conditions = FieldLoader.GetValue("", n.Value.Value); + if (conditions.Length > 1) + Console.WriteLine("Unable to automatically migrate multiple GainsExperience upgrades to a condition. This must be corrected manually"); + } + } + } + + if (node.Key.StartsWith("DisableOnUpgrade", StringComparison.Ordinal)) + RenameNodeKey(node, "DisableOnCondition"); + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } diff --git a/OpenRA.Mods.D2k/Activities/SwallowActor.cs b/OpenRA.Mods.D2k/Activities/SwallowActor.cs index a8344700c6..a5f220c772 100644 --- a/OpenRA.Mods.D2k/Activities/SwallowActor.cs +++ b/OpenRA.Mods.D2k/Activities/SwallowActor.cs @@ -37,6 +37,7 @@ namespace OpenRA.Mods.D2k.Activities int countdown; CPos burrowLocation; AttackState stance; + int attackingToken = UpgradeManager.InvalidConditionToken; public SwallowActor(Actor self, Target target, WeaponInfo weapon) { @@ -45,7 +46,7 @@ namespace OpenRA.Mods.D2k.Activities sandworm = self.Trait(); positionable = self.Trait(); swallow = self.Trait(); - manager = self.Trait(); + manager = self.TraitOrDefault(); radarPings = self.World.WorldActor.TraitOrDefault(); } @@ -105,10 +106,12 @@ namespace OpenRA.Mods.D2k.Activities switch (stance) { case AttackState.Uninitialized: - GrantUpgrades(self); stance = AttackState.Burrowed; countdown = swallow.Info.AttackDelay; burrowLocation = self.Location; + if (manager != null && attackingToken == UpgradeManager.InvalidConditionToken && + !string.IsNullOrEmpty(swallow.Info.AttackingCondition)) + attackingToken = manager.GrantCondition(self, swallow.Info.AttackingCondition); break; case AttackState.Burrowed: if (--countdown > 0) @@ -119,14 +122,14 @@ namespace OpenRA.Mods.D2k.Activities // The target has moved too far away if ((burrowLocation - targetLocation).Length > NearEnough) { - RevokeUpgrades(self); + RevokeCondition(self); return NextActivity; } // The target reached solid ground if (!positionable.CanEnterCell(targetLocation, null, false)) { - RevokeUpgrades(self); + RevokeCondition(self); return NextActivity; } @@ -135,7 +138,7 @@ namespace OpenRA.Mods.D2k.Activities if (!targets.Any()) { - RevokeUpgrades(self); + RevokeCondition(self); return NextActivity; } @@ -158,23 +161,17 @@ namespace OpenRA.Mods.D2k.Activities self.World.AddFrameEndTask(w => self.Dispose()); } - RevokeUpgrades(self); + RevokeCondition(self); return NextActivity; } return this; } - void GrantUpgrades(Actor self) + void RevokeCondition(Actor self) { - foreach (var up in swallow.Info.AttackingUpgrades) - manager.GrantUpgrade(self, up, this); - } - - void RevokeUpgrades(Actor self) - { - foreach (var up in swallow.Info.AttackingUpgrades) - manager.RevokeUpgrade(self, up, this); + if (attackingToken != UpgradeManager.InvalidConditionToken) + attackingToken = manager.RevokeCondition(self, attackingToken); } } } diff --git a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs index 3516680a71..19b8fc53f7 100644 --- a/OpenRA.Mods.D2k/Traits/AttackSwallow.cs +++ b/OpenRA.Mods.D2k/Traits/AttackSwallow.cs @@ -27,8 +27,8 @@ namespace OpenRA.Mods.D2k.Traits public readonly int AttackDelay = 30; [UpgradeGrantedReference] - [Desc("The upgrades to grant while attacking.")] - public readonly string[] AttackingUpgrades = { "attacking" }; + [Desc("The condition to grant to self while attacking.")] + public readonly string AttackingCondition = null; public readonly string WormAttackSound = "WORM.WAV"; diff --git a/OpenRA.Mods.RA/Traits/Disguise.cs b/OpenRA.Mods.RA/Traits/Disguise.cs index 1a39180949..2416bb55ee 100644 --- a/OpenRA.Mods.RA/Traits/Disguise.cs +++ b/OpenRA.Mods.RA/Traits/Disguise.cs @@ -65,13 +65,13 @@ namespace OpenRA.Mods.RA.Traits [VoiceReference] public readonly string Voice = "Action"; [UpgradeGrantedReference] - [Desc("Upgrades to grant when disguised.")] - public readonly string[] Upgrades = { "disguise" }; + [Desc("The condition to grant to self while disguised.")] + public readonly string DisguisedCondition = null; public object Create(ActorInitializer init) { return new Disguise(init.Self, this); } } - class Disguise : IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack + class Disguise : INotifyCreated, IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack { public Player AsPlayer { get; private set; } public string AsSprite { get; private set; } @@ -82,14 +82,19 @@ namespace OpenRA.Mods.RA.Traits readonly Actor self; readonly DisguiseInfo info; - readonly Lazy um; + + UpgradeManager um; + int disguisedToken = UpgradeManager.InvalidConditionToken; public Disguise(Actor self, DisguiseInfo info) { this.self = self; this.info = info; + } - um = Exts.Lazy(() => self.TraitOrDefault()); + void INotifyCreated.Created(Actor self) + { + um = self.TraitOrDefault(); } public IEnumerable Orders @@ -182,18 +187,12 @@ namespace OpenRA.Mods.RA.Traits foreach (var t in self.TraitsImplementing()) t.OnEffectiveOwnerChanged(self, oldEffectiveOwner, AsPlayer); - if (Disguised != oldDisguiseSetting && um.Value != null) + if (Disguised != oldDisguiseSetting && um != null) { - foreach (var u in info.Upgrades) - { - if (!um.Value.AcknowledgesUpgrade(self, u)) - continue; - - if (Disguised) - um.Value.GrantUpgrade(self, u, this); - else - um.Value.RevokeUpgrade(self, u, this); - } + if (Disguised && disguisedToken == UpgradeManager.InvalidConditionToken && !string.IsNullOrEmpty(info.DisguisedCondition)) + disguisedToken = um.GrantCondition(self, info.DisguisedCondition); + else if (!Disguised && disguisedToken != UpgradeManager.InvalidConditionToken) + disguisedToken = um.RevokeCondition(self, disguisedToken); } } diff --git a/mods/cnc/rules/aircraft.yaml b/mods/cnc/rules/aircraft.yaml index 484a3fb1f6..9513645366 100644 --- a/mods/cnc/rules/aircraft.yaml +++ b/mods/cnc/rules/aircraft.yaml @@ -167,7 +167,7 @@ C17: TurnSpeed: 5 Speed: 326 Repulsable: False - AirborneUpgrades: airborne + AirborneCondition: airborne MaximumPitch: 36 Health: HP: 25 @@ -206,7 +206,7 @@ A10: TurnSpeed: 4 Speed: 373 Repulsable: False - AirborneUpgrades: airborne + AirborneCondition: airborne Health: HP: 150 Armor: diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index f202f1c81b..b4dd0a4f0b 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -16,7 +16,7 @@ ^GainsExperience: GainsExperience: - Upgrades: + Conditions: 200: rank-veteran-1 400: rank-veteran-2 800: rank-veteran-3 @@ -202,8 +202,8 @@ Aircraft: RepairBuildings: hpad LandWhenIdle: false - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising CanHover: True HiddenUnderFog: Type: CenterPosition @@ -283,8 +283,8 @@ DamageInterval: 16 DamageTypes: TiberiumDeath RequiresCondition: !hazmatsuits - GlobalUpgradable@BIO: - Upgrades: hazmatsuits + GrantConditionOnPrerequisite@BIO: + Condition: hazmatsuits Prerequisites: bio WithDecoration@HAZMAT: Image: pips @@ -309,8 +309,8 @@ HealIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal - GlobalUpgradable@HOSPITAL: - Upgrades: hospitalheal + GrantConditionOnPrerequisite@HOSPITAL: + Condition: hospitalheal Prerequisites: hosp WithDecoration@REDCROSS: Image: pips @@ -839,7 +839,7 @@ Offset: 43, 128, 0 ZOffset: -129 Aircraft: - AirborneUpgrades: airborne + AirborneCondition: airborne CanHover: True FallsToEarth: Spins: True diff --git a/mods/cnc/rules/player.yaml b/mods/cnc/rules/player.yaml index 7ed7a2fa29..1abb134acd 100644 --- a/mods/cnc/rules/player.yaml +++ b/mods/cnc/rules/player.yaml @@ -32,6 +32,6 @@ Player: Name: Unrestricted Prerequisites: techlevel.low, techlevel.medium, techlevel.high, techlevel.superweapons Id: unrestricted - GlobalUpgradeManager: + GrantConditionOnPrerequisiteManager: ResourceStorageWarning: PlayerExperience: diff --git a/mods/d2k/rules/aircraft.yaml b/mods/d2k/rules/aircraft.yaml index 9d94195832..ab18638171 100644 --- a/mods/d2k/rules/aircraft.yaml +++ b/mods/d2k/rules/aircraft.yaml @@ -16,7 +16,7 @@ carryall.reinforce: LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune Repulsable: False LandWhenIdle: False - AirborneUpgrades: airborne + AirborneCondition: airborne CanHover: True Targetable@GROUND: TargetTypes: Ground, Vehicle diff --git a/mods/d2k/rules/arrakis.yaml b/mods/d2k/rules/arrakis.yaml index 1fec4f6d62..680f14e3cd 100644 --- a/mods/d2k/rules/arrakis.yaml +++ b/mods/d2k/rules/arrakis.yaml @@ -87,6 +87,7 @@ sandworm: AttackSwallow: AttackRequiresEnteringCell: true IgnoresVisibility: true + AttackingCondition: attacking Armament: Weapon: WormJaw Sandworm: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 18a7091b96..ca0edf36ba 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -16,7 +16,7 @@ ^GainsExperience: GainsExperience: - Upgrades: + Conditions: 200: rank-veteran-1 400: rank-veteran-2 800: rank-veteran-3 diff --git a/mods/d2k/rules/infantry.yaml b/mods/d2k/rules/infantry.yaml index 61d76e4aff..ecb99177e1 100644 --- a/mods/d2k/rules/infantry.yaml +++ b/mods/d2k/rules/infantry.yaml @@ -96,8 +96,8 @@ thumper: Mobile: Speed: 43 RequiresCondition: !deployed - DeployToUpgrade: - DeployedUpgrades: deployed + GrantConditionOnDeploy: + DeployedCondition: deployed Facing: 128 AllowedTerrainTypes: Sand, Spice, Dune, SpiceSand WithInfantryBody: diff --git a/mods/d2k/rules/player.yaml b/mods/d2k/rules/player.yaml index 07953f32a6..3cab2f57e6 100644 --- a/mods/d2k/rules/player.yaml +++ b/mods/d2k/rules/player.yaml @@ -88,7 +88,7 @@ Player: Id: unrestricted EnemyWatcher: HarvesterInsurance: - GlobalUpgradeManager: + GrantConditionOnPrerequisiteManager: ResourceStorageWarning: AdviceInterval: 26 PlayerExperience: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 1aa889744e..4630126854 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -88,10 +88,11 @@ construction_yard: WithBuildingPlacedOverlay: Palette: d2k PrimaryBuilding: + PrimaryCondition: primary ProvidesPrerequisite@buildingname: - GlobalUpgradable: + GrantConditionOnPrerequisite: Prerequisites: upgrade.conyard - Upgrades: stardecoration + Condition: stardecoration WithDecoration@upgraded: RequiresSelection: true Image: pips @@ -181,6 +182,7 @@ barracks: Production: Produces: Infantry PrimaryBuilding: + PrimaryCondition: primary ProductionBar: ProvidesPrerequisite@atreides: Prerequisite: barracks.atreides @@ -201,9 +203,9 @@ barracks: smuggler: barracks.ordos mercenary: barracks.ordos ProvidesPrerequisite@buildingname: - GlobalUpgradable: + GrantConditionOnPrerequisite: Prerequisites: upgrade.barracks - Upgrades: stardecoration + Condition: stardecoration WithDecoration@upgraded: RequiresSelection: true Image: pips @@ -360,6 +362,7 @@ light_factory: Production: Produces: Vehicle PrimaryBuilding: + PrimaryCondition: primary ProductionBar: ProvidesPrerequisite@atreides: Prerequisite: light.atreides @@ -380,9 +383,9 @@ light_factory: Sequence: idle-top Power: Amount: -125 - GlobalUpgradable: + GrantConditionOnPrerequisite: Prerequisites: upgrade.light - Upgrades: stardecoration + Condition: stardecoration WithDecoration@upgraded: RequiresSelection: true Image: pips @@ -430,6 +433,7 @@ heavy_factory: Production: Produces: Armor PrimaryBuilding: + PrimaryCondition: primary ProductionBar: ProvidesPrerequisite@atreides: Prerequisite: heavy.atreides @@ -459,9 +463,9 @@ heavy_factory: ProvidesPrerequisite@buildingname: SelectionDecorations: VisualBounds: 96,96 - GlobalUpgradable: + GrantConditionOnPrerequisite: Prerequisites: upgrade.heavy - Upgrades: stardecoration + Condition: stardecoration WithDecoration@upgraded: RequiresSelection: true Image: pips @@ -567,6 +571,7 @@ starport: Palette: starportlights ProductionBar: PrimaryBuilding: + PrimaryCondition: primary RequiresPower: CanPowerDown: PowerupSound: EnablePower @@ -836,9 +841,9 @@ high_tech_factory: Amount: -75 SelectionDecorations: VisualBounds: 96,96 - GlobalUpgradable: + GrantConditionOnPrerequisite: Prerequisites: upgrade.hightech - Upgrades: stardecoration + Condition: stardecoration WithDecoration@upgraded: RequiresSelection: true Image: pips diff --git a/mods/ra/maps/desert-shellmap/rules.yaml b/mods/ra/maps/desert-shellmap/rules.yaml index accc448782..96760317c5 100644 --- a/mods/ra/maps/desert-shellmap/rules.yaml +++ b/mods/ra/maps/desert-shellmap/rules.yaml @@ -17,7 +17,7 @@ World: GivesBounty: Percentage: 0 GainsExperience: - Upgrades: + Conditions: DamageMultiplier@UNKILLABLE: RequiresCondition: unkillable Modifier: 0 @@ -28,7 +28,7 @@ World: GivesBounty: Percentage: 0 GainsExperience: - Upgrades: + Conditions: DamageMultiplier@UNKILLABLE: RequiresCondition: unkillable Modifier: 0 @@ -39,7 +39,7 @@ World: GivesBounty: Percentage: 0 GainsExperience: - Upgrades: + Conditions: DeathSounds@NORMAL: VolumeMultiplier: 0.1 DeathSounds@BURNED: @@ -56,7 +56,7 @@ World: GivesBounty: Percentage: 0 GainsExperience: - Upgrades: + Conditions: DamageMultiplier@UNKILLABLE: RequiresCondition: unkillable Modifier: 0 diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 13b5c8d31e..8e17e5ac05 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -15,7 +15,7 @@ ^GainsExperience: GainsExperience: - Upgrades: + Conditions: 200: rank-veteran-1 400: rank-veteran-2 800: rank-veteran-3 @@ -191,6 +191,7 @@ GroundCorpsePalette: WaterCorpseSequence: WaterCorpsePalette: + ParachutingCondition: parachute Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall @@ -290,8 +291,8 @@ HealIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal - GlobalUpgradable: - Upgrades: hospitalheal + GrantConditionOnPrerequisite: + Condition: hospitalheal Prerequisites: hosp DeathSounds@NORMAL: DeathTypes: DefaultDeath, BulletDeath, SmallExplosionDeath, ExplosionDeath @@ -307,6 +308,7 @@ GroundImpactSound: squishy2.aud WaterImpactSound: splash9.aud WaterCorpseSequence: small_splash + ParachutingCondition: parachute Cloneable: Types: Infantry Voiced: @@ -425,8 +427,8 @@ Aircraft: RepairBuildings: fix RearmBuildings: afld - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising Targetable@GROUND: TargetTypes: Ground, Repair, Vehicle RequiresCondition: !airborne @@ -796,8 +798,8 @@ Tooltip: GenericName: Destroyed Plane Aircraft: - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising FallsToEarth: Spins: False Moves: True @@ -811,8 +813,8 @@ Tooltip: GenericName: Destroyed Helicopter Aircraft: - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising CanHover: True FallsToEarth: BodyOrientation: @@ -884,6 +886,7 @@ Parachutable: FallRate: 26 KilledOnImpassableTerrain: false + ParachutingCondition: parachute Passenger: WithParachute: Image: parach diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index dac456257e..577b3a984a 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -211,6 +211,7 @@ SPY: Voice: Move Disguise: Voice: Move + DisguisedCondition: disguise Infiltrates: Types: SpyInfiltrate PlayerExperience: 50 diff --git a/mods/ra/rules/player.yaml b/mods/ra/rules/player.yaml index 6ef8a5fbff..366cafcc6f 100644 --- a/mods/ra/rules/player.yaml +++ b/mods/ra/rules/player.yaml @@ -69,7 +69,7 @@ Player: Name: Unrestricted Prerequisites: techlevel.infonly, techlevel.low, techlevel.medium, techlevel.high, techlevel.unrestricted Id: unrestricted - GlobalUpgradeManager: + GrantConditionOnPrerequisiteManager: EnemyWatcher: VeteranProductionIconOverlay: Image: iconchevrons diff --git a/mods/ra/rules/ships.yaml b/mods/ra/rules/ships.yaml index 7af2caa9d0..d5b48e149f 100644 --- a/mods/ra/rules/ships.yaml +++ b/mods/ra/rules/ships.yaml @@ -31,7 +31,7 @@ SS: CloakDelay: 50 CloakSound: subshow1.aud UncloakSound: subshow1.aud - WhileCloakedUpgrades: underwater + CloakedCondition: underwater Palette: submerged Armament: Weapon: TorpTube @@ -85,7 +85,7 @@ MSUB: CloakDelay: 100 CloakSound: subshow1.aud UncloakSound: subshow1.aud - WhileCloakedUpgrades: underwater + CloakedCondition: underwater Palette: submerged Armament@PRIMARY: Weapon: SubMissile diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index b16ba50ff3..4c36480fea 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -134,6 +134,7 @@ SPEN: Production: Produces: Ship, Submarine PrimaryBuilding: + PrimaryCondition: primary -EmitInfantryOnSell: RepairsUnits: FinishRepairingNotification: UnitRepaired @@ -223,6 +224,7 @@ SYRD: Production: Produces: Ship, Boat PrimaryBuilding: + PrimaryCondition: primary -EmitInfantryOnSell: RepairsUnits: FinishRepairingNotification: UnitRepaired @@ -854,6 +856,7 @@ WEAP: RequiresPrerequisites: structures.ukraine Prerequisite: vehicles.ukraine PrimaryBuilding: + PrimaryCondition: primary ProductionBar: Power: Amount: -30 @@ -1060,6 +1063,7 @@ HPAD: Reservable: ProductionBar: PrimaryBuilding: + PrimaryCondition: primary Power: Amount: -10 ProvidesPrerequisite@allies: @@ -1206,6 +1210,7 @@ AFLD: ProductionBar: SupportPowerChargeBar: PrimaryBuilding: + PrimaryCondition: primary Power: Amount: -20 ProvidesPrerequisite@buildingname: @@ -1354,6 +1359,7 @@ BARR: Production: Produces: Infantry, Soldier PrimaryBuilding: + PrimaryCondition: primary ProductionBar: ProvidesPrerequisite: Prerequisite: barracks @@ -1428,6 +1434,7 @@ KENN: Production: Produces: Infantry, Dog PrimaryBuilding: + PrimaryCondition: primary ProductionBar: -EmitInfantryOnSell: Power: @@ -1472,6 +1479,7 @@ TENT: Production: Produces: Infantry, Soldier PrimaryBuilding: + PrimaryCondition: primary ProductionBar: ProvidesPrerequisite@barracks: Prerequisite: barracks diff --git a/mods/ts/rules/aircraft.yaml b/mods/ts/rules/aircraft.yaml index baf4bc07a0..bb2cdeea07 100644 --- a/mods/ts/rules/aircraft.yaml +++ b/mods/ts/rules/aircraft.yaml @@ -121,7 +121,7 @@ ORCAB: MaximumPitch: 120 TurnSpeed: 3 Speed: 96 - AirborneUpgrades: airborne + AirborneCondition: airborne MoveIntoShroud: false TakeoffSound: orcaup1.aud LandingSound: orcadwn1.aud @@ -243,7 +243,7 @@ SCRIN: MaximumPitch: 90 TurnSpeed: 3 Speed: 168 - AirborneUpgrades: airborne + AirborneCondition: airborne MoveIntoShroud: false TakeoffSound: dropup1.aud LandingSound: dropdwn1.aud diff --git a/mods/ts/rules/civilian-infantry.yaml b/mods/ts/rules/civilian-infantry.yaml index b74e1c2654..8b5ce6436e 100644 --- a/mods/ts/rules/civilian-infantry.yaml +++ b/mods/ts/rules/civilian-infantry.yaml @@ -64,6 +64,7 @@ CHAMSPY: Range: 9c0 Passenger: Disguise: + DisguisedCondition: disguise WithDecoration@disguise: Image: pips Sequence: pip-disguise diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index fbea23e652..435e15b237 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -17,7 +17,7 @@ ^GainsExperience: GainsExperience: - Upgrades: + Conditions: 500: rank-veteran 1000: rank-elite FirepowerMultiplier@VETERAN: @@ -71,7 +71,7 @@ UpgradeOverlay@EMPDISABLE: RequiresCondition: empdisable Palette: disabled - DisableOnUpgrade@EMPDISABLE: + DisableOnCondition@EMPDISABLE: RequiresCondition: empdisable TimedConditionBar@EMPDISABLE: Condition: empdisable @@ -326,8 +326,8 @@ HealIfBelow: 100 DamageCooldown: 125 RequiresCondition: hospitalheal - GlobalUpgradable@HOSPITAL: - Upgrades: hospitalheal + GrantConditionOnPrerequisite@HOSPITAL: + Condition: hospitalheal Prerequisites: cahosp WithDecoration@REDCROSS: Image: pips @@ -418,8 +418,8 @@ WithInfantryBody: DefaultAttackSequence: attack IdleSequences: idle1,idle2 - UpgradeOnDamageState@CRITICAL: - Upgrades: criticalspeed + GrantConditionOnDamageState@CRITICAL: + Condition: criticalspeed ValidDamageStates: Critical GrantPermanently: true SpeedMultiplier@CRITICAL: @@ -498,11 +498,11 @@ Weapons: SmallDebris Pieces: 3, 7 Range: 2c0, 5c0 - UpgradeOnDamageState@DAMAGED: - Upgrades: damagedspeed + GrantConditionOnDamageState@DAMAGED: + Condition: damagedspeed ValidDamageStates: Heavy - UpgradeOnDamageState@CRITICAL: - Upgrades: criticalspeed + GrantConditionOnDamageState@CRITICAL: + Condition: criticalspeed ValidDamageStates: Critical SpeedMultiplier@DAMAGED: RequiresCondition: damagedspeed @@ -569,8 +569,8 @@ SelectionDecorations: Palette: pips Aircraft: - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising RepairBuildings: gadept RearmBuildings: gahpad, nahpad LandWhenIdle: false @@ -615,8 +615,8 @@ QuantizedFacings: 0 CameraPitch: 90 Aircraft: - AirborneUpgrades: airborne - CruisingUpgrades: cruising + AirborneCondition: airborne + CruisingCondition: cruising Health: HP: 280 Armor: @@ -917,9 +917,9 @@ DamageInterval: 16 DamageTypes: BulletDeath Terrain: Veins - UpgradeOnTerrain@VEINS: + GrantConditionOnTerrain@VEINS: TerrainTypes: Veins - Upgrades: veins + Condition: veins WithIdleOverlay@VEINS: Sequence: veins RequiresCondition: veins diff --git a/mods/ts/rules/gdi-structures.yaml b/mods/ts/rules/gdi-structures.yaml index b3005c315c..19f495c6f4 100644 --- a/mods/ts/rules/gdi-structures.yaml +++ b/mods/ts/rules/gdi-structures.yaml @@ -38,7 +38,7 @@ GAPOWR: DisabledOverlay: Pluggable@pluga: Offset: 0,1 - Upgrades: + Conditions: powrup: powrup.a Power@pluga: RequiresCondition: powrup.a @@ -48,7 +48,7 @@ GAPOWR: Sequence: idle-powrupa Pluggable@plugb: Offset: 1,1 - Upgrades: + Conditions: powrup: powrup.b WithIdleOverlay@plugb: RequiresCondition: powrup.b @@ -96,6 +96,7 @@ GAPILE: Production: Produces: Infantry PrimaryBuilding: + PrimaryCondition: primary ProductionBar: WithProductionOverlay@LIGHTS: Sequence: production-lights @@ -153,6 +154,7 @@ GAWEAP: Production: Produces: Vehicle PrimaryBuilding: + PrimaryCondition: primary ProductionBar: WithIdleOverlay@ROOF: Sequence: idle-roof @@ -206,6 +208,7 @@ GAHPAD: Production: Produces: Air PrimaryBuilding: + PrimaryCondition: primary Reservable: RepairsUnits: PlayerExperience: 15 @@ -435,7 +438,7 @@ GAPLUG: Amount: -50 Pluggable@pluga: Offset: 0,2 - Upgrades: + Conditions: plug.ioncannon: plug.ioncannona plug.hunterseeker: plug.hunterseekera WithIdleOverlay@ioncannona: @@ -446,7 +449,7 @@ GAPLUG: Sequence: idle-hunterseekera Pluggable@plugb: Offset: 1,2 - Upgrades: + Conditions: plug.ioncannon: plug.ioncannonb plug.hunterseeker: plug.hunterseekerb WithIdleOverlay@ioncannonb: diff --git a/mods/ts/rules/gdi-support.yaml b/mods/ts/rules/gdi-support.yaml index c4469e53b8..31f5c8723e 100644 --- a/mods/ts/rules/gdi-support.yaml +++ b/mods/ts/rules/gdi-support.yaml @@ -126,7 +126,7 @@ GACTWR: RequiresCondition: tower.sam Amount: -10 Pluggable: - Upgrades: + Conditions: tower.vulcan: tower.vulcan tower.rocket: tower.rocket tower.sam: tower.sam diff --git a/mods/ts/rules/gdi-vehicles.yaml b/mods/ts/rules/gdi-vehicles.yaml index 4ae451de5e..21312e62a3 100644 --- a/mods/ts/rules/gdi-vehicles.yaml +++ b/mods/ts/rules/gdi-vehicles.yaml @@ -30,8 +30,8 @@ APC: UnloadVoice: Unload LoadingCondition: loading EjectOnDeath: true - UpgradeOnTerrain: - Upgrades: inwater + GrantConditionOnTerrain: + Condition: inwater TerrainTypes: Water WithVoxelBody: RequiresCondition: !inwater @@ -95,7 +95,7 @@ HVR: StationaryInterval: 18 MovingInterval: 6 -DamagedByTerrain@VEINS: - -UpgradeOnTerrain@VEINS: + -GrantConditionOnTerrain@VEINS: -WithIdleOverlay@VEINS: SMECH: @@ -137,7 +137,7 @@ SMECH: Selectable: Bounds: 20, 32, 0, -8 -DamagedByTerrain@VEINS: - -UpgradeOnTerrain@VEINS: + -GrantConditionOnTerrain@VEINS: -WithIdleOverlay@VEINS: MMCH: diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml index e2346a6604..2e4e978bc8 100644 --- a/mods/ts/rules/nod-structures.yaml +++ b/mods/ts/rules/nod-structures.yaml @@ -112,6 +112,7 @@ NAHAND: Production: Produces: Infantry PrimaryBuilding: + PrimaryCondition: primary ProductionBar: WithIdleOverlay@LIGHTS: Sequence: idle-lights @@ -167,6 +168,7 @@ NAWEAP: Production: Produces: Vehicle PrimaryBuilding: + PrimaryCondition: primary ProductionBar: WithIdleOverlay@ROOF: Sequence: idle-roof @@ -216,6 +218,7 @@ NAHPAD: Production: Produces: Air PrimaryBuilding: + PrimaryCondition: primary Reservable: RepairsUnits: PlayerExperience: 15 diff --git a/mods/ts/rules/nod-vehicles.yaml b/mods/ts/rules/nod-vehicles.yaml index 550b8554ae..8c1259b06f 100644 --- a/mods/ts/rules/nod-vehicles.yaml +++ b/mods/ts/rules/nod-vehicles.yaml @@ -29,7 +29,7 @@ BGGY: AutoTarget: WithMuzzleOverlay: -DamagedByTerrain@VEINS: - -UpgradeOnTerrain@VEINS: + -GrantConditionOnTerrain@VEINS: -WithIdleOverlay@VEINS: BIKE: @@ -105,9 +105,9 @@ TTNK: MaxHeightDelta: 3 RenderSprites: Image: ttnk - DeployToUpgrade: - DeployedUpgrades: deployed - UndeployedUpgrades: undeployed + GrantConditionOnDeploy: + DeployedCondition: deployed + UndeployedCondition: undeployed DeployAnimation: make Facing: 160 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough @@ -256,7 +256,7 @@ WEED: WithVoxelUnloadBody: -GainsExperience: -DamagedByTerrain@VEINS: - -UpgradeOnTerrain@VEINS: + -GrantConditionOnTerrain@VEINS: -WithIdleOverlay@VEINS: SAPC: diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml index 738db4d503..61fa7f4d64 100644 --- a/mods/ts/rules/player.yaml +++ b/mods/ts/rules/player.yaml @@ -1,7 +1,7 @@ Player: AlwaysVisible: TechTree: - GlobalUpgradeManager: + GrantConditionOnPrerequisiteManager: ClassicProductionQueue@Building: Type: Building BuildDurationModifier: 120 diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml index d66be951c3..282fe137e7 100644 --- a/mods/ts/rules/shared-vehicles.yaml +++ b/mods/ts/rules/shared-vehicles.yaml @@ -100,7 +100,7 @@ HARV: gdi: harv.gdi nod: harv.nod -DamagedByTerrain@VEINS: - -UpgradeOnTerrain@VEINS: + -GrantConditionOnTerrain@VEINS: -WithIdleOverlay@VEINS: LPST: @@ -137,9 +137,9 @@ LPST: FactionImages: gdi: lpst.gdi nod: lpst.nod - DeployToUpgrade: - DeployedUpgrades: deployed - UndeployedUpgrades: undeployed + GrantConditionOnDeploy: + DeployedCondition: deployed + UndeployedCondition: undeployed DeployAnimation: make Facing: 160 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough @@ -156,4 +156,4 @@ LPST: RenderDetectionCircle: TrailCount: 3 Carryable: - RequiresCondition: undeployed \ No newline at end of file + RequiresCondition: undeployed