Compare commits

...

49 Commits

Author SHA1 Message Date
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
100 changed files with 517 additions and 369 deletions

View File

@@ -124,9 +124,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();
});

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

@@ -475,11 +475,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 +507,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

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

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

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

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

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

@@ -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;
}
}
@@ -564,6 +568,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,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.

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)

View File

@@ -225,7 +225,7 @@ Actors:
Location: 69,49
Owner: Greece
Facing: 32
Radar: dome
RadarDome: dome
Location: 70,45
Owner: France
Actor57: fact

View File

@@ -214,7 +214,7 @@ WorldLoaded = function()
Trigger.OnDamaged(mcvGG, Expand)
Trigger.OnDamaged(mcvtransport, Expand)
Trigger.OnKilled(Radar, function()
Trigger.OnKilled(RadarDome, function()
if not player.IsObjectiveCompleted(CaptureObjective) then
player.MarkFailedObjective(CaptureObjective)
end
@@ -224,8 +224,8 @@ WorldLoaded = function()
end
end)
Radar.GrantCondition("french")
Trigger.OnCapture(Radar, function()
RadarDome.GrantCondition("french")
Trigger.OnCapture(RadarDome, function()
HoldObjective = player.AddPrimaryObjective("Defend the Radar Dome.")
player.MarkCompletedObjective(CaptureObjective)
Beacon.New(player, MCVDeploy.CenterPosition)
@@ -244,17 +244,17 @@ WorldLoaded = function()
Reinforcements.Reinforce(Greece, ArmorReinfGreece, AlliedCrossroadsToRadarPath , 0, IdleHunt)
Radar.RevokeCondition(1)
Trigger.ClearAll(Radar)
RadarDome.RevokeCondition(1)
Trigger.ClearAll(RadarDome)
Trigger.AfterDelay(0, function()
Trigger.OnRemovedFromWorld(Radar, function()
Trigger.OnRemovedFromWorld(RadarDome, function()
player.MarkFailedObjective(HoldObjective)
end)
end)
end)
Trigger.OnEnteredProximityTrigger(USSRExpansionPoint.CenterPosition, WDist.New(4 * 1024), function(unit, id)
if unit.Owner == player and Radar.Owner == player then
if unit.Owner == player and RadarDome.Owner == player then
Trigger.RemoveProximityTrigger(id)
Para2()

Binary file not shown.

View File

@@ -147,6 +147,7 @@ Player:
syrd: 1
hpad: 4
afld: 4
afld.ukraine: 4
atek: 1
stek: 1
fix: 1
@@ -161,6 +162,7 @@ Player:
spen: 1%
syrd: 1%
afld: 4%
afld.ukraine: 4%
pbox: 7%
gun: 7%
ftur: 10%
@@ -284,6 +286,7 @@ Player:
syrd: 1
hpad: 4
afld: 4
afld.ukraine: 4
atek: 1
stek: 1
fix: 1
@@ -294,6 +297,8 @@ Player:
kenn: 0.5%
weap: 3%
hpad: 2%
afld: 2%
afld.ukraine: 2%
spen: 1%
syrd: 1%
pbox: 10%
@@ -418,6 +423,7 @@ Player:
syrd: 1
hpad: 8
afld: 8
afld.ukraine: 8
weap: 1
atek: 1
stek: 1
@@ -428,6 +434,7 @@ Player:
weap: 1%
hpad: 20%
afld: 20%
afld.ukraine: 20%
atek: 1%
stek: 1%
spen: 1%

View File

@@ -127,6 +127,7 @@ E2:
Explodes:
Weapon: UnitExplodeSmall
EmptyWeapon: UnitExplodeSmall
DamageSource: Killer
ProducibleWithLevel:
Prerequisites: barracks.upgraded

View File

@@ -409,8 +409,8 @@ JEEP:
WithSpriteTurret:
Cargo:
Types: Infantry
MaxWeight: 2
PipCount: 2
MaxWeight: 1
PipCount: 1
LoadingCondition: notmobile
ProducibleWithLevel:
Prerequisites: vehicles.upgraded
@@ -769,7 +769,10 @@ QTNK:
Armor:
Type: Heavy
Mobile:
RequiresCondition: !deployed
Speed: 56
Chronoshiftable:
RequiresCondition: !deployed
RevealsShroud:
Range: 6c0
RevealGeneratedShroud: False
@@ -777,6 +780,7 @@ QTNK:
Range: 4c0
SelectionDecorations:
MadTank:
DeployedCondition: deployed
Targetable:
TargetTypes: Ground, MADTank, Repair, Vehicle
Selectable:

View File

@@ -1169,19 +1169,19 @@ einstein:
Facings: 8
Tick: 80
die1:
Start: 115
Start: 120
Length: 8
die2:
Start: 123
Start: 128
Length: 8
die3:
Start: 135
Start: 136
Length: 12
die4:
Start: 135
Start: 136
Length: 12
die5:
Start: 147
Start: 148
Length: 17
die6: electro
Length: *
@@ -1215,19 +1215,19 @@ delphi:
Facings: 8
Tick: 80
die1:
Start: 115
Start: 329
Length: 8
die2:
Start: 123
Start: 337
Length: 8
die3:
Start: 135
Start: 345
Length: 12
die4:
Start: 135
Start: 345
Length: 12
die5:
Start: 147
Start: 357
Length: 17
die6: electro
Length: *
@@ -1261,19 +1261,19 @@ chan:
Facings: 8
Tick: 80
die1:
Start: 115
Start: 120
Length: 8
die2:
Start: 123
Start: 128
Length: 8
die3:
Start: 135
Start: 136
Length: 12
die4:
Start: 135
Start: 136
Length: 12
die5:
Start: 147
Start: 148
Length: 17
die6: electro
Length: *

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -277,7 +277,7 @@ TorpTube:
Falloff: 1000, 368, 135, 50, 18, 7, 0
Versus:
None: 40
Wood: 80
Wood: 50
Light: 30
Heavy: 30
Concrete: 100

View File

@@ -377,6 +377,8 @@ lobby-bits: buttons.png
huepicker: 194,0,7,15
protected: 202,0,10,13
protected-disabled: 213,0,10,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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -15,7 +15,6 @@
# openra_ServerName="<ServerName>" (default: "Dedicated Server")
# openra_Mod="<Mod>" (default: ra)
# openra_ListenPort="<number>" (default: 1234)
# openra_ExternalPort="<number>" (default: 1234)
# openra_AdvertiseOnline="<True|False>" (default: True)
# openra_extraflags="<set as needed>"
#
@@ -43,7 +42,6 @@ status_cmd="${name}_status"
: ${openra_ServerName="Dedicated Server"}
: ${openra_Mod="ra"}
: ${openra_ListenPort="1234"}
: ${openra_ExternalPort="1234"}
: ${openra_AdvertiseOnline="True"}
openra_Dedicated="True"
@@ -54,7 +52,6 @@ openra_DedicatedLoop="True"
Server.DedicatedLoop=${openra_DedicatedLoop} \
Server.Name=\"${openra_ServerName}\" \
Server.ListenPort=${openra_ListenPort} \
Server.ExternalPort=${openra_ExternalPort} \
Server.AdvertiseOnline=${openra_AdvertiseOnline}\
${openra_extraflags}"}

View File

@@ -4,7 +4,7 @@
MINIMUM_MONO_VERSION="4.2"
prompt_apt_install_mono_complete() {
command -v mono >/dev/null 2>&1 && return 1
command -v mono >/dev/null 2>&1 && command -v cert-sync >/dev/null 2>&1 && return 1
command -v apt-cache > /dev/null || return 1
command -v xdg-mime > /dev/null || return 1
command -v xdg-open > /dev/null || return 1
@@ -19,6 +19,7 @@ make_version() {
mono_missing_or_old() {
command -v mono >/dev/null 2>&1 || return 0
command -v cert-sync >/dev/null 2>&1 || return 0
MONO_VERSION=$(mono --version | head -n1 | cut -d' ' -f5)
[ "$(make_version "${MONO_VERSION}")" -lt "$(make_version "${MINIMUM_MONO_VERSION}")" ] && return 0
return 1
@@ -43,7 +44,7 @@ if prompt_apt_install_mono_complete; then
fi
if mono_missing_or_old; then
ERROR_MESSAGE="{MODNAME} requires Mono ${MINIMUM_MONO_VERSION} or greater.\nPlease install Mono using your system package manager.\n\nSee http://wiki.openra.net/AppImages for more information."
ERROR_MESSAGE="{MODNAME} requires Mono ${MINIMUM_MONO_VERSION} or greater and the cert-sync utility.\nPlease install Mono using your system package manager.\n\nSee http://wiki.openra.net/AppImages for more information."
if command -v zenity > /dev/null; then
zenity --no-wrap --error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null
elif command -v kdialog > /dev/null; then

View File

@@ -9,7 +9,7 @@ if [[ "$OSTYPE" != "darwin"* ]]; then
command -v genisoimage >/dev/null 2>&1 || { echo >&2 "macOS packaging requires genisoimage."; exit 1; }
fi
LAUNCHER_TAG="osx-launcher-20180723"
LAUNCHER_TAG="osx-launcher-20171118"
if [ $# -ne "2" ]; then
echo "Usage: `basename $0` tag outputdir"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
LAUNCHER_TAG="osx-launcher-20180723"
LAUNCHER_TAG="osx-launcher-20171118"
download_dir="${0%/*}/download/osx"
mkdir -p "$download_dir"