From 86eabeea3f804a3acef3e3df56e564292843c677 Mon Sep 17 00:00:00 2001 From: teees Date: Wed, 20 Apr 2016 08:10:54 +0200 Subject: [PATCH 1/6] Add AttackOrderPower as Supportpower --- .../SupportPowers/SupportPowerManager.cs | 3 +- OpenRA.Mods.TS/OpenRA.Mods.TS.csproj | 1 + .../Traits/SupportPowers/AttackOrderPower.cs | 148 ++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs index 1926c2d204..e6ea859e95 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs @@ -235,7 +235,8 @@ namespace OpenRA.Mods.Common.Traits if (!Ready) return; - var power = Instances.FirstOrDefault(i => !InstanceDisabled(i)); + var power = Instances.Where(i => !InstanceDisabled(i)) + .MinByOrDefault(a => (a.Self.CenterPosition - a.Self.World.Map.CenterOfCell(order.TargetLocation)).HorizontalLengthSquared); if (power == null) return; diff --git a/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj b/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj index 14bab04b9a..1dfe59b25f 100644 --- a/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj +++ b/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj @@ -74,6 +74,7 @@ + diff --git a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs new file mode 100644 index 0000000000..1f8e2e0c0f --- /dev/null +++ b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs @@ -0,0 +1,148 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.TS.Traits +{ + class AttackOrderPowerInfo : SupportPowerInfo + { + public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } + } + + class AttackOrderPower : SupportPower, INotifyAddedToWorld, INotifyAttack + { + readonly AttackOrderPowerInfo info; + AttackBase attack; + + public AttackOrderPower(Actor self, AttackOrderPowerInfo info) + : base(self, info) + { + this.info = info; + } + + public override void SelectTarget(Actor self, string order, SupportPowerManager manager) + { + Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound); + self.World.OrderGenerator = new SelectAttackPowerTarget(self, order, manager, info.Cursor, MouseButton.Left, attack); + } + + public override void Activate(Actor self, Order order, SupportPowerManager manager) + { + base.Activate(self, order, manager); + attack.AttackTarget(Target.FromCell(self.World, order.TargetLocation), false, false, true); + } + + void INotifyAddedToWorld.AddedToWorld(Actor self) + { + attack = self.Trait(); + } + + void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + { + self.World.IssueOrder(new Order("Stop", self, false)); + } + } + + public class SelectAttackPowerTarget : IOrderGenerator + { + readonly SupportPowerManager manager; + readonly SupportPowerInstance instance; + readonly string order; + readonly string cursor; + readonly string cursorBlocked; + readonly MouseButton expectedButton; + readonly AttackBase attack; + + public SelectAttackPowerTarget(Actor self, string order, SupportPowerManager manager, string cursor, MouseButton button, AttackBase attack) + { + // Clear selection if using Left-Click Orders + if (Game.Settings.Game.UseClassicMouseStyle) + manager.Self.World.Selection.Clear(); + + instance = manager.GetPowersForActor(self).FirstOrDefault(); + this.manager = manager; + this.order = order; + this.cursor = cursor; + expectedButton = button; + this.attack = attack; + cursorBlocked = cursor + "-blocked"; + } + + Actor GetFiringActor(World world, CPos cell) + { + var pos = world.Map.CenterOfCell(cell); + var range = attack.GetMaximumRange().LengthSquared; + + return instance.Instances.Where(i => !i.Self.IsDisabled()).MinByOrDefault(a => (a.Self.CenterPosition - pos).HorizontalLengthSquared).Self; + } + + bool IsValidTarget(World world, CPos cell) + { + var pos = world.Map.CenterOfCell(cell); + var range = attack.GetMaximumRange().LengthSquared; + + return world.Map.Contains(cell) && instance.Instances.Any(a => !a.Self.IsDisabled() && (a.Self.CenterPosition - pos).HorizontalLengthSquared < range); + } + + IEnumerable IOrderGenerator.Order(World world, CPos cell, int2 worldPixel, MouseInput mi) + { + world.CancelInputMode(); + if (mi.Button == expectedButton && IsValidTarget(world, cell)) + yield return new Order(order, manager.Self, false) + { + TargetActor = GetFiringActor(world, cell), + TargetLocation = cell, + SuppressVisualFeedback = true + }; + } + + void IOrderGenerator.Tick(World world) + { + // Cancel the OG if we can't use the power + if (!manager.Powers.ContainsKey(order)) + world.CancelInputMode(); + } + + IEnumerable IOrderGenerator.Render(WorldRenderer wr, World world) { yield break; } + + IEnumerable IOrderGenerator.RenderAfterWorld(WorldRenderer wr, World world) + { + foreach (var a in instance.Instances.Where(i => !i.Self.IsDisabled())) + { + yield return new RangeCircleRenderable( + a.Self.CenterPosition, + attack.GetMinimumRange(), + 0, + Color.Red, + Color.FromArgb(96, Color.Black)); + + yield return new RangeCircleRenderable( + a.Self.CenterPosition, + attack.GetMaximumRange(), + 0, + Color.Red, + Color.FromArgb(96, Color.Black)); + } + } + + string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) + { + return IsValidTarget(world, cell) ? cursor : cursorBlocked; + } + } +} From ea4f33123eadb33fb486fcbd6020c9c30c0c860b Mon Sep 17 00:00:00 2001 From: teees Date: Wed, 20 Apr 2016 08:11:18 +0200 Subject: [PATCH 2/6] Use AttackOrderPower for EMP support power --- mods/ts/cursors.yaml | 6 ++++++ mods/ts/rules/shared-support.yaml | 15 +++++++++++++-- mods/ts/sequences/misc.yaml | 1 + mods/ts/weapons/superweapons.yaml | 4 ++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mods/ts/cursors.yaml b/mods/ts/cursors.yaml index 31c884bf40..3bd577ab17 100644 --- a/mods/ts/cursors.yaml +++ b/mods/ts/cursors.yaml @@ -152,6 +152,12 @@ Cursors: nuke: Start: 319 Length: 9 + emp: + Start: 357 + Length: 19 + emp-blocked: + Start: 377 + Length: 1 sell: Start: 129 Length: 10 diff --git a/mods/ts/rules/shared-support.yaml b/mods/ts/rules/shared-support.yaml index a11b01cb61..fc7aaea63f 100644 --- a/mods/ts/rules/shared-support.yaml +++ b/mods/ts/rules/shared-support.yaml @@ -3,8 +3,8 @@ NAPULS: Valued: Cost: 1000 Tooltip: - Name: EMP Cannon - Description: Disables vehicles.\nRequires power to operate.\n Strong vs Vehicles\n Weak vs Infantry, Aircraft + Name: E.M. Pulse Cannon + Description: Disables mechanical units in an area.\nRequires power to operate. Buildable: Queue: Defense BuildPaletteOrder: 90 @@ -22,12 +22,15 @@ NAPULS: Type: Heavy RevealsShroud: Range: 8c0 + -AutoTarget: Turreted: TurnSpeed: 10 InitialFacing: 224 AttackTurreted: Armament: Weapon: EMPulseCannon + LocalOffset: 150,0,1250 + LocalYaw: 0,100 WithSpriteTurret: Sequence: turret Power: @@ -39,3 +42,11 @@ NAPULS: FactionImages: gdi: napuls.gdi nod: napuls.nod + AttackOrderPower: + Cursor: emp + Icon: emp + ChargeTime: 135 + Description: E.M. Pulse + LongDesc: Fires a pulse blast which disables\nall mechanical units in the area. + EndChargeSound: 00-i158.aud + SelectTargetSound: 00-i042.aud diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml index 9323b27762..324d14058c 100644 --- a/mods/ts/sequences/misc.yaml +++ b/mods/ts/sequences/misc.yaml @@ -368,6 +368,7 @@ icon: clustermissile: mltiicon ioncannon: ioncicon hunterseeker: detnicon + emp: pulsicon clustermissile: up: null # TODO diff --git a/mods/ts/weapons/superweapons.yaml b/mods/ts/weapons/superweapons.yaml index cd12202d69..cbbbb7edb0 100644 --- a/mods/ts/weapons/superweapons.yaml +++ b/mods/ts/weapons/superweapons.yaml @@ -79,7 +79,7 @@ IonCannon: EMPulseCannon: ReloadDelay: 100 - Range: 10c0 + Range: 40c0 Report: plsecan2.aud Projectile: Bullet Speed: 425 @@ -90,7 +90,7 @@ EMPulseCannon: Warhead@1Eff: CreateEffect Explosions: pulse_explosion Warhead@emp: GrantUpgrade - Range: 3c0 + Range: 4c0 Duration: 250 Upgrades: empdisable, notmobile From de14264ead2c85c888a89a98a10cc4e2807364ef Mon Sep 17 00:00:00 2001 From: abcdefg30 Date: Sun, 12 Jun 2016 13:16:43 +0200 Subject: [PATCH 3/6] Use the new INotifyBurstComplete interface instead of INotifyAttack --- OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs index 1f8e2e0c0f..8e889a8eaa 100644 --- a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs +++ b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs @@ -24,7 +24,7 @@ namespace OpenRA.Mods.TS.Traits public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } } - class AttackOrderPower : SupportPower, INotifyAddedToWorld, INotifyAttack + class AttackOrderPower : SupportPower, INotifyAddedToWorld, INotifyBurstComplete { readonly AttackOrderPowerInfo info; AttackBase attack; @@ -52,7 +52,7 @@ namespace OpenRA.Mods.TS.Traits attack = self.Trait(); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + void INotifyBurstComplete.FiredBurst(Actor self, Target target, Armament a) { self.World.IssueOrder(new Order("Stop", self, false)); } From c2c07d2451c9c157fa3d46f83b34f8ccffa01744 Mon Sep 17 00:00:00 2001 From: abcdefg30 Date: Sun, 12 Jun 2016 13:36:28 +0200 Subject: [PATCH 4/6] Add Requires to AttackOrderPowerInfo --- OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs index 8e889a8eaa..da41545cf7 100644 --- a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs +++ b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs @@ -19,7 +19,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.TS.Traits { - class AttackOrderPowerInfo : SupportPowerInfo + class AttackOrderPowerInfo : SupportPowerInfo, Requires { public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } } From 1ea06075486aa8b7cb7624f0e87744a0c3ba5cbb Mon Sep 17 00:00:00 2001 From: abcdefg30 Date: Sun, 12 Jun 2016 14:24:59 +0200 Subject: [PATCH 5/6] Support faction specific speech sounds --- mods/ts/rules/shared-support.yaml | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/mods/ts/rules/shared-support.yaml b/mods/ts/rules/shared-support.yaml index fc7aaea63f..a15036d5aa 100644 --- a/mods/ts/rules/shared-support.yaml +++ b/mods/ts/rules/shared-support.yaml @@ -42,11 +42,31 @@ NAPULS: FactionImages: gdi: napuls.gdi nod: napuls.nod - AttackOrderPower: + ProvidesPrerequisite@gdi: + Prerequisite: emp.gdi + Factions: gdi + ResetOnOwnerChange: true + ProvidesPrerequisite@nod: + Prerequisite: emp.nod + Factions: nod + ResetOnOwnerChange: true + AttackOrderPower@nod: Cursor: emp Icon: emp ChargeTime: 135 Description: E.M. Pulse LongDesc: Fires a pulse blast which disables\nall mechanical units in the area. - EndChargeSound: 00-i158.aud - SelectTargetSound: 00-i042.aud + EndChargeSound: speech-nod|00-i158.aud + SelectTargetSound: speech-nod|00-i042.aud + Prerequisites: emp.nod + OrderName: Nodemp + AttackOrderPower@gdi: + Cursor: emp + Icon: emp + ChargeTime: 135 + Description: E.M. Pulse + LongDesc: Fires a pulse blast which disables\nall mechanical units in the area. + EndChargeSound: speech-gdi|00-i158.aud + SelectTargetSound: speech-gdi|00-i042.aud + Prerequisites: emp.gdi + OrderName: GDIemp From b898e810bb34f42955ce870aecea925e58ac75e5 Mon Sep 17 00:00:00 2001 From: abcdefg30 Date: Sun, 12 Jun 2016 14:46:01 +0200 Subject: [PATCH 6/6] Use INotifyCreated instead of INotifyAddedToWorld in AttackOrderPower --- OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs index da41545cf7..76af6fe64a 100644 --- a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs +++ b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs @@ -24,7 +24,7 @@ namespace OpenRA.Mods.TS.Traits public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } } - class AttackOrderPower : SupportPower, INotifyAddedToWorld, INotifyBurstComplete + class AttackOrderPower : SupportPower, INotifyCreated, INotifyBurstComplete { readonly AttackOrderPowerInfo info; AttackBase attack; @@ -47,7 +47,7 @@ namespace OpenRA.Mods.TS.Traits attack.AttackTarget(Target.FromCell(self.World, order.TargetLocation), false, false, true); } - void INotifyAddedToWorld.AddedToWorld(Actor self) + void INotifyCreated.Created(Actor self) { attack = self.Trait(); }