Compare commits

...

83 Commits

Author SHA1 Message Date
Paul Chote
c00ed84b25 Fix player joins resetting the server timestep. 2016-10-19 21:05:37 +02:00
Paul Chote
7f7f037ffd Fix a desync in GpsDot.IsTargetableBy.
World.ShroudExplores depends on RenderPlayer,
which makes it completely bogus for this purpose.
2016-10-19 19:16:41 +02:00
SoScared
bd8dc18bad move AA towards traditional 2016-10-15 15:57:28 +01:00
Oliver Brakmann
dd50004d91 Fix yak attacks in Evacuation 2016-10-15 12:02:12 +02:00
abcdefg30
b4033c609e Fix yaks trying to attack invalid targets 2016-10-14 19:00:58 +02:00
abcdefg30
9800b3513e Add a CanTarget method to lua 2016-10-14 19:00:46 +02:00
abcdefg30
047f94613b Target.FromActor never returns a TargetType.FrozenActor 2016-10-14 19:00:17 +02:00
RoosterDragon
74c69f835c Make sure AI can deploy an MCV when it lacks a base. 2016-10-14 18:24:12 +02:00
Paul Chote
bea6523f5e Add support for an older/alternative d2k release. 2016-10-14 18:14:42 +02:00
abcdefg30
38dab424fb Fix soviet units not attack moving to their rally points
and remove unnecessary (duplicated) code from the tick function
(the call to IdleHunt inside SpawnSovietUnits is enough)
2016-10-13 20:40:46 +02:00
abcdefg30
605f3b65a9 Fix soviet units not stopping to hunt after being captured in Exodus 2016-10-13 20:40:46 +02:00
abcdefg30
1f7a483fd6 Make HIJACKER unbuildable in the Evacuation mission
We don't allow building Mechanics as well
2016-10-13 20:40:46 +02:00
abcdefg30
d82549ec00 Merge pull request #12212 from obrakmann/remove-ai-capturing
Remove AI capturing from TD and RA, and AIs using mechanics and medics in RA
2016-10-12 14:53:18 +02:00
Oliver Brakmann
d003885bca Remove medics and mechanics from RA AIs 2016-10-11 21:08:56 +02:00
Oliver Brakmann
f907403ca7 Remove AI capturing from TD and RA 2016-10-11 20:50:36 +02:00
Paul Chote
29c13a4c26 Work around an initialisation order conflict. 2016-10-09 14:15:17 +02:00
Paul Chote
379ece7592 Fix non-selectable support actor health bars. 2016-10-08 15:32:05 +02:00
RoosterDragon
5b815ca2cf Marshal results in QueryDevices correctly. 2016-10-07 16:27:01 +02:00
abcdefg30
391c378118 Fix floating text showing up beneath shroud 2016-10-06 21:30:14 +02:00
Paul Chote
bd8aeb3cae Allow spys to infiltrate fake structures in RA. 2016-10-01 20:21:39 +02:00
Paul Chote
bab4cac2d7 Add InfiltrateForDecoration trait. 2016-10-01 20:21:39 +02:00
Oliver Brakmann
98664ce3e5 Log unknown orders instead of crashing with an NIE 2016-09-30 16:13:57 +02:00
Jonas A. Lind
57065de55e Changed MSUB Description
Simplified initial text and fixed strong/weak vs.
2016-09-28 13:39:10 +02:00
SoScared
2dd0e05423 AA Missile Sub + Tweak 2016-09-28 13:38:51 +02:00
abcdefg30
9b158b459c Remove a bogus LZRange field together with an unnecessary ParaDrop definition 2016-09-26 21:25:27 +02:00
Matthias Mailänder
80b06d1dd2 Only save a syncreport.log when a desync occurs. 2016-09-26 21:25:18 +02:00
Paul Chote
a33321390f Hack around the Lua API. 2016-09-26 19:04:28 +02:00
Paul Chote
1607173769 Change aircraft default to move to rally point after resupplying. 2016-09-26 19:04:28 +02:00
Paul Chote
bf957f09ff Add AbortOnResupply property to cancel aircraft activities on resupply. 2016-09-26 19:04:28 +02:00
Paul Chote
dbc8b0a99a Remove unnecessarily queued ResupplyAircraft activity. 2016-09-26 19:04:28 +02:00
Paul Chote
799b07cd1e Avoid landing-dances when issuing mixed full/empty aircraft RTB orders. 2016-09-26 19:04:28 +02:00
Paul Chote
c83b8b712e Fix integer overflows in Wangle.ArcTan. 2016-09-26 18:36:17 +02:00
reaperrr
c7adfd43a0 Fix LaserZap not being removed if HitAnim is not defined
This avoids degrading performance over time as well as an (albeit unlikely) OutOfMemoryException.
2016-09-26 14:54:27 +02:00
SoScared
55c1b6a663 Camo Pillbox HP 450 2016-09-25 22:01:22 +02:00
SoScared
2693f9de1c Mammoth Tank speed 50 2016-09-25 22:01:07 +02:00
Paul Chote
dc684e244e Use CosmeticRandom for picking smudge type. 2016-09-24 20:49:03 +02:00
Oliver Brakmann
8334e9adeb Fix setting MayYieldReservation when there is no reservation 2016-09-24 20:32:01 +02:00
Oliver Brakmann
e55f2f3bee Fix helicopters not taking off when their target got covered by shroud 2016-09-24 20:31:46 +02:00
Oliver Brakmann
59ee9bcb96 Prevent an infinite loop when planes go out of ammo and all airfields are gone 2016-09-24 20:31:29 +02:00
Oliver Brakmann
b3ba4f5ca2 Use the yield reservation logic for helicopters as well. Oops. 2016-09-24 20:30:51 +02:00
Oliver Brakmann
e628d756fb Remove brain-dead logic from TakeOff
1. TakeOff's Tick() method never checks itself whether it is canceled
2. If NextActivity is null, TakeOff is the only activity on the queue
3. Takeoff canceling the queue then just cancels itself, with no effect at all

4. If Takeoff however is running as an inner activity, it will cancel the complete main queue, wrecking all sorts of havoc
2016-09-24 20:30:40 +02:00
Paul Chote
4f55edad74 Report mission briefings in the mp lobby. 2016-09-23 23:52:28 +02:00
abcdefg30
43a30f6497 Render WithDecoration above shroud 2016-09-23 23:51:56 +02:00
Oliver Brakmann
a84815a832 Fix AI still producing units with captured factories in Nod missions 2016-09-23 19:42:42 +01:00
Paul Chote
d3dae5c34f Add a range check to Repair. 2016-09-23 18:57:24 +01:00
Oliver Brakmann
8a666b973f Fix kicking players joining servers hosting a map with non-default rules
Specifically, rules that remove traits which implement ILobbyOptions
2016-09-23 18:48:14 +01:00
Paul Chote
4a039166e4 Fix control group decoration position. 2016-09-23 18:34:20 +01:00
abcdefg30
25a63530d3 Split a UnitCommandWidget from WorldCommandWidget 2016-09-22 17:52:21 +01:00
abcdefg30
5349db0384 Fix spectators not being able to issue commands in TD 2016-09-22 17:52:14 +01:00
Paul Chote
60244d4910 Clean up ClientPings when a player drops from the server. 2016-09-21 18:17:40 +02:00
abcdefg30
a7251b7e95 Fix beacons not being cancelable 2016-09-21 18:14:06 +02:00
RoosterDragon
6e56349a26 Change Game.RunTime to a long to prevent overflow. 2016-09-21 18:13:56 +02:00
Paul Chote
cb553fbe15 Converting dates to string using the InvariantCulture. 2016-09-21 17:57:14 +02:00
Paul Chote
955f39620b Restore missing GameUid. 2016-09-21 17:57:03 +02:00
Paul Chote
af5402d41c Timestamp syncreport and exception log files. 2016-09-21 17:56:56 +02:00
Paul Chote
aaa1484643 Read data from *all* connections to the server. 2016-09-21 17:46:33 +02:00
Paul Chote
fb7b79e8fc Fix d2k lobby admin icon. 2016-09-21 17:11:49 +02:00
Chris Forbes
1f0d98344b server: Fix server getting wedged after map query with bad minimap
If the mapserver returned an unusable minimap blob, we'd end up dropping
the resulting exceptions on the floor, and committing a completely broken
MapPreview, which would then blow up the tail end of the map change
process, and all future ValidateClient calls after players join (which
itself was handled by kicking the player and logging some noise of dubious
value).

Adjusts exception handling in a number of places to log the exception
rather than dropping it on the floor, and makes the mapserver response
parsing tolerant of bogus minimap blobs -- in this case, we'd rather just
have no minimap.

Candidate for stable, as it fixes a bug present in the current release and
the current playtest series.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
2016-09-21 04:06:36 +01:00
Oliver Brakmann
37155ec9dd Remove workarounds for ownership change breakage from 'Infiltration' 2016-09-20 09:16:09 +01:00
Oliver Brakmann
5e3f0721ce Fix crashing when a spy's "real" owner gets changed 2016-09-20 09:16:02 +01:00
Matthias Mailänder
90a7d1f3e9 Fix a crash when no sync report is available. 2016-09-19 20:02:23 +02:00
Oliver Brakmann
3971b99363 Add advisory upgrade rule for WithRearmAnimation 2016-09-18 16:20:33 +02:00
Oliver Brakmann
b99c4903a6 Add WithRearmAnimation to buildings that need it 2016-09-18 16:20:09 +02:00
Oliver Brakmann
f7e5cce0ab Fix locking an airfield that is rearming aircraft while being sold 2016-09-18 16:19:26 +02:00
abcdefg30
19983e9e7f Fix the music resetting from time to time 2016-09-18 15:57:45 +02:00
Oliver Brakmann
b84bd1762b Fix not being able to close the chat window in replays 2016-09-18 15:31:00 +02:00
Paul Chote
9623bbebc8 Improve error message. 2016-09-18 15:27:43 +02:00
Paul Chote
7becb92a00 Don't crash if a replay can't be read. 2016-09-18 15:27:32 +02:00
Paul Chote
a812b937f3 Other misc fixes in Platform. 2016-09-18 14:17:34 +02:00
Paul Chote
8bbced1582 Fix string comparison cultures in Platform. 2016-09-18 14:17:21 +02:00
Paul Chote
a4eb40efe4 Resolve a bare "." to the game install path. 2016-09-18 14:17:07 +02:00
Paul Chote
214d7325bd Account for terrain height in AttackBomber. 2016-09-18 14:08:02 +02:00
Paul Chote
be09392c35 Give window modes human-friendly names.
* Fullscreen -> Fullscreen (Legacy)
* Pseudo-fullscreen -> Fullscreen
2016-09-18 12:51:13 +02:00
Paul Chote
f6e892a2dd Work around incorrect mono behaviour under OSX. 2016-09-17 18:22:56 +02:00
Paul Chote
cdd70e7daf Fix explicit oramap path lint checking. 2016-09-17 14:13:53 +02:00
Oliver Brakmann
4cf98effa4 Remove 'campaign-' prefix from disable-experience.yaml files 2016-09-16 17:32:29 +01:00
abcdefg30
1d8048c133 Create a PlayLaunchSounds method in SupportPower.cs 2016-09-12 19:14:17 +02:00
abcdefg30
ecbedad308 Fix the support power SpeechNotifications not being played to the correct player 2016-09-12 19:14:17 +02:00
Mustafa Alperen Seki
31c99d8071 Fix Sardaukar's prerequisite 2016-09-12 15:34:05 +02:00
Paul Chote
303a2be612 Fix bogus observer stats graph positioning. 2016-09-09 21:16:32 +02:00
abcdefg30
ece2f8494e Remove the TopBottomSpacing from the score screen player list 2016-09-09 12:14:29 +02:00
clemty
23f9998c7e gdi07 map yaml polish 2016-09-07 23:50:53 +02:00
abc013
fcab4e9eed Fixed enemy missiles not being deflected by Radar Jammers 2016-09-05 23:06:11 +02:00
123 changed files with 2665 additions and 536 deletions

