Merge pull request #1 from OpenRA/bleed

Bleed
This commit is contained in:
Okunev Yu Dmitry
2013-03-02 00:19:25 -08:00
162 changed files with 1236 additions and 966 deletions

View File

@@ -37,6 +37,7 @@ Also thanks to:
* Raymond Martineau (mart0258) * Raymond Martineau (mart0258)
* Riderr3 * Riderr3
* Tim Mylemans (gecko) * Tim Mylemans (gecko)
* Tirili
Past developers included: Past developers included:
* Paul Chote (pchote) * Paul Chote (pchote)

View File

@@ -39,6 +39,12 @@ namespace OpenRA.FileFormats
get { return colors; } get { return colors; }
} }
public void ApplyRemap(IPaletteRemap r)
{
for(int i = 0; i < 256; i++)
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)colors[i]),i).ToArgb();
}
public Palette(Stream s, int[] remapShadow) public Palette(Stream s, int[] remapShadow)
{ {
colors = new uint[256]; colors = new uint[256];
@@ -61,9 +67,8 @@ namespace OpenRA.FileFormats
public Palette(Palette p, IPaletteRemap r) public Palette(Palette p, IPaletteRemap r)
{ {
colors = new uint[256]; colors = (uint[])p.colors.Clone();
for(int i = 0; i < 256; i++) ApplyRemap(r);
colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb();
} }
public Palette(Palette p) public Palette(Palette p)
@@ -71,6 +76,13 @@ namespace OpenRA.FileFormats
colors = (uint[])p.colors.Clone(); colors = (uint[])p.colors.Clone();
} }
public Palette(uint[] data)
{
if (data.Length != 256)
throw new InvalidDataException("Attempting to create palette with incorrect array size");
colors = (uint[])data.Clone();
}
public ColorPalette AsSystemPalette() public ColorPalette AsSystemPalette()
{ {
ColorPalette pal; ColorPalette pal;
@@ -88,6 +100,21 @@ namespace OpenRA.FileFormats
return pal; return pal;
} }
public Bitmap AsBitmap()
{
var b = new Bitmap(256, 1, PixelFormat.Format32bppArgb);
var data = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
uint* c = (uint*)data.Scan0;
for (var x = 0; x < 256; x++)
*(c + x) = colors[x];
}
b.UnlockBits(data);
return b;
}
public static Palette Load(string filename, int[] remap) public static Palette Load(string filename, int[] remap)
{ {
using(var s = File.OpenRead(filename)) using(var s = File.OpenRead(filename))

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Thirdparty
int index = 0; int index = 0;
public int Last; public int Last;
public int TotalCount = 0;
public Random() : this(Environment.TickCount) { } public Random() : this(Environment.TickCount) { }
@@ -41,13 +42,14 @@ namespace OpenRA.Thirdparty
y ^= y >> 18; y ^= y >> 18;
index = (index + 1) % 624; index = (index + 1) % 624;
TotalCount++;
Last = (int)(y % int.MaxValue); Last = (int)(y % int.MaxValue);
return Last; return Last;
} }
public int Next(int low, int high) { return low + Next() % (high - low); } public int Next(int low, int high) { return low + Next() % (high - low); }
public int Next(int high) { return Next() % high; } public int Next(int high) { return Next() % high; }
public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); } public float NextFloat() { return Math.Abs(Next() / (float)0x7fffffff); }
void Generate() void Generate()
{ {

View File

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA namespace OpenRA
@@ -73,7 +74,7 @@ namespace OpenRA
AddTrait(trait.Create(init)); AddTrait(trait.Create(init));
} }
Move = Lazy.New( () => TraitOrDefault<IMove>() ); Move = Lazy.New(() => TraitOrDefault<IMove>());
Size = Lazy.New(() => Size = Lazy.New(() =>
{ {
@@ -81,27 +82,23 @@ namespace OpenRA
if (si != null && si.Bounds != null) if (si != null && si.Bounds != null)
return new int2(si.Bounds[0], si.Bounds[1]); return new int2(si.Bounds[0], si.Bounds[1]);
// auto size from render return TraitsImplementing<IAutoSelectionSize>().Select(x => x.SelectionSize(this)).FirstOrDefault();
var firstSprite = TraitsImplementing<IRender>().SelectMany(ApplyIRender).FirstOrDefault();
if (firstSprite.Sprite == null) return int2.Zero;
return (firstSprite.Sprite.size * firstSprite.Scale).ToInt2();
}); });
if(this.HasTrait<RevealsShroud>()) if (this.HasTrait<RevealsShroud>())
{ {
Sight = new Shroud.ActorVisibility Sight = new Shroud.ActorVisibility
{ {
range = this.Trait<RevealsShroud>().RevealRange, range = this.Trait<RevealsShroud>().RevealRange,
vis = Shroud.GetVisOrigins(this).ToArray() vis = Shroud.GetVisOrigins(this).ToArray()
}; };
} }
ApplyIRender = x => x.Render(this);
ApplyRenderModifier = (m, p) => p.ModifyRender(this, m);
Bounds = Cached.New( () => CalculateBounds(false) ); ApplyIRender = (x, wr) => x.Render(this, wr);
ExtendedBounds = Cached.New( () => CalculateBounds(true) ); ApplyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);
Bounds = Cached.New(() => CalculateBounds(false));
ExtendedBounds = Cached.New(() => CalculateBounds(true));
} }
public void Tick() public void Tick()
@@ -109,7 +106,7 @@ namespace OpenRA
Bounds.Invalidate(); Bounds.Invalidate();
ExtendedBounds.Invalidate(); ExtendedBounds.Invalidate();
currentActivity = Util.RunActivity( this, currentActivity ); currentActivity = Traits.Util.RunActivity( this, currentActivity );
} }
public void UpdateSight() public void UpdateSight()
@@ -125,13 +122,13 @@ namespace OpenRA
OpenRA.FileFormats.Lazy<int2> Size; OpenRA.FileFormats.Lazy<int2> Size;
// note: these delegates are cached to avoid massive allocation. // note: these delegates are cached to avoid massive allocation.
Func<IRender, IEnumerable<Renderable>> ApplyIRender; Func<IRender, WorldRenderer, IEnumerable<Renderable>> ApplyIRender;
Func<IEnumerable<Renderable>, IRenderModifier, IEnumerable<Renderable>> ApplyRenderModifier; Func<IEnumerable<Renderable>, IRenderModifier, WorldRenderer, IEnumerable<Renderable>> ApplyRenderModifier;
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
var mods = TraitsImplementing<IRenderModifier>(); var mods = TraitsImplementing<IRenderModifier>();
var sprites = TraitsImplementing<IRender>().SelectMany(ApplyIRender); var sprites = TraitsImplementing<IRender>().SelectMany(x => ApplyIRender(x, wr));
return mods.Aggregate(sprites, ApplyRenderModifier); return mods.Aggregate(sprites, (m,p) => ApplyRenderModifier(m,p,wr));
} }
// When useAltitude = true, the bounding box is extended // When useAltitude = true, the bounding box is extended
@@ -146,22 +143,14 @@ namespace OpenRA
var si = Info.Traits.GetOrDefault<SelectableInfo>(); var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null && si.Bounds.Length > 2) if (si != null && si.Bounds != null && si.Bounds.Length > 2)
{ {
#if true
loc += new PVecInt(si.Bounds[2], si.Bounds[3]); loc += new PVecInt(si.Bounds[2], si.Bounds[3]);
#else
loc.X += si.Bounds[2];
loc.Y += si.Bounds[3];
#endif
} }
var move = Move.Value; var move = Move.Value;
if (move != null) if (move != null)
{ {
#if true
loc -= new PVecInt(0, move.Altitude); loc -= new PVecInt(0, move.Altitude);
#else
loc.Y -= move.Altitude;
#endif
if (useAltitude) if (useAltitude)
size = new PVecInt(size.X, size.Y + move.Altitude); size = new PVecInt(size.X, size.Y + move.Altitude);
} }
@@ -257,10 +246,15 @@ namespace OpenRA
{ {
World.AddFrameEndTask(w => World.AddFrameEndTask(w =>
{ {
var oldOwner = Owner;
// momentarily remove from world so the ownership queries don't get confused // momentarily remove from world so the ownership queries don't get confused
w.Remove(this); w.Remove(this);
Owner = newOwner; Owner = newOwner;
w.Add(this); w.Add(this);
foreach (var t in this.TraitsImplementing<INotifyOwnerChanged>())
t.OnOwnerChanged(this, oldOwner, newOwner);
}); });
} }
} }

View File

@@ -10,6 +10,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Effects namespace OpenRA.Effects
@@ -25,12 +26,12 @@ namespace OpenRA.Effects
this.delay = delay; this.delay = delay;
} }
public void Tick( World world ) public void Tick(World world)
{ {
if (--delay <= 0) if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); a(); }); world.AddFrameEndTask(w => { w.Remove(this); a(); });
} }
public IEnumerable<Renderable> Render() { yield break; } public IEnumerable<Renderable> Render(WorldRenderer wr) { yield break; }
} }
} }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Effects namespace OpenRA.Effects
@@ -32,14 +33,14 @@ namespace OpenRA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (!target.IsInWorld) if (!target.IsInWorld)
yield break; yield break;
if (remainingTicks % 2 == 0) if (remainingTicks % 2 == 0)
foreach (var r in target.Render()) foreach (var r in target.Render(wr))
yield return r.WithPalette("highlight"); yield return r.WithPalette(wr.Palette("highlight"));
} }
} }
} }

View File

@@ -9,13 +9,14 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Effects namespace OpenRA.Effects
{ {
public interface IEffect public interface IEffect
{ {
void Tick( World world ); void Tick(World world);
IEnumerable<Renderable> Render(); IEnumerable<Renderable> Render(WorldRenderer r);
} }
} }

View File

@@ -58,7 +58,7 @@ namespace OpenRA
static string ChooseReplayFilename() static string ChooseReplayFilename()
{ {
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep"); return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ");
} }
static void JoinInner(OrderManager om) static void JoinInner(OrderManager om)

View File

@@ -120,6 +120,26 @@ namespace OpenRA.GameRules
public string ConnectTo = ""; public string ConnectTo = "";
} }
public class KeySettings
{
public string PauseKey = "f3";
public string CycleBaseKey = "backspace";
public string GotoLastEventKey = "space";
public string SellKey = "v";
public string PowerDownKey = "b";
public string RepairKey = "n";
public string AttackMoveKey = "a";
public string StopKey = "s";
public string ScatterKey = "x";
public string StanceCycleKey = "z";
public string DeployKey = "f";
public string CycleTabsKey = "tab";
}
public class Settings public class Settings
{ {
string SettingsFile; string SettingsFile;
@@ -130,6 +150,7 @@ namespace OpenRA.GameRules
public GraphicSettings Graphics = new GraphicSettings(); public GraphicSettings Graphics = new GraphicSettings();
public ServerSettings Server = new ServerSettings(); public ServerSettings Server = new ServerSettings();
public DebugSettings Debug = new DebugSettings(); public DebugSettings Debug = new DebugSettings();
public KeySettings Keys = new KeySettings();
public Dictionary<string, object> Sections; public Dictionary<string, object> Sections;
@@ -144,6 +165,7 @@ namespace OpenRA.GameRules
{"Graphics", Graphics}, {"Graphics", Graphics},
{"Server", Server}, {"Server", Server},
{"Debug", Debug}, {"Debug", Debug},
{"Keys", Keys},
}; };
// Override fieldloader to ignore invalid entries // Override fieldloader to ignore invalid entries

View File

@@ -32,7 +32,7 @@ namespace OpenRA.Graphics
this.DisableFunc = d; this.DisableFunc = d;
} }
public Renderable Image(Actor self, string pal) public Renderable Image(Actor self, PaletteReference pal)
{ {
var p = self.CenterLocation; var p = self.CenterLocation;
var loc = p.ToFloat2() - 0.5f * Animation.Image.size var loc = p.ToFloat2() - 0.5f * Animation.Image.size

View File

@@ -19,6 +19,7 @@ namespace OpenRA.Graphics
{ {
public static class CursorProvider public static class CursorProvider
{ {
public static Dictionary<string, Palette> Palettes { get; private set; }
static Dictionary<string, CursorSequence> cursors; static Dictionary<string, CursorSequence> cursors;
public static void Initialize(string[] sequenceFiles) public static void Initialize(string[] sequenceFiles)
@@ -28,13 +29,14 @@ namespace OpenRA.Graphics
int[] ShadowIndex = { }; int[] ShadowIndex = { };
if (sequences.NodesDict.ContainsKey("ShadowIndex")) if (sequences.NodesDict.ContainsKey("ShadowIndex"))
{ {
Array.Resize(ref ShadowIndex, ShadowIndex.Length + 1); Array.Resize(ref ShadowIndex, ShadowIndex.Length + 1);
ShadowIndex[ShadowIndex.Length - 1] = Convert.ToInt32(sequences.NodesDict["ShadowIndex"].Value); ShadowIndex[ShadowIndex.Length - 1] = Convert.ToInt32(sequences.NodesDict["ShadowIndex"].Value);
} }
Palettes = new Dictionary<string, Palette>();
foreach (var s in sequences.NodesDict["Palettes"].Nodes) foreach (var s in sequences.NodesDict["Palettes"].Nodes)
Game.modData.Palette.AddPalette(s.Key, new Palette(FileSystem.Open(s.Value.Value), ShadowIndex)); Palettes.Add(s.Key, new Palette(FileSystem.Open(s.Value.Value), ShadowIndex));
foreach (var s in sequences.NodesDict["Cursors"].Nodes) foreach (var s in sequences.NodesDict["Cursors"].Nodes)
LoadSequencesForCursor(s.Key, s.Value); LoadSequencesForCursor(s.Key, s.Value);

View File

@@ -25,11 +25,13 @@ namespace OpenRA.Graphics
ITexture texture; ITexture texture;
Dictionary<string, Palette> palettes; Dictionary<string, Palette> palettes;
Dictionary<string, int> indices; Dictionary<string, int> indices;
Dictionary<string, bool> allowsMods;
public HardwarePalette() public HardwarePalette()
{ {
palettes = new Dictionary<string, Palette>(); palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>(); indices = new Dictionary<string, int>();
allowsMods = new Dictionary<string, bool>();
texture = Game.Renderer.Device.CreateTexture(); texture = Game.Renderer.Device.CreateTexture();
} }
@@ -49,22 +51,24 @@ namespace OpenRA.Graphics
return ret; return ret;
} }
public void AddPalette(string name, Palette p) public void AddPalette(string name, Palette p, bool allowModifiers)
{ {
if (palettes.ContainsKey(name)) if (palettes.ContainsKey(name))
throw new InvalidOperationException("Palette {0} has already been defined".F(name)); throw new InvalidOperationException("Palette {0} has already been defined".F(name));
palettes.Add(name, p); palettes.Add(name, p);
indices.Add(name, allocated++); indices.Add(name, allocated++);
allowsMods.Add(name, allowModifiers);
} }
uint[,] data = new uint[MaxPalettes, 256]; uint[,] data = new uint[MaxPalettes, 256];
public void Update(IEnumerable<IPaletteModifier> paletteMods) public void Update(IEnumerable<IPaletteModifier> paletteMods)
{ {
var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value)); var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value));
var modifiable = copy.Where(p => allowsMods[p.Key]).ToDictionary(p => p.Key, p => p.Value);
foreach (var mod in paletteMods) foreach (var mod in paletteMods)
mod.AdjustPalette(copy); mod.AdjustPalette(modifiable);
foreach (var pal in copy) foreach (var pal in copy)
{ {

View File

@@ -50,20 +50,20 @@ namespace OpenRA.Graphics
TempBufferCount = Game.Settings.Graphics.NumTempBuffers; TempBufferCount = Game.Settings.Graphics.NumTempBuffers;
SheetSize = Game.Settings.Graphics.SheetSize; SheetSize = Game.Settings.Graphics.SheetSize;
WorldSpriteShader = device.CreateShader("world-shp"); WorldSpriteShader = device.CreateShader("shp");
WorldLineShader = device.CreateShader("world-line"); WorldLineShader = device.CreateShader("line");
LineShader = device.CreateShader("chrome-line"); LineShader = device.CreateShader("line");
RgbaSpriteShader = device.CreateShader("chrome-rgba"); RgbaSpriteShader = device.CreateShader("rgba");
SpriteShader = device.CreateShader("chrome-shp"); SpriteShader = device.CreateShader("shp");
WorldSpriteRenderer = new SpriteRenderer( this, WorldSpriteShader ); WorldSpriteRenderer = new SpriteRenderer(this, WorldSpriteShader);
WorldLineRenderer = new LineRenderer(this, WorldLineShader); WorldLineRenderer = new LineRenderer(this, WorldLineShader);
LineRenderer = new LineRenderer(this, LineShader); LineRenderer = new LineRenderer(this, LineShader);
RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader ); RgbaSpriteRenderer = new SpriteRenderer(this, RgbaSpriteShader);
SpriteRenderer = new SpriteRenderer( this, SpriteShader ); SpriteRenderer = new SpriteRenderer(this, SpriteShader);
for( int i = 0 ; i < TempBufferCount ; i++ ) for (int i = 0; i < TempBufferCount; i++)
tempBuffers.Enqueue( device.CreateVertexBuffer( TempBufferSize ) ); tempBuffers.Enqueue(device.CreateVertexBuffer(TempBufferSize));
} }
public void InitializeFonts(Manifest m) public void InitializeFonts(Manifest m)
@@ -80,22 +80,22 @@ namespace OpenRA.Graphics
float2 r2 = new float2(-1, 1); float2 r2 = new float2(-1, 1);
var zr1 = zoom*r1; var zr1 = zoom*r1;
SetShaderParams( WorldSpriteShader, zr1, r2, scroll ); SetShaderParams(WorldSpriteShader, zr1, r2, scroll);
SetShaderParams( WorldLineShader, zr1, r2, scroll ); SetShaderParams(WorldLineShader, zr1, r2, scroll);
SetShaderParams( LineShader, r1, r2, scroll ); SetShaderParams(LineShader, r1, r2, float2.Zero);
SetShaderParams( RgbaSpriteShader, r1, r2, scroll ); SetShaderParams(RgbaSpriteShader, r1, r2, float2.Zero);
SetShaderParams( SpriteShader, r1, r2, scroll ); SetShaderParams(SpriteShader, r1, r2, float2.Zero);
} }
void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll ) void SetShaderParams(IShader s, float2 r1, float2 r2, float2 scroll)
{ {
s.SetValue( "Palette", PaletteTexture ); s.SetValue("Palette", PaletteTexture);
s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y ); s.SetValue("Scroll", (int)scroll.X, (int)scroll.Y);
s.SetValue( "r1", r1.X, r1.Y ); s.SetValue("r1", r1.X, r1.Y);
s.SetValue( "r2", r2.X, r2.Y ); s.SetValue("r2", r2.X, r2.Y);
} }
public void EndFrame( IInputHandler inputHandler ) public void EndFrame(IInputHandler inputHandler)
{ {
Flush(); Flush();
device.PumpInput(inputHandler); device.PumpInput(inputHandler);
@@ -129,17 +129,17 @@ namespace OpenRA.Graphics
// which makes the window non-interactive in Windowed/Pseudofullscreen mode. // which makes the window non-interactive in Windowed/Pseudofullscreen mode.
static Screen FixOSX() { return Screen.PrimaryScreen; } static Screen FixOSX() { return Screen.PrimaryScreen; }
internal static void Initialize( WindowMode windowMode ) internal static void Initialize(WindowMode windowMode)
{ {
if (Platform.CurrentPlatform == PlatformType.OSX) if (Platform.CurrentPlatform == PlatformType.OSX)
FixOSX(); FixOSX();
var resolution = GetResolution( windowMode ); var resolution = GetResolution(windowMode);
string renderer = Game.Settings.Server.Dedicated?"Null":Game.Settings.Graphics.Renderer; string renderer = Game.Settings.Server.Dedicated ? "Null" : Game.Settings.Graphics.Renderer;
var rendererPath = Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(renderer) ); var rendererPath = Path.GetFullPath("OpenRA.Renderer.{0}.dll".F(renderer));
device = CreateDevice( Assembly.LoadFile( rendererPath ), resolution.Width, resolution.Height, windowMode ); device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, windowMode);
} }
static Size GetResolution(WindowMode windowmode) static Size GetResolution(WindowMode windowmode)
@@ -150,12 +150,12 @@ namespace OpenRA.Graphics
return new Size(size.X, size.Y); return new Size(size.X, size.Y);
} }
static IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, WindowMode window ) static IGraphicsDevice CreateDevice(Assembly rendererDll, int width, int height, WindowMode window)
{ {
foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) ) foreach (RendererAttribute r in rendererDll.GetCustomAttributes(typeof(RendererAttribute), false))
{ {
var factory = (IDeviceFactory) r.Type.GetConstructor( Type.EmptyTypes ).Invoke( null ); var factory = (IDeviceFactory)r.Type.GetConstructor(Type.EmptyTypes).Invoke(null);
return factory.Create( new Size( width, height ), window ); return factory.Create(new Size(width, height), window);
} }
throw new InvalidOperationException("Renderer DLL is missing RendererAttribute to tell us what type to use!"); throw new InvalidOperationException("Renderer DLL is missing RendererAttribute to tell us what type to use!");
@@ -164,7 +164,7 @@ namespace OpenRA.Graphics
internal IVertexBuffer<Vertex> GetTempVertexBuffer() internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{ {
var ret = tempBuffers.Dequeue(); var ret = tempBuffers.Dequeue();
tempBuffers.Enqueue( ret ); tempBuffers.Enqueue(ret);
return ret; return ret;
} }
@@ -176,8 +176,8 @@ namespace OpenRA.Graphics
get { return currentBatchRenderer; } get { return currentBatchRenderer; }
set set
{ {
if( currentBatchRenderer == value ) return; if (currentBatchRenderer == value) return;
if( currentBatchRenderer != null ) if (currentBatchRenderer != null)
currentBatchRenderer.Flush(); currentBatchRenderer.Flush();
currentBatchRenderer = value; currentBatchRenderer = value;
} }
@@ -186,7 +186,7 @@ namespace OpenRA.Graphics
public void EnableScissor(int left, int top, int width, int height) public void EnableScissor(int left, int top, int width, int height)
{ {
Flush(); Flush();
Device.EnableScissor( left, top, width, height ); Device.EnableScissor(left, top, width, height);
} }
public void DisableScissor() public void DisableScissor()

