Add backend code for unit command bar.
This commit is contained in:
@@ -15,8 +15,8 @@ namespace OpenRA.Orders
|
||||
{
|
||||
public class GenericSelectTarget : UnitOrderGenerator
|
||||
{
|
||||
public readonly string OrderName;
|
||||
protected readonly IEnumerable<Actor> Subjects;
|
||||
protected readonly string OrderName;
|
||||
protected readonly string Cursor;
|
||||
protected readonly MouseButton ExpectedButton;
|
||||
|
||||
|
||||
@@ -25,9 +25,10 @@ namespace OpenRA
|
||||
|
||||
void UpdateHash()
|
||||
{
|
||||
Hash = actors.Count << 16;
|
||||
foreach (var a in actors)
|
||||
Hash ^= Sync.HashActor(a);
|
||||
// Not a real hash, but things checking this only care about checking when the selection has changed
|
||||
// For this purpose, having a false positive (forcing a refresh when nothing changed) is much better
|
||||
// than a false negative (selection state mismatch)
|
||||
Hash += 1;
|
||||
}
|
||||
|
||||
public void Add(World w, Actor a)
|
||||
@@ -107,7 +108,8 @@ namespace OpenRA
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(world.RenderPlayer) && world.FogObscures(a)));
|
||||
var removed = actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(world.RenderPlayer) && world.FogObscures(a)));
|
||||
if (removed > 0)
|
||||
UpdateHash();
|
||||
|
||||
foreach (var cg in controlGroups.Values)
|
||||
|
||||
259
OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs
Normal file
259
OpenRA.Mods.Common/Widgets/Logic/Ingame/CommandBarLogic.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
#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;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
/// <summary> Contains all functions that are unit-specific. </summary>
|
||||
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;
|
||||
|
||||
int deployHighlighted;
|
||||
int scatterHighlighted;
|
||||
int stopHighlighted;
|
||||
|
||||
TraitPair<IIssueDeployOrder>[] selectedDeploys = { };
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public CommandBarLogic(Widget widget, World world)
|
||||
{
|
||||
this.world = world;
|
||||
var ks = Game.Settings.Keys;
|
||||
|
||||
var attackMoveButton = widget.GetOrNull<ButtonWidget>("ATTACK_MOVE");
|
||||
if (attackMoveButton != null)
|
||||
{
|
||||
BindButtonIcon(attackMoveButton);
|
||||
|
||||
attackMoveButton.GetKey = _ => ks.AttackMoveKey;
|
||||
attackMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return attackMoveDisabled; };
|
||||
attackMoveButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget
|
||||
&& ((GenericSelectTarget)world.OrderGenerator).OrderName == "AttackMove";
|
||||
|
||||
attackMoveButton.OnClick = () =>
|
||||
{
|
||||
if (attackMoveButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
else
|
||||
world.OrderGenerator = new GenericSelectTarget(selectedActors,
|
||||
"AttackMove", "attackmove", Game.Settings.Game.MouseButtonPreference.Action);
|
||||
};
|
||||
}
|
||||
|
||||
var forceMoveButton = widget.GetOrNull<ButtonWidget>("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<ButtonWidget>("FORCE_ATTACK");
|
||||
if (forceAttackButton != null)
|
||||
{
|
||||
BindButtonIcon(forceAttackButton);
|
||||
|
||||
forceAttackButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceAttackDisabled; };
|
||||
forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl);
|
||||
forceAttackButton.OnClick = () =>
|
||||
{
|
||||
if (forceAttackButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
else
|
||||
world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Ctrl, true);
|
||||
};
|
||||
}
|
||||
|
||||
var guardButton = widget.GetOrNull<ButtonWidget>("GUARD");
|
||||
if (guardButton != null)
|
||||
{
|
||||
BindButtonIcon(guardButton);
|
||||
|
||||
guardButton.GetKey = _ => ks.GuardKey;
|
||||
guardButton.IsDisabled = () => { UpdateStateIfNecessary(); return guardDisabled; };
|
||||
guardButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget
|
||||
&& ((GenericSelectTarget)world.OrderGenerator).OrderName == "Guard";
|
||||
|
||||
guardButton.OnClick = () =>
|
||||
{
|
||||
if (guardButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
else
|
||||
world.OrderGenerator = new GuardOrderGenerator(selectedActors,
|
||||
"Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
|
||||
};
|
||||
}
|
||||
|
||||
var scatterButton = widget.GetOrNull<ButtonWidget>("SCATTER");
|
||||
if (scatterButton != null)
|
||||
{
|
||||
BindButtonIcon(scatterButton);
|
||||
|
||||
scatterButton.GetKey = _ => ks.ScatterKey;
|
||||
scatterButton.IsDisabled = () => { UpdateStateIfNecessary(); return scatterDisabled; };
|
||||
scatterButton.IsHighlighted = () => scatterHighlighted > 0;
|
||||
scatterButton.OnClick = () => PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false));
|
||||
scatterButton.OnKeyPress = ki => { scatterHighlighted = 2; scatterButton.OnClick(); };
|
||||
}
|
||||
|
||||
var deployButton = widget.GetOrNull<ButtonWidget>("DEPLOY");
|
||||
if (deployButton != null)
|
||||
{
|
||||
BindButtonIcon(deployButton);
|
||||
|
||||
deployButton.GetKey = _ => ks.DeployKey;
|
||||
deployButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedDeploys.Any(Exts.IsTraitEnabled); };
|
||||
deployButton.IsHighlighted = () => deployHighlighted > 0;
|
||||
deployButton.OnClick = PerformDeployOrderOnSelection;
|
||||
deployButton.OnKeyPress = ki => { deployHighlighted = 2; deployButton.OnClick(); };
|
||||
}
|
||||
|
||||
var stopButton = widget.GetOrNull<ButtonWidget>("STOP");
|
||||
if (stopButton != null)
|
||||
{
|
||||
BindButtonIcon(stopButton);
|
||||
|
||||
stopButton.GetKey = _ => ks.StopKey;
|
||||
stopButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedActors.Any(); };
|
||||
stopButton.IsHighlighted = () => stopHighlighted > 0;
|
||||
stopButton.OnClick = () => PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false));
|
||||
stopButton.OnKeyPress = ki => { stopHighlighted = 2; stopButton.OnClick(); };
|
||||
}
|
||||
|
||||
var queueOrdersButton = widget.GetOrNull<ButtonWidget>("QUEUE_ORDERS");
|
||||
if (queueOrdersButton != null)
|
||||
{
|
||||
BindButtonIcon(queueOrdersButton);
|
||||
|
||||
queueOrdersButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedActors.Any(); };
|
||||
queueOrdersButton.IsHighlighted = () => !queueOrdersButton.IsDisabled() && IsForceModifiersActive(Modifiers.Shift);
|
||||
queueOrdersButton.OnClick = () =>
|
||||
{
|
||||
if (queueOrdersButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
else
|
||||
world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Shift, 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<ImageWidget>("ICON");
|
||||
icon.GetImageName = () => button.IsDisabled() ? icon.ImageName + "-disabled" : 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)
|
||||
.ToArray();
|
||||
|
||||
attackMoveDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo<AttackMoveInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>());
|
||||
guardDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo<GuardInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>());
|
||||
forceMoveDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo<MobileInfo>() || a.Info.HasTraitInfo<AircraftInfo>());
|
||||
forceAttackDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo<AttackBaseInfo>());
|
||||
scatterDisabled = !selectedActors.Any(a => a.Info.HasTraitInfo<MobileInfo>());
|
||||
|
||||
selectedDeploys = selectedActors
|
||||
.SelectMany(a => a.TraitsImplementing<IIssueDeployOrder>()
|
||||
.Select(d => new TraitPair<IIssueDeployOrder>(a, d)))
|
||||
.ToArray();
|
||||
|
||||
selectionHash = world.Selection.Hash;
|
||||
}
|
||||
|
||||
void PerformKeyboardOrderOnSelection(Func<Actor, Order> 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(Exts.IsTraitEnabled)
|
||||
.Select(d => d.Trait.IssueDeployOrder(d.Actor))
|
||||
.ToArray();
|
||||
|
||||
foreach (var o in orders)
|
||||
world.IssueOrder(o);
|
||||
|
||||
world.PlayVoiceForOrders(orders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#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;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class StanceSelectorLogic : ChromeLogic
|
||||
{
|
||||
readonly World world;
|
||||
|
||||
int selectionHash;
|
||||
TraitPair<AutoTarget>[] actorStances = { };
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public StanceSelectorLogic(Widget widget, World world)
|
||||
{
|
||||
this.world = world;
|
||||
var ks = Game.Settings.Keys;
|
||||
|
||||
var holdFireButton = widget.GetOrNull<ButtonWidget>("STANCE_HOLDFIRE");
|
||||
if (holdFireButton != null)
|
||||
BindStanceButton(holdFireButton, UnitStance.HoldFire, _ => ks.StanceHoldFireKey);
|
||||
|
||||
var returnFireButton = widget.GetOrNull<ButtonWidget>("STANCE_RETURNFIRE");
|
||||
if (returnFireButton != null)
|
||||
BindStanceButton(returnFireButton, UnitStance.ReturnFire, _ => ks.StanceReturnFireKey);
|
||||
|
||||
var defendButton = widget.GetOrNull<ButtonWidget>("STANCE_DEFEND");
|
||||
if (defendButton != null)
|
||||
BindStanceButton(defendButton, UnitStance.Defend, _ => ks.StanceDefendKey);
|
||||
|
||||
var attackAnythingButton = widget.GetOrNull<ButtonWidget>("STANCE_ATTACKANYTHING");
|
||||
if (attackAnythingButton != null)
|
||||
BindStanceButton(attackAnythingButton, UnitStance.AttackAnything, _ => ks.StanceAttackAnythingKey);
|
||||
}
|
||||
|
||||
void BindStanceButton(ButtonWidget button, UnitStance stance, Func<ButtonWidget, Hotkey> getHotkey)
|
||||
{
|
||||
var icon = button.Get<ImageWidget>("ICON");
|
||||
icon.GetImageName = () => button.IsDisabled() ? icon.ImageName + "-disabled" :
|
||||
button.IsHighlighted() ? icon.ImageName + "-active" : icon.ImageName;
|
||||
|
||||
button.GetKey = getHotkey;
|
||||
button.IsDisabled = () => { UpdateStateIfNecessary(); return !actorStances.Any(); };
|
||||
button.IsHighlighted = () => actorStances.Any(
|
||||
at => !at.Trait.IsTraitDisabled && at.Trait.PredictedStance == stance);
|
||||
button.OnClick = () => SetSelectionStance(stance);
|
||||
}
|
||||
|
||||
void UpdateStateIfNecessary()
|
||||
{
|
||||
if (selectionHash == world.Selection.Hash)
|
||||
return;
|
||||
|
||||
actorStances = world.Selection.Actors
|
||||
.Where(a => a.Owner == world.LocalPlayer && a.IsInWorld)
|
||||
.SelectMany(a => a.TraitsImplementing<AutoTarget>()
|
||||
.Where(at => at.Info.EnableStances)
|
||||
.Select(at => new TraitPair<AutoTarget>(a, at)))
|
||||
.ToArray();
|
||||
|
||||
selectionHash = world.Selection.Hash;
|
||||
}
|
||||
|
||||
void SetSelectionStance(UnitStance stance)
|
||||
{
|
||||
foreach (var at in actorStances)
|
||||
{
|
||||
if (!at.Trait.IsTraitDisabled)
|
||||
at.Trait.PredictedStance = stance;
|
||||
|
||||
world.IssueOrder(new Order("SetUnitStance", at.Actor, false) { ExtraData = (uint)stance });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user