Merge branch 'master' of git://github.com/chrisforbes/OpenRA

This commit is contained in:
Caleb Anderson
2010-01-03 00:17:41 -06:00
36 changed files with 756 additions and 245 deletions

View File

@@ -9,9 +9,9 @@ namespace OpenRa.FileFormats
static List<IFolder> mountedFolders = new List<IFolder>();
static List<IFolder> temporaryMounts = new List<IFolder>();
public static void MountDefault( bool useAftermath )
public static void MountDefaultPackages()
{
FileSystem.Mount( new Folder( "./" ) );
FileSystem.Mount(new Folder("./"));
if( File.Exists( "main.mix" ) )
FileSystem.Mount( new Package( "main.mix" ) );
FileSystem.Mount( new Package( "redalert.mix" ) );
@@ -23,11 +23,12 @@ namespace OpenRa.FileFormats
FileSystem.Mount( new Package( "speech.mix" ) );
FileSystem.Mount( new Package( "allies.mix" ) );
FileSystem.Mount( new Package( "russian.mix" ) );
if( useAftermath )
{
FileSystem.Mount( new Package( "expand2.mix" ) );
FileSystem.Mount( new Package( "hires1.mix" ) );
}
}
public static void MountAftermathPackages()
{
FileSystem.Mount( new Package( "expand2.mix" ) );
FileSystem.Mount( new Package( "hires1.mix" ) );
}
public static void Mount(IFolder folder)
@@ -73,5 +74,20 @@ namespace OpenRa.FileFormats
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
}
public static bool Exists(string filename)
{
foreach (var folder in mountedFolders)
{
var s = folder.GetContent(filename);
if (s != null)
{
s.Dispose();
return true;
}
}
return false;
}
}
}

View File

@@ -71,6 +71,9 @@ namespace OpenRa.Game
{
get
{
if (Info != null && Info.SelectionSize != null)
return new float2(Info.SelectionSize[0], Info.SelectionSize[1]);
var firstSprite = Render().FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size;
@@ -107,6 +110,8 @@ namespace OpenRa.Game
{
var size = SelectedSize;
var loc = CenterLocation - 0.5f * size;
if (Info != null && Info.SelectionSize != null && Info.SelectionSize.Length > 2)
loc += new float2(Info.SelectionSize[2], Info.SelectionSize[3]);
if (useAltitude)
{

View File

@@ -7,17 +7,26 @@ using OpenRa.Game.GameRules;
using OpenRa.Game.Graphics;
using OpenRa.Game.Orders;
using OpenRa.Game.Support;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
class Chrome : IHandleInput
{
readonly Renderer renderer;
readonly LineRenderer lineRenderer;
readonly Sheet specialBin;
readonly SpriteRenderer chromeRenderer;
readonly Sprite specialBinSprite;
readonly Sprite moneyBinSprite;
readonly Sprite tooltipSprite;
readonly Sprite powerIndicatorSprite;
readonly Sprite powerLevelTopSprite;
readonly Sprite powerLevelBottomSprite;
readonly Animation repairButton;
readonly Animation sellButton;
readonly SpriteRenderer buildPaletteRenderer;
readonly Animation cantBuild;
readonly Animation ready;
@@ -37,17 +46,36 @@ namespace OpenRa.Game
// Positioning of chrome elements
// Build palette
paletteColumns = 4;
paletteOrigin = new int2(Game.viewport.Width - paletteColumns * 64 - 9, 240 - 9);
paletteOrigin = new int2(Game.viewport.Width - paletteColumns * 64 - 9 - 20, 240 - 9);
this.renderer = r;
specialBin = new Sheet(renderer, "specialbin.png");
chromeRenderer = new SpriteRenderer(renderer, true, renderer.RgbaSpriteShader);
lineRenderer = new LineRenderer(renderer);
buildPaletteRenderer = new SpriteRenderer(renderer, true);
specialBinSprite = new Sprite(specialBin, new Rectangle(0, 0, 32, 192), TextureChannel.Alpha);
moneyBinSprite = new Sprite(specialBin, new Rectangle(512 - 320, 0, 320, 32), TextureChannel.Alpha);
tooltipSprite = new Sprite(specialBin, new Rectangle(0, 288, 272, 136), TextureChannel.Alpha);
var powerIndicator = new Animation("power");
powerIndicator.PlayRepeating("power-level-indicator");
powerIndicatorSprite = powerIndicator.Image;
var powerTop = new Animation("powerbar");
powerTop.PlayRepeating("powerbar-top");
powerLevelTopSprite = powerTop.Image;
var powerBottom = new Animation("powerbar");
powerBottom.PlayRepeating("powerbar-bottom");
powerLevelBottomSprite = powerBottom.Image;
repairButton = new Animation("repair");
repairButton.PlayRepeating("normal");
sellButton = new Animation("sell");
sellButton.PlayRepeating("normal");
blank = SheetBuilder.Add(new Size(64, 48), 16);
sprites = groups
@@ -59,7 +87,7 @@ namespace OpenRa.Game
tabSprites = groups.Select(
(g, i) => Pair.New(g,
Util.MakeArray(3,
OpenRa.Game.Graphics.Util.MakeArray(3,
n => new Sprite(specialBin,
new Rectangle(512 - (n + 1) * 27, 64 + i * 40, 27, 40),
TextureChannel.Alpha))))
@@ -68,7 +96,7 @@ namespace OpenRa.Game
cantBuild = new Animation("clock");
cantBuild.PlayFetchIndex("idle", () => 0);
digitSprites = Util.MakeArray(10, a => a)
digitSprites = OpenRa.Game.Graphics.Util.MakeArray(10, a => a)
.Select(n => new Sprite(specialBin, new Rectangle(32 + 13 * n, 0, 13, 17), TextureChannel.Alpha)).ToList();
shimSprites = new[]
@@ -106,14 +134,17 @@ namespace OpenRa.Game
chromeRenderer.DrawSprite(moneyBinSprite, new float2(Game.viewport.Width - 320, 0), PaletteType.Chrome);
DrawMoney();
DrawPower();
chromeRenderer.Flush();
DrawButtons();
int paletteHeight = DrawBuildPalette(currentTab);
DrawBuildTabs(paletteHeight);
DrawChat();
}
void AddButton(Rectangle r, Action<bool> b) { buttons.Add(Pair.New(r, b)); }
void DrawBuildTabs(int paletteHeight)
{
const int tabWidth = 24;
@@ -184,7 +215,64 @@ namespace OpenRa.Game
x -= 14;
}
}
void DrawPower()
{
//draw background
float2 powerOrigin = Game.viewport.Location+new float2(Game.viewport.Width - 20, 240 - 9);
buildPaletteRenderer.DrawSprite(powerLevelTopSprite, powerOrigin, PaletteType.Chrome);
buildPaletteRenderer.DrawSprite(powerLevelBottomSprite, powerOrigin + new float2(0, powerLevelTopSprite.size.Y), PaletteType.Chrome);
buildPaletteRenderer.Flush();
float2 top = powerOrigin + new float2(0, 15);
float2 bottom = powerOrigin + new float2(0, powerLevelTopSprite.size.Y + powerLevelBottomSprite.size.Y) - new float2(0, 50);
var scale = 100;
while(Game.LocalPlayer.PowerProvided >= scale) scale += 100;
//draw bar
float2 powerTop = new float2(bottom.X, bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale));
for(int i = 7; i < 11; i++)
lineRenderer.DrawLine(bottom + new float2(i, 0), powerTop + new float2(i, 0), Color.LimeGreen, Color.LimeGreen);
lineRenderer.Flush();
//draw indicator
float2 drainedPosition = new float2(bottom.X , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale));
buildPaletteRenderer.DrawSprite(powerIndicatorSprite, drainedPosition, PaletteType.Chrome);
buildPaletteRenderer.Flush();
}
void DrawButtons()
{
// Repair
Rectangle repairRect = new Rectangle(Game.viewport.Width - 100, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height);
var repairDrawPos = Game.viewport.Location + new float2(repairRect.Location);
var hasFact = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains<ConstructionYard>());
if (Game.Settings.RepairRequiresConyard && !hasFact)
repairButton.ReplaceAnim("disabled");
else
{
repairButton.ReplaceAnim(Game.controller.orderGenerator is RepairOrderGenerator ? "pressed" : "normal");
AddButton(repairRect, isLmb => Game.controller.ToggleInputMode<RepairOrderGenerator>());
}
buildPaletteRenderer.DrawSprite(repairButton.Image, repairDrawPos, PaletteType.Chrome);
// Sell
Rectangle sellRect = new Rectangle(Game.viewport.Width - 60, 5,
sellButton.Image.bounds.Width, sellButton.Image.bounds.Height);
var sellDrawPos = Game.viewport.Location + new float2(sellRect.Location);
sellButton.ReplaceAnim(Game.controller.orderGenerator is SellOrderGenerator ? "pressed" : "normal");
AddButton(sellRect, isLmb => Game.controller.ToggleInputMode<SellOrderGenerator>());
buildPaletteRenderer.DrawSprite(sellButton.Image, sellDrawPos, PaletteType.Chrome);
buildPaletteRenderer.Flush();
}
void DrawChat()
{
var chatpos = new int2(400, Game.viewport.Height - 20);
@@ -300,8 +388,7 @@ namespace OpenRa.Game
overlayBits.Add(Pair.New(cantBuild.Image, drawPos));
var closureItem = item;
buttons.Add(Pair.New(rect,
(Action<bool>)(isLmb => HandleBuildPalette(closureItem, isLmb))));
AddButton(rect, isLmb => HandleBuildPalette(closureItem, isLmb));
if (++x == columns) { x = 0; y++; }
}
@@ -310,7 +397,7 @@ namespace OpenRa.Game
var rect = new Rectangle(origin.X + x * 64, origin.Y + 48 * y, 64, 48);
var drawPos = Game.viewport.Location + new float2(rect.Location);
buildPaletteRenderer.DrawSprite(blank, drawPos, PaletteType.Chrome);
buttons.Add(Pair.New(rect, (Action<bool>)(_ => { })));
AddButton(rect, _ => { });
if (++x == columns) { x = 0; y++; }
}