View File

@@ -18,12 +18,13 @@ namespace OpenRA.Graphics
public class Sequence public class Sequence
{ {
readonly Sprite[] sprites; readonly Sprite[] sprites;
readonly int start, length, facings, tick; readonly int start, length, stride, facings, tick;
public readonly string Name; public readonly string Name;
public int Start { get { return start; } } public int Start { get { return start; } }
public int End { get { return start + length; } } public int End { get { return start + length; } }
public int Length { get { return length; } } public int Length { get { return length; } }
public int Stride { get { return stride; } }
public int Facings { get { return facings; } } public int Facings { get { return facings; } }
public int Tick { get { return tick; } } public int Tick { get { return tick; } }
@@ -43,6 +44,10 @@ namespace OpenRA.Graphics
else else
length = int.Parse(d["Length"].Value); length = int.Parse(d["Length"].Value);
if (d.ContainsKey("Stride"))
stride = int.Parse(d["Stride"].Value);
else
stride = length;
if(d.ContainsKey("Facings")) if(d.ContainsKey("Facings"))
facings = int.Parse(d["Facings"].Value); facings = int.Parse(d["Facings"].Value);
@@ -54,10 +59,15 @@ namespace OpenRA.Graphics
else else
tick = 40; tick = 40;
if (start < 0 || start + facings * length > sprites.Length) if (length > stride)
throw new InvalidOperationException(
"{0}: Sequence {1}.{2}: Length must be <= stride"
.F(info.Nodes[0].Location, unit, name));
if (start < 0 || start + facings * stride > sprites.Length)
throw new InvalidOperationException( throw new InvalidOperationException(
"{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist" "{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist"
.F(unit, name, start, start + facings * length - 1, srcOverride ?? unit, sprites.Length - 1, .F(unit, name, start, start + facings * stride - 1, srcOverride ?? unit, sprites.Length - 1,
info.Nodes[0].Location)); info.Nodes[0].Location));
} }
@@ -69,7 +79,7 @@ namespace OpenRA.Graphics
public Sprite GetSprite(int frame, int facing) public Sprite GetSprite(int frame, int facing)
{ {
var f = Traits.Util.QuantizeFacing( facing, facings ); var f = Traits.Util.QuantizeFacing( facing, facings );
return sprites[ (f * length) + ( frame % length ) + start ]; return sprites[ (f * stride) + ( frame % length ) + start ];
} }
} }
} }

View File

@@ -105,8 +105,17 @@ namespace OpenRA.Graphics
return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
} }
internal void Draw( WorldRenderer wr ) bool initializePalettes = true;
PaletteReference fogPalette, shroudPalette;
internal void Draw(WorldRenderer wr)
{ {
if (initializePalettes)
{
fogPalette = wr.Palette("fog");
shroudPalette = wr.Palette("shroud");
initializePalettes = false;
}
if (shroud != null && shroud.dirty) if (shroud != null && shroud.dirty)
{ {
shroud.dirty = false; shroud.dirty = false;
@@ -120,14 +129,12 @@ namespace OpenRA.Graphics
} }
var clipRect = Game.viewport.WorldBounds(wr.world); var clipRect = Game.viewport.WorldBounds(wr.world);
DrawShroud( wr, clipRect, fogSprites, "fog" ); DrawShroud(wr, clipRect, fogSprites, fogPalette);
DrawShroud( wr, clipRect, sprites, "shroud" ); DrawShroud(wr, clipRect, sprites, shroudPalette);
} }
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal ) void DrawShroud(WorldRenderer wr, Rectangle clip, Sprite[,] s, PaletteReference pal)
{ {
var shroudPalette = wr.GetPaletteIndex(pal);
for (var j = clip.Top; j < clip.Bottom; j++) for (var j = clip.Top; j < clip.Bottom; j++)
{ {
var starti = clip.Left; var starti = clip.Left;
@@ -142,14 +149,14 @@ namespace OpenRA.Graphics
{ {
s[starti, j].DrawAt( s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j), Game.CellSize * new float2(starti, j),
shroudPalette, pal.Index,
new float2(Game.CellSize * (i - starti), Game.CellSize)); new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i + 1; starti = i + 1;
} }
s[i, j].DrawAt( s[i, j].DrawAt(
Game.CellSize * new float2(i, j), Game.CellSize * new float2(i, j),
shroudPalette); pal.Index);
starti = i + 1; starti = i + 1;
last = s[i, j]; last = s[i, j];
} }
@@ -157,7 +164,7 @@ namespace OpenRA.Graphics
if (starti < clip.Right) if (starti < clip.Right)
s[starti, j].DrawAt( s[starti, j].DrawAt(
Game.CellSize * new float2(starti, j), Game.CellSize * new float2(starti, j),
shroudPalette, pal.Index,
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize)); new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
} }
} }

View File

@@ -49,12 +49,12 @@ namespace OpenRA.Graphics
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette) public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette)
{ {
DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size); DrawSprite(s, location, wr.Palette(palette).Index, s.size);
} }
public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size) public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size)
{ {
DrawSprite(s, location, wr.GetPaletteIndex(palette), size); DrawSprite(s, location, wr.Palette(palette).Index, size);
} }
public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Graphics
int nv = 0; int nv = 0;
var terrainPalette = Game.modData.Palette.GetPaletteIndex("terrain"); var terrainPalette = wr.Palette("terrain").Index;
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ ) for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ ) for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )

View File

@@ -133,7 +133,7 @@ namespace OpenRA.Graphics
renderer.SpriteRenderer.DrawSprite(cursorSprite, renderer.SpriteRenderer.DrawSprite(cursorSprite,
Viewport.LastMousePos - cursorSequence.Hotspot, Viewport.LastMousePos - cursorSequence.Hotspot,
Game.modData.Palette.GetPaletteIndex(cursorSequence.Palette), wr.Palette(cursorSequence.Palette).Index,
cursorSprite.size); cursorSprite.size);
} }

View File

@@ -17,27 +17,56 @@ using OpenRA.Traits;
namespace OpenRA.Graphics namespace OpenRA.Graphics
{ {
public class PaletteReference
{
public readonly string Name;
public readonly int Index;
public readonly Palette Palette;
public PaletteReference(string name, int index, Palette palette)
{
Name = name;
Index = index;
Palette = palette;
}
}
public class WorldRenderer public class WorldRenderer
{ {
public readonly World world; public readonly World world;
internal readonly TerrainRenderer terrainRenderer; internal readonly TerrainRenderer terrainRenderer;
internal readonly ShroudRenderer shroudRenderer; internal readonly ShroudRenderer shroudRenderer;
internal readonly HardwarePalette palette; internal readonly HardwarePalette palette;
internal Cache<string, PaletteReference> palettes;
internal WorldRenderer(World world) internal WorldRenderer(World world)
{ {
this.world = world; this.world = world;
this.palette = Game.modData.Palette; palette = new HardwarePalette();
foreach( var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>( world ) ) foreach (var p in CursorProvider.Palettes)
palette.AddPalette(p.Key, p.Value, false);
palettes = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var pal in world.traitDict.ActorsWithTraitMultiple<IPalette>(world))
pal.Trait.InitPalette( this ); pal.Trait.InitPalette( this );
// Generate initial palette texture
palette.Update(new IPaletteModifier[] {});
terrainRenderer = new TerrainRenderer(world, this); terrainRenderer = new TerrainRenderer(world, this);
shroudRenderer = new ShroudRenderer(world); shroudRenderer = new ShroudRenderer(world);
} }
public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); } PaletteReference CreatePaletteReference(string name)
public Palette GetPalette(string name) { return palette.GetPalette(name); } {
public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); } var pal = palette.GetPalette(name);
if (pal == null)
throw new InvalidOperationException("Palette `{0}` does not exist".F(name));
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
}
public PaletteReference Palette(string name) { return palettes[name]; }
public void AddPalette(string name, Palette pal, bool allowModifiers) { palette.AddPalette(name, pal, allowModifiers); }
class SpriteComparer : IComparer<Renderable> class SpriteComparer : IComparer<Renderable>
{ {
@@ -57,10 +86,10 @@ namespace OpenRA.Graphics
bounds.BottomRightAsCPos().ToPPos() bounds.BottomRightAsCPos().ToPPos()
); );
var renderables = actors.SelectMany(a => a.Render()) var renderables = actors.SelectMany(a => a.Render(this))
.OrderBy(r => r, comparer); .OrderBy(r => r, comparer);
var effects = world.Effects.SelectMany(e => e.Render()); var effects = world.Effects.SelectMany(e => e.Render(this));
return renderables.Concat(effects); return renderables.Concat(effects);
} }
@@ -77,8 +106,8 @@ namespace OpenRA.Graphics
terrainRenderer.Draw(this, Game.viewport); terrainRenderer.Draw(this, Game.viewport);
foreach (var a in world.traitDict.ActorsWithTraitMultiple<IRenderAsTerrain>(world)) foreach (var a in world.traitDict.ActorsWithTraitMultiple<IRenderAsTerrain>(world))
foreach (var r in a.Trait.RenderAsTerrain(a.Actor)) foreach (var r in a.Trait.RenderAsTerrain(this, a.Actor))
r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale); r.Sprite.DrawAt(r.Pos, r.Palette.Index, r.Scale);
foreach (var a in world.Selection.Actors) foreach (var a in world.Selection.Actors)
if (!a.Destroyed) if (!a.Destroyed)
@@ -91,7 +120,7 @@ namespace OpenRA.Graphics
world.OrderGenerator.RenderBeforeWorld(this, world); world.OrderGenerator.RenderBeforeWorld(this, world);
foreach (var image in SpritesToRender()) foreach (var image in SpritesToRender())
image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale); image.Sprite.DrawAt(image.Pos, image.Palette.Index, image.Scale);
// added for contrails // added for contrails
foreach (var a in world.ActorsWithTrait<IPostRender>()) foreach (var a in world.ActorsWithTrait<IPostRender>())

View File

@@ -28,7 +28,6 @@ namespace OpenRA
public ILoadScreen LoadScreen = null; public ILoadScreen LoadScreen = null;
public SheetBuilder SheetBuilder; public SheetBuilder SheetBuilder;
public SpriteLoader SpriteLoader; public SpriteLoader SpriteLoader;
public HardwarePalette Palette { get; private set; }
public ModData( params string[] mods ) public ModData( params string[] mods )
{ {
@@ -51,13 +50,11 @@ namespace OpenRA
AvailableMaps = FindMaps(Manifest.Mods); AvailableMaps = FindMaps(Manifest.Mods);
Palette = new HardwarePalette();
ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeMetrics.Initialize(Manifest.ChromeMetrics);
ChromeProvider.Initialize(Manifest.Chrome); ChromeProvider.Initialize(Manifest.Chrome);
SheetBuilder = new SheetBuilder(TextureChannel.Red); SheetBuilder = new SheetBuilder(TextureChannel.Red);
SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder); SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder);
CursorProvider.Initialize(Manifest.Cursors); CursorProvider.Initialize(Manifest.Cursors);
Palette.Update(new IPaletteModifier[] { });
} }
public Map PrepareMap(string uid) public Map PrepareMap(string uid)

View File

@@ -34,12 +34,23 @@ namespace OpenRA.Network
void StartSavingReplay(byte[] initialContent) void StartSavingReplay(byte[] initialContent)
{ {
var filename = chooseFilename(); var filename = chooseFilename();
var replayPath = Path.Combine(Platform.SupportDir, "Replays"); var replaysDirectory = Path.Combine(Platform.SupportDir, "Replays");
if (!Directory.Exists(replayPath)) if (!Directory.Exists(replaysDirectory))
Directory.CreateDirectory(replayPath); Directory.CreateDirectory(replaysDirectory);
var file = File.Create(Path.Combine(replayPath, filename)); string fullFilename;
var id = -1;
do
{
fullFilename = Path.Combine(replaysDirectory, id < 0
? "{0}.rep".F(filename)
: "{0}-{1}.rep".F(filename, id));
id++;
}
while (File.Exists(fullFilename));
var file = File.Create(fullFilename);
file.Write(initialContent); file.Write(initialContent);
this.writer = new BinaryWriter(file); this.writer = new BinaryWriter(file);
} }

View File

@@ -42,7 +42,9 @@ namespace OpenRA.Network
public class Client public class Client
{ {
public int Index; public int Index;
public ColorRamp ColorRamp; public ColorRamp PreferredColorRamp; // Color that the client normally uses from settings.yaml.
public ColorRamp ColorRamp; // Actual color that the client is using.
// Usually the same as PreferredColorRamp but can be different on maps with locked colors.
public string Country; public string Country;
public int SpawnPoint; public int SpawnPoint;
public string Name; public string Name;
@@ -79,6 +81,7 @@ namespace OpenRA.Network
public bool AllowCheats = false; public bool AllowCheats = false;
public bool Dedicated; public bool Dedicated;
public string Difficulty; public string Difficulty;
public bool Crates = true;
} }
public Session(string[] mods) public Session(string[] mods)

View File

