diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 4182ebf6a4..9b2cfa048c 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -66,7 +66,7 @@ namespace OpenRA.Traits public interface INotifyOwnerChanged { void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner); } public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); } - public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } + public interface IAcceptInfiltrator { void OnInfiltrate(Actor self, Actor infiltrator); } public interface IStoreOre { int Capacity { get; } } public interface IToolTip { diff --git a/OpenRA.Mods.RA/Activities/Infiltrate.cs b/OpenRA.Mods.RA/Activities/Infiltrate.cs index a6da250746..b5d82cd3cc 100644 --- a/OpenRA.Mods.RA/Activities/Infiltrate.cs +++ b/OpenRA.Mods.RA/Activities/Infiltrate.cs @@ -28,7 +28,7 @@ namespace OpenRA.Mods.RA.Activities if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) ) return NextActivity; - foreach (var t in target.TraitsImplementing()) + foreach (var t in target.TraitsImplementing()) t.OnInfiltrate(target, self); if (self.HasTrait()) diff --git a/OpenRA.Mods.RA/InfiltrateForCash.cs b/OpenRA.Mods.RA/InfiltrateForCash.cs index e59a4959b0..03fde1bc2c 100644 --- a/OpenRA.Mods.RA/InfiltrateForCash.cs +++ b/OpenRA.Mods.RA/InfiltrateForCash.cs @@ -25,16 +25,16 @@ namespace OpenRA.Mods.RA public object Create(ActorInitializer init) { return new InfiltrateForCash(this); } } - class InfiltrateForCash : IAcceptSpy + class InfiltrateForCash : IAcceptInfiltrator { InfiltrateForCashInfo info; public InfiltrateForCash(InfiltrateForCashInfo info) { this.info = info; } - public void OnInfiltrate(Actor self, Actor spy) + public void OnInfiltrate(Actor self, Actor infiltrator) { var targetResources = self.Owner.PlayerActor.Trait(); - var spyResources = spy.Owner.PlayerActor.Trait(); + var spyResources = infiltrator.Owner.PlayerActor.Trait(); var toTake = (targetResources.Cash + targetResources.Ore) * info.Percentage / 100; var toGive = Math.Max(toTake, info.Minimum); @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA Sound.PlayToPlayer(self.Owner, info.SoundToVictim); self.World.AddFrameEndTask(w => w.Add(new CashTick(toGive, 30, 2, self.CenterLocation, - spy.Owner.ColorRamp.GetColor(0)))); + infiltrator.Owner.ColorRamp.GetColor(0)))); } } } diff --git a/OpenRA.Mods.RA/InfiltrateForExploration.cs b/OpenRA.Mods.RA/InfiltrateForExploration.cs index 736d1a21aa..85fc6b93b7 100644 --- a/OpenRA.Mods.RA/InfiltrateForExploration.cs +++ b/OpenRA.Mods.RA/InfiltrateForExploration.cs @@ -16,11 +16,11 @@ namespace OpenRA.Mods.RA { class InfiltrateForExplorationInfo : TraitInfo {} - class InfiltrateForExploration : IAcceptSpy + class InfiltrateForExploration : IAcceptInfiltrator { - public void OnInfiltrate(Actor self, Actor spy) + public void OnInfiltrate(Actor self, Actor infiltrator) { - spy.Owner.Shroud.MergeShroud(self.Owner.Shroud); + infiltrator.Owner.Shroud.MergeShroud(self.Owner.Shroud); if (!self.Owner.HasFogVisibility()) self.Owner.Shroud.ResetExploration(); } diff --git a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs b/OpenRA.Mods.RA/InfiltrateForSupportPower.cs index 334fdb92cf..8b7fec37bc 100644 --- a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs +++ b/OpenRA.Mods.RA/InfiltrateForSupportPower.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA public object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); } } - class InfiltrateForSupportPower : IAcceptSpy + class InfiltrateForSupportPower : IAcceptInfiltrator { InfiltrateForSupportPowerInfo Info; @@ -29,11 +29,11 @@ namespace OpenRA.Mods.RA Info = info; } - public void OnInfiltrate(Actor self, Actor spy) + public void OnInfiltrate(Actor self, Actor infiltrator) { - spy.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary + infiltrator.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary { - new OwnerInit( spy.Owner ) + new OwnerInit(infiltrator.Owner) })); } } diff --git a/OpenRA.Mods.RA/Infiltrates.cs b/OpenRA.Mods.RA/Infiltrates.cs new file mode 100644 index 0000000000..abd59a6b75 --- /dev/null +++ b/OpenRA.Mods.RA/Infiltrates.cs @@ -0,0 +1,114 @@ +#region Copyright & License Information +/* + * Copyright 2007-2012 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; +using OpenRA.Mods.RA.Missions; + +namespace OpenRA.Mods.RA +{ + class InfiltratesInfo : ITraitInfo + { + public string[] InfiltrateTypes = {"Cash", "SupportPower", "Exploration"}; + public object Create(ActorInitializer init) { return new Infiltrates(this); } + } + + class Infiltrates : IIssueOrder, IResolveOrder, IOrderVoice + { + public readonly InfiltratesInfo Info; + + public Infiltrates(InfiltratesInfo info) + { + Info = info; + + } + + public IEnumerable Orders + { + get + { + yield return new InfiltratorOrderTargeter(target => CanInfiltrate(target)); + } + } + + public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + { + if (order.OrderID == "Infiltrate") + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Infiltrate" && CanInfiltrate(order.TargetActor)) ? "Attack" : null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Infiltrate") + { + if (!CanInfiltrate(order.TargetActor)) + return; + + self.SetTargetLine(Target.FromOrder(order), Color.Red); + + self.CancelActivity(); + self.QueueActivity(new Enter(order.TargetActor)); + self.QueueActivity(new Infiltrate(order.TargetActor)); + } + } + + bool CanInfiltrate(Actor target) + { + if (Info.InfiltrateTypes.Contains("Cash") && target.HasTrait()) + return true; + + if (Info.InfiltrateTypes.Contains("SupportPower") && target.HasTrait()) + return true; + + if (Info.InfiltrateTypes.Contains("Exploration") && target.HasTrait()) + return true; + + if (Info.InfiltrateTypes.Contains("MissionObjective") && target.HasTrait()) + return true; + + return false; + } + + class InfiltratorOrderTargeter : UnitTraitOrderTargeter + { + readonly Func useEnterCursor; + + public InfiltratorOrderTargeter(Func useEnterCursor) : base("Infiltrate", 7, "enter", true, false) + { + ForceAttack=false; + this.useEnterCursor = useEnterCursor; + } + + public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor) + { + if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor)) + return false; + + if (!useEnterCursor(target)) + cursor = "enter-blocked"; + + return true; + } + } + } +} diff --git a/OpenRA.Mods.RA/Missions/Allies04Script.cs b/OpenRA.Mods.RA/Missions/Allies04Script.cs index 39f4c92f0b..06d7253094 100644 --- a/OpenRA.Mods.RA/Missions/Allies04Script.cs +++ b/OpenRA.Mods.RA/Missions/Allies04Script.cs @@ -410,7 +410,7 @@ namespace OpenRA.Mods.RA.Missions }; lab = actors["Lab"]; - lab.AddTrait(new InfiltrateAction(OnLabInfiltrated)); + lab.AddTrait(new InfiltrateForMissionObjective(OnLabInfiltrated)); lab.AddTrait(new TransformedAction(self => lab = self)); reinforcementsEntryPoint = actors["ReinforcementsEntryPoint"]; @@ -456,13 +456,17 @@ namespace OpenRA.Mods.RA.Missions public object Create(ActorInitializer init) { return new Allies04Hijackable(init.self); } } - class Allies04Hijackable : IAcceptSpy, INotifyPassengerExited + class Allies04Hijackable : IAcceptInfiltrator, INotifyPassengerExited { public Player OldOwner; + void OnTruckHijacked(Actor spy) { } + public Allies04Hijackable(Actor self) { OldOwner = self.Owner; + + self.AddTrait(new InfiltrateForMissionObjective(OnTruckHijacked)); } public void OnInfiltrate(Actor self, Actor spy) diff --git a/OpenRA.Mods.RA/Missions/MissionUtils.cs b/OpenRA.Mods.RA/Missions/MissionUtils.cs index 885d2b810f..7b8e743a49 100644 --- a/OpenRA.Mods.RA/Missions/MissionUtils.cs +++ b/OpenRA.Mods.RA/Missions/MissionUtils.cs @@ -230,11 +230,11 @@ namespace OpenRA.Mods.RA.Missions } } - class InfiltrateAction : IAcceptSpy + class InfiltrateForMissionObjective : IAcceptInfiltrator { Action a; - public InfiltrateAction(Action a) + public InfiltrateForMissionObjective(Action a) { this.a = a; } diff --git a/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs b/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs index 7570160b19..1e7feb2864 100644 --- a/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs +++ b/OpenRA.Mods.RA/Missions/MonsterTankMadnessScript.cs @@ -329,7 +329,7 @@ namespace OpenRA.Mods.RA.Missions world.CreateActor("camera", greece, provingGroundsCameraPoint.Location, null); superTankDome = actors["SuperTankDome"]; - superTankDome.AddTrait(new InfiltrateAction(OnSuperTankDomeInfiltrated)); + superTankDome.AddTrait(new InfiltrateForMissionObjective(OnSuperTankDomeInfiltrated)); superTankDome.AddTrait(new TransformedAction(self => superTankDome = self)); Game.MoveViewport(startEntryPoint.Location.ToFloat2()); diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 353821fbd6..3742e613b8 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -409,6 +409,7 @@ + diff --git a/OpenRA.Mods.RA/Spy.cs b/OpenRA.Mods.RA/Spy.cs index 7d74fdee5c..29d05d483d 100644 --- a/OpenRA.Mods.RA/Spy.cs +++ b/OpenRA.Mods.RA/Spy.cs @@ -84,15 +84,12 @@ namespace OpenRA.Mods.RA { get { - yield return new UnitTraitOrderTargeter( "SpyInfiltrate", 7, "enter", true, false ) { ForceAttack=false }; - yield return new UnitTraitOrderTargeter( "Disguise", 7, "ability", true, true ) { ForceAttack=false }; + yield return new UnitTraitOrderTargeter("Disguise", 7, "ability", true, true) { ForceAttack=false }; } } public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) { - if( order.OrderID == "SpyInfiltrate" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; if( order.OrderID == "Disguise" ) return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; return null; @@ -100,14 +97,6 @@ namespace OpenRA.Mods.RA public void ResolveOrder(Actor self, Order order) { - if (order.OrderString == "SpyInfiltrate") - { - self.SetTargetLine(Target.FromOrder(order), Color.Red); - - self.CancelActivity(); - self.QueueActivity(new Enter(order.TargetActor)); - self.QueueActivity(new Infiltrate(order.TargetActor)); - } if (order.OrderString == "Disguise") { var target = order.TargetActor == self ? null : order.TargetActor; @@ -121,8 +110,7 @@ namespace OpenRA.Mods.RA public string VoicePhraseForOrder(Actor self, Order order) { - return (order.OrderString == "Disguise" - || order.OrderString == "SpyInfiltrate") ? "Attack" : null; + return (order.OrderString == "Disguise") ? "Attack" : null; } public Color RadarColorOverride(Actor self) diff --git a/mods/ra-classic/rules/infantry.yaml b/mods/ra-classic/rules/infantry.yaml index f49f01978e..1079d02e8b 100644 --- a/mods/ra-classic/rules/infantry.yaml +++ b/mods/ra-classic/rules/infantry.yaml @@ -190,13 +190,45 @@ SPY: PipType: Yellow TakeCover: Spy: + Infiltrates: + InfiltrateTypes: SupportPower, Exploration -AutoTarget: AttackMove: JustMove: true -RenderInfantry: RenderSpy: IdleAnimations: idle1,idle2 - + +THF: + Inherits: ^Infantry + Buildable: + Queue: Infantry + BuildPaletteOrder: 60 + Prerequisites: techcenter, tent + Owner: allies + Valued: + Cost: 400 + Tooltip: + Name: Thief + Description: Steals enemy credits.\n Strong vs Nothing\n Weak vs Everything\n + Selectable: + Voice: ThiefVoice + Bounds: 12,17,0,-9 + Health: + HP: 25 + Mobile: + Speed: 4 + RevealsShroud: + Range: 5 + Passenger: + PipType: Yellow + Infiltrates: + InfiltrateTypes: Cash + TakeCover: + -AutoTarget: + AttackMove: + JustMove: true + E7: Inherits: ^Infantry Buildable: diff --git a/mods/ra/maps/allies-04/map.yaml b/mods/ra/maps/allies-04/map.yaml index 6ad7e412a1..b3e95a6b03 100644 --- a/mods/ra/maps/allies-04/map.yaml +++ b/mods/ra/maps/allies-04/map.yaml @@ -301,27 +301,27 @@ Actors: Actor83: ftur Location: 67,34 Owner: Soviets - Actor73: spen.noinfiltrate + Actor73: spen Location: 31,82 Owner: Soviets - Actor37: dome.noinfiltrate + Actor37: dome Location: 44,57 Owner: Soviets Actor65: sam Location: 50,37 Owner: Soviets TurretFacing: 192 - Actor70: spen.noinfiltrate + Actor70: spen Location: 39,71 Owner: Soviets - Actor71: spen.noinfiltrate + Actor71: spen Location: 25,68 Owner: Soviets Actor64: sam Location: 28,43 Owner: Soviets TurretFacing: 48 - Actor72: spen.noinfiltrate + Actor72: spen Location: 23,76 Owner: Soviets Actor88: tsla @@ -465,13 +465,13 @@ Actors: Actor130: apwr Location: 101,16 Owner: Soviets - Actor134: proc.noinfiltrate + Actor134: proc Location: 106,30 Owner: Soviets Actor135: fix Location: 102,25 Owner: Soviets - Actor136: dome.noinfiltrate + Actor136: dome Location: 107,25 Owner: Soviets HijackFactory: weap @@ -1312,7 +1312,7 @@ Actors: Actor414: sbag Location: 74,60 Owner: Soviets - Actor412: proc.noinfiltrate + Actor412: proc Location: 84,68 Owner: Soviets Actor472: brl3 @@ -1809,44 +1809,6 @@ Rules: AutoTargetIgnore: Allies04TransformOnLabInfiltrate: ToActor: MISS - PROC.NoInfiltrate: - Inherits: PROC - -Buildable: - RenderBuilding: - Image: PROC - Tooltip: - Icon: procicon - -InfiltrateForCash: - Allies04TransformOnLabInfiltrate: - ToActor: PROC.NoFreeActor - PROC.NoFreeActor: - Inherits: PROC - -Buildable: - RenderBuilding: - Image: PROC - Tooltip: - Icon: procicon - -FreeActor: - DOME.NoInfiltrate: - Inherits: DOME - -Buildable: - RenderBuilding: - Image: DOME - Tooltip: - Icon: domeicon - -InfiltrateForExploration: - Allies04TransformOnLabInfiltrate: - ToActor: DOME - SPEN.NoInfiltrate: - Inherits: SPEN - -Buildable: - RenderBuilding: - Image: SPEN - Tooltip: - Icon: spenicon - -InfiltrateForSupportPower: - Allies04TransformOnLabInfiltrate: - ToActor: SPEN LST.Unselectable: Inherits: LST Buildable: @@ -1875,6 +1837,8 @@ Rules: RevealsShroud: Range: 6 Spy: + Infiltrates: + InfiltrateTypes: MissionObjective DOG.Patrol: Inherits: DOG Buildable: diff --git a/mods/ra/maps/monster-tank-madness/map.yaml b/mods/ra/maps/monster-tank-madness/map.yaml index e00da1a10d..c41b565b40 100644 --- a/mods/ra/maps/monster-tank-madness/map.yaml +++ b/mods/ra/maps/monster-tank-madness/map.yaml @@ -2535,11 +2535,14 @@ Rules: MonsterTankMadnessScript: FirstStartUnits: 1tnk, 1tnk, 2tnk, 2tnk SecondStartUnits: e1, e1, e1, e3, e3 - ThirdStartUnits: spy, e6, e6 + ThirdStartUnits: thf, e6, e6 FirstBaseUnits: 1tnk, 1tnk, 2tnk, arty, arty CivilianEvacuees: c1, c2, c5, c7, c8 MissionObjectivesPanel: ObjectivesPanel: MISSION_OBJECTIVES + SPY: + Infiltrates: + InfiltrateTypes: MissionObjective DEMITRI: Inherits: DELPHI Tooltip: diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index 84fdf0cb71..e2f4a1a756 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -196,6 +196,8 @@ SPY: PipType: Yellow TakeCover: Spy: + Infiltrates: + InfiltrateTypes: Cash, SupportPower, Exploration -AutoTarget: AttackMove: JustMove: true @@ -427,6 +429,8 @@ THF: Range: 5 Passenger: PipType: Yellow + Infiltrates: + InfiltrateTypes: Cash TakeCover: -AutoTarget: AttackMove: