Files
OpenRA/OpenRA.Game/Orders/UnitOrderGenerator.cs
Paul Chote e545865599 Add Selectable field to Selectable.
There are a bunch of bogus assumptions about
targetable actors being selectable. These aren't
easily fixed, so this add a Selectable field that
can be diabled for things we want to target, but
not select.
2013-04-15 08:06:52 +12:00

141 lines
4.4 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2013 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. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class UnitOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.HasTrait<ITargetable>())
.OrderByDescending(a => a.SelectionPriority())
.FirstOrDefault();
var orders = world.Selection.Actors
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.self).Distinct();
if (actorsInvolved.Any())
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false)
{
TargetString = actorsInvolved.Select(a => a.ActorID).JoinWith(",")
};
foreach (var o in orders)
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift)));
}
public void Tick(World world) { }
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
public void RenderAfterWorld(WorldRenderer wr, World world) { }
public string GetCursor(World world, CPos xy, MouseInput mi)
{
bool useSelect = false;
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.HasTrait<ITargetable>())
.OrderByDescending(a => a.SelectionPriority())
.FirstOrDefault();
if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
{
var selectable = underCursor.TraitOrDefault<Selectable>();
if (selectable != null && selectable.Info.Selectable)
useSelect = true;
}
var orders = world.Selection.Actors
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
var cursorName = orders.Select(o => o.cursor).FirstOrDefault();
return cursorName ?? (useSelect ? "select" : "default");
}
static UnitOrderResult OrderForUnit(Actor self, CPos xy, MouseInput mi, Actor underCursor)
{
if (self.Owner != self.World.LocalPlayer)
return null;
if (self.Destroyed)
return null;
if (mi.Button == Game.mouseButtonPreference.Action)
{
foreach( var o in self.TraitsImplementing<IIssueOrder>()
.SelectMany(trait => trait.Orders
.Select(x => new { Trait = trait, Order = x } ))
.OrderByDescending(x => x.Order.OrderPriority))
{
var actorsAt = self.World.ActorMap.GetUnitsAt(xy).ToList();
var forceAttack = mi.Modifiers.HasModifier(Modifiers.Ctrl);
var forceQueue = mi.Modifiers.HasModifier(Modifiers.Shift);
string cursor = null;
if (underCursor != null)
if (o.Order.CanTargetActor(self, underCursor, forceAttack, forceQueue, ref cursor))
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromActor(underCursor));
if (o.Order.CanTargetLocation(self, xy, actorsAt, forceAttack, forceQueue, ref cursor))
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromCell(xy));
}
}
return null;
}
static Order CheckSameOrder(IOrderTargeter iot, Order order)
{
if (order == null && iot.OrderID != null)
Game.Debug("BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID);
else if (iot.OrderID != order.OrderString)
Game.Debug("BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString);
return order;
}
class UnitOrderResult
{
public readonly Actor self;
public readonly IOrderTargeter iot;
public readonly IIssueOrder trait;
public readonly string cursor;
public readonly Target target;
public UnitOrderResult(Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target)
{
this.self = self;
this.iot = iot;
this.trait = trait;
this.cursor = cursor;
this.target = target;
}
}
}
public static class SelectableExts
{
public static int SelectionPriority(this Actor a)
{
var selectableInfo = a.Info.Traits.GetOrDefault<SelectableInfo>();
return selectableInfo != null ? selectableInfo.Priority : int.MinValue;
}
}
}