@@ -36,6 +36,7 @@ namespace OpenRA.Network
{ {
report.Frame = orderManager.NetFrameNumber; report.Frame = orderManager.NetFrameNumber;
report.SyncedRandom = orderManager.world.SharedRandom.Last; report.SyncedRandom = orderManager.world.SharedRandom.Last;
report.TotalCount = orderManager.world.SharedRandom.TotalCount;
report.Traits.Clear(); report.Traits.Clear();
foreach (var a in orderManager.world.ActorsWithTrait<ISync>()) foreach (var a in orderManager.world.ActorsWithTrait<ISync>())
{ {
@@ -58,7 +59,7 @@ namespace OpenRA.Network
if (r.Frame == frame) if (r.Frame == frame)
{ {
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame); Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
Log.Write("sync", "SharedRandom: "+r.SyncedRandom); Log.Write("sync", "SharedRandom: {0} (#{1})", r.SyncedRandom, r.TotalCount);
Log.Write("sync", "Synced Traits:"); Log.Write("sync", "Synced Traits:");
foreach (var a in r.Traits) foreach (var a in r.Traits)
Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F( Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(
@@ -77,6 +78,7 @@ namespace OpenRA.Network
{ {
public int Frame; public int Frame;
public int SyncedRandom; public int SyncedRandom;
public int TotalCount;
public List<TraitReport> Traits = new List<TraitReport>(); public List<TraitReport> Traits = new List<TraitReport>();
} }

View File

@@ -119,6 +119,7 @@ namespace OpenRA.Network
var info = new Session.Client() var info = new Session.Client()
{ {
Name = Game.Settings.Player.Name, Name = Game.Settings.Player.Name,
PreferredColorRamp = Game.Settings.Player.ColorRamp,
ColorRamp = Game.Settings.Player.ColorRamp, ColorRamp = Game.Settings.Player.ColorRamp,
Country = "random", Country = "random",
SpawnPoint = 0, SpawnPoint = 0,

View File

@@ -374,6 +374,8 @@ namespace OpenRA.Server
return; return;
if (pr.LockColor) if (pr.LockColor)
c.ColorRamp = pr.ColorRamp; c.ColorRamp = pr.ColorRamp;
else
c.ColorRamp = c.PreferredColorRamp;
if (pr.LockRace) if (pr.LockRace)
c.Country = pr.Race; c.Country = pr.Race;
if (pr.LockSpawn) if (pr.LockSpawn)

View File

@@ -76,8 +76,7 @@ namespace OpenRA.Traits
case "DevShroud": case "DevShroud":
{ {
DisableShroud ^= true; DisableShroud ^= true;
if (self.World.LocalPlayer == self.Owner) self.Owner.Shroud.Disabled = DisableShroud;
self.World.RenderedShroud.Disabled = DisableShroud;
break; break;
} }
case "DevPathDebug": case "DevPathDebug":
@@ -87,8 +86,7 @@ namespace OpenRA.Traits
} }
case "DevGiveExploration": case "DevGiveExploration":
{ {
if (self.World.LocalPlayer == self.Owner) self.Owner.Shroud.ExploreAll(self.World);
self.World.LocalPlayer.Shroud.ExploreAll(self.World);
break; break;
} }
case "DevUnlimitedPower": case "DevUnlimitedPower":

View File

@@ -10,6 +10,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
namespace OpenRA.Traits namespace OpenRA.Traits
@@ -23,16 +24,16 @@ namespace OpenRA.Traits
public virtual object Create(ActorInitializer init) { return new RenderSimple(init.self); } public virtual object Create(ActorInitializer init) { return new RenderSimple(init.self); }
public virtual IEnumerable<Renderable> RenderPreview(ActorInfo building, Player owner) public virtual IEnumerable<Renderable> RenderPreview(ActorInfo building, PaletteReference pr)
{ {
var anim = new Animation(RenderSimple.GetImage(building), () => 0); var anim = new Animation(RenderSimple.GetImage(building), () => 0);
anim.PlayRepeating("idle"); anim.PlayRepeating("idle");
yield return new Renderable(anim.Image, 0.5f * anim.Image.size * (1 - Scale),
Palette ?? (owner != null ? PlayerPalette + owner.InternalName : null), 0, Scale); yield return new Renderable(anim.Image, 0.5f * anim.Image.size * (1 - Scale), pr, 0, Scale);
} }
} }
public class RenderSimple : IRender, ITick public class RenderSimple : IRender, IAutoSelectionSize, ITick, INotifyOwnerChanged
{ {
public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>(); public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
@@ -55,7 +56,6 @@ namespace OpenRA.Traits
return Info.Image ?? actor.Name; return Info.Image ?? actor.Name;
} }
string cachedImage = null;
public string GetImage(Actor self) public string GetImage(Actor self)
{ {
if (cachedImage != null) if (cachedImage != null)
@@ -65,6 +65,9 @@ namespace OpenRA.Traits
} }
RenderSimpleInfo Info; RenderSimpleInfo Info;
string cachedImage = null;
bool initializePalette = true;
protected PaletteReference palette;
public RenderSimple(Actor self, Func<int> baseFacing) public RenderSimple(Actor self, Func<int> baseFacing)
{ {
@@ -77,20 +80,40 @@ namespace OpenRA.Traits
anim.PlayRepeating("idle"); anim.PlayRepeating("idle");
} }
public string Palette(Player p) { return Info.Palette ?? Info.PlayerPalette + p.InternalName; } protected virtual string PaletteName(Actor self)
public virtual IEnumerable<Renderable> Render(Actor self)
{ {
return Info.Palette ?? Info.PlayerPalette + self.Owner.InternalName;
}
protected void UpdatePalette() { initializePalette = true; }
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { UpdatePalette(); }
public virtual IEnumerable<Renderable> Render(Actor self, WorldRenderer wr)
{
if (initializePalette)
{
palette = wr.Palette(PaletteName(self));
initializePalette = false;
}
foreach (var a in anims.Values) foreach (var a in anims.Values)
if (a.DisableFunc == null || !a.DisableFunc()) if (a.DisableFunc == null || !a.DisableFunc())
{ {
Renderable ret = a.Image(self, Palette(self.Owner)); Renderable ret = a.Image(self, palette);
if (Info.Scale != 1f) if (Info.Scale != 1f)
ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f * ret.Sprite.size * (1 - Info.Scale)); ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f * ret.Sprite.size * (1 - Info.Scale));
yield return ret; yield return ret;
} }
} }
public int2 SelectionSize(Actor self)
{
return anims.Values.Where(b => (b.DisableFunc == null || !b.DisableFunc())
&& b.Animation.CurrentSequence != null)
.Select(a => (a.Animation.Image.size*Info.Scale).ToInt2())
.FirstOrDefault();
}
public virtual void Tick(Actor self) public virtual void Tick(Actor self)
{ {
foreach (var a in anims.Values) foreach (var a in anims.Values)

View File

@@ -34,7 +34,8 @@ namespace OpenRA.Traits
} }
public interface ITick { void Tick(Actor self); } public interface ITick { void Tick(Actor self); }
public interface IRender { IEnumerable<Renderable> Render(Actor self); } public interface IRender { IEnumerable<Renderable> Render(Actor self, WorldRenderer wr); }
public interface IAutoSelectionSize { int2 SelectionSize(Actor self); }
public interface IIssueOrder public interface IIssueOrder
{ {
@@ -62,6 +63,7 @@ namespace OpenRA.Traits
public interface INotifyAppliedDamage { void AppliedDamage(Actor self, Actor damaged, AttackInfo e); } public interface INotifyAppliedDamage { void AppliedDamage(Actor self, Actor damaged, AttackInfo e); }
public interface INotifyBuildComplete { void BuildingComplete(Actor self); } public interface INotifyBuildComplete { void BuildingComplete(Actor self); }
public interface INotifyProduction { void UnitProduced(Actor self, Actor other, CPos exit); } public interface INotifyProduction { void UnitProduced(Actor self, Actor other, CPos exit); }
public interface INotifyOwnerChanged { void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner); }
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); }
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
@@ -113,7 +115,7 @@ namespace OpenRA.Traits
} }
public interface INotifyAttack { void Attacking(Actor self, Target target); } public interface INotifyAttack { void Attacking(Actor self, Target target); }
public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); } public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r); }
public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); } public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); }
public interface ISpeedModifier { decimal GetSpeedModifier(); } public interface ISpeedModifier { decimal GetSpeedModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); } public interface IFirepowerModifier { float GetFirepowerModifier(); }
@@ -154,12 +156,12 @@ namespace OpenRA.Traits
{ {
public readonly Sprite Sprite; public readonly Sprite Sprite;
public readonly float2 Pos; public readonly float2 Pos;
public readonly string Palette; public readonly PaletteReference Palette;
public readonly int Z; public readonly int Z;
public readonly int ZOffset; public readonly int ZOffset;
public float Scale; public float Scale;
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale) public Renderable(Sprite sprite, float2 pos, PaletteReference palette, int z, int zOffset, float scale)
{ {
Sprite = sprite; Sprite = sprite;
Pos = pos; Pos = pos;
@@ -169,14 +171,14 @@ namespace OpenRA.Traits
Scale = scale; /* default */ Scale = scale; /* default */
} }
public Renderable(Sprite sprite, float2 pos, string palette, int z) public Renderable(Sprite sprite, float2 pos, PaletteReference palette, int z)
: this(sprite, pos, palette, z, 0, 1f) { } : this(sprite, pos, palette, z, 0, 1f) { }
public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale) public Renderable(Sprite sprite, float2 pos, PaletteReference palette, int z, float scale)
: this(sprite, pos, palette, z, 0, scale) { } : this(sprite, pos, palette, z, 0, scale) { }
public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); } public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); }
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); } public Renderable WithPalette(PaletteReference newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); }
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); } public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); }
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); } public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); }
} }
@@ -208,7 +210,7 @@ namespace OpenRA.Traits
public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr); } public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr); }
public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); } public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); }
public interface IRenderAsTerrain { IEnumerable<Renderable> RenderAsTerrain(Actor self); } public interface IRenderAsTerrain { IEnumerable<Renderable> RenderAsTerrain(WorldRenderer wr, Actor self); }
public interface ITargetable public interface ITargetable
{ {

View File

@@ -18,6 +18,7 @@ namespace OpenRA.Traits
public readonly string BasePalette = null; public readonly string BasePalette = null;
public readonly string BaseName = "player"; public readonly string BaseName = "player";
public readonly int[] RemapIndex = {}; public readonly int[] RemapIndex = {};
public readonly bool AllowModifiers = true;
public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); } public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); }
} }
@@ -36,9 +37,9 @@ namespace OpenRA.Traits
public void InitPalette( WorldRenderer wr ) public void InitPalette( WorldRenderer wr )
{ {
var paletteName = "{0}{1}".F( info.BaseName, owner.InternalName ); var paletteName = "{0}{1}".F( info.BaseName, owner.InternalName );
var newpal = new Palette(wr.GetPalette(info.BasePalette), var newpal = new Palette(wr.Palette(info.BasePalette).Palette,
new PlayerColorRemap(info.RemapIndex, owner.ColorRamp)); new PlayerColorRemap(info.RemapIndex, owner.ColorRamp));
wr.AddPalette(paletteName, newpal); wr.AddPalette(paletteName, newpal, info.AllowModifiers);
} }
} }
} }

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Traits
{ {
hasSetupPalettes = true; hasSetupPalettes = true;
foreach (var rt in world.WorldActor.TraitsImplementing<ResourceType>()) foreach (var rt in world.WorldActor.TraitsImplementing<ResourceType>())
rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette); rt.info.PaletteRef = wr.Palette(rt.info.Palette);
} }
var clip = Game.viewport.WorldBounds(world); var clip = Game.viewport.WorldBounds(world);
@@ -47,7 +47,7 @@ namespace OpenRA.Traits
if (c.image != null) if (c.image != null)
c.image[c.density].DrawAt( c.image[c.density].DrawAt(
new CPos(x, y).ToPPos().ToFloat2(), new CPos(x, y).ToPPos().ToFloat2(),
c.type.info.PaletteIndex); c.type.info.PaletteRef.Index);
} }
} }

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Traits
public readonly bool AllowUnderActors = false; public readonly bool AllowUnderActors = false;
public Sprite[][] Sprites; public Sprite[][] Sprites;
public int PaletteIndex; public PaletteReference PaletteRef;
public PipType PipColor = PipType.Yellow; public PipType PipColor = PipType.Yellow;

View File

@@ -137,6 +137,9 @@ namespace OpenRA.Traits
if (a.Owner.World.LocalPlayer == null if (a.Owner.World.LocalPlayer == null
|| a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally) return; || a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally) return;
if (v == null)
return;
foreach (var p in v.vis) foreach (var p in v.vis)
foreach (var q in FindVisibleTiles(a.World, p, range)) foreach (var q in FindVisibleTiles(a.World, p, range))
foggedCells[q.X, q.Y] = exploredCells[q.X, q.Y]; foggedCells[q.X, q.Y] = exploredCells[q.X, q.Y];

View File

@@ -101,7 +101,7 @@ namespace OpenRA.Widgets
var xAxisSize = GetXAxisSize(); var xAxisSize = GetXAxisSize();
var yAxisSize = GetYAxisSize(); var yAxisSize = GetYAxisSize();
var maxValue = GetSeries().Select(p => p.Points).SelectMany(d => d).Max(); var maxValue = GetSeries().Select(p => p.Points).SelectMany(d => d).Concat(new[] { 0f }).Max();
var scale = 200 / Math.Max(5000, (float)Math.Ceiling(maxValue / 1000) * 1000); var scale = 200 / Math.Max(5000, (float)Math.Ceiling(maxValue / 1000) * 1000);
var xStep = width / xAxisSize; var xStep = width / xAxisSize;

View File

@@ -127,7 +127,7 @@ namespace OpenRA
public static float Gauss1D(this Thirdparty.Random r, int samples) public static float Gauss1D(this Thirdparty.Random r, int samples)
{ {
return Exts.MakeArray(samples, _ => (float)r.NextDouble() * 2 - 1f) return Exts.MakeArray(samples, _ => r.NextFloat() * 2 - 1f)
.Sum() / samples; .Sum() / samples;
} }

View File

@@ -61,8 +61,6 @@ namespace OpenRA.Mods.Cnc
} }
} }
static Set<string> excludePalettes = new Set<string>("cursor", "chrome", "colorpicker", "shroud", "fog");
public void AdjustPalette(Dictionary<string,Palette> palettes) public void AdjustPalette(Dictionary<string,Palette> palettes)
{ {
if (to == EffectType.None && remainingFrames == 0) if (to == EffectType.None && remainingFrames == 0)
@@ -70,9 +68,6 @@ namespace OpenRA.Mods.Cnc
foreach (var pal in palettes) foreach (var pal in palettes)
{ {
if (excludePalettes.Contains(pal.Key))
continue;
for (var x = 0; x < 256; x++) for (var x = 0; x < 256; x++)
{ {
var orig = pal.Value.GetColor(x); var orig = pal.Value.GetColor(x);

View File

@@ -32,11 +32,11 @@ namespace OpenRA.Mods.Cnc.Effects
public void Tick(World world) { anim.Tick(); } public void Tick(World world) { anim.Tick(); }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, yield return new Renderable(anim.Image,
target.CenterLocation.ToFloat2() - new float2(.5f * anim.Image.size.X, anim.Image.size.Y - Game.CellSize), target.CenterLocation.ToFloat2() - new float2(.5f * anim.Image.size.X, anim.Image.size.Y - Game.CellSize),
"effect", (int)target.CenterLocation.Y); wr.Palette("effect"), (int)target.CenterLocation.Y);
} }
void Finish( World world ) void Finish( World world )

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Mods.RA; using OpenRA.Mods.RA;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Cnc namespace OpenRA.Mods.Cnc
@@ -39,7 +40,7 @@ namespace OpenRA.Mods.Cnc
Info = info; Info = info;
} }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
foreach (var c in cargo.Passengers) foreach (var c in cargo.Passengers)
{ {
@@ -55,7 +56,7 @@ namespace OpenRA.Mods.Cnc
Info.PassengerTypes.Contains(p.Trait<Passenger>().info.CargoType)) Info.PassengerTypes.Contains(p.Trait<Passenger>().info.CargoType))
: cargo.Passengers; : cargo.Passengers;
return r.Concat(visiblePassengers.SelectMany(a => a.Render()) return r.Concat(visiblePassengers.SelectMany(a => a.Render(wr))
.Select(a => a.WithPos(a.Pos - new float2(0, Info.RelativeAltitude)) .Select(a => a.WithPos(a.Pos - new float2(0, Info.RelativeAltitude))
.WithZOffset(a.ZOffset + Info.RelativeAltitude))); .WithZOffset(a.ZOffset + Info.RelativeAltitude)));
} }

View File

@@ -10,6 +10,7 @@
using System; using System;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
@@ -20,7 +21,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
Widget menu; Widget menu;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public CncIngameMenuLogic(Widget widget, World world, Action onExit) public CncIngameMenuLogic(Widget widget, World world, Action onExit, WorldRenderer worldRenderer)
{ {
var resumeDisabled = false; var resumeDisabled = false;
menu = widget.Get("INGAME_MENU"); menu = widget.Get("INGAME_MENU");
@@ -72,6 +73,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs() Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs()
{ {
{ "world", world }, { "world", world },
{ "worldRenderer", worldRenderer },
{ "onExit", () => hideButtons = false }, { "onExit", () => hideButtons = false },
}); });
}; };

View File

@@ -85,9 +85,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
settingsMenu.Get<ButtonWidget>("SETTINGS_BUTTON").OnClick = () => settingsMenu.Get<ButtonWidget>("SETTINGS_BUTTON").OnClick = () =>
{ {
Menu = MenuType.None; Menu = MenuType.None;
Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs() Game.OpenWindow("SETTINGS_PANEL", new WidgetArgs()
{ {
{ "world", world },
{ "onExit", () => Menu = MenuType.Settings }, { "onExit", () => Menu = MenuType.Settings },
}); });
}; };

View File

