Compare commits

...

67 Commits

Author SHA1 Message Date
abcdefg30
f14414d5af Prevent ReturnToBase from causing a divide by zero crash 2018-12-10 10:11:45 +13:00
abcdefg30
105fd83520 Revert balance changes to civilian buildings for the campaign missions 2018-12-10 10:06:47 +13:00
abcdefg30
3fed03df84 Use the tooltips from the original game for MISS and FCOM 2018-12-10 10:05:50 +13:00
abcdefg30
a8c57beebf Disable inaccurate tooltip descriptions in the campaign missions 2018-12-10 10:02:47 +13:00
Paul Chote
bfaacb2868 Fix queued EnterTransport unload glitch. 2018-12-08 11:42:47 +01:00
Paul Chote
724c93533b Prevent multiple Transforms from triggering in the same tick.
This leads to actor duplication.
2018-12-08 11:34:05 +01:00
Paul Chote
987b236ab6 Avoid a crash if subjects is empty.
This can happen in the rare instance that the last
actor in the selection is killed in the same tick
that the OG is activated, and GetCursor is called
before the next tick cancels the OG.
2018-11-20 21:56:46 +01:00
teinarss
23f69bc903 Defer setting slot on client to completeConnection 2018-11-19 22:06:05 +00:00
teinarss
3b485c1364 Show team/spawn widget after admin transfer. 2018-11-18 14:48:08 +01:00
Paul Chote
0f8df1b67a Work around a race condition between server join and auth validation. 2018-11-03 14:26:06 +01:00
Paul Chote
c057f3ec67 Limit samplers to 8 in combined.frag.
The additional palette sampler wasn't accounted
for in the original PR.
2018-11-01 19:10:06 +01:00
Paul Chote
ffcaa2779b Fix sampler index check
The index values are round numbers. Checking agaist
the half-values improves robustness against small
floating point delta errors that occur on some GPUs.
2018-10-06 15:11:05 +01:00
abcdefg30
9092946848 Properly end capturing during an owner change 2018-10-06 15:01:32 +01:00
Mustafa Alperen Seki
77ef5ff148 Make WithBuildingPlacedAnimation not play during vortex 2018-10-06 13:32:28 +01:00
Mustafa Alperen Seki
a0562a6c99 Make WithBuildingPlacedAnimation conditional 2018-10-06 13:32:22 +01:00
Paul Chote
a94b3f605d Rework master server ping rate-limit logic.
Pings are now delayed instead of dropped to avoid data loss.
2018-09-30 19:24:41 +01:00
Paul Chote
88e40ebdc7 Simplify server tick timeout handling. 2018-09-30 19:23:41 +01:00
abcdefg30
be5aa044a9 Prevent units from gaining more experience than MaxLevel requires 2018-09-28 22:49:01 +01:00
Paul Chote
65fc9af8b5 Revert "Update macOS launcher template to osx-launcher-20180723."
This reverts commit 904c3afc4d.
2018-09-22 19:00:42 +02:00
abcdefg30
dc8c8b9fb5 Disable the restart button on dedicated servers 2018-09-22 15:45:32 +01:00
abcdefg30
968c5b7fba Make the menu widget readonly 2018-09-22 15:45:25 +01:00
Paul Chote
086938b812 Revert RA Grenadier explosion DamageSource. 2018-09-13 17:12:07 +02:00
SoScared
c1bd98626b Fix d2k bots not excluding harvesters from squads 2018-09-13 17:05:17 +02:00
SoScared
6a50c156dd Enable airfield for AI as Ukraine 2018-09-10 03:46:31 +01:00
abcdefg30
20aca08fa2 Remove the CodeAnalysisRuleSet property from all csproj files 2018-08-25 22:06:22 +02:00
Paul Chote
78929ab311 Make SetupLatencyWidget consistent with SetupProfileWidget. 2018-08-25 22:06:00 +02:00
Paul Chote
06946b3a10 Don't crash when mousing over a bot as a non-admin. 2018-08-25 22:05:47 +02:00
Paul Chote
424bf012a7 Ignore malformed orders instead of crashing. 2018-08-25 18:27:46 +02:00
rtri
8c173dc870 fix threadedRenderer context creation logic 2018-08-23 01:50:28 +02:00
Paul Chote
14b286291f Add requires-auth indicator to the server lists. 2018-08-18 17:02:03 +02:00
Paul Chote
c4de10a974 Give server operators more control over client validation. 2018-08-18 17:01:45 +02:00
Paul Chote
518bbed9dc Sync auth information with the master server. 2018-08-18 17:01:31 +02:00
Paul Chote
4236e52c25 Revert "Re-active Edge-Scrolling for inverted Mouse-Scrolling"
This reverts commit c4867d4030.
2018-08-18 16:55:47 +02:00
Paul Chote
79fe31530e Add Engine.SupportDir argument. 2018-08-17 21:06:18 +02:00
Paul Chote
fbb31720c2 Ensure that TLS 1.2 is enabled for web downloads. 2018-08-16 19:59:43 +02:00
Mustafa Alperen Seki
f8e9692fa6 Fix GivesExperienceModifier not working 2018-08-16 19:49:28 +02:00
Paul Chote
772344ea02 Add a hard requirement on the cert-sync utility.
This tool is required to sync the certificates
used for https queries. This also has a side-effect
of prompting the mono-complete package on Mint,
which pulls in other required but missing packages.
2018-08-15 21:23:19 +01:00
Paul Chote
ce979a16dc Fix the Chronoshift-return cancellation bug. 2018-08-15 21:20:22 +01:00
Paul Chote
6fd99fdd4a Kill chronoshifted actors if the return-to-origin fails. 2018-08-15 21:20:18 +01:00
Paul Chote
d0ebe02cbb Remove IPreventsTeleport interface.
MadTank is changed to use conditions instead.
This has a side-benefit of disabling the move
cursor while deployed.
2018-08-15 21:20:14 +01:00
Paul Chote
f36c7bbca1 Make Chronoshiftable conditional. 2018-08-15 21:20:09 +01:00
Paul Chote
5c98973b6d Fix a typo in ChronosphereProperties class name. 2018-08-15 21:20:03 +01:00
reaperrr
115567f67f Fix husks not updating targetable positions on teleport
This should have checked for IPositionableInfo to begin with.

Husk already implements IPositionable, so implementing *Info as well
makes sense, even if it only serves to exclude it from
ITargetablePositions caching for now.
2018-08-14 17:27:06 +01:00
Paul Chote
15400cad3b Revert "Add "Restart" button for multiplayer replays"
This reverts commit 3a377a572c.
2018-08-12 19:08:14 +02:00
Smittytron
cbc33b91a7 Revert ranger change and dial back missile sub damage 2018-08-11 22:58:04 +02:00
Paul Chote
2d9bb75cbb Fix badge label padding. 2018-08-11 22:57:36 +02:00
abcdefg30
d3be09b60a Remove RA95Launcher.exe from the IDFiles of the origin ra install 2018-08-11 22:54:27 +02:00
abcdefg30
0985e12777 Remove CNC95Launcher.exe from the IDFiles of the origin cnc and ra installs 2018-08-11 22:54:09 +02:00
Paul Chote
510757cb2e Add EnabledByDefault check to WithInfantryBody. 2018-08-11 14:34:57 +02:00
Paul Chote
cccced6709 Add missing EnabledByDefault checks to WithSpriteBodyInfo subclasses. 2018-08-11 14:34:43 +02:00
abcdefg30
3cf09a7a18 Revert "Add conyard.corrino"
This reverts commit bdaff27656.
2018-08-10 21:04:41 +02:00
abcdefg30
ce3df9d859 Revert "Limit D2K Palace SWs to their Faction's Palaces'"
This reverts commit d110b9c648.
2018-08-10 21:04:41 +02:00
abcdefg30
4fd0d047a0 Resolve conflicts between actor and API names (Radar) 2018-08-10 20:50:25 +02:00
Oliver Brakmann
de0ccf8769 Fix issueing superfluous difficulty lobby command from mission browser 2018-08-09 20:07:31 +01:00
Smittytron
a152e526e5 Fix death sequences of Chan, Einstein, and Delphi 2018-08-05 13:12:33 +02:00
reaperrr
1e3545c6f3 Fix AI idle harvester management
This was broken because our default mods now list `harv` under `ExcludeFromSquads`, which prevents them from being added to `activeUnits`.
2018-08-04 22:30:51 +02:00
reaperrr
3c4f19d855 Some HackyAI cleanups
- harvManager.Tick should run after FindNewUnits() in case new harvesters have appeared
- moved the FindNewUnits Mcv and ExcludeFromSquads checks to the foreach loop, for better readability and preparation of the idle harvester fix
2018-08-04 22:30:40 +02:00
Paul Chote
8220f4122a Hide the Ready checkbox when a spectator transfers away Admin. 2018-08-04 22:17:16 +02:00
Paul Chote
f4dc0aa0f4 Clear selection when a text field's contents is changed programatically. 2018-08-04 20:35:20 +02:00
Paul Chote
1ebb16e418 Fix missing profile indicator for spectators. 2018-08-04 20:25:29 +02:00
Paul Chote
9395f0c672 Disable the threaded renderer on Windows.
A DisableWindowsRenderThread graphics setting is
added to allow players to optionally reenable it.
2018-08-04 20:15:05 +02:00
reaperrr
999b998329 Fix tree owners in TD (for real this time) 2018-08-04 19:07:42 +01:00
Paul Chote
a3559d8803 Revert ShpTD empty space trimming.
This reverts the following commits:
 * 1faae73c08
 * a7d39fc76d
2018-08-04 20:04:25 +02:00
reaperrr
9d0d25eca6 Fix tree owner on TD maps
Needs to be Neutral instead of Creeps, to avoid confusing the AI.
2018-08-04 14:03:30 +01:00
reaperrr
ced9ff26b5 Fix tree owner on several RA maps
Owner: Creeps can lead to AI trying to attack trees, so all trees must have Neutral as owner.
2018-08-04 14:03:24 +01:00
abcdefg30
3498ad11dd Remove all uses of Server.ExternalPort 2018-08-04 12:38:35 +02:00
abcdefg30
ad03b40635 Fix the die1 sequence of fremen 2018-07-31 21:05:14 +02:00
118 changed files with 643 additions and 442 deletions

View File

