1 #region Copyright & License Information 2 /* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10 #endregion 11 12 using System.Linq; 13 14 namespace OpenRA.Mods.Common.Traits 15 { 16 [Desc("This actor blocks bullets and missiles with 'Blockable' property.")] 17 public class BlocksProjectilesInfo : ConditionalTraitInfo, IBlocksProjectilesInfo 18 { 19 public readonly WDist Height = WDist.FromCells(1); 20 Create(ActorInitializer init)21 public override object Create(ActorInitializer init) { return new BlocksProjectiles(init.Self, this); } 22 } 23 24 public class BlocksProjectiles : ConditionalTrait<BlocksProjectilesInfo>, IBlocksProjectiles 25 { BlocksProjectiles(Actor self, BlocksProjectilesInfo info)26 public BlocksProjectiles(Actor self, BlocksProjectilesInfo info) 27 : base(info) { } 28 29 WDist IBlocksProjectiles.BlockingHeight { get { return Info.Height; } } 30 AnyBlockingActorAt(World world, WPos pos)31 public static bool AnyBlockingActorAt(World world, WPos pos) 32 { 33 var dat = world.Map.DistanceAboveTerrain(pos); 34 35 return world.ActorMap.GetActorsAt(world.Map.CellContaining(pos)) 36 .Any(a => a.TraitsImplementing<IBlocksProjectiles>() 37 .Where(t => t.BlockingHeight > dat) 38 .Any(Exts.IsTraitEnabled)); 39 } 40 AnyBlockingActorsBetween(World world, WPos start, WPos end, WDist width, out WPos hit)41 public static bool AnyBlockingActorsBetween(World world, WPos start, WPos end, WDist width, out WPos hit) 42 { 43 var actors = world.FindBlockingActorsOnLine(start, end, width); 44 var length = (end - start).Length; 45 46 foreach (var a in actors) 47 { 48 var blockers = a.TraitsImplementing<IBlocksProjectiles>() 49 .Where(Exts.IsTraitEnabled).ToList(); 50 51 if (!blockers.Any()) 52 continue; 53 54 var hitPos = WorldExtensions.MinimumPointLineProjection(start, end, a.CenterPosition); 55 var dat = world.Map.DistanceAboveTerrain(hitPos); 56 if ((hitPos - start).Length < length && blockers.Any(t => t.BlockingHeight > dat)) 57 { 58 hit = hitPos; 59 return true; 60 } 61 } 62 63 hit = WPos.Zero; 64 return false; 65 } 66 } 67 } 68