diff --git a/OpenRa.DataStructures/Tuple.cs b/OpenRa.DataStructures/Tuple.cs
index ebd08dedf8..f5260fcfbb 100644
--- a/OpenRa.DataStructures/Tuple.cs
+++ b/OpenRa.DataStructures/Tuple.cs
@@ -37,4 +37,12 @@ namespace OpenRa
public Tuple(A a, B b, C c, D d) { this.a = a; this.b = b; this.c = c; this.d = d; }
}
+
+ public static class Tuple
+ {
+ public static Tuple New(A a, B b, C c)
+ {
+ return new Tuple(a, b, c);
+ }
+ }
}
diff --git a/OpenRa.FileFormats/PaletteRemap.cs b/OpenRa.FileFormats/PaletteRemap.cs
index f4d3b57c41..92fda46b50 100644
--- a/OpenRa.FileFormats/PaletteRemap.cs
+++ b/OpenRa.FileFormats/PaletteRemap.cs
@@ -8,7 +8,9 @@ namespace OpenRa.FileFormats
{
public class PaletteRemap
{
+ int offset;
List remapColors = new List();
+ Color shadowColor;
public PaletteRemap(Stream s)
{
@@ -23,14 +25,26 @@ namespace OpenRa.FileFormats
remapColors.Add(Color.FromArgb(r, g, b));
}
}
+
+ offset = 80;
+ }
+
+ public PaletteRemap( Color shadowColor )
+ {
+ this.shadowColor = shadowColor;
}
public Color GetRemappedColor(Color original, int index)
{
- if (index < 80 || index >= 96)
- return original;
+ if (remapColors.Count > 0)
+ {
+ if (index < offset || index >= offset + remapColors.Count)
+ return original;
- return remapColors[index - 80];
+ return remapColors[index - offset];
+ }
+
+ return original.A > 0 ? shadowColor : original;
}
}
}
diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs
index 76085ea89b..e5cbbeec93 100755
--- a/OpenRa.Game/Actor.cs
+++ b/OpenRa.Game/Actor.cs
@@ -59,9 +59,9 @@ namespace OpenRa.Game
}
public float2 CenterLocation;
- public float2 SelectedSize { get { return Render().First().First.size; } }
+ public float2 SelectedSize { get { return Render().First().a.size; } }
- public IEnumerable> Render()
+ public IEnumerable> Render()
{
return traits.WithInterface().SelectMany( x => x.Render( this ) );
}
diff --git a/OpenRa.Game/Bullet.cs b/OpenRa.Game/Bullet.cs
index 6c3e05d445..38d15a4c78 100644
--- a/OpenRa.Game/Bullet.cs
+++ b/OpenRa.Game/Bullet.cs
@@ -11,7 +11,7 @@ namespace OpenRa.Game
interface IEffect
{
void Tick();
- IEnumerable> Render();
+ IEnumerable> Render();
Player Owner { get; }
}
@@ -94,16 +94,32 @@ namespace OpenRa.Game
foreach (var victim in hitActors)
victim.InflictDamage(FiredBy, this, (int)GetDamageToInflict(victim));
}
- }
+ }
+
+ const float height = .1f;
- public IEnumerable> Render()
+ public IEnumerable> Render()
{
if (anim != null)
- yield return Pair.New(anim.Image,
- float2.Lerp(
+ {
+ var pos = float2.Lerp(
Src.ToFloat2(),
VisualDest.ToFloat2(),
- (float)t / TotalTime()) - 0.5f * anim.Image.size);
+ (float)t / TotalTime()) - 0.5f * anim.Image.size;
+
+ if (Projectile.High || Projectile.Arcing)
+ {
+ if (Projectile.Shadow)
+ yield return Tuple.New(anim.Image, pos, 8); /* todo: shadow pal */
+
+ var at = (float)t / TotalTime();
+ var highPos = pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at));
+
+ yield return Tuple.New(anim.Image, highPos, Owner.Palette);
+ }
+ else
+ yield return Tuple.New(anim.Image, pos, Owner.Palette);
+ }
}
float GetMaximumSpread()
diff --git a/OpenRa.Game/Explosion.cs b/OpenRa.Game/Explosion.cs
index 3e8fe08c78..1180031d3f 100644
--- a/OpenRa.Game/Explosion.cs
+++ b/OpenRa.Game/Explosion.cs
@@ -24,9 +24,9 @@ namespace OpenRa.Game
public void Tick() { anim.Tick(); }
- public IEnumerable> Render()
+ public IEnumerable> Render()
{
- yield return Pair.New(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size);
+ yield return Tuple.New(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size, 0);
}
public Player Owner { get { return null; } }
diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs
index 9f371fdb52..4ddd12fec6 100644
--- a/OpenRa.Game/Game.cs
+++ b/OpenRa.Game/Game.cs
@@ -46,7 +46,8 @@ namespace OpenRa.Game
Rules.LoadRules(mapName);
for (int i = 0; i < 8; i++)
- players.Add(i, new Player(i, i, string.Format("Multi{0}", i), Race.Allies));
+ players.Add(i, new Player(i, i, string.Format("Multi{0}", i),
+ Race.Allies));
localPlayerIndex = localPlayer;
@@ -84,8 +85,7 @@ namespace OpenRa.Game
PlaySound("intro.aud", false);
skipMakeAnims = false;
-
- sw = new Stopwatch();
+ PerfHistory.items["render"].hasNormalTick = false;
}
static void LoadMapBuildings( IniFile mapfile )
@@ -143,11 +143,6 @@ namespace OpenRa.Game
const int oreFrequency = 30;
static int oreTicks = oreFrequency;
public static int RenderFrame = 0;
- public static double RenderTime = 0.0;
- public static double TickTime = 0.0;
- public static double OreTime = 0.0;
-
- public static Stopwatch sw;
public static void Tick()
{
@@ -157,7 +152,6 @@ namespace OpenRa.Game
{
using (new PerfSample("tick_time"))
{
- sw.Reset();
lastTime += timestep;
if (orderManager.Tick())
@@ -166,29 +160,27 @@ namespace OpenRa.Game
controller.orderGenerator.Tick();
if (--oreTicks == 0)
- {
- var oresw = new Stopwatch();
- map.GrowOre(SharedRandom);
- OreTime = oresw.ElapsedTime();
- oreTicks = oreFrequency;
- }
+ using( new PerfSample("ore"))
+ map.GrowOre(SharedRandom);
world.Tick();
UnitInfluence.Tick();
foreach (var player in players.Values)
player.Tick();
}
-
- TickTime = sw.ElapsedTime();
}
PerfHistory.Tick();
}
- sw.Reset();
- ++RenderFrame;
- viewport.cursor = controller.ChooseCursor();
- viewport.DrawRegions();
- RenderTime = sw.ElapsedTime();
+ using (new PerfSample("render"))
+ {
+
+ ++RenderFrame;
+ viewport.cursor = controller.ChooseCursor();
+ viewport.DrawRegions();
+ }
+
+ PerfHistory.items["render"].Tick();
}
public static bool IsCellBuildable(int2 a, UnitMovementType umt)
diff --git a/OpenRa.Game/Graphics/HardwarePalette.cs b/OpenRa.Game/Graphics/HardwarePalette.cs
index d76e423a0f..61a7ea9343 100644
--- a/OpenRa.Game/Graphics/HardwarePalette.cs
+++ b/OpenRa.Game/Graphics/HardwarePalette.cs
@@ -10,7 +10,7 @@ namespace OpenRa.Game.Graphics
{
class HardwarePalette : Sheet
{
- const int maxEntries = 8;
+ const int maxEntries = 16;
int allocated = 0;
public HardwarePalette(Renderer renderer, Map map, int rotate)
@@ -22,6 +22,8 @@ namespace OpenRa.Game.Graphics
foreach (string remap in new string[] { "blue", "red", "orange", "teal", "salmon", "green", "gray" })
AddPalette(new Palette(pal, new PaletteRemap(FileSystem.Open(remap + ".rem"))));
+ AddPalette(new Palette(pal, new PaletteRemap(Color.FromArgb(140, 0, 0, 0))));
+
using (var bitmapCopy = new Bitmap(bitmap))
for (int j = 0; j < maxEntries; j++)
for (int i = 0; i < 7; i++)
diff --git a/OpenRa.Game/Graphics/Util.cs b/OpenRa.Game/Graphics/Util.cs
index 2f3f11f181..d4d7ab60c7 100644
--- a/OpenRa.Game/Graphics/Util.cs
+++ b/OpenRa.Game/Graphics/Util.cs
@@ -58,7 +58,7 @@ namespace OpenRa.Game.Graphics
public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni)
{
- float2 attrib = new float2(palette / 8.0f, channelSelect[(int)r.channel]);
+ float2 attrib = new float2(palette / 16.0f, channelSelect[(int)r.channel]);
vertices[nv] = new Vertex(KLerp(o, r.size, 0), r.FastMapTextureCoords(0), attrib);
vertices[nv + 1] = new Vertex(KLerp(o, r.size, 1), r.FastMapTextureCoords(1), attrib);
diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs
index ec9ba83177..d3c51dea07 100644
--- a/OpenRa.Game/Graphics/WorldRenderer.cs
+++ b/OpenRa.Game/Graphics/WorldRenderer.cs
@@ -35,82 +35,80 @@ namespace OpenRa.Game.Graphics
lineRenderer = new LineRenderer(renderer);
uiOverlay = new UiOverlay(spriteRenderer);
}
-
- void DrawSpriteList(Player owner, RectangleF rect,
- IEnumerable> images)
- {
- foreach (var image in images)
- {
- var loc = image.Second;
-
- if (loc.X > rect.Right || loc.X < rect.Left
- - image.First.bounds.Width)
- continue;
- if (loc.Y > rect.Bottom || loc.Y < rect.Top
- - image.First.bounds.Height)
- continue;
-
- spriteRenderer.DrawSprite(image.First, loc,
- (owner != null) ? owner.Palette : 0);
- }
- }
-
- public void Draw()
+
+ void DrawSpriteList(RectangleF rect,
+ IEnumerable> images)
{
- terrainRenderer.Draw( Game.viewport );
-
- var rect = new RectangleF((region.Position + Game.viewport.Location).ToPointF(),
- region.Size.ToSizeF());
-
- foreach (Actor a in Game.world.Actors.OrderBy( u => u.CenterLocation.Y ))
- DrawSpriteList(a.Owner, rect, a.Render());
-
- foreach (var a in Game.world.Actors
- .Where(u => u.traits.Contains())
- .Select(u => u.traits.Get()))
- DrawSpriteList(a.self.Owner, rect, a.RenderRoof(a.self)); /* RUDE HACK */
-
- foreach (IEffect e in Game.world.Effects)
- DrawSpriteList(e.Owner, rect, e.Render());
-
- uiOverlay.Draw();
-
- spriteRenderer.Flush();
-
- var selbox = Game.controller.SelectionBox;
- if (selbox != null)
- {
- var a = selbox.Value.First;
- var b = new float2(selbox.Value.Second.X - a.X, 0);
- var c = new float2(0, selbox.Value.Second.Y - a.Y);
-
- lineRenderer.DrawLine(a, a + b, Color.White, Color.White);
- lineRenderer.DrawLine(a + b, a + b + c, Color.White, Color.White);
- lineRenderer.DrawLine(a + b + c, a + c, Color.White, Color.White);
- lineRenderer.DrawLine(a, a + c, Color.White, Color.White);
-
- foreach (var u in Game.SelectUnitsInBox(selbox.Value.First, selbox.Value.Second))
- DrawSelectionBox(u, Color.Yellow, false);
- }
-
- var uog = Game.controller.orderGenerator as UnitOrderGenerator;
- if (uog != null)
- foreach( var a in uog.selection )
- DrawSelectionBox(a, Color.White, true);
-
- lineRenderer.Flush();
-
- renderer.DrawText(string.Format("RenderFrame {0} ({2:F1} ms)\nTick {1} ({3:F1} ms)\nOre ({4:F1} ms)\n$ {5}\nPower {7}\nTiles Expanded {6:F0}",
- Game.RenderFrame, Game.orderManager.FrameNumber,
- Game.RenderTime * 1000,
- Game.TickTime * 1000,
- Game.OreTime * 1000,
- Game.LocalPlayer.Cash,
- PerfHistory.items[ "nodes_expanded" ].LastValue,
- Game.LocalPlayer.Power
+ foreach (var image in images)
+ {
+ var loc = image.b;
+
+ if (loc.X > rect.Right || loc.X < rect.Left
+ - image.a.bounds.Width)
+ continue;
+ if (loc.Y > rect.Bottom || loc.Y < rect.Top
+ - image.a.bounds.Height)
+ continue;
+
+ spriteRenderer.DrawSprite(image.a, loc, image.c);
+ }
+ }
+
+ public void Draw()
+ {
+ terrainRenderer.Draw(Game.viewport);
+
+ var rect = new RectangleF((region.Position + Game.viewport.Location).ToPointF(),
+ region.Size.ToSizeF());
+
+ foreach (Actor a in Game.world.Actors.OrderBy(u => u.CenterLocation.Y))
+ DrawSpriteList(rect, a.Render());
+
+ foreach (var a in Game.world.Actors
+ .Where(u => u.traits.Contains())
+ .Select(u => u.traits.Get()))
+ DrawSpriteList(rect, a.RenderRoof(a.self)); /* RUDE HACK */
+
+ foreach (IEffect e in Game.world.Effects)
+ DrawSpriteList(rect, e.Render());
+
+ uiOverlay.Draw();
+
+ spriteRenderer.Flush();
+
+ var selbox = Game.controller.SelectionBox;
+ if (selbox != null)
+ {
+ var a = selbox.Value.First;
+ var b = new float2(selbox.Value.Second.X - a.X, 0);
+ var c = new float2(0, selbox.Value.Second.Y - a.Y);
+
+ lineRenderer.DrawLine(a, a + b, Color.White, Color.White);
+ lineRenderer.DrawLine(a + b, a + b + c, Color.White, Color.White);
+ lineRenderer.DrawLine(a + b + c, a + c, Color.White, Color.White);
+ lineRenderer.DrawLine(a, a + c, Color.White, Color.White);
+
+ foreach (var u in Game.SelectUnitsInBox(selbox.Value.First, selbox.Value.Second))
+ DrawSelectionBox(u, Color.Yellow, false);
+ }
+
+ var uog = Game.controller.orderGenerator as UnitOrderGenerator;
+ if (uog != null)
+ foreach (var a in uog.selection)
+ DrawSelectionBox(a, Color.White, true);
+
+ lineRenderer.Flush();
+
+ renderer.DrawText(string.Format("RenderFrame {0} ({2:F1} ms)\nTick {1} ({3:F1} ms)\n$ {4}\nPower {5}",
+ Game.RenderFrame,
+ Game.orderManager.FrameNumber,
+ PerfHistory.items["render"].LastValue,
+ PerfHistory.items["tick_time"].LastValue,
+ Game.LocalPlayer.Cash,
+ Game.LocalPlayer.GetTotalPower()
), new int2(5, 5), Color.White);
- PerfHistory.Render(renderer, lineRenderer);
+ PerfHistory.Render(renderer, lineRenderer);
}
void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar)
diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs
index a759587ef0..92b4f4067f 100755
--- a/OpenRa.Game/MainWindow.cs
+++ b/OpenRa.Game/MainWindow.cs
@@ -61,10 +61,13 @@ namespace OpenRa.Game
Game.world.Add( new Actor( "mcv", Game.map.Offset + new int2( 5, 5 ), Game.players[ 1 ]) );
Game.world.Add( new Actor( "mcv", Game.map.Offset + new int2( 7, 5 ), Game.players[ 2 ] ) );
Game.world.Add( new Actor( "mcv", Game.map.Offset + new int2( 9, 5 ), Game.players[ 0 ] ) );
- Game.world.Add( new Actor( "jeep", Game.map.Offset + new int2( 9, 15 ), Game.players[ 1 ] ) );
+ Game.world.Add( new Actor( "jeep", Game.map.Offset + new int2( 9, 14 ), Game.players[ 1 ] ) );
Game.world.Add( new Actor( "3tnk", Game.map.Offset + new int2( 12, 7 ), Game.players[ 1 ] ) );
+ Game.world.Add(new Actor("apc", Game.map.Offset + new int2(13, 7), Game.players[1]));
Game.world.Add(new Actor("ca", Game.map.Offset + new int2(40, 7), Game.players[1]));
Game.world.Add(new Actor("e1", Game.map.Offset + new int2(9, 13), Game.players[1]));
+ Game.world.Add(new Actor("arty", Game.map.Offset + new int2(10, 13), Game.players[1]));
+ Game.world.Add(new Actor("heli", Game.map.Offset + new int2(11, 12), Game.players[1]));
renderer.BuildPalette(Game.map);
sidebar = new Sidebar(renderer, Game.LocalPlayer);
diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index f601117070..5cd94575af 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -153,6 +153,7 @@
+
diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs
index c3b08fdc17..76d43c7e59 100644
--- a/OpenRa.Game/Player.cs
+++ b/OpenRa.Game/Player.cs
@@ -11,7 +11,8 @@ namespace OpenRa.Game
public Race Race;
public readonly int Index;
public int Cash;
- public int Power;
+ int powerProvided;
+ int powerDrained;
public Player( int index, int palette, string playerName, Race race )
{
@@ -20,7 +21,20 @@ namespace OpenRa.Game
this.PlayerName = playerName;
this.Race = race;
this.Cash = 10000;
- this.Power = 0;
+ this.powerProvided = this.powerDrained = 0;
+ }
+
+ public void ChangePower(int dPower)
+ {
+ if (dPower > 0)
+ powerProvided += dPower;
+ if (dPower < 0)
+ powerDrained -= dPower;
+ }
+
+ public int GetTotalPower()
+ {
+ return powerProvided - powerDrained;
}
public float GetSiloFullness()
diff --git a/OpenRa.Game/Support/PerfHistory.cs b/OpenRa.Game/Support/PerfHistory.cs
index 60954912e1..bad5cd80c0 100644
--- a/OpenRa.Game/Support/PerfHistory.cs
+++ b/OpenRa.Game/Support/PerfHistory.cs
@@ -29,7 +29,8 @@ namespace OpenRa.Game.Support
public static void Tick()
{
foreach (var item in items.Values)
- item.Tick();
+ if (item.hasNormalTick)
+ item.Tick();
}
public static void Render(Renderer r, LineRenderer lr)
@@ -65,6 +66,7 @@ namespace OpenRa.Game.Support
public double[] samples = new double[100];
public double val = 0.0;
int head = 1, tail = 0;
+ public bool hasNormalTick = true;
public PerfItem(string name, Color c)
{
diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs
index 0dda1090c1..e79f5ddc28 100755
--- a/OpenRa.Game/Traits/AttackTurreted.cs
+++ b/OpenRa.Game/Traits/AttackTurreted.cs
@@ -13,6 +13,8 @@ namespace OpenRa.Game.Traits
protected int primaryFireDelay = 0;
protected int secondaryFireDelay = 0;
+ public float primaryRecoil = 0.0f, secondaryRecoil = 0.0f;
+
public AttackBase(Actor self) { }
protected bool CanAttack( Actor self )
@@ -25,6 +27,9 @@ namespace OpenRa.Game.Traits
if (primaryFireDelay > 0) --primaryFireDelay;
if (secondaryFireDelay > 0) --secondaryFireDelay;
+ primaryRecoil = Math.Max(0f, primaryRecoil - .2f);
+ secondaryRecoil = Math.Max(0f, secondaryRecoil - .2f);
+
if (target != null && target.IsDead) target = null; /* he's dead, jim. */
}
@@ -36,20 +41,15 @@ namespace OpenRa.Game.Traits
self.unitInfo.PrimaryOffset ) )
{
secondaryFireDelay = Math.Max( 4, secondaryFireDelay );
- if (rut != null) rut.primaryRecoil = 1;
+ primaryRecoil = 1;
return;
}
if (self.unitInfo.Secondary != null && CheckFire(self, self.unitInfo.Secondary, ref secondaryFireDelay,
self.unitInfo.SecondaryOffset ?? self.unitInfo.PrimaryOffset))
{
- if (rut != null)
- {
- if (self.unitInfo.SecondaryOffset != null)
- rut.secondaryRecoil = 1;
- else
- rut.primaryRecoil = 1;
- }
+ if (self.unitInfo.SecondaryOffset != null) secondaryRecoil = 1;
+ else primaryRecoil = 1;
return;
}
}
diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs
index 4f1890680a..0894e00baf 100644
--- a/OpenRa.Game/Traits/Building.cs
+++ b/OpenRa.Game/Traits/Building.cs
@@ -26,7 +26,7 @@ namespace OpenRa.Game.Traits
UnitInfo.BuildingInfo bi = self.unitInfo as UnitInfo.BuildingInfo;
if (bi == null) return;
- self.Owner.Power += bi.Power;
+ self.Owner.ChangePower(bi.Power);
}
}
}
diff --git a/OpenRa.Game/Traits/InfantrySquad.cs b/OpenRa.Game/Traits/InfantrySquad.cs
index d54e2c93a4..2a05288db7 100644
--- a/OpenRa.Game/Traits/InfantrySquad.cs
+++ b/OpenRa.Game/Traits/InfantrySquad.cs
@@ -35,11 +35,11 @@ namespace OpenRa.Game.Traits
self.CenterLocation.ToInt2() + elementOffsets[elements.Count][i], self);
}
- public IEnumerable> Render(Actor self)
+ 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! */
+ e => Util.Centered(self, e.anim.Image, e.location))
+ .OrderBy( a => a.b.Y ); /* important to y-order elements of a squad! */
}
}
diff --git a/OpenRa.Game/Traits/RallyPoint.cs b/OpenRa.Game/Traits/RallyPoint.cs
index e71f33eeb7..c2527f29b9 100644
--- a/OpenRa.Game/Traits/RallyPoint.cs
+++ b/OpenRa.Game/Traits/RallyPoint.cs
@@ -21,11 +21,11 @@ namespace OpenRa.Game.Traits
anim.PlayRepeating("idle");
}
- public IEnumerable> Render(Actor self)
+ public IEnumerable> Render(Actor self)
{
var uog = Game.controller.orderGenerator as UnitOrderGenerator;
if (uog != null && self.Owner == Game.LocalPlayer && uog.selection.Contains(self))
- yield return Util.Centered(
+ yield return Util.Centered( self,
anim.Image, Game.CellSize * (new float2(.5f, .5f) + rallyPoint.ToFloat2()));
}
diff --git a/OpenRa.Game/Traits/RenderBuilding.cs b/OpenRa.Game/Traits/RenderBuilding.cs
index 67468e3975..b8f46e28b6 100644
--- a/OpenRa.Game/Traits/RenderBuilding.cs
+++ b/OpenRa.Game/Traits/RenderBuilding.cs
@@ -64,9 +64,9 @@ namespace OpenRa.Game.Traits
}
}
- public override IEnumerable> Render(Actor self)
+ public override IEnumerable> Render(Actor self)
{
- yield return Pair.New(anim.Image, 24f * (float2)self.Location);
+ yield return Tuple.New(anim.Image, 24f * (float2)self.Location, self.Owner.Palette);
}
public virtual void Damaged(Actor self, DamageState state)
diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs
index 9bed59f2c7..e489a47482 100644
--- a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs
+++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs
@@ -29,10 +29,11 @@ namespace OpenRa.Game.Traits
}, self);
}
- public IEnumerable> RenderRoof(Actor self)
+ public IEnumerable> RenderRoof(Actor self)
{
if (doneBuilding)
- yield return Pair.New(roof.Image, 24f * (float2)self.Location);
+ yield return Tuple.New(roof.Image,
+ 24f * (float2)self.Location, self.Owner.Palette);
}
public override void Tick(Actor self)
diff --git a/OpenRa.Game/Traits/RenderSimple.cs b/OpenRa.Game/Traits/RenderSimple.cs
index 3a098b6a32..abee7174ad 100644
--- a/OpenRa.Game/Traits/RenderSimple.cs
+++ b/OpenRa.Game/Traits/RenderSimple.cs
@@ -16,7 +16,7 @@ namespace OpenRa.Game.Traits
anim = new Animation(self.unitInfo.Image ?? self.unitInfo.Name);
}
- public abstract IEnumerable> Render(Actor self);
+ public abstract IEnumerable> Render(Actor self);
public virtual void Tick(Actor self)
{
diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs
index efd2ac58ae..18f43284fb 100644
--- a/OpenRa.Game/Traits/RenderUnit.cs
+++ b/OpenRa.Game/Traits/RenderUnit.cs
@@ -29,11 +29,11 @@ namespace OpenRa.Game.Traits
anim.PlayThen(newAnim, () => { PlayFacingAnim(self); if (after != null) after(); });
}
- public override IEnumerable> Render(Actor self)
+ public override IEnumerable> Render(Actor self)
{
- yield return Util.Centered(anim.Image, self.CenterLocation);
+ yield return Util.Centered(self, anim.Image, self.CenterLocation);
if (isSmoking)
- yield return Util.Centered(smoke.Image, self.CenterLocation);
+ yield return Util.Centered(self, smoke.Image, self.CenterLocation);
}
bool isSmoking;
diff --git a/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs b/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs
new file mode 100644
index 0000000000..194cc8d2c8
--- /dev/null
+++ b/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using OpenRa.Game.Graphics;
+
+namespace OpenRa.Game.Traits
+{
+ class RenderUnitMuzzleFlash : RenderUnit
+ {
+ Animation muzzleFlash;
+
+ public RenderUnitMuzzleFlash(Actor self)
+ : base(self)
+ {
+ if (!self.unitInfo.MuzzleFlash) throw new InvalidOperationException("wtf??");
+
+ muzzleFlash = new Animation(self.unitInfo.Name);
+ muzzleFlash.PlayFetchIndex("muzzle",
+ () =>
+ {
+ var attack = self.traits.WithInterface().First();
+ var mobile = self.traits.WithInterface().First();
+ return (Util.QuantizeFacing(
+ mobile.facing, 8)) * 6 + (int)(attack.primaryRecoil * 5.9f);
+ });
+ }
+
+ public override void Tick(Actor self)
+ {
+ base.Tick(self);
+ muzzleFlash.Tick();
+ }
+
+ public override IEnumerable> Render(Actor self)
+ {
+ var attack = self.traits.WithInterface().First();
+ if (attack.primaryRecoil > 0)
+ return base.Render(self).Concat(new[] {Util.Centered(self,
+ muzzleFlash.Image, self.CenterLocation + new float2(
+ self.unitInfo.PrimaryOffset.ElementAtOrDefault(2),
+ self.unitInfo.PrimaryOffset.ElementAtOrDefault(3)))});
+ else
+ return base.Render(self);
+ }
+ }
+}
diff --git a/OpenRa.Game/Traits/RenderUnitRotor.cs b/OpenRa.Game/Traits/RenderUnitRotor.cs
index 4b446d7d8c..090b84ee60 100755
--- a/OpenRa.Game/Traits/RenderUnitRotor.cs
+++ b/OpenRa.Game/Traits/RenderUnitRotor.cs
@@ -23,18 +23,31 @@ namespace OpenRa.Game.Traits
}
}
- public override IEnumerable> Render(Actor self)
+ public override IEnumerable> Render(Actor self)
{
var mobile = self.traits.Get();
- yield return Util.Centered(anim.Image, self.CenterLocation);
- yield return Util.Centered(rotorAnim.Image, self.CenterLocation
+ yield return Util.CenteredShadow(self, anim.Image, self.CenterLocation);
+ yield return Util.CenteredShadow(self, rotorAnim.Image, self.CenterLocation
+ Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, 0));
if (self.unitInfo.SecondaryOffset != null)
- yield return Util.Centered((secondRotorAnim ?? rotorAnim).Image, self.CenterLocation
+ yield return Util.CenteredShadow(self, (secondRotorAnim ?? rotorAnim).Image, self.CenterLocation
+ + Util.GetTurretPosition(self, self.unitInfo.SecondaryOffset, 0));
+
+ var p = self.CenterLocation - new float2( 0, altitude );
+
+ yield return Util.Centered(self, anim.Image, p);
+ yield return Util.Centered(self, rotorAnim.Image, p
+ + Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, 0));
+ if (self.unitInfo.SecondaryOffset != null)
+ yield return Util.Centered(self, (secondRotorAnim ?? rotorAnim).Image, p
+ Util.GetTurretPosition(self, self.unitInfo.SecondaryOffset, 0));
}
+ int altitude = 0;
+ const int climbRate = 1;
+ const int cruiseAltitude = 20;
+
public override void Tick(Actor self)
{
base.Tick(self);
@@ -44,12 +57,18 @@ namespace OpenRa.Game.Traits
var mobile = self.traits.Get();
var isFlying = mobile.HasActivity;
- if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor"))
+
+ if (isFlying && altitude < cruiseAltitude)
+ altitude = Math.Min(altitude + climbRate, cruiseAltitude);
+ else if (!isFlying && altitude > 0)
+ altitude = Math.Max(altitude - climbRate, 0);
+
+ if ((altitude >0) ^ (rotorAnim.CurrentSequence.Name != "rotor"))
return;
- rotorAnim.PlayRepeatingPreservingPosition(isFlying ? "rotor" : "slow-rotor");
+ rotorAnim.PlayRepeatingPreservingPosition((altitude>0) ? "rotor" : "slow-rotor");
if (secondRotorAnim != null)
- secondRotorAnim.PlayRepeatingPreservingPosition(isFlying ? "rotor2" : "slow-rotor2");
+ secondRotorAnim.PlayRepeatingPreservingPosition((altitude>0) ? "rotor2" : "slow-rotor2");
}
}
}
diff --git a/OpenRa.Game/Traits/RenderUnitTurreted.cs b/OpenRa.Game/Traits/RenderUnitTurreted.cs
index 130a3a0430..bcdac9a98d 100644
--- a/OpenRa.Game/Traits/RenderUnitTurreted.cs
+++ b/OpenRa.Game/Traits/RenderUnitTurreted.cs
@@ -11,7 +11,6 @@ namespace OpenRa.Game.Traits
{
public Animation turretAnim;
public Animation muzzleFlash;
- public float primaryRecoil = 0.0f, secondaryRecoil = 0.0f;
public RenderUnitTurreted(Actor self)
: base(self)
@@ -21,9 +20,11 @@ namespace OpenRa.Game.Traits
{
if (self.unitInfo.MuzzleFlash)
{
+ var attack = self.traits.WithInterface().First();
muzzleFlash = new Animation(self.unitInfo.Name);
muzzleFlash.PlayFetchIndex("muzzle",
- () => (Util.QuantizeFacing(self.traits.Get().turretFacing,8)) * 6 + (int)(primaryRecoil * 6));
+ () => (Util.QuantizeFacing(self.traits.Get().turretFacing,8)) * 6 + (int)(attack.primaryRecoil * 5.9f));
+ /* hack: recoil can be 1.0f, but don't overflow into next anim */
}
turretAnim.PlayFetchIndex("turret",
@@ -33,28 +34,27 @@ namespace OpenRa.Game.Traits
turretAnim.PlayRepeating("turret"); /* not really a turret; it's a spinner */
}
- public override IEnumerable> Render(Actor self)
+ public override IEnumerable> Render(Actor self)
{
var mobile = self.traits.Get();
+ var attack = self.traits.WithInterface().FirstOrDefault();
- yield return Util.Centered(anim.Image, self.CenterLocation);
- yield return Util.Centered(turretAnim.Image, self.CenterLocation
- + Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, primaryRecoil));
+ yield return Util.Centered(self, anim.Image, self.CenterLocation);
+ yield return Util.Centered(self, turretAnim.Image, self.CenterLocation
+ + Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, attack.primaryRecoil));
if (self.unitInfo.SecondaryOffset != null)
- yield return Util.Centered(turretAnim.Image, self.CenterLocation
- + Util.GetTurretPosition(self, self.unitInfo.SecondaryOffset, secondaryRecoil));
+ yield return Util.Centered(self, turretAnim.Image, self.CenterLocation
+ + Util.GetTurretPosition(self, self.unitInfo.SecondaryOffset, attack.secondaryRecoil));
- if (muzzleFlash != null && primaryRecoil > 0)
- yield return Util.Centered(muzzleFlash.Image, self.CenterLocation
- + Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, primaryRecoil));
+ if (muzzleFlash != null && attack.primaryRecoil > 0)
+ yield return Util.Centered(self, muzzleFlash.Image, self.CenterLocation
+ + Util.GetTurretPosition(self, self.unitInfo.PrimaryOffset, attack.primaryRecoil));
}
public override void Tick(Actor self)
{
base.Tick(self);
turretAnim.Tick();
- primaryRecoil = Math.Max(0f, primaryRecoil - .2f);
- secondaryRecoil = Math.Max(0f, secondaryRecoil - .2f);
if (muzzleFlash != null)
muzzleFlash.Tick();
}
diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs
index d2400acf00..cf3505afce 100644
--- a/OpenRa.Game/Traits/TraitsInterfaces.cs
+++ b/OpenRa.Game/Traits/TraitsInterfaces.cs
@@ -10,7 +10,7 @@ namespace OpenRa.Game.Traits
enum DamageState { Normal, Half, Dead };
interface ITick { void Tick(Actor self); }
- interface IRender { IEnumerable> Render(Actor self); }
+ interface IRender { IEnumerable> Render(Actor self); }
interface IOrder { Order Order(Actor self, int2 xy, bool lmb, Actor underCursor); }
interface INotifyDamage { void Damaged(Actor self, DamageState ds); }
interface INotifyDamageEx : INotifyDamage { void Damaged(Actor self, int damage); }
diff --git a/OpenRa.Game/Traits/Tree.cs b/OpenRa.Game/Traits/Tree.cs
index bb6aa717bc..44cfd7c1a6 100644
--- a/OpenRa.Game/Traits/Tree.cs
+++ b/OpenRa.Game/Traits/Tree.cs
@@ -16,9 +16,9 @@ namespace OpenRa.Game.Traits
Image = treeImage;
}
- public IEnumerable> Render(Actor self)
+ public IEnumerable> Render(Actor self)
{
- yield return Pair.New(Image, Game.CellSize * (float2)self.Location);
+ yield return Tuple.New(Image, Game.CellSize * (float2)self.Location, 0);
}
}
}
diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs
index b420a01c91..c7b3507869 100755
--- a/OpenRa.Game/Traits/Util.cs
+++ b/OpenRa.Game/Traits/Util.cs
@@ -81,7 +81,7 @@ namespace OpenRa.Game.Traits
if (rut == null) return float2.Zero;
var facing = self.traits.Get().turretFacing;
- var quantizedFacing = facing - facing % rut.turretAnim.CurrentSequence.Length;
+ var quantizedFacing = QuantizeFacing(facing, rut.turretAnim.CurrentSequence.Length) * (256 / rut.turretAnim.CurrentSequence.Length);
return RotateVectorByFacing(new float2(0, recoil * self.unitInfo.Recoil), quantizedFacing, .7f);
}
@@ -92,17 +92,22 @@ namespace OpenRa.Game.Traits
if (ru == null) return int2.Zero; /* things that don't have a rotating base don't need the turrets repositioned */
var bodyFacing = self.traits.Get().facing;
- var quantizedFacing = bodyFacing - bodyFacing % ru.anim.CurrentSequence.Length;
+ var quantizedFacing = QuantizeFacing(bodyFacing, ru.anim.CurrentSequence.Length) * (256 / ru.anim.CurrentSequence.Length);
return (RotateVectorByFacing(new float2(offset[0], offset[1]), quantizedFacing, .7f) + GetRecoil(self, recoil))
+ new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3));
}
- public static Pair Centered(Sprite s, float2 location)
+ public static Tuple Centered(Actor self, Sprite s, float2 location)
{
var loc = location - 0.5f * s.size;
- return Pair.New(s, loc.Round());
+ return Tuple.New(s, loc.Round(), self.Owner.Palette);
}
+ public static Tuple CenteredShadow(Actor self, Sprite s, float2 location)
+ {
+ var loc = location - 0.5f * s.size;
+ return Tuple.New(s, loc.Round(), 8);
+ }
}
}
diff --git a/sequences.xml b/sequences.xml
index e3b88530a2..cc38b910b7 100644
--- a/sequences.xml
+++ b/sequences.xml
@@ -275,6 +275,7 @@
+
diff --git a/units.ini b/units.ini
index 1f194060e3..5fd9cd1c0a 100755
--- a/units.ini
+++ b/units.ini
@@ -15,7 +15,7 @@ MNLY
[V2RL]
Description=V2 Rocket
-Traits=Mobile, RenderUnit
+Traits=Mobile, RenderUnit, AttackBase
[1TNK]
Description=Light Tank
Traits=Mobile, Turreted, AttackTurreted, RenderUnitTurreted
@@ -55,7 +55,9 @@ PrimaryOffset=0,0,0,-2
MuzzleFlash=yes
[APC]
Description=Armored Personnel Carrier
-Traits=Mobile, RenderUnit, AttackBase
+Traits=Mobile, AttackBase, RenderUnitMuzzleFlash
+PrimaryOffset=0,0,0,-4
+MuzzleFlash=yes
[MNLY]
Description=Minelayer
Traits=Mobile, RenderUnit