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.Collections.Generic; 13 using System.Linq; 14 using OpenRA.Mods.Common.Traits; 15 using OpenRA.Traits; 16 17 namespace OpenRA.Mods.Cnc.Traits 18 { 19 [Desc("Required for `GpsPower`. Attach this to the player actor.")] 20 class GpsWatcherInfo : ITraitInfo 21 { Create(ActorInitializer init)22 public object Create(ActorInitializer init) { return new GpsWatcher(init.Self.Owner); } 23 } 24 OnGpsRefresh(Actor self, Player player)25 interface IOnGpsRefreshed { void OnGpsRefresh(Actor self, Player player); } 26 27 class GpsWatcher : ISync, IPreventsShroudReset 28 { 29 [Sync] 30 public bool Launched { get; private set; } 31 32 [Sync] 33 public bool GrantedAllies { get; private set; } 34 35 [Sync] 36 public bool Granted { get; private set; } 37 38 // Whether this watcher has explored the terrain (by becoming Launched, or an ally becoming Launched) 39 [Sync] 40 bool explored; 41 42 readonly Player owner; 43 44 readonly List<Actor> actors = new List<Actor>(); 45 readonly HashSet<TraitPair<IOnGpsRefreshed>> notifyOnRefresh = new HashSet<TraitPair<IOnGpsRefreshed>>(); 46 GpsWatcher(Player owner)47 public GpsWatcher(Player owner) 48 { 49 this.owner = owner; 50 } 51 GpsRemove(Actor atek)52 public void GpsRemove(Actor atek) 53 { 54 actors.Remove(atek); 55 RefreshGps(atek.Owner); 56 } 57 GpsAdd(Actor atek)58 public void GpsAdd(Actor atek) 59 { 60 actors.Add(atek); 61 RefreshGps(atek.Owner); 62 } 63 ReachedOrbit(Player launcher)64 public void ReachedOrbit(Player launcher) 65 { 66 Launched = true; 67 RefreshGps(launcher); 68 } 69 RefreshGps(Player launcher)70 public void RefreshGps(Player launcher) 71 { 72 RefreshGranted(); 73 74 foreach (var i in launcher.World.ActorsWithTrait<GpsWatcher>()) 75 i.Trait.RefreshGranted(); 76 } 77 RefreshGranted()78 void RefreshGranted() 79 { 80 var wasGranted = Granted; 81 var wasGrantedAllies = GrantedAllies; 82 var allyWatchers = owner.World.ActorsWithTrait<GpsWatcher>().Where(kv => kv.Actor.Owner.IsAlliedWith(owner)); 83 84 Granted = actors.Count > 0 && Launched; 85 GrantedAllies = allyWatchers.Any(w => w.Trait.Granted); 86 87 var allyLaunched = allyWatchers.Any(w => w.Trait.Launched); 88 if ((Launched || allyLaunched) && !explored) 89 { 90 explored = true; 91 owner.Shroud.ExploreAll(); 92 } 93 94 if (wasGranted != Granted || wasGrantedAllies != GrantedAllies) 95 foreach (var tp in notifyOnRefresh.ToList()) 96 tp.Trait.OnGpsRefresh(tp.Actor, owner); 97 } 98 IPreventsShroudReset.PreventShroudReset(Actor self)99 bool IPreventsShroudReset.PreventShroudReset(Actor self) 100 { 101 return Granted || GrantedAllies; 102 } 103 RegisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified)104 public void RegisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified) 105 { 106 notifyOnRefresh.Add(new TraitPair<IOnGpsRefreshed>(actor, toBeNotified)); 107 } 108 UnregisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified)109 public void UnregisterForOnGpsRefreshed(Actor actor, IOnGpsRefreshed toBeNotified) 110 { 111 notifyOnRefresh.Remove(new TraitPair<IOnGpsRefreshed>(actor, toBeNotified)); 112 } 113 } 114 } 115