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; 13 using System.Collections.Generic; 14 using System.Linq; 15 using OpenRA.Traits; 16 17 namespace OpenRA.Mods.Common.Traits 18 { 19 [Desc("Where the unit should leave the building. Multiples are allowed if IDs are added: Exit@2, ...")] 20 public class ExitInfo : ConditionalTraitInfo, Requires<IOccupySpaceInfo> 21 { 22 [Desc("Offset at which that the exiting actor is spawned relative to the center of the producing actor.")] 23 public readonly WVec SpawnOffset = WVec.Zero; 24 25 [Desc("Cell offset where the exiting actor enters the ActorMap relative to the topleft cell of the producing actor.")] 26 public readonly CVec ExitCell = CVec.Zero; 27 public readonly int Facing = -1; 28 29 [Desc("Type tags on this exit.")] 30 public readonly HashSet<string> ProductionTypes = new HashSet<string>(); 31 32 [Desc("Number of ticks to wait before moving into the world.")] 33 public readonly int ExitDelay = 0; 34 35 [Desc("Exits with larger priorities will be used before lower priorities.")] 36 public readonly int Priority = 1; 37 Create(ActorInitializer init)38 public override object Create(ActorInitializer init) { return new Exit(init, this); } 39 } 40 41 public class Exit : ConditionalTrait<ExitInfo> 42 { Exit(ActorInitializer init, ExitInfo info)43 public Exit(ActorInitializer init, ExitInfo info) 44 : base(info) { } 45 } 46 47 public static class ExitExts 48 { FirstExitOrDefault(this Actor actor, string productionType = null)49 public static Exit FirstExitOrDefault(this Actor actor, string productionType = null) 50 { 51 var all = actor.TraitsImplementing<Exit>() 52 .Where(Exts.IsTraitEnabled) 53 .OrderBy(e => e.Info.Priority); 54 55 if (string.IsNullOrEmpty(productionType)) 56 return all.FirstOrDefault(); 57 58 return all.FirstOrDefault(e => e.Info.ProductionTypes.Count == 0 || e.Info.ProductionTypes.Contains(productionType)); 59 } 60 Exits(this Actor actor, string productionType = null)61 public static IEnumerable<Exit> Exits(this Actor actor, string productionType = null) 62 { 63 var all = actor.TraitsImplementing<Exit>() 64 .Where(Exts.IsTraitEnabled); 65 66 if (string.IsNullOrEmpty(productionType)) 67 return all; 68 69 return all.Where(e => e.Info.ProductionTypes.Count == 0 || e.Info.ProductionTypes.Contains(productionType)); 70 } 71 RandomExitOrDefault(this Actor actor, World world, string productionType, Func<Exit, bool> p = null)72 public static Exit RandomExitOrDefault(this Actor actor, World world, string productionType, Func<Exit, bool> p = null) 73 { 74 var allOfType = Exits(actor, productionType); 75 if (!allOfType.Any()) 76 return null; 77 78 foreach (var g in allOfType.GroupBy(e => e.Info.Priority)) 79 { 80 var shuffled = g.Shuffle(world.SharedRandom); 81 if (p == null) 82 return shuffled.First(); 83 84 var valid = shuffled.FirstOrDefault(p); 85 if (valid != null) 86 return valid; 87 } 88 89 return null; 90 } 91 } 92 } 93