diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs
index 9028824c85..62aded8acf 100755
--- a/OpenRA.Game/Actor.cs
+++ b/OpenRA.Game/Actor.cs
@@ -1,254 +1,254 @@
-#region Copyright & License Information
-/*
- * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
- * This file is part of OpenRA.
- *
- * OpenRA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * OpenRA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with OpenRA. If not, see .
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using OpenRA.FileFormats;
-using OpenRA.GameRules;
-using OpenRA.Traits;
-using OpenRA.Traits.Activities;
-
-namespace OpenRA
-{
- public class Actor
- {
- [Sync]
- public readonly TypeDictionary traits = new TypeDictionary();
- public readonly ActorInfo Info;
-
- public readonly World World;
- public readonly uint ActorID;
-
- [Sync]
- public int2 Location;
- [Sync]
- public Player Owner;
- [Sync]
- public int Health;
- IActivity currentActivity;
-
- public Actor(World world, string name, int2 location, Player owner)
- {
- World = world;
- ActorID = world.NextAID();
- Location = location;
- CenterLocation = Traits.Util.CenterOfCell(Location);
- Owner = owner;
-
- if (name != null)
- {
- if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
- throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
-
- Info = Rules.Info[name.ToLowerInvariant()];
- Health = this.GetMaxHP();
-
- foreach (var trait in Info.TraitsInConstructOrder())
- traits.Add(trait.Create(this));
- }
-
- Size = Lazy.New(() =>
- {
- var si = Info.Traits.GetOrDefault();
- if (si != null && si.Bounds != null)
- return new float2(si.Bounds[0], si.Bounds[1]);
-
- // auto size from render
- var firstSprite = traits.WithInterface().SelectMany(x => x.Render(this)).FirstOrDefault();
- if (firstSprite.Sprite == null) return float2.Zero;
- return firstSprite.Sprite.size;
- });
- }
-
- public void Tick()
- {
- var wasIdle = currentActivity is Idle;
- while (currentActivity != null)
- {
- var a = currentActivity;
- currentActivity = a.Tick(this) ?? new Idle();
-
- if (a == currentActivity) break;
-
- if (currentActivity is Idle)
- {
- if (!wasIdle)
- foreach (var ni in traits.WithInterface())
- ni.Idle(this);
-
- break;
- }
- }
- }
-
- public bool IsIdle
- {
- get { return currentActivity == null || currentActivity is Idle; }
- }
-
- public float2 CenterLocation;
-
- Lazy Size;
-
- public IEnumerable Render()
- {
- var mods = traits.WithInterface();
- var sprites = traits.WithInterface().SelectMany(x => x.Render(this));
- return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
- }
-
- public Order Order( int2 xy, MouseInput mi )
- {
- if (Owner != World.LocalPlayer)
- return null;
-
- if (!World.Map.IsInMap(xy.X, xy.Y))
- return null;
-
- var underCursor = World.FindUnitsAtMouse(mi.Location)
- .Where(a => a.Info.Traits.Contains())
- .OrderByDescending(a => a.Info.Traits.Get().Priority)
- .FirstOrDefault();
-
- return traits.WithInterface()
- .Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
- .FirstOrDefault( x => x != null );
- }
-
- public RectangleF GetBounds(bool useAltitude)
- {
- var si = Info.Traits.GetOrDefault();
-
- var size = Size.Value;
- var loc = CenterLocation - 0.5f * size;
-
- if (si != null && si.Bounds != null && si.Bounds.Length > 2)
- loc += new float2(si.Bounds[2], si.Bounds[3]);
-
- if (useAltitude)
- {
- var unit = traits.GetOrDefault();
- if (unit != null) loc -= new float2(0, unit.Altitude);
- }
-
- return new RectangleF(loc.X, loc.Y, size.X, size.Y);
- }
-
- public bool IsDead { get { return Health <= 0; } }
- public bool IsInWorld { get; set; }
- public bool RemoveOnDeath = true;
-
- public DamageState GetDamageState()
- {
- if (Health <= 0)
- return DamageState.Dead;
-
- if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
- return DamageState.Half;
-
- return DamageState.Normal;
- }
-
- public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
- {
- if (IsDead) return; /* overkill! don't count extra hits as more kills! */
-
- var rawDamage = damage;
- var oldState = GetDamageState();
-
- /* apply the damage modifiers, if we have any. */
- var modifier = (float)traits.WithInterface()
- .Select(t => t.GetDamageModifier()).Product();
-
- damage = (int)(damage * modifier);
-
- Health -= damage;
- if (Health <= 0)
- {
- Health = 0;
-
- attacker.Owner.Kills++;
- Owner.Deaths++;
-
- if (RemoveOnDeath)
- World.AddFrameEndTask(w => w.Remove(this));
- }
-
- var maxHP = this.GetMaxHP();
-
- if (Health > maxHP) Health = maxHP;
-
- Log.Write("InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}",
- attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier);
-
- var newState = GetDamageState();
-
- foreach (var nd in traits.WithInterface())
- nd.Damaged(this, new AttackInfo
- {
- Attacker = attacker,
- Damage = damage,
- DamageState = newState,
- DamageStateChanged = newState != oldState,
- Warhead = warhead
- });
- }
-
- public void QueueActivity( IActivity nextActivity )
- {
- if( currentActivity == null )
- {
- currentActivity = nextActivity;
- return;
- }
- var act = currentActivity;
- while( act.NextActivity != null )
- {
- act = act.NextActivity;
- }
- act.NextActivity = nextActivity;
- }
-
- public void CancelActivity()
- {
- if( currentActivity != null )
- currentActivity.Cancel( this );
- }
-
- // For pathdebug, et al
- public IActivity GetCurrentActivity()
- {
- return currentActivity;
- }
-
- public override int GetHashCode()
- {
- return (int)ActorID;
- }
-
- public override bool Equals( object obj )
- {
- var o = obj as Actor;
- return ( o != null && o.ActorID == ActorID );
- }
- }
-}
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using OpenRA.FileFormats;
+using OpenRA.GameRules;
+using OpenRA.Traits;
+using OpenRA.Traits.Activities;
+
+namespace OpenRA
+{
+ public class Actor
+ {
+ [Sync]
+ public readonly TypeDictionary traits = new TypeDictionary();
+ public readonly ActorInfo Info;
+
+ public readonly World World;
+ public readonly uint ActorID;
+
+ [Sync]
+ public int2 Location;
+ [Sync]
+ public Player Owner;
+ [Sync]
+ public int Health;
+ IActivity currentActivity;
+
+ public Actor(World world, string name, int2 location, Player owner)
+ {
+ World = world;
+ ActorID = world.NextAID();
+ Location = location;
+ CenterLocation = Traits.Util.CenterOfCell(Location);
+ Owner = owner;
+
+ if (name != null)
+ {
+ if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
+ throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
+
+ Info = Rules.Info[name.ToLowerInvariant()];
+ Health = this.GetMaxHP();
+
+ foreach (var trait in Info.TraitsInConstructOrder())
+ traits.Add(trait.Create(this));
+ }
+
+ Size = Lazy.New(() =>
+ {
+ var si = Info.Traits.GetOrDefault();
+ if (si != null && si.Bounds != null)
+ return new float2(si.Bounds[0], si.Bounds[1]);
+
+ // auto size from render
+ var firstSprite = traits.WithInterface().SelectMany(x => x.Render(this)).FirstOrDefault();
+ if (firstSprite.Sprite == null) return float2.Zero;
+ return firstSprite.Sprite.size;
+ });
+ }
+
+ public void Tick()
+ {
+ var wasIdle = currentActivity is Idle;
+ while (currentActivity != null)
+ {
+ var a = currentActivity;
+ currentActivity = a.Tick(this) ?? new Idle();
+
+ if (a == currentActivity) break;
+
+ if (currentActivity is Idle)
+ {
+ if (!wasIdle)
+ foreach (var ni in traits.WithInterface())
+ ni.Idle(this);
+
+ break;
+ }
+ }
+ }
+
+ public bool IsIdle
+ {
+ get { return currentActivity == null || currentActivity is Idle; }
+ }
+
+ public float2 CenterLocation;
+
+ OpenRA.FileFormats.Lazy Size;
+
+ public IEnumerable Render()
+ {
+ var mods = traits.WithInterface();
+ var sprites = traits.WithInterface().SelectMany(x => x.Render(this));
+ return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
+ }
+
+ public Order Order( int2 xy, MouseInput mi )
+ {
+ if (Owner != World.LocalPlayer)
+ return null;
+
+ if (!World.Map.IsInMap(xy.X, xy.Y))
+ return null;
+
+ var underCursor = World.FindUnitsAtMouse(mi.Location)
+ .Where(a => a.Info.Traits.Contains())
+ .OrderByDescending(a => a.Info.Traits.Get().Priority)
+ .FirstOrDefault();
+
+ return traits.WithInterface()
+ .Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
+ .FirstOrDefault( x => x != null );
+ }
+
+ public RectangleF GetBounds(bool useAltitude)
+ {
+ var si = Info.Traits.GetOrDefault();
+
+ var size = Size.Value;
+ var loc = CenterLocation - 0.5f * size;
+
+ if (si != null && si.Bounds != null && si.Bounds.Length > 2)
+ loc += new float2(si.Bounds[2], si.Bounds[3]);
+
+ if (useAltitude)
+ {
+ var unit = traits.GetOrDefault();
+ if (unit != null) loc -= new float2(0, unit.Altitude);
+ }
+
+ return new RectangleF(loc.X, loc.Y, size.X, size.Y);
+ }
+
+ public bool IsDead { get { return Health <= 0; } }
+ public bool IsInWorld { get; set; }
+ public bool RemoveOnDeath = true;
+
+ public DamageState GetDamageState()
+ {
+ if (Health <= 0)
+ return DamageState.Dead;
+
+ if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
+ return DamageState.Half;
+
+ return DamageState.Normal;
+ }
+
+ public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
+ {
+ if (IsDead) return; /* overkill! don't count extra hits as more kills! */
+
+ var rawDamage = damage;
+ var oldState = GetDamageState();
+
+ /* apply the damage modifiers, if we have any. */
+ var modifier = (float)traits.WithInterface()
+ .Select(t => t.GetDamageModifier()).Product();
+
+ damage = (int)(damage * modifier);
+
+ Health -= damage;
+ if (Health <= 0)
+ {
+ Health = 0;
+
+ attacker.Owner.Kills++;
+ Owner.Deaths++;
+
+ if (RemoveOnDeath)
+ World.AddFrameEndTask(w => w.Remove(this));
+ }
+
+ var maxHP = this.GetMaxHP();
+
+ if (Health > maxHP) Health = maxHP;
+
+ Log.Write("InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}",
+ attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier);
+
+ var newState = GetDamageState();
+
+ foreach (var nd in traits.WithInterface())
+ nd.Damaged(this, new AttackInfo
+ {
+ Attacker = attacker,
+ Damage = damage,
+ DamageState = newState,
+ DamageStateChanged = newState != oldState,
+ Warhead = warhead
+ });
+ }
+
+ public void QueueActivity( IActivity nextActivity )
+ {
+ if( currentActivity == null )
+ {
+ currentActivity = nextActivity;
+ return;
+ }
+ var act = currentActivity;
+ while( act.NextActivity != null )
+ {
+ act = act.NextActivity;
+ }
+ act.NextActivity = nextActivity;
+ }
+
+ public void CancelActivity()
+ {
+ if( currentActivity != null )
+ currentActivity.Cancel( this );
+ }
+
+ // For pathdebug, et al
+ public IActivity GetCurrentActivity()
+ {
+ return currentActivity;
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)ActorID;
+ }
+
+ public override bool Equals( object obj )
+ {
+ var o = obj as Actor;
+ return ( o != null && o.ActorID == ActorID );
+ }
+ }
+}
diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs
index 3b3e033594..2430f0577e 100644
--- a/OpenRA.Game/Game.cs
+++ b/OpenRA.Game/Game.cs
@@ -33,6 +33,8 @@ using OpenRA.Network;
using OpenRA.Server;
using OpenRA.Support;
using OpenRA.Traits;
+using OpenRA.Widgets;
+
using Timer = OpenRA.Support.Timer;
using XRandom = OpenRA.Thirdparty.Random;
@@ -47,7 +49,7 @@ namespace OpenRA
public static Controller controller;
internal static Chrome chrome;
internal static UserSettings Settings;
-
+
internal static OrderManager orderManager;
public static bool skipMakeAnims = true;
@@ -69,12 +71,12 @@ namespace OpenRA
foreach (var dir in manifest.Folders) FileSystem.Mount(dir);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
-
+
Timer.Time("mount temporary packages: {0}");
}
-
+
public static void LoadModAssemblies(Manifest m)
- {
+ {
// All the core namespaces
var asms = typeof(Game).Assembly.GetNamespaces()
.Select(c => Pair.New(typeof(Game).Assembly, c))
@@ -102,9 +104,9 @@ namespace OpenRA
throw new InvalidOperationException("Cannot locate type: {0}".F(classname));
}
-
- public static Dictionary AvailableMaps;
-
+
+ public static Dictionary AvailableMaps;
+
// TODO: Do this nicer
static Dictionary FindMaps(string[] mods)
{
@@ -118,48 +120,48 @@ namespace OpenRA
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
}
-
+
static void ChangeMods()
{
- Timer.Time( "----ChangeMods" );
+ Timer.Time("----ChangeMods");
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
- Timer.Time( "manifest: {0}" );
+ Timer.Time("manifest: {0}");
LoadModAssemblies(manifest);
SheetBuilder.Initialize(renderer);
LoadModPackages(manifest);
- Timer.Time( "load assemblies, packages: {0}" );
+ Timer.Time("load assemblies, packages: {0}");
packageChangePending = false;
}
-
+
static void LoadMap(string mapName)
{
- Timer.Time( "----LoadMap" );
+ Timer.Time("----LoadMap");
SheetBuilder.Initialize(renderer);
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
- Timer.Time( "manifest: {0}" );
-
+ Timer.Time("manifest: {0}");
+
if (!Game.AvailableMaps.ContainsKey(mapName))
throw new InvalidDataException("Cannot find map with Uid {0}".F(mapName));
-
- var map = new Map( Game.AvailableMaps[mapName].Package );
-
+
+ var map = new Map(Game.AvailableMaps[mapName].Package);
+
viewport = new Viewport(clientSize, map.TopLeft, map.BottomRight, renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
ChromeProvider.Initialize(manifest.Chrome);
- Timer.Time( "viewport, ChromeProvider: {0}" );
- world = new World(manifest,map);
- Timer.Time( "world: {0}" );
-
+ Timer.Time("viewport, ChromeProvider: {0}");
+ world = new World(manifest, map);
+ Timer.Time("world: {0}");
+
SequenceProvider.Initialize(manifest.Sequences);
- Timer.Time( "ChromeProv, SeqProv: {0}" );
+ Timer.Time("ChromeProv, SeqProv: {0}");
chrome = new Chrome(renderer, manifest);
- Timer.Time( "chrome: {0}" );
+ Timer.Time("chrome: {0}");
- Timer.Time( "----end LoadMap" );
+ Timer.Time("----end LoadMap");
Debug("Map change {0} -> {1}".F(Game.mapName, mapName));
}
-
+
public static void MoveViewport(int2 loc)
{
viewport.Center(loc);
@@ -174,21 +176,21 @@ namespace OpenRA
CurrentHost = host;
CurrentPort = port;
-
- orderManager = new OrderManager(new NetworkConnection( host, port ), ChooseReplayFilename());
+
+ orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
}
-
+
static void JoinLocal()
{
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection());
}
-
+
static int lastTime = Environment.TickCount;
static void ResetTimer()
@@ -242,7 +244,7 @@ namespace OpenRA
return sb.ToString();
}
- internal static void DumpSyncReport( int frame )
+ internal static void DumpSyncReport(int frame)
{
var f = syncReports.FirstOrDefault(a => a.First == frame);
if (f == null)
@@ -262,11 +264,11 @@ namespace OpenRA
// TODO: Only do this on mod change
Timer.Time("----begin maplist");
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
- Timer.Time( "maplist: {0}" );
+ Timer.Time("maplist: {0}");
ChangeMods();
return;
}
-
+
if (mapChangePending)
{
mapName = LobbyInfo.GlobalSettings.Map;
@@ -281,9 +283,9 @@ namespace OpenRA
using (new PerfSample("tick_time"))
{
lastTime += Settings.Timestep;
- chrome.Tick( world );
+ chrome.Tick(world);
- orderManager.TickImmediate( world );
+ orderManager.TickImmediate(world);
var isNetTick = LocalTick % NetTickScale == 0;
@@ -309,7 +311,7 @@ namespace OpenRA
using (new PerfSample("render"))
{
++RenderFrame;
- viewport.DrawRegions( world );
+ viewport.DrawRegions(world);
}
PerfHistory.items["render"].Tick();
@@ -364,7 +366,7 @@ namespace OpenRA
if (mapName != LobbyInfo.GlobalSettings.Map)
mapChangePending = true;
-
+
if (string.Join(",", oldLobbyInfo.GlobalSettings.Mods)
!= string.Join(",", LobbyInfo.GlobalSettings.Mods))
{
@@ -379,18 +381,18 @@ namespace OpenRA
static void LoadShellMap(string map)
{
- LoadMap(map);
+ LoadMap(map);
world.Queries = new World.AllQueries(world);
foreach (var p in world.players.Values)
foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q);
-
+
foreach (var gs in world.WorldActor.traits.WithInterface())
gs.GameStarted(world);
orderManager.StartGame();
}
-
+
internal static void StartGame()
{
LoadMap(LobbyInfo.GlobalSettings.Map);
@@ -405,13 +407,13 @@ namespace OpenRA
foreach (var p in world.players.Values)
foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q);
-
+
world.Queries = new World.AllQueries(world);
foreach (var gs in world.WorldActor.traits.WithInterface())
gs.GameStarted(world);
- viewport.GoToStartLocation( world.LocalPlayer );
+ viewport.GoToStartLocation(world.LocalPlayer);
orderManager.StartGame();
}
@@ -423,7 +425,7 @@ namespace OpenRA
var pc = GetClientForPlayer(p);
var qc = GetClientForPlayer(q);
- return pc.Team != 0 && pc.Team == qc.Team
+ return pc.Team != 0 && pc.Team == qc.Team
? Stance.Ally : Stance.Enemy;
}
@@ -441,8 +443,8 @@ namespace OpenRA
if (ev == MouseInputEvent.Down)
lastPos = new int2(e.Location);
- if (ev == MouseInputEvent.Move &&
- (e.Button == MouseButtons.Middle ||
+ if (ev == MouseInputEvent.Move &&
+ (e.Button == MouseButtons.Middle ||
e.Button == (MouseButtons.Left | MouseButtons.Right)))
{
var p = new int2(e.Location);
@@ -450,7 +452,7 @@ namespace OpenRA
lastPos = p;
}
- viewport.DispatchMouseInput( world,
+ viewport.DispatchMouseInput(world,
new MouseInput
{
Button = (MouseButton)(int)e.Button,
@@ -459,8 +461,8 @@ namespace OpenRA
Modifiers = modifierKeys,
});
- if( sync != world.SyncHash() && world == initialWorld )
- throw new InvalidOperationException( "Desync in DispatchMouseInput" );
+ if (sync != world.SyncHash() && world == initialWorld)
+ throw new InvalidOperationException("Desync in DispatchMouseInput");
}
internal static bool IsHost
@@ -487,11 +489,11 @@ namespace OpenRA
{ ')', '0' },
};
- public static void HandleKeyPress( KeyPressEventArgs e, Modifiers modifiers )
+ public static void HandleKeyPress(KeyPressEventArgs e, Modifiers modifiers)
{
int sync = world.SyncHash();
-
- if( e.KeyChar == '\r' )
+
+ if (e.KeyChar == '\r')
chat.Toggle();
else if (Game.chat.isChatting)
chat.TypeChar(e.KeyChar);
@@ -503,12 +505,17 @@ namespace OpenRA
Game.controller.selection.DoControlGroup(world,
c - '0', modifiers);
- if (c == 'h')
+ if (c == 08)
Game.controller.GotoNextBase();
+
+ if (c == 09)
+ BuildPaletteWidget.TabChange((Control.ModifierKeys & Keys.Shift) == Keys.Shift ? true : false);
+
+ BuildPaletteWidget.DoBuildingHotkey(c, world);
}
- if( sync != Game.world.SyncHash() )
- throw new InvalidOperationException( "Desync in OnKeyPress" );
+ if (sync != Game.world.SyncHash())
+ throw new InvalidOperationException("Desync in OnKeyPress");
}
public static void HandleModifierKeys(Modifiers mods)
@@ -539,15 +546,15 @@ namespace OpenRA
throw new InvalidOperationException("Unable to find game root.");
Directory.SetCurrentDirectory("..");
}
-
+
LoadUserSettings(settings);
LobbyInfo.GlobalSettings.Mods = Settings.InitialMods;
-
+
// Load the default mod to access required files
LoadModPackages(new Manifest(LobbyInfo.GlobalSettings.Mods));
-
+
Renderer.SheetSize = Settings.SheetSize;
-
+
bool windowed = !Game.Settings.Fullscreen;
var resolution = GetResolution(settings);
renderer = new Renderer(resolution, windowed);
@@ -555,21 +562,21 @@ namespace OpenRA
controller = new Controller();
clientSize = new int2(resolution);
-
+
Sound.Initialize();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false;
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
-
+
ChangeMods();
- if( Settings.Replay != "" )
- orderManager = new OrderManager( new ReplayConnection( Settings.Replay ) );
+ if (Settings.Replay != "")
+ orderManager = new OrderManager(new ReplayConnection(Settings.Replay));
else
JoinLocal();
-
+
LoadShellMap(new Manifest(LobbyInfo.GlobalSettings.Mods).ShellmapUid);
ResetTimer();
diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs
index af4dc78838..f5e8038a55 100644
--- a/OpenRA.Game/Player.cs
+++ b/OpenRA.Game/Player.cs
@@ -1,198 +1,198 @@
-#region Copyright & License Information
-/*
- * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
- * This file is part of OpenRA.
- *
- * OpenRA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * OpenRA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with OpenRA. If not, see .
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using OpenRA.FileFormats;
-using OpenRA.Traits;
-
-namespace OpenRA
-{
- public enum PowerState { Normal, Low, Critical };
-
- public class Player
- {
- public Actor PlayerActor;
- public int Kills;
- public int Deaths;
-
- public readonly string Palette;
- public readonly Color Color;
-
- public readonly string PlayerName;
- public readonly string InternalName;
- public readonly CountryInfo Country;
- public readonly int Index;
-
- public int Cash = 10000;
- public int Ore = 0;
- public int OreCapacity;
- public int DisplayCash = 0;
- public int PowerProvided = 0;
- public int PowerDrained = 0;
-
- public ShroudRenderer Shroud;
- public World World { get; private set; }
-
- public static List> PlayerColors( World world )
- {
- return world.WorldActor.Info.Traits.WithInterface()
- .Where(p => p.Playable)
- .Select(p => Tuple.New(p.Name, p.DisplayName, p.Color))
- .ToList();
- }
-
- public Player( World world, Session.Client client )
- {
- World = world;
- Shroud = new ShroudRenderer(this, world.Map);
-
- PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
-
- if (client != null)
- {
- Index = client.Index;
- Palette = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].a;
- Color = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].c;
- PlayerName = client.Name;
- InternalName = "Multi{0}".F(client.Index);
- }
- else
- {
- Index = -1;
- PlayerName = InternalName = "Neutral";
- Palette = "neutral";
- Color = Color.Gray; // HACK HACK
- }
-
- Country = world.GetCountries()
- .FirstOrDefault(c => client != null && client.Country == c.Name)
- ?? world.GetCountries().Random(world.SharedRandom);
- }
-
- void UpdatePower()
- {
- var oldBalance = PowerProvided - PowerDrained;
-
- PowerProvided = 0;
- PowerDrained = 0;
-
- var myBuildings = World.Queries.OwnedBy[this]
- .WithTrait();
-
- foreach (var a in myBuildings)
- {
- var p = a.Trait.GetPowerUsage();
- if (p > 0)
- PowerProvided += p;
- else
- PowerDrained -= p;
- }
-
- if (PowerProvided - PowerDrained < 0)
- if (PowerProvided - PowerDrained != oldBalance)
- GiveAdvice(World.WorldActor.Info.Traits.Get().LowPower);
- }
-
- public float GetSiloFullness()
- {
- return (float)Ore / OreCapacity;
- }
-
- public PowerState GetPowerState()
- {
- if (PowerProvided >= PowerDrained) return PowerState.Normal;
- if (PowerProvided > PowerDrained / 2) return PowerState.Low;
- return PowerState.Critical;
- }
-
- void UpdateOreCapacity()
- {
- OreCapacity = World.Queries.OwnedBy[this]
- .Where(a => a.traits.Contains())
- .Select(a => a.Info.Traits.Get())
- .Sum(b => b.Capacity);
- }
-
- void GiveAdvice(string advice)
- {
- // todo: store the condition or something.
- // repeat after World.Defaults.SpeakDelay, as long as the condition holds.
- Sound.PlayToPlayer(this, advice);
- }
-
- public void GiveCash( int num ) { Cash += num; }
- public void GiveOre(int num)
- {
- Ore += num;
-
- if (Ore > OreCapacity)
- Ore = OreCapacity; // trim off the overflow.
-
- if (Ore > .8 * OreCapacity)
- GiveAdvice(World.WorldActor.Info.Traits.Get().SilosNeeded);
- }
-
- public bool TakeCash( int num )
- {
- if (Cash + Ore < num) return false;
- if (Ore <= num)
- {
- num -= Ore;
- Ore = 0;
- Cash -= num;
- }
- else
- Ore -= num;
-
- return true;
- }
-
- const float displayCashFracPerFrame = .07f;
- const int displayCashDeltaPerFrame = 37;
-
- public void Tick()
- {
- UpdatePower();
- UpdateOreCapacity();
-
- var totalMoney = Cash + Ore;
- var diff = Math.Abs(totalMoney - DisplayCash);
- var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame),
- displayCashDeltaPerFrame), diff);
-
- var eva = World.WorldActor.Info.Traits.Get();
- if (DisplayCash < totalMoney)
- {
- DisplayCash += move;
- Sound.PlayToPlayer(this, eva.CashTickUp);
- }
- else if (DisplayCash > totalMoney)
- {
- DisplayCash -= move;
- Sound.PlayToPlayer(this, eva.CashTickDown);
- }
- }
-
- public Dictionary Stances = new Dictionary();
- }
-}
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using OpenRA.FileFormats;
+using OpenRA.Traits;
+
+namespace OpenRA
+{
+ public enum PowerState { Normal, Low, Critical };
+
+ public class Player
+ {
+ public Actor PlayerActor;
+ public int Kills;
+ public int Deaths;
+
+ public readonly string Palette;
+ public readonly Color Color;
+
+ public readonly string PlayerName;
+ public readonly string InternalName;
+ public readonly CountryInfo Country;
+ public readonly int Index;
+
+ public int Cash = 10000;
+ public int Ore = 0;
+ public int OreCapacity;
+ public int DisplayCash = 0;
+ public int PowerProvided = 0;
+ public int PowerDrained = 0;
+
+ public ShroudRenderer Shroud;
+ public World World { get; private set; }
+
+ public static List> PlayerColors(World world)
+ {
+ return world.WorldActor.Info.Traits.WithInterface()
+ .Where(p => p.Playable)
+ .Select(p => OpenRA.FileFormats.Tuple.New(p.Name, p.DisplayName, p.Color))
+ .ToList();
+ }
+
+ public Player( World world, Session.Client client )
+ {
+ World = world;
+ Shroud = new ShroudRenderer(this, world.Map);
+
+ PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
+
+ if (client != null)
+ {
+ Index = client.Index;
+ Palette = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].a;
+ Color = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].c;
+ PlayerName = client.Name;
+ InternalName = "Multi{0}".F(client.Index);
+ }
+ else
+ {
+ Index = -1;
+ PlayerName = InternalName = "Neutral";
+ Palette = "neutral";
+ Color = Color.Gray; // HACK HACK
+ }
+
+ Country = world.GetCountries()
+ .FirstOrDefault(c => client != null && client.Country == c.Name)
+ ?? world.GetCountries().Random(world.SharedRandom);
+ }
+
+ void UpdatePower()
+ {
+ var oldBalance = PowerProvided - PowerDrained;
+
+ PowerProvided = 0;
+ PowerDrained = 0;
+
+ var myBuildings = World.Queries.OwnedBy[this]
+ .WithTrait();
+
+ foreach (var a in myBuildings)
+ {
+ var p = a.Trait.GetPowerUsage();
+ if (p > 0)
+ PowerProvided += p;
+ else
+ PowerDrained -= p;
+ }
+
+ if (PowerProvided - PowerDrained < 0)
+ if (PowerProvided - PowerDrained != oldBalance)
+ GiveAdvice(World.WorldActor.Info.Traits.Get().LowPower);
+ }
+
+ public float GetSiloFullness()
+ {
+ return (float)Ore / OreCapacity;
+ }
+
+ public PowerState GetPowerState()
+ {
+ if (PowerProvided >= PowerDrained) return PowerState.Normal;
+ if (PowerProvided > PowerDrained / 2) return PowerState.Low;
+ return PowerState.Critical;
+ }
+
+ void UpdateOreCapacity()
+ {
+ OreCapacity = World.Queries.OwnedBy[this]
+ .Where(a => a.traits.Contains())
+ .Select(a => a.Info.Traits.Get())
+ .Sum(b => b.Capacity);
+ }
+
+ void GiveAdvice(string advice)
+ {
+ // todo: store the condition or something.
+ // repeat after World.Defaults.SpeakDelay, as long as the condition holds.
+ Sound.PlayToPlayer(this, advice);
+ }
+
+ public void GiveCash( int num ) { Cash += num; }
+ public void GiveOre(int num)
+ {
+ Ore += num;
+
+ if (Ore > OreCapacity)
+ Ore = OreCapacity; // trim off the overflow.
+
+ if (Ore > .8 * OreCapacity)
+ GiveAdvice(World.WorldActor.Info.Traits.Get().SilosNeeded);
+ }
+
+ public bool TakeCash( int num )
+ {
+ if (Cash + Ore < num) return false;
+ if (Ore <= num)
+ {
+ num -= Ore;
+ Ore = 0;
+ Cash -= num;
+ }
+ else
+ Ore -= num;
+
+ return true;
+ }
+
+ const float displayCashFracPerFrame = .07f;
+ const int displayCashDeltaPerFrame = 37;
+
+ public void Tick()
+ {
+ UpdatePower();
+ UpdateOreCapacity();
+
+ var totalMoney = Cash + Ore;
+ var diff = Math.Abs(totalMoney - DisplayCash);
+ var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame),
+ displayCashDeltaPerFrame), diff);
+
+ var eva = World.WorldActor.Info.Traits.Get();
+ if (DisplayCash < totalMoney)
+ {
+ DisplayCash += move;
+ Sound.PlayToPlayer(this, eva.CashTickUp);
+ }
+ else if (DisplayCash > totalMoney)
+ {
+ DisplayCash -= move;
+ Sound.PlayToPlayer(this, eva.CashTickDown);
+ }
+ }
+
+ public Dictionary Stances = new Dictionary();
+ }
+}
diff --git a/OpenRA.Game/Traits/Buildable.cs b/OpenRA.Game/Traits/Buildable.cs
index 8286018638..7f1310a610 100755
--- a/OpenRA.Game/Traits/Buildable.cs
+++ b/OpenRA.Game/Traits/Buildable.cs
@@ -1,48 +1,49 @@
-#region Copyright & License Information
-/*
- * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
- * This file is part of OpenRA.
- *
- * OpenRA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * OpenRA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with OpenRA. If not, see .
- */
-#endregion
-
-namespace OpenRA.Traits
-{
- class ValuedInfo : ITraitInfo
- {
- public readonly int Cost = 0;
- public readonly string Description = "";
- public readonly string LongDesc = "";
-
- public virtual object Create(Actor self) { return new Valued(); }
- }
-
- class BuildableInfo : ValuedInfo
- {
- public readonly int TechLevel = -1;
- public readonly string[] Prerequisites = { };
- public readonly string[] BuiltAt = { };
- public readonly string[] Owner = { };
-
- public readonly string Icon = null;
- public readonly string[] AlternateName = { };
- public readonly int BuildPaletteOrder = 50;
-
- public override object Create(Actor self) { return new Buildable(); }
- }
-
- class Valued { } /* halfway to buildable */
- class Buildable { }
-}
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+namespace OpenRA.Traits
+{
+ class ValuedInfo : ITraitInfo
+ {
+ public readonly int Cost = 0;
+ public readonly string Description = "";
+ public readonly string LongDesc = "";
+
+ public virtual object Create(Actor self) { return new Valued(); }
+ }
+
+ class BuildableInfo : ValuedInfo
+ {
+ public readonly int TechLevel = -1;
+ public readonly string[] Prerequisites = { };
+ public readonly string[] BuiltAt = { };
+ public readonly string[] Owner = { };
+
+ public readonly string Icon = null;
+ public readonly string[] AlternateName = { };
+ public readonly int BuildPaletteOrder = 50;
+ public readonly string Hotkey = null;
+
+ public override object Create(Actor self) { return new Buildable(); }
+ }
+
+ class Valued { } /* halfway to buildable */
+ class Buildable { }
+}
diff --git a/OpenRA.Game/Traits/World/ScreenShaker.cs b/OpenRA.Game/Traits/World/ScreenShaker.cs
index b825a3ff64..53d0967ce4 100644
--- a/OpenRA.Game/Traits/World/ScreenShaker.cs
+++ b/OpenRA.Game/Traits/World/ScreenShaker.cs
@@ -1,72 +1,72 @@
-#region Copyright & License Information
-/*
- * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
- * This file is part of OpenRA.
- *
- * OpenRA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * OpenRA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with OpenRA. If not, see .
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using OpenRA.FileFormats;
-
-namespace OpenRA.Traits
-{
- class ScreenShakerInfo : ITraitInfo
- {
- public object Create( Actor self ) { return new ScreenShaker(); }
- }
-
- public class ScreenShaker : ITick
- {
- int ticks = 0;
- List> shakeEffects = new List>();
-
- public void Tick (Actor self)
- {
- Game.viewport.Scroll(getScrollOffset());
- shakeEffects.RemoveAll(t => t.a == ticks);
- ticks++;
- }
-
- public void AddEffect(int time, float2 position, int intensity)
- {
- shakeEffects.Add(Tuple.New(ticks + time, position, intensity));
- }
-
- public float2 getScrollOffset()
- {
- int xFreq = 4;
- int yFreq = 5;
-
- return GetIntensity() * new float2(
- (float) Math.Sin((ticks*2*Math.PI)/xFreq) ,
- (float) Math.Cos((ticks*2*Math.PI)/yFreq));
- }
-
- public float GetIntensity()
- {
- var cp = Game.viewport.Location
- + .5f * new float2(Game.viewport.Width, Game.viewport.Height);
-
- var intensity = 24 * 24 * 100 * shakeEffects.Sum(
- e => e.c / (e.b - cp).LengthSquared);
-
- return Math.Min(intensity, 10);
- }
-
- }
-}
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA.FileFormats;
+
+namespace OpenRA.Traits
+{
+ class ScreenShakerInfo : ITraitInfo
+ {
+ public object Create( Actor self ) { return new ScreenShaker(); }
+ }
+
+ public class ScreenShaker : ITick
+ {
+ int ticks = 0;
+ List> shakeEffects = new List>();
+
+ public void Tick (Actor self)
+ {
+ Game.viewport.Scroll(getScrollOffset());
+ shakeEffects.RemoveAll(t => t.a == ticks);
+ ticks++;
+ }
+
+ public void AddEffect(int time, float2 position, int intensity)
+ {
+ shakeEffects.Add(OpenRA.FileFormats.Tuple.New(ticks + time, position, intensity));
+ }
+
+ public float2 getScrollOffset()
+ {
+ int xFreq = 4;
+ int yFreq = 5;
+
+ return GetIntensity() * new float2(
+ (float) Math.Sin((ticks*2*Math.PI)/xFreq) ,
+ (float) Math.Cos((ticks*2*Math.PI)/yFreq));
+ }
+
+ public float GetIntensity()
+ {
+ var cp = Game.viewport.Location
+ + .5f * new float2(Game.viewport.Width, Game.viewport.Height);
+
+ var intensity = 24 * 24 * 100 * shakeEffects.Sum(
+ e => e.c / (e.b - cp).LengthSquared);
+
+ return Math.Min(intensity, 10);
+ }
+
+ }
+}
diff --git a/OpenRA.Game/Widgets/BuildPaletteWidget.cs b/OpenRA.Game/Widgets/BuildPaletteWidget.cs
index f84d67344c..d1301ffc43 100644
--- a/OpenRA.Game/Widgets/BuildPaletteWidget.cs
+++ b/OpenRA.Game/Widgets/BuildPaletteWidget.cs
@@ -1,95 +1,95 @@
-#region Copyright & License Information
-/*
- * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
- * This file is part of OpenRA.
- *
- * OpenRA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * OpenRA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with OpenRA. If not, see .
- */
-#endregion
-
-using System.Drawing;
-using System.Collections.Generic;
-using System.Linq;
-using OpenRA;
-using OpenRA.Traits;
-using OpenRA.Graphics;
-using OpenRA.FileFormats;
-using OpenRA.Orders;
-using System;
-
-namespace OpenRA.Widgets
-{
- class BuildPaletteWidget : Widget
- {
- public int Columns = 3;
- public int Rows = 5;
-
- string currentTab = "Building";
- bool paletteOpen = false;
- Dictionary tabImageNames;
- Dictionary tabSprites;
- static float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280);
- static float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280);
- static float2 paletteOrigin = paletteClosedOrigin;
- const int paletteAnimationLength = 7;
- int paletteAnimationFrame = 0;
- bool paletteAnimating = false;
- List>> buttons = new List>>();
- Animation cantBuild;
- Animation ready;
- Animation clock;
- List visibleTabs = new List();
-
- public BuildPaletteWidget() : base() { }
-
- public BuildPaletteWidget(Widget other)
- : base(other)
- {
- throw new NotImplementedException("Why are you Cloning BuildPalette?");
- }
-
- public override Widget Clone() { return new BuildPaletteWidget(this); }
-
- public override void Initialize()
- {
- base.Initialize();
-
- cantBuild = new Animation("clock");
- cantBuild.PlayFetchIndex("idle", () => 0);
- ready = new Animation("pips");
- ready.PlayRepeating("ready");
- clock = new Animation("clock");
-
- tabSprites = Rules.Info.Values
- .Where(u => u.Traits.Contains())
- .ToDictionary(
- u => u.Name,
- u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get().Icon ?? (u.Name + "icon"))[0]);
-
- var groups = Rules.Categories();
-
- tabImageNames = groups.Select(
- (g, i) => Pair.New(g,
- OpenRA.Graphics.Util.MakeArray(3,
- n => i.ToString())))
- .ToDictionary(a => a.First, a => a.Second);
-
- }
-
- public override void Tick(World world)
- {
- visibleTabs.Clear();
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System.Drawing;
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA;
+using OpenRA.Traits;
+using OpenRA.Graphics;
+using OpenRA.FileFormats;
+using OpenRA.Orders;
+using System;
+
+namespace OpenRA.Widgets
+{
+ class BuildPaletteWidget : Widget
+ {
+ public int Columns = 3;
+ public int Rows = 5;
+
+ string currentTab = "Building";
+ bool paletteOpen = false;
+ Dictionary tabImageNames;
+ Dictionary tabSprites;
+ static float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280);
+ static float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280);
+ static float2 paletteOrigin = paletteClosedOrigin;
+ const int paletteAnimationLength = 7;
+ int paletteAnimationFrame = 0;
+ bool paletteAnimating = false;
+ List>> buttons = new List>>();
+ Animation cantBuild;
+ Animation ready;
+ Animation clock;
+ List visibleTabs = new List();
+
+ public BuildPaletteWidget() : base() { }
+
+ public BuildPaletteWidget(Widget other)
+ : base(other)
+ {
+ throw new NotImplementedException("Why are you Cloning BuildPalette?");
+ }
+
+ public override Widget Clone() { return new BuildPaletteWidget(this); }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ cantBuild = new Animation("clock");
+ cantBuild.PlayFetchIndex("idle", () => 0);
+ ready = new Animation("pips");
+ ready.PlayRepeating("ready");
+ clock = new Animation("clock");
+
+ tabSprites = Rules.Info.Values
+ .Where(u => u.Traits.Contains())
+ .ToDictionary(
+ u => u.Name,
+ u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get().Icon ?? (u.Name + "icon"))[0]);
+
+ var groups = Rules.Categories();
+
+ tabImageNames = groups.Select(
+ (g, i) => Pair.New(g,
+ OpenRA.Graphics.Util.MakeArray(3,
+ n => i.ToString())))
+ .ToDictionary(a => a.First, a => a.Second);
+
+ }
+
+ public override void Tick(World world)
+ {
+ visibleTabs.Clear();
foreach (var q in tabImageNames)
if (!Rules.TechTree.BuildableItems(world.LocalPlayer, q.Key).Any())
{
@@ -97,84 +97,84 @@ namespace OpenRA.Widgets
currentTab = null;
}
else
- visibleTabs.Add(q.Key);
-
- if (currentTab == null)
- currentTab = visibleTabs.FirstOrDefault();
-
- TickPaletteAnimation(world);
-
- base.Tick(world);
- }
-
- void TickPaletteAnimation(World world)
- {
- if (!paletteAnimating)
- return;
-
- // Increment frame
- if (paletteOpen)
- paletteAnimationFrame++;
- else
- paletteAnimationFrame--;
-
- // Calculate palette position
- if (paletteAnimationFrame <= paletteAnimationLength)
- paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength);
-
- var eva = world.WorldActor.Info.Traits.Get();
-
- // Play palette-open sound at the start of the activate anim (open)
- if (paletteAnimationFrame == 1 && paletteOpen)
- Sound.Play(eva.BuildPaletteOpen);
-
- // Play palette-close sound at the start of the activate anim (close)
- if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen)
- Sound.Play(eva.BuildPaletteClose);
-
- // Animation is complete
- if ((paletteAnimationFrame == 0 && !paletteOpen)
- || (paletteAnimationFrame == paletteAnimationLength && paletteOpen))
- {
- paletteAnimating = false;
- }
- }
-
- public void SetCurrentTab(string produces)
- {
- if (!paletteOpen)
- paletteAnimating = true;
- paletteOpen = true;
- currentTab = produces;
- }
-
- public override bool HandleInput(MouseInput mi)
- {
- // Are we able to handle this event?
- if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y))
- return base.HandleInput(mi);
-
- if (base.HandleInput(mi))
- return true;
-
- if (mi.Event == MouseInputEvent.Down)
- {
- var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint()))
- .Select(a => a.Second).FirstOrDefault();
- if (action == null)
- return false;
-
- action(mi);
- return true;
- }
-
- return false;
- }
-
- public override void Draw (World world)
- {
- int paletteHeight = DrawPalette(world, currentTab);
- DrawBuildTabs(world, paletteHeight);
+ visibleTabs.Add(q.Key);
+
+ if (currentTab == null)
+ currentTab = visibleTabs.FirstOrDefault();
+
+ TickPaletteAnimation(world);
+
+ base.Tick(world);
+ }
+
+ void TickPaletteAnimation(World world)
+ {
+ if (!paletteAnimating)
+ return;
+
+ // Increment frame
+ if (paletteOpen)
+ paletteAnimationFrame++;
+ else
+ paletteAnimationFrame--;
+
+ // Calculate palette position
+ if (paletteAnimationFrame <= paletteAnimationLength)
+ paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength);
+
+ var eva = world.WorldActor.Info.Traits.Get();
+
+ // Play palette-open sound at the start of the activate anim (open)
+ if (paletteAnimationFrame == 1 && paletteOpen)
+ Sound.Play(eva.BuildPaletteOpen);
+
+ // Play palette-close sound at the start of the activate anim (close)
+ if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen)
+ Sound.Play(eva.BuildPaletteClose);
+
+ // Animation is complete
+ if ((paletteAnimationFrame == 0 && !paletteOpen)
+ || (paletteAnimationFrame == paletteAnimationLength && paletteOpen))
+ {
+ paletteAnimating = false;
+ }
+ }
+
+ public void SetCurrentTab(string produces)
+ {
+ if (!paletteOpen)
+ paletteAnimating = true;
+ paletteOpen = true;
+ currentTab = produces;
+ }
+
+ public override bool HandleInput(MouseInput mi)
+ {
+ // Are we able to handle this event?
+ if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y))
+ return base.HandleInput(mi);
+
+ if (base.HandleInput(mi))
+ return true;
+
+ if (mi.Event == MouseInputEvent.Down)
+ {
+ var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint()))
+ .Select(a => a.Second).FirstOrDefault();
+ if (action == null)
+ return false;
+
+ action(mi);
+ return true;
+ }
+
+ return false;
+ }
+
+ public override void Draw (World world)
+ {
+ int paletteHeight = DrawPalette(world, currentTab);
+ DrawBuildTabs(world, paletteHeight);
}
int DrawPalette(World world, string queueName)
@@ -307,98 +307,107 @@ namespace OpenRA.Widgets
Game.chrome.renderer.RgbaSpriteRenderer.Flush();
return 48 * y + 9;
- }
-
- Action HandleClick(string name, World world)
- {
- return mi => {
- var eva = world.WorldActor.Info.Traits.Get();
- Sound.Play(eva.TabClick);
-
- if (name != null)
- HandleBuildPalette(world, name, (mi.Button == MouseButton.Left));
- };
- }
-
- Action HandleTabClick(string button, World world)
- {
- return mi => {
- if (mi.Button != MouseButton.Left)
- return;
-
- var eva = world.WorldActor.Info.Traits.Get();
- Sound.Play(eva.TabClick);
- var wasOpen = paletteOpen;
- paletteOpen = (currentTab == button && wasOpen) ? false : true;
- currentTab = button;
- if (wasOpen != paletteOpen)
- paletteAnimating = true;
- };
- }
-
- static string Description( string a )
- {
- if( a[ 0 ] == '@' )
- return "any " + a.Substring( 1 );
- else
- return Rules.Info[ a.ToLowerInvariant() ].Traits.Get().Description;
- }
-
- void HandleBuildPalette( World world, string item, bool isLmb )
- {
- var player = world.LocalPlayer;
- var unit = Rules.Info[item];
- var queue = player.PlayerActor.traits.Get();
- var eva = world.WorldActor.Info.Traits.Get();
- var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item );
-
- if (isLmb)
- {
- if (producing != null && producing == queue.CurrentItem(unit.Category))
- {
- if (producing.Done)
- {
- if (unit.Traits.Contains())
- Game.controller.orderGenerator = new PlaceBuildingOrderGenerator(player.PlayerActor, item);
- return;
- }
-
- if (producing.Paused)
- {
- Game.IssueOrder(Order.PauseProduction(player, item, false));
- return;
- }
- }
-
- StartProduction(world, item);
- }
- else
- {
- if (producing != null)
- {
- // instant cancel of things we havent really started yet, and things that are finished
- if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost)
- {
- Sound.Play(eva.CancelledAudio);
- Game.IssueOrder(Order.CancelProduction(player, item));
- }
- else
- {
- Sound.Play(eva.OnHoldAudio);
- Game.IssueOrder(Order.PauseProduction(player, item, true));
- }
- }
- }
- }
-
- void StartProduction( World world, string item )
- {
- var eva = world.WorldActor.Info.Traits.Get();
- var unit = Rules.Info[item];
-
- Sound.Play(unit.Traits.Contains() ? eva.BuildingSelectAudio : eva.UnitSelectAudio);
- Game.IssueOrder(Order.StartProduction(world.LocalPlayer, item,
- Game.controller.GetModifiers().HasModifier(Modifiers.Shift) ? 5 : 1));
+ }
+
+ Action HandleClick(string name, World world)
+ {
+ return mi => {
+ var eva = world.WorldActor.Info.Traits.Get();
+ Sound.Play(eva.TabClick);
+
+ if (name != null)
+ HandleBuildPalette(world, name, (mi.Button == MouseButton.Left));
+ };
+ }
+
+ static void Hotkey(World world, String name)
+ {
+ var eva = world.WorldActor.Info.Traits.Get();
+ Sound.Play(eva.TabClick);
+
+ if (name != null)
+ HandleBuildPalette(world, name, true);
+ }
+
+ Action HandleTabClick(string button, World world)
+ {
+ return mi => {
+ if (mi.Button != MouseButton.Left)
+ return;
+
+ var eva = world.WorldActor.Info.Traits.Get();
+ Sound.Play(eva.TabClick);
+ var wasOpen = paletteOpen;
+ paletteOpen = (currentTab == button && wasOpen) ? false : true;
+ currentTab = button;
+ if (wasOpen != paletteOpen)
+ paletteAnimating = true;
+ };
+ }
+
+ static string Description( string a )
+ {
+ if( a[ 0 ] == '@' )
+ return "any " + a.Substring( 1 );
+ else
+ return Rules.Info[ a.ToLowerInvariant() ].Traits.Get().Description;
+ }
+
+ static void HandleBuildPalette( World world, string item, bool isLmb )
+ {
+ var player = world.LocalPlayer;
+ var unit = Rules.Info[item];
+ var queue = player.PlayerActor.traits.Get();
+ var eva = world.WorldActor.Info.Traits.Get();
+ var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item );
+
+ if (isLmb)
+ {
+ if (producing != null && producing == queue.CurrentItem(unit.Category))
+ {
+ if (producing.Done)
+ {
+ if (unit.Traits.Contains())
+ Game.controller.orderGenerator = new PlaceBuildingOrderGenerator(player.PlayerActor, item);
+ return;
+ }
+
+ if (producing.Paused)
+ {
+ Game.IssueOrder(Order.PauseProduction(player, item, false));
+ return;
+ }
+ }
+
+ StartProduction(world, item);
+ }
+ else
+ {
+ if (producing != null)
+ {
+ // instant cancel of things we havent really started yet, and things that are finished
+ if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost)
+ {
+ Sound.Play(eva.CancelledAudio);
+ Game.IssueOrder(Order.CancelProduction(player, item));
+ }
+ else
+ {
+ Sound.Play(eva.OnHoldAudio);
+ Game.IssueOrder(Order.PauseProduction(player, item, true));
+ }
+ }
+ }
+ }
+
+ static void StartProduction( World world, string item )
+ {
+ var eva = world.WorldActor.Info.Traits.Get();
+ var unit = Rules.Info[item];
+
+ Sound.Play(unit.Traits.Contains() ? eva.BuildingSelectAudio : eva.UnitSelectAudio);
+ Game.IssueOrder(Order.StartProduction(world.LocalPlayer, item,
+ Game.controller.GetModifiers().HasModifier(Modifiers.Shift) ? 5 : 1));
}
static Dictionary CategoryNameRemaps = new Dictionary
@@ -408,32 +417,32 @@ namespace OpenRA.Widgets
{ "Plane", "Aircraft" },
{ "Ship", "Ships" },
{ "Vehicle", "Vehicles" },
- };
-
- void DrawBuildTabs( World world, int paletteHeight)
- {
- const int tabWidth = 24;
- const int tabHeight = 40;
- var x = paletteOrigin.X - tabWidth;
- var y = paletteOrigin.Y + 9;
-
- var queue = world.LocalPlayer.PlayerActor.traits.Get();
-
- foreach (var q in tabImageNames)
- {
- var groupName = q.Key;
- if (!visibleTabs.Contains(groupName))
- continue;
-
- string[] tabKeys = { "normal", "ready", "selected" };
- var producing = queue.CurrentItem(groupName);
- var index = q.Key == currentTab ? 2 : (producing != null && producing.Done) ? 1 : 0;
- var race = world.LocalPlayer.Country.Race;
- WidgetUtils.DrawRGBA(ChromeProvider.GetImage(Game.chrome.renderer,"tabs-"+tabKeys[index], race+"-"+q.Key), new float2(x, y));
-
+ };
+
+ void DrawBuildTabs( World world, int paletteHeight)
+ {
+ const int tabWidth = 24;
+ const int tabHeight = 40;
+ var x = paletteOrigin.X - tabWidth;
+ var y = paletteOrigin.Y + 9;
+
+ var queue = world.LocalPlayer.PlayerActor.traits.Get();
+
+ foreach (var q in tabImageNames)
+ {
+ var groupName = q.Key;
+ if (!visibleTabs.Contains(groupName))
+ continue;
+
+ string[] tabKeys = { "normal", "ready", "selected" };
+ var producing = queue.CurrentItem(groupName);
+ var index = q.Key == currentTab ? 2 : (producing != null && producing.Done) ? 1 : 0;
+ var race = world.LocalPlayer.Country.Race;
+ WidgetUtils.DrawRGBA(ChromeProvider.GetImage(Game.chrome.renderer,"tabs-"+tabKeys[index], race+"-"+q.Key), new float2(x, y));
+
var rect = new Rectangle((int)x,(int)y,(int)tabWidth,(int)tabHeight);
- buttons.Add(Pair.New(rect, HandleTabClick(groupName, world)));
-
+ buttons.Add(Pair.New(rect, HandleTabClick(groupName, world)));
+
if (rect.Contains(Game.chrome.lastMousePos.ToPoint()))
{
var text = CategoryNameRemaps.ContainsKey(groupName) ? CategoryNameRemaps[groupName] : groupName;
@@ -444,20 +453,20 @@ namespace OpenRA.Widgets
Game.chrome.renderer.BoldFont.DrawText(text,
new float2(rect.Left - sz.X - 20, rect.Top + 12), Color.White);
- }
-
- y += tabHeight;
- }
-
- Game.chrome.renderer.RgbaSpriteRenderer.Flush();
- }
-
+ }
+
+ y += tabHeight;
+ }
+
+ Game.chrome.renderer.RgbaSpriteRenderer.Flush();
+ }
+
void DrawRightAligned(string text, int2 pos, Color c)
{
Game.chrome.renderer.BoldFont.DrawText(text,
pos - new int2(Game.chrome.renderer.BoldFont.Measure(text).X, 0), c);
- }
-
+ }
+
void DrawProductionTooltip(World world, string unit, int2 pos)
{
pos.Y += 15;
@@ -481,6 +490,9 @@ namespace OpenRA.Widgets
DrawRightAligned( "${0}".F(buildable.Cost), pos + new int2(-5,5),
world.LocalPlayer.Cash + world.LocalPlayer.Ore >= buildable.Cost ? Color.White : Color.Red);
+ if (buildable.Hotkey != null)
+ DrawRightAligned("{0}".F(buildable.Hotkey.ToUpper()), pos + new int2(-5, 35),Color.White);
+
var bi = info.Traits.GetOrDefault();
if (bi != null)
DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20),
@@ -506,6 +518,43 @@ namespace OpenRA.Widgets
p.ToInt2(), Color.White);
Game.chrome.renderer.RgbaSpriteRenderer.Flush();
- }
- }
+ }
+
+ public static void DoBuildingHotkey(char c, World world)
+ {
+ if (Game.world.LocalPlayer == null) return;
+
+ var buildable = Rules.TechTree.BuildableItems(Game.world.LocalPlayer, Chrome.rootWidget.GetWidget("INGAME_BUILD_PALETTE").currentTab);
+
+ var toBuild = buildable.FirstOrDefault(b => Rules.Info[b.ToLowerInvariant()].Traits.Get().Hotkey == c.ToString());
+
+ if (toBuild != null) Hotkey(world, toBuild);
+
+ }
+ public static void TabChange(bool shift)
+ {
+ var p = Chrome.rootWidget.GetWidget("INGAME_BUILD_PALETTE");
+ int size = p.visibleTabs.Count();
+ if (size > 0)
+ {
+ string last = p.visibleTabs.Last();
+ string first = p.visibleTabs.First();
+ int current = p.visibleTabs.IndexOf(p.currentTab);
+ if (!shift)
+ {
+ if (current + 1 >= size)
+ p.SetCurrentTab(p.visibleTabs.FirstOrDefault());
+ else
+ p.SetCurrentTab(p.visibleTabs[current + 1]);
+ }
+ else
+ {
+ if (current - 1 < 0)
+ p.SetCurrentTab(p.visibleTabs.LastOrDefault());
+ else
+ p.SetCurrentTab(p.visibleTabs[current - 1]);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/mods/ra/structures.yaml b/mods/ra/structures.yaml
index 352cc37e64..2064084687 100644
--- a/mods/ra/structures.yaml
+++ b/mods/ra/structures.yaml
@@ -1,884 +1,918 @@
-MSLO:
- Category: Defense
- NukeSilo:
- Inherits: ^Building
- Buildable:
- TechLevel: 13
- Prerequisites: @Tech Center
- Owner: soviet,allies
- Cost: 2500
- Description: Missile Silo
- LongDesc: Launches a devastating nuclear strike.\n Strong vs Infantry, Buildings\n Weak vs Tanks\n Special Ability: Nuclear Missile
- Building:
- Power: -100
- Footprint: xx
- Dimensions: 2,1
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 5
- IronCurtainable:
-
-GAP:
- Category: Defense
- RequiresPower:
- CanPowerDown:
- GeneratesGap:
- Range: 10
- Inherits: ^Building
- Buildable:
- TechLevel: 10
- Prerequisites: atek
- Owner: allies
- Cost: 500
- Description: Gap Generator
- LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed
- Building:
- Power: -60
- Footprint: _ x
- Dimensions: 1,2
- Capturable: true
- HP: 1000
- Armor: wood
- Crewed: yes
- Sight: 10
- IronCurtainable:
-
-SPEN:
- InfiltrateForSonarPulse:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: @Power Plant
- Owner: soviet
- Cost: 650
- Description: Sub Pen
- LongDesc: Produces and repairs submarines and \ntransports
- Building:
- Power: -30
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- BaseNormal: no
- Adjacent: 8
- HP: 1000
- Armor: light
- WaterBound: yes
- Sight: 4
- ProductionSurround:
- Produces: Ship
- IronCurtainable:
- -EmitInfantryOnSell:
-
-SYRD:
- InfiltrateForSonarPulse:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: @Power Plant
- Owner: allies
- Cost: 650
- Description: Shipyard
- LongDesc: Produces and repairs ships
- BuildPaletteOrder: 4
- Building:
- Power: -30
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- BaseNormal: no
- Adjacent: 8
- HP: 1000
- Armor: light
- WaterBound: yes
- Sight: 4
- ProductionSurround:
- Produces: Ship
- IronCurtainable:
- -EmitInfantryOnSell:
-
-IRON:
- Category: Defense
- RequiresPower:
- CanPowerDown:
- Inherits: ^Building
- Buildable:
- TechLevel: 12
- Prerequisites: stek
- Owner: soviet
- Cost: 2800
- Description: Iron Curtain
- LongDesc: Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability
- Building:
- Power: -200
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 400
- Armor: wood
- Crewed: yes
- Sight: 10
- Bib:
- IronCurtainable:
- IronCurtain:
-
-PDOX:
- Category: Defense
- RequiresPower:
- CanPowerDown:
- Inherits: ^Building
- Buildable:
- TechLevel: 12
- Prerequisites: atek
- Owner: allies
- Cost: 2800
- Description: Chronosphere
- LongDesc: Teleports a unit from one place \nto another, for a limited time.\n Special Ability: Chronoshift
- Building:
- Power: -200
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 400
- Armor: wood
- Crewed: yes
- Sight: 10
- Bib:
- Chronosphere:
- IronCurtainable:
-
-TSLA:
- Category: Defense
- RequiresPower:
- CanPowerDown:
- Inherits: ^Building
- Buildable:
- TechLevel: 7
- Prerequisites: weap
- Owner: soviet
- Cost: 1500
- Description: Tesla Coil
- LongDesc: Advanced base defense. Requires power\nto operate.\n Strong vs Tanks, Infantry\n Weak vs Aircraft
- Building:
- Power: -150
- Footprint: _ x
- Dimensions: 1,2
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 8
- RenderBuildingCharge:
- AttackTesla:
- PrimaryWeapon: TeslaZap
- FireDelay: 8
- AutoTarget:
- IronCurtainable:
- -RenderBuilding:
- RenderRangeCircle:
-
-AGUN:
- Category: Defense
- RequiresPower:
- CanPowerDown:
- Inherits: ^Building
- Buildable:
- TechLevel: 5
- Prerequisites: dome
- Owner: allies
- Cost: 600
- Description: AA Gun
- LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
- Building:
- Power: -50
- Footprint: _ x
- Dimensions: 1,2
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 6
- Turreted:
- ROT: 15
- InitialFacing: 224
- RenderBuildingTurreted:
- AttackTurreted:
- PrimaryWeapon: ZSU-23
- SecondaryWeapon: ZSU-23
- AutoTarget:
- IronCurtainable:
- -RenderBuilding:
- RenderRangeCircle:
-
-DOME:
- RequiresPower:
- CanPowerDown:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: proc
- Owner: allies,soviet
- Cost: 1000
- Description: Radar Dome
- LongDesc: Provides an overview of the battlefield.\n Requires power to operate.
- BuildPaletteOrder: 6
- Building:
- Power: -40
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 1000
- Armor: wood
- Crewed: yes
- Sight: 10
- Bib:
- ProvidesRadar:
- IronCurtainable:
-
-PBOX:
- Category: Defense
- Inherits: ^Building
- Buildable:
- TechLevel: 2
- Prerequisites: tent
- Owner: allies
- Cost: 400
- Description: Pillbox
- LongDesc: Basic defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
- Building:
- Power: -15
- HP: 400
- Armor: wood
- Crewed: yes
- Sight: 5
- AttackOmni:
- PrimaryWeapon: Vulcan
- AutoTarget:
- IronCurtainable:
- RenderRangeCircle:
-
-HBOX:
- Category: Defense
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: tent
- Owner: allies
- Cost: 600
- Description: Camo Pillbox
- LongDesc: Hidden defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
- Building:
- Power: -15
- HP: 600
- Armor: wood
- Crewed: yes
- Sight: 5
- AttackOmni:
- PrimaryWeapon: Vulcan
- AutoTarget:
- IronCurtainable:
- RenderRangeCircle:
-
-GUN:
- Category: Defense
- Inherits: ^Building
- Buildable:
- TechLevel: 4
- Prerequisites: tent
- Owner: allies
- Cost: 600
- Description: Turret
- LongDesc: Anti-Armor base defense.\n Strong vs Tanks\n Weak vs Infantry, Aircraft
- Building:
- Power: -40
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 6
- Turreted:
- ROT: 12
- InitialFacing: 50
- RenderBuildingTurreted:
- AttackTurreted:
- PrimaryWeapon: TurretGun
- AutoTarget:
- IronCurtainable:
- -RenderBuilding:
- RenderRangeCircle:
-
-FTUR:
- Category: Defense
- Inherits: ^Building
- Buildable:
- TechLevel: 2
- Prerequisites: barr
- Owner: soviet
- Cost: 600
- Description: Flame Turret
- LongDesc: Anti-Infantry base defense.\n Strong vs Infantry\n Weak vs Aircraft
- Building:
- Power: -20
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 6
- AttackOmni:
- PrimaryWeapon: FireballLauncher
- PrimaryOffset: 0,0,12,8
- AutoTarget:
- IronCurtainable:
- RenderRangeCircle:
-
-SAM:
- Category: Defense
- Inherits: ^Building
- Buildable:
- TechLevel: 9
- Prerequisites: dome
- Owner: soviet
- Cost: 750
- Description: SAM Site
- LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
- Building:
- Power: -20
- Footprint: xx
- Dimensions: 2,1
- HP: 400
- Armor: heavy
- Crewed: yes
- Sight: 5
- Turreted:
- ROT: 30
- InitialFacing: 0
- RenderBuildingTurreted:
- AttackTurreted:
- PrimaryWeapon: Nike
- AutoTarget:
- IronCurtainable:
- -RenderBuilding:
- RenderRangeCircle:
-
-ATEK:
- Inherits: ^Building
- Buildable:
- TechLevel: 10
- Prerequisites: weap,dome
- Owner: allies
- Cost: 1500
- Description: Allied Tech Center
- LongDesc: Provides Allied advanced technologies.\n Special Ability: GPS Satellite
- AlternateName: @Tech Center
- Building:
- Power: -200
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 400
- Armor: wood
- Crewed: yes
- Sight: 10
- Bib:
- IronCurtainable:
- GpsLaunchSite:
-
-WEAP:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: proc
- Owner: soviet,allies
- Cost: 2000
- Description: War Factory
- LongDesc: Produces tanks & light vehicles.
- BuildPaletteOrder: 5
- Building:
- Power: -30
- Footprint: xxx xxx
- Dimensions: 3,2
- Capturable: true
- HP: 1000
- Armor: light
- Crewed: yes
- Sight: 4
- Bib:
- RenderWarFactory:
- RallyPoint:
- Production:
- Produces: Vehicle
- IronCurtainable:
-
-FACT:
- Inherits: ^Building
- Building:
- Power: 0
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- HP: 1000
- Armor: heavy
- Crewed: yes
- Sight: 5
- Bib:
- Production:
- Produces: Building,Defense
- ConstructionYard:
- IronCurtainable:
- Valued:
- Cost: 2500
- Description: Construction Yard
- CustomSellValue:
- Value: 2500
- BaseBuilding:
-
-PROC:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Prerequisites: @Power Plant
- Owner: allies,soviet
- Cost: 2000
- Description: Ore Refinery
- LongDesc: Converts Ore and Gems into money
- BuildPaletteOrder: 1
- Building:
- Power: -30
- Footprint: _x_ xxx x==
- Dimensions: 3,3
- Capturable: true
- HP: 900
- Armor: wood
- Crewed: yes
- Sight: 6
- Bib:
- OreRefinery:
- StoresOre:
- Pips: 17
- Capacity: 2000
- IronCurtainable:
- CustomSellValue:
- Value: 600
- HasUnitOnBuild:
- Unit: HARV
- InitialActivity: Harvest
- SpawnOffset: 1,2
- Facing: 64
-
-SILO:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Prerequisites: proc
- Owner: allies,soviet
- Cost: 150
- Description: Silo
- LongDesc: Stores excess harvested Ore
- Building:
- Power: -10
- Capturable: true
- HP: 300
- Armor: wood
- Sight: 4
- RenderBuildingOre:
- StoresOre:
- Pips: 5
- Capacity: 1500
- IronCurtainable:
- -RenderBuilding:
-
-HPAD:
- Inherits: ^Building
- Buildable:
- TechLevel: 9
- Prerequisites: dome
- Owner: allies
- Cost: 1500
- Description: Helipad
- LongDesc: Produces and reloads helicopters
- Building:
- Power: -10
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 800
- Armor: wood
- Crewed: yes
- Sight: 5
- Bib:
- Production:
- SpawnOffset: 0,-4
- Produces: Plane
- BelowUnits:
- Reservable:
- IronCurtainable:
-
-AFLD:
- Inherits: ^Building
- Buildable:
- TechLevel: 5
- Prerequisites: dome
- Owner: soviet
- Cost: 600
- Description: Airstrip
- LongDesc: Produces and reloads planes\n Special Ability: Paratroopers\n Special Ability: Spy Plane
- Building:
- Power: -30
- Footprint: xxx xxx
- Dimensions: 3,2
- Capturable: true
- HP: 1000
- Armor: heavy
- Crewed: yes
- Sight: 7
- Production:
- Produces: Plane
- BelowUnits:
- Reservable:
- IronCurtainable:
-
-POWR:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Owner: allies,soviet
- Cost: 300
- Description: Power Plant
- LongDesc: Provides power for other structures
- BuildPaletteOrder: 0
- AlternateName: @Power Plant
- Building:
- Power: 100
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 400
- Armor: wood
- Crewed: yes
- Sight: 4
- Bib:
- IronCurtainable:
-
-APWR:
- Inherits: ^Building
- Buildable:
- TechLevel: 8
- Prerequisites: @Power Plant
- Owner: allies,soviet
- Cost: 500
- Description: Advanced Power Plant
- LongDesc: Provides more power, cheaper than the \nstandard Power Plant
- BuildPaletteOrder:2
- AlternateName: @Power Plant
- Building:
- Power: 200
- Footprint: ___ xxx xxx
- Dimensions: 3,3
- Capturable: true
- HP: 700
- Armor: wood
- Crewed: yes
- Sight: 4
- Bib:
- IronCurtainable:
-
-STEK:
- Inherits: ^Building
- Buildable:
- TechLevel: 6
- Prerequisites: weap,dome
- Owner: soviet
- Cost: 1500
- Description: Soviet Tech Center
- LongDesc: Provides Soviet advanced technologies
- AlternateName: @Tech Center
- Building:
- Power: -100
- Footprint: xxx xxx
- Dimensions: 3,2
- Capturable: true
- HP: 600
- Armor: wood
- Crewed: yes
- Sight: 4
- Bib:
- IronCurtainable:
-
-BARR:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Prerequisites: @Power Plant
- Owner: soviet
- Cost: 300
- Description: Soviet Barracks
- LongDesc: Produces infantry
- BuildPaletteOrder: 3
- Building:
- Power: -20
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 800
- Armor: wood
- Crewed: yes
- Sight: 5
- Bib:
- RallyPoint:
- Production:
- Produces: Infantry
- IronCurtainable:
-
-TENT:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Prerequisites: @Power Plant
- Owner: allies
- Cost: 300
- Description: Allied Barracks
- LongDesc: Produces infantry
- BuildPaletteOrder: 3
- Building:
- Power: -20
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- HP: 800
- Armor: wood
- Crewed: yes
- Sight: 5
- Bib:
- RallyPoint:
- Production:
- Produces: Infantry
- IronCurtainable:
-
-KENN:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: barr
- Owner: soviet
- Cost: 200
- Description: Kennel
- LongDesc: Produces attack dogs
- Building:
- Power: -10
- HP: 400
- Armor: wood
- Sight: 4
- RallyPoint:
- Production:
- IronCurtainable:
-
-FIX:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: weap
- Owner: allies,soviet
- Cost: 1200
- Description: Service Depot
- LongDesc: Repairs vehicles, reloads minelayers, and \nallows the construction of additional bases.
- Building:
- Power: -30
- Footprint: _x_ xxx _x_
- Dimensions: 3,3
- Capturable: true
- HP: 800
- Armor: wood
- Crewed: yes
- Sight: 5
- BelowUnits:
- Reservable:
- IronCurtainable:
- RepairsUnits:
-
-FACF:
- Inherits: ^Building
- Buildable:
- TechLevel: 1
- Owner: allies
- Cost: 50
- Description: Fake Construction Yard
- LongDesc: Looks like a Construction Yard.
- BuildPaletteOrder: 90
- Building:
- Power: -2
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- BaseNormal: no
- HP: 30
- Sight: 4
- Bib:
- RenderBuilding:
- Image: FACT
- Fake:
- IronCurtainable:
-
-WEAF:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: proc
- Owner: allies
- Cost: 50
- Description: Fake War Factory
- LongDesc: Looks like a War Factory.
- BuildPaletteOrder: 90
- Building:
- Power: -2
- Footprint: xxx xxx
- Dimensions: 3,2
- Capturable: true
- BaseNormal: no
- HP: 30
- Sight: 4
- Bib:
- RenderWarFactory:
- RenderBuilding:
- Image: WEAP
- Fake:
- IronCurtainable:
-
-SYRF:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: @Power Plant
- Owner: allies
- Cost: 50
- Description: Fake Shipyard
- LongDesc: Looks like a Shipyard
- BuildPaletteOrder: 90
- Building:
- Power: -2
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- BaseNormal: no
- Adjacent: 8
- HP: 30
- WaterBound: yes
- Sight: 4
- RenderBuilding:
- Image: SYRD
- Fake:
- -EmitInfantryOnSell:
-
-SPEF:
- Inherits: ^Building
- Building:
- Power: -2
- Footprint: xxx xxx xxx
- Dimensions: 3,3
- Capturable: true
- BaseNormal: no
- Adjacent: 8
- HP: 30
- WaterBound: yes
- Sight: 4
- RenderBuilding:
- Image: SPEN
- Fake:
- -EmitInfantryOnSell:
-
-DOMF:
- Inherits: ^Building
- Buildable:
- TechLevel: 3
- Prerequisites: proc
- Owner: allies
- Cost: 50
- Description: Fake Radar Dome
- LongDesc: Looks like a Radar Dome
- BuildPaletteOrder: 90
- Building:
- Power: -2
- Footprint: xx xx
- Dimensions: 2,2
- Capturable: true
- BaseNormal: no
- HP: 30
- Sight: 4
- Bib:
- RenderBuilding:
- Image: DOME
- Fake:
-
-SBAG:
- Category: Defense
- Inherits: ^Wall
- Buildable:
- TechLevel: 2
- Prerequisites: fact
- Owner: allies
- Cost: 25
- Description: Sandbag Wall
- LongDesc: Stops infantry and blocks enemy fire.\nCan be crushed by tanks.
- BuildPaletteOrder: 100
- Building:
- HP: 100
- Armor: none
- Wall:
- CrushableBy: Wheel, Track
-
-FENC:
- Category: Defense
- Inherits: ^Wall
- Buildable:
- TechLevel: 2
- Prerequisites: fact
- Owner: soviet
- Cost: 25
- Description: Wire Fence
- LongDesc: Stops infantry and blocks enemy fire.\nCan be crushed by tanks.
- BuildPaletteOrder: 100
- Building:
- HP: 100
- Armor: none
- Wall:
- CrushableBy: Track
-
-BRIK:
- Category: Defense
- Inherits: ^Wall
- Buildable:
- TechLevel: 8
- Prerequisites: fact
- Owner: allies,soviet
- Cost: 100
- Description: Concrete Wall
- LongDesc: Stop units and blocks enemy fire.
- BuildPaletteOrder: 100
- Building:
- HP: 100
- Armor: none
- DamagedSound: crmble2.aud
- DestroyedSound: kaboom30.aud
- RenderBuildingWall:
- DamageStates: 4
-
-CYCL:
- Inherits: ^Wall
- Building:
- HP: 100
- Armor: none
- RenderBuildingWall:
- DamageStates: 3
- Wall:
- CrushableBy: Track
-
-BARB:
- Inherits: ^Wall
- Building:
- HP: 100
- Armor: none
- Wall:
- CrushableBy: Track
-
-WOOD:
- Inherits: ^Wall
- Building:
- HP: 100
- Armor: none
- Wall:
- CrushableBy: Track
+MSLO:
+ Category: Defense
+ NukeSilo:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 13
+ Prerequisites: @Tech Center
+ Owner: soviet,allies
+ Cost: 2500
+ Description: Missile Silo
+ LongDesc: Launches a devastating nuclear strike.\n Strong vs Infantry, Buildings\n Weak vs Tanks\n Special Ability: Nuclear Missile
+ Hotkey: m
+ Building:
+ Power: -100
+ Footprint: xx
+ Dimensions: 2,1
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 5
+ IronCurtainable:
+
+GAP:
+ Category: Defense
+ RequiresPower:
+ CanPowerDown:
+ GeneratesGap:
+ Range: 10
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 10
+ Prerequisites: atek
+ Owner: allies
+ Cost: 500
+ Description: Gap Generator
+ LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed
+ Hotkey: g
+ Building:
+ Power: -60
+ Footprint: _ x
+ Dimensions: 1,2
+ Capturable: true
+ HP: 1000
+ Armor: wood
+ Crewed: yes
+ Sight: 10
+ IronCurtainable:
+
+SPEN:
+ InfiltrateForSonarPulse:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: @Power Plant
+ Owner: soviet
+ Cost: 650
+ Description: Sub Pen
+ LongDesc: Produces and repairs submarines and \ntransports
+ Hotkey: s
+ Building:
+ Power: -30
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ BaseNormal: no
+ Adjacent: 8
+ HP: 1000
+ Armor: light
+ WaterBound: yes
+ Sight: 4
+ ProductionSurround:
+ Produces: Ship
+ IronCurtainable:
+ -EmitInfantryOnSell:
+
+SYRD:
+ InfiltrateForSonarPulse:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: @Power Plant
+ Owner: allies
+ Cost: 650
+ Description: Shipyard
+ LongDesc: Produces and repairs ships
+ BuildPaletteOrder: 4
+ Hotkey: s
+ Building:
+ Power: -30
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ BaseNormal: no
+ Adjacent: 8
+ HP: 1000
+ Armor: light
+ WaterBound: yes
+ Sight: 4
+ ProductionSurround:
+ Produces: Ship
+ IronCurtainable:
+ -EmitInfantryOnSell:
+
+IRON:
+ Category: Defense
+ RequiresPower:
+ CanPowerDown:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 12
+ Prerequisites: stek
+ Owner: soviet
+ Cost: 2800
+ Description: Iron Curtain
+ LongDesc: Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability
+ Hotkey: c
+ Building:
+ Power: -200
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 400
+ Armor: wood
+ Crewed: yes
+ Sight: 10
+ Bib:
+ IronCurtainable:
+ IronCurtain:
+
+PDOX:
+ Category: Defense
+ RequiresPower:
+ CanPowerDown:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 12
+ Prerequisites: atek
+ Owner: allies
+ Cost: 2800
+ Description: Chronosphere
+ LongDesc: Teleports a unit from one place \nto another, for a limited time.\n Special Ability: Chronoshift
+ Hotkey: o
+ Building:
+ Power: -200
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 400
+ Armor: wood
+ Crewed: yes
+ Sight: 10
+ Bib:
+ Chronosphere:
+ IronCurtainable:
+
+TSLA:
+ Category: Defense
+ RequiresPower:
+ CanPowerDown:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 7
+ Prerequisites: weap
+ Owner: soviet
+ Cost: 1500
+ Description: Tesla Coil
+ LongDesc: Advanced base defense. Requires power\nto operate.\n Strong vs Tanks, Infantry\n Weak vs Aircraft
+ Hotkey: t
+ Building:
+ Power: -150
+ Footprint: _ x
+ Dimensions: 1,2
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 8
+ RenderBuildingCharge:
+ AttackTesla:
+ PrimaryWeapon: TeslaZap
+ FireDelay: 8
+ AutoTarget:
+ IronCurtainable:
+ -RenderBuilding:
+ RenderRangeCircle:
+
+AGUN:
+ Category: Defense
+ RequiresPower:
+ CanPowerDown:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 5
+ Prerequisites: dome
+ Owner: allies
+ Cost: 600
+ Description: AA Gun
+ LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
+ Hotkey: a
+ Building:
+ Power: -50
+ Footprint: _ x
+ Dimensions: 1,2
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 6
+ Turreted:
+ ROT: 15
+ InitialFacing: 224
+ RenderBuildingTurreted:
+ AttackTurreted:
+ PrimaryWeapon: ZSU-23
+ SecondaryWeapon: ZSU-23
+ AutoTarget:
+ IronCurtainable:
+ -RenderBuilding:
+ RenderRangeCircle:
+
+DOME:
+ RequiresPower:
+ CanPowerDown:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: proc
+ Owner: allies,soviet
+ Cost: 1000
+ Description: Radar Dome
+ LongDesc: Provides an overview of the battlefield.\n Requires power to operate.
+ BuildPaletteOrder: 6
+ Hotkey: r
+ Building:
+ Power: -40
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 1000
+ Armor: wood
+ Crewed: yes
+ Sight: 10
+ Bib:
+ ProvidesRadar:
+ IronCurtainable:
+
+PBOX:
+ Category: Defense
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 2
+ Prerequisites: tent
+ Owner: allies
+ Cost: 400
+ Description: Pillbox
+ LongDesc: Basic defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
+ Hotkey: x
+ Building:
+ Power: -15
+ HP: 400
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ AttackOmni:
+ PrimaryWeapon: Vulcan
+ AutoTarget:
+ IronCurtainable:
+ RenderRangeCircle:
+
+HBOX:
+ Category: Defense
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: tent
+ Owner: allies
+ Cost: 600
+ Description: Camo Pillbox
+ LongDesc: Hidden defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft
+ Hotkey: c
+ Building:
+ Power: -15
+ HP: 600
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ AttackOmni:
+ PrimaryWeapon: Vulcan
+ AutoTarget:
+ IronCurtainable:
+ RenderRangeCircle:
+
+GUN:
+ Category: Defense
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 4
+ Prerequisites: tent
+ Owner: allies
+ Cost: 600
+ Description: Turret
+ LongDesc: Anti-Armor base defense.\n Strong vs Tanks\n Weak vs Infantry, Aircraft
+ Hotkey: t
+ Building:
+ Power: -40
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 6
+ Turreted:
+ ROT: 12
+ InitialFacing: 50
+ RenderBuildingTurreted:
+ AttackTurreted:
+ PrimaryWeapon: TurretGun
+ AutoTarget:
+ IronCurtainable:
+ -RenderBuilding:
+ RenderRangeCircle:
+
+FTUR:
+ Category: Defense
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 2
+ Prerequisites: barr
+ Owner: soviet
+ Cost: 600
+ Description: Flame Turret
+ LongDesc: Anti-Infantry base defense.\n Strong vs Infantry\n Weak vs Aircraft
+ Hotkey: f
+ Building:
+ Power: -20
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 6
+ AttackOmni:
+ PrimaryWeapon: FireballLauncher
+ PrimaryOffset: 0,0,12,8
+ AutoTarget:
+ IronCurtainable:
+ RenderRangeCircle:
+
+SAM:
+ Category: Defense
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 9
+ Prerequisites: dome
+ Owner: soviet
+ Cost: 750
+ Description: SAM Site
+ LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
+ Hotkey: s
+ Building:
+ Power: -20
+ Footprint: xx
+ Dimensions: 2,1
+ HP: 400
+ Armor: heavy
+ Crewed: yes
+ Sight: 5
+ Turreted:
+ ROT: 30
+ InitialFacing: 0
+ RenderBuildingTurreted:
+ AttackTurreted:
+ PrimaryWeapon: Nike
+ AutoTarget:
+ IronCurtainable:
+ -RenderBuilding:
+ RenderRangeCircle:
+
+ATEK:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 10
+ Prerequisites: weap,dome
+ Owner: allies
+ Cost: 1500
+ Description: Allied Tech Center
+ LongDesc: Provides Allied advanced technologies.\n Special Ability: GPS Satellite
+ AlternateName: @Tech Center
+ Hotkey: t
+ Building:
+ Power: -200
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 400
+ Armor: wood
+ Crewed: yes
+ Sight: 10
+ Bib:
+ IronCurtainable:
+ GpsLaunchSite:
+
+WEAP:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: proc
+ Owner: soviet,allies
+ Cost: 2000
+ Description: War Factory
+ LongDesc: Produces tanks & light vehicles.
+ BuildPaletteOrder: 5
+ Hotkey: w
+ Building:
+ Power: -30
+ Footprint: xxx xxx
+ Dimensions: 3,2
+ Capturable: true
+ HP: 1000
+ Armor: light
+ Crewed: yes
+ Sight: 4
+ Bib:
+ RenderWarFactory:
+ RallyPoint:
+ Production:
+ Produces: Vehicle
+ IronCurtainable:
+
+FACT:
+ Inherits: ^Building
+ Building:
+ Power: 0
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ HP: 1000
+ Armor: heavy
+ Crewed: yes
+ Sight: 5
+ Bib:
+ Production:
+ Produces: Building,Defense
+ ConstructionYard:
+ IronCurtainable:
+ Valued:
+ Cost: 2500
+ Description: Construction Yard
+ CustomSellValue:
+ Value: 2500
+ BaseBuilding:
+
+PROC:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Prerequisites: @Power Plant
+ Owner: allies,soviet
+ Cost: 2000
+ Description: Ore Refinery
+ LongDesc: Converts Ore and Gems into money
+ BuildPaletteOrder: 1
+ Hotkey: e
+ Building:
+ Power: -30
+ Footprint: _x_ xxx x==
+ Dimensions: 3,3
+ Capturable: true
+ HP: 900
+ Armor: wood
+ Crewed: yes
+ Sight: 6
+ Bib:
+ OreRefinery:
+ StoresOre:
+ Pips: 17
+ Capacity: 2000
+ IronCurtainable:
+ CustomSellValue:
+ Value: 600
+ HasUnitOnBuild:
+ Unit: HARV
+ InitialActivity: Harvest
+ SpawnOffset: 1,2
+ Facing: 64
+
+SILO:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Prerequisites: proc
+ Owner: allies,soviet
+ Cost: 150
+ Description: Silo
+ LongDesc: Stores excess harvested Ore
+ Hotkey: o
+ Building:
+ Power: -10
+ Capturable: true
+ HP: 300
+ Armor: wood
+ Sight: 4
+ RenderBuildingOre:
+ StoresOre:
+ Pips: 5
+ Capacity: 1500
+ IronCurtainable:
+ -RenderBuilding:
+
+HPAD:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 9
+ Prerequisites: dome
+ Owner: allies
+ Cost: 1500
+ Description: Helipad
+ LongDesc: Produces and reloads helicopters
+ Hotkey: i
+ Building:
+ Power: -10
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 800
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ Bib:
+ Production:
+ SpawnOffset: 0,-4
+ Produces: Plane
+ BelowUnits:
+ Reservable:
+ IronCurtainable:
+
+AFLD:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 5
+ Prerequisites: dome
+ Owner: soviet
+ Cost: 600
+ Description: Airstrip
+ LongDesc: Produces and reloads planes\n Special Ability: Paratroopers\n Special Ability: Spy Plane
+ Hotkey: a
+ Building:
+ Power: -30
+ Footprint: xxx xxx
+ Dimensions: 3,2
+ Capturable: true
+ HP: 1000
+ Armor: heavy
+ Crewed: yes
+ Sight: 7
+ Production:
+ Produces: Plane
+ BelowUnits:
+ Reservable:
+ IronCurtainable:
+
+POWR:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Owner: allies,soviet
+ Cost: 300
+ Description: Power Plant
+ LongDesc: Provides power for other structures
+ BuildPaletteOrder: 0
+ AlternateName: @Power Plant
+ Hotkey: p
+ Building:
+ Power: 100
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 400
+ Armor: wood
+ Crewed: yes
+ Sight: 4
+ Bib:
+ IronCurtainable:
+
+APWR:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 8
+ Prerequisites: @Power Plant
+ Owner: allies,soviet
+ Cost: 500
+ Description: Advanced Power Plant
+ LongDesc: Provides more power, cheaper than the \nstandard Power Plant
+ BuildPaletteOrder:2
+ Hotkey: l
+ AlternateName: @Power Plant
+ Building:
+ Power: 200
+ Footprint: ___ xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ HP: 700
+ Armor: wood
+ Crewed: yes
+ Sight: 4
+ Bib:
+ IronCurtainable:
+
+STEK:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 6
+ Prerequisites: weap,dome
+ Owner: soviet
+ Cost: 1500
+ Description: Soviet Tech Center
+ LongDesc: Provides Soviet advanced technologies
+ AlternateName: @Tech Center
+ Hotkey: t
+ Building:
+ Power: -100
+ Footprint: xxx xxx
+ Dimensions: 3,2
+ Capturable: true
+ HP: 600
+ Armor: wood
+ Crewed: yes
+ Sight: 4
+ Bib:
+ IronCurtainable:
+
+BARR:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Prerequisites: @Power Plant
+ Owner: soviet
+ Cost: 300
+ Description: Soviet Barracks
+ LongDesc: Produces infantry
+ BuildPaletteOrder: 3
+ Hotkey: b
+ Building:
+ Power: -20
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 800
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ Bib:
+ RallyPoint:
+ Production:
+ Produces: Infantry
+ IronCurtainable:
+
+TENT:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Prerequisites: @Power Plant
+ Owner: allies
+ Cost: 300
+ Description: Allied Barracks
+ LongDesc: Produces infantry
+ BuildPaletteOrder: 3
+ Hotkey: b
+ Building:
+ Power: -20
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ HP: 800
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ Bib:
+ RallyPoint:
+ Production:
+ Produces: Infantry
+ IronCurtainable:
+
+KENN:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: barr
+ Owner: soviet
+ Cost: 200
+ Description: Kennel
+ LongDesc: Produces attack dogs
+ Hotkey: k
+ Building:
+ Power: -10
+ HP: 400
+ Armor: wood
+ Sight: 4
+ RallyPoint:
+ Production:
+ IronCurtainable:
+
+FIX:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: weap
+ Owner: allies,soviet
+ Cost: 1200
+ Description: Service Depot
+ LongDesc: Repairs vehicles, reloads minelayers, and \nallows the construction of additional bases.
+ Hotkey: d
+ Building:
+ Power: -30
+ Footprint: _x_ xxx _x_
+ Dimensions: 3,3
+ Capturable: true
+ HP: 800
+ Armor: wood
+ Crewed: yes
+ Sight: 5
+ BelowUnits:
+ Reservable:
+ IronCurtainable:
+ RepairsUnits:
+
+FACF:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 1
+ Owner: allies
+ Cost: 50
+ Description: Fake Construction Yard
+ LongDesc: Looks like a Construction Yard.
+ BuildPaletteOrder: 90
+ Hotkey: c
+ Building:
+ Power: -2
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ BaseNormal: no
+ HP: 30
+ Sight: 4
+ Bib:
+ RenderBuilding:
+ Image: FACT
+ Fake:
+ IronCurtainable:
+
+WEAF:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: proc
+ Owner: allies
+ Cost: 50
+ Description: Fake War Factory
+ LongDesc: Looks like a War Factory.
+ BuildPaletteOrder: 90
+ Hotkey: x
+ Building:
+ Power: -2
+ Footprint: xxx xxx
+ Dimensions: 3,2
+ Capturable: true
+ BaseNormal: no
+ HP: 30
+ Sight: 4
+ Bib:
+ RenderWarFactory:
+ RenderBuilding:
+ Image: WEAP
+ Fake:
+ IronCurtainable:
+
+SYRF:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: @Power Plant
+ Owner: allies
+ Cost: 50
+ Description: Fake Shipyard
+ LongDesc: Looks like a Shipyard
+ BuildPaletteOrder: 90
+ Hotkey: z
+ Building:
+ Power: -2
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ BaseNormal: no
+ Adjacent: 8
+ HP: 30
+ WaterBound: yes
+ Sight: 4
+ RenderBuilding:
+ Image: SYRD
+ Fake:
+ -EmitInfantryOnSell:
+
+SPEF:
+ Inherits: ^Building
+ Building:
+ Power: -2
+ Footprint: xxx xxx xxx
+ Dimensions: 3,3
+ Capturable: true
+ BaseNormal: no
+ Adjacent: 8
+ HP: 30
+ WaterBound: yes
+ Sight: 4
+ RenderBuilding:
+ Image: SPEN
+ Fake:
+ -EmitInfantryOnSell:
+
+DOMF:
+ Inherits: ^Building
+ Buildable:
+ TechLevel: 3
+ Prerequisites: proc
+ Owner: allies
+ Cost: 50
+ Description: Fake Radar Dome
+ LongDesc: Looks like a Radar Dome
+ BuildPaletteOrder: 90
+ Hotkey: v
+ Building:
+ Power: -2
+ Footprint: xx xx
+ Dimensions: 2,2
+ Capturable: true
+ BaseNormal: no
+ HP: 30
+ Sight: 4
+ Bib:
+ RenderBuilding:
+ Image: DOME
+ Fake:
+
+SBAG:
+ Category: Defense
+ Inherits: ^Wall
+ Buildable:
+ TechLevel: 2
+ Prerequisites: fact
+ Owner: allies
+ Cost: 25
+ Description: Sandbag Wall
+ LongDesc: Stops infantry and blocks enemy fire.\nCan be crushed by tanks.
+ BuildPaletteOrder: 100
+ Hotkey: b
+ Building:
+ HP: 100
+ Armor: none
+ Wall:
+ CrushableBy: Wheel, Track
+
+FENC:
+ Category: Defense
+ Inherits: ^Wall
+ Buildable:
+ TechLevel: 2
+ Prerequisites: fact
+ Owner: soviet
+ Cost: 25
+ Description: Wire Fence
+ LongDesc: Stops infantry and blocks enemy fire.\nCan be crushed by tanks.
+ BuildPaletteOrder: 100
+ Hotkey: n
+ Building:
+ HP: 100
+ Armor: none
+ Wall:
+ CrushableBy: Track
+
+BRIK:
+ Category: Defense
+ Inherits: ^Wall
+ Buildable:
+ TechLevel: 8
+ Prerequisites: fact
+ Owner: allies,soviet
+ Cost: 100
+ Description: Concrete Wall
+ LongDesc: Stop units and blocks enemy fire.
+ BuildPaletteOrder: 100
+ Hotkey: w
+ Building:
+ HP: 100
+ Armor: none
+ DamagedSound: crmble2.aud
+ DestroyedSound: kaboom30.aud
+ RenderBuildingWall:
+ DamageStates: 4
+
+CYCL:
+ Inherits: ^Wall
+ Building:
+ HP: 100
+ Armor: none
+ RenderBuildingWall:
+ DamageStates: 3
+ Wall:
+ CrushableBy: Track
+
+BARB:
+ Inherits: ^Wall
+ Building:
+ HP: 100
+ Armor: none
+ Wall:
+ CrushableBy: Track
+
+WOOD:
+ Inherits: ^Wall
+ Building:
+ HP: 100
+ Armor: none
+ Wall:
+ CrushableBy: Track