@@ -6,6 +6,7 @@
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
* see COPYING. * see COPYING.
*/ */
#endregion #endregion
using System; using System;
@@ -17,6 +18,7 @@ using OpenRA.GameRules;
using OpenRA.Mods.RA; using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Widgets.Logic; using OpenRA.Mods.RA.Widgets.Logic;
using OpenRA.Widgets; using OpenRA.Widgets;
using OpenRA.Mods.RA.Widgets;
namespace OpenRA.Mods.Cnc.Widgets.Logic namespace OpenRA.Mods.Cnc.Widgets.Logic
{ {
@@ -25,7 +27,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
enum PanelType { General, Input } enum PanelType { General, Input }
PanelType Settings = PanelType.General; PanelType Settings = PanelType.General;
ColorPickerPaletteModifier playerPalettePreview; ColorPreviewManagerWidget colorPreview;
World world; World world;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
@@ -52,8 +54,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
var nameTextfield = generalPane.Get<TextFieldWidget>("NAME_TEXTFIELD"); var nameTextfield = generalPane.Get<TextFieldWidget>("NAME_TEXTFIELD");
nameTextfield.Text = playerSettings.Name; nameTextfield.Text = playerSettings.Name;
playerPalettePreview = world.WorldActor.Trait<ColorPickerPaletteModifier>(); colorPreview = panel.Get<ColorPreviewManagerWidget>("COLOR_MANAGER");
playerPalettePreview.Ramp = playerSettings.ColorRamp; colorPreview.Ramp = playerSettings.ColorRamp;
var colorDropdown = generalPane.Get<DropDownButtonWidget>("COLOR"); var colorDropdown = generalPane.Get<DropDownButtonWidget>("COLOR");
colorDropdown.OnMouseDown = _ => ShowColorPicker(colorDropdown, playerSettings); colorDropdown.OnMouseDown = _ => ShowColorPicker(colorDropdown, playerSettings);
@@ -153,8 +155,8 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
bool ShowColorPicker(DropDownButtonWidget color, PlayerSettings s) bool ShowColorPicker(DropDownButtonWidget color, PlayerSettings s)
{ {
Action<ColorRamp> onSelect = c => { s.ColorRamp = c; color.RemovePanel(); }; Action<ColorRamp> onSelect = c => {s.ColorRamp = c; color.RemovePanel();};
Action<ColorRamp> onChange = c => { playerPalettePreview.Ramp = c; }; Action<ColorRamp> onChange = c => {colorPreview.Ramp = c;};
var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs() var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs()
{ {

View File

@@ -266,7 +266,7 @@ namespace OpenRA.Mods.Cnc.Widgets
public override bool HandleKeyPress(KeyInput e) public override bool HandleKeyPress(KeyInput e)
{ {
if (e.Event != KeyInputEvent.Down) return false; if (e.Event != KeyInputEvent.Down) return false;
if (e.KeyName == "tab") if (e.KeyName == Game.Settings.Keys.CycleTabsKey)
{ {
Sound.PlayNotification(null, "Sounds", "ClickSound", null); Sound.PlayNotification(null, "Sounds", "ClickSound", null);
SelectNextTab(e.Modifiers.HasModifier(Modifiers.Shift)); SelectNextTab(e.Modifiers.HasModifier(Modifiers.Shift));

View File

@@ -35,10 +35,8 @@ namespace OpenRA.Mods.RA
if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && aircraft.Altitude > 10 if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && aircraft.Altitude > 10
&& self.Owner.WinState != WinState.Lost) && self.Owner.WinState != WinState.Lost)
{ {
self.World.AddFrameEndTask(w => w.Add( self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot,
new Parachute(pilot.Owner, Util.CenterOfCell(self.CenterLocation.ToCPos()), aircraft.Altitude)));
Util.CenterOfCell(self.CenterLocation.ToCPos()),
aircraft.Altitude, pilot)));
Sound.Play(info.ChuteSound, self.CenterLocation); Sound.Play(info.ChuteSound, self.CenterLocation);
} }

View File

@@ -38,13 +38,12 @@ namespace OpenRA.Mods.RA.Air
} }
var attack = self.Trait<AttackHeli>(); var attack = self.Trait<AttackHeli>();
var range = attack.GetMaximumRange() * 0.625f;
var dist = target.CenterLocation - self.CenterLocation; var dist = target.CenterLocation - self.CenterLocation;
var desiredFacing = Util.GetFacing(dist, aircraft.Facing); var desiredFacing = Util.GetFacing(dist, aircraft.Facing);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
if( !float2.WithinEpsilon( float2.Zero, dist.ToFloat2(), range * Game.CellSize ) ) if (!Combat.IsInRange(self.CenterLocation, attack.GetMaximumRange(), target))
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing); aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing);
attack.DoAttack( self, target ); attack.DoAttack( self, target );

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Air
} }
var dist = Dest - aircraft.PxPosition; var dist = Dest - aircraft.PxPosition;
if (float2.WithinEpsilon(float2.Zero, dist.ToFloat2(), 2)) if (Math.Abs(dist.X) < 2 && Math.Abs(dist.Y) < 2)
{ {
aircraft.SubPxPosition = Dest.ToPSubPos(); aircraft.SubPxPosition = Dest.ToPSubPos();
return NextActivity; return NextActivity;

View File

@@ -56,17 +56,17 @@ namespace OpenRA.Mods.RA.Air
var altitude = aircraft.Altitude; var altitude = aircraft.Altitude;
if (altitude == 0) altitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude; if (altitude == 0) altitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
var approachStart = landPos.ToFloat2() - new float2(altitude * speed, 0); var approachStart = landPos.ToInt2() - new float2(altitude * speed, 0);
var turnRadius = (128f / self.Info.Traits.Get<AircraftInfo>().ROT) * speed / (float)Math.PI; var turnRadius = (128f / self.Info.Traits.Get<AircraftInfo>().ROT) * speed / (float)Math.PI;
/* work out the center points */ /* work out the center points */
var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI); var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI);
var side = new float2(-fwd.Y, fwd.X); /* rotate */ var side = new float2(-fwd.Y, fwd.X); /* rotate */
var sideTowardBase = new[] { side, -side } var sideTowardBase = new[] { side, -side }
.OrderBy(a => float2.Dot(a, self.CenterLocation.ToFloat2() - approachStart)) .OrderBy(a => float2.Dot(a, self.CenterLocation.ToInt2() - approachStart))
.First(); .First();
var c1 = self.CenterLocation.ToFloat2() + turnRadius * sideTowardBase; var c1 = self.CenterLocation.ToInt2() + turnRadius * sideTowardBase;
var c2 = approachStart + new float2(0, turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point var c2 = approachStart + new float2(0, turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point
/* work out tangent points */ /* work out tangent points */

View File

@@ -107,7 +107,7 @@ namespace OpenRA.Mods.RA
{ {
var info = self.Info.Traits.Get<AttackBaseInfo>(); var info = self.Info.Traits.Get<AttackBaseInfo>();
nextScanTime = (int)(25 * (info.ScanTimeAverage + nextScanTime = (int)(25 * (info.ScanTimeAverage +
(self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread)); (self.World.SharedRandom.NextFloat() * 2 - 1) * info.ScanTimeSpread));
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, (int)(Game.CellSize * range)); var inRange = self.World.FindUnitsInCircle(self.CenterLocation, (int)(Game.CellSize * range));

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -18,7 +19,7 @@ namespace OpenRA.Mods.RA
class BelowUnits : IRenderModifier class BelowUnits : IRenderModifier
{ {
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
return r.Select(a => a.WithZOffset((int) -a.Sprite.size.Y)); return r.Select(a => a.WithZOffset((int) -a.Sprite.size.Y));
} }

View File

@@ -135,10 +135,18 @@ namespace OpenRA.Mods.RA
return bridges.GetBridge(self.Location + new CVec(offset[0], offset[1])); return bridges.GetBridge(self.Location + new CVec(offset[0], offset[1]));
} }
public IEnumerable<Renderable> RenderAsTerrain(Actor self) bool initializePalettes = true;
PaletteReference terrainPalette;
public IEnumerable<Renderable> RenderAsTerrain(WorldRenderer wr, Actor self)
{ {
if (initializePalettes)
{
terrainPalette = wr.Palette("terrain");
initializePalettes = false;
}
foreach (var t in TileSprites[currentTemplate]) foreach (var t in TileSprites[currentTemplate])
yield return new Renderable(t.Value, t.Key.ToPPos().ToFloat2(), "terrain", Game.CellSize * t.Key.Y); yield return new Renderable(t.Value, t.Key.ToPPos().ToFloat2(), terrainPalette, Game.CellSize * t.Key.Y);
} }
bool IsIntact(Bridge b) bool IsIntact(Bridge b)

View File

@@ -19,6 +19,7 @@ namespace OpenRA.Mods.RA.Buildings
public readonly int RepairPercent = 20; public readonly int RepairPercent = 20;
public readonly int RepairInterval = 24; public readonly int RepairInterval = 24;
public readonly int RepairStep = 7; public readonly int RepairStep = 7;
public readonly string IndicatorPalettePrefix = "player";
public object Create(ActorInitializer init) { return new RepairableBuilding(init.self, this); } public object Create(ActorInitializer init) { return new RepairableBuilding(init.self, this); }
} }
@@ -51,7 +52,7 @@ namespace OpenRA.Mods.RA.Buildings
Sound.PlayNotification(Repairer, "Speech", "Repairing", self.Owner.Country.Race); Sound.PlayNotification(Repairer, "Speech", "Repairing", self.Owner.Country.Race);
self.World.AddFrameEndTask( self.World.AddFrameEndTask(
w => w.Add(new RepairIndicator(self, p))); w => w.Add(new RepairIndicator(self, Info.IndicatorPalettePrefix, p)));
} }
} }
} }

View File

@@ -10,8 +10,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using OpenRA.Effects;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Orders; using OpenRA.Mods.RA.Orders;
using OpenRA.Traits; using OpenRA.Traits;
@@ -35,12 +35,12 @@ namespace OpenRA.Mods.RA
public IEnumerable<IOrderTargeter> Orders public IEnumerable<IOrderTargeter> Orders
{ {
get { yield return new UnitTraitOrderTargeter<Building>( "C4", 6, "c4", true, false ); } get { yield return new UnitTraitOrderTargeter<C4Demolishable>("C4", 6, "c4", true, false); }
} }
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
{ {
if( order.OrderID == "C4" ) if (order.OrderID == "C4")
return new Order("C4", self, queued) { TargetActor = target.Actor }; return new Order("C4", self, queued) { TargetActor = target.Actor };
return null; return null;
@@ -65,4 +65,7 @@ namespace OpenRA.Mods.RA
return (order.OrderString == "C4") ? "Attack" : null; return (order.OrderString == "C4") ? "Attack" : null;
} }
} }
class C4DemolishableInfo : TraitInfo<C4Demolishable> { }
class C4Demolishable { }
} }

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
@@ -56,7 +57,7 @@ namespace OpenRA.Mods.RA
self.World.Add(args.weapon.Projectile.Create(args)); self.World.Add(args.weapon.Projectile.Create(args));
if (args.weapon.Report != null) if (args.weapon.Report != null && args.weapon.Report.Any())
Sound.Play(args.weapon.Report.Random(self.World.SharedRandom) + ".aud", self.CenterLocation); Sound.Play(args.weapon.Report.Random(self.World.SharedRandom) + ".aud", self.CenterLocation);
} }
} }

View File

@@ -32,8 +32,6 @@ namespace OpenRA.Mods.RA
if (remainingFrames > 0) if (remainingFrames > 0)
remainingFrames--; remainingFrames--;
} }
static List<string> excludePalettes = new List<string>{"cursor", "chrome", "colorpicker", "shroud", "fog"};
public void AdjustPalette(Dictionary<string,Palette> palettes) public void AdjustPalette(Dictionary<string,Palette> palettes)
{ {
@@ -44,9 +42,6 @@ namespace OpenRA.Mods.RA
foreach (var pal in palettes) foreach (var pal in palettes)
{ {
if (excludePalettes.Contains(pal.Key))
continue;
for (var x = 0; x < 256; x++) for (var x = 0; x < 256; x++)
{ {
var orig = pal.Value.GetColor(x); var orig = pal.Value.GetColor(x);

View File

@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -67,13 +68,13 @@ namespace OpenRA.Mods.RA
static readonly Renderable[] Nothing = { }; static readonly Renderable[] Nothing = { };
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> rs) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
if (remainingTime > 0) if (remainingTime > 0)
return rs; return r;
if (Cloaked && IsVisible(self)) if (Cloaked && IsVisible(self))
return rs.Select(a => a.WithPalette(info.Palette)); return r.Select(a => a.WithPalette(wr.Palette(info.Palette)));
else else
return Nothing; return Nothing;
} }

View File

@@ -1,47 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class ColorPickerPaletteModifierInfo : ITraitInfo
{
public string PlayerPalette = "player";
public object Create( ActorInitializer init ) { return new ColorPickerPaletteModifier( this ); }
}
public class ColorPickerPaletteModifier : IPalette, IPaletteModifier
{
ColorPickerPaletteModifierInfo Info;
int[] index;
public ColorRamp Ramp;
public ColorPickerPaletteModifier(ColorPickerPaletteModifierInfo info) { Info = info; }
public void InitPalette( WorldRenderer wr )
{
var info = Rules.Info["player"].Traits.WithInterface<PlayerColorPaletteInfo>()
.First(p => p.BaseName == Info.PlayerPalette);
index = info.RemapIndex;
wr.AddPalette("colorpicker", wr.GetPalette(info.BasePalette));
}
public void AdjustPalette(Dictionary<string, Palette> palettes)
{
palettes["colorpicker"] = new Palette(palettes["colorpicker"],
new PlayerColorRemap(index, Ramp));
}
}
}

View File

@@ -153,7 +153,7 @@ namespace OpenRA.Mods.RA
facing = 0 facing = 0
}; };
if (args.weapon.Report != null) if (args.weapon.Report != null && args.weapon.Report.Any())
Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom) + ".aud", pos); Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom) + ".aud", pos);
DoImpacts(args); DoImpacts(args);
@@ -208,18 +208,18 @@ namespace OpenRA.Mods.RA
return false; return false;
} }
static float2 GetRecoil(Actor self, float recoil) static PVecFloat GetRecoil(Actor self, float recoil)
{ {
if (!self.HasTrait<RenderUnitTurreted>()) if (!self.HasTrait<RenderUnitTurreted>())
return float2.Zero; return PVecFloat.Zero;
var facing = self.Trait<Turreted>().turretFacing; var facing = self.Trait<Turreted>().turretFacing;
var localRecoil = new float2(0, recoil); // vector in turret-space. var localRecoil = new float2(0, recoil); // vector in turret-space.
return Util.RotateVectorByFacing(localRecoil, facing, .7f); return (PVecFloat)Util.RotateVectorByFacing(localRecoil, facing, .7f);
} }
public static PVecInt GetTurretPosition(Actor self, IFacing facing, Turret turret) public static PVecFloat GetTurretPosition(Actor self, IFacing facing, Turret turret)
{ {
if (facing == null) return turret.ScreenSpacePosition; /* things that don't have a rotating base don't need the turrets repositioned */ if (facing == null) return turret.ScreenSpacePosition; /* things that don't have a rotating base don't need the turrets repositioned */
@@ -228,23 +228,23 @@ namespace OpenRA.Mods.RA
var bodyFacing = facing.Facing; var bodyFacing = facing.Facing;
var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs);
return (PVecInt) ((PVecFloat)(Util.RotateVectorByFacing(turret.UnitSpacePosition.ToFloat2(), quantizedFacing, .7f) return (PVecFloat)Util.RotateVectorByFacing(turret.UnitSpacePosition.ToFloat2(), quantizedFacing, .7f)
+ GetRecoil(self, turret.Recoil)) + GetRecoil(self, turret.Recoil)
+ turret.ScreenSpacePosition); + (PVecFloat)turret.ScreenSpacePosition.ToFloat2();
} }
static PVecInt GetUnitspaceBarrelOffset(Actor self, IFacing facing, Turret turret, Barrel barrel) static PVecFloat GetUnitspaceBarrelOffset(Actor self, IFacing facing, Turret turret, Barrel barrel)
{ {
var turreted = self.TraitOrDefault<Turreted>(); var turreted = self.TraitOrDefault<Turreted>();
if (turreted == null && facing == null) if (turreted == null && facing == null)
return PVecInt.Zero; return PVecFloat.Zero;
var turretFacing = turreted != null ? turreted.turretFacing : facing.Facing; var turretFacing = turreted != null ? turreted.turretFacing : facing.Facing;
return (PVecInt)(PVecFloat)Util.RotateVectorByFacing(barrel.TurretSpaceOffset.ToFloat2(), turretFacing, .7f); return (PVecFloat)Util.RotateVectorByFacing(barrel.TurretSpaceOffset.ToFloat2(), turretFacing, .7f);
} }
// gets the screen-space position of a barrel. // gets the screen-space position of a barrel.
public static PVecInt GetBarrelPosition(Actor self, IFacing facing, Turret turret, Barrel barrel) public static PVecFloat GetBarrelPosition(Actor self, IFacing facing, Turret turret, Barrel barrel)
{ {
return GetTurretPosition(self, facing, turret) + barrel.ScreenSpaceOffset return GetTurretPosition(self, facing, turret) + barrel.ScreenSpaceOffset
+ GetUnitspaceBarrelOffset(self, facing, turret, barrel); + GetUnitspaceBarrelOffset(self, facing, turret, barrel);

View File

@@ -40,6 +40,8 @@ namespace OpenRA.Mods.RA
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (!self.World.LobbyInfo.GlobalSettings.Crates) return;
if (--ticks <= 0) if (--ticks <= 0)
{ {
ticks = Info.SpawnInterval * 25; // todo: randomize ticks = Info.SpawnInterval * 25; // todo: randomize
@@ -76,7 +78,7 @@ namespace OpenRA.Mods.RA
void SpawnCrate(Actor self) void SpawnCrate(Actor self)
{ {
var inWater = self.World.SharedRandom.NextDouble() < Info.WaterChance; var inWater = self.World.SharedRandom.NextFloat() < Info.WaterChance;
var pp = ChooseDropCell(self, inWater, 100); var pp = ChooseDropCell(self, inWater, 100);
if (pp == null) return; if (pp == null) return;

View File

@@ -34,6 +34,8 @@ namespace OpenRA.Mods.RA
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (!self.World.LobbyInfo.GlobalSettings.Crates) return;
if (--ticks <= 0) if (--ticks <= 0)
{ {
var info = self.Info.Traits.Get<CrateSpawnerInfo>(); var info = self.Info.Traits.Get<CrateSpawnerInfo>();
@@ -52,7 +54,7 @@ namespace OpenRA.Mods.RA
void SpawnCrate(Actor self, CrateSpawnerInfo info) void SpawnCrate(Actor self, CrateSpawnerInfo info)
{ {
var threshold = 100; var threshold = 100;
var inWater = self.World.SharedRandom.NextDouble() < info.WaterChance; var inWater = self.World.SharedRandom.NextFloat() < info.WaterChance;
for (var n = 0; n < threshold; n++ ) for (var n = 0; n < threshold; n++ )
{ {

View File

@@ -13,10 +13,11 @@ using System.Linq;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Mods.RA.Effects; using OpenRA.Mods.RA.Effects;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Render;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
class CrushableInfantryInfo : ITraitInfo, Requires<MobileInfo> class CrushableInfantryInfo : ITraitInfo, Requires<MobileInfo>, Requires<RenderInfantryInfo>
{ {
public readonly string CrushSound = "squish2.aud"; public readonly string CrushSound = "squish2.aud";
public readonly string CorpseSequence = "die-crushed"; public readonly string CorpseSequence = "die-crushed";
@@ -29,11 +30,13 @@ namespace OpenRA.Mods.RA
{ {
readonly Actor self; readonly Actor self;
readonly CrushableInfantryInfo Info; readonly CrushableInfantryInfo Info;
readonly RenderInfantry ri;
public CrushableInfantry(Actor self, CrushableInfantryInfo info) public CrushableInfantry(Actor self, CrushableInfantryInfo info)
{ {
this.self = self; this.self = self;
this.Info = info; this.Info = info;
ri = self.Trait<RenderInfantry>();
} }
public void WarnCrush(Actor crusher) public void WarnCrush(Actor crusher)
@@ -45,12 +48,7 @@ namespace OpenRA.Mods.RA
public void OnCrush(Actor crusher) public void OnCrush(Actor crusher)
{ {
Sound.Play(Info.CrushSound, crusher.CenterLocation); Sound.Play(Info.CrushSound, crusher.CenterLocation);
self.World.AddFrameEndTask(w => ri.SpawnCorpse(self, Info.CorpseSequence);
{
if (!self.Destroyed)
w.Add(new Corpse(self, Info.CorpseSequence));
});
self.Kill(crusher); self.Kill(crusher);
} }

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.RA.Effects
if (info.Inaccuracy > 0) if (info.Inaccuracy > 0)
{ {
var factor = ((Args.dest - Args.src).Length / (float)Game.CellSize) / args.weapon.Range; var factor = ((Args.dest - Args.src).Length / Game.CellSize) / (float)args.weapon.Range;
Args.dest += (PVecInt) (info.Inaccuracy * factor * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2(); Args.dest += (PVecInt) (info.Inaccuracy * factor * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2();
} }
@@ -144,7 +144,7 @@ namespace OpenRA.Mods.RA.Effects
const float height = .1f; const float height = .1f;
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (anim != null) if (anim != null)
{ {
@@ -158,15 +158,15 @@ namespace OpenRA.Mods.RA.Effects
if (Info.High || Info.Angle > 0) if (Info.High || Info.Angle > 0)
{ {
if (Info.Shadow) if (Info.Shadow)
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y); yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, wr.Palette("shadow"), (int)pos.Y);
var highPos = pos - new float2(0, GetAltitude()); var highPos = pos - new float2(0, GetAltitude());
yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, "effect", (int)pos.Y); yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, wr.Palette("effect"), (int)pos.Y);
} }
else else
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, yield return new Renderable(anim.Image, pos - .5f * anim.Image.size,
Args.weapon.Underwater ? "shadow" : "effect", (int)pos.Y); wr.Palette(Args.weapon.Underwater ? "shadow" : "effect"), (int)pos.Y);
} }
} }

View File

@@ -49,7 +49,7 @@ namespace OpenRA.Mods.RA.Effects
pos -= new PVecInt(0, velocity); pos -= new PVecInt(0, velocity);
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
font.DrawTextWithContrast(s, Game.viewport.Zoom*(pos.ToFloat2() - Game.viewport.Location) - offset, color, Color.Black,1); font.DrawTextWithContrast(s, Game.viewport.Zoom*(pos.ToFloat2() - Game.viewport.Location) - offset, color, Color.Black,1);
yield break; yield break;

View File

@@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA
public void Tick(Actor self) public void Tick(Actor self)
{ {
history.Tick(self.CenterLocation - new PVecInt(0, move.Altitude) - Combat.GetTurretPosition(self, facing, contrailTurret)); history.Tick(self.CenterLocation - new PVecInt(0, move.Altitude) - (PVecInt)Combat.GetTurretPosition(self, facing, contrailTurret).ToInt2());
} }
public void RenderAfterWorld(WorldRenderer wr, Actor self) { history.Render(self); } public void RenderAfterWorld(WorldRenderer wr, Actor self) { history.Render(self); }

View File

@@ -19,24 +19,21 @@ namespace OpenRA.Mods.RA.Effects
{ {
readonly Animation anim; readonly Animation anim;
readonly float2 pos; readonly float2 pos;
readonly string palette; readonly string paletteName;
public Corpse(Actor fromActor, string sequence) public Corpse(World world, float2 pos, string image, string sequence, string paletteName)
{ {
var rs = fromActor.Trait<RenderSimple>(); this.pos = pos;
palette = rs.Palette(fromActor.Owner); this.paletteName = paletteName;
anim = new Animation(rs.GetImage(fromActor)); anim = new Animation(image);
anim.PlayThen(sequence, anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
() => fromActor.World.AddFrameEndTask(w => w.Remove(this)));
pos = fromActor.CenterLocation.ToFloat2();
} }
public void Tick( World world ) { anim.Tick(); } public void Tick(World world) { anim.Tick(); }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, palette, (int)pos.Y); yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, wr.Palette(paletteName), (int)pos.Y);
} }
} }
} }

View File

@@ -39,11 +39,12 @@ namespace OpenRA.Mods.RA.Effects
anim.Tick(); anim.Tick();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (a.IsInWorld) if (a.IsInWorld)
yield return new Renderable(anim.Image, yield return new Renderable(anim.Image,
a.CenterLocation.ToFloat2() - .5f * anim.Image.size + offset, "effect", (int)a.CenterLocation.Y); a.CenterLocation.ToFloat2() - .5f * anim.Image.size + offset,
wr.Palette("effect"), (int)a.CenterLocation.Y);
} }
} }
} }