@@ -42,6 +42,7 @@ namespace OpenRA
public Player Owner { get; internal set; }
public bool IsInWorld { get; internal set; }
public bool WillDispose { get; private set; }
public bool Disposed { get; private set; }
public Activity CurrentActivity { get; private set; }
@@ -124,9 +125,9 @@ namespace OpenRA
world.AddFrameEndTask(w =>
{
// Caching this in a AddFrameEndTask, because trait construction order might cause problems if done directly at creation time.
// All actors that can move should have IMove, if not it's pretty safe to assume the actor is immobile and
// All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and
// all targetable positions can be cached if all ITargetablePositions have no conditional requirements.
if (!Info.HasTraitInfo<IMoveInfo>() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled))
if (!Info.HasTraitInfo<IPositionableInfo>() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled))
staticTargetablePositions = targetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray();
});
@@ -265,6 +266,9 @@ namespace OpenRA
public void Dispose()
{
// Allow traits/activities to prevent a race condition when they depend on disposing the actor (e.g. Transforms)
WillDispose = true;
World.AddFrameEndTask(w =>
{
if (Disposed)

View File

@@ -43,8 +43,19 @@ namespace OpenRA
}
}
void EnableTLS12OnWindows()
{
// Enable TLS 1.2 on Windows: .NET 4.7 on Windows 10 only supports obsolete protocols by default
// SecurityProtocolType.Tls12 is not defined in the .NET 4.5 reference dlls used by mono,
// so we must use the enum's constant value directly
if (Platform.CurrentPlatform == PlatformType.Windows)
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072;
}
public Download(string url, string path, Action<DownloadProgressChangedEventArgs> onProgress, Action<AsyncCompletedEventArgs> onComplete)
{
EnableTLS12OnWindows();
lock (syncObject)
{
wc = new WebClient { Proxy = null };
@@ -56,6 +67,8 @@ namespace OpenRA
public Download(string url, Action<DownloadProgressChangedEventArgs> onProgress, Action<DownloadDataCompletedEventArgs> onComplete)
{
EnableTLS12OnWindows();
lock (syncObject)
{
wc = new WebClient { Proxy = null };

View File

@@ -258,6 +258,10 @@ namespace OpenRA
static void Initialize(Arguments args)
{
var supportDirArg = args.GetValue("Engine.SupportDir", null);
if (supportDirArg != null)
Platform.OverrideSupportDir(supportDirArg);
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
// Load the engine version as early as possible so it can be written to exception logs

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Graphics
readonly IShader shader;
readonly Vertex[] vertices;
readonly Sheet[] sheets = new Sheet[8];
readonly Sheet[] sheets = new Sheet[7];
BlendMode currentBlend = BlendMode.Alpha;
int nv = 0;

View File

@@ -168,7 +168,11 @@ namespace OpenRA
public string Sign(params string[] data)
{
if (State != LinkState.Linked)
// If we don't have any keys, or we know for sure that they haven't been linked to the forum
// then we can't do much here. If we have keys but don't yet know if they have been linked to the
// forum (LinkState.CheckingLink or ConnectionFailed) then we sign to avoid blocking the main thread
// but accept that - if the cert is invalid - the server will reject the result.
if (State <= LinkState.Unlinked)
return null;
return CryptoUtil.Sign(parameters, data.Where(x => !string.IsNullOrEmpty(x)).JoinWith(string.Empty));
@@ -176,7 +180,7 @@ namespace OpenRA
public string DecryptString(string data)
{
if (State != LinkState.Linked)
if (State <= LinkState.Unlinked)
return null;
return CryptoUtil.DecryptString(parameters, data);

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Network
public class GameClient
{
public readonly string Name;
public readonly string Fingerprint;
public readonly HSLColor Color;
public readonly string Faction;
public readonly int Team;
@@ -33,6 +34,7 @@ namespace OpenRA.Network
public GameClient(Session.Client c)
{
Name = c.Name;
Fingerprint = c.Fingerprint;
Color = c.Color;
Faction = c.Faction;
Team = c.Team;
@@ -54,7 +56,7 @@ namespace OpenRA.Network
"Mod", "Version", "ModTitle", "ModWebsite", "ModIcon32",
// Current server state
"Map", "State", "MaxPlayers", "Protected"
"Map", "State", "MaxPlayers", "Protected", "Authentication"
};
public const int ProtocolVersion = 2;
@@ -98,6 +100,9 @@ namespace OpenRA.Network
/// <summary>Password protected</summary>
public readonly bool Protected = false;
/// <summary>Players must be authenticated with the OpenRA forum</summary>
public readonly bool Authentication = false;
/// <summary>UTC datetime string when the game changed to the Playing state</summary>
public readonly string Started = null;
@@ -222,6 +227,7 @@ namespace OpenRA.Network
ModWebsite = manifest.Metadata.Website;
ModIcon32 = manifest.Metadata.WebIcon32;
Protected = !string.IsNullOrEmpty(server.Settings.Password);
Authentication = server.Settings.RequireAuthentication || server.Settings.ProfileIDWhitelist.Any();
Clients = server.LobbyInfo.Clients.Select(c => new GameClient(c)).ToArray();
}

View File

@@ -76,10 +76,12 @@ namespace OpenRA
public static Order Deserialize(World world, BinaryReader r)
{
var magic = r.ReadByte();
switch (magic)
try
{
case 0xFF:
var magic = r.ReadByte();
switch (magic)
{
case 0xFF:
{
var order = r.ReadString();
var subjectId = r.ReadUInt32();
@@ -156,7 +158,7 @@ namespace OpenRA
return new Order(order, subject, target, targetString, queued, extraLocation, extraData);
}
case 0xfe:
case 0xfe:
{
var name = r.ReadString();
var data = r.ReadString();
@@ -164,11 +166,23 @@ namespace OpenRA
return new Order(name, null, false) { IsImmediate = true, TargetString = data };
}
default:
default:
{
Log.Write("debug", "Received unknown order with magic {0}", magic);
return null;
}
}
}
catch (Exception e)
{
Log.Write("debug", "Caught exception while processing order");
Log.Write("debug", e.ToString());
// HACK: this can hopefully go away in the future
Game.Debug("Ignoring malformed order that would have crashed the game");
Game.Debug("Please file a bug report and include the replay from this match");
return null;
}
}

View File

@@ -38,7 +38,6 @@
<OutputPath>..</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<StartArguments>Game.Mod=ra</StartArguments>
@@ -53,7 +52,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
<StartArguments>Game.Mod=ra</StartArguments>
<Commandlineparameters>Game.Mod=ra</Commandlineparameters>

View File

@@ -71,9 +71,30 @@ namespace OpenRA
/// </summary>
public static string SupportDir { get { return supportDir.Value; } }
static Lazy<string> supportDir = Exts.Lazy(GetSupportDir);
static string supportDirOverride;
/// <summary>
/// Specify a custom support directory that already exists on the filesystem.
/// MUST be called before Platform.SupportDir is first accessed.
/// </summary>
public static void OverrideSupportDir(string path)
{
if (!Directory.Exists(path))
throw new DirectoryNotFoundException(path);
if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) &&
!path.EndsWith(Path.AltDirectorySeparatorChar.ToString(), StringComparison.Ordinal))
path += Path.DirectorySeparatorChar;
supportDirOverride = path;
}
static string GetSupportDir()
{
// Use the custom override if it has been defined
if (supportDirOverride != null)
return supportDirOverride;
// Use a local directory in the game root if it exists (shared with the system support dir)
var localSupportDir = Path.Combine(GameDir, "Support");
if (Directory.Exists(localSupportDir))

View File

@@ -170,7 +170,6 @@ namespace OpenRA.Server
Log.Write("server", "Initial mod: {0}", ModData.Manifest.Id);
Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);
var timeout = serverTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
for (;;)
{
var checkRead = new List<Socket>();
@@ -180,7 +179,9 @@ namespace OpenRA.Server
checkRead.AddRange(Conns.Select(c => c.Socket));
checkRead.AddRange(PreConns.Select(c => c.Socket));
var localTimeout = waitingForAuthenticationCallback > 0 ? 100000 : timeout;
// Block for at most 1 second in order to guarantee a minimum tick rate for ServerTraits
// Decrease this to 100ms to improve responsiveness if we are waiting for an authentication query
var localTimeout = waitingForAuthenticationCallback > 0 ? 100000 : 1000000;
if (checkRead.Count > 0)
Socket.Select(checkRead, null, null, localTimeout);
@@ -323,7 +324,6 @@ namespace OpenRA.Server
Name = OpenRA.Settings.SanitizedPlayerName(handshake.Client.Name),
IpAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address.ToString(),
Index = newConn.PlayerIndex,
Slot = LobbyInfo.FirstEmptySlot(),
PreferredColor = handshake.Client.PreferredColor,
Color = handshake.Client.Color,
Faction = "Random",
@@ -340,11 +340,6 @@ namespace OpenRA.Server
return;
}
if (client.Slot != null)
SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]);
else
client.Color = HSLColor.FromRGB(255, 255, 255);
if (ModData.Manifest.Id != handshake.Mod)
{
Log.Write("server", "Rejected connection from {0}; mods do not match.",
@@ -377,6 +372,13 @@ namespace OpenRA.Server
Action completeConnection = () =>
{
client.Slot = LobbyInfo.FirstEmptySlot();
if (client.Slot != null)
SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]);
else
client.Color = HSLColor.FromRGB(255, 255, 255);
// Promote connection to a valid client
PreConns.Remove(newConn);
Conns.Add(newConn);
@@ -475,11 +477,25 @@ namespace OpenRA.Server
delayedActions.Add(() =>
{
if (Dedicated && Settings.RequireAuthIDs.Any() &&
(profile == null || !Settings.RequireAuthIDs.Contains(profile.ProfileID)))
var notAuthenticated = Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any());
var blacklisted = Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
var notWhitelisted = Dedicated && Settings.ProfileIDWhitelist.Any() &&
(profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID));
if (notAuthenticated)
{
Log.Write("server", "Rejected connection from {0}; Not in server whitelist.", newConn.Socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "You are not authenticated for this server");
Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
DropClient(newConn);
}
else if (blacklisted || notWhitelisted)
{
if (blacklisted)
Log.Write("server", "Rejected connection from {0}; In server blacklist.", newConn.Socket.RemoteEndPoint);
else
Log.Write("server", "Rejected connection from {0}; Not in server whitelist.", newConn.Socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "You do not have permission to join this server");
DropClient(newConn);
}
else
@@ -493,10 +509,10 @@ namespace OpenRA.Server
}
else
{
if (Dedicated && Settings.RequireAuthIDs.Any())
if (Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()))
{
Log.Write("server", "Rejected connection from {0}; Not authenticated and whitelist is set.", newConn.Socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "You are not authenticated for this server");
Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
DropClient(newConn);
}
else

View File

@@ -23,11 +23,7 @@ namespace OpenRA.Server
public interface IStartGame { void GameStarted(Server server); }
public interface IClientJoined { void ClientJoined(Server server, Connection conn); }
public interface IEndGame { void GameEnded(Server server); }
public interface ITick
{
void Tick(Server server);
int TickTimeout { get; }
}
public interface ITick { void Tick(Server server); }
public abstract class ServerTrait { }

View File

@@ -59,8 +59,14 @@ namespace OpenRA
[Desc("Takes a comma separated list of IP addresses that are not allowed to join.")]
public string[] Ban = { };
[Desc("If non-empty, only allow authenticated players with these user IDs to join.")]
public int[] RequireAuthIDs = { };
[Desc("For dedicated servers only, allow anonymous clients to join.")]
public bool RequireAuthentication = false;
[Desc("For dedicated servers only, if non-empty, only allow authenticated players with these profile IDs to join.")]
public int[] ProfileIDWhitelist = { };
[Desc("For dedicated servers only, if non-empty, always reject players with these user IDs from joining.")]
public int[] ProfileIDBlacklist = { };
[Desc("For dedicated servers only, controls whether a game can be started with just one human player in the lobby.")]
public bool EnableSingleplayer = false;
@@ -130,6 +136,9 @@ namespace OpenRA
[Desc("Disable high resolution DPI scaling on Windows operating systems.")]
public bool DisableWindowsDPIScaling = true;
[Desc("Disable separate OpenGL render thread on Windows operating systems.")]
public bool DisableWindowsRenderThread = true;
public int BatchSize = 8192;
public int SheetSize = 2048;

View File

@@ -15,22 +15,25 @@ using OpenRA.Activities;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Activities
{
public interface IPreventsTeleport { bool PreventsTeleport(Actor self); }
public class Teleport : Activity
{
readonly Actor teleporter;
readonly int? maximumDistance;
readonly bool killOnFailure;
readonly BitSet<DamageType> killDamageTypes;
CPos destination;
bool killCargo;
bool screenFlash;
string sound;
public Teleport(Actor teleporter, CPos destination, int? maximumDistance, bool killCargo, bool screenFlash, string sound)
public Teleport(Actor teleporter, CPos destination, int? maximumDistance,
bool killCargo, bool screenFlash, string sound, bool interruptable = true,
bool killOnFailure = false, BitSet<DamageType> killDamageTypes = default(BitSet<DamageType>))
{
var max = teleporter.World.Map.Grid.MaximumTileSearchRange;
if (maximumDistance > max)
@@ -42,21 +45,32 @@ namespace OpenRA.Mods.Cnc.Activities
this.killCargo = killCargo;
this.screenFlash = screenFlash;
this.sound = sound;
this.killOnFailure = killOnFailure;
this.killDamageTypes = killDamageTypes;
if (!interruptable)
IsInterruptible = false;
}
public override Activity Tick(Actor self)
{
var pc = self.TraitOrDefault<PortableChrono>();
if (teleporter == self && pc != null && !pc.CanTeleport)
return NextActivity;
{
if (killOnFailure)
self.Kill(teleporter, killDamageTypes);
foreach (var condition in self.TraitsImplementing<IPreventsTeleport>())
if (condition.PreventsTeleport(self))
return NextActivity;
return NextActivity;
}
var bestCell = ChooseBestDestinationCell(self, destination);
if (bestCell == null)
{
if (killOnFailure)
self.Kill(teleporter, killDamageTypes);
return NextActivity;
}
destination = bestCell.Value;

View File

@@ -39,7 +39,6 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<OutputPath>bin\Debug\</OutputPath>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>5</LangVersion>
</PropertyGroup>
@@ -51,7 +50,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -17,9 +17,9 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Scripting
{
[ScriptPropertyGroup("Support Powers")]
public class ChronsphereProperties : ScriptActorProperties, Requires<ChronoshiftPowerInfo>
public class ChronosphereProperties : ScriptActorProperties, Requires<ChronoshiftPowerInfo>
{
public ChronsphereProperties(ScriptContext context, Actor self)
public ChronosphereProperties(ScriptContext context, Actor self)
: base(context, self) { }
[Desc("Chronoshift a group of actors. A duration of 0 will teleport the actors permanently.")]
@@ -37,7 +37,9 @@ namespace OpenRA.Mods.Cnc.Scripting
kv.Key.WrappedClrType().Name, kv.Value.WrappedClrType().Name));
}
var cs = actor.TraitOrDefault<Chronoshiftable>();
var cs = actor.TraitsImplementing<Chronoshiftable>()
.FirstEnabledTraitOrDefault();
if (cs != null && cs.CanChronoshiftTo(actor, cell))
cs.Teleport(actor, cell, duration, killCargo, Self);
}

View File

@@ -10,7 +10,9 @@
#endregion
using System.Drawing;
using OpenRA.Activities;
using OpenRA.Mods.Cnc.Activities;
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -18,12 +20,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
[Desc("Can be teleported via Chronoshift power.")]
public class ChronoshiftableInfo : ITraitInfo
public class ChronoshiftableInfo : ConditionalTraitInfo
{
[Desc("Should the actor die instead of being teleported?")]
public readonly bool ExplodeInstead = false;
[Desc("Types of damage that this trait causes to self when 'ExplodeInstead' is true. Leave empty for no damage types.")]
[Desc("Types of damage that this trait causes to self when 'ExplodeInstead' is true",
"or the return-to-origin is blocked. Leave empty for no damage types.")]
public readonly BitSet<DamageType> DamageTypes = default(BitSet<DamageType>);
public readonly string ChronoshiftSound = "chrono2.aud";
@@ -34,12 +37,12 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("The color the bar of the 'return-to-origin' logic has.")]
public readonly Color TimeBarColor = Color.White;
public object Create(ActorInitializer init) { return new Chronoshiftable(init, this); }
public override object Create(ActorInitializer init) { return new Chronoshiftable(init, this); }
}
public class Chronoshiftable : ITick, ISync, ISelectionBar, IDeathActorInitModifier, ITransformActorInitModifier, INotifyCreated
public class Chronoshiftable : ConditionalTrait<ChronoshiftableInfo>, ITick, ISync, ISelectionBar,
IDeathActorInitModifier, ITransformActorInitModifier, INotifyCreated
{
readonly ChronoshiftableInfo info;
readonly Actor self;
Actor chronosphere;
bool killCargo;
@@ -51,8 +54,8 @@ namespace OpenRA.Mods.Cnc.Traits
[Sync] public int ReturnTicks = 0;
public Chronoshiftable(ActorInitializer init, ChronoshiftableInfo info)
: base(info)
{
this.info = info;
self = init.Self;
if (init.Contains<ChronoshiftReturnInit>())
@@ -70,14 +73,29 @@ namespace OpenRA.Mods.Cnc.Traits
void ITick.Tick(Actor self)
{
if (!info.ReturnToOrigin || ReturnTicks <= 0)
if (IsTraitDisabled || !Info.ReturnToOrigin || ReturnTicks <= 0)
return;
// Return to original location
if (--ReturnTicks == 0)
{
self.CancelActivity();
self.QueueActivity(new Teleport(chronosphere, Origin, null, killCargo, true, info.ChronoshiftSound));
// The Move activity is not immediately cancelled, which, combined
// with Activity.Cancel discarding NextActivity without checking the
// IsInterruptable flag, means that a well timed order can cancel the
// Teleport activity queued below - an exploit / cheat of the return mechanic.
// The Teleport activity queued below is guaranteed to either complete
// (force-resetting the actor to the middle of the target cell) or kill
// the actor. It is therefore safe to force-erase the Move activity to
// work around the cancellation bug.
// HACK: this is manipulating private internal actor state
if (self.CurrentActivity is Move)
typeof(Actor).GetProperty("CurrentActivity").SetValue(self, null);
// The actor is killed using Info.DamageTypes if the teleport fails
self.QueueActivity(new Teleport(chronosphere, Origin, null, true, killCargo, Info.ChronoshiftSound,
false, true, Info.DamageTypes));
}
}
@@ -90,19 +108,22 @@ namespace OpenRA.Mods.Cnc.Traits
public virtual bool CanChronoshiftTo(Actor self, CPos targetLocation)
{
// TODO: Allow enemy units to be chronoshifted into bad terrain to kill them
return iPositionable != null && iPositionable.CanEnterCell(targetLocation);
return !IsTraitDisabled && iPositionable != null && iPositionable.CanEnterCell(targetLocation);
}
public virtual bool Teleport(Actor self, CPos targetLocation, int duration, bool killCargo, Actor chronosphere)
{
if (IsTraitDisabled)
return false;
// Some things appear chronoshiftable, but instead they just die.
if (info.ExplodeInstead)
if (Info.ExplodeInstead)
{
self.World.AddFrameEndTask(w =>
{
// Damage is inflicted by the chronosphere
if (!self.Disposed)
self.Kill(chronosphere, info.DamageTypes);
self.Kill(chronosphere, Info.DamageTypes);
});
return true;
}
@@ -122,7 +143,7 @@ namespace OpenRA.Mods.Cnc.Traits
// Set up the teleport
self.CancelActivity();
self.QueueActivity(new Teleport(chronosphere, targetLocation, null, killCargo, true, info.ChronoshiftSound));
self.QueueActivity(new Teleport(chronosphere, targetLocation, null, killCargo, true, Info.ChronoshiftSound));
return true;
}
@@ -130,7 +151,7 @@ namespace OpenRA.Mods.Cnc.Traits
// Show the remaining time as a bar
float ISelectionBar.GetValue()
{
if (!info.ReturnToOrigin)
if (IsTraitDisabled || !Info.ReturnToOrigin)
return 0f;
// Otherwise an empty bar is rendered all the time
@@ -140,12 +161,12 @@ namespace OpenRA.Mods.Cnc.Traits
return (float)ReturnTicks / duration;
}
Color ISelectionBar.GetColor() { return info.TimeBarColor; }
Color ISelectionBar.GetColor() { return Info.TimeBarColor; }
bool ISelectionBar.DisplayWhenEmpty { get { return false; } }
void ModifyActorInit(TypeDictionary init)
{
if (!info.ReturnToOrigin || ReturnTicks <= 0)
if (IsTraitDisabled || !Info.ReturnToOrigin || ReturnTicks <= 0)
return;
init.Add(new ChronoshiftOriginInit(Origin));

View File

@@ -188,6 +188,9 @@ namespace OpenRA.Mods.Cnc.Traits
void ITick.Tick(Actor self)
{
if (self.WillDispose)
return;
if (triggered)
health.InflictDamage(self, chronosphere, new Damage(info.Damage, info.DamageTypes), true);

View File

@@ -50,6 +50,10 @@ namespace OpenRA.Mods.Cnc.Traits
[VoiceReference] public readonly string Voice = "Action";
[GrantedConditionReference]
[Desc("The condition to grant to self while deployed.")]
public readonly string DeployedCondition = null;
public WeaponInfo ThumpDamageWeaponInfo { get; private set; }
public WeaponInfo DetonationWeaponInfo { get; private set; }
@@ -75,12 +79,13 @@ namespace OpenRA.Mods.Cnc.Traits
}
}
class MadTank : IIssueOrder, IResolveOrder, IOrderVoice, ITick, IPreventsTeleport, IIssueDeployOrder
class MadTank : INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, ITick, IIssueDeployOrder
{
readonly Actor self;
readonly MadTankInfo info;
readonly WithFacingSpriteBody wfsb;
readonly ScreenShaker screenShaker;
ConditionManager conditionManager;
bool deployed;
int tick;
@@ -92,6 +97,11 @@ namespace OpenRA.Mods.Cnc.Traits
screenShaker = self.World.WorldActor.Trait<ScreenShaker>();
}
void INotifyCreated.Created(Actor self)
{
conditionManager = self.TraitOrDefault<ConditionManager>();
}
void ITick.Tick(Actor self)
{
if (!deployed)
@@ -172,6 +182,9 @@ namespace OpenRA.Mods.Cnc.Traits
if (deployed)
return;
if (conditionManager != null && !string.IsNullOrEmpty(info.DeployedCondition))
conditionManager.GrantCondition(self, info.DeployedCondition);
self.World.AddFrameEndTask(w => EjectDriver());
if (info.ThumpSequence != null)
wfsb.PlayCustomAnimationRepeating(self, info.ThumpSequence);

View File

@@ -27,6 +27,9 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var t = init.Actor.TraitInfos<TurretedInfo>().FirstOrDefault();
var wsb = init.Actor.TraitInfos<WithSpriteBodyInfo>().FirstOrDefault();

View File

@@ -65,7 +65,12 @@ namespace OpenRA.Mods.Cnc.Traits
foreach (var target in UnitsInRange(order.ExtraLocation))
{
var cs = target.Trait<Chronoshiftable>();
var cs = target.TraitsImplementing<Chronoshiftable>()
.FirstEnabledTraitOrDefault();
if (cs == null)
continue;
var targetCell = target.Location + (order.TargetLocation - order.ExtraLocation);
var cpi = Info as ChronoshiftPowerInfo;
@@ -82,8 +87,7 @@ namespace OpenRA.Mods.Cnc.Traits
foreach (var t in tiles)
units.UnionWith(Self.World.ActorMap.GetActorsAt(t));
return units.Where(a => a.Info.HasTraitInfo<ChronoshiftableInfo>() &&
!a.TraitsImplementing<IPreventsTeleport>().Any(condition => condition.PreventsTeleport(a)));
return units.Where(a => a.TraitsImplementing<Chronoshiftable>().Any(cs => !cs.IsTraitDisabled));
}
public bool SimilarTerrain(CPos xy, CPos sourceLocation)

View File

@@ -61,18 +61,15 @@ namespace OpenRA.Mods.Common.AI
return path[0];
}
public void Tick(List<Actor> activeUnits)
public void Tick(List<Actor> harvesters)
{
if (resLayer == null || resLayer.IsResourceLayerEmpty)
return;
// Find idle harvesters and give them orders:
foreach (var harvester in activeUnits)
foreach (var harvester in harvesters)
{
var harv = harvester.TraitOrDefault<Harvester>();
if (harv == null)
continue;
var harv = harvester.Trait<Harvester>();
if (!harv.IsEmpty)
continue;

View File

@@ -286,6 +286,10 @@ namespace OpenRA.Mods.Common.AI
// Units that the ai already knows about. Any unit not on this list needs to be given a role.
List<Actor> activeUnits = new List<Actor>();
// Harvesters are usually listed under ExcludeFromSquads, so they're not included in the activeUnits list, but still needed in AIHarvesterManager.
// TODO: Consider adding an explicit UnitsCommonNames.Harvester category.
List<Actor> harvesters = new List<Actor>();
public const int FeedbackTime = 30; // ticks; = a bit over 1s. must be >= netlag.
public readonly World World;
@@ -597,6 +601,7 @@ namespace OpenRA.Mods.Common.AI
activeUnits.RemoveAll(unitCannotBeOrdered);
unitsHangingAroundTheBase.RemoveAll(unitCannotBeOrdered);
harvesters.RemoveAll(unitCannotBeOrdered);
if (--rushTicks <= 0)
{
@@ -614,8 +619,8 @@ namespace OpenRA.Mods.Common.AI
if (--assignRolesTicks <= 0)
{
assignRolesTicks = Info.AssignRolesInterval;
harvManager.Tick(activeUnits);
FindNewUnits(self);
harvManager.Tick(harvesters);
InitializeBase(self, true);
}
@@ -738,11 +743,16 @@ namespace OpenRA.Mods.Common.AI
void FindNewUnits(Actor self)
{
var newUnits = self.World.ActorsHavingTrait<IPositionable>()
.Where(a => a.Owner == Player && !Info.UnitsCommonNames.Mcv.Contains(a.Info.Name) &&
!Info.UnitsCommonNames.ExcludeFromSquads.Contains(a.Info.Name) && !activeUnits.Contains(a));
.Where(a => a.Owner == Player && !activeUnits.Contains(a) && !harvesters.Contains(a));
foreach (var a in newUnits)
{
if (a.Info.HasTraitInfo<HarvesterInfo>())
harvesters.Add(a);
if (Info.UnitsCommonNames.Mcv.Contains(a.Info.Name) || Info.UnitsCommonNames.ExcludeFromSquads.Contains(a.Info.Name))
continue;
unitsHangingAroundTheBase.Add(a);
if (a.Info.HasTraitInfo<AircraftInfo>() && a.Info.HasTraitInfo<AttackBaseInfo>())

View File

@@ -83,7 +83,10 @@ namespace OpenRA.Mods.Common.Activities
var posCenter = new WPos(cp.X, cp.Y, altitude);
var approachCenter = approachStart + new WVec(0, turnRadius * Math.Sign(self.CenterPosition.Y - approachStart.Y), 0);
var tangentDirection = approachCenter - posCenter;
var tangentOffset = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentDirection.Length;
var tangentLength = tangentDirection.Length;
var tangentOffset = WVec.Zero;
if (tangentLength != 0)
tangentOffset = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentLength;
// TODO: correctly handle CCW <-> CW turns
if (tangentOffset.X > 0)

View File

@@ -55,6 +55,10 @@ namespace OpenRA.Mods.Common.Activities
});
Done(self);
// Preemptively cancel any activities to avoid an edge-case where successively queued
// EnterTransports corrupt the actor state. Activities are cancelled again on unload
self.CancelActivity();
}
protected override bool TryGetAlternateTarget(Actor self, int tries, ref Target target)

View File

@@ -50,7 +50,8 @@ namespace OpenRA.Mods.Common.Activities
BeginCapture(self);
else
{
if (capturable.Captor != self) return NextActivity;
if (capturable.Captor != self)
return NextActivity;
if (capturable.CaptureProgressTime % 25 == 0)
{
@@ -99,8 +100,9 @@ namespace OpenRA.Mods.Common.Activities
void EndCapture(Actor self)
{
if (target.Type == TargetType.Actor && capturable.CaptureInProgress)
if (capturable.CaptureInProgress)
capturable.EndCapture();
if (capturingToken != ConditionManager.InvalidConditionToken)
capturingToken = conditionManager.RevokeCondition(self, capturingToken);
}

View File

@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Activities
{
self.World.AddFrameEndTask(w =>
{
if (self.IsDead)
if (self.IsDead || self.WillDispose)
return;
foreach (var nt in self.TraitsImplementing<INotifyTransform>())

View File

@@ -23,7 +23,6 @@
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
@@ -34,7 +33,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -11,9 +11,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using BeaconLib;
using OpenRA.Network;
@@ -24,8 +22,12 @@ namespace OpenRA.Mods.Common.Server
{
public class MasterServerPinger : ServerTrait, ITick, INotifyServerStart, INotifySyncLobbyInfo, IStartGame, IEndGame
{
// 3 minutes. Server has a 5 minute TTL for games, so give ourselves a bit of leeway.
const int MasterPingInterval = 60 * 3;
// 3 minutes (in milliseconds). Server has a 5 minute TTL for games, so give ourselves a bit of leeway.
const int MasterPingInterval = 60 * 3 * 1000;
// 1 second (in milliseconds) minimum delay between pings
const int RateLimitInterval = 1000;
static readonly Beacon LanGameBeacon;
static readonly Dictionary<int, string> MasterServerErrors = new Dictionary<int, string>()
{
@@ -33,9 +35,8 @@ namespace OpenRA.Mods.Common.Server
{ 2, "Server name contains a blacklisted word." }
};
public int TickTimeout { get { return MasterPingInterval * 10000; } }
long lastPing = 0;
long lastChanged = 0;
bool isInitialPing = true;
volatile bool isBusy;
@@ -55,12 +56,28 @@ namespace OpenRA.Mods.Common.Server
public void Tick(S server)
{
if ((Game.RunTime - lastPing > MasterPingInterval * 1000) || isInitialPing)
PublishGame(server);
else
lock (masterServerMessages)
while (masterServerMessages.Count > 0)
server.SendMessage(masterServerMessages.Dequeue());
// Force an update if the last one was too long ago so the advertisement doesn't time out
if (Game.RunTime - lastChanged > MasterPingInterval)
lastChanged = Game.RunTime;
// Update the master server and LAN clients if something has changed
// Note that isBusy is set while the master server ping is running on a
// background thread, and limits LAN pings as well as master server pings for simplicity.
if (!isBusy && ((lastChanged > lastPing && Game.RunTime - lastPing > RateLimitInterval) || isInitialPing))
{
var gs = new GameServer(server);
if (server.Settings.AdvertiseOnline)
UpdateMasterServer(server, gs.ToPOSTData(false));
if (LanGameBeacon != null)
LanGameBeacon.BeaconData = gs.ToPOSTData(true);
lastPing = Game.RunTime;
}
lock (masterServerMessages)
while (masterServerMessages.Count > 0)
server.SendMessage(masterServerMessages.Dequeue());
}
public void ServerStarted(S server)
@@ -71,12 +88,12 @@ namespace OpenRA.Mods.Common.Server
public void LobbyInfoSynced(S server)
{
PublishGame(server);
lastChanged = Game.RunTime;
}
public void GameStarted(S server)
{
PublishGame(server);
lastChanged = Game.RunTime;
}
public void GameEnded(S server)
@@ -84,24 +101,11 @@ namespace OpenRA.Mods.Common.Server
if (LanGameBeacon != null)
LanGameBeacon.Stop();
PublishGame(server);
}
void PublishGame(S server)
{
// Cache the server info on the main thread to ensure data consistency
var gs = new GameServer(server);
if (!isBusy && server.Settings.AdvertiseOnline)
UpdateMasterServer(server, gs.ToPOSTData(false));
if (LanGameBeacon != null)
LanGameBeacon.BeaconData = gs.ToPOSTData(true);
lastChanged = Game.RunTime;
}
void UpdateMasterServer(S server, string postData)
{
lastPing = Game.RunTime;
isBusy = true;
Action a = () =>

View File

@@ -74,91 +74,6 @@ namespace OpenRA.Mods.Common.SpriteLoaders
{
enum Format { XORPrev = 0x20, XORLCW = 0x40, LCW = 0x80 }
class TrimmedFrame : ISpriteFrame
{
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
public float2 Offset { get; private set; }
public byte[] Data { get; private set; }
public bool DisableExportPadding { get { return false; } }
public TrimmedFrame(ImageHeader header)
{
var origData = header.Data;
var origSize = header.Size;
var top = origSize.Height - 1;
var bottom = 0;
var left = origSize.Width - 1;
var right = 0;
// Scan frame data to find left-, top-, right-, bottom-most
// rows/columns with non-zero pixel data
var i = 0;
for (var y = 0; y < origSize.Height; y++)
{
for (var x = 0; x < origSize.Width; x++, i++)
{
if (origData[i] != 0)
{
top = Math.Min(y, top);
bottom = Math.Max(y, bottom);
left = Math.Min(x, left);
right = Math.Max(x, right);
}
}
}
// Keep a 1px empty border to work avoid rounding issues in the gpu shader
if (left > 0)
left -= 1;
if (top > 0)
top -= 1;
if (right < origSize.Width - 1)
right += 1;
if (bottom < origSize.Height - 1)
bottom += 1;
var trimmedWidth = right - left + 1;
var trimmedHeight = bottom - top + 1;
// Pad the dimensions to an even number to avoid issues with half-integer offsets
var widthFudge = trimmedWidth % 2;
var heightFudge = trimmedHeight % 2;
var destWidth = trimmedWidth + widthFudge;
var destHeight = trimmedHeight + heightFudge;
if (trimmedWidth == origSize.Width && trimmedHeight == origSize.Height)
{
// Nothing to trim, so copy old data directly
Size = header.Size;
FrameSize = header.FrameSize;
Offset = header.Offset;
Data = header.Data;
}
else if (trimmedWidth > 0 && trimmedHeight > 0)
{
// Trim frame
Data = new byte[destWidth * destHeight];
for (var y = 0; y < trimmedHeight; y++)
Array.Copy(origData, (y + top) * origSize.Width + left, Data, y * destWidth, trimmedWidth);
Size = new Size(destWidth, destHeight);
FrameSize = origSize;
Offset = 0.5f * new float2(
left + right + widthFudge - origSize.Width + 1,
top + bottom + heightFudge - origSize.Height + 1);
}
else
{
// Empty frame
Data = new byte[0];
}
}
}
class ImageHeader : ISpriteFrame
{
public Size Size { get { return reader.Size; } }
@@ -217,6 +132,7 @@ namespace OpenRA.Mods.Common.SpriteLoaders
stream.Position += 4;
var headers = new ImageHeader[imageCount];
Frames = headers.AsReadOnly();
for (var i = 0; i < headers.Length; i++)
headers[i] = new ImageHeader(stream, this);
@@ -238,10 +154,6 @@ namespace OpenRA.Mods.Common.SpriteLoaders
foreach (var h in headers)
Decompress(h);
Frames = headers.Select(f => (ISpriteFrame)new TrimmedFrame(f))
.ToArray()
.AsReadOnly();
}
void Decompress(ImageHeader h)

View File

@@ -175,7 +175,7 @@ namespace OpenRA.Mods.Common.Traits
{
var prefix = mi.Modifiers.HasModifier(Modifiers.Ctrl) ? "assaultmove" : "attackmove";
if (world.Map.Contains(cell))
if (world.Map.Contains(cell) && subjects.Any())
{
var explored = subjects.First().Actor.Owner.Shroud.IsExplored(cell);
var blocked = !explored && subjects.Any(a => !a.Trait.Info.MoveIntoShroud);

View File

@@ -52,18 +52,18 @@ namespace OpenRA.Mods.Common.Traits
{
[Sync] public int CaptureProgressTime = 0;
[Sync] public Actor Captor;
private Actor self;
public bool CaptureInProgress { get { return Captor != null; } }
readonly Building building;
public ExternalCapturable(Actor self, ExternalCapturableInfo info)
: base(info)
{
this.self = self;
building = self.TraitOrDefault<Building>();
}
public void BeginCapture(Actor captor)
{
var building = self.TraitOrDefault<Building>();
if (building != null)
building.Lock();
@@ -72,7 +72,6 @@ namespace OpenRA.Mods.Common.Traits
public void EndCapture()
{
var building = self.TraitOrDefault<Building>();
if (building != null)
building.Unlock();

View File

@@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits
if (amount < 0)
throw new ArgumentException("Revoking experience is not implemented.", "amount");
experience += amount;
experience = (experience + amount).Clamp(0, nextLevel[MaxLevel - 1].First);
while (Level < MaxLevel && experience >= nextLevel[Level].First)
{

View File

@@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits
: valued != null ? valued.Cost : 0;
var experienceModifier = self.TraitsImplementing<IGivesExperienceModifier>().Select(x => x.GetGivesExperienceModifier());
Util.ApplyPercentageModifiers(exp, experienceModifier);
exp = Util.ApplyPercentageModifiers(exp, experienceModifier);
var killer = e.Attacker.TraitOrDefault<GainsExperience>();
if (killer != null)

View File

@@ -18,7 +18,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Spawns remains of a husk actor with the correct facing.")]
public class HuskInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo, IActorPreviewInitInfo
public class HuskInfo : ITraitInfo, IPositionableInfo, IFacingInfo, IActorPreviewInitInfo
{
public readonly HashSet<string> AllowedTerrain = new HashSet<string>();
@@ -41,6 +41,13 @@ namespace OpenRA.Mods.Common.Traits
}
bool IOccupySpaceInfo.SharesCell { get { return false; } }
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
{
// IPositionable*Info*.CanEnterCell is only ever used for things like exiting production facilities,
// all places relevant for husks check IPositionable.CanEnterCell instead, so we can safely set this to true.
return true;
}
}
public class Husk : IPositionable, IFacing, ISync, INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld,

View File

@@ -44,6 +44,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var anim = new Animation(init.World, image);
anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequences.First()), () => 0);

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render
{
[Desc("Changes the animation when the actor constructed a building.")]
public class WithBuildingPlacedAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo>
public class WithBuildingPlacedAnimationInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>
{
[Desc("Sequence name to use"), SequenceReference]
public readonly string Sequence = "build";
@@ -23,18 +23,17 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Which sprite body to play the animation on.")]
public readonly string Body = "body";
public object Create(ActorInitializer init) { return new WithBuildingPlacedAnimation(init.Self, this); }
public override object Create(ActorInitializer init) { return new WithBuildingPlacedAnimation(init.Self, this); }
}
public class WithBuildingPlacedAnimation : INotifyBuildingPlaced, INotifyBuildComplete, INotifySold, INotifyTransform
public class WithBuildingPlacedAnimation : ConditionalTrait<WithBuildingPlacedAnimationInfo>, INotifyBuildingPlaced, INotifyBuildComplete, INotifySold, INotifyTransform
{
readonly WithBuildingPlacedAnimationInfo info;
readonly WithSpriteBody wsb;
bool buildComplete;
public WithBuildingPlacedAnimation(Actor self, WithBuildingPlacedAnimationInfo info)
: base(info)
{
this.info = info;
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>();
}
@@ -60,8 +59,8 @@ namespace OpenRA.Mods.Common.Traits.Render
void INotifyBuildingPlaced.BuildingPlaced(Actor self)
{
if (buildComplete)
wsb.PlayCustomAnimation(self, info.Sequence);
if (!IsTraitDisabled && buildComplete)
wsb.PlayCustomAnimation(self, Info.Sequence);
}
}
}

View File

@@ -49,6 +49,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var anim = new Animation(init.World, image);
var sequence = init.World.Type == WorldType.Editor ? EditorSequence : Sequence;
var palette = init.World.Type == WorldType.Editor ? init.WorldRenderer.Palette(EditorPalette) : p;

View File

@@ -23,6 +23,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var anim = new Animation(init.World, image, init.GetFacing());
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));

View File

@@ -33,6 +33,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var anim = new Animation(init.World, image);
anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0);

View File

@@ -36,6 +36,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var anim = new Animation(init.World, image, init.GetFacing());
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), StandSequences.First()));
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);

View File

@@ -33,6 +33,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
if (!EnabledByDefault)
yield break;
var adjacent = 0;
if (init.Contains<RuntimeNeighbourInit>())

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
public class IngameMenuLogic : ChromeLogic
{
Widget menu;
readonly Widget menu;
[ObjectCreator.UseCtor]
public IngameMenuLogic(Widget widget, ModData modData, World world, Action onExit, WorldRenderer worldRenderer, IngameInfoPanel activePanel)
@@ -97,7 +97,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var iop = world.WorldActor.TraitsImplementing<IObjectivesPanel>().FirstOrDefault();
var exitDelay = iop != null ? iop.ExitDelay : 0;
if (world.IsReplay || world.LobbyInfo.NonBotClients.Count() == 1)
if (!world.LobbyInfo.GlobalSettings.Dedicated && world.LobbyInfo.NonBotClients.Count() == 1)
{
restartAction = () =>
{

View File

@@ -576,7 +576,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (template == null || template.Id != editablePlayerTemplate.Id)
template = editablePlayerTemplate.Clone();
LobbyUtils.SetupLatencyWidget(template, client, orderManager, client.Bot == null);
LobbyUtils.SetupLatencyWidget(template, client, orderManager);
if (client.Bot != null)
LobbyUtils.SetupEditableSlotWidget(template, slot, client, orderManager, worldRenderer, map);
@@ -595,7 +595,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (template == null || template.Id != nonEditablePlayerTemplate.Id)
template = nonEditablePlayerTemplate.Clone();
LobbyUtils.SetupLatencyWidget(template, client, orderManager, client.Bot == null);
LobbyUtils.SetupLatencyWidget(template, client, orderManager);
LobbyUtils.SetupColorWidget(template, slot, client);
LobbyUtils.SetupFactionWidget(template, slot, client, factions);
@@ -646,6 +646,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (client.IsAdmin)
LobbyUtils.SetupEditableReadyWidget(template, null, client, orderManager, map);
else
LobbyUtils.HideReadyWidgets(template);
}
else
{
@@ -661,9 +663,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (client.IsAdmin)
LobbyUtils.SetupReadyWidget(template, null, client);
else
LobbyUtils.HideReadyWidgets(template);
}
LobbyUtils.SetupLatencyWidget(template, c, orderManager, true);
LobbyUtils.SetupLatencyWidget(template, c, orderManager);
template.IsVisible = () => true;
if (idx >= players.Children.Count)

View File

@@ -296,8 +296,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
return "Poor";
}
public static void SetupLatencyWidget(Widget parent, Session.Client c, OrderManager orderManager, bool visible)
public static void SetupLatencyWidget(Widget parent, Session.Client c, OrderManager orderManager)
{
var visible = c != null && c.Bot == null;
var block = parent.GetOrNull("LATENCY");
if (block != null)
{
@@ -309,31 +310,34 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
var tooltip = parent.Get<ClientTooltipRegionWidget>("LATENCY_REGION");
tooltip.IsVisible = () => c != null && visible;
if (c != null)
tooltip.IsVisible = () => visible;
if (visible)
tooltip.Bind(orderManager, null, c);
}
public static void SetupProfileWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer)
{
var visible = c != null && c.Bot == null;
var profile = parent.GetOrNull<ImageWidget>("PROFILE");
if (profile != null && c.Bot == null)
if (profile != null)
{
var imageName = (c != null && c.IsAdmin ? "admin-" : "player-")
+ (c.Fingerprint != null ? "registered" : "anonymous");
profile.GetImageName = () => imageName;
profile.IsVisible = () => true;
profile.IsVisible = () => visible;
}
var profileTooltip = parent.GetOrNull<ClientTooltipRegionWidget>("PROFILE_TOOLTIP");
if (profileTooltip != null && c.Bot == null)
if (profileTooltip != null)
{
if (c != null && c.Fingerprint != null)
profileTooltip.Template = "REGISTERED_PLAYER_TOOLTIP";
profileTooltip.Bind(orderManager, worldRenderer, c);
profileTooltip.IsVisible = () => true;
if (visible)
profileTooltip.Bind(orderManager, worldRenderer, c);
profileTooltip.IsVisible = () => visible;
}
}
@@ -520,7 +524,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public static void SetupTeamWidget(Widget parent, Session.Slot s, Session.Client c)
{
parent.Get<LabelWidget>("TEAM").GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
var team = parent.Get<LabelWidget>("TEAM");
team.IsVisible = () => true;
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
HideChildWidget(parent, "TEAM_DROPDOWN");
}
@@ -543,7 +549,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public static void SetupSpawnWidget(Widget parent, Session.Slot s, Session.Client c)
{
parent.Get<LabelWidget>("SPAWN").GetText = () => (c.SpawnPoint == 0) ? "-" : Convert.ToChar('A' - 1 + c.SpawnPoint).ToString();
var spawn = parent.Get<LabelWidget>("SPAWN");
spawn.IsVisible = () => true;
spawn.GetText = () => (c.SpawnPoint == 0) ? "-" : Convert.ToChar('A' - 1 + c.SpawnPoint).ToString();
HideChildWidget(parent, "SPAWN_DROPDOWN");
}
@@ -564,6 +572,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
parent.Get<ImageWidget>("STATUS_IMAGE").IsVisible = () => c.IsReady || c.Bot != null;
}
public static void HideReadyWidgets(Widget parent)
{
HideChildWidget(parent, "STATUS_CHECKBOX");
HideChildWidget(parent, "STATUS_IMAGE");
}
public static void AddPlayerFlagAndName(ScrollItemWidget template, Player player)
{
var flag = template.Get<ImageWidget>("FLAG");

View File

@@ -374,11 +374,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (selectedMap.InvalidCustomRules)
return;
var orders = new[] {
Order.Command("option gamespeed {0}".F(gameSpeed)),
Order.Command("option difficulty {0}".F(difficulty)),
Order.Command("state {0}".F(Session.ClientState.Ready))
};
var orders = new List<Order>();
if (difficulty != null)
orders.Add(Order.Command("option difficulty {0}".F(difficulty)));
orders.Add(Order.Command("option gamespeed {0}".F(gameSpeed)));
orders.Add(Order.Command("state {0}".F(Session.ClientState.Ready)));
var missionData = selectedMap.Rules.Actors["world"].TraitInfoOrDefault<MissionDataInfo>();
if (missionData != null && missionData.StartVideo != null && modData.DefaultFileSystem.Exists(missionData.StartVideo))

View File

@@ -153,6 +153,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
messageHeader.IsVisible = () => !profileLoaded;
var profileWidth = 0;
var maxProfileWidth = widget.Bounds.Width;
var messageText = "Loading player profile...";
var messageWidth = messageFont.Measure(messageText).X + 2 * message.Bounds.Left;
@@ -199,7 +200,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
Func<int, int> negotiateWidth = badgeWidth =>
{
profileWidth = Math.Min(Math.Max(badgeWidth, profileWidth), widget.Bounds.Width);
profileWidth = Math.Min(Math.Max(badgeWidth, profileWidth), maxProfileWidth);
return profileWidth;
};
@@ -219,7 +220,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}
}
profileWidth = Math.Min(profileWidth, widget.Bounds.Width);
profileWidth = Math.Min(profileWidth, maxProfileWidth);
header.Bounds.Width = widget.Bounds.Width = badgeContainer.Bounds.Width = profileWidth;
widget.Bounds.Height = header.Bounds.Height + badgeContainer.Bounds.Height;
@@ -267,8 +268,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var badgeTemplate = widget.Get("BADGE_TEMPLATE");
widget.RemoveChild(badgeTemplate);
var width = 0;
// Negotiate the label length that the tooltip will allow
var maxLabelWidth = 0;
var templateIcon = badgeTemplate.Get<SpriteWidget>("ICON");
var templateLabel = badgeTemplate.Get<LabelWidget>("LABEL");
var templateLabelFont = Game.Renderer.Fonts[templateLabel.Font];
foreach (var badge in profile.Badges)
maxLabelWidth = Math.Max(maxLabelWidth, templateLabelFont.Measure(badge.Label).X);
widget.Bounds.Width = negotiateWidth(2 * templateLabel.Bounds.Left - templateIcon.Bounds.Right + maxLabelWidth);
var badgeOffset = badgeTemplate.Bounds.Y;
if (profile.Badges.Any())
badgeOffset += 3;
foreach (var badge in profile.Badges)
{
var b = badgeTemplate.Clone();
@@ -278,11 +291,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var label = b.Get<LabelWidget>("LABEL");
var labelFont = Game.Renderer.Fonts[label.Font];
var labelText = WidgetUtils.TruncateText(badge.Label, label.Bounds.Width, labelFont);
var labelText = WidgetUtils.TruncateText(badge.Label, widget.Bounds.Width - label.Bounds.X - icon.Bounds.X, labelFont);
label.GetText = () => labelText;
width = Math.Max(width, label.Bounds.Left + labelFont.Measure(labelText).X + icon.Bounds.X);
b.Bounds.Y = badgeOffset;
widget.AddChild(b);
@@ -292,7 +303,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (badgeOffset > badgeTemplate.Bounds.Y)
badgeOffset += 5;
widget.Bounds.Width = negotiateWidth(width);
widget.Bounds.Height = badgeOffset;
}
}

View File

@@ -599,6 +599,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
password.GetImageName = () => canJoin ? "protected" : "protected-disabled";
}
var auth = item.GetOrNull<ImageWidget>("REQUIRES_AUTHENTICATION");
if (auth != null)
{
auth.IsVisible = () => game.Authentication;
auth.GetImageName = () => canJoin ? "authentication" : "authentication-disabled";
if (game.Protected && password != null)
auth.Bounds.X -= password.Bounds.Width + 5;
}
var players = item.GetOrNull<LabelWithTooltipWidget>("PLAYERS");
if (players != null)
{

View File

@@ -32,6 +32,7 @@ namespace OpenRA.Mods.Common.Widgets
{
text = RemoveInvalidCharacters(value ?? "");
CursorPosition = CursorPosition.Clamp(0, text.Length);
ClearSelection();
}
}

View File

@@ -368,7 +368,7 @@ namespace OpenRA.Mods.Common.Widgets
else if (mi.Event == MouseInputEvent.Move && (isStandardScrolling ||
(standardScrollStart.HasValue && ((standardScrollStart.Value - mi.Location).Length > Game.Settings.Game.MouseScrollDeadzone))))
{
isStandardScrolling = scrollType == MouseScrollType.Standard;
isStandardScrolling = true;
var d = scrollType == MouseScrollType.Inverted ? -1 : 1;
worldRenderer.Viewport.Scroll((Viewport.LastMousePos - mi.Location) * d, false);
return true;

View File

@@ -40,7 +40,6 @@
<ErrorReport>prompt</ErrorReport>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;</DefineConstants>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>5</LangVersion>
</PropertyGroup>
@@ -52,7 +51,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -19,7 +19,6 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
@@ -30,7 +29,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -187,7 +187,16 @@ namespace OpenRA.Platforms.Default
// Run graphics rendering on a dedicated thread.
// The calling thread will then have more time to process other tasks, since rendering happens in parallel.
// If the calling thread is the main game thread, this means it can run more logic and render ticks.
context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);
// This is disabled on Windows because it breaks the ability to minimize/restore the window from the taskbar for reasons that we dont understand.
var threadedRenderer = Platform.CurrentPlatform != PlatformType.Windows || !Game.Settings.Graphics.DisableWindowsRenderThread;
if (!threadedRenderer)
{
var ctx = new Sdl2GraphicsContext(this);
ctx.InitializeOpenGL();
context = ctx;
}
else
context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);
SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
input = new Sdl2Input();

View File

@@ -39,7 +39,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<UseVSHostingProcess>false</UseVSHostingProcess>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>5</LangVersion>
@@ -53,7 +52,6 @@
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -11,7 +11,6 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using OpenRA.Support;
@@ -23,6 +22,10 @@ namespace OpenRA.Server
static void Main(string[] args)
{
var arguments = new Arguments(args);
var supportDirArg = arguments.GetValue("Engine.SupportDir", null);
if (supportDirArg != null)
Platform.OverrideSupportDir(supportDirArg);
Log.AddChannel("debug", "dedicated-debug.log");
Log.AddChannel("perf", "dedicated-perf.log");
Log.AddChannel("server", "dedicated-server.log");

View File

@@ -19,7 +19,6 @@
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
@@ -29,7 +28,6 @@
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -39,7 +39,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<UseVSHostingProcess>false</UseVSHostingProcess>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>5</LangVersion>
@@ -53,7 +52,6 @@
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@@ -5,7 +5,6 @@ uniform sampler2D Texture3;
uniform sampler2D Texture4;
uniform sampler2D Texture5;
uniform sampler2D Texture6;
uniform sampler2D Texture7;
uniform sampler2D Palette;
uniform bool EnableDepthPreview;
@@ -38,22 +37,20 @@ float jet_b(float x)
vec4 Sample(float samplerIndex, vec2 pos)
{
if (samplerIndex < 1.0)
if (samplerIndex < 0.5)
return texture2D(Texture0, pos);
else if (samplerIndex < 2.0)
else if (samplerIndex < 1.5)
return texture2D(Texture1, pos);
else if (samplerIndex < 3.0)
else if (samplerIndex < 2.5)
return texture2D(Texture2, pos);
else if (samplerIndex < 4.0)
else if (samplerIndex < 3.5)
return texture2D(Texture3, pos);
else if (samplerIndex < 5.0)
else if (samplerIndex < 4.5)
return texture2D(Texture4, pos);
else if (samplerIndex < 6.0)
else if (samplerIndex < 5.5)
return texture2D(Texture5, pos);
else if (samplerIndex < 7.0)
return texture2D(Texture6, pos);
return texture2D(Texture7, pos);
return texture2D(Texture6, pos);
}
void main()

View File

@@ -5,13 +5,12 @@
set Name="Dedicated Server"
set Mod=ra
set ListenPort=1234
set ExternalPort=1234
set AdvertiseOnline=True
set EnableSingleplayer=False
set Password=""
:loop
OpenRA.Server.exe Game.Mod=%Mod% Server.Name=%Name% Server.ListenPort=%ListenPort% Server.ExternalPort=%ExternalPort% Server.AdvertiseOnline=%AdvertiseOnline% Server.EnableSingleplayer=%EnableSingleplayer% Server.Password=%Password%
OpenRA.Server.exe Game.Mod=%Mod% Server.Name=%Name% Server.ListenPort=%ListenPort% Server.AdvertiseOnline=%AdvertiseOnline% Server.EnableSingleplayer=%EnableSingleplayer% Server.Password=%Password%
goto loop

View File

@@ -9,14 +9,13 @@
Name="${Name:-"Dedicated Server"}"
Mod="${Mod:-"ra"}"
ListenPort="${ListenPort:-"1234"}"
ExternalPort="${ExternalPort:-"1234"}"
AdvertiseOnline="${AdvertiseOnline:-"True"}"
EnableSingleplayer="${EnableSingleplayer:-"False"}"
Password="${Password:-""}"
while true; do
mono --debug OpenRA.Server.exe Game.Mod=$Mod \
Server.Name="$Name" Server.ListenPort=$ListenPort Server.ExternalPort=$ExternalPort \
Server.Name="$Name" Server.ListenPort=$ListenPort \
Server.AdvertiseOnline=$AdvertiseOnline \
Server.EnableSingleplayer=$EnableSingleplayer Server.Password=$Password
done

View File

@@ -449,8 +449,10 @@ lobby-bits: chrome.png
colorpicker: 257,33,14,14
huepicker: 388,96,7,15
kick: 386,115,11,11
protected: 403,97,10,13
protected-disabled: 403,113,10,13
protected: 402,97,12,13
protected-disabled: 402,113,12,13
authentication: 418,97,12,13
authentication-disabled: 418,113,12,13
admin-registered: 448,112,16,16
admin-anonymous: 464,112,16,16
player-registered: 480,112,16,16

View File

@@ -87,17 +87,26 @@ Container@LOBBY_SERVERS_BIN:
Children:
Label@TITLE:
X: 5
Width: 255
Width: 245
Height: 25
Image@PASSWORD_PROTECTED:
X: 272
Y: 6
Width: 8
Height: 10
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires Password
Image@REQUIRES_AUTHENTICATION:
X: 272
Y: 6
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires OpenRA forum account
LabelWithTooltip@PLAYERS:
X: 290
Width: 85

View File

@@ -108,17 +108,26 @@ Container@MULTIPLAYER_PANEL:
Children:
Label@TITLE:
X: 5
Width: 255
Width: 245
Height: 25
Image@PASSWORD_PROTECTED:
X: 272
Y: 6
Width: 8
Height: 10
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires Password
Image@REQUIRES_AUTHENTICATION:
X: 272
Y: 6
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires OpenRA forum account
LabelWithTooltip@PLAYERS:
X: 290
Width: 85

View File

@@ -4,7 +4,6 @@ origin: C&C The Ultimate Collection (Origin version, English)
RegistryKey: EA Games\CNC and The Covert Operations
RegistryValue: Install Dir
IDFiles:
CNC95Launcher.exe: 1d711adf09ac08738b2599b3092a1b448169b32a
CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30
Install:
copy: .

Binary file not shown.

View File

@@ -342,7 +342,7 @@ Actors:
Tower2: gtwr
Location: 23,21
Owner: GDI
Radar: hq
CommCenter: hq
Location: 21,14
Owner: GDI
Silo1: silo

View File

@@ -45,16 +45,16 @@ Gdi12Waypoints = { waypoint0, waypoint1, waypoint3, waypoint11, waypoint12 }
AllWaypoints = { Gdi1Waypoints, Gdi2Waypoints, Gdi3Waypoints, Gdi5Waypoints, Gdi11Waypoints, Gdi12Waypoints }
PrimaryTargets = { Tower1, Tower2, Radar, Silo1, Silo2, Silo3, Refinery, Barracks, Plant1, Plant2, Yard, Factory }
PrimaryTargets = { Tower1, Tower2, CommCenter, Silo1, Silo2, Silo3, Refinery, Barracks, Plant1, Plant2, Yard, Factory }
GDIStartUnits = { }
SendGDIAirstrike = function()
if not Radar.IsDead and Radar.Owner == enemy then
if not CommCenter.IsDead and CommCenter.Owner == enemy then
local target = getAirstrikeTarget()
if target then
Radar.SendAirstrike(target, false, Facing.NorthEast + 4)
CommCenter.SendAirstrike(target, false, Facing.NorthEast + 4)
Trigger.AfterDelay(AirstrikeDelay, SendGDIAirstrike)
else
Trigger.AfterDelay(AirstrikeDelay/4, SendGDIAirstrike)

View File

@@ -638,7 +638,7 @@ Actors:
Detonator: CRATE.plain
Location: 59,43
Owner: GDI
Radar: hq
CommCenter: hq
Location: 57,32
Owner: GDI
Actor187: jeep

View File

@@ -91,12 +91,12 @@ end
Atk3TriggerFunction = function()
if not Atk3Switch then
Atk3Switch = true
if not Radar.IsDead then
if not CommCenter.IsDead then
local targets = player.GetGroundAttackers()
local target = targets[DateTime.GameTime % #targets + 1].CenterPosition
if target then
Radar.SendAirstrike(target, false, Facing.NorthEast + 4)
CommCenter.SendAirstrike(target, false, Facing.NorthEast + 4)
end
end
end
@@ -135,7 +135,7 @@ InsertNodUnits = function()
local difficulty = Map.LobbyOption("difficulty")
NodStartUnitsRight = NodStartUnitsRight[difficulty]
NodStartUnitsLeft = NodStartUnitsLeft[difficulty]
Camera.Position = UnitsRallyRight.CenterPosition
Media.PlaySpeechNotification(player, "Reinforce")
@@ -183,7 +183,7 @@ WorldLoaded = function()
OnAnyDamaged(Atk1ActorTriggerActivator, Atk1TriggerFunction)
OnAnyDamaged(Atk2ActorTriggerActivator, Atk2TriggerFunction)
if Map.LobbyOption("difficulty") == "tough" then
Trigger.OnDamaged(Atk3Activator, Atk3TriggerFunction)
end

Binary file not shown.

Binary file not shown.

View File

@@ -67,6 +67,10 @@ MISS:
GenericVisibility: None
ShowOwnerRow: False
BIO:
-TooltipDescription@ally:
-TooltipDescription@other:
ARCO:
Tooltip:
GenericVisibility: None

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -401,6 +401,20 @@ Container@LOBBY_PLAYER_BIN:
Font: Regular
Visible: false
Align: Left
LeftMargin: 24
Children:
Image@PROFILE:
ImageCollection: lobby-bits
X: 3
Y: 3
Visible: false
ClientTooltipRegion@PROFILE_TOOLTIP:
X: 3
Y: 3
Width: 16
Height: 16
TooltipContainer: TOOLTIP_CONTAINER
Template: ANONYMOUS_PLAYER_TOOLTIP
Label@SPECTATOR:
X: 190
Width: 326

View File

@@ -84,17 +84,26 @@ Container@LOBBY_SERVERS_BIN:
Children:
Label@TITLE:
X: 5
Width: 255
Width: 245
Height: 25
Image@PASSWORD_PROTECTED:
X: 272
Y: 6
Width: 10
Height: 12
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires Password
Image@REQUIRES_AUTHENTICATION:
X: 272
Y: 6
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires OpenRA forum account
LabelWithTooltip@PLAYERS:
X: 290
Width: 85

View File

@@ -100,17 +100,26 @@ Background@MULTIPLAYER_PANEL:
Children:
Label@TITLE:
X: 5
Width: 255
Width: 245
Height: 25
Image@PASSWORD_PROTECTED:
X: 272
Y: 6
Width: 10
Height: 12
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires Password
Image@REQUIRES_AUTHENTICATION:
X: 272
Y: 6
Width: 12
Height: 13
ImageCollection: lobby-bits
TooltipContainer: TOOLTIP_CONTAINER
TooltipTemplate: SIMPLE_TOOLTIP
TooltipText: Requires OpenRA forum account
LabelWithTooltip@PLAYERS:
X: 290
Width: 85

View File

@@ -215,6 +215,8 @@ lobby-bits: buttons.png
huepicker: 193,0,7,15
protected: 200,0,12,13
protected-disabled: 211,0,12,13
authentication: 199,16,12,13
authentication-disabled: 212,16,12,13
admin-registered: 224,0,16,16
admin-anonymous: 240,0,16,16
player-registered: 224,16,16,16

View File

@@ -17,7 +17,7 @@ Player:
Silo: silo
UnitsCommonNames:
Mcv: mcv
ExcludeFromSquads: harv
ExcludeFromSquads: harvester
BuildingLimits:
barracks: 1
refinery: 4
@@ -140,7 +140,7 @@ Player:
Silo: silo
UnitsCommonNames:
Mcv: mcv
ExcludeFromSquads: harv
ExcludeFromSquads: harvester
BuildingLimits:
barracks: 1
refinery: 4
@@ -265,7 +265,7 @@ Player:
Silo: silo
UnitsCommonNames:
Mcv: mcv
ExcludeFromSquads: harv
ExcludeFromSquads: harvester
BuildingLimits:
barracks: 1
refinery: 4

View File

@@ -1101,18 +1101,16 @@ palace:
Factions: corrino
PrimaryBuilding:
PrimaryCondition: primary
RequiresCondition: atreides || ordos
WithTextDecoration@primary:
RequiresSelection: true
Text: PRIMARY
ReferencePoint: Top
ZOffset: 256
RequiresCondition: primary && (atreides || ordos)
RequiresCondition: primary
NukePower:
Cursor: nuke
Icon: deathhand
PauseOnCondition: disabled
RequiresCondition: harkonnen
Prerequisites: ~techlevel.superweapons, ~palace.nuke
ChargeInterval: 7500
Description: Death Hand
@@ -1129,7 +1127,7 @@ palace:
ArrowSequence: arrow
CircleSequence: circles
WithNukeLaunchOverlay:
RequiresCondition: !launchpad-damaged && harkonnen
RequiresCondition: !launchpad-damaged
GrantConditionOnDamageState@LAUNCHPADDAMAGED:
Condition: launchpad-damaged
ProduceActorPower@fremen:
@@ -1137,10 +1135,9 @@ palace:
LongDesc: Elite infantry unit armed with assault rifles and rockets\n Strong vs Infantry, Vehicles\n Weak vs Artillery\n Special Ability: Invisibility
Icon: fremen
PauseOnCondition: disabled
RequiresCondition: atreides
Prerequisites: ~techlevel.superweapons, ~palace.fremen
Actors: fremen, fremen
Type: Fremen
Type: Palace
ChargeInterval: 2250
ReadyAudio: Reinforce
BlockedAudio: NoRoom
@@ -1150,10 +1147,9 @@ palace:
LongDesc: Sneaky infantry, armed with explosives\n Strong vs Buildings\n Weak vs Everything\n Special Ability: destroy buildings
Icon: saboteur
PauseOnCondition: disabled
RequiresCondition: ordos
Prerequisites: ~techlevel.superweapons, ~palace.saboteur
Actors: saboteur
Type: Saboteur
Type: Palace
ChargeInterval: 2250
ReadyAudio: Reinforce
BlockedAudio: NoRoom
@@ -1167,23 +1163,9 @@ palace:
Exit@3:
SpawnOffset: -704,768,0
ExitCell: 0,3
Production@Atreides:
Produces: Fremen
RequiresCondition: atreides
Production@Ordos:
Produces: Saboteur
RequiresCondition: ordos
GrantConditionOnFaction@Atreides:
Condition: atreides
Factions: atreides, fremen
GrantConditionOnFaction@Harkonnen:
Condition: harkonnen
Factions: harkonnen
GrantConditionOnFaction@Ordos:
Condition: ordos
Factions: ordos, mercenary, smuggler
Production:
Produces: Palace
SupportPowerChargeBar:
RequiresCondition: atreides || harkonnen || ordos
ProvidesPrerequisite@buildingname:
conyard.atreides:
@@ -1208,17 +1190,6 @@ conyard.harkonnen:
Image: conyard.harkonnen
-FactionImages:
conyard.corrino:
Inherits: construction_yard
Buildable:
Queue: Building
BuildPaletteOrder: 1000
Prerequisites: ~disabled
ForceFaction: corrino
RenderSprites:
Image: conyard.harkonnen
-FactionImages:
conyard.ordos:
Inherits: construction_yard
Buildable:

View File

@@ -310,7 +310,7 @@ fremen:
Facings: -8
Transpose: true
die1: DATA.R8
Frames: 870, 877, 884, 891, 898, 905, 912, 919, 926, 933, 940, 947
Frames: 870, 877, 884, 891, 898, 905, 912, 919, 926, 927, 928, 929
Length: 12
Tick: 80
die2: DATA.R8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -531,8 +531,10 @@ lobby-bits: buttons.png
admin: 187,5,7,5
colorpicker: 127,5,23,22
huepicker: 194,0,7,15
protected: 202,0,10,13
protected-disabled: 213,0,10,13
protected: 201,0,12,13
protected-disabled: 212,0,12,13
authentication: 199,16,12,13
authentication-disabled: 212,16,12,13
admin-registered: 224,0,16,16
admin-anonymous: 240,0,16,16
player-registered: 224,16,16,16

View File

@@ -4,7 +4,6 @@ ra-origin: C&C The Ultimate Collection (Origin version, English)
RegistryKey: EA Games\Command and Conquer Red Alert
RegistryValue: Install Dir
IDFiles:
RA95Launcher.exe: 22bf7a1f9f1c2498823e3216541e6012f291c2c0
REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef
Install:
copy: .
@@ -463,7 +462,6 @@ cnc-origin: Command & Conquer (Origin version, English)
RegistryKey: EA Games\CNC and The Covert Operations
RegistryValue: Install Dir
IDFiles:
CNC95Launcher.exe: 1d711adf09ac08738b2599b3092a1b448169b32a
CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30
Install:
copy: .

Binary file not shown.

View File

@@ -109,11 +109,11 @@ InitialAlliedReinforcements = function()
end
CaptureRadarDome = function()
Trigger.OnKilled(Radar, function()
Trigger.OnKilled(RadarDome, function()
player.MarkFailedObjective(CaptureRadarDomeObj)
end)
Trigger.OnCapture(Radar, function()
Trigger.OnCapture(RadarDome, function()
player.MarkCompletedObjective(CaptureRadarDomeObj)
Beacon.New(player, TechLab1.CenterPosition)
Beacon.New(player, TechLab2.CenterPosition)

View File

@@ -630,7 +630,7 @@ Actors:
Refinery: proc
Location: 81,90
Owner: USSR
Radar: dome
RadarDome: dome
Location: 20,83
Owner: USSR
WeaponMeetPoint: waypoint

View File

@@ -120,11 +120,11 @@ InitialAlliedReinforcements = function()
end
CaptureRadarDome = function()
Trigger.OnKilled(Radar, function()
Trigger.OnKilled(RadarDome, function()
player.MarkFailedObjective(CaptureRadarDomeObj)
end)
Trigger.OnCapture(Radar, function()
Trigger.OnCapture(RadarDome, function()
player.MarkCompletedObjective(CaptureRadarDomeObj)
Beacon.New(player, TechLab1.CenterPosition)
Beacon.New(player, TechLab2.CenterPosition)

View File

@@ -618,7 +618,7 @@ Actors:
Refinery: proc
Location: 68,35
Owner: USSR
Radar: dome
RadarDome: dome
Location: 75,86
Owner: USSR
Radar2: dome

View File

@@ -229,7 +229,7 @@ Actors:
Location: 56,97
Owner: Neutral
Actor273: tc01
Owner: Creeps
Owner: Neutral
Location: 24,118
Actor384: mine
Owner: Neutral
@@ -427,10 +427,10 @@ Actors:
Location: 49,18
Owner: Neutral
Actor274: tc01
Owner: Creeps
Owner: Neutral
Location: 42,114
Actor275: tc01
Owner: Creeps
Owner: Neutral
Location: 22,116
Actor132: t17
Location: 29,16
@@ -859,28 +859,28 @@ Actors:
Location: 121,96
Owner: Creeps
Actor276: tc01
Owner: Creeps
Owner: Neutral
Location: 33,121
Actor277: tc02
Owner: Creeps
Owner: Neutral
Location: 32,117
Actor278: t05
Owner: Creeps
Owner: Neutral
Location: 33,122
Actor279: t05
Owner: Creeps
Owner: Neutral
Location: 21,114
Actor280: t02
Owner: Creeps
Owner: Neutral
Location: 30,120
Actor281: t02
Owner: Creeps
Owner: Neutral
Location: 27,113
Actor282: t02
Owner: Creeps
Owner: Neutral
Location: 39,122
Actor283: t02
Owner: Creeps
Owner: Neutral
Location: 31,119
Actor284: tc01
Owner: Neutral

Binary file not shown.

View File

@@ -1582,34 +1582,34 @@ Actors:
Facing: 160
Actor507: t11
Location: 86,42
Owner: Soviets
Owner: Neutral
Actor508: t03
Location: 85,43
Owner: Soviets
Owner: Neutral
Actor509: tc01
Location: 84,39
Owner: Soviets
Owner: Neutral
Actor510: t14
Location: 79,43
Owner: Soviets
Owner: Neutral
Actor511: tc04
Location: 81,42
Owner: Soviets
Owner: Neutral
Actor512: t12
Location: 84,43
Owner: Soviets
Owner: Neutral
Actor513: t01
Location: 67,38
Owner: Soviets
Owner: Neutral
Actor514: tc02
Location: 68,40
Owner: Soviets
Owner: Neutral
Actor515: t15
Location: 69,36
Owner: Soviets
Owner: Neutral
Actor516: t11
Location: 66,39
Owner: Soviets
Owner: Neutral
Actor517: tc04
Location: 35,40
Owner: Neutral

Binary file not shown.

Binary file not shown.

View File

@@ -93,7 +93,7 @@ Actors:
Owner: Neutral
Location: 16,55
Actor57: tc04
Owner: Creeps
Owner: Neutral
Location: 65,150
Actor48: v19
Owner: Neutral
@@ -296,97 +296,97 @@ Actors:
Owner: Neutral
Location: 133,114
Actor236: tc04
Owner: Creeps
Owner: Neutral
Location: 120,115
Actor237: tc04
Owner: Creeps
Owner: Neutral
Location: 130,115
Actor238: tc01
Owner: Creeps
Owner: Neutral
Location: 128,110
Actor239: tc01
Owner: Creeps
Owner: Neutral
Location: 118,112
Actor240: tc04
Owner: Creeps
Owner: Neutral
Location: 122,111
Actor241: tc04
Owner: Creeps
Owner: Neutral
Location: 131,110
Actor242: tc04
Owner: Creeps
Owner: Neutral
Location: 135,108
Actor243: tc03
Owner: Creeps
Owner: Neutral
Location: 126,115
Actor244: tc01
Owner: Creeps
Owner: Neutral
Location: 130,108
Actor245: tc04
Owner: Creeps
Owner: Neutral
Location: 138,91
Actor246: tc04
Owner: Creeps
Owner: Neutral
Location: 134,96
Actor247: tc04
Owner: Creeps
Owner: Neutral
Location: 141,99
Actor248: tc04
Owner: Creeps
Owner: Neutral
Location: 136,103
Actor249: tc01
Owner: Creeps
Owner: Neutral
Location: 139,97
Actor250: tc01
Owner: Creeps
Owner: Neutral
Location: 136,93
Actor251: tc01
Owner: Creeps
Owner: Neutral
Location: 134,100
Actor252: tc01
Owner: Creeps
Owner: Neutral
Location: 139,105
Actor253: t16
Owner: Creeps
Owner: Neutral
Location: 141,97
Actor254: t16
Owner: Creeps
Owner: Neutral
Location: 138,95
Actor255: t16
Owner: Creeps
Owner: Neutral
Location: 138,99
Actor256: t16
Owner: Creeps
Owner: Neutral
Location: 133,105
Actor257: t16
Owner: Creeps
Owner: Neutral
Location: 131,102
Actor258: t16
Owner: Creeps
Owner: Neutral
Location: 131,97
Actor259: t16
Owner: Creeps
Owner: Neutral
Location: 131,100
Actor260: t16
Owner: Creeps
Owner: Neutral
Location: 133,103
Actor261: tc04
Owner: Creeps
Owner: Neutral
Location: 131,104
Actor263: t05
Owner: Creeps
Owner: Neutral
Location: 138,101
Actor264: t05
Owner: Creeps
Owner: Neutral
Location: 140,103
Actor265: t05
Owner: Creeps
Owner: Neutral
Location: 136,106
Actor266: t05
Owner: Creeps
Owner: Neutral
Location: 133,106
Actor268: tc04
Owner: Creeps
Owner: Neutral
Location: 130,98
Actor610: v15
Owner: Neutral
@@ -935,10 +935,10 @@ Actors:
Owner: Neutral
Location: 223,192
Actor634: tc04
Owner: Creeps
Owner: Neutral
Location: 194,82
Actor567: t01
Owner: Creeps
Owner: Neutral
Location: 72,93
Actor652: tc01
Owner: Neutral
@@ -1049,10 +1049,10 @@ Actors:
Owner: Neutral
Location: 130,148
Actor654: t06
Owner: Creeps
Owner: Neutral
Location: 166,51
Actor657: gmine
Owner: Creeps
Owner: Neutral
Location: 37,193
Actor658: c3
Owner: Neutral

View File

@@ -415,7 +415,7 @@ Actors:
Actor159: mine
Location: 77,46
Owner: Neutral
Radar: dome
RadarDome: dome
Location: 49,46
Owner: Greece
CYard: fact

View File

@@ -39,7 +39,7 @@ AttackPaths =
}
ReinfInf = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end
@@ -49,7 +49,7 @@ ReinfInf = function()
end
ReinfArmor = function()
if not Radar.IsDead and Radar.Owner == Greece then
if not RadarDome.IsDead and RadarDome.Owner == Greece then
RCheck = true
Reinforcements.Reinforce(Greece, ArmorReinfGreece, ArmorReinfPath, 0, function(soldier)
soldier.Hunt()
@@ -58,7 +58,7 @@ ReinfArmor = function()
end
BringPatrol1 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end
@@ -77,7 +77,7 @@ BringPatrol1 = function()
end
BringPatrol2 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end

View File

@@ -154,7 +154,7 @@ WorldLoaded = function()
Media.PlaySpeechNotification(player, "Win")
end)
Trigger.OnKilled(Radar, function()
Trigger.OnKilled(RadarDome, function()
player.MarkCompletedObjective(KillRadar)
Media.PlaySpeechNotification(player, "ObjectiveMet")
end)

View File

@@ -482,7 +482,7 @@ Actors:
Actor169: mine
Location: 91,87
Owner: Neutral
Radar: dome
RadarDome: dome
Location: 111,50
Owner: Greece
Pbox1: pbox

View File

@@ -39,7 +39,7 @@ AttackPaths =
}
ReinfInf = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end
@@ -49,7 +49,7 @@ ReinfInf = function()
end
ReinfArmor = function()
if not Radar.IsDead and Radar.Owner == Greece then
if not RadarDome.IsDead and RadarDome.Owner == Greece then
RCheck = true
Reinforcements.Reinforce(Greece, ArmorReinfGreece, InfReinfPath, 0, function(soldier)
soldier.Hunt()
@@ -58,7 +58,7 @@ ReinfArmor = function()
end
BringPatrol1 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end
@@ -77,7 +77,7 @@ BringPatrol1 = function()
end
BringPatrol2 = function()
if Radar.IsDead or Radar.Owner ~= Greece then
if RadarDome.IsDead or RadarDome.Owner ~= Greece then
return
end

View File

@@ -139,7 +139,7 @@ WorldLoaded = function()
Media.PlaySpeechNotification(player, "Win")
end)
Trigger.OnKilled(Radar, function()
Trigger.OnKilled(RadarDome, function()
player.MarkCompletedObjective(KillRadar)
Media.PlaySpeechNotification(player, "ObjectiveMet")
end)

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