Compare commits

...

91 Commits

Author SHA1 Message Date
Chris Forbes
c85dbfb53d fix dumb bug in replay viewer 2010-12-19 20:49:14 +13:00
Chris Forbes
d6c71c6618 fix crash in RA music dialog 2010-12-19 19:14:00 +13:00
Chris Forbes
7802931e54 SAM requires power to operate 2010-12-19 18:51:14 +13:00
Chris Forbes
14737cc1dc nerf 1tnk pretty hard; add more hp for 2tnk but increase price slightly 2010-12-19 18:48:51 +13:00
Matthew Bowra-Dean
d8d33811e4 Added minimize button to launcher. 2010-12-19 18:41:36 +13:00
Chris Forbes
c99f89c987 fix crash on server overfill, fix another problem preventing spec slots from autofilling 2010-12-19 18:40:10 +13:00
Chris Forbes
7c76b25a44 blah 2010-12-19 18:40:09 +13:00
Chris Forbes
4fdc8222e8 blah 2010-12-19 18:40:09 +13:00
Chris Forbes
07d2e54bcc fix another crash in replay browser 2010-12-19 17:48:53 +13:00
Chris Forbes
f3d0e4b8ed fix a crash in the replay browser 2010-12-19 17:48:53 +13:00
Chris Forbes
2fad6f3bf1 move replay viewer delegate into mod 2010-12-19 17:48:52 +13:00
Chris Forbes
9482955a83 blah, cleanup 2010-12-19 17:48:51 +13:00
Chris Forbes
9d75c8d820 fix breakage 2010-12-19 17:48:51 +13:00
Chris Forbes
e3925b752d add support for replay viewer to cnc 2010-12-19 17:48:50 +13:00
Chris Forbes
f990006587 hack around the local player being set in replays 2010-12-19 17:48:50 +13:00
Chris Forbes
0b7bee480c extract [final] lobbyinfo from replay order stream; show map name & preview in replay browser 2010-12-19 17:48:49 +13:00
Chris Forbes
05f4aeea9f show duration in the replay browser 2010-12-19 17:48:49 +13:00
Chris Forbes
5f37b9e7d2 fix crash in replay playback (no world) 2010-12-19 17:48:48 +13:00
Chris Forbes
734b464de3 wire up replay browser to actually start a game. doesnt work. 2010-12-19 17:48:48 +13:00
Chris Forbes
4206cf1b09 refactor game joining; add replay joining support 2010-12-19 17:48:47 +13:00
Chris Forbes
17e3ef131c actually populate the replay browser; fix listbox ContentHeight not being reset. 2010-12-19 17:48:47 +13:00
Chris Forbes
2c13ebc6e7 wire cancel button for replay viewer 2010-12-19 17:48:46 +13:00
Chris Forbes
4f3b16cab2 add non-functional replay browser 2010-12-19 17:48:46 +13:00
Chris Forbes
25ebdea758 hack in stop order support to various classes. not happy with this. 2010-12-19 17:48:18 +13:00
Paul Chote
8b82df8298 Remove broken powered-techtree hack. 2010-12-07 22:35:40 +13:00
Paul Chote
0298a9e3a9 Remove debug logging from ChronoshiftPower. 2010-12-07 22:27:16 +13:00
Paul Chote
f2f60fb1f7 Don't apply palette effects to shroud/fog. 2010-12-07 22:26:27 +13:00
Paul Chote
b07eb9b8a1 Fast charge devhack. 2010-12-07 22:21:52 +13:00
Paul Chote
f5bffc4da9 Restore sane timings. 2010-12-07 22:19:58 +13:00
Paul Chote
55d60bd466 Don't crash if two powers have the same icon. 2010-12-07 22:00:26 +13:00
Paul Chote
c2a945b7ed Fix Spy infiltration. 2010-12-07 22:00:26 +13:00
Paul Chote
48b7cdad44 InfiltrateForSupportPower / Sonar pulse. 2010-12-07 22:00:20 +13:00
Paul Chote
c7500084df Parabomb crates. Multiple can be collected and queued. Support uncharged powers (0 charge time) with appropriate tooltip. 2010-12-07 21:50:33 +13:00
Paul Chote
d1850e8b4b Fix a time format bug. Fix subsequent gps bug. 2010-12-07 21:49:33 +13:00
Paul Chote
c465a58976 Sonar Pulse power. It still doesn't do anything. 2010-12-07 21:49:26 +13:00
Paul Chote
6b05b2c2f0 Iron Curtain. 2010-12-07 21:45:04 +13:00
Paul Chote
cd10fb1db0 GPS Satellite. 2010-12-07 21:45:04 +13:00
Paul Chote
172e1eb295 Paratroopers, Spyplane. 2010-12-07 21:45:04 +13:00
Paul Chote
9e16eb513f Reimplemented chronoshift. (still has desync) 2010-12-07 21:45:04 +13:00
Paul Chote
24b322053c Fix ra shellmap; reimplement ra nuke. 2010-12-07 21:45:04 +13:00
Paul Chote
e52771c367 Reimplement Ion Cannon and cnc nuke. Disable ra shellmap nukes. 2010-12-07 21:45:04 +13:00
Paul Chote
76f792bfdf New special powers mechanism. Only cnc Airstrike has been reimplemented so far. Special power crates, and spy bonuses have also been disabled. 2010-12-07 21:45:03 +13:00
Paul Chote
c6fad7fe98 Render IPreRenderSelection independently of OG. 2010-12-07 21:45:03 +13:00
Paul Chote
915cb589b3 Fix some more special power exploits 2010-12-07 21:45:03 +13:00
Chris Forbes
664692cef9 #398 c4 vs friendly buildings goes through the motions, but does nothing 2010-12-06 20:46:44 +13:00
Chris Forbes
220579ff85 wire 's' (default binding) to issue 'Stop' order to each selected actor 2010-12-06 20:43:09 +13:00
Chris Forbes
1a8e964c04 clean up usings 2010-12-06 14:35:37 +13:00
Chris Forbes
3a309ec916 remap hotkeys 's' -> 'y' in prep for adding 'stop' order 2010-12-05 12:29:11 +13:00
Chris Forbes
d46c64fad5 blah 2010-12-05 12:24:11 +13:00
Chris Forbes
3f47715c36 harvesters show colors for each resource type 2010-12-05 12:10:52 +13:00
Chris Forbes
94715a1561 add AutoTargetIgnore to ^Wall in ra and cnc 2010-12-05 11:41:14 +13:00
Chris Forbes
a752c47b5a allow marking things with AutoTargetIgnore so AutoTarget won't go for them 2010-12-05 11:39:44 +13:00
Chris Forbes
4d0535daa9 fix exploit in sonar pulse power 2010-12-05 11:36:05 +13:00
Chris Forbes
a3e64d1733 add AutoTargetIgnore 2010-12-05 11:32:30 +13:00
Chris Forbes
2618a7dadc fix perf of floodfill in editor 2010-12-05 11:31:24 +13:00
Chris Forbes
5617465294 remove sync attribute from DisplayCash/DisplayOre 2010-12-04 11:14:40 +13:00
Chris Forbes
9c20fba4a0 fix spy crashing things when disguised as a unit with fewer idle anims 2010-12-04 11:02:53 +13:00
Chris Forbes
05718f9e8e #400 bogus pip color for e7 fixed 2010-12-04 10:36:01 +13:00
Chris Forbes
81dad0bd34 tidying 2010-12-04 10:35:34 +13:00
Chris Forbes
c177cf9f9a #401 bogus footprint for ATWR fixed 2010-12-03 20:49:43 +13:00
Chris Forbes
e1761d8969 cleanup some usings 2010-12-03 20:43:27 +13:00
Paul Chote
0ae464d1f7 New attack-move cursor for cnc. 2010-12-02 10:28:34 +13:00
Paul Chote
4913d82bce Autotarget sets target line 2010-12-01 21:14:10 +13:00
Paul Chote
4f6027e772 Add Autotarget to cnc helis. 2010-12-01 21:03:41 +13:00
Paul Chote
fa84cfb26e Rebalance Invulnerability and Chronoshift. 2010-12-01 18:43:12 +13:00
Paul Chote
971287e989 Fix shroud crash 2010-12-01 18:22:46 +13:00
Paul Chote
deed6c7267 Make LST unbuildable; it is completely broken. 2010-12-01 13:19:56 +13:00
Paul Chote
f58f460355 Fix copypasta bogosity that mono accepts as valid code. 2010-12-01 13:19:09 +13:00
Paul Chote
2c897d4454 Fix ra shellmap low power and broken GAP position 2010-11-30 23:16:40 +13:00
Paul Chote
b4101c03ee MSLO requires power and can be powered down. 2010-11-30 23:13:51 +13:00
Paul Chote
200e90a590 Right click cancel chronoshift targeting. 2010-11-30 23:02:45 +13:00
Paul Chote
be8f042e49 Fix autoattack target flashes 2010-11-30 22:53:11 +13:00
Paul Chote
4b1eb993e4 Swap map selector button order 2010-11-30 22:30:18 +13:00
Paul Chote
f6ce673345 Fix KOTH maps 2010-11-30 22:28:28 +13:00
Paul Chote
08eeec4d99 More lobby polish (mainly map chooser). 2010-11-30 21:20:57 +13:00
Matthew Bowra-Dean
564a4598b9 Added renderer selection to Windows launcher. 2010-11-30 19:08:34 +13:00
Matthew Bowra-Dean
7e25b6e58e Moved map description to bottom of labels. 2010-11-30 19:08:24 +13:00
Matthew Bowra-Dean
57f74606f0 Added author and description to map chooser, fixes #290. Added word wrap to the LabelWidget to support it. 2010-11-30 19:08:18 +13:00
Paul Chote
b44cb9ad57 Pulse the rally point circles when a new location is set. 2010-11-30 19:07:41 +13:00
Paul Chote
dfd5906d7f Refactor AutoHeal. 2010-11-30 14:20:15 +13:00
Paul Chote
2e7b5e8712 Fix moonwalking infantry 2010-11-30 14:17:39 +13:00
Paul Chote
eb8682fd0e Fix AutoHeal 2010-11-30 13:37:10 +13:00
Paul Chote
2d224a207c Fix idle animations / prone. 2010-11-30 12:51:25 +13:00
Paul Chote
5070a81db4 Move CancelableActivity into the Activities namespace. Remove the Idle activity. 2010-11-30 11:11:14 +13:00
Paul Chote
e97dd2ee47 make currentActivity private. 2010-11-29 13:47:50 +13:00
Paul Chote
da74c6ad23 Add some logging to see what is going on. 2010-11-29 13:43:00 +13:00
Paul Chote
c7f1d08748 Some thoughts towards improving our bogus idle handling. Untested. 2010-11-29 13:15:44 +13:00
Paul Chote
7850acc6fb Fix AttackLeap. 2010-11-29 11:52:27 +13:00
Matthew Bowra-Dean
ec5b9a1150 Select last mod at start of launcher. Don't run download action elevated. 2010-11-28 23:12:19 +13:00
Matthew Bowra-Dean
83f67a9d48 Revert Window installer to not having launcher as default. 2010-11-28 23:12:18 +13:00
Paul Chote
fb799ad436 Fix dropdown miscompile bug under mono 2.6.7. 2010-11-28 22:23:50 +13:00
130 changed files with 2302 additions and 1568 deletions

View File

@@ -143,6 +143,16 @@ namespace OpenRA.Editor
{
var queue = new Queue<int2>();
var replace = Map.MapTiles[pos.X, pos.Y];
var touched = new bool[Map.MapSize.X, Map.MapSize.Y];
Action<int, int> MaybeEnqueue = (x, y) =>
{
if (Map.IsInMap(x, y) && !touched[x, y])
{
queue.Enqueue(new int2(x, y));
touched[x, y] = true;
}
};
queue.Enqueue(pos);
while (queue.Count > 0)
@@ -157,10 +167,10 @@ namespace OpenRA.Editor
for (var x = a.X; x <= b.X; x++)
{
Map.MapTiles[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, image = (byte)0, index = (byte)0 };
if (Map.MapTiles[x, p.Y - 1].Equals(replace) && Map.IsInMap(x, p.Y - 1))
queue.Enqueue(new int2(x, p.Y - 1));
if (Map.MapTiles[x, p.Y + 1].Equals(replace) && Map.IsInMap(x, p.Y + 1))
queue.Enqueue(new int2(x, p.Y + 1));
if (Map.MapTiles[x, p.Y - 1].Equals(replace))
MaybeEnqueue(x, p.Y - 1);
if (Map.MapTiles[x, p.Y + 1].Equals(replace))
MaybeEnqueue(x, p.Y + 1);
}
}

View File

@@ -24,6 +24,7 @@ namespace OpenRA.FileFormats
[FieldLoader.Load] public bool Selectable;
[FieldLoader.Load] public string Title;
[FieldLoader.Load] public string Type = "Conquest";
[FieldLoader.Load] public string Description;
[FieldLoader.Load] public string Author;
[FieldLoader.Load] public int PlayerCount;

View File

@@ -31,7 +31,7 @@ namespace OpenRA
[Sync]
public Player Owner;
IActivity currentActivity;
private IActivity currentActivity;
public Group Group;
internal Actor(World world, string name, TypeDictionary initDict )
@@ -77,7 +77,7 @@ namespace OpenRA
public bool IsIdle
{
get { return currentActivity == null || currentActivity is Idle; }
get { return currentActivity == null; }
}
OpenRA.FileFormats.Lazy<float2> Size;
@@ -130,7 +130,6 @@ namespace OpenRA
currentActivity.Cancel( this );
}
// For pathdebug, et al
public IActivity GetCurrentActivity()
{
return currentActivity;

View File

@@ -52,29 +52,36 @@ namespace OpenRA
public static void JoinServer(string host, int port)
{
if (orderManager != null) orderManager.Dispose();
var replayFilename = ChooseReplayFilename();
string path = Path.Combine( Game.SupportDir, "Replays" );
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
orderManager = new OrderManager( host, port, new ReplayRecorderConnection( new NetworkConnection( host, port ), replayFile ) );
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged(orderManager);
}
JoinInner(new OrderManager(host, port,
new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile)));
}
static string ChooseReplayFilename()
{
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
}
static void JoinLocal()
static void JoinInner(OrderManager om)
{
if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager("<no server>", -1, new EchoConnection());
orderManager = om;
lastConnectionState = ConnectionState.PreConnecting;
ConnectionStateChanged( orderManager );
ConnectionStateChanged(orderManager);
}
public static void JoinReplay(string replayFile)
{
JoinInner(new OrderManager("<no server>", -1, new ReplayConnection(replayFile)));
}
static void JoinLocal()
{
JoinInner(new OrderManager("<no server>", -1, new EchoConnection()));
}
public static int RenderFrame = 0;
@@ -128,29 +135,33 @@ namespace OpenRA
Sound.Tick();
Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } );
var isNetTick = LocalTick % NetTickScale == 0;
if( !isNetTick || orderManager.IsReadyForNextFrame )
if (world != null)
{
++orderManager.LocalFrameNumber;
var isNetTick = LocalTick % NetTickScale == 0;
Log.Write( "debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local" );
if (!isNetTick || orderManager.IsReadyForNextFrame)
{
++orderManager.LocalFrameNumber;
if( isNetTick ) orderManager.Tick();
Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local");
Sync.CheckSyncUnchanged(world, () =>
{
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
});
world.Tick();
if (isNetTick) orderManager.Tick();
PerfHistory.Tick();
Sync.CheckSyncUnchanged(world, () =>
{
world.OrderGenerator.Tick(world);
world.Selection.Tick(world);
});
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.NetFrameNumber == 0)
orderManager.LastTickTime = Environment.TickCount;
}
else
if( orderManager.NetFrameNumber == 0 )
orderManager.LastTickTime = Environment.TickCount;
}
}

View File

@@ -56,13 +56,14 @@ namespace OpenRA.Graphics
PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) );
}
public void ReplaceAnim(string sequenceName)
public bool ReplaceAnim(string sequenceName)
{
if (!HasSequence(sequenceName))
return;
return false;
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
return true;
}
public void PlayThen( string sequenceName, Action after )
@@ -124,14 +125,15 @@ namespace OpenRA.Graphics
}
}
public void ChangeImage(string newImage)
public void ChangeImage(string newImage, string newAnimIfMissing)
{
newImage = newImage.ToLowerInvariant();
if (name != newImage)
{
name = newImage.ToLowerInvariant();
ReplaceAnim(CurrentSequence.Name);
if (!ReplaceAnim(CurrentSequence.Name))
ReplaceAnim(newAnimIfMissing);
}
}

View File

@@ -78,6 +78,13 @@ namespace OpenRA.Graphics
terrainRenderer.Draw(this, Game.viewport);
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(this, a);
Game.Renderer.Flush();
if (world.OrderGenerator != null)
world.OrderGenerator.RenderBeforeWorld(this, world);

View File

@@ -58,6 +58,10 @@ namespace OpenRA
this.ExtraLocation = extraLocation;
}
// For scripting special powers
public Order()
: this(null, null, null, int2.Zero, null, false, int2.Zero) { }
public Order(string orderString, Actor subject, bool queued)
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }

View File

@@ -13,7 +13,7 @@ using System.IO;
namespace OpenRA.Network
{
static class OrderIO
public static class OrderIO
{
public static void Write(this Stream s, byte[] buf)
{

View File

@@ -6,7 +6,7 @@ using System.IO;
namespace OpenRA.Network
{
class ReplayConnection : IConnection
public class ReplayConnection : IConnection
{
//uint nextFrame = 1;
FileStream replayStream;

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -118,7 +118,6 @@
<Compile Include="Graphics\CursorSheetBuilder.cs" />
<Compile Include="Graphics\LineRenderer.cs" />
<Compile Include="Graphics\WorldRenderer.cs" />
<Compile Include="Traits\Activities\Idle.cs" />
<Compile Include="Orders\IOrderGenerator.cs" />
<Compile Include="Player.cs" />
<Compile Include="Graphics\Sheet.cs" />
@@ -225,6 +224,9 @@
<ItemGroup>
<Content Include="OpenRA.ico" />
</ItemGroup>
<ItemGroup>
<Folder Include="Widgets\Delegates\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -65,20 +65,9 @@ namespace OpenRA.Orders
}
}
public virtual void Tick(World world) { }
public void RenderBeforeWorld(WorldRenderer wr, World world)
{
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld(wr, a);
Game.Renderer.Flush();
}
public void RenderAfterWorld(WorldRenderer wr, World world) {}
public virtual void Tick(World world) { }
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
public void RenderAfterWorld(WorldRenderer wr, World world) { }
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}

View File

@@ -74,11 +74,6 @@ namespace OpenRA.Orders
return;
}
foreach (var a in world.Selection.Actors)
if (!a.Destroyed)
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
t.RenderBeforeWorld( wr, a );
Game.Renderer.Flush();
}

View File

@@ -11,7 +11,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
@@ -171,18 +170,16 @@ namespace OpenRA.Server
public void UpdateInFlightFrames(Connection conn)
{
if (conn.Frame != 0)
{
if (!inFlightFrames.ContainsKey(conn.Frame))
inFlightFrames[conn.Frame] = new List<Connection> { conn };
else
inFlightFrames[conn.Frame].Add(conn);
if (conn.Frame == 0)
return;
if (conns.All(c => inFlightFrames[conn.Frame].Contains(c)))
{
inFlightFrames.Remove(conn.Frame);
}
}
if (!inFlightFrames.ContainsKey(conn.Frame))
inFlightFrames[conn.Frame] = new List<Connection> { conn };
else
inFlightFrames[conn.Frame].Add(conn);
if (conns.All(c => inFlightFrames[conn.Frame].Contains(c)))
inFlightFrames.Remove(conn.Frame);
}
void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data)
@@ -266,15 +263,18 @@ namespace OpenRA.Server
case "Chat":
case "TeamChat":
var fromClient = GetClient(conn);
var fromIndex = fromClient != null ? fromClient.Index : 0;
foreach (var c in conns.Except(conn).ToArray())
DispatchOrdersToClient(c, GetClient(conn).Index, 0, so.Serialize());
DispatchOrdersToClient(c, fromIndex, 0, so.Serialize());
break;
}
}
public Session.Client GetClient(Connection conn)
{
return lobbyInfo.Clients.First(c => c.Index == conn.PlayerIndex);
return lobbyInfo.ClientWithIndex(conn.PlayerIndex);
}
public void DropClient(Connection toDrop, Exception e)

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRA.Traits
namespace OpenRA.Traits.Activities
{
public abstract class CancelableActivity : IActivity
{

View File

@@ -1,17 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
namespace OpenRA.Traits.Activities
{
public class Idle : CancelableActivity
{
public override IActivity Tick(Actor self) { return NextActivity ?? this; }
}
}

View File

@@ -36,14 +36,13 @@ namespace OpenRA.Traits
[Sync]
public int Cash;
[Sync]
public int DisplayCash;
[Sync]
public int Ore;
[Sync]
public int OreCapacity;
[Sync]
public int DisplayCash;
public int DisplayOre;
public float GetSiloFullness() { return (float)Ore / OreCapacity; }

View File

@@ -24,6 +24,8 @@ namespace OpenRA.Traits
public Sprite[][] Sprites;
public int PaletteIndex;
public PipType PipColor = PipType.Yellow;
public object Create(ActorInitializer init) { return new ResourceType(this); }
}

View File

@@ -216,6 +216,11 @@ namespace OpenRA.Traits
if (Disabled)
return true;
// Visibility is allowed to extend beyond the map cordon so that
// the fog tiles are not visible at the edge of the world
if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y)
return false;
return visibleCells[x,y] != 0;
}

View File

@@ -117,12 +117,11 @@ namespace OpenRA.Widgets
public static void ShowDropPanel(Widget w, Widget panel, IEnumerable<Widget> dismissAfter, Func<bool> onDismiss)
{
var fullscreenMask = new ContainerWidget
{
Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height),
ClickThrough = false,
Visible = true
};
var fullscreenMask = new ContainerWidget();
// Don't use initializers - breaks on mono 2.6.7
fullscreenMask.Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
fullscreenMask.ClickThrough = false;
fullscreenMask.Visible = true;
Widget.RootWidget.AddChild(fullscreenMask);
Action HideDropDown = () =>

View File

@@ -11,6 +11,7 @@
using System;
using System.Drawing;
using OpenRA.Graphics;
using System.Collections.Generic;
namespace OpenRA.Widgets
{
@@ -24,6 +25,7 @@ namespace OpenRA.Widgets
public TextAlign Align = TextAlign.Left;
public TextVAlign VAlign = TextVAlign.Middle;
public bool Bold = false;
public bool WordWrap = false;
public Func<string> GetText;
public Func<string> GetBackground;
@@ -58,7 +60,7 @@ namespace OpenRA.Widgets
int2 textSize = font.Measure(text);
int2 position = RenderOrigin;
if (VAlign == TextVAlign.Middle)
position += new int2(0, (Bounds.Height - textSize.Y)/2);
@@ -69,7 +71,58 @@ namespace OpenRA.Widgets
position += new int2((Bounds.Width - textSize.X)/2, 0);
if (Align == TextAlign.Right)
position += new int2(Bounds.Width - textSize.X,0);
position += new int2(Bounds.Width - textSize.X,0);
if (WordWrap)
{
if (textSize.X > Bounds.Width)
{
string[] lines = text.Split('\n');
List<string> newLines = new List<string>();
int i = 0;
string line = lines[i++];
while (true)
{
newLines.Add(line);
int2 m = font.Measure(line);
int spaceIndex = 0, start = line.Length - 1;
if (m.X <= Bounds.Width)
{
if (i < lines.Length - 1)
{
line = lines[i++];
continue;
}
else
break;
}
while (m.X > Bounds.Width)
{
if (-1 == (spaceIndex = line.LastIndexOf(' ', start)))
break;
start = spaceIndex - 1;
m = font.Measure(line.Substring(0, spaceIndex));
}
if (spaceIndex != -1)
{
newLines.RemoveAt(newLines.Count - 1);
newLines.Add(line.Substring(0, spaceIndex));
line = line.Substring(spaceIndex + 1);
}
else if (i < lines.Length - 1)
{
line = lines[i++];
continue;
}
else
break;
}
text = string.Join("\n", newLines.ToArray());
}
}
font.DrawText(text, position, Color.White);
}

View File

@@ -346,11 +346,26 @@ namespace OpenRA.Widgets
}
public class ContainerWidget : Widget {
public ContainerWidget() : base() { }
public Func<string> GetBackground;
public string Background = null;
public ContainerWidget() : base()
{
GetBackground = () => Background;
}
public ContainerWidget(ContainerWidget other) : base(other)
{
Background = other.Background;
GetBackground = other.GetBackground;
}
public ContainerWidget(Widget other) : base(other) { }
public override void DrawInner( WorldRenderer wr ) { }
public override void DrawInner( WorldRenderer wr )
{
var bg = GetBackground();
if (bg != null)
WidgetUtils.DrawPanel(bg, RenderBounds );
}
public override string GetCursor(int2 pos) { return null; }
public override Widget Clone() { return new ContainerWidget(this); }

View File

@@ -132,7 +132,7 @@ namespace OpenRA.Widgets
public static string FormatTime(int ticks)
{
var seconds = ticks / 25;
var seconds = (int)Math.Ceiling(ticks / 25f);
var minutes = seconds / 60;
if (minutes >= 60)

View File

@@ -48,7 +48,8 @@ namespace OpenRA
public void SetLocalPlayer(int index)
{
localPlayerIndex = index;
if (!(orderManager.Connection is ReplayConnection))
localPlayerIndex = index;
}
public readonly Actor WorldActor;

View File

@@ -101,7 +101,7 @@ namespace OpenRA.Launcher
string[] args = e.Argument as string[];
string url = args[0];
string dest = args[1];
var p = UtilityProgram.CallWithAdmin("--download-url", url, dest);
var p = UtilityProgram.Call("--download-url", url, dest);
Regex r = new Regex(@"(\d{1,3})% (\d+)/(\d+) bytes");
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);

View File

@@ -58,6 +58,7 @@ namespace OpenRA.Launcher
Process p = new Process();
p.StartInfo.FileName = "OpenRA.Game.exe";
p.StartInfo.Arguments = "Game.Mods=" + string.Join(",", modList.ToArray());
p.StartInfo.Arguments += " Graphics.Renderer=" + Launcher.Renderer;
p.Start();
return true;
}

View File

@@ -29,13 +29,14 @@
private void InitializeComponent()
{
System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Mods", -2, -2);
System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Broken Mods");
this.installButton = new System.Windows.Forms.Button();
this.installModDialog = new System.Windows.Forms.OpenFileDialog();
this.treeView = new System.Windows.Forms.TreeView();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.webBrowser = new System.Windows.Forms.WebBrowser();
this.panel1 = new System.Windows.Forms.Panel();
this.cgButton = new System.Windows.Forms.RadioButton();
this.glButton = new System.Windows.Forms.RadioButton();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
@@ -67,11 +68,8 @@
treeNode1.Name = "ModsNode";
treeNode1.SelectedImageIndex = -2;
treeNode1.Text = "Mods";
treeNode2.Name = "BrokenModsNode";
treeNode2.Text = "Broken Mods";
this.treeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
treeNode1,
treeNode2});
treeNode1});
this.treeView.ShowLines = false;
this.treeView.Size = new System.Drawing.Size(160, 465);
this.treeView.TabIndex = 3;
@@ -107,6 +105,8 @@
//
// panel1
//
this.panel1.Controls.Add(this.cgButton);
this.panel1.Controls.Add(this.glButton);
this.panel1.Controls.Add(this.installButton);
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel1.Location = new System.Drawing.Point(0, 465);
@@ -114,6 +114,30 @@
this.panel1.Size = new System.Drawing.Size(671, 47);
this.panel1.TabIndex = 5;
//
// cgButton
//
this.cgButton.AutoSize = true;
this.cgButton.Location = new System.Drawing.Point(481, 18);
this.cgButton.Name = "cgButton";
this.cgButton.Size = new System.Drawing.Size(87, 17);
this.cgButton.TabIndex = 4;
this.cgButton.TabStop = true;
this.cgButton.Text = "CG Renderer";
this.cgButton.UseVisualStyleBackColor = true;
this.cgButton.CheckedChanged += new System.EventHandler(this.rendererChanged);
//
// glButton
//
this.glButton.AutoSize = true;
this.glButton.Location = new System.Drawing.Point(574, 18);
this.glButton.Name = "glButton";
this.glButton.Size = new System.Drawing.Size(86, 17);
this.glButton.TabIndex = 3;
this.glButton.TabStop = true;
this.glButton.Text = "GL Renderer";
this.glButton.UseVisualStyleBackColor = true;
this.glButton.CheckedChanged += new System.EventHandler(this.rendererChanged);
//
// Launcher
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -123,7 +147,6 @@
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Launcher";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "OpenRA Launcher";
@@ -131,6 +154,7 @@
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
@@ -143,5 +167,7 @@
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.WebBrowser webBrowser;
private System.Windows.Forms.RadioButton cgButton;
private System.Windows.Forms.RadioButton glButton;
}
}

View File

@@ -21,14 +21,15 @@ namespace OpenRA.Launcher
public partial class Launcher : Form
{
Dictionary<string, Mod> allMods;
public static string Renderer = "Gl";
static string SupportDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "OpenRA";
public Launcher()
{
InitializeComponent();
Util.UacShield(installButton);
//treeView.Nodes["ModsNode"].ImageIndex = 1;
//treeView.Nodes["ModsNode"].SelectedImageIndex = 1;
webBrowser.ObjectForScripting = new JSBridge();
webBrowser.DocumentCompleted += (o, e) =>
{
@@ -36,16 +37,17 @@ namespace OpenRA.Launcher
(b.ObjectForScripting as JSBridge).Document = b.Document;
};
RefreshMods();
string response = UtilityProgram.CallSimpleResponse("--settings-value", SupportDir, "Graphics.Renderer");
if (Util.IsError(ref response) || response.Equals("gl", StringComparison.InvariantCultureIgnoreCase))
glButton.Checked = true;
else
cgButton.Checked = true;
}
Mod GetMetadata(string mod)
{
string responseString;
using (var response = UtilityProgram.Call("-i", mod))
{
responseString = response.ReadToEnd();
}
string responseString = UtilityProgram.CallSimpleResponse("-i", mod);
if (Util.IsError(ref responseString)) return null;
string[] lines = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < lines.Length; i++)
@@ -89,11 +91,7 @@ namespace OpenRA.Launcher
void RefreshMods()
{
string responseString;
using (var response = UtilityProgram.Call("--list-mods"))
{
responseString = response.ReadToEnd();
}
string responseString = UtilityProgram.CallSimpleResponse("--list-mods");
string[] mods;
if (!Util.IsError(ref responseString))
@@ -167,12 +165,22 @@ namespace OpenRA.Launcher
missing.Nodes.Add(new TreeNode(allMods[s].Title)
{ ForeColor = SystemColors.GrayText, Name = s });
}
treeView.Nodes["BrokenModsNode"].Nodes.Add(unspecified);
treeView.Nodes["BrokenModsNode"].Nodes.Add(missing);
string brokenKey = "BrokenModsNode";
if (treeView.Nodes[brokenKey] != null)
treeView.Nodes.RemoveByKey(brokenKey);
treeView.Nodes.Add(brokenKey, "Broken Mods");
treeView.Nodes[brokenKey].Nodes.Add(unspecified);
treeView.Nodes[brokenKey].Nodes.Add(missing);
}
treeView.Nodes["ModsNode"].ExpandAll();
treeView.Invalidate();
string responseString = UtilityProgram.CallSimpleResponse("--settings-value", SupportDir, "Game.Mods");
if (Util.IsError(ref responseString))
treeView.SelectedNode = treeView.Nodes["ModsNode"].Nodes["ra"];
else
treeView.SelectedNode = treeView.Nodes["ModsNode"].Nodes[responseString];
}
void treeView_AfterSelect(object sender, TreeViewEventArgs e)
@@ -182,7 +190,14 @@ namespace OpenRA.Launcher
string modHtmlPath = string.Format("mods{0}{1}{0}mod.html", Path.DirectorySeparatorChar, e.Node.Name);
if (!File.Exists(modHtmlPath)) return;
webBrowser.Navigate(Path.GetFullPath(modHtmlPath));
}
private void rendererChanged(object sender, EventArgs e)
{
if (sender == glButton)
Renderer = "Gl";
else
Renderer = "Cg";
}
}
}

View File

@@ -66,7 +66,7 @@ namespace OpenRA.Launcher
return arguments.ToString();
}
public static StreamReader Call(string command, params string[] args)
public static Process Call(string command, params string[] args)
{
Process p = new Process();
p.StartInfo.FileName = "OpenRA.Utility.exe";
@@ -76,9 +76,21 @@ namespace OpenRA.Launcher
p.Start();
return p;
}
public static string CallSimpleResponse(string command, params string[] args)
{
var p = Call(command, args);
string responseString;
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
pipe.Connect();
return new StreamReader(pipe);
using (var response = new StreamReader(pipe))
{
responseString = response.ReadToEnd();
}
return responseString;
}
public static Process CallWithAdmin(string command, params string[] args)

View File

@@ -20,33 +20,16 @@ namespace OpenRA.Mods.Cnc
public override object Create(ActorInitializer init) { return new IonCannonPower(init.self, this); }
}
class IonCannonPower : SupportPower, IResolveOrder
class IonCannonPower : SupportPower
{
public IonCannonPower(Actor self, IonCannonPowerInfo info) : base(self, info) { }
public void ResolveOrder(Actor self, Order order)
public override void Activate(Actor self, Order order)
{
if (!IsReady) return;
if (order.OrderString == "IonCannon")
self.World.AddFrameEndTask(w =>
{
Owner.World.AddFrameEndTask(w =>
{
Sound.Play(Info.LaunchSound, Game.CellSize * order.TargetLocation.ToFloat2());
w.Add(new IonCannon(self, w, order.TargetLocation));
});
FinishActivate();
}
}
protected override void OnActivate()
{
Self.World.OrderGenerator =
new GenericSelectTargetWithBuilding<IonControl>(Owner.PlayerActor, "IonCannon", "ability");
Sound.Play(Info.LaunchSound, Game.CellSize * order.TargetLocation.ToFloat2());
w.Add(new IonCannon(self, w, order.TargetLocation));
});
}
}
class IonControlInfo : TraitInfo<IonControl> { }
class IonControl { }
}

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Mods.RA.Activities
/* non-turreted attack */
public class Attack : CancelableActivity
{
Target Target;
protected Target Target;
ITargetable targetable;
int Range;
bool AllowMovement;
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA.Activities
return ret;
}
IActivity InnerTick( Actor self, AttackBase attack )
protected virtual IActivity InnerTick( Actor self, AttackBase attack )
{
if (IsCanceled) return NextActivity;
var facing = self.Trait<IFacing>();

View File

@@ -10,6 +10,7 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -11,6 +11,7 @@
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{
@@ -24,7 +25,6 @@ namespace OpenRA.Mods.RA.Activities
{
if (IsCanceled) return NextActivity;
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (target.Owner == self.Owner) return NextActivity;
if( !target.Trait<IOccupySpace>().OccupiedCells().Any( x => x == self.Location ) )
return NextActivity;

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -0,0 +1,32 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
using OpenRA.Mods.RA.Move;
namespace OpenRA.Mods.RA.Activities
{
/* non-turreted attack */
public class Heal : Attack
{
public Heal(Target target, int range, bool allowMovement)
: base(target, range, allowMovement) {}
protected override IActivity InnerTick( Actor self, AttackBase attack )
{
if (Target.IsActor && Target.Actor.GetDamageState() == DamageState.Undamaged)
return NextActivity;
return base.InnerTick(self, attack);
}
}
}

View File

@@ -1,47 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{
public class IdleAnimation : Idle
{
string sequence;
int delay;
public IdleAnimation(string sequence, int delay)
{
this.sequence = sequence;
this.delay = delay;
}
bool active = true;
public override IActivity Tick(Actor self)
{
if (!active) return NextActivity;
if (delay > 0 && --delay == 0)
self.Trait<RenderInfantry>().anim.PlayThen(sequence, () => active = false);
return this;
}
protected override bool OnCancel( Actor self )
{
active = false;
return true;
}
}
}

View File

@@ -10,6 +10,7 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -10,8 +10,9 @@
using System.Linq;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Mods.RA.Move;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -11,6 +11,7 @@
using System.Linq;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -11,6 +11,7 @@
using System;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -10,6 +10,7 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -10,6 +10,7 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -12,6 +12,7 @@ using OpenRA.FileFormats;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -10,6 +10,7 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Activities
{

View File

@@ -10,6 +10,7 @@
using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -9,6 +9,7 @@
#endregion
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -109,6 +109,17 @@ namespace OpenRA.Mods.RA.Air
self.QueueActivity(Info.RearmBuildings.Contains(order.TargetActor.Info.Name)
? (IActivity)new Rearm() : new Repair(order.TargetActor));
}
if (order.OrderString == "Stop")
{
self.CancelActivity();
if (Info.LandWhenIdle)
{
self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(true));
}
}
}
int offsetTicks = 0;

View File

@@ -11,6 +11,7 @@
using System;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -112,6 +112,11 @@ namespace OpenRA.Mods.RA.Air
info.RearmBuildings.Contains(order.TargetActor.Info.Name)
? (IActivity)new Rearm() : new Repair(order.TargetActor));
}
else if (order.OrderString == "Stop")
{
UnReserve();
self.CancelActivity();
}
else
{
// Game.Debug("Unreserve due to unhandled order: {0}".F(order.OrderString));

View File

@@ -11,6 +11,7 @@
using System;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA.Air
{

View File

@@ -115,7 +115,7 @@ namespace OpenRA.Mods.RA
a();
}
public void DoAttack(Actor self, Target target)
public virtual void DoAttack(Actor self, Target target)
{
if( !CanAttack( self, target ) ) return;
@@ -149,14 +149,14 @@ namespace OpenRA.Mods.RA
return null;
}
public void ResolveOrder(Actor self, Order order)
public virtual void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Attack")
AttackTarget( Target.FromOrder( order ), order.Queued, true );
else if(order.OrderString == "AttackHold")
AttackTarget( Target.FromOrder( order ), order.Queued, false );
if (order.OrderString == "Attack" || order.OrderString == "AttackHold")
{
var target = Target.FromOrder(order);
self.SetTargetLine(target, Color.Red);
AttackTarget(target, order.Queued, order.OrderString == "Attack");
}
else
{
/* hack */
@@ -181,7 +181,6 @@ namespace OpenRA.Mods.RA
{
if( !target.IsValid ) return;
self.QueueActivity(queued, GetAttackActivity(self, target, allowMove));
self.SetTargetLine(target, Color.Red);
}
public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill)
@@ -217,6 +216,7 @@ namespace OpenRA.Mods.RA
return inRange
.Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy)
.Where(a => !a.HasTrait<AutoTargetIgnore>())
.Where(a => HasAnyValidWeapons(Target.FromActor(a)))
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
.FirstOrDefault();

View File

@@ -14,25 +14,22 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class AttackLeapInfo : AttackBaseInfo
class AttackLeapInfo : AttackFrontalInfo
{
public override object Create(ActorInitializer init) { return new AttackLeap(init.self); }
public override object Create(ActorInitializer init) { return new AttackLeap(init.self, this); }
}
class AttackLeap : AttackBase
class AttackLeap : AttackFrontal
{
internal bool IsLeaping;
protected Target target;
public AttackLeap(Actor self)
: base(self) {}
public AttackLeap(Actor self, AttackLeapInfo info)
: base(self, info) {}
public override void Tick(Actor self)
public override void DoAttack(Actor self, Target target)
{
base.Tick(self);
if (!target.IsValid) return;
if (IsLeaping) return;
if( !CanAttack( self, target ) ) return;
var weapon = Weapons[0].Info;
if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return;

View File

@@ -0,0 +1,34 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class AttackMedicInfo : AttackFrontalInfo
{
public override object Create( ActorInitializer init ) { return new AttackMedic( init.self, this ); }
}
public class AttackMedic : AttackFrontal
{
public AttackMedic(Actor self, AttackMedicInfo info)
: base( self, info ) {}
public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{
var weapon = ChooseWeaponForTarget(newTarget);
if( weapon == null )
return null;
return new Activities.Heal(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove);
}
}
}

View File

@@ -12,6 +12,7 @@ using System.Drawing;
using OpenRA.Effects;
using OpenRA.Mods.RA.Move;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA
{

View File

@@ -10,6 +10,7 @@
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA
{

View File

@@ -11,6 +11,7 @@
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA
{

View File

@@ -14,6 +14,7 @@ using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move;
using OpenRA.Traits;
using OpenRA.Traits.Activities;
namespace OpenRA.Mods.RA
{
@@ -52,6 +53,14 @@ namespace OpenRA.Mods.RA
return new AttackActivity( newTarget );
}
public override void ResolveOrder(Actor self, Order order)
{
base.ResolveOrder(self, order);
if (order.OrderString == "Stop")
target = Target.None;
}
bool buildComplete = false;
public void BuildingComplete(Actor self) { buildComplete = true; }

View File

@@ -20,70 +20,19 @@ namespace OpenRA.Mods.RA
{
public void TickIdle( Actor self )
{
self.QueueActivity( new IdleHealActivity() );
}
var attack = self.Trait<AttackBase>();
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * attack.GetMaximumRange());
class IdleHealActivity : Idle
{
Actor currentTarget;
IActivity inner;
public override IActivity Tick( Actor self )
{
if( inner == null )
{
if( NextActivity != null )
return NextActivity;
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
if (NeedsNewTarget(self))
{
currentTarget = ChooseTarget(self, range);
if( currentTarget != null )
inner = self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( currentTarget ), false );
}
}
if( inner != null )
{
if( NeedsNewTarget(self) )
inner.Cancel( self );
inner = Util.RunActivity( self, inner );
}
return this;
}
bool NeedsNewTarget(Actor self)
{
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
if (currentTarget == null || !currentTarget.IsInWorld)
return true; // he's dead.
if( !Combat.IsInRange( self.CenterLocation, range, currentTarget ) )
return true; // wandered off faster than we could follow
if (currentTarget.GetDamageState() == DamageState.Undamaged)
return true; // fully healed
return false;
}
Actor ChooseTarget(Actor self, float range)
{
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
var attack = self.Trait<AttackBase>();
return inRange
.Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally)
.Where(a => a.IsInWorld && !a.IsDead())
.Where(a => a.HasTrait<Health>() && a.GetDamageState() > DamageState.Undamaged)
.Where(a => attack.HasAnyValidWeapons(Target.FromActor(a)))
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
.FirstOrDefault();
}
var target = inRange
.Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally)
.Where(a => a.IsInWorld && !a.IsDead())
.Where(a => a.HasTrait<Health>() && a.GetDamageState() > DamageState.Undamaged)
.Where(a => attack.HasAnyValidWeapons(Target.FromActor(a)))
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
.FirstOrDefault();
if( target != null )
self.QueueActivity(self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( target ), false ));
}
}
}
}

View File

@@ -10,6 +10,7 @@
using OpenRA.Traits;
using OpenRA.Traits.Activities;
using System.Drawing;
namespace OpenRA.Mods.RA
{
@@ -24,7 +25,7 @@ namespace OpenRA.Mods.RA
{
if (!self.IsIdle) return;
if (e.Attacker.Destroyed) return;
// not a lot we can do about things we can't hurt... although maybe we should automatically run away?
var attack = self.Trait<AttackBase>();
if (!attack.HasAnyValidWeapons(Target.FromActor(e.Attacker))) return;
@@ -37,35 +38,20 @@ namespace OpenRA.Mods.RA
self.Trait<AttackBase>().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get<AutoTargetInfo>().AllowMovement);
}
public void TickIdle( Actor self )
public void TickIdle(Actor self)
{
self.QueueActivity( new IdleAttackActivity() );
}
class IdleAttackActivity : Idle
{
Actor currentTarget;
IActivity inner;
public override IActivity Tick( Actor self )
var attack = self.Trait<AttackBase>();
var target = attack.ScanForTarget(self, null);
if (target != null)
{
if( NextActivity != null && inner != null )
inner.Cancel( self );
if( inner == null )
{
if( NextActivity != null )
return NextActivity;
var attack = self.Trait<AttackBase>();
currentTarget = attack.ScanForTarget(self, null);
if( currentTarget != null )
inner = attack.GetAttackActivity( self, Target.FromActor(currentTarget), self.Info.Traits.Get<AutoTargetInfo>().AllowMovement );
}
if( inner != null )
inner = Util.RunActivity( self, inner );
return this;
self.SetTargetLine(Target.FromActor(target), Color.Red, false);
self.QueueActivity(attack.GetAttackActivity(self,
Target.FromActor(target),
self.Info.Traits.Get<AutoTargetInfo>().AllowMovement));
}
}
}
class AutoTargetIgnoreInfo : TraitInfo<AutoTargetIgnore> { }
class AutoTargetIgnore { }
}

View File

@@ -11,7 +11,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Buildings

View File

@@ -46,13 +46,7 @@ namespace OpenRA.Mods.RA.Buildings
public void Add(string key, List<string> prerequisites, ITechTreeElement tte)
{
Add(key, prerequisites, false, tte);
}
// set requiresPowered = true to discard buildings that have an IDisabled active (eg manually powered down)
public void Add(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement tte)
{
watchers.Add(new Watcher( key, prerequisites, requiresPowered, tte ));
watchers.Add(new Watcher( key, prerequisites, tte ));
}
public void Remove(string key)
@@ -86,21 +80,19 @@ namespace OpenRA.Mods.RA.Buildings
bool hasPrerequisites;
bool requiresPowered;
public Watcher(string key, List<string> prerequisites, bool requiresPowered, ITechTreeElement watcher)
public Watcher(string key, List<string> prerequisites, ITechTreeElement watcher)
{
this.key = key;
this.prerequisites = prerequisites;
this.watcher = watcher;
this.hasPrerequisites = false;
this.requiresPowered = requiresPowered;
}
public void Update(Cache<string, List<Actor>> buildings)
{
var nowHasPrerequisites = true;
foreach (var p in prerequisites)
if (!buildings.Keys.Contains(p) ||
(requiresPowered && buildings[p].All(b => b.TraitsImplementing<IDisable>().Any(d => d.Disabled))))
if (!buildings.Keys.Contains(p))
{
nowHasPrerequisites = false;
break;

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA
return;
var frac = (float)remainingFrames / chronoEffectLength;
var excludePalettes = new List<string>(){"cursor", "chrome", "colorpicker"};
var excludePalettes = new List<string>(){"cursor", "chrome", "colorpicker", "shroud", "fog"};
foreach (var pal in palettes)
{
if (excludePalettes.Contains(pal.Key))

View File

@@ -12,7 +12,7 @@ using System.Collections.Generic;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Traits;
using OpenRA.Widgets.Delegates;
using OpenRA.Mods.RA.Widgets.Delegates;
namespace OpenRA.Mods.RA
{

View File

@@ -10,31 +10,31 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA.Crates
{
class SupportPowerCrateActionInfo : CrateActionInfo
{
public readonly string Power = null;
[ActorReference]
public readonly string Proxy = null;
public override object Create(ActorInitializer init) { return new SupportPowerCrateAction(init.self, this); }
}
class SupportPowerCrateAction : CrateAction
{
SupportPowerCrateActionInfo Info;
public SupportPowerCrateAction(Actor self, SupportPowerCrateActionInfo info)
: base(self, info) { }
: base(self, info) { Info = info; }
// The free unit crate requires same race, and the actor to be at least ITeleportable.
// We want neither of these properties for crate power proxies.
public override void Activate(Actor collector)
{
// shit and broken. if you have a single-use and a multi-use version of the same
// support power, this only works by order-coincidence. that's stupid.
var p = collector.Owner.PlayerActor.TraitsImplementing<SupportPower>()
.FirstOrDefault(sp => sp.GetType().Name == (info as SupportPowerCrateActionInfo).Power);
if (p != null) p.Give(1);
base.Activate(collector);
collector.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary
{
new OwnerInit( collector.Owner )
}));
}
}
}

View File

@@ -51,14 +51,15 @@ namespace OpenRA.Mods.RA
Pair.New(Actors["ca2"], new int2(92, 71))
}, Actors["pdox"], -1, false);
}
if (ticks == 100)
Actors["mslo1"].Trait<NukeSilo>().Attack(new int2(98, 52));
Actors["mslo1"].Trait<NukePower>().Activate(Actors["mslo1"], new Order(){ TargetLocation = new int2(98, 52) });
if (ticks == 140)
Actors["mslo2"].Trait<NukeSilo>().Attack(new int2(95, 54));
Actors["mslo2"].Trait<NukePower>().Activate(Actors["mslo2"], new Order(){ TargetLocation = new int2(95, 54) });
if (ticks == 180)
Actors["mslo3"].Trait<NukeSilo>().Attack(new int2(95, 49));
Actors["mslo3"].Trait<NukePower>().Activate(Actors["mslo3"], new Order(){ TargetLocation = new int2(95, 49) });
if (ticks == 430)
{
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);

View File

@@ -32,10 +32,17 @@ namespace OpenRA.Mods.RA.Effects
circles.Play("circles");
}
int2 cachedLocation;
public void Tick( World world )
{
flag.Tick();
circles.Tick();
if (cachedLocation != rp.rallyPoint)
{
cachedLocation = rp.rallyPoint;
circles.Play("circles");
}
if (!building.IsInWorld || building.IsDead())
world.AddFrameEndTask(w => w.Remove(this));
}

View File

@@ -10,7 +10,6 @@
using System.Collections.Generic;
using System.Drawing;
using OpenRA.Effects;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Orders;
@@ -51,7 +50,6 @@ namespace OpenRA.Mods.RA
self.CancelActivity();
self.QueueActivity(new Enter(order.TargetActor));
//self.QueueActivity(new Move(order.TargetActor.Location, order.TargetActor));
self.QueueActivity(new CaptureBuilding(order.TargetActor));
}
}

View File

@@ -10,7 +10,6 @@
using System.Collections.Generic;
using System.Drawing;
using OpenRA.Effects;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Orders;

View File

@@ -11,7 +11,6 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Orders;
@@ -23,7 +22,6 @@ namespace OpenRA.Mods.RA
{
public readonly int Capacity = 28;
public readonly int PipCount = 7;
public readonly PipType PipColor = PipType.Yellow;
public readonly string[] Resources = { };
public readonly decimal FullyLoadedSpeed = .85m;
@@ -64,11 +62,11 @@ namespace OpenRA.Mods.RA
var refs = self.World.Queries.OwnedBy[self.Owner]
.Where(x => x != ignore && x.HasTrait<IAcceptOre>())
.ToList();
var mi = self.Info.Traits.Get<MobileInfo>();
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(PathSearch.FromPoints(self.World, mi,
refs.Select(r => r.Location + r.Trait<IAcceptOre>().DeliverOffset),
self.Location,
false));
var mi = self.Info.Traits.Get<MobileInfo>();
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
PathSearch.FromPoints(self.World, mi,
refs.Select(r => r.Location + r.Trait<IAcceptOre>().DeliverOffset),
self.Location, false));
path.Reverse();
if (path.Count != 0)
return refs.FirstOrDefault(x => x.Location + x.Trait<IAcceptOre>().DeliverOffset == path[0]);
@@ -168,20 +166,27 @@ namespace OpenRA.Mods.RA
return;
ChooseNewProc(self, proc);
}
PipType GetPipAt(int i)
{
var n = i * Info.Capacity / Info.PipCount;
foreach (var rt in contents)
if (n < rt.Value)
return rt.Key.PipColor;
else
n -= rt.Value;
return PipType.Transparent;
}
public IEnumerable<PipType> GetPips(Actor self)
{
int numPips = Info.PipCount;
int n = contents.Values.Sum();
for (int i = 0; i < numPips; i++)
{
if (n * 1.0f / Info.Capacity > i * 1.0f / numPips)
yield return Info.PipColor;
else
yield return PipType.Transparent;
}
int numPips = Info.PipCount;
for (int i = 0; i < numPips; i++)
yield return GetPipAt(i);
}
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)

View File

@@ -8,36 +8,68 @@
*/
#endregion
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class IdleAnimationInfo : ITraitInfo
class IdleAnimationInfo : ITraitInfo, ITraitPrerequisite<RenderInfantryInfo>
{
public readonly int IdleWaitTicks = 50;
public readonly string[] Animations = {};
public object Create(ActorInitializer init) { return new IdleAnimation(this); }
}
// infantry prone behavior
class IdleAnimation : INotifyDamage, INotifyIdle
class IdleAnimation : ITick, INotifyIdle
{
enum IdleState
{
None,
Waiting,
Active
};
IdleAnimationInfo Info;
string sequence;
int delay;
IdleState state;
public IdleAnimation(IdleAnimationInfo info)
{
Info = info;
}
public void Damaged(Actor self, AttackInfo e)
{
if (self.GetCurrentActivity() is Activities.IdleAnimation)
self.CancelActivity();
}
public void Tick(Actor self)
{
if (!self.IsIdle)
{
state = IdleState.None;
return;
}
if (state == IdleState.Active)
return;
else if (delay > 0 && --delay == 0)
{
state = IdleState.Active;
var ri = self.TraitOrDefault<RenderInfantry>();
if (ri.anim.HasSequence(sequence))
ri.anim.PlayThen(sequence, () => state = IdleState.None);
else
state = IdleState.None;
}
}
public void TickIdle(Actor self)
{
self.QueueActivity(new Activities.IdleAnimation(Info.Animations.Random(self.World.SharedRandom),
Info.IdleWaitTicks));
if (state != IdleState.None)
return;
state = IdleState.Waiting;
sequence = Info.Animations.Random(self.World.SharedRandom);
delay = Info.IdleWaitTicks;
}
}
}

View File

@@ -10,29 +10,31 @@
using System.Linq;
using OpenRA.Traits;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA
{
class InfiltrateForSupportPowerInfo : ITraitInfo
{
public readonly string Power = null;
[ActorReference]
public readonly string Proxy = null;
public object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); }
}
class InfiltrateForSupportPower : IAcceptSpy
{
InfiltrateForSupportPowerInfo info;
InfiltrateForSupportPowerInfo Info;
public InfiltrateForSupportPower(InfiltrateForSupportPowerInfo info)
{
this.info = info;
Info = info;
}
public void OnInfiltrate(Actor self, Actor spy)
{
var p = spy.Owner.PlayerActor.TraitsImplementing<SupportPower>()
.FirstOrDefault(sp => sp.GetType().Name == info.Power);
if (p != null) p.Give(1);
spy.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary
{
new OwnerInit( spy.Owner )
}));
}
}
}

View File

@@ -205,6 +205,11 @@ namespace OpenRA.Mods.RA.Move
var target = order.TargetLocation.Clamp(self.World.Map.Bounds);
PerformMove(self, target, order.Queued && !self.IsIdle);
}
if (order.OrderString == "Stop")
{
self.CancelActivity();
}
}
public string VoicePhraseForOrder(Actor self, Order order)

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA
var frac = (float)remainingFrames / nukeEffectLength;
var excludePalettes = new List<string>(){"cursor", "chrome", "colorpicker"};
var excludePalettes = new List<string>(){"cursor", "chrome", "colorpicker", "shroud", "fog"};
foreach (var pal in palettes)
{
if (excludePalettes.Contains(pal.Key))

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -259,6 +259,7 @@
<Compile Include="Widgets\BuildPaletteWidget.cs" />
<Compile Include="Widgets\Delegates\IngameObserverChromeDelegate.cs" />
<Compile Include="Widgets\Delegates\IngameChromeDelegate.cs" />
<Compile Include="Widgets\Delegates\ReplayBrowserDelegate.cs" />
<Compile Include="Widgets\MoneyBinWidget.cs" />
<Compile Include="Widgets\OrderButtonWidget.cs" />
<Compile Include="Widgets\PowerBinWidget.cs" />
@@ -299,7 +300,6 @@
<Compile Include="HackyAI.cs" />
<Compile Include="RALoadScreen.cs" />
<Compile Include="NullLoadScreen.cs" />
<Compile Include="Activities\IdleAnimation.cs" />
<Compile Include="IdleAnimation.cs" />
<Compile Include="World\GotoNextBase.cs" />
<Compile Include="World\SmudgeLayer.cs" />
@@ -324,6 +324,9 @@
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
<Compile Include="TargetableSubmarine.cs" />
<Compile Include="Effects\RallyPoint.cs" />
<Compile Include="AttackMedic.cs" />
<Compile Include="Activities\Heal.cs" />
<Compile Include="SupportPowers\SupportPowerManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -350,4 +353,8 @@
copy "$(TargetPath)" "$(SolutionDir)mods/ra/"
cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Folder Include="SupportPowers\" />
<Folder Include="Player\" />
</ItemGroup>
</Project>

View File

@@ -21,60 +21,62 @@ namespace OpenRA.Mods.RA.Render
public override object Create(ActorInitializer init) { return new RenderInfantry(init.self); }
}
public class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage
public class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage, INotifyIdle
{
public enum AnimationState
{
Idle,
Attacking,
Moving,
Waiting
};
public AnimationState State { get; private set; }
Mobile mobile;
public RenderInfantry(Actor self)
: base(self, () => self.Trait<IFacing>().Facing)
{
anim.Play("stand");
}
bool ChooseMoveAnim(Actor self)
{
var mobile = self.Trait<Mobile>();
if( !mobile.IsMoving ) return false;
if (float2.WithinEpsilon(self.CenterLocation, Util.CenterOfCell(mobile.toCell), 2)) return false;
var seq = IsProne(self) ? "crawl" : "run";
if (anim.CurrentSequence.Name != seq)
anim.PlayRepeating(seq);
return true;
}
bool inAttack = false;
bool IsProne(Actor self)
{
var takeCover = self.TraitOrDefault<TakeCover>();
return takeCover != null && takeCover.IsProne;
State = AnimationState.Idle;
mobile = self.Trait<Mobile>();
}
public void Attacking(Actor self, Target target)
{
inAttack = true;
var seq = IsProne(self) ? "prone-shoot" : "shoot";
if (anim.HasSequence(seq))
anim.PlayThen(seq, () => inAttack = false);
State = AnimationState.Attacking;
if (anim.HasSequence("shoot"))
anim.PlayThen("shoot", () => State = AnimationState.Idle);
else if (anim.HasSequence("heal"))
anim.PlayThen("heal", () => inAttack = false);
anim.PlayThen("heal", () => State = AnimationState.Idle);
}
public override void Tick(Actor self)
{
base.Tick(self);
if (inAttack) return;
if (self.GetCurrentActivity() is Activities.IdleAnimation) return;
if (ChooseMoveAnim(self)) return;
if (IsProne(self))
anim.PlayFetchIndex("crawl", () => 0); /* what a hack. */
else
// If path is blocked, we can have !isMoving and !idle
// Need to handle this case specially
if (!mobile.IsMoving && State == AnimationState.Moving)
{
State = AnimationState.Waiting;
anim.Play("stand");
}
else if (State != AnimationState.Moving && mobile.IsMoving)
{
State = AnimationState.Moving;
anim.PlayRepeating("run");
}
}
public void TickIdle(Actor self)
{
if (State != AnimationState.Idle)
{
anim.Play("stand");
State = AnimationState.Idle;
}
}
public void Damaged(Actor self, AttackInfo e)
{

View File

@@ -46,13 +46,13 @@ namespace OpenRA.Mods.RA.Render
{
disguisedAsPlayer = target.Owner;
disguisedAsSprite = target.Trait<RenderSimple>().GetImage(target);
anim.ChangeImage(disguisedAsSprite);
anim.ChangeImage(disguisedAsSprite, "stand");
}
else
{
disguisedAsPlayer = null;
disguisedAsSprite = null;
anim.ChangeImage(GetImage(self));
anim.ChangeImage(GetImage(self), "stand");
}
}
}

View File

@@ -6,16 +6,10 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
#endregion
using System;
using OpenRA.Widgets;
using OpenRA.Traits.Activities;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities;
using System;
namespace OpenRA.Scripting
{

View File

@@ -6,13 +6,13 @@
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using OpenRA.FileFormats;
using OpenRA.Mods.RA;
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Render;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Scripting
{

View File

@@ -285,7 +285,7 @@ namespace OpenRA.Mods.RA.Server
};
var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot );
if (slotData != null)
if (slotData != null && slotData.MapPlayer != null)
SyncClientToPlayerReference(client, server.Map.Players[slotData.MapPlayer]);
server.lobbyInfo.Clients.Add(client);

View File

@@ -38,9 +38,10 @@ namespace OpenRA.Mods.RA
{
if (order.OrderString == "SpyInfiltrate")
{
self.CancelActivity();
self.QueueActivity(new MoveAdjacentTo(order.TargetActor));
self.SetTargetLine(Target.FromOrder(order), Color.Red);
self.CancelActivity();
self.QueueActivity(new Enter(order.TargetActor));
self.QueueActivity(new Infiltrate(order.TargetActor));
}
}

