Let order generators account for selection changes
This commit is contained in:
@@ -18,13 +18,14 @@ namespace OpenRA.Orders
|
||||
public class GenericSelectTarget : UnitOrderGenerator
|
||||
{
|
||||
public readonly string OrderName;
|
||||
protected readonly IEnumerable<Actor> Subjects;
|
||||
protected readonly string Cursor;
|
||||
protected readonly MouseButton ExpectedButton;
|
||||
|
||||
protected IEnumerable<Actor> subjects;
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor, MouseButton button)
|
||||
{
|
||||
Subjects = subjects;
|
||||
this.subjects = subjects;
|
||||
OrderName = order;
|
||||
Cursor = cursor;
|
||||
ExpectedButton = button;
|
||||
@@ -53,7 +54,7 @@ namespace OpenRA.Orders
|
||||
world.CancelInputMode();
|
||||
|
||||
var queued = mi.Modifiers.HasModifier(Modifiers.Shift);
|
||||
yield return new Order(OrderName, null, Target.FromCell(world, cell), queued, null, Subjects.ToArray());
|
||||
yield return new Order(OrderName, null, Target.FromCell(world, cell), queued, null, subjects.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +69,11 @@ namespace OpenRA.Orders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SelectionChanged(World world, IEnumerable<Actor> selected)
|
||||
{
|
||||
subjects = selected;
|
||||
}
|
||||
|
||||
public override bool ClearSelectionOnLeftClick { get { return false; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,6 @@ namespace OpenRA
|
||||
string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi);
|
||||
void Deactivate();
|
||||
bool HandleKeyPress(KeyInput e);
|
||||
void SelectionChanged(World world, IEnumerable<Actor> selected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,8 @@ namespace OpenRA.Orders
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void SelectionChanged(World world, IEnumerable<Actor> selected) { }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the most appropriate order for a given actor and target.
|
||||
/// First priority is given to orders that interact with the given actors.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Cnc.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
@@ -211,9 +212,10 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick(World world)
|
||||
protected override void SelectionChanged(World world, IEnumerable<Actor> selected)
|
||||
{
|
||||
minelayers.RemoveAll(minelayer => !minelayer.IsInWorld || minelayer.IsDead);
|
||||
minelayers.Clear();
|
||||
minelayers.AddRange(selected.Where(s => s.Info.HasTraitInfo<MinelayerInfo>()));
|
||||
if (!minelayers.Any())
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Cnc.Activities;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
@@ -209,9 +210,9 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick(World world)
|
||||
protected override void SelectionChanged(World world, IEnumerable<Actor> selected)
|
||||
{
|
||||
if (!self.IsInWorld || self.IsDead)
|
||||
if (!selected.Contains(self))
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace OpenRA.Mods.Common.Orders
|
||||
yield return new Order("PlaceBeacon", world.LocalPlayer.PlayerActor, Target.FromCell(world, cell), false) { SuppressVisualFeedback = true };
|
||||
}
|
||||
|
||||
protected override void Tick(World world) { }
|
||||
protected override IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
protected override IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr, World world) { yield break; }
|
||||
protected override IEnumerable<IRenderable> RenderAnnotations(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
@@ -28,29 +28,31 @@ namespace OpenRA.Mods.Common.Orders
|
||||
yield break;
|
||||
|
||||
var target = FriendlyGuardableUnits(world, mi).FirstOrDefault();
|
||||
if (target == null || Subjects.All(s => s.IsDead))
|
||||
if (target == null)
|
||||
yield break;
|
||||
|
||||
world.CancelInputMode();
|
||||
|
||||
var queued = mi.Modifiers.HasModifier(Modifiers.Shift);
|
||||
yield return new Order(OrderName, null, Target.FromActor(target), queued, null, Subjects.Where(s => s != target).ToArray());
|
||||
yield return new Order(OrderName, null, Target.FromActor(target), queued, null, subjects.Where(s => s != target).ToArray());
|
||||
}
|
||||
|
||||
public override void Tick(World world)
|
||||
public override void SelectionChanged(World world, IEnumerable<Actor> selected)
|
||||
{
|
||||
if (Subjects.All(s => s.IsDead || !s.Info.HasTraitInfo<GuardInfo>()))
|
||||
// Guarding doesn't work without AutoTarget, so require at least one unit in the selection to have it
|
||||
subjects = selected.Where(s => s.Info.HasTraitInfo<GuardInfo>());
|
||||
if (!subjects.Any(s => s.Info.HasTraitInfo<AutoTargetInfo>()))
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
if (!Subjects.Any())
|
||||
if (!subjects.Any())
|
||||
return null;
|
||||
|
||||
var multiple = Subjects.Count() > 1;
|
||||
var multiple = subjects.Count() > 1;
|
||||
var canGuard = FriendlyGuardableUnits(world, mi)
|
||||
.Any(a => multiple || a != Subjects.First());
|
||||
.Any(a => multiple || a != subjects.First());
|
||||
|
||||
return canGuard ? Cursor : "move-blocked";
|
||||
}
|
||||
|
||||
@@ -32,12 +32,14 @@ namespace OpenRA.Mods.Common.Orders
|
||||
string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) { return GetCursor(world, cell, worldPixel, mi); }
|
||||
void IOrderGenerator.Deactivate() { }
|
||||
bool IOrderGenerator.HandleKeyPress(KeyInput e) { return false; }
|
||||
void IOrderGenerator.SelectionChanged(World world, IEnumerable<Actor> selected) { SelectionChanged(world, selected); }
|
||||
|
||||
protected abstract void Tick(World world);
|
||||
protected virtual void Tick(World world) { }
|
||||
protected abstract IEnumerable<IRenderable> Render(WorldRenderer wr, World world);
|
||||
protected abstract IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr, World world);
|
||||
protected abstract IEnumerable<IRenderable> RenderAnnotations(WorldRenderer wr, World world);
|
||||
protected abstract string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi);
|
||||
protected abstract IEnumerable<Order> OrderInner(World world, CPos cell, int2 worldPixel, MouseInput mi);
|
||||
protected virtual void SelectionChanged(World world, IEnumerable<Actor> selected) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,8 @@ namespace OpenRA.Mods.Common.Orders
|
||||
v.Preview.Tick();
|
||||
}
|
||||
|
||||
void IOrderGenerator.SelectionChanged(World world, IEnumerable<Actor> selected) { }
|
||||
|
||||
bool AcceptsPlug(CPos cell, PlugInfo plug)
|
||||
{
|
||||
var host = buildingInfluence.GetBuildingAt(cell);
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public class AttackMoveOrderGenerator : UnitOrderGenerator
|
||||
{
|
||||
readonly TraitPair<AttackMove>[] subjects;
|
||||
TraitPair<AttackMove>[] subjects;
|
||||
|
||||
readonly MouseButton expectedButton;
|
||||
|
||||
public AttackMoveOrderGenerator(IEnumerable<Actor> subjects, MouseButton button)
|
||||
@@ -120,9 +121,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public override void Tick(World world)
|
||||
public override void SelectionChanged(World world, IEnumerable<Actor> selected)
|
||||
{
|
||||
if (subjects.All(s => s.Actor.IsDead))
|
||||
subjects = selected.SelectMany(a => a.TraitsImplementing<AttackMove>()
|
||||
.Select(am => new TraitPair<AttackMove>(a, am)))
|
||||
.ToArray();
|
||||
|
||||
// AttackMove doesn't work without AutoTarget, so require at least one unit in the selection to have it
|
||||
if (!subjects.Any(s => s.Actor.Info.HasTraitInfo<AutoTargetInfo>()))
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
void IOrderGenerator.SelectionChanged(World world, IEnumerable<Actor> selected) { }
|
||||
|
||||
bool IsOutsideDragZone
|
||||
{
|
||||
get { return dragStarted && dragDirection.Length > MinDragThreshold; }
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public IEnumerable<Actor> Actors { get { return actors; } }
|
||||
|
||||
readonly HashSet<Actor> actors = new HashSet<Actor>();
|
||||
World world;
|
||||
IEnumerable<Actor> rolloverActors;
|
||||
|
||||
INotifySelection[] worldNotifySelection;
|
||||
@@ -37,6 +38,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
worldNotifySelection = self.TraitsImplementing<INotifySelection>().ToArray();
|
||||
world = self.World;
|
||||
}
|
||||
|
||||
void UpdateHash()
|
||||
@@ -55,6 +57,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var sel in a.TraitsImplementing<INotifySelected>())
|
||||
sel.Selected(a);
|
||||
|
||||
Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors));
|
||||
foreach (var ns in worldNotifySelection)
|
||||
ns.SelectionChanged();
|
||||
}
|
||||
@@ -64,6 +67,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (actors.Remove(a))
|
||||
{
|
||||
UpdateHash();
|
||||
Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors));
|
||||
foreach (var ns in worldNotifySelection)
|
||||
ns.SelectionChanged();
|
||||
}
|
||||
@@ -76,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
// Remove the actor from the original owners selection
|
||||
// Call UpdateHash directly for everyone else so watchers can account for the owner change if needed
|
||||
if (oldOwner == a.World.LocalPlayer)
|
||||
if (oldOwner == world.LocalPlayer)
|
||||
Remove(a);
|
||||
else
|
||||
UpdateHash();
|
||||
@@ -91,7 +95,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (isClick)
|
||||
{
|
||||
var adjNewSelection = newSelection.Take(1); // TODO: select BEST, not FIRST
|
||||
// TODO: select BEST, not FIRST
|
||||
var adjNewSelection = newSelection.Take(1);
|
||||
if (isCombine)
|
||||
actors.SymmetricExceptWith(adjNewSelection);
|
||||
else
|
||||
@@ -117,6 +122,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var sel in a.TraitsImplementing<INotifySelected>())
|
||||
sel.Selected(a);
|
||||
|
||||
Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors));
|
||||
foreach (var ns in worldNotifySelection)
|
||||
ns.SelectionChanged();
|
||||
|
||||
@@ -143,6 +149,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
actors.Clear();
|
||||
UpdateHash();
|
||||
Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors));
|
||||
foreach (var ns in worldNotifySelection)
|
||||
ns.SelectionChanged();
|
||||
}
|
||||
|
||||
public void SetRollover(IEnumerable<Actor> rollover)
|
||||
@@ -157,18 +166,23 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
var removed = actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(self.World.RenderPlayer) && self.World.FogObscures(a)));
|
||||
var removed = actors.RemoveWhere(a => !a.IsInWorld || (!a.Owner.IsAlliedWith(world.RenderPlayer) && world.FogObscures(a)));
|
||||
if (removed > 0)
|
||||
{
|
||||
UpdateHash();
|
||||
Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, world, () => world.OrderGenerator.SelectionChanged(world, actors));
|
||||
foreach (var ns in worldNotifySelection)
|
||||
ns.SelectionChanged();
|
||||
}
|
||||
|
||||
foreach (var cg in controlGroups.Values)
|
||||
{
|
||||
// note: NOT `!a.IsInWorld`, since that would remove things that are in transports.
|
||||
cg.RemoveAll(a => a.Disposed || a.Owner != self.World.LocalPlayer);
|
||||
cg.RemoveAll(a => a.Disposed || a.Owner != world.LocalPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
|
||||
readonly Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
|
||||
|
||||
public void DoControlGroup(World world, WorldRenderer worldRenderer, int group, Modifiers mods, int multiTapCount)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user