added IIssueOrder2. most orders are broken, but Minelayer is fixed

This commit is contained in:
Bob
2010-10-02 18:16:02 +12:00
committed by Paul Chote
parent 0cd140849b
commit 3d805ff40d
7 changed files with 215 additions and 103 deletions

View File

@@ -110,23 +110,6 @@ namespace OpenRA
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
}
public Order Order( int2 xy, MouseInput mi, Actor underCursor )
{
if (Owner != World.LocalPlayer)
return null;
if (!World.Map.IsInMap(xy.X, xy.Y))
return null;
if (Destroyed)
return null;
return TraitsImplementing<IIssueOrder>()
.OrderByDescending( x => x.OrderPriority( this, xy, mi, underCursor ) )
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null );
}
public RectangleF GetBounds(bool useAltitude)
{
var si = Info.Traits.GetOrDefault<SelectableInfo>();

View File

@@ -178,7 +178,7 @@ namespace OpenRA
LobbyInfoChanged();
}
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
public static void IssueOrder( Order o ) { orderManager.IssueOrder( o ); } /* avoid exposing the OM to mod code */
public static event Action AfterGameStart = () => {};

View File

@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Orders
{
@@ -25,17 +26,17 @@ namespace OpenRA.Orders
.FirstOrDefault();
var orders = world.Selection.Actors
.Select(a => a.Order(xy, mi, underCursor))
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
var actorsInvolved = orders.Select(o => o.Subject).Distinct();
var actorsInvolved = orders.Select(o => o.self).Distinct();
if (actorsInvolved.Any())
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
foreach (var o in orders)
yield return o;
foreach( var o in orders )
yield return CheckSameOrder( o.iot, o.trait.IssueOrder( o.self, o.iot, o.target ) );
}
public void Tick( World world ) {}
@@ -61,23 +62,90 @@ namespace OpenRA.Orders
}
public string GetCursor( World world, int2 xy, MouseInput mi )
{
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
.Any();
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
.FirstOrDefault();
if (underCursor)
if( mi.Modifiers.HasModifier( Modifiers.Shift ) || !world.Selection.Actors.Any() )
if( underCursor != null )
return "select";
var orders = world.Selection.Actors
.Select(a => OrderForUnit(a, xy, mi, underCursor))
.Where(o => o != null)
.ToArray();
if( orders.Length == 0 ) return "default";
return orders[ 0 ].cursor ?? "default";
}
var c = Order(world, xy, mi)
.Select(o => o.Subject.TraitsImplementing<IOrderCursor>()
.Select(pc => pc.CursorForOrder(o.Subject, o)).FirstOrDefault(a => a != null))
.FirstOrDefault(a => a != null);
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
{
if (self.Owner != self.World.LocalPlayer)
return null;
return c ?? "default";
if (!self.World.Map.IsInMap(xy.X, xy.Y))
return null;
if (self.Destroyed)
return null;
//var old = self.TraitsImplementing<IIssueOrder>()
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
// .FirstOrDefault( x => x != null );
//if( old != null )
// return old;
if( mi.Button == MouseButton.Right )
{
var uim = self.World.WorldActor.Trait<UnitInfluence>();
foreach( var o in self.TraitsImplementing<IIssueOrder2>()
.SelectMany( trait => trait.Orders
.Select( x => new { Trait = trait, Order = x } ) )
.OrderByDescending( x => x.Order.OrderPriority ) )
{
var actorsAt = uim.GetUnitsAt( xy ).ToList();
string cursor = null;
if( o.Order.CanTargetUnit( self, underCursor, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
if( o.Order.CanTargetLocation( self, xy, actorsAt, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), 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 IIssueOrder2 trait;
public readonly string cursor;
public readonly Target target;
public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder2 trait, string cursor, Target target )
{
this.self = self;
this.iot = iot;
this.trait = trait;
this.cursor = cursor;
this.target = target;
}
}
}
}

View File

@@ -16,6 +16,7 @@ using OpenRA.Effects;
using OpenRA.Traits.Activities;
using OpenRA.FileFormats;
using System.Diagnostics;
using OpenRA.Orders;
namespace OpenRA.Traits
{
@@ -53,7 +54,7 @@ namespace OpenRA.Traits
}
}
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
public class Mobile : IIssueOrder2, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
{
public readonly Actor self;
public readonly MobileInfo Info;
@@ -131,21 +132,17 @@ namespace OpenRA.Traits
self.CenterLocation = Util.CenterOfCell(fromCell);
}
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
// Force move takes precedence
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
}
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter( Info ); } }
// Note: Returns a valid order even if the unit can't move to the target
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
{
if (Info.OnRails) return null;
if (mi.Button == MouseButton.Left) return null;
var type = (!self.World.LocalPlayer.Shroud.IsVisible(xy) || CanEnterCell(xy)) ? "Move" : "Move-Blocked";
return new Order(type, self, xy, mi.Modifiers.HasModifier(Modifiers.Shift));
if( order is MoveOrderTargeter )
{
if( Info.OnRails ) return null;
return new Order( "Move", self, Util.CellContaining( target.CenterLocation ), false );
}
return null;
}
public int2 NearestMoveableCell(int2 target)
@@ -369,5 +366,31 @@ namespace OpenRA.Traits
Log.Write("debug", "OnNudge #{0} refuses at {1}",
self.ActorID, self.Location);
}
class MoveOrderTargeter : IOrderTargeter
{
readonly MobileInfo unitType;
public MoveOrderTargeter( MobileInfo unitType )
{
this.unitType = unitType;
}
public string OrderID { get { return "Move"; } }
public int OrderPriority { get { return 4; } }
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
{
return false;
}
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
{
cursor = "move";
if( self.World.LocalPlayer.Shroud.IsVisible( location ) && !self.Trait<Mobile>().CanEnterCell( location ) )
cursor = "move-blocked";
return true;
}
}
}
}