View File

@@ -27,6 +27,14 @@ namespace OpenRa.Game
orderGenerator = new UnitOrderGenerator(new Actor[] { });
}
public void ToggleInputMode<T>() where T : IOrderGenerator, new()
{
if (orderGenerator is T)
CancelInputMode();
else
orderGenerator = new T();
}
List<Order> recentOrders = new List<Order>();
void ApplyOrders(float2 xy, MouseInput mi)
@@ -133,60 +141,14 @@ namespace OpenRa.Game
public Cursor ChooseCursor()
{
var mods = GetModifierKeys();
var mi = new MouseInput {
Location = (Game.CellSize * dragEnd - Game.viewport.Location).ToInt2(),
Button = MouseButton.Right,
Modifiers = mods,
IsFake = true,
var mi = new MouseInput
{
Location = (Game.CellSize * MousePosition - Game.viewport.Location).ToInt2(),
Button = MouseButton.Right,
Modifiers = GetModifierKeys(),
};
var c = orderGenerator.Order(dragEnd.ToInt2(), mi)
.Where(o => o.Validate())
.Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
.FirstOrDefault(a => a != null);
return c ??
(Game.SelectActorsInBox(Game.CellSize * dragEnd, Game.CellSize * dragEnd).Any()
? Cursor.Select : Cursor.Default);
}
Cursor CursorForOrderString( string s, Actor a, int2 location )
{
var movement = a.traits.WithInterface<IMovement>().FirstOrDefault();
switch( s )
{
case "Attack": return Cursor.Attack;
case "Heal": return Cursor.Heal;
case "C4": return Cursor.C4;
case "Move":
if (movement.CanEnterCell(location))
return Cursor.Move;
else
return Cursor.MoveBlocked;
case "DeployMcv":
var factBuildingInfo = (BuildingInfo)Rules.UnitInfo[ "fact" ];
if( Game.CanPlaceBuilding( factBuildingInfo, a.Location - new int2( 1, 1 ), a, false ) )
return Cursor.Deploy;
else
return Cursor.DeployBlocked;
case "Deploy": return Cursor.Deploy;
case "Chronoshift":
if (movement.CanEnterCell(location))
return Cursor.Chronoshift;
else
return Cursor.MoveBlocked;
case "Enter": return Cursor.Enter;
case "Infiltrate": return Cursor.Enter;
case "Capture": return Cursor.Capture;
case "Harvest": return Cursor.Attack; // TODO: special harvest cursor?
case "PlaceBuilding": return Cursor.Default;
case "Sell": return Cursor.Sell;
case "NoSell": return Cursor.SellBlocked;
default:
return null;
}
return orderGenerator.GetCursor(MousePosition.ToInt2(), mi);
}
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
@@ -194,9 +156,11 @@ namespace OpenRa.Game
public void DoControlGroup(int group, Modifiers mods)
{
var uog = orderGenerator as UnitOrderGenerator;
if (uog == null) return;
if (mods.HasModifier(Modifiers.Ctrl))
{
if (uog == null || !uog.selection.Any())
if (!uog.selection.Any())
return;
controlGroups[group].Clear();
@@ -214,7 +178,6 @@ namespace OpenRa.Game
return;
}
if (uog == null) return;
CombineSelection(controlGroups[group], mods.HasModifier(Modifiers.Shift), false);
}

View File

@@ -22,11 +22,13 @@ namespace OpenRa.Game
public static Cursor Deploy { get { return new Cursor("deploy"); } }
public static Cursor Enter { get { return new Cursor("enter"); } }
public static Cursor DeployBlocked { get { return new Cursor("deploy-blocked"); } }
public static Cursor Chronoshift { get { return new Cursor("chrono"); } }
public static Cursor Chronoshift { get { return new Cursor("chrono"); } }
public static Cursor C4 { get { return new Cursor("c4"); } }
public static Cursor Capture { get { return new Cursor("capture"); } }
public static Cursor Heal { get { return new Cursor("heal"); } }
public static Cursor Sell { get { return new Cursor("sell"); } }
public static Cursor SellBlocked { get { return new Cursor("sell-blocked"); } }
public static Cursor Repair { get { return new Cursor("repair"); } }
public static Cursor RepairBlocked { get { return new Cursor("repair-blocked"); } }
}
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
class RepairIndicator : IEffect
{
int framesLeft = (int)(Rules.General.RepairRate * 25 * 60 / 2);
Actor a;
Animation anim = new Animation("select");
public RepairIndicator(Actor a) { this.a = a; anim.PlayRepeating("repair"); }
public void Tick()
{
if (--framesLeft == 0 || a.IsDead)
Game.world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image,
a.CenterLocation - .5f * anim.Image.size, PaletteType.Chrome);
}
}
}

View File

@@ -22,7 +22,8 @@ namespace OpenRa.Game
public static WorldRenderer worldRenderer;
public static Controller controller;
public static Chrome chrome;
public static UserSettings Settings;
public static OrderManager orderManager;
static int localPlayerIndex;
@@ -41,11 +42,6 @@ namespace OpenRa.Game
public static BuildingInfluenceMap BuildingInfluence;
public static UnitInfluenceMap UnitInfluence;
public static string Replay;
public static string NetworkHost;
public static int NetworkPort;
public static bool skipMakeAnims = true;
static Renderer renderer;
@@ -121,13 +117,13 @@ namespace OpenRa.Game
ChangeMap(mapName);
if (Replay != "")
orderManager = new OrderManager(new IOrderSource[] { new ReplayOrderSource(Replay) });
if (Settings.Replay != "")
orderManager = new OrderManager(new IOrderSource[] { new ReplayOrderSource(Settings.Replay) });
else
{
var orderSources = (string.IsNullOrEmpty(NetworkHost))
var orderSources = (string.IsNullOrEmpty(Settings.NetworkHost))
? new IOrderSource[] { new LocalOrderSource() }
: new IOrderSource[] { new LocalOrderSource(), new NetworkOrderSource(new TcpClient(NetworkHost, NetworkPort)) };
: new IOrderSource[] { new LocalOrderSource(), new NetworkOrderSource(new TcpClient(Settings.NetworkHost, Settings.NetworkPort)) };
orderManager = new OrderManager(orderSources, "replay.rep");
}
}
@@ -149,7 +145,6 @@ namespace OpenRa.Game
}
static int lastTime = Environment.TickCount;
public static int timestep = 40;
public static void ResetTimer()
{
@@ -166,11 +161,11 @@ namespace OpenRa.Game
{
int t = Environment.TickCount;
int dt = t - lastTime;
if (dt >= timestep)
if (dt >= Settings.Timestep)
{
using (new PerfSample("tick_time"))
{
lastTime += timestep;
lastTime += Settings.Timestep;
UpdatePalette(world.Actors.SelectMany(
a => a.traits.WithInterface<IPaletteModifier>()));
orderManager.TickImmediate();

View File

@@ -10,8 +10,8 @@ namespace OpenRa.Game.GameRules
{
foreach( var x in ini )
{
var field = self.GetType().GetField( x.Key );
field.SetValue( self, GetValue( field.FieldType, x.Value ) );
var field = self.GetType().GetField( x.Key.Trim() );
field.SetValue( self, GetValue( field.FieldType, x.Value.Trim() ) );
}
}

View File

@@ -19,7 +19,7 @@ namespace OpenRa.Game
public static InfoLoader<VoiceInfo> VoiceInfo;
public static InfoLoader<SupportPowerInfo> SupportPowerInfo;
public static GeneralInfo General;
public static AftermathInfo Aftermath;
public static AftermathInfo Aftermath;
public static TechTree TechTree;
public static Map Map;
public static TileSet TileSet;
@@ -48,7 +48,7 @@ namespace OpenRa.Game
General = new GeneralInfo();
FieldLoader.Load(General, AllRules.GetSection("General"));
Aftermath = new AftermathInfo();
Aftermath = new AftermathInfo();
if (useAftermath)
FieldLoader.Load(Aftermath, AllRules.GetSection("Aftermath"));

View File

@@ -54,6 +54,7 @@ namespace OpenRa.Game.GameRules
public readonly string LongDesc = null;
public readonly int OrePips = 0;
public readonly string Icon = null;
public readonly int[] SelectionSize = null;
public UnitInfo(string name) { Name = name; }
}

View File

@@ -0,0 +1,32 @@
namespace OpenRa.Game.GameRules
{
class UserSettings
{
// Debug settings
public readonly bool UnitDebug = false;
public readonly bool BuildingDebug = false;
public readonly bool PathDebug = false;
// Window settings
public readonly int Width = 0;
public readonly int Height = 0;
public readonly bool Fullscreen = false;
// Internal game settings
public readonly int Timestep = 40;
public readonly int SheetSize = 512;
// External game settings
public readonly bool UseAftermath = false;
public readonly string NetworkHost = "";
public readonly int NetworkPort = 0;
public readonly string Map = "scm12ea.ini";
public readonly int Player = 1;
public readonly string Replay = "";
// Gameplay options
public readonly bool RepairRequiresConyard = false;
}
}

View File

@@ -82,7 +82,7 @@ namespace OpenRa.Game.Graphics
spriteRenderer.Flush();
DrawBandBox();
DrawBandBox();
if (Game.controller.orderGenerator != null)
Game.controller.orderGenerator.Render();

View File

@@ -6,6 +6,8 @@ using System.Windows.Forms;
using OpenRa.FileFormats;
using OpenRa.Game.Graphics;
using OpenRa.Game.Orders;
using OpenRa.Game.GameRules;
namespace OpenRa.Game
{
@@ -16,52 +18,72 @@ namespace OpenRa.Game
static Size GetResolution(Settings settings)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
if (Game.Settings.Width > 0 && Game.Settings.Height > 0)
{
desktopResolution.Width = Game.Settings.Width;
desktopResolution.Height = Game.Settings.Height;
}
return new Size(
settings.GetValue("width", desktopResolution.Width),
settings.GetValue("height", desktopResolution.Height));
desktopResolution.Width,
desktopResolution.Height);
}
[DllImport("user32")]
static extern int ShowCursor([MarshalAs(UnmanagedType.Bool)] bool visible);
public MainWindow(Settings settings)
{
FormBorderStyle = FormBorderStyle.None;
BackColor = Color.Black;
StartPosition = FormStartPosition.Manual;
Location = Point.Empty;
Visible = true;
UiOverlay.ShowUnitDebug = settings.GetValue("udebug", false);
UiOverlay.ShowBuildDebug = settings.GetValue("bdebug", false);
WorldRenderer.ShowUnitPaths = settings.GetValue("pathdebug", false);
Game.timestep = settings.GetValue("rate", 40);
Game.Replay = settings.GetValue("replay", "");
Game.NetworkHost = settings.GetValue("host", "");
Game.NetworkPort = int.Parse(settings.GetValue("port", "0"));
var useAftermath = bool.Parse(settings.GetValue("aftermath", "false"));
Renderer.SheetSize = int.Parse(settings.GetValue("sheetsize", "512"));
// Load user settings
Game.Settings = new UserSettings();
while (!File.Exists("redalert.mix"))
{
var current = Directory.GetCurrentDirectory();
if (Directory.GetDirectoryRoot(current) == current)
throw new InvalidOperationException("Unable to load MIX files.");
Directory.SetCurrentDirectory("..");
try
{
// settings.ini should be located with the mix files
FileSystem.MountTemporary(new Folder("./"));
IniFile SettingsRules = new IniFile(FileSystem.Open("settings.ini"));
FieldLoader.Load(Game.Settings, SettingsRules.GetSection("Settings"));
FileSystem.UnmountTemporaryPackages();
}
catch (FileNotFoundException) { }
}
FileSystem.MountDefault(useAftermath);
UiOverlay.ShowUnitDebug = Game.Settings.UnitDebug;
UiOverlay.ShowBuildDebug = Game.Settings.BuildingDebug;
WorldRenderer.ShowUnitPaths = Game.Settings.PathDebug;
Renderer.SheetSize = Game.Settings.SheetSize;
bool windowed = !settings.GetValue("fullscreen", false);
FileSystem.MountDefaultPackages();
if (Game.Settings.UseAftermath)
{
FileSystem.MountAftermathPackages();
}
bool windowed = !Game.Settings.Fullscreen;
renderer = new Renderer(this, GetResolution(settings), windowed);
var controller = new Controller(() => (Modifiers)(int)ModifierKeys); /* a bit of insane input routing */
Game.Initialize(settings.GetValue("map", "scm12ea.ini"), renderer, new int2(ClientSize),
settings.GetValue("player", 1), useAftermath, controller);
Game.Initialize(Game.Settings.Map, renderer, new int2(ClientSize),
Game.Settings.Player, Game.Settings.UseAftermath, controller);
ShowCursor(false);
Game.ResetTimer();
@@ -135,6 +157,8 @@ namespace OpenRa.Game
Game.LocalPlayer = Game.players[(Game.LocalPlayer.Index + 1) % 4];
if (e.KeyCode == Keys.F3)
Game.controller.orderGenerator = new SellOrderGenerator();
if (e.KeyCode == Keys.F4)
Game.controller.orderGenerator = new RepairOrderGenerator();
if (!Game.chat.isChatting)
if (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)
@@ -176,7 +200,6 @@ namespace OpenRa.Game
public int2 Location;
public MouseButton Button;
public Modifiers Modifiers;
public bool IsFake;
}
enum MouseInputEvent { Down, Move, Up };

View File

@@ -83,6 +83,7 @@
<Compile Include="Effects\Corpse.cs" />
<Compile Include="Effects\DelayedAction.cs" />
<Compile Include="Effects\MoveFlash.cs" />
<Compile Include="Effects\RepairIndicator.cs" />
<Compile Include="Effects\Smoke.cs" />
<Compile Include="Effects\TeslaZap.cs" />
<Compile Include="Exts.cs" />
@@ -91,6 +92,7 @@
<Compile Include="GameRules\GeneralInfo.cs" />
<Compile Include="GameRules\SupportPowerInfo.cs" />
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="GameRules\UserSettings.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
<Compile Include="Effects\IEffect.cs" />
<Compile Include="Orders\IOrderSource.cs" />
@@ -99,7 +101,9 @@
<Compile Include="Orders\NetworkOrderSource.cs" />
<Compile Include="Orders\OrderIO.cs" />
<Compile Include="Orders\OrderManager.cs" />
<Compile Include="Orders\RepairOrderGenerator.cs" />
<Compile Include="Orders\SellOrderGenerator.cs" />
<Compile Include="Orders\TeleportOrderGenerator.cs" />
<Compile Include="Ore.cs" />
<Compile Include="PathSearch.cs" />
<Compile Include="ProductionItem.cs" />
@@ -178,6 +182,7 @@
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Follow.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\Activities\UndeployMcv.cs" />
<Compile Include="Traits\APMine.cs" />
<Compile Include="Traits\ATMine.cs" />
<Compile Include="Traits\AttackBase.cs" />
@@ -198,6 +203,7 @@
<Compile Include="Traits\Harvester.cs" />
<Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\InvisibleToOthers.cs" />
<Compile Include="Traits\ConstructionYard.cs" />
<Compile Include="Traits\MineImmune.cs" />
<Compile Include="Traits\Minelayer.cs" />
<Compile Include="Traits\LimitedAmmo.cs" />

View File

@@ -7,5 +7,6 @@ namespace OpenRa.Game
IEnumerable<Order> Order( int2 xy, MouseInput mi );
void Tick();
void Render();
Cursor GetCursor(int2 xy, MouseInput mi);
}
}

View File

@@ -16,13 +16,14 @@ namespace OpenRa.Game.Orders
public IEnumerable<Order> Order(int2 xy, MouseInput mi)
{
if (mi.IsFake)
{
// this order is never actually issued, but it's used for choosing a cursor
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, null, xy, Building.Name);
yield break;
}
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return InnerOrder(xy, mi);
}
IEnumerable<Order> InnerOrder(int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
if (!Game.CanPlaceBuilding(Building, xy, null, true)
@@ -34,8 +35,6 @@ namespace OpenRa.Game.Orders
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, null, xy, Building.Name);
}
else
Game.controller.CancelInputMode();
}
public void Tick()
@@ -49,5 +48,10 @@ namespace OpenRa.Game.Orders
{
Game.worldRenderer.uiOverlay.DrawBuildingGrid( Building );
}
public Cursor GetCursor(int2 xy, MouseInput mi)
{
return Cursor.Default;
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.GameRules;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Orders
{
class RepairOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order(int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return OrderInner(xy, mi);
}
IEnumerable<Order> OrderInner(int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
var loc = mi.Location + Game.viewport.Location;
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
if (building != null && building.Repairable && underCursor.Health < building.Strength)
yield return new Order("Repair", underCursor, null, int2.Zero, null);
}
}
public void Tick()
{
if (!Game.Settings.RepairRequiresConyard)
return;
var hasFact = Game.world.Actors
.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains<ConstructionYard>());
if (!hasFact)
Game.controller.CancelInputMode();
}
public void Render() {}
public Cursor GetCursor(int2 xy, MouseInput mi)
{
mi.Button = MouseButton.Left;
return OrderInner(xy, mi).Any()
? Cursor.Repair : Cursor.RepairBlocked;
}
}
}

