Compare commits
174 Commits
playtest-2
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77e795cfd4 | ||
|
|
94f800dc8c | ||
|
|
808baa6afd | ||
|
|
2a67fb39a3 | ||
|
|
fc455ba9e2 | ||
|
|
62baeb38a6 | ||
|
|
43a98b4cbd | ||
|
|
2f57c6c33c | ||
|
|
47f2a721b3 | ||
|
|
1f912d94d2 | ||
|
|
ad383170d5 | ||
|
|
399f554316 | ||
|
|
985cd6f7ea | ||
|
|
338093b710 | ||
|
|
76b94cc7f3 | ||
|
|
885068f89d | ||
|
|
886ae8786e | ||
|
|
6bd430fbc2 | ||
|
|
f0ff1c12ed | ||
|
|
02e1cc6172 | ||
|
|
c1c1e30203 | ||
|
|
83e80cd9fd | ||
|
|
646ca0f629 | ||
|
|
02e044dd8b | ||
|
|
a1f7e16085 | ||
|
|
f94b44574d | ||
|
|
2842ea42d7 | ||
|
|
0051d0ce08 | ||
|
|
1c7c329f1d | ||
|
|
4d368c1ec1 | ||
|
|
c504b2a9ae | ||
|
|
b9f08b4607 | ||
|
|
5897230226 | ||
|
|
f26b0f1251 | ||
|
|
7bc4d205fe | ||
|
|
71d4e29483 | ||
|
|
0e082183e3 | ||
|
|
00bce1266f | ||
|
|
09f0242059 | ||
|
|
aa14f1b0a2 | ||
|
|
3cf6148c03 | ||
|
|
eddda3ecca | ||
|
|
ec001a608e | ||
|
|
07ca72127f | ||
|
|
246b25f008 | ||
|
|
0bca700bff | ||
|
|
0d286e12b2 | ||
|
|
811acc5a58 | ||
|
|
265faa3452 | ||
|
|
bc51d6638d | ||
|
|
60a27f9f83 | ||
|
|
a7cfaff96c | ||
|
|
d957a5a15e | ||
|
|
026a27296c | ||
|
|
f7c2043e06 | ||
|
|
4efe8d091c | ||
|
|
97e810d753 | ||
|
|
7ed82fa4c7 | ||
|
|
32b4402ba0 | ||
|
|
897c0f01f0 | ||
|
|
b21b9c9762 | ||
|
|
5bcc83bc0c | ||
|
|
509662d8a6 | ||
|
|
fd171d842e | ||
|
|
9258face3c | ||
|
|
41e5032d48 | ||
|
|
6006dbd235 | ||
|
|
b7e7ff7fc0 | ||
|
|
6d98635e94 | ||
|
|
46762140a5 | ||
|
|
09cdf3b257 | ||
|
|
033e469bea | ||
|
|
7e680b9c02 | ||
|
|
a56d367f60 | ||
|
|
bd2629196a | ||
|
|
011f566c6f | ||
|
|
161907b852 | ||
|
|
1576101a2c | ||
|
|
67ba3e53f2 | ||
|
|
52b061a8a8 | ||
|
|
5755f4048d | ||
|
|
b1b210ea6d | ||
|
|
fc8f1d40c5 | ||
|
|
5d83a5a7d6 | ||
|
|
8c24e87de2 | ||
|
|
13c4f16272 | ||
|
|
20a33b8411 | ||
|
|
51fcb55b22 | ||
|
|
8e7469e194 | ||
|
|
7e0617075f | ||
|
|
4ff6ba8c37 | ||
|
|
958a72aaf8 | ||
|
|
e7df117892 | ||
|
|
57d49d0aeb | ||
|
|
ee86b5f45f | ||
|
|
ba0e3130af | ||
|
|
64427dd1a6 | ||
|
|
7412669d03 | ||
|
|
ec8e9f537d | ||
|
|
9c71d555c1 | ||
|
|
0f191484d7 | ||
|
|
4be5979b90 | ||
|
|
6bd092f192 | ||
|
|
bd6bcda6d0 | ||
|
|
f12deca9ca | ||
|
|
5ea82b4e5e | ||
|
|
2d210a97df | ||
|
|
f03a100115 | ||
|
|
1e30684782 | ||
|
|
abb45197b1 | ||
|
|
a7935f6166 | ||
|
|
7b75a9c2f7 | ||
|
|
9b694f6044 | ||
|
|
0a75019aa0 | ||
|
|
d3e41b6d50 | ||
|
|
18f3e1f57b | ||
|
|
1760f8acd6 | ||
|
|
4154553318 | ||
|
|
e5e8e64ace | ||
|
|
0ae58c10ad | ||
|
|
89ea810cbe | ||
|
|
f6cf35c99c | ||
|
|
5fbaeabb6d | ||
|
|
581907f53a | ||
|
|
7cf4be9d78 | ||
|
|
bdf9f5e201 | ||
|
|
b26b1f410f | ||
|
|
ce69abe1f2 | ||
|
|
b3d2b36875 | ||
|
|
f28b37323f | ||
|
|
7c82ab60e8 | ||
|
|
d14fbd0f84 | ||
|
|
c567f5cbdd | ||
|
|
51a9831fc2 | ||
|
|
4d5777cbc9 | ||
|
|
a6a835d95f | ||
|
|
e16be14ec7 | ||
|
|
11939d3af1 | ||
|
|
feb133c2eb | ||
|
|
f6361b031b | ||
|
|
36967951e6 | ||
|
|
012a9d71ba | ||
|
|
cff369850c | ||
|
|
136b4c0fa9 | ||
|
|
aae2459d0b | ||
|
|
d47ba1d135 | ||
|
|
133cffff24 | ||
|
|
52f6c993d5 | ||
|
|
21eecb048d | ||
|
|
b97398a671 | ||
|
|
a285c908db | ||
|
|
35b39162ff | ||
|
|
0b5b6adc7c | ||
|
|
5357eb6f29 | ||
|
|
e274ac5ff8 | ||
|
|
f8e39bd142 | ||
|
|
48881f4e73 | ||
|
|
d2eb56183d | ||
|
|
afd75c7f55 | ||
|
|
6d1551c9fd | ||
|
|
a015b0990b | ||
|
|
6dd08bbc98 | ||
|
|
343616e924 | ||
|
|
91242a832f | ||
|
|
1c53bfed11 | ||
|
|
e5e7d037a3 | ||
|
|
2a301392c6 | ||
|
|
e35bb8ea95 | ||
|
|
7a4002ff08 | ||
|
|
523fe20255 | ||
|
|
31e0c8b2e3 | ||
|
|
7c37d1cfcc | ||
|
|
8e76a109bd | ||
|
|
ba9b18ccb7 |
1
AUTHORS
1
AUTHORS
@@ -44,6 +44,7 @@ Also thanks to:
|
||||
* clem
|
||||
* Cody Brittain (Generalcamo)
|
||||
* D2k Sardaukar
|
||||
* D'Arcy Rush (r34ch)
|
||||
* Daniel Derejvanik (Harisson)
|
||||
* Danny Keary (Dan9550)
|
||||
* David Jiménez (Rydra)
|
||||
|
||||
@@ -329,7 +329,6 @@ namespace OpenRA
|
||||
Console.WriteLine("Error was: " + e.Message);
|
||||
|
||||
Cursor = new SoftwareCursor(ModData.CursorProvider);
|
||||
Settings.Graphics.HardwareCursors = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace OpenRA.Chat
|
||||
}
|
||||
|
||||
client.Listen();
|
||||
}) { Name = "IrcListenThread" }.Start();
|
||||
}) { Name = "IrcListenThread", IsBackground = true }.Start();
|
||||
}
|
||||
|
||||
void AddNotification(string text)
|
||||
@@ -364,8 +364,19 @@ namespace OpenRA.Chat
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (client.IsConnected)
|
||||
client.Disconnect();
|
||||
// HACK: The IRC library we are using has terrible thread-handling code that relies on Thread.Abort.
|
||||
// There is a thread reading from the network socket which is aborted, however on Windows this is inside
|
||||
// native code so this abort call hangs until the network socket reads something and returns to managed
|
||||
// code where it can then be aborted.
|
||||
//
|
||||
// This means we may hang for several seconds during shutdown (until we receive something over IRC!) before
|
||||
// closing.
|
||||
//
|
||||
// Since our IRC client currently lives forever, the only time we call this Dispose method is during the
|
||||
// shutdown of our process. Therefore, we can work around the problem by just not bothering to disconnect
|
||||
// properly. Since our process is about to die anyway, it's not like anyone will care.
|
||||
////if (client.IsConnected)
|
||||
//// client.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,13 @@ namespace OpenRA.Graphics
|
||||
readonly TerrainSpriteLayer terrain;
|
||||
readonly Theater theater;
|
||||
readonly CellLayer<TerrainTile> mapTiles;
|
||||
readonly CellLayer<byte> mapHeight;
|
||||
|
||||
public TerrainRenderer(World world, WorldRenderer wr)
|
||||
{
|
||||
theater = wr.Theater;
|
||||
mapTiles = world.Map.MapTiles.Value;
|
||||
mapHeight = world.Map.MapHeight.Value;
|
||||
|
||||
terrain = new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha,
|
||||
wr.Palette("terrain"), wr.World.Type != WorldType.Editor);
|
||||
@@ -30,8 +32,8 @@ namespace OpenRA.Graphics
|
||||
foreach (var cell in world.Map.AllCells)
|
||||
UpdateCell(cell);
|
||||
|
||||
world.Map.MapTiles.Value.CellEntryChanged += UpdateCell;
|
||||
world.Map.MapHeight.Value.CellEntryChanged += UpdateCell;
|
||||
mapTiles.CellEntryChanged += UpdateCell;
|
||||
mapHeight.CellEntryChanged += UpdateCell;
|
||||
}
|
||||
|
||||
public void UpdateCell(CPos cell)
|
||||
@@ -48,6 +50,8 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
mapTiles.CellEntryChanged -= UpdateCell;
|
||||
mapHeight.CellEntryChanged -= UpdateCell;
|
||||
terrain.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace OpenRA.Graphics
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly Map map;
|
||||
|
||||
float paletteIndex;
|
||||
readonly PaletteReference palette;
|
||||
|
||||
public TerrainSpriteLayer(World world, WorldRenderer wr, Sheet sheet, BlendMode blendMode, PaletteReference palette, bool restrictToBounds)
|
||||
{
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Graphics
|
||||
this.restrictToBounds = restrictToBounds;
|
||||
Sheet = sheet;
|
||||
BlendMode = blendMode;
|
||||
paletteIndex = palette.TextureIndex;
|
||||
this.palette = palette;
|
||||
|
||||
map = world.Map;
|
||||
rowStride = 4 * map.MapSize.X;
|
||||
@@ -50,21 +50,21 @@ namespace OpenRA.Graphics
|
||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(vertices.Length);
|
||||
emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||
|
||||
wr.PaletteInvalidated += () =>
|
||||
wr.PaletteInvalidated += UpdatePaletteIndices;
|
||||
}
|
||||
|
||||
void UpdatePaletteIndices()
|
||||
{
|
||||
// Everything in the layer uses the same palette,
|
||||
// so we can fix the indices in one pass
|
||||
for (var i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
paletteIndex = palette.TextureIndex;
|
||||
var v = vertices[i];
|
||||
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.U, v.V, palette.TextureIndex, v.C);
|
||||
}
|
||||
|
||||
// Everything in the layer uses the same palette,
|
||||
// so we can fix the indices in one pass
|
||||
for (var i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
var v = vertices[i];
|
||||
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.U, v.V, paletteIndex, v.C);
|
||||
}
|
||||
|
||||
for (var row = 0; row < map.MapSize.Y; row++)
|
||||
dirtyRows.Add(row);
|
||||
};
|
||||
for (var row = 0; row < map.MapSize.Y; row++)
|
||||
dirtyRows.Add(row);
|
||||
}
|
||||
|
||||
public void Update(CPos cell, Sprite sprite)
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA.Graphics
|
||||
sprite = emptySprite;
|
||||
|
||||
var offset = rowStride * uv.V + 4 * uv.U;
|
||||
Util.FastCreateQuad(vertices, pos, sprite, paletteIndex, offset, sprite.Size);
|
||||
Util.FastCreateQuad(vertices, pos, sprite, palette.TextureIndex, offset, sprite.Size);
|
||||
|
||||
dirtyRows.Add(uv.V);
|
||||
}
|
||||
@@ -130,6 +130,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
worldRenderer.PaletteInvalidated -= UpdatePaletteIndices;
|
||||
vertexBuffer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,19 +13,19 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
{
|
||||
public class GenericSelectTarget : IOrderGenerator
|
||||
public class GenericSelectTarget : UnitOrderGenerator
|
||||
{
|
||||
readonly IEnumerable<Actor> subjects;
|
||||
readonly string order;
|
||||
readonly string cursor;
|
||||
readonly MouseButton expectedButton;
|
||||
protected readonly IEnumerable<Actor> Subjects;
|
||||
protected readonly string OrderName;
|
||||
protected readonly string Cursor;
|
||||
protected readonly MouseButton ExpectedButton;
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor, MouseButton button)
|
||||
{
|
||||
this.subjects = subjects;
|
||||
this.order = order;
|
||||
this.cursor = cursor;
|
||||
expectedButton = button;
|
||||
Subjects = subjects;
|
||||
OrderName = order;
|
||||
Cursor = cursor;
|
||||
ExpectedButton = button;
|
||||
}
|
||||
|
||||
public GenericSelectTarget(IEnumerable<Actor> subjects, string order, string cursor)
|
||||
@@ -37,26 +37,23 @@ namespace OpenRA.Orders
|
||||
public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button)
|
||||
: this(new Actor[] { subject }, order, cursor, button) { }
|
||||
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
public override IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button != expectedButton)
|
||||
if (mi.Button != ExpectedButton)
|
||||
world.CancelInputMode();
|
||||
return OrderInner(world, xy, mi);
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, CPos xy, MouseInput mi)
|
||||
protected virtual IEnumerable<Order> OrderInner(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == expectedButton && world.Map.Contains(xy))
|
||||
if (mi.Button == ExpectedButton && world.Map.Contains(xy))
|
||||
{
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in subjects)
|
||||
yield return new Order(order, subject, false) { TargetLocation = xy };
|
||||
foreach (var subject in Subjects)
|
||||
yield return new Order(OrderName, subject, false) { TargetLocation = xy };
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Tick(World world) { }
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? cursor : "generic-blocked"; }
|
||||
public override string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? Cursor : "generic-blocked"; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
{
|
||||
class UnitOrderGenerator : IOrderGenerator
|
||||
public class UnitOrderGenerator : IOrderGenerator
|
||||
{
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
public virtual IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
var underCursor = world.ScreenMap.ActorsAt(mi)
|
||||
.Where(a => !world.FogObscures(a) && a.Info.HasTraitInfo<ITargetableInfo>())
|
||||
@@ -50,11 +50,11 @@ namespace OpenRA.Orders
|
||||
yield return CheckSameOrder(o.Order, o.Trait.IssueOrder(o.Actor, o.Order, o.Target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
}
|
||||
|
||||
public void Tick(World world) { }
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
public virtual void Tick(World world) { }
|
||||
public virtual IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public virtual IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
public virtual string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
var useSelect = false;
|
||||
var underCursor = world.ScreenMap.ActorsAt(mi)
|
||||
@@ -130,7 +130,7 @@ namespace OpenRA.Orders
|
||||
modifiers |= TargetModifiers.ForceMove;
|
||||
|
||||
string cursor = null;
|
||||
if (o.Order.CanTarget(self, target, actorsAt, modifiers, ref cursor))
|
||||
if (o.Order.CanTarget(self, target, actorsAt, ref modifiers, ref cursor))
|
||||
return new UnitOrderResult(self, o.Order, o.Trait, cursor, target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,13 +159,13 @@ namespace OpenRA
|
||||
|
||||
public bool CanTargetActor(Actor a)
|
||||
{
|
||||
if (HasFogVisibility)
|
||||
if (HasFogVisibility && fogVisibilities.Any(f => f.IsVisible(a)))
|
||||
return true;
|
||||
|
||||
return CanViewActor(a);
|
||||
}
|
||||
|
||||
public bool HasFogVisibility { get { return fogVisibilities.Any(f => f.HasFogVisibility(this)); } }
|
||||
public bool HasFogVisibility { get { return fogVisibilities.Any(f => f.HasFogVisibility()); } }
|
||||
|
||||
#region Scripting interface
|
||||
|
||||
|
||||
@@ -372,6 +372,9 @@ namespace OpenRA.Server
|
||||
|
||||
SyncLobbyInfo();
|
||||
|
||||
Log.Write("server", "{0} ({1}) has joined the game.",
|
||||
client.Name, newConn.Socket.RemoteEndPoint);
|
||||
|
||||
if (!LobbyInfo.IsSinglePlayer)
|
||||
SendMessage("{0} has joined the game.".F(client.Name));
|
||||
|
||||
|
||||
@@ -179,7 +179,6 @@ namespace OpenRA
|
||||
|
||||
public bool FetchNews = true;
|
||||
public string NewsUrl = "http://www.openra.net/gamenews";
|
||||
public DateTime NewsFetchedDate;
|
||||
}
|
||||
|
||||
public class KeySettings
|
||||
|
||||
@@ -41,8 +41,12 @@ namespace OpenRA.Traits
|
||||
public DamageState DamageState;
|
||||
|
||||
public bool Visible = true;
|
||||
public bool NeedRenderables { get; private set; }
|
||||
public bool IsRendering { get; private set; }
|
||||
public bool Shrouded { get; private set; }
|
||||
public bool NeedRenderables { get; set; }
|
||||
public IRenderable[] Renderables = NoRenderables;
|
||||
static readonly IRenderable[] NoRenderables = new IRenderable[0];
|
||||
|
||||
int flashTicks;
|
||||
|
||||
public FrozenActor(Actor self, PPos[] footprint, Shroud shroud, bool startsRevealed)
|
||||
{
|
||||
@@ -68,11 +72,6 @@ namespace OpenRA.Traits
|
||||
public ActorInfo Info { get { return actor.Info; } }
|
||||
public Actor Actor { get { return !actor.IsDead ? actor : null; } }
|
||||
|
||||
static readonly IRenderable[] NoRenderables = new IRenderable[0];
|
||||
|
||||
int flashTicks;
|
||||
IRenderable[] renderables = NoRenderables;
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
UpdateVisibility();
|
||||
@@ -84,6 +83,7 @@ namespace OpenRA.Traits
|
||||
void UpdateVisibility()
|
||||
{
|
||||
var wasVisible = Visible;
|
||||
Shrouded = true;
|
||||
|
||||
// We are doing the following LINQ manually for performance since this is a hot path.
|
||||
// Visible = !Footprint.Any(shroud.IsVisible);
|
||||
@@ -93,12 +93,15 @@ namespace OpenRA.Traits
|
||||
if (shroud.IsVisible(puv))
|
||||
{
|
||||
Visible = false;
|
||||
Shrouded = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Shrouded && shroud.IsExplored(puv))
|
||||
Shrouded = false;
|
||||
}
|
||||
|
||||
if (Visible && !wasVisible)
|
||||
NeedRenderables = true;
|
||||
NeedRenderables |= Visible && !wasVisible;
|
||||
}
|
||||
|
||||
public void Flash()
|
||||
@@ -108,28 +111,20 @@ namespace OpenRA.Traits
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (NeedRenderables)
|
||||
{
|
||||
NeedRenderables = false;
|
||||
if (!actor.Disposed)
|
||||
{
|
||||
IsRendering = true;
|
||||
renderables = actor.Render(wr).ToArray();
|
||||
IsRendering = false;
|
||||
}
|
||||
}
|
||||
if (Shrouded)
|
||||
return NoRenderables;
|
||||
|
||||
if (flashTicks > 0 && flashTicks % 2 == 0)
|
||||
{
|
||||
var highlight = wr.Palette("highlight");
|
||||
return renderables.Concat(renderables.Where(r => !r.IsDecoration)
|
||||
return Renderables.Concat(Renderables.Where(r => !r.IsDecoration)
|
||||
.Select(r => r.WithPalette(highlight)));
|
||||
}
|
||||
|
||||
return renderables;
|
||||
return Renderables;
|
||||
}
|
||||
|
||||
public bool HasRenderables { get { return renderables.Any(); } }
|
||||
public bool HasRenderables { get { return !Shrouded && Renderables.Any(); } }
|
||||
|
||||
public bool ShouldBeRemoved(Player owner)
|
||||
{
|
||||
@@ -175,6 +170,8 @@ namespace OpenRA.Traits
|
||||
VisibilityHash = 0;
|
||||
FrozenHash = 0;
|
||||
|
||||
// TODO: Track shroud updates using Shroud.CellsChanged
|
||||
// and then only tick FrozenActors that might have changed
|
||||
foreach (var kvp in frozen)
|
||||
{
|
||||
var hash = (int)kvp.Key;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
string OrderID { get; }
|
||||
int OrderPriority { get; }
|
||||
bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor);
|
||||
bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor);
|
||||
bool IsQueued { get; }
|
||||
bool OverrideSelection { get; }
|
||||
}
|
||||
@@ -189,7 +189,12 @@ namespace OpenRA.Traits
|
||||
public interface IDefaultVisibilityInfo : ITraitInfo { }
|
||||
public interface IDefaultVisibility { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IFogVisibilityModifier { bool HasFogVisibility(Player byPlayer); }
|
||||
|
||||
public interface IFogVisibilityModifier
|
||||
{
|
||||
bool IsVisible(Actor actor);
|
||||
bool HasFogVisibility();
|
||||
}
|
||||
|
||||
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace OpenRA.Widgets
|
||||
public class ChromeLogic : IDisposable
|
||||
{
|
||||
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
|
||||
public virtual void Tick() { }
|
||||
protected virtual void Dispose(bool disposing) { }
|
||||
}
|
||||
|
||||
@@ -436,6 +437,10 @@ namespace OpenRA.Widgets
|
||||
Tick();
|
||||
foreach (var child in Children)
|
||||
child.TickOuter();
|
||||
|
||||
if (LogicObjects != null)
|
||||
foreach (var l in LogicObjects)
|
||||
l.Tick();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,22 @@ namespace OpenRA.Widgets
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string TruncateText(string text, int width, SpriteFont font)
|
||||
{
|
||||
var trimmedWidth = font.Measure(text).X;
|
||||
if (trimmedWidth <= width)
|
||||
return text;
|
||||
|
||||
var trimmed = text;
|
||||
while (trimmedWidth > width && trimmed.Length > 3)
|
||||
{
|
||||
trimmed = text.Substring(0, trimmed.Length - 4) + "...";
|
||||
trimmedWidth = font.Measure(trimmed).X;
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public static Action Once(Action a) { return () => { if (a != null) { a(); a = null; } }; }
|
||||
|
||||
public static string ChooseInitialMap(string initialUid)
|
||||
@@ -242,6 +258,32 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
public class CachedTransform<T, U>
|
||||
{
|
||||
readonly Func<T, U> transform;
|
||||
|
||||
bool initialized;
|
||||
T lastInput;
|
||||
U lastOutput;
|
||||
|
||||
public CachedTransform(Func<T, U> transform)
|
||||
{
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
public U Update(T input)
|
||||
{
|
||||
if (initialized && ((input == null && lastInput == null) || (input != null && input.Equals(lastInput))))
|
||||
return lastOutput;
|
||||
|
||||
lastInput = input;
|
||||
lastOutput = transform(input);
|
||||
initialized = true;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PanelSides
|
||||
{
|
||||
|
||||
@@ -120,12 +120,26 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dragStart.HasValue)
|
||||
else
|
||||
{
|
||||
// Select actors in the dragbox
|
||||
var newSelection = SelectActorsInBoxWithDeadzone(World, dragStart.Value, xy);
|
||||
World.Selection.Combine(World, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy);
|
||||
/* The block below does three things:
|
||||
// 1. Allows actor selection using a selection box regardless of input mode.
|
||||
// 2. Allows actor deselection with a single click in the default input mode (UnitOrderGenerator).
|
||||
// 3. Prevents units from getting deselected when exiting input modes (eg. AttackMove or Guard).
|
||||
//
|
||||
// We cannot check for UnitOrderGenerator here since it's the default order generator that gets activated in
|
||||
// World.CancelInputMode. If we did check it, actor de-selection would not be possible by just clicking somewhere,
|
||||
// only by dragging an empty selection box.
|
||||
*/
|
||||
if (dragStart.HasValue && (!(World.OrderGenerator is GenericSelectTarget) || hasBox))
|
||||
{
|
||||
// Select actors in the dragbox
|
||||
var newSelection = SelectActorsInBoxWithDeadzone(World, dragStart.Value, xy);
|
||||
World.Selection.Combine(World, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy);
|
||||
}
|
||||
}
|
||||
|
||||
World.CancelInputMode();
|
||||
}
|
||||
|
||||
dragStart = dragEnd = null;
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
new FacingInit(64)
|
||||
});
|
||||
|
||||
actor.QueueActivity(new Fly(actor, Target.FromCell(w, self.Location + new CVec(9, 0))));
|
||||
actor.QueueActivity(new Fly(actor, Target.FromCell(w, self.Location + new CVec(12, 0))));
|
||||
actor.QueueActivity(new Land(actor, Target.FromActor(self)));
|
||||
actor.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
readonly Actor target;
|
||||
readonly IDemolishable[] demolishables;
|
||||
readonly EnterBehaviour enterBehaviour;
|
||||
readonly int delay;
|
||||
readonly int flashes;
|
||||
readonly int flashesDelay;
|
||||
@@ -28,11 +29,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
readonly Cloak cloak;
|
||||
|
||||
public Demolish(Actor self, Actor target, int delay, int flashes, int flashesDelay, int flashInterval, int flashDuration)
|
||||
public Demolish(Actor self, Actor target, EnterBehaviour enterBehaviour, int delay,
|
||||
int flashes, int flashesDelay, int flashInterval, int flashDuration)
|
||||
: base(self, target)
|
||||
{
|
||||
this.target = target;
|
||||
demolishables = target.TraitsImplementing<IDemolishable>().ToArray();
|
||||
this.enterBehaviour = enterBehaviour;
|
||||
this.delay = delay;
|
||||
this.flashes = flashes;
|
||||
this.flashesDelay = flashesDelay;
|
||||
@@ -72,6 +75,11 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (Util.ApplyPercentageModifiers(100, modifiers) > 0)
|
||||
demolishables.Do(d => d.Demolish(target, self));
|
||||
}));
|
||||
|
||||
if (enterBehaviour == EnterBehaviour.Suicide)
|
||||
self.Kill(self);
|
||||
else if (enterBehaviour == EnterBehaviour.Dispose)
|
||||
self.Dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
public enum EnterBehaviour { Exit, Suicide, Dispose }
|
||||
|
||||
public abstract class Enter : Activity
|
||||
{
|
||||
public enum ReserveStatus { None, TooFar, Pending, Ready }
|
||||
|
||||
@@ -24,7 +24,7 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class EditorActorBrush : IEditorBrush
|
||||
public sealed class EditorActorBrush : IEditorBrush
|
||||
{
|
||||
public readonly ActorInfo Actor;
|
||||
|
||||
@@ -89,8 +89,13 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
if (mi.Button == MouseButton.Right)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
if (mi.Event == MouseInputEvent.Up)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
@@ -143,5 +148,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
preview.Bounds.Width = (int)(zoom * s.X);
|
||||
preview.Bounds.Height = (int)(zoom * s.Y);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
174
OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs
Normal file
174
OpenRA.Mods.Common/EditorBrushes/EditorCopyPasteBrush.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public sealed class EditorCopyPasteBrush : IEditorBrush
|
||||
{
|
||||
enum State { SelectFirst, SelectSecond, Paste }
|
||||
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly EditorSelectionLayer selectionLayer;
|
||||
readonly EditorActorLayer editorLayer;
|
||||
|
||||
State state;
|
||||
CPos start;
|
||||
CPos end;
|
||||
|
||||
public EditorCopyPasteBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr)
|
||||
{
|
||||
this.editorWidget = editorWidget;
|
||||
worldRenderer = wr;
|
||||
|
||||
selectionLayer = wr.World.WorldActor.Trait<EditorSelectionLayer>();
|
||||
editorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
|
||||
}
|
||||
|
||||
public bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
// Exclusively uses left and right mouse buttons, but nothing else
|
||||
if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right)
|
||||
return false;
|
||||
|
||||
if (mi.Button == MouseButton.Right)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Up)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mi.Button == MouseButton.Left && (mi.Event == MouseInputEvent.Up || mi.Event == MouseInputEvent.Down))
|
||||
{
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
switch (state)
|
||||
{
|
||||
case State.SelectFirst:
|
||||
if (mi.Event != MouseInputEvent.Down)
|
||||
break;
|
||||
start = cell;
|
||||
selectionLayer.SetCopyRegion(start, end);
|
||||
state = State.SelectSecond;
|
||||
break;
|
||||
case State.SelectSecond:
|
||||
if (mi.Event != MouseInputEvent.Up)
|
||||
break;
|
||||
end = cell;
|
||||
selectionLayer.SetCopyRegion(start, end);
|
||||
state = State.Paste;
|
||||
break;
|
||||
case State.Paste:
|
||||
{
|
||||
var gridType = worldRenderer.World.Map.Grid.Type;
|
||||
var source = CellRegion.BoundingRegion(gridType, new[] { start, end });
|
||||
Copy(source, cell - end);
|
||||
editorWidget.ClearBrush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Copy(CellRegion source, CVec offset)
|
||||
{
|
||||
var gridType = worldRenderer.World.Map.Grid.Type;
|
||||
var mapTiles = worldRenderer.World.Map.MapTiles.Value;
|
||||
var mapHeight = worldRenderer.World.Map.MapHeight.Value;
|
||||
var mapResources = worldRenderer.World.Map.MapResources.Value;
|
||||
|
||||
var dest = new CellRegion(gridType, source.TopLeft + offset, source.BottomRight + offset);
|
||||
|
||||
var previews = new Dictionary<string, ActorReference>();
|
||||
var tiles = new Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>>();
|
||||
|
||||
foreach (var cell in source)
|
||||
{
|
||||
if (!mapTiles.Contains(cell) || !mapTiles.Contains(cell + offset))
|
||||
continue;
|
||||
|
||||
tiles.Add(cell + offset, Tuple.Create(mapTiles[cell], mapResources[cell], mapHeight[cell]));
|
||||
|
||||
foreach (var preview in editorLayer.PreviewsAt(cell))
|
||||
{
|
||||
if (previews.ContainsKey(preview.ID))
|
||||
continue;
|
||||
|
||||
var copy = preview.Export();
|
||||
if (copy.InitDict.Contains<LocationInit>())
|
||||
{
|
||||
var location = copy.InitDict.Get<LocationInit>();
|
||||
copy.InitDict.Remove(location);
|
||||
copy.InitDict.Add(new LocationInit(location.Value(worldRenderer.World) + offset));
|
||||
}
|
||||
|
||||
previews.Add(preview.ID, copy);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
mapTiles[kv.Key] = kv.Value.Item1;
|
||||
mapResources[kv.Key] = kv.Value.Item2;
|
||||
mapHeight[kv.Key] = kv.Value.Item3;
|
||||
}
|
||||
|
||||
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
|
||||
foreach (var preview in removeActors)
|
||||
editorLayer.Remove(preview);
|
||||
|
||||
foreach (var kv in previews)
|
||||
editorLayer.Add(kv.Value);
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||
if (state == State.Paste)
|
||||
{
|
||||
selectionLayer.SetPasteRegion(cell + (start - end), cell);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State.SelectFirst)
|
||||
start = end = cell;
|
||||
else if (state == State.SelectSecond)
|
||||
end = cell;
|
||||
|
||||
selectionLayer.SetCopyRegion(start, end);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
selectionLayer.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,13 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public interface IEditorBrush
|
||||
public interface IEditorBrush : IDisposable
|
||||
{
|
||||
bool HandleMouseInput(MouseInput mi);
|
||||
void Tick();
|
||||
}
|
||||
|
||||
public class EditorDefaultBrush : IEditorBrush
|
||||
public sealed class EditorDefaultBrush : IEditorBrush
|
||||
{
|
||||
public readonly ActorInfo Actor;
|
||||
|
||||
@@ -55,12 +55,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
// Exclusively uses mouse wheel and right mouse buttons, but nothing else
|
||||
// Mouse move events are important for tooltips, so we always allow these through
|
||||
if (mi.Button != MouseButton.Right && mi.Event != MouseInputEvent.Move && mi.Event != MouseInputEvent.Scroll)
|
||||
if ((mi.Button != MouseButton.Right && mi.Event != MouseInputEvent.Move && mi.Event != MouseInputEvent.Scroll) ||
|
||||
mi.Event == MouseInputEvent.Down)
|
||||
return false;
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
if (mi.Event == MouseInputEvent.Up)
|
||||
return true;
|
||||
|
||||
var underCursor = editorLayer.PreviewsAt(worldRenderer.Viewport.ViewToWorldPx(mi.Location))
|
||||
.FirstOrDefault();
|
||||
@@ -111,5 +110,6 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class EditorResourceBrush : IEditorBrush
|
||||
public sealed class EditorResourceBrush : IEditorBrush
|
||||
{
|
||||
public readonly ResourceTypeInfo ResourceType;
|
||||
|
||||
@@ -64,8 +64,13 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
if (mi.Button == MouseButton.Right)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
if (mi.Event == MouseInputEvent.Up)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
@@ -114,5 +119,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
preview.Bounds.X = cellScreenPixel.X;
|
||||
preview.Bounds.Y = cellScreenPixel.Y;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class EditorTileBrush : IEditorBrush
|
||||
public sealed class EditorTileBrush : IEditorBrush
|
||||
{
|
||||
public readonly ushort Template;
|
||||
|
||||
@@ -64,8 +64,13 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
if (mi.Button == MouseButton.Right)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
if (mi.Event == MouseInputEvent.Up)
|
||||
{
|
||||
editorWidget.ClearBrush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mi.Button == MouseButton.Left)
|
||||
@@ -151,5 +156,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
preview.Bounds.Width = (int)(zoom * bounds.Width);
|
||||
preview.Bounds.Height = (int)(zoom * bounds.Height);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ namespace OpenRA.Mods.Common.Effects
|
||||
public readonly bool Shadow = false;
|
||||
|
||||
[Desc("Minimum vertical launch angle (pitch).")]
|
||||
public readonly WAngle MinimumLaunchAngle = WAngle.Zero;
|
||||
public readonly WAngle MinimumLaunchAngle = new WAngle(-64);
|
||||
|
||||
[Desc("Maximum vertical launch angle (pitch).")]
|
||||
public readonly WAngle MaximumLaunchAngle = new WAngle(64);
|
||||
public readonly WAngle MaximumLaunchAngle = new WAngle(128);
|
||||
|
||||
[Desc("Minimum launch speed in WDist / tick")]
|
||||
public readonly WDist MinimumLaunchSpeed = new WDist(75);
|
||||
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Effects
|
||||
public readonly WDist MaximumSpeed = new WDist(384);
|
||||
|
||||
[Desc("Projectile acceleration when propulsion activated.")]
|
||||
public readonly WDist Acceleration = new WDist(5);
|
||||
public readonly WDist Acceleration = WDist.Zero;
|
||||
|
||||
[Desc("How many ticks before this missile is armed and can explode.")]
|
||||
public readonly int Arm = 0;
|
||||
|
||||
@@ -705,6 +705,8 @@
|
||||
<Compile Include="Lint\CheckChromeLogic.cs" />
|
||||
<Compile Include="Lint\CheckMapMetadata.cs" />
|
||||
<Compile Include="Widgets\Logic\MultiplayerLogic.cs" />
|
||||
<Compile Include="EditorBrushes\EditorCopyPasteBrush.cs" />
|
||||
<Compile Include="Traits\World\EditorSelectionLayer.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.Mods.Common.Orders
|
||||
|
||||
public AircraftMoveOrderTargeter(AircraftInfo info) { this.info = info; }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (target.Type != TargetType.Terrain)
|
||||
return false;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Orders
|
||||
public int OrderPriority { get; private set; }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (target.Type != TargetType.Actor)
|
||||
return false;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Orders
|
||||
public abstract bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor);
|
||||
public abstract bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor);
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var type = target.Type;
|
||||
if (type != TargetType.Actor && type != TargetType.FrozenActor)
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
[Desc("Demolish the target actor.")]
|
||||
public void Demolish(Actor target)
|
||||
{
|
||||
Self.QueueActivity(new Demolish(Self, target, info.C4Delay, info.Flashes,
|
||||
info.FlashesDelay, info.FlashInterval, info.FlashDuration));
|
||||
Self.QueueActivity(new Demolish(Self, target, info.EnterBehaviour, info.C4Delay,
|
||||
info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public PlayerProperties(ScriptContext context, Player player)
|
||||
: base(context, player) { }
|
||||
|
||||
[Desc("The player's internal name.")]
|
||||
public string InternalName { get { return Player.InternalName; } }
|
||||
|
||||
[Desc("The player's name.")]
|
||||
public string Name { get { return Player.PlayerName; } }
|
||||
|
||||
@@ -52,6 +55,12 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
[Desc("Returns true if the player is a bot.")]
|
||||
public bool IsBot { get { return Player.IsBot; } }
|
||||
|
||||
[Desc("Returns true if the player is non combatant.")]
|
||||
public bool IsNonCombatant { get { return Player.NonCombatant; } }
|
||||
|
||||
[Desc("Returns true if the player is the local player.")]
|
||||
public bool IsLocalPlayer { get { return Player == (Player.World.RenderPlayer ?? Player.World.LocalPlayer); } }
|
||||
|
||||
[Desc("Returns an array of actors representing all ground attack units of this player.")]
|
||||
public Actor[] GetGroundAttackers()
|
||||
{
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
if (actionFunc != null)
|
||||
{
|
||||
var playerIndex = Self.Owner.ClientIndex;
|
||||
var player = Self.Owner;
|
||||
var squadSize = actorTypes.Length;
|
||||
var squad = new List<Actor>();
|
||||
var func = actionFunc.CopyReference() as LuaFunction;
|
||||
@@ -120,7 +120,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
Action<Actor, Actor> productionHandler = (_, __) => { };
|
||||
productionHandler = (factory, unit) =>
|
||||
{
|
||||
if (playerIndex != factory.Owner.ClientIndex)
|
||||
if (player != factory.Owner)
|
||||
{
|
||||
triggers.OnProducedInternal -= productionHandler;
|
||||
return;
|
||||
|
||||
@@ -135,6 +135,10 @@ namespace OpenRA.Mods.Common.Server
|
||||
|
||||
client.Slot = s;
|
||||
S.SyncClientToPlayerReference(client, server.MapPlayers.Players[s]);
|
||||
|
||||
var validatedColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, client.Color, client.Index, conn);
|
||||
client.PreferredColor = client.Color = validatedColor;
|
||||
|
||||
server.SyncLobbyClients();
|
||||
CheckAutoStart(server);
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (self.IsDisabled())
|
||||
return false;
|
||||
|
||||
if (target.Type == TargetType.Actor && !self.Owner.CanTargetActor(target.Actor))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -279,13 +282,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public int OrderPriority { get; private set; }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
bool CanTargetActor(Actor self, Target target, TargetModifiers modifiers, ref string cursor)
|
||||
bool CanTargetActor(Actor self, Target target, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||
|
||||
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
|
||||
// Disguised actors are revealed by the attack cursor
|
||||
// HACK: works around limitations in the targeting code that force the
|
||||
// targeting and attacking logic (which should be logically separate)
|
||||
// to use the same code
|
||||
if (target.Type == TargetType.Actor && target.Actor.EffectiveOwner != null &&
|
||||
target.Actor.EffectiveOwner.Disguised && self.Owner.Stances[target.Actor.Owner] == Stance.Enemy)
|
||||
modifiers |= TargetModifiers.ForceAttack;
|
||||
|
||||
var forceAttack = modifiers.HasModifier(TargetModifiers.ForceAttack);
|
||||
var a = ab.ChooseArmamentsForTarget(target, forceAttack).FirstOrDefault();
|
||||
if (a == null)
|
||||
@@ -326,13 +337,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
switch (target.Type)
|
||||
{
|
||||
case TargetType.Actor:
|
||||
case TargetType.FrozenActor:
|
||||
return CanTargetActor(self, target, modifiers, ref cursor);
|
||||
return CanTargetActor(self, target, ref modifiers, ref cursor);
|
||||
case TargetType.Terrain:
|
||||
return CanTargetLocation(self, self.World.Map.CellContaining(target.CenterPosition), othersAtTarget, modifiers, ref cursor);
|
||||
default:
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
&& !target.IsInRange(self.CenterPosition, arm.Weapon.MinRange))), a);
|
||||
})
|
||||
|
||||
.Where(kv => kv.Key != null && self.Owner.CanViewActor(kv.Value))
|
||||
.Where(kv => kv.Key != null && (self.Owner.HasFogVisibility || self.Owner.CanViewActor(kv.Value)))
|
||||
.GroupBy(kv => kv.Key, kv => kv.Value)
|
||||
.ToDictionary(kv => kv.Key, kv => kv.ClosestTo(self));
|
||||
|
||||
|
||||
@@ -38,10 +38,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public RallyPointInfo Info;
|
||||
public string PaletteName { get; private set; }
|
||||
|
||||
public void ResetLocation(Actor self)
|
||||
{
|
||||
Location = self.Location + Info.Offset;
|
||||
}
|
||||
|
||||
public RallyPoint(Actor self, RallyPointInfo info)
|
||||
{
|
||||
Info = info;
|
||||
Location = self.Location + info.Offset;
|
||||
ResetLocation(self);
|
||||
PaletteName = info.IsPlayerPalette ? info.Palette + self.Owner.InternalName : info.Palette;
|
||||
self.World.Add(new RallyPointIndicator(self, this));
|
||||
}
|
||||
@@ -50,6 +55,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (Info.IsPlayerPalette)
|
||||
PaletteName = Info.Palette + newOwner.InternalName;
|
||||
|
||||
ResetLocation(self);
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
@@ -77,7 +84,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public int OrderPriority { get { return 0; } }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (target.Type != TargetType.Terrain)
|
||||
return false;
|
||||
|
||||
@@ -23,18 +23,22 @@ namespace OpenRA.Mods.Common.Traits
|
||||
"Measured in game ticks. Default is 1.8 seconds.")]
|
||||
public readonly int C4Delay = 45;
|
||||
|
||||
[Desc("Number of times to flash the target")]
|
||||
[Desc("Number of times to flash the target.")]
|
||||
public readonly int Flashes = 3;
|
||||
|
||||
[Desc("Delay before the flashing starts")]
|
||||
[Desc("Delay before the flashing starts.")]
|
||||
public readonly int FlashesDelay = 4;
|
||||
|
||||
[Desc("Interval between each flash")]
|
||||
[Desc("Interval between each flash.")]
|
||||
public readonly int FlashInterval = 4;
|
||||
|
||||
[Desc("Duration of each flash")]
|
||||
[Desc("Duration of each flash.")]
|
||||
public readonly int FlashDuration = 3;
|
||||
|
||||
[Desc("Behaviour when entering the structure.",
|
||||
"Possible values are Exit, Suicide, Dispose.")]
|
||||
public readonly EnterBehaviour EnterBehaviour = EnterBehaviour.Exit;
|
||||
|
||||
[Desc("Voice string when planting explosive charges.")]
|
||||
[VoiceReference] public readonly string Voice = "Action";
|
||||
|
||||
@@ -83,8 +87,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new Demolish(self,
|
||||
target.Actor, info.C4Delay, info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration));
|
||||
self.QueueActivity(new Demolish(self, target.Actor, info.EnterBehaviour, info.C4Delay,
|
||||
info.Flashes, info.FlashesDelay, info.FlashInterval, info.FlashDuration));
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -59,52 +60,40 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public class GuardOrderGenerator : IOrderGenerator
|
||||
public class GuardOrderGenerator : GenericSelectTarget
|
||||
{
|
||||
readonly IEnumerable<Actor> subjects;
|
||||
public GuardOrderGenerator(IEnumerable<Actor> subjects, string order, string cursor, MouseButton button)
|
||||
: base(subjects, order, cursor, button) { }
|
||||
|
||||
public GuardOrderGenerator(IEnumerable<Actor> subjects)
|
||||
protected override IEnumerable<Order> OrderInner(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
this.subjects = subjects;
|
||||
}
|
||||
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == Game.Settings.Game.MouseButtonPreference.Cancel)
|
||||
{
|
||||
world.CancelInputMode();
|
||||
yield break;
|
||||
}
|
||||
|
||||
var target = FriendlyGuardableUnits(world, mi).FirstOrDefault();
|
||||
|
||||
if (target == null || subjects.All(s => s.IsDead))
|
||||
if (target == null || Subjects.All(s => s.IsDead))
|
||||
yield break;
|
||||
|
||||
foreach (var subject in subjects)
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in Subjects)
|
||||
if (subject != target)
|
||||
yield return new Order("Guard", subject, false) { TargetActor = target };
|
||||
yield return new Order(OrderName, subject, false) { TargetActor = target };
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
public override void Tick(World world)
|
||||
{
|
||||
if (subjects.All(s => s.IsDead || !s.Info.HasTraitInfo<GuardInfo>()))
|
||||
if (Subjects.All(s => s.IsDead || !s.Info.HasTraitInfo<GuardInfo>()))
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
public override string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (!subjects.Any())
|
||||
if (!Subjects.Any())
|
||||
return null;
|
||||
|
||||
var multiple = subjects.Count() > 1;
|
||||
var multiple = Subjects.Count() > 1;
|
||||
var canGuard = FriendlyGuardableUnits(world, mi)
|
||||
.Any(a => multiple || a != subjects.First());
|
||||
.Any(a => multiple || a != Subjects.First());
|
||||
|
||||
return canGuard ? "guard" : "move-blocked";
|
||||
return canGuard ? Cursor : "move-blocked";
|
||||
}
|
||||
|
||||
static IEnumerable<Actor> FriendlyGuardableUnits(World world, MouseInput mi)
|
||||
|
||||
@@ -454,7 +454,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public bool IsQueued { get; protected set; }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (target.Type != TargetType.Terrain)
|
||||
return false;
|
||||
|
||||
@@ -706,7 +706,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public int OrderPriority { get { return 4; } }
|
||||
public bool IsQueued { get; protected set; }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (rejectMove || !target.IsValidFor(self))
|
||||
return false;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
||||
}
|
||||
|
||||
public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ISync
|
||||
public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ITickRender, ISync
|
||||
{
|
||||
[Sync] public int VisibilityHash;
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly Dictionary<Player, FrozenState> stateByPlayer = new Dictionary<Player, FrozenState>();
|
||||
|
||||
bool initialized;
|
||||
bool isRendering;
|
||||
|
||||
class FrozenState
|
||||
{
|
||||
@@ -132,11 +133,35 @@ namespace OpenRA.Mods.Common.Traits
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void TickRender(WorldRenderer wr, Actor self)
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
IRenderable[] renderables = null;
|
||||
foreach (var player in self.World.Players)
|
||||
{
|
||||
var frozen = stateByPlayer[player].FrozenActor;
|
||||
if (!frozen.NeedRenderables)
|
||||
continue;
|
||||
|
||||
if (renderables == null)
|
||||
{
|
||||
isRendering = true;
|
||||
renderables = self.Render(wr).ToArray();
|
||||
isRendering = false;
|
||||
}
|
||||
|
||||
frozen.NeedRenderables = false;
|
||||
frozen.Renderables = renderables;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
{
|
||||
return
|
||||
IsVisible(self, self.World.RenderPlayer) ||
|
||||
(initialized && stateByPlayer[self.World.RenderPlayer].FrozenActor.IsRendering) ?
|
||||
(initialized && isRendering) ?
|
||||
r : SpriteRenderable.None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
@@ -59,19 +60,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Should this be visible to enemy players?")]
|
||||
public readonly bool ShowToEnemies = false;
|
||||
|
||||
[Desc("Should this be visible only when selected?")]
|
||||
public readonly bool SelectionDecoration = false;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new WithDecoration(init.Self, this); }
|
||||
}
|
||||
|
||||
public class WithDecoration : UpgradableTrait<WithDecorationInfo>, IRender
|
||||
public class WithDecoration : UpgradableTrait<WithDecorationInfo>, IRender, IPostRenderSelection
|
||||
{
|
||||
readonly WithDecorationInfo info;
|
||||
readonly string image;
|
||||
readonly Animation anim;
|
||||
readonly Actor self;
|
||||
|
||||
public WithDecoration(Actor self, WithDecorationInfo info)
|
||||
: base(info)
|
||||
{
|
||||
this.info = info;
|
||||
this.self = self;
|
||||
image = info.Image ?? self.Info.Name;
|
||||
anim = new Animation(self.World, image);
|
||||
anim.Paused = () => self.World.Paused;
|
||||
@@ -86,6 +92,16 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public virtual bool ShouldRender(Actor self) { return true; }
|
||||
|
||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||
{
|
||||
return !info.SelectionDecoration ? RenderInner(self, wr, self.Bounds) : Enumerable.Empty<IRenderable>();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr)
|
||||
{
|
||||
return info.SelectionDecoration ? RenderInner(self, wr, self.VisualBounds) : Enumerable.Empty<IRenderable>();
|
||||
}
|
||||
|
||||
IEnumerable<IRenderable> RenderInner(Actor self, WorldRenderer wr, Rectangle actorBounds)
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
return Enumerable.Empty<IRenderable>();
|
||||
@@ -111,7 +127,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return Enumerable.Empty<IRenderable>();
|
||||
|
||||
var pxPos = wr.ScreenPxPosition(self.CenterPosition);
|
||||
var actorBounds = self.Bounds;
|
||||
actorBounds.Offset(pxPos.X, pxPos.Y);
|
||||
|
||||
var img = anim.Image;
|
||||
|
||||
@@ -65,7 +65,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
var cell = Util.RandomWalk(self.Location, self.World.SharedRandom)
|
||||
.Take(info.MaxRange)
|
||||
.SkipWhile(p => resLayer.GetResource(p) == resourceType && resLayer.IsFull(p))
|
||||
.SkipWhile(p => !self.World.Map.Contains(p) ||
|
||||
(resLayer.GetResource(p) == resourceType && resLayer.IsFull(p)))
|
||||
.Cast<CPos?>().FirstOrDefault();
|
||||
|
||||
if (cell != null && resLayer.CanSpawnResourceAt(resourceType, cell.Value))
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly int Range = 1;
|
||||
public readonly string GrantUpgradeSound = "ironcur9.aud";
|
||||
|
||||
[Desc("Sequence to play for granting actor when activated."), SequenceReference]
|
||||
[SequenceReference, Desc("Sequence to play for granting actor when activated.",
|
||||
"This requires the actor to have the WithSpriteBody trait or one of its derivatives.")]
|
||||
public readonly string GrantUpgradeSequence = "active";
|
||||
|
||||
public override object Create(ActorInitializer init) { return new GrantUpgradePower(init.Self, this); }
|
||||
@@ -56,7 +57,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
base.Activate(self, order, manager);
|
||||
|
||||
self.Trait<WithSpriteBody>().PlayCustomAnimation(self, info.GrantUpgradeSequence);
|
||||
var wsb = self.TraitOrDefault<WithSpriteBody>();
|
||||
if (wsb != null && wsb.DefaultAnimation.HasSequence(info.GrantUpgradeSequence))
|
||||
wsb.PlayCustomAnimation(self, info.GrantUpgradeSequence);
|
||||
|
||||
Game.Sound.Play(info.GrantUpgradeSound, self.World.Map.CenterOfCell(order.TargetLocation));
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Traits;
|
||||
@@ -95,9 +96,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void DeployTransform(bool queued)
|
||||
{
|
||||
var building = self.TraitOrDefault<Building>();
|
||||
if (!CanDeploy() || (building != null && !building.Lock()))
|
||||
if (!queued && !CanDeploy())
|
||||
{
|
||||
// Only play the "Cannot deploy here" audio
|
||||
// for non-queued orders
|
||||
foreach (var s in info.NoTransformSounds)
|
||||
Game.Sound.PlayToPlayer(self.Owner, s);
|
||||
|
||||
@@ -115,23 +117,31 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (self.Info.HasTraitInfo<AircraftInfo>())
|
||||
self.QueueActivity(new HeliLand(self, true));
|
||||
|
||||
foreach (var nt in self.TraitsImplementing<INotifyTransform>())
|
||||
nt.BeforeTransform(self);
|
||||
|
||||
var transform = new Transform(self, info.IntoActor)
|
||||
self.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
Offset = info.Offset,
|
||||
Facing = info.Facing,
|
||||
Sounds = info.TransformSounds,
|
||||
Notification = info.TransformNotification,
|
||||
Faction = faction
|
||||
};
|
||||
// Prevent deployment in bogus locations
|
||||
var building = self.TraitOrDefault<Building>();
|
||||
if (!CanDeploy() || (building != null && !building.Lock()))
|
||||
return;
|
||||
|
||||
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
|
||||
if (makeAnimation != null)
|
||||
makeAnimation.Reverse(self, transform);
|
||||
else
|
||||
self.QueueActivity(transform);
|
||||
foreach (var nt in self.TraitsImplementing<INotifyTransform>())
|
||||
nt.BeforeTransform(self);
|
||||
|
||||
var transform = new Transform(self, info.IntoActor)
|
||||
{
|
||||
Offset = info.Offset,
|
||||
Facing = info.Facing,
|
||||
Sounds = info.TransformSounds,
|
||||
Notification = info.TransformNotification,
|
||||
Faction = faction
|
||||
};
|
||||
|
||||
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
|
||||
if (makeAnimation != null)
|
||||
makeAnimation.Reverse(self, transform);
|
||||
else
|
||||
self.QueueActivity(transform);
|
||||
}));
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
@@ -20,9 +19,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class DeployToUpgradeInfo : ITraitInfo, Requires<UpgradeManagerInfo>
|
||||
{
|
||||
[UpgradeGrantedReference]
|
||||
[Desc("The upgrades to grant while the actor is undeployed.")]
|
||||
public readonly string[] UndeployedUpgrades = { };
|
||||
|
||||
[UpgradeGrantedReference, FieldLoader.Require]
|
||||
[Desc("The upgrades to grant when deploying and revoke when undeploying.")]
|
||||
public readonly string[] Upgrades = { };
|
||||
[Desc("The upgrades to grant after deploying and revoke before undeploying.")]
|
||||
public readonly string[] DeployedUpgrades = { };
|
||||
|
||||
[Desc("The terrain types that this actor can deploy on to receive these upgrades. " +
|
||||
"Leave empty to allow any.")]
|
||||
@@ -52,8 +55,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public object Create(ActorInitializer init) { return new DeployToUpgrade(init.Self, this); }
|
||||
}
|
||||
|
||||
public class DeployToUpgrade : IResolveOrder, IIssueOrder
|
||||
public class DeployToUpgrade : IResolveOrder, IIssueOrder, INotifyCreated
|
||||
{
|
||||
enum DeployState { Undeployed, Deploying, Deployed }
|
||||
|
||||
readonly Actor self;
|
||||
readonly DeployToUpgradeInfo info;
|
||||
readonly UpgradeManager manager;
|
||||
@@ -61,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly bool canTurn;
|
||||
readonly Lazy<ISpriteBody> body;
|
||||
|
||||
bool isUpgraded;
|
||||
DeployState deployState;
|
||||
|
||||
public DeployToUpgrade(Actor self, DeployToUpgradeInfo info)
|
||||
{
|
||||
@@ -73,6 +78,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
body = Exts.Lazy(self.TraitOrDefault<ISpriteBody>);
|
||||
}
|
||||
|
||||
public void Created(Actor self)
|
||||
{
|
||||
OnUndeployCompleted();
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get { yield return new DeployOrderTargeter("DeployToUpgrade", 5,
|
||||
@@ -89,59 +99,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "DeployToUpgrade")
|
||||
if (order.OrderString != "DeployToUpgrade" || deployState == DeployState.Deploying)
|
||||
return;
|
||||
|
||||
if (!IsOnValidTerrain())
|
||||
return;
|
||||
|
||||
if (isUpgraded)
|
||||
{
|
||||
// Play undeploy animation and after that revoke the upgrades
|
||||
self.QueueActivity(false, new CallFunc(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.UndeploySound))
|
||||
Game.Sound.Play(info.UndeploySound, self.CenterPosition);
|
||||
|
||||
if (string.IsNullOrEmpty(info.DeployAnimation))
|
||||
{
|
||||
RevokeUpgrades();
|
||||
return;
|
||||
}
|
||||
|
||||
if (body.Value != null)
|
||||
body.Value.PlayCustomAnimationBackwards(self, info.DeployAnimation, RevokeUpgrades);
|
||||
else
|
||||
RevokeUpgrades();
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!order.Queued)
|
||||
self.CancelActivity();
|
||||
|
||||
// Turn
|
||||
if (deployState == DeployState.Deployed)
|
||||
{
|
||||
self.QueueActivity(new CallFunc(Undeploy));
|
||||
}
|
||||
else if (deployState == DeployState.Undeployed)
|
||||
{
|
||||
// Turn to the required facing.
|
||||
if (info.Facing != -1 && canTurn)
|
||||
self.QueueActivity(new Turn(self, info.Facing));
|
||||
|
||||
// Grant the upgrade
|
||||
self.QueueActivity(new CallFunc(GrantUpgrades));
|
||||
|
||||
// Play deploy sound and animation
|
||||
self.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.DeploySound))
|
||||
Game.Sound.Play(info.DeploySound, self.CenterPosition);
|
||||
|
||||
if (string.IsNullOrEmpty(info.DeployAnimation))
|
||||
return;
|
||||
|
||||
if (body.Value != null)
|
||||
body.Value.PlayCustomAnimation(self, info.DeployAnimation,
|
||||
() => body.Value.PlayCustomAnimationRepeating(self, "idle"));
|
||||
}));
|
||||
self.QueueActivity(new CallFunc(Deploy));
|
||||
}
|
||||
|
||||
isUpgraded = !isUpgraded;
|
||||
}
|
||||
|
||||
bool IsOnValidTerrain()
|
||||
@@ -181,16 +156,80 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return ramp == 0;
|
||||
}
|
||||
|
||||
void GrantUpgrades()
|
||||
/// <summary>Play deploy sound and animation.</summary>
|
||||
void Deploy()
|
||||
{
|
||||
foreach (var up in info.Upgrades)
|
||||
manager.GrantUpgrade(self, up, this);
|
||||
// Something went wrong, most likely due to deploy order spam and the fact that this is a delayed action.
|
||||
if (deployState != DeployState.Undeployed)
|
||||
return;
|
||||
|
||||
if (!IsOnValidTerrain())
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(info.DeploySound))
|
||||
Game.Sound.Play(info.DeploySound, self.CenterPosition);
|
||||
|
||||
// Revoke upgrades that are used while undeployed.
|
||||
OnDeployStarted();
|
||||
|
||||
// If there is no animation to play just grant the upgrades that are used while deployed.
|
||||
// Alternatively, play the deploy animation and then grant the upgrades.
|
||||
if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null)
|
||||
OnDeployCompleted();
|
||||
else
|
||||
body.Value.PlayCustomAnimation(self, info.DeployAnimation, OnDeployCompleted);
|
||||
}
|
||||
|
||||
void RevokeUpgrades()
|
||||
/// <summary>Play undeploy sound and animation and after that revoke the upgrades.</summary>
|
||||
void Undeploy()
|
||||
{
|
||||
foreach (var up in info.Upgrades)
|
||||
// Something went wrong, most likely due to deploy order spam and the fact that this is a delayed action.
|
||||
if (deployState != DeployState.Deployed)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(info.UndeploySound))
|
||||
Game.Sound.Play(info.UndeploySound, self.CenterPosition);
|
||||
|
||||
OnUndeployStarted();
|
||||
|
||||
// If there is no animation to play just grant the upgrades that are used while undeployed.
|
||||
// Alternatively, play the undeploy animation and then grant the upgrades.
|
||||
if (string.IsNullOrEmpty(info.DeployAnimation))
|
||||
OnUndeployCompleted();
|
||||
else
|
||||
body.Value.PlayCustomAnimationBackwards(self, info.DeployAnimation, OnUndeployCompleted);
|
||||
}
|
||||
|
||||
void OnDeployStarted()
|
||||
{
|
||||
deployState = DeployState.Deploying;
|
||||
|
||||
foreach (var up in info.UndeployedUpgrades)
|
||||
manager.RevokeUpgrade(self, up, this);
|
||||
}
|
||||
|
||||
void OnDeployCompleted()
|
||||
{
|
||||
foreach (var up in info.DeployedUpgrades)
|
||||
manager.GrantUpgrade(self, up, this);
|
||||
|
||||
deployState = DeployState.Deployed;
|
||||
}
|
||||
|
||||
void OnUndeployStarted()
|
||||
{
|
||||
foreach (var up in info.DeployedUpgrades)
|
||||
manager.RevokeUpgrade(self, up, this);
|
||||
|
||||
deployState = DeployState.Deploying;
|
||||
}
|
||||
|
||||
void OnUndeployCompleted()
|
||||
{
|
||||
deployState = DeployState.Undeployed;
|
||||
|
||||
foreach (var up in info.UndeployedUpgrades)
|
||||
manager.GrantUpgrade(self, up, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void ActorEntered(Actor a)
|
||||
{
|
||||
if (a.Disposed)
|
||||
if (a.Disposed || self.Disposed)
|
||||
return;
|
||||
|
||||
if (a == self && !info.AffectsParent)
|
||||
@@ -106,6 +106,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void UnitProducedByOther(Actor self, Actor producer, Actor produced)
|
||||
{
|
||||
// If the produced Actor doesn't occupy space, it can't be in range
|
||||
if (produced.OccupiesSpace == null)
|
||||
return;
|
||||
|
||||
// Work around for actors produced within the region not triggering until the second tick
|
||||
if ((produced.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= info.Range.LengthSquared)
|
||||
{
|
||||
@@ -123,7 +127,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void ActorExited(Actor a)
|
||||
{
|
||||
if (a == self || a.Disposed)
|
||||
if (a == self || a.Disposed || self.Disposed)
|
||||
return;
|
||||
|
||||
var stance = self.Owner.Stances[a.Owner];
|
||||
|
||||
@@ -186,6 +186,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
Players.Players.Add(pr.Name, pr);
|
||||
worldRenderer.UpdatePalettesForPlayer(pr.Name, pr.Color, true);
|
||||
}
|
||||
|
||||
var creeps = Players.Players.Keys.FirstOrDefault(p => p == "Creeps");
|
||||
if (!string.IsNullOrEmpty(creeps))
|
||||
Players.Players[creeps].Enemies = Players.Players.Keys.Where(p => !Players.Players[p].NonCombatant).ToArray();
|
||||
}
|
||||
|
||||
void UpdateNeighbours(IReadOnlyDictionary<CPos, SubCell> footprint)
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
var tooltip = Info.TraitInfoOrDefault<TooltipInfo>();
|
||||
Tooltip = tooltip == null ? ID + ": " + Info.Name : ID + ": " + tooltip.Name + " (" + Info.Name + ")" + "\n" + owner.Name + " (" + owner.Faction + ")";
|
||||
Tooltip = tooltip == null ? ID + ": " + Info.Name : ID + ": " + tooltip.Name + " (" + Info.Name + ")";
|
||||
|
||||
GeneratePreviews();
|
||||
|
||||
@@ -160,5 +160,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
.SelectMany(rpi => rpi.RenderPreview(init))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public ActorReference Export()
|
||||
{
|
||||
return new ActorReference(actor.Type, actor.Save().ToDictionary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var kv in spriteLayers.Values)
|
||||
kv.Dispose();
|
||||
|
||||
Map.MapResources.Value.CellEntryChanged -= UpdateCell;
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
105
OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs
Normal file
105
OpenRA.Mods.Common/Traits/World/EditorSelectionLayer.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Required for the map editor to work. Attach this to the world actor.")]
|
||||
public class EditorSelectionLayerInfo : ITraitInfo
|
||||
{
|
||||
[PaletteReference]
|
||||
[Desc("Palette to use for rendering the placement sprite.")]
|
||||
public readonly string Palette = "terrain";
|
||||
|
||||
[Desc("Sequence image where the selection overlay types are defined.")]
|
||||
public readonly string Image = "editor-overlay";
|
||||
|
||||
[SequenceReference("Image")]
|
||||
[Desc("Sequence to use for the copy overlay.")]
|
||||
public readonly string CopySequence = "copy";
|
||||
|
||||
[SequenceReference("Image")]
|
||||
[Desc("Sequence to use for the paste overlay.")]
|
||||
public readonly string PasteSequence = "paste";
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new EditorSelectionLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
public class EditorSelectionLayer : IWorldLoaded, IPostRender
|
||||
{
|
||||
readonly EditorSelectionLayerInfo info;
|
||||
readonly Map map;
|
||||
readonly Sprite copySprite;
|
||||
readonly Sprite pasteSprite;
|
||||
PaletteReference palette;
|
||||
|
||||
public CellRegion CopyRegion { get; private set; }
|
||||
public CellRegion PasteRegion { get; private set; }
|
||||
|
||||
public EditorSelectionLayer(Actor self, EditorSelectionLayerInfo info)
|
||||
{
|
||||
if (self.World.Type != WorldType.Editor)
|
||||
return;
|
||||
|
||||
this.info = info;
|
||||
map = self.World.Map;
|
||||
copySprite = map.SequenceProvider.GetSequence(info.Image, info.CopySequence).GetSprite(0);
|
||||
pasteSprite = map.SequenceProvider.GetSequence(info.Image, info.PasteSequence).GetSprite(0);
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
if (w.Type != WorldType.Editor)
|
||||
return;
|
||||
|
||||
palette = wr.Palette(info.Palette);
|
||||
}
|
||||
|
||||
public void SetCopyRegion(CPos start, CPos end)
|
||||
{
|
||||
CopyRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end });
|
||||
}
|
||||
|
||||
public void SetPasteRegion(CPos start, CPos end)
|
||||
{
|
||||
PasteRegion = CellRegion.BoundingRegion(map.Grid.Type, new[] { start, end });
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
CopyRegion = PasteRegion = null;
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, Actor self)
|
||||
{
|
||||
if (wr.World.Type != WorldType.Editor)
|
||||
return;
|
||||
|
||||
if (CopyRegion != null)
|
||||
foreach (var c in CopyRegion)
|
||||
new SpriteRenderable(copySprite, wr.World.Map.CenterOfCell(c),
|
||||
WVec.Zero, -511, palette, 1f, true).PrepareRender(wr).Render(wr);
|
||||
|
||||
if (PasteRegion != null)
|
||||
foreach (var c in PasteRegion)
|
||||
new SpriteRenderable(pasteSprite, wr.World.Map.CenterOfCell(c),
|
||||
WVec.Zero, -511, palette, 1f, true).PrepareRender(wr).Render(wr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,6 +294,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var kv in spriteLayers.Values)
|
||||
kv.Dispose();
|
||||
|
||||
RenderContent.CellEntryChanged -= UpdateSpriteLayers;
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Hard or soft fading between the WindLevels.")]
|
||||
public readonly bool InstantWindChanges = false;
|
||||
|
||||
[Desc("Particles are drawn in squares when enabled, else with lines.")]
|
||||
[Desc("Particles are drawn in squares when enabled, otherwise with lines.")]
|
||||
public readonly bool UseSquares = true;
|
||||
|
||||
[Desc("Works only with squares enabled. Size min. and max. value in pixels.")]
|
||||
public readonly int[] PaticleSize = { 1, 3 };
|
||||
public readonly int[] ParticleSize = { 1, 3 };
|
||||
|
||||
[Desc("Scatters falling direction on the x-axis. Scatter min. and max. value in px/tick.")]
|
||||
public readonly int[] ScatterDirection = { -1, 1 };
|
||||
@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
Color.FromArgb(255, 188, 188, 188)
|
||||
};
|
||||
|
||||
[Desc("Works only with line enabled and can get used to fade out the tail of the line like a contrail.")]
|
||||
[Desc("Works only with line enabled and can be used to fade out the tail of the line like a contrail.")]
|
||||
public readonly byte LineTailAlphaValue = 200;
|
||||
|
||||
public object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); }
|
||||
@@ -130,7 +130,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
PosX = Game.CosmeticRandom.Next(Game.Renderer.Resolution.Width),
|
||||
PosY = Game.CosmeticRandom.Next(rangeY),
|
||||
Size = Game.CosmeticRandom.Next(info.PaticleSize[0], info.PaticleSize[1] + 1),
|
||||
Size = Game.CosmeticRandom.Next(info.ParticleSize[0], info.ParticleSize[1] + 1),
|
||||
DirectionScatterX = info.ScatterDirection[0] + Game.CosmeticRandom.Next(info.ScatterDirection[1] - info.ScatterDirection[0]),
|
||||
Gravity = float2.Lerp(info.Gravity[0], info.Gravity[1], Game.CosmeticRandom.NextFloat()),
|
||||
SwingOffset = float2.Lerp(info.SwingOffset[0], info.SwingOffset[1], Game.CosmeticRandom.NextFloat()),
|
||||
|
||||
@@ -31,6 +31,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
"Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow")]
|
||||
public void Run(ModData modData, string[] args)
|
||||
{
|
||||
// HACK: The engine code assumes that Game.modData is set.
|
||||
Game.ModData = modData;
|
||||
Game.ModData.MountFiles();
|
||||
|
||||
var src = args[1];
|
||||
var shadowIndex = new int[] { };
|
||||
if (args.Contains("--noshadow"))
|
||||
|
||||
@@ -1611,7 +1611,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
|
||||
var otherNodes = nodes;
|
||||
var inherits = new Func<string, bool>(traitName => node.Value.Nodes.Where(n => n.Key.StartsWith("Inherits"))
|
||||
.Any(inh => otherNodes.First(n => n.Key.StartsWith(inh.Value.Value)).Value.Nodes.Any(n => n.Key.StartsWith(traitName))));
|
||||
.Any(inh =>
|
||||
{
|
||||
var otherNode = otherNodes.FirstOrDefault(n => n.Key.StartsWith(inh.Value.Value));
|
||||
|
||||
if (otherNode == null)
|
||||
return false;
|
||||
|
||||
return otherNode.Value.Nodes.Any(n => n.Key.StartsWith(traitName));
|
||||
}));
|
||||
|
||||
// For actors that have or inherit a TargetableUnit, disable the trait while parachuting
|
||||
var tu = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("TargetableUnit"));
|
||||
@@ -1727,7 +1735,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
|
||||
// SpawnViceroid was replaced by SpawnActorOnDeath
|
||||
// And LeavesHusk was renamed to SpawnActorOnDeath
|
||||
if (engineVersion < 20150809)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (node.Key == "SpawnViceroid")
|
||||
{
|
||||
@@ -1774,15 +1782,21 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
if (actor != null)
|
||||
actor.Key = "Actor";
|
||||
}
|
||||
|
||||
if (node.Key == "-SpawnViceroid")
|
||||
node.Key = "-SpawnActorOnDeath";
|
||||
|
||||
if (node.Key == "-LeavesHusk")
|
||||
node.Key = "-SpawnActorOnDeath";
|
||||
}
|
||||
|
||||
if (engineVersion < 20150810)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (depth == 2 && parentKey == "RallyPoint" && node.Key == "RallyPoint")
|
||||
node.Key = "Offset";
|
||||
}
|
||||
|
||||
if (engineVersion < 20150811)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (node.Key.StartsWith("ProductionQueue"))
|
||||
{
|
||||
@@ -1806,7 +1820,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20150816)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
// Rename RenderSprites.RaceImages
|
||||
if (depth == 2 && node.Key == "RaceImages")
|
||||
@@ -1820,35 +1834,40 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
node.Key = "ValidFactions";
|
||||
}
|
||||
|
||||
if (engineVersion < 20150823)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
// Introduce QuantizeFacingsFromSequence
|
||||
// This will only do roughly the right thing and probably require the modder to do some manual cleanup
|
||||
if (depth == 0)
|
||||
{
|
||||
var inftraits = node.Value.Nodes.FirstOrDefault(n =>
|
||||
n.Key.StartsWith("WithInfantryBody")
|
||||
|| n.Key.StartsWith("WithDisguisingInfantryBody"));
|
||||
if (inftraits != null)
|
||||
// Check if the upgrade rule ran already before
|
||||
var qffs = node.Value.Nodes.FirstOrDefault(n => n.Key == "QuantizeFacingsFromSequence");
|
||||
if (qffs == null)
|
||||
{
|
||||
node.Value.Nodes.Add(new MiniYamlNode("QuantizeFacingsFromSequence", null, new List<MiniYamlNode>
|
||||
var inftraits = node.Value.Nodes.FirstOrDefault(n =>
|
||||
n.Key.StartsWith("WithInfantryBody")
|
||||
|| n.Key.StartsWith("WithDisguisingInfantryBody"));
|
||||
if (inftraits != null)
|
||||
{
|
||||
new MiniYamlNode("Sequence", "stand"),
|
||||
}));
|
||||
}
|
||||
node.Value.Nodes.Add(new MiniYamlNode("QuantizeFacingsFromSequence", null, new List<MiniYamlNode>
|
||||
{
|
||||
new MiniYamlNode("Sequence", "stand"),
|
||||
}));
|
||||
}
|
||||
|
||||
var other = node.Value.Nodes.FirstOrDefault(x =>
|
||||
x.Key.StartsWith("RenderBuilding")
|
||||
|| x.Key.StartsWith("RenderSimple")
|
||||
|| x.Key.StartsWith("WithCrateBody")
|
||||
|| x.Key.StartsWith("WithSpriteBody")
|
||||
|| x.Key.StartsWith("WithFacingSpriteBody"));
|
||||
if (other != null)
|
||||
node.Value.Nodes.Add(new MiniYamlNode("QuantizeFacingsFromSequence", ""));
|
||||
var other = node.Value.Nodes.FirstOrDefault(x =>
|
||||
x.Key.StartsWith("RenderBuilding")
|
||||
|| x.Key.StartsWith("RenderSimple")
|
||||
|| x.Key.StartsWith("WithCrateBody")
|
||||
|| x.Key.StartsWith("WithSpriteBody")
|
||||
|| x.Key.StartsWith("WithFacingSpriteBody"));
|
||||
if (other != null)
|
||||
node.Value.Nodes.Add(new MiniYamlNode("QuantizeFacingsFromSequence", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20150826)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
// Replaced RenderBuildingCharge with RenderSprites + WithSpriteBody + WithChargeAnimation (+AutoSelectionSize)
|
||||
if (depth == 0)
|
||||
@@ -1969,7 +1988,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20150828)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
// Replaced RenderBuilding with RenderSprites + WithSpriteBody (+AutoSelectionSize)
|
||||
if (depth == 0)
|
||||
@@ -2003,7 +2022,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20150902)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (depth == 1)
|
||||
{
|
||||
@@ -2041,7 +2060,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
// Add `WhileCloakedUpgrades: underwater` to Cloak trait if `CloakTypes: Underwater`
|
||||
var cloak = node.Value.Nodes.FirstOrDefault(n => (n.Key == "Cloak" || n.Key.StartsWith("Cloak@"))
|
||||
&& n.Value.Nodes.Any(p => p.Key == "CloakTypes" && p.Value.Value == "Underwater"));
|
||||
if (cloak != null)
|
||||
if (cloak != null && !cloak.Value.Nodes.Any(n => n.Key == "WhileCloakedUpgrades"))
|
||||
cloak.Value.Nodes.Add(new MiniYamlNode("WhileCloakedUpgrades", "underwater"));
|
||||
|
||||
// Remove split traits if TargetableSubmarine was removed
|
||||
@@ -2092,14 +2111,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// WaterPaletteRotation renamed to RotationPaletteEffect
|
||||
if (engineVersion < 20150903)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (depth == 1 && node.Key == "WaterPaletteRotation")
|
||||
node.Key = "RotationPaletteEffect";
|
||||
}
|
||||
|
||||
// Replace RenderSimple with RenderSprites + WithSpriteBody + AutoSelectionSize
|
||||
if (engineVersion < 20150909)
|
||||
if (engineVersion < 20150920)
|
||||
{
|
||||
if (depth == 0)
|
||||
{
|
||||
@@ -2125,18 +2144,19 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// Rename D2k actors to match the original game.
|
||||
if (engineVersion < 20150910 && Game.ModData.Manifest.Mod.Id == "d2k")
|
||||
if (engineVersion < 20150920 && Game.ModData.Manifest.Mod.Id == "d2k")
|
||||
node.Key = RenameD2kActors(node.Key);
|
||||
|
||||
// Make Range WDist for all traits with circular ranges.
|
||||
if (engineVersion < 20150917 && depth == 2 && node.Key == "Range")
|
||||
if (engineVersion < 20150920 && depth == 2 && node.Key == "Range")
|
||||
{
|
||||
if (parentKey == "DetectCloaked"
|
||||
if ((parentKey == "DetectCloaked"
|
||||
|| parentKey == "JamsMissiles"
|
||||
|| parentKey == "JamsRadar"
|
||||
|| parentKey == "Guardable"
|
||||
|| parentKey == "BaseProvider"
|
||||
|| parentKey == "ProximityCapturable")
|
||||
&& !node.Value.Value.Contains("c0"))
|
||||
node.Value.Value = node.Value.Value + "c0";
|
||||
}
|
||||
|
||||
@@ -2197,15 +2217,54 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
node.Key = "Aircraft";
|
||||
node.Value.Nodes.Add(new MiniYamlNode("CanHover", "True"));
|
||||
}
|
||||
|
||||
var mplane = node.Value.Nodes.FirstOrDefault(n => n.Key == "-Plane");
|
||||
if (mplane != null)
|
||||
{
|
||||
// Check if a Helicopter trait was renamed to Aircraft
|
||||
// In that case, we don't want to straight negate it with -Aircraft again
|
||||
if (node.Value.Nodes.Any(n => n.Key == "Aircraft" || n.Key == "Helicopter"))
|
||||
{
|
||||
Console.WriteLine("Warning: Removed '-Plane:', this can introduce side effects with inherited 'Aircraft' definitions.");
|
||||
node.Value.Nodes.Remove(mplane);
|
||||
}
|
||||
else
|
||||
mplane.Key = "-Aircraft";
|
||||
}
|
||||
|
||||
var mheli = node.Value.Nodes.FirstOrDefault(n => n.Key == "-Helicopter");
|
||||
if (mheli != null)
|
||||
{
|
||||
// Check if a Plane trait was renamed to Aircraft
|
||||
// In that case, we don't want to straight negate it with -Aircraft again
|
||||
if (node.Value.Nodes.Any(n => n.Key == "Aircraft" || n.Key == "Plane"))
|
||||
{
|
||||
Console.WriteLine("Warning: Removed '-Helicopter:', this can introduce side effects with inherited 'Aircraft' definitions.");
|
||||
node.Value.Nodes.Remove(mheli);
|
||||
}
|
||||
else
|
||||
mheli.Key = "-Aircraft";
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20151004)
|
||||
{
|
||||
if (depth == 1 && node.Key == "WithRotor")
|
||||
// Rename WithRotor to WithSpriteRotorOverlay
|
||||
if (depth == 1 && node.Key.StartsWith("WithRotor"))
|
||||
{
|
||||
var parts = node.Key.Split('@');
|
||||
node.Key = "WithSpriteRotorOverlay";
|
||||
if (parts.Length > 1)
|
||||
node.Key += "@" + parts[1];
|
||||
}
|
||||
|
||||
if (depth == 1 && node.Key == "-WithRotor")
|
||||
if (depth == 1 && node.Key.StartsWith("-WithRotor"))
|
||||
{
|
||||
var parts = node.Key.Split('@');
|
||||
node.Key = "-WithSpriteRotorOverlay";
|
||||
if (parts.Length > 1)
|
||||
node.Key += "@" + parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20151005)
|
||||
@@ -2216,7 +2275,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
{
|
||||
var otherNodes = nodes;
|
||||
var inherits = new Func<string, bool>(traitName => node.Value.Nodes.Where(n => n.Key.StartsWith("Inherits"))
|
||||
.Any(inh => otherNodes.First(n => n.Key.StartsWith(inh.Value.Value)).Value.Nodes.Any(n => n.Key.StartsWith(traitName))));
|
||||
.Any(inh =>
|
||||
{
|
||||
var otherNode = otherNodes.FirstOrDefault(n => n.Key.StartsWith(inh.Value.Value));
|
||||
|
||||
if (otherNode == null)
|
||||
return false;
|
||||
|
||||
return otherNode.Value.Nodes.Any(n => n.Key.StartsWith(traitName));
|
||||
}));
|
||||
|
||||
var target = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("-AutoTarget"));
|
||||
if (target != null)
|
||||
@@ -2272,11 +2339,29 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
if (depth == 1 && node.Key == "AutoTarget")
|
||||
{
|
||||
var stance = node.Value.Nodes.FirstOrDefault(n => n.Key == "InitialStance");
|
||||
if (stance != null)
|
||||
var aiStance = node.Value.Nodes.FirstOrDefault(n => n.Key == "InitialStanceAI");
|
||||
if (stance != null && aiStance == null)
|
||||
node.Value.Nodes.Add(new MiniYamlNode("InitialStanceAI", stance.Value.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (engineVersion < 20151107 && depth == 2)
|
||||
{
|
||||
if (node.Key == "PaticleSize")
|
||||
node.Key = "ParticleSize";
|
||||
}
|
||||
|
||||
// Upgrades on DeployToUpgrade were renamed to DeployedUpgrades
|
||||
if (engineVersion < 20151122)
|
||||
{
|
||||
if (node.Key == "DeployToUpgrade")
|
||||
{
|
||||
var u = node.Value.Nodes.FirstOrDefault(n => n.Key == "Upgrades");
|
||||
if (u != null)
|
||||
u.Key = "DeployedUpgrades";
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||
}
|
||||
}
|
||||
@@ -2368,8 +2453,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
oldNodeAtName = "_" + curNode.Key.Split('@')[1];
|
||||
|
||||
// Per Cell Damage Model
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DamageModel") &&
|
||||
n.Value.Value.Contains("PerCell")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("DamageModel") &&
|
||||
n.Value.Value.Contains("PerCell")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
@@ -2404,14 +2489,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// HealthPercentage damage model
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DamageModel") &&
|
||||
n.Value.Value.Contains("HealthPercentage")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("DamageModel") &&
|
||||
n.Value.Value.Contains("HealthPercentage")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
var newYaml = new List<MiniYamlNode>();
|
||||
|
||||
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Size"); // New HealthPercentage warhead allows 2 spreads, as opposed to 1 size
|
||||
// New HealthPercentage warhead allows 2 spreads, as opposed to 1 size
|
||||
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Size");
|
||||
if (temp != null)
|
||||
{
|
||||
var newValue = temp.Value.Value.Split(',').First() + "c0";
|
||||
@@ -2440,7 +2526,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// SpreadDamage
|
||||
{ // Always occurs, since by definition all warheads were SpreadDamage warheads before
|
||||
// Always occurs, since by definition all warheads were SpreadDamage warheads before
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
var newYaml = new List<MiniYamlNode>();
|
||||
@@ -2467,8 +2554,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// DestroyResource
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DestroyResources") ||
|
||||
n.Key.Contains("Ore")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("DestroyResources") ||
|
||||
n.Key.Contains("Ore")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
@@ -2486,7 +2573,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// CreateResource
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("AddsResourceType")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("AddsResourceType")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
@@ -2505,7 +2592,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// LeaveSmudge
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("SmudgeType")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("SmudgeType")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
@@ -2524,8 +2611,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// CreateEffect - Explosion
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("Explosion") ||
|
||||
n.Key.Contains("ImpactSound")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("Explosion") ||
|
||||
n.Key.Contains("ImpactSound")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
@@ -2546,8 +2633,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
// CreateEffect - Water Explosion
|
||||
if (curNode.Value.Nodes.Where(n => n.Key.Contains("WaterExplosion") ||
|
||||
n.Key.Contains("WaterImpactSound")).Any())
|
||||
if (curNode.Value.Nodes.Any(n => n.Key.Contains("WaterExplosion") ||
|
||||
n.Key.Contains("WaterImpactSound")))
|
||||
{
|
||||
warheadCounter++;
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
|
||||
public virtual void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
|
||||
{
|
||||
if (!IsValidAgainst(victim, firedBy))
|
||||
return;
|
||||
|
||||
var damage = Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(DamageVersus(victim)));
|
||||
victim.InflictDamage(firedBy, damage, this);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
|
||||
public override void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
|
||||
{
|
||||
if (!IsValidAgainst(victim, firedBy))
|
||||
return;
|
||||
|
||||
var healthInfo = victim.Info.TraitInfoOrDefault<HealthInfo>();
|
||||
if (healthInfo == null)
|
||||
return;
|
||||
|
||||
@@ -62,9 +62,6 @@ namespace OpenRA.Mods.Common.Warheads
|
||||
|
||||
foreach (var victim in hitActors)
|
||||
{
|
||||
if (!IsValidAgainst(victim, firedBy))
|
||||
continue;
|
||||
|
||||
var localModifiers = damageModifiers;
|
||||
var healthInfo = victim.Info.TraitInfoOrDefault<HealthInfo>();
|
||||
if (healthInfo != null)
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public void ClearBrush() { SetBrush(null); }
|
||||
public void SetBrush(IEditorBrush brush)
|
||||
{
|
||||
if (CurrentBrush != null)
|
||||
CurrentBrush.Dispose();
|
||||
|
||||
CurrentBrush = brush ?? defaultBrush;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
[ObjectCreator.UseCtor]
|
||||
public MapEditorLogic(Widget widget, World world, WorldRenderer worldRenderer)
|
||||
{
|
||||
var editorViewport = widget.Get<EditorViewportControllerWidget>("MAP_EDITOR");
|
||||
|
||||
var gridButton = widget.GetOrNull<ButtonWidget>("GRID_BUTTON");
|
||||
var terrainGeometryTrait = world.WorldActor.Trait<TerrainGeometryOverlay>();
|
||||
|
||||
@@ -63,6 +65,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
};
|
||||
}
|
||||
|
||||
var copypasteButton = widget.GetOrNull<ButtonWidget>("COPYPASTE_BUTTON");
|
||||
if (copypasteButton != null)
|
||||
{
|
||||
copypasteButton.OnClick = () => editorViewport.SetBrush(new EditorCopyPasteBrush(editorViewport, worldRenderer));
|
||||
copypasteButton.IsHighlighted = () => editorViewport.CurrentBrush is EditorCopyPasteBrush;
|
||||
}
|
||||
|
||||
var coordinateLabel = widget.GetOrNull<LabelWidget>("COORDINATE_LABEL");
|
||||
if (coordinateLabel != null)
|
||||
coordinateLabel.GetText = () => worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos).ToString();
|
||||
|
||||
@@ -76,8 +76,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var mapDirectory = map.Path != null ? Platform.UnresolvePath(Path.GetDirectoryName(map.Path)) : null;
|
||||
var initialDirectory = mapDirectories.Keys.FirstOrDefault(f => f == mapDirectory);
|
||||
|
||||
// Prioritize MapClassification.User directories over system directories
|
||||
if (initialDirectory == null)
|
||||
initialDirectory = mapDirectories.Keys.First();
|
||||
initialDirectory = mapDirectories.OrderByDescending(kv => kv.Value).First().Key;
|
||||
|
||||
directoryDropdown.Text = initialDirectory;
|
||||
directoryDropdown.OnClick = () =>
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
@@ -50,11 +53,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var client = world.LobbyInfo.ClientWithIndex(pp.ClientIndex);
|
||||
var item = playerTemplate.Clone();
|
||||
var nameLabel = item.Get<LabelWidget>("NAME");
|
||||
var nameFont = Game.Renderer.Fonts[nameLabel.Font];
|
||||
|
||||
var suffixLength = new CachedTransform<string, int>(s => nameFont.Measure(s).X);
|
||||
var name = new CachedTransform<Pair<string, int>, string>(c =>
|
||||
WidgetUtils.TruncateText(c.First, nameLabel.Bounds.Width - c.Second, nameFont));
|
||||
|
||||
nameLabel.GetText = () =>
|
||||
{
|
||||
var suffix = pp.WinState == WinState.Undefined ? "" : " (" + pp.WinState + ")";
|
||||
if (client != null && client.State == Network.Session.ClientState.Disconnected)
|
||||
return pp.PlayerName + " (Gone)";
|
||||
return pp.PlayerName + (pp.WinState == WinState.Undefined ? "" : " (" + pp.WinState + ")");
|
||||
suffix = " (Gone)";
|
||||
|
||||
var sl = suffixLength.Update(suffix);
|
||||
return name.Update(Pair.New(pp.PlayerName, sl)) + suffix;
|
||||
};
|
||||
nameLabel.GetColor = () => pp.Color.RGB;
|
||||
|
||||
|
||||
@@ -62,6 +62,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
readonly LabelWidget chatLabel;
|
||||
bool teamChat;
|
||||
|
||||
int lobbyChatUnreadMessages;
|
||||
int globalChatLastReadMessages;
|
||||
int globalChatUnreadMessages;
|
||||
|
||||
// Listen for connection failures
|
||||
void ConnectionStateChanged(OrderManager om)
|
||||
{
|
||||
@@ -583,6 +587,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
globalChatInput.TakeKeyboardFocus();
|
||||
};
|
||||
|
||||
var globalChatLabel = globalChatTab.Text;
|
||||
globalChatTab.GetText = () =>
|
||||
{
|
||||
if (globalChatUnreadMessages == 0 || chatPanel == ChatPanelType.Global)
|
||||
return globalChatLabel;
|
||||
|
||||
return globalChatLabel + " ({0})".F(globalChatUnreadMessages);
|
||||
};
|
||||
|
||||
globalChatLastReadMessages = Game.GlobalChat.History.Count;
|
||||
|
||||
var lobbyChat = lobby.Get("LOBBYCHAT");
|
||||
lobbyChat.IsVisible = () => chatPanel == ChatPanelType.Lobby;
|
||||
|
||||
@@ -624,6 +639,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
chatTextField.TakeKeyboardFocus();
|
||||
};
|
||||
|
||||
var lobbyChatLabel = lobbyChatTab.Text;
|
||||
lobbyChatTab.GetText = () =>
|
||||
{
|
||||
if (lobbyChatUnreadMessages == 0 || chatPanel == ChatPanelType.Lobby)
|
||||
return lobbyChatLabel;
|
||||
|
||||
return lobbyChatLabel + " ({0})".F(lobbyChatUnreadMessages);
|
||||
};
|
||||
|
||||
lobbyChatPanel = lobby.Get<ScrollPanelWidget>("CHAT_DISPLAY");
|
||||
chatTemplate = lobbyChatPanel.Get("CHAT_TEMPLATE");
|
||||
lobbyChatPanel.RemoveChildren();
|
||||
@@ -652,8 +676,23 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
}
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
var newMessages = Game.GlobalChat.History.Count;
|
||||
globalChatUnreadMessages += newMessages - globalChatLastReadMessages;
|
||||
globalChatLastReadMessages = newMessages;
|
||||
|
||||
if (chatPanel == ChatPanelType.Lobby)
|
||||
lobbyChatUnreadMessages = 0;
|
||||
|
||||
if (chatPanel == ChatPanelType.Global)
|
||||
globalChatUnreadMessages = 0;
|
||||
}
|
||||
|
||||
void AddChatLine(Color c, string from, string text)
|
||||
{
|
||||
lobbyChatUnreadMessages += 1;
|
||||
|
||||
var template = chatTemplate.Clone();
|
||||
var nameLabel = template.Get<LabelWidget>("NAME");
|
||||
var timeLabel = template.Get<LabelWidget>("TIME");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
@@ -28,17 +29,25 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
preview.OnMouseDown = mi => LobbyUtils.SelectSpawnPoint(orderManager, preview, lobby.Map, mi);
|
||||
preview.SpawnOccupants = () => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, lobby.Map);
|
||||
|
||||
var title = available.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||
if (title != null)
|
||||
title.GetText = () => lobby.Map.Title;
|
||||
var titleLabel = available.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||
if (titleLabel != null)
|
||||
{
|
||||
var font = Game.Renderer.Fonts[titleLabel.Font];
|
||||
var title = new CachedTransform<MapPreview, string>(m => WidgetUtils.TruncateText(m.Title, titleLabel.Bounds.Width, font));
|
||||
titleLabel.GetText = () => title.Update(lobby.Map);
|
||||
}
|
||||
|
||||
var type = available.GetOrNull<LabelWidget>("MAP_TYPE");
|
||||
if (type != null)
|
||||
type.GetText = () => lobby.Map.Type;
|
||||
var typeLabel = available.GetOrNull<LabelWidget>("MAP_TYPE");
|
||||
if (typeLabel != null)
|
||||
typeLabel.GetText = () => lobby.Map.Type;
|
||||
|
||||
var author = available.GetOrNull<LabelWidget>("MAP_AUTHOR");
|
||||
if (author != null)
|
||||
author.GetText = () => "Created by {0}".F(lobby.Map.Author);
|
||||
var authorLabel = available.GetOrNull<LabelWidget>("MAP_AUTHOR");
|
||||
if (authorLabel != null)
|
||||
{
|
||||
var font = Game.Renderer.Fonts[authorLabel.Font];
|
||||
var author = new CachedTransform<MapPreview, string>(m => WidgetUtils.TruncateText("Created by {0}".F(lobby.Map.Author), authorLabel.Bounds.Width, font));
|
||||
authorLabel.GetText = () => author.Update(lobby.Map);
|
||||
}
|
||||
}
|
||||
|
||||
var invalid = widget.GetOrNull("MAP_INVALID");
|
||||
|
||||
@@ -291,7 +291,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
public static void SetupNameWidget(Widget parent, Session.Slot s, Session.Client c)
|
||||
{
|
||||
var name = parent.Get<LabelWidget>("NAME");
|
||||
name.GetText = () => c.Name;
|
||||
var font = Game.Renderer.Fonts[name.Font];
|
||||
var label = WidgetUtils.TruncateText(c.Name, name.Bounds.Width, font);
|
||||
name.GetText = () => label;
|
||||
}
|
||||
|
||||
public static void SetupEditableSlotWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, Ruleset rules)
|
||||
@@ -472,14 +474,23 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
else
|
||||
flag.GetImageName = () => player.Faction.InternalName;
|
||||
|
||||
var playerName = template.Get<LabelWidget>("PLAYER");
|
||||
var client = player.World.LobbyInfo.ClientWithIndex(player.ClientIndex);
|
||||
var playerName = template.Get<LabelWidget>("PLAYER");
|
||||
var playerNameFont = Game.Renderer.Fonts[playerName.Font];
|
||||
var suffixLength = new CachedTransform<string, int>(s => playerNameFont.Measure(s).X);
|
||||
var name = new CachedTransform<Pair<string, int>, string>(c =>
|
||||
WidgetUtils.TruncateText(c.First, playerName.Bounds.Width - c.Second, playerNameFont));
|
||||
|
||||
playerName.GetText = () =>
|
||||
{
|
||||
var suffix = player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")";
|
||||
if (client != null && client.State == Network.Session.ClientState.Disconnected)
|
||||
return player.PlayerName + " (Gone)";
|
||||
return player.PlayerName + (player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")");
|
||||
suffix = " (Gone)";
|
||||
|
||||
var sl = suffixLength.Update(suffix);
|
||||
return name.Update(Pair.New(player.PlayerName, sl)) + suffix;
|
||||
};
|
||||
|
||||
playerName.GetColor = () => player.Color.RGB;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
readonly Widget newsTemplate;
|
||||
readonly LabelWidget newsStatus;
|
||||
|
||||
// Update news once per game launch
|
||||
static bool fetchedNews;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public MainMenuLogic(Widget widget, World world)
|
||||
{
|
||||
@@ -207,27 +210,28 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
if (newsButton != null)
|
||||
{
|
||||
// Only query for news once per day.
|
||||
var cacheValid = currentNews != null && DateTime.Today.ToUniversalTime() <= Game.Settings.Game.NewsFetchedDate;
|
||||
if (!cacheValid)
|
||||
if (!fetchedNews)
|
||||
new Download(Game.Settings.Game.NewsUrl, cacheFile, e => { },
|
||||
(e, c) => NewsDownloadComplete(e, cacheFile, currentNews, () => newsButton.AttachPanel(newsPanel)));
|
||||
(e, c) => NewsDownloadComplete(e, cacheFile, currentNews,
|
||||
() => newsButton.AttachPanel(newsPanel)));
|
||||
|
||||
newsButton.OnClick = () => newsButton.AttachPanel(newsPanel);
|
||||
}
|
||||
}
|
||||
|
||||
Game.OnRemoteDirectConnect += (host, port) =>
|
||||
Game.OnRemoteDirectConnect += OnRemoteDirectConnect;
|
||||
}
|
||||
|
||||
void OnRemoteDirectConnect(string host, int port)
|
||||
{
|
||||
menuType = MenuType.None;
|
||||
Ui.OpenWindow("MULTIPLAYER_PANEL", new WidgetArgs
|
||||
{
|
||||
menuType = MenuType.None;
|
||||
Ui.OpenWindow("MULTIPLAYER_PANEL", new WidgetArgs
|
||||
{
|
||||
{ "onStart", RemoveShellmapUI },
|
||||
{ "onExit", () => menuType = MenuType.Main },
|
||||
{ "directConnectHost", host },
|
||||
{ "directConnectPort", port },
|
||||
});
|
||||
};
|
||||
{ "onStart", RemoveShellmapUI },
|
||||
{ "onExit", () => menuType = MenuType.Main },
|
||||
{ "directConnectHost", host },
|
||||
{ "directConnectPort", port },
|
||||
});
|
||||
}
|
||||
|
||||
void LoadMapIntoEditor(Map map)
|
||||
@@ -290,6 +294,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return;
|
||||
}
|
||||
|
||||
fetchedNews = true;
|
||||
var newNews = ParseNews(cacheFile);
|
||||
if (newNews == null)
|
||||
return;
|
||||
@@ -298,9 +303,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
if (oldNews == null || newNews.Any(n => !oldNews.Select(c => c.DateTime).Contains(n.DateTime)))
|
||||
onNewsDownloaded();
|
||||
|
||||
Game.Settings.Game.NewsFetchedDate = DateTime.Today.ToUniversalTime();
|
||||
Game.Settings.Save();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -362,5 +364,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
OpenSkirmishLobbyPanel,
|
||||
() => { Game.CloseServer(); menuType = MenuType.Main; });
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
Game.OnRemoteDirectConnect -= OnRemoteDirectConnect;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
item.IsVisible = () => item.RenderBounds.IntersectsWith(scrollpanels[tab].RenderBounds);
|
||||
|
||||
var titleLabel = item.Get<LabelWidget>("TITLE");
|
||||
titleLabel.GetText = () => preview.Title;
|
||||
if (titleLabel != null)
|
||||
{
|
||||
var font = Game.Renderer.Fonts[titleLabel.Font];
|
||||
var title = WidgetUtils.TruncateText(preview.Title, titleLabel.Bounds.Width, font);
|
||||
titleLabel.GetText = () => title;
|
||||
}
|
||||
|
||||
var previewWidget = item.Get<MapPreviewWidget>("PREVIEW");
|
||||
previewWidget.Preview = () => preview;
|
||||
@@ -246,7 +251,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
var authorWidget = item.GetOrNull<LabelWidget>("AUTHOR");
|
||||
if (authorWidget != null)
|
||||
authorWidget.GetText = () => "Created by {0}".F(preview.Author);
|
||||
{
|
||||
var font = Game.Renderer.Fonts[authorWidget.Font];
|
||||
var author = WidgetUtils.TruncateText("Created by {0}".F(preview.Author), authorWidget.Bounds.Width, font);
|
||||
authorWidget.GetText = () => author;
|
||||
}
|
||||
|
||||
var sizeWidget = item.GetOrNull<LabelWidget>("SIZE");
|
||||
if (sizeWidget != null)
|
||||
|
||||
@@ -198,7 +198,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
var mapTitle = widget.GetOrNull<LabelWidget>("SELECTED_MAP");
|
||||
if (mapTitle != null)
|
||||
mapTitle.GetText = () => currentMap != null ? currentMap.Title : "No Server Selected";
|
||||
{
|
||||
var font = Game.Renderer.Fonts[mapTitle.Font];
|
||||
var title = new CachedTransform<MapPreview, string>(m => m == null ? "No Server Selected" :
|
||||
WidgetUtils.TruncateText(m.Title, mapTitle.Bounds.Width, font));
|
||||
mapTitle.GetText = () => title.Update(currentMap);
|
||||
}
|
||||
|
||||
var ip = widget.GetOrNull<LabelWidget>("SELECTED_IP");
|
||||
if (ip != null)
|
||||
@@ -219,8 +224,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
if (modVersion != null)
|
||||
{
|
||||
modVersion.IsVisible = () => currentServer != null;
|
||||
modVersion.GetText = () => currentServer.ModLabel;
|
||||
modVersion.GetColor = () => currentServer.IsCompatible ? modVersion.TextColor : incompatibleVersionColor;
|
||||
|
||||
var font = Game.Renderer.Fonts[modVersion.Font];
|
||||
var version = new CachedTransform<GameServer, string>(s => WidgetUtils.TruncateText(s.ModLabel, mapTitle.Bounds.Width, font));
|
||||
modVersion.GetText = () => version.Update(currentServer);
|
||||
}
|
||||
|
||||
var players = widget.GetOrNull<LabelWidget>("SELECTED_PLAYERS");
|
||||
@@ -358,7 +366,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var title = item.GetOrNull<LabelWidget>("TITLE");
|
||||
if (title != null)
|
||||
{
|
||||
title.GetText = () => game.Name;
|
||||
var font = Game.Renderer.Fonts[title.Font];
|
||||
var label = WidgetUtils.TruncateText(game.Name, title.Bounds.Width, font);
|
||||
title.GetText = () => label;
|
||||
title.GetColor = () => canJoin ? title.TextColor : incompatibleGameColor;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
preview.SpawnOccupants = () => selectedSpawns;
|
||||
preview.Preview = () => selectedReplay != null ? selectedReplay.GameInfo.MapPreview : null;
|
||||
|
||||
var title = panel.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||
if (title != null)
|
||||
title.GetText = () => selectedReplay != null ? selectedReplay.GameInfo.MapPreview.Title : null;
|
||||
var titleLabel = panel.GetOrNull<LabelWidget>("MAP_TITLE");
|
||||
if (titleLabel != null)
|
||||
{
|
||||
titleLabel.IsVisible = () => selectedReplay != null;
|
||||
|
||||
var font = Game.Renderer.Fonts[titleLabel.Font];
|
||||
var title = new CachedTransform<MapPreview, string>(m => WidgetUtils.TruncateText(m.Title, titleLabel.Bounds.Width, font));
|
||||
titleLabel.GetText = () => title.Update(selectedReplay.GameInfo.MapPreview);
|
||||
}
|
||||
|
||||
var type = panel.GetOrNull<LabelWidget>("MAP_TYPE");
|
||||
if (type != null)
|
||||
@@ -633,7 +639,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var item = ScrollItemWidget.Setup(playerTemplate, () => false, () => { });
|
||||
|
||||
var label = item.Get<LabelWidget>("LABEL");
|
||||
label.GetText = () => o.Name;
|
||||
var font = Game.Renderer.Fonts[label.Font];
|
||||
var name = WidgetUtils.TruncateText(o.Name, label.Bounds.Width, font);
|
||||
label.GetText = () => name;
|
||||
label.GetColor = () => color;
|
||||
|
||||
var flag = item.Get<ImageWidget>("FLAG");
|
||||
|
||||
@@ -52,7 +52,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
};
|
||||
|
||||
panel.Get<MapPreviewWidget>("MAP_PREVIEW").Preview = () => preview;
|
||||
panel.Get<LabelWidget>("MAP_NAME").GetText = () => preview.Title;
|
||||
|
||||
var mapTitle = panel.Get<LabelWidget>("MAP_NAME");
|
||||
if (mapTitle != null)
|
||||
{
|
||||
var font = Game.Renderer.Fonts[mapTitle.Font];
|
||||
var title = new CachedTransform<MapPreview, string>(m => WidgetUtils.TruncateText(m.Title, mapTitle.Bounds.Width, font));
|
||||
mapTitle.GetText = () => title.Update(preview);
|
||||
}
|
||||
}
|
||||
|
||||
var serverName = panel.Get<TextFieldWidget>("SERVER_NAME");
|
||||
|
||||
@@ -26,13 +26,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
tooltipContainer.BeforeRender = () =>
|
||||
{
|
||||
labelText = getText();
|
||||
var textDim = font.Measure(labelText);
|
||||
if (textDim.X != cachedWidth)
|
||||
var textWidth = font.Measure(labelText).X;
|
||||
if (textWidth != cachedWidth)
|
||||
{
|
||||
label.Bounds.Width = textDim.X;
|
||||
widget.Bounds.Width = 2 * label.Bounds.X + textDim.X;
|
||||
label.Bounds.Height = textDim.Y;
|
||||
widget.Bounds.Height = 4 * label.Bounds.Y + textDim.Y;
|
||||
label.Bounds.Width = textWidth;
|
||||
widget.Bounds.Width = 2 * label.Bounds.X + textWidth;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
return;
|
||||
|
||||
var powers = player.PlayerActor.Trait<SupportPowerManager>().Powers
|
||||
.Select((a, i) => new { a, i });
|
||||
.Where(x => !x.Value.Disabled).Select((a, i) => new { a, i });
|
||||
foreach (var power in powers)
|
||||
{
|
||||
if (!clocks.ContainsKey(power.a.Key))
|
||||
|
||||
@@ -442,5 +442,12 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var v = (int)((p.Y - mapRect.Y) / previewScale) + world.Map.Bounds.Top;
|
||||
return new MPos(u, v).ToCPos(world.Map);
|
||||
}
|
||||
|
||||
public override void Removed()
|
||||
{
|
||||
base.Removed();
|
||||
world.Map.MapTiles.Value.CellEntryChanged -= UpdateTerrainCell;
|
||||
world.Map.CustomTerrain.CellEntryChanged -= UpdateTerrainCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
.Where(a => !a.Disposed && a.Owner == world.LocalPlayer && a.Info.HasTraitInfo<GuardInfo>());
|
||||
|
||||
if (actors.Any())
|
||||
world.OrderGenerator = new GuardOrderGenerator(actors);
|
||||
world.OrderGenerator = new GuardOrderGenerator(actors,
|
||||
"Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
[Desc("Reduces health points over time when the actor is placed on unsafe terrain.")]
|
||||
class DamagedWithoutFoundationInfo : ITraitInfo, IRulesetLoaded, Requires<HealthInfo>
|
||||
{
|
||||
[WeaponReference]
|
||||
[WeaponReference, Desc("The weapon to use for causing damage.")]
|
||||
public readonly string Weapon = "weathering";
|
||||
|
||||
[Desc("Terrain types on which no damage is caused.")]
|
||||
public readonly HashSet<string> SafeTerrain = new HashSet<string> { "Concrete" };
|
||||
|
||||
[Desc("The percentage of health the actor should keep.")]
|
||||
public readonly int DamageThreshold = 50;
|
||||
|
||||
public WeaponInfo WeaponInfo { get; private set; }
|
||||
@@ -64,6 +68,8 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
var delta = health.HP - damageThreshold;
|
||||
if (delta > 0)
|
||||
health.InflictDamage(self, self.World.WorldActor, delta, null, false);
|
||||
|
||||
damageTicks = info.WeaponInfo.ReloadDelay;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
foreach (var c in FootprintUtils.Tiles(self))
|
||||
{
|
||||
// Only place on allowed terrain types
|
||||
if (!info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type))
|
||||
if (!map.Contains(c) || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type))
|
||||
continue;
|
||||
|
||||
// Don't place under other buildings or custom terrain
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
@@ -21,8 +22,11 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.D2k.Traits
|
||||
{
|
||||
[Desc("Seeds resources by explosive eruptions after accumulation times.")]
|
||||
public class SpiceBloomInfo : ITraitInfo, Requires<RenderSpritesInfo>
|
||||
public class SpiceBloomInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>
|
||||
{
|
||||
[ActorReference]
|
||||
public readonly string SpawnActor = "spicebloom.spawnpoint";
|
||||
|
||||
[SequenceReference]
|
||||
public readonly string[] GrowthSequences = { "grow1", "grow2", "grow3" };
|
||||
|
||||
@@ -30,21 +34,32 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
public readonly int[] RespawnDelay = { 1500, 2500 };
|
||||
|
||||
[Desc("The range of time (in ticks) that the spicebloom will take to grow.")]
|
||||
public readonly int[] GrowthDelay = { 1000, 1500 };
|
||||
public readonly int[] GrowthDelay = { 1000, 3000 };
|
||||
|
||||
public readonly string ResourceType = "Spice";
|
||||
|
||||
[Desc("Spice blooms only grow on these terrain types.")]
|
||||
public readonly HashSet<string> GrowthTerrainTypes = new HashSet<string>();
|
||||
|
||||
[Desc("The weapon to use for spice creation.")]
|
||||
[WeaponReference]
|
||||
public readonly string Weapon = "SpiceExplosion";
|
||||
public readonly string Weapon = null;
|
||||
|
||||
[Desc("The amount of spice to expel.")]
|
||||
public readonly int[] Pieces = { 3, 10 };
|
||||
public readonly int[] Pieces = { 2, 12 };
|
||||
|
||||
[Desc("The maximum distance in cells that spice may be expelled.")]
|
||||
public readonly int Range = 5;
|
||||
|
||||
public object Create(ActorInitializer init) { return new SpiceBloom(init, this); }
|
||||
|
||||
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
|
||||
{
|
||||
var anim = new Animation(init.World, image);
|
||||
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), GrowthSequences[0]));
|
||||
|
||||
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
|
||||
}
|
||||
}
|
||||
|
||||
public class SpiceBloom : ITick, INotifyKilled
|
||||
@@ -78,6 +93,12 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.World.Map.Contains(self.Location))
|
||||
return;
|
||||
|
||||
if (info.GrowthTerrainTypes.Count > 0 && !info.GrowthTerrainTypes.Contains(self.World.Map.GetTerrainInfo(self.Location).Type))
|
||||
return;
|
||||
|
||||
ticks++;
|
||||
|
||||
if (ticks >= growTicks)
|
||||
@@ -89,32 +110,35 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
void SeedResources(Actor self)
|
||||
{
|
||||
var args = new ProjectileArgs
|
||||
{
|
||||
Weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()],
|
||||
Facing = 0,
|
||||
|
||||
DamageModifiers = self.TraitsImplementing<IFirepowerModifier>()
|
||||
.Select(a => a.GetFirepowerModifier()).ToArray(),
|
||||
|
||||
InaccuracyModifiers = self.TraitsImplementing<IInaccuracyModifier>()
|
||||
.Select(a => a.GetInaccuracyModifier()).ToArray(),
|
||||
|
||||
Source = self.CenterPosition,
|
||||
SourceActor = self,
|
||||
};
|
||||
|
||||
var pieces = self.World.SharedRandom.Next(info.Pieces[0], info.Pieces[1]) * ticks / growTicks;
|
||||
for (var i = 0; pieces > i; i++)
|
||||
{
|
||||
var cells = OpenRA.Traits.Util.RandomWalk(self.Location, self.World.SharedRandom);
|
||||
var cell = cells.Take(info.Range).SkipWhile(p => resLayer.GetResource(p) == resType && resLayer.IsFull(p)).Cast<CPos?>().RandomOrDefault(self.World.SharedRandom);
|
||||
if (cell == null)
|
||||
cell = cells.Take(info.Range).Random(self.World.SharedRandom);
|
||||
if (pieces < info.Pieces[0])
|
||||
pieces = info.Pieces[0];
|
||||
|
||||
args.PassiveTarget = self.World.Map.CenterOfCell(cell.Value);
|
||||
var cells = self.World.Map.FindTilesInAnnulus(self.Location, 1, info.Range);
|
||||
|
||||
for (var i = 0; i < pieces; i++)
|
||||
{
|
||||
var cell = cells.SkipWhile(p => resLayer.GetResource(p) == resType && resLayer.IsFull(p)).Cast<CPos?>().RandomOrDefault(self.World.SharedRandom);
|
||||
if (cell == null)
|
||||
cell = cells.Random(self.World.SharedRandom);
|
||||
|
||||
var args = new ProjectileArgs
|
||||
{
|
||||
Weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()],
|
||||
Facing = 0,
|
||||
|
||||
DamageModifiers = self.TraitsImplementing<IFirepowerModifier>()
|
||||
.Select(a => a.GetFirepowerModifier()).ToArray(),
|
||||
|
||||
InaccuracyModifiers = self.TraitsImplementing<IInaccuracyModifier>()
|
||||
.Select(a => a.GetInaccuracyModifier()).ToArray(),
|
||||
|
||||
Source = self.CenterPosition,
|
||||
SourceActor = self,
|
||||
PassiveTarget = self.World.Map.CenterOfCell(cell.Value)
|
||||
};
|
||||
|
||||
self.World.AddFrameEndTask(_ =>
|
||||
{
|
||||
@@ -129,6 +153,12 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.Weapon))
|
||||
SeedResources(self);
|
||||
|
||||
self.World.AddFrameEndTask(t => t.Add(new DelayedAction(respawnTicks, () =>
|
||||
{
|
||||
@@ -141,7 +171,7 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
new FactionInit(self.Owner.Faction.InternalName),
|
||||
new SkipMakeAnimsInit()
|
||||
};
|
||||
self.World.CreateActor(self.Info.Name, td);
|
||||
self.World.CreateActor(info.SpawnActor, td);
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
if (teleporter != null && self != teleporter && !teleporter.Disposed)
|
||||
{
|
||||
var building = teleporter.TraitOrDefault<WithSpriteBody>();
|
||||
if (building != null)
|
||||
if (building != null && building.DefaultAnimation.HasSequence("active"))
|
||||
building.PlayCustomAnimation(teleporter, "active");
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
@@ -36,14 +37,23 @@ namespace OpenRA.Mods.RA.Effects
|
||||
readonly GpsDotInfo info;
|
||||
readonly Animation anim;
|
||||
|
||||
Lazy<HiddenUnderFog> huf;
|
||||
Lazy<FrozenUnderFog> fuf;
|
||||
Lazy<Disguise> disguise;
|
||||
Lazy<Cloak> cloak;
|
||||
Cache<Player, GpsWatcher> watcher;
|
||||
Cache<Player, FrozenActorLayer> frozen;
|
||||
readonly Dictionary<Player, DotState> stateByPlayer = new Dictionary<Player, DotState>();
|
||||
readonly Lazy<HiddenUnderFog> huf;
|
||||
readonly Lazy<FrozenUnderFog> fuf;
|
||||
readonly Lazy<Disguise> disguise;
|
||||
readonly Lazy<Cloak> cloak;
|
||||
readonly Cache<Player, FrozenActorLayer> frozen;
|
||||
|
||||
bool show = false;
|
||||
class DotState
|
||||
{
|
||||
public readonly GpsWatcher Gps;
|
||||
public bool IsTargetable;
|
||||
public bool ShouldRender;
|
||||
public DotState(GpsWatcher gps)
|
||||
{
|
||||
Gps = gps;
|
||||
}
|
||||
}
|
||||
|
||||
public GpsDot(Actor self, GpsDotInfo info)
|
||||
{
|
||||
@@ -59,32 +69,49 @@ namespace OpenRA.Mods.RA.Effects
|
||||
disguise = Exts.Lazy(() => self.TraitOrDefault<Disguise>());
|
||||
cloak = Exts.Lazy(() => self.TraitOrDefault<Cloak>());
|
||||
|
||||
watcher = new Cache<Player, GpsWatcher>(p => p.PlayerActor.Trait<GpsWatcher>());
|
||||
frozen = new Cache<Player, FrozenActorLayer>(p => p.PlayerActor.Trait<FrozenActorLayer>());
|
||||
|
||||
stateByPlayer = self.World.Players.ToDictionary(p => p, p => new DotState(p.PlayerActor.Trait<GpsWatcher>()));
|
||||
}
|
||||
|
||||
bool ShouldShowIndicator()
|
||||
public bool IsDotVisible(Player toPlayer)
|
||||
{
|
||||
return stateByPlayer[toPlayer].IsTargetable;
|
||||
}
|
||||
|
||||
bool IsTargetableBy(Player toPlayer, out bool shouldRenderIndicator)
|
||||
{
|
||||
shouldRenderIndicator = false;
|
||||
|
||||
if (cloak.Value != null && cloak.Value.Cloaked)
|
||||
return false;
|
||||
|
||||
if (disguise.Value != null && disguise.Value.Disguised)
|
||||
return false;
|
||||
|
||||
if (huf.Value != null && !huf.Value.IsVisible(self, self.World.RenderPlayer))
|
||||
if (huf.Value != null && !huf.Value.IsVisible(self, toPlayer)
|
||||
&& toPlayer.Shroud.IsExplored(self.CenterPosition))
|
||||
{
|
||||
var f1 = FrozenActorForPlayer(toPlayer);
|
||||
shouldRenderIndicator = f1 == null || !f1.HasRenderables;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fuf.Value == null)
|
||||
return false;
|
||||
|
||||
var f = frozen[self.World.RenderPlayer].FromID(self.ActorID);
|
||||
if (f == null)
|
||||
var f2 = FrozenActorForPlayer(toPlayer);
|
||||
if (f2 == null)
|
||||
return false;
|
||||
|
||||
if (f.HasRenderables || f.NeedRenderables)
|
||||
return false;
|
||||
shouldRenderIndicator = !f2.HasRenderables;
|
||||
|
||||
return f.Visible;
|
||||
return f2.Visible && !f2.Shrouded;
|
||||
}
|
||||
|
||||
FrozenActor FrozenActorForPlayer(Player player)
|
||||
{
|
||||
return frozen[player].FromID(self.ActorID);
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
@@ -92,17 +119,22 @@ namespace OpenRA.Mods.RA.Effects
|
||||
if (self.Disposed)
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
show = false;
|
||||
if (!self.IsInWorld || self.IsDead || self.World.RenderPlayer == null)
|
||||
if (!self.IsInWorld || self.IsDead)
|
||||
return;
|
||||
|
||||
var gps = watcher[self.World.RenderPlayer];
|
||||
show = (gps.Granted || gps.GrantedAllies) && ShouldShowIndicator();
|
||||
foreach (var player in self.World.Players)
|
||||
{
|
||||
var state = stateByPlayer[player];
|
||||
var shouldRender = false;
|
||||
var targetable = (state.Gps.Granted || state.Gps.GrantedAllies) && IsTargetableBy(player, out shouldRender);
|
||||
state.IsTargetable = targetable;
|
||||
state.ShouldRender = targetable && shouldRender;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (!show || self.Disposed)
|
||||
if (self.World.RenderPlayer == null || !stateByPlayer[self.World.RenderPlayer].ShouldRender || self.Disposed)
|
||||
return SpriteRenderable.None;
|
||||
|
||||
var palette = wr.Palette(info.IndicatorPalettePrefix + self.Owner.InternalName);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
class InfiltrateForPowerOutageInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Duration = 25 * 30;
|
||||
public readonly int Duration = 25 * 20;
|
||||
|
||||
public object Create(ActorInitializer init) { return new InfiltrateForPowerOutage(init.Self, this); }
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace OpenRA.Mods.RA.Traits
|
||||
public int OrderPriority { get { return 5; } }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
if (target.Type != TargetType.Terrain)
|
||||
return false;
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace OpenRA.Mods.RA.Traits
|
||||
public bool IsQueued { get; protected set; }
|
||||
public bool OverrideSelection { get { return true; } }
|
||||
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
// TODO: When target modifiers are configurable this needs to be revisited
|
||||
if (modifiers.HasModifier(TargetModifiers.ForceMove) || modifiers.HasModifier(TargetModifiers.ForceQueue))
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace OpenRA.Mods.RA.Traits
|
||||
return;
|
||||
|
||||
var warhead = e.Warhead as DamageWarhead;
|
||||
if (info.DeathType != null && warhead != null && !warhead.DamageTypes.Contains(info.DeathType))
|
||||
if (info.DeathType != null && (warhead == null || !warhead.DamageTypes.Contains(info.DeathType)))
|
||||
return;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.RA.Traits
|
||||
foreach (var i in atek.World.ActorsWithTrait<GpsWatcher>())
|
||||
i.Trait.RefreshGranted();
|
||||
|
||||
if ((Granted || GrantedAllies) && atek.Owner.IsAlliedWith(atek.World.RenderPlayer))
|
||||
if ((Granted || GrantedAllies) && atek.Owner.IsAlliedWith(Owner))
|
||||
atek.Owner.Shroud.ExploreAll(atek.World);
|
||||
}
|
||||
|
||||
@@ -76,10 +76,19 @@ namespace OpenRA.Mods.RA.Traits
|
||||
Owner.Shroud.ExploreAll(Owner.World);
|
||||
}
|
||||
|
||||
public bool HasFogVisibility(Player byPlayer)
|
||||
public bool HasFogVisibility()
|
||||
{
|
||||
return Granted || GrantedAllies;
|
||||
}
|
||||
|
||||
public bool IsVisible(Actor actor)
|
||||
{
|
||||
var gpsDot = actor.TraitOrDefault<GpsDot>();
|
||||
if (gpsDot == null)
|
||||
return false;
|
||||
|
||||
return gpsDot.IsDotVisible(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
class GpsPowerInfo : SupportPowerInfo
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace OpenRA.Platforms.Default
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidDataException("Failed to create hardware cursor `{0}`".F(name), ex);
|
||||
throw new InvalidDataException("Failed to create hardware cursor `{0}` - {1}".F(name, ex.Message), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
mods/cnc/bits/camera.shp
Normal file
BIN
mods/cnc/bits/camera.shp
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@ Container@NEW_MAP_BG:
|
||||
Height: 125
|
||||
Children:
|
||||
Label@TITLE:
|
||||
Text:New Map
|
||||
Text: New Map
|
||||
Width: PARENT_RIGHT
|
||||
Y: 0-25
|
||||
Font: BigBold
|
||||
@@ -73,7 +73,6 @@ Container@NEW_MAP_BG:
|
||||
Font: Bold
|
||||
Key: return
|
||||
|
||||
|
||||
Background@SAVE_MAP_PANEL:
|
||||
Logic: SaveMapLogic
|
||||
X: (WINDOW_RIGHT - WIDTH)/2
|
||||
@@ -361,7 +360,7 @@ Container@EDITOR_WORLD_ROOT:
|
||||
Text: Actors
|
||||
Font: Bold
|
||||
Button@GRID_BUTTON:
|
||||
X: WINDOW_RIGHT - 420
|
||||
X: WINDOW_RIGHT - 500
|
||||
Y: 5
|
||||
Width: 100
|
||||
Height: 25
|
||||
@@ -372,7 +371,7 @@ Container@EDITOR_WORLD_ROOT:
|
||||
TooltipText: Toggle the terrain grid
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
Label@ZOOM_LABEL:
|
||||
X: WINDOW_RIGHT - 500 - 55
|
||||
X: WINDOW_RIGHT - 580 - 55
|
||||
Y: 5
|
||||
Width: 50
|
||||
Height: 25
|
||||
@@ -381,11 +380,17 @@ Container@EDITOR_WORLD_ROOT:
|
||||
Font: Bold
|
||||
Contrast: true
|
||||
DropDownButton@ZOOM_BUTTON:
|
||||
X: WINDOW_RIGHT - 500
|
||||
X: WINDOW_RIGHT - 580
|
||||
Y: 5
|
||||
Width: 70
|
||||
Height: 25
|
||||
Font: Bold
|
||||
Button@COPYPASTE_BUTTON:
|
||||
X: WINDOW_RIGHT-390
|
||||
Y: 5
|
||||
Width: 96
|
||||
Height: 25
|
||||
Text: Copy/Paste
|
||||
Label@COORDINATE_LABEL:
|
||||
X: 10
|
||||
Width: 50
|
||||
@@ -400,3 +405,4 @@ Container@EDITOR_WORLD_ROOT:
|
||||
Align: Left
|
||||
Font: Bold
|
||||
Contrast: true
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Container@SCRIPT_ERROR_PANEL:
|
||||
Width: PARENT_RIGHT-30
|
||||
Height: 20
|
||||
Font: Bold
|
||||
Align:Center
|
||||
Align: Center
|
||||
Text: The map script has encountered a fatal error
|
||||
Label@DESCB:
|
||||
X: 15
|
||||
@@ -24,4 +24,5 @@ Container@SCRIPT_ERROR_PANEL:
|
||||
Width: PARENT_RIGHT-30
|
||||
Height: 20
|
||||
Font: Regular
|
||||
Text: Please send this file to the map author so that they can fix this issue.
|
||||
Text: Please send this file to the map author so that they can fix this issue.
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Logic: ObserverShroudSelectorLogic
|
||||
X: WINDOW_RIGHT-WIDTH-5
|
||||
Y: 260
|
||||
Width:256
|
||||
Width: 256
|
||||
Height: 25
|
||||
Font: Bold
|
||||
Children:
|
||||
@@ -467,6 +467,7 @@ Container@PLAYER_WIDGETS:
|
||||
Y: 268
|
||||
Width: 194
|
||||
Height: 20
|
||||
|
||||
Background@FMVPLAYER:
|
||||
Width: WINDOW_RIGHT
|
||||
Height: WINDOW_BOTTOM
|
||||
|
||||
@@ -23,12 +23,12 @@ Container@LOBBY_GLOBALCHAT_PANEL:
|
||||
Y: 19
|
||||
Width: 582
|
||||
Height: PARENT_BOTTOM - 19
|
||||
ItemSpacing: 5
|
||||
TopBottomSpacing: 4
|
||||
ItemSpacing: 4
|
||||
Children:
|
||||
Label@HISTORY_TEMPLATE:
|
||||
X: 5
|
||||
Width: 530
|
||||
Height: 25
|
||||
WordWrap: True
|
||||
TextField@CHAT_TEXTFIELD:
|
||||
X: 200
|
||||
|
||||
@@ -45,6 +45,7 @@ Background@KICK_CLIENT_DIALOG:
|
||||
Height: 25
|
||||
Text: Cancel
|
||||
Font: Bold
|
||||
|
||||
Background@KICK_SPECTATORS_DIALOG:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -78,6 +79,7 @@ Background@KICK_SPECTATORS_DIALOG:
|
||||
Height: 25
|
||||
Text: Cancel
|
||||
Font: Bold
|
||||
|
||||
Background@FORCE_START_DIALOG:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -137,3 +139,4 @@ Background@FORCE_START_DIALOG:
|
||||
Height: 25
|
||||
Text: Cancel
|
||||
Font: Bold
|
||||
|
||||
|
||||
@@ -89,25 +89,25 @@ Container@MAPCHOOSER_PANEL:
|
||||
IgnoreMouseOver: true
|
||||
IgnoreMouseInput: true
|
||||
Label@TITLE:
|
||||
X: 2
|
||||
X: 4
|
||||
Y: PARENT_BOTTOM-48
|
||||
Width: PARENT_RIGHT-4
|
||||
Width: PARENT_RIGHT-8
|
||||
Align: Center
|
||||
Label@DETAILS:
|
||||
Width: PARENT_RIGHT-4
|
||||
X: 2
|
||||
Width: PARENT_RIGHT-8
|
||||
X: 4
|
||||
Y: PARENT_BOTTOM-34
|
||||
Align: Center
|
||||
Font: Tiny
|
||||
Label@AUTHOR:
|
||||
Width: PARENT_RIGHT-4
|
||||
X: 2
|
||||
Width: PARENT_RIGHT-8
|
||||
X: 4
|
||||
Y: PARENT_BOTTOM-22
|
||||
Align: Center
|
||||
Font: Tiny
|
||||
Label@SIZE:
|
||||
Width: PARENT_RIGHT-4
|
||||
X: 2
|
||||
Width: PARENT_RIGHT-8
|
||||
X: 4
|
||||
Y: PARENT_BOTTOM-10
|
||||
Align: Center
|
||||
Font: Tiny
|
||||
|
||||
@@ -148,6 +148,7 @@ Container@MISSIONBROWSER_PANEL:
|
||||
Y: 1
|
||||
Width: 640
|
||||
Height: 375
|
||||
|
||||
Background@FULLSCREEN_PLAYER:
|
||||
Width: WINDOW_RIGHT
|
||||
Height: WINDOW_BOTTOM
|
||||
@@ -159,3 +160,4 @@ Background@FULLSCREEN_PLAYER:
|
||||
Y: 0
|
||||
Width: WINDOW_RIGHT
|
||||
Height: WINDOW_BOTTOM
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ Container@GLOBALCHAT_PANEL:
|
||||
Y: 19
|
||||
Width: 582
|
||||
Height: PARENT_BOTTOM - 49
|
||||
ItemSpacing: 5
|
||||
TopBottomSpacing: 4
|
||||
ItemSpacing: 4
|
||||
Children:
|
||||
Label@HISTORY_TEMPLATE:
|
||||
X: 5
|
||||
Width: 530
|
||||
Height: 25
|
||||
WordWrap: True
|
||||
TextField@CHAT_TEXTFIELD:
|
||||
Y: PARENT_BOTTOM - 25
|
||||
|
||||
@@ -73,7 +73,7 @@ ScrollPanel@MULTIPLAYER_FILTER_PANEL:
|
||||
Checkbox@WAITING_FOR_PLAYERS:
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 137
|
||||
Width: PARENT_RIGHT-29
|
||||
Height: 20
|
||||
Text: Waiting
|
||||
TextColor: 50,205,50
|
||||
@@ -81,14 +81,14 @@ ScrollPanel@MULTIPLAYER_FILTER_PANEL:
|
||||
Checkbox@EMPTY:
|
||||
X: 5
|
||||
Y: 30
|
||||
Width: 137
|
||||
Width: PARENT_RIGHT-29
|
||||
Height: 20
|
||||
Text: Empty
|
||||
Font: Regular
|
||||
Checkbox@PASSWORD_PROTECTED:
|
||||
X: 5
|
||||
Y: 55
|
||||
Width: 137
|
||||
Width: PARENT_RIGHT-29
|
||||
Height: 20
|
||||
Text: Protected
|
||||
TextColor: 255,0,0
|
||||
@@ -96,7 +96,7 @@ ScrollPanel@MULTIPLAYER_FILTER_PANEL:
|
||||
Checkbox@ALREADY_STARTED:
|
||||
X: 5
|
||||
Y: 80
|
||||
Width: 137
|
||||
Width: PARENT_RIGHT-29
|
||||
Height: 20
|
||||
Text: Started
|
||||
TextColor: 255,165,0
|
||||
@@ -104,8 +104,8 @@ ScrollPanel@MULTIPLAYER_FILTER_PANEL:
|
||||
Checkbox@INCOMPATIBLE_VERSION:
|
||||
X: 5
|
||||
Y: 105
|
||||
Width: 137
|
||||
Width: PARENT_RIGHT-29
|
||||
Height: 20
|
||||
Text: Incompatible
|
||||
TextColor: 190,190,190
|
||||
Font: Regular
|
||||
Font: Regular
|
||||
|
||||
@@ -273,7 +273,7 @@ Container@REPLAYBROWSER_PANEL:
|
||||
Height: 16
|
||||
Label@LABEL:
|
||||
X: 40
|
||||
Width: 60
|
||||
Width: PARENT_RIGHT-50
|
||||
Height: 25
|
||||
Label@NOFLAG_LABEL:
|
||||
X: 5
|
||||
|
||||
@@ -293,7 +293,7 @@ Actors:
|
||||
Location: 38,27
|
||||
Owner: Neutral
|
||||
Actor77: split3
|
||||
Location: 31,27
|
||||
Location: 31,28
|
||||
Owner: Neutral
|
||||
Actor78: tc01
|
||||
Location: 29,27
|
||||
@@ -332,13 +332,13 @@ Actors:
|
||||
Location: 21,9
|
||||
Owner: Neutral
|
||||
Actor90: split2
|
||||
Location: 19,59
|
||||
Location: 19,60
|
||||
Owner: Neutral
|
||||
Actor91: split3
|
||||
Location: 22,58
|
||||
Location: 22,59
|
||||
Owner: Neutral
|
||||
Actor92: split3
|
||||
Location: 42,56
|
||||
Location: 42,57
|
||||
Owner: Neutral
|
||||
Actor93: tc05
|
||||
Location: 44,59
|
||||
@@ -428,16 +428,16 @@ Actors:
|
||||
Location: 4,14
|
||||
Owner: Neutral
|
||||
Actor122: split3
|
||||
Location: 7,28
|
||||
Location: 7,29
|
||||
Owner: Neutral
|
||||
Actor123: split3
|
||||
Location: 7,32
|
||||
Location: 7,33
|
||||
Owner: Neutral
|
||||
Actor124: split3
|
||||
Location: 3,33
|
||||
Location: 3,34
|
||||
Owner: Neutral
|
||||
Actor125: split3
|
||||
Location: 22,41
|
||||
Location: 22,42
|
||||
Owner: Neutral
|
||||
AttackTrigger1: proc
|
||||
Location: 46,42
|
||||
@@ -804,6 +804,8 @@ Rules:
|
||||
-WithRoof:
|
||||
-Selectable:
|
||||
RejectsOrders:
|
||||
Cargo:
|
||||
Types: disabled
|
||||
airstrike.proxy:
|
||||
AlwaysVisible:
|
||||
AirstrikePower:
|
||||
|
||||
@@ -488,6 +488,8 @@ Rules:
|
||||
-WithRoof:
|
||||
-Selectable:
|
||||
RejectsOrders:
|
||||
Cargo:
|
||||
Types: disabled
|
||||
TREX:
|
||||
Health:
|
||||
HP: 750
|
||||
|
||||
@@ -535,6 +535,8 @@ Rules:
|
||||
-WithRoof:
|
||||
-Selectable:
|
||||
RejectsOrders:
|
||||
Cargo:
|
||||
Types: disabled
|
||||
|
||||
Sequences:
|
||||
oldlst:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user