View File

@@ -26,53 +26,39 @@ namespace OpenRA.Mods.RA
public override object Create(ActorInitializer init) { return new AirstrikePower(init.self, this); }
}
class AirstrikePower : SupportPower, IResolveOrder
class AirstrikePower : SupportPower
{
public AirstrikePower(Actor self, AirstrikePowerInfo info) : base(self, info) { }
protected override void OnActivate()
public override void Activate(Actor self, Order order)
{
Self.World.OrderGenerator = new GenericSelectTarget(Owner.PlayerActor, Info.OrderName, "ability");
}
public void ResolveOrder(Actor self, Order order)
{
if (!IsAvailable) return;
if (order.OrderString == Info.OrderName)
var startPos = self.World.ChooseRandomEdgeCell();
self.World.AddFrameEndTask(w =>
{
var startPos = Owner.World.ChooseRandomEdgeCell();
var info = (Info as AirstrikePowerInfo);
var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( self.Owner ),
}) : null;
var a = w.CreateActor(info.UnitType, new TypeDictionary
{
new LocationInit( startPos ),
new OwnerInit( self.Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ),
new AltitudeInit( Rules.Info[info.UnitType].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
a.Trait<CarpetBomb>().SetTarget(order.TargetLocation);
Owner.World.AddFrameEndTask(w =>
{
var info = (Info as AirstrikePowerInfo);
var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( Owner ),
}) : null;
var a = w.CreateActor(info.UnitType, new TypeDictionary
{
new LocationInit( startPos ),
new OwnerInit( Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ),
new AltitudeInit( Rules.Info[info.UnitType].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
a.Trait<CarpetBomb>().SetTarget(order.TargetLocation);
a.CancelActivity();
a.QueueActivity(Fly.ToCell(order.TargetLocation));
a.CancelActivity();
a.QueueActivity(Fly.ToCell(order.TargetLocation));
if (flare != null)
a.QueueActivity(new CallFunc(() => flare.Destroy()));
if (flare != null)
a.QueueActivity(new CallFunc(() => flare.Destroy()));
a.QueueActivity(new FlyOffMap { Interruptible = false });
a.QueueActivity(new RemoveSelf());
});
FinishActivate();
}
a.QueueActivity(new FlyOffMap { Interruptible = false });
a.QueueActivity(new RemoveSelf());
});
}
}
}

View File

@@ -20,62 +20,52 @@ namespace OpenRA.Mods.RA
{
class ChronoshiftPowerInfo : SupportPowerInfo
{
public readonly int Range = 2; // Range in cells
public readonly int Duration = 30;
public readonly int Range = 1; // Range in cells
public readonly int Duration = 30; // Seconds
public readonly bool KillCargo = true;
public override object Create(ActorInitializer init) { return new ChronoshiftPower(init.self,this); }
}
class ChronoshiftPower : SupportPower, IResolveOrder
class ChronoshiftPower : SupportPower
{
public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) : base(self, info) { }
protected override void OnActivate() { Self.World.OrderGenerator = new SelectTarget(this); }
public void ResolveOrder(Actor self, Order order)
public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
{
if (!IsReady) return;
if (order.OrderString == "Chronoshift")
Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound);
return new SelectTarget(order, manager, this);
}
public override void Activate(Actor self, Order order)
{
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
// Trigger screen desaturate effect
foreach (var a in self.World.Queries.WithTrait<ChronoshiftPaletteEffect>())
a.Trait.Enable();
Sound.Play("chrono2.aud", Game.CellSize * order.TargetLocation);
Sound.Play("chrono2.aud", Game.CellSize * order.ExtraLocation);
foreach (var target in UnitsInRange(order.ExtraLocation))
{
var chronosphere = self.World.Queries
.OwnedBy[self.Owner]
.WithTrait<Chronosphere>()
.Select(x => x.Actor).FirstOrDefault();
if (chronosphere != null)
chronosphere.Trait<RenderBuilding>().PlayCustomAnim(chronosphere, "active");
// Trigger screen desaturate effect
foreach (var a in self.World.Queries.WithTrait<ChronoshiftPaletteEffect>())
a.Trait.Enable();
Sound.Play("chrono2.aud", Game.CellSize * order.TargetLocation);
Sound.Play("chrono2.aud", Game.CellSize * order.ExtraLocation);
var targets = UnitsInRange(order.ExtraLocation);
foreach (var target in targets)
{
var cs = target.Trait<Chronoshiftable>();
var targetCell = target.Location + order.TargetLocation - order.ExtraLocation;
if (cs.CanChronoshiftTo(target, targetCell))
target.Trait<Chronoshiftable>().Teleport(target,
targetCell,
(int)((Info as ChronoshiftPowerInfo).Duration * 25 * 60),
(Info as ChronoshiftPowerInfo).KillCargo,
chronosphere);
}
FinishActivate();
var cs = target.Trait<Chronoshiftable>();
var targetCell = target.Location + order.TargetLocation - order.ExtraLocation;
// TODO: Fix CanChronoshiftTo desync
if (cs.CanChronoshiftTo(target, targetCell))
target.Trait<Chronoshiftable>().Teleport(target,
targetCell,
(Info as ChronoshiftPowerInfo).Duration * 25,
(Info as ChronoshiftPowerInfo).KillCargo,
self);
}
}
public IEnumerable<Actor> UnitsInRange(int2 xy)
{
int range = (Info as ChronoshiftPowerInfo).Range;
var uim = Self.World.WorldActor.Trait<UnitInfluence>();
var tiles = Self.World.FindTilesInCircle(xy, range);
var uim = self.World.WorldActor.Trait<UnitInfluence>();
var tiles = self.World.FindTilesInCircle(xy, range);
var units = new List<Actor>();
foreach (var t in tiles)
units.AddRange(uim.GetUnitsAt(t));
@@ -85,36 +75,35 @@ namespace OpenRA.Mods.RA
class SelectTarget : IOrderGenerator
{
ChronoshiftPower power;
int range;
Sprite tile;
readonly ChronoshiftPower power;
readonly int range;
readonly Sprite tile;
readonly SupportPowerManager manager;
readonly string order;
public SelectTarget(ChronoshiftPower power)
public SelectTarget(string order, SupportPowerManager manager, ChronoshiftPower power)
{
this.manager = manager;
this.order = order;
this.power = power;
this.range = (power.Info as ChronoshiftPowerInfo).Range;
tile = UiOverlay.SynthesizeTile(0x04);
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
world.CancelInputMode();
world.OrderGenerator = new SelectDestination(power, xy);
world.CancelInputMode();
world.OrderGenerator = new SelectDestination(order, manager, power, xy);
yield break;
}
public void Tick( World world )
public void Tick(World world)
{
var hasChronosphere = world.Queries.OwnedBy[world.LocalPlayer]
.WithTrait<Chronosphere>()
.Any();
if (!hasChronosphere)
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
public void RenderAfterWorld(WorldRenderer wr, World world)
{
var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2();
@@ -139,13 +128,17 @@ namespace OpenRA.Mods.RA
class SelectDestination : IOrderGenerator
{
ChronoshiftPower power;
int2 sourceLocation;
int range;
Sprite validTile, invalidTile, sourceTile;
readonly ChronoshiftPower power;
readonly int2 sourceLocation;
readonly int range;
readonly Sprite validTile, invalidTile, sourceTile;
readonly SupportPowerManager manager;
readonly string order;
public SelectDestination(ChronoshiftPower power, int2 sourceLocation)
public SelectDestination(string order, SupportPowerManager manager, ChronoshiftPower power, int2 sourceLocation)
{
this.manager = manager;
this.order = order;
this.power = power;
this.sourceLocation = sourceLocation;
this.range = (power.Info as ChronoshiftPowerInfo).Range;
@@ -174,23 +167,20 @@ namespace OpenRA.Mods.RA
{
// Cannot chronoshift into unexplored location
if (isValidTarget(xy))
yield return new Order("Chronoshift", world.LocalPlayer.PlayerActor, false)
yield return new Order(order, manager.self, false)
{
TargetLocation = xy,
ExtraLocation = sourceLocation
};
}
public void Tick(World world)
{
var hasChronosphere = world.Queries.OwnedBy[world.LocalPlayer]
.WithTrait<Chronosphere>()
.Any();
if (!hasChronosphere)
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
public void RenderAfterWorld(WorldRenderer wr, World world)
{
foreach (var unit in power.UnitsInRange(sourceLocation))
@@ -243,14 +233,11 @@ namespace OpenRA.Mods.RA
}
return canTeleport;
}
public string GetCursor(World world, int2 xy, MouseInput mi)
{
return isValidTarget(xy) ? "chrono-target" : "move-blocked";
}
}
}
// tag trait for the building
class ChronosphereInfo : TraitInfo<Chronosphere> {}
class Chronosphere {}
}

View File

@@ -26,28 +26,21 @@ namespace OpenRA.Mods.RA
{
public GpsPower(Actor self, GpsPowerInfo info) : base(self, info) { }
protected override void OnFinishCharging()
public override void Charged(Actor self, string key)
{
var launchSite = Owner.World.Queries.OwnedBy[Owner]
.FirstOrDefault(a => a.HasTrait<GpsLaunchSite>());
if (launchSite == null)
return;
Owner.World.AddFrameEndTask(w =>
self.Owner.PlayerActor.Trait<SupportPowerManager>().Powers[key].Activate(new Order());
}
public override void Activate(Actor self, Order order)
{
self.World.AddFrameEndTask(w =>
{
Sound.PlayToPlayer(Owner, Info.LaunchSound);
Sound.PlayToPlayer(self.Owner, Info.LaunchSound);
w.Add(new SatelliteLaunch(launchSite));
w.Add(new SatelliteLaunch(self));
w.Add(new DelayedAction((Info as GpsPowerInfo).RevealDelay * 25,
() => Owner.Shroud.Disabled = true));
() => self.Owner.Shroud.Disabled = true));
});
FinishActivate();
}
}
// tag trait to identify the building
class GpsLaunchSiteInfo : TraitInfo<GpsLaunchSite> { }
class GpsLaunchSite { }
}

View File

@@ -21,52 +21,35 @@ namespace OpenRA.Mods.RA
{
class IronCurtainPowerInfo : SupportPowerInfo
{
public readonly float Duration = 0f;
public readonly int Range = 2; // Range in cells
public readonly int Duration = 10; // Seconds
public readonly int Range = 1; // Range in cells
public override object Create(ActorInitializer init) { return new IronCurtainPower(init.self, this); }
}
class IronCurtainPower : SupportPower, IResolveOrder
class IronCurtainPower : SupportPower
{
public IronCurtainPower(Actor self, IronCurtainPowerInfo info) : base(self, info) { }
protected override void OnBeginCharging() { Sound.PlayToPlayer(Owner, "ironchg1.aud"); }
protected override void OnFinishCharging() { Sound.PlayToPlayer(Owner, "ironrdy1.aud"); }
protected override void OnActivate()
public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
{
Self.World.OrderGenerator = new SelectTarget(this);
Sound.Play("slcttgt1.aud");
Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound);
return new SelectTarget(order, manager, this);
}
public void ResolveOrder(Actor self, Order order)
public override void Activate(Actor self, Order order)
{
if (!IsReady) return;
if (order.OrderString == "IronCurtain")
{
var curtain = self.World.Queries
.OwnedBy[self.Owner]
.WithTrait<IronCurtain>()
.Select(x => x.Actor).FirstOrDefault();
if (curtain != null)
curtain.Trait<RenderBuilding>().PlayCustomAnim(curtain, "active");
Sound.Play("ironcur9.aud", Game.CellSize * order.TargetLocation);
foreach (var target in UnitsInRange(order.TargetLocation))
target.Trait<IronCurtainable>().Activate(target, (int)((Info as IronCurtainPowerInfo).Duration * 25 * 60));
FinishActivate();
}
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
Sound.Play("ironcur9.aud", Game.CellSize * order.TargetLocation);
foreach (var target in UnitsInRange(order.TargetLocation))
target.Trait<IronCurtainable>().Activate(target, (Info as IronCurtainPowerInfo).Duration * 25);
}
public IEnumerable<Actor> UnitsInRange(int2 xy)
{
int range = (Info as IronCurtainPowerInfo).Range;
var uim = Self.World.WorldActor.Trait<UnitInfluence>();
var tiles = Self.World.FindTilesInCircle(xy, range);
var uim = self.World.WorldActor.Trait<UnitInfluence>();
var tiles = self.World.FindTilesInCircle(xy, range);
var units = new List<Actor>();
foreach (var t in tiles)
units.AddRange(uim.GetUnitsAt(t));
@@ -76,12 +59,16 @@ namespace OpenRA.Mods.RA
class SelectTarget : IOrderGenerator
{
IronCurtainPower power;
int range;
Sprite tile;
readonly IronCurtainPower power;
readonly int range;
readonly Sprite tile;
readonly SupportPowerManager manager;
readonly string order;
public SelectTarget(IronCurtainPower power)
public SelectTarget(string order, SupportPowerManager manager, IronCurtainPower power)
{
this.manager = manager;
this.order = order;
this.power = power;
this.range = (power.Info as IronCurtainPowerInfo).Range;
tile = UiOverlay.SynthesizeTile(0x04);
@@ -89,28 +76,15 @@ namespace OpenRA.Mods.RA
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
world.CancelInputMode();
return OrderInner(world, xy, mi);
world.CancelInputMode();
if (mi.Button == MouseButton.Left && power.UnitsInRange(xy).Any())
yield return new Order(order, manager.self, false) { TargetLocation = xy };
}
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left && power.UnitsInRange(xy).Any() )
{
world.CancelInputMode();
yield return new Order("IronCurtain", world.LocalPlayer.PlayerActor, false) { TargetLocation = xy };
}
}
public void Tick(World world)
{
var hasStructure = world.Queries.OwnedBy[world.LocalPlayer]
.WithTrait<IronCurtain>()
.Any();
if (!hasStructure)
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
@@ -134,8 +108,4 @@ namespace OpenRA.Mods.RA
}
}
}
// tag trait for the building
class IronCurtainInfo : TraitInfo<IronCurtain> { }
class IronCurtain { }
}