View File

@@ -11,30 +11,37 @@ namespace OpenRa.Game.Orders
{
public IEnumerable<Order> Order(int2 xy, MouseInput mi)
{
if (!mi.IsFake && mi.Button == MouseButton.Right)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
yield break;
}
var loc = mi.Location + Game.viewport.Location;
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
return OrderInner(xy, mi);
}
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
if (building == null || building.Unsellable)
IEnumerable<Order> OrderInner(int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
yield return new Order("NoSell", Game.LocalPlayer.PlayerActor, null, int2.Zero, null);
yield break;
}
var loc = mi.Location + Game.viewport.Location;
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
yield return new Order("Sell", underCursor, null, int2.Zero, null);
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
if (building != null && !building.Unsellable)
yield return new Order("Sell", underCursor, null, int2.Zero, null);
}
}
public void Tick() {}
public void Render() {}
public Cursor GetCursor(int2 xy, MouseInput mi)
{
mi.Button = MouseButton.Left;
return OrderInner(xy, mi).Any()
? Cursor.Sell : Cursor.SellBlocked;
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace OpenRa.Game.Orders
{
class TeleportOrderGenerator : IOrderGenerator
{
public readonly Actor self;
public TeleportOrderGenerator(Actor self)
{
this.self = self;
}
public IEnumerable<Order> Order(int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
Game.controller.CancelInputMode();
yield break;
}
yield return new Order("Chronoshift", self, null, xy, null);
}
public void Tick() {}
public void Render()
{
Game.worldRenderer.DrawSelectionBox(self, Color.White, true);
}
public Cursor GetCursor(int2 xy, MouseInput mi)
{
return Cursor.Chronoshift;
}
}
}

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRa.Game.Traits;
using OpenRa.Game.GameRules;
namespace OpenRa.Game.Orders
{
@@ -33,5 +35,59 @@ namespace OpenRa.Game.Orders
foreach( var a in selection )
Game.worldRenderer.DrawSelectionBox( a, Color.White, true );
}
public Cursor GetCursor(int2 xy, MouseInput mi)
{
return ChooseCursor(mi);
}
Cursor ChooseCursor( MouseInput mi )
{
var p = Game.controller.MousePosition;
var c = Order(p.ToInt2(), mi)
.Where(o => o.Validate())
.Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
.FirstOrDefault(a => a != null);
return c ??
(Game.SelectActorsInBox(Game.CellSize * p,
Game.CellSize * p).Any()
? Cursor.Select : Cursor.Default);
}
Cursor CursorForOrderString(string s, Actor a, int2 location)
{
var movement = a.traits.WithInterface<IMovement>().FirstOrDefault();
switch (s)
{
case "Attack": return Cursor.Attack;
case "Heal": return Cursor.Heal;
case "C4": return Cursor.C4;
case "Move":
if (movement.CanEnterCell(location))
return Cursor.Move;
else
return Cursor.MoveBlocked;
case "DeployMcv":
var factBuildingInfo = (BuildingInfo)Rules.UnitInfo["fact"];
if (Game.CanPlaceBuilding(factBuildingInfo, a.Location - new int2(1, 1), a, false))
return Cursor.Deploy;
else
return Cursor.DeployBlocked;
case "Deploy": return Cursor.Deploy;
case "Chronoshift":
if (movement.CanEnterCell(location))
return Cursor.Chronoshift;
else
return Cursor.MoveBlocked;
case "Enter": return Cursor.Enter;
case "Deliver": return Cursor.Enter;
case "Infiltrate": return Cursor.Enter;
case "Capture": return Cursor.Capture;
case "Harvest": return Cursor.Attack; // TODO: special harvest cursor?
default:
return null;
}
}
}
}

View File

@@ -10,6 +10,7 @@ namespace OpenRa.Game.Traits.Activities
{
Game.world.AddFrameEndTask( _ =>
{
self.Health = 0;
Game.world.Remove( self );
if (self.Owner == Game.LocalPlayer)
{

View File

@@ -35,7 +35,7 @@ namespace OpenRa.Game.Traits.Activities
self.traits.Get<Helicopter>().reservation = res.Reserve(self);
var offset = (dest.Info as BuildingInfo).SpawnOffset;
var offsetVec = new float2(offset[0], offset[1]);
var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero;
return Util.SequenceActivities(
new HeliFly(dest.CenterLocation + offsetVec),

View File

@@ -9,17 +9,23 @@ namespace OpenRa.Game.Traits.Activities
{
public IActivity NextActivity { get; set; }
bool isCanceled;
int remainingTicks = ticksPerPoint;
const int ticksPerPoint = 15;
const int hpPerPoint = 8;
int remainingTicks;
public IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
if (--remainingTicks == 0)
if (remainingTicks == 0)
{
self.InflictDamage(self, -hpPerPoint, Rules.WarheadInfo["Super"]);
var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength;
var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.TakeCash(cost))
{
remainingTicks = 1;
return this;
}
self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]);
if (self.Health == self.Info.Strength)
return NextActivity;
@@ -27,10 +33,12 @@ namespace OpenRa.Game.Traits.Activities
.FirstOrDefault(a => a.traits.Contains<RenderBuilding>());
if (hostBuilding != null)
hostBuilding.traits.Get<RenderBuilding>().PlayCustomAnim(hostBuilding, "active" );
hostBuilding.traits.Get<RenderBuilding>().PlayCustomAnim(hostBuilding, "active");
remainingTicks = ticksPerPoint;
remainingTicks = (int)(Rules.General.RepairRate * 60 * 25);
}
else
--remainingTicks;
return this;
}

View File

@@ -6,24 +6,24 @@ using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits.Activities
{
class Teleport : IActivity
{
public IActivity NextActivity { get; set; }
class Teleport : IActivity
{
public IActivity NextActivity { get; set; }
int2 destination;
int2 destination;
public Teleport(int2 destination)
{
this.destination = destination;
}
public Teleport(int2 destination)
{
this.destination = destination;
}
public IActivity Tick(Actor self)
{
var mobile = self.traits.Get<Mobile>();
public IActivity Tick(Actor self)
{
var mobile = self.traits.Get<Mobile>();
mobile.TeleportTo(self, destination);
return NextActivity;
}
return NextActivity;
}
public void Cancel(Actor self) { }
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace OpenRa.Game.Traits.Activities
{
class UndeployMcv : IActivity
{
public IActivity NextActivity { get; set; }
bool started;
void DoUndeploy(World w,Actor self)
{
self.Health = 0;
foreach (var ns in self.traits.WithInterface<INotifySold>())
ns.Sold(self);
w.Remove(self);
var mcv = new Actor(Rules.UnitInfo["MCV"], self.Location + new int2(1, 1), self.Owner);
mcv.traits.Get<Unit>().Facing = 96;
w.Add(mcv);
}
public IActivity Tick(Actor self)
{
if (!started)
{
var rb = self.traits.Get<RenderBuilding>();
rb.PlayCustomAnimBackwards(self, "make",
() => Game.world.AddFrameEndTask(w => DoUndeploy(w,self)));
Sound.Play("cashturn.aud");
started = true;
}
return this;
}
public void Cancel(Actor self)
{
// Cancel can't happen between this being moved to the head of the list, and it being Ticked.
throw new InvalidOperationException("UndeployMcvAction: Cancel() should never occur.");
}
}
}

View File

@@ -1,11 +1,17 @@
using OpenRa.Game.GameRules;
using OpenRa.Game.Traits.Activities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.Effects;
namespace OpenRa.Game.Traits
{
class Building : INotifyDamage, IOrder
class Building : INotifyDamage, IOrder, ITick
{
public readonly BuildingInfo unitInfo;
bool isRepairing = false;
public Building(Actor self)
{
@@ -32,6 +38,41 @@ namespace OpenRa.Game.Traits
self.CancelActivity();
self.QueueActivity(new Sell());
}
if (order.OrderString == "Repair")
{
isRepairing = !isRepairing;
}
}
int remainingTicks;
public void Tick(Actor self)
{
if (!isRepairing) return;
if (remainingTicks == 0)
{
var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength;
var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.TakeCash(cost))
{
remainingTicks = 1;
return;
}
Game.world.AddFrameEndTask(w => w.Add(new RepairIndicator(self)));
self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]);
if (self.Health == self.Info.Strength)
{
isRepairing = false;
return;
}
remainingTicks = (int)(Rules.General.RepairRate * 60 * 25);
}
else
--remainingTicks;
}
}
}

View File

@@ -1,58 +1,54 @@
using System.Collections.Generic;
using System.Linq;
using OpenRa.Game.Orders;
namespace OpenRa.Game.Traits
{
class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips
{
public ChronoshiftDeploy(Actor self) { }
bool chronoshiftActive = false; // Is the chronoshift engine active?
int remainingChargeTime = 0; // How long until we can chronoshift again?
int chargeTime = (int)(Rules.Aftermath.ChronoTankDuration * 60 * 25); // How long between shifts?
class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips
{
public ChronoshiftDeploy(Actor self) { }
int remainingChargeTime = 0; // How long until we can chronoshift again?
int chargeTime = (int)(Rules.Aftermath.ChronoTankDuration * 60 * 25); // How long between shifts?
public void Tick(Actor self)
{
if (remainingChargeTime > 0)
remainingChargeTime--;
}
public void Tick(Actor self)
{
if (remainingChargeTime > 0)
remainingChargeTime--;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Left) return null;
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if( mi.Button == MouseButton.Right && xy == self.Location && remainingChargeTime <= 0 )
return new Order( "Deploy", self, null, int2.Zero, null );
if (chronoshiftActive)
return new Order("Chronoshift", self, null, xy, null);
return null;
}
else if (xy == self.Location && remainingChargeTime <= 0)
return new Order("Deploy", self, null, int2.Zero, null);
return null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Deploy")
{
Game.controller.orderGenerator = new TeleportOrderGenerator(self);
return;
}
public void ResolveOrder(Actor self, Order order)
{
var movement = self.traits.WithInterface<IMovement>().FirstOrDefault();
if (order.OrderString == "Deploy" && remainingChargeTime <= 0)
{
chronoshiftActive = true;
self.CancelActivity();
}
if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation))
{
{
Game.controller.CancelInputMode();
self.CancelActivity();
self.QueueActivity(new Activities.Teleport(order.TargetLocation));
Sound.Play("chrotnk1.aud");
chronoshiftActive = false;
remainingChargeTime = chargeTime;
}
}
public float GetSpeedModifier()
{
return chronoshiftActive ? 0f : 1f;
}
self.QueueActivity(new Activities.Teleport(order.TargetLocation));
Sound.Play("chrotnk1.aud");
remainingChargeTime = chargeTime;
}
}
public float GetSpeedModifier()
{
// ARGH! You must not do this, it will desync!
return (Game.controller.orderGenerator is TeleportOrderGenerator) ? 0f : 1f;
}
// Display 5 pips indicating the current charge status
public IEnumerable<PipType> GetPips()
{
@@ -81,5 +77,5 @@ namespace OpenRa.Game.Traits
}
}
}
}
}
}

View File

@@ -12,16 +12,16 @@ namespace OpenRa.Game.Traits
public void Attacking(Actor self)
{
if (remainingUncloakTime <= 0)
if (remainingUncloakTime <= 0)
OnCloak();
remainingUncloakTime = (int)(Rules.General.SubmergeDelay * 60 * 25);
remainingUncloakTime = (int)(Rules.General.SubmergeDelay * 60 * 25);
}
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingUncloakTime > 0)
if (remainingUncloakTime > 0)
return rs;
if (self.Owner == Game.LocalPlayer)
@@ -32,8 +32,8 @@ namespace OpenRa.Game.Traits
public void Tick(Actor self)
{
if (remainingUncloakTime > 0)
if (--remainingUncloakTime <= 0)
if (remainingUncloakTime > 0)
if (--remainingUncloakTime <= 0)
OnUncloak();
}

View File

@@ -0,0 +1,69 @@
using OpenRa.Game.GameRules;
using OpenRa.Game.Traits.Activities;
namespace OpenRa.Game.Traits
{
class ConstructionYard : IOrder, IMovement
{
readonly Actor self;
public ConstructionYard(Actor self)
{
this.self = self;
}
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (!Rules.General.MCVUndeploy) return null;
if (mi.Button == MouseButton.Left) return null;
if (underCursor != null)
{
// force-move
if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null;
if (!Game.IsActorCrushableByActor(underCursor, self)) return null;
}
return new Order("Move", self, null, xy, null);
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Move")
{
self.CancelActivity();
self.QueueActivity(new UndeployMcv());
}
}
// HACK: This should make reference to an MCV actor, and use of its Mobile trait
public UnitMovementType GetMovementType()
{
return UnitMovementType.Wheel;
}
public bool CanEnterCell(int2 a)
{
if (!Game.BuildingInfluence.CanMoveHere(a)) return false;
var crushable = true;
foreach (Actor actor in Game.UnitInfluence.GetUnitsAt(a))
{
if (actor == self) continue;
if (!Game.IsActorCrushableByActor(actor, self))
{
crushable = false;
break;
}
}
if (!crushable) return false;
return Rules.Map.IsInMap(a.X, a.Y) &&
TerrainCosts.Cost(GetMovementType(),
Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity;
}
}
}

View File

@@ -34,7 +34,7 @@ namespace OpenRa.Game.Traits
if (underCursor != null
&& underCursor.Owner == self.Owner
&& underCursor.traits.Contains<AcceptsOre>() && !IsEmpty)
return new Order("Enter", self, underCursor, int2.Zero, null);
return new Order("Deliver", self, underCursor, int2.Zero, null);
if (underCursor == null && Rules.Map.ContainsResource(xy))
return new Order("Harvest", self, null, xy, null);
@@ -50,7 +50,7 @@ namespace OpenRa.Game.Traits
self.QueueActivity(new Move(order.TargetLocation, 0));
self.QueueActivity(new Harvest());
}
else if (order.OrderString == "Enter")
else if (order.OrderString == "Deliver")
{
self.CancelActivity();
self.QueueActivity(new DeliverOre(order.TargetActor));

View File

@@ -56,7 +56,7 @@ namespace OpenRa.Game.Traits
reservation = res.Reserve(self);
var offset = (order.TargetActor.Info as BuildingInfo).SpawnOffset;
var offsetVec = new float2(offset[0], offset[1]);
var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero;
self.CancelActivity();
self.QueueActivity(new HeliFly(order.TargetActor.CenterLocation + offsetVec));

View File

@@ -14,6 +14,10 @@ namespace OpenRa.Game.Traits
var limitedAmmo = self.traits.GetOrDefault<LimitedAmmo>();
if (limitedAmmo != null && !limitedAmmo.HasAmmo())
return null;
// Ensure that the cell is empty except for the minelayer
if (Game.UnitInfluence.GetUnitsAt( xy ).Any(a => a != self))
return null;
if (mi.Button == MouseButton.Right && underCursor == self)
return new Order("Deploy", self, null, int2.Zero, null);

View File

@@ -4,11 +4,11 @@ using OpenRa.Game.Graphics;
namespace OpenRa.Game.Traits
{
class Submarine : IRenderModifier, INotifyAttack, ITick, INotifyDamage
{
int remainingSurfaceTime = 2; /* setup for initial dive */
class Submarine : IRenderModifier, INotifyAttack, ITick, INotifyDamage
{
int remainingSurfaceTime = 2; /* setup for initial dive */
public Submarine(Actor self) { }
public Submarine(Actor self) { }
void DoSurface()
{
@@ -18,36 +18,36 @@ namespace OpenRa.Game.Traits
remainingSurfaceTime = (int)(Rules.General.SubmergeDelay * 60 * 25);
}
public void Attacking(Actor self) { DoSurface(); }
public void Attacking(Actor self) { DoSurface(); }
public void Damaged(Actor self, AttackInfo e) { DoSurface(); }
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingSurfaceTime > 0)
return rs;
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingSurfaceTime > 0)
return rs;
if (self.Owner == Game.LocalPlayer)
return rs.Select(a => a.WithPalette(PaletteType.Shadow));
else
return new Renderable[] { };
}
}
public void Tick(Actor self)
{
if (remainingSurfaceTime > 0)
if (--remainingSurfaceTime <= 0)
OnDive();
}
public void Tick(Actor self)
{
if (remainingSurfaceTime > 0)
if (--remainingSurfaceTime <= 0)
OnDive();
}
void OnSurface()
{
Sound.Play("subshow1.aud");
}
void OnSurface()
{
Sound.Play("subshow1.aud");
}
void OnDive()
{
Sound.Play("subshow1.aud"); /* is this the right sound?? */
}
void OnDive()
{
Sound.Play("subshow1.aud"); /* is this the right sound?? */
}
}
}

View File

@@ -70,16 +70,12 @@ namespace SequenceEditor
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
FileSystem.MountDefaultPackages();
try
{
FileSystem.MountDefault( true );
}
catch( FileNotFoundException fnf )
{
if( fnf.FileName != "expand2.mix" )
throw new InvalidOperationException( "Unable to load MIX files" );
FileSystem.MountAftermathPackages();
}
catch( FileNotFoundException ){}
FileSystem.MountTemporary(new Package("temperat.mix"));

View File

@@ -372,7 +372,7 @@
<sequence name="move-minimap" start="29" length="6" />
<sequence name="repair" start="35" length="24" />
<sequence name="deploy" start="59" length="9" x="12" y="12" />
<sequence name="sell" start="68" length="12" x="12" y="12"/>
<sequence name="sell" start="68" length="12" x="12" y="12" />
<sequence name="default-minimap" start="80" length="1" />
<sequence name="ability" start="82" length="8" />
<sequence name="nuke" start="90" length="7" x="12" y="12" />
@@ -388,7 +388,7 @@
<sequence name="guard-minimap" start="146" length="1" />
<sequence name="guard" start="147" length="1" x="12" y="12" />
<sequence name="sell-vehicle" start="148" length="12" />
<sequence name="heal" start="160" length="4" x="12" y="12"/>
<sequence name="heal" start="160" length="4" x="12" y="12" />
<sequence name="capture" start="164" length="3" />
<sequence name="capture-minimap" start="167" length="3" />
<sequence name="repair2" start="170" length="24" />
@@ -991,4 +991,24 @@
<unit name="minv">
<sequence name="idle" start="0" length="1" />
</unit>
<unit name="select">
<sequence name="repair" start="2" length="1" />
</unit>
<unit name="power">
<sequence name="power-level-indicator" start="0" length="1" />
</unit>
<unit name="powerbar">
<sequence name="powerbar-top" start="0" length="1" />
<sequence name="powerbar-bottom" start="1" length="1" />
</unit>
<unit name="repair">
<sequence name="normal" start="0" length="1" />
<sequence name="pressed" start="1" length="1" />
<sequence name="disabled" start="2" length="1" />
</unit>
<unit name="sell">
<sequence name="normal" start="0" length="1" />
<sequence name="pressed" start="1" length="1" />
<sequence name="disabled" start="2" length="1" />
</unit>
</sequences>

View File

@@ -92,13 +92,13 @@ LongDesc=Deploys into another Construction Yard.\n Unarmed
[MNLY.AP]
Description=Minelayer (Anti-Personnel)
Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable
Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo
Voice=VehicleVoice
LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed
Primary=MINP ;; temporary hack
[MNLY.AT]
Description=Minelayer (Anti-Tank)
Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable
Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo
Voice=VehicleVoice
LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed
Primary=MINV ;; temporary hack
@@ -373,7 +373,7 @@ SelectionPriority=3
LongDesc=Produces and repairs submarines and \ntransports
[FACT]
Description=Construction Yard
Traits=Building, RenderBuilding
Traits=Building, RenderBuilding, ConstructionYard
Dimensions=3,3
Footprint=xxx xxx xxx
Produces=Building,Defense
@@ -544,54 +544,64 @@ MEDI
Description=Attack Dog
BuiltAt=KENN
Voice=DogVoice
Traits=Unit, Mobile, RenderInfantry, Infantry, AutoTarget
Traits=Unit, Mobile, RenderInfantry ;; AttackBase, SquishByTank, AutoTarget, dog??
LongDesc=Anti-infantry unit. Not fooled by the \nSpy's disguise.\n Strong vs Infantry\n Weak vs Vehicles
SelectionSize=12,17,-1,-4
[E1]
Description=Rifle Infantry
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget
LongDesc=General-purpose infantry. Strong vs Infantry\n Weak vs Vehicles
SelectionSize=12,17,0,-9
[E2]
Description=Grenadier
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget
FireDelay=15
PrimaryOffset=0,0,0,-13
LongDesc=Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles
SelectionSize=12,17,0,-9
[E3]
Description=Rocket Soldier
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget
PrimaryOffset=0,0,0,-13
LongDesc=Anti-tank/Anti-aircraft infantry.\n Strong vs Tanks, Aircraft\n Weak vs Infantry
SelectionSize=12,17,0,-9
[E4]
Description=Flamethrower
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget
FireDelay=8
PrimaryOffset=0,0,0,-7
LongDesc=Advanced Anti-infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles
SelectionSize=12,17,0,-9
[E6]
Description=Engineer
Traits=Unit, Mobile, EngineerCapture, RenderInfantry, TakeCover, SquishByTank
Voice=EngineerVoice
LongDesc=Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything
SelectionSize=12,17,0,-9
[SPY]
Description=Spy
Voice=SpyVoice
Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank
LongDesc=Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised
SelectionSize=12,17,0,-9
[THF]
Description=Thief
Voice=ThiefVoice
Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank
LongDesc=Infiltrates enemy refineries & \nsilos, and steals money stored there.\n Unarmed
SelectionSize=12,17,0,-9
[E7]
Description=Tanya
Voice=TanyaVoice
Traits=Unit, Mobile, RenderInfantry, C4Demolition, AttackBase, TakeCover, SquishByTank, AutoTarget
LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4
SelectionSize=12,17,0,-9
[MEDI]
Description=Medic
Voice=MedicVoice
Traits=Unit, Mobile, RenderInfantry, AutoHeal, AttackBase, TakeCover, SquishByTank
LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything
SelectionSize=12,17,0,-9