diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index d322129ffe..af8e2c5bad 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -99,7 +99,7 @@ namespace OpenRA.Orders if (self.Owner != self.World.LocalPlayer) return null; - if (self.Destroyed || target.Type == TargetType.Invalid) + if (self.Destroyed || !target.IsValidFor(self)) return null; if (mi.Button == Game.mouseButtonPreference.Action) diff --git a/OpenRA.Game/Traits/DrawLineToTarget.cs b/OpenRA.Game/Traits/DrawLineToTarget.cs index 319bf94fce..a0fb811743 100644 --- a/OpenRA.Game/Traits/DrawLineToTarget.cs +++ b/OpenRA.Game/Traits/DrawLineToTarget.cs @@ -64,7 +64,7 @@ namespace OpenRA.Traits foreach (var target in targets) { - if (!target.IsValid) + if (target.Type == TargetType.Invalid) continue; var to = wr.ScreenPxPosition(target.CenterPosition); diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 2a8f95f485..0a5d6d9609 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -161,7 +161,7 @@ namespace OpenRA.Traits var c = Color.Green; var wlr = Game.Renderer.WorldLineRenderer; - foreach (var stp in targets.Where(t => t.IsValid).Select(p => wr.ScreenPxPosition(p.CenterPosition))) + foreach (var stp in targets.Where(t => t.Type != TargetType.Invalid).Select(p => wr.ScreenPxPosition(p.CenterPosition))) { wlr.DrawLine(stp + new float2(-1, -1), stp + new float2(-1, 1), c, c); wlr.DrawLine(stp + new float2(-1, 1), stp + new float2(1, 1), c, c); diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs index bc7ae62151..50e17d9fab 100644 --- a/OpenRA.Game/Traits/Target.cs +++ b/OpenRA.Game/Traits/Target.cs @@ -22,6 +22,7 @@ namespace OpenRA.Traits TargetType type; Actor actor; + ITargetable targetable; FrozenActor frozen; WPos pos; int generation; @@ -37,17 +38,20 @@ namespace OpenRA.Traits public static Target FromActor(Actor a) { + if (a == null) + return Target.Invalid; + return new Target { actor = a, - type = a != null ? TargetType.Actor : TargetType.Invalid, + targetable = a.TraitOrDefault(), + type = TargetType.Actor, generation = a.Generation, }; } public static Target FromFrozenActor(FrozenActor a) { return new Target { frozen = a, type = TargetType.FrozenActor }; } - public bool IsValid { get { return Type != TargetType.Invalid; } } public Actor Actor { get { return actor; } } public FrozenActor FrozenActor { get { return frozen; } } @@ -70,6 +74,17 @@ namespace OpenRA.Traits } } + public bool IsValidFor(Actor targeter) + { + if (targeter == null || Type == TargetType.Invalid) + return false; + + if (targetable != null && !targetable.TargetableBy(actor, targeter)) + return false; + + return true; + } + // Representative position - see Positions for the full set of targetable positions. public WPos CenterPosition { diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index 7437b08734..7b64fa2795 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -99,7 +99,7 @@ namespace OpenRA.Mods.RA.AI HackyAI bot; XRandom random; - Actor target; + Target target; StateMachine fsm; //fuzzy @@ -113,7 +113,8 @@ namespace OpenRA.Mods.RA.AI this.world = bot.world; this.random = bot.random; this.type = type; - this.target = target; + this.target = Traits.Target.FromActor(target); + fsm = new StateMachine(this); switch (type) @@ -144,14 +145,13 @@ namespace OpenRA.Mods.RA.AI public Actor Target { - get { return target; } - set { target = value; } + get { return target.Actor; } + set { target = Traits.Target.FromActor(value); } } public bool TargetIsValid { - get { return (target != null && !target.IsDead() && !target.Destroyed - && target.IsInWorld && !target.HasTrait()); } + get { return target.IsValidFor(units.FirstOrDefault()) && !target.Actor.HasTrait(); } } //********************************************************************************** diff --git a/OpenRA.Mods.RA/Activities/Attack.cs b/OpenRA.Mods.RA/Activities/Attack.cs index 0d8f045cd6..8be668ed38 100755 --- a/OpenRA.Mods.RA/Activities/Attack.cs +++ b/OpenRA.Mods.RA/Activities/Attack.cs @@ -18,7 +18,6 @@ namespace OpenRA.Mods.RA.Activities public class Attack : Activity { protected Target Target; - ITargetable targetable; WRange Range; bool AllowMovement; @@ -33,9 +32,6 @@ namespace OpenRA.Mods.RA.Activities public Attack(Target target, WRange range, bool allowMovement) { Target = target; - if (target.Type == TargetType.Actor) - targetable = target.Actor.TraitOrDefault(); - Range = range; AllowMovement = allowMovement; } @@ -54,13 +50,11 @@ namespace OpenRA.Mods.RA.Activities return NextActivity; var type = Target.Type; - if (type != TargetType.Actor && type != TargetType.Terrain) - return NextActivity; - - if (type == TargetType.Actor && !self.Owner.HasFogVisibility() && Target.Actor.HasTrait() && !self.Owner.Shroud.IsTargetable(Target.Actor)) + if (!Target.IsValidFor(self) || type == TargetType.FrozenActor) return NextActivity; - if (targetable != null && !targetable.TargetableBy(Target.Actor, self)) + // TODO: This is horrible, and probably wrong. Work out what it is trying to solve, then redo it properly. + if (type == TargetType.Actor && !self.Owner.HasFogVisibility() && Target.Actor.HasTrait() && !self.Owner.Shroud.IsTargetable(Target.Actor)) return NextActivity; if (!Target.IsInRange(self.CenterPosition, Range)) diff --git a/OpenRA.Mods.RA/Activities/CaptureActor.cs b/OpenRA.Mods.RA/Activities/CaptureActor.cs index 8b694abad2..77bd9617b1 100644 --- a/OpenRA.Mods.RA/Activities/CaptureActor.cs +++ b/OpenRA.Mods.RA/Activities/CaptureActor.cs @@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA.Activities var capturable = target.Actor.Trait(); - if (IsCanceled || !self.IsInWorld || self.IsDead()) + if (IsCanceled || !self.IsInWorld || self.IsDead() || !target.IsValidFor(self)) { if (capturable.CaptureInProgress) capturable.EndCapture(); diff --git a/OpenRA.Mods.RA/Activities/Demolish.cs b/OpenRA.Mods.RA/Activities/Demolish.cs index 5161cb7509..4371a2c723 100644 --- a/OpenRA.Mods.RA/Activities/Demolish.cs +++ b/OpenRA.Mods.RA/Activities/Demolish.cs @@ -27,7 +27,7 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - if (IsCanceled || target.Type != TargetType.Actor) + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => diff --git a/OpenRA.Mods.RA/Activities/DonateSupplies.cs b/OpenRA.Mods.RA/Activities/DonateSupplies.cs index 4382f60895..5c8e7d88f9 100644 --- a/OpenRA.Mods.RA/Activities/DonateSupplies.cs +++ b/OpenRA.Mods.RA/Activities/DonateSupplies.cs @@ -27,7 +27,10 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - if (IsCanceled || target.Type != TargetType.Actor) + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; + + if (target.Type != TargetType.Actor) return NextActivity; var targetActor = target.Actor; diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index cddb4b1cf2..cd74111176 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -27,7 +27,10 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - if (IsCanceled || target.Type != TargetType.Actor) + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; + + if (target.Type != TargetType.Actor) return NextActivity; if (!Util.AdjacentCells(target).Any(c => c == self.Location)) diff --git a/OpenRA.Mods.RA/Activities/Follow.cs b/OpenRA.Mods.RA/Activities/Follow.cs index 70827aeb6b..4795202509 100644 --- a/OpenRA.Mods.RA/Activities/Follow.cs +++ b/OpenRA.Mods.RA/Activities/Follow.cs @@ -16,21 +16,23 @@ namespace OpenRA.Mods.RA.Activities public class Follow : Activity { Target target; + Mobile mobile; WRange range; int nextPathTime; const int delayBetweenPathingAttempts = 20; const int delaySpread = 5; - public Follow(Target target, WRange range) + public Follow(Actor self, Target target, WRange range) { this.target = target; + mobile = self.Trait(); this.range = range; } public override Activity Tick(Actor self) { - if (IsCanceled || !target.IsValid) + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; if (target.IsInRange(self.CenterPosition, range) || --nextPathTime > 0) @@ -39,7 +41,6 @@ namespace OpenRA.Mods.RA.Activities nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, delayBetweenPathingAttempts + delaySpread); - var mobile = self.Trait(); return Util.SequenceActivities(mobile.MoveWithinRange(target, range), this); } } diff --git a/OpenRA.Mods.RA/Activities/Heal.cs b/OpenRA.Mods.RA/Activities/Heal.cs index ea000e910e..d6b0d236ed 100755 --- a/OpenRA.Mods.RA/Activities/Heal.cs +++ b/OpenRA.Mods.RA/Activities/Heal.cs @@ -22,6 +22,9 @@ namespace OpenRA.Mods.RA.Activities protected override Activity InnerTick(Actor self, AttackBase attack) { + if (!Target.IsValidFor(self)) + return NextActivity; + if (Target.Type == TargetType.Actor && Target.Actor.GetDamageState() == DamageState.Undamaged) return NextActivity; diff --git a/OpenRA.Mods.RA/Activities/LegacyCaptureActor.cs b/OpenRA.Mods.RA/Activities/LegacyCaptureActor.cs index a2ba106cca..6455e7dc72 100644 --- a/OpenRA.Mods.RA/Activities/LegacyCaptureActor.cs +++ b/OpenRA.Mods.RA/Activities/LegacyCaptureActor.cs @@ -23,7 +23,10 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - if (IsCanceled || target.Type != TargetType.Actor) + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; + + if (target.Type != TargetType.Actor) return NextActivity; var actor = target.Actor; diff --git a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs index 285312b7b0..083a8b04be 100755 --- a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs +++ b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Activities public override Activity Tick(Actor self) { - if (IsCanceled || !target.IsValid) + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; var mobile = self.Trait(); diff --git a/OpenRA.Mods.RA/Air/FlyAttack.cs b/OpenRA.Mods.RA/Air/FlyAttack.cs index 1e577804f4..cb8ea4eea5 100755 --- a/OpenRA.Mods.RA/Air/FlyAttack.cs +++ b/OpenRA.Mods.RA/Air/FlyAttack.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { - if (!target.IsValid) + if (!target.IsValidFor(self)) Cancel(self); var limitedAmmo = self.TraitOrDefault(); diff --git a/OpenRA.Mods.RA/Air/HeliAttack.cs b/OpenRA.Mods.RA/Air/HeliAttack.cs index 1ba4d4d417..9655601307 100755 --- a/OpenRA.Mods.RA/Air/HeliAttack.cs +++ b/OpenRA.Mods.RA/Air/HeliAttack.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { - if (IsCanceled || !target.IsValid) + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; var limitedAmmo = self.TraitOrDefault(); diff --git a/OpenRA.Mods.RA/Air/Land.cs b/OpenRA.Mods.RA/Air/Land.cs index d6bde50f44..82106ab876 100755 --- a/OpenRA.Mods.RA/Air/Land.cs +++ b/OpenRA.Mods.RA/Air/Land.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Air public override Activity Tick(Actor self) { - if (!target.IsValid) + if (!target.IsValidFor(self)) Cancel(self); if (IsCanceled) diff --git a/OpenRA.Mods.RA/Attack/AttackBase.cs b/OpenRA.Mods.RA/Attack/AttackBase.cs index 343bc7fcdd..45e2a8e248 100644 --- a/OpenRA.Mods.RA/Attack/AttackBase.cs +++ b/OpenRA.Mods.RA/Attack/AttackBase.cs @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA if (!self.IsInWorld) return false; - if (!target.IsValid) + if (!target.IsValidFor(self)) return false; if (Armaments.All(a => a.IsReloading)) @@ -54,10 +54,6 @@ namespace OpenRA.Mods.RA if (self.IsDisabled()) return false; - if (target.Type == TargetType.Actor && target.Actor.HasTrait() && - !target.Actor.Trait().TargetableBy(target.Actor, self)) - return false; - return true; } @@ -133,7 +129,7 @@ namespace OpenRA.Mods.RA if (order.OrderString == "Attack") { var target = self.ResolveFrozenActorOrder(order, Color.Red); - if (!target.IsValid) + if (!target.IsValidFor(self)) return; self.SetTargetLine(target, Color.Red); @@ -155,7 +151,7 @@ namespace OpenRA.Mods.RA public void AttackTarget(Target target, bool queued, bool allowMove) { - if (!target.IsValid) + if (!target.IsValidFor(self)) return; if (!queued) diff --git a/OpenRA.Mods.RA/Attack/AttackOmni.cs b/OpenRA.Mods.RA/Attack/AttackOmni.cs index 07a06a7d64..80389ca35b 100644 --- a/OpenRA.Mods.RA/Attack/AttackOmni.cs +++ b/OpenRA.Mods.RA/Attack/AttackOmni.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA public override Activity Tick( Actor self ) { - if( IsCanceled || !target.IsValid ) + if (IsCanceled || !target.IsValidFor(self)) return NextActivity; self.Trait().DoAttack(self, target); diff --git a/OpenRA.Mods.RA/Attack/AttackTesla.cs b/OpenRA.Mods.RA/Attack/AttackTesla.cs index 034fc66dcf..56f2091ec3 100644 --- a/OpenRA.Mods.RA/Attack/AttackTesla.cs +++ b/OpenRA.Mods.RA/Attack/AttackTesla.cs @@ -67,7 +67,8 @@ namespace OpenRA.Mods.RA public override Activity Tick( Actor self ) { - if( IsCanceled || !target.IsValid ) return NextActivity; + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; var attack = self.Trait(); if( attack.charges == 0 || !attack.CanAttack( self, target ) ) @@ -85,7 +86,8 @@ namespace OpenRA.Mods.RA public override Activity Tick( Actor self ) { - if( IsCanceled || !target.IsValid ) return NextActivity; + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; var attack = self.Trait(); if( attack.charges == 0 ) return NextActivity; diff --git a/OpenRA.Mods.RA/Attack/AttackTurreted.cs b/OpenRA.Mods.RA/Attack/AttackTurreted.cs index ed3f2ef799..8b0022fa34 100644 --- a/OpenRA.Mods.RA/Attack/AttackTurreted.cs +++ b/OpenRA.Mods.RA/Attack/AttackTurreted.cs @@ -38,7 +38,8 @@ namespace OpenRA.Mods.RA if (self.HasTrait() && !buildComplete) return false; - if (!target.IsValid) return false; + if (!target.IsValidFor(self)) + return false; bool canAttack = false; foreach (var t in turrets) @@ -53,7 +54,7 @@ namespace OpenRA.Mods.RA { base.Tick(self); DoAttack(self, Target); - IsAttacking = Target.IsValid; + IsAttacking = Target.IsValidFor(self); } public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) @@ -84,7 +85,8 @@ namespace OpenRA.Mods.RA public override Activity Tick(Actor self) { - if (IsCanceled || !target.IsValid) return NextActivity; + if (IsCanceled || !target.IsValidFor(self)) + return NextActivity; if (self.IsDisabled()) return this; @@ -98,7 +100,7 @@ namespace OpenRA.Mods.RA attack.Target = target; if (allowMove && self.HasTrait() && !self.Info.Traits.Get().OnRails) - return Util.SequenceActivities(new Follow(target, range), this); + return Util.SequenceActivities(new Follow(self, target, range), this); } return NextActivity; diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index e2dc8ccc3d..bcbeabf7ab 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -19,12 +19,14 @@ namespace OpenRA.Mods.RA { public class CloakInfo : ITraitInfo { - public int InitialDelay = 10; // Ticks - public int CloakDelay = 30; // Ticks - public string CloakSound = "subshow1.aud"; - public string UncloakSound = "subshow1.aud"; - public readonly string Palette = "cloak"; + public readonly int InitialDelay = 10; // Ticks + public readonly int CloakDelay = 30; // Ticks public readonly bool UncloakOnMove = false; + public readonly bool RequiresCrate = false; + + public readonly string CloakSound = "subshow1.aud"; + public readonly string UncloakSound = "subshow1.aud"; + public readonly string Palette = "cloak"; public object Create(ActorInitializer init) { return new Cloak(init.self, this); } } @@ -32,7 +34,8 @@ namespace OpenRA.Mods.RA public class Cloak : IRenderModifier, INotifyDamageStateChanged, INotifyAttack, ITick, IVisibilityModifier, IRadarColorModifier, ISync { [Sync] int remainingTime; - [Sync] bool canCloak = true; + [Sync] bool damageDisabled; + [Sync] bool crateDisabled; Actor self; CloakInfo info; @@ -44,6 +47,7 @@ namespace OpenRA.Mods.RA this.self = self; remainingTime = info.InitialDelay; + crateDisabled = info.RequiresCrate; } public void Uncloak() { Uncloak(info.CloakDelay); } @@ -62,8 +66,9 @@ namespace OpenRA.Mods.RA public void DamageStateChanged(Actor self, AttackInfo e) { - canCloak = (e.DamageState < DamageState.Critical); - if (!canCloak) Uncloak(); + damageDisabled = e.DamageState >= DamageState.Critical; + if (damageDisabled) + Uncloak(); } public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) @@ -82,9 +87,12 @@ namespace OpenRA.Mods.RA public void Tick(Actor self) { - if (remainingTime > 0 && canCloak) - if (--remainingTime <= 0) - Sound.Play(info.CloakSound, self.CenterPosition); + if (remainingTime > 0 && !crateDisabled && !damageDisabled && --remainingTime <= 0) + { + self.Generation++; + Sound.Play(info.CloakSound, self.CenterPosition); + } + if (self.IsDisabled()) Uncloak(); @@ -95,15 +103,14 @@ namespace OpenRA.Mods.RA } } - public bool IsVisible(Actor self, Player byPlayer) + public bool IsVisible(Actor self, Player viewer) { - if (!Cloaked || self.Owner.IsAlliedWith(byPlayer)) + if (!Cloaked || self.Owner.IsAlliedWith(viewer)) return true; - // TODO: Change this to be per-player? A cloak detector revealing to everyone is dumb - return self.World.ActorsWithTrait().Any(a => - a.Actor.Owner.Stances[self.Owner] != Stance.Ally && - (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); + var centerPosition = self.CenterPosition; + return self.World.ActorsWithTrait().Any(a => a.Actor.Owner.IsAlliedWith(viewer) && + (centerPosition - a.Actor.CenterPosition).Length < WRange.FromCells(a.Actor.Info.Traits.Get().Range).Range); } public Color RadarColorOverride(Actor self) @@ -113,5 +120,12 @@ namespace OpenRA.Mods.RA c = Color.FromArgb(128, c); return c; } + + public bool AcceptsCloakCrate { get { return info.RequiresCrate && crateDisabled; } } + + public void ReceivedCloakCrate(Actor self) + { + crateDisabled = false; + } } } diff --git a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs index e7b7498685..4095eda5a0 100644 --- a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs @@ -16,52 +16,27 @@ namespace OpenRA.Mods.RA.Crates { public class CloakCrateActionInfo : CrateActionInfo { - public readonly int InitialDelay = 10; - public readonly int CloakDelay = 30; - public readonly string CloakSound = "subshow1.aud"; - public readonly string UncloakSound = "subshow1.aud"; - public override object Create(ActorInitializer init) { return new CloakCrateAction(init.self, this); } } public class CloakCrateAction : CrateAction { - CloakCrateActionInfo Info; public CloakCrateAction(Actor self, CloakCrateActionInfo info) - : base(self, info) { Info = info; } + : base(self, info) { } public override int GetSelectionShares(Actor collector) { - return collector.HasTrait() && !collector.HasTrait() - ? base.GetSelectionShares(collector) : 0; + var cloak = collector.TraitOrDefault(); + if (cloak == null || !cloak.AcceptsCloakCrate) + return 0; + + return base.GetSelectionShares(collector); } public override void Activate(Actor collector) { - var cloakInfo = new CloakInfo() - { - InitialDelay = Info.InitialDelay, - CloakDelay = Info.CloakDelay, - CloakSound = Info.CloakSound, - UncloakSound = Info.UncloakSound - }; - var cloak = new Cloak(collector, cloakInfo); - - collector.World.AddFrameEndTask(w => - { - w.Remove(collector); - - collector.AddTrait(cloak); - var t = collector.TraitOrDefault(); - if (t != null) t.ReceivedCloak(collector); - - w.Add(collector); - }); - + collector.Trait().ReceivedCloakCrate(collector); base.Activate(collector); } } - - public class AcceptsCloakCrateInfo : TraitInfo {} - public class AcceptsCloakCrate {} } diff --git a/OpenRA.Mods.RA/Effects/GpsDot.cs b/OpenRA.Mods.RA/Effects/GpsDot.cs index ab2291f1a7..3bc28aea69 100644 --- a/OpenRA.Mods.RA/Effects/GpsDot.cs +++ b/OpenRA.Mods.RA/Effects/GpsDot.cs @@ -36,6 +36,7 @@ namespace OpenRA.Mods.RA.Effects Lazy huf; Lazy fuf; Lazy spy; + Lazy cloak; Cache watcher; Cache frozen; @@ -53,15 +54,15 @@ namespace OpenRA.Mods.RA.Effects huf = Lazy.New(() => self.TraitOrDefault()); fuf = Lazy.New(() => self.TraitOrDefault()); spy = Lazy.New(() => self.TraitOrDefault()); + cloak = Lazy.New(() => self.TraitOrDefault()); + watcher = new Cache(p => p.PlayerActor.Trait()); frozen = new Cache(p => p.PlayerActor.Trait()); } bool ShouldShowIndicator() { - // Can be granted at runtime via a crate, so can't cache - var cloak = self.TraitOrDefault(); - if (cloak != null && cloak.Cloaked) + if (cloak.Value != null && cloak.Value.Cloaked) return false; if (spy.Value != null && spy.Value.Disguised) diff --git a/OpenRA.Mods.RA/Effects/LaserZap.cs b/OpenRA.Mods.RA/Effects/LaserZap.cs index 5f26485fd7..f11caddeec 100755 --- a/OpenRA.Mods.RA/Effects/LaserZap.cs +++ b/OpenRA.Mods.RA/Effects/LaserZap.cs @@ -59,7 +59,7 @@ namespace OpenRA.Mods.RA.Effects public void Tick(World world) { // Beam tracks target - if (args.guidedTarget.IsValid) + if (args.guidedTarget.IsValidFor(args.sourceActor)) target = args.guidedTarget.CenterPosition; if (!doneDamage) diff --git a/OpenRA.Mods.RA/Effects/Missile.cs b/OpenRA.Mods.RA/Effects/Missile.cs index 23e8c362e4..15cc87aa42 100755 --- a/OpenRA.Mods.RA/Effects/Missile.cs +++ b/OpenRA.Mods.RA/Effects/Missile.cs @@ -120,7 +120,7 @@ namespace OpenRA.Mods.RA.Effects anim.Tick(); // Missile tracks target - if (args.guidedTarget.IsValid) + if (args.guidedTarget.IsValidFor(args.sourceActor)) target = args.guidedTarget.CenterPosition; var dist = target + offset - pos; @@ -133,7 +133,7 @@ namespace OpenRA.Mods.RA.Effects desiredFacing = facing + world.SharedRandom.Next(-20, 21); desiredAltitude = world.SharedRandom.Next(-43, 86); } - else if (!args.guidedTarget.IsValid) + else if (!args.guidedTarget.IsValidFor(args.sourceActor)) desiredFacing = facing; facing = Traits.Util.TickFacing(facing, desiredFacing, info.ROT); diff --git a/OpenRA.Mods.RA/Effects/TeslaZap.cs b/OpenRA.Mods.RA/Effects/TeslaZap.cs index 56dfbb32ed..f4c4a5eae7 100755 --- a/OpenRA.Mods.RA/Effects/TeslaZap.cs +++ b/OpenRA.Mods.RA/Effects/TeslaZap.cs @@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Effects if (!doneDamage) { - var pos = Args.guidedTarget.IsValid ? Args.guidedTarget.CenterPosition : Args.passiveTarget; + var pos = Args.guidedTarget.IsValidFor(Args.sourceActor) ? Args.guidedTarget.CenterPosition : Args.passiveTarget; Combat.DoImpacts(pos, Args.sourceActor, Args.weapon, Args.firepowerModifier); doneDamage = true; } @@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA.Effects { if (!initialized) { - var pos = Args.guidedTarget.IsValid ? Args.guidedTarget.CenterPosition : Args.passiveTarget; + var pos = Args.guidedTarget.IsValidFor(Args.sourceActor) ? Args.guidedTarget.CenterPosition : Args.passiveTarget; zap = new TeslaZapRenderable(Args.source, 0, pos - Args.source, Info.Image, Info.BrightZaps, Info.DimZaps); } yield return zap; diff --git a/OpenRA.Mods.RA/Guard.cs b/OpenRA.Mods.RA/Guard.cs index 8550b0017c..94cf1cba70 100644 --- a/OpenRA.Mods.RA/Guard.cs +++ b/OpenRA.Mods.RA/Guard.cs @@ -31,7 +31,7 @@ namespace OpenRA.Mods.RA var range = WRange.FromCells(target.Actor.Info.Traits.Get().Range); self.QueueActivity(false, new AttackMove.AttackMoveActivity(self, - new Follow(target, range))); + new Follow(self, target, range))); } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 1b9217f3d0..5f5345e0b5 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -496,7 +496,7 @@ namespace OpenRA.Mods.RA.Move public bool CanTarget(Actor self, Target target, List othersAtTarget, TargetModifiers modifiers, ref string cursor) { - if (!target.IsValid) + if (!target.IsValidFor(self)) return false; var location = target.CenterPosition.ToCPos(); diff --git a/OpenRA.Mods.RA/Move/Move.cs b/OpenRA.Mods.RA/Move/Move.cs index c192c648ce..0c021faf20 100755 --- a/OpenRA.Mods.RA/Move/Move.cs +++ b/OpenRA.Mods.RA/Move/Move.cs @@ -73,7 +73,7 @@ namespace OpenRA.Mods.RA.Move { this.getPath = (self, mobile) => { - if (!target.IsValid) + if (!target.IsValidFor(self)) return NoPath; return self.World.WorldActor.Trait().FindUnitPathToRange( diff --git a/OpenRA.Mods.RA/Reservable.cs b/OpenRA.Mods.RA/Reservable.cs index 27d91d61a8..6527c3078a 100755 --- a/OpenRA.Mods.RA/Reservable.cs +++ b/OpenRA.Mods.RA/Reservable.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA if (reservedFor == null) return; /* nothing to do */ - if (!Target.FromActor( reservedFor ).IsValid) + if (!Target.FromActor(reservedFor).IsValidFor(self)) reservedFor = null; /* not likely to arrive now. */ } diff --git a/OpenRA.Mods.RA/TargetableUnit.cs b/OpenRA.Mods.RA/TargetableUnit.cs index 195e8226c7..34d3d3ab20 100755 --- a/OpenRA.Mods.RA/TargetableUnit.cs +++ b/OpenRA.Mods.RA/TargetableUnit.cs @@ -30,24 +30,15 @@ namespace OpenRA.Mods.RA public TargetableUnit(Actor self, TargetableUnitInfo info) { this.info = info; - ReceivedCloak(self); - } - - // Arbitrary units can receive cloak via a crate during gameplay - public void ReceivedCloak(Actor self) - { cloak = self.TraitOrDefault(); } - public virtual bool TargetableBy(Actor self, Actor byActor) + public virtual bool TargetableBy(Actor self, Actor viewer) { if (cloak == null || !cloak.Cloaked) return true; - if (self.Owner.IsAlliedWith(byActor.Owner)) - return true; - - return self.World.ActorsWithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); + return cloak.IsVisible(self, viewer.Owner); } public virtual string[] TargetTypes { get { return info.TargetTypes; } } diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index f110faa08f..38686db5c4 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -28,13 +28,18 @@ DrawLineToTarget: ActorLostNotification: AttackMove: - AcceptsCloakCrate: WithSmoke: DebugMuzzlePositions: Guard: Guardable: BodyOrientation: UpdatesPlayerStatistics: + Cloak: + RequiresCrate: true + InitialDelay: 15 + CloakDelay: 90 + CloakSound: trans1.aud + UncloakSound: trans1.aud ^Tank: AppearsOnRadar: @@ -66,7 +71,6 @@ DrawLineToTarget: ActorLostNotification: AttackMove: - AcceptsCloakCrate: WithSmoke: Explodes: Weapon: UnitExplodeSmall @@ -76,6 +80,12 @@ Guardable: BodyOrientation: UpdatesPlayerStatistics: + Cloak: + RequiresCrate: true + InitialDelay: 15 + CloakDelay: 90 + CloakSound: trans1.aud + UncloakSound: trans1.aud ^Helicopter: AppearsOnRadar: diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index f3a5eabfbb..5bfd668932 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -393,10 +393,6 @@ CRATE: SelectionShares: 5 CloakCrateAction: SelectionShares: 5 - InitialDelay: 15 - CloakDelay: 90 - CloakSound: trans1.aud - UncloakSound: trans1.aud Effect: cloak GiveMcvCrateAction: SelectionShares: 0 diff --git a/mods/cnc/rules/vehicles.yaml b/mods/cnc/rules/vehicles.yaml index b0c4050320..b9ee9338e5 100644 --- a/mods/cnc/rules/vehicles.yaml +++ b/mods/cnc/rules/vehicles.yaml @@ -33,7 +33,7 @@ MCV: LeavesHusk: HuskActor: MCV.Husk -GainsExperience: - -AcceptsCloakCrate: + -Cloak: Explodes: Weapon: UnitExplodeSmall EmptyWeapon: UnitExplodeSmall @@ -519,6 +519,7 @@ STNK: RevealsShroud: Range: 7 Cloak: + RequiresCrate: false InitialDelay: 90 CloakDelay: 90 CloakSound: trans1.aud diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 23c0048411..565c0a58c9 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -554,13 +554,6 @@ CRATE: SelectionShares: 0 NoBaseSelectionShares: 9001 Unit: mcvo - CloakCrateAction: - SelectionShares: 15 - InitialDelay: 15 - CloakDelay: 90 - CloakSound: STEALTH1.WAV - UncloakSound: STEALTH2.WAV - Effect: cloak RenderSimple: ProximityCaptor: Types:Crate