View File

@@ -38,6 +38,18 @@ namespace OpenRA.Traits
Order IssueOrder( Actor self, int2 xy, MouseInput mi, Actor underCursor );
int OrderPriority( Actor self, int2 xy, MouseInput mi, Actor underCursor );
}
public interface IIssueOrder2
{
IEnumerable<IOrderTargeter> Orders { get; }
Order IssueOrder( Actor self, IOrderTargeter order, Target target );
}
public interface IOrderTargeter
{
string OrderID { get; }
int OrderPriority { get; }
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor );
bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor );
}
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
public interface IOrderCursor { string CursorForOrder(Actor self, Order order); }
public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); }

View File

@@ -26,44 +26,35 @@ namespace OpenRA.Mods.RA
public readonly string[] RearmBuildings = { "fix" };
}
class Minelayer : IIssueOrder, IResolveOrder, IOrderCursor, IPostRenderSelection
class Minelayer : IIssueOrder2, IResolveOrder, IPostRenderSelection
{
/* [Sync] when sync can cope with arrays! */
public int2[] minefield = null;
[Sync] int2 minefieldStart;
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
public IEnumerable<IOrderTargeter> Orders
{
return 5;
get { yield return new BeginMinefieldOrderTargeter(); }
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
{
if (mi.Button == MouseButton.Right && underCursor == null && mi.Modifiers.HasModifier(Modifiers.Ctrl))
return new Order("BeginMinefield", self, xy);
if( order is BeginMinefieldOrderTargeter )
{
var start = Util.CellContaining( target.CenterLocation );
self.World.OrderGenerator = new MinefieldOrderGenerator( self, start );
return new Order( "BeginMinefield", self, start );
}
return null;
}
public string CursorForOrder(Actor self, Order order)
{
return (order.OrderString == "BeginMinefield") ? "ability" : null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "BeginMinefield")
{
//minefieldStart = order.TargetLocation;
//if (self.Owner == self.World.LocalPlayer)
// self.World.OrderGenerator = new MinefieldOrderGenerator(self);
}
if( order.OrderString == "BeginMinefield" )
minefieldStart = order.TargetLocation;
if (order.OrderString == "PlaceMinefield")
{
if (self.Owner == self.World.LocalPlayer)
self.World.CancelInputMode();
var movement = self.Trait<IMove>();
minefield = GetMinefieldCells(minefieldStart, order.TargetLocation,
@@ -97,9 +88,10 @@ namespace OpenRA.Mods.RA
class MinefieldOrderGenerator : IOrderGenerator
{
Actor minelayer;
readonly Actor minelayer;
readonly int2 minefieldStart;
public MinefieldOrderGenerator(Actor self) { minelayer = self; }
public MinefieldOrderGenerator(Actor self, int2 xy ) { minelayer = self; minefieldStart = xy; }
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
@@ -114,8 +106,11 @@ namespace OpenRA.Mods.RA
? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
.FirstOrDefault();
if (mi.Button == MouseButton.Right && underCursor == null)
yield return new Order("PlaceMinefield", minelayer, xy);
if( mi.Button == MouseButton.Right && underCursor == null )
{
minelayer.World.CancelInputMode();
yield return new Order( "PlaceMinefield", minelayer, xy );
}
}
public void Tick(World world)
@@ -132,7 +127,7 @@ namespace OpenRA.Mods.RA
var ml = minelayer.Trait<Minelayer>();
var movement = minelayer.Trait<IMove>();
var minefield = GetMinefieldCells(ml.minefieldStart, lastMousePos, minelayer.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
var minefield = GetMinefieldCells(minefieldStart, lastMousePos, minelayer.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
.Where(p => movement.CanEnterCell(p)).ToArray();
world.WorldRenderer.DrawLocus(Color.Cyan, minefield);
@@ -151,5 +146,22 @@ namespace OpenRA.Mods.RA
if (minefield != null)
self.World.WorldRenderer.DrawLocus(Color.Cyan, minefield);
}
class BeginMinefieldOrderTargeter : IOrderTargeter
{
public string OrderID { get { return "BeginMinefield"; } }
public int OrderPriority { get { return 5; } }
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
{
return false;
}
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
{
cursor = "ability";
return ( actorsAtLocation.Count == 0 && forceAttack );
}
}
}
}

View File

@@ -12,6 +12,7 @@ using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
using OpenRA.GameRules;
using System.Collections.Generic;
namespace OpenRA.Mods.RA
{
@@ -27,7 +28,7 @@ namespace OpenRA.Mods.RA
public virtual object Create(ActorInitializer init) { return new Transforms(this); }
}
class Transforms : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
class Transforms : IIssueOrder2, IResolveOrder, IOrderVoice
{
TransformsInfo Info;
BuildingInfo bi;
@@ -38,19 +39,6 @@ namespace OpenRA.Mods.RA
bi = Rules.Info[info.IntoActor].Traits.GetOrDefault<BuildingInfo>();
}
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
return 5;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && self == underCursor)
return new Order("DeployTransform", self);
return null;
}
public string VoicePhraseForOrder(Actor self, Order order)
{
return (order.OrderString == "DeployTransform") ? "Move" : null;
@@ -61,6 +49,16 @@ namespace OpenRA.Mods.RA
return (bi == null || self.World.CanPlaceBuilding(Info.IntoActor, bi, self.Location + Info.Offset, self));
}
public IEnumerable<IOrderTargeter> Orders { get { yield return new TransformOrderTargeter(); } }
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
{
if( order is TransformOrderTargeter )
return new Order( "DeployTransform", self );
return null;
}
public void ResolveOrder( Actor self, Order order )
{
if (order.OrderString == "DeployTransform")
@@ -80,12 +78,28 @@ namespace OpenRA.Mods.RA
}
}
public string CursorForOrder(Actor self, Order order)
class TransformOrderTargeter : IOrderTargeter
{
if (order.OrderString != "DeployTransform")
return null;
public string OrderID
{
get { return "DeployTransform"; }
}
return CanDeploy(self) ? "deploy" : "deploy-blocked";
public int OrderPriority
{
get { return 5; }
}
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
{
cursor = self.Trait<Transforms>().CanDeploy( self ) ? "deploy" : "deploy-blocked";
return self == target;
}
public bool CanTargetLocation( Actor self, int2 location, System.Collections.Generic.List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
{
return false;
}
}
}
}