diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 6d68a330ce..f56b68c832 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -17,7 +17,7 @@ namespace OpenRa.Game public readonly UnitInfo unitInfo; public int2 Location; - public Player Owner; + public Player Owner; public int Health; public Actor( string name, int2 location, Player owner ) @@ -25,21 +25,21 @@ namespace OpenRa.Game unitInfo = Rules.UnitInfo[ name ]; Location = location; CenterLocation = new float2( 12, 12 ) + Game.CellSize * (float2)Location; - Owner = owner; - Health = unitInfo.Strength; /* todo: handle cases where this is not true! */ - - if( unitInfo.Traits != null ) - { - foreach( var traitName in unitInfo.Traits ) - { - var type = typeof( Traits.Mobile ).Assembly.GetType( typeof( Traits.Mobile ).Namespace + "." + traitName, true, false ); - var ctor = type.GetConstructor( new[] { typeof( Actor ) } ); - traits.Add( type, ctor.Invoke( new object[] { this } ) ); - } - } - else - throw new InvalidOperationException( "No Actor traits for " + unitInfo.Name - + "; add Traits= to units.ini for appropriate unit" ); + Owner = owner; + Health = unitInfo.Strength; /* todo: handle cases where this is not true! */ + + if( unitInfo.Traits != null ) + { + foreach( var traitName in unitInfo.Traits ) + { + var type = typeof( Traits.Mobile ).Assembly.GetType( typeof( Traits.Mobile ).Namespace + "." + traitName, true, false ); + var ctor = type.GetConstructor( new[] { typeof( Actor ) } ); + traits.Add( type, ctor.Invoke( new object[] { this } ) ); + } + } + else + throw new InvalidOperationException( "No Actor traits for " + unitInfo.Name + + "; add Traits= to units.ini for appropriate unit" ); } public Actor( TreeReference tree, TreeCache treeRenderer, int2 mapOffset ) @@ -49,8 +49,8 @@ namespace OpenRa.Game } public void Tick() - { - foreach (var tick in traits.WithInterface()) + { + foreach (var tick in traits.WithInterface()) tick.Tick(this); } @@ -63,8 +63,8 @@ namespace OpenRa.Game } public Order Order( int2 xy ) - { - if (Owner != Game.LocalPlayer) + { + if (Owner != Game.LocalPlayer) return null; return traits.WithInterface() @@ -80,32 +80,32 @@ namespace OpenRa.Game var loc = CenterLocation - 0.5f * size; return new RectangleF(loc.X, loc.Y, size.X, size.Y); } - } - - public bool IsDead { get { return Health <= 0; } } - - public void InflictDamage(Actor attacker, Bullet inflictor, int damage) - { - /* todo: auto-retaliate, etc */ - /* todo: death sequence for infantry based on inflictor */ - /* todo: start smoking if < conditionYellow and took damage, and not already smoking */ - - if (Health <= 0) return; /* overkill! don't count extra hits as more kills! */ - - Health -= damage; - if (Health <= 0) - { - Health = 0; - if (attacker.Owner != null) - attacker.Owner.Kills++; - - Game.world.AddFrameEndTask(w => w.Remove(this)); - - if (Owner == Game.LocalPlayer) - Game.PlaySound("unitlst1.aud", false); - - /* todo: explosion */ - } + } + + public bool IsDead { get { return Health <= 0; } } + + public void InflictDamage(Actor attacker, Bullet inflictor, int damage) + { + /* todo: auto-retaliate, etc */ + /* todo: death sequence for infantry based on inflictor */ + /* todo: start smoking if < conditionYellow and took damage, and not already smoking */ + + if (Health <= 0) return; /* overkill! don't count extra hits as more kills! */ + + Health -= damage; + if (Health <= 0) + { + Health = 0; + if (attacker.Owner != null) + attacker.Owner.Kills++; + + Game.world.AddFrameEndTask(w => w.Remove(this)); + + if (Owner == Game.LocalPlayer) + Game.PlaySound("unitlst1.aud", false); + + /* todo: explosion */ + } } } } diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index 3687128503..67dc19ece7 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -87,7 +87,8 @@ namespace OpenRa.Game.Traits List path; int moveFraction, moveFractionTotal; - float2 from, to; + float2 from, to; + int fromFacing, toFacing; Action OnComplete; @@ -129,28 +130,41 @@ namespace OpenRa.Game.Traits path.RemoveAt( path.Count - 1 ); moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 35 : 25; from = CenterOfCell( mobile.fromCell ); - to = BetweenCells( mobile.fromCell, mobile.toCell ); + to = BetweenCells( mobile.fromCell, mobile.toCell ); + CalculateMoveFraction(); + fromFacing = mobile.facing; + toFacing = mobile.facing; OnComplete = OnCompleteFirstHalf; } mobile.currentAction.Tick( self, mobile ); - } + } void TickMove( Actor self, Mobile mobile ) { moveFraction += ( self.unitInfo as UnitInfo.MobileInfo ).Speed; - UpdateCenterLocation( self, (float)moveFraction / moveFractionTotal, from, to ); + UpdateCenterLocation( self, mobile, (float)moveFraction / moveFractionTotal ); if( moveFraction >= moveFractionTotal ) { moveFraction -= moveFractionTotal; OnComplete( self, mobile ); - mobile.fromCell = mobile.toCell; + //mobile.fromCell = mobile.toCell; } return; - } - - static void UpdateCenterLocation( Actor self, float frac, float2 from, float2 to ) - { - self.CenterLocation = float2.Lerp( from, to, frac ); + } + + void UpdateCenterLocation( Actor self, Mobile mobile, float frac ) + { + self.CenterLocation = float2.Lerp( from, to, frac ); + if( moveFraction >= moveFractionTotal ) + mobile.facing = toFacing; + else + mobile.facing = ( fromFacing + ( toFacing - fromFacing ) * moveFraction / moveFractionTotal ) & 0xFF; + } + + void CalculateMoveFraction() + { + var d = to - from; + moveFractionTotal = (int)Math.Sqrt( d.X * d.X + d.Y * d.Y ) * (25 / 6); } static float2 CenterOfCell( int2 loc ) @@ -164,17 +178,38 @@ namespace OpenRa.Game.Traits } void OnCompleteFirstHalf( Actor self, Mobile mobile ) - { - from = BetweenCells( mobile.fromCell, mobile.toCell ); - to = CenterOfCell( mobile.toCell ); - OnComplete = OnCompleteSecondHalf; + { + if( path.Count > 0 ) + { + var nextCell = path[ path.Count - 1 ]; + if( ( nextCell - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) ) + { + path.RemoveAt( path.Count - 1 ); + from = BetweenCells( mobile.fromCell, mobile.toCell ); + to = BetweenCells( mobile.toCell, nextCell ); + CalculateMoveFraction(); + mobile.fromCell = mobile.toCell; + mobile.toCell = nextCell; + fromFacing = mobile.facing; + toFacing = Util.GetNearestFacing( fromFacing, Util.GetFacing( mobile.toCell-mobile.fromCell, fromFacing ) ); + OnComplete = OnCompleteFirstHalf; + return; + } + } + from = BetweenCells( mobile.fromCell, mobile.toCell ); + to = CenterOfCell( mobile.toCell ); + CalculateMoveFraction(); + fromFacing = toFacing = mobile.facing; + OnComplete = OnCompleteSecondHalf; + mobile.fromCell = mobile.toCell; } void OnCompleteSecondHalf( Actor self, Mobile mobile ) - { + { moveFractionTotal = 0; self.CenterLocation = CenterOfCell( mobile.toCell ); - OnComplete = null; + OnComplete = null; + mobile.fromCell = mobile.toCell; } } } diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs index 9676226e4f..40303f559b 100755 --- a/OpenRa.Game/Traits/Util.cs +++ b/OpenRa.Game/Traits/Util.cs @@ -43,5 +43,15 @@ namespace OpenRa.Game.Traits return highest * 8; } + public static int GetNearestFacing( int facing, int desiredFacing ) + { + var turn = desiredFacing - facing; + if( turn > 128 ) + turn -= 256; + if( turn < -128 ) + turn += 256; + + return facing + turn; + } } }