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