#region Copyright & License Information /* * Copyright 2007-2018 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; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; using OpenRA.Orders; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets { /// Contains all functions that are unit-specific. public class CommandBarLogic : ChromeLogic { readonly World world; int selectionHash; Actor[] selectedActors = { }; bool attackMoveDisabled = true; bool forceMoveDisabled = true; bool forceAttackDisabled = true; bool guardDisabled = true; bool scatterDisabled = true; bool stopDisabled = true; bool waypointModeDisabled = true; int deployHighlighted; int scatterHighlighted; int stopHighlighted; TraitPair[] selectedDeploys = { }; [ObjectCreator.UseCtor] public CommandBarLogic(Widget widget, World world, Dictionary logicArgs) { this.world = world; var highlightOnButtonPress = false; if (logicArgs.ContainsKey("HighlightOnButtonPress")) highlightOnButtonPress = FieldLoader.GetValue("HighlightOnButtonPress", logicArgs["HighlightOnButtonPress"].Value); var attackMoveButton = widget.GetOrNull("ATTACK_MOVE"); if (attackMoveButton != null) { BindButtonIcon(attackMoveButton); attackMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return attackMoveDisabled; }; attackMoveButton.IsHighlighted = () => world.OrderGenerator is AttackMoveOrderGenerator; Action toggle = allowCancel => { if (attackMoveButton.IsHighlighted()) { if (allowCancel) world.CancelInputMode(); } else world.OrderGenerator = new AttackMoveOrderGenerator(selectedActors, Game.Settings.Game.MouseButtonPreference.Action); }; attackMoveButton.OnClick = () => toggle(true); attackMoveButton.OnKeyPress = _ => toggle(false); } var forceMoveButton = widget.GetOrNull("FORCE_MOVE"); if (forceMoveButton != null) { BindButtonIcon(forceMoveButton); forceMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceMoveDisabled; }; forceMoveButton.IsHighlighted = () => !forceMoveButton.IsDisabled() && IsForceModifiersActive(Modifiers.Alt); forceMoveButton.OnClick = () => { if (forceMoveButton.IsHighlighted()) world.CancelInputMode(); else world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Alt, true); }; } var forceAttackButton = widget.GetOrNull("FORCE_ATTACK"); if (forceAttackButton != null) { BindButtonIcon(forceAttackButton); forceAttackButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceAttackDisabled; }; forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl) && !(world.OrderGenerator is AttackMoveOrderGenerator); forceAttackButton.OnClick = () => { if (forceAttackButton.IsHighlighted()) world.CancelInputMode(); else world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Ctrl, true); }; } var guardButton = widget.GetOrNull("GUARD"); if (guardButton != null) { BindButtonIcon(guardButton); guardButton.IsDisabled = () => { UpdateStateIfNecessary(); return guardDisabled; }; guardButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget && ((GenericSelectTarget)world.OrderGenerator).OrderName == "Guard"; Action toggle = allowCancel => { if (guardButton.IsHighlighted()) { if (allowCancel) world.CancelInputMode(); } else world.OrderGenerator = new GuardOrderGenerator(selectedActors, "Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action); }; guardButton.OnClick = () => toggle(true); guardButton.OnKeyPress = _ => toggle(false); } var scatterButton = widget.GetOrNull("SCATTER"); if (scatterButton != null) { BindButtonIcon(scatterButton); scatterButton.IsDisabled = () => { UpdateStateIfNecessary(); return scatterDisabled; }; scatterButton.IsHighlighted = () => scatterHighlighted > 0; scatterButton.OnClick = () => { if (highlightOnButtonPress) scatterHighlighted = 2; PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false)); }; scatterButton.OnKeyPress = ki => { scatterHighlighted = 2; scatterButton.OnClick(); }; } var deployButton = widget.GetOrNull("DEPLOY"); if (deployButton != null) { BindButtonIcon(deployButton); deployButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedDeploys.Any(pair => pair.Trait.CanIssueDeployOrder(pair.Actor)); }; deployButton.IsHighlighted = () => deployHighlighted > 0; deployButton.OnClick = () => { if (highlightOnButtonPress) deployHighlighted = 2; PerformDeployOrderOnSelection(); }; deployButton.OnKeyPress = ki => { deployHighlighted = 2; deployButton.OnClick(); }; } var stopButton = widget.GetOrNull("STOP"); if (stopButton != null) { BindButtonIcon(stopButton); stopButton.IsDisabled = () => { UpdateStateIfNecessary(); return stopDisabled; }; stopButton.IsHighlighted = () => stopHighlighted > 0; stopButton.OnClick = () => { if (highlightOnButtonPress) stopHighlighted = 2; PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false)); }; stopButton.OnKeyPress = ki => { stopHighlighted = 2; stopButton.OnClick(); }; } var queueOrdersButton = widget.GetOrNull("QUEUE_ORDERS"); if (queueOrdersButton != null) { BindButtonIcon(queueOrdersButton); queueOrdersButton.IsDisabled = () => { UpdateStateIfNecessary(); return waypointModeDisabled; }; queueOrdersButton.IsHighlighted = () => !queueOrdersButton.IsDisabled() && IsForceModifiersActive(Modifiers.Shift); queueOrdersButton.OnClick = () => { if (queueOrdersButton.IsHighlighted()) world.CancelInputMode(); else world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Shift, false); }; } var keyOverrides = widget.GetOrNull("MODIFIER_OVERRIDES"); if (keyOverrides != null) { keyOverrides.AddHandler(e => { // HACK: enable attack move to be triggered if the ctrl key is pressed e.Modifiers &= ~Modifiers.Ctrl; if (!attackMoveDisabled && attackMoveButton.Key.IsActivatedBy(e)) { attackMoveButton.OnKeyPress(e); return true; } return false; }); } } public override void Tick() { if (deployHighlighted > 0) deployHighlighted--; if (scatterHighlighted > 0) scatterHighlighted--; if (stopHighlighted > 0) stopHighlighted--; base.Tick(); } void BindButtonIcon(ButtonWidget button) { var icon = button.Get("ICON"); var hasDisabled = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-disabled") != null; var hasActive = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active") != null; var hasActiveHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-active-hover") != null; var hasHover = ChromeProvider.GetImage(icon.ImageCollection, icon.ImageName + "-hover") != null; icon.GetImageName = () => hasActive && button.IsHighlighted() ? (hasActiveHover && Ui.MouseOverWidget == button ? icon.ImageName + "-active-hover" : icon.ImageName + "-active") : hasDisabled && button.IsDisabled() ? icon.ImageName + "-disabled" : hasHover && Ui.MouseOverWidget == button ? icon.ImageName + "-hover" : icon.ImageName; } bool IsForceModifiersActive(Modifiers modifiers) { var fmog = world.OrderGenerator as ForceModifiersOrderGenerator; if (fmog != null && fmog.Modifiers.HasFlag(modifiers)) return true; var uog = world.OrderGenerator as UnitOrderGenerator; if (uog != null && Game.GetModifierKeys().HasFlag(modifiers)) return true; return false; } void UpdateStateIfNecessary() { if (selectionHash == world.Selection.Hash) return; selectedActors = world.Selection.Actors .Where(a => a.Owner == world.LocalPlayer && a.IsInWorld && !a.IsDead) .ToArray(); attackMoveDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo() && a.Info.HasTraitInfo()); guardDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo() && a.Info.HasTraitInfo()); forceMoveDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo() || a.Info.HasTraitInfo()); forceAttackDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo()); scatterDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo()); selectedDeploys = selectedActors .SelectMany(a => a.TraitsImplementing() .Select(d => new TraitPair(a, d))) .ToArray(); var cbbInfos = selectedActors.Select(a => a.Info.TraitInfoOrDefault()).ToArray(); stopDisabled = !cbbInfos.Any(i => i == null || !i.DisableStop); waypointModeDisabled = !cbbInfos.Any(i => i == null || !i.DisableWaypointMode); selectionHash = world.Selection.Hash; } void PerformKeyboardOrderOnSelection(Func f) { UpdateStateIfNecessary(); var orders = selectedActors .Select(f) .ToArray(); foreach (var o in orders) world.IssueOrder(o); world.PlayVoiceForOrders(orders); } void PerformDeployOrderOnSelection() { UpdateStateIfNecessary(); var orders = selectedDeploys .Where(pair => pair.Trait.CanIssueDeployOrder(pair.Actor)) .Select(d => d.Trait.IssueDeployOrder(d.Actor)) .Where(d => d != null) .ToArray(); foreach (var o in orders) world.IssueOrder(o); world.PlayVoiceForOrders(orders); } } }