View File

@@ -17,72 +17,33 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class NukePowerInfo : SupportPowerInfo
{
public override object Create(ActorInitializer init) { return new NukePower(init.self, this); }
}
class NukePower : SupportPower, IResolveOrder
{
public NukePower(Actor self, NukePowerInfo info) : base(self, info) { }
protected override void OnActivate()
{
Self.World.OrderGenerator =
new GenericSelectTargetWithBuilding<NukeSilo>(Owner.PlayerActor, "NuclearMissile", "nuke");
}
public void ResolveOrder(Actor self, Order order)
{
if (!IsReady) return;
if (order.OrderString == "NuclearMissile")
{
var silo = self.World.Queries.OwnedBy[self.Owner]
.Where(a => a.HasTrait<NukeSilo>())
.FirstOrDefault();
if (silo != null)
silo.Trait<RenderBuilding>().PlayCustomAnim(silo, "active");
// Play to everyone but the current player
if (Owner != Owner.World.LocalPlayer)
Sound.Play(Info.LaunchSound);
silo.Trait<NukeSilo>().Attack(order.TargetLocation);
FinishActivate();
}
}
}
// tag trait for the building
class NukeSiloInfo : ITraitInfo
{
[WeaponReference]
public readonly string MissileWeapon = "";
public readonly int2 SpawnOffset = int2.Zero;
public object Create(ActorInitializer init) { return new NukeSilo(init.self, this); }
public override object Create(ActorInitializer init) { return new NukePower(init.self, this); }
}
class NukeSilo
{
Actor self;
NukeSiloInfo info;
public NukeSilo(Actor self, NukeSiloInfo info)
class NukePower : SupportPower
{
public NukePower(Actor self, NukePowerInfo info) : base(self, info) { }
public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
{
this.self = self;
this.info = info;
Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound);
return new SelectGenericPowerTarget(order, manager, "nuke", MouseButton.Left);
}
public void Attack(int2 targetLocation)
public override void Activate(Actor self, Order order)
{
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
// Play to everyone but the current player
if (self.Owner != self.World.LocalPlayer)
Sound.Play(Info.LaunchSound);
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
self.World.AddFrameEndTask(w =>
{
//FIRE ZE MISSILES
w.Add(new NukeLaunch(self, info.MissileWeapon, info.SpawnOffset, targetLocation));
w.Add(new NukeLaunch(self, (Info as NukePowerInfo).MissileWeapon, (Info as NukePowerInfo).SpawnOffset, order.TargetLocation));
});
}
}

View File

@@ -16,7 +16,7 @@ using OpenRA.Mods.RA.Air;
namespace OpenRA.Mods.RA
{
class ParatroopersPowerInfo : SupportPowerInfo
public class ParatroopersPowerInfo : SupportPowerInfo
{
[ActorReference]
public string[] DropItems = { };
@@ -28,56 +28,39 @@ namespace OpenRA.Mods.RA
public override object Create(ActorInitializer init) { return new ParatroopersPower(init.self, this); }
}
class ParatroopersPower : SupportPower, IResolveOrder
public class ParatroopersPower : SupportPower
{
public ParatroopersPower(Actor self, ParatroopersPowerInfo info) : base(self, info) { }
protected override void OnActivate()
public override void Activate(Actor self, Order order)
{
Self.World.OrderGenerator =
new GenericSelectTarget( Owner.PlayerActor, "ParatroopersActivate", "ability" );
}
public void ResolveOrder(Actor self, Order order)
{
if (!IsAvailable) return;
if (order.OrderString == "ParatroopersActivate")
{
DoParadrop(Owner, order.TargetLocation,
self.Info.Traits.Get<ParatroopersPowerInfo>().DropItems);
FinishActivate();
}
}
void DoParadrop(Player owner, int2 p, string[] items)
{
var startPos = owner.World.ChooseRandomEdgeCell();
owner.World.AddFrameEndTask(w =>
var items = (Info as ParatroopersPowerInfo).DropItems;
var startPos = self.World.ChooseRandomEdgeCell();
self.World.AddFrameEndTask(w =>
{
var info = (Info as ParatroopersPowerInfo);
var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary
{
new LocationInit( p ),
new OwnerInit( owner ),
new LocationInit( order.TargetLocation ),
new OwnerInit( self.Owner ),
}) : null;
var a = w.CreateActor(info.UnitType, new TypeDictionary
{
new LocationInit( startPos ),
new OwnerInit( owner ),
new FacingInit( Util.GetFacing(p - startPos, 0) ),
new OwnerInit( self.Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ),
new AltitudeInit( Rules.Info[info.UnitType].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
a.CancelActivity();
a.QueueActivity(new FlyCircle(p));
a.Trait<ParaDrop>().SetLZ(p, flare);
a.QueueActivity(new FlyCircle(order.TargetLocation));
a.Trait<ParaDrop>().SetLZ(order.TargetLocation, flare);
var cargo = a.Trait<Cargo>();
foreach (var i in items)
cargo.Load(a, owner.World.CreateActor(false, i.ToLowerInvariant(), new TypeDictionary { new OwnerInit( a.Owner ) }));
cargo.Load(a, self.World.CreateActor(false, i.ToLowerInvariant(), new TypeDictionary { new OwnerInit( a.Owner ) }));
});
}
}

View File

@@ -17,30 +17,15 @@ namespace OpenRA.Mods.RA
public override object Create(ActorInitializer init) { return new SonarPulsePower(init.self, this); }
}
public class SonarPulsePower : SupportPower, IResolveOrder
public class SonarPulsePower : SupportPower
{
public SonarPulsePower(Actor self, SonarPulsePowerInfo info) : base(self, info) { }
protected override void OnBeginCharging() { }
protected override void OnFinishCharging() { Sound.PlayToPlayer(Owner, "pulse1.aud"); }
protected override void OnActivate()
public override void Activate(Actor self, Order order)
{
Self.World.IssueOrder(new Order("SonarPulse", Owner.PlayerActor, false));
}
// TODO: Reveal submarines
public void ResolveOrder(Actor self, Order order)
{
if (!IsAvailable) return;
if (order.OrderString == "SonarPulse")
{
// TODO: Reveal submarines
// Should this play for all players?
Sound.Play("sonpulse.aud");
FinishActivate();
}
// Should this play for all players?
Sound.Play("sonpulse.aud");
}
}
}

View File

@@ -19,55 +19,41 @@ namespace OpenRA.Mods.RA
{
class SpyPlanePowerInfo : SupportPowerInfo
{
public readonly float RevealTime = .1f; // minutes
public readonly int RevealTime = 6; // seconds
public override object Create(ActorInitializer init) { return new SpyPlanePower(init.self,this); }
}
class SpyPlanePower : SupportPower, IResolveOrder
class SpyPlanePower : SupportPower
{
public SpyPlanePower(Actor self, SpyPlanePowerInfo info) : base(self, info) { }
protected override void OnFinishCharging() { Sound.PlayToPlayer(Owner, "spypln1.aud"); }
protected override void OnActivate()
public override void Activate(Actor self, Order order)
{
Self.World.OrderGenerator = new GenericSelectTarget(Owner.PlayerActor, "SpyPlane", "ability");
Sound.Play("slcttgt1.aud");
}
var enterCell = self.World.ChooseRandomEdgeCell();
public void ResolveOrder(Actor self, Order order)
{
if (!IsAvailable) return;
if (order.OrderString == "SpyPlane")
var plane = self.World.CreateActor("u2", new TypeDictionary
{
FinishActivate();
new LocationInit( enterCell ),
new OwnerInit( self.Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - enterCell, 0) ),
new AltitudeInit( Rules.Info["u2"].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
var enterCell = self.World.ChooseRandomEdgeCell();
var plane = self.World.CreateActor("u2", new TypeDictionary
plane.CancelActivity();
plane.QueueActivity(Fly.ToCell(order.TargetLocation));
plane.QueueActivity(new CallFunc(() => plane.World.AddFrameEndTask( w =>
{
new LocationInit( enterCell ),
new OwnerInit( self.Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - enterCell, 0) ),
new AltitudeInit( Rules.Info["u2"].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
var camera = w.CreateActor("camera", new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( self.Owner ),
});
plane.CancelActivity();
plane.QueueActivity(Fly.ToCell(order.TargetLocation));
plane.QueueActivity(new CallFunc(() => plane.World.AddFrameEndTask( w =>
{
var camera = w.CreateActor("camera", new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( Owner ),
});
camera.QueueActivity(new Wait((int)(25 * 60 * (Info as SpyPlanePowerInfo).RevealTime)));
camera.QueueActivity(new RemoveSelf());
})));
plane.QueueActivity(new FlyOffMap { Interruptible = false });
plane.QueueActivity(new RemoveSelf());
}
camera.QueueActivity(new Wait(25 * (Info as SpyPlanePowerInfo).RevealTime));
camera.QueueActivity(new RemoveSelf());
})));
plane.QueueActivity(new FlyOffMap { Interruptible = false });
plane.QueueActivity(new RemoveSelf());
}
}
}

View File

@@ -14,136 +14,52 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public abstract class SupportPowerInfo : ITraitInfo, ITraitPrerequisite<TechTreeInfo>, ITraitPrerequisite<PowerManagerInfo>
public abstract class SupportPowerInfo : ITraitInfo
{
public readonly bool RequiresPower = true;
public readonly bool OneShot = false;
public readonly float ChargeTime = 0;
public readonly int ChargeTime = 0;
public readonly string Image = null;
public readonly string Description = "";
public readonly string LongDesc = "";
[ActorReference]
public readonly string[] Prerequisites = { };
public readonly bool GivenAuto = true;
public readonly string OrderName;
public readonly bool AllowMultiple = false;
public readonly bool OneShot = false;
public readonly string BeginChargeSound = null;
public readonly string EndChargeSound = null;
public readonly string SelectTargetSound = null;
public readonly string LaunchSound = null;
public readonly string OrderName;
public abstract object Create(ActorInitializer init);
public SupportPowerInfo() { OrderName = GetType().Name + "Order"; }
}
public class SupportPower : ITick, ITechTreeElement
public class SupportPower
{
public readonly Actor self;
public readonly SupportPowerInfo Info;
public int RemainingTime { get; private set; }
public int TotalTime { get { return (int)(Info.ChargeTime * 60 * 25); } }
public bool IsUsed;
public bool IsAvailable;
public bool IsReady { get { return IsAvailable && RemainingTime == 0; } }
protected readonly Actor Self;
protected readonly Player Owner;
bool notifiedCharging;
bool notifiedReady;
readonly PowerManager PlayerPower;
public SupportPower(Actor self, SupportPowerInfo info)
{
Info = info;
RemainingTime = TotalTime;
Self = self;
Owner = self.Owner;
PlayerPower = self.Trait<PowerManager>();
self.Trait<TechTree>().Add( Info.OrderName, Info.Prerequisites.Select( a => a.ToLowerInvariant() ).ToList(), this );
this.self = self;
}
public virtual void Charging(Actor self, string key)
{
Sound.PlayToPlayer(self.Owner, Info.BeginChargeSound);
}
public virtual void Charged(Actor self, string key)
{
Sound.PlayToPlayer(self.Owner, Info.EndChargeSound);
}
public void Tick(Actor self)
public virtual void Activate(Actor self, Order order) { }
public virtual IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
{
if (Info.OneShot && IsUsed)
return;
if (Info.GivenAuto)
IsAvailable = hasPrerequisites;
if (IsAvailable && (!Info.RequiresPower || PlayerPower.PowerState == PowerState.Normal))
{
if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Trait<DeveloperMode>().FastCharge) RemainingTime = 0;
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
Sound.PlayToPlayer(Owner, Info.BeginChargeSound);
OnBeginCharging();
notifiedCharging = true;
}
}
if (RemainingTime == 0
&& !notifiedReady)
{
Sound.PlayToPlayer(Owner, Info.EndChargeSound);
OnFinishCharging();
notifiedReady = true;
}
}
public void FinishActivate()
{
if (Info.OneShot)
{
IsUsed = true;
IsAvailable = false;
}
RemainingTime = TotalTime;
notifiedReady = false;
notifiedCharging = false;
}
public void Give(float charge)
{
IsAvailable = true;
IsUsed = false;
RemainingTime = (int)(charge * TotalTime);
}
protected virtual void OnBeginCharging() { }
protected virtual void OnFinishCharging() { }
protected virtual void OnActivate() { }
public void Activate()
{
if (!IsAvailable || !IsReady)
return;
if (Info.RequiresPower && PlayerPower.PowerState != PowerState.Normal)
{
var eva = Owner.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.AbilityInsufficientPower);
return;
}
Sound.PlayToPlayer(Owner, Info.SelectTargetSound);
OnActivate();
}
bool hasPrerequisites;
public void PrerequisitesAvailable(string key)
{
hasPrerequisites = true;
}
public void PrerequisitesUnavailable(string key)
{
hasPrerequisites = false;
Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound);
return new SelectGenericPowerTarget(order, manager, "ability", MouseButton.Left);
}
}
}

