Improve Replaceable logic:
- Remove BuildingInfluence checks - Support multiple Replaceable/Replacement traits on the same actors - Fix description typos
This commit is contained in:
@@ -22,22 +22,52 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!world.Map.Contains(cell))
|
if (!world.Map.Contains(cell))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var building = world.WorldActor.Trait<BuildingInfluence>().GetBuildingAt(cell);
|
if (!bi.AllowInvalidPlacement)
|
||||||
if (building != null)
|
|
||||||
{
|
{
|
||||||
if (ai == null)
|
// Replaceable actors are rare, so avoid initializing state unless we have to
|
||||||
|
var checkReplacements = ai != null && ai.HasTraitInfo<ReplacementInfo>();
|
||||||
|
HashSet<string> acceptedReplacements = null;
|
||||||
|
|
||||||
|
var foundActors = false;
|
||||||
|
foreach (var a in world.ActorMap.GetActorsAt(cell))
|
||||||
|
{
|
||||||
|
if (a == toIgnore)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this is potentially a replacement actor we must check *all* cell occupants
|
||||||
|
// before we know the placement is invalid
|
||||||
|
// Otherwise, we can bail immediately
|
||||||
|
if (!checkReplacements)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var replacementInfo = ai.TraitInfoOrDefault<ReplacementInfo>();
|
foundActors = true;
|
||||||
if (replacementInfo == null)
|
foreach (var r in a.TraitsImplementing<Replaceable>())
|
||||||
|
{
|
||||||
|
if (r.IsTraitDisabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (acceptedReplacements == null)
|
||||||
|
acceptedReplacements = new HashSet<string>();
|
||||||
|
|
||||||
|
acceptedReplacements.UnionWith(r.Info.Types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replacements are enabled and the cell contained at least one (not ignored) actor
|
||||||
|
if (foundActors)
|
||||||
|
{
|
||||||
|
// The cell contains at least one actor, and none were replaceable
|
||||||
|
if (acceptedReplacements == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!building.TraitsImplementing<Replaceable>().Any(p => !p.IsTraitDisabled &&
|
// The cell contains at least one replaceable actor, but not of the types we accept
|
||||||
p.Info.Types.Overlaps(replacementInfo.ReplaceableTypes)))
|
var foundReplacement = ai.TraitInfos<ReplacementInfo>()
|
||||||
|
.Any(r => r.ReplaceableTypes.Overlaps(acceptedReplacements));
|
||||||
|
|
||||||
|
if (!foundReplacement)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!bi.AllowInvalidPlacement && world.ActorMap.GetActorsAt(cell).Any(a => a != toIgnore))
|
}
|
||||||
return false;
|
|
||||||
|
|
||||||
// Buildings can never be placed on ramps
|
// Buildings can never be placed on ramps
|
||||||
return world.Map.Ramp[cell] == 0 && bi.TerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type);
|
return world.Map.Ramp[cell] == 0 && bi.TerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type);
|
||||||
|
|||||||
@@ -163,16 +163,15 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|| !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, actorInfo, targetLocation))
|
|| !buildingInfo.IsCloseEnoughToBase(self.World, order.Player, actorInfo, targetLocation))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var replacementInfo = actorInfo.TraitInfoOrDefault<ReplacementInfo>();
|
var replaceableTypes = actorInfo.TraitInfos<ReplacementInfo>()
|
||||||
if (replacementInfo != null)
|
.SelectMany(r => r.ReplaceableTypes)
|
||||||
{
|
.ToHashSet();
|
||||||
var buildingInfluence = self.World.WorldActor.Trait<BuildingInfluence>();
|
|
||||||
|
if (replaceableTypes.Any())
|
||||||
foreach (var t in buildingInfo.Tiles(targetLocation))
|
foreach (var t in buildingInfo.Tiles(targetLocation))
|
||||||
{
|
foreach (var a in self.World.ActorMap.GetActorsAt(t))
|
||||||
var host = buildingInfluence.GetBuildingAt(t);
|
if (a.TraitsImplementing<Replaceable>().Any(r => !r.IsTraitDisabled && r.Info.Types.Overlaps(replaceableTypes)))
|
||||||
host?.World.Remove(host);
|
self.World.Remove(a);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var building = w.CreateActor(actorInfo.Name, new TypeDictionary
|
var building = w.CreateActor(actorInfo.Name, new TypeDictionary
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public class ReplaceableInfo : ConditionalTraitInfo
|
public class ReplaceableInfo : ConditionalTraitInfo
|
||||||
{
|
{
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[Desc("Replacement types this Relpaceable actor accepts.")]
|
[Desc("Replacement types this Replaceable actor accepts.")]
|
||||||
public readonly HashSet<string> Types = new HashSet<string>();
|
public readonly HashSet<string> Types = new HashSet<string>();
|
||||||
|
|
||||||
public override object Create(ActorInitializer init) { return new Replaceable(init, this); }
|
public override object Create(ActorInitializer init) { return new Replaceable(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Replaceable : ConditionalTrait<ReplaceableInfo>
|
public class Replaceable : ConditionalTrait<ReplaceableInfo>
|
||||||
{
|
{
|
||||||
public Replaceable(ActorInitializer init, ReplaceableInfo info)
|
public Replaceable(ReplaceableInfo info)
|
||||||
: base(info) { }
|
: base(info) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public class ReplacementInfo : TraitInfo<Replacement>
|
public class ReplacementInfo : TraitInfo<Replacement>
|
||||||
{
|
{
|
||||||
[FieldLoader.Require]
|
[FieldLoader.Require]
|
||||||
[Desc("Replacement type (matched against Conditions in Replaceable).")]
|
[Desc("Replacement type (matched against Types in Replaceable).")]
|
||||||
public readonly HashSet<string> ReplaceableTypes = new HashSet<string>();
|
public readonly HashSet<string> ReplaceableTypes = new HashSet<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user