diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 9243e8d516..a10b6e5f8e 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -480,6 +480,8 @@
+
+
diff --git a/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs b/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs
index edde98d1fe..223c86b9c9 100644
--- a/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs
+++ b/OpenRA.Mods.Common/Traits/Buildings/BuildingUtils.cs
@@ -22,10 +22,21 @@ namespace OpenRA.Mods.Common.Traits
if (!world.Map.Contains(cell))
return false;
- if (world.WorldActor.Trait().GetBuildingAt(cell) != null)
- return false;
+ var building = world.WorldActor.Trait().GetBuildingAt(cell);
+ if (building != null)
+ {
+ if (ai == null)
+ return false;
- if (!bi.AllowInvalidPlacement && world.ActorMap.GetActorsAt(cell).Any(a => a != toIgnore))
+ var replacementInfo = ai.TraitInfoOrDefault();
+ if (replacementInfo == null)
+ return false;
+
+ if (!building.TraitsImplementing().Any(p => !p.IsTraitDisabled &&
+ p.Info.Types.Overlaps(replacementInfo.ReplaceableTypes)))
+ return false;
+ }
+ else if (!bi.AllowInvalidPlacement && world.ActorMap.GetActorsAt(cell).Any(a => a != toIgnore))
return false;
var tile = world.Map.Tiles[cell];
diff --git a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs
index b424c8c4f8..d0d6ef9f08 100644
--- a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs
+++ b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs
@@ -136,6 +136,18 @@ namespace OpenRA.Mods.Common.Traits
|| !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, actorInfo, order.TargetLocation))
return;
+ var replacementInfo = actorInfo.TraitInfoOrDefault();
+ if (replacementInfo != null)
+ {
+ var buildingInfluence = self.World.WorldActor.Trait();
+ foreach (var t in buildingInfo.Tiles(order.TargetLocation))
+ {
+ var host = buildingInfluence.GetBuildingAt(t);
+ if (host != null)
+ host.World.Remove(host);
+ }
+ }
+
var building = w.CreateActor(order.TargetString, new TypeDictionary
{
new LocationInit(order.TargetLocation),
diff --git a/OpenRA.Mods.Common/Traits/Replaceable.cs b/OpenRA.Mods.Common/Traits/Replaceable.cs
new file mode 100644
index 0000000000..4d2f0f122c
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Replaceable.cs
@@ -0,0 +1,31 @@
+#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 OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class ReplaceableInfo : ConditionalTraitInfo, ITraitInfo
+ {
+ [FieldLoader.Require]
+ [Desc("Replacement types this Relpaceable actor accepts.")]
+ public readonly HashSet Types = new HashSet();
+
+ public override object Create(ActorInitializer init) { return new Replaceable(init, this); }
+ }
+
+ public class Replaceable : ConditionalTrait
+ {
+ public Replaceable(ActorInitializer init, ReplaceableInfo info)
+ : base(info) { }
+ }
+}
diff --git a/OpenRA.Mods.Common/Traits/Replacement.cs b/OpenRA.Mods.Common/Traits/Replacement.cs
new file mode 100644
index 0000000000..5edc764dea
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Replacement.cs
@@ -0,0 +1,25 @@
+#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 OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class ReplacementInfo : TraitInfo
+ {
+ [FieldLoader.Require]
+ [Desc("Replacement type (matched against Conditions in Replaceable).")]
+ public readonly HashSet ReplaceableTypes = new HashSet();
+ }
+
+ public class Replacement { }
+}