View File

@@ -0,0 +1,205 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see LICENSE.
*/
#endregion
using System.Linq;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
using System.Collections.Generic;
using OpenRA.Graphics;
namespace OpenRA.Mods.RA
{
public class SupportPowerManagerInfo : ITraitInfo, ITraitPrerequisite<DeveloperModeInfo>
{
public object Create(ActorInitializer init) { return new SupportPowerManager(init); }
}
public class SupportPowerManager : ITick, IResolveOrder
{
public readonly Actor self;
public Dictionary<string, SupportPowerInstance> Powers = new Dictionary<string, SupportPowerInstance>();
public readonly DeveloperMode devMode;
public SupportPowerManager(ActorInitializer init)
{
self = init.self;
devMode = init.self.Trait<DeveloperMode>();
init.world.ActorAdded += ActorAdded;
init.world.ActorRemoved += ActorRemoved;
}
void ActorAdded(Actor a)
{
if (a.Owner != self.Owner || !a.HasTrait<SupportPower>())
return;
foreach (var t in a.TraitsImplementing<SupportPower>())
{
var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName;
if (Powers.ContainsKey(key))
{
Powers[key].Instances.Add(t);
}
else
{
var si = new SupportPowerInstance(key, this)
{
Instances = new List<SupportPower>() { t },
RemainingTime = t.Info.ChargeTime * 25,
TotalTime = t.Info.ChargeTime * 25,
};
Powers.Add(key, si);
}
}
}
void ActorRemoved(Actor a)
{
if (a.Owner != self.Owner || !a.HasTrait<SupportPower>())
return;
foreach (var t in a.TraitsImplementing<SupportPower>())
{
var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName;
Powers[key].Instances.Remove(t);
if (Powers[key].Instances.Count == 0 && !Powers[key].Disabled)
Powers.Remove(key);
}
}
public void Tick(Actor self)
{
foreach(var power in Powers.Values)
power.Tick();
}
public void ResolveOrder(Actor self, Order order)
{
// order.OrderString is the key of the support power
if (Powers.ContainsKey(order.OrderString))
Powers[order.OrderString].Activate(order);
}
public void Target(string key)
{
if (Powers.ContainsKey(key))
Powers[key].Target();
}
public class SupportPowerInstance
{
readonly SupportPowerManager Manager;
readonly string Key;
public List<SupportPower> Instances;
public int RemainingTime;
public int TotalTime;
public bool Active { get; private set; }
public bool Disabled { get; private set; }
public SupportPowerInfo Info { get { return Instances.First().Info; } }
public bool Ready { get { return Active && RemainingTime == 0; } }
public SupportPowerInstance(string key, SupportPowerManager manager)
{
Manager = manager;
Key = key;
}
bool notifiedCharging;
bool notifiedReady;
public void Tick()
{
Active = !Disabled && Instances.Any(i => !i.self.TraitsImplementing<IDisable>().Any(d => d.Disabled));
if (Active)
{
var power = Instances.First();
if (Manager.devMode.FastCharge && RemainingTime > 25)
RemainingTime = 25;
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
power.Charging(power.self, Key);
notifiedCharging = true;
}
if (RemainingTime == 0
&& !notifiedReady)
{
power.Charged(power.self, Key);
notifiedReady = true;
}
}
}
public void Target()
{
if (!Ready)
return;
Manager.self.World.OrderGenerator = Instances.First().OrderGenerator(Key, Manager);
}
public void Activate(Order order)
{
if (!Ready)
return;
var power = Instances.First();
// Note: order.Subject is the *player* actor
power.Activate(power.self, order);
RemainingTime = TotalTime;
notifiedCharging = notifiedReady = false;
if (Info.OneShot)
Disabled = true;
}
}
}
public class SelectGenericPowerTarget : IOrderGenerator
{
readonly SupportPowerManager manager;
readonly string order;
readonly string cursor;
readonly MouseButton expectedButton;
public SelectGenericPowerTarget(string order, SupportPowerManager manager, string cursor, MouseButton button)
{
this.manager = manager;
this.order = order;
this.cursor = cursor;
expectedButton = button;
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
world.CancelInputMode();
if (mi.Button == expectedButton && world.Map.IsInMap(xy))
yield return new Order(order, manager.self, false) { TargetLocation = xy };
}
public virtual void Tick(World world)
{
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
public void RenderAfterWorld(WorldRenderer wr, World world) { }
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}
}

View File

@@ -10,10 +10,11 @@
using OpenRA.GameRules;
using OpenRA.Traits;
using OpenRA.Mods.RA.Render;
namespace OpenRA.Mods.RA
{
class TakeCoverInfo : TraitInfo<TakeCover> { }
class TakeCoverInfo : TraitInfo<TakeCover>, ITraitPrerequisite<RenderInfantryInfo> { }
// infantry prone behavior
class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier
@@ -29,17 +30,45 @@ namespace OpenRA.Mods.RA
public void Damaged(Actor self, AttackInfo e)
{
if (e.Damage > 0) /* fix to allow healing via `damage` */
if (e.Damage > 0) /* Don't go prone when healed */
{
if (e.Warhead == null || !e.Warhead.PreventProne)
remainingProneTime = defaultProneTime;
}
}
public void Tick(Actor self)
{
if (IsProne)
--remainingProneTime;
if (!IsProne)
return;
remainingProneTime--;
var ri = self.Trait<RenderInfantry>();
// Mobile.IsMoving isn't set to true until after the first move tick
// so we need a hack here to prevent a single frame of stand state
if (IsProne && (ri.State == RenderInfantry.AnimationState.Idle ||
ri.State == RenderInfantry.AnimationState.Waiting ||
ri.anim.CurrentSequence.Name == "stand"))
ri.anim.PlayFetchIndex("crawl", () => 0);
else if (!IsProne && (ri.State == RenderInfantry.AnimationState.Idle ||
ri.State == RenderInfantry.AnimationState.Waiting ||
ri.anim.CurrentSequence.Name == "stand"))
ri.anim.Play("stand");
if (ri.anim.CurrentSequence.Name == "run" && IsProne)
ri.anim.ReplaceAnim("crawl");
else if (ri.anim.CurrentSequence.Name == "crawl" && !IsProne)
ri.anim.ReplaceAnim("run");
if (ri.anim.CurrentSequence.Name == "shoot" && IsProne)
ri.anim.ReplaceAnim("prone-shoot");
else if (ri.anim.CurrentSequence.Name == "prone-shoot" && !IsProne)
ri.anim.ReplaceAnim("shoot");
}
public float GetDamageModifier(Actor attacker, WarheadInfo warhead )
{
return IsProne ? proneDamage : 1f;

View File

@@ -54,11 +54,11 @@ namespace OpenRA.Mods.RA.Widgets
{
this.world = world;
}
public override void Initialize()
{
base.Initialize();
cantBuild = new Animation("clock");
cantBuild.PlayFetchIndex("idle", () => 0);
ready = new Animation("pips");
@@ -66,12 +66,12 @@ namespace OpenRA.Mods.RA.Widgets
clock = new Animation("clock");
iconSprites = Rules.Info.Values
.Where(u => u.Traits.Contains<BuildableInfo>() && u.Name[0] != '^' )
.Where(u => u.Traits.Contains<BuildableInfo>() && u.Name[0] != '^')
.ToDictionary(
u => u.Name,
u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get<TooltipInfo>().Icon ?? (u.Name + "icon"))[0]);
IsVisible = () => { return CurrentQueue != null || (CurrentQueue == null && !paletteOpen); };
IsVisible = () => { return CurrentQueue != null || (CurrentQueue == null && !paletteOpen); };
}
public override Rectangle EventBounds

View File

@@ -7,6 +7,7 @@
* see LICENSE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -14,8 +15,9 @@ using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Network;
using OpenRA.Graphics;
using OpenRA.Widgets;
namespace OpenRA.Widgets.Delegates
namespace OpenRA.Mods.RA.Widgets.Delegates
{
public class LobbyDelegate : IWidgetDelegate
{

View File

@@ -21,14 +21,15 @@ namespace OpenRA.Mods.RA.Widgets.Delegates
static bool FirstInit = true;
[ObjectCreator.UseCtor]
public MainMenuButtonsDelegate( [ObjectCreator.Param] Widget widget )
public MainMenuButtonsDelegate([ObjectCreator.Param] Widget widget)
{
// Main menu is the default window
widget.GetWidget( "MAINMENU_BUTTON_JOIN" ).OnMouseUp = mi => { Widget.OpenWindow( "JOINSERVER_BG" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_CREATE" ).OnMouseUp = mi => { Widget.OpenWindow( "CREATESERVER_BG" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_SETTINGS" ).OnMouseUp = mi => { Widget.OpenWindow( "SETTINGS_MENU" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_MUSIC" ).OnMouseUp = mi => { Widget.OpenWindow( "MUSIC_MENU" ); return true; };
widget.GetWidget( "MAINMENU_BUTTON_QUIT" ).OnMouseUp = mi => { Game.Exit(); return true; };
widget.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi => { Widget.OpenWindow("JOINSERVER_BG"); return true; };
widget.GetWidget("MAINMENU_BUTTON_CREATE").OnMouseUp = mi => { Widget.OpenWindow("CREATESERVER_BG"); return true; };
widget.GetWidget("MAINMENU_BUTTON_SETTINGS").OnMouseUp = mi => { Widget.OpenWindow("SETTINGS_MENU"); return true; };
widget.GetWidget("MAINMENU_BUTTON_MUSIC").OnMouseUp = mi => { Widget.OpenWindow("MUSIC_MENU"); return true; };
widget.GetWidget("MAINMENU_BUTTON_REPLAY_VIEWER").OnMouseUp = mi => { Widget.OpenWindow("REPLAYBROWSER_BG"); return true; };
widget.GetWidget("MAINMENU_BUTTON_QUIT").OnMouseUp = mi => { Game.Exit(); return true; };
var version = widget.GetWidget<LabelWidget>("VERSION_STRING");

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