diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index 0aa18fa011..33e2cbc10b 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -161,7 +161,7 @@
-
+
diff --git a/OpenRa.Game/Traits/Activities/Attack.cs b/OpenRa.Game/Traits/Activities/Attack.cs
index 908efe790e..5160223cb9 100644
--- a/OpenRa.Game/Traits/Activities/Attack.cs
+++ b/OpenRa.Game/Traits/Activities/Attack.cs
@@ -27,10 +27,12 @@ namespace OpenRa.Game.Traits.Activities
return new Move( Target, Range ) { NextActivity = this };
var desiredFacing = Util.GetFacing((Target.Location - self.Location).ToFloat2(), 0);
- var renderUnit = self.traits.WithInterface().First();
+ var renderUnit = self.traits.WithInterface().FirstOrDefault();
+ var numDirs = (renderUnit != null)
+ ? renderUnit.anim.CurrentSequence.Length : 8;
- if (Util.QuantizeFacing(unit.Facing, renderUnit.anim.CurrentSequence.Length)
- != Util.QuantizeFacing(desiredFacing, renderUnit.anim.CurrentSequence.Length))
+ if (Util.QuantizeFacing(unit.Facing, numDirs)
+ != Util.QuantizeFacing(desiredFacing, numDirs))
{
return new Turn( desiredFacing ) { NextActivity = this };
}
diff --git a/OpenRa.Game/Traits/AttackBase.cs b/OpenRa.Game/Traits/AttackBase.cs
index fe77cbaa3c..a90214711f 100644
--- a/OpenRa.Game/Traits/AttackBase.cs
+++ b/OpenRa.Game/Traits/AttackBase.cs
@@ -94,6 +94,9 @@ namespace OpenRa.Game.Traits
Game.world.Add(new Bullet(weaponName, self.Owner, self,
firePos, target.CenterLocation.ToInt2()));
+ foreach (var na in self.traits.WithInterface())
+ na.Attacking(self);
+
return true;
}
diff --git a/OpenRa.Game/Traits/InfantrySquad.cs b/OpenRa.Game/Traits/InfantrySquad.cs
deleted file mode 100644
index dfbe60ea9f..0000000000
--- a/OpenRa.Game/Traits/InfantrySquad.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OpenRa.Game.GameRules;
-using OpenRa.Game.Graphics;
-
-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 = (InfantryInfo)self.Info;
- for (int i = 0; i < ii.SquadSize; i++)
- elements.Add(new Soldier(self.Info.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], self);
- }
-
- public IEnumerable> Render(Actor self)
- {
- return elements.Select(
- e => Util.Centered(self, e.anim.Image, e.location))
- .OrderBy( a => a.b.Y ); /* important to y-order elements of a squad! */
- }
- }
-
- class Soldier
- {
- public Animation anim;
- public float2 location;
- string name;
- int facing = 128;
- float speed;
-
- string currentSequence;
-
- void PlaySequence(string seq, bool isFacing)
- {
- if (currentSequence == seq) return;
-
- if (isFacing)
- anim.PlayFacing(seq, () => facing );
- else
- anim.PlayRepeatingPreservingPosition(seq);
-
- currentSequence = seq;
- }
-
- public Soldier(string type, int2 initialLocation)
- {
- name = type;
- anim = new Animation(type);
- anim.PlayFacing("stand", () => facing);
- location = initialLocation;
- speed = ((InfantryInfo)Rules.UnitInfo[name]).Speed / 2;
- }
-
- public void Tick( int2 desiredLocation, Actor self )
- {
- anim.Tick();
- var d = (desiredLocation - location);
-
- facing = /*Util.GetFacing(d, facing); */ self.traits.Get().Facing;
-
- if (float2.WithinEpsilon(d, float2.Zero, .1f))
- PlaySequence("stand", true);
- else
- PlaySequence("run-" + Util.QuantizeFacing(facing, 8), false);
-
- if (d.Length <= speed)
- location = desiredLocation;
- else
- location += (speed / d.Length) * d;
- }
- }
-}
diff --git a/OpenRa.Game/Traits/RenderInfantry.cs b/OpenRa.Game/Traits/RenderInfantry.cs
new file mode 100644
index 0000000000..f11a27837f
--- /dev/null
+++ b/OpenRa.Game/Traits/RenderInfantry.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using OpenRa.Game.Graphics;
+
+namespace OpenRa.Game.Traits
+{
+ class RenderInfantry : RenderSimple, INotifyAttack
+ {
+ public RenderInfantry(Actor self)
+ : base(self)
+ {
+ anim.PlayFacing("stand",
+ () => self.traits.Get().Facing);
+ }
+
+ bool ChooseMoveAnim(Actor self)
+ {
+ if (!(self.GetCurrentActivity() is Activities.Move))
+ return false;
+
+ var mobile = self.traits.Get();
+ if (float2.WithinEpsilon(self.CenterLocation, Util.CenterOfCell(mobile.toCell), 2)) return false;
+ var dir = Util.QuantizeFacing(self.traits.Get().Facing, 8);
+
+ if (anim.CurrentSequence.Name.StartsWith("run-"))
+ anim.ReplaceAnim("run-" + dir);
+ else
+ anim.PlayRepeating("run-" + dir);
+
+ return true;
+ }
+
+ bool inAttack = false;
+
+ public void Attacking(Actor self)
+ {
+ var dir = Util.QuantizeFacing(self.traits.Get().Facing, 8);
+ inAttack = true;
+ anim.PlayThen("shoot-" + dir, () => inAttack = false);
+ }
+
+ public override void Tick(Actor self)
+ {
+ base.Tick(self);
+ if (inAttack) return;
+ if (ChooseMoveAnim(self)) return;
+
+ /* todo: idle anims, etc */
+
+ anim.PlayFacing("stand",
+ () => self.traits.Get().Facing);
+ }
+
+ public override IEnumerable> Render(Actor self)
+ {
+ yield return Util.Centered(self, anim.Image, self.CenterLocation);
+ }
+ }
+}
diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs
index 56094cd736..504578fefa 100644
--- a/OpenRa.Game/Traits/TraitsInterfaces.cs
+++ b/OpenRa.Game/Traits/TraitsInterfaces.cs
@@ -18,4 +18,5 @@ namespace OpenRa.Game.Traits
}
interface IProducer { bool Produce( Actor self, UnitInfo producee ); }
interface IOccupySpace { IEnumerable OccupiedCells(); }
+ interface INotifyAttack { void Attacking(Actor self); }
}
diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs
index df0cd9aef4..818688e05f 100755
--- a/OpenRa.Game/Traits/Util.cs
+++ b/OpenRa.Game/Traits/Util.cs
@@ -105,8 +105,9 @@ namespace OpenRa.Game.Traits
if( unit == null ) return int2.Zero; /* things that don't have a rotating base don't need the turrets repositioned */
var ru = self.traits.WithInterface().FirstOrDefault();
+ var numDirs = (ru != null) ? ru.anim.CurrentSequence.Length : 8;
var bodyFacing = unit.Facing;
- var quantizedFacing = QuantizeFacing(bodyFacing, ru.anim.CurrentSequence.Length) * (256 / ru.anim.CurrentSequence.Length);
+ var quantizedFacing = QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs);
return (RotateVectorByFacing(new float2(offset[0], offset[1]), quantizedFacing, .7f) + GetRecoil(self, recoil))
+ new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3));
diff --git a/sequences.xml b/sequences.xml
index 02ad1a71b3..c6e2edf7a9 100644
--- a/sequences.xml
+++ b/sequences.xml
@@ -407,6 +407,14 @@
+
+
+
+
+
+
+
+
diff --git a/units.ini b/units.ini
index 8b2b01bbe5..f0244bd4d2 100755
--- a/units.ini
+++ b/units.ini
@@ -463,13 +463,13 @@ BuiltAt=KENN
Voice=DogVoice
[E1]
Description=Rifle Infantry
-Traits=Unit, Mobile, InfantrySquad
+Traits=Unit, Mobile, RenderInfantry, AttackBase
SquadSize=3
[E2]
Description=Grenadier
[E3]
Description=Rocket Soldier
-Traits=Unit, Mobile, InfantrySquad
+Traits=Unit, Mobile, RenderInfantry, AttackBase
SquadSize=2
[E4]
Description=Flamethrower