#region Copyright & License Information /* * Copyright 2007-2017 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.Cnc.Traits { class AttackOrderPowerInfo : SupportPowerInfo, Requires { public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); } } class AttackOrderPower : SupportPower, INotifyCreated, INotifyBurstComplete { 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(SoundType.UI, 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 INotifyCreated.Created(Actor self) { attack = self.Trait(); } void INotifyBurstComplete.FiredBurst(Actor self, Target target, Armament a) { 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.IsTraitPaused).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.IsTraitPaused && (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.RenderAboveShroud(WorldRenderer wr, World world) { foreach (var a in instance.Instances.Where(i => !i.IsTraitPaused)) { 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; } } }