View File

@@ -32,11 +32,11 @@ namespace OpenRA.Mods.RA.Effects
public void Tick( World world ) { anim.Tick(); } public void Tick( World world ) { anim.Tick(); }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, yield return new Renderable(anim.Image,
pos.ToFloat2() - .5f * anim.Image.size - new int2(0,altitude), pos.ToFloat2() - .5f * anim.Image.size - new int2(0,altitude),
"effect", (int)pos.Y - altitude); wr.Palette("effect"), (int)pos.Y - altitude);
} }
public Player Owner { get { return null; } } public Player Owner { get { return null; } }

View File

@@ -15,65 +15,76 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Effects namespace OpenRA.Mods.RA.Effects
{ {
class GpsDotInfo : ITraitInfo, Requires<RenderSimpleInfo> class GpsDotInfo : ITraitInfo
{ {
public readonly string String = "Infantry"; public readonly string String = "Infantry";
public readonly string IndicatorPalettePrefix = "player";
public object Create(ActorInitializer init) public object Create(ActorInitializer init)
{ {
return new GpsDot(init, String); return new GpsDot(init.self, this);
} }
} }
class GpsDot : IEffect class GpsDot : IEffect
{ {
Actor self; Actor self;
GpsWatcher watcher; GpsDotInfo info;
RenderSimple rs;
bool show = false;
Animation anim; Animation anim;
public GpsDot(ActorInitializer init, string s) GpsWatcher watcher;
{ HiddenUnderFog huf;
anim = new Animation("gpsdot"); Spy spy;
anim.PlayRepeating(s); bool show = false;
public GpsDot(Actor self, GpsDotInfo info)
{
this.self = self;
this.info = info;
anim = new Animation("gpsdot");
anim.PlayRepeating(info.String);
self = init.self;
rs = self.Trait<RenderSimple>();
self.World.AddFrameEndTask(w => w.Add(this)); self.World.AddFrameEndTask(w => w.Add(this));
if(self.World.LocalPlayer != null) if (self.World.LocalPlayer != null)
watcher = self.World.LocalPlayer.PlayerActor.Trait<GpsWatcher>(); watcher = self.World.LocalPlayer.PlayerActor.Trait<GpsWatcher>();
} }
bool firstTick = true;
public void Tick(World world) public void Tick(World world)
{ {
show = false;
if (self.Destroyed) if (self.Destroyed)
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
if (world.LocalPlayer == null) if (world.LocalPlayer == null || !self.IsInWorld || self.Destroyed)
return; return;
if ( // Can be granted at runtime via a crate, so can't cache
self.IsInWorld var cloak = self.TraitOrDefault<Cloak>();
&& (watcher.Granted || watcher.GrantedAllies)
&& !self.Trait<HiddenUnderFog>().IsVisible(self.World.RenderedShroud, self) // WRONG if (firstTick)
&& (!self.HasTrait<Cloak>() || !self.Trait<Cloak>().Cloaked)
&& (!self.HasTrait<Spy>() || !self.Trait<Spy>().Disguised)
)
{ {
show = true; huf = self.TraitOrDefault<HiddenUnderFog>();
spy = self.TraitOrDefault<Spy>();
firstTick = false;
} }
var hasGps = (watcher != null && (watcher.Granted || watcher.GrantedAllies));
var hasDot = (huf != null && !huf.IsVisible(self.World.RenderedShroud, self)); // WRONG (why?)
var dotHidden = (cloak != null && cloak.Cloaked) || (spy != null && spy.Disguised);
show = hasGps && hasDot && !dotHidden;
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (show && !self.Destroyed) if (!show || self.Destroyed)
{ yield break;
var p = self.CenterLocation;
yield return new Renderable(anim.Image, p.ToFloat2() - 0.5f * anim.Image.size, rs.Palette(self.Owner), p.Y) var p = self.CenterLocation;
.WithScale(1.5f); var palette = wr.Palette(info.IndicatorPalettePrefix+self.Owner.InternalName);
} yield return new Renderable(anim.Image, p.ToFloat2() - 0.5f * anim.Image.size, palette, p.Y)
.WithScale(1.5f);
} }
} }
} }

View File

@@ -36,9 +36,9 @@ namespace OpenRA.Mods.RA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image,offset, "effect", (int)offset.Y); yield return new Renderable(anim.Image,offset, wr.Palette("effect"), (int)offset.Y);
} }
} }
} }

View File

@@ -51,10 +51,10 @@ namespace OpenRA.Mods.RA.Effects
anim.Tick(); anim.Tick();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, var pos = Args.dest.ToInt2() - new int2(0, altitude) - .5f * anim.Image.size;
Args.dest.ToInt2() - new int2(0, altitude) - .5f * anim.Image.size, "effect", Args.dest.Y); yield return new Renderable(anim.Image, pos, wr.Palette("effect"), Args.dest.Y);
} }
} }
} }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA.Effects namespace OpenRA.Mods.RA.Effects
@@ -31,13 +32,13 @@ namespace OpenRA.Mods.RA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (a.Destroyed) // Tick will clean up if (a.Destroyed) // Tick will clean up
yield break; yield break;
foreach (var r in a.Render()) foreach (var r in a.Render(wr))
yield return r.WithPalette("invuln"); yield return r.WithPalette(wr.Palette("invuln"));
} }
} }
} }

View File

@@ -74,11 +74,11 @@ namespace OpenRA.Mods.RA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (explosion != null) if (explosion != null)
yield return new Renderable(explosion.Image, yield return new Renderable(explosion.Image, args.dest.ToFloat2() - .5f * explosion.Image.size,
args.dest.ToFloat2() - .5f * explosion.Image.size, "effect", (int)args.dest.Y); wr.Palette("effect"), (int)args.dest.Y);
if (ticks >= info.BeamDuration) if (ticks >= info.BeamDuration)
yield break; yield break;

View File

@@ -152,11 +152,11 @@ namespace OpenRA.Mods.RA.Effects
Combat.DoImpacts(Args); Combat.DoImpacts(Args);
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (Args.firedBy.World.RenderedShroud.IsVisible(PxPosition.ToCPos())) if (Args.firedBy.World.RenderedShroud.IsVisible(PxPosition.ToCPos()))
yield return new Renderable(anim.Image, PxPosition.ToFloat2() - 0.5f * anim.Image.size - new float2(0, Altitude), yield return new Renderable(anim.Image, PxPosition.ToFloat2() - 0.5f * anim.Image.size - new float2(0, Altitude),
Args.weapon.Underwater ? "shadow" : "effect", PxPosition.Y); wr.Palette(Args.weapon.Underwater ? "shadow" : "effect"), PxPosition.Y);
if (Trail != null) if (Trail != null)
Trail.Render(Args.firedBy); Trail.Render(Args.firedBy);

View File

@@ -77,10 +77,10 @@ namespace OpenRA.Mods.RA.Effects
a.Trait.Enable(); a.Trait.Enable();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size - new float2(0, altitude), yield return new Renderable(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size - new float2(0, altitude),
"effect", (int)pos.Y); wr.Palette("effect"), (int)pos.Y);
} }
} }
} }

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
@@ -17,8 +18,6 @@ namespace OpenRA.Mods.RA.Effects
{ {
public class Parachute : IEffect public class Parachute : IEffect
{ {
readonly Animation anim;
readonly string palette;
readonly Animation paraAnim; readonly Animation paraAnim;
readonly PPos location; readonly PPos location;
@@ -28,29 +27,19 @@ namespace OpenRA.Mods.RA.Effects
float altitude; float altitude;
const float fallRate = .3f; const float fallRate = .3f;
public Parachute(Player owner, PPos location, int altitude, Actor cargo) public Parachute(Actor cargo, PPos location, int altitude)
{ {
this.location = location; this.location = location;
this.altitude = altitude; this.altitude = altitude;
this.cargo = cargo; this.cargo = cargo;
var rs = cargo.Trait<RenderSimple>();
var image = rs.anim.Name;
palette = rs.Palette(owner);
anim = new Animation(image);
if (anim.HasSequence("idle"))
anim.PlayFetchIndex("idle", () => 0);
else
anim.PlayFetchIndex("stand", () => 0);
anim.Tick();
var pai = cargo.Info.Traits.GetOrDefault<ParachuteAttachmentInfo>(); var pai = cargo.Info.Traits.GetOrDefault<ParachuteAttachmentInfo>();
paraAnim = new Animation(pai != null ? pai.ParachuteSprite : "parach"); paraAnim = new Animation(pai != null ? pai.ParachuteSprite : "parach");
paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle")); paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle"));
if (pai != null) offset = pai.Offset; if (pai != null) offset = pai.Offset;
cargo.Trait<ITeleportable>().SetPxPosition(cargo, location);
} }
public void Tick(World world) public void Tick(World world)
@@ -73,12 +62,23 @@ namespace OpenRA.Mods.RA.Effects
}); });
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
var rc = cargo.Render(wr).Select(a => a.WithPos(a.Pos - new float2(0, altitude))
.WithZOffset(a.ZOffset + (int)altitude));
// Don't render anything if the cargo is invisible (e.g. under fog)
if (!rc.Any())
yield break;
foreach (var c in rc)
{
yield return c.WithPos(location.ToFloat2() - .5f * c.Sprite.size).WithPalette(wr.Palette("shadow")).WithZOffset(0);
yield return c.WithZOffset(2);
}
var pos = location.ToFloat2() - new float2(0, altitude); var pos = location.ToFloat2() - new float2(0, altitude);
yield return new Renderable(anim.Image, location.ToFloat2() - .5f * anim.Image.size, "shadow", 0); yield return new Renderable(paraAnim.Image, pos - .5f * paraAnim.Image.size + offset, rc.First().Palette, 3);
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, palette, 2);
yield return new Renderable(paraAnim.Image, pos - .5f * paraAnim.Image.size + offset, palette, 3);
} }
} }
} }

View File

@@ -34,11 +34,11 @@ namespace OpenRA.Mods.RA.Effects
anim.Tick(); anim.Tick();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (!a.Destroyed && (a.World.LocalPlayer == null || a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally)) if (!a.Destroyed && (a.World.LocalPlayer == null || a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally))
yield return new Renderable(anim.Image, yield return new Renderable(anim.Image, a.CenterLocation.ToFloat2() - .5f * anim.Image.size,
a.CenterLocation.ToFloat2() - .5f * anim.Image.size, "chrome", (int)a.CenterLocation.Y); wr.Palette("chrome"), (int)a.CenterLocation.Y);
} }
} }
} }

View File

