Merge branch 'master' of git://github.com/beedee/OpenRA

This commit is contained in:
Chris Forbes
2009-11-12 00:26:00 +13:00
29 changed files with 290 additions and 165 deletions

View File

@@ -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<A, B, C> New<A, B, C>(A a, B b, C c)
{
return new Tuple<A, B, C>(a, b, c);
}
}
}

View File

@@ -8,7 +8,9 @@ namespace OpenRa.FileFormats
{
public class PaletteRemap
{
int offset;
List<Color> remapColors = new List<Color>();
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)
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;
}
}
}

View File

@@ -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<Pair<Sprite, float2>> Render()
public IEnumerable<Tuple<Sprite, float2, int>> Render()
{
return traits.WithInterface<Traits.IRender>().SelectMany( x => x.Render( this ) );
}

View File

@@ -11,7 +11,7 @@ namespace OpenRa.Game
interface IEffect
{
void Tick();
IEnumerable<Pair<Sprite, float2>> Render();
IEnumerable<Tuple<Sprite, float2, int>> Render();
Player Owner { get; }
}
@@ -96,14 +96,30 @@ namespace OpenRa.Game
}
}
public IEnumerable<Pair<Sprite, float2>> Render()
const float height = .1f;
public IEnumerable<Tuple<Sprite, float2, int>> 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()

View File

@@ -24,9 +24,9 @@ namespace OpenRa.Game
public void Tick() { anim.Tick(); }
public IEnumerable<Pair<Sprite, float2>> Render()
public IEnumerable<Tuple<Sprite, float2, int>> 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; } }

View File

@@ -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();
using( new PerfSample("ore"))
map.GrowOre(SharedRandom);
OreTime = oresw.ElapsedTime();
oreTicks = oreFrequency;
}
world.Tick();
UnitInfluence.Tick();
foreach (var player in players.Values)
player.Tick();
}
TickTime = sw.ElapsedTime();
}
PerfHistory.Tick();
}
sw.Reset();
using (new PerfSample("render"))
{
++RenderFrame;
viewport.cursor = controller.ChooseCursor();
viewport.DrawRegions();
RenderTime = sw.ElapsedTime();
}
PerfHistory.items["render"].Tick();
}
public static bool IsCellBuildable(int2 a, UnitMovementType umt)

View File

@@ -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++)

View File

@@ -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);

View File

@@ -36,42 +36,41 @@ namespace OpenRa.Game.Graphics
uiOverlay = new UiOverlay(spriteRenderer);
}
void DrawSpriteList(Player owner, RectangleF rect,
IEnumerable<Pair<Sprite, float2>> images)
void DrawSpriteList(RectangleF rect,
IEnumerable<Tuple<Sprite, float2, int>> images)
{
foreach (var image in images)
{
var loc = image.Second;
var loc = image.b;
if (loc.X > rect.Right || loc.X < rect.Left
- image.First.bounds.Width)
- image.a.bounds.Width)
continue;
if (loc.Y > rect.Bottom || loc.Y < rect.Top
- image.First.bounds.Height)
- image.a.bounds.Height)
continue;
spriteRenderer.DrawSprite(image.First, loc,
(owner != null) ? owner.Palette : 0);
spriteRenderer.DrawSprite(image.a, loc, image.c);
}
}
public void Draw()
{
terrainRenderer.Draw( Game.viewport );
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 (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<Traits.RenderWarFactory>())
.Select(u => u.traits.Get<Traits.RenderWarFactory>()))
DrawSpriteList(a.self.Owner, rect, a.RenderRoof(a.self)); /* RUDE HACK */
DrawSpriteList(rect, a.RenderRoof(a.self)); /* RUDE HACK */
foreach (IEffect e in Game.world.Effects)
DrawSpriteList(e.Owner, rect, e.Render());
DrawSpriteList(rect, e.Render());
uiOverlay.Draw();
@@ -95,19 +94,18 @@ namespace OpenRa.Game.Graphics
var uog = Game.controller.orderGenerator as UnitOrderGenerator;
if (uog != null)
foreach( var a in uog.selection )
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,
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,
PerfHistory.items[ "nodes_expanded" ].LastValue,
Game.LocalPlayer.Power
Game.LocalPlayer.GetTotalPower()
), new int2(5, 5), Color.White);
PerfHistory.Render(renderer, lineRenderer);

View File

@@ -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);

View File

@@ -153,6 +153,7 @@
<Compile Include="Traits\RenderBuildingWarFactory.cs" />
<Compile Include="Traits\RenderSimple.cs" />
<Compile Include="Traits\RenderUnit.cs" />
<Compile Include="Traits\RenderUnitMuzzleFlash.cs" />
<Compile Include="Traits\RenderUnitRotor.cs" />
<Compile Include="Traits\RenderUnitTurreted.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />

View File

@@ -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()

View File

@@ -29,6 +29,7 @@ namespace OpenRa.Game.Support
public static void Tick()
{
foreach (var item in items.Values)
if (item.hasNormalTick)
item.Tick();
}
@@ -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)
{

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -35,11 +35,11 @@ namespace OpenRa.Game.Traits
self.CenterLocation.ToInt2() + elementOffsets[elements.Count][i], self);
}
public IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public IEnumerable<Tuple<Sprite, float2, int>> 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! */
}
}

View File

@@ -21,11 +21,11 @@ namespace OpenRa.Game.Traits
anim.PlayRepeating("idle");
}
public IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public IEnumerable<Tuple<Sprite, float2, int>> 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()));
}

View File

@@ -64,9 +64,9 @@ namespace OpenRa.Game.Traits
}
}
public override IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public override IEnumerable<Tuple<Sprite, float2, int>> 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)

View File

@@ -29,10 +29,11 @@ namespace OpenRa.Game.Traits
}, self);
}
public IEnumerable<Pair<Sprite, float2>> RenderRoof(Actor self)
public IEnumerable<Tuple<Sprite, float2, int>> 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)

View File

@@ -16,7 +16,7 @@ namespace OpenRa.Game.Traits
anim = new Animation(self.unitInfo.Image ?? self.unitInfo.Name);
}
public abstract IEnumerable<Pair<Sprite, float2>> Render(Actor self);
public abstract IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self);
public virtual void Tick(Actor self)
{

View File

@@ -29,11 +29,11 @@ namespace OpenRa.Game.Traits
anim.PlayThen(newAnim, () => { PlayFacingAnim(self); if (after != null) after(); });
}
public override IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public override IEnumerable<Tuple<Sprite, float2, int>> 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;

View File

@@ -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<AttackBase>().First();
var mobile = self.traits.WithInterface<Mobile>().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<Tuple<Sprite, float2, int>> Render(Actor self)
{
var attack = self.traits.WithInterface<AttackBase>().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);
}
}
}

View File

@@ -23,18 +23,31 @@ namespace OpenRa.Game.Traits
}
}
public override IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public override IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self)
{
var mobile = self.traits.Get<Mobile>();
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<Mobile>();
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");
}
}
}

View File

@@ -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<AttackBase>().First();
muzzleFlash = new Animation(self.unitInfo.Name);
muzzleFlash.PlayFetchIndex("muzzle",
() => (Util.QuantizeFacing(self.traits.Get<Turreted>().turretFacing,8)) * 6 + (int)(primaryRecoil * 6));
() => (Util.QuantizeFacing(self.traits.Get<Turreted>().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<Pair<Sprite, float2>> Render(Actor self)
public override IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self)
{
var mobile = self.traits.Get<Mobile>();
var attack = self.traits.WithInterface<AttackBase>().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();
}

View File

@@ -10,7 +10,7 @@ namespace OpenRa.Game.Traits
enum DamageState { Normal, Half, Dead };
interface ITick { void Tick(Actor self); }
interface IRender { IEnumerable<Pair<Sprite, float2>> Render(Actor self); }
interface IRender { IEnumerable<Tuple<Sprite, float2, int>> 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); }

View File

@@ -16,9 +16,9 @@ namespace OpenRa.Game.Traits
Image = treeImage;
}
public IEnumerable<Pair<Sprite, float2>> Render(Actor self)
public IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self)
{
yield return Pair.New(Image, Game.CellSize * (float2)self.Location);
yield return Tuple.New(Image, Game.CellSize * (float2)self.Location, 0);
}
}
}

View File

@@ -81,7 +81,7 @@ namespace OpenRa.Game.Traits
if (rut == null) return float2.Zero;
var facing = self.traits.Get<Turreted>().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<Mobile>().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<Sprite, float2> Centered(Sprite s, float2 location)
public static Tuple<Sprite, float2, int> 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<Sprite, float2, int> CenteredShadow(Actor self, Sprite s, float2 location)
{
var loc = location - 0.5f * s.size;
return Tuple.New(s, loc.Round(), 8);
}
}
}

View File

@@ -275,6 +275,7 @@
<!-- apc -->
<unit name="apc">
<sequence name="idle" start="0" length="32" />
<sequence name="muzzle" start="0" length="48" src="minigun" />
</unit>
<!-- mine layer -->
<unit name="mnly">

View File

@@ -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