diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index ca7f54665d..ec35cb5415 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -154,332 +154,4 @@ namespace OpenRa.Game } } } - - namespace Traits - { - interface ITick - { - void Tick( Actor self, Game game, int dt ); - } - - interface IRender - { - IEnumerable> Render( Actor self ); - } - - interface IOrder - { - Order Order( Actor self, Game game, int2 xy ); - } - - abstract class RenderSimple : IRender, ITick - { - public Animation anim; - - public RenderSimple( Actor self ) - { - anim = new Animation( self.unitInfo.Image ?? self.unitInfo.Name ); - } - - public abstract IEnumerable> Render( Actor self ); - - public virtual void Tick( Actor self, Game game, int dt ) - { - anim.Tick( dt ); - } - } - - class RenderBuilding : RenderSimple - { - public RenderBuilding( Actor self ) - : base( self ) - { - anim.PlayThen( "make", () => anim.PlayRepeating( "idle" ) ); - } - - public override IEnumerable> Render( Actor self ) - { - yield return Pair.New( anim.Image, 24f * (float2)self.Location ); - } - } - - class RenderBuildingTurreted : RenderBuilding - { - public RenderBuildingTurreted( Actor self ) - : base( self ) - { - anim.PlayThen( "make", () => anim.PlayFetchIndex( "idle", () => self.traits.Get().turretFacing ) ); - } - } - - class RenderBuildingOre : RenderBuilding - { - public RenderBuildingOre(Actor self) - : base(self) - { - anim.PlayThen("make", () => anim.PlayFetchIndex("idle", () => (int)(5 * self.Owner.GetSiloFullness()))); - } - } - - class RenderWarFactory : RenderBuilding - { - public Animation roof; - bool doneBuilding; - - public RenderWarFactory( Actor self ) - : base( self ) - { - roof = new Animation( self.unitInfo.Image ?? self.unitInfo.Name ); - anim.PlayThen( "make", () => - { - doneBuilding = true; - anim.Play( "idle" ); - roof.Play( "idle-top" ); - } ); - } - - public override IEnumerable> Render( Actor self ) - { - yield return Pair.New( anim.Image, 24f * (float2)self.Location ); - if( doneBuilding ) - yield return Pair.New( roof.Image, 24f * (float2)self.Location ); - } - - public override void Tick( Actor self, Game game, int dt ) - { - base.Tick( self, game, dt ); - roof.Tick( dt ); - } - } - - class RenderUnit : RenderSimple - { - public RenderUnit( Actor self ) - : base( self ) - { - anim.PlayFetchIndex( "idle", () => self.traits.Get().facing ); - } - - 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 ) - { - var mobile = self.traits.Get(); - float fraction = ( mobile.moveFraction > 0 ) ? (float)mobile.moveFraction / mobile.moveFractionTotal : 0f; - var centerLocation = new float2( 12, 12 ) + 24 * float2.Lerp( mobile.fromCell, mobile.toCell, fraction ); - yield return Centered( anim.Image, centerLocation ); - } - } - - class RenderUnitTurreted : RenderUnit - { - public Animation turretAnim; - - public RenderUnitTurreted( Actor self ) - : base( self ) - { - turretAnim = new Animation( self.unitInfo.Name ); - turretAnim.PlayFetchIndex( "turret", () => self.traits.Get().turretFacing ); - } - - public override IEnumerable> Render( Actor self ) - { - var mobile = self.traits.Get(); - yield return Centered( anim.Image, self.CenterLocation ); - yield return Centered( turretAnim.Image, self.CenterLocation ); - } - - public override void Tick( Actor self, Game game, int dt ) - { - base.Tick( self, game, dt ); - turretAnim.Tick( dt ); - } - } - - class Mobile : ITick, IOrder - { - public Actor self; - - public int2 fromCell, destination; - public int2 toCell { get { return self.Location; } } - public int moveFraction, moveFractionTotal; - public int facing; - - public Mobile( Actor self ) - { - this.self = self; - fromCell = destination = self.Location; - } - - public bool Turn( int desiredFacing ) - { - if( facing == desiredFacing ) - return false; - - int df = ( desiredFacing - facing + 32 ) % 32; - facing = ( facing + ( df > 16 ? 31 : 1 ) ) % 32; - return true; - } - - static float2[] fvecs = Util.MakeArray( 32, - i => -float2.FromAngle( i / 16.0f * (float)Math.PI ) * new float2( 1f, 1.3f ) ); - - int GetFacing( float2 d ) - { - if( float2.WithinEpsilon( d, float2.Zero, 0.001f ) ) - return facing; - - int highest = -1; - float highestDot = -1.0f; - - for( int i = 0 ; i < fvecs.Length ; i++ ) - { - float dot = float2.Dot( fvecs[ i ], d ); - if( dot > highestDot ) - { - highestDot = dot; - highest = i; - } - } - - return highest; - } - - void UpdateCenterLocation() - { - float fraction = ( moveFraction > 0 ) ? (float)moveFraction / moveFractionTotal : 0f; - self.CenterLocation = new float2( 12, 12 ) + 24 * float2.Lerp( fromCell, toCell, fraction ); - } - - public void Tick( Actor self, Game game, int dt ) - { - Move( self, game, dt ); - UpdateCenterLocation(); - } - - void Move( Actor self, Game game, int dt ) - { - if( fromCell != toCell ) - { - if( Turn( GetFacing( toCell - fromCell ) ) ) - return; - - moveFraction += dt * ( (UnitInfo.MobileInfo)self.unitInfo ).Speed; - } - if( moveFraction < moveFractionTotal ) - return; - - moveFraction = 0; - moveFractionTotal = 0; - fromCell = toCell; - - if( destination == toCell ) - return; - - List res = game.pathFinder.FindUnitPath( toCell, PathFinder.DefaultEstimator( destination ) ); - if( res.Count != 0 ) - { - self.Location = res[ res.Count - 1 ]; - - int2 dir = toCell - fromCell; - moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 2500 : 2000; - } - else - destination = toCell; - } - - public Order Order( Actor self, Game game, int2 xy ) - { - if( xy != toCell ) - return new MoveOrder( self, xy ); - return null; - } - } - - class McvDeploy : IOrder, ITick - { - public bool Deploying; - - public McvDeploy( Actor self ) - { - } - - public Order Order( Actor self, Game game, int2 xy ) - { - // TODO: check that there's enough space at the destination. - if( xy == self.Location ) - return new DeployMcvOrder( self ); - - return null; - } - - public void Tick( Actor self, Game game, int dt ) - { - if( !Deploying ) - return; - - if( self.traits.Get().Turn( 12 ) ) - return; - - game.world.AddFrameEndTask( _ => - { - game.world.Remove( self ); - game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) ); - } ); - } - } - - class Turreted - : ITick // temporary. - { - public int turretFacing = 24; - - public Turreted( Actor self ) - { - } - - // temporary. - public void Tick( Actor self, Game game, int dt ) - { - turretFacing = ( turretFacing + 1 ) % 32; - } - } - - class Building : ITick - { - public Building( Actor self ) - { - } - - bool first = true; - public void Tick( Actor self, Game game, int dt ) - { - if( first && self.Owner == game.LocalPlayer ) - { - self.Owner.TechTree.Build( self.unitInfo.Name, true ); - self.CenterLocation = 24 * (float2)self.Location + 0.5f * self.SelectedSize; - } - first = false; - } - } - - class Tree : IRender - { - Sprite Image; - - public Tree( Sprite treeImage ) - { - Image = treeImage; - } - - public IEnumerable> Render( Actor self ) - { - yield return Pair.New( Image, 24 * (float2)self.Location ); - } - } - } } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index dd105181d4..82f0380c62 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -116,6 +116,19 @@ + + + + + + + + + + + + + diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs new file mode 100644 index 0000000000..3144c90fcd --- /dev/null +++ b/OpenRa.Game/Traits/Building.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class Building : ITick + { + public Building(Actor self) + { + } + + bool first = true; + public void Tick(Actor self, Game game, int dt) + { + if (first && self.Owner == game.LocalPlayer) + { + self.Owner.TechTree.Build(self.unitInfo.Name, true); + self.CenterLocation = 24 * (float2)self.Location + 0.5f * self.SelectedSize; + } + first = false; + } + } +} diff --git a/OpenRa.Game/Traits/McvDeploy.cs b/OpenRa.Game/Traits/McvDeploy.cs new file mode 100644 index 0000000000..b4bee7fffb --- /dev/null +++ b/OpenRa.Game/Traits/McvDeploy.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class McvDeploy : IOrder, ITick + { + public bool Deploying; + + public McvDeploy(Actor self) + { + } + + public Order Order(Actor self, Game game, int2 xy) + { + // TODO: check that there's enough space at the destination. + if (xy == self.Location) + return new DeployMcvOrder(self); + + return null; + } + + public void Tick(Actor self, Game game, int dt) + { + if (!Deploying) + return; + + if (self.traits.Get().Turn(12)) + return; + + game.world.AddFrameEndTask(_ => + { + game.world.Remove(self); + game.world.Add(new Actor("fact", self.Location - new int2(1, 1), self.Owner)); + }); + } + } +} diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs new file mode 100644 index 0000000000..0eb62d2d3b --- /dev/null +++ b/OpenRa.Game/Traits/Mobile.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.GameRules; +using OpenRa.Game.Graphics; + +namespace OpenRa.Game.Traits +{ + class Mobile : ITick, IOrder + { + public Actor self; + + public int2 fromCell, destination; + public int2 toCell { get { return self.Location; } } + public int moveFraction, moveFractionTotal; + public int facing; + + public Mobile(Actor self) + { + this.self = self; + fromCell = destination = self.Location; + } + + public bool Turn(int desiredFacing) + { + if (facing == desiredFacing) + return false; + + int df = (desiredFacing - facing + 32) % 32; + facing = (facing + (df > 16 ? 31 : 1)) % 32; + return true; + } + + static float2[] fvecs = Util.MakeArray(32, + i => -float2.FromAngle(i / 16.0f * (float)Math.PI) * new float2(1f, 1.3f)); + + int GetFacing(float2 d) + { + if (float2.WithinEpsilon(d, float2.Zero, 0.001f)) + return facing; + + int highest = -1; + float highestDot = -1.0f; + + for (int i = 0; i < fvecs.Length; i++) + { + float dot = float2.Dot(fvecs[i], d); + if (dot > highestDot) + { + highestDot = dot; + highest = i; + } + } + + return highest; + } + + void UpdateCenterLocation() + { + float fraction = (moveFraction > 0) ? (float)moveFraction / moveFractionTotal : 0f; + self.CenterLocation = new float2(12, 12) + 24 * float2.Lerp(fromCell, toCell, fraction); + } + + public void Tick(Actor self, Game game, int dt) + { + Move(self, game, dt); + UpdateCenterLocation(); + } + + void Move(Actor self, Game game, int dt) + { + if (fromCell != toCell) + { + if (Turn(GetFacing(toCell - fromCell))) + return; + + moveFraction += dt * ((UnitInfo.MobileInfo)self.unitInfo).Speed; + } + if (moveFraction < moveFractionTotal) + return; + + moveFraction = 0; + moveFractionTotal = 0; + fromCell = toCell; + + if (destination == toCell) + return; + + List res = game.pathFinder.FindUnitPath(toCell, PathFinder.DefaultEstimator(destination)); + if (res.Count != 0) + { + self.Location = res[res.Count - 1]; + + int2 dir = toCell - fromCell; + moveFractionTotal = (dir.X != 0 && dir.Y != 0) ? 2500 : 2000; + } + else + destination = toCell; + } + + public Order Order(Actor self, Game game, int2 xy) + { + if (xy != toCell) + return new MoveOrder(self, xy); + return null; + } + } +} diff --git a/OpenRa.Game/Traits/RenderBuilding.cs b/OpenRa.Game/Traits/RenderBuilding.cs new file mode 100644 index 0000000000..4abb5877f4 --- /dev/null +++ b/OpenRa.Game/Traits/RenderBuilding.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using IjwFramework.Types; +using OpenRa.Game.Graphics; + +namespace OpenRa.Game.Traits +{ + class RenderBuilding : RenderSimple + { + public RenderBuilding(Actor self) + : base(self) + { + anim.PlayThen("make", () => anim.PlayRepeating("idle")); + } + + public override IEnumerable> Render(Actor self) + { + yield return Pair.New(anim.Image, 24f * (float2)self.Location); + } + } +} diff --git a/OpenRa.Game/Traits/RenderBuildingOre.cs b/OpenRa.Game/Traits/RenderBuildingOre.cs new file mode 100644 index 0000000000..4c93fffca4 --- /dev/null +++ b/OpenRa.Game/Traits/RenderBuildingOre.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class RenderBuildingOre : RenderBuilding + { + public RenderBuildingOre(Actor self) + : base(self) + { + anim.PlayThen("make", () => anim.PlayFetchIndex("idle", + () => (int)(5 * self.Owner.GetSiloFullness()))); + } + } +} diff --git a/OpenRa.Game/Traits/RenderBuildingTurreted.cs b/OpenRa.Game/Traits/RenderBuildingTurreted.cs new file mode 100644 index 0000000000..77a01e4095 --- /dev/null +++ b/OpenRa.Game/Traits/RenderBuildingTurreted.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class RenderBuildingTurreted : RenderBuilding + { + public RenderBuildingTurreted(Actor self) + : base(self) + { + anim.PlayThen("make", () => anim.PlayFetchIndex("idle", + () => self.traits.Get().turretFacing)); + } + } +} diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs new file mode 100644 index 0000000000..eeb57f16e7 --- /dev/null +++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + class RenderWarFactory : RenderBuilding + { + public Animation roof; + bool doneBuilding; + + public RenderWarFactory(Actor self) + : base(self) + { + roof = new Animation(self.unitInfo.Image ?? self.unitInfo.Name); + anim.PlayThen("make", () => + { + doneBuilding = true; + anim.Play("idle"); + roof.Play("idle-top"); + }); + } + + public override IEnumerable> Render(Actor self) + { + yield return Pair.New(anim.Image, 24f * (float2)self.Location); + if (doneBuilding) + yield return Pair.New(roof.Image, 24f * (float2)self.Location); + } + + public override void Tick(Actor self, Game game, int dt) + { + base.Tick(self, game, dt); + roof.Tick(dt); + } + } +} diff --git a/OpenRa.Game/Traits/RenderSimple.cs b/OpenRa.Game/Traits/RenderSimple.cs new file mode 100644 index 0000000000..1dcfaac17d --- /dev/null +++ b/OpenRa.Game/Traits/RenderSimple.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + abstract class RenderSimple : IRender, ITick + { + public Animation anim; + + public RenderSimple(Actor self) + { + anim = new Animation(self.unitInfo.Image ?? self.unitInfo.Name); + } + + public abstract IEnumerable> Render(Actor self); + + public virtual void Tick(Actor self, Game game, int dt) + { + anim.Tick(dt); + } + } +} diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs new file mode 100644 index 0000000000..20853e2569 --- /dev/null +++ b/OpenRa.Game/Traits/RenderUnit.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + class RenderUnit : RenderSimple + { + public RenderUnit(Actor self) + : base(self) + { + anim.PlayFetchIndex("idle", () => self.traits.Get().facing); + } + + 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) + { + var mobile = self.traits.Get(); + float fraction = (mobile.moveFraction > 0) ? (float)mobile.moveFraction / mobile.moveFractionTotal : 0f; + var centerLocation = new float2(12, 12) + 24 * float2.Lerp(mobile.fromCell, mobile.toCell, fraction); + yield return Centered(anim.Image, centerLocation); + } + } +} diff --git a/OpenRa.Game/Traits/RenderUnitTurreted.cs b/OpenRa.Game/Traits/RenderUnitTurreted.cs new file mode 100644 index 0000000000..303467eae1 --- /dev/null +++ b/OpenRa.Game/Traits/RenderUnitTurreted.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + class RenderUnitTurreted : RenderUnit + { + public Animation turretAnim; + + public RenderUnitTurreted(Actor self) + : base(self) + { + turretAnim = new Animation(self.unitInfo.Name); + turretAnim.PlayFetchIndex("turret", () => self.traits.Get().turretFacing); + } + + public override IEnumerable> Render(Actor self) + { + var mobile = self.traits.Get(); + yield return Centered(anim.Image, self.CenterLocation); + yield return Centered(turretAnim.Image, self.CenterLocation); + } + + public override void Tick(Actor self, Game game, int dt) + { + base.Tick(self, game, dt); + turretAnim.Tick(dt); + } + } +} diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs new file mode 100644 index 0000000000..5d645a1dd7 --- /dev/null +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + interface ITick { void Tick(Actor self, Game game, int dt); } + interface IRender { IEnumerable> Render(Actor self); } + interface IOrder { Order Order(Actor self, Game game, int2 xy); } +} diff --git a/OpenRa.Game/Traits/Tree.cs b/OpenRa.Game/Traits/Tree.cs new file mode 100644 index 0000000000..103e40123d --- /dev/null +++ b/OpenRa.Game/Traits/Tree.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Graphics; +using IjwFramework.Types; + +namespace OpenRa.Game.Traits +{ + class Tree : IRender + { + Sprite Image; + + public Tree(Sprite treeImage) + { + Image = treeImage; + } + + public IEnumerable> Render(Actor self) + { + yield return Pair.New(Image, 24 * (float2)self.Location); + } + } +} diff --git a/OpenRa.Game/Traits/Turreted.cs b/OpenRa.Game/Traits/Turreted.cs new file mode 100644 index 0000000000..33c1d346d6 --- /dev/null +++ b/OpenRa.Game/Traits/Turreted.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class Turreted : ITick // temporary. + { + public int turretFacing = 24; + + public Turreted(Actor self) + { + } + + // temporary. + public void Tick(Actor self, Game game, int dt) + { + turretFacing = (turretFacing + 1) % 32; + } + } +}