View File

@@ -489,6 +489,11 @@ namespace OpenRA
return int.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i);
}
public static bool TryParseInt64Invariant(string s, out long i)
{
return long.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i);
}
public static bool IsTraitEnabled(this object trait)
{
return trait as IDisabledTrait == null || !(trait as IDisabledTrait).IsTraitDisabled;

View File

@@ -14,6 +14,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
@@ -71,9 +72,8 @@ namespace OpenRA
static string TimestampedFilename(bool includemilliseconds = false)
{
return includemilliseconds
? DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssfffZ")
: DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ");
var format = includemilliseconds ? "yyyy-MM-ddTHHmmssfffZ" : "yyyy-MM-ddTHHmmssZ";
return "OpenRA-" + DateTime.UtcNow.ToString(format, CultureInfo.InvariantCulture);
}
static void JoinInner(OrderManager om)
@@ -96,7 +96,7 @@ namespace OpenRA
// More accurate replacement for Environment.TickCount
static Stopwatch stopwatch = Stopwatch.StartNew();
public static int RunTime { get { return (int)stopwatch.ElapsedMilliseconds; } }
public static long RunTime { get { return stopwatch.ElapsedMilliseconds; } }
public static int RenderFrame = 0;
public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } }
@@ -260,7 +260,6 @@ namespace OpenRA
Log.AddChannel("perf", "perf.log");
Log.AddChannel("debug", "debug.log");
Log.AddChannel("sync", "syncreport.log");
Log.AddChannel("server", "server.log");
Log.AddChannel("sound", "sound.log");
Log.AddChannel("graphics", "graphics.log");
@@ -736,7 +735,7 @@ namespace OpenRA
}
}
else
Thread.Sleep(nextUpdate - now);
Thread.Sleep((int)(nextUpdate - now));
}
}

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Graphics
}
}
public static int TicksSinceLastMove = 0;
public static long TicksSinceLastMove = 0;
public static int2 LastMousePos;
float ClosestTo(float[] collection, float target)

View File

@@ -150,9 +150,10 @@ namespace OpenRA
foreach (var kv in yaml)
maps[kv.Key].UpdateRemoteSearch(MapStatus.DownloadAvailable, kv.Value, mapDetailsReceived);
}
catch
catch (Exception e)
{
Log.Write("debug", "Can't parse remote map search data:\n{0}", data);
Log.Write("debug", "Exception: {0}", e);
if (queryFailed != null)
queryFailed();
}

View File

@@ -367,7 +367,15 @@ namespace OpenRA
spawns[j / 2] = new CPos(r.spawnpoints[j], r.spawnpoints[j + 1]);
newData.SpawnPoints = spawns;
newData.GridType = r.map_grid_type;
newData.Preview = new Bitmap(new MemoryStream(Convert.FromBase64String(r.minimap)));
try
{
newData.Preview = new Bitmap(new MemoryStream(Convert.FromBase64String(r.minimap)));
}
catch (Exception e)
{
Log.Write("debug", "Failed parsing mapserver minimap response: {0}", e);
newData.Preview = null;
}
var playersString = Encoding.UTF8.GetString(Convert.FromBase64String(r.players_block));
newData.Players = new MapPlayers(MiniYaml.FromString(playersString));
@@ -389,7 +397,10 @@ namespace OpenRA
return Pair.New(rules, flagged);
});
}
catch (Exception) { }
catch (Exception e)
{
Log.Write("debug", "Failed parsing mapserver response: {0}", e);
}
// Commit updated data before running the callbacks
innerData = newData;

View File

@@ -64,7 +64,8 @@ namespace OpenRA
public static Order Deserialize(World world, BinaryReader r)
{
switch (r.ReadByte())
var magic = r.ReadByte();
switch (magic)
{
case 0xFF:
{
@@ -98,7 +99,10 @@ namespace OpenRA
}
default:
throw new NotImplementedException();
{
Log.Write("debug", "Received unknown order with magic {0}", magic);
return null;
}
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Network
public int LocalFrameNumber;
public int FramesAhead = 0;
public int LastTickTime = Game.RunTime;
public long LastTickTime = Game.RunTime;
public bool GameStarted { get { return NetFrameNumber != 0; } }
public IConnection Connection { get; private set; }

View File

@@ -135,9 +135,9 @@ namespace OpenRA.Network
public class ClientPing
{
public int Index;
public int Latency = -1;
public int LatencyJitter = -1;
public int[] LatencyHistory = { };
public long Latency = -1;
public long LatencyJitter = -1;
public long[] LatencyHistory = { };
public static ClientPing Deserialize(MiniYaml data)
{

View File

@@ -18,6 +18,7 @@ using OpenRA.Primitives;
namespace OpenRA.Network
{
using System.Globalization;
using NamesValuesPair = Pair<string[], object[]>;
class SyncReport
@@ -92,11 +93,15 @@ namespace OpenRA.Network
internal void DumpSyncReport(int frame, IEnumerable<FrameData.ClientOrder> orders)
{
var reportName = "syncreport-" + DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture) + ".log";
Log.AddChannel("sync", reportName);
foreach (var r in syncReports)
{
if (r.Frame == frame)
{
var mod = Game.ModData.Manifest.Metadata;
Log.AddChannel("sync", "syncreport.log");
Log.Write("sync", "Player: {0} ({1} {2} {3})", Game.Settings.Player.Name, Platform.CurrentPlatform, Environment.OSVersion, Platform.RuntimeVersion);
Log.Write("sync", "Game ID: {0} (Mod: {1} at Version {2})", orderManager.LobbyInfo.GlobalSettings.GameUid, mod.Title, mod.Version);
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);

View File

@@ -39,8 +39,8 @@ namespace OpenRA
var kernelName = p.StandardOutput.ReadToEnd();
if (kernelName.Contains("Darwin"))
return PlatformType.OSX;
else
return PlatformType.Linux;
return PlatformType.Linux;
}
catch { }
@@ -82,7 +82,6 @@ namespace OpenRA
case PlatformType.OSX:
dir += "/Library/Application Support/OpenRA";
break;
case PlatformType.Linux:
default:
dir += "/.openra";
break;
@@ -101,12 +100,15 @@ namespace OpenRA
{
path = path.TrimEnd(new char[] { ' ', '\t' });
// paths starting with ^ are relative to the support dir
if (path.StartsWith("^"))
// Paths starting with ^ are relative to the support dir
if (path.StartsWith("^", StringComparison.Ordinal))
path = SupportDir + path.Substring(1);
// paths starting with . are relative to the game dir
if (path.StartsWith("./") || path.StartsWith(".\\"))
// Paths starting with . are relative to the game dir
if (path == ".")
return GameDir;
if (path.StartsWith("./", StringComparison.Ordinal) || path.StartsWith(".\\", StringComparison.Ordinal))
path = GameDir + path.Substring(2);
return path;
@@ -121,10 +123,10 @@ namespace OpenRA
/// <summary>Replace the full path prefix with the special notation characters ^ or .</summary>
public static string UnresolvePath(string path)
{
if (path.StartsWith(SupportDir))
if (path.StartsWith(SupportDir, StringComparison.Ordinal))
path = "^" + path.Substring(SupportDir.Length);
if (path.StartsWith(GameDir))
if (path.StartsWith(GameDir, StringComparison.Ordinal))
path = "./" + path.Substring(GameDir.Length);
return path;

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Primitives
{
readonly List<DelayedAction> actions = new List<DelayedAction>();
public void Add(Action a, int desiredTime)
public void Add(Action a, long desiredTime)
{
if (a == null)
throw new ArgumentNullException("a");
@@ -34,7 +34,7 @@ namespace OpenRA.Primitives
}
}
public void PerformActions(int currentTime)
public void PerformActions(long currentTime)
{
DelayedAction[] pendingActions;
lock (actions)
@@ -67,10 +67,10 @@ namespace OpenRA.Primitives
struct DelayedAction : IComparable<DelayedAction>
{
public readonly int Time;
public readonly long Time;
public readonly Action Action;
public DelayedAction(Action action, int time)
public DelayedAction(Action action, long time)
{
Action = action;
Time = time;

View File

@@ -26,9 +26,9 @@ namespace OpenRA.Server
public int Frame = 0;
public int MostRecentFrame = 0;
public int TimeSinceLastResponse { get { return Game.RunTime - lastReceivedTime; } }
public long TimeSinceLastResponse { get { return Game.RunTime - lastReceivedTime; } }
public bool TimeoutMessageShown = false;
int lastReceivedTime = 0;
long lastReceivedTime = 0;
/* client data */
public int PlayerIndex;

View File

@@ -152,6 +152,7 @@ namespace OpenRA.Server
Map = settings.Map,
ServerName = settings.Name,
EnableSingleplayer = settings.EnableSingleplayer || !dedicated,
GameUid = Guid.NewGuid().ToString()
}
};
@@ -185,17 +186,21 @@ namespace OpenRA.Server
foreach (var s in checkRead)
{
if (s == listener.Server)
{
AcceptConnection();
else if (PreConns.Count > 0)
{
var p = PreConns.SingleOrDefault(c => c.Socket == s);
if (p != null) p.ReadData(this);
continue;
}
else if (Conns.Count > 0)
var preConn = PreConns.SingleOrDefault(c => c.Socket == s);
if (preConn != null)
{
var conn = Conns.SingleOrDefault(c => c.Socket == s);
if (conn != null) conn.ReadData(this);
preConn.ReadData(this);
continue;
}
var conn = Conns.SingleOrDefault(c => c.Socket == s);
if (conn != null)
conn.ReadData(this);
}
foreach (var t in serverTraits.WithInterface<ITick>())
@@ -501,8 +506,8 @@ namespace OpenRA.Server
break;
case "Pong":
{
int pingSent;
if (!OpenRA.Exts.TryParseIntegerInvariant(so.Data, out pingSent))
long pingSent;
if (!OpenRA.Exts.TryParseInt64Invariant(so.Data, out pingSent))
{
Log.Write("server", "Invalid order pong payload: {0}", so.Data);
break;
@@ -563,6 +568,7 @@ namespace OpenRA.Server
DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize());
LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex);
// Client was the server admin
// TODO: Reassign admin for game in progress via an order

View File

@@ -76,6 +76,7 @@ namespace OpenRA
public void Initialize(ISoundLoader[] loaders, IReadOnlyFileSystem fileSystem)
{
sounds = new Cache<string, ISoundSource>(s => LoadSound(loaders, fileSystem, s));
currentSounds = new Dictionary<uint, ISound>();
music = null;
currentMusic = null;
video = null;

View File

@@ -11,6 +11,7 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -48,7 +49,8 @@ namespace OpenRA
static void FatalError(Exception e)
{
Log.AddChannel("exception", "exception.log");
var exceptionName = "exception-" + DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture) + ".log";
Log.AddChannel("exception", exceptionName);
if (Game.ModData != null)
{

View File

@@ -91,11 +91,13 @@ namespace OpenRA
var ax = Math.Abs(x);
// Find the closest angle that satisfies y = x*tan(theta)
var bestVal = int.MaxValue;
// Uses a long to store bestVal to eliminate integer overflow issues in the common cases
// (may still fail for unrealistically large ax and ay)
var bestVal = long.MaxValue;
var bestAngle = 0;
for (var i = 0; i < 256; i += stride)
{
var val = Math.Abs(1024 * ay - ax * TanTable[i]);
var val = Math.Abs(1024 * ay - (long)ax * TanTable[i]);
if (val < bestVal)
{
bestVal = val;

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Widgets
{
public static Widget Root = new RootWidget();
public static int LastTickTime = Game.RunTime;
public static long LastTickTime = Game.RunTime;
static readonly Stack<Widget> WindowList = new Stack<Widget>();

View File

@@ -964,8 +964,12 @@ namespace OpenRA.Mods.Common.AI
if (!mcv.IsIdle)
continue;
// If we lack a base, we need to make sure we don't restrict deployment of the MCV to the base!
var restrictToBase =
Info.RestrictMCVDeploymentFallbackToBase &&
CountBuildingByCommonName(Info.BuildingCommonNames.ConstructionYard, Player) > 0;
var factType = mcv.Info.TraitInfo<TransformsInfo>().IntoActor;
var desiredLocation = ChooseBuildLocation(factType, Info.RestrictMCVDeploymentFallbackToBase, BuildingType.Building);
var desiredLocation = ChooseBuildLocation(factType, restrictToBase, BuildingType.Building);
if (desiredLocation == null)
continue;

View File

@@ -0,0 +1,32 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class AllowYieldingReservation : Activity
{
readonly Aircraft aircraft;
public AllowYieldingReservation(Actor self)
{
aircraft = self.Trait<Aircraft>();
}
public override Activity Tick(Actor self)
{
aircraft.AllowYieldingReservation();
return NextActivity;
}
}
}

View File

@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Activities
// TODO: This should check whether there is ammo left that is actually suitable for the target
if (ammoPools.All(x => !x.Info.SelfReloads && !x.HasAmmo()))
return ActivityUtils.SequenceActivities(new ReturnToBase(self), this);
return ActivityUtils.SequenceActivities(new ReturnToBase(self, aircraft.Info.AbortOnResupply), this);
if (attackPlane != null)
attackPlane.DoAttack(self, target);

View File

@@ -60,14 +60,14 @@ namespace OpenRA.Mods.Common.Activities
{
var newTarget = Target.FromCell(self.World, self.World.Map.CellContaining(target.CenterPosition));
self.CancelActivity();
Cancel(self);
self.SetTargetLine(newTarget, Color.Green);
return ActivityUtils.SequenceActivities(new HeliFly(self, newTarget));
return new HeliFly(self, newTarget);
}
// If any AmmoPool is depleted and no weapon is valid against target, return to helipad to reload and then resume the activity
if (ammoPools.Any(x => !x.Info.SelfReloads && !x.HasAmmo()) && !attackHeli.HasAnyValidWeapons(target))
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self), this);
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, helicopter.Info.AbortOnResupply), this);
var dist = target.CenterPosition - self.CenterPosition;

View File

@@ -19,10 +19,14 @@ namespace OpenRA.Mods.Common.Activities
public class HeliReturnToBase : Activity
{
readonly Aircraft heli;
readonly bool alwaysLand;
readonly bool abortOnResupply;
public HeliReturnToBase(Actor self)
public HeliReturnToBase(Actor self, bool abortOnResupply, bool alwaysLand = true)
{
heli = self.Trait<Aircraft>();
this.alwaysLand = alwaysLand;
this.abortOnResupply = abortOnResupply;
}
public Actor ChooseHelipad(Actor self)
@@ -68,17 +72,36 @@ namespace OpenRA.Mods.Common.Activities
}
}
heli.MakeReservation(dest);
var exit = dest.Info.TraitInfos<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffset : WVec.Zero;
if (ShouldLandAtBuilding(self, dest))
{
heli.MakeReservation(dest);
return ActivityUtils.SequenceActivities(
new HeliFly(self, Target.FromPos(dest.CenterPosition + offset)),
new Turn(self, initialFacing),
new HeliLand(self, false),
new ResupplyAircraft(self),
!abortOnResupply ? NextActivity : null);
}
return ActivityUtils.SequenceActivities(
new HeliFly(self, Target.FromPos(dest.CenterPosition + offset)),
new Turn(self, initialFacing),
new HeliLand(self, false),
new ResupplyAircraft(self),
NextActivity);
}
bool ShouldLandAtBuilding(Actor self, Actor dest)
{
if (alwaysLand)
return true;
if (heli.Info.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
return true;
return heli.Info.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing<AmmoPool>()
.Any(p => !p.Info.SelfReloads && !p.FullAmmo());
}
}
}

View File

@@ -42,16 +42,18 @@ namespace OpenRA.Mods.Common.Activities
{
inner = ActivityUtils.SequenceActivities(
aircraft.GetResupplyActivities(host)
.Append(new CallFunc(() => aircraft.MayYieldReservation = true))
.Append(new AllowYieldingReservation(self))
.Append(new WaitFor(() => NextActivity != null || aircraft.ReservedActor == null))
.ToArray());
}
else
{
// Helicopters should take off from their helipad immediately after resupplying.
// HACK: NextActivity needs to be appended here because otherwise TakeOff does stupid things.
// HACK: Append NextActivity to TakeOff to avoid moving to the Rallypoint (if NextActivity is non-null).
inner = ActivityUtils.SequenceActivities(
aircraft.GetResupplyActivities(host).Append(new TakeOff(self)).Append(NextActivity).ToArray());
aircraft.GetResupplyActivities(host)
.Append(new AllowYieldingReservation(self))
.Append(new TakeOff(self)).Append(NextActivity).ToArray());
}
}
else

View File

@@ -22,13 +22,17 @@ namespace OpenRA.Mods.Common.Activities
{
readonly Aircraft plane;
readonly AircraftInfo planeInfo;
readonly bool alwaysLand;
readonly bool abortOnResupply;
bool isCalculated;
Actor dest;
WPos w1, w2, w3;
public ReturnToBase(Actor self, Actor dest = null)
public ReturnToBase(Actor self, bool abortOnResupply, Actor dest = null, bool alwaysLand = true)
{
this.dest = dest;
this.alwaysLand = alwaysLand;
this.abortOnResupply = abortOnResupply;
plane = self.Trait<Aircraft>();
planeInfo = self.Info.TraitInfo<AircraftInfo>();
}
@@ -51,8 +55,6 @@ namespace OpenRA.Mods.Common.Activities
if (dest == null)
return;
plane.MakeReservation(dest);
var landPos = dest.CenterPosition;
var altitude = planeInfo.CruiseAltitude.Length;
@@ -94,6 +96,18 @@ namespace OpenRA.Mods.Common.Activities
isCalculated = true;
}
bool ShouldLandAtBuilding(Actor self, Actor dest)
{
if (alwaysLand)
return true;
if (planeInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
return true;
return planeInfo.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing<AmmoPool>()
.Any(p => !p.Info.SelfReloads && !p.FullAmmo());
}
public override Activity Tick(Actor self)
{
if (IsCanceled || self.IsDead)
@@ -112,7 +126,11 @@ namespace OpenRA.Mods.Common.Activities
new FlyCircleTimed(self, plane.Info.NumberOfTicksToVerifyAvailableAirport),
this);
else
{
// Prevent an infinite loop in case we'd return to the activity that called ReturnToBase in the first place. Go idle instead.
Cancel(self);
return NextActivity;
}
}
List<Activity> landingProcedures = new List<Activity>();
@@ -124,9 +142,17 @@ namespace OpenRA.Mods.Common.Activities
// Fix a problem when the airplane is send to resupply near the airport
landingProcedures.Add(new Fly(self, Target.FromPos(w3), WDist.Zero, new WDist(turnRadius / 2)));
landingProcedures.Add(new Land(self, Target.FromActor(dest)));
landingProcedures.Add(new ResupplyAircraft(self));
landingProcedures.Add(NextActivity);
if (ShouldLandAtBuilding(self, dest))
{
plane.MakeReservation(dest);
landingProcedures.Add(new Land(self, Target.FromActor(dest)));
landingProcedures.Add(new ResupplyAircraft(self));
}
if (!abortOnResupply)
landingProcedures.Add(NextActivity);
return ActivityUtils.SequenceActivities(landingProcedures.ToArray());
}

View File

@@ -28,9 +28,6 @@ namespace OpenRA.Mods.Common.Activities
public override Activity Tick(Actor self)
{
if (NextActivity == null)
self.CancelActivity();
aircraft.UnReserve();
var host = aircraft.GetActorBelow();

View File

@@ -59,9 +59,8 @@ namespace OpenRA.Mods.Common.Activities
if (!pool.GiveAmmo())
continue;
var wsb = hostBuilding.Trait<WithSpriteBody>();
if (wsb.DefaultAnimation.HasSequence("active"))
wsb.PlayCustomAnimation(hostBuilding, "active", () => wsb.CancelCustomAnimation(hostBuilding));
foreach (var host in hostBuilding.TraitsImplementing<INotifyRearm>())
host.Rearming(hostBuilding, self);
var sound = pool.Info.RearmSound;
if (sound != null)

View File

@@ -19,15 +19,22 @@ namespace OpenRA.Mods.Common.Activities
public class Repair : Activity
{
readonly RepairsUnitsInfo repairsUnits;
readonly Actor host;
readonly Target host;
readonly WDist closeEnough;
int remainingTicks;
Health health;
bool played = false;
public Repair(Actor host)
public Repair(Actor self, Actor host)
: this(self, host, WDist.Zero) { }
public Repair(Actor self, Actor host, WDist closeEnough)
{
this.host = host;
this.host = Target.FromActor(host);
this.closeEnough = closeEnough;
repairsUnits = host.Info.TraitInfo<RepairsUnitsInfo>();
health = self.TraitOrDefault<Health>();
}
public override Activity Tick(Actor self)
@@ -40,18 +47,17 @@ namespace OpenRA.Mods.Common.Activities
return this;
}
if (host == null || !host.IsInWorld)
if (host.Type == TargetType.Invalid || health == null)
return NextActivity;
health = self.TraitOrDefault<Health>();
if (health == null)
if (closeEnough.LengthSquared > 0 && !host.IsInRange(self.CenterPosition, closeEnough))
return NextActivity;
if (health.DamageState == DamageState.Undamaged)
{
if (host.Owner != self.Owner)
if (host.Actor.Owner != self.Owner)
{
var exp = host.Owner.PlayerActor.TraitOrDefault<PlayerExperience>();
var exp = host.Actor.Owner.PlayerActor.TraitOrDefault<PlayerExperience>();
if (exp != null)
exp.GiveExperience(repairsUnits.PlayerExperience);
}
@@ -80,8 +86,8 @@ namespace OpenRA.Mods.Common.Activities
self.InflictDamage(self, new Damage(-hpToRepair));
foreach (var depot in host.TraitsImplementing<INotifyRepair>())
depot.Repairing(host, self);
foreach (var depot in host.Actor.TraitsImplementing<INotifyRepair>())
depot.Repairing(host.Actor, self);
remainingTicks = repairsUnits.Interval;
}

View File

@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Effects
public IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr)
{
if (wr.World.FogObscures(pos))
if (wr.World.FogObscures(pos) || wr.World.ShroudObscures(pos))
yield break;
// Arbitrary large value used for the z-offset to try and ensure the text displays above everything else.

View File

@@ -77,7 +77,13 @@ namespace OpenRA.Mods.Common.LoadScreens
// Load a replay directly
if (!string.IsNullOrEmpty(Launch.Replay))
{
var replayMeta = ReplayMetadata.Read(Launch.Replay);
ReplayMetadata replayMeta = null;
try
{
replayMeta = ReplayMetadata.Read(Launch.Replay);
}
catch { }
if (ReplayUtils.PromptConfirmReplayCompatibility(replayMeta, Game.LoadShellMap))
Game.JoinReplay(Launch.Replay);

View File

@@ -83,6 +83,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Activities\Air\AllowYieldingReservation.cs" />
<Compile Include="Activities\Air\FallToEarth.cs" />
<Compile Include="Activities\Air\Fly.cs" />
<Compile Include="Activities\Air\FlyAttack.cs" />
@@ -453,6 +454,7 @@
<Compile Include="Traits\Render\WithParachute.cs" />
<Compile Include="Traits\Render\WithRangeCircle.cs" />
<Compile Include="Traits\Render\WithRankDecoration.cs" />
<Compile Include="Traits\Render\WithRearmAnimation.cs" />
<Compile Include="Traits\Render\WithRepairAnimation.cs" />
<Compile Include="Traits\Render\WithRepairOverlay.cs" />
<Compile Include="Traits\Render\WithResources.cs" />
@@ -559,6 +561,7 @@
<Compile Include="UtilityCommands\ExtractSettingsDocsCommand.cs" />
<Compile Include="UtilityCommands\ExtractTraitDocsCommand.cs" />
<Compile Include="Widgets\Logic\Ingame\MusicControllerLogic.cs" />
<Compile Include="Widgets\UnitCommandWidget.cs" />
<Compile Include="WorldExtensions.cs" />
<Compile Include="UtilityCommands\GetMapHashCommand.cs" />
<Compile Include="UtilityCommands\Glob.cs" />

View File

@@ -19,7 +19,9 @@ namespace OpenRA.Mods.Common.Orders
public IEnumerable<Order> Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
{
world.CancelInputMode();
yield return new Order("PlaceBeacon", world.LocalPlayer.PlayerActor, false) { TargetLocation = cell, SuppressVisualFeedback = true };
if (mi.Button == MouseButton.Left)
yield return new Order("PlaceBeacon", world.LocalPlayer.PlayerActor, false) { TargetLocation = cell, SuppressVisualFeedback = true };
}
public virtual void Tick(World world) { }

View File

@@ -86,6 +86,8 @@ namespace OpenRA.Mods.Common.Projectiles
{
if (hitanim != null)
hitanim.PlayThen(info.HitAnimSequence, () => animationComplete = true);
else
animationComplete = true;
args.Weapon.Impact(Target.FromPos(target), args.SourceActor, args.DamageModifiers);
doneDamage = true;

View File

@@ -396,7 +396,7 @@ namespace OpenRA.Mods.Common.Projectiles
if ((tp.Actor.CenterPosition - pos).HorizontalLengthSquared > tp.Trait.Range.LengthSquared)
return false;
if (!tp.Actor.Owner.Stances[args.SourceActor.Owner].HasStance(tp.Trait.DeflectionStances))
if (!tp.Trait.DeflectionStances.HasStance(tp.Actor.Owner.Stances[args.SourceActor.Owner]))
return false;
return tp.Actor.World.SharedRandom.Next(100 / tp.Trait.Chance) == 0;

View File

@@ -42,9 +42,9 @@ namespace OpenRA.Mods.Common.Scripting
public void ReturnToBase(Actor airfield = null)
{
if (isPlane)
Self.QueueActivity(new ReturnToBase(Self, airfield));
Self.QueueActivity(new ReturnToBase(Self, false, airfield));
else
Self.QueueActivity(new HeliReturnToBase(Self));
Self.QueueActivity(new HeliReturnToBase(Self, false));
}
[ScriptActorPropertyActivity]

View File

@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Scripting
public void Attack(Actor targetActor, bool allowMove = true, bool forceAttack = false)
{
var target = Target.FromActor(targetActor);
if (!target.IsValidFor(Self) || target.Type == TargetType.FrozenActor)
if (!target.IsValidFor(Self))
Log.Write("lua", "{1} is an invalid target for {0}!", Self, targetActor);
if (!targetActor.Info.HasTraitInfo<FrozenUnderFogInfo>() && !Self.Owner.CanTargetActor(targetActor))
@@ -98,5 +98,11 @@ namespace OpenRA.Mods.Common.Scripting
attackBase.AttackTarget(target, true, allowMove, forceAttack);
}
[Desc("Checks if the targeted actor is a valid target for this actor.")]
public bool CanTarget(Actor targetActor)
{
return Target.FromActor(targetActor).IsValidFor(Self);
}
}
}

View File

@@ -407,6 +407,10 @@ namespace OpenRA.Mods.Common.Server
server.SendMessage(server.TwoHumansRequiredText);
else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
server.SendMessage("Bots have been disabled on this map.");
var briefing = MissionBriefingOrDefault(server);
if (briefing != null)
server.SendMessage(briefing);
};
Action queryFailed = () =>
@@ -817,8 +821,8 @@ namespace OpenRA.Mods.Common.Server
if (o.Id == "gamespeed")
{
var speed = server.ModData.Manifest.Get<GameSpeeds>().Speeds[value];
server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep;
server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency;
gs.Timestep = speed.Timestep;
gs.OrderLatency = speed.OrderLatency;
}
}
}
@@ -842,6 +846,15 @@ namespace OpenRA.Mods.Common.Server
return validator.MakeValid(askColor.RGB, server.Random, terrainColors, playerColors, onError);
}
static string MissionBriefingOrDefault(S server)
{
var missionData = server.Map.Rules.Actors["world"].TraitInfoOrDefault<MissionDataInfo>();
if (missionData != null && !string.IsNullOrEmpty(missionData.Briefing))
return missionData.Briefing.Replace("\\n", "\n");
return null;
}
public void ClientJoined(S server, Connection conn)
{
var client = server.GetClient(conn);
@@ -849,6 +862,13 @@ namespace OpenRA.Mods.Common.Server
// Validate whether color is allowed and get an alternative if it isn't
if (client.Slot == null || !server.LobbyInfo.Slots[client.Slot].LockColor)
client.Color = SanitizePlayerColor(server, client.Color, client.Index);
// Report any custom map details
// HACK: this isn't the best place for this to live, but if we move it somewhere else
// then we need a larger hack to hook the map change event.
var briefing = MissionBriefingOrDefault(server);
if (briefing != null)
server.SendOrderTo(conn, "Message", briefing);
}
public PlayerReference PlayerReferenceForSlot(S server, Session.Slot slot)

