diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index e4494b326d..ac5b98c520 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -166,6 +166,7 @@ + @@ -244,6 +245,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/CaptureBuilding.cs b/OpenRa.Game/Traits/Activities/CaptureBuilding.cs index ca304c8505..f6778c439b 100644 --- a/OpenRa.Game/Traits/Activities/CaptureBuilding.cs +++ b/OpenRa.Game/Traits/Activities/CaptureBuilding.cs @@ -35,7 +35,6 @@ namespace OpenRa.Game.Traits.Activities } // the engineer is sacrificed. - self.Health = 0; Game.world.AddFrameEndTask(w => w.Remove(self)); return NextActivity; diff --git a/OpenRa.Game/Traits/Activities/Infiltrate.cs b/OpenRa.Game/Traits/Activities/Infiltrate.cs new file mode 100644 index 0000000000..c32f3c32d0 --- /dev/null +++ b/OpenRa.Game/Traits/Activities/Infiltrate.cs @@ -0,0 +1,25 @@ + +namespace OpenRa.Game.Traits.Activities +{ + class Infiltrate : IActivity + { + Actor target; + public Infiltrate(Actor target) { this.target = target; } + public IActivity NextActivity { get; set; } + + public IActivity Tick(Actor self) + { + if (target == null || target.IsDead) return NextActivity; + if (target.Owner == self.Owner) return NextActivity; + + foreach (var t in target.traits.WithInterface()) + t.OnInfiltrate(target, self); + + Game.world.AddFrameEndTask(w => w.Remove(self)); + + return NextActivity; + } + + public void Cancel(Actor self) { target = null; NextActivity = null; } + } +} diff --git a/OpenRa.Game/Traits/Activities/Steal.cs b/OpenRa.Game/Traits/Activities/Steal.cs index b0605691c0..3fbf7751d6 100644 --- a/OpenRa.Game/Traits/Activities/Steal.cs +++ b/OpenRa.Game/Traits/Activities/Steal.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - + namespace OpenRa.Game.Traits.Activities { class Steal : IActivity @@ -20,6 +16,8 @@ namespace OpenRa.Game.Traits.Activities foreach (var t in target.traits.WithInterface()) t.OnSteal(target, self); + + Game.world.AddFrameEndTask(w => w.Remove(self)); return NextActivity; } diff --git a/OpenRa.Game/Traits/Spy.cs b/OpenRa.Game/Traits/Spy.cs new file mode 100644 index 0000000000..7948a6a2f7 --- /dev/null +++ b/OpenRa.Game/Traits/Spy.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Traits.Activities; + +namespace OpenRa.Game.Traits +{ + class SpyInfo : StatelessTraitInfo { } + + class Spy : IIssueOrder, IResolveOrder + { + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + if (mi.Button != MouseButton.Right) return null; + if (underCursor != null) return null; + if (underCursor.traits.WithInterface().Any()) return null; + + return new Order("Infiltrate", self, underCursor, int2.Zero, null); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Infiltrate") + { + self.CancelActivity(); + self.QueueActivity(new Move(order.TargetActor, 1)); + self.QueueActivity(new Infiltrate(order.TargetActor)); + } + } + } +} diff --git a/OpenRa.Game/Traits/StoresOre.cs b/OpenRa.Game/Traits/StoresOre.cs index f3591580c3..f85edaa63c 100644 --- a/OpenRa.Game/Traits/StoresOre.cs +++ b/OpenRa.Game/Traits/StoresOre.cs @@ -20,10 +20,6 @@ namespace OpenRa.Game.Traits if (Game.LocalPlayer == thief.Owner) Sound.Play("credit1.aud"); - - // the thief is sacrificed. - thief.Health = 0; - Game.world.AddFrameEndTask(w => w.Remove(thief)); } public IEnumerable GetPips(Actor self) @@ -33,7 +29,6 @@ namespace OpenRa.Game.Traits return Graphics.Util.MakeArray( numPips, i => (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / numPips) ? PipType.Yellow : PipType.Transparent ); - } } } diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 6a1e6aa0a6..26170266d1 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Drawing; +using IjwFramework.Types; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; -using IjwFramework.Types; namespace OpenRa.Game.Traits { @@ -21,7 +21,9 @@ namespace OpenRa.Game.Traits interface INotifyDamage { void Damaged(Actor self, AttackInfo e); } interface INotifyBuildComplete { void BuildingComplete (Actor self); } interface INotifyProduction { void UnitProduced(Actor self, Actor other); } + interface IAcceptThief { void OnSteal(Actor self, Actor thief); } + interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } interface IProducer { diff --git a/ra.yaml b/ra.yaml index cbb726bc60..4b8fafd2b0 100644 --- a/ra.yaml +++ b/ra.yaml @@ -2130,6 +2130,7 @@ SPY: Sight: 5 Speed: 4 TakeCover: + Spy: -AutoTarget: THF: diff --git a/units.ini b/units.ini index 5ababd4b2b..ca8f915bcf 100644 --- a/units.ini +++ b/units.ini @@ -586,7 +586,7 @@ SelectionSize=12,17,0,-9 [SPY] Description=Spy Voice=SpyVoice -Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank, Passenger +Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank, Passenger, Spy LongDesc=Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised SelectionSize=12,17,0,-9 [THF]