diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 19a1a42820..6bf6769b07 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -709,6 +709,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/GrantUpgradePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/GrantUpgradePower.cs
index 368074de39..49b8ad1d21 100644
--- a/OpenRA.Mods.Common/Traits/SupportPowers/GrantUpgradePower.cs
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/GrantUpgradePower.cs
@@ -46,10 +46,10 @@ namespace OpenRA.Mods.Common.Traits
this.info = info;
}
- public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
+ public override void SelectTarget(Actor self, string order, SupportPowerManager manager)
{
Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound);
- return new SelectTarget(Self.World, order, manager, this);
+ self.World.OrderGenerator = new SelectUpgradeTarget(Self.World, order, manager, this);
}
public override void Activate(Actor self, Order order, SupportPowerManager manager)
@@ -101,7 +101,7 @@ namespace OpenRA.Mods.Common.Traits
});
}
- class SelectTarget : IOrderGenerator
+ class SelectUpgradeTarget : IOrderGenerator
{
readonly GrantUpgradePower power;
readonly int range;
@@ -109,7 +109,7 @@ namespace OpenRA.Mods.Common.Traits
readonly SupportPowerManager manager;
readonly string order;
- public SelectTarget(World world, string order, SupportPowerManager manager, GrantUpgradePower power)
+ public SelectUpgradeTarget(World world, string order, SupportPowerManager manager, GrantUpgradePower power)
{
// Clear selection if using Left-Click Orders
if (Game.Settings.Game.UseClassicMouseStyle)
diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs
new file mode 100644
index 0000000000..bbe7737ea9
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/ProduceActorPower.cs
@@ -0,0 +1,75 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2015 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.Linq;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ [Desc("Produces an actor without using the standard production queue.")]
+ public class ProduceActorPowerInfo : SupportPowerInfo
+ {
+ [ActorReference, FieldLoader.Require]
+ [Desc("Actors to produce.")]
+ public readonly string[] Actors = null;
+
+ [FieldLoader.Require]
+ [Desc("Production queue type to use")]
+ public readonly string Type = null;
+
+ [Desc("Notification played when production is activated.",
+ "The filename of the audio is defined per faction in notifications.yaml.")]
+ public readonly string ReadyAudio = null;
+
+ [Desc("Notification played when the exit is jammed.",
+ "The filename of the audio is defined per faction in notifications.yaml.")]
+ public readonly string BlockedAudio = null;
+
+ public override object Create(ActorInitializer init) { return new ProduceActorPower(init, this); }
+ }
+
+ public class ProduceActorPower : SupportPower
+ {
+ readonly string faction;
+
+ public ProduceActorPower(ActorInitializer init, ProduceActorPowerInfo info)
+ : base(init.Self, info)
+ {
+ faction = init.Contains() ? init.Get() : init.Self.Owner.Faction.InternalName;
+ }
+
+ public override void SelectTarget(Actor self, string order, SupportPowerManager manager)
+ {
+ self.World.IssueOrder(new Order(order, manager.Self, false));
+ }
+
+ public override void Activate(Actor self, Order order, SupportPowerManager manager)
+ {
+ base.Activate(self, order, manager);
+
+ var info = Info as ProduceActorPowerInfo;
+ var sp = self.TraitsImplementing()
+ .FirstOrDefault(p => p.Info.Produces.Contains(info.Type));
+
+ // TODO: The power should not reset if the production fails.
+ // Fixing this will require a larger rework of the support power code
+ var activated = false;
+
+ if (sp != null)
+ foreach (var name in info.Actors)
+ activated |= sp.Produce(self, self.World.Map.Rules.Actors[name], faction);
+
+ if (activated)
+ Game.Sound.PlayNotification(self.World.Map.Rules, manager.Self.Owner, "Speech", info.ReadyAudio, self.Owner.Faction.InternalName);
+ else
+ Game.Sound.PlayNotification(self.World.Map.Rules, manager.Self.Owner, "Speech", info.BlockedAudio, self.Owner.Faction.InternalName);
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs
index d05c1959d8..2fa461bb18 100644
--- a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs
@@ -81,6 +81,12 @@ namespace OpenRA.Mods.Common.Traits
Game.Sound.PlayToPlayer(self.Owner, Info.EndChargeSound);
}
+ public virtual void SelectTarget(Actor self, string order, SupportPowerManager manager)
+ {
+ Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound);
+ self.World.OrderGenerator = new SelectGenericPowerTarget(order, manager, info.Cursor, MouseButton.Left);
+ }
+
public virtual void Activate(Actor self, Order order, SupportPowerManager manager)
{
if (Info.DisplayRadarPing && manager.RadarPings != null)
@@ -92,11 +98,5 @@ namespace OpenRA.Mods.Common.Traits
Info.RadarPingDuration);
}
}
-
- public virtual IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
- {
- Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound);
- return new SelectGenericPowerTarget(order, manager, info.Cursor, MouseButton.Left);
- }
}
}
diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
index 908ae81489..eeb32378f8 100644
--- a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
@@ -222,7 +222,11 @@ namespace OpenRA.Mods.Common.Traits
if (!Ready)
return;
- manager.Self.World.OrderGenerator = Instances.First().OrderGenerator(key, manager);
+ var power = Instances.FirstOrDefault();
+ if (power == null)
+ return;
+
+ power.SelectTarget(power.Self, key, manager);
}
public void Activate(Order order)
diff --git a/OpenRA.Mods.RA/Traits/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.RA/Traits/SupportPowers/ChronoshiftPower.cs
index a9ebfd1328..de66933d82 100644
--- a/OpenRA.Mods.RA/Traits/SupportPowers/ChronoshiftPower.cs
+++ b/OpenRA.Mods.RA/Traits/SupportPowers/ChronoshiftPower.cs
@@ -35,10 +35,10 @@ namespace OpenRA.Mods.RA.Traits
{
public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) : base(self, info) { }
- public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
+ public override void SelectTarget(Actor self, string order, SupportPowerManager manager)
{
Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound);
- return new SelectTarget(Self.World, order, manager, this);
+ self.World.OrderGenerator = new SelectChronoshiftTarget(Self.World, order, manager, this);
}
public override void Activate(Actor self, Order order, SupportPowerManager manager)
@@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA.Traits
return true;
}
- class SelectTarget : IOrderGenerator
+ class SelectChronoshiftTarget : IOrderGenerator
{
readonly ChronoshiftPower power;
readonly int range;
@@ -102,7 +102,7 @@ namespace OpenRA.Mods.RA.Traits
readonly SupportPowerManager manager;
readonly string order;
- public SelectTarget(World world, string order, SupportPowerManager manager, ChronoshiftPower power)
+ public SelectChronoshiftTarget(World world, string order, SupportPowerManager manager, ChronoshiftPower power)
{
// Clear selection if using Left-Click Orders
if (Game.Settings.Game.UseClassicMouseStyle)
diff --git a/mods/d2k/rules/infantry.yaml b/mods/d2k/rules/infantry.yaml
index 3f8812bc8f..a8fa0c52b1 100644
--- a/mods/d2k/rules/infantry.yaml
+++ b/mods/d2k/rules/infantry.yaml
@@ -113,7 +113,7 @@ fremen:
Buildable:
Queue: Infantry
BuildPaletteOrder: 100
- Prerequisites: ~barracks.atreides, palace, ~techlevel.high
+ Prerequisites: ~disabled
Mobile:
Speed: 43
Health:
@@ -207,7 +207,7 @@ saboteur:
Buildable:
Queue: Infantry
BuildPaletteOrder: 100
- Prerequisites: ~barracks.ordos, palace, ~techlevel.high
+ Prerequisites: ~disabled
Valued:
Cost: 800
Tooltip:
diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml
index 34a3020956..5fc064a4be 100644
--- a/mods/d2k/rules/structures.yaml
+++ b/mods/d2k/rules/structures.yaml
@@ -782,6 +782,12 @@ palace:
ProvidesPrerequisite@nuke:
Prerequisite: palace.nuke
Factions: harkonnen
+ ProvidesPrerequisite@fremen:
+ Prerequisite: palace.fremen
+ Factions: atreides
+ ProvidesPrerequisite@saboteur:
+ Prerequisite: palace.saboteur
+ Factions: ordos
NukePower:
Cursor: nuke
Icon: deathhand
@@ -800,6 +806,39 @@ palace:
DisplayRadarPing: True
CameraActor: camera
ActivationSequence:
+ ProduceActorPower@fremen:
+ Description: Recruit Fremen
+ LongDesc: Elite sniper infantry unit \n Strong vs Infantry\n Weak vs Vehicles\n Special Ability: Invisibility
+ Icon: fremen
+ Prerequisites: ~techlevel.superweapons, ~palace.fremen
+ Actors: fremen, fremen
+ Type: Palace
+ ChargeTime: 60
+ ReadyAudio: Reinforce
+ BlockedAudio: NoRoom
+ OrderName: ProduceActorPower.Fremen
+ ProduceActorPower@saboteur:
+ Description: Recruit Saboteur
+ LongDesc: Sneaky infantry, armed with explosives \n Strong vs Buildings\n Weak vs Everything\n Special Ability: destroy buildings
+ Icon: saboteur
+ Prerequisites: ~techlevel.superweapons, ~palace.saboteur
+ Actors: saboteur
+ Type: Palace
+ ChargeTime: 40
+ ReadyAudio: Reinforce
+ BlockedAudio: NoRoom
+ OrderName: ProduceActorPower.Saboteur
+ Exit@1:
+ SpawnOffset: -704,768,0
+ ExitCell: -1,2
+ Exit@2:
+ SpawnOffset: -704,768,0
+ ExitCell: -1,3
+ Exit@3:
+ SpawnOffset: -704,768,0
+ ExitCell: 0,3
+ Production:
+ Produces: Palace
CanPowerDown:
DisabledOverlay:
RequiresPower:
diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml
index bb02238c20..8bbdd66857 100644
--- a/mods/d2k/sequences/misc.yaml
+++ b/mods/d2k/sequences/misc.yaml
@@ -324,6 +324,12 @@ icon:
ornistrike: DATA.R8
Start: 4031
Offset: -30,-24
+ fremen: DATA.R8
+ Start: 4032
+ Offset: -30,-24
+ saboteur: DATA.R8
+ Start: 4034
+ Offset: -30,-24
deathhand: DATA.R8
Start: 4035
Offset: -30,-24
diff --git a/mods/ts/rules/aircraft.yaml b/mods/ts/rules/aircraft.yaml
index d32dd5380c..bfe1196264 100644
--- a/mods/ts/rules/aircraft.yaml
+++ b/mods/ts/rules/aircraft.yaml
@@ -287,3 +287,44 @@ APACHE:
RenderSprites:
Hovers:
+HUNTER:
+ Inherits@1: ^GainsExperience
+ Inherits@2: ^ExistsInWorld
+ Valued:
+ Cost: 1000
+ Tooltip:
+ Name: Hunter-Seeker Droid
+ Health:
+ HP: 500
+ Armor:
+ Type: Light
+ DemoTruck:
+ Explodes:
+ Weapon: SuicideBomb
+ EmptyWeapon: SuicideBomb
+ Aircraft:
+ RearmBuildings:
+ RepairBuildings:
+ ROT: 16
+ Speed: 355
+ CruiseAltitude: 256
+ CanHover: True
+ Targetable:
+ TargetTypes: Ground, Vehicle
+ HiddenUnderFog:
+ Type: CenterPosition
+ BodyOrientation:
+ UseClassicPerspectiveFudge: False
+ RenderSprites:
+ Image: GGHUNT
+ WithFacingSpriteBody:
+ Hovers:
+ QuantizeFacingsFromSequence:
+ AutoSelectionSize:
+ DrawLineToTarget:
+ AppearsOnRadar:
+ UseLocation: yes
+ Selectable:
+ SelectionDecorations:
+ Palette: pips
+ ActorLostNotification:
diff --git a/mods/ts/rules/gdi-structures.yaml b/mods/ts/rules/gdi-structures.yaml
index 879a3964c5..c559a543e3 100644
--- a/mods/ts/rules/gdi-structures.yaml
+++ b/mods/ts/rules/gdi-structures.yaml
@@ -375,6 +375,18 @@ GAPLUG:
InsufficientPowerSound:
DisplayRadarPing: True
CameraActor: camera
+ ProduceActorPower:
+ UpgradeTypes: plug.hunterseeker
+ UpgradeMinEnabledLevel: 1
+ Description: Hunter Seeker
+ LongDesc: Releases a drone that will acquire and destroy an enemy target.
+ Icon: hunterseeker
+ Actors: hunter
+ Type: HunterSeeker
+ ChargeTime: 720
+ Production:
+ Produces: HunterSeeker
+ Exit@1:
SupportPowerChargeBar:
Power:
Amount: -150
@@ -382,22 +394,36 @@ GAPLUG:
UpgradeTypes: plug.ioncannon
UpgradeMinEnabledLevel: 1
Amount: -100
+ Power@hunterseeker:
+ UpgradeTypes: plug.hunterseeker
+ UpgradeMinEnabledLevel: 1
+ Amount: -50
Pluggable@pluga:
Offset: 0,2
Upgrades:
plug.ioncannon: plug.ioncannon, plug.ioncannona
+ plug.hunterseeker: plug.hunterseeker, plug.hunterseekera
WithIdleOverlay@ioncannona:
UpgradeTypes: plug.ioncannona
UpgradeMinEnabledLevel: 1
Sequence: idle-ioncannona
+ WithIdleOverlay@hunterseekera:
+ UpgradeTypes: plug.hunterseekera
+ UpgradeMinEnabledLevel: 1
+ Sequence: idle-hunterseekera
Pluggable@plugb:
Offset: 1,2
Upgrades:
plug.ioncannon: plug.ioncannon, plug.ioncannonb
+ plug.hunterseeker: plug.hunterseeker, plug.hunterseekerb
WithIdleOverlay@ioncannonb:
UpgradeTypes: plug.ioncannonb
UpgradeMinEnabledLevel: 1
Sequence: idle-ioncannonb
+ WithIdleOverlay@hunterseekerb:
+ UpgradeTypes: plug.hunterseekerb
+ UpgradeMinEnabledLevel: 1
+ Sequence: idle-hunterseekerb
ProvidesPrerequisite@buildingname:
SelectionDecorations:
VisualBounds: 115,104,0,-24
diff --git a/mods/ts/rules/gdi-support.yaml b/mods/ts/rules/gdi-support.yaml
index 5d1f9b1fe0..9bebf43ebc 100644
--- a/mods/ts/rules/gdi-support.yaml
+++ b/mods/ts/rules/gdi-support.yaml
@@ -189,6 +189,22 @@ GAPOWRUP:
Power:
Amount: 50
+GAPLUG2:
+ Inherits: ^BuildingPlug
+ Valued:
+ Cost: 1000
+ Tooltip:
+ Name: Seeker Control
+ Description: Enables use of the hunter-seeker droid.
+ Buildable:
+ Queue: Defense
+ BuildPaletteOrder: 1000
+ Prerequisites: gaplug, gatech, gaweap, ~structures.gdi
+ Plug:
+ Type: plug.hunterseeker
+ Power:
+ Amount: -50
+
GAPLUG3:
Inherits: ^BuildingPlug
Valued:
diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml
index 7437004358..5d23c5cdba 100644
--- a/mods/ts/rules/nod-structures.yaml
+++ b/mods/ts/rules/nod-structures.yaml
@@ -311,6 +311,16 @@ NATMPL:
Amount: -200
WithIdleOverlay@LIGHTS:
Sequence: idle-lights
+ ProduceActorPower:
+ Description: Hunter Seeker
+ LongDesc: Releases a drone that will acquire and destroy an enemy target.
+ Icon: hunterseeker
+ Actors: hunter
+ Type: HunterSeeker
+ ChargeTime: 720
+ Production:
+ Produces: HunterSeeker
+ Exit@1:
NASTLH:
Inherits: ^Building
diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml
index 01256b59f0..5b9d61178a 100644
--- a/mods/ts/rules/shared-vehicles.yaml
+++ b/mods/ts/rules/shared-vehicles.yaml
@@ -148,27 +148,3 @@ LPST:
UpgradeMinEnabledLevel: 1
Range: 18
RenderDetectionCircle:
-
-GGHUNT:
- Inherits: ^Vehicle
- Valued:
- Cost: 1000
- Tooltip:
- Name: Hunter-Seeker Droid
- Mobile:
- ROT: 16
- Speed: 355
- Health:
- HP: 500
- Armor:
- Type: Light
- RevealsShroud:
- Range: 7c0
- WithFacingSpriteBody:
- DemoTruck:
- Voice: Attack
- Explodes:
- Weapon: SuicideBomb
- EmptyWeapon: SuicideBomb
- AutoSelectionSize:
-
diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml
index 503d966cbe..b9877ce5c7 100644
--- a/mods/ts/sequences/misc.yaml
+++ b/mods/ts/sequences/misc.yaml
@@ -334,6 +334,7 @@ largecraters:
icon:
clustermissile: mltiicon
ioncannon: ioncicon
+ hunterseeker: detnicon
clustermissile:
up: null # TODO
diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml
index 7f9e449028..4f6af930dd 100644
--- a/mods/ts/sequences/structures.yaml
+++ b/mods/ts/sequences/structures.yaml
@@ -1234,6 +1234,15 @@ gaplug:
Length: 15
Reverses: true
Tick: 120
+ idle-hunterseekera: gaplug_e
+ Length: 15
+ Tick: 120
+ Reverses: true
+ Offset: -12, -42
+ idle-hunterseekerb: gaplug_e
+ Length: 15
+ Reverses: true
+ Tick: 120
make: gtplugmk
Length: 17
ShadowStart: 17
@@ -1241,5 +1250,8 @@ gaplug:
Offset: 0, 0
UseTilesetCode: false
+gaplug2:
+ icon: rad2icon
+
gaplug3:
icon: rad3icon
\ No newline at end of file