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