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/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/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/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/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 793bec7ac1..4800738b1e 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -603,6 +603,13 @@ namespace OpenRA.Mods.Common.UtilityCommands 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")); + } } UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index daa2ce47a3..c477179ba5 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -191,6 +191,7 @@ GroundCorpsePalette: WaterCorpseSequence: WaterCorpsePalette: + ParachutingCondition: parachute Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall @@ -307,6 +308,7 @@ GroundImpactSound: squishy2.aud WaterImpactSound: splash9.aud WaterCorpseSequence: small_splash + ParachutingCondition: parachute Cloneable: Types: Infantry Voiced: @@ -884,6 +886,7 @@ Parachutable: FallRate: 26 KilledOnImpassableTerrain: false + ParachutingCondition: parachute Passenger: WithParachute: Image: parach