Add place variant building for BaseBuilderBotModule.
1. If it follow the refinery placing logic, then we can use Facings in PlaceBuildingVariants to help BaseBuilderBotModule "rotates" it to minefield. 2. If it is a normal building, BaseBuilderBotModule will place a random variant actor.
This commit is contained in:
committed by
Matthias Mailänder
parent
f74d1c3cf8
commit
4f43b157a8
@@ -135,11 +135,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
// TODO: Derive this from BuildingCommonNames instead
|
// TODO: Derive this from BuildingCommonNames instead
|
||||||
var type = BuildingType.Building;
|
var type = BuildingType.Building;
|
||||||
CPos? location = null;
|
CPos? location = null;
|
||||||
|
var actorVariant = 0;
|
||||||
string orderString = "PlaceBuilding";
|
string orderString = "PlaceBuilding";
|
||||||
|
|
||||||
// Check if Building is a plug for other Building
|
// Check if Building is a plug for other Building
|
||||||
var actorInfo = world.Map.Rules.Actors[currentBuilding.Item];
|
var actorInfo = world.Map.Rules.Actors[currentBuilding.Item];
|
||||||
var plugInfo = actorInfo.TraitInfoOrDefault<PlugInfo>();
|
var plugInfo = actorInfo.TraitInfoOrDefault<PlugInfo>();
|
||||||
|
|
||||||
if (plugInfo != null)
|
if (plugInfo != null)
|
||||||
{
|
{
|
||||||
var possibleBuilding = world.ActorsWithTrait<Pluggable>().FirstOrDefault(a =>
|
var possibleBuilding = world.ActorsWithTrait<Pluggable>().FirstOrDefault(a =>
|
||||||
@@ -159,7 +161,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
else if (baseBuilder.Info.RefineryTypes.Contains(actorInfo.Name))
|
else if (baseBuilder.Info.RefineryTypes.Contains(actorInfo.Name))
|
||||||
type = BuildingType.Refinery;
|
type = BuildingType.Refinery;
|
||||||
|
|
||||||
location = ChooseBuildLocation(currentBuilding.Item, true, type);
|
var pack = ChooseBuildLocation(currentBuilding.Item, true, type);
|
||||||
|
location = pack.Location;
|
||||||
|
actorVariant = pack.Variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location == null)
|
if (location == null)
|
||||||
@@ -184,6 +188,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
// Building to place
|
// Building to place
|
||||||
TargetString = currentBuilding.Item,
|
TargetString = currentBuilding.Item,
|
||||||
|
|
||||||
|
// Actor variant will always be small enough to safely pack in a CPos
|
||||||
|
ExtraLocation = new CPos(actorVariant, 0),
|
||||||
|
|
||||||
// Actor ID to associate the placement with
|
// Actor ID to associate the placement with
|
||||||
ExtraData = queue.Actor.ActorID,
|
ExtraData = queue.Actor.ActorID,
|
||||||
SuppressVisualFeedback = true
|
SuppressVisualFeedback = true
|
||||||
@@ -325,8 +332,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!buildableThings.Any(b => b.Name == name))
|
if (!buildableThings.Any(b => b.Name == name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check the number of this structure and its variants
|
||||||
|
var actorInfo = world.Map.Rules.Actors[name];
|
||||||
|
var buildingVariantInfo = actorInfo.TraitInfoOrDefault<PlaceBuildingVariantsInfo>();
|
||||||
|
var variants = buildingVariantInfo?.Actors ?? Array.Empty<string>();
|
||||||
|
|
||||||
|
var count = playerBuildings.Count(a => a.Info.Name == name || variants.Contains(a.Info.Name));
|
||||||
|
|
||||||
// Do we want to build this structure?
|
// Do we want to build this structure?
|
||||||
var count = playerBuildings.Count(a => a.Info.Name == name);
|
|
||||||
if (count * 100 > frac.Value * playerBuildings.Length)
|
if (count * 100 > frac.Value * playerBuildings.Length)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -368,36 +381,86 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPos? ChooseBuildLocation(string actorType, bool distanceToBaseIsImportant, BuildingType type)
|
(CPos? Location, int Variant) ChooseBuildLocation(string actorType, bool distanceToBaseIsImportant, BuildingType type)
|
||||||
{
|
{
|
||||||
var actorInfo = world.Map.Rules.Actors[actorType];
|
var actorInfo = world.Map.Rules.Actors[actorType];
|
||||||
var bi = actorInfo.TraitInfoOrDefault<BuildingInfo>();
|
var bi = actorInfo.TraitInfoOrDefault<BuildingInfo>();
|
||||||
|
|
||||||
if (bi == null)
|
if (bi == null)
|
||||||
return null;
|
return (null, 0);
|
||||||
|
|
||||||
// Find the buildable cell that is closest to pos and centered around center
|
// Find the buildable cell that is closest to pos and centered around center
|
||||||
Func<CPos, CPos, int, int, CPos?> findPos = (center, target, minRange, maxRange) =>
|
Func<CPos, CPos, int, int, (CPos? Location, int Variant)> findPos = (center, target, minRange, maxRange) =>
|
||||||
{
|
{
|
||||||
|
var actorVariant = 0;
|
||||||
|
var buildingVariantInfo = actorInfo.TraitInfoOrDefault<PlaceBuildingVariantsInfo>();
|
||||||
|
var variantActorInfo = actorInfo;
|
||||||
|
var vbi = bi;
|
||||||
|
|
||||||
var cells = world.Map.FindTilesInAnnulus(center, minRange, maxRange);
|
var cells = world.Map.FindTilesInAnnulus(center, minRange, maxRange);
|
||||||
|
|
||||||
// Sort by distance to target if we have one
|
// Sort by distance to target if we have one
|
||||||
if (center != target)
|
if (center != target)
|
||||||
|
{
|
||||||
cells = cells.OrderBy(c => (c - target).LengthSquared);
|
cells = cells.OrderBy(c => (c - target).LengthSquared);
|
||||||
|
|
||||||
|
// Rotate building if we have a Facings in buildingVariantInfo.
|
||||||
|
// If we don't have Facings in buildingVariantInfo, use a random variant
|
||||||
|
if (buildingVariantInfo?.Actors != null)
|
||||||
|
{
|
||||||
|
if (buildingVariantInfo.Facings != null)
|
||||||
|
{
|
||||||
|
var vector = world.Map.CenterOfCell(target) - world.Map.CenterOfCell(center);
|
||||||
|
|
||||||
|
// The rotation Y point to upside vertically, so -Y = Y(rotation)
|
||||||
|
var desireFacing = new WAngle(WAngle.ArcSin((int)((long)Math.Abs(vector.X) * 1024 / vector.Length)).Angle);
|
||||||
|
if (vector.X > 0 && vector.Y >= 0)
|
||||||
|
desireFacing = new WAngle(512) - desireFacing;
|
||||||
|
else if (vector.X < 0 && vector.Y >= 0)
|
||||||
|
desireFacing = new WAngle(512) + desireFacing;
|
||||||
|
else if (vector.X < 0 && vector.Y < 0)
|
||||||
|
desireFacing = -desireFacing;
|
||||||
|
|
||||||
|
for (int i = 0, e = 1024; i < buildingVariantInfo.Facings.Length; i++)
|
||||||
|
{
|
||||||
|
var minDelta = Math.Min((desireFacing - buildingVariantInfo.Facings[i]).Angle, (buildingVariantInfo.Facings[i] - desireFacing).Angle);
|
||||||
|
if (e > minDelta)
|
||||||
|
{
|
||||||
|
e = minDelta;
|
||||||
|
actorVariant = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actorVariant = world.LocalRandom.Next(buildingVariantInfo.Actors.Length + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
cells = cells.Shuffle(world.LocalRandom);
|
cells = cells.Shuffle(world.LocalRandom);
|
||||||
|
|
||||||
|
if (buildingVariantInfo?.Actors != null)
|
||||||
|
actorVariant = world.LocalRandom.Next(buildingVariantInfo.Actors.Length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actorVariant != 0)
|
||||||
|
{
|
||||||
|
variantActorInfo = world.Map.Rules.Actors[buildingVariantInfo.Actors[actorVariant - 1]];
|
||||||
|
vbi = variantActorInfo.TraitInfoOrDefault<BuildingInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var cell in cells)
|
foreach (var cell in cells)
|
||||||
{
|
{
|
||||||
if (!world.CanPlaceBuilding(cell, actorInfo, bi, null))
|
if (!world.CanPlaceBuilding(cell, variantActorInfo, vbi, null))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (distanceToBaseIsImportant && !bi.IsCloseEnoughToBase(world, player, actorInfo, cell))
|
if (distanceToBaseIsImportant && !vbi.IsCloseEnoughToBase(world, player, variantActorInfo, cell))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return cell;
|
return (cell, actorVariant);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return (null, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
var baseCenter = baseBuilder.GetRandomBaseCenter();
|
var baseCenter = baseBuilder.GetRandomBaseCenter();
|
||||||
@@ -411,6 +474,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
.ClosestTo(world.Map.CenterOfCell(baseBuilder.DefenseCenter));
|
.ClosestTo(world.Map.CenterOfCell(baseBuilder.DefenseCenter));
|
||||||
|
|
||||||
var targetCell = closestEnemy != null ? closestEnemy.Location : baseCenter;
|
var targetCell = closestEnemy != null ? closestEnemy.Location : baseCenter;
|
||||||
|
|
||||||
return findPos(baseBuilder.DefenseCenter, targetCell, baseBuilder.Info.MinimumDefenseRadius, baseBuilder.Info.MaximumDefenseRadius);
|
return findPos(baseBuilder.DefenseCenter, targetCell, baseBuilder.Info.MinimumDefenseRadius, baseBuilder.Info.MaximumDefenseRadius);
|
||||||
|
|
||||||
case BuildingType.Refinery:
|
case BuildingType.Refinery:
|
||||||
@@ -425,7 +489,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
foreach (var r in nearbyResources)
|
foreach (var r in nearbyResources)
|
||||||
{
|
{
|
||||||
var found = findPos(baseCenter, r, baseBuilder.Info.MinBaseRadius, baseBuilder.Info.MaxBaseRadius);
|
var found = findPos(baseCenter, r, baseBuilder.Info.MinBaseRadius, baseBuilder.Info.MaxBaseRadius);
|
||||||
if (found != null)
|
if (found.Location != null)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -439,7 +503,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Can't find a build location
|
// Can't find a build location
|
||||||
return null;
|
return (null, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("Variant actors that can be cycled between when placing a structure.")]
|
[Desc("Variant actors that can be cycled between when placing a structure.")]
|
||||||
public readonly string[] Actors = null;
|
public readonly string[] Actors = null;
|
||||||
|
|
||||||
|
[Desc("Facing of the non-variant actor, followed by facings for each variant actor. The length equals the length of Actors + 1.")]
|
||||||
|
public readonly WAngle[] Facings = null;
|
||||||
|
|
||||||
public override object Create(ActorInitializer init) { return new PlaceBuildingVariants(); }
|
public override object Create(ActorInitializer init) { return new PlaceBuildingVariants(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user