Merge remote-tracking branch 'openra/bleed' into bleed
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -22,6 +22,8 @@ mods/*/packages/*.[mM][iI][xX]
|
||||
# backup files by various editors
|
||||
*~
|
||||
*.orig
|
||||
\#*
|
||||
.*.sw?
|
||||
# dependency DLLs (different for every platform!)
|
||||
cg.dll
|
||||
cgGL.dll
|
||||
@@ -32,8 +34,6 @@ cgGL.dll
|
||||
*.pidb
|
||||
*.userprefs
|
||||
|
||||
packaging/windows/*.exe
|
||||
|
||||
# osx crap
|
||||
.DS_Store
|
||||
|
||||
@@ -52,8 +52,3 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
*.config
|
||||
*.resources
|
||||
|
||||
# other crap
|
||||
Logs/
|
||||
Replays/
|
||||
\#*
|
||||
.*.sw?
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace OpenRA.FileFormats
|
||||
ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value );
|
||||
return true;
|
||||
}
|
||||
else if ( n.Count > 1 )
|
||||
{
|
||||
throw new InvalidOperationException("The field {0} has multiple definitions:\n{1}"
|
||||
.F(fieldName, n.Select(m => "\t- " + m.Location).JoinWith("\n")));
|
||||
}
|
||||
throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -105,11 +105,14 @@ namespace OpenRA.FileFormats
|
||||
levels.Add(new List<MiniYamlNode>());
|
||||
|
||||
var lineNo = 0;
|
||||
foreach (var line in lines)
|
||||
foreach (var ll in lines)
|
||||
{
|
||||
var line = ll;
|
||||
++lineNo;
|
||||
if (line.Contains('#'))
|
||||
line = line.Substring(0, line.IndexOf('#')).TrimEnd(' ', '\t');
|
||||
var t = line.TrimStart(' ', '\t');
|
||||
if (t.Length == 0 || t[0] == '#')
|
||||
if (t.Length == 0)
|
||||
continue;
|
||||
var level = line.Length - t.Length;
|
||||
var location = new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo };
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace OpenRA
|
||||
{
|
||||
var isNetTick = LocalTick % NetTickScale == 0;
|
||||
|
||||
if (!isNetTick || orderManager.IsReadyForNextFrame)
|
||||
if ((!isNetTick || orderManager.IsReadyForNextFrame) && !orderManager.GamePaused )
|
||||
{
|
||||
++orderManager.LocalFrameNumber;
|
||||
|
||||
@@ -188,6 +188,8 @@ namespace OpenRA
|
||||
else
|
||||
if (orderManager.NetFrameNumber == 0)
|
||||
orderManager.LastTickTime = Environment.TickCount;
|
||||
|
||||
viewport.Tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ using OpenRA.Server;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
public enum MouseScrollType { Disabled, Standard, Inverted }
|
||||
public enum SoundCashTicks { Disabled, Normal, Extreme }
|
||||
|
||||
public class ServerSettings
|
||||
{
|
||||
public string Name = "OpenRA Game";
|
||||
@@ -26,8 +29,11 @@ namespace OpenRA.GameRules
|
||||
public int ExternalPort = 1234;
|
||||
public bool AdvertiseOnline = true;
|
||||
public string MasterServer = "http://master.open-ra.org/";
|
||||
public bool AllowUPnP = true;
|
||||
public bool AllowCheats = false;
|
||||
public string Map = null;
|
||||
public string[] Ban = null;
|
||||
public int TimeOut = 0;
|
||||
|
||||
public ServerSettings() { }
|
||||
|
||||
@@ -38,8 +44,11 @@ namespace OpenRA.GameRules
|
||||
ExternalPort = other.ExternalPort;
|
||||
AdvertiseOnline = other.AdvertiseOnline;
|
||||
MasterServer = other.MasterServer;
|
||||
AllowUPnP = other.AllowUPnP;
|
||||
AllowCheats = other.AllowCheats;
|
||||
Map = other.Map;
|
||||
Ban = other.Ban;
|
||||
TimeOut = other.TimeOut;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +86,8 @@ namespace OpenRA.GameRules
|
||||
public bool Repeat = false;
|
||||
public bool ShellmapMusic = true;
|
||||
public string Engine = "AL";
|
||||
|
||||
public SoundCashTicks SoundCashTickType = SoundCashTicks.Extreme;
|
||||
}
|
||||
|
||||
public class PlayerSettings
|
||||
@@ -86,8 +97,6 @@ namespace OpenRA.GameRules
|
||||
public string LastServer = "localhost:1234";
|
||||
}
|
||||
|
||||
public enum MouseScrollType { Disabled, Standard, Inverted }
|
||||
|
||||
public class GameSettings
|
||||
{
|
||||
public string[] Mods = { "ra" };
|
||||
|
||||
@@ -27,10 +27,9 @@ namespace OpenRA.Graphics
|
||||
public int Facings { get { return facings; } }
|
||||
public int Tick { get { return tick; } }
|
||||
|
||||
string srcOverride;
|
||||
public Sequence(string unit, string name, MiniYaml info)
|
||||
{
|
||||
srcOverride = info.Value;
|
||||
var srcOverride = info.Value;
|
||||
Name = name;
|
||||
var d = info.NodesDict;
|
||||
|
||||
@@ -62,26 +61,6 @@ namespace OpenRA.Graphics
|
||||
info.Nodes[0].Location));
|
||||
}
|
||||
|
||||
public MiniYaml Save()
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
|
||||
root.Add(new MiniYamlNode("Start", start.ToString()));
|
||||
|
||||
if (length > 1 && (start != 0 || length != sprites.Length - start))
|
||||
root.Add(new MiniYamlNode("Length", length.ToString()));
|
||||
else if (length > 1 && length == sprites.Length - start)
|
||||
root.Add(new MiniYamlNode("Length", "*"));
|
||||
|
||||
if (facings > 1)
|
||||
root.Add(new MiniYamlNode("Facings", facings.ToString()));
|
||||
|
||||
if (tick != 40)
|
||||
root.Add(new MiniYamlNode("Tick", tick.ToString()));
|
||||
|
||||
return new MiniYaml(srcOverride, root);
|
||||
}
|
||||
|
||||
public Sprite GetSprite( int frame )
|
||||
{
|
||||
return GetSprite( frame, 0 );
|
||||
|
||||
@@ -199,7 +199,18 @@ namespace OpenRA
|
||||
{
|
||||
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order PauseRequest()
|
||||
{
|
||||
return new Order("PauseRequest", null, false) { IsImmediate = true, TargetString="" }; //TODO: targetbool?
|
||||
}
|
||||
|
||||
public static Order PauseGame()
|
||||
{
|
||||
return new Order("PauseGame", null, false) { IsImmediate = true, TargetString=""}; //TODO: targetbool?
|
||||
}
|
||||
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace OpenRA.Network
|
||||
public int LastTickTime = Environment.TickCount;
|
||||
|
||||
public bool GameStarted { get { return NetFrameNumber != 0; } }
|
||||
public bool GamePaused {get; set;}
|
||||
public IConnection Connection { get; private set; }
|
||||
|
||||
public readonly int SyncHeaderSize = 9;
|
||||
|
||||
@@ -70,6 +70,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Ban;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
public int RandomSeed = 0;
|
||||
|
||||
@@ -94,6 +94,19 @@ namespace OpenRA.Network
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case "PauseGame":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if(client != null)
|
||||
{
|
||||
orderManager.GamePaused = !orderManager.GamePaused;
|
||||
var pausetext = "The game is {0} by {1}".F( orderManager.GamePaused ? "paused" : "un-paused", client.Name );
|
||||
Game.AddChatLine(Color.White, "", pausetext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "HandshakeRequest":
|
||||
{
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
<Compile Include="Server\Server.cs" />
|
||||
<Compile Include="Server\ServerOrder.cs" />
|
||||
<Compile Include="Server\TraitInterfaces.cs" />
|
||||
<Compile Include="Server\UPnP.cs" />
|
||||
<Compile Include="Sound.cs" />
|
||||
<Compile Include="Support\Arguments.cs" />
|
||||
<Compile Include="Support\PerfHistory.cs" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -15,11 +15,15 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.NetworkInformation;
|
||||
using UPnP;
|
||||
using System.Threading;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Network;
|
||||
|
||||
using XTimer = System.Timers.Timer;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
public class Server
|
||||
@@ -45,6 +49,7 @@ namespace OpenRA.Server
|
||||
public ServerSettings Settings;
|
||||
public ModData ModData;
|
||||
public Map Map;
|
||||
XTimer gameTimeout;
|
||||
|
||||
volatile bool shutdown = false;
|
||||
public void Shutdown() { shutdown = true; }
|
||||
@@ -64,6 +69,9 @@ namespace OpenRA.Server
|
||||
|
||||
randomSeed = (int)DateTime.Now.ToBinary();
|
||||
|
||||
if (settings.AllowUPnP)
|
||||
PortForward();
|
||||
|
||||
foreach (var trait in modData.Manifest.ServerTraits)
|
||||
ServerTraits.Add( modData.ObjectCreator.CreateObject<ServerTrait>(trait) );
|
||||
|
||||
@@ -71,6 +79,7 @@ namespace OpenRA.Server
|
||||
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
|
||||
lobbyInfo.GlobalSettings.Map = settings.Map;
|
||||
lobbyInfo.GlobalSettings.ServerName = settings.Name;
|
||||
lobbyInfo.GlobalSettings.Ban = settings.Ban;
|
||||
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerStart>())
|
||||
t.ServerStarted(this);
|
||||
@@ -122,6 +131,20 @@ namespace OpenRA.Server
|
||||
} ) { IsBackground = true }.Start();
|
||||
}
|
||||
|
||||
void PortForward()
|
||||
{
|
||||
if (UPnP.NAT.Discover())
|
||||
{
|
||||
Log.Write("server", "UPnP-enabled router discovered.");
|
||||
UPnP.NAT.ForwardPort(Port, ProtocolType.Tcp, "OpenRA"); //might timeout after second try
|
||||
Log.Write("server", "Port {0} (TCP) has been forwarded.", Port);
|
||||
Log.Write("server", "Your IP is: {0}", UPnP.NAT.GetExternalIP() );
|
||||
}
|
||||
else
|
||||
Log.Write("server", "No UPnP-enabled router detected.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* lobby rework todo:
|
||||
* - "teams together" option for team games -- will eliminate most need
|
||||
* for manual spawnpoint choosing.
|
||||
@@ -205,6 +228,21 @@ namespace OpenRA.Server
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if IP is banned
|
||||
if (lobbyInfo.GlobalSettings.Ban != null)
|
||||
{
|
||||
var remote_addr = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
|
||||
if (lobbyInfo.GlobalSettings.Ban.Contains(remote_addr))
|
||||
{
|
||||
Console.WriteLine("Rejected connection from "+client.Name+"("+newConn.socket.RemoteEndPoint+"); Banned.");
|
||||
Log.Write("server", "Rejected connection from {0}; Banned.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
SendOrderTo(newConn, "ServerError", "You are banned from the server!");
|
||||
DropClient(newConn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Promote connection to a valid client
|
||||
preConns.Remove(newConn);
|
||||
conns.Add(newConn);
|
||||
@@ -332,6 +370,9 @@ namespace OpenRA.Server
|
||||
|
||||
void InterpretServerOrder(Connection conn, ServerOrder so)
|
||||
{
|
||||
var fromClient = GetClient(conn);
|
||||
var fromIndex = fromClient != null ? fromClient.Index : 0;
|
||||
|
||||
switch (so.Name)
|
||||
{
|
||||
case "Command":
|
||||
@@ -347,17 +388,23 @@ namespace OpenRA.Server
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "HandshakeResponse":
|
||||
ValidateClient(conn, so.Data);
|
||||
break;
|
||||
|
||||
case "Chat":
|
||||
case "TeamChat":
|
||||
var fromClient = GetClient(conn);
|
||||
var fromIndex = fromClient != null ? fromClient.Index : 0;
|
||||
|
||||
foreach (var c in conns.Except(conn).ToArray())
|
||||
DispatchOrdersToClient(c, fromIndex, 0, so.Serialize());
|
||||
break;
|
||||
break;
|
||||
|
||||
case "PauseRequest":
|
||||
foreach (var c in conns.ToArray())
|
||||
{ var x = Order.PauseGame();
|
||||
DispatchOrdersToClient(c, fromIndex, 0, x.Serialize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +453,9 @@ namespace OpenRA.Server
|
||||
public void StartGame()
|
||||
{
|
||||
GameStarted = true;
|
||||
listener.Stop();
|
||||
Console.WriteLine("Game started");
|
||||
|
||||
foreach( var c in conns )
|
||||
foreach( var d in conns )
|
||||
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
|
||||
@@ -419,6 +469,18 @@ namespace OpenRA.Server
|
||||
|
||||
foreach (var t in ServerTraits.WithInterface<IStartGame>())
|
||||
t.GameStarted(this);
|
||||
|
||||
// Check TimeOut
|
||||
if ( Settings.TimeOut > 10000 )
|
||||
{
|
||||
gameTimeout = new XTimer(Settings.TimeOut);
|
||||
gameTimeout.Elapsed += (_,e) =>
|
||||
{
|
||||
Console.WriteLine("Timeout at {0}!!!", e.SignalTime);
|
||||
Environment.Exit(0);
|
||||
};
|
||||
gameTimeout.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
137
OpenRA.Game/Server/UPnP.cs
Normal file
137
OpenRA.Game/Server/UPnP.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2008-2009 http://www.codeproject.com/Members/Harold-Aptroot
|
||||
* Source: http://www.codeproject.com/Articles/27992/NAT-Traversal-with-UPnP-in-C
|
||||
* This file is licensed under A Public Domain dedication.
|
||||
* For more information, see http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
|
||||
namespace UPnP
|
||||
{
|
||||
public class NAT
|
||||
{
|
||||
public static TimeSpan _timeout = new TimeSpan(0, 0, 0, 3);
|
||||
static string _serviceUrl;
|
||||
|
||||
public static bool Discover()
|
||||
{
|
||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||
string req = "M-SEARCH * HTTP/1.1\r\n" +
|
||||
"HOST: 239.255.255.250:1900\r\n" +
|
||||
"ST:upnp:rootdevice\r\n" +
|
||||
"MAN:\"ssdp:discover\"\r\n" +
|
||||
"MX:3\r\n\r\n";
|
||||
byte[] data = Encoding.ASCII.GetBytes(req);
|
||||
IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
|
||||
byte[] buffer = new byte[0x1000];
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
do
|
||||
{
|
||||
s.SendTo(data, ipe);
|
||||
|
||||
int length = 0;
|
||||
do
|
||||
{
|
||||
length = s.Receive(buffer);
|
||||
|
||||
string resp = Encoding.ASCII.GetString(buffer, 0, length).ToLower();
|
||||
if (resp.Contains("upnp:rootdevice"))
|
||||
{
|
||||
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
||||
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
||||
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
|
||||
return true;
|
||||
}
|
||||
} while (length > 0);
|
||||
} while ((start - DateTime.Now) < _timeout);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String GetServiceUrl(string resp)
|
||||
{
|
||||
XmlDocument desc = new XmlDocument();
|
||||
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
|
||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
||||
if (!typen.Value.Contains("InternetGatewayDevice"))
|
||||
return null;
|
||||
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
|
||||
if (node == null)
|
||||
return null;
|
||||
Uri respUri = new Uri(resp);
|
||||
Uri combinedUri = new Uri(respUri, node.Value);
|
||||
return combinedUri.AbsoluteUri;
|
||||
}
|
||||
|
||||
public static void ForwardPort(int port, ProtocolType protocol, string description)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
string body = String.Format("<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"+
|
||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
||||
"<NewProtocol>{1}</NewProtocol><NewInternalPort>{0}</NewInternalPort>" +
|
||||
"<NewInternalClient>{2}</NewInternalClient><NewEnabled>1</NewEnabled>" +
|
||||
"<NewPortMappingDescription>{3}</NewPortMappingDescription>"+
|
||||
"<NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>",
|
||||
port, protocol.ToString().ToUpper(),Dns.GetHostAddresses(Dns.GetHostName())[0], description);
|
||||
SOAPRequest(_serviceUrl, body, "AddPortMapping");
|
||||
}
|
||||
|
||||
public static void DeleteForwardingRule(int port, ProtocolType protocol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
string body = String.Format("<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
||||
"<NewProtocol>{1}</NewProtocol></u:DeletePortMapping>", port, protocol.ToString().ToUpper() );
|
||||
SOAPRequest(_serviceUrl, body, "DeletePortMapping");
|
||||
}
|
||||
|
||||
public static IPAddress GetExternalIP()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
XmlDocument xdoc = SOAPRequest(_serviceUrl, "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
||||
"</u:GetExternalIPAddress>", "GetExternalIPAddress");
|
||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
|
||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||
string IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value;
|
||||
return IPAddress.Parse(IP);
|
||||
}
|
||||
|
||||
private static XmlDocument SOAPRequest(string url, string soap, string function)
|
||||
{
|
||||
string req = "<?xml version=\"1.0\"?>" +
|
||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
|
||||
"<s:Body>" +
|
||||
soap +
|
||||
"</s:Body>" +
|
||||
"</s:Envelope>";
|
||||
WebRequest r = HttpWebRequest.Create(url);
|
||||
r.Method = "POST";
|
||||
byte[] b = Encoding.UTF8.GetBytes(req);
|
||||
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
||||
r.ContentType = "text/xml; charset=\"utf-8\"";
|
||||
r.ContentLength = b.Length;
|
||||
r.GetRequestStream().Write(b, 0, b.Length);
|
||||
XmlDocument resp = new XmlDocument();
|
||||
WebResponse wres = r.GetResponse();
|
||||
Stream ress = wres.GetResponseStream();
|
||||
resp.Load(ress);
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public int HP { get { return hp; } }
|
||||
public readonly int MaxHP;
|
||||
public int MaxHP;
|
||||
|
||||
public bool IsDead { get { return hp <= 0; } }
|
||||
public bool RemoveOnDeath = true;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -62,6 +63,8 @@ namespace OpenRA.Traits
|
||||
{
|
||||
readonly Player Owner;
|
||||
int AdviceInterval;
|
||||
|
||||
int cashtickallowed = 0;
|
||||
|
||||
public PlayerResources(Actor self, PlayerResourcesInfo info)
|
||||
{
|
||||
@@ -134,7 +137,11 @@ namespace OpenRA.Traits
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
|
||||
|
||||
if(cashtickallowed > 0) {
|
||||
cashtickallowed = cashtickallowed - 1;
|
||||
}
|
||||
|
||||
OreCapacity = self.World.ActorsWithTrait<IStoreOre>()
|
||||
.Where(a => a.Actor.Owner == Owner)
|
||||
.Sum(a => a.Trait.Capacity);
|
||||
@@ -158,12 +165,12 @@ namespace OpenRA.Traits
|
||||
if (DisplayCash < Cash)
|
||||
{
|
||||
DisplayCash += move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
|
||||
playCashTickUp(self);
|
||||
}
|
||||
else if (DisplayCash > Cash)
|
||||
{
|
||||
DisplayCash -= move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
playCashTickDown(self);
|
||||
}
|
||||
|
||||
diff = Math.Abs(Ore - DisplayOre);
|
||||
@@ -173,13 +180,36 @@ namespace OpenRA.Traits
|
||||
if (DisplayOre < Ore)
|
||||
{
|
||||
DisplayOre += move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
|
||||
playCashTickUp(self);
|
||||
}
|
||||
else if (DisplayOre > Ore)
|
||||
{
|
||||
DisplayOre -= move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
playCashTickDown(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void playCashTickUp(Actor self)
|
||||
{
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
if (Game.Settings.Sound.SoundCashTickType != SoundCashTicks.Disabled)
|
||||
{
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
|
||||
}
|
||||
}
|
||||
|
||||
public void playCashTickDown(Actor self)
|
||||
{
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
if (
|
||||
Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Extreme ||
|
||||
(Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Normal && cashtickallowed == 0)
|
||||
) {
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
cashtickallowed = 3;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public override void Draw()
|
||||
{
|
||||
var s = WidgetUtils.FormatTime(Game.LocalTick);
|
||||
var font = Game.Renderer.Fonts["Title"];
|
||||
var rb = RenderBounds;
|
||||
|
||||
var s = WidgetUtils.FormatTime(Game.LocalTick) + (Game.orderManager.GamePaused?" (paused)":"");
|
||||
var pos = new float2(rb.Left - font.Measure(s).X / 2, rb.Top);
|
||||
|
||||
font.DrawTextWithContrast(s, pos, Color.White, Color.Black, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +148,10 @@ namespace OpenRA.Widgets
|
||||
world.Selection.DoControlGroup(world, e.KeyName[0] - '0', e.Modifiers);
|
||||
return true;
|
||||
}
|
||||
else if(e.KeyName == "pause" || e.KeyName == "f3")
|
||||
{
|
||||
world.IssueOrder(Order.PauseRequest());
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace OpenRA
|
||||
|
||||
while (frameEndActions.Count != 0)
|
||||
frameEndActions.Dequeue()(this);
|
||||
Game.viewport.Tick();
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> Actors { get { return actors; } }
|
||||
|
||||
@@ -15,31 +15,43 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Cnc
|
||||
{
|
||||
class RenderCargoInfo : ITraitInfo, Requires<CargoInfo>
|
||||
public class RenderCargoInfo : ITraitInfo, Requires<CargoInfo>
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new RenderCargo(init.self); }
|
||||
/* altitude of the cargo, relative to us. -ve is underneath us */
|
||||
public readonly int RelativeAltitude = 0;
|
||||
|
||||
public object Create(ActorInitializer init) { return new RenderCargo(init.self, this); }
|
||||
}
|
||||
|
||||
public class RenderCargo : IRenderModifier
|
||||
{
|
||||
Cargo cargo;
|
||||
IFacing facing;
|
||||
IMove move;
|
||||
RenderCargoInfo Info;
|
||||
|
||||
public RenderCargo(Actor self)
|
||||
public RenderCargo(Actor self, RenderCargoInfo info)
|
||||
{
|
||||
cargo = self.Trait<Cargo>();
|
||||
facing = self.TraitOrDefault<IFacing>();
|
||||
move = self.Trait<IMove>();
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
foreach (var c in cargo.Passengers)
|
||||
{
|
||||
c.Trait<ITeleportable>().SetPxPosition( c, self.Trait<IHasLocation>().PxPosition );
|
||||
if (facing != null && c.HasTrait<IFacing>())
|
||||
c.Trait<IFacing>().Facing = facing.Facing;
|
||||
c.Trait<ITeleportable>().SetPxPosition( c, move.PxPosition );
|
||||
|
||||
var cargoFacing = c.TraitOrDefault<IFacing>();
|
||||
if (facing != null && cargoFacing != null)
|
||||
cargoFacing.Facing = facing.Facing;
|
||||
}
|
||||
return r.Concat(cargo.Passengers.SelectMany(a => a.Render()));
|
||||
|
||||
return r.Concat(cargo.Passengers.SelectMany(a => a.Render())
|
||||
.Select(a => a.WithPos(a.Pos - new float2(0, Info.RelativeAltitude))
|
||||
.WithZOffset(a.ZOffset + Info.RelativeAltitude)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,10 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
|
||||
Game.viewport.Zoom = graphicsSettings.PixelDouble ? 2 : 1;
|
||||
};
|
||||
|
||||
var showShellmapCheckbox = generalPane.Get<CheckboxWidget>("SHOW_SHELLMAP");
|
||||
showShellmapCheckbox.IsChecked = () => gameSettings.ShowShellmap;
|
||||
showShellmapCheckbox.OnClick = () => gameSettings.ShowShellmap ^= true;
|
||||
|
||||
generalPane.Get("WINDOW_RESOLUTION").IsVisible = () => graphicsSettings.Mode == WindowMode.Windowed;
|
||||
var windowWidth = generalPane.Get<TextFieldWidget>("WINDOW_WIDTH");
|
||||
windowWidth.Text = graphicsSettings.WindowedSize.X.ToString();
|
||||
|
||||
@@ -28,8 +28,13 @@ namespace OpenRA.Mods.RA.Activities
|
||||
if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
|
||||
return NextActivity;
|
||||
|
||||
var capturable = target.TraitOrDefault<Capturable>();
|
||||
if (capturable != null && capturable.CaptureInProgress && capturable.Captor.Owner.Stances[self.Owner] == Stance.Ally)
|
||||
return NextActivity;
|
||||
|
||||
var sellable = target.TraitOrDefault<Sellable>();
|
||||
if (sellable != null && sellable.Selling) return NextActivity;
|
||||
if (sellable != null && sellable.Selling)
|
||||
return NextActivity;
|
||||
|
||||
target.Trait<Capturable>().BeginCapture(target, self);
|
||||
self.World.AddFrameEndTask(w => self.Destroy());
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public class Capturable : ITick
|
||||
{
|
||||
[Sync] Actor captor = null;
|
||||
[Sync] public Actor Captor = null;
|
||||
[Sync] public int CaptureProgressTime = 0;
|
||||
public bool CaptureInProgress { get { return captor != null; } }
|
||||
public bool CaptureInProgress { get { return Captor != null; } }
|
||||
public CapturableInfo Info;
|
||||
|
||||
public Capturable(CapturableInfo info)
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
CaptureProgressTime = 0;
|
||||
|
||||
this.captor = captor;
|
||||
this.Captor = captor;
|
||||
|
||||
if (self.Owner != self.World.WorldActor.Owner)
|
||||
self.ChangeOwner(self.World.WorldActor.Owner);
|
||||
@@ -57,17 +57,28 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
self.ChangeOwner(captor.Owner);
|
||||
self.ChangeOwner(Captor.Owner);
|
||||
ChangeCargoOwner(self, Captor.Owner);
|
||||
|
||||
foreach (var t in self.TraitsImplementing<INotifyCapture>())
|
||||
t.OnCapture(self, captor, self.Owner, captor.Owner);
|
||||
t.OnCapture(self, Captor, self.Owner, Captor.Owner);
|
||||
|
||||
foreach (var t in captor.World.ActorsWithTrait<INotifyOtherCaptured>())
|
||||
t.Trait.OnActorCaptured(t.Actor, self, captor, self.Owner, captor.Owner);
|
||||
foreach (var t in Captor.World.ActorsWithTrait<INotifyOtherCaptured>())
|
||||
t.Trait.OnActorCaptured(t.Actor, self, Captor, self.Owner, Captor.Owner);
|
||||
|
||||
captor = null;
|
||||
Captor = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeCargoOwner(Actor self, Player captor)
|
||||
{
|
||||
var cargo = self.TraitOrDefault<Cargo>();
|
||||
if (cargo == null)
|
||||
return;
|
||||
|
||||
foreach (var c in cargo.Passengers)
|
||||
c.Owner = captor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -21,14 +22,17 @@ namespace OpenRA.Mods.RA
|
||||
class CapturesInfo : ITraitInfo
|
||||
{
|
||||
public string[] CaptureTypes = {"building"};
|
||||
public object Create(ActorInitializer init) { return new Captures(this); }
|
||||
public object Create(ActorInitializer init) { return new Captures(init.self, this); }
|
||||
}
|
||||
|
||||
class Captures : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public readonly CapturesInfo Info;
|
||||
public Captures(CapturesInfo info)
|
||||
readonly Actor self;
|
||||
|
||||
public Captures(Actor self, CapturesInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
Info = info;
|
||||
}
|
||||
|
||||
@@ -36,7 +40,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new CaptureOrderTargeter(Info.CaptureTypes);
|
||||
yield return new CaptureOrderTargeter(Info.CaptureTypes, target => CanEnter(target));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,13 +54,16 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "CaptureActor") ? "Attack" : null;
|
||||
return (order.OrderString == "CaptureActor"
|
||||
&& CanEnter(order.TargetActor)) ? "Attack" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "CaptureActor")
|
||||
{
|
||||
if (!CanEnter(order.TargetActor)) return;
|
||||
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
||||
|
||||
self.CancelActivity();
|
||||
@@ -64,15 +71,24 @@ namespace OpenRA.Mods.RA
|
||||
self.QueueActivity(new CaptureActor(order.TargetActor));
|
||||
}
|
||||
}
|
||||
|
||||
bool CanEnter(Actor target)
|
||||
{
|
||||
var c = target.TraitOrDefault<Capturable>();
|
||||
return c != null && ( !c.CaptureInProgress || c.Captor.Owner.Stances[self.Owner] != Stance.Ally );
|
||||
}
|
||||
}
|
||||
|
||||
class CaptureOrderTargeter : UnitTraitOrderTargeter<Capturable>
|
||||
{
|
||||
readonly string[] captureTypes;
|
||||
public CaptureOrderTargeter(string[] captureTypes)
|
||||
: base( "CaptureActor", 6, "enter", true, true )
|
||||
readonly Func<Actor, bool> useEnterCursor;
|
||||
|
||||
public CaptureOrderTargeter(string[] captureTypes, Func<Actor, bool> useEnterCursor)
|
||||
: base( "CaptureActor", 6, "enter", true, true)
|
||||
{
|
||||
this.captureTypes = captureTypes;
|
||||
this.useEnterCursor = useEnterCursor;
|
||||
}
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
@@ -87,9 +103,10 @@ namespace OpenRA.Mods.RA
|
||||
if( playerRelationship == Stance.Neutral && !ci.AllowNeutral ) return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
|
||||
if (captureTypes.Contains(ci.Type))
|
||||
{
|
||||
cursor = "enter";
|
||||
cursor = useEnterCursor(target) ? "enter" : "enter-blocked";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,8 @@ namespace OpenRA.Mods.RA
|
||||
if (remainingTime > 0 && canCloak)
|
||||
if (--remainingTime <= 0)
|
||||
Sound.Play(info.CloakSound, self.CenterLocation);
|
||||
if (self.IsDisabled())
|
||||
Uncloak();
|
||||
}
|
||||
|
||||
public bool IsVisible(Actor self)
|
||||
|
||||
@@ -38,13 +38,10 @@ namespace OpenRA.Mods.RA
|
||||
class Crate : ITick, IOccupySpace, ITeleportable, ICrushable, ISync
|
||||
{
|
||||
readonly Actor self;
|
||||
[Sync]
|
||||
int ticks;
|
||||
|
||||
[Sync]
|
||||
public int2 Location;
|
||||
|
||||
[Sync] int ticks;
|
||||
[Sync] public int2 Location;
|
||||
CrateInfo Info;
|
||||
|
||||
public Crate(ActorInitializer init, CrateInfo info)
|
||||
{
|
||||
this.self = init.self;
|
||||
|
||||
@@ -99,13 +99,14 @@ namespace OpenRA.Mods.RA.Effects
|
||||
|
||||
Altitude += Math.Sign(targetAltitude - Altitude);
|
||||
|
||||
Facing = Traits.Util.TickFacing(Facing,
|
||||
Traits.Util.GetFacing(dist, Facing),
|
||||
Info.ROT);
|
||||
if (Args.target.IsValid)
|
||||
Facing = Traits.Util.TickFacing(Facing,
|
||||
Traits.Util.GetFacing(dist, Facing),
|
||||
Info.ROT);
|
||||
|
||||
anim.Tick();
|
||||
|
||||
if (dist.LengthSquared < MissileCloseEnough * MissileCloseEnough || !Args.target.IsValid )
|
||||
if (dist.LengthSquared < MissileCloseEnough * MissileCloseEnough && Args.target.IsValid )
|
||||
Explode(world);
|
||||
|
||||
// TODO: Replace this with a lookup table
|
||||
|
||||
@@ -13,7 +13,7 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class ExplodesInfo : TraitInfo<Explodes>
|
||||
class ExplodesInfo : ITraitInfo
|
||||
{
|
||||
[WeaponReference]
|
||||
public readonly string Weapon = "UnitExplode";
|
||||
@@ -21,13 +21,23 @@ namespace OpenRA.Mods.RA
|
||||
public readonly string EmptyWeapon = "UnitExplode";
|
||||
|
||||
public readonly int Chance = 100;
|
||||
public readonly int[] InfDeath = null;
|
||||
|
||||
public object Create (ActorInitializer init) { return new Explodes(this); }
|
||||
}
|
||||
|
||||
class Explodes : INotifyKilled
|
||||
{
|
||||
readonly ExplodesInfo Info;
|
||||
|
||||
public Explodes( ExplodesInfo info ) { Info = info; }
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
if (self.World.SharedRandom.Next(100) > self.Info.Traits.Get<ExplodesInfo>().Chance)
|
||||
if (self.World.SharedRandom.Next(100) > Info.Chance)
|
||||
return;
|
||||
|
||||
if (Info.InfDeath != null && e.Warhead != null && !Info.InfDeath.Contains(e.Warhead.InfDeath))
|
||||
return;
|
||||
|
||||
var weapon = ChooseWeaponForExplosion(self);
|
||||
@@ -42,9 +52,7 @@ namespace OpenRA.Mods.RA
|
||||
string ChooseWeaponForExplosion(Actor self)
|
||||
{
|
||||
var shouldExplode = self.TraitsImplementing<IExplodeModifier>().All(a => a.ShouldExplode(self));
|
||||
|
||||
var info = self.Info.Traits.Get<ExplodesInfo>();
|
||||
return shouldExplode ? info.Weapon : info.EmptyWeapon;
|
||||
return shouldExplode ? Info.Weapon : Info.EmptyWeapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,13 @@ namespace OpenRA.Mods.RA
|
||||
* - actually steal their exploration before resetting it
|
||||
*/
|
||||
if (self.World.LocalPlayer != null && self.World.LocalPlayer.Stances[self.Owner] == Stance.Ally)
|
||||
{
|
||||
var gpsWatcher = self.Owner.PlayerActor.TraitOrDefault<GpsWatcher>();
|
||||
if (gpsWatcher != null && (gpsWatcher.Granted || gpsWatcher.GrantedAllies))
|
||||
return;
|
||||
|
||||
self.Owner.Shroud.ResetExploration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
public readonly int Speed = 1;
|
||||
public readonly bool OnRails = false;
|
||||
public readonly bool SharesCell = false;
|
||||
public readonly int Altitude;
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new Mobile(init, this); }
|
||||
|
||||
@@ -110,7 +111,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
int2 __fromCell, __toCell;
|
||||
public SubCell fromSubCell, toSubCell;
|
||||
|
||||
int __altitude;
|
||||
//int __altitude;
|
||||
|
||||
[Sync]
|
||||
public int Facing
|
||||
@@ -120,11 +121,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
}
|
||||
|
||||
[Sync]
|
||||
public int Altitude
|
||||
{
|
||||
get { return __altitude; }
|
||||
set { __altitude = value; }
|
||||
}
|
||||
public int Altitude { get; set; }
|
||||
|
||||
public int ROT { get { return Info.ROT; } }
|
||||
public int InitialFacing { get { return Info.InitialFacing; } }
|
||||
|
||||
@@ -95,6 +95,14 @@ namespace OpenRA.Mods.RA.Move
|
||||
public override Activity Tick( Actor self )
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var info = self.Info.Traits.Get<MobileInfo>();
|
||||
|
||||
if (mobile.Altitude != info.Altitude)
|
||||
{
|
||||
if (mobile.Altitude < info.Altitude)
|
||||
++mobile.Altitude;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (destination == mobile.toCell)
|
||||
return NextActivity;
|
||||
|
||||
@@ -48,7 +48,13 @@ namespace OpenRA.Mods.RA.Orders
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(World world) { }
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (world.LocalPlayer != null &&
|
||||
world.LocalPlayer.WinState != WinState.Undefined)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) { }
|
||||
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
|
||||
|
||||
|
||||
@@ -42,7 +42,13 @@ namespace OpenRA.Mods.RA.Orders
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(World world) { }
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (world.LocalPlayer != null &&
|
||||
world.LocalPlayer.WinState != WinState.Undefined)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) { }
|
||||
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Air;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
@@ -25,12 +26,12 @@ namespace OpenRA.Mods.RA.Render
|
||||
var move = self.Trait<IMove>();
|
||||
|
||||
/* rude hack */
|
||||
var visualOffset = (move is Helicopter && move.Altitude > 0)
|
||||
var visualOffset = ((move is Helicopter || move is Mobile) && move.Altitude > 0)
|
||||
? Math.Abs((self.ActorID + Game.LocalTick) / 5 % 4 - 1) - 1 : 0;
|
||||
|
||||
var shadowSprites = r.Select(a => a.WithPalette("shadow"));
|
||||
var flyingSprites = (move.Altitude <= 0) ? r
|
||||
: r.Select(a => a.WithPos(a.Pos - new float2(0, move.Altitude + visualOffset)).WithZOffset(move.Altitude));
|
||||
: r.Select(a => a.WithPos(a.Pos - new float2(0, move.Altitude + visualOffset)).WithZOffset(move.Altitude + a.ZOffset));
|
||||
|
||||
return shadowSprites.Concat(flyingSprites);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,8 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return order.OrderString == "Disguise" ? "Attack" : null;
|
||||
return (order.OrderString == "Disguise"
|
||||
|| order.OrderString == "SpyInfiltrate") ? "Attack" : null;
|
||||
}
|
||||
|
||||
public Color RadarColorOverride(Actor self)
|
||||
|
||||
@@ -435,8 +435,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
}
|
||||
}
|
||||
|
||||
bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
|
||||
|
||||
void CycleReady()
|
||||
{
|
||||
orderManager.IssueOrder(Order.Command("ready"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
Action onExit;
|
||||
Map map;
|
||||
bool advertiseOnline;
|
||||
bool allowUPnP;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public ServerCreationLogic(Widget widget, Action onExit, Action openLobby)
|
||||
@@ -64,6 +65,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
var advertiseCheckbox = panel.Get<CheckboxWidget>("ADVERTISE_CHECKBOX");
|
||||
advertiseCheckbox.IsChecked = () => advertiseOnline;
|
||||
advertiseCheckbox.OnClick = () => advertiseOnline ^= true;
|
||||
|
||||
var UPnPCheckbox = panel.Get<CheckboxWidget>("UPNP_CHECKBOX");
|
||||
UPnPCheckbox.IsChecked = () => allowUPnP;
|
||||
UPnPCheckbox.OnClick = () => allowUPnP ^= true;
|
||||
}
|
||||
|
||||
void CreateAndJoin()
|
||||
@@ -81,6 +86,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
Game.Settings.Server.ListenPort = listenPort;
|
||||
Game.Settings.Server.ExternalPort = externalPort;
|
||||
Game.Settings.Server.AdvertiseOnline = advertiseOnline;
|
||||
Game.Settings.Server.AllowUPnP = allowUPnP;
|
||||
Game.Settings.Server.Map = map.Uid;
|
||||
Game.Settings.Save();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -71,6 +71,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
// Audio
|
||||
var audio = bg.Get("AUDIO_PANE");
|
||||
var soundSettings = Game.Settings.Sound;
|
||||
|
||||
var soundslider = audio.Get<SliderWidget>("SOUND_VOLUME");
|
||||
soundslider.OnChange += x => Sound.SoundVolume = x;
|
||||
@@ -80,10 +81,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
musicslider.OnChange += x => Sound.MusicVolume = x;
|
||||
musicslider.Value = Sound.MusicVolume;
|
||||
|
||||
var cashticksdropdown = audio.Get<DropDownButtonWidget>("CASH_TICK_TYPE");
|
||||
cashticksdropdown.OnMouseDown = _ => ShowSoundTickDropdown(cashticksdropdown, soundSettings);
|
||||
cashticksdropdown.GetText = () => soundSettings.SoundCashTickType == SoundCashTicks.Extreme ?
|
||||
"Extreme" : soundSettings.SoundCashTickType == SoundCashTicks.Normal ? "Normal" : "Disabled";
|
||||
|
||||
|
||||
// Display
|
||||
var display = bg.Get("DISPLAY_PANE");
|
||||
var gs = Game.Settings.Graphics;
|
||||
|
||||
var GraphicsRendererDropdown = display.Get<DropDownButtonWidget>("GRAPHICS_RENDERER");
|
||||
GraphicsRendererDropdown.OnMouseDown = _ => ShowRendererDropdown(GraphicsRendererDropdown, gs);
|
||||
GraphicsRendererDropdown.GetText = () => gs.Renderer == "Gl" ?
|
||||
"OpenGL" : gs.Renderer == "Cg" ? "Cg Toolkit" : "OpenGL";
|
||||
|
||||
var windowModeDropdown = display.Get<DropDownButtonWidget>("MODE_DROPDOWN");
|
||||
windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, gs);
|
||||
windowModeDropdown.GetText = () => gs.Mode == WindowMode.Windowed ?
|
||||
@@ -138,6 +150,29 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool ShowSoundTickDropdown(DropDownButtonWidget dropdown, SoundSettings audio)
|
||||
{
|
||||
var options = new Dictionary<string, SoundCashTicks>()
|
||||
{
|
||||
{ "Extreme", SoundCashTicks.Extreme },
|
||||
{ "Normal", SoundCashTicks.Normal },
|
||||
{ "Disabled", SoundCashTicks.Disabled },
|
||||
};
|
||||
|
||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => audio.SoundCashTickType == options[o],
|
||||
() => audio.SoundCashTickType = options[o]);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
};
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ShowWindowModeDropdown(DropDownButtonWidget dropdown, GraphicSettings s)
|
||||
{
|
||||
var options = new Dictionary<string, WindowMode>()
|
||||
@@ -159,5 +194,26 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ShowRendererDropdown(DropDownButtonWidget dropdown, GraphicSettings s)
|
||||
{
|
||||
var options = new Dictionary<string, string>()
|
||||
{
|
||||
{ "OpenGL", "Gl" },
|
||||
{ "Cg Toolkit", "Cg" },
|
||||
};
|
||||
|
||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => s.Renderer == options[o],
|
||||
() => s.Renderer = options[o]);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
};
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,5 +398,28 @@ namespace OpenRA.Utility
|
||||
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height,
|
||||
srcImage.Frames.Select( im => im.Image.Select(px => (byte)remap[px]).ToArray() ));
|
||||
}
|
||||
|
||||
public static void TransposeShp(string[] args)
|
||||
{
|
||||
var srcImage = ShpReader.Load(args[1]);
|
||||
|
||||
var srcFrames = srcImage.Frames.ToArray();
|
||||
var destFrames = srcImage.Frames.ToArray();
|
||||
|
||||
for( var z = 3; z < args.Length - 2; z += 3 )
|
||||
{
|
||||
var start = int.Parse(args[z]);
|
||||
var m = int.Parse(args[z+1]);
|
||||
var n = int.Parse(args[z+2]);
|
||||
|
||||
for( var i = 0; i < m; i++ )
|
||||
for( var j = 0; j < n; j++ )
|
||||
destFrames[ start + i*n + j ] = srcFrames[ start + j*m + i ];
|
||||
}
|
||||
|
||||
using( var destStream = File.Create(args[2]) )
|
||||
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height,
|
||||
destFrames.Select(f => f.Image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA.Utility
|
||||
{ "--tmp-png", Command.ConvertTmpToPng },
|
||||
{ "--remap", Command.RemapShp },
|
||||
{ "--r8", Command.ConvertR8ToPng },
|
||||
{ "--transpose", Command.TransposeShp },
|
||||
};
|
||||
|
||||
if (args.Length == 0) { PrintUsage(); return; }
|
||||
@@ -61,6 +62,7 @@ namespace OpenRA.Utility
|
||||
Console.WriteLine(" --tmp-png MOD[,MOD]* THEATER FILES Extract terrain tiles to PNG");
|
||||
Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette");
|
||||
Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--transparent] [--infrantry] [--vehicle] [--projectile] [--building] [--wall] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type for correct offset to append multiple frames to one PNG named by filename optionally setting up transparency.");
|
||||
Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START.");
|
||||
}
|
||||
|
||||
static string GetNamedArg(string[] args, string arg)
|
||||
|
||||
@@ -197,7 +197,7 @@ Container@PLAYER_WIDGETS:
|
||||
ToggleButton@BUILDING:
|
||||
Width:30
|
||||
Height:30
|
||||
Key: y
|
||||
Key: q
|
||||
TooltipText: Buildings
|
||||
TooltipContainer:TOOLTIP_CONTAINER
|
||||
ClickSound:button.aud
|
||||
@@ -211,7 +211,7 @@ Container@PLAYER_WIDGETS:
|
||||
X:35
|
||||
Width:30
|
||||
Height:30
|
||||
Key: u
|
||||
Key: w
|
||||
TooltipText: Defense
|
||||
TooltipContainer:TOOLTIP_CONTAINER
|
||||
ClickSound:button.aud
|
||||
@@ -225,7 +225,7 @@ Container@PLAYER_WIDGETS:
|
||||
X:70
|
||||
Width:30
|
||||
Height:30
|
||||
Key: i
|
||||
Key: e
|
||||
TooltipText: Infantry
|
||||
TooltipContainer:TOOLTIP_CONTAINER
|
||||
ClickSound:button.aud
|
||||
@@ -239,7 +239,7 @@ Container@PLAYER_WIDGETS:
|
||||
X:105
|
||||
Width:30
|
||||
Height:30
|
||||
Key: o
|
||||
Key: r
|
||||
TooltipText: Vehicles
|
||||
TooltipContainer:TOOLTIP_CONTAINER
|
||||
ClickSound:button.aud
|
||||
@@ -253,7 +253,7 @@ Container@PLAYER_WIDGETS:
|
||||
X:140
|
||||
Width:30
|
||||
Height:30
|
||||
Key: p
|
||||
Key: t
|
||||
TooltipText: Aircraft
|
||||
TooltipContainer:TOOLTIP_CONTAINER
|
||||
ClickSound:button.aud
|
||||
|
||||
@@ -14,7 +14,7 @@ Container@SETTINGS_PANEL:
|
||||
Text:Settings
|
||||
Background@GENERAL_CONTROLS:
|
||||
Width:740
|
||||
Height:250
|
||||
Height:290
|
||||
Background:panel-black
|
||||
Children:
|
||||
Label@TITLE:
|
||||
@@ -142,49 +142,56 @@ Container@SETTINGS_PANEL:
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Enable Pixel Doubling
|
||||
Checkbox@SHOW_SHELLMAP:
|
||||
X:375
|
||||
Y:120
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Show Shellmap
|
||||
Label@AUDIO_TITLE:
|
||||
X:375
|
||||
Y:130
|
||||
Y:160
|
||||
Width:340
|
||||
Font:Bold
|
||||
Text:Sound
|
||||
Align:Center
|
||||
Label@SOUND_LABEL:
|
||||
X:375
|
||||
Y:145
|
||||
Y:175
|
||||
Width:95
|
||||
Height:25
|
||||
Align:Right
|
||||
Text:Sound Volume:
|
||||
Slider@SOUND_SLIDER:
|
||||
X:475
|
||||
Y:150
|
||||
Y:180
|
||||
Width:240
|
||||
Height:20
|
||||
Ticks:5
|
||||
Label@MUSIC_LABEL:
|
||||
X:375
|
||||
Y:175
|
||||
Y:205
|
||||
Width:95
|
||||
Height:25
|
||||
Align:Right
|
||||
Text:Music Volume:
|
||||
Slider@MUSIC_SLIDER:
|
||||
X:475
|
||||
Y:180
|
||||
Y:210
|
||||
Width:240
|
||||
Height:20
|
||||
Ticks:5
|
||||
Checkbox@SHELLMAP_MUSIC:
|
||||
X:375
|
||||
Y:210
|
||||
Y:240
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Shellmap Music
|
||||
Background@INPUT_CONTROLS:
|
||||
Width:740
|
||||
Height:250
|
||||
Height:290
|
||||
Background:panel-black
|
||||
Visible:false
|
||||
Children:
|
||||
@@ -260,20 +267,20 @@ Container@SETTINGS_PANEL:
|
||||
Font:Regular
|
||||
Text:Shift-Enter Toggles Team Chat
|
||||
Button@GENERAL_BUTTON:
|
||||
Y:249
|
||||
Y:289
|
||||
Width:140
|
||||
Height:35
|
||||
Text:General
|
||||
Button@INPUT_BUTTON:
|
||||
X:150
|
||||
Y:249
|
||||
Y:289
|
||||
Width:140
|
||||
Height:35
|
||||
Text:Input
|
||||
Button@BACK_BUTTON:
|
||||
Key:escape
|
||||
X:600
|
||||
Y:249
|
||||
Y:289
|
||||
Width:140
|
||||
Height:35
|
||||
Text:Back
|
||||
|
||||
@@ -11,6 +11,8 @@ TRAN:
|
||||
Prerequisites: hpad
|
||||
BuiltAt: hpad
|
||||
Owner: gdi,nod
|
||||
Selectable:
|
||||
Bounds: 41,41
|
||||
Helicopter:
|
||||
LandWhenIdle: true
|
||||
ROT: 5
|
||||
@@ -49,6 +51,8 @@ HELI:
|
||||
Prerequisites: hpad, hq
|
||||
BuiltAt: hpad
|
||||
Owner: nod
|
||||
Selectable:
|
||||
Bounds: 30,24
|
||||
Helicopter:
|
||||
ROT: 4
|
||||
Speed: 20
|
||||
@@ -93,6 +97,8 @@ ORCA:
|
||||
Prerequisites: hpad, hq
|
||||
BuiltAt: hpad
|
||||
Owner: gdi
|
||||
Selectable:
|
||||
Bounds: 30,24
|
||||
Helicopter:
|
||||
ROT: 4
|
||||
Speed: 20
|
||||
|
||||
@@ -69,8 +69,9 @@
|
||||
^Helicopter:
|
||||
AppearsOnRadar:
|
||||
UseLocation: yes
|
||||
TargetableUnit:
|
||||
TargetableAircraft:
|
||||
TargetTypes: Air
|
||||
GroundedTargetTypes: Ground
|
||||
SelectionDecorations:
|
||||
Selectable:
|
||||
Voice: VehicleVoice
|
||||
|
||||
@@ -12,7 +12,9 @@ FACT:
|
||||
Footprint: xxx xxx
|
||||
Dimensions: 3,2
|
||||
Health:
|
||||
HP: 1750
|
||||
HP: 2000
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
Range: 10
|
||||
Bib:
|
||||
@@ -240,7 +242,7 @@ AFLD:
|
||||
Footprint: xxxx xxxx
|
||||
Dimensions: 4,2
|
||||
Health:
|
||||
HP: 1000
|
||||
HP: 1750
|
||||
RevealsShroud:
|
||||
Range: 7
|
||||
Bib:
|
||||
@@ -282,7 +284,7 @@ WEAP:
|
||||
Footprint: ___ xxx ===
|
||||
Dimensions: 3,3
|
||||
Health:
|
||||
HP: 1000
|
||||
HP: 1750
|
||||
RevealsShroud:
|
||||
Range: 4
|
||||
Bib:
|
||||
@@ -362,7 +364,7 @@ NUK2:
|
||||
Footprint: xx xx
|
||||
Dimensions: 2,2
|
||||
Health:
|
||||
HP: 600
|
||||
HP: 650
|
||||
RevealsShroud:
|
||||
Range: 4
|
||||
Bib:
|
||||
@@ -409,7 +411,7 @@ HPAD:
|
||||
Footprint: xx xx
|
||||
Dimensions: 2,2
|
||||
Health:
|
||||
HP: 800
|
||||
HP: 400
|
||||
RevealsShroud:
|
||||
Range: 5
|
||||
Exit@1:
|
||||
@@ -561,7 +563,7 @@ CYCL:
|
||||
Prerequisites: fact
|
||||
Owner: nod
|
||||
Health:
|
||||
HP: 300
|
||||
HP: 100
|
||||
Armor:
|
||||
Type: Light
|
||||
|
||||
@@ -581,7 +583,7 @@ SBAG:
|
||||
Prerequisites: fact
|
||||
Owner: gdi
|
||||
Health:
|
||||
HP: 250
|
||||
HP: 100
|
||||
Armor:
|
||||
Type: Light
|
||||
|
||||
@@ -601,7 +603,7 @@ BRIK:
|
||||
Prerequisites: vehicleproduction
|
||||
Owner: gdi,nod
|
||||
Health:
|
||||
HP: 1000
|
||||
HP: 250
|
||||
Armor:
|
||||
Type: Heavy
|
||||
Wall:
|
||||
@@ -620,7 +622,7 @@ GUN:
|
||||
Description: Anti-Armor base defense.\n Strong vs Tanks\n Weak vs Infantry, Aircraft
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 40
|
||||
BuildPaletteOrder: 45
|
||||
Prerequisites: barracks
|
||||
Owner: gdi,nod
|
||||
Building:
|
||||
@@ -678,7 +680,6 @@ SAM:
|
||||
PrimaryWeapon: SAMMissile
|
||||
WithMuzzleFlash:
|
||||
AutoTarget:
|
||||
-AutoTargetIgnore:
|
||||
-RenderBuilding:
|
||||
RenderRangeCircle:
|
||||
|
||||
@@ -692,7 +693,7 @@ GTWR:
|
||||
Description: Basic defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 50
|
||||
BuildPaletteOrder: 40
|
||||
Prerequisites: barracks
|
||||
Owner: gdi,nod
|
||||
Building:
|
||||
|
||||
@@ -19,7 +19,7 @@ MCV:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
Range: 4
|
||||
Range: 8
|
||||
Transforms:
|
||||
IntoActor: fact
|
||||
Offset:-1,-1
|
||||
@@ -84,7 +84,7 @@ APC:
|
||||
Owner: gdi
|
||||
Mobile:
|
||||
ROT: 5
|
||||
Speed: 11
|
||||
Speed: 10
|
||||
Health:
|
||||
HP: 200
|
||||
Armor:
|
||||
@@ -186,7 +186,7 @@ BGGY:
|
||||
Owner: nod
|
||||
Mobile:
|
||||
ROT: 10
|
||||
Speed: 12
|
||||
Speed: 16
|
||||
Health:
|
||||
HP: 140
|
||||
Armor:
|
||||
@@ -218,7 +218,14 @@ BIKE:
|
||||
Owner: nod
|
||||
Mobile:
|
||||
ROT: 10
|
||||
Speed: 13
|
||||
Speed: 20
|
||||
TerrainSpeeds:
|
||||
Clear: 42
|
||||
Rough: 25
|
||||
Road: 100
|
||||
Tiberium: 25
|
||||
BlueTiberium: 25
|
||||
Beach: 25
|
||||
Health:
|
||||
HP: 120
|
||||
Armor:
|
||||
@@ -248,7 +255,7 @@ JEEP:
|
||||
Owner: gdi
|
||||
Mobile:
|
||||
ROT: 10
|
||||
Speed: 10
|
||||
Speed: 14
|
||||
Health:
|
||||
HP: 150
|
||||
Armor:
|
||||
@@ -314,7 +321,7 @@ MTNK:
|
||||
Prerequisites: hq
|
||||
Owner: gdi
|
||||
Mobile:
|
||||
Speed: 9
|
||||
Speed: 7
|
||||
Health:
|
||||
HP: 400
|
||||
Armor:
|
||||
@@ -373,6 +380,8 @@ HTNK:
|
||||
AutoTarget:
|
||||
SelfHealing:
|
||||
Ticks: 10
|
||||
HealIfBelow: 50%
|
||||
DamageCooldown: 200
|
||||
LeavesHusk:
|
||||
HuskActor: HTNK.Husk
|
||||
Explodes:
|
||||
@@ -384,7 +393,7 @@ HTNK:
|
||||
MSAM:
|
||||
Inherits: ^Tank
|
||||
Valued:
|
||||
Cost: 800
|
||||
Cost: 1200
|
||||
Tooltip:
|
||||
Name: Rocket Launcher
|
||||
Icon: msamicnh
|
||||
@@ -400,7 +409,7 @@ MSAM:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
Range: 6
|
||||
Range: 10
|
||||
Turreted:
|
||||
ROT: 255
|
||||
AttackFrontal:
|
||||
|
||||
@@ -94,6 +94,10 @@ explosion:
|
||||
6w: atomsfx
|
||||
Start: 0
|
||||
Length: *
|
||||
chemball: chemball
|
||||
Start: 0
|
||||
Length: *
|
||||
|
||||
rank:
|
||||
rank:
|
||||
Start: 0
|
||||
|
||||
@@ -530,18 +530,18 @@ MammothMissiles:
|
||||
Damage: 75
|
||||
|
||||
227mm:
|
||||
ROF: 80
|
||||
Range: 10
|
||||
MinRange: 2
|
||||
Burst: 6
|
||||
BurstDelay: 1
|
||||
ROF: 45
|
||||
Range: 15
|
||||
MinRange: 4
|
||||
Burst: 8
|
||||
BurstDelay: 3
|
||||
Report: ROCKET1
|
||||
ValidTargets: Ground
|
||||
Projectile: Bullet
|
||||
Arm: 5
|
||||
High: yes
|
||||
Shadow: yes
|
||||
Inaccuracy: 30
|
||||
Inaccuracy: 60
|
||||
Angle: 0.1
|
||||
Image: DRAGON
|
||||
ROT: 5
|
||||
@@ -551,8 +551,8 @@ MammothMissiles:
|
||||
Spread: 10
|
||||
Versus:
|
||||
None: 30%
|
||||
Wood: 75%
|
||||
Light: 75%
|
||||
Wood: 50%
|
||||
Light: 100%
|
||||
Heavy: 50%
|
||||
InfDeath: 3
|
||||
Explosion: 4
|
||||
@@ -597,11 +597,11 @@ ArtilleryShell:
|
||||
MinRange: 2
|
||||
Report: TNKFIRE2
|
||||
Projectile: Bullet
|
||||
ContrailLength: 30
|
||||
Speed: 12
|
||||
High: yes
|
||||
Angle: .09
|
||||
Inaccuracy: 30
|
||||
ContrailLength: 30
|
||||
Image: 120MM
|
||||
Warhead:
|
||||
Damage: 150
|
||||
@@ -612,7 +612,7 @@ ArtilleryShell:
|
||||
Light: 60%
|
||||
Heavy: 25%
|
||||
InfDeath: 2
|
||||
Explosion: 5
|
||||
Explosion: 8
|
||||
SmudgeType: Crater
|
||||
ImpactSound: XPLOSML2
|
||||
|
||||
@@ -815,4 +815,4 @@ APCGun:
|
||||
Versus:
|
||||
Light: 100%
|
||||
Explosion: 5
|
||||
Damage: 6
|
||||
Damage: 12
|
||||
|
||||
@@ -60,6 +60,12 @@ Background@CREATESERVER_BG:
|
||||
Width:300
|
||||
Height:20
|
||||
Text:Advertise game Online
|
||||
Checkbox@UPNP_CHECKBOX:
|
||||
X:165
|
||||
Y:165
|
||||
Width:300
|
||||
Height:20
|
||||
Text:Allow UPnP port forwarding
|
||||
Button@CREATE_BUTTON:
|
||||
X:130
|
||||
Y:PARENT_BOTTOM - 45
|
||||
|
||||
@@ -136,6 +136,17 @@ Background@SETTINGS_MENU:
|
||||
Width:250
|
||||
Height:20
|
||||
Ticks:5
|
||||
Label@SOUND_TICK_TYPE_LABEL:
|
||||
X:0
|
||||
Y:70
|
||||
Text: Cash ticks
|
||||
DropDownButton@CASH_TICK_TYPE:
|
||||
X:100
|
||||
Y:60
|
||||
Width:250
|
||||
Height:20
|
||||
Font:Regular
|
||||
Text:Extreme
|
||||
Container@DISPLAY_PANE:
|
||||
X:37
|
||||
Y:100
|
||||
@@ -143,22 +154,35 @@ Background@SETTINGS_MENU:
|
||||
Height:PARENT_BOTTOM - 100
|
||||
Visible: false
|
||||
Children:
|
||||
Label@MODE_LABEL:
|
||||
Label@RENDERER_LABEL:
|
||||
X:0
|
||||
Y:0
|
||||
Width:75
|
||||
Height:25
|
||||
Text:Renderer:
|
||||
DropDownButton@GRAPHICS_RENDERER:
|
||||
X:80
|
||||
Y:1
|
||||
Width:120
|
||||
Height:25
|
||||
Font:Regular
|
||||
Text:OpenGL
|
||||
Label@MODE_LABEL:
|
||||
X:0
|
||||
Y:30
|
||||
Width:45
|
||||
Height:25
|
||||
Text:Mode:
|
||||
DropDownButton@MODE_DROPDOWN:
|
||||
X:50
|
||||
Y:1
|
||||
Y:30
|
||||
Width:170
|
||||
Height:25
|
||||
Font:Regular
|
||||
Text:Windowed
|
||||
Container@WINDOW_RESOLUTION:
|
||||
X:220
|
||||
Y:0
|
||||
X:225
|
||||
Y:30
|
||||
Children:
|
||||
Label@At:
|
||||
Text:@
|
||||
@@ -186,14 +210,14 @@ Background@SETTINGS_MENU:
|
||||
Height:25
|
||||
MaxLength:5
|
||||
Label@VIDEO_DESC:
|
||||
Y:25
|
||||
Y:60
|
||||
Width:PARENT_RIGHT
|
||||
Height:25
|
||||
Font:Tiny
|
||||
Align:Center
|
||||
Text:Mode/Resolution changes will be applied after the game is restarted
|
||||
Text:Renderer/Mode/Resolution changes will be applied after the game is restarted.
|
||||
Checkbox@PIXELDOUBLE_CHECKBOX:
|
||||
Y:50
|
||||
Y:90
|
||||
Width:200
|
||||
Height:20
|
||||
Font:Regular
|
||||
|
||||
BIN
mods/ra/maps/bomber-john.oramap
Normal file
BIN
mods/ra/maps/bomber-john.oramap
Normal file
Binary file not shown.
Binary file not shown.
BIN
mods/ra/maps/ice-woods.oramap
Normal file
BIN
mods/ra/maps/ice-woods.oramap
Normal file
Binary file not shown.
BIN
mods/ra/maps/nishnekolymsk.oramap
Normal file
BIN
mods/ra/maps/nishnekolymsk.oramap
Normal file
Binary file not shown.
@@ -89,11 +89,9 @@ V18:
|
||||
Inherits: ^CivField
|
||||
|
||||
BARL:
|
||||
Inherits: ^Building
|
||||
Inherits: ^CivBuilding
|
||||
Selectable:
|
||||
Priority: 0
|
||||
-RepairableBuilding:
|
||||
-GivesBuildableArea:
|
||||
Health:
|
||||
HP: 10
|
||||
Explodes:
|
||||
@@ -101,11 +99,9 @@ BARL:
|
||||
Name: Explosive Barrel
|
||||
|
||||
BRL3:
|
||||
Inherits: ^Building
|
||||
Inherits: ^CivBuilding
|
||||
Selectable:
|
||||
Priority: 0
|
||||
-RepairableBuilding:
|
||||
-GivesBuildableArea:
|
||||
Health:
|
||||
HP: 10
|
||||
Explodes:
|
||||
|
||||
@@ -497,36 +497,142 @@ PBOX.SHOK:
|
||||
|
||||
HBOX:
|
||||
Inherits: ^Building
|
||||
# Buildable:
|
||||
# Queue: Defense
|
||||
# BuildPaletteOrder: 30
|
||||
# Prerequisites: tent
|
||||
# Owner: allies
|
||||
# Hotkey: c
|
||||
Valued:
|
||||
Cost: 600
|
||||
Tooltip:
|
||||
Name: Camo Pillbox
|
||||
Description: Hidden defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
|
||||
Name: Camo Pillbox (Unarmed)
|
||||
Building:
|
||||
Power: -15
|
||||
-GivesBuildableArea:
|
||||
Valued:
|
||||
Cost: 600
|
||||
Health:
|
||||
HP: 600
|
||||
Armor:
|
||||
Type: Wood
|
||||
RevealsShroud:
|
||||
Range: 6
|
||||
Cloak:
|
||||
InitialDelay: 125
|
||||
CloakDelay: 60
|
||||
CloakSound: appear1.aud
|
||||
UncloakSound: appear1.aud
|
||||
IronCurtainable:
|
||||
-AcceptsSupplies:
|
||||
Turreted:
|
||||
ROT: 255
|
||||
Cargo:
|
||||
Types: Infantry
|
||||
MaxWeight: 1
|
||||
PipCount: 1
|
||||
-EmitInfantryOnSell:
|
||||
# EmitCargoOnSell:
|
||||
TransformOnPassenger@e1:
|
||||
PassengerTypes: e1
|
||||
OnEnter: HBOX.e1
|
||||
OnExit: HBOX
|
||||
SkipMakeAnims: true
|
||||
# TransformOnPassenger@e2:
|
||||
# PassengerTypes: e2
|
||||
# OnEnter: HBOX.e2
|
||||
# OnExit: HBOX
|
||||
# SkipMakeAnims: true
|
||||
TransformOnPassenger@e3:
|
||||
PassengerTypes: e3
|
||||
OnEnter: HBOX.e3
|
||||
OnExit: HBOX
|
||||
SkipMakeAnims: true
|
||||
TransformOnPassenger@e4:
|
||||
PassengerTypes: e4
|
||||
OnEnter: HBOX.e4
|
||||
OnExit: HBOX
|
||||
SkipMakeAnims: true
|
||||
TransformOnPassenger@e7:
|
||||
PassengerTypes: e7
|
||||
OnEnter: HBOX.e7
|
||||
OnExit: HBOX
|
||||
SkipMakeAnims: true
|
||||
TransformOnPassenger@SHOK:
|
||||
PassengerTypes: shok
|
||||
OnEnter: HBOX.shok
|
||||
OnExit: HBOX
|
||||
SkipMakeAnims: true
|
||||
|
||||
HBOX.E1:
|
||||
Inherits: HBOX
|
||||
Buildable:
|
||||
Queue: Defense
|
||||
BuildPaletteOrder: 20
|
||||
Prerequisites: tent
|
||||
Owner: allies
|
||||
Hotkey: p
|
||||
Tooltip:
|
||||
Name: Camo Pillbox (Guns)
|
||||
Description: Hidden defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
|
||||
Icon: HBOXICON
|
||||
RenderBuilding:
|
||||
Image: HBOX
|
||||
RenderRangeCircle:
|
||||
AutoTarget:
|
||||
AttackTurreted:
|
||||
PrimaryWeapon: Vulcan
|
||||
PrimaryLocalOffset: 0,-11,0,0,0
|
||||
AutoTarget:
|
||||
IronCurtainable:
|
||||
RenderRangeCircle:
|
||||
-AcceptsSupplies:
|
||||
WithMuzzleFlash:
|
||||
Turreted:
|
||||
ROT: 255
|
||||
Cargo:
|
||||
InitialUnits: e1
|
||||
|
||||
#HBOX.E2:
|
||||
# Inherits: HBOX
|
||||
# Tooltip:
|
||||
# Name: Camo Pillbox (Grenades)
|
||||
# RenderBuilding:
|
||||
# Image: HBOX
|
||||
|
||||
HBOX.E3:
|
||||
Inherits: HBOX
|
||||
Tooltip:
|
||||
Name: Camo Pillbox (Rockets)
|
||||
RenderBuilding:
|
||||
Image: HBOX
|
||||
RenderRangeCircle:
|
||||
AutoTarget:
|
||||
AttackTurreted:
|
||||
PrimaryWeapon: Dragon
|
||||
PrimaryLocalOffset: 0,-11,0,0,0
|
||||
|
||||
HBOX.E4:
|
||||
Inherits: HBOX
|
||||
Tooltip:
|
||||
Name: Camo Pillbox (Flamethrower)
|
||||
RenderBuilding:
|
||||
Image: HBOX
|
||||
RenderRangeCircle:
|
||||
AutoTarget:
|
||||
AttackTurreted:
|
||||
PrimaryWeapon: Flamer
|
||||
PrimaryLocalOffset: 0,-11,0,0,0
|
||||
|
||||
HBOX.E7:
|
||||
Inherits: HBOX
|
||||
Tooltip:
|
||||
Name: Camo Pillbox (Tanya)
|
||||
RenderBuilding:
|
||||
Image: HBOX
|
||||
RenderRangeCircle:
|
||||
AutoTarget:
|
||||
AttackTurreted:
|
||||
PrimaryWeapon: Colt45
|
||||
PrimaryLocalOffset: 0,-11,0,0,0
|
||||
|
||||
HBOX.SHOK:
|
||||
Inherits: HBOX
|
||||
Tooltip:
|
||||
Name: Camo Pillbox (Tesla)
|
||||
RenderBuilding:
|
||||
Image: HBOX
|
||||
RenderRangeCircle:
|
||||
AutoTarget:
|
||||
AttackTurreted:
|
||||
PrimaryWeapon: PortaTesla
|
||||
PrimaryLocalOffset: 0,-11,0,0,0
|
||||
|
||||
GUN:
|
||||
Inherits: ^Building
|
||||
|
||||
@@ -47,7 +47,7 @@ Player:
|
||||
barr: 1%
|
||||
tent: 1%
|
||||
weap: 1%
|
||||
pbox: 7%
|
||||
pbox.e1: 7%
|
||||
gun: 7%
|
||||
tsla: 5%
|
||||
ftur: 10%
|
||||
@@ -77,7 +77,7 @@ Player:
|
||||
tent: 1%
|
||||
barr: 1%
|
||||
weap: 1%
|
||||
pbox: 7%
|
||||
pbox.e1: 7%
|
||||
gun: 7%
|
||||
ftur: 10%
|
||||
tsla: 5%
|
||||
@@ -98,15 +98,44 @@ Player:
|
||||
2tnk: 25%
|
||||
3tnk: 50%
|
||||
SquadSize: 10
|
||||
HackyAI@OptiAI:
|
||||
Name:Eisenhower AI
|
||||
BuildingFractions:
|
||||
proc: 25.1%
|
||||
powr: 35%
|
||||
tent: 0.1%
|
||||
barr: 0.1%
|
||||
weap: 0.1%
|
||||
fix: 0.1%
|
||||
dome: 0.1%
|
||||
atek: 0.1%
|
||||
stek: 0.1%
|
||||
UnitsToBuild:
|
||||
e1: 50%
|
||||
e2: 1%
|
||||
e3: 10%
|
||||
medi: 0.01%
|
||||
e7: 0.01%
|
||||
apc: 10%
|
||||
jeep: 10%
|
||||
ftrk: 25%
|
||||
1tnk: 25%
|
||||
2tnk: 50%
|
||||
3tnk: 75%
|
||||
4tnk: 100%
|
||||
arty: 30%
|
||||
v2rl: 30%
|
||||
SquadSize: 10
|
||||
HackyAI@ZhukovAI:
|
||||
Name:Zhukov AI
|
||||
BuildingFractions:
|
||||
proc: 30%
|
||||
proc: 20%
|
||||
powr: 35%
|
||||
tent: 1%
|
||||
barr: 1%
|
||||
weap: 1%
|
||||
pbox: 7%
|
||||
pbox.e1: 4%
|
||||
hbox.e1: 3%
|
||||
gun: 10%
|
||||
ftur: 10%
|
||||
tsla: 5%
|
||||
@@ -117,16 +146,16 @@ Player:
|
||||
atek: 1%
|
||||
stek: 1%
|
||||
UnitsToBuild:
|
||||
e1: 40%
|
||||
e3: 10%
|
||||
e1: 4%
|
||||
e3: 1%
|
||||
harv: 10%
|
||||
ftrk: 5%
|
||||
v2rl: 40%
|
||||
arty: 40%
|
||||
1tnk: 20%
|
||||
2tnk: 20%
|
||||
3tnk: 20%
|
||||
SquadSize: 30
|
||||
1tnk: 15%
|
||||
2tnk: 15%
|
||||
3tnk: 15%
|
||||
SquadSize: 25
|
||||
HackyAI@RommelAI:
|
||||
Name:Rommel AI
|
||||
BuildingFractions:
|
||||
@@ -135,7 +164,7 @@ Player:
|
||||
tent: 1%
|
||||
barr: 1%
|
||||
weap: 1%
|
||||
pbox: 7%
|
||||
pbox.e1: 7%
|
||||
gun: 7%
|
||||
ftur: 10%
|
||||
tsla: 5%
|
||||
|
||||
Reference in New Issue
Block a user