Compare commits

...

71 Commits

Author SHA1 Message Date
Oliver Brakmann
bd6bcda6d0 Merge pull request #9993 from pchote/nsprocess-fix
Switch to a (hopefully) working NSProcess url.
2015-11-14 22:52:56 +01:00
Paul Chote
f12deca9ca Switch to a (hopefully) working NSProcess url. 2015-11-14 21:47:21 +00:00
Oliver Brakmann
5ea82b4e5e Increase range of flak truck against air targets
From 6 cells to 8 cells
2015-11-14 22:10:40 +01:00
DArcy Rush
2d210a97df Rebalance Tesla Tank.
Allow attacking of target regardless of facing.
2015-11-14 22:10:40 +01:00
DArcy Rush
f03a100115 Rebalance phase transport.
Passengers increased to 4, speed and LoS increased.
2015-11-14 22:10:40 +01:00
DArcy Rush
1e30684782 Reduce chronotank charge time.
Chronotank charge decreased from 20s to 12s.
2015-11-14 22:10:40 +01:00
Curtis Shmyr
abb45197b1 lower InfiltrateForPowerOutage time from 30->20sec 2015-11-14 19:34:37 +00:00
Paul Chote
a7935f6166 Check deploy location at the time of transform. 2015-11-14 16:46:18 +01:00
Oliver Brakmann
7b75a9c2f7 Fix reinforcements appearing in soviet04a/b despite killed radar dome 2015-11-14 15:01:51 +02:00
reaperrr
9b694f6044 Fix spice bloom editor visibility 2015-11-14 12:09:07 +00:00
Biofreak1987
0a75019aa0 Fix ai building in soviet04/06 missions despite killed construction yard 2015-11-13 20:53:26 +01:00
Biofreak1987
d3e41b6d50 Fix nod05 airstrike Lua crash and update map rules
- Fix airstrike Lua crash when there are no targets
- Increased harvester search range
- Hide owner row from husks and walls

Changes to make it closer to the original:
- Added e3 and sandbag production
- Made airstrikes gdi only
- Limited airstrike squadsize to 1
- Allow to attack civilian buildings
2015-11-12 22:52:38 +01:00
Oliver Brakmann
18f3e1f57b Merge pull request #9971 from pchote/tooltip-fix
Fix map editor crash
2015-11-12 19:32:02 +01:00
Paul Chote
1760f8acd6 Fix tooltip colour definition. 2015-11-11 23:15:33 +00:00
Pavel Penev
4154553318 Validate player color when changing slots in the lobby 2015-11-11 22:59:48 +00:00
Oliver Brakmann
e5e8e64ace Fix bogus owner check in Lua API production code 2015-11-11 22:24:05 +00:00
OmegaBolt
0ae58c10ad D2k thumper worm attraction balance 2015-11-11 23:01:53 +02:00
Paul Chote
89ea810cbe Truncate player name in replay browser. 2015-11-11 22:40:00 +02:00
Paul Chote
f6cf35c99c Truncate player name in observer stats and diplomacy panels. 2015-11-11 22:39:52 +02:00
Paul Chote
5fbaeabb6d Truncate player name in ingame menu stats. 2015-11-11 22:39:37 +02:00
Paul Chote
581907f53a Prevent frozen actors leaking through shroud. 2015-11-11 22:33:16 +02:00
Paul Chote
7cf4be9d78 Add copy/paste to the map editor. 2015-11-11 01:02:16 +02:00
Paul Chote
bdf9f5e201 Make editor brushes disposable. 2015-11-11 01:02:09 +02:00
Pavel Penev
b26b1f410f Enable AutoTarget to aquire targets under fog if GPS is present 2015-11-10 22:27:40 +01:00
OmegaBolt
ce69abe1f2 D2k fixed armour & AI typos 2015-11-10 22:04:09 +01:00
atlimit8
b3d2b36875 Make ActorSelector tooltips better match actor tooltips in map editor 2015-11-10 21:08:53 +01:00
atlimit8
f28b37323f Made editor actor preview tooltip easier to read 2015-11-10 21:08:53 +01:00
atlimit8
7c82ab60e8 Multiline support for SimpleTooltipLogic 2015-11-10 21:08:53 +01:00
Zimmermann Gyula
d14fbd0f84 Fix observer GUI showing disabled support powers. 2015-11-09 21:07:19 +01:00
OmegaBolt
c567f5cbdd D2k super weapon timers 2015-11-09 21:51:02 +02:00
OmegaBolt
51a9831fc2 D2k Ornithopter bomb damage increase 2015-11-09 19:58:36 +01:00
OmegaBolt
4d5777cbc9 D2k, fixed infantry moving slow on dunes and rough 2015-11-08 21:59:07 +02:00
Paul Chote
a6a835d95f Truncate long player names in lobby. 2015-11-08 17:24:24 +02:00
Paul Chote
e16be14ec7 Truncate long server names in MP browser. 2015-11-08 17:24:19 +02:00
Paul Chote
11939d3af1 Truncate long map name in replay browser. 2015-11-08 17:24:13 +02:00
Paul Chote
feb133c2eb Truncate long map name / mod version in MP panel. 2015-11-08 17:24:02 +02:00
Paul Chote
f6361b031b Truncate long map name / author in map chooser. 2015-11-08 17:23:56 +02:00
Paul Chote
36967951e6 Truncate long map name / author in lobby. 2015-11-08 17:23:39 +02:00
Paul Chote
012a9d71ba Add helpers for truncating long labels. 2015-11-08 17:23:31 +02:00
Paul Chote
cff369850c Set the default map location to the support dir. 2015-11-08 14:49:38 +02:00
DArcy Rush
136b4c0fa9 Add self to AUTHORS. 2015-11-08 11:40:37 +00:00
DArcy Rush
aae2459d0b Move blossom trees south one cell in cnc64gdi01. 2015-11-08 11:40:27 +00:00
teees
d47ba1d135 only change editor brushes on mouseup
let other uses of the right mouse button bubble up
2015-11-08 11:30:25 +00:00
teees
133cffff24 Handle mouse up event in default editor brush 2015-11-08 11:30:08 +00:00
Oliver Brakmann
52f6c993d5 Fix lint warning in gdi06 2015-11-08 11:17:22 +00:00
Biofreak1987
21eecb048d Fix soviet06 prerequisites 2015-11-08 09:48:47 +01:00
Oliver Brakmann
b97398a671 Fix typo in WeatherOverlayInfo 2015-11-08 09:14:22 +01:00
Curtis Shmyr
a285c908db Added 3 Lua player API properties 2015-11-08 08:53:15 +01:00
reaperrr
35b39162ff Fix spice debris target cell randomization 2015-11-07 18:32:21 +01:00
reaperrr
0b5b6adc7c Improve SpiceExplosion and add BloomExplosion
Fixes angle and loudness of spice debris, adds BloomExplosion to add proper animation and damage crushing actors.
2015-11-07 18:32:14 +01:00
reaperrr
5357eb6f29 Increase variation and average of spice bloom growth 2015-11-07 18:32:04 +01:00
reaperrr
e274ac5ff8 Make sure that a spice bloom spawns at least the minimum of pieces 2015-11-07 18:31:59 +01:00
reaperrr
f8e39bd142 Reduce spawned spice per piece 2015-11-07 18:31:56 +01:00
Pavel Penev
48881f4e73 Fix repair pad reference in units' Repairable trait 2015-11-07 18:31:52 +01:00
Pavel Penev
d2eb56183d Buff D2k repair pads 2015-11-07 18:10:40 +01:00
reaperrr
afd75c7f55 Fix WithSpriteRotorOverlay upgrade rule to account for @ separator 2015-11-07 16:18:29 +02:00
reaperrr
6d1551c9fd Change engineVersion for upgrade rules of changes made between 20150808 and 20150919
Those changes were merged after the feature-freeze, but predate the stable release. Changing the engine version to the day after release makes it easier for modders to upgrade without using bogus engine dates.
2015-11-07 16:18:18 +02:00
Paul Chote
a015b0990b Fetch battlefield news once per game launch. 2015-11-07 14:13:31 +02:00
Paul Chote
6dd08bbc98 Fix global chat line margins. 2015-11-07 12:43:14 +01:00
Paul Chote
343616e924 Add unread message count to lobby chat tabs. 2015-11-07 12:43:03 +01:00
Paul Chote
91242a832f Add Tick method to ChromeLogic. 2015-11-07 12:43:03 +01:00
OmegaBolt
1c53bfed11 D2k crate balance
- Fixed prerequisites.
- Added more infantry crates.
- Upped the create explosion damage, though it is still very little. Takes about a third health off a Trike.
2015-11-06 19:47:34 +01:00
RoosterDragon
e5e7d037a3 Remove event handler when disposed in MainMenuLogic.
Removes a static event handler to Game.OnRemoteDirectConnect which allow the GC to reclaim the MainMenuLogic class after it has been disposed.
2015-11-05 22:49:25 +01:00
RoosterDragon
2a301392c6 Remove event handlers to CellEntryChanged when done.
Several classes would attach event handlers to the Map which would live longer then they did. Detaching them when no longer needed allows the GC to reclaim them.
2015-11-05 22:49:25 +01:00
RoosterDragon
e35bb8ea95 Detach event handlers on dispose in TerrainSpriteLayer.
The WorldRenderer outlives the TerrainSpriteLayer and thus keeps it alive longer than expected via the event handler. We detach it to allow the GC to reclaim it.
2015-11-05 22:49:25 +01:00
Pavel Penev
7a4002ff08 Fix the C17 delivery plane doing a steep dive when trying to land 2015-11-05 19:49:04 +00:00
RoosterDragon
523fe20255 Work around a hang on shutdown caused by IRC.
Our IRC client doesn't shut down properly - but we only need to shut it down when we're about to close the game anyway, so we just don't bother since it won't hurt anybody.
2015-11-05 20:42:15 +01:00
Zimmermann Gyula
31e0c8b2e3 Fix (HealthPercentage)DamageWarheads ignoring stances/TargetTypes.
Moves the IsValidAgainst check from SpreadDamage level to Damage level
and adds a duplication to HealthPercentageDamageWarhead.
2015-11-04 22:34:48 +00:00
Pavel Penev
7c37d1cfcc Fix server filter width 2015-11-04 22:31:27 +01:00
Oliver Brakmann
8e76a109bd Fix viceroids being spawned by crushed infantry 2015-11-03 10:33:40 +00:00
Michael Rätzel
ba9b18ccb7 reset RallyPoint Location after capture. resolves #9163. 2015-10-31 21:59:03 +01:00
99 changed files with 1215 additions and 353 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -179,7 +179,6 @@ namespace OpenRA
public bool FetchNews = true;
public string NewsUrl = "http://www.openra.net/gamenews";
public DateTime NewsFetchedDate;
}
public class KeySettings

View File

@@ -41,6 +41,7 @@ namespace OpenRA.Traits
public DamageState DamageState;
public bool Visible = true;
public bool Shrouded { get; private set; }
public bool NeedRenderables { get; private set; }
public bool IsRendering { get; private set; }
@@ -84,6 +85,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,8 +95,12 @@ namespace OpenRA.Traits
if (shroud.IsVisible(puv))
{
Visible = false;
Shrouded = false;
break;
}
if (Shrouded && shroud.IsExplored(puv))
Shrouded = false;
}
if (Visible && !wasVisible)
@@ -119,6 +125,9 @@ namespace OpenRA.Traits
}
}
if (Shrouded)
return NoRenderables;
if (flashTicks > 0 && flashTicks % 2 == 0)
{
var highlight = wr.Palette("highlight");
@@ -129,7 +138,7 @@ namespace OpenRA.Traits
return renderables;
}
public bool HasRenderables { get { return renderables.Any(); } }
public bool HasRenderables { get { return !Shrouded && renderables.Any(); } }
public bool ShouldBeRemoved(Player owner)
{
@@ -175,6 +184,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;

View File

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

View File

@@ -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.Equals(lastInput)))
return lastOutput;
lastInput = input;
lastOutput = transform(input);
initialized = true;
return lastOutput;
}
}
[Flags]
public enum PanelSides
{

View File

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

View File

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

View 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();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -70,7 +70,8 @@ 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 ? " < " + Info.Name + " >" : tooltip.Name) + "\n" + owner.Name + " (" + owner.Faction + ")"
+ "\nID: " + ID + "\nType: " + Info.Name;
GeneratePreviews();
@@ -160,5 +161,10 @@ namespace OpenRA.Mods.Common.Traits
.SelectMany(rpi => rpi.RenderPreview(init))
.ToArray();
}
public ActorReference Export()
{
return new ActorReference(actor.Type, actor.Save().ToDictionary());
}
}
}

View File

@@ -207,6 +207,8 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in spriteLayers.Values)
kv.Dispose();
Map.MapResources.Value.CellEntryChanged -= UpdateCell;
disposed = true;
}
}

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

View File

@@ -294,6 +294,8 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in spriteLayers.Values)
kv.Dispose();
RenderContent.CellEntryChanged -= UpdateSpriteLayers;
disposed = true;
}

View File

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

View File

@@ -1727,7 +1727,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")
{
@@ -1776,13 +1776,13 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
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 +1806,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150816)
if (engineVersion < 20150920)
{
// Rename RenderSprites.RaceImages
if (depth == 2 && node.Key == "RaceImages")
@@ -1820,7 +1820,7 @@ 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
@@ -1848,7 +1848,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150826)
if (engineVersion < 20150920)
{
// Replaced RenderBuildingCharge with RenderSprites + WithSpriteBody + WithChargeAnimation (+AutoSelectionSize)
if (depth == 0)
@@ -1969,7 +1969,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150828)
if (engineVersion < 20150920)
{
// Replaced RenderBuilding with RenderSprites + WithSpriteBody (+AutoSelectionSize)
if (depth == 0)
@@ -2003,7 +2003,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150902)
if (engineVersion < 20150920)
{
if (depth == 1)
{
@@ -2092,14 +2092,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,11 +2125,11 @@ 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"
|| parentKey == "JamsMissiles"
@@ -2201,11 +2201,22 @@ namespace OpenRA.Mods.Common.UtilityCommands
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)
@@ -2277,6 +2288,12 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20151107 && depth == 2)
{
if (node.Key == "PaticleSize")
node.Key = "ParticleSize";
}
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -137,7 +137,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
item.IsVisible = () => true;
var tooltip = actor.TraitInfoOrDefault<TooltipInfo>();
item.GetTooltipText = () => tooltip == null ? actor.Name : tooltip.Name + " (" + actor.Name + ")";
item.GetTooltipText = () => (tooltip == null ? "\nType: " : tooltip.Name + "\nType: ") + actor.Name;
panel.AddChild(item);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,17 +22,26 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var font = Game.Renderer.Fonts[label.Font];
var cachedWidth = 0;
var cachedHeight = 0;
var horizontalPadding = label.Bounds.Width - widget.Bounds.Width;
if (horizontalPadding <= 0)
horizontalPadding = 2 * label.Bounds.X;
var vertcalPadding = widget.Bounds.Height - label.Bounds.Height;
if (vertcalPadding <= 0)
vertcalPadding = 2 * label.Bounds.Y;
var labelText = "";
tooltipContainer.BeforeRender = () =>
{
labelText = getText();
var textDim = font.Measure(labelText);
if (textDim.X != cachedWidth)
if (textDim.X != cachedWidth || textDim.Y != cachedHeight)
{
label.Bounds.Width = textDim.X;
widget.Bounds.Width = 2 * label.Bounds.X + textDim.X;
widget.Bounds.Width = horizontalPadding + textDim.X;
label.Bounds.Height = textDim.Y;
widget.Bounds.Height = 4 * label.Bounds.Y + textDim.Y;
widget.Bounds.Height = vertcalPadding + textDim.Y;
cachedWidth = textDim.X;
cachedHeight = textDim.Y;
}
};

View File

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

View File

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

View File

@@ -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,7 +22,7 @@ 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>
{
[SequenceReference]
public readonly string[] GrowthSequences = { "grow1", "grow2", "grow3" };
@@ -30,7 +31,7 @@ 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";
@@ -39,12 +40,20 @@ namespace OpenRA.Mods.D2k.Traits
public readonly string Weapon = "SpiceExplosion";
[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
@@ -91,22 +100,10 @@ namespace OpenRA.Mods.D2k.Traits
public void Killed(Actor self, AttackInfo e)
{
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;
if (pieces < info.Pieces[0])
pieces = info.Pieces[0];
for (var i = 0; pieces > i; i++)
{
var cells = OpenRA.Traits.Util.RandomWalk(self.Location, self.World.SharedRandom);
@@ -114,7 +111,21 @@ namespace OpenRA.Mods.D2k.Traits
if (cell == null)
cell = cells.Take(info.Range).Random(self.World.SharedRandom);
args.PassiveTarget = self.World.Map.CenterOfCell(cell.Value);
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(_ =>
{

View File

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

View File

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

View File

@@ -329,6 +329,7 @@ Container@EDITOR_WORLD_ROOT:
Visible: false
Width: PARENT_RIGHT - 35
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: TWO_LINE_TOOLTIP
IgnoreChildMouseOver: true
Children:
ActorPreview@ACTOR_PREVIEW:
@@ -361,7 +362,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 +373,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 +382,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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,28 @@
Background@SIMPLE_TOOLTIP:
Logic: SimpleTooltipLogic
Background: panel-black
Height: 25
Height: 27
Children:
Label@LABEL:
X: 5
Height: 23
Font: Bold
Background@TWO_LINE_TOOLTIP:
Logic: ButtonTooltipLogic
Background: panel-black
Height: 48
Children:
Label@LABEL:
X: 5
Height: 46
Font: Bold
Label@HOTKEY:
Visible: false
TextColor: 255,255,0
Height: 23
Font: Bold
Background@BUTTON_TOOLTIP:
Logic: ButtonTooltipLogic
Background: panel-black

View File

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

View File

@@ -46,7 +46,6 @@ Players:
OwnsWorld: True
NonCombatant: True
Faction: gdi
Enemies: GDI, Nod
PlayerReference@Nod:
Name: Nod
Faction: nod
@@ -1060,7 +1059,7 @@ Rules:
WindTick: 150, 550
InstantWindChanges: false
UseSquares: false
PaticleSize: 0, 0
ParticleSize: 0, 0
ScatterDirection: 0, 0
Gravity: 8.00, 12.00
SwingOffset: 0, 0

View File

@@ -48,6 +48,11 @@ Players:
OwnsWorld: True
NonCombatant: True
Faction: gdi
PlayerReference@Civilians:
Name: Civilians
NonCombatant: True
Faction: gdi
Enemies: Nod
PlayerReference@Nod:
Name: Nod
Playable: True
@@ -60,7 +65,7 @@ Players:
LockSpawn: True
LockTeam: True
Allies: Nod
Enemies: GDI
Enemies: GDI, Civilians
Actors:
Actor0: sbag
@@ -224,28 +229,28 @@ Actors:
Owner: Neutral
Actor65: v24
Location: 18,38
Owner: Neutral
Owner: Civilians
Actor66: v32
Location: 19,41
Owner: Neutral
Owner: Civilians
Actor67: v30
Location: 15,40
Owner: Neutral
Owner: Civilians
Actor68: v29
Location: 17,40
Owner: Neutral
Owner: Civilians
Actor69: v28
Location: 23,38
Owner: Neutral
Owner: Civilians
Actor70: v27
Location: 23,36
Owner: Neutral
Owner: Civilians
Actor71: v27
Location: 22,36
Owner: Neutral
Owner: Civilians
Actor72: v26
Location: 16,37
Owner: Neutral
Owner: Civilians
Actor82: mtnk
Location: 21,21
Owner: GDI
@@ -429,6 +434,14 @@ Rules:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Wall:
Tooltip:
ShowOwnerRow: false
^Husk:
Tooltip:
GenericVisibility: Enemy, Ally, Neutral
GenericStancePrefix: false
ShowOwnerRow: false
NUK2:
Buildable:
Prerequisites: ~disabled
@@ -486,6 +499,8 @@ Rules:
HARV:
Buildable:
Prerequisites: ~disabled
Harvester:
SearchFromOrderRadius: 24
FTNK:
Buildable:
Prerequisites: ~disabled
@@ -495,9 +510,6 @@ Rules:
ARTY:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~disabled
MTNK:
Buildable:
Prerequisites: ~disabled
@@ -510,6 +522,13 @@ Rules:
MSAM:
Buildable:
Prerequisites: ~disabled
SBAG:
Buildable:
Queue: Defence.GDI, Defence.Nod
HQ:
AirstrikePower:
Prerequisites: gdi
SquadSize: 1
A10:
Targetable:

View File

@@ -319,6 +319,11 @@ end
searches = 0
getAirstrikeTarget = function()
local list = player.GetGroundAttackers()
if #list == 0 then
return
end
local target = list[DateTime.GameTime % #list + 1].CenterPosition
local sams = Map.ActorsInCircle(target, WDist.New(8 * 1024), function(actor)

View File

@@ -153,6 +153,7 @@ C17:
Speed: 326
Repulsable: False
AirborneUpgrades: airborne
MaximumPitch: 36
Health:
HP: 25
Armor:

View File

@@ -401,7 +401,6 @@
RejectsOrders:
Aircraft:
CruiseAltitude: 2560
MaximumPitch: 56
^Ship:
Inherits@1: ^ExistsInWorld

View File

@@ -154,4 +154,5 @@ EditorWorld:
Inherits: ^BaseWorld
EditorActorLayer:
EditorResourceLayer:
EditorSelectionLayer:

View File

@@ -240,6 +240,12 @@ overlay:
target-invalid:
Start: 1
editor-overlay:
copy: overlay
Start: 0
paste: overlay
Start: 1
poweroff:
offline:
Length: *

View File

@@ -1,7 +1,7 @@
Background@SIMPLE_TOOLTIP:
Logic: SimpleTooltipLogic
Background: dialog3
Height: 31
Height: 34
Children:
Label@LABEL:
X: 5
@@ -9,6 +9,23 @@ Background@SIMPLE_TOOLTIP:
Height: 23
Font: Bold
Background@TWO_LINE_TOOLTIP:
Logic: ButtonTooltipLogic
Background: dialog3
Height: 54
Children:
Label@LABEL:
X: 5
Y: 3
Height: 46
Font: Bold
Label@HOTKEY:
Visible: false
Y: 3
Height: 23
TextColor: 255,255,0
Font: Bold
Background@BUTTON_TOOLTIP:
Logic: ButtonTooltipLogic
Background: dialog3

View File

@@ -5,7 +5,7 @@ Player:
BuildingQueues: Building, Upgrade
UnitQueues: Infantry, Vehicle, Armor, Starport
BuildingCommonNames:
ConstructionYard: conyard
ConstructionYard: construction_yard
Refinery: refinery
Power: wind_trap
VehiclesFactory: light_factory, heavy_factory, starport
@@ -23,6 +23,7 @@ Player:
outpost: 1
high_tech_factory: 1
palace: 1
upgrade.conyard: 1
upgrade.barracks: 1
upgrade.light: 1
upgrade.heavy: 1
@@ -40,6 +41,7 @@ Player:
medium_gun_turret: 8%
large_gun_turret: 6%
wind_trap: 10%
upgrade.conyard: 0.1%
upgrade.barracks: 0.1%
upgrade.light: 0.1%
upgrade.heavy: 0.1%
@@ -119,7 +121,7 @@ Player:
BuildingQueues: Building, Upgrade
UnitQueues: Infantry, Vehicle, Armor, Starport
BuildingCommonNames:
ConstructionYard: conyard
ConstructionYard: construction_yard
Refinery: refinery
Power: wind_trap
VehiclesFactory: light_factory, heavy_factory, starport
@@ -137,6 +139,7 @@ Player:
outpost: 1
high_tech_factory: 1
palace: 1
upgrade.conyard: 1
upgrade.barracks: 1
upgrade.light: 1
upgrade.heavy: 1
@@ -154,6 +157,7 @@ Player:
medium_gun_turret: 5%
large_gun_turret: 10%
wind_trap: 12%
upgrade.conyard: 0.1%
upgrade.barracks: 0.1%
upgrade.light: 0.1%
upgrade.heavy: 0.1%
@@ -233,7 +237,7 @@ Player:
BuildingQueues: Building, Upgrade
UnitQueues: Infantry, Vehicle, Armor, Starport
BuildingCommonNames:
ConstructionYard: conyard
ConstructionYard: construction_yard
Refinery: refinery
Power: wind_trap
VehiclesFactory: light_factory, heavy_factory, starport
@@ -251,6 +255,7 @@ Player:
outpost: 1
high_tech_factory: 1
palace: 1
upgrade.conyard: 1
upgrade.barracks: 1
upgrade.light: 1
upgrade.heavy: 1
@@ -268,6 +273,7 @@ Player:
medium_gun_turret: 4%
large_gun_turret: 12%
wind_trap: 10%
upgrade.conyard: 0.1%
upgrade.barracks: 0.1%
upgrade.light: 0.1%
upgrade.heavy: 0.1%

View File

@@ -64,6 +64,7 @@ frigate:
RepairBuildings:
RearmBuildings:
Repulsable: False
MaximumPitch: 20
-AppearsOnRadar:
Cargo:
MaxWeight: 20

View File

@@ -10,6 +10,9 @@ spicebloom:
Name: Spice Bloom
SpiceBloom:
Weapon: SpiceExplosion
Explodes:
Weapon: BloomExplosion
EmptyWeapon: BloomExplosion
Crushable:
CrushClasses: spicebloom
CrushedByFriendlies: true
@@ -23,7 +26,7 @@ spicebloom:
TargetTypes: Ground
RequiresForceFire: yes
Armor:
Type: None
Type: none
sandworm:
Inherits@1: ^SpriteActor
@@ -34,7 +37,7 @@ sandworm:
HP: 9990
Radius: 256
Armor:
Type: None
Type: heavy
Mobile:
Speed: 42
TerrainSpeeds:
@@ -70,9 +73,9 @@ sietch:
Dimensions: 2,2
TerrainTypes: Cliff
Health:
HP: 400
HP: 6000
Armor:
Type: Concrete
Type: wood
RevealsShroud:
Range: 10c0
-DamagedWithoutFoundation:

View File

@@ -80,7 +80,7 @@
HiddenUnderFog:
ActorLostNotification:
Repairable:
RepairBuildings: repair
RepairBuildings: repair_pad
Guard:
Voice: Guard
Guardable:
@@ -106,7 +106,7 @@
Health:
HP: 75
Armor:
Type: Light
Type: light
HiddenUnderFog:
Type: CenterPosition
Tooltip:
@@ -141,7 +141,7 @@
Health:
HP: 125
Armor:
Type: Concrete
Type: concrete
Husk:
AppearsOnRadar:
HiddenUnderFog:
@@ -158,7 +158,7 @@
Health:
Radius: 96
Armor:
Type: None
Type: none
RevealsShroud:
Range: 3c768
Mobile:
@@ -171,7 +171,7 @@
Concrete: 100
Spice: 100
SpiceBlobs: 100
Dune: 50
Dune: 80
Rough: 80
SelectionDecorations:
Selectable:

View File

@@ -116,6 +116,7 @@ thumper:
UpgradeMinEnabledLevel: 1
AttractsWorms:
Intensity: 1000
Falloff: 0, 0, 0, 100, 100, 100, 25, 11, 6, 4, 3, 2, 1, 0
UpgradeTypes: deployed
UpgradeMinEnabledLevel: 1
DisableOnUpgrade:

View File

@@ -28,77 +28,90 @@ crate:
RevealMapCrateAction:
SelectionShares: 2
Effect: reveal-map
GiveUnitCrateAction@Trike:
SelectionShares: 20
Units: trike
Prerequisites: techlevel.low, Light
GiveUnitCrateAction@Raider:
GiveUnitCrateAction@LightInfantry:
SelectionShares: 15
Units: light_inf, light_inf, light_inf, light_inf, light_inf
Prerequisites: techlevel.low, barracks
GiveUnitCrateAction@Trooper:
SelectionShares: 10
Units: trooper, trooper, trooper, trooper
Prerequisites: techlevel.low, barracks, upgrade.barracks
GiveUnitCrateAction@Engineer:
SelectionShares: 10
Units: engineer
Prerequisites: techlevel.low, barracks, upgrade.barracks
GiveUnitCrateAction@Trike:
SelectionShares: 25
Units: trike
ValidFactions: atreides, harkonnen
Prerequisites: techlevel.low, light_factory
GiveUnitCrateAction@Raider:
SelectionShares: 25
Units: raider
ValidFactions: ordos
Prerequisites: techlevel.low, Light
Prerequisites: techlevel.low, light_factory
GiveUnitCrateAction@Quad:
SelectionShares: 40
SelectionShares: 20
Units: quad
Prerequisites: techlevel.medium, Light, Outpost
Prerequisites: techlevel.medium, light_factory, upgrade.light
GiveUnitCrateAction@CombatA:
SelectionShares: 10
SelectionShares: 15
Units: combat_tank_a
ValidFactions: atreides
Prerequisites: techlevel.low, Heavy
Prerequisites: techlevel.low, heavy_factory
GiveUnitCrateAction@CombatH:
SelectionShares: 10
SelectionShares: 15
Units: combat_tank_h
ValidFactions: harkonnen
Prerequisites: techlevel.low, Heavy
Prerequisites: techlevel.low, heavy_factory
GiveUnitCrateAction@CombatO:
SelectionShares: 10
SelectionShares: 15
Units: combat_tank_o
ValidFactions: ordos
Prerequisites: techlevel.low, Heavy
Prerequisites: techlevel.low, heavy_factory
GiveUnitCrateAction@SiegeTank:
SelectionShares: 10
SelectionShares: 12
Units: siege_tank
Prerequisites: techlevel.medium, Heavy, Outpost
Prerequisites: techlevel.medium, heavy_factory, upgrade.heavy
GiveUnitCrateAction@MissileTank:
SelectionShares: 10
Units: missile_tank
Prerequisites: techlevel.high, Hitech
Prerequisites: techlevel.high, heavy_factory, research_centre
GiveUnitCrateAction@StealthRaider:
SelectionShares: 7
SelectionShares: 8
Units: stealth_raider
ValidFactions: ordos
Prerequisites: techlevel.medium, Hitech
Prerequisites: techlevel.medium, light_factory, upgrade.light, high_tech_factory
GiveUnitCrateAction@Fremen:
SelectionShares: 5
Units: fremen,fremen
Units: fremen, fremen
ValidFactions: atreides
Prerequisites: techlevel.high, Palace
Prerequisites: techlevel.high, palace
GiveUnitCrateAction@Sardaukar:
SelectionShares: 8
Units: sardaukar,sardaukar
SelectionShares: 5
Units: sardaukar, sardaukar, sardaukar
ValidFactions: harkonnen
Prerequisites: techlevel.high, Palace
Prerequisites: techlevel.high, palace
GiveUnitCrateAction@Saboteur:
SelectionShares: 3
Units: saboteur,saboteur
SelectionShares: 5
Units: saboteur
ValidFactions: ordos
Prerequisites: techlevel.high, Palace
Prerequisites: techlevel.high, palace
GiveUnitCrateAction@SonicTank:
SelectionShares: 5
Units: sonic_tank
ValidFactions: atreides
Prerequisites: techlevel.high, Research
Prerequisites: techlevel.high, research_centre
GiveUnitCrateAction@Devast:
SelectionShares: 2
SelectionShares: 5
Units: devastator
ValidFactions: harkonnen
Prerequisites: techlevel.high, Research
Prerequisites: techlevel.high, research_centre
GiveUnitCrateAction@DeviatorTank:
SelectionShares: 5
Units: deviator
ValidFactions: ordos
Prerequisites: techlevel.high, Research
Prerequisites: techlevel.high, research_centre
GiveMcvCrateAction:
SelectionShares: 0
NoBaseSelectionShares: 9001

View File

@@ -662,8 +662,8 @@ repair_pad:
VisualBounds: 96,80
Reservable:
RepairsUnits:
Interval: 15
ValuePercentage: 50
Interval: 10
HpPerStep: 80
FinishRepairingNotification: UnitRepaired
RallyPoint:
Offset: 1,3
@@ -721,7 +721,7 @@ high_tech_factory:
Icon: ornistrike
Description: Air Strike
Prerequisites: ~techlevel.superweapons, upgrade.hightech
ChargeTime: 180
ChargeTime: 300
SquadSize: 3
LongDesc: Ornithopters hit the target with bombs
UnitType: ornithopter
@@ -841,7 +841,7 @@ palace:
Prerequisites: ~techlevel.superweapons, ~palace.fremen
Actors: fremen, fremen
Type: Palace
ChargeTime: 60
ChargeTime: 90
ReadyAudio: Reinforce
BlockedAudio: NoRoom
OrderName: ProduceActorPower.Fremen
@@ -852,7 +852,7 @@ palace:
Prerequisites: ~techlevel.superweapons, ~palace.saboteur
Actors: saboteur
Type: Palace
ChargeTime: 40
ChargeTime: 90
ReadyAudio: Reinforce
BlockedAudio: NoRoom
OrderName: ProduceActorPower.Saboteur

View File

@@ -148,4 +148,5 @@ EditorWorld:
Inherits: ^BaseWorld
EditorActorLayer:
D2kEditorResourceLayer:
EditorSelectionLayer:

View File

@@ -126,19 +126,23 @@ rank:
Length: *
overlay:
build-valid-arrakis: DATA.R8
Defaults: DATA.R8
Offset: -16,-16
build-invalid: DATA.R8
build-valid-arrakis:
build-invalid:
Start: 1
Offset: -16,-16
target-select: DATA.R8
target-select:
Start: 2
Offset: -16,-16
target-valid-arrakis: DATA.R8
Offset: -16,-16
target-invalid: DATA.R8
target-valid-arrakis:
target-invalid:
Start: 1
editor-overlay:
Defaults: DATA.R8
Offset: -16,-16
copy:
paste:
Start: 1
rallypoint:
flag: flagfly.shp

View File

@@ -581,7 +581,7 @@ OrniBomb:
Warhead@1Dam: SpreadDamage
Spread: 320
Falloff: 100, 60, 30, 15, 0
Damage: 400
Damage: 1000 #400 in original, reduce when bombers can do multiple passes
Versus:
none: 90
wall: 50
@@ -658,7 +658,7 @@ CrateExplosion:
Warhead@1Dam: SpreadDamage
Spread: 320
Falloff: 100, 60, 30, 15, 0
Damage: 200
Damage: 500
Versus:
none: 90
wall: 5
@@ -766,13 +766,12 @@ SardDeath:
ImpactSound: EXPLSML2.WAV
SpiceExplosion:
Report: EXPLMD1.WAV
Projectile: Bullet
Speed: 50, 75
High: true
Angle: 91, 264
Blockable: false
Angle: 60, 90
Trail: large_trail
Image: null
Image: 120mm
Warhead@1Dam: SpreadDamage
Spread: 320
Falloff: 100, 60, 30, 15, 0
@@ -791,7 +790,31 @@ SpiceExplosion:
AffectsParent: true
Warhead@2Res: CreateResource
AddsResourceType: Spice
Size: 2,2
Size: 1
Warhead@3Eff: CreateEffect
Explosion: med_explosion
BloomExplosion:
Report: EXPLMD1.WAV
Range: 0c8
Projectile: Bullet
Speed: 1c0
Blockable: false
Image: null
Warhead@1Dam: SpreadDamage
Spread: 320
Falloff: 100, 60, 30, 15, 0
Damage: 750
Versus:
none: 90
wall: 5
building: 65
wood: 50
light: 40
heavy: 30
invulnerable: 0
cy: 20
harvester: 25
DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath
AffectsParent: true

View File

@@ -307,6 +307,7 @@ Container@EDITOR_WORLD_ROOT:
Visible: false
Width: PARENT_RIGHT - 35
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: TWO_LINE_TOOLTIP
IgnoreChildMouseOver: true
Children:
ActorPreview@ACTOR_PREVIEW:
@@ -350,9 +351,15 @@ Container@EDITOR_WORLD_ROOT:
TooltipContainer: TOOLTIP_CONTAINER
Font: Bold
Key: escape
Button@COPYPASTE_BUTTON:
X: 170
Width: 90
Height: 25
Text: Copy/Paste
Font: Bold
Button@GRID_BUTTON:
X: 180
Width: 160
X: 270
Width: 70
Height: 25
Text: Grid
TooltipTemplate: BUTTON_TOOLTIP

View File

@@ -23,12 +23,12 @@ Container@LOBBY_GLOBALCHAT_PANEL:
Y: 20
Width: 582
Height: PARENT_BOTTOM - 50
ItemSpacing: 5
TopBottomSpacing: 4
ItemSpacing: 4
Children:
Label@HISTORY_TEMPLATE:
X: 5
Width: 530
Height: 25
WordWrap: True
TextField@CHAT_TEXTFIELD:
X: 205

View File

@@ -60,25 +60,25 @@ Background@MAPCHOOSER_PANEL:
IgnoreMouseOver: true
IgnoreMouseInput: true
Label@TITLE:
X: 2
X: 4
Y: PARENT_BOTTOM-53
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-37
Align: Center
Font: Tiny
Label@AUTHOR:
Width: PARENT_RIGHT-4
X: 2
Width: PARENT_RIGHT-8
X: 4
Y: PARENT_BOTTOM-25
Align: Center
Font: Tiny
Label@SIZE:
Width: PARENT_RIGHT-4
X: 2
Width: PARENT_RIGHT-8
X: 4
Y: PARENT_BOTTOM-13
Align: Center
Font: Tiny

View File

@@ -23,12 +23,12 @@ Container@GLOBALCHAT_PANEL:
Y: 20
Width: 582
Height: PARENT_BOTTOM - 50
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

View File

@@ -68,7 +68,7 @@ Background@MULTIPLAYER_PANEL:
Font: Bold
ScrollPanel@MULTIPLAYER_FILTER_PANEL:
Width: 147
Width: 158
Height: 130
Children:
Checkbox@WAITING_FOR_PLAYERS:
@@ -109,4 +109,4 @@ ScrollPanel@MULTIPLAYER_FILTER_PANEL:
Height: 20
Text: Incompatible
TextColor: 190,190,190
Font: Regular
Font: Regular

View File

@@ -262,7 +262,7 @@ Background@REPLAYBROWSER_PANEL:
Height: 16
Label@LABEL:
X: 40
Width: 60
Width: PARENT_RIGHT-50
Height: 25
Label@NOFLAG_LABEL:
X: 5

View File

@@ -1,7 +1,7 @@
Background@SIMPLE_TOOLTIP:
Logic: SimpleTooltipLogic
Background: dialog4
Height: 29
Height: 32
Children:
Label@LABEL:
X: 7
@@ -9,6 +9,23 @@ Background@SIMPLE_TOOLTIP:
Height: 23
Font: Bold
Background@TWO_LINE_TOOLTIP:
Logic: ButtonTooltipLogic
Background: dialog4
Height: 52
Children:
Label@LABEL:
X: 7
Y: 2
Height: 46
Font: Bold
Label@HOTKEY:
Visible: false
Y: 2
Height: 23
TextColor: 255,255,0
Font: Bold
Background@BUTTON_TOOLTIP:
Logic: ButtonTooltipLogic
Background: dialog4

View File

@@ -1356,7 +1356,7 @@ Weapons:
Range: 10c0
TTankZap:
Range: 4c768
FLAK-23:
FLAK-23-AG:
Range: 4c0
Voices:

View File

@@ -508,7 +508,7 @@ Rules:
WindTick: 150, 550
InstantWindChanges: false
UseSquares: false
PaticleSize: 0, 0
ParticleSize: 0, 0
ScatterDirection: 0, 0
Gravity: 8.00, 12.00
SwingOffset: 0, 0
@@ -672,6 +672,14 @@ Rules:
Prerequisites: barracks
Valued:
Cost: 300
FTRK:
-Armament@AA:
-Armament@AG:
Armament:
Weapon: FLAK-23
Recoil: 85
LocalOffset: 512,0,192
MuzzleSequence: muzzle
ARTY:
Inherits: ^Tank
Valued:

View File

@@ -668,7 +668,7 @@ Rules:
WindTick: 150, 550
InstantWindChanges: false
UseSquares: true
PaticleSize: 1, 3
ParticleSize: 1, 3
ScatterDirection: -1, 1
Gravity: 1.00, 2.00
SwingOffset: 1.0, 1.5

View File

@@ -23,12 +23,6 @@ BaseBuildings =
}
BuildBase = function()
if CYard.IsDead or CYard.Owner ~= Greece then
return
elseif Harvester.IsDead and Greece.Resources <= 299 then
return
end
for i,v in ipairs(BaseBuildings) do
if not v.exists then
BuildBuilding(v)
@@ -41,6 +35,12 @@ end
BuildBuilding = function(building)
Trigger.AfterDelay(Actor.BuildTime(building.type), function()
if CYard.IsDead or CYard.Owner ~= Greece then
return
elseif Harvester.IsDead and Greece.Resources <= 299 then
return
end
local actor = Actor.Create(building.type, true, { Owner = Greece, Location = GreeceCYard.Location + building.pos })
Greece.Cash = Greece.Cash - building.cost

View File

@@ -31,6 +31,10 @@ AttackPaths =
}
ReinfInf = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
Reinforcements.Reinforce(Greece, InfantryReinfGreece, InfReinfPath, 0, function(soldier)
soldier.Hunt()
end)
@@ -46,35 +50,39 @@ ReinfArmor = function()
end
BringPatrol1 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
local units = Reinforcements.Reinforce(Greece, Patrol1Group, { SWRoadPoint.Location }, 0)
Utils.Do(units, function(patrols)
patrols.Patrol(Patrol1Path, true, 250)
end)
if not Radar.IsDead and Radar.Owner == Greece then
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol1)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol1)
end
end)
end
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol1)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol1)
end
end)
end
BringPatrol2 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
local units = Reinforcements.Reinforce(Greece, Patrol2Group, { NRoadPoint.Location }, 0)
Utils.Do(units, function(patrols)
patrols.Patrol(Patrol2Path, true, 250)
end)
if not Radar.IsDead and Radar.Owner == Greece then
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol2)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol2)
end
end)
end
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol2)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol2)
end
end)
end

View File

@@ -19,12 +19,6 @@ BaseWeaponsFactory = { type = "weap", pos = CVec.New(-12, -1), cost = 2000, exis
BaseBuildings = { BasePower, BaseBarracks, BaseProc, BaseWeaponsFactory }
BuildBase = function()
if CYard.IsDead or CYard.Owner ~= Greece then
return
elseif Harvester.IsDead and Greece.Resources <= 299 then
return
end
for i,v in ipairs(BaseBuildings) do
if not v.exists then
BuildBuilding(v)
@@ -37,6 +31,12 @@ end
BuildBuilding = function(building)
Trigger.AfterDelay(Actor.BuildTime(building.type), function()
if CYard.IsDead or CYard.Owner ~= Greece then
return
elseif Harvester.IsDead and Greece.Resources <= 299 then
return
end
local actor = Actor.Create(building.type, true, { Owner = Greece, Location = GreeceCYard.Location + building.pos })
Greece.Cash = Greece.Cash - building.cost

View File

@@ -31,6 +31,10 @@ AttackPaths =
}
ReinfInf = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
Reinforcements.Reinforce(Greece, InfantryReinfGreece, InfReinfPath, 0, function(soldier)
soldier.Hunt()
end)
@@ -46,35 +50,39 @@ ReinfArmor = function()
end
BringPatrol1 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
local units = Reinforcements.Reinforce(Greece, Patrol1Group, { NRoadPoint.Location }, 0)
Utils.Do(units, function(patrols)
patrols.Patrol(Patrol1Path, true, 250)
end)
if not Radar.IsDead and Radar.Owner == Greece then
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol1)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol1)
end
end)
end
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol1)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol1)
end
end)
end
BringPatrol2 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
return
end
local units = Reinforcements.Reinforce(Greece, Patrol2Group, { NRoadPoint.Location }, 0)
Utils.Do(units, function(patrols)
patrols.Patrol(Patrol2Path, true, 250)
end)
if not Radar.IsDead and Radar.Owner == Greece then
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol2)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol2)
end
end)
end
Trigger.OnAllKilled(units, function()
if Map.Difficulty == "Hard" then
Trigger.AfterDelay(DateTime.Minutes(4), BringPatrol2)
else
Trigger.AfterDelay(DateTime.Minutes(7), BringPatrol2)
end
end)
end

View File

@@ -882,10 +882,13 @@ Rules:
ShowOwnerRow: false
APWR:
Buildable:
Prerequisites: ~disabled
Prerequisites: ~structures.allies
ARTY:
Buildable:
Prerequisites: ~vehicles.allies, ~techlevel.low
ATEK:
Buildable:
Prerequisites: ~disabled
BRIK:
Buildable:
Prerequisites: ~disabled
@@ -898,15 +901,24 @@ Rules:
IRON:
Buildable:
Prerequisites: ~disabled
MECH:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~tent
E7:
Buildable:
Prerequisites: ~disabled
SHOK:
Buildable:
Prerequisites: ~disabled
SPY:
Buildable:
Prerequisites: ~disabled
SNIPER:
Buildable:
Prerequisites: ~disabled
@@ -945,6 +957,24 @@ Rules:
STEK:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: dome, ~structures.allies, ~techlevel.medium
MNLY.AT:
Buildable:
Prerequisites: ~disabled
DOG:
Health:
HP: 25

View File

@@ -20,12 +20,6 @@ BaseApwr2 = { type = "apwr", pos = CVec.New(-4, 1), cost = 500, exists = true }
BaseBuildings = { BaseApwr, BaseTent, BaseProc, BaseWeap, BaseApwr2 }
BuildBase = function()
if CYard.IsDead or CYard.Owner ~= enemy then
return
elseif Harvester.IsDead and enemy.Resources <= 299 then
return
end
for i,v in ipairs(BaseBuildings) do
if not v.exists then
BuildBuilding(v)
@@ -38,6 +32,12 @@ end
BuildBuilding = function(building)
Trigger.AfterDelay(Actor.BuildTime(building.type), function()
if CYard.IsDead or CYard.Owner ~= enemy then
return
elseif Harvester.IsDead and enemy.Resources <= 299 then
return
end
local actor = Actor.Create(building.type, true, { Owner = enemy, Location = CYardLocation.Location + building.pos })
enemy.Cash = enemy.Cash - building.cost

View File

@@ -571,10 +571,13 @@ Rules:
ShowOwnerRow: false
APWR:
Buildable:
Prerequisites: ~disabled
Prerequisites: ~structures.allies
ARTY:
Buildable:
Prerequisites: ~vehicles.allies, ~techlevel.low
ATEK:
Buildable:
Prerequisites: ~disabled
BRIK:
Buildable:
Prerequisites: ~disabled
@@ -587,15 +590,24 @@ Rules:
IRON:
Buildable:
Prerequisites: ~disabled
MECH:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~tent
E7:
Buildable:
Prerequisites: ~disabled
SHOK:
Buildable:
Prerequisites: ~disabled
SPY:
Buildable:
Prerequisites: ~disabled
SNIPER:
Buildable:
Prerequisites: ~disabled
@@ -634,6 +646,24 @@ Rules:
STEK:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: dome, ~structures.allies, ~techlevel.medium
MNLY.AT:
Buildable:
Prerequisites: ~disabled
DOG:
Health:
HP: 25

View File

@@ -20,12 +20,6 @@ BaseApwr2 = { type = "apwr", pos = CVec.New(6, -5), cost = 500, exists = true }
BaseBuildings = { BaseApwr, BaseTent, BaseProc, BaseWeap, BaseApwr2 }
BuildBase = function()
if CYard.IsDead or CYard.Owner ~= enemy then
return
elseif Harvester.IsDead and enemy.Resources <= 299 then
return
end
for i,v in ipairs(BaseBuildings) do
if not v.exists then
BuildBuilding(v)
@@ -38,6 +32,12 @@ end
BuildBuilding = function(building)
Trigger.AfterDelay(Actor.BuildTime(building.type), function()
if CYard.IsDead or CYard.Owner ~= enemy then
return
elseif Harvester.IsDead and enemy.Resources <= 299 then
return
end
local actor = Actor.Create(building.type, true, { Owner = enemy, Location = CYardLocation.Location + building.pos })
enemy.Cash = enemy.Cash - building.cost

View File

@@ -563,7 +563,8 @@ TTNK:
Armament:
Weapon: TTankZap
LocalOffset: 0,0,213
AttackFrontal:
AttackTurreted:
Turreted:
WithIdleOverlay@SPINNER:
Sequence: spinner
SelectionDecorations:
@@ -595,8 +596,13 @@ FTRK:
Turreted:
ROT: 10
Offset: -298,0,298
Armament:
Weapon: FLAK-23
Armament@AA:
Weapon: FLAK-23-AA
Recoil: 85
LocalOffset: 512,0,192
MuzzleSequence: muzzle
Armament@AG:
Weapon: FLAK-23-AG
Recoil: 85
LocalOffset: 512,0,192
MuzzleSequence: muzzle
@@ -672,6 +678,7 @@ CTNK:
LocalYaw: -100
AttackFrontal:
PortableChrono:
ChargeDelay: 300
ProducibleWithLevel:
Prerequisites: vehicles.upgraded
@@ -718,10 +725,10 @@ STNK:
Armor:
Type: Light
Mobile:
Speed: 113
Speed: 142
Crushes: wall, mine, crate, infantry
RevealsShroud:
Range: 6c0
Range: 7c0
AutoTarget:
InitialStance: HoldFire
InitialStanceAI: ReturnFire
@@ -734,8 +741,8 @@ STNK:
WithTurret:
Cargo:
Types: Infantry
MaxWeight: 3
PipCount: 3
MaxWeight: 4
PipCount: 4
Cloak:
InitialDelay: 125
CloakDelay: 250
@@ -743,7 +750,7 @@ STNK:
UncloakSound: appear1.aud
IsPlayerPalette: true
DetectCloaked:
Range: 6c0
Range: 7c0
-MustBeDestroyed:
ProducibleWithLevel:
Prerequisites: vehicles.upgraded

View File

@@ -173,4 +173,5 @@ EditorWorld:
Inherits: ^BaseWorld
EditorActorLayer:
EditorResourceLayer:
EditorSelectionLayer:

View File

@@ -474,6 +474,12 @@ overlay:
target-invalid:
Start: 1
editor-overlay:
copy: overlay
Start: 0
paste: overlay
Start: 1
resources:
Defaults:
Length: *

View File

@@ -295,11 +295,34 @@ SilencedPPK:
Explosion: water_piffs
ValidImpactTypes: Water
FLAK-23:
FLAK-23-AA:
ReloadDelay: 10
Range: 8c0
Report: AACANON3.AUD
ValidTargets: Air
Projectile: Bullet
Speed: 1c682
Blockable: false
Warhead@1Dam: SpreadDamage
Spread: 213
Damage: 20
ValidTargets: Air, Ground, Water
Versus:
None: 40
Wood: 10
Light: 60
Heavy: 10
Concrete: 20
DamageTypes: Prone50Percent, TriggerProne, DefaultDeath
Warhead@2EffAir: CreateEffect
Explosion: small_explosion_air
ValidImpactTypes: Air, AirHit
FLAK-23-AG:
ReloadDelay: 10
Range: 6c0
Report: AACANON3.AUD
ValidTargets: Air, Ground, Water
ValidTargets: Ground, Water
Projectile: Bullet
Speed: 1c682
Blockable: false
@@ -316,11 +339,8 @@ FLAK-23:
DamageTypes: Prone50Percent, TriggerProne, DefaultDeath
Warhead@2Eff: CreateEffect
Explosion: small_explosion
InvalidImpactTypes: Air, AirHit, Water
Warhead@3EffAir: CreateEffect
Explosion: small_explosion_air
ValidImpactTypes: Air, AirHit
Warhead@4EffWater: CreateEffect
InvalidImpactTypes: Air, AirHit
Warhead@3EffWater: CreateEffect
Explosion: small_splash
ValidImpactTypes: Water

View File

@@ -175,4 +175,6 @@ EditorWorld:
Inherits: ^BaseWorld
EditorActorLayer:
EditorResourceLayer:
EditorSelectionLayer:
Palette: placebuilding

View File

@@ -7,6 +7,13 @@ overlay:
Start: 1
target-select:
editor-overlay:
Defaults: place
Offset: 0, -12
copy:
paste:
Start: 1
poweroff:
offline:
Length: *

View File

@@ -46,5 +46,5 @@ if [ ! -f soft_oal.dll ]; then
fi
if [ ! -f ../NsProcess.zip ]; then
curl -s -L -o ../NsProcess.zip http://nsis.sourceforge.net/mediawiki/images/archive/1/18/20140806212030!NsProcess.zip
curl -s -L -o ../NsProcess.zip https://build.opensuse.org/source/windows:mingw:win32/mingw32-cross-nsis-plugin-nsprocess/20140806212030!NsProcess.zip?rev=3319b671b847e6545d6d8a3f3834f82a
fi