View File

@@ -35,8 +35,10 @@ namespace OpenRA.Mods.Common.Server
foreach (var kv in server.LobbyInfo.GlobalSettings.LobbyOptions)
{
Session.LobbyOptionState def;
LobbyOption option;
if (!defaults.LobbyOptions.TryGetValue(kv.Key, out def) || kv.Value.Value != def.Value)
server.SendOrderTo(conn, "Message", options[kv.Key].Name + ": " + kv.Value.Value);
if (options.TryGetValue(kv.Key, out option))
server.SendOrderTo(conn, "Message", option.Name + ": " + kv.Value.Value);
}
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Server
public void GameStarted(S server) { PingMasterServer(server); }
public void GameEnded(S server) { PingMasterServer(server); }
int lastPing = 0;
long lastPing = 0;
bool isInitialPing = true;
volatile bool isBusy;

View File

@@ -24,8 +24,8 @@ namespace OpenRA.Mods.Common.Server
// TickTimeout is in microseconds
public int TickTimeout { get { return PingInterval * 100; } }
int lastPing = 0;
int lastConnReport = 0;
long lastPing = 0;
long lastConnReport = 0;
bool isInitialPing = true;
public void Tick(S server)

View File

@@ -69,6 +69,9 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Does this actor need to turn before landing?")]
public readonly bool TurnToLand = false;
[Desc("Does this actor cancel its previous activity after resupplying?")]
public readonly bool AbortOnResupply = true;
public readonly WDist LandAltitude = WDist.Zero;
[Desc("How fast this actor ascends or descends when using horizontal take off/landing.")]
@@ -111,7 +114,7 @@ namespace OpenRA.Mods.Common.Traits
public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } }
public int TurnSpeed { get { return Info.TurnSpeed; } }
public Actor ReservedActor { get; private set; }
public bool MayYieldReservation;
public bool MayYieldReservation { get; private set; }
bool airborne;
bool cruising;
@@ -282,6 +285,14 @@ namespace OpenRA.Mods.Common.Traits
}
}
public void AllowYieldingReservation()
{
if (reservation == null)
return;
MayYieldReservation = true;
}
public void UnReserve()
{
if (reservation == null)
@@ -341,7 +352,7 @@ namespace OpenRA.Mods.Common.Traits
if (Info.RearmBuildings.Contains(name))
yield return new Rearm(self);
if (Info.RepairBuildings.Contains(name))
yield return new Repair(a);
yield return new Repair(self, a);
}
public void ModifyDeathActorInit(Actor self, TypeDictionary init)
@@ -551,9 +562,9 @@ namespace OpenRA.Mods.Common.Traits
if (Reservable.IsReserved(order.TargetActor))
{
if (IsPlane)
self.QueueActivity(new ReturnToBase(self));
self.QueueActivity(new ReturnToBase(self, Info.AbortOnResupply));
else
self.QueueActivity(new HeliReturnToBase(self));
self.QueueActivity(new HeliReturnToBase(self, Info.AbortOnResupply));
}
else
{
@@ -562,7 +573,7 @@ namespace OpenRA.Mods.Common.Traits
if (IsPlane)
{
self.QueueActivity(order.Queued, ActivityUtils.SequenceActivities(
new ReturnToBase(self, order.TargetActor),
new ReturnToBase(self, Info.AbortOnResupply, order.TargetActor),
new ResupplyAircraft(self)));
}
else
@@ -610,11 +621,9 @@ namespace OpenRA.Mods.Common.Traits
UnReserve();
self.CancelActivity();
if (IsPlane)
self.QueueActivity(new ReturnToBase(self));
self.QueueActivity(new ReturnToBase(self, Info.AbortOnResupply, null, false));
else
self.QueueActivity(new HeliReturnToBase(self));
self.QueueActivity(new ResupplyAircraft(self));
self.QueueActivity(new HeliReturnToBase(self, Info.AbortOnResupply, false));
}
}

View File

@@ -47,8 +47,8 @@ namespace OpenRA.Mods.Common.Traits
public void Tick(Actor self)
{
var cp = self.CenterPosition;
var bombTarget = Target.FromPos(cp - new WVec(0, 0, cp.Z));
var bombHeight = self.World.Map.DistanceAboveTerrain(self.CenterPosition);
var bombTarget = Target.FromPos(self.CenterPosition - new WVec(WDist.Zero, WDist.Zero, bombHeight));
var wasInAttackRange = inAttackRange;
var wasFacingTarget = facingTarget;
@@ -77,9 +77,11 @@ namespace OpenRA.Mods.Common.Traits
if (!target.IsInRange(self.CenterPosition, a.MaxRange()))
continue;
var t = Target.FromPos(cp - new WVec(0, a.MaxRange().Length / 2, cp.Z).Rotate(WRot.FromFacing(f)));
inAttackRange = true;
a.CheckFire(self, facing.Value, t);
var gunPos = self.CenterPosition - new WVec(0, a.MaxRange().Length / 2, 0).Rotate(WRot.FromFacing(f));
var gunHeight = self.World.Map.DistanceAboveTerrain(gunPos);
a.CheckFire(self, facing.Value, Target.FromPos(gunPos - new WVec(WDist.Zero, WDist.Zero, gunHeight)));
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits
var airfield = ReturnToBase.ChooseAirfield(self, true);
if (airfield != null)
{
self.QueueActivity(new ReturnToBase(self, airfield));
self.QueueActivity(new ReturnToBase(self, aircraftInfo.AbortOnResupply, airfield));
self.QueueActivity(new ResupplyAircraft(self));
}
else

View File

@@ -65,7 +65,7 @@ namespace OpenRA.Mods.Common.Traits.Render
Color GetColor()
{
return self.EffectiveOwner != null ? self.EffectiveOwner.Owner.Color.RGB : self.Owner.Color.RGB;
return self.EffectiveOwner != null && self.EffectiveOwner.Disguised ? self.EffectiveOwner.Owner.Color.RGB : self.Owner.Color.RGB;
}
IEnumerable<IRenderable> IRenderAboveShroudWhenSelected.RenderAboveShroud(Actor self, WorldRenderer wr)

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
@@ -27,16 +28,16 @@ namespace OpenRA.Mods.Common.Traits.Render
public readonly WDist FallbackRange = WDist.Zero;
// Computed range
WDist range;
Lazy<WDist> range;
public IEnumerable<IRenderable> Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition)
{
if (range == WDist.Zero)
if (range == null || range.Value == WDist.Zero)
return SpriteRenderable.None;
var localRange = new RangeCircleRenderable(
centerPosition,
range,
range.Value,
0,
Color.FromArgb(128, Color.Yellow),
Color.FromArgb(96, Color.Black));
@@ -52,12 +53,16 @@ namespace OpenRA.Mods.Common.Traits.Render
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
var armaments = ai.TraitInfos<ArmamentInfo>().Where(a => a.UpgradeMinEnabledLevel == 0);
// ArmamentInfo.ModifiedRange is set by RulesetLoaded, and may not have been initialized yet.
// Defer this lookup until we really need it to ensure we get the correct value.
range = Exts.Lazy(() =>
{
var armaments = ai.TraitInfos<ArmamentInfo>().Where(a => a.UpgradeMinEnabledLevel == 0);
if (!armaments.Any())
return FallbackRange;
if (armaments.Any())
range = armaments.Select(a => a.ModifiedRange).Max();
else
range = FallbackRange;
return armaments.Max(a => a.ModifiedRange);
});
}
}

View File

@@ -55,7 +55,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithDecoration(init.Self, this); }
}
public class WithDecoration : UpgradableTrait<WithDecorationInfo>, ITick, IRender, IRenderAboveShroudWhenSelected
public class WithDecoration : UpgradableTrait<WithDecorationInfo>, ITick, IRenderAboveShroud, IRenderAboveShroudWhenSelected
{
protected readonly Animation Anim;
@@ -69,9 +69,19 @@ namespace OpenRA.Mods.Common.Traits.Render
Anim.PlayRepeating(info.Sequence);
}
public virtual bool ShouldRender(Actor self) { return true; }
protected virtual bool ShouldRender(Actor self)
{
if (self.World.RenderPlayer != null)
{
var stance = self.Owner.Stances[self.World.RenderPlayer];
if (!Info.ValidStances.HasStance(stance))
return false;
}
IEnumerable<IRenderable> IRender.Render(Actor self, WorldRenderer wr)
return true;
}
IEnumerable<IRenderable> IRenderAboveShroud.RenderAboveShroud(Actor self, WorldRenderer wr)
{
return !Info.RequiresSelection ? RenderInner(self, wr) : SpriteRenderable.None;
}
@@ -86,13 +96,6 @@ namespace OpenRA.Mods.Common.Traits.Render
if (IsTraitDisabled || self.IsDead || !self.IsInWorld || Anim == null)
return Enumerable.Empty<IRenderable>();
if (self.World.RenderPlayer != null)
{
var stance = self.Owner.Stances[self.World.RenderPlayer];
if (!Info.ValidStances.HasStance(stance))
return Enumerable.Empty<IRenderable>();
}
if (!ShouldRender(self) || self.World.FogObscures(self))
return Enumerable.Empty<IRenderable>();

View File

@@ -0,0 +1,57 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
{
[Desc("Replaces the building animation when it rearms a unit.")]
public class WithRearmAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo>
{
[Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "active";
public readonly bool PauseOnLowPower = false;
public object Create(ActorInitializer init) { return new WithRearmAnimation(init.Self, this); }
}
public class WithRearmAnimation : INotifyRearm, INotifyBuildComplete, INotifySold
{
readonly WithRearmAnimationInfo info;
readonly WithSpriteBody spriteBody;
bool buildComplete;
public WithRearmAnimation(Actor self, WithRearmAnimationInfo info)
{
this.info = info;
spriteBody = self.TraitOrDefault<WithSpriteBody>();
}
void INotifyRearm.Rearming(Actor self, Actor target)
{
if (buildComplete && spriteBody != null && !(info.PauseOnLowPower && self.IsDisabled()))
spriteBody.PlayCustomAnimation(self, info.Sequence, () => spriteBody.CancelCustomAnimation(self));
}
public void BuildingComplete(Actor self)
{
buildComplete = true;
}
public void Selling(Actor self)
{
buildComplete = false;
}
public void Sold(Actor self) { }
}
}

View File

@@ -69,33 +69,20 @@ namespace OpenRA.Mods.Common.Traits.Render
pipImages.PlayFetchIndex(Info.GroupSequence, () => (int)group);
var bounds = self.VisualBounds;
var halfSize = (0.5f * pipImages.Image.Size.XY).ToInt2();
var boundsOffset = new int2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom) / 2;
var sizeOffset = -halfSize;
var boundsOffset = 0.5f * new float2(bounds.Left + bounds.Right, bounds.Top + bounds.Bottom);
if (Info.ReferencePoint.HasFlag(ReferencePoints.Top))
{
boundsOffset -= new int2(0, bounds.Height / 2);
sizeOffset += new int2(0, halfSize.Y);
}
else if (Info.ReferencePoint.HasFlag(ReferencePoints.Bottom))
{
boundsOffset += new int2(0, bounds.Height / 2);
sizeOffset -= new int2(0, halfSize.Y);
}
boundsOffset -= new float2(0, 0.5f * bounds.Height);
if (Info.ReferencePoint.HasFlag(ReferencePoints.Bottom))
boundsOffset += new float2(0, 0.5f * bounds.Height);
if (Info.ReferencePoint.HasFlag(ReferencePoints.Left))
{
boundsOffset -= new int2(bounds.Width / 2, 0);
sizeOffset += new int2(halfSize.X, 0);
}
else if (Info.ReferencePoint.HasFlag(ReferencePoints.Right))
{
boundsOffset += new int2(bounds.Width / 2, 0);
sizeOffset -= new int2(halfSize.X, 0);
}
boundsOffset -= new float2(0.5f * bounds.Width, 0);
var pxPos = wr.Viewport.WorldToViewPx(wr.ScreenPxPosition(self.CenterPosition) + boundsOffset) + sizeOffset;
if (Info.ReferencePoint.HasFlag(ReferencePoints.Right))
boundsOffset += new float2(0.5f * bounds.Width, 0);
var pxPos = wr.Viewport.WorldToViewPx(wr.ScreenPxPosition(self.CenterPosition) + boundsOffset.ToInt2()) - (0.5f * pipImages.Image.Size.XY).ToInt2();
yield return new UISpriteRenderable(pipImages.Image, self.CenterPosition, pxPos, 0, palette, 1f);
}
}

View File

@@ -114,7 +114,7 @@ namespace OpenRA.Mods.Common.Traits
if (CanRearmAt(order.TargetActor) && CanRearm())
self.QueueActivity(new Rearm(self));
self.QueueActivity(new Repair(order.TargetActor));
self.QueueActivity(new Repair(self, order.TargetActor));
var rp = order.TargetActor.TraitOrDefault<RallyPoint>();
if (rp != null)

View File

@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Traits
self.CancelActivity();
self.QueueActivity(movement.MoveWithinRange(target, info.CloseEnough));
self.QueueActivity(new Repair(order.TargetActor));
self.QueueActivity(new Repair(self, order.TargetActor, info.CloseEnough));
self.SetTargetLine(target, Color.Green, false);
}

View File

@@ -127,11 +127,7 @@ namespace OpenRA.Mods.Common.Traits
self.World.AddFrameEndTask(w =>
{
var isAllied = self.Owner.IsAlliedWith(self.World.RenderPlayer);
Game.Sound.Play(isAllied ? Info.LaunchSound : Info.IncomingSound);
var speech = isAllied ? Info.LaunchSpeechNotification : Info.IncomingSpeechNotification;
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", speech, self.Owner.Faction.InternalName);
PlayLaunchSounds();
Actor distanceTestActor = null;
for (var i = -info.SquadSize / 2; i <= info.SquadSize / 2; i++)

View File

@@ -92,19 +92,7 @@ namespace OpenRA.Mods.Common.Traits
public override void Activate(Actor self, Order order, SupportPowerManager manager)
{
base.Activate(self, order, manager);
if (self.Owner.IsAlliedWith(self.World.RenderPlayer))
{
Game.Sound.Play(Info.LaunchSound);
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech",
Info.LaunchSpeechNotification, self.Owner.Faction.InternalName);
}
else
{
Game.Sound.Play(Info.IncomingSound);
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech",
Info.IncomingSpeechNotification, self.Owner.Faction.InternalName);
}
PlayLaunchSounds();
if (!string.IsNullOrEmpty(info.ActivationSequence))
{

View File

@@ -120,5 +120,17 @@ namespace OpenRA.Mods.Common.Traits
Info.RadarPingDuration);
}
}
public virtual void PlayLaunchSounds()
{
var renderPlayer = Self.World.RenderPlayer;
var isAllied = Self.Owner.IsAlliedWith(renderPlayer);
Game.Sound.Play(isAllied ? Info.LaunchSound : Info.IncomingSound);
// IsAlliedWith returns true if renderPlayer is null, so we are safe here.
var toPlayer = isAllied ? renderPlayer ?? Self.Owner : renderPlayer;
var speech = isAllied ? Info.LaunchSpeechNotification : Info.IncomingSpeechNotification;
Game.Sound.PlayNotification(Self.World.Map.Rules, toPlayer, "Speech", speech, toPlayer.Faction.InternalName);
}
}
}

View File

@@ -146,7 +146,7 @@ namespace OpenRA.Mods.Common.Traits
if ((!dirty.ContainsKey(loc) || dirty[loc].Sprite == null) && !tiles.ContainsKey(loc))
{
// No smudge; create a new one
var st = smudges.Keys.Random(world.SharedRandom);
var st = smudges.Keys.Random(Game.CosmeticRandom);
dirty[loc] = new Smudge { Type = st, Depth = 0, Sprite = smudges[st][0] };
}
else

View File

@@ -139,4 +139,7 @@ namespace OpenRA.Mods.Common.Traits
{
void ModifyActorPreviewInit(Actor self, TypeDictionary inits);
}
[RequireExplicitImplementation]
public interface INotifyRearm { void Rearming(Actor host, Actor other); }
}

View File

@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
.Select(m => new Map(modData, m.Package)));
}
else
maps.Add(new Map(modData, modData.ModFiles.OpenPackage(args[1])));
maps.Add(new Map(modData, modData.ModFiles.OpenPackage(args[1], new FileSystem.Folder("."))));
foreach (var testMap in maps)
{

View File

@@ -358,6 +358,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
// Add a warning to add WithRearmAnimation to actors that might need it.
// Update rule added during prep-1609 stable period, date needs fixing after release.
if (engineVersion < 20160918 && depth == 2)
{
if (node.Key == "RearmBuildings")
foreach (var host in node.Value.Value.Split(','))
Console.WriteLine("Actor type `{0}` is denoted as a RearmBuilding. Consider adding the `WithRearmAnimation` trait to it.".F(host));
}
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
}

View File

@@ -131,6 +131,21 @@ namespace OpenRA.Mods.Common.Widgets.Logic
CloseChat();
chatText.IsDisabled = () => world.IsReplay;
var keyListener = chatChrome.Get<LogicKeyListenerWidget>("KEY_LISTENER");
keyListener.OnKeyPress = e =>
{
if (e.Event == KeyInputEvent.Up || !chatText.IsDisabled())
return false;
if ((e.Key == Keycode.RETURN || e.Key == Keycode.KP_ENTER || e.Key == Keycode.ESCAPE) && e.Modifiers == Modifiers.None)
{
CloseChat();
return true;
}
return false;
};
}
bool SwitchTeamChat()
@@ -151,7 +166,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
chatText.Text = "";
chatChrome.Visible = true;
chatScrollPanel.ScrollToBottom();
chatText.TakeKeyboardFocus();
if (!chatText.IsDisabled())
chatText.TakeKeyboardFocus();
chatOverlay.Visible = false;
}

View File

@@ -171,6 +171,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
(p.PlayerActor.TraitOrDefault<PlayerStatistics>() ?? new PlayerStatistics(p.PlayerActor)).EarnedSamples.Select(s => (float)s)));
playerStatsPanel.AddChild(template);
playerStatsPanel.ScrollToTop();
}
void DisplayStats(Func<Player, ScrollItemWidget> createItem)

View File

@@ -96,6 +96,18 @@ namespace OpenRA.Mods.Common.Widgets.Logic
DetectContentDisks();
}
static bool IsValidDrive(DriveInfo d)
{
if (d.DriveType == DriveType.CDRom && d.IsReady)
return true;
// HACK: the "TFD" DVD is detected as a fixed udf-formatted drive on OSX
if (d.DriveType == DriveType.Fixed && d.DriveFormat == "udf")
return true;
return false;
}
void DetectContentDisks()
{
var message = "Detecting drives";
@@ -105,7 +117,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
new Task(() =>
{
var volumes = DriveInfo.GetDrives()
.Where(v => v.DriveType == DriveType.CDRom && v.IsReady)
.Where(IsValidDrive)
.Select(v => v.RootDirectory.FullName);
foreach (var kv in sources)

View File

@@ -24,7 +24,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
onCancel = DoNothing;
if (replayMeta == null)
return IncompatibleReplayDialog("outdated engine", null, onCancel);
{
ConfirmationDialogs.ButtonPrompt("Incompatible Replay", "Replay metadata could not be read.", onCancel: onCancel);
return false;
}
var version = replayMeta.GameInfo.Version;
if (version == null)

View File

@@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var windowModeDropdown = panel.Get<DropDownButtonWidget>("MODE_DROPDOWN");
windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, ds);
windowModeDropdown.GetText = () => ds.Mode == WindowMode.Windowed ?
"Windowed" : ds.Mode == WindowMode.Fullscreen ? "Fullscreen" : "Pseudo-Fullscreen";
"Windowed" : ds.Mode == WindowMode.Fullscreen ? "Fullscreen (Legacy)" : "Fullscreen";
var statusBarsDropDown = panel.Get<DropDownButtonWidget>("STATUS_BAR_DROPDOWN");
statusBarsDropDown.OnMouseDown = _ => ShowStatusBarsDropdown(statusBarsDropDown, gs);
@@ -748,8 +748,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
var options = new Dictionary<string, WindowMode>()
{
{ "Pseudo-Fullscreen", WindowMode.PseudoFullscreen },
{ "Fullscreen", WindowMode.Fullscreen },
{ "Fullscreen", WindowMode.PseudoFullscreen },
{ "Fullscreen (Legacy)", WindowMode.Fullscreen },
{ "Windowed", WindowMode.Windowed },
};

View File

@@ -0,0 +1,178 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Orders;
using OpenRA.Mods.Common.Traits;
using OpenRA.Orders;
using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
/// <summary> Contains all functions that are unit-specific. </summary>
public class UnitCommandWidget : Widget
{
readonly World world;
[ObjectCreator.UseCtor]
public UnitCommandWidget(World world, WorldRenderer worldRenderer)
{
this.world = world;
}
public override string GetCursor(int2 pos) { return null; }
public override Rectangle GetEventBounds() { return Rectangle.Empty; }
public override bool HandleKeyPress(KeyInput e)
{
if (world == null)
return false;
// Put all functions that are valid for observers/spectators inside WorldCommandWidget.
if (world.LocalPlayer == null || world.LocalPlayer.Spectating)
return false;
if (world.IsGameOver || !world.Selection.Actors.Any())
return false;
return ProcessInput(e);
}
bool ProcessInput(KeyInput e)
{
if (e.Event == KeyInputEvent.Down)
{
var key = Hotkey.FromKeyInput(e);
var ks = Game.Settings.Keys;
if (key == ks.AttackMoveKey)
return PerformAttackMove();
if (key == ks.StopKey)
return PerformStop();
if (key == ks.ScatterKey)
return PerformScatter();
if (key == ks.DeployKey)
return PerformDeploy();
if (key == ks.StanceCycleKey)
return PerformStanceCycle();
if (key == ks.GuardKey)
return PerformGuard();
}
return false;
}
// TODO: take ALL this garbage and route it through the OrderTargeter stuff.
bool PerformAttackMove()
{
var actors = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer)
.ToArray();
if (actors.Any(a => a.Info.HasTraitInfo<AttackMoveInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>()))
world.OrderGenerator = new GenericSelectTarget(actors,
"AttackMove", "attackmove", Game.Settings.Game.MouseButtonPreference.Action);
return true;
}
void PerformKeyboardOrderOnSelection(Func<Actor, Order> f)
{
var orders = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer && !a.Disposed)
.Select(f)
.ToArray();
foreach (var o in orders)
world.IssueOrder(o);
world.PlayVoiceForOrders(orders);
}
bool PerformStop()
{
PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false));
return true;
}
bool PerformScatter()
{
PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false));
return true;
}
bool PerformDeploy()
{
// HACK: multiple orders here
PerformKeyboardOrderOnSelection(a => new Order("ReturnToBase", a, false));
PerformKeyboardOrderOnSelection(a => new Order("DeployTransform", a, false));
PerformKeyboardOrderOnSelection(a => new Order("Unload", a, false));
PerformKeyboardOrderOnSelection(a => new Order("Detonate", a, false));
PerformKeyboardOrderOnSelection(a => new Order("DeployToUpgrade", a, false));
return true;
}
bool PerformStanceCycle()
{
var actor = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer && !a.Disposed)
.Select(a => Pair.New(a, a.TraitOrDefault<AutoTarget>()))
.FirstOrDefault(a => a.Second != null);
if (actor.First == null)
return true;
var ati = actor.First.Info.TraitInfoOrDefault<AutoTargetInfo>();
if (ati == null || !ati.EnableStances)
return false;
var stances = Enum<UnitStance>.GetValues();
var nextStance = stances.Concat(stances)
.SkipWhile(s => s != actor.Second.PredictedStance)
.Skip(1)
.First();
PerformKeyboardOrderOnSelection(a =>
{
var at = a.TraitOrDefault<AutoTarget>();
if (at != null)
at.PredictedStance = nextStance;
return new Order("SetUnitStance", a, false) { ExtraData = (uint)nextStance };
});
Game.Debug("Unit stance set to: {0}".F(nextStance));
return true;
}
bool PerformGuard()
{
var actors = world.Selection.Actors
.Where(a => !a.Disposed && a.Owner == world.LocalPlayer);
if (actors.Any(a => a.Info.HasTraitInfo<GuardInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>()))
world.OrderGenerator = new GuardOrderGenerator(actors,
"Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
return true;
}
}
}

View File

@@ -124,7 +124,7 @@ namespace OpenRA.Mods.Common.Widgets
tooltipContainer.Value.RemoveTooltip();
}
int lastScrollTime = 0;
long lastScrollTime = 0;
public override void Draw()
{
if (IsJoystickScrolling)

View File

@@ -13,15 +13,13 @@ using System;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Orders;
using OpenRA.Mods.Common.Traits;
using OpenRA.Orders;
using OpenRA.Primitives;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
/// <summary> Contains all functions that are valid for players and observers/spectators. </summary>
public class WorldCommandWidget : Widget
{
readonly World world;
@@ -65,133 +63,11 @@ namespace OpenRA.Mods.Common.Widgets
if (key == ks.ToSelectionKey)
return ToSelection();
// Put all functions that are valid for observers/spectators above this line.
if (world.LocalPlayer == null || world.LocalPlayer.Spectating)
return false;
// Put all functions that aren't unit-specific before this line!
if (!world.Selection.Actors.Any() || world.IsGameOver)
return false;
if (key == ks.AttackMoveKey)
return PerformAttackMove();
if (key == ks.StopKey)
return PerformStop();
if (key == ks.ScatterKey)
return PerformScatter();
if (key == ks.DeployKey)
return PerformDeploy();
if (key == ks.StanceCycleKey)
return PerformStanceCycle();
if (key == ks.GuardKey)
return PerformGuard();
}
return false;
}
// TODO: take ALL this garbage and route it through the OrderTargeter stuff.
bool PerformAttackMove()
{
var actors = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer)
.ToArray();
if (actors.Any(a => a.Info.HasTraitInfo<AttackMoveInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>()))
world.OrderGenerator = new GenericSelectTarget(actors,
"AttackMove", "attackmove", Game.Settings.Game.MouseButtonPreference.Action);
return true;
}
void PerformKeyboardOrderOnSelection(Func<Actor, Order> f)
{
var orders = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer && !a.Disposed)
.Select(f)
.ToArray();
foreach (var o in orders)
world.IssueOrder(o);
world.PlayVoiceForOrders(orders);
}
bool PerformStop()
{
PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false));
return true;
}
bool PerformScatter()
{
PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false));
return true;
}
bool PerformDeploy()
{
// HACK: multiple orders here
PerformKeyboardOrderOnSelection(a => new Order("ReturnToBase", a, false));
PerformKeyboardOrderOnSelection(a => new Order("DeployTransform", a, false));
PerformKeyboardOrderOnSelection(a => new Order("Unload", a, false));
PerformKeyboardOrderOnSelection(a => new Order("Detonate", a, false));
PerformKeyboardOrderOnSelection(a => new Order("DeployToUpgrade", a, false));
return true;
}
bool PerformStanceCycle()
{
var actor = world.Selection.Actors
.Where(a => a.Owner == world.LocalPlayer && !a.Disposed)
.Select(a => Pair.New(a, a.TraitOrDefault<AutoTarget>()))
.FirstOrDefault(a => a.Second != null);
if (actor.First == null)
return true;
var ati = actor.First.Info.TraitInfoOrDefault<AutoTargetInfo>();
if (ati == null || !ati.EnableStances)
return false;
var stances = Enum<UnitStance>.GetValues();
var nextStance = stances.Concat(stances)
.SkipWhile(s => s != actor.Second.PredictedStance)
.Skip(1)
.First();
PerformKeyboardOrderOnSelection(a =>
{
var at = a.TraitOrDefault<AutoTarget>();
if (at != null)
at.PredictedStance = nextStance;
return new Order("SetUnitStance", a, false) { ExtraData = (uint)nextStance };
});
Game.Debug("Unit stance set to: {0}".F(nextStance));
return true;
}
bool PerformGuard()
{
var actors = world.Selection.Actors
.Where(a => !a.Disposed && a.Owner == world.LocalPlayer);
if (actors.Any(a => a.Info.HasTraitInfo<GuardInfo>() && a.Info.HasTraitInfo<AutoTargetInfo>()))
world.OrderGenerator = new GuardOrderGenerator(actors,
"Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
return true;
}
bool CycleBases()
{
var player = world.RenderPlayer ?? world.LocalPlayer;

View File

@@ -31,9 +31,9 @@ namespace OpenRA.Mods.D2k.Traits.Render
carryable = self.Trait<Carryable>();
}
public override bool ShouldRender(Actor self)
protected override bool ShouldRender(Actor self)
{
return carryable.Reserved;
return carryable.Reserved && base.ShouldRender(self);
}
}
}

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.RA.Activities
new MoveAdjacentTo(self, Target.FromActor(rearmTarget)),
movement.MoveTo(self.World.Map.CellContaining(rearmTarget.CenterPosition), rearmTarget),
new Rearm(self),
new Repair(rearmTarget),
new Repair(self, rearmTarget),
this);
}

