#region Copyright & License Information /* * Copyright 2007-2021 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.Linq; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor blocks bullets and missiles with 'Blockable' property.")] public class BlocksProjectilesInfo : ConditionalTraitInfo, IBlocksProjectilesInfo { public readonly WDist Height = WDist.FromCells(1); [Desc("Determines what projectiles to block based on their allegiance to the wall owner.")] public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; public override object Create(ActorInitializer init) { return new BlocksProjectiles(init.Self, this); } } public class BlocksProjectiles : ConditionalTrait, IBlocksProjectiles { public BlocksProjectiles(Actor self, BlocksProjectilesInfo info) : base(info) { } WDist IBlocksProjectiles.BlockingHeight => Info.Height; PlayerRelationship IBlocksProjectiles.ValidRelationships { get { return Info.ValidRelationships; } } public static bool AnyBlockingActorAt(World world, WPos pos) { var dat = world.Map.DistanceAboveTerrain(pos); return world.ActorMap.GetActorsAt(world.Map.CellContaining(pos)) .Any(a => a.TraitsImplementing() .Where(t => t.BlockingHeight > dat) .Any(Exts.IsTraitEnabled)); } public static bool AnyBlockingActorsBetween(World world, Player owner, WPos start, WPos end, WDist width, out WPos hit) { var actors = world.FindBlockingActorsOnLine(start, end, width); var length = (end - start).Length; foreach (var a in actors) { var blockers = a.TraitsImplementing() .Where(Exts.IsTraitEnabled).Where(t => t.ValidRelationships.HasRelationship(a.Owner.RelationshipWith(owner))) .ToList(); if (!blockers.Any()) continue; var hitPos = WorldExtensions.MinimumPointLineProjection(start, end, a.CenterPosition); var dat = world.Map.DistanceAboveTerrain(hitPos); if ((hitPos - start).Length < length && blockers.Any(t => t.BlockingHeight > dat)) { hit = hitPos; return true; } } hit = WPos.Zero; return false; } } }