Ensure starting units or units granted by a crate are not isolated.

When spawning starting units, or spawning units when collecting a crate, nearby locations will be used. If a nearby location cannot be reached, e.g. it is on top of a cliff or blocked in by trees, then any unit spawned there will be isolated which is not ideal.

Use the PathMightExistForLocomotorBlockedByImmovable method to filter nearby locations to those where the spawned unit can path back to the original location. This ensures the spawned unit is not isolated.
This commit is contained in:
RoosterDragon
2024-08-03 20:42:12 +01:00
committed by Matthias Mailänder
parent 6bc613e93f
commit 2c435c0506
3 changed files with 65 additions and 15 deletions

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits
[TraitLocation(SystemActors.World)]
[Desc("Spawn base actor at the spawnpoint and support units in an annulus around the base actor. " +
"Both are defined at MPStartUnits. Attach this to the world actor.")]
public class SpawnStartingUnitsInfo : TraitInfo, Requires<StartingUnitsInfo>, NotBefore<LocomotorInfo>, ILobbyOptions
public class SpawnStartingUnitsInfo : TraitInfo, Requires<StartingUnitsInfo>, NotBefore<PathFinderInfo>, ILobbyOptions
{
public readonly string StartingUnitsClass = "none";
@@ -102,13 +102,29 @@ namespace OpenRA.Mods.Common.Traits
if (unitGroup.SupportActors.Length == 0)
return;
var supportSpawnCells = w.Map.FindTilesInAnnulus(p.HomeLocation, unitGroup.InnerSupportRadius + 1, unitGroup.OuterSupportRadius);
var supportSpawnCells = w.Map
.FindTilesInAnnulus(p.HomeLocation, unitGroup.InnerSupportRadius + 1, unitGroup.OuterSupportRadius)
.ToList();
var pathFinder = w.WorldActor.TraitOrDefault<IPathFinder>();
var locomotorsByName = w.WorldActor.TraitsImplementing<Locomotor>().ToDictionary(l => l.Info.Name);
foreach (var s in unitGroup.SupportActors)
{
var actorRules = w.Map.Rules.Actors[s.ToLowerInvariant()];
var ip = actorRules.TraitInfo<IPositionableInfo>();
var validCell = supportSpawnCells.Shuffle(w.SharedRandom).FirstOrDefault(c => ip.CanEnterCell(w, null, c));
var validCells = supportSpawnCells.Where(c => ip.CanEnterCell(w, null, c));
if (pathFinder != null)
{
var locomotorName = actorRules.TraitInfoOrDefault<MobileInfo>()?.Locomotor;
var locomotor = locomotorName != null ? locomotorsByName[locomotorName] : null;
if (locomotor != null)
validCells = validCells
.Where(c => pathFinder.PathMightExistForLocomotorBlockedByImmovable(locomotor, c, p.HomeLocation + unitGroup.BaseActorOffset));
}
var validCell = validCells.RandomOrDefault(w.SharedRandom);
if (validCell == CPos.Zero)
{