@@ -20,13 +20,15 @@ namespace OpenRA.Mods.RA.Effects
{ {
readonly Actor building; readonly Actor building;
readonly RA.RallyPoint rp; readonly RA.RallyPoint rp;
readonly string palettePrefix;
public Animation flag = new Animation("rallypoint"); public Animation flag = new Animation("rallypoint");
public Animation circles = new Animation("rallypoint"); public Animation circles = new Animation("rallypoint");
public RallyPoint(Actor building) public RallyPoint(Actor building, string palettePrefix)
{ {
this.building = building; this.building = building;
rp = building.Trait<RA.RallyPoint>(); rp = building.Trait<RA.RallyPoint>();
this.palettePrefix = palettePrefix;
flag.PlayRepeating("flag"); flag.PlayRepeating("flag");
circles.Play("circles"); circles.Play("circles");
} }
@@ -46,13 +48,13 @@ namespace OpenRA.Mods.RA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (building.IsInWorld && building.Owner == building.World.LocalPlayer if (building.IsInWorld && building.Owner == building.World.LocalPlayer
&& building.World.Selection.Actors.Contains(building)) && building.World.Selection.Actors.Contains(building))
{ {
var pos = Traits.Util.CenterOfCell(rp.rallyPoint); var pos = Traits.Util.CenterOfCell(rp.rallyPoint);
var palette = building.Trait<RenderSimple>().Palette(building.Owner); var palette = wr.Palette(palettePrefix+building.Owner.InternalName);
yield return new Renderable(circles.Image, yield return new Renderable(circles.Image,
pos.ToFloat2() - .5f * circles.Image.size, pos.ToFloat2() - .5f * circles.Image.size,

View File

@@ -20,34 +20,35 @@ namespace OpenRA.Mods.RA.Effects
{ {
Actor building; Actor building;
Player player; Player player;
string palettePrefix;
Animation anim = new Animation("allyrepair"); Animation anim = new Animation("allyrepair");
RepairableBuilding rb;
public RepairIndicator(Actor building, Player player) public RepairIndicator(Actor building, string palettePrefix, Player player)
{ {
this.building = building; this.building = building;
this.player = player; this.player = player;
this.palettePrefix = palettePrefix;
rb = building.Trait<RepairableBuilding>();
anim.PlayRepeating("repair"); anim.PlayRepeating("repair");
} }
public void Tick(World world) public void Tick(World world)
{ {
if (!building.IsInWorld || if (!building.IsInWorld || building.IsDead() ||
building.IsDead() || rb.Repairer == null || rb.Repairer != player)
building.Trait<RepairableBuilding>().Repairer == null ||
building.Trait<RepairableBuilding>().Repairer != player)
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
anim.Tick(); anim.Tick();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
if (!building.Destroyed) if (!building.Destroyed)
{ {
var palette = building.Trait<RenderSimple>().Palette(player);
yield return new Renderable(anim.Image, yield return new Renderable(anim.Image,
building.CenterLocation.ToFloat2() - .5f * anim.Image.size, palette, (int)building.CenterLocation.Y); building.CenterLocation.ToFloat2() - .5f * anim.Image.size,
wr.Palette(palettePrefix+player.InternalName), (int)building.CenterLocation.Y);
} }
} }
} }

View File

@@ -40,9 +40,9 @@ namespace OpenRA.Mods.RA.Effects
} }
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(doors.Image, pos, "effect", (int)doorOffset.Y); yield return new Renderable(doors.Image, pos, wr.Palette("effect"), (int)doorOffset.Y);
} }
} }
} }

View File

@@ -33,9 +33,10 @@ namespace OpenRA.Mods.RA.Effects
anim.Tick(); anim.Tick();
} }
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render(WorldRenderer wr)
{ {
yield return new Renderable(anim.Image, pos.ToFloat2() - .5f * anim.Image.size, "effect", (int)pos.Y); yield return new Renderable(anim.Image, pos.ToFloat2() - .5f * anim.Image.size,
wr.Palette("effect"), (int)pos.Y);
} }
} }
} }

View File

@@ -29,27 +29,35 @@ namespace OpenRA.Mods.RA.Effects
class TeslaZap : IEffect class TeslaZap : IEffect
{ {
readonly ProjectileArgs Args; readonly ProjectileArgs Args;
readonly TeslaZapInfo Info;
IEnumerable<Renderable> renderables;
int timeUntilRemove = 2; // # of frames int timeUntilRemove = 2; // # of frames
bool doneDamage = false; bool doneDamage = false;
bool initialized = false;
readonly List<Renderable> renderables = new List<Renderable>();
public TeslaZap(TeslaZapInfo info, ProjectileArgs args) public TeslaZap(TeslaZapInfo info, ProjectileArgs args)
{ {
Args = args; Args = args;
var bright = SequenceProvider.GetSequence(info.Image, "bright"); Info = info;
var dim = SequenceProvider.GetSequence(info.Image, "dim");
for( var n = 0; n < info.DimZaps; n++ )
renderables.AddRange(DrawZapWandering(args.src, args.dest, dim));
for( var n = 0; n < info.BrightZaps; n++ )
renderables.AddRange(DrawZapWandering(args.src, args.dest, bright));
} }
public void Tick( World world ) public IEnumerable<Renderable> GenerateRenderables(WorldRenderer wr)
{ {
if( timeUntilRemove <= 0 ) var bright = SequenceProvider.GetSequence(Info.Image, "bright");
world.AddFrameEndTask( w => w.Remove( this ) ); var dim = SequenceProvider.GetSequence(Info.Image, "dim");
for (var n = 0; n < Info.DimZaps; n++)
foreach (var z in DrawZapWandering(wr, Args.src, Args.dest, dim))
yield return z;
for (var n = 0; n < Info.BrightZaps; n++)
foreach (var z in DrawZapWandering(wr, Args.src, Args.dest, bright))
yield return z;
}
public void Tick(World world)
{
if (timeUntilRemove <= 0)
world.AddFrameEndTask(w => w.Remove(this));
--timeUntilRemove; --timeUntilRemove;
if (!doneDamage) if (!doneDamage)
@@ -62,9 +70,18 @@ namespace OpenRA.Mods.RA.Effects
} }
} }
public IEnumerable<Renderable> Render() { return renderables; } public IEnumerable<Renderable> Render(WorldRenderer wr)
{
if (!initialized)
{
renderables = GenerateRenderables(wr);
initialized = true;
}
static IEnumerable<Renderable> DrawZapWandering(PPos from, PPos to, Sequence s) return renderables;
}
static IEnumerable<Renderable> DrawZapWandering(WorldRenderer wr, PPos from, PPos to, Sequence s)
{ {
var z = float2.Zero; /* hack */ var z = float2.Zero; /* hack */
var dist = to - from; var dist = to - from;
@@ -76,22 +93,22 @@ namespace OpenRA.Mods.RA.Effects
var p1 = from.ToFloat2() + (1 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; var p1 = from.ToFloat2() + (1 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
var p2 = from.ToFloat2() + (2 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; var p2 = from.ToFloat2() + (2 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
renderables.AddRange(DrawZap(from.ToFloat2(), p1, s, out p1)); renderables.AddRange(DrawZap(wr, from.ToFloat2(), p1, s, out p1));
renderables.AddRange(DrawZap(p1, p2, s, out p2)); renderables.AddRange(DrawZap(wr, p1, p2, s, out p2));
renderables.AddRange(DrawZap(p2, to.ToFloat2(), s, out z)); renderables.AddRange(DrawZap(wr, p2, to.ToFloat2(), s, out z));
} }
else else
{ {
var p1 = from.ToFloat2() + (1 / 2f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; var p1 = from.ToFloat2() + (1 / 2f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm;
renderables.AddRange(DrawZap(from.ToFloat2(), p1, s, out p1)); renderables.AddRange(DrawZap(wr, from.ToFloat2(), p1, s, out p1));
renderables.AddRange(DrawZap(p1, to.ToFloat2(), s, out z)); renderables.AddRange(DrawZap(wr, p1, to.ToFloat2(), s, out z));
} }
return renderables; return renderables;
} }
static IEnumerable<Renderable> DrawZap(float2 from, float2 to, Sequence s, out float2 p) static IEnumerable<Renderable> DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p)
{ {
var dist = to - from; var dist = to - from;
var q = new float2(-dist.Y, dist.X); var q = new float2(-dist.Y, dist.X);
@@ -104,7 +121,8 @@ namespace OpenRA.Mods.RA.Effects
var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared ) var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared )
.OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First(); .OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First();
rs.Add(new Renderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), "effect", (int)from.Y)); rs.Add(new Renderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]),
wr.Palette("effect"), (int)from.Y));
z += new float2(step[0], step[1]); z += new float2(step[0], step[1]);
if( rs.Count >= 1000 ) if( rs.Count >= 1000 )
break; break;

View File

@@ -0,0 +1,44 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class FogPaletteInfo : ITraitInfo
{
public readonly string Name = "fog";
public object Create(ActorInitializer init) { return new FogPalette(this); }
}
class FogPalette : IPalette
{
readonly FogPaletteInfo info;
public FogPalette(FogPaletteInfo info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
{
var c = new[] {
Color.Transparent, Color.Green,
Color.Blue, Color.Yellow,
Color.FromArgb(128,0,0,0),
Color.FromArgb(128,0,0,0),
Color.FromArgb(128,0,0,0),
Color.FromArgb(64,0,0,0)
};
wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false);
}
}
}

View File

@@ -21,20 +21,22 @@ namespace OpenRA.Mods.RA
public readonly int2 SpawnOffset = int2.Zero; public readonly int2 SpawnOffset = int2.Zero;
public readonly int Facing = 0; public readonly int Facing = 0;
public object Create( ActorInitializer init ) { return new FreeActor(init.self, this); } public object Create( ActorInitializer init ) { return new FreeActor(init, this); }
} }
public class FreeActor public class FreeActor
{ {
public FreeActor(Actor self, FreeActorInfo info) public FreeActor(ActorInitializer init, FreeActorInfo info)
{ {
self.World.AddFrameEndTask( if (init.Contains<FreeActorInit>() && !init.Get<FreeActorInit>().value) return;
init.self.World.AddFrameEndTask(
w => w =>
{ {
var a = w.CreateActor(info.Actor, new TypeDictionary var a = w.CreateActor(info.Actor, new TypeDictionary
{ {
new LocationInit( self.Location + (CVec)info.SpawnOffset ), new LocationInit( init.self.Location + (CVec)info.SpawnOffset ),
new OwnerInit( self.Owner ), new OwnerInit( init.self.Owner ),
new FacingInit( info.Facing ), new FacingInit( info.Facing ),
}); });
@@ -43,4 +45,13 @@ namespace OpenRA.Mods.RA
}); });
} }
} }
public class FreeActorInit : IActorInit<bool>
{
[FieldFromYamlKey]
public readonly bool value = true;
public FreeActorInit() { }
public FreeActorInit(bool init) { value = init; }
public bool Value(World world) { return value; }
}
} }

View File

@@ -97,23 +97,23 @@ namespace OpenRA.Mods.RA
return Level > 0 ? Info.SpeedModifier[Level - 1] : 1m; return Level > 0 ? Info.SpeedModifier[Level - 1] : 1m;
} }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> rs) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
if (self.Owner == self.World.LocalPlayer && Level > 0) if (self.Owner == self.World.LocalPlayer && Level > 0)
return InnerModifyRender(self, rs); return InnerModifyRender(self, wr, r);
else else
return rs; return r;
} }
IEnumerable<Renderable> InnerModifyRender(Actor self, IEnumerable<Renderable> rs) IEnumerable<Renderable> InnerModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
foreach (var r in rs) foreach (var rs in r)
yield return r; yield return rs;
RankAnim.Tick(); // HACK RankAnim.Tick(); // HACK
var bounds = self.Bounds.Value; var bounds = self.Bounds.Value;
yield return new Renderable(RankAnim.Image, yield return new Renderable(RankAnim.Image, new float2(bounds.Right - 6, bounds.Bottom - 8),
new float2(bounds.Right - 6, bounds.Bottom - 8), "effect", self.CenterLocation.Y); wr.Palette("effect"), self.CenterLocation.Y);
} }
} }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -32,7 +33,7 @@ namespace OpenRA.Mods.RA
static readonly Renderable[] Nothing = { }; static readonly Renderable[] Nothing = { };
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
return IsVisible(self.Owner.Shroud, self) ? r : Nothing; return IsVisible(self.Owner.Shroud, self) ? r : Nothing;
} }

View File

@@ -24,15 +24,10 @@ namespace OpenRA.Mods.RA
t += .5f; t += .5f;
} }
static readonly string[] ExcludePalettes = { "cursor", "chrome", "colorpicker", "terrain" };
public void AdjustPalette(Dictionary<string,Palette> palettes) public void AdjustPalette(Dictionary<string,Palette> palettes)
{ {
foreach (var pal in palettes) foreach (var pal in palettes)
{ {
if (ExcludePalettes.Contains(pal.Key))
continue;
var rotate = (int)t % 18; var rotate = (int)t % 18;
if (rotate > 9) if (rotate > 9)
rotate = 18 - rotate; rotate = 18 - rotate;

View File

@@ -81,7 +81,7 @@ namespace OpenRA.Mods.RA
var p = end - start; var p = end - start;
var q = new float2(p.Y, -p.X); var q = new float2(p.Y, -p.X);
q = (start != end) ? (1 / q.Length) * q : new float2(1, 0); q = (start != end) ? (1 / q.Length) * q : new float2(1, 0);
var c = -float2.Dot(q, start.ToFloat2()); var c = -float2.Dot(q, start.ToInt2());
/* return all points such that |ax + by + c| < depth */ /* return all points such that |ax + by + c| < depth */

View File

@@ -57,6 +57,7 @@ namespace OpenRA.Mods.RA.Missions
Actor sam2; Actor sam2;
Actor sam3; Actor sam3;
Actor sam4; Actor sam4;
Actor[] sams;
Actor tanya; Actor tanya;
Actor einstein; Actor einstein;
Actor engineer; Actor engineer;
@@ -74,8 +75,6 @@ namespace OpenRA.Mods.RA.Missions
Actor parabombPoint1; Actor parabombPoint1;
Actor parabombPoint2; Actor parabombPoint2;
Actor sovietRallyPoint; Actor sovietRallyPoint;
Actor flamersEntryPoint;
Actor tanksEntryPoint;
Actor townPoint; Actor townPoint;
Actor sovietTownAttackPoint1; Actor sovietTownAttackPoint1;
Actor sovietTownAttackPoint2; Actor sovietTownAttackPoint2;
@@ -103,7 +102,7 @@ namespace OpenRA.Mods.RA.Missions
static readonly string[] SovietVehicles1 = { "3tnk" }; static readonly string[] SovietVehicles1 = { "3tnk" };
static readonly string[] SovietVehicles2 = { "3tnk", "v2rl" }; static readonly string[] SovietVehicles2 = { "3tnk", "v2rl" };
const int SovietVehiclesUpgradeTicks = 1500 * 4; const int SovietVehiclesUpgradeTicks = 1500 * 4;
const int SovietGroupSize = 20; const int SovietGroupSize = 5;
const int ReinforcementsTicks = 1500 * 12; const int ReinforcementsTicks = 1500 * 12;
static readonly string[] Reinforcements = static readonly string[] Reinforcements =
@@ -120,18 +119,11 @@ namespace OpenRA.Mods.RA.Missions
const int ParabombTicks = 750; const int ParabombTicks = 750;
const int FlamersTicks = 1500 * 2;
static readonly string[] Flamers = { "e4", "e4", "e4", "e4", "e4" };
const string ApcName = "apc";
const int ParatroopersTicks = 1500 * 5; const int ParatroopersTicks = 1500 * 5;
static readonly string[] Badger1Passengers = { "e1", "e1", "e1", "e2", "3tnk" }; static readonly string[] Badger1Passengers = { "e1", "e1", "e1", "e2", "3tnk" };
static readonly string[] Badger2Passengers = { "e1", "e1", "e1", "e2", "e2" }; static readonly string[] Badger2Passengers = { "e1", "e1", "e1", "e2", "e2" };
static readonly string[] Badger3Passengers = { "e1", "e1", "e1", "e2", "e2" }; static readonly string[] Badger3Passengers = { "e1", "e1", "e1", "e2", "e2" };
const int TanksTicks = 1500 * 11;
static readonly string[] Tanks = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk" };
const string SignalFlareName = "flare"; const string SignalFlareName = "flare";
const string YakName = "yak"; const string YakName = "yak";
@@ -180,12 +172,6 @@ namespace OpenRA.Mods.RA.Missions
if (allies1 != allies2) if (allies1 != allies2)
{ {
if (world.FrameNumber == TanksTicks)
RushSovietUnits();
if (world.FrameNumber == FlamersTicks)
RushSovietFlamers();
if (yak == null || (yak != null && !yak.IsDead() && (yak.GetCurrentActivity() is FlyCircle || yak.IsIdle))) if (yak == null || (yak != null && !yak.IsDead() && (yak.GetCurrentActivity() is FlyCircle || yak.IsIdle)))
{ {
var alliedUnitsNearYakPoint = world.FindAliveCombatantActorsInCircle(yakAttackPoint.CenterLocation, 10) var alliedUnitsNearYakPoint = world.FindAliveCombatantActorsInCircle(yakAttackPoint.CenterLocation, 10)
@@ -218,22 +204,19 @@ namespace OpenRA.Mods.RA.Missions
} }
if (objectives[DestroySamSitesID].Status == ObjectiveStatus.InProgress) if (objectives[DestroySamSitesID].Status == ObjectiveStatus.InProgress)
{ {
if ((sam1.Destroyed || sam1.Owner != soviets) if (sams.All(s => s.IsDead() || s.Owner != soviets))
&& (sam2.Destroyed || sam2.Owner != soviets)
&& (sam3.Destroyed || sam3.Owner != soviets)
&& (sam4.Destroyed || sam4.Owner != soviets))
{ {
objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed; objectives[DestroySamSitesID].Status = ObjectiveStatus.Completed;
objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress; objectives[ExtractEinsteinID].Status = ObjectiveStatus.InProgress;
OnObjectivesUpdated(true); OnObjectivesUpdated(true);
SpawnSignalFlare(); world.CreateActor(SignalFlareName, new TypeDictionary { new OwnerInit(allies1), new LocationInit(extractionLZ.Location) });
Sound.Play("flaren1.aud"); Sound.Play("flaren1.aud");
ExtractEinsteinAtLZ(); ExtractEinsteinAtLZ();
} }
} }
if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null) if (objectives[ExtractEinsteinID].Status == ObjectiveStatus.InProgress && einsteinChinook != null)
{ {
if (einsteinChinook.Destroyed) if (einsteinChinook.IsDead())
{ {
objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed; objectives[ExtractEinsteinID].Status = ObjectiveStatus.Failed;
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed; objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
@@ -253,22 +236,19 @@ namespace OpenRA.Mods.RA.Missions
} }
} }
if (tanya.Destroyed) if (tanya.IsDead())
MissionFailed("Tanya was killed."); MissionFailed("Tanya was killed.");
else if (einstein.Destroyed) else if (einstein.IsDead())
MissionFailed("Einstein was killed."); MissionFailed("Einstein was killed.");
world.AddFrameEndTask(w => else if (!world.Actors.Any(a => (a.Owner == allies || a.Owner == allies2) && !a.IsDead()
&& (a.HasTrait<Building>() && !a.HasTrait<Wall>()) || a.HasTrait<BaseBuilding>()))
{ {
if (!world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20) objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed;
.Any(a => a.HasTrait<Building>() && !a.HasTrait<Wall>() && (a.Owner == allies || a.Owner == allies2))) OnObjectivesUpdated(true);
{ MissionFailed("The Allied reinforcements have been defeated.");
objectives[MaintainPresenceID].Status = ObjectiveStatus.Failed; }
OnObjectivesUpdated(true);
MissionFailed("The Allied reinforcements have been defeated.");
}
});
} }
void UpdateDeaths() void UpdateDeaths()
@@ -308,10 +288,10 @@ namespace OpenRA.Mods.RA.Missions
void BuildSovietUnits() void BuildSovietUnits()
{ {
if (!sovietBarracks.Destroyed) if (!sovietBarracks.IsDead())
BuildSovietUnit(InfantryQueueName, SovietInfantry.Random(world.SharedRandom)); BuildSovietUnit(InfantryQueueName, SovietInfantry.Random(world.SharedRandom));
if (!sovietWarFactory.Destroyed) if (!sovietWarFactory.IsDead())
{ {
var vehicles = world.FrameNumber >= SovietVehiclesUpgradeTicks ? SovietVehicles2 : SovietVehicles1; var vehicles = world.FrameNumber >= SovietVehiclesUpgradeTicks ? SovietVehicles2 : SovietVehicles1;
BuildSovietUnit(VehicleQueueName, vehicles.Random(world.SharedRandom)); BuildSovietUnit(VehicleQueueName, vehicles.Random(world.SharedRandom));
@@ -320,44 +300,39 @@ namespace OpenRA.Mods.RA.Missions
void ManageSovietUnits() void ManageSovietUnits()
{ {
var idleSovietUnitsAtRP = world.FindAliveCombatantActorsInCircle(sovietRallyPoint.CenterLocation, 3) var units = world.FindAliveCombatantActorsInCircle(sovietRallyPoint.CenterLocation, 10)
.Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>()); .Where(u => u.IsIdle && u.HasTrait<Mobile>() && u.HasTrait<AttackBase>() && u.Owner == soviets)
.Except(world.WorldActor.Trait<SpawnMapActors>().Actors.Values);
if (idleSovietUnitsAtRP.Count() >= SovietGroupSize) if (units.Count() >= SovietGroupSize)
{ {
var firstUnit = idleSovietUnitsAtRP.FirstOrDefault(); foreach (var unit in units)
if (firstUnit != null) MissionUtils.AttackNearestLandActor(true, unit, allies2);
}
var scatteredUnits = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && u.IsIdle
&& u.HasTrait<Mobile>() && u.HasTrait<AttackBase>() && u.Owner == soviets)
.Except(world.WorldActor.Trait<SpawnMapActors>().Actors.Values)
.Except(units);
foreach (var unit in scatteredUnits)
MissionUtils.AttackNearestLandActor(true, unit, allies2);
}
void SetupAlliedBase()
{
foreach (var actor in world.Actors.Where(a => a.Owner == allies && a != allies.PlayerActor))
{
actor.ChangeOwner(allies2);
if (actor.Info.Name == "pbox")
{ {
var closestAlliedBuilding = ClosestAlliedBuilding(firstUnit, 40); actor.AddTrait(new TransformedAction(s => s.Trait<Cargo>().Load(s, world.CreateActor(false, "e1", allies2, null, null))));
if (closestAlliedBuilding != null) actor.QueueActivity(new Transform(actor, "hbox.e1") { SkipMakeAnims = true });
foreach (var unit in idleSovietUnitsAtRP)
{
unit.Trait<Mobile>().Nudge(unit, unit, true);
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Attack(Target.FromActor(closestAlliedBuilding), 3)));
}
} }
if (actor.Info.Name == "proc")
actor.QueueActivity(new Transform(actor, "proc") { SkipMakeAnims = true });
foreach (var c in actor.TraitsImplementing<INotifyCapture>())
c.OnCapture(actor, actor, allies, allies2);
} }
var idleSovietUnits = world.FindAliveCombatantActorsInCircle(allies2BasePoint.CenterLocation, 20)
.Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
foreach (var unit in idleSovietUnits)
{
var closestAlliedBuilding = ClosestAlliedBuilding(unit, 40);
if (closestAlliedBuilding != null)
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Attack(Target.FromActor(closestAlliedBuilding), 3)));
}
}
Actor ClosestAlliedBuilding(Actor actor, int range)
{
return MissionUtils.ClosestPlayerBuilding(world, allies2, actor.CenterLocation, range);
}
IEnumerable<Actor> ClosestAlliedBuildings(Actor actor, int range)
{
return MissionUtils.ClosestPlayerBuildings(world, allies2, actor.CenterLocation, range);
} }
void InitializeSovietFactories() void InitializeSovietFactories()
@@ -365,7 +340,7 @@ namespace OpenRA.Mods.RA.Missions
var sbrp = sovietBarracks.Trait<RallyPoint>(); var sbrp = sovietBarracks.Trait<RallyPoint>();
var swrp = sovietWarFactory.Trait<RallyPoint>(); var swrp = sovietWarFactory.Trait<RallyPoint>();
sbrp.rallyPoint = swrp.rallyPoint = sovietRallyPoint.Location; sbrp.rallyPoint = swrp.rallyPoint = sovietRallyPoint.Location;
sbrp.nearEnough = swrp.nearEnough = 3; sbrp.nearEnough = swrp.nearEnough = 6;
sovietBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietBarracks, true); sovietBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietBarracks, true);
sovietWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietWarFactory, true); sovietWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(sovietWarFactory, true);
} }
@@ -378,11 +353,6 @@ namespace OpenRA.Mods.RA.Missions
queue.ResolveOrder(queue.self, Order.StartProduction(queue.self, unit, 1)); queue.ResolveOrder(queue.self, Order.StartProduction(queue.self, unit, 1));
} }
void SpawnSignalFlare()
{
world.CreateActor(SignalFlareName, new TypeDictionary { new OwnerInit(allies1), new LocationInit(extractionLZ.Location) });
}
void StartReinforcementsTimer() void StartReinforcementsTimer()
{ {
Sound.Play("timergo1.aud"); Sound.Play("timergo1.aud");
@@ -409,38 +379,6 @@ namespace OpenRA.Mods.RA.Missions
.QueueActivity(new Move.Move(allies2BasePoint.Location)); .QueueActivity(new Move.Move(allies2BasePoint.Location));
} }
void RushSovietUnits()
{
var closestAlliedBuildings = ClosestAlliedBuildings(badgerDropPoint1, 40);
if (!closestAlliedBuildings.Any()) return;
foreach (var tank in Tanks)
{
var unit = world.CreateActor(tank, new TypeDictionary
{
new OwnerInit(soviets),
new LocationInit(tanksEntryPoint.Location)
});
foreach (var building in closestAlliedBuildings)
unit.QueueActivity(new Attack(Target.FromActor(building), 3));
}
}
void RushSovietFlamers()
{
var closestAlliedBuilding = ClosestAlliedBuilding(badgerDropPoint1, 40);
if (closestAlliedBuilding == null) return;
var apc = world.CreateActor(ApcName, new TypeDictionary { new OwnerInit(soviets), new LocationInit(flamersEntryPoint.Location) });
foreach (var flamer in Flamers)
{
var unit = world.CreateActor(false, flamer, new TypeDictionary { new OwnerInit(soviets) });
apc.Trait<Cargo>().Load(apc, unit);
}
apc.QueueActivity(new MoveAdjacentTo(Target.FromActor(closestAlliedBuilding)));
apc.QueueActivity(new UnloadCargo(true));
}
void ExtractEinsteinAtLZ() void ExtractEinsteinAtLZ()
{ {
einsteinChinook = MissionUtils.ExtractUnitWithChinook( einsteinChinook = MissionUtils.ExtractUnitWithChinook(
@@ -461,7 +399,7 @@ namespace OpenRA.Mods.RA.Missions
void TransferTownUnitsToAllies() void TransferTownUnitsToAllies()
{ {
foreach (var unit in world.FindAliveNonCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange) foreach (var unit in world.FindAliveNonCombatantActorsInCircle(townPoint.CenterLocation, AlliedTownTransferRange)
.Where(a => a.HasTrait<IMove>())) .Where(a => a.HasTrait<Mobile>()))
unit.ChangeOwner(allies1); unit.ChangeOwner(allies1);
} }
@@ -492,11 +430,14 @@ namespace OpenRA.Mods.RA.Missions
allies = w.Players.Single(p => p.InternalName == "Allies"); allies = w.Players.Single(p => p.InternalName == "Allies");
soviets = w.Players.Single(p => p.InternalName == "Soviets"); soviets = w.Players.Single(p => p.InternalName == "Soviets");
soviets.PlayerActor.Trait<PlayerResources>().Cash = 1000;
var actors = w.WorldActor.Trait<SpawnMapActors>().Actors; var actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
sam1 = actors["SAM1"]; sam1 = actors["SAM1"];
sam2 = actors["SAM2"]; sam2 = actors["SAM2"];
sam3 = actors["SAM3"]; sam3 = actors["SAM3"];
sam4 = actors["SAM4"]; sam4 = actors["SAM4"];
sams = new[] { sam1, sam2, sam3, sam4 };
tanya = actors["Tanya"]; tanya = actors["Tanya"];
einstein = actors["Einstein"]; einstein = actors["Einstein"];
engineer = actors["Engineer"]; engineer = actors["Engineer"];
@@ -515,17 +456,15 @@ namespace OpenRA.Mods.RA.Missions
sovietBarracks = actors["SovietBarracks"]; sovietBarracks = actors["SovietBarracks"];
sovietWarFactory = actors["SovietWarFactory"]; sovietWarFactory = actors["SovietWarFactory"];
sovietRallyPoint = actors["SovietRallyPoint"]; sovietRallyPoint = actors["SovietRallyPoint"];
flamersEntryPoint = actors["FlamersEntryPoint"];
tanksEntryPoint = actors["TanksEntryPoint"];
townPoint = actors["TownPoint"]; townPoint = actors["TownPoint"];
sovietTownAttackPoint1 = actors["SovietTownAttackPoint1"]; sovietTownAttackPoint1 = actors["SovietTownAttackPoint1"];
sovietTownAttackPoint2 = actors["SovietTownAttackPoint2"]; sovietTownAttackPoint2 = actors["SovietTownAttackPoint2"];
yakEntryPoint = actors["YakEntryPoint"]; yakEntryPoint = actors["YakEntryPoint"];
yakAttackPoint = actors["YakAttackPoint"]; yakAttackPoint = actors["YakAttackPoint"];
SetupAlliedBase(actors); SetupAlliedBase();
var shroud = w.WorldActor.Trait<Shroud>(); var shroud = allies1.Shroud;
shroud.Explore(w, sam1.Location, 2); shroud.Explore(w, sam1.Location, 2);
shroud.Explore(w, sam2.Location, 2); shroud.Explore(w, sam2.Location, 2);
shroud.Explore(w, sam3.Location, 2); shroud.Explore(w, sam3.Location, 2);
@@ -539,20 +478,5 @@ namespace OpenRA.Mods.RA.Missions
MissionUtils.PlayMissionMusic(); MissionUtils.PlayMissionMusic();
} }
void SetupAlliedBase(Dictionary<string, Actor> actors)
{
world.AddFrameEndTask(w =>
{
foreach (var actor in actors.Where(a => a.Value.Owner == allies))
actor.Value.ChangeOwner(allies2);
world.CreateActor("proc", new TypeDictionary
{
new LocationInit(actors["Allies2ProcPoint"].Location),
new OwnerInit(allies2)
});
});
}
} }
} }

View File

@@ -10,12 +10,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Render; using OpenRA.Mods.RA.Render;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
@@ -488,19 +490,21 @@ namespace OpenRA.Mods.RA.Missions
public override object Create(ActorInitializer init) { return new Allies04RenderHijacked(init.self, this); } public override object Create(ActorInitializer init) { return new Allies04RenderHijacked(init.self, this); }
} }
class Allies04RenderHijacked : RenderUnit, IRenderModifier class Allies04RenderHijacked : RenderUnit
{ {
Allies04Hijackable hijackable; Allies04Hijackable hijackable;
Allies04RenderHijackedInfo info;
public Allies04RenderHijacked(Actor self, Allies04RenderHijackedInfo info) public Allies04RenderHijacked(Actor self, Allies04RenderHijackedInfo info)
: base(self) : base(self)
{ {
this.info = info;
hijackable = self.Trait<Allies04Hijackable>(); hijackable = self.Trait<Allies04Hijackable>();
} }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) protected override string PaletteName(Actor self)
{ {
return r.Select(a => a.WithPalette(Palette(hijackable.OldOwner))); return info.Palette ?? info.PlayerPalette + hijackable.OldOwner.InternalName;
} }
} }
@@ -533,4 +537,27 @@ namespace OpenRA.Mods.RA.Missions
} }
class Allies04TransformOnLabInfiltrate { } class Allies04TransformOnLabInfiltrate { }
class Allies04HazyPaletteEffectInfo : TraitInfo<Allies04HazyPaletteEffect> { }
class Allies04HazyPaletteEffect : IPaletteModifier
{
static readonly string[] ExcludePalettes = { "cursor", "chrome", "colorpicker", "fog", "shroud" };
public void AdjustPalette(Dictionary<string, Palette> palettes)
{
foreach (var pal in palettes)
{
if (ExcludePalettes.Contains(pal.Key))
continue;
for (var x = 0; x < 256; x++)
{
var from = pal.Value.GetColor(x);
var to = Color.FromArgb(from.A, Color.FromKnownColor(KnownColor.DarkOrange));
pal.Value.SetColor(x, Exts.ColorLerp(0.15f, from, to));
}
}
}
}
} }

View File

@@ -109,30 +109,6 @@ namespace OpenRA.Mods.RA.Missions
return units.Any() && units.All(a => a.Owner == player); return units.Any() && units.All(a => a.Owner == player);
} }
public static Actor ClosestPlayerUnit(World world, Player player, PPos location, int range)
{
return ClosestPlayerUnits(world, player, location, range).FirstOrDefault();
}
public static IEnumerable<Actor> ClosestPlayerUnits(World world, Player player, PPos location, int range)
{
return world.FindAliveCombatantActorsInCircle(location, range)
.Where(a => a.Owner == player && a.HasTrait<IMove>())
.OrderBy(a => (location - a.CenterLocation).LengthSquared);
}
public static Actor ClosestPlayerBuilding(World world, Player player, PPos location, int range)
{
return ClosestPlayerBuildings(world, player, location, range).FirstOrDefault();
}
public static IEnumerable<Actor> ClosestPlayerBuildings(World world, Player player, PPos location, int range)
{
return world.FindAliveCombatantActorsInCircle(location, range)
.Where(a => a.Owner == player && a.HasTrait<Building>() && !a.HasTrait<Wall>())
.OrderBy(a => (location - a.CenterLocation).LengthSquared);
}
public static IEnumerable<ProductionQueue> FindQueues(World world, Player player, string category) public static IEnumerable<ProductionQueue> FindQueues(World world, Player player, string category)
{ {
return world.ActorsWithTrait<ProductionQueue>() return world.ActorsWithTrait<ProductionQueue>()
@@ -231,7 +207,7 @@ namespace OpenRA.Mods.RA.Missions
public static void AttackNearestLandActor(bool queued, Actor self, Player enemyPlayer) public static void AttackNearestLandActor(bool queued, Actor self, Player enemyPlayer)
{ {
var enemies = self.World.Actors.Where(u => u.AppearsHostileTo(self) && u.Owner == enemyPlayer var enemies = self.World.Actors.Where(u => u.AppearsHostileTo(self) && u.Owner == enemyPlayer
&& ((u.HasTrait<Building>() && !u.HasTrait<Wall>()) || u.HasTrait<Mobile>()) && u.IsInWorld && !u.IsDead()); && ((u.HasTrait<Building>() && !u.HasTrait<Wall>()) || (u.HasTrait<Mobile>() && !u.HasTrait<Aircraft>())) && u.IsInWorld && !u.IsDead());
var enemy = enemies.OrderBy(u => (self.CenterLocation - u.CenterLocation).LengthSquared).FirstOrDefault(); var enemy = enemies.OrderBy(u => (self.CenterLocation - u.CenterLocation).LengthSquared).FirstOrDefault();
if (enemy != null) if (enemy != null)

View File

@@ -8,13 +8,13 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Traits; using OpenRA.Traits;
using System;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Mods.RA.Missions namespace OpenRA.Mods.RA.Missions
{ {
@@ -137,11 +137,10 @@ namespace OpenRA.Mods.RA.Missions
if (baseTransferredTick == -1) if (baseTransferredTick == -1)
{ {
var actorsInBase = world.FindUnits(alliedBaseTopLeft.CenterLocation, alliedBaseBottomRight.CenterLocation).Where(a => !a.IsDead() && a.IsInWorld); var actorsInBase = world.FindUnits(alliedBaseTopLeft.CenterLocation, alliedBaseBottomRight.CenterLocation).Where(a => a != a.Owner.PlayerActor);
if (actorsInBase.Any(a => a.Owner == greece)) if (actorsInBase.Any(a => a.Owner == greece))
{ {
foreach (var actor in actorsInBase) SetupAlliedBase(actorsInBase);
TransferActorToAllies(actor);
baseTransferredTick = world.FrameNumber; baseTransferredTick = world.FrameNumber;
objectives[FindOutpostID].Status = ObjectiveStatus.Completed; objectives[FindOutpostID].Status = ObjectiveStatus.Completed;
OnObjectivesUpdated(true); OnObjectivesUpdated(true);
@@ -234,20 +233,22 @@ namespace OpenRA.Mods.RA.Missions
} }
} }
void TransferActorToAllies(Actor actor) void SetupAlliedBase(IEnumerable<Actor> actors)
{ {
// hack hack hack foreach (var actor in actors)
actor.ChangeOwner(greece);
if (actor.Info.Name == "pbox")
{ {
actor.AddTrait(new TransformedAction(s => s.Trait<Cargo>().Load(s, world.CreateActor(false, "e1", greece, null, null)))); // hack hack hack
actor.QueueActivity(new Transform(actor, "hbox.e1") { SkipMakeAnims = true }); actor.ChangeOwner(greece);
if (actor.Info.Name == "pbox")
{
actor.AddTrait(new TransformedAction(s => s.Trait<Cargo>().Load(s, world.CreateActor(false, "e1", greece, null, null))));
actor.QueueActivity(new Transform(actor, "hbox.e1") { SkipMakeAnims = true });
}
else if (actor.Info.Name == "proc")
actor.QueueActivity(new Transform(actor, "proc") { SkipMakeAnims = true });
foreach (var c in actor.TraitsImplementing<INotifyCapture>())
c.OnCapture(actor, actor, neutral, greece);
} }
else if (actor.Info.Name == "proc.nofreeactor")
actor.QueueActivity(new Transform(actor, "proc") { SkipMakeAnims = true });
var building = actor.TraitOrDefault<Building>();
if (building != null)
building.OnCapture(actor, actor, neutral, greece);
} }
void EvacuateCivilians() void EvacuateCivilians()

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -24,7 +25,7 @@ namespace OpenRA.Mods.RA
} }
Renderable[] cache = { }; Renderable[] cache = { };
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
if (IsVisible(self.World.RenderedShroud, self)) if (IsVisible(self.World.RenderedShroud, self))
cache = r.ToArray(); cache = r.ToArray();

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -24,7 +25,7 @@ namespace OpenRA.Mods.RA
} }
static Renderable[] Nothing = { }; static Renderable[] Nothing = { };
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
return IsVisible(self.World.RenderedShroud, self) ? r : Nothing; return IsVisible(self.World.RenderedShroud, self) ? r : Nothing;
} }

View File

@@ -32,8 +32,6 @@ namespace OpenRA.Mods.RA
if (remainingFrames > 0) if (remainingFrames > 0)
remainingFrames--; remainingFrames--;
} }
static List<string> excludePalettes = new List<string>{ "cursor", "chrome", "colorpicker", "shroud", "fog" };
public void AdjustPalette(Dictionary<string,Palette> palettes) public void AdjustPalette(Dictionary<string,Palette> palettes)
{ {
@@ -44,9 +42,6 @@ namespace OpenRA.Mods.RA
foreach (var pal in palettes) foreach (var pal in palettes)
{ {
if (excludePalettes.Contains(pal.Key))
continue;
for (var x = 0; x < 256; x++) for (var x = 0; x < 256; x++)
{ {
var orig = pal.Value.GetColor(x); var orig = pal.Value.GetColor(x);

View File

@@ -169,7 +169,6 @@
<Compile Include="ChronoshiftPaletteEffect.cs" /> <Compile Include="ChronoshiftPaletteEffect.cs" />
<Compile Include="Chronoshiftable.cs" /> <Compile Include="Chronoshiftable.cs" />
<Compile Include="Cloak.cs" /> <Compile Include="Cloak.cs" />
<Compile Include="ColorPickerPaletteModifier.cs" />
<Compile Include="Combat.cs" /> <Compile Include="Combat.cs" />
<Compile Include="ConquestVictoryConditions.cs" /> <Compile Include="ConquestVictoryConditions.cs" />
<Compile Include="ContainsCrate.cs" /> <Compile Include="ContainsCrate.cs" />
@@ -408,6 +407,8 @@
<Compile Include="RenderShroudCircle.cs" /> <Compile Include="RenderShroudCircle.cs" />
<Compile Include="Widgets\Logic\CheatsLogic.cs" /> <Compile Include="Widgets\Logic\CheatsLogic.cs" />
<Compile Include="CloakPaletteEffect.cs" /> <Compile Include="CloakPaletteEffect.cs" />
<Compile Include="Widgets\ColorPreviewManagerWidget.cs" />
<Compile Include="FogPalette.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj"> <ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -21,9 +21,10 @@ namespace OpenRA.Mods.RA.Orders
{ {
readonly Actor Producer; readonly Actor Producer;
readonly string Building; readonly string Building;
readonly IEnumerable<Renderable> Preview;
readonly BuildingInfo BuildingInfo; readonly BuildingInfo BuildingInfo;
IEnumerable<Renderable> preview;
Sprite buildOk, buildBlocked; Sprite buildOk, buildBlocked;
bool initialized = false;
public PlaceBuildingOrderGenerator(Actor producer, string name) public PlaceBuildingOrderGenerator(Actor producer, string name)
{ {
@@ -31,9 +32,6 @@ namespace OpenRA.Mods.RA.Orders
Building = name; Building = name;
BuildingInfo = Rules.Info[Building].Traits.Get<BuildingInfo>(); BuildingInfo = Rules.Info[Building].Traits.Get<BuildingInfo>();
Preview = Rules.Info[Building].Traits.Get<RenderBuildingInfo>()
.RenderPreview(Rules.Info[Building], producer.Owner);
buildOk = SequenceProvider.GetSequence("overlay", "build-valid").GetSprite(0); buildOk = SequenceProvider.GetSequence("overlay", "build-valid").GetSprite(0);
buildBlocked = SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0); buildBlocked = SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0);
} }
@@ -43,7 +41,7 @@ namespace OpenRA.Mods.RA.Orders
if (mi.Button == MouseButton.Right) if (mi.Button == MouseButton.Right)
world.CancelInputMode(); world.CancelInputMode();
var ret = InnerOrder( world, xy, mi ).ToList(); var ret = InnerOrder(world, xy, mi).ToList();
if (ret.Count > 0) if (ret.Count > 0)
world.CancelInputMode(); world.CancelInputMode();
@@ -54,26 +52,26 @@ namespace OpenRA.Mods.RA.Orders
{ {
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var topLeft = xy - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); var topLeft = xy - FootprintUtils.AdjustForBuildingSize(BuildingInfo);
if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null) if (!world.CanPlaceBuilding(Building, BuildingInfo, topLeft, null)
|| !BuildingInfo.IsCloseEnoughToBase(world, Producer.Owner, Building, topLeft)) || !BuildingInfo.IsCloseEnoughToBase(world, Producer.Owner, Building, topLeft))
{ {
Sound.PlayNotification(Producer.Owner, "Speech", "BuildingCannotPlaceAudio", Producer.Owner.Country.Race); Sound.PlayNotification(Producer.Owner, "Speech", "BuildingCannotPlaceAudio", Producer.Owner.Country.Race);
yield break; yield break;
} }
var isLineBuild = Rules.Info[ Building ].Traits.Contains<LineBuildInfo>(); var isLineBuild = Rules.Info[Building].Traits.Contains<LineBuildInfo>();
yield return new Order(isLineBuild ? "LineBuild" : "PlaceBuilding", yield return new Order(isLineBuild ? "LineBuild" : "PlaceBuilding",
Producer.Owner.PlayerActor, false) { TargetLocation = topLeft, TargetString = Building }; Producer.Owner.PlayerActor, false) { TargetLocation = topLeft, TargetString = Building };
} }
} }
public void Tick( World world ) {} public void Tick(World world) {}
public void RenderAfterWorld( WorldRenderer wr, World world ) {} public void RenderAfterWorld(WorldRenderer wr, World world) {}
public void RenderBeforeWorld( WorldRenderer wr, World world ) public void RenderBeforeWorld(WorldRenderer wr, World world)
{ {
var position = Game.viewport.ViewToWorld(Viewport.LastMousePos); var position = Game.viewport.ViewToWorld(Viewport.LastMousePos);
var topLeft = position - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); var topLeft = position - FootprintUtils.AdjustForBuildingSize(BuildingInfo);
var actorInfo = Rules.Info[Building]; var actorInfo = Rules.Info[Building];
foreach (var dec in actorInfo.Traits.WithInterface<IPlaceBuildingDecoration>()) foreach (var dec in actorInfo.Traits.WithInterface<IPlaceBuildingDecoration>())
@@ -84,24 +82,34 @@ namespace OpenRA.Mods.RA.Orders
// Assumes a 1x1 footprint; weird things will happen for other footprints // Assumes a 1x1 footprint; weird things will happen for other footprints
if (Rules.Info[Building].Traits.Contains<LineBuildInfo>()) if (Rules.Info[Building].Traits.Contains<LineBuildInfo>())
{ {
foreach( var t in BuildingUtils.GetLineBuildCells( world, topLeft, Building, BuildingInfo ) ) foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, Building, BuildingInfo))
cells.Add( t, BuildingInfo.IsCloseEnoughToBase( world, world.LocalPlayer, Building, t ) ); cells.Add(t, BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, t));
} }
else else
{ {
foreach (var r in Preview) if (!initialized)
{
var rbi = Rules.Info[Building].Traits.Get<RenderBuildingInfo>();
var palette = rbi.Palette ?? (Producer.Owner != null ?
rbi.PlayerPalette + Producer.Owner.InternalName : null);
preview = rbi.RenderPreview(Rules.Info[Building], wr.Palette(palette));
initialized = true;
}
foreach (var r in preview)
r.Sprite.DrawAt(topLeft.ToPPos().ToFloat2() + r.Pos, r.Sprite.DrawAt(topLeft.ToPPos().ToFloat2() + r.Pos,
wr.GetPaletteIndex(r.Palette), r.Palette.Index,
r.Scale*r.Sprite.size); r.Scale*r.Sprite.size);
var res = world.WorldActor.Trait<ResourceLayer>(); var res = world.WorldActor.Trait<ResourceLayer>();
var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft);
foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft))
cells.Add( t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null ); cells.Add(t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo) && res.GetResource(t) == null);
} }
foreach( var c in cells ) foreach (var c in cells)
( c.Value ? buildOk : buildBlocked ).DrawAt(wr, c.Key.ToPPos().ToFloat2(), "terrain" ); (c.Value ? buildOk : buildBlocked).DrawAt(wr, c.Key.ToPPos().ToFloat2(), "terrain");
} }
public string GetCursor(World world, CPos xy, MouseInput mi) { return "default"; } public string GetCursor(World world, CPos xy, MouseInput mi) { return "default"; }

View File

@@ -17,6 +17,7 @@ namespace OpenRA.Mods.RA
{ {
public readonly string Name = null; public readonly string Name = null;
public readonly int[] ShadowIndex = { }; public readonly int[] ShadowIndex = { };
public readonly bool AllowModifiers = true;
public object Create(ActorInitializer init) { return new PaletteFromCurrentTileset(init.world, this); } public object Create(ActorInitializer init) { return new PaletteFromCurrentTileset(init.world, this); }
} }
@@ -32,9 +33,9 @@ namespace OpenRA.Mods.RA
this.info = info; this.info = info;
} }
public void InitPalette( OpenRA.Graphics.WorldRenderer wr ) public void InitPalette(OpenRA.Graphics.WorldRenderer wr)
{ {
wr.AddPalette( info.Name, new Palette( FileSystem.Open( world.TileSet.Palette ), info.ShadowIndex ) ); wr.AddPalette(info.Name, new Palette(FileSystem.Open(world.TileSet.Palette), info.ShadowIndex), info.AllowModifiers);
} }
} }
} }

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA
public readonly string Tileset = null; public readonly string Tileset = null;
public readonly string Filename = null; public readonly string Filename = null;
public readonly int[] ShadowIndex = { }; public readonly int[] ShadowIndex = { };
public readonly bool AllowModifiers = true;
public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); } public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); }
} }
@@ -34,10 +35,10 @@ namespace OpenRA.Mods.RA
this.info = info; this.info = info;
} }
public void InitPalette( WorldRenderer wr ) public void InitPalette(WorldRenderer wr)
{ {
if( info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant() ) if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant())
wr.AddPalette( info.Name, new Palette( FileSystem.Open( info.Filename ), info.ShadowIndex ) ); wr.AddPalette(info.Name, new Palette(FileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers);
} }
} }
} }

View File

@@ -23,6 +23,7 @@ namespace OpenRA.Mods.RA
public readonly int G = 0; public readonly int G = 0;
public readonly int B = 0; public readonly int B = 0;
public readonly int A = 255; public readonly int A = 255;
public readonly bool AllowModifiers = true;
public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.world, this); } public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.world, this); }
} }
@@ -37,28 +38,14 @@ namespace OpenRA.Mods.RA
this.info = info; this.info = info;
} }
public void InitPalette( WorldRenderer wr ) public void InitPalette(WorldRenderer wr)
{ {
if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant()) // Enable palette only for a specific tileset
{ if (info.Tileset != null && info.Tileset.ToLowerInvariant() != world.Map.Tileset.ToLowerInvariant())
// TODO: This shouldn't rely on a base palette return;
var pal = wr.GetPalette("terrain");
wr.AddPalette(info.Name, new Palette(pal, new SingleColorRemap(Color.FromArgb(info.A, info.R, info.G, info.B))));
}
}
}
class SingleColorRemap : IPaletteRemap var c = (uint)((info.A << 24) | (info.R << 16) | (info.G << 8) | info.B);
{ wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (i == 0) ? 0 : c)), info.AllowModifiers);
Color c;
public SingleColorRemap(Color c)
{
this.c = c;
}
public Color GetRemappedColor(Color original, int index)
{
return original.A > 0 ? c : original;
} }
} }
} }

View File

@@ -55,11 +55,9 @@ namespace OpenRA.Mods.RA
var aircraft = self.Trait<IMove>(); var aircraft = self.Trait<IMove>();
self.World.AddFrameEndTask(w => w.Add( self.World.AddFrameEndTask(w => w.Add(
new Parachute( new Parachute(a,
self.Owner,
Util.CenterOfCell(self.CenterLocation.ToCPos()), Util.CenterOfCell(self.CenterLocation.ToCPos()),
aircraft.Altitude, a aircraft.Altitude)
)
)); ));
Sound.Play(info.ChuteSound, self.CenterLocation); Sound.Play(info.ChuteSound, self.CenterLocation);

View File

@@ -17,6 +17,7 @@ namespace OpenRA.Mods.RA
{ {
public readonly string Name = null; public readonly string Name = null;
public readonly int[] ShadowIndex = { }; public readonly int[] ShadowIndex = { };
public readonly bool AllowModifiers = true;
public object Create(ActorInitializer init) { return new PlayerPaletteFromCurrentTileset(init.world, this); } public object Create(ActorInitializer init) { return new PlayerPaletteFromCurrentTileset(init.world, this); }
} }
@@ -35,7 +36,7 @@ namespace OpenRA.Mods.RA
public void InitPalette (OpenRA.Graphics.WorldRenderer wr) public void InitPalette (OpenRA.Graphics.WorldRenderer wr)
{ {
string Filename = world.TileSet.PlayerPalette == null ? world.TileSet.Palette : world.TileSet.PlayerPalette; string Filename = world.TileSet.PlayerPalette == null ? world.TileSet.Palette : world.TileSet.PlayerPalette;
wr.AddPalette(info.Name, new Palette(FileSystem.Open(Filename), info.ShadowIndex)); wr.AddPalette(info.Name, new Palette(FileSystem.Open(Filename), info.ShadowIndex), info.AllowModifiers);
} }
} }
} }

View File

@@ -14,11 +14,12 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {
class RallyPointInfo : ITraitInfo, Requires<RenderSimpleInfo> public class RallyPointInfo : ITraitInfo
{ {
public readonly int[] RallyPoint = { 1, 3 }; public readonly int[] RallyPoint = { 1, 3 };
public readonly string IndicatorPalettePrefix = "player";
public object Create(ActorInitializer init) { return new RallyPoint(init.self); } public object Create(ActorInitializer init) { return new RallyPoint(init.self, this); }
} }
public class RallyPoint : IIssueOrder, IResolveOrder, ISync public class RallyPoint : IIssueOrder, IResolveOrder, ISync
@@ -26,11 +27,10 @@ namespace OpenRA.Mods.RA
[Sync] public CPos rallyPoint; [Sync] public CPos rallyPoint;
public int nearEnough = 1; public int nearEnough = 1;
public RallyPoint(Actor self) public RallyPoint(Actor self, RallyPointInfo info)
{ {
var info = self.Info.Traits.Get<RallyPointInfo>();
rallyPoint = self.Location + new CVec(info.RallyPoint[0], info.RallyPoint[1]); rallyPoint = self.Location + new CVec(info.RallyPoint[0], info.RallyPoint[1]);
self.World.AddFrameEndTask(w => w.Add(new Effects.RallyPoint(self))); self.World.AddFrameEndTask(w => w.Add(new Effects.RallyPoint(self, info.IndicatorPalettePrefix)));
} }
public IEnumerable<IOrderTargeter> Orders public IEnumerable<IOrderTargeter> Orders

View File

@@ -25,9 +25,9 @@ namespace OpenRA.Mods.RA.Render
public readonly float2 Origin = float2.Zero; public readonly float2 Origin = float2.Zero;
public override object Create(ActorInitializer init) { return new RenderBuilding(init, this);} public override object Create(ActorInitializer init) { return new RenderBuilding(init, this);}
public override IEnumerable<Renderable> RenderPreview(ActorInfo building, Player owner) public override IEnumerable<Renderable> RenderPreview(ActorInfo building, PaletteReference pr)
{ {
return base.RenderPreview(building, owner) return base.RenderPreview(building, pr)
.Select(a => a.WithPos(a.Pos + building.Traits.Get<RenderBuildingInfo>().Origin)); .Select(a => a.WithPos(a.Pos + building.Traits.Get<RenderBuildingInfo>().Origin));
} }
} }
@@ -54,7 +54,7 @@ namespace OpenRA.Mods.RA.Render
self.QueueActivity(new CallFunc(() => Complete(self))); self.QueueActivity(new CallFunc(() => Complete(self)));
} }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r) public IEnumerable<Renderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<Renderable> r)
{ {
var disabled = self.IsDisabled(); var disabled = self.IsDisabled();
foreach (var a in r) foreach (var a in r)
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.RA.Render
var ret = a.WithPos(a.Pos - Info.Origin); var ret = a.WithPos(a.Pos - Info.Origin);
yield return ret; yield return ret;
if (disabled) if (disabled)
yield return ret.WithPalette("disabled").WithZOffset(1); yield return ret.WithPalette(wr.Palette("disabled")).WithZOffset(1);
} }
} }

Some files were not shown because too many files have changed in this diff Show More