diff --git a/OpenRa.Game/GameRules/UnitInfo.cs b/OpenRa.Game/GameRules/UnitInfo.cs
index 03d7cb66ef..420ca1811f 100755
--- a/OpenRa.Game/GameRules/UnitInfo.cs
+++ b/OpenRa.Game/GameRules/UnitInfo.cs
@@ -38,7 +38,7 @@ namespace OpenRa.Game.GameRules
public readonly string[] Prerequisite = { };
public readonly string Primary = null;
public readonly string Secondary = null;
- public readonly int ROT = 0;
+ public readonly int ROT = 255;
public readonly int Reload = 0;
public readonly bool SelfHealing = false;
public readonly bool Sensors = false; // no idea what this does
@@ -67,6 +67,7 @@ namespace OpenRa.Game.GameRules
public readonly bool FraidyCat = false;
public readonly bool Infiltrate = false;
public readonly bool IsCanine = false;
+ public readonly int SquadSize = 1;
public InfantryInfo(string name) : base(name) { }
}
diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index 850c205523..34349e70fc 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -129,6 +129,7 @@
+
diff --git a/OpenRa.Game/Traits/InfantrySquad.cs b/OpenRa.Game/Traits/InfantrySquad.cs
new file mode 100644
index 0000000000..6f04a50d9f
--- /dev/null
+++ b/OpenRa.Game/Traits/InfantrySquad.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using OpenRa.Game.Graphics;
+using IjwFramework.Types;
+using OpenRa.Game.GameRules;
+
+namespace OpenRa.Game.Traits
+{
+ class InfantrySquad : ITick, IRender
+ {
+ readonly List elements = new List();
+
+ readonly int2[][] elementOffsets = new []
+ {
+ new int2[] {},
+ new [] { new int2(0,0) },
+ new [] { new int2(-5,-5), new int2(5,5) },
+ new [] { new int2(-6,5), new int2(0, -5), new int2(6,4) }, /* todo: move squad arrangements ! */
+ };
+
+ public InfantrySquad(Actor self)
+ {
+ var ii = (UnitInfo.InfantryInfo)self.unitInfo;
+ for (int i = 0; i < ii.SquadSize; i++)
+ elements.Add(new Soldier(self.unitInfo.Name,
+ self.CenterLocation.ToInt2() + elementOffsets[ii.SquadSize][i]));
+ }
+
+ public void Tick(Actor self)
+ {
+ for (int i = 0; i < elements.Count; i++)
+ elements[i].Tick(
+ self.CenterLocation.ToInt2() + elementOffsets[elements.Count][i]);
+ }
+
+ public IEnumerable> Render(Actor self)
+ {
+ return elements.Select(
+ e => Util.Centered(e.anim.Image, e.location))
+ .OrderBy( a => a.Second.Y ); /* important to y-order elements of a squad! */
+ }
+ }
+
+ class Soldier
+ {
+ public Animation anim;
+ public float2 location;
+ string name;
+ int facing = 128;
+
+ string currentSequence;
+
+ void PlaySequence(string seq, bool isFacing)
+ {
+ if (currentSequence == seq) return;
+ currentSequence = seq;
+
+ if (isFacing)
+ anim.PlayFetchIndex(seq, () => facing / (256 / anim.CurrentSequence.Length));
+ else
+ anim.PlayRepeating(seq);
+ }
+
+ public Soldier(string type, int2 initialLocation)
+ {
+ name = type;
+ anim = new Animation(type);
+ anim.PlayFetchIndex("stand",
+ () => facing / (256 / anim.CurrentSequence.Length) );
+ location = initialLocation;
+ }
+
+ public void Tick( int2 desiredLocation )
+ {
+ anim.Tick();
+ var d = (desiredLocation - location);
+ var speed = ((UnitInfo.InfantryInfo)Rules.UnitInfo[name]).Speed / 2;
+
+ facing = Util.GetFacing(d, facing);
+
+ if (float2.WithinEpsilon(d, float2.Zero, .1f))
+ PlaySequence("stand", true);
+ else
+ PlaySequence("run-" + (facing / 32), false);
+
+ if (d.Length > speed)
+ d = (d.Length / speed) * d;
+
+ location += d;
+ }
+ }
+}
diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs
index 900c614191..fa15ebcf74 100644
--- a/OpenRa.Game/Traits/Mobile.cs
+++ b/OpenRa.Game/Traits/Mobile.cs
@@ -74,7 +74,7 @@ namespace OpenRa.Game.Traits
public UnitMovementType GetMovementType()
{
- var vi = self.unitInfo as UnitInfo.VehicleInfo;
+ var vi = self.unitInfo as UnitInfo.VehicleInfo;
if (vi == null) return UnitMovementType.Foot;
if (vi.WaterBound) return UnitMovementType.Float;
return vi.Tracked ? UnitMovementType.Track : UnitMovementType.Wheel;
diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs
index 43f3430aae..a20cb6d793 100644
--- a/OpenRa.Game/Traits/RenderUnit.cs
+++ b/OpenRa.Game/Traits/RenderUnit.cs
@@ -17,15 +17,9 @@ namespace OpenRa.Game.Traits
/ (256/anim.CurrentSequence.Length));
}
- protected static Pair Centered(Sprite s, float2 location)
- {
- var loc = location - 0.5f * s.size;
- return Pair.New(s, loc.Round());
- }
-
public override IEnumerable> Render(Actor self)
{
- yield return Centered( anim.Image, self.CenterLocation );
+ yield return Util.Centered(anim.Image, self.CenterLocation);
}
}
}
diff --git a/OpenRa.Game/Traits/RenderUnitTurreted.cs b/OpenRa.Game/Traits/RenderUnitTurreted.cs
index fea38cb4d5..88691f5ad7 100644
--- a/OpenRa.Game/Traits/RenderUnitTurreted.cs
+++ b/OpenRa.Game/Traits/RenderUnitTurreted.cs
@@ -23,11 +23,11 @@ namespace OpenRa.Game.Traits
{
var mobile = self.traits.Get();
- yield return Centered(anim.Image, self.CenterLocation);
- yield return Centered(turretAnim.Image, self.CenterLocation
+ yield return Util.Centered(anim.Image, self.CenterLocation);
+ yield return Util.Centered(turretAnim.Image, self.CenterLocation
+ Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, primaryRecoil));
if (self.unitInfo.SecondaryOffset != null)
- yield return Centered(turretAnim.Image, self.CenterLocation
+ yield return Util.Centered(turretAnim.Image, self.CenterLocation
+ Util.GetTurretPosition(self, self.unitInfo.SecondaryOffset, secondaryRecoil));
}
diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs
index 34fe637be9..dca26daaa9 100755
--- a/OpenRa.Game/Traits/Util.cs
+++ b/OpenRa.Game/Traits/Util.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using IjwFramework.Types;
+using OpenRa.Game.Graphics;
namespace OpenRa.Game.Traits
{
@@ -88,5 +90,11 @@ namespace OpenRa.Game.Traits
return (RotateVectorByFacing(new float2(offset[0], offset[1]), quantizedFacing, .7f) + GetRecoil(self, recoil));
}
+ public static Pair Centered(Sprite s, float2 location)
+ {
+ var loc = location - 0.5f * s.size;
+ return Pair.New(s, loc.Round());
+ }
+
}
}
diff --git a/units.ini b/units.ini
index 6033e558f0..117c9a1450 100755
--- a/units.ini
+++ b/units.ini
@@ -372,14 +372,19 @@ Description=Attack Dog
BuiltAt=KENN
[E1]
Description=Rifle Infantry
+Traits=InfantrySquad,Mobile
+SquadSize=3
[E2]
Description=Grenadier
[E3]
Description=Rocket Soldier
+Traits=InfantrySquad,Mobile
+SquadSize=2
[E4]
Description=Flamethrower
[E6]
Description=Engineer
+Traits=InfantrySquad,Mobile
[SPY]
Description=Spy
[THF]