View File

@@ -111,7 +111,7 @@ namespace OpenRA.Mods.RA.Effects
shouldRenderIndicator = !f2.HasRenderables;
return f2.Visible && !f2.Shrouded && !toPlayer.World.ShroudObscures(self.CenterPosition);
return f2.Visible && !f2.Shrouded && toPlayer.Shroud.IsExplored(self.CenterPosition);
}
FrozenActor FrozenActorForPlayer(Player player)

View File

@@ -116,6 +116,7 @@
<Compile Include="Scripting\Properties\ParatroopersProperties.cs" />
<Compile Include="Traits\Render\WithDisguisingInfantryBody.cs" />
<Compile Include="ImportRedAlertLegacyMapCommand.cs" />
<Compile Include="Traits\Infiltration\InfiltrateForDecoration.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">

View File

@@ -0,0 +1,43 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("Reveals a decoration sprite to the indicated players when infiltrated.")]
class InfiltrateForDecorationInfo : WithDecorationInfo
{
public override object Create(ActorInitializer init) { return new InfiltrateForDecoration(init.Self, this); }
}
class InfiltrateForDecoration : WithDecoration, INotifyInfiltrated
{
readonly HashSet<Player> infiltrators = new HashSet<Player>();
public InfiltrateForDecoration(Actor self, InfiltrateForDecorationInfo info)
: base(self, info) { }
public void Infiltrated(Actor self, Actor infiltrator)
{
infiltrators.Add(infiltrator.Owner);
}
protected override bool ShouldRender(Actor self)
{
return self.World.RenderPlayer == null || infiltrators.Any(i =>
Info.ValidStances.HasStance(i.Stances[self.World.RenderPlayer]));
}
}
}

View File

@@ -153,11 +153,7 @@ namespace OpenRA.Mods.RA.Traits
self.World.AddFrameEndTask(w =>
{
var isAllied = self.Owner.IsAlliedWith(self.World.RenderPlayer);
Game.Sound.Play(isAllied ? Info.LaunchSound : Info.IncomingSound);
var speech = isAllied ? Info.LaunchSpeechNotification : Info.IncomingSpeechNotification;
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", speech, self.Owner.Faction.InternalName);
PlayLaunchSounds();
Actor distanceTestActor = null;

View File

@@ -55,20 +55,35 @@ namespace OpenRA.Platforms.Default
// Clear error bit
AL10.alGetError();
var devices = new List<string>();
var next = ALC10.alcGetString(IntPtr.Zero, type);
if (next == IntPtr.Zero || AL10.alGetError() != AL10.AL_NO_ERROR)
// Returns a null separated list of strings, terminated by two nulls.
var devicesPtr = ALC10.alcGetString(IntPtr.Zero, type);
if (devicesPtr == IntPtr.Zero || AL10.alGetError() != AL10.AL_NO_ERROR)
{
Log.Write("sound", "Failed to query OpenAL device list using {0}", label);
return new string[] { };
return new string[0];
}
do
var devices = new List<string>();
var buffer = new List<byte>();
var offset = 0;
while (true)
{
var str = Marshal.PtrToStringAuto(next);
next += Encoding.Default.GetByteCount(str) + 1;
devices.Add(str);
} while (Marshal.ReadByte(next) != 0);
var b = Marshal.ReadByte(devicesPtr, offset++);
if (b != 0)
{
buffer.Add(b);
continue;
}
// A null indicates termination of that string, so add that to our list.
devices.Add(Encoding.Default.GetString(buffer.ToArray()));
buffer.Clear();
// Two successive nulls indicates the end of the list.
if (Marshal.ReadByte(devicesPtr, offset) == 0)
break;
}
return devices.ToArray();
}

View File

@@ -41,6 +41,7 @@ Container@CHAT_PANEL:
ImageName: kick
X: 6
Y: 8
LogicKeyListener@KEY_LISTENER:
ScrollPanel@CHAT_SCROLLPANEL:
Y: PARENT_BOTTOM - HEIGHT - 30
Width: 550

View File

@@ -57,7 +57,6 @@ Container@SKIRMISH_STATS:
Y: 105
Width: 482
Height: 255
TopBottomSpacing: 5
ItemSpacing: 5
Children:
ScrollItem@TEAM_TEMPLATE:

View File

@@ -40,6 +40,9 @@ Container@INGAME_ROOT:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
TooltipContainer: TOOLTIP_CONTAINER
WorldCommand:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
Container@PLAYER_ROOT:
Container@MENU_ROOT:
TooltipContainer@TOOLTIP_CONTAINER:
@@ -232,7 +235,7 @@ Container@PLAYER_WIDGETS:
LogicKeyListener@CONTROLGROUP_KEYHANDLER:
Logic: ControlGroupLogic
LogicTicker@SIDEBAR_TICKER:
WorldCommand:
UnitCommand:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
Container@SUPPORT_POWERS:

View File

@@ -41,6 +41,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -41,6 +41,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -100,6 +100,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -109,6 +109,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -60,6 +60,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -14,7 +14,7 @@ Bounds: 4,1,58,50
Visibility: MissionSelector
Categories: Mission
Categories: Campaign
LockPreview: True
@@ -155,319 +155,319 @@ Actors:
Owner: Nod
Actor36: brik
Location: 58,19
Owner: Neutral
Owner: Nod
Actor37: brik
Location: 57,19
Owner: Neutral
Owner: Nod
Actor38: brik
Location: 56,19
Owner: Neutral
Owner: Nod
Actor39: brik
Location: 55,19
Owner: Neutral
Owner: Nod
Actor40: brik
Location: 54,19
Owner: Neutral
Owner: Nod
Actor41: brik
Location: 53,19
Owner: Neutral
Owner: Nod
Actor42: brik
Location: 52,19
Owner: Neutral
Owner: Nod
Actor43: brik
Location: 47,19
Owner: Neutral
Owner: Nod
Actor44: brik
Location: 46,19
Owner: Neutral
Owner: Nod
Actor45: brik
Location: 45,19
Owner: Neutral
Owner: Nod
Actor46: brik
Location: 44,19
Owner: Neutral
Owner: Nod
Actor47: brik
Location: 43,19
Owner: Neutral
Owner: Nod
Actor48: brik
Location: 42,19
Owner: Neutral
Owner: Nod
Actor49: brik
Location: 41,19
Owner: Neutral
Owner: Nod
Actor50: brik
Location: 40,19
Owner: Neutral
Owner: Nod
Actor51: brik
Location: 58,18
Owner: Neutral
Owner: Nod
Actor52: brik
Location: 57,18
Owner: Neutral
Owner: Nod
Actor53: brik
Location: 53,18
Owner: Neutral
Owner: Nod
Actor54: brik
Location: 52,18
Owner: Neutral
Owner: Nod
Actor55: brik
Location: 47,18
Owner: Neutral
Owner: Nod
Actor56: brik
Location: 46,18
Owner: Neutral
Owner: Nod
Actor57: brik
Location: 41,18
Owner: Neutral
Owner: Nod
Actor58: brik
Location: 40,18
Owner: Neutral
Owner: Nod
Actor59: brik
Location: 58,17
Owner: Neutral
Owner: Nod
Actor60: brik
Location: 40,17
Owner: Neutral
Owner: Nod
Actor61: brik
Location: 58,16
Owner: Neutral
Owner: Nod
Actor62: brik
Location: 40,16
Owner: Neutral
Owner: Nod
Actor63: brik
Location: 58,15
Owner: Neutral
Owner: Nod
Actor64: brik
Location: 40,15
Owner: Neutral
Owner: Nod
Actor65: brik
Location: 58,14
Owner: Neutral
Owner: Nod
Actor66: brik
Location: 41,14
Owner: Neutral
Owner: Nod
Actor67: brik
Location: 40,14
Owner: Neutral
Owner: Nod
Actor68: brik
Location: 58,13
Owner: Neutral
Owner: Nod
Actor69: brik
Location: 41,13
Owner: Neutral
Owner: Nod
Actor70: brik
Location: 40,13
Owner: Neutral
Owner: Nod
Actor71: brik
Location: 58,12
Owner: Neutral
Owner: Nod
Actor72: brik
Location: 58,11
Owner: Neutral
Owner: Nod
Actor73: brik
Location: 57,11
Owner: Neutral
Owner: Nod
Actor74: brik
Location: 58,10
Owner: Neutral
Owner: Nod
Actor75: brik
Location: 57,10
Owner: Neutral
Owner: Nod
Actor76: brik
Location: 41,10
Owner: Neutral
Owner: Nod
Actor77: brik
Location: 40,10
Owner: Neutral
Owner: Nod
Actor78: brik
Location: 41,9
Owner: Neutral
Owner: Nod
Actor79: brik
Location: 40,9
Owner: Neutral
Owner: Nod
Actor80: cycl
Location: 58,8
Owner: Neutral
Owner: Nod
Actor81: cycl
Location: 54,8
Owner: Neutral
Owner: Nod
Actor82: cycl
Location: 48,8
Owner: Neutral
Owner: Nod
Actor83: cycl
Location: 47,8
Owner: Neutral
Owner: Nod
Actor84: cycl
Location: 44,8
Owner: Neutral
Owner: Nod
Actor85: cycl
Location: 43,8
Owner: Neutral
Owner: Nod
Actor86: brik
Location: 40,8
Owner: Neutral
Owner: Nod
Actor87: brik
Location: 61,7
Owner: Neutral
Owner: Nod
Actor88: brik
Location: 60,7
Owner: Neutral
Owner: Nod
Actor89: cycl
Location: 59,7
Owner: Neutral
Owner: Nod
Actor90: cycl
Location: 58,7
Owner: Neutral
Owner: Nod
Actor91: cycl
Location: 54,7
Owner: Neutral
Owner: Nod
Actor92: cycl
Location: 53,7
Owner: Neutral
Owner: Nod
Actor93: cycl
Location: 52,7
Owner: Neutral
Owner: Nod
Actor94: cycl
Location: 51,7
Owner: Neutral
Owner: Nod
Actor95: cycl
Location: 50,7
Owner: Neutral
Owner: Nod
Actor96: cycl
Location: 49,7
Owner: Neutral
Owner: Nod
Actor97: cycl
Location: 48,7
Owner: Neutral
Owner: Nod
Actor98: cycl
Location: 43,7
Owner: Neutral
Owner: Nod
Actor99: brik
Location: 40,7
Owner: Neutral
Owner: Nod
Actor100: brik
Location: 61,6
Owner: Neutral
Owner: Nod
Actor101: brik
Location: 60,6
Owner: Neutral
Owner: Nod
Actor102: cycl
Location: 48,6
Owner: Neutral
Owner: Nod
Actor103: cycl
Location: 43,6
Owner: Neutral
Owner: Nod
Actor104: brik
Location: 40,6
Owner: Neutral
Owner: Nod
Actor105: brik
Location: 61,5
Owner: Neutral
Owner: Nod
Actor106: cycl
Location: 48,5
Owner: Neutral
Owner: Nod
Actor107: cycl
Location: 47,5
Owner: Neutral
Owner: Nod
Actor108: cycl
Location: 46,5
Owner: Neutral
Owner: Nod
Actor109: cycl
Location: 45,5
Owner: Neutral
Owner: Nod
Actor110: cycl
Location: 44,5
Owner: Neutral
Owner: Nod
Actor111: cycl
Location: 43,5
Owner: Neutral
Owner: Nod
Actor112: brik
Location: 40,5
Owner: Neutral
Owner: Nod
Actor113: brik
Location: 61,4
Owner: Neutral
Owner: Nod
Actor114: brik
Location: 40,4
Owner: Neutral
Owner: Nod
Actor115: brik
Location: 61,3
Owner: Neutral
Owner: Nod
Actor116: brik
Location: 60,3
Owner: Neutral
Owner: Nod
Actor117: brik
Location: 41,3
Owner: Neutral
Owner: Nod
Actor118: brik
Location: 40,3
Owner: Neutral
Owner: Nod
Actor119: brik
Location: 61,2
Owner: Neutral
Owner: Nod
Actor120: brik
Location: 60,2
Owner: Neutral
Owner: Nod
Actor121: brik
Location: 59,2
Owner: Neutral
Owner: Nod
Actor122: brik
Location: 58,2
Owner: Neutral
Owner: Nod
Actor123: brik
Location: 57,2
Owner: Neutral
Owner: Nod
Actor124: brik
Location: 56,2
Owner: Neutral
Owner: Nod
Actor125: brik
Location: 55,2
Owner: Neutral
Owner: Nod
Actor126: brik
Location: 54,2
Owner: Neutral
Owner: Nod
Actor127: brik
Location: 53,2
Owner: Neutral
Owner: Nod
Actor128: brik
Location: 52,2
Owner: Neutral
Owner: Nod
Actor129: brik
Location: 51,2
Owner: Neutral
Owner: Nod
Actor130: brik
Location: 50,2
Owner: Neutral
Owner: Nod
Actor131: brik
Location: 49,2
Owner: Neutral
Owner: Nod
Actor132: brik
Location: 48,2
Owner: Neutral
Owner: Nod
Actor133: brik
Location: 47,2
Owner: Neutral
Owner: Nod
Actor134: brik
Location: 46,2
Owner: Neutral
Owner: Nod
Actor135: brik
Location: 45,2
Owner: Neutral
Owner: Nod
Actor136: brik
Location: 44,2
Owner: Neutral
Owner: Nod
Actor137: brik
Location: 43,2
Owner: Neutral
Owner: Nod
Actor138: brik
Location: 42,2
Owner: Neutral
Owner: Nod
Actor139: brik
Location: 41,2
Owner: Neutral
Owner: Nod
Actor140: brik
Location: 40,2
Owner: Neutral
Owner: Nod
Actor141: t01
Location: 30,36
Owner: Neutral

