Restructuring orders.

This commit is contained in:
Bob
2009-10-28 22:06:39 +13:00
parent 5d1ae1cb2a
commit c0cb248bc1
14 changed files with 632 additions and 621 deletions

View File

@@ -15,13 +15,22 @@ namespace OpenRa.Game
void ApplyOrders(float2 xy, bool left) void ApplyOrders(float2 xy, bool left)
{ {
var doVoice = true; var doVoice = null as Actor;
if (orderGenerator != null) if (orderGenerator != null)
foreach (var order in orderGenerator.Order(xy.ToInt2(), left)) foreach( var order in orderGenerator.Order( xy.ToInt2(), left ) )
{ {
order.Apply(doVoice); UnitOrders.ProcessOrder( order );
doVoice = false; if( order.Subject != null && order.Player == Game.LocalPlayer )
doVoice = order.Subject;
} }
if( doVoice != null )
Game.PlaySound( Game.SovietVoices.First.GetNext() + GetVoiceSuffix( doVoice ), false );
}
static string GetVoiceSuffix( Actor unit )
{
var suffixes = new[] { ".r01", ".r03" };
return suffixes[ unit.traits.Get<Traits.Mobile>().Voice ];
} }
float2 dragStart, dragEnd; float2 dragStart, dragEnd;

View File

@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
abstract class Order
{
public abstract void Apply(bool doVoice);
}
class MoveOrder : Order
{
public readonly Actor Unit;
public readonly int2 Destination;
public MoveOrder(Actor unit, int2 destination)
{
this.Unit = unit;
this.Destination = destination;
}
string GetVoiceSuffix()
{
var suffixes = new[] { ".r01", ".r03" };
return suffixes[Unit.traits.Get<Traits.Mobile>().Voice];
}
public override void Apply(bool doVoice)
{
if (doVoice && Game.LocalPlayer == Unit.Owner)
Game.PlaySound(Game.SovietVoices.First.GetNext() + GetVoiceSuffix(), false);
var mobile = Unit.traits.Get<Mobile>();
mobile.Cancel(Unit);
mobile.QueueActivity(new Mobile.MoveTo(Destination));
var attackBase = Unit.traits.WithInterface<AttackBase>().FirstOrDefault();
if (attackBase != null)
attackBase.target = null; /* move cancels attack order */
}
}
}

View File

@@ -74,6 +74,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Traits\Activities\DeployMcv.cs" />
<Compile Include="Actor.cs" /> <Compile Include="Actor.cs" />
<Compile Include="Bullet.cs" /> <Compile Include="Bullet.cs" />
<Compile Include="Controller.cs" /> <Compile Include="Controller.cs" />
@@ -97,7 +98,6 @@
<Compile Include="BuildingInfluenceMap.cs" /> <Compile Include="BuildingInfluenceMap.cs" />
<Compile Include="IOrderGenerator.cs" /> <Compile Include="IOrderGenerator.cs" />
<Compile Include="PlaceBuilding.cs" /> <Compile Include="PlaceBuilding.cs" />
<Compile Include="PlaceBuildingOrder.cs" />
<Compile Include="TechTree\Item.cs" /> <Compile Include="TechTree\Item.cs" />
<Compile Include="Network\Packet.cs" /> <Compile Include="Network\Packet.cs" />
<Compile Include="Player.cs" /> <Compile Include="Player.cs" />
@@ -108,7 +108,7 @@
<Compile Include="Network\Network.cs" /> <Compile Include="Network\Network.cs" />
<Compile Include="PathFinder.cs" /> <Compile Include="PathFinder.cs" />
<Compile Include="Graphics\Sequence.cs" /> <Compile Include="Graphics\Sequence.cs" />
<Compile Include="MoveOrder.cs" /> <Compile Include="Order.cs" />
<Compile Include="Graphics\Region.cs" /> <Compile Include="Graphics\Region.cs" />
<Compile Include="Graphics\SequenceProvider.cs" /> <Compile Include="Graphics\SequenceProvider.cs" />
<Compile Include="Graphics\SheetBuilder.cs" /> <Compile Include="Graphics\SheetBuilder.cs" />
@@ -143,6 +143,7 @@
<Compile Include="Traits\TraitsInterfaces.cs" /> <Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Tree.cs" /> <Compile Include="Traits\Tree.cs" />
<Compile Include="Traits\Turreted.cs" /> <Compile Include="Traits\Turreted.cs" />
<Compile Include="UnitOrders.cs" />
<Compile Include="Traits\Util.cs" /> <Compile Include="Traits\Util.cs" />
<Compile Include="UiOverlay.cs" /> <Compile Include="UiOverlay.cs" />
<Compile Include="Graphics\UnitSheetBuilder.cs" /> <Compile Include="Graphics\UnitSheetBuilder.cs" />

50
OpenRa.Game/Order.cs Normal file
View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
sealed class Order
{
public readonly Player Player;
public readonly string OrderString;
public readonly Actor Subject;
public readonly Actor TargetActor;
public readonly int2 TargetLocation;
public readonly string TargetString;
private Order( Player player, string orderString, Actor subject, Actor targetActor, int2 targetLocation, string targetString )
{
this.Player = player;
this.OrderString = orderString;
this.Subject = subject;
this.TargetActor = targetActor;
this.TargetLocation = targetLocation;
this.TargetString = targetString;
}
// TODO: serialize / deserialize
public static Order Attack( Actor subject, Actor target )
{
return new Order( subject.Owner, "Attack", subject, target, int2.Zero, null );
}
public static Order Move( Actor subject, int2 target )
{
return new Order( subject.Owner, "Move", subject, null, target, null );
}
public static Order DeployMcv( Actor subject )
{
return new Order( subject.Owner, "DeployMcv", subject, null, int2.Zero, null );
}
public static Order PlaceBuilding( Player subject, int2 target, string buildingName )
{
return new Order( subject, "PlaceBuilding", null, null, target, buildingName );
}
}
}

View File

@@ -33,7 +33,7 @@ namespace OpenRa.Game
t => Game.GetDistanceToBase( t, Owner ) < maxDistance ) ) t => Game.GetDistanceToBase( t, Owner ) < maxDistance ) )
yield break; yield break;
yield return new PlaceBuildingOrder( this, xy ); yield return OpenRa.Game.Order.PlaceBuilding( Owner, xy, Name );
} }
else // rmb else // rmb
{ {

View File

@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game
{
class PlaceBuildingOrder : Order
{
PlaceBuilding building;
int2 xy;
public PlaceBuildingOrder( PlaceBuilding building, int2 xy )
{
this.building = building;
this.xy = xy;
}
public override void Apply(bool doVoice)
{
Game.world.AddFrameEndTask( _ =>
{
Log.Write( "Player \"{0}\" builds {1}", building.Owner.PlayerName, building.Name );
//Adjust placement for cursor to be in middle
Game.world.Add( new Actor( building.Name, xy - GameRules.Footprint.AdjustForBuildingSize( building.Name ), building.Owner ) );
Game.controller.orderGenerator = null;
Game.worldRenderer.uiOverlay.KillOverlay();
} );
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits.Activities
{
class DeployMcv : Mobile.CurrentActivity
{
public Mobile.CurrentActivity NextActivity { get; set; }
public void Tick( Actor self, Mobile mobile )
{
Game.world.AddFrameEndTask( _ =>
{
Game.world.Remove( self );
Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) );
} );
}
public void Cancel( Actor self, Mobile mobile )
{
// Cancel can't happen between this being moved to the head of the list, and it being Ticked.
throw new InvalidOperationException( "DeployMcvAction: Cancel() should never occur." );
}
}
}

View File

@@ -56,7 +56,7 @@ namespace OpenRa.Game.Traits
if( underCursor.Owner == self.Owner ) return null; if( underCursor.Owner == self.Owner ) return null;
return new AttackOrder( self, underCursor ); return OpenRa.Game.Order.Attack( self, underCursor );
} }
} }
@@ -76,36 +76,4 @@ namespace OpenRa.Game.Traits
DoAttack( self ); DoAttack( self );
} }
} }
class AttackOrder : Order
{
public readonly Actor Attacker;
public readonly Actor Target;
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
public AttackOrder( Actor attacker, Actor target )
{
this.Attacker = attacker;
this.Target = target;
}
public override void Apply( bool doVoice )
{
var mobile = Attacker.traits.GetOrDefault<Mobile>();
if (mobile != null)
{
var weapon = Attacker.unitInfo.Primary ?? Attacker.unitInfo.Secondary;
/* todo: choose the appropriate weapon, when only one works against this target */
var range = Rules.WeaponInfo[weapon].Range;
mobile.Cancel(Attacker);
mobile.QueueActivity(
new Mobile.MoveTo(Target,
Math.Max(0, (int)range - RangeTolerance)));
}
Attacker.traits.Get<AttackTurreted>().target = Target;
}
}
} }

View File

@@ -17,48 +17,9 @@ namespace OpenRa.Game.Traits
// TODO: check that there's enough space at the destination. // TODO: check that there's enough space at the destination.
if( xy == self.Location ) if( xy == self.Location )
return new DeployMcvOrder( self, xy ); return OpenRa.Game.Order.DeployMcv( self );
return null; return null;
} }
} }
class DeployMcvOrder : Order
{
Actor Unit;
int2 Location;
public DeployMcvOrder( Actor unit, int2 location )
{
Unit = unit;
Location = location;
}
public override void Apply( bool doVoice )
{
var mobile = Unit.traits.Get<Mobile>();
mobile.QueueActivity( new Mobile.Turn( 96 ) );
mobile.QueueActivity( new DeployAction() );
}
class DeployAction : Mobile.CurrentActivity
{
public Mobile.CurrentActivity NextActivity { get; set; }
public void Tick( Actor self, Mobile mobile )
{
Game.world.AddFrameEndTask( _ =>
{
Game.world.Remove( self );
Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) );
} );
}
public void Cancel( Actor self, Mobile mobile )
{
// Cancel can't happen between this being moved to the head of the list, and it being Ticked.
throw new InvalidOperationException( "DeployMcvAction: Cancel() should never occur." );
}
}
}
} }

View File

@@ -55,8 +55,8 @@ namespace OpenRa.Game.Traits
if( underCursor != null ) if( underCursor != null )
return null; return null;
if (xy != toCell) if( xy != toCell )
return new MoveOrder(self, xy); return OpenRa.Game.Order.Move( self, xy );
return null; return null;
} }

73
OpenRa.Game/UnitOrders.cs Executable file
View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
static class UnitOrders
{
public static void ProcessOrder( Order order )
{
switch( order.OrderString )
{
case "Move":
{
var mobile = order.Subject.traits.Get<Mobile>();
mobile.Cancel( order.Subject );
mobile.QueueActivity( new Mobile.MoveTo( order.TargetLocation ) );
var attackBase = order.Subject.traits.WithInterface<AttackBase>().FirstOrDefault();
if( attackBase != null )
attackBase.target = null; /* move cancels attack order */
break;
}
case "Attack":
{
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
var mobile = order.Subject.traits.GetOrDefault<Mobile>();
var weapon = order.Subject.unitInfo.Primary ?? order.Subject.unitInfo.Secondary;
mobile.Cancel( order.Subject );
// TODO: this block should be a separate activity; "MoveNear", maybe?
{
/* todo: choose the appropriate weapon, when only one works against this target */
var range = Rules.WeaponInfo[ weapon ].Range;
mobile.QueueActivity(
new Mobile.MoveTo( order.TargetActor,
Math.Max( 0, (int)range - RangeTolerance ) ) );
}
order.Subject.traits.Get<AttackTurreted>().target = order.TargetActor;
break;
}
case "DeployMcv":
{
var mobile = order.Subject.traits.Get<Mobile>();
mobile.QueueActivity( new Mobile.Turn( 96 ) );
mobile.QueueActivity( new Traits.Activities.DeployMcv() );
break;
}
case "PlaceBuilding":
{
Game.world.AddFrameEndTask( _ =>
{
var building = Rules.UnitInfo[ order.TargetString ];
Log.Write( "Player \"{0}\" builds {1}", order.Player.PlayerName, building.Name );
//Adjust placement for cursor to be in middle
Game.world.Add( new Actor( building.Name, order.TargetLocation - GameRules.Footprint.AdjustForBuildingSize( building.Name ), order.Player ) );
Game.controller.orderGenerator = null;
Game.worldRenderer.uiOverlay.KillOverlay();
} );
break;
}
default:
throw new NotImplementedException();
}
}
}
}