diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 658208b07b..9c77838202 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -596,6 +596,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Armament.cs b/OpenRA.Mods.Common/Traits/Armament.cs index a317469c3f..488d830a7d 100644 --- a/OpenRA.Mods.Common/Traits/Armament.cs +++ b/OpenRA.Mods.Common/Traits/Armament.cs @@ -101,7 +101,7 @@ namespace OpenRA.Mods.Common.Traits } } - public class Armament : PausableConditionalTrait, ITick, IExplodeModifier + public class Armament : PausableConditionalTrait, ITick { public readonly WeaponInfo Weapon; public readonly Barrel[] Barrels; @@ -369,8 +369,6 @@ namespace OpenRA.Mods.Common.Traits } public virtual bool IsReloading { get { return FireDelay > 0 || IsTraitDisabled; } } - public virtual bool AllowExplode { get { return !IsReloading; } } - bool IExplodeModifier.ShouldExplode(Actor self) { return AllowExplode; } public WVec MuzzleOffset(Actor self, Barrel b) { diff --git a/OpenRA.Mods.Common/Traits/Explodes.cs b/OpenRA.Mods.Common/Traits/Explodes.cs index f8b94022f1..f852c527eb 100644 --- a/OpenRA.Mods.Common/Traits/Explodes.cs +++ b/OpenRA.Mods.Common/Traits/Explodes.cs @@ -127,7 +127,12 @@ namespace OpenRA.Mods.Common.Traits WeaponInfo ChooseWeaponForExplosion(Actor self) { - var shouldExplode = self.TraitsImplementing().All(a => a.ShouldExplode(self)); + var armaments = self.TraitsImplementing(); + if (!armaments.Any()) + return Info.WeaponInfo; + + // TODO: EmptyWeapon should be removed in favour of conditions + var shouldExplode = !armaments.All(a => a.IsReloading); var useFullExplosion = self.World.SharedRandom.Next(100) <= Info.LoadedChance; return (shouldExplode && useFullExplosion) ? Info.WeaponInfo : Info.EmptyWeaponInfo; } diff --git a/OpenRA.Mods.Common/Traits/Harvester.cs b/OpenRA.Mods.Common/Traits/Harvester.cs index 0264ffde52..4127e43b48 100644 --- a/OpenRA.Mods.Common/Traits/Harvester.cs +++ b/OpenRA.Mods.Common/Traits/Harvester.cs @@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new Harvester(init.Self, this); } } - public class Harvester : IIssueOrder, IResolveOrder, IPips, IExplodeModifier, IOrderVoice, + public class Harvester : IIssueOrder, IResolveOrder, IPips, IOrderVoice, ISpeedModifier, ISync, INotifyCreated, INotifyIdle, INotifyBlockingMove { public readonly HarvesterInfo Info; @@ -470,8 +470,6 @@ namespace OpenRA.Mods.Common.Traits yield return GetPipAt(i); } - bool IExplodeModifier.ShouldExplode(Actor self) { return !IsEmpty; } - int ISpeedModifier.GetSpeedModifier() { return 100 - (100 - Info.FullyLoadedSpeed) * contents.Values.Sum() / Info.Capacity; diff --git a/OpenRA.Mods.Common/Traits/StoresResources.cs b/OpenRA.Mods.Common/Traits/StoresResources.cs index 9edfb7cbef..dd54918db9 100644 --- a/OpenRA.Mods.Common/Traits/StoresResources.cs +++ b/OpenRA.Mods.Common/Traits/StoresResources.cs @@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new StoresResources(init.Self, this); } } - class StoresResources : IPips, INotifyOwnerChanged, INotifyCapture, IExplodeModifier, IStoreResources, ISync, INotifyKilled + class StoresResources : IPips, INotifyOwnerChanged, INotifyCapture, IStoreResources, ISync, INotifyKilled { readonly StoresResourcesInfo info; PlayerResources player; @@ -70,7 +70,5 @@ namespace OpenRA.Mods.Common.Traits player.Resources * info.PipCount > i * player.ResourceCapacity ? info.PipColor : PipType.Transparent); } - - bool IExplodeModifier.ShouldExplode(Actor self) { return Stored > 0; } } } diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index cca6f002f5..c5ee6f92d2 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -142,7 +142,6 @@ namespace OpenRA.Mods.Common.Traits public interface IRenderActorPreviewInfo : ITraitInfo { IEnumerable RenderPreview(ActorPreviewInitializer init); } public interface ICruiseAltitudeInfo : ITraitInfo { WDist GetCruiseAltitude(); } - public interface IExplodeModifier { bool ShouldExplode(Actor self); } public interface IHuskModifier { string HuskActor(Actor self); } public interface ISeedableResource { void Seed(Actor self); } diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20180923/RemoveResourceExplodeModifier.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/RemoveResourceExplodeModifier.cs new file mode 100644 index 0000000000..77d84df05a --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/RemoveResourceExplodeModifier.cs @@ -0,0 +1,49 @@ +#region Copyright & License Information +/* + * Copyright 2007-2018 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.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemoveResourceExplodeModifier : UpdateRule + { + public override string Name { get { return "Harvester and StoresResources traits no longer force Explodes.EmptyWeapon"; } } + public override string Description + { + get + { + return "The hardcoded behaviour forcing Explodes to use EmptyWeapon when the harvester/player has no\n" + + "resources has been removed. Affected actors are listed so that conditions may be manually defined."; + } + } + + readonly List locations = new List(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "Review the following definitions and, if the actor uses Harvester or StoresResources,\n" + + "define a new Explodes trait with the previous EmptyWeapon, enabled by Harvester.EmptyCondition or\n" + + "GrantConditionOnPlayerResources.Condition (negated):\n" + UpdateUtils.FormatMessageList(locations); + + locations.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + if (actorNode.LastChildMatching("Explodes") != null) + locations.Add("{0} ({1})".F(actorNode.Key, actorNode.Location.Filename)); + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index ca627cbd56..c480de2659 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.UpdateRules new AddBotOrderManager(), new AddHarvesterBotModule(), new RemoveNegativeDamageFullHealthCheck(), + new RemoveResourceExplodeModifier(), }) }; diff --git a/mods/cnc/rules/vehicles.yaml b/mods/cnc/rules/vehicles.yaml index 94292f7328..c22e8c3f42 100644 --- a/mods/cnc/rules/vehicles.yaml +++ b/mods/cnc/rules/vehicles.yaml @@ -66,6 +66,7 @@ HARV: BaleUnloadDelay: 6 SearchFromProcRadius: 25 SearchFromOrderRadius: 15 + EmptyCondition: no-tiberium Mobile: Speed: 85 Health: @@ -83,6 +84,7 @@ HARV: WithHarvestAnimation: WithDockingAnimation: Explodes: + RequiresCondition: !no-tiberium Weapon: TiberiumExplosion SelectionDecorations: diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index fcebcbe708..6da5853558 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -301,6 +301,7 @@ HARV: BaleUnloadDelay: 1 SearchFromProcRadius: 30 SearchFromOrderRadius: 11 + EmptyCondition: no-ore Health: HP: 60000 Armor: @@ -328,6 +329,7 @@ HARV: HealIfBelow: 50 DamageCooldown: 500 Explodes: + RequiresCondition: !no-ore Weapon: OreExplosion MCV: diff --git a/mods/ts/rules/shared-structures.yaml b/mods/ts/rules/shared-structures.yaml index 20701a4324..1a00738dc8 100644 --- a/mods/ts/rules/shared-structures.yaml +++ b/mods/ts/rules/shared-structures.yaml @@ -123,7 +123,10 @@ PROC: FactionImages: gdi: proc.gdi nod: proc.nod + GrantConditionOnPlayerResources: + Condition: contains-tiberium Explodes: + RequiresCondition: contains-tiberium Weapon: TiberiumExplosion GASILO: @@ -172,7 +175,10 @@ GASILO: Power: Amount: -10 SelectionDecorations: + GrantConditionOnPlayerResources: + Condition: contains-tiberium Explodes: + RequiresCondition: contains-tiberium Weapon: TiberiumExplosion ANYPOWER: diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml index 6640f87153..192d51031f 100644 --- a/mods/ts/rules/shared-vehicles.yaml +++ b/mods/ts/rules/shared-vehicles.yaml @@ -67,6 +67,7 @@ HARV: SearchFromOrderRadius: 18 HarvestVoice: Attack DeliverVoice: Move + EmptyCondition: no-tiberium Mobile: Speed: 71 Health: @@ -85,6 +86,7 @@ HARV: -WithVoxelBody: WithVoxelUnloadBody: Explodes: + RequiresCondition: !no-tiberium Weapon: TiberiumExplosion WithHarvestOverlay: LocalOffset: 543,0,0