View File

@@ -116,6 +116,8 @@ OLDLST:
Inherits: LST
-WithRoof:
-Selectable:
SelectionDecorations:
RenderSelectionBars: False
RejectsOrders:
Cargo:
Types: disabled

View File

@@ -92,7 +92,7 @@ ProduceHarvester = function(building)
end
ProduceInfantry = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end)
@@ -116,7 +116,7 @@ ProduceInfantry = function(building)
end
ProduceVehicle = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
ProduceHarvester(building)

View File

@@ -92,7 +92,7 @@ ProduceHarvester = function(building)
end
ProduceInfantry = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end)
@@ -116,7 +116,7 @@ ProduceInfantry = function(building)
end
ProduceVehicle = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
ProduceHarvester(building)

View File

@@ -114,7 +114,7 @@ ProduceHarvester = function(building)
end
ProduceInfantry = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end)
@@ -138,7 +138,7 @@ ProduceInfantry = function(building)
end
ProduceVehicle = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
ProduceHarvester(building)

View File

@@ -114,7 +114,7 @@ ProduceHarvester = function(building)
end
ProduceInfantry = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end)
@@ -138,7 +138,7 @@ ProduceInfantry = function(building)
end
ProduceVehicle = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
ProduceHarvester(building)

View File

@@ -114,7 +114,7 @@ ProduceHarvester = function(building)
end
ProduceInfantry = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
Trigger.AfterDelay(DateTime.Seconds(10), function() ProduceInfantry(building) end)
@@ -138,7 +138,7 @@ ProduceInfantry = function(building)
end
ProduceVehicle = function(building)
if building.IsDead then
if building.IsDead or building.Owner ~= enemy then
return
elseif not CheckForHarvester() then
ProduceHarvester(building)

View File

@@ -46,17 +46,12 @@ Player:
silo: 0%
fix: 1%
hpad: 2%
CapturingActorTypes: e6
CapturableActorTypes: fact, fact.gdi, fact.nod, nuke, nuk2, proc, pyle, hand, afld, weap, hpad, hq, fix, eye, tmpl, obli, v19
CheckCaptureTargetsForVisibility: false
MaximumCaptureTargetOptions: 15
UnitsToBuild:
e1: 65%
e2: 25%
e3: 40%
e4: 15%
e5: 15%
e6: 5%
harv: 10%
bggy: 5%
bike: 40%
@@ -72,7 +67,6 @@ Player:
orca: 5%
UnitLimits:
harv: 8
e6: 3
SquadSize: 15
SupportPowerDecision@Airstrike:
OrderName: AirstrikePowerInfoOrder

View File

@@ -165,8 +165,6 @@ ORCA:
C17:
Inherits: ^Plane
ParaDrop:
LZRange: 1
Tooltip:
Name: Supply Aircraft
Description: Drops vehicle reinforcements on Airstrips

View File

@@ -194,7 +194,6 @@
Beach: 80
SelectionDecorations:
WithSpriteControlGroupDecoration:
ReferencePoint: Top
Selectable:
Bounds: 12,17,0,-6
Targetable:
@@ -591,6 +590,7 @@
^CivField:
Inherits: ^CivBuilding
-Selectable:
-SelectionDecorations:
Tooltip:
GenericName: Field
-WithBuildingExplosion:

View File

@@ -255,6 +255,7 @@ pips:
Length: *
groups: pdigits
Length: *
Offset: 9, 5
pip-hazmat: pip-hazmat
Length: *

View File

@@ -152,7 +152,7 @@ dialog4: dialog.png
lobby-bits: buttons.png
spawn-unclaimed: 159,5,23,22
spawn-claimed: 127,5,23,22
admin: 187,5,7,5
admin: 186,5,7,5
colorpicker: 127,5,23,22
huepicker: 194,0,7,15
protected: 202,0,10,13

View File

@@ -57,7 +57,6 @@ Container@SKIRMISH_STATS:
Y: 105
Width: 482
Height: 265
TopBottomSpacing: 5
ItemSpacing: 5
Children:
ScrollItem@TEAM_TEMPLATE:

View File

@@ -3,6 +3,9 @@ Container@PLAYER_WIDGETS:
LogicKeyListener@CONTROLGROUP_KEYHANDLER:
Logic: ControlGroupLogic
LogicTicker@SIDEBAR_TICKER:
UnitCommand:
Width: WINDOW_RIGHT
Height: WINDOW_BOTTOM
Container@SUPPORT_POWERS:
Logic: SupportPowerBinLogic
X: 10

View File

@@ -1,4 +1,4 @@
d2k: Dune 2000 (English)
d2k-a: Dune 2000 (English)
IDFiles:
MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a
SETUP/SETUP.Z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7
@@ -854,7 +854,7 @@ d2k: Dune 2000 (English)
^Content/d2k/v2/SOUND.RS:
Offset: 20559431
Length: 1929247
d2k-linux: Dune 2000 (English)
d2k-a-linux: Dune 2000 (English)
IDFiles:
music/ambush.aud: bd5926a56a83bc0e49f96037e1f909014ac0772a
setup/setup.z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7

1712
mods/d2k/installer/d2kb.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -206,7 +206,7 @@ ModContent:
Packages:
base: Base Game Files
TestFiles: ^Content/d2k/v2/BLOXBASE.R8, ^Content/d2k/v2/BLOXBAT.R8, ^Content/d2k/v2/BLOXBGBS.R8, ^Content/d2k/v2/BLOXICE.R8, ^Content/d2k/v2/BLOXTREE.R8, ^Content/d2k/v2/BLOXWAST.R8, ^Content/d2k/v2/SOUND.RS, ^Content/d2k/v2/PALETTE.BIN, ^Content/d2k/v2/FONT.BIN, ^Content/d2k/v2/FONTCOL.FNT, ^Content/d2k/v2/FONTCOL.FPL
Sources: d2k, d2k-linux, gruntmods
Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux, gruntmods
Required: true
Download: basefiles
patch: 1.06 Patch Content
@@ -216,13 +216,14 @@ ModContent:
Download: patch106
music: Game Music
TestFiles: ^Content/d2k/v2/Music/AMBUSH.AUD
Sources: d2k, d2k-linux, gruntmods
Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux, gruntmods
movies: Campaign Briefings
TestFiles: ^Content/d2k/v2/Movies/A_BR01_E.VQA
Sources: d2k, d2k-linux
Sources: d2k-a, d2k-a-linux, d2k-b, d2k-b-linux
Downloads:
d2k|installer/downloads.yaml
Sources:
d2k|installer/d2k.yaml
d2k|installer/d2ka.yaml
d2k|installer/d2kb.yaml
d2k|installer/downloads.yaml
d2k|installer/gruntmods.yaml

View File

@@ -198,7 +198,7 @@ sardaukar:
Buildable:
Queue: Infantry
BuildPaletteOrder: 80
Prerequisites: ~barracks.harkonnen, palace, ~techlevel.high
Prerequisites: ~barracks.harkonnen, upgrade.barracks, high_tech_factory, ~techlevel.high
BuildDuration: 81
BuildDurationModifier: 40
Valued:

View File

@@ -124,6 +124,7 @@ pips:
groups: DATA.R8
Start: 17
Length: 10
Offset: 3, 3
pickup-indicator: DATA.R8
Start: 112
pip-empty: DATA.R8

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