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