Compare commits
117 Commits
release-20
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3d71acb05 | ||
|
|
580f1cfe97 | ||
|
|
3d7434f42e | ||
|
|
ef96604f9e | ||
|
|
465f5d295b | ||
|
|
1feb377d43 | ||
|
|
a065fb464e | ||
|
|
e39917ca19 | ||
|
|
318f496bf9 | ||
|
|
ed8a155249 | ||
|
|
40ac5f7b6e | ||
|
|
517754027e | ||
|
|
ef4f478e10 | ||
|
|
92c30b89f8 | ||
|
|
7331a9c4fb | ||
|
|
d2b9e150f1 | ||
|
|
8ba329f1be | ||
|
|
8868eab247 | ||
|
|
f12889e684 | ||
|
|
5c095bc174 | ||
|
|
0c24a08436 | ||
|
|
9762b540b0 | ||
|
|
fd34f2ba99 | ||
|
|
ad6481c8e8 | ||
|
|
7426d47cd5 | ||
|
|
761f62292f | ||
|
|
63b8555bc9 | ||
|
|
3209da4a4a | ||
|
|
aebef4f1c8 | ||
|
|
d3244184c1 | ||
|
|
39e62354a8 | ||
|
|
f525c3808e | ||
|
|
87a0b52ce5 | ||
|
|
4bc9e01516 | ||
|
|
711d05da98 | ||
|
|
3d805ff40d | ||
|
|
0cd140849b | ||
|
|
d6110b9ef0 | ||
|
|
26d1db778e | ||
|
|
f41aa474aa | ||
|
|
0002e80a19 | ||
|
|
759a52d86e | ||
|
|
44fe0396bb | ||
|
|
dd6d8d916e | ||
|
|
5af8f5e2d9 | ||
|
|
c85503811c | ||
|
|
ab431fe9ee | ||
|
|
7ec9958d47 | ||
|
|
cfc74a6dee | ||
|
|
cecdd73e08 | ||
|
|
381e080b11 | ||
|
|
c6a047cb1a | ||
|
|
4c51733e04 | ||
|
|
8f613b80e8 | ||
|
|
10de282daa | ||
|
|
915e123956 | ||
|
|
8cb7a7b8ce | ||
|
|
ce5cf93077 | ||
|
|
1390bb7428 | ||
|
|
3c5b136216 | ||
|
|
66785e606a | ||
|
|
e2239fa50c | ||
|
|
7f7712aa64 | ||
|
|
b1605e115a | ||
|
|
69b2da86be | ||
|
|
18e965e5aa | ||
|
|
24f0c28f56 | ||
|
|
25af51b4ac | ||
|
|
ecd7064cc3 | ||
|
|
477a21e782 | ||
|
|
899d9af62b | ||
|
|
17eca983ef | ||
|
|
2fc219ecd5 | ||
|
|
49a645cd2d | ||
|
|
7cb8da411d | ||
|
|
4bcdf3cf11 | ||
|
|
1b525ff809 | ||
|
|
cdec3fce26 | ||
|
|
7bdf6a953f | ||
|
|
06b20c8ba5 | ||
|
|
9b484b53ec | ||
|
|
9620b4ed46 | ||
|
|
d8908c44d0 | ||
|
|
cfe705531a | ||
|
|
9a2fd38ab6 | ||
|
|
911e7f62de | ||
|
|
403b81bdc9 | ||
|
|
a0714b00b3 | ||
|
|
d5239ee77a | ||
|
|
03ec97f302 | ||
|
|
3255f95ee9 | ||
|
|
4c8fd5e73d | ||
|
|
7179ef0f45 | ||
|
|
6d5918b11d | ||
|
|
81c484d1c9 | ||
|
|
de1044c24c | ||
|
|
e4c31939d9 | ||
|
|
7f48d6796e | ||
|
|
4fd77aec8e | ||
|
|
92fece01de | ||
|
|
d8d987f844 | ||
|
|
de429a4c62 | ||
|
|
c0ca35a4ff | ||
|
|
1bff8559fb | ||
|
|
de98274165 | ||
|
|
59e2228b2a | ||
|
|
96d1408d45 | ||
|
|
ff45ae2d16 | ||
|
|
47950c9113 | ||
|
|
f402ec7898 | ||
|
|
a3c0448e15 | ||
|
|
699b4b1154 | ||
|
|
911db3feb1 | ||
|
|
c790db8e84 | ||
|
|
d6dd392028 | ||
|
|
636b2a8ea7 | ||
|
|
959d3f8bd7 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -12,20 +12,11 @@ mods/*/*.dll
|
||||
# Red Alert binary files
|
||||
mods/*/packages/*.[mM][iI][xX]
|
||||
|
||||
# Crap generated by OpenRa
|
||||
sheet-*.png
|
||||
log.txt
|
||||
|
||||
*.rep
|
||||
|
||||
#binary stuff
|
||||
/*.dll
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.exe
|
||||
OpenRA
|
||||
OpenRA.app
|
||||
*.vqa
|
||||
|
||||
# backup files by various editors
|
||||
*~
|
||||
@@ -33,10 +24,8 @@ OpenRA.app
|
||||
# dependency DLLs (different for every platform!)
|
||||
cg.dll
|
||||
cgGL.dll
|
||||
glfw.dll
|
||||
|
||||
/OpenRa.Gl.dll
|
||||
settings.ini
|
||||
|
||||
#monodevelop
|
||||
*.pidb
|
||||
|
||||
3
AUTHORS
3
AUTHORS
@@ -6,4 +6,5 @@ The OpenRA developers are:
|
||||
* Matthew Bowra-Dean
|
||||
* Paul Chote
|
||||
* Alli Witheford
|
||||
* Joakim Lindberg
|
||||
* Joakim Lindberg
|
||||
* Andrew Riedi
|
||||
|
||||
@@ -17,6 +17,7 @@ using OpenRA;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
@@ -401,7 +402,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
|
||||
new OwnerInit(parts[0]),
|
||||
new HealthInit(float.Parse(parts[2])/256),
|
||||
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
|
||||
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
|
||||
new ActorStanceInit(stance),
|
||||
};
|
||||
|
||||
19
OpenRA.Editor/MapSelect.Designer.cs
generated
19
OpenRA.Editor/MapSelect.Designer.cs
generated
@@ -52,11 +52,13 @@
|
||||
this.txtTitle = new System.Windows.Forms.TextBox();
|
||||
this.lblMapName = new System.Windows.Forms.Label();
|
||||
this.lblMinimap = new System.Windows.Forms.Label();
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbMinimap)).BeginInit();
|
||||
this.pnlBottom.SuspendLayout();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// MapList
|
||||
@@ -85,9 +87,9 @@
|
||||
//
|
||||
// MapIconsList
|
||||
//
|
||||
this.MapIconsList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("MapIconsList.ImageStream")));
|
||||
this.MapIconsList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
|
||||
this.MapIconsList.ImageSize = new System.Drawing.Size(24, 24);
|
||||
this.MapIconsList.TransparentColor = System.Drawing.Color.Transparent;
|
||||
this.MapIconsList.Images.SetKeyName(0, "mapicon");
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
@@ -141,6 +143,7 @@
|
||||
//
|
||||
// pnlBottom
|
||||
//
|
||||
this.pnlBottom.Controls.Add(this.pictureBox1);
|
||||
this.pnlBottom.Controls.Add(this.txtPathOut);
|
||||
this.pnlBottom.Controls.Add(this.lblPathOut);
|
||||
this.pnlBottom.Controls.Add(this.lblPath);
|
||||
@@ -301,6 +304,16 @@
|
||||
this.lblMinimap.TabIndex = 6;
|
||||
this.lblMinimap.Text = "Map preview:";
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
|
||||
this.pictureBox1.Location = new System.Drawing.Point(336, -9);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(54, 35);
|
||||
this.pictureBox1.TabIndex = 7;
|
||||
this.pictureBox1.TabStop = false;
|
||||
this.pictureBox1.Visible = false;
|
||||
//
|
||||
// MapSelect
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
@@ -327,6 +340,7 @@
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.PerformLayout();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@@ -356,5 +370,6 @@
|
||||
public System.Windows.Forms.Label lblPathOut;
|
||||
public System.Windows.Forms.Label lblPath;
|
||||
public System.Windows.Forms.TextBox txtPathOut;
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
@@ -19,11 +13,11 @@ namespace OpenRA.Editor
|
||||
public MapSelect()
|
||||
{
|
||||
InitializeComponent();
|
||||
MapIconsList.Images.Add(pictureBox1.Image);
|
||||
}
|
||||
|
||||
private void MapSelect_Load(object sender, EventArgs e)
|
||||
void MapSelect_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
DirectoryInfo directory = new DirectoryInfo(MapFolderPath);
|
||||
DirectoryInfo[] directories = directory.GetDirectories();
|
||||
MapList.Items.Clear();
|
||||
@@ -33,20 +27,14 @@ namespace OpenRA.Editor
|
||||
ListViewItem map1 = new ListViewItem(subDirectory.Name);
|
||||
map1.ImageIndex = 0;
|
||||
MapList.Items.Add(map1);
|
||||
|
||||
}
|
||||
if (txtNew.Text == "unnamed")
|
||||
{
|
||||
//dumb indian code
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// hack
|
||||
if (txtNew.Text != "unnamed")
|
||||
MapList.Items[0].Selected = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void MapList_SelectedIndexChanged(object sender, EventArgs e)
|
||||
void MapList_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (MapList.SelectedItems.Count == 1)
|
||||
{
|
||||
@@ -69,7 +57,7 @@ namespace OpenRA.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void txtPathOut_TextChanged(object sender, EventArgs e)
|
||||
void txtPathOut_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
MapFolderPath = txtPathOut.Text;
|
||||
}
|
||||
|
||||
@@ -120,73 +120,58 @@
|
||||
<metadata name="MapIconsList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<data name="MapIconsList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABW
|
||||
DgAAAk1TRnQBSQFMAwEBAAEoAQABKAEAARgBAAEYAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABYAMA
|
||||
ARgDAAEBAQABIAYAASQhAAEBAx8BLAM/AW8DSQGJAzYBWQMYASIDAQECDAADHQEqA0gBhQNCAXYDDwEU
|
||||
AwEBAgMNARIDMwFSA0MBdwNRAacDDwEU/wAwAAEBAwMBBAM0BFQBwgFlAVMBUgH0AV4CWAHYA0oBjQMW
|
||||
AR4DAgEDAwABAQMCAQMDGgElA00BlAEIAQkBJgH9A1ABpAM1AVcDQQFzA1MBugJDAVMB4wJTAVQBsgMA
|
||||
AQH/ADAAAQEDDAEQA0IBdAFVAVQBUQHYAZkBiAGBAf8BoAGMAYUB/wF8AXABZQH4AzoBYQMKAQ4DCgEN
|
||||
Ax0BKgM/AW0DVAG7ARkCGgH5AQABBQG/Af8BFwEbAUcB+QE5AUYBSwHrAQABBQFEAf8CCAFOAf0DDQER
|
||||
/wAxAAMDAQQDHQEpA1ABpAFdAVMBUQHtAZsBiwGDAf8BnAGMAYQB/wGWAYQBdwH/AVsBWgFYAdgDMwFT
|
||||
AzQBVANPAZ0CUwFSAdMCTAFOAfMBMAGeAbsB/wEUAXMBqwH/ARQBdQG/Af8BEAFmAbYB/wEXAY0BwgH/
|
||||
AUgBYQFpAeEDAQEC/wAwAAEBAwkBDAMwAUwBVgJVAcMBewFqAWAB+gGoAZkBjwH/AZMBhAF3Af8BjAF3
|
||||
AXAB/wGHAXEBbAH/A1YBvgNTAbwBTAFIAUYB5QF2AVsBUgH6AYMBbQFlAf8BUQFIAUcB/wEOAUsBpAH/
|
||||
AQMBGgG4Af8BDQFRAZUB/wEZAZUBwAH/AUABagGBAesDMwFSAw0BEgMCAQP/ACUAAwEBAgMYASEDSwGP
|
||||
A1EB3AGbAY4BhQH9AaEBkQGJAf8BhwFzAWsB/wGBAW4BZQH/AXUBZwFgAf8BUwFKAUMB/QFHAT4BOwH8
|
||||
AZYBhgF5Af8BowGSAYoB/wFTAUoBUwH/AQMBGAHzAf8BEgFgAaYB/wEVAXYBlQH/AS8B/QH+Af8BBwEy
|
||||
AZQB/wEVAXoByAH/AgABVAH/A00BlAMZASP/ACUAAwYBCAMtAUYDUwG8AWoBZQFiAfQBqgGbAZEB/wGJ
|
||||
AXQBbQH/AYwBdwFuAf8BmgGJAYEB/wGLAXcBbwH/AXUBZQFeAf8BhgFxAWkB/wGVAYYBegH/AUEBPAFK
|
||||
Af8BEwEfAYgB/wEKAREBrgH/ARwBegGVAf8BKgHfAeIB/wEOAVMBdwH/AQkBOQG8Af8BGQGBAaoB/wEK
|
||||
ARIBqQH/ASABJQFSAfcDUQGg/wAlAAMQARUDQQFyA08B1gGTAYQBcgH9AZoBiQGDAf8BjwGAAXMB/wGW
|
||||
AYYBeAH/AZ8BjQGEAf8BlgGFAXkB/wGUAYQBdwH/AZQBgwF3Af8BlwGHAYAB/wFqAV8BXAH/AWMBVwFW
|
||||
Af8BYAFVAVMB/wFTAVcBWAH/ASIBYwGaAf8BDQFLAZ0B/wEgAY4BsAH/AUwBnAGvAf8BaAGaAa4B/wE7
|
||||
AUsBWgH+A1ABn/8AJQADGAEiA00BlQF8AXUBbwH8AagBmAGOAf8BkQGBAXUB/wGNAXcBcAH/AZoBiQGB
|
||||
Af8BkwGDAXYB/wGZAYgBgQH/AZwBiwGDAf8BlQGGAXgB/wGWAYYBeQH/AaABjwGHAf8BlgGFAXgB/wF2
|
||||
AW8BbAH/AUwBbQGBAf8BHgE7AV0B/wEdAZ4BhAH/AVMBlwGpAf8BhgHFAd8B/wGIAb4B1wH/AUUBXwFi
|
||||
AfsDQQFz/wAlAAMYASIDTQGVAZ0BjwGGAf8BmwGLAYMB/wGGAXEBagH/AYUBbwFoAf8BiAFzAWwB/wGJ
|
||||
AXQBbAH/AZABdwFvAf8BlQGEAXcB/wGWAYUBeAH/AZ8BjwGGAf8BmQGLAYQB/wFtAYABhgH/AVYBkwGw
|
||||
Af8BWgGmAccB/wFMAYMBpAH/AQUBFgGgAf8BYwGaAbAB/wGCAb8B2QH/AXEBrQHIAf8BXQFpAXIB3gMq
|
||||
AUD/ACEAAwMBBAMmATgDUAGjAZoBjAGEAf8BpwGWAY4B/wGXAYYBegH/AZQBggF2Af8BlAGDAXcB/wGW
|
||||
AYUBeAH/AZIBeQFyAf8BjwF5AXIB/wGVAYQBeAH/AY8BdgFrAf8BcAGAAYcB/wFaAZcBswH/AU8BmgHC
|
||||
Af8BZQG1AdQB/wFlAaQBvgH/AR4BKgE1Af8BeAG6AdMB/wGAAbsB1QH/AYEBvwHaAf8BVQFWAVkBtQMP
|
||||
ART/ACEAAwoBDQNBAXMDUgHPAasBmgGRAf8BmgGJAYIB/wGOAXgBcQH/AZEBgQF1Af8BlQGEAXcB/wGY
|
||||
AYgBgAH/AYsBdQFuAf8BkQF6AXMB/wF4AW4BagH/AW8BrwHIAf8BWQGoAc0B/wFZAasBzAH/AVUBpgHJ
|
||||
Af8BdQHDAeAB/wF6AcIB3wH/AYMBwAHbAf8BggHBAd0B/wFvAa4ByAH/AYsBvwHbAf8DSAGGAwUBB/8A
|
||||
IQADHgErA1EBoAFSAVABTQHtAYMBbwFoAf8BgwFuAWcB/wGBAWwBZQH/AYEBbQFmAf8BiAFzAWsB/wGH
|
||||
AXIBawH/AZQBhAF4Af8BhQF2AXMB/wFUAWwBgwH/AU0BhAGmAf8BZgGwAdAB/wFdAaoBywH/AWEBsQHR
|
||||
Af8BdgG/Ad0B/wGFAcgB4wH/AYEBxAHfAf8BiAHHAeIB/wF3AbYB0QH/AW0BngG2Af8DPgFrAwIBA/8A
|
||||
IQADOAFcA1UByAFrAlwB+AGRAYABdAH/AZgBiAGAAf8BlQGEAXgB/wGNAXcBcAH/AZUBhAF4Af8BmAGH
|
||||
AYAB/wGTAYMBdwH/AWgBgAGLAf8BVgGQAbEB/wE3AUoBagH/AWMBqQHKAf8BYAGuAc8B/wFhAawBzAH/
|
||||
AXYBvwHcAf8BiQHMAecB/wGDAcYB4gH/AYUBxQHgAf8BhwHDAd4B/wFIAYMBmwH/AzwBaAMEAQX/ACEA
|
||||
A0kBiQFXAVYBVQHiAaQBkwGKAf8BrAGcAZMB/wGlAZUBjAH/AZYBhgF5Af8BkAF5AXQB/wGZAYgBgQH/
|
||||
AaIBkQGJAf8BbgFdAVUB/wFkAZUBqwH/AWgBtQHVAf8BcgHBAd0B/wF0AbsB2wH/AV4BrAHOAf8BXwGt
|
||||
AcwB/wF4AcMB4AH/AYgBywHmAf8BhQHGAeQB/wGDAcYB4gH/AYcBvwHdAf8BQwFVAWkB7gMbASb/ACUA
|
||||
A08BpQFiAlgB7wGjAZMBigH/AZgBhwGAAf8BnwGOAYYB/wGdAYwBhAH/AZABeQFzAf8BiAFyAWsB/wGI
|
||||
AXYBbwH/AWoBhQGPAf8BaAGwAdAB/wFvAbwB2gH/AWYBtgHWAf8BXwGxAdAB/wFdAa8B0AH/AXEBvQHa
|
||||
Af8BcAG7AdoB/wGAAcQB3wH/AY8BzQHpAf8BigHJAeUB/wFbAZcBrAH9A0QBeQMAAQH/ACUAA1MBsQFs
|
||||
Al8B8wGjAZIBigH/AZUBgwF4Af8BlAGCAXcB/wGUAYUBdwH/AYQBiwGNAf8BWwFzAYYB/wFcAYcBnQH/
|
||||
AWEBrwHSAf8BbwG7AdoB/wF3AcEB3gH/AWwBuQHXAf8BYQGzAdIB/wFpAbkB1gH/AYABxQHhAf8BeAHC
|
||||
Ad8B/wGAAcUB4QH/AYUBxAHhAf8BiQHGAeIB/wFSAXMBhAHzAzEBTv8AKQADUQHHAXsBcQFnAfgBqwGb
|
||||
AZIB/wGQAYABdQH/AYQBbwFmAf8BcgGaAasB/wFiAasBzwH/AWQBsgHTAf8BbQG8AdoB/wFrAbgB1QH/
|
||||
AXEBvgHbAf8BdgG/Ad0B/wFwAb4B2wH/AWgBuQHWAf8BgAHHAeEB/wGJAcsB5AH/AYoBzAHnAf8BjQHR
|
||||
AewB/wGFAckB5gH/AW0BswHUAf8DTgGYAzABTAMAAQEDAAEB/wAhAAM+AWwBYgFfAV4ByQGJAYIBfAH1
|
||||
AaQBkwGLAf8BhgGeAakB/wFnAa8B0gH/AXgBxAHgAf8BdgHCAd4B/wF2AcIB3gH/AXEBvwHbAf8BcwG8
|
||||
AdoB/wFyAbsB2AH/AXQBuwHZAf8BdAG/Ad0B/wFhAZ0BwwH/AUEBYwGUAf8BbQGnAcgB/wGHAcQB4AH/
|
||||
AYgBzQHpAf8BXwFxAXkB4AMsAUQDBwEJAwQBBgMAAQH/ACEAAwQBBQMZASMDNAFUA0oBiQFYAlsBwQFh
|
||||
AXIBeQHiAW4BlwGoAfUBfQG0Ac8B/gGAAcUB4gH/AXIBvAHaAf8BcQG8AdoB/wFwAbsB2AH/AXUBvAHZ
|
||||
Af8BjgHPAesB/wFtAa8B0gH/AU8BdQGkAf8BbAGrAc0B/wFuAa8BzwH/AY8BygHnAf8BWAFjAWYB0QMi
|
||||
ATH/AD0AAwEBAgMJAQwDGgElA0IBdgFSAVwBZQHqAYEBxAHgAf4BigHHAeQB/wF5AcAB3QH/AYoBxgHi
|
||||
Af8BlgHUAe4B/wF5AbgB1wH/AWEBoQHIAf8BaQGmAcwB/wFZAZIBvwH/AX8BwwHdAf4CRgFHAYEDAwEE
|
||||
/wBJAAMCAQMDEAEWAzIBUANKAY0DUAGdA1IBoQFmAXUBewHgAXIBrwHFAf0BYAGXAb4B/wFgAZQBwAH/
|
||||
AW8BqAHOAf8BQAF5AaoB/wM1AVYDAAEB/wBVAAMCAQMDBgEIAwoBDQMoAT0DQAFxAU8CUQGcAVsBYgFo
|
||||
AdYBZQF/AZMB8gFKAX0BoQH8AyABL/8AcAABAQMIAQsDJAE2A0YBgQMDAQT/ADEAAUIBTQE+BwABPgMA
|
||||
ASgDAAFgAwABGAMAAQEBAAEBBQABIAEBFgAD/wEAAeABOAEBCQABwAEAAQEJAAHAAQABAwkAAcABAAED
|
||||
CQABgAsAAYALAAGACwABgAsAAYALAAGAPQABAQsAAQELAAEDIwABBwkAAfABAAEHCQAB/gEAAQcJAAH/
|
||||
AcABDwkAAf8B/gEPCQAL
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAArjSURBVFhHrVcJUFRXFmVpkE0Wg0ZEMoIBl8RodGSMmVES
|
||||
R0NiChVxCyIIAmFfhe6maeh9AZodZHFpUFQWcQmKisiuLKLEKFFEcIuljtZMYmI5Uc/c14EZYyapmpq8
|
||||
qlP/9/+/373v3HPu+19P7/cf+jSlEWHCOEuzZfNn2Yvo3Pj3D/PTjCwYAwtgyeFwFk163Tos2tvtWJZw
|
||||
zeUjmYFP6vL9fhw31vRPI8/9LnmMrtCWZhtPcJ7hbC/W8DwfnS0LR0t5NKoFazHcqsaprE3YGbMQLrYW
|
||||
W/7fBAxogjGEd5wcXuPK4jxa60qD75VrfIbKMrYMD7VlPX/Ul49rp8RoyPbFIaEnhpuU6NRGoVa2HKuX
|
||||
zEj/X8vAVmlIsDY2Nna2sjBd+ee5b7Yq4tfgfm8a7pxNw60OFa6e4uFmhxr/uFSIexfz0VsZh7PaIJzb
|
||||
F42u8hAcV2/ANz3KF8Hub52kucb+Fv+jAccbm5quWOfxYX5y6Mcnq/IDh1oreX/vOcx9drdbjTudUgye
|
||||
Tsb1piT0H4/DACUw0JiEh33ZePhlFi7UxOCLtI1o2x6IW2cUqM/egLtdediV9MnjSTYm60bE+Ys8rMzN
|
||||
zd1c3/vLgVRV3lN1XjkqyzNoNaEUjIvrLXwMtQsw1JqEy/UxuHg0DJcp+KXj8bh0IobOucSGDA8vpqE6
|
||||
+VNINixBU0kQbp5JJ8jxDSXdeyAE5arlAxTZ/BfRra2tS8Tqwh9L9tQhq6gSabm7odLkoP8oF90V/rjR
|
||||
LsRgExc32oS40ZFCiQgw2Mgj+gW42pBI4OPSsUh6Jgn1mX4ojXJH865IXDzCx50uDe6fV+P8oQQ4Tx6r
|
||||
pOATmVteKgdjXu/Mhk1h328rO4TMwn3gp2YhmquEX7gAfYfjcb4qGH0HQ3D5WAiunU7ApfpofH0ymhIS
|
||||
UwkSqQRb6VoYvm6IZvXG7W4VBVbjwQU1/tanIQZkGDqtwOmSjzHXxXaLsZnZpy85QpdAnfunax/mllRD
|
||||
ma2FQJyHxORMJAqzwBVpUJgtRLF8E7bxlqKjzA991QEYaIijgFwMt6VggJK60hCFr46F4sqprbjbLaf6
|
||||
S0icIh1rwy1i3OvNQff+GEgj3r87/c1JLIGfjX1LP/F6KJDlIy1vN4SyQohVRdAU7IVIXQxuSiZ8/OOw
|
||||
JYyP8EiqfV04Lh2JoHIwMSbiwoFgtO1ah97aTSTMKGIjDl/WhONWl5jKlYrbZ9OJGRWVIg/+axf8SK5a
|
||||
8WoC5fPm//l2qqIIOaVVECm3QZG5C7L0HZCklYJLTCQKNUiWFYAnykJYRDRaywNxrTGRyhKNKyciiIEY
|
||||
dFd743z1ZioT6eJkHK41kXDbRFSKbHzTpcJwsxoHc71fTLGzyBix+L/zUFlaWX+VTcFZ4NzSamQXV1Lw
|
||||
EggkeeBRAsnSfKgyy6DKKcNnxEahIgRfHg5B/7EoDDYn4ma7FD0VAThfG4Cemi3EDI90IKWVq3GbHHKz
|
||||
nUpCbrh6QokEr5mPTEw4773MQij9aPZY5fNYrC6hEhRAnrkTjJEkcS5ieWokS/IhUZdCrtlJbGQiIjQQ
|
||||
/YeD0VMVhoTVbmgs8iVBctG11xtdlUHkDGpQpIN7velUAhmG2+W43spclI6K9JWY6TyxlGKOGxWjG53s
|
||||
5HBMBpZ7+iI6UY44vhoiVTH4ohxCLoTyArqu1OlBll6CZHE20mI9EOjuis3L5uFCbTh6D4Wgu8offYeC
|
||||
qSRccgcPD/qyMEiBb55VYahFgSuNckhjlr2YaGMqH2ntOiKmEAQGBgbnNviGPg2LFSM4UoiAUD78ghLo
|
||||
yEVojBhRiQqEx0nAI5sKiBH/z+OgVfuic7c/Lh+NwZndfughDfQdCtL1hKFmEW51ymn1EjpSAh1ytFCL
|
||||
Pl+nhKebY8XLTYn16DWEgzY2ttdzyI6yjB06+uP4acRANokvhzRRjBR5oe4aN4WupeYgNCIWZ2vj0b17
|
||||
I/UKf3Tt34jOis9otTyyILmkORUDTRKyqxj9DSI07Y0k26Yhes38Roo3YVQH7OVhGiGR0K7O0epEqCRB
|
||||
shKwRIQkQrZqMelAIM6ncihII9uQSCXZEi2HSMjDXvVqXKSGdTLbg6z6OVkwGcfLQvHB4jkYbJMS/UL0
|
||||
1aeSM6So1Hg/oljTR93AupEVYSXhGE+soZa8X+cIlgALzFhg5/HJ6YhIzACXVs9EKiHRMmckSfMQGx0G
|
||||
rXIldU4/dJSvJx3EoSDZC7OszHByTxTOfZGEq00y9B3lo70iElamhp4Ujy1eN8wIrEOd0BRW6DpiWEwq
|
||||
giKSdYiIl5IOUskRKh39AmKECZNP7Mg0O6Ci59Pzd4O/NQK7FBvQULyGOmMUpBsX4KqjGTL5qzHQIqJy
|
||||
iNG6Px5dtYlY7jqhmeKxvUE32C7FGKiP58uf5W6v0ekgPkmNrYIMor4YqcoinQBFdGQrl2ZsB4/cwBJR
|
||||
Zml/+k0sxcQnQZzgDWHIIni9NQHSHU5IS15EPSEN11ok6G9UQs1dh/lvv/GdkZHR3NEETOhkIUE7zvb1
|
||||
wRRFwYv0vD3UBTORJCEdSHMhydgFCXVHVnuWEGvZrDewjqmzKbHDNjHmFl5KBlasWokiFwtop5nhyL6p
|
||||
2JO/CN2HBdSgMpHJ88GH82c8s7b4T1vmUPA3CFxCp19QzBPdtpxdRqon2kkDKRSYXeOJcyBUFMI7IJ70
|
||||
kYsEgRLTXGbgrzNnwmWqC2Y4OsLZZjx43El4ggXI1zohy24MAFd4u9tj8YLpmD71DTiMtwGHY1A7ygB7
|
||||
52N29CLULV7qeT+HnFCoPairu87/RC9rTjE8JYJoY/p4lR8lVQAp7Rc+/pHY7OKE61NN8a21MbQpfwC+
|
||||
m4fbQ7MQNdcCfWMMsTPWDi2yyRgyNkDhOGPYGhpeo97jP5oAcwJjYQ4hk3DOyzvwn9v3HtUJjHXAzSFc
|
||||
RHHlCAznIyAsCZa2k56u3xT2gtHPmGHCdXtnHh47mKBqjS1K5Q7ITrCjlf8RqXPM0bDUCr3bp2C9nj70
|
||||
DDinKMYSwmujCbAjY4G9ZrN3tyMLP/D4IT1vP/J21CBeoKaa55MTUhAeK8J7i91v0DMdxqZmgw7Oc74N
|
||||
iFQ8T5YX6ZzisWI9Uiebo8rKCOcsjLAv1Z72BydUxE5ElcTuKf2P9RunEeGzmD8bTIzsI0I7wc7xdgyf
|
||||
NiayWVoueZ1qz7zPT8l5McnBqZieYZsYO/a4zF7yaKWP4HlASMKLj9xX4WrXWzhdMxUFlkaI1tPDAZE9
|
||||
Htc4wWuhOas5Y/oXgUezYDdZdmK2N6zzCfuB1V1GFkulNswT5cFllms73f+QMIWwjCDjGJnUW1rbfu2z
|
||||
wvXJk85pUH5gieNJdugvd8QV7RSc0TjgiMwevkvH3np1xa/+ZplZE9jecNh14UcPmO8VmnLyfzGr/feU
|
||||
mB/dY7VjybItdSZhrb6+fvEYY6PuMWOMn7ZbGeILfQNYmnN+mO1o/OBdCw74HAMsMjR8NjL/r+Yx+p3H
|
||||
XhjKZs93uxMZr4Z/uOb54qWf3bGf4pw3EpC1UPYsS3g0EU9K4uBsI86zYHPOY3MOp4zuRRLyDfT1O941
|
||||
Mrzvb86Bob4h+0r6zcEmdiFICA2vvT55kLFBYOJhnYt9or06TOmCJ7HTbGxgADpndmaJMU29QxAQKvTo
|
||||
vhnHkN1nX12/OlgCNoT3CZsIvgRWc9ao2IT/bTD3+BID7N1/zisBWCKOBB/CagKf8PboJP8CoUmu3yhA
|
||||
ga8AAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -439,10 +439,6 @@ namespace OpenRA.Editor
|
||||
float OffsetY = t.Centered ? t.Bitmap.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawY = TileSet.TileSize * p.Y * Zoom + Offset.Y - OffsetY;
|
||||
|
||||
float width = t.Bitmap.Width * Zoom;
|
||||
float height = t.Bitmap.Height * Zoom;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, t.Bitmap.Width, t.Bitmap.Height);
|
||||
RectangleF destRect = new RectangleF(DrawX, DrawY, width, height);
|
||||
g.DrawRectangle(CordonPen,
|
||||
DrawX, DrawY,
|
||||
t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
|
||||
|
||||
10
OpenRA.FileFormats/Exts.cs
Normal file → Executable file
10
OpenRA.FileFormats/Exts.cs
Normal file → Executable file
@@ -85,5 +85,15 @@ namespace OpenRA
|
||||
{
|
||||
return (T[])mi.GetCustomAttributes( typeof( T ), true );
|
||||
}
|
||||
|
||||
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
|
||||
{
|
||||
if (val.CompareTo(min) < 0)
|
||||
return min;
|
||||
else if (val.CompareTo(max) > 0)
|
||||
return max;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
OpenRA.FileFormats/FieldLoader.cs
Normal file → Executable file
12
OpenRA.FileFormats/FieldLoader.cs
Normal file → Executable file
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
@@ -99,7 +100,7 @@ namespace OpenRA.FileFormats
|
||||
else if (fieldType == typeof(float))
|
||||
{
|
||||
float res;
|
||||
if (float.TryParse(x.Replace("%",""), out res))
|
||||
if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res))
|
||||
return res * (x.Contains( '%' ) ? 0.01f : 1f);
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
@@ -111,9 +112,9 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
var parts = x.Split(',');
|
||||
if (parts.Length == 3)
|
||||
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
|
||||
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255));
|
||||
if (parts.Length == 4)
|
||||
return Color.FromArgb(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
|
||||
return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255));
|
||||
return InvalidValueAction(x,fieldType, field);
|
||||
}
|
||||
|
||||
@@ -263,7 +264,10 @@ namespace OpenRA.FileFormats
|
||||
if (f.FieldType == typeof(Color))
|
||||
{
|
||||
var c = (Color)v;
|
||||
return "{0},{1},{2},{3}".F(c.A,c.R,c.G,c.B);
|
||||
return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255),
|
||||
((int)c.R).Clamp(0, 255),
|
||||
((int)c.G).Clamp(0, 255),
|
||||
((int)c.B).Clamp(0, 255));
|
||||
}
|
||||
|
||||
return f.FieldType.IsArray
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
@@ -110,23 +110,6 @@ namespace OpenRA
|
||||
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
|
||||
}
|
||||
|
||||
public Order Order( int2 xy, MouseInput mi, Actor underCursor )
|
||||
{
|
||||
if (Owner != World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (Destroyed)
|
||||
return null;
|
||||
|
||||
return TraitsImplementing<IIssueOrder>()
|
||||
.OrderByDescending( x => x.OrderPriority( this, xy, mi, underCursor ) )
|
||||
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
|
||||
.FirstOrDefault( x => x != null );
|
||||
}
|
||||
|
||||
public RectangleF GetBounds(bool useAltitude)
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
|
||||
20
OpenRA.Game/Exts.cs
Normal file → Executable file
20
OpenRA.Game/Exts.cs
Normal file → Executable file
@@ -34,17 +34,17 @@ namespace OpenRA
|
||||
return xs.Aggregate(1f, (a, x) => a * x);
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
|
||||
where V : new()
|
||||
{
|
||||
return d.GetOrAdd( k, _ => new V() );
|
||||
return d.GetOrAdd(k, _ => new V());
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k, Func<K, V> createFn )
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
|
||||
{
|
||||
V ret;
|
||||
if( !d.TryGetValue( k, out ret ) )
|
||||
d.Add( k, ret = createFn( k ) );
|
||||
if (!d.TryGetValue(k, out ret))
|
||||
d.Add(k, ret = createFn(k));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -54,18 +54,18 @@ namespace OpenRA
|
||||
return xs[r.Next(xs.Length)];
|
||||
}
|
||||
|
||||
public static void DoTimed<T>( this IEnumerable<T> e, Action<T> a, string text, double time )
|
||||
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
||||
e.Do( x =>
|
||||
e.Do(x =>
|
||||
{
|
||||
var t = sw.ElapsedTime();
|
||||
a( x );
|
||||
a(x);
|
||||
var dt = sw.ElapsedTime() - t;
|
||||
if( dt > time )
|
||||
if (dt > time)
|
||||
Log.Write("perf", text, x, dt * 1000, Game.LocalTick);
|
||||
} );
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace OpenRA
|
||||
var map = modData.PrepareMap(uid);
|
||||
|
||||
viewport = new Viewport(new float2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
|
||||
world = new World(modData.Manifest, map);
|
||||
}
|
||||
|
||||
@@ -101,7 +100,7 @@ namespace OpenRA
|
||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
|
||||
|
||||
static void Tick()
|
||||
static void Tick( World world, OrderManager orderManager, Viewport viewPort )
|
||||
{
|
||||
if (orderManager.Connection.ConnectionState != lastConnectionState)
|
||||
{
|
||||
@@ -159,7 +158,7 @@ namespace OpenRA
|
||||
|
||||
internal static event Action LobbyInfoChanged = () => { };
|
||||
|
||||
internal static void SyncLobbyInfo(string data)
|
||||
internal static void SyncLobbyInfo( World world, string data)
|
||||
{
|
||||
LobbyInfo = Session.Deserialize(data);
|
||||
|
||||
@@ -179,13 +178,14 @@ namespace OpenRA
|
||||
LobbyInfoChanged();
|
||||
}
|
||||
|
||||
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
|
||||
public static void IssueOrder( Order o ) { orderManager.IssueOrder( o ); } /* avoid exposing the OM to mod code */
|
||||
|
||||
|
||||
public static event Action AfterGameStart = () => {};
|
||||
public static event Action BeforeGameStart = () => {};
|
||||
internal static void StartGame(string map)
|
||||
{
|
||||
world = null;
|
||||
BeforeGameStart();
|
||||
LoadMap(map);
|
||||
if (orderManager.GameStarted) return;
|
||||
@@ -200,23 +200,20 @@ namespace OpenRA
|
||||
|
||||
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
|
||||
{
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
int sync = world.SyncHash();
|
||||
var initialWorld = world;
|
||||
var world = Game.world;
|
||||
if (world == null) return;
|
||||
|
||||
var mi = new MouseInput
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Button = (MouseButton)(int)e.Button,
|
||||
Event = ev,
|
||||
Location = new int2(e.Location),
|
||||
Modifiers = modifierKeys,
|
||||
};
|
||||
Widget.HandleInput(world, mi);
|
||||
|
||||
if (sync != world.SyncHash() && world == initialWorld)
|
||||
throw new InvalidOperationException("Desync in DispatchMouseInput");
|
||||
var mi = new MouseInput
|
||||
{
|
||||
Button = (MouseButton)(int)e.Button,
|
||||
Event = ev,
|
||||
Location = new int2( e.Location ),
|
||||
Modifiers = modifierKeys,
|
||||
};
|
||||
Widget.HandleInput( world, mi );
|
||||
} );
|
||||
}
|
||||
|
||||
public static bool IsHost
|
||||
@@ -231,16 +228,13 @@ namespace OpenRA
|
||||
|
||||
public static void HandleKeyEvent(KeyInput e)
|
||||
{
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
int sync = world.SyncHash();
|
||||
|
||||
if (Widget.HandleKeyPress(e))
|
||||
return;
|
||||
var world = Game.world;
|
||||
if( world == null ) return;
|
||||
|
||||
if (sync != Game.world.SyncHash())
|
||||
throw new InvalidOperationException("Desync in OnKeyPress");
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Widget.HandleKeyPress( e );
|
||||
} );
|
||||
}
|
||||
|
||||
static Modifiers modifiers;
|
||||
@@ -257,6 +251,12 @@ namespace OpenRA
|
||||
SupportDir = args.GetValue("SupportDir", defaultSupport);
|
||||
Settings = new Settings(SupportDir + "settings.yaml", args);
|
||||
|
||||
// force master server upgrade -- remove once everyone is switched over.
|
||||
if (Settings.Server.MasterServer == "http://open-ra.org/master/")
|
||||
Settings.Server.MasterServer = "http://master.open-ra.org/";
|
||||
|
||||
Settings.Save();
|
||||
|
||||
Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar;
|
||||
Log.AddChannel("perf", "perf.log");
|
||||
Log.AddChannel("debug", "debug.log");
|
||||
@@ -267,7 +267,14 @@ namespace OpenRA
|
||||
Renderer.SheetSize = Settings.Game.SheetSize;
|
||||
Renderer = new Renderer();
|
||||
|
||||
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods;
|
||||
Console.WriteLine("Available mods:");
|
||||
foreach(var mod in ModData.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
|
||||
// Discard any invalid mods
|
||||
LobbyInfo.GlobalSettings.Mods = Settings.Game.Mods.Where(m => ModData.AllMods.ContainsKey(m)).ToArray();
|
||||
Console.WriteLine("Loading mods: {0}",string.Join(",",LobbyInfo.GlobalSettings.Mods));
|
||||
|
||||
modData = new ModData( LobbyInfo.GlobalSettings.Mods );
|
||||
|
||||
Sound.Initialize();
|
||||
@@ -317,7 +324,7 @@ namespace OpenRA
|
||||
internal static void Run()
|
||||
{
|
||||
while (!quit)
|
||||
{
|
||||
{
|
||||
Tick( world, orderManager, viewport );
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.GameRules
|
||||
public int ListenPort = 1234;
|
||||
public int ExternalPort = 1234;
|
||||
public bool AdvertiseOnline = true;
|
||||
public string MasterServer = "http://open-ra.org/master/";
|
||||
public string MasterServer = "http://master.open-ra.org/";
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace OpenRA.GameRules
|
||||
// Behaviour settings
|
||||
public bool ViewportEdgeScroll = true;
|
||||
public bool InverseDragScroll = false;
|
||||
public float ViewportEdgeScrollStep = 10f;
|
||||
|
||||
// Internal game settings
|
||||
public int Timestep = 40;
|
||||
@@ -106,12 +107,12 @@ namespace OpenRA.GameRules
|
||||
|
||||
FieldLoader.UnknownFieldAction = (s,f) =>
|
||||
{
|
||||
System.Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
|
||||
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
|
||||
};
|
||||
|
||||
if (File.Exists(SettingsFile))
|
||||
{
|
||||
System.Console.WriteLine("Loading settings file {0}",SettingsFile);
|
||||
Console.WriteLine("Loading settings file {0}",SettingsFile);
|
||||
var yaml = MiniYaml.DictFromFile(SettingsFile);
|
||||
|
||||
foreach (var kv in Sections)
|
||||
@@ -123,7 +124,7 @@ namespace OpenRA.GameRules
|
||||
foreach (var kv in Sections)
|
||||
foreach (var f in kv.Value.GetType().GetFields())
|
||||
if (args.Contains(kv.Key+"."+f.Name))
|
||||
OpenRA.FileFormats.FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
|
||||
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
|
||||
|
||||
FieldLoader.UnknownFieldAction = err1;
|
||||
FieldLoader.InvalidValueAction = err2;
|
||||
@@ -133,16 +134,11 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
foreach( var kv in Sections )
|
||||
root.Add( new MiniYamlNode( kv.Key, SectionYaml( kv.Value ) ) );
|
||||
root.Add( new MiniYamlNode( kv.Key, FieldSaver.Save(kv.Value) ) );
|
||||
|
||||
root.WriteToFile(SettingsFile);
|
||||
}
|
||||
|
||||
MiniYaml SectionYaml(object section)
|
||||
{
|
||||
return FieldSaver.SaveDifferences(section, Activator.CreateInstance(section.GetType()));
|
||||
}
|
||||
|
||||
void LoadSectionYaml(MiniYaml yaml, object section)
|
||||
{
|
||||
object defaults = Activator.CreateInstance(section.GetType());
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.GameRules
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public readonly Lazy<Dictionary<string, VoicePool>> Pools;
|
||||
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
|
||||
|
||||
public VoiceInfo( MiniYaml y )
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace OpenRA.GameRules
|
||||
[FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal
|
||||
[FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model)
|
||||
[FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use
|
||||
[FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry.
|
||||
|
||||
public float EffectivenessAgainst(Actor self)
|
||||
{
|
||||
@@ -92,6 +93,7 @@ namespace OpenRA.GameRules
|
||||
[FieldLoader.Load] public readonly bool Underwater = false;
|
||||
[FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" };
|
||||
[FieldLoader.Load] public readonly int BurstDelay = 5;
|
||||
[FieldLoader.Load] public readonly float MinRange = 0;
|
||||
|
||||
[FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile;
|
||||
[FieldLoader.LoadUsing( "LoadWarheads" )] public List<WarheadInfo> Warheads;
|
||||
|
||||
@@ -80,17 +80,20 @@ namespace OpenRA.Graphics
|
||||
GlyphInfo CreateGlyph(Pair<char,Color> c)
|
||||
{
|
||||
var index = FT.FT_Get_Char_Index(face, (uint)c.First);
|
||||
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
|
||||
if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER))
|
||||
throw new InvalidOperationException( "FT_Load_Glyph failed." );
|
||||
|
||||
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
|
||||
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
|
||||
|
||||
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
|
||||
var s = builder.Allocate(
|
||||
new Size(_glyph.metrics.width.ToInt32() >> 6,
|
||||
_glyph.metrics.height.ToInt32() >> 6));
|
||||
|
||||
var g = new GlyphInfo
|
||||
{
|
||||
Sprite = s,
|
||||
Advance = _glyph.metrics.horiAdvance / 64f,
|
||||
Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f,
|
||||
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
|
||||
};
|
||||
|
||||
|
||||
@@ -97,8 +97,8 @@ namespace OpenRA.Graphics
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderBeforeWorld(world);
|
||||
|
||||
foreach (var image in worldSprites)
|
||||
image.Sprite.DrawAt(image.Pos, image.Palette);
|
||||
foreach( var image in worldSprites )
|
||||
image.Sprite.DrawAt( image.Pos, this.GetPaletteIndex( image.Palette ) );
|
||||
uiOverlay.Draw(world);
|
||||
|
||||
if (world.OrderGenerator != null)
|
||||
|
||||
@@ -19,6 +19,35 @@ namespace OpenRA
|
||||
{
|
||||
public class ModData
|
||||
{
|
||||
public static readonly Dictionary<string,Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public static Dictionary<string,Mod> ValidateMods(string[] mods)
|
||||
{
|
||||
var ret = new Dictionary<string,Mod>();
|
||||
foreach (var m in mods)
|
||||
{
|
||||
if (!File.Exists("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"))
|
||||
continue;
|
||||
|
||||
var yaml = new MiniYaml( null, MiniYaml.FromFile("mods" + Path.DirectorySeparatorChar + m + Path.DirectorySeparatorChar + "mod.yaml"));
|
||||
if (!yaml.NodesDict.ContainsKey("Metadata"))
|
||||
{
|
||||
System.Console.WriteLine("Invalid mod: "+m);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret.Add(m,FieldLoader.Load<Mod>(yaml.NodesDict["Metadata"]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class Mod
|
||||
{
|
||||
public string Title;
|
||||
public string Description;
|
||||
public string Version;
|
||||
}
|
||||
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
@@ -28,7 +57,7 @@ namespace OpenRA
|
||||
public ILoadScreen LoadScreen = null;
|
||||
|
||||
public ModData( params string[] mods )
|
||||
{
|
||||
{
|
||||
Manifest = new Manifest( mods );
|
||||
ObjectCreator = new ObjectCreator( Manifest );
|
||||
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
|
||||
|
||||
@@ -187,9 +187,9 @@ namespace OpenRA
|
||||
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item);
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item)
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, item);
|
||||
return new Order("CancelProduction", subject, new int2( count, 0 ), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ namespace OpenRA.Network
|
||||
return Game.LobbyInfo.Clients.FirstOrDefault(c => c.Index == id);
|
||||
}
|
||||
|
||||
static Player FindPlayerByClientId(int id)
|
||||
static Player FindPlayerByClientId( this World world, int id)
|
||||
{
|
||||
/* todo: find the interactive player. */
|
||||
return Game.world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
|
||||
return world.players.Values.FirstOrDefault(p => p.ClientIndex == id);
|
||||
}
|
||||
|
||||
public static void ProcessOrder( World world, int clientId, Order order )
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Network
|
||||
var client = FindClientById(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = FindPlayerByClientId(clientId);
|
||||
var player = world.FindPlayerByClientId(clientId);
|
||||
if (player != null && player.WinState == WinState.Lost)
|
||||
Game.AddChatLine(client.Color1, client.Name + " (Dead)", order.TargetString);
|
||||
else
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.Network
|
||||
var client = FindClientById(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = FindPlayerByClientId(clientId);
|
||||
var player = world.FindPlayerByClientId(clientId);
|
||||
var display = (world.GameHasStarted) ?
|
||||
player != null && (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost) :
|
||||
@@ -78,7 +78,7 @@ namespace OpenRA.Network
|
||||
}
|
||||
case "SyncInfo":
|
||||
{
|
||||
Game.SyncLobbyInfo(order.TargetString);
|
||||
Game.SyncLobbyInfo( world, order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "SetStance":
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
@@ -230,6 +230,7 @@
|
||||
<Compile Include="Traits\Valued.cs" />
|
||||
<Compile Include="Traits\World\BibLayer.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
<Compile Include="Widgets\ScrollingTextWidget.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
|
||||
@@ -35,8 +35,11 @@ namespace OpenRA.Orders
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left && world.Map.IsInMap(xy))
|
||||
yield return new Order(order, subject, xy);
|
||||
if( mi.Button == MouseButton.Left && world.Map.IsInMap( xy ) )
|
||||
{
|
||||
world.CancelInputMode();
|
||||
yield return new Order( order, subject, xy );
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Tick(World world) { }
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
{
|
||||
@@ -25,17 +26,17 @@ namespace OpenRA.Orders
|
||||
.FirstOrDefault();
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => a.Order(xy, mi, underCursor))
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
var actorsInvolved = orders.Select(o => o.Subject).Distinct();
|
||||
var actorsInvolved = orders.Select(o => o.self).Distinct();
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return o;
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()));
|
||||
|
||||
foreach( var o in orders )
|
||||
yield return CheckSameOrder( o.iot, o.trait.IssueOrder( o.self, o.iot, o.target ) );
|
||||
}
|
||||
|
||||
public void Tick( World world ) {}
|
||||
@@ -45,39 +46,107 @@ namespace OpenRA.Orders
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPreRenderSelection>())
|
||||
t.RenderBeforeWorld(a);
|
||||
|
||||
t.RenderBeforeWorld(a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld( World world )
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(a);
|
||||
t.RenderAfterWorld(a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
|
||||
{
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<SelectableInfo>())
|
||||
.Any();
|
||||
|
||||
if (underCursor)
|
||||
return "select";
|
||||
}
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.Info.Traits.Contains<TargetableInfo>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
var c = Order(world, xy, mi)
|
||||
.Select(o => o.Subject.TraitsImplementing<IOrderCursor>()
|
||||
.Select(pc => pc.CursorForOrder(o.Subject, o)).FirstOrDefault(a => a != null))
|
||||
.FirstOrDefault(a => a != null);
|
||||
|
||||
return c ?? "default";
|
||||
if( mi.Modifiers.HasModifier( Modifiers.Shift ) || !world.Selection.Actors.Any() )
|
||||
if( underCursor != null )
|
||||
return "select";
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
if( orders.Length == 0 ) return "default";
|
||||
|
||||
return orders[ 0 ].cursor ?? "default";
|
||||
}
|
||||
|
||||
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!self.World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (self.Destroyed)
|
||||
return null;
|
||||
|
||||
//var old = self.TraitsImplementing<IIssueOrder>()
|
||||
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
|
||||
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
|
||||
// .FirstOrDefault( x => x != null );
|
||||
//if( old != null )
|
||||
// return old;
|
||||
|
||||
if( mi.Button == MouseButton.Right )
|
||||
{
|
||||
var uim = self.World.WorldActor.Trait<UnitInfluence>();
|
||||
foreach( var o in self.TraitsImplementing<IIssueOrder>()
|
||||
.SelectMany( trait => trait.Orders
|
||||
.Select( x => new { Trait = trait, Order = x } ) )
|
||||
.OrderByDescending( x => x.Order.OrderPriority ) )
|
||||
{
|
||||
var actorsAt = uim.GetUnitsAt( xy ).ToList();
|
||||
|
||||
string cursor = null;
|
||||
if( underCursor != null )
|
||||
if( o.Order.CanTargetUnit( self, underCursor, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
|
||||
if( o.Order.CanTargetLocation( self, xy, actorsAt, mi.Modifiers.HasModifier( Modifiers.Ctrl ), mi.Modifiers.HasModifier( Modifiers.Alt ), ref cursor ) )
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Order CheckSameOrder( IOrderTargeter iot, Order order )
|
||||
{
|
||||
if( order == null && iot.OrderID != null )
|
||||
Game.Debug( "BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID );
|
||||
else if( iot.OrderID != order.OrderString )
|
||||
Game.Debug( "BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString );
|
||||
return order;
|
||||
}
|
||||
|
||||
class UnitOrderResult
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly IOrderTargeter iot;
|
||||
public readonly IIssueOrder trait;
|
||||
public readonly string cursor;
|
||||
public readonly Target target;
|
||||
|
||||
public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target )
|
||||
{
|
||||
this.self = self;
|
||||
this.iot = iot;
|
||||
this.trait = trait;
|
||||
this.cursor = cursor;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace OpenRA
|
||||
public readonly int Index;
|
||||
public readonly bool NonCombatant = false;
|
||||
public readonly int ClientIndex;
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public World World { get; private set; }
|
||||
@@ -49,6 +50,7 @@ namespace OpenRA
|
||||
|
||||
Index = index;
|
||||
Palette = "player"+index;
|
||||
|
||||
Color = pr.Color;
|
||||
Color2 = pr.Color2;
|
||||
ClientIndex = 0; /* it's a map player, "owned" by host */
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA
|
||||
else
|
||||
actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList();
|
||||
|
||||
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.HasVoice());
|
||||
var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoice());
|
||||
if (voicedUnit != null)
|
||||
Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race);
|
||||
|
||||
@@ -56,6 +56,10 @@ namespace OpenRA
|
||||
public void Tick(World world)
|
||||
{
|
||||
actors.RemoveAll(a => !a.IsInWorld);
|
||||
|
||||
foreach (var cg in controlGroups.Values)
|
||||
cg.RemoveAll(a => a.Destroyed); // note: NOT `!a.IsInWorld`, since that would remove things
|
||||
// that are in transports.
|
||||
}
|
||||
|
||||
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
|
||||
|
||||
1
OpenRA.Game/Server/Exts.cs
Normal file → Executable file
1
OpenRA.Game/Server/Exts.cs
Normal file → Executable file
@@ -11,6 +11,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
|
||||
60
OpenRA.Game/Server/MasterServerQuery.cs
Normal file → Executable file
60
OpenRA.Game/Server/MasterServerQuery.cs
Normal file → Executable file
@@ -14,15 +14,20 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
static class MasterServerQuery
|
||||
{
|
||||
public static event Action<GameServer[]> OnComplete = _ => { };
|
||||
public static event Action<string> OnVersion = _ => { };
|
||||
|
||||
static GameServer[] Games = { };
|
||||
public static string ClientVersion = "";
|
||||
public static string ServerVersion = "";
|
||||
static AutoResetEvent ev = new AutoResetEvent(false);
|
||||
static AutoResetEvent ev2 = new AutoResetEvent(false);
|
||||
|
||||
public static void Refresh(string masterServerUrl)
|
||||
{
|
||||
@@ -30,9 +35,7 @@ namespace OpenRA.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
var wc = new WebClient();
|
||||
var data = wc.DownloadData(new Uri(masterServerUrl + "list.php"));
|
||||
var str = Encoding.UTF8.GetString(data);
|
||||
var str = GetData(new Uri(masterServerUrl + "list.php"));
|
||||
|
||||
var yaml = MiniYaml.FromString(str);
|
||||
|
||||
@@ -48,10 +51,61 @@ namespace OpenRA.Server
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public static void GetMOTD(string masterServerUrl)
|
||||
{
|
||||
var motd = Widget.RootWidget.GetWidget<ScrollingTextWidget>("MOTD_SCROLLER");
|
||||
|
||||
// Runs in a separate thread to prevent dns lookup hitches
|
||||
new Thread(() =>
|
||||
{
|
||||
if (motd != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
motd.SetText(GetData(new Uri(masterServerUrl + "motd.php?v=" + ClientVersion)));
|
||||
motd.ResetScroll();
|
||||
}
|
||||
catch
|
||||
{
|
||||
motd.SetText("Welcome to OpenRA. MOTD unable to be loaded from server.");
|
||||
motd.ResetScroll();
|
||||
}
|
||||
}
|
||||
|
||||
ev.Set();
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public static void Tick()
|
||||
{
|
||||
if (ev.WaitOne(TimeSpan.FromMilliseconds(0)))
|
||||
OnComplete(Games);
|
||||
if (ev2.WaitOne(TimeSpan.FromMilliseconds(0)))
|
||||
OnVersion(ServerVersion);
|
||||
}
|
||||
|
||||
static string GetData(Uri uri)
|
||||
{
|
||||
var wc = new WebClient();
|
||||
var data = wc.DownloadData(uri);
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public static void GetCurrentVersion(string masterServerUrl)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerVersion = GetData(new Uri(masterServerUrl + "VERSION"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
ServerVersion = "";
|
||||
}
|
||||
|
||||
ev2.Set();
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,8 @@ namespace OpenRA.Server
|
||||
|
||||
static int ChooseFreeSlot()
|
||||
{
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null).Index;
|
||||
return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null
|
||||
&& !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index;
|
||||
}
|
||||
|
||||
static void AcceptConnection()
|
||||
@@ -588,8 +589,9 @@ namespace OpenRA.Server
|
||||
|
||||
static void SyncLobbyInfo()
|
||||
{
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
|
||||
PingMasterServer();
|
||||
}
|
||||
|
||||
@@ -129,5 +129,34 @@ namespace OpenRA
|
||||
return p.Index * 0x567;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void CheckSyncUnchanged( World world, Action fn )
|
||||
{
|
||||
CheckSyncUnchanged( world, () => { fn(); return true; } );
|
||||
}
|
||||
|
||||
static bool inUnsyncedCode = false;
|
||||
|
||||
public static T CheckSyncUnchanged<T>( World world, Func<T> fn )
|
||||
{
|
||||
int sync = world.SyncHash();
|
||||
inUnsyncedCode = true;
|
||||
try
|
||||
{
|
||||
return fn();
|
||||
}
|
||||
finally
|
||||
{
|
||||
inUnsyncedCode = false;
|
||||
if( sync != world.SyncHash() )
|
||||
throw new InvalidOperationException( "Desync in DispatchMouseInput" );
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertUnsynced( string message )
|
||||
{
|
||||
if( !inUnsyncedCode )
|
||||
throw new InvalidOperationException( message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
class Idle : CancelableActivity
|
||||
public class Idle : CancelableActivity
|
||||
{
|
||||
public override IActivity Tick(Actor self) { return NextActivity; }
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace OpenRA.Traits
|
||||
if ((lifetime <= 0 || --lifetime <= 0) && !force)
|
||||
return;
|
||||
|
||||
if (!target.IsValid)
|
||||
return;
|
||||
|
||||
var p = target.CenterLocation;
|
||||
|
||||
Game.Renderer.LineRenderer.DrawLine(self.CenterLocation, p, c, c);
|
||||
|
||||
6
OpenRA.Game/Traits/Health.cs
Normal file → Executable file
6
OpenRA.Game/Traits/Health.cs
Normal file → Executable file
@@ -140,6 +140,8 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public static bool IsDead(this Actor self)
|
||||
{
|
||||
if (self.Destroyed) return true;
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
return (health == null) ? true : health.IsDead;
|
||||
}
|
||||
@@ -161,7 +163,9 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (health == null) return;
|
||||
health.InflictDamage(self, attacker, health.HP, null);
|
||||
|
||||
/* hack. Fix for proper */
|
||||
health.InflictDamage(self, attacker, int.MaxValue, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using OpenRA.Effects;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Diagnostics;
|
||||
using OpenRA.Orders;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -53,7 +54,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, INudge
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly MobileInfo Info;
|
||||
@@ -131,21 +132,17 @@ namespace OpenRA.Traits
|
||||
self.CenterLocation = Util.CenterOfCell(fromCell);
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
// Force move takes precedence
|
||||
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
|
||||
}
|
||||
|
||||
// Note: Returns a valid order even if the unit can't move to the target
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (Info.OnRails) return null;
|
||||
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter( Info ); } }
|
||||
|
||||
var type = (!self.World.LocalPlayer.Shroud.IsVisible(xy) || CanEnterCell(xy)) ? "Move" : "Move-Blocked";
|
||||
return new Order(type, self, xy, mi.Modifiers.HasModifier(Modifiers.Shift));
|
||||
// Note: Returns a valid order even if the unit can't move to the target
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order is MoveOrderTargeter )
|
||||
{
|
||||
if( Info.OnRails ) return null;
|
||||
return new Order( "Move", self, Util.CellContaining( target.CenterLocation ), false );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int2 NearestMoveableCell(int2 target)
|
||||
@@ -170,7 +167,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
|
||||
if (order.OrderString == "Move")
|
||||
{
|
||||
int2 currentLocation = NearestMoveableCell(order.TargetLocation);
|
||||
if (!CanEnterCell(currentLocation))
|
||||
@@ -190,20 +187,9 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move")
|
||||
return "move";
|
||||
|
||||
if (order.OrderString == "Move-Blocked")
|
||||
return "move-blocked";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move" || order.OrderString == "Move-Blocked")
|
||||
if (order.OrderString == "Move")
|
||||
return "Move";
|
||||
return null;
|
||||
}
|
||||
@@ -369,5 +355,31 @@ namespace OpenRA.Traits
|
||||
Log.Write("debug", "OnNudge #{0} refuses at {1}",
|
||||
self.ActorID, self.Location);
|
||||
}
|
||||
|
||||
class MoveOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly MobileInfo unitType;
|
||||
|
||||
public MoveOrderTargeter( MobileInfo unitType )
|
||||
{
|
||||
this.unitType = unitType;
|
||||
}
|
||||
|
||||
public string OrderID { get { return "Move"; } }
|
||||
public int OrderPriority { get { return 4; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = "move";
|
||||
if( self.World.LocalPlayer.Shroud.IsVisible( location ) && !self.Trait<Mobile>().CanEnterCell( location ) )
|
||||
cursor = "move-blocked";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,10 +67,10 @@ namespace OpenRA.Traits
|
||||
break;
|
||||
}
|
||||
case "DevShroud":
|
||||
{
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
Game.world.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
self.World.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
break;
|
||||
}
|
||||
case "DevPathDebug":
|
||||
@@ -83,17 +83,17 @@ namespace OpenRA.Traits
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
Game.Settings.Debug.ShowCollisions ^= true;
|
||||
break;
|
||||
}
|
||||
case "DevGiveExploration":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case "DevGiveExploration":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Game.Debug("Cheat used: {0} by {1}"
|
||||
.F(order.OrderString, self.Owner.PlayerName));
|
||||
}
|
||||
|
||||
@@ -61,9 +61,10 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawHealthBar(Actor self, float2 xy, float2 Xy)
|
||||
{
|
||||
if (!self.IsInWorld) return;
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (self.IsDead() || health == null)
|
||||
return;
|
||||
if (health == null || health.IsDead) return;
|
||||
|
||||
var c = Color.Gray;
|
||||
Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
|
||||
@@ -158,7 +159,7 @@ namespace OpenRA.Traits
|
||||
|
||||
void DrawUnitPath(Actor self)
|
||||
{
|
||||
if (!Game.world.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
|
||||
|
||||
var activity = self.GetCurrentActivity();
|
||||
var mobile = self.TraitOrDefault<IMove>();
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace OpenRA.Traits
|
||||
public class TargetableInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] TargetTypes = {};
|
||||
public object Create( ActorInitializer init ) { return new Targetable(this); }
|
||||
public virtual object Create( ActorInitializer init ) { return new Targetable(this); }
|
||||
}
|
||||
|
||||
public class Targetable : ITargetable
|
||||
|
||||
@@ -35,8 +35,15 @@ namespace OpenRA.Traits
|
||||
public interface IRender { IEnumerable<Renderable> Render(Actor self); }
|
||||
public interface IIssueOrder
|
||||
{
|
||||
Order IssueOrder( Actor self, int2 xy, MouseInput mi, Actor underCursor );
|
||||
int OrderPriority( Actor self, int2 xy, MouseInput mi, Actor underCursor );
|
||||
IEnumerable<IOrderTargeter> Orders { get; }
|
||||
Order IssueOrder( Actor self, IOrderTargeter order, Target target );
|
||||
}
|
||||
public interface IOrderTargeter
|
||||
{
|
||||
string OrderID { get; }
|
||||
int OrderPriority { get; }
|
||||
bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor );
|
||||
bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor );
|
||||
}
|
||||
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
|
||||
public interface IOrderCursor { string CursorForOrder(Actor self, Order order); }
|
||||
|
||||
202
OpenRA.Game/Widgets/Delegates/LobbyDelegate.cs
Normal file → Executable file
202
OpenRA.Game/Widgets/Delegates/LobbyDelegate.cs
Normal file → Executable file
@@ -12,7 +12,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
|
||||
Dictionary<string, string> CountryNames;
|
||||
string MapUid;
|
||||
MapStub Map;
|
||||
MapStub Map;
|
||||
|
||||
public static Color CurrentColorPreview1;
|
||||
public static Color CurrentColorPreview2;
|
||||
@@ -133,74 +133,74 @@ namespace OpenRA.Widgets.Delegates
|
||||
teamChat ^= true;
|
||||
chatLabel.Text = (teamChat) ? "Team:" : "Chat:";
|
||||
return true;
|
||||
};
|
||||
|
||||
var colorChooser = lobby.GetWidget("COLOR_CHOOSER");
|
||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
|
||||
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
|
||||
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
|
||||
|
||||
hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
|
||||
colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnMouseUp = mi =>
|
||||
{
|
||||
colorChooser.IsVisible = () => false;
|
||||
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
void UpdatePlayerColor(float hf, float sf, float lf, float r)
|
||||
{
|
||||
var c1 = ColorFromHSL(hf, sf, lf);
|
||||
var c2 = ColorFromHSL(hf, sf, r*lf);
|
||||
|
||||
Game.Settings.Player.Color1 = c1;
|
||||
Game.Settings.Player.Color2 = c2;
|
||||
Game.Settings.Save();
|
||||
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
|
||||
}
|
||||
|
||||
void UpdateColorPreview(float hf, float sf, float lf, float r)
|
||||
{
|
||||
CurrentColorPreview1 = ColorFromHSL(hf, sf, lf);
|
||||
CurrentColorPreview2 = ColorFromHSL(hf, sf, r*lf);
|
||||
Game.viewport.RefreshPalette();
|
||||
}
|
||||
|
||||
var colorChooser = lobby.GetWidget("COLOR_CHOOSER");
|
||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
|
||||
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
|
||||
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
|
||||
|
||||
hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
|
||||
colorChooser.GetWidget<ButtonWidget>("BUTTON_OK").OnMouseUp = mi =>
|
||||
{
|
||||
colorChooser.IsVisible = () => false;
|
||||
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
// hk is hue in the range [0,1] instead of [0,360]
|
||||
Color ColorFromHSL(float hk, float s, float l)
|
||||
{
|
||||
// Convert from HSL to RGB
|
||||
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
|
||||
var p = 2 * l - q;
|
||||
|
||||
float[] trgb = { hk + 1 / 3.0f,
|
||||
hk,
|
||||
hk - 1/3.0f };
|
||||
float[] rgb = { 0, 0, 0 };
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
while (trgb[k] < 0) trgb[k] += 1.0f;
|
||||
while (trgb[k] > 1) trgb[k] -= 1.0f;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
|
||||
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
|
||||
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
|
||||
else { rgb[k] = p; }
|
||||
}
|
||||
|
||||
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
|
||||
}
|
||||
void UpdatePlayerColor(float hf, float sf, float lf, float r)
|
||||
{
|
||||
var c1 = ColorFromHSL(hf, sf, lf);
|
||||
var c2 = ColorFromHSL(hf, sf, r*lf);
|
||||
|
||||
Game.Settings.Player.Color1 = c1;
|
||||
Game.Settings.Player.Color2 = c2;
|
||||
Game.Settings.Save();
|
||||
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
|
||||
}
|
||||
|
||||
void UpdateColorPreview(float hf, float sf, float lf, float r)
|
||||
{
|
||||
CurrentColorPreview1 = ColorFromHSL(hf, sf, lf);
|
||||
CurrentColorPreview2 = ColorFromHSL(hf, sf, r*lf);
|
||||
Game.viewport.RefreshPalette();
|
||||
}
|
||||
|
||||
// hk is hue in the range [0,1] instead of [0,360]
|
||||
public static Color ColorFromHSL(float hk, float s, float l)
|
||||
{
|
||||
// Convert from HSL to RGB
|
||||
var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s);
|
||||
var p = 2 * l - q;
|
||||
|
||||
float[] trgb = { hk + 1 / 3.0f,
|
||||
hk,
|
||||
hk - 1/3.0f };
|
||||
float[] rgb = { 0, 0, 0 };
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
while (trgb[k] < 0) trgb[k] += 1.0f;
|
||||
while (trgb[k] > 1) trgb[k] -= 1.0f;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); }
|
||||
else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; }
|
||||
else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); }
|
||||
else { rgb[k] = p; }
|
||||
}
|
||||
|
||||
return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255));
|
||||
}
|
||||
|
||||
|
||||
void UpdateCurrentMap()
|
||||
@@ -209,23 +209,23 @@ namespace OpenRA.Widgets.Delegates
|
||||
MapUid = Game.LobbyInfo.GlobalSettings.Map;
|
||||
Map = Game.modData.AvailableMaps[MapUid];
|
||||
}
|
||||
|
||||
|
||||
bool hasJoined = false;
|
||||
void JoinedServer()
|
||||
{
|
||||
if (hasJoined)
|
||||
return;
|
||||
hasJoined = true;
|
||||
|
||||
if (Game.LocalClient.Name != Game.Settings.Player.Name)
|
||||
Game.IssueOrder(Order.Command("name " + Game.Settings.Player.Name));
|
||||
|
||||
|
||||
bool hasJoined = false;
|
||||
void JoinedServer()
|
||||
{
|
||||
if (hasJoined)
|
||||
return;
|
||||
hasJoined = true;
|
||||
|
||||
if (Game.LocalClient.Name != Game.Settings.Player.Name)
|
||||
Game.IssueOrder(Order.Command("name " + Game.Settings.Player.Name));
|
||||
|
||||
var c1 = Game.Settings.Player.Color1;
|
||||
var c2 = Game.Settings.Player.Color2;
|
||||
|
||||
if (Game.LocalClient.Color1 != c1 || Game.LocalClient.Color2 != c2)
|
||||
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
|
||||
|
||||
if (Game.LocalClient.Color1 != c1 || Game.LocalClient.Color2 != c2)
|
||||
Game.IssueOrder(Order.Command("color {0},{1},{2},{3},{4},{5}".F(c1.R,c1.G,c1.B,c2.R,c2.G,c2.B)));
|
||||
}
|
||||
|
||||
void ResetConnectionState()
|
||||
@@ -313,24 +313,24 @@ namespace OpenRA.Widgets.Delegates
|
||||
name.OnLoseFocus = () => name.OnEnterKey();
|
||||
|
||||
var color = template.GetWidget<ButtonWidget>("COLOR");
|
||||
color.OnMouseUp = mi =>
|
||||
{
|
||||
var colorChooser = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("COLOR_CHOOSER");
|
||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||
hueSlider.Offset = Game.LocalClient.Color1.GetHue()/360f;
|
||||
|
||||
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
|
||||
satSlider.Offset = Game.LocalClient.Color1.GetSaturation();
|
||||
|
||||
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
|
||||
lumSlider.Offset = Game.LocalClient.Color1.GetBrightness();
|
||||
|
||||
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
|
||||
rangeSlider.Offset = Game.LocalClient.Color1.GetBrightness() == 0 ? 0 : Game.LocalClient.Color2.GetBrightness()/Game.LocalClient.Color1.GetBrightness();
|
||||
|
||||
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
colorChooser.IsVisible = () => true;
|
||||
return true;
|
||||
color.OnMouseUp = mi =>
|
||||
{
|
||||
var colorChooser = Widget.RootWidget.GetWidget("SERVER_LOBBY").GetWidget("COLOR_CHOOSER");
|
||||
var hueSlider = colorChooser.GetWidget<SliderWidget>("HUE_SLIDER");
|
||||
hueSlider.SetOffset(Game.LocalClient.Color1.GetHue()/360f);
|
||||
|
||||
var satSlider = colorChooser.GetWidget<SliderWidget>("SAT_SLIDER");
|
||||
satSlider.SetOffset(Game.LocalClient.Color1.GetSaturation());
|
||||
|
||||
var lumSlider = colorChooser.GetWidget<SliderWidget>("LUM_SLIDER");
|
||||
lumSlider.SetOffset(Game.LocalClient.Color1.GetBrightness());
|
||||
|
||||
var rangeSlider = colorChooser.GetWidget<SliderWidget>("RANGE_SLIDER");
|
||||
rangeSlider.SetOffset(Game.LocalClient.Color1.GetBrightness() == 0 ? 0 : Game.LocalClient.Color2.GetBrightness()/Game.LocalClient.Color1.GetBrightness());
|
||||
|
||||
UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
|
||||
colorChooser.IsVisible = () => true;
|
||||
return true;
|
||||
};
|
||||
|
||||
var colorBlock = color.GetWidget<ColorBlockWidget>("COLORBLOCK");
|
||||
@@ -422,4 +422,4 @@ namespace OpenRA.Widgets.Delegates
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
OpenRA.Game/Widgets/Delegates/MainMenuButtonsDelegate.cs
Normal file → Executable file
12
OpenRA.Game/Widgets/Delegates/MainMenuButtonsDelegate.cs
Normal file → Executable file
@@ -9,6 +9,9 @@
|
||||
#endregion
|
||||
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Server;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Widgets.Delegates
|
||||
{
|
||||
@@ -31,7 +34,16 @@ namespace OpenRA.Widgets.Delegates
|
||||
var s = FileSystem.Open("VERSION");
|
||||
version.Text = s.ReadAllText();
|
||||
s.Close();
|
||||
MasterServerQuery.OnVersion += v => { if (!string.IsNullOrEmpty(v)) version.Text += "\nLatest: " + v; };
|
||||
MasterServerQuery.GetCurrentVersion(Game.Settings.Server.MasterServer);
|
||||
}
|
||||
else
|
||||
{
|
||||
version.Text = "Dev Build";
|
||||
}
|
||||
MasterServerQuery.ClientVersion = version.Text;
|
||||
|
||||
MasterServerQuery.GetMOTD(Game.Settings.Server.MasterServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.Widgets.Delegates
|
||||
|
||||
MasterServerQuery.OnComplete += games => RefreshServerList(games);
|
||||
|
||||
widget.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
|
||||
widget.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
|
||||
bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
|
||||
bg.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
|
||||
|
||||
bg.Children.RemoveAll(a => GameButtons.Contains(a));
|
||||
GameButtons.Clear();
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA.Widgets.Delegates
|
||||
preview.IsVisible = () => CurrentMap() != null;
|
||||
|
||||
bg.GetWidget<LabelWidget>("SERVER_IP").GetText = () => currentServer.Address;
|
||||
bg.GetWidget<LabelWidget>("SERVER_MODS").GetText = () => string.Join(",", currentServer.Mods);
|
||||
bg.GetWidget<LabelWidget>("SERVER_MODS").GetText = () => GenerateModsLabel();
|
||||
bg.GetWidget<LabelWidget>("MAP_TITLE").GetText = () => (CurrentMap() != null) ? CurrentMap().Title : "Unknown";
|
||||
bg.GetWidget<LabelWidget>("MAP_PLAYERS").GetText = () =>
|
||||
{
|
||||
@@ -62,8 +62,8 @@ namespace OpenRA.Widgets.Delegates
|
||||
|
||||
bg.GetWidget("REFRESH_BUTTON").OnMouseUp = mi =>
|
||||
{
|
||||
widget.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
|
||||
widget.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
|
||||
bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
|
||||
bg.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list...";
|
||||
|
||||
bg.Children.RemoveAll(a => GameButtons.Contains(a));
|
||||
GameButtons.Clear();
|
||||
@@ -120,11 +120,22 @@ namespace OpenRA.Widgets.Delegates
|
||||
return (currentServer == null || !Game.modData.AvailableMaps.ContainsKey(currentServer.Map))
|
||||
? null : Game.modData.AvailableMaps[currentServer.Map];
|
||||
}
|
||||
|
||||
string GenerateModsLabel()
|
||||
{
|
||||
return string.Join("\n", currentServer.Mods.Select(m =>
|
||||
ModData.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", ModData.AllMods[m].Title, ModData.AllMods[m].Version)
|
||||
: string.Format("Unknown Mod: {0}",m)).ToArray());
|
||||
}
|
||||
|
||||
void RefreshServerList(IEnumerable<GameServer> games)
|
||||
{
|
||||
var r = Widget.RootWidget;
|
||||
var bg = r.GetWidget("JOINSERVER_BG");
|
||||
|
||||
if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko
|
||||
return;
|
||||
|
||||
var sl = bg.GetWidget<ListBoxWidget>("SERVER_LIST");
|
||||
|
||||
sl.Children.Clear();
|
||||
@@ -184,7 +195,6 @@ namespace OpenRA.Widgets.Delegates
|
||||
|
||||
dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi =>
|
||||
{
|
||||
|
||||
var address = dc.GetWidget<TextFieldWidget>("SERVER_ADDRESS").Text;
|
||||
var cpts = address.Split(':').ToArray();
|
||||
if (cpts.Length != 2)
|
||||
@@ -201,7 +211,8 @@ namespace OpenRA.Widgets.Delegates
|
||||
dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi =>
|
||||
{
|
||||
Widget.CloseWindow();
|
||||
return widget.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp(mi);
|
||||
Widget.OpenWindow("MAINMENU_BG");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,15 @@ namespace OpenRA.Widgets.Delegates
|
||||
Game.Settings.Game.ViewportEdgeScroll ^= true;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Added scroll sensitivity - Gecko
|
||||
var edgeScrollSlider = general.GetWidget<SliderWidget>("EDGE_SCROLL_AMOUNT");
|
||||
if (edgeScrollSlider != null) // Backwards compatible - Gecko
|
||||
{
|
||||
edgeScrollSlider.SetOffset(Game.Settings.Game.ViewportEdgeScrollStep);
|
||||
edgeScrollSlider.OnChange += _ => { Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); };
|
||||
Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset();
|
||||
}
|
||||
|
||||
var inverseScroll = general.GetWidget<CheckboxWidget>("INVERSE_SCROLL");
|
||||
inverseScroll.Checked = () => Game.Settings.Game.InverseDragScroll;
|
||||
@@ -68,10 +77,12 @@ namespace OpenRA.Widgets.Delegates
|
||||
var soundslider = audio.GetWidget<SliderWidget>("SOUND_VOLUME");
|
||||
soundslider.OnChange += x => { Sound.SoundVolume = x; };
|
||||
soundslider.GetOffset = () => { return Sound.SoundVolume; };
|
||||
soundslider.SetOffset(Sound.SoundVolume);
|
||||
|
||||
var musicslider = audio.GetWidget<SliderWidget>("MUSIC_VOLUME");
|
||||
musicslider.OnChange += x => { Sound.MusicVolume = x; };
|
||||
musicslider.GetOffset = () => { return Sound.MusicVolume; };
|
||||
musicslider.SetOffset(Sound.MusicVolume);
|
||||
|
||||
|
||||
// Display
|
||||
|
||||
@@ -16,10 +16,12 @@ namespace OpenRA.Widgets
|
||||
public class LabelWidget : Widget
|
||||
{
|
||||
public enum TextAlign { Left, Center, Right }
|
||||
public enum TextVAlign { Top, Middle, Bottom }
|
||||
|
||||
public string Text = null;
|
||||
public string Background = null;
|
||||
public TextAlign Align = TextAlign.Left;
|
||||
public TextVAlign VAlign = TextVAlign.Middle;
|
||||
public bool Bold = false;
|
||||
public Func<string> GetText;
|
||||
public Func<string> GetBackground;
|
||||
@@ -54,8 +56,14 @@ namespace OpenRA.Widgets
|
||||
return;
|
||||
|
||||
int2 textSize = font.Measure(text);
|
||||
int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y)/2);
|
||||
|
||||
int2 position = RenderOrigin;
|
||||
|
||||
if (VAlign == TextVAlign.Middle)
|
||||
position += new int2(0, (Bounds.Height - textSize.Y)/2);
|
||||
|
||||
if (VAlign == TextVAlign.Bottom)
|
||||
position += new int2(0, Bounds.Height - textSize.Y);
|
||||
|
||||
if (Align == TextAlign.Center)
|
||||
position += new int2((Bounds.Width - textSize.X)/2, 0);
|
||||
|
||||
|
||||
118
OpenRA.Game/Widgets/ScrollingTextWidget.cs
Executable file
118
OpenRA.Game/Widgets/ScrollingTextWidget.cs
Executable file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class ScrollingTextWidget : Widget
|
||||
{
|
||||
public string Text = "";
|
||||
private string ScrollingText = "";
|
||||
|
||||
public string Background = null;
|
||||
|
||||
public bool Bold = false;
|
||||
|
||||
public int ScrollLength = 200;
|
||||
|
||||
// ticks per single letter scroll
|
||||
public int ScrollRate = 4;
|
||||
|
||||
private string ScrollBuffer = "";
|
||||
|
||||
private int ScrollLocation = 0;
|
||||
private int ScrollTick = 0;
|
||||
|
||||
public Func<string> GetText;
|
||||
public Func<string> GetBackground;
|
||||
|
||||
public ScrollingTextWidget()
|
||||
: base()
|
||||
{
|
||||
GetText = () => Text;
|
||||
GetBackground = () => Background;
|
||||
}
|
||||
|
||||
protected ScrollingTextWidget(ScrollingTextWidget other)
|
||||
: base(other)
|
||||
{
|
||||
Text = other.Text;
|
||||
GetText = other.GetText;
|
||||
Bold = other.Bold;
|
||||
GetBackground = other.GetBackground;
|
||||
}
|
||||
|
||||
public override void Tick(World world)
|
||||
{
|
||||
if (Text != "")
|
||||
{
|
||||
ScrollingText = Text;
|
||||
Text = "";
|
||||
}
|
||||
UpdateScrollBuffer();
|
||||
}
|
||||
|
||||
public void ResetScroll()
|
||||
{
|
||||
ScrollLocation = 0;
|
||||
ScrollTick = 0;
|
||||
}
|
||||
|
||||
private void UpdateScrollBuffer()
|
||||
{
|
||||
ScrollTick++;
|
||||
|
||||
if (ScrollTick < ScrollRate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ScrollTick = 0;
|
||||
ScrollBuffer = "";
|
||||
|
||||
if (ScrollingText.Substring(ScrollingText.Length - 4, 3) != " ")
|
||||
{
|
||||
ScrollingText += " ";
|
||||
}
|
||||
|
||||
int tempScrollLocation = ScrollLocation;
|
||||
for (int i = 0; i < ScrollLength; ++i)
|
||||
{
|
||||
ScrollBuffer += ScrollingText.Substring(tempScrollLocation, 1);
|
||||
tempScrollLocation = (tempScrollLocation + 1) % ScrollingText.Length;
|
||||
}
|
||||
|
||||
ScrollLocation = (ScrollLocation + 1) % ScrollingText.Length;
|
||||
}
|
||||
|
||||
public void SetText(string newText)
|
||||
{
|
||||
Text = newText.Replace("\n", " ");
|
||||
Text = Text.Replace("\r", "");
|
||||
}
|
||||
|
||||
public override void DrawInner(World world)
|
||||
{
|
||||
var bg = GetBackground();
|
||||
|
||||
if (bg != null)
|
||||
WidgetUtils.DrawPanel(bg, RenderBounds);
|
||||
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var text = GetText();
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
int2 textSize = font.Measure(text);
|
||||
int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y) / 2);
|
||||
|
||||
Game.Renderer.EnableScissor(position.X, position.Y, Bounds.Width, Bounds.Height);
|
||||
font.DrawText(ScrollBuffer, position, Color.White);
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ScrollingTextWidget(this); }
|
||||
}
|
||||
}
|
||||
45
OpenRA.Game/Widgets/SliderWidget.cs
Normal file → Executable file
45
OpenRA.Game/Widgets/SliderWidget.cs
Normal file → Executable file
@@ -6,9 +6,9 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
@@ -17,9 +17,11 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public event Action<float> OnChange;
|
||||
public Func<float> GetOffset;
|
||||
public float Offset = 0;
|
||||
public int Ticks = 0;
|
||||
public int TrackHeight = 5;
|
||||
public float2 Range = new float2(0f, 1f);
|
||||
|
||||
private float Offset = 0;
|
||||
|
||||
int2 lastMouseLocation;
|
||||
bool isMoving = false;
|
||||
@@ -27,8 +29,15 @@ namespace OpenRA.Widgets
|
||||
public SliderWidget()
|
||||
: base()
|
||||
{
|
||||
GetOffset = () => Offset;
|
||||
OnChange = x => Offset = x;
|
||||
GetOffset = () =>
|
||||
{
|
||||
var Big = Math.Max(Range.X, Range.Y);
|
||||
var Little = Math.Min(Range.X, Range.Y);
|
||||
var Spread = Big - Little;
|
||||
|
||||
return Spread * Offset + Little;
|
||||
};
|
||||
OnChange = x => Offset = x.Clamp(0f, 1f);
|
||||
}
|
||||
|
||||
public SliderWidget(SliderWidget other)
|
||||
@@ -36,13 +45,23 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
OnChange = other.OnChange;
|
||||
GetOffset = other.GetOffset;
|
||||
Offset = other.Offset;
|
||||
Ticks = other.Ticks;
|
||||
Range = other.Range;
|
||||
Offset = GetOffset();
|
||||
TrackHeight = other.TrackHeight;
|
||||
lastMouseLocation = other.lastMouseLocation;
|
||||
isMoving = other.isMoving;
|
||||
}
|
||||
|
||||
public void SetOffset(float newOffset)
|
||||
{
|
||||
var Big = Math.Max(Range.X, Range.Y);
|
||||
var Little = Math.Min(Range.X, Range.Y);
|
||||
var Spread = Big - Little;
|
||||
|
||||
Offset = ((newOffset - Little) / Spread).Clamp(0f, 1f);
|
||||
}
|
||||
|
||||
public override bool HandleInputInner(MouseInput mi)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi))
|
||||
@@ -72,7 +91,7 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
else if (Ticks != 0)
|
||||
{
|
||||
var pos = GetOffset();
|
||||
var pos = Offset;
|
||||
|
||||
// Offset slightly the direction we want to move so we don't get stuck on a tick
|
||||
var delta = 0.001;
|
||||
@@ -92,7 +111,7 @@ namespace OpenRA.Widgets
|
||||
var thumb = thumbRect;
|
||||
var center = thumb.X + thumb.Width / 2;
|
||||
var newOffset = OffsetBy((mi.Location.X - center) * 1f / (RenderBounds.Width - thumb.Width));
|
||||
if (newOffset != GetOffset())
|
||||
if (newOffset != Offset)
|
||||
{
|
||||
OnChange(newOffset);
|
||||
|
||||
@@ -127,7 +146,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
float OffsetBy(float amount)
|
||||
{
|
||||
var centerPos = GetOffset() + amount;
|
||||
var centerPos = Offset + amount;
|
||||
if (centerPos < 0) centerPos = 0;
|
||||
if (centerPos > 1) centerPos = 1;
|
||||
return centerPos;
|
||||
@@ -141,7 +160,7 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
var width = RenderBounds.Height;
|
||||
var height = RenderBounds.Height;
|
||||
var origin = (int)((RenderBounds.X + width / 2) + GetOffset() * (RenderBounds.Width - width) - width / 2f);
|
||||
var origin = (int)((RenderBounds.X + width / 2) + Offset * (RenderBounds.Width - width) - width / 2f);
|
||||
return new Rectangle(origin, RenderBounds.Y, width, height);
|
||||
}
|
||||
}
|
||||
@@ -169,5 +188,5 @@ namespace OpenRA.Widgets
|
||||
WidgetUtils.DrawPanel("dialog2", thumbRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,172 +1,178 @@
|
||||
#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
|
||||
|
||||
#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.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
[Flags]
|
||||
public enum ScrollDirection
|
||||
{
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Left = 2,
|
||||
Down = 4,
|
||||
Right = 8
|
||||
}
|
||||
|
||||
class ViewportScrollControllerWidget : Widget
|
||||
{
|
||||
public int EdgeScrollThreshold = 15;
|
||||
|
||||
ScrollDirection Keyboard;
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
[Flags]
|
||||
public enum ScrollDirection
|
||||
{
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Left = 2,
|
||||
Down = 4,
|
||||
Right = 8
|
||||
}
|
||||
|
||||
class ViewportScrollControllerWidget : Widget
|
||||
{
|
||||
public int EdgeScrollThreshold = 15;
|
||||
|
||||
ScrollDirection Keyboard;
|
||||
ScrollDirection Edge;
|
||||
|
||||
public ViewportScrollControllerWidget() : base() { }
|
||||
protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {}
|
||||
public override void DrawInner( World world ) {}
|
||||
|
||||
public override bool HandleInputInner(MouseInput mi)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Move &&
|
||||
(mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right)))
|
||||
public ViewportScrollControllerWidget() : base() { }
|
||||
protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {}
|
||||
public override void DrawInner( World world ) {}
|
||||
|
||||
public override bool HandleInputInner(MouseInput mi)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Move &&
|
||||
(mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right)))
|
||||
{
|
||||
int InverseScroll = Game.Settings.Game.InverseDragScroll ? -1 : 1;
|
||||
Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GetCursor(int2 pos)
|
||||
{
|
||||
if (!Game.Settings.Game.ViewportEdgeScroll)
|
||||
return null;
|
||||
|
||||
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left))
|
||||
return "scroll-tl-blocked";
|
||||
else
|
||||
return "scroll-tl";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right))
|
||||
return "scroll-tr-blocked";
|
||||
else
|
||||
return "scroll-tr";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left))
|
||||
return "scroll-bl-blocked";
|
||||
else
|
||||
return "scroll-bl";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right))
|
||||
return "scroll-br-blocked";
|
||||
else
|
||||
return "scroll-br";
|
||||
}
|
||||
|
||||
if (Edge.Includes(ScrollDirection.Up))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up))
|
||||
return "scroll-t-blocked";
|
||||
else
|
||||
return "scroll-t";
|
||||
if (Edge.Includes(ScrollDirection.Down))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down))
|
||||
return "scroll-b-blocked";
|
||||
else
|
||||
return "scroll-b";
|
||||
if (Edge.Includes(ScrollDirection.Left))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left))
|
||||
return "scroll-l-blocked";
|
||||
else
|
||||
return "scroll-l";
|
||||
if (Edge.Includes(ScrollDirection.Right))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right))
|
||||
return "scroll-r-blocked";
|
||||
else
|
||||
return "scroll-r";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool LoseFocus (MouseInput mi)
|
||||
{
|
||||
Keyboard = ScrollDirection.None;
|
||||
return base.LoseFocus(mi);
|
||||
}
|
||||
|
||||
public override bool HandleKeyPressInner(KeyInput e)
|
||||
{
|
||||
switch (e.KeyName)
|
||||
{
|
||||
case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Tick(World world)
|
||||
{
|
||||
Edge = ScrollDirection.None;
|
||||
if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus)
|
||||
{
|
||||
// Check for edge-scroll
|
||||
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Left, true);
|
||||
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Up, true);
|
||||
if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Right, true);
|
||||
if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Down, true);
|
||||
}
|
||||
|
||||
if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None)
|
||||
{
|
||||
var scroll = new float2(0,0);
|
||||
if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up))
|
||||
scroll += new float2(0, -10);
|
||||
if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right))
|
||||
scroll += new float2(10, 0);
|
||||
if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down))
|
||||
scroll += new float2(0, 10);
|
||||
if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left))
|
||||
scroll += new float2(-10, 0);
|
||||
|
||||
Game.viewport.Scroll(scroll);
|
||||
}
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ViewportScrollControllerWidget(this); }
|
||||
}
|
||||
|
||||
public static class ViewportExts
|
||||
{
|
||||
public static bool Includes(this ScrollDirection d, ScrollDirection s)
|
||||
{
|
||||
return (d & s) == s;
|
||||
}
|
||||
|
||||
public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val)
|
||||
{
|
||||
return (d.Includes(s) != val) ? d ^ s : d;
|
||||
}
|
||||
}
|
||||
}
|
||||
Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GetCursor(int2 pos)
|
||||
{
|
||||
if (!Game.Settings.Game.ViewportEdgeScroll)
|
||||
return null;
|
||||
|
||||
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left))
|
||||
return "scroll-tl-blocked";
|
||||
else
|
||||
return "scroll-tl";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right))
|
||||
return "scroll-tr-blocked";
|
||||
else
|
||||
return "scroll-tr";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left))
|
||||
return "scroll-bl-blocked";
|
||||
else
|
||||
return "scroll-bl";
|
||||
}
|
||||
if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){
|
||||
ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections();
|
||||
if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right))
|
||||
return "scroll-br-blocked";
|
||||
else
|
||||
return "scroll-br";
|
||||
}
|
||||
|
||||
if (Edge.Includes(ScrollDirection.Up))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up))
|
||||
return "scroll-t-blocked";
|
||||
else
|
||||
return "scroll-t";
|
||||
if (Edge.Includes(ScrollDirection.Down))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down))
|
||||
return "scroll-b-blocked";
|
||||
else
|
||||
return "scroll-b";
|
||||
if (Edge.Includes(ScrollDirection.Left))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left))
|
||||
return "scroll-l-blocked";
|
||||
else
|
||||
return "scroll-l";
|
||||
if (Edge.Includes(ScrollDirection.Right))
|
||||
if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right))
|
||||
return "scroll-r-blocked";
|
||||
else
|
||||
return "scroll-r";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool LoseFocus (MouseInput mi)
|
||||
{
|
||||
Keyboard = ScrollDirection.None;
|
||||
return base.LoseFocus(mi);
|
||||
}
|
||||
|
||||
public override bool HandleKeyPressInner(KeyInput e)
|
||||
{
|
||||
switch (e.KeyName)
|
||||
{
|
||||
case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true;
|
||||
case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Tick(World world)
|
||||
{
|
||||
Edge = ScrollDirection.None;
|
||||
if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus)
|
||||
{
|
||||
// Check for edge-scroll
|
||||
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Left, true);
|
||||
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Up, true);
|
||||
if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Right, true);
|
||||
if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold)
|
||||
Edge = Edge.Set(ScrollDirection.Down, true);
|
||||
}
|
||||
|
||||
if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None)
|
||||
{
|
||||
var scroll = new float2(0, 0);
|
||||
|
||||
// Modified to use the ViewportEdgeScrollStep setting - Gecko
|
||||
if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up))
|
||||
scroll += new float2(0, -1);
|
||||
if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right))
|
||||
scroll += new float2(1, 0);
|
||||
if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down))
|
||||
scroll += new float2(0, 1);
|
||||
if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left))
|
||||
scroll += new float2(-1, 0);
|
||||
|
||||
float length = Math.Max(1, scroll.Length);
|
||||
scroll.X = (scroll.X / length) * Game.Settings.Game.ViewportEdgeScrollStep;
|
||||
scroll.Y = (scroll.Y / length) * Game.Settings.Game.ViewportEdgeScrollStep;
|
||||
|
||||
Game.viewport.Scroll(scroll);
|
||||
}
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ViewportScrollControllerWidget(this); }
|
||||
}
|
||||
|
||||
public static class ViewportExts
|
||||
{
|
||||
public static bool Includes(this ScrollDirection d, ScrollDirection s)
|
||||
{
|
||||
return (d & s) == s;
|
||||
}
|
||||
|
||||
public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val)
|
||||
{
|
||||
return (d.Includes(s) != val) ? d ^ s : d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Orders;
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
@@ -109,9 +109,8 @@ namespace OpenRA.Widgets
|
||||
public override string GetCursor(int2 pos)
|
||||
{
|
||||
var world = Game.world;
|
||||
int sync = world.SyncHash();
|
||||
try
|
||||
{
|
||||
return Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
if (!world.GameHasStarted)
|
||||
return "default";
|
||||
|
||||
@@ -122,29 +121,24 @@ namespace OpenRA.Widgets
|
||||
Modifiers = Game.GetModifierKeys()
|
||||
};
|
||||
|
||||
return Game.world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi );
|
||||
}
|
||||
finally
|
||||
{
|
||||
if( sync != world.SyncHash() )
|
||||
throw new InvalidOperationException( "Desync in InputControllerWidget.GetCursor" );
|
||||
}
|
||||
return world.OrderGenerator.GetCursor( world, Game.viewport.ViewToWorld(mi).ToInt2(), mi );
|
||||
} );
|
||||
}
|
||||
|
||||
public override bool HandleKeyPressInner(KeyInput e)
|
||||
{
|
||||
if (e.Event == KeyInputEvent.Down)
|
||||
{
|
||||
if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0]))
|
||||
{
|
||||
Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyChar == '\b')
|
||||
{
|
||||
GotoNextBase();
|
||||
return true;
|
||||
{
|
||||
if (e.KeyName.Length == 1 && char.IsDigit(e.KeyName[0]))
|
||||
{
|
||||
Game.world.Selection.DoControlGroup(Game.world, e.KeyName[0] - '0', e.Modifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyChar == '\b')
|
||||
{
|
||||
GotoNextBase();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -54,8 +54,18 @@ namespace OpenRA
|
||||
public readonly TileSet TileSet;
|
||||
|
||||
public readonly WorldRenderer WorldRenderer;
|
||||
|
||||
public IOrderGenerator OrderGenerator = new UnitOrderGenerator();
|
||||
|
||||
IOrderGenerator orderGenerator_;
|
||||
public IOrderGenerator OrderGenerator
|
||||
{
|
||||
get { return orderGenerator_; }
|
||||
set
|
||||
{
|
||||
Sync.AssertUnsynced( "The current order generator may not be changed from synced code" );
|
||||
orderGenerator_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Selection Selection = new Selection();
|
||||
|
||||
public void CancelInputMode() { OrderGenerator = new UnitOrderGenerator(); }
|
||||
@@ -76,6 +86,7 @@ namespace OpenRA
|
||||
|
||||
public World(Manifest manifest, Map map)
|
||||
{
|
||||
orderGenerator_ = new UnitOrderGenerator();
|
||||
Map = map;
|
||||
|
||||
TileSet = Rules.TileSets[Map.Tileset];
|
||||
@@ -194,7 +205,6 @@ namespace OpenRA
|
||||
readonly World world;
|
||||
|
||||
public readonly Cache<Player, OwnedByCachedView> OwnedBy;
|
||||
readonly TypeDictionary hasTrait = new TypeDictionary();
|
||||
|
||||
public AllQueries( World world )
|
||||
{
|
||||
|
||||
@@ -34,9 +34,6 @@ namespace OpenRA.Mods.Cnc
|
||||
w.Add(new IonCannon(self, w, order.TargetLocation));
|
||||
});
|
||||
|
||||
if (Owner == Owner.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
FinishActivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
// GoodGuy win conditions
|
||||
// BadGuy is dead
|
||||
int badcount = self.World.Queries.OwnedBy[Players["BadGuy"]].Count(a => a.IsInWorld && !a.IsDead());
|
||||
int badcount = self.World.Queries.OwnedBy[Players["BadGuy"]].Count(a => !a.IsDead());
|
||||
if (badcount != lastBadCount)
|
||||
{
|
||||
Game.Debug("{0} badguys remain".F(badcount));
|
||||
@@ -137,7 +137,7 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
|
||||
//GoodGuy lose conditions
|
||||
if (self.World.Queries.OwnedBy[Players["GoodGuy"]].Count( a => a.IsInWorld && !a.IsDead()) == 0)
|
||||
if (self.World.Queries.OwnedBy[Players["GoodGuy"]].Count( a => !a.IsDead()) == 0)
|
||||
OnLose(self.World);
|
||||
|
||||
// GoodGuy reinforcements
|
||||
|
||||
@@ -12,9 +12,9 @@ using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Mods.RA;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Render;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.Mods.RA.Render;
|
||||
|
||||
namespace OpenRA.Mods.Cnc
|
||||
{
|
||||
@@ -33,8 +33,7 @@ namespace OpenRA.Mods.Cnc
|
||||
|
||||
// Start and end beyond the edge of the map, to give a finite delay, and ability to land when AFLD is on map edge
|
||||
var startPos = new int2(owner.World.Map.XOffset + owner.World.Map.Width+5, self.Location.Y);
|
||||
var endPos = new int2(owner.World.Map.XOffset-5, self.Location.Y);
|
||||
|
||||
var endPos = new int2(owner.World.Map.XOffset-5, self.Location.Y);
|
||||
|
||||
// Assume a single exit point for simplicity
|
||||
var exit = self.Info.Traits.WithInterface<ExitInfo>().First();
|
||||
@@ -55,8 +54,9 @@ namespace OpenRA.Mods.Cnc
|
||||
a.QueueActivity(new Land(Target.FromActor(self)));
|
||||
a.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
if (self.IsDead())
|
||||
if (!self.IsInWorld || self.IsDead())
|
||||
return;
|
||||
|
||||
rb.PlayCustomAnimRepeating(self, "idle");
|
||||
self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit));
|
||||
}));
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Mods.RA.Render;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class IdleAnimation : IActivity
|
||||
{
|
||||
public class IdleAnimation : Idle
|
||||
{
|
||||
string sequence;
|
||||
int delay;
|
||||
@@ -25,10 +26,8 @@ namespace OpenRA.Mods.RA.Activities
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
IActivity NextActivity { get; set; }
|
||||
|
||||
bool active = true;
|
||||
public IActivity Tick(Actor self)
|
||||
public override IActivity Tick(Actor self)
|
||||
{
|
||||
if (!active) return NextActivity;
|
||||
|
||||
@@ -38,23 +37,11 @@ namespace OpenRA.Mods.RA.Activities
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Cancel(Actor self)
|
||||
protected override bool OnCancel()
|
||||
{
|
||||
active = false;
|
||||
NextActivity = null;
|
||||
active = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Queue( IActivity activity )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
NextActivity.Queue( activity );
|
||||
else
|
||||
NextActivity = activity;
|
||||
}
|
||||
|
||||
public IEnumerable<float2> GetCurrentPath()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
public override IActivity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (target == null || target.IsDead()) return NextActivity;
|
||||
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
|
||||
if (target.Owner == self.Owner) return NextActivity;
|
||||
|
||||
foreach (var t in target.TraitsImplementing<IAcceptSpy>())
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class AircraftInfo : ITraitInfo
|
||||
{
|
||||
public readonly int CruiseAltitude = 20;
|
||||
public readonly int CruiseAltitude = 30;
|
||||
[ActorReference]
|
||||
public readonly string[] RepairBuildings = { "fix" };
|
||||
[ActorReference]
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public class Aircraft : IMove, IFacing, IOccupySpace
|
||||
{
|
||||
protected readonly Actor self;
|
||||
[Sync]
|
||||
public int2 Location;
|
||||
[Sync]
|
||||
@@ -41,6 +42,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public Aircraft( ActorInitializer init , AircraftInfo info)
|
||||
{
|
||||
this.self = init.self;
|
||||
if (init.Contains<LocationInit>())
|
||||
this.Location = init.Get<LocationInit,int2>();
|
||||
|
||||
@@ -64,8 +66,9 @@ namespace OpenRA.Mods.RA
|
||||
self.CenterLocation = Util.CenterOfCell(cell);
|
||||
}
|
||||
|
||||
public bool AircraftCanEnter(Actor self, Actor a)
|
||||
public bool AircraftCanEnter(Actor a)
|
||||
{
|
||||
if( self.Owner != a.Owner ) return false;
|
||||
return Info.RearmBuildings.Contains( a.Info.Name )
|
||||
|| Info.RepairBuildings.Contains( a.Info.Name );
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA
|
||||
public virtual object Create(ActorInitializer init) { return new AttackBase(init.self); }
|
||||
}
|
||||
|
||||
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderCursor, IOrderVoice
|
||||
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice
|
||||
{
|
||||
public bool IsAttacking { get; internal set; }
|
||||
public Target target;
|
||||
@@ -123,6 +123,9 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (w.Info.Range * w.Info.Range * Game.CellSize * Game.CellSize
|
||||
< (target.CenterLocation - self.CenterLocation).LengthSquared) return false;
|
||||
|
||||
if (w.Info.MinRange * w.Info.MinRange * Game.CellSize * Game.CellSize >
|
||||
(target.CenterLocation - self.CenterLocation).LengthSquared) return false;
|
||||
|
||||
if (!w.IsValidAgainst(target)) return false;
|
||||
|
||||
@@ -176,48 +179,23 @@ namespace OpenRA.Mods.RA
|
||||
return info.FireDelay;
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
bool IsHeal { get { return Weapons[ 0 ].Info.Warheads[ 0 ].Damage < 0; } }
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return mi.Modifiers.HasModifier(Modifiers.Ctrl) ? 1000 : 1;
|
||||
get { yield return new AttackOrderTargeter( "Attack", 6, IsHeal ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
if (self == underCursor) return null;
|
||||
|
||||
var target = underCursor == null ? Target.FromCell(xy) : Target.FromActor(underCursor);
|
||||
|
||||
var isHeal = Weapons[0].Info.Warheads[0].Damage < 0;
|
||||
var forceFire = mi.Modifiers.HasModifier(Modifiers.Ctrl);
|
||||
|
||||
if (isHeal)
|
||||
if( order is AttackOrderTargeter )
|
||||
{
|
||||
// we can never "heal ground"; that makes no sense.
|
||||
if (!target.IsActor) return null;
|
||||
|
||||
// unless forced, only heal allies.
|
||||
if (self.Owner.Stances[underCursor.Owner] != Stance.Ally && !forceFire) return null;
|
||||
|
||||
// don't allow healing of fully-healed stuff!
|
||||
if (underCursor.GetDamageState() == DamageState.Undamaged) return null;
|
||||
if( target.IsActor )
|
||||
return new Order( IsHeal ? "Heal" : "Attack", self, target.Actor );
|
||||
else
|
||||
return new Order( IsHeal ? "Heal" : "Attack", self, Util.CellContaining( target.CenterLocation ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!target.IsActor)
|
||||
{
|
||||
if (!forceFire) return null;
|
||||
if (!self.Info.Traits.Get<AttackBaseInfo>().CanAttackGround) return null;
|
||||
return new Order("Attack", self, xy);
|
||||
}
|
||||
|
||||
if ((self.Owner.Stances[underCursor.Owner] != Stance.Enemy) && !forceFire)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!HasAnyValidWeapons(target)) return null;
|
||||
|
||||
return new Order(isHeal ? "Heal" : "Attack", self, underCursor);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
@@ -248,16 +226,6 @@ namespace OpenRA.Mods.RA
|
||||
self.Trait<Turreted>().desiredFacing = null;
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
switch (order.OrderString)
|
||||
{
|
||||
case "Attack": return "attack";
|
||||
case "Heal": return "heal";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
@@ -279,5 +247,48 @@ namespace OpenRA.Mods.RA
|
||||
public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); }
|
||||
|
||||
public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(t)); }
|
||||
|
||||
class AttackOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly bool isHeal;
|
||||
|
||||
public AttackOrderTargeter( string order, int priority, bool isHeal )
|
||||
{
|
||||
this.OrderID = order;
|
||||
this.OrderPriority = priority;
|
||||
this.isHeal = isHeal;
|
||||
}
|
||||
|
||||
public string OrderID { get; private set; }
|
||||
public int OrderPriority { get; private set; }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = isHeal ? "heal" : "attack";
|
||||
if( self == target ) return false;
|
||||
if( !self.Trait<AttackBase>().HasAnyValidWeapons( Target.FromActor( target ) ) ) return false;
|
||||
|
||||
var playerRelationship = self.Owner.Stances[ target.Owner ];
|
||||
|
||||
if( isHeal )
|
||||
return playerRelationship == Stance.Ally || forceAttack;
|
||||
|
||||
else
|
||||
return playerRelationship == Stance.Enemy || forceAttack;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = isHeal ? "heal" : "attack";
|
||||
if( isHeal ) return false;
|
||||
if( !self.Trait<AttackBase>().HasAnyValidWeapons( Target.FromCell( location ) ) ) return false;
|
||||
|
||||
if( forceAttack )
|
||||
if( self.Info.Traits.Get<AttackBaseInfo>().CanAttackGround )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
protected override void QueueAttack(Actor self, Order order)
|
||||
{
|
||||
if (self.Trait<Aircraft>().Altitude == 0)
|
||||
return; // dont fire while landed
|
||||
|
||||
target = Target.FromOrder(order);
|
||||
self.QueueActivity(new FlyAttack(target));
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
return inRange
|
||||
.Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally)
|
||||
.Where(a => !a.IsDead())
|
||||
.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.Location - self.Location).LengthSquared)
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
bool IsIntact(Bridge b)
|
||||
{
|
||||
return b != null && b.self.IsInWorld && !b.self.IsDead();
|
||||
return b != null && !b.self.IsDead();
|
||||
}
|
||||
|
||||
void KillUnitsOnBridge()
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -21,21 +24,19 @@ namespace OpenRA.Mods.RA
|
||||
public readonly float C4Delay = 0;
|
||||
}
|
||||
|
||||
class C4Demolition : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class C4Demolition : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return mi.Modifiers.HasModifier(Modifiers.Ctrl) ? 1001 : 1;
|
||||
get { yield return new UnitTraitOrderTargeter<Building>( "C4", 6, "c4", true, false ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
if (!underCursor.HasTrait<Building>()) return null;
|
||||
if (self.Owner.Stances[underCursor.Owner] != Stance.Enemy && !mi.Modifiers.HasModifier(Modifiers.Ctrl)) return null;
|
||||
|
||||
return new Order("C4", self, underCursor);
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "C4" )
|
||||
return new Order( "C4", self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
@@ -58,11 +59,6 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "C4") ? "c4" : null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "C4") ? "Attack" : null;
|
||||
|
||||
@@ -12,38 +12,46 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class CargoInfo : TraitInfo<Cargo>
|
||||
public class CargoInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Passengers = 0;
|
||||
public readonly string[] Types = { };
|
||||
public readonly int UnloadFacing = 0;
|
||||
|
||||
public object Create( ActorInitializer init ) { return new Cargo( init.self ); }
|
||||
}
|
||||
|
||||
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, INotifyDamage
|
||||
public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyDamage
|
||||
{
|
||||
readonly Actor self;
|
||||
List<Actor> cargo = new List<Actor>();
|
||||
public IEnumerable<Actor> Passengers { get { return cargo; } }
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public Cargo( Actor self )
|
||||
{
|
||||
return 5;
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right && underCursor == self)
|
||||
return new Order("Unload", self);
|
||||
|
||||
if (mi.Button == MouseButton.Right && underCursor != null && underCursor.Owner == self.Owner)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
var pi = underCursor.Info.Traits.GetOrDefault<PassengerInfo>();
|
||||
var ci = self.Info.Traits.Get<CargoInfo>();
|
||||
if (pi != null && ci.Types.Contains(pi.CargoType))
|
||||
return new Order("EnterTransport", underCursor, self);
|
||||
yield return new DeployOrderTargeter( "Unload", 10, () => CanUnload( self ) );
|
||||
yield return new UnitTraitOrderTargeter<Passenger>( "ReverseEnterTransport", 6, null, false, true );
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "Unload" )
|
||||
return new Order( order.OrderID, self );
|
||||
|
||||
if( order.OrderID == "ReverseEnterTransport" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -58,6 +66,15 @@ namespace OpenRA.Mods.RA
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new UnloadCargo());
|
||||
}
|
||||
|
||||
if( order.OrderString == "ReverseEnterTransport" )
|
||||
{
|
||||
if( order.TargetActor != null && order.Subject.Owner == order.TargetActor.Owner )
|
||||
{
|
||||
var passenger = order.TargetActor.Trait<Passenger>();
|
||||
passenger.ResolveOrder( order.TargetActor, new Order( "EnterTransport", order.TargetActor, self ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanUnload(Actor self)
|
||||
@@ -74,7 +91,6 @@ namespace OpenRA.Mods.RA
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "Unload") return null;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA
|
||||
public readonly int ChargeTime = 120; // Seconds
|
||||
}
|
||||
|
||||
class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ITick, IPips, IOrderCursor, IOrderVoice
|
||||
class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ITick, IPips, IOrderVoice
|
||||
{
|
||||
// Recharge logic
|
||||
[Sync]
|
||||
@@ -33,29 +33,22 @@ namespace OpenRA.Mods.RA
|
||||
chargeTick--;
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get { yield return new DeployOrderTargeter( "ChronoshiftDeploy", 5, () => chargeTick <= 0 ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button == MouseButton.Right && xy == self.Location)
|
||||
return new Order("ChronoshiftDeploy", self);
|
||||
if( order.OrderID == "ChronoshiftDeploy" )
|
||||
if (chargeTick <= 0)
|
||||
self.World.OrderGenerator = new SetChronoTankDestination( self );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "ChronoshiftDeploy")
|
||||
{
|
||||
if (chargeTick <= 0)
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.OrderGenerator = new SetChronoTankDestination(self);
|
||||
return;
|
||||
}
|
||||
|
||||
var movement = self.TraitOrDefault<IMove>();
|
||||
if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation))
|
||||
{
|
||||
@@ -76,14 +69,6 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "ChronoshiftDeploy")
|
||||
return null;
|
||||
|
||||
return (chargeTick <= 0) ? "deploy" : "deploy-blocked";
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "ChronoshiftDeploy" && chargeTick <= 0) ? "Move" : null;
|
||||
|
||||
@@ -62,7 +62,11 @@ namespace OpenRA.Mods.RA
|
||||
smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])) ;
|
||||
|
||||
foreach (var sc in smudgeCells)
|
||||
{
|
||||
smudgeLayer.AddSmudge(sc);
|
||||
if (warhead.Ore)
|
||||
world.WorldActor.Trait<ResourceLayer>().Destroy(sc);
|
||||
}
|
||||
}
|
||||
else
|
||||
smudgeLayer.AddSmudge(targetTile);
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA
|
||||
public void OnCrush(Actor crusher)
|
||||
{
|
||||
var shares = self.TraitsImplementing<CrateAction>().Select(
|
||||
a => Pair.New(a, a.GetSelectionShares(crusher)));
|
||||
a => Pair.New(a, a.GetSelectionSharesOuter(crusher)));
|
||||
var totalShares = shares.Sum(a => a.Second);
|
||||
var n = self.World.SharedRandom.Next(totalShares);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.RA.Effects;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -18,6 +19,7 @@ namespace OpenRA.Mods.RA
|
||||
public int SelectionShares = 10;
|
||||
public string Effect = null;
|
||||
public string Notification = null;
|
||||
public string[] ExcludedActorTypes = { };
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new CrateAction(init.self, this); }
|
||||
}
|
||||
@@ -32,6 +34,14 @@ namespace OpenRA.Mods.RA
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public int GetSelectionSharesOuter(Actor collector)
|
||||
{
|
||||
if (info.ExcludedActorTypes.Contains(collector.Info.Name))
|
||||
return 0;
|
||||
|
||||
return GetSelectionShares(collector);
|
||||
}
|
||||
|
||||
public virtual int GetSelectionShares(Actor collector)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets.Delegates;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -47,6 +48,14 @@ namespace OpenRA.Mods.RA
|
||||
else if (slot.Bot != null)
|
||||
{
|
||||
/* spawn a bot in this slot, "owned" by the host */
|
||||
|
||||
/* pick a random color for the bot */
|
||||
var hue = (float)w.SharedRandom.NextDouble();
|
||||
w.Map.Players[slot.MapPlayer].Color = LobbyDelegate.ColorFromHSL(hue, 1.0f, 0.7f);
|
||||
w.Map.Players[slot.MapPlayer].Color2 = LobbyDelegate.ColorFromHSL(hue, 1.0f, 0.2f);
|
||||
|
||||
/* todo: pick a random name from the pool */
|
||||
|
||||
var player = new Player(w, w.Map.Players[slot.MapPlayer], playerIndex++);
|
||||
w.AddPlayer(player);
|
||||
|
||||
@@ -54,6 +63,9 @@ namespace OpenRA.Mods.RA
|
||||
if (Game.IsHost)
|
||||
foreach (var bot in player.PlayerActor.TraitsImplementing<IBot>())
|
||||
bot.Activate(player);
|
||||
|
||||
/* a bit of a hack */
|
||||
player.IsBot = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +89,9 @@ namespace OpenRA.Mods.RA
|
||||
// Hack: All map players are neutral wrt everyone else
|
||||
if (p.Index < 0 || q.Index < 0) return Stance.Neutral;
|
||||
|
||||
if (p.IsBot ^ q.IsBot)
|
||||
return Stance.Enemy; // bots and humans hate each other
|
||||
|
||||
var pc = GetClientForPlayer(p);
|
||||
var qc = GetClientForPlayer(q);
|
||||
|
||||
|
||||
@@ -41,8 +41,9 @@ namespace OpenRA.Mods.RA.Effects
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
{
|
||||
yield return new Renderable(anim.Image,
|
||||
a.CenterLocation - .5f * anim.Image.size + offset, "effect", (int)a.CenterLocation.Y);
|
||||
if (a.IsInWorld)
|
||||
yield return new Renderable(anim.Image,
|
||||
a.CenterLocation - .5f * anim.Image.size + offset, "effect", (int)a.CenterLocation.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace OpenRA.Mods.RA.Effects
|
||||
|
||||
if (!doneDamage)
|
||||
{
|
||||
if (args.target.IsValid)
|
||||
args.dest = args.target.CenterLocation.ToInt2();
|
||||
|
||||
Combat.DoImpacts(args);
|
||||
doneDamage = true;
|
||||
}
|
||||
|
||||
@@ -13,32 +13,31 @@ using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class EngineerCaptureInfo : TraitInfo<EngineerCapture> {}
|
||||
class EngineerCapture : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class EngineerCapture : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
if (self.Owner.Stances[underCursor.Owner] == Stance.Ally) return null;
|
||||
if (!underCursor.HasTrait<Building>() || !underCursor.Info.Traits.Get<BuildingInfo>().Capturable) return null;
|
||||
|
||||
return new Order("CaptureBuilding", self, underCursor);
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<Building>( "CaptureBuilding", 5, true, false,
|
||||
_ => true, target => target.Info.Traits.Get<BuildingInfo>().Capturable );
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
return (order.OrderString == "CaptureBuilding") ? "capture" : null;
|
||||
if( order.OrderID == "CaptureBuilding" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "CaptureBuilding") ? "Attack" : null;
|
||||
|
||||
@@ -6,47 +6,35 @@
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class EngineerRepairInfo : TraitInfo<EngineerRepair> {}
|
||||
|
||||
class EngineerRepair : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class EngineerRepair : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
if (!CanRepair(self, underCursor)) return null;
|
||||
|
||||
return new Order("EngineerRepair", self, underCursor);
|
||||
}
|
||||
|
||||
bool CanRepair(Actor self, Actor a)
|
||||
{
|
||||
if (!a.HasTrait<Building>()) return false;
|
||||
return (self.Owner.Stances[a.Owner] == Stance.Ally);
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "EngineerRepair") return null;
|
||||
if (order.TargetActor == null) return null;
|
||||
return (order.TargetActor.GetDamageState() == DamageState.Undamaged) ? "goldwrench-blocked" : "goldwrench";
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get { yield return new EngineerRepairOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "EngineerRepair" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "EngineerRepair"
|
||||
@@ -71,6 +59,23 @@ namespace OpenRA.Mods.RA
|
||||
self.QueueActivity(new Move(order.TargetActor.Location, order.TargetActor));
|
||||
self.QueueActivity(new RepairBuilding(order.TargetActor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EngineerRepairOrderTargeter : UnitTraitOrderTargeter<Building>
|
||||
{
|
||||
public EngineerRepairOrderTargeter()
|
||||
: base( "EngineerRepair", 6, "goldwrench", false, true )
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
if( !base.CanTargetUnit( self, target, forceAttack, forceMove, ref cursor ) ) return false;
|
||||
|
||||
if( target.GetDamageState() > DamageState.Undamaged )
|
||||
cursor = "goldwrench-blocked";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
OpenRA.Mods.RA/FallsToEarth.cs
Normal file
57
OpenRA.Mods.RA/FallsToEarth.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
#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.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class FallsToEarthInfo : TraitInfo<FallsToEarth> { }
|
||||
|
||||
class FallsToEarth : INotifyDamage
|
||||
{
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
if (self.IsDead())
|
||||
{
|
||||
self.Trait<Health>().RemoveOnDeath = false;
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new FallToEarth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FallToEarth : CancelableActivity
|
||||
{
|
||||
int acceleration = 0;
|
||||
int spin = 0;
|
||||
|
||||
public override IActivity Tick(Actor self)
|
||||
{
|
||||
if (acceleration == 0)
|
||||
acceleration = self.World.SharedRandom.Next(2) * 2 - 1;
|
||||
|
||||
var aircraft = self.Trait<Aircraft>();
|
||||
if (aircraft.Altitude <= 0)
|
||||
{
|
||||
self.Destroy();
|
||||
return null;
|
||||
}
|
||||
|
||||
spin += acceleration;
|
||||
aircraft.Facing = (aircraft.Facing + spin) % 256;
|
||||
aircraft.Altitude--;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override bool OnCancel() { return false; }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,17 @@
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
#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 System.Collections.Generic;
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using XRandom = OpenRA.Thirdparty.Random;
|
||||
|
||||
|
||||
@@ -36,18 +45,37 @@ namespace OpenRA.Mods.RA
|
||||
int2 baseCenter;
|
||||
XRandom random = new XRandom(); //we do not use the synced random number generator.
|
||||
|
||||
World world { get { return p.PlayerActor.World; } }
|
||||
|
||||
Dictionary<string, float> unitsToBuild = new Dictionary<string, float>
|
||||
{
|
||||
{"e1", .0f},
|
||||
{"e2", .0f},
|
||||
{"e3", .0f},
|
||||
{"1tnk", .0f},
|
||||
{"2tnk", .0f},
|
||||
{"3tnk", .0f}
|
||||
};
|
||||
|
||||
Dictionary<string, float> buildingFractions = new Dictionary<string, float>
|
||||
{
|
||||
{ "proc", .2f },
|
||||
{ "barr", .05f },
|
||||
{ "tent", .05f },
|
||||
{ "weap", .05f },
|
||||
{ "pbox", .05f },
|
||||
{ "hbox", .05f },
|
||||
{ "gun", .05f },
|
||||
{ "tsla", .05f },
|
||||
{ "ftur", .05f },
|
||||
{ "agun", .01f },
|
||||
{ "sam", .01f },
|
||||
{ "atek", .01f },
|
||||
{ "stek", .01f },
|
||||
{ "silo", .05f },
|
||||
{ "fix", .01f },
|
||||
{ "hpad", .01f },
|
||||
{ "afld", .01f },
|
||||
//{ "hpad", .01f },
|
||||
//{ "afld", .01f },
|
||||
{ "dome", .01f },
|
||||
};
|
||||
|
||||
@@ -62,7 +90,8 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
const int MaxBaseDistance = 15;
|
||||
|
||||
BuildState state = BuildState.WaitForFeedback;
|
||||
BuildState bstate = BuildState.WaitForFeedback;
|
||||
BuildState dstate = BuildState.WaitForFeedback;
|
||||
|
||||
/* called by the host's player creation code */
|
||||
public void Activate(Player p)
|
||||
@@ -86,11 +115,18 @@ namespace OpenRA.Mods.RA
|
||||
return buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count()));
|
||||
}
|
||||
|
||||
bool HasAdequatePower()
|
||||
{
|
||||
/* note: CNC `fact` provides a small amount of power. don't get jammed because of that. */
|
||||
return playerPower.PowerProvided > 50 &&
|
||||
playerPower.PowerProvided > playerPower.PowerDrained * 1.2;
|
||||
}
|
||||
|
||||
ActorInfo ChooseBuildingToBuild(ProductionQueue queue)
|
||||
{
|
||||
var buildableThings = queue.BuildableItems();
|
||||
|
||||
if (playerPower.PowerProvided <= playerPower.PowerDrained * 1.2) /* try to maintain 20% excess power */
|
||||
if (!HasAdequatePower()) /* try to maintain 20% excess power */
|
||||
{
|
||||
/* find the best thing we can build which produces power */
|
||||
var best = buildableThings.Where(a => GetPowerProvidedBy(a) > 0)
|
||||
@@ -107,7 +143,8 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
var myBuildings = p.World.Queries.OwnedBy[p].WithTrait<Building>()
|
||||
.Select( a => a.Actor.Info.Name ).ToArray();
|
||||
|
||||
|
||||
|
||||
foreach (var frac in buildingFractions)
|
||||
if (buildableThings.Any(b => b.Name == frac.Key))
|
||||
if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length)
|
||||
@@ -116,14 +153,29 @@ namespace OpenRA.Mods.RA
|
||||
return null;
|
||||
}
|
||||
|
||||
ActorInfo ChooseDefenseToBuild(ProductionQueue queue)
|
||||
{
|
||||
var buildableThings = queue.BuildableItems();
|
||||
|
||||
var myBuildings = p.World.Queries.OwnedBy[p].WithTrait<Building>()
|
||||
.Select(a => a.Actor.Info.Name).ToArray();
|
||||
|
||||
foreach (var frac in buildingFractions)
|
||||
if (buildableThings.Any(b => b.Name == frac.Key))
|
||||
if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length)
|
||||
return Rules.Info[frac.Key];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
int2? ChooseBuildLocation(ProductionItem item)
|
||||
{
|
||||
var bi = Rules.Info[item.Item].Traits.Get<BuildingInfo>();
|
||||
|
||||
for (var k = 0; k < MaxBaseDistance; k++)
|
||||
foreach (var t in Game.world.FindTilesInCircle(baseCenter, k))
|
||||
if (Game.world.CanPlaceBuilding(item.Item, bi, t, null))
|
||||
if (Game.world.IsCloseEnoughToBase(p, item.Item, bi, t))
|
||||
foreach (var t in world.FindTilesInCircle(baseCenter, k))
|
||||
if (world.CanPlaceBuilding(item.Item, bi, t, null))
|
||||
if (world.IsCloseEnoughToBase(p, item.Item, bi, t))
|
||||
return t;
|
||||
|
||||
return null; // i don't know where to put it.
|
||||
@@ -158,7 +210,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
|
||||
BuildBuildings();
|
||||
//build Defense
|
||||
BuildDefense();
|
||||
//build Ship
|
||||
}
|
||||
|
||||
@@ -173,7 +225,29 @@ namespace OpenRA.Mods.RA
|
||||
//This is purely to identify production buildings that don't have a rally point set.
|
||||
List<Actor> activeProductionBuildings = new List<Actor>();
|
||||
|
||||
private void AssignRolesToIdleUnits(Actor self)
|
||||
bool IsHumanPlayer(Player p)
|
||||
{
|
||||
/* hack hack: this actually detects 'is not HackyAI' -- possibly actually a good thing. */
|
||||
var hackyAI = p.PlayerActor.Trait<HackyAI>();
|
||||
return !hackyAI.enabled;
|
||||
}
|
||||
|
||||
int2? ChooseEnemyTarget()
|
||||
{
|
||||
// Criteria for picking an enemy:
|
||||
// 1. not ourself.
|
||||
// 2. human.
|
||||
// 3. not dead.
|
||||
|
||||
var possibleTargets = world.WorldActor.Trait<MPStartLocations>().Start
|
||||
.Where(kv => kv.Key != p && IsHumanPlayer(kv.Key)
|
||||
&& p.WinState == WinState.Undefined)
|
||||
.Select(kv => kv.Value);
|
||||
|
||||
return possibleTargets.Any() ? possibleTargets.Random(random) : (int2?) null;
|
||||
}
|
||||
|
||||
void AssignRolesToIdleUnits(Actor self)
|
||||
{
|
||||
//HACK: trim these lists -- we really shouldn't be hanging onto all this state
|
||||
//when it's invalidated so easily, but that's Matthew/Alli's problem.
|
||||
@@ -196,17 +270,18 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
/* Create an attack force when we have enough units around our base. */
|
||||
// (don't bother leaving any behind for defense.)
|
||||
if (unitsHangingAroundTheBase.Count > 5)
|
||||
if (unitsHangingAroundTheBase.Count > 8)
|
||||
{
|
||||
Game.Debug("Launch an attack.");
|
||||
|
||||
int2 attackTarget = Game.world.WorldActor.Trait<MPStartLocations>().Start
|
||||
.Where(kv => kv.Key != p)
|
||||
.Select(kv => kv.Value)
|
||||
.Random(random);
|
||||
foreach (var a in unitsHangingAroundTheBase)
|
||||
if (TryToMove(a, attackTarget))
|
||||
var attackTarget = ChooseEnemyTarget();
|
||||
if (attackTarget == null)
|
||||
return;
|
||||
|
||||
foreach (var a in unitsHangingAroundTheBase)
|
||||
if (TryToMove(a, attackTarget.Value))
|
||||
attackForce.Add(a);
|
||||
|
||||
unitsHangingAroundTheBase.Clear();
|
||||
}
|
||||
}
|
||||
@@ -215,12 +290,15 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
var newProdBuildings = self.World.Queries.OwnedBy[p]
|
||||
.Where(a => (a.TraitOrDefault<RallyPoint>() != null
|
||||
&& !activeProductionBuildings.Contains(a))).ToArray();
|
||||
&& !activeProductionBuildings.Contains(a)
|
||||
)).ToArray();
|
||||
|
||||
foreach (var a in newProdBuildings)
|
||||
{
|
||||
activeProductionBuildings.Add(a);
|
||||
int2 newRallyPoint = ChooseRallyLocationNear(a.Location);
|
||||
newRallyPoint.X += 4;
|
||||
newRallyPoint.Y += 4;
|
||||
Game.IssueOrder(new Order("SetRallyPoint", a, newRallyPoint));
|
||||
}
|
||||
}
|
||||
@@ -228,10 +306,11 @@ namespace OpenRA.Mods.RA
|
||||
//won't work for shipyards...
|
||||
private int2 ChooseRallyLocationNear(int2 startPos)
|
||||
{
|
||||
foreach (var t in Game.world.FindTilesInCircle(startPos, 6))
|
||||
if (Game.world.IsCellBuildable(t, false) && t != startPos)
|
||||
Random r = new Random();
|
||||
foreach (var t in world.FindTilesInCircle(startPos, 8))
|
||||
if (world.IsCellBuildable(t, false) && t != startPos && r.Next(64) == 0)
|
||||
return t;
|
||||
|
||||
|
||||
return startPos; // i don't know where to put it.
|
||||
}
|
||||
|
||||
@@ -276,7 +355,7 @@ namespace OpenRA.Mods.RA
|
||||
private void BuildRandom(string category)
|
||||
{
|
||||
// Pick a free queue
|
||||
var queue = Game.world.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
var queue = world.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(a => a.Actor.Owner == p &&
|
||||
a.Trait.Info.Type == category &&
|
||||
a.Trait.CurrentItem() == null)
|
||||
@@ -287,17 +366,30 @@ namespace OpenRA.Mods.RA
|
||||
return;
|
||||
|
||||
var unit = ChooseRandomUnitToBuild(queue);
|
||||
if (unit != null)
|
||||
{
|
||||
Game.IssueOrder(Order.StartProduction(queue.self, unit.Name, 1));
|
||||
}
|
||||
Boolean found = false;
|
||||
if (unit != null)
|
||||
{
|
||||
foreach (var un in unitsToBuild)
|
||||
{
|
||||
if (un.Key == unit.Name)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == true)
|
||||
{
|
||||
Game.IssueOrder(Order.StartProduction(queue.self, unit.Name, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildBuildings()
|
||||
{
|
||||
// Pick a free queue
|
||||
var queue = Game.world.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(a => a.Actor.Owner == p && a.Trait.Info.Type == "Building")
|
||||
var queue = world.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(a => a.Actor.Owner == p && a.Trait.Info.Type == "Building")
|
||||
.Select(a => a.Trait)
|
||||
.FirstOrDefault();
|
||||
|
||||
@@ -305,19 +397,20 @@ namespace OpenRA.Mods.RA
|
||||
return;
|
||||
|
||||
var currentBuilding = queue.CurrentItem();
|
||||
switch (state)
|
||||
switch (bstate)
|
||||
{
|
||||
case BuildState.ChooseItem:
|
||||
{
|
||||
var item = ChooseBuildingToBuild(queue);
|
||||
if (item == null)
|
||||
{
|
||||
state = BuildState.WaitForFeedback;
|
||||
bstate = BuildState.WaitForFeedback;
|
||||
lastThinkTick = ticks;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = BuildState.WaitForProduction;
|
||||
Game.Debug("AI: Starting production of {0}".F(item.Name));
|
||||
bstate = BuildState.WaitForProduction;
|
||||
Game.IssueOrder(Order.StartProduction(queue.self, item.Name, 1));
|
||||
}
|
||||
}
|
||||
@@ -330,7 +423,7 @@ namespace OpenRA.Mods.RA
|
||||
Game.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false));
|
||||
else if (currentBuilding.Done)
|
||||
{
|
||||
state = BuildState.WaitForFeedback;
|
||||
bstate = BuildState.WaitForFeedback;
|
||||
lastThinkTick = ticks;
|
||||
|
||||
/* place the building */
|
||||
@@ -338,7 +431,7 @@ namespace OpenRA.Mods.RA
|
||||
if (location == null)
|
||||
{
|
||||
Game.Debug("AI: Nowhere to place {0}".F(currentBuilding.Item));
|
||||
Game.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item));
|
||||
Game.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -349,7 +442,69 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
case BuildState.WaitForFeedback:
|
||||
if (ticks - lastThinkTick > feedbackTime)
|
||||
state = BuildState.ChooseItem;
|
||||
bstate = BuildState.ChooseItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildDefense()
|
||||
{
|
||||
// Pick a free queue
|
||||
var queue = world.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(a => a.Actor.Owner == p && a.Trait.Info.Type == "Defense")
|
||||
.Select(a => a.Trait)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (queue == null)
|
||||
return;
|
||||
|
||||
var currentBuilding = queue.CurrentItem();
|
||||
switch (dstate)
|
||||
{
|
||||
case BuildState.ChooseItem:
|
||||
{
|
||||
var item = ChooseDefenseToBuild(queue);
|
||||
if (item == null)
|
||||
{
|
||||
dstate = BuildState.WaitForFeedback;
|
||||
lastThinkTick = ticks;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.Debug("AI: Starting production of {0}".F(item.Name));
|
||||
dstate = BuildState.WaitForProduction;
|
||||
Game.IssueOrder(Order.StartProduction(queue.self, item.Name, 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildState.WaitForProduction:
|
||||
if (currentBuilding == null) return; /* let it happen.. */
|
||||
|
||||
else if (currentBuilding.Paused)
|
||||
Game.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false));
|
||||
else if (currentBuilding.Done)
|
||||
{
|
||||
dstate = BuildState.WaitForFeedback;
|
||||
lastThinkTick = ticks;
|
||||
|
||||
/* place the building */
|
||||
var location = ChooseBuildLocation(currentBuilding);
|
||||
if (location == null)
|
||||
{
|
||||
Game.Debug("AI: Nowhere to place {0}".F(currentBuilding.Item));
|
||||
Game.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.IssueOrder(new Order("PlaceBuilding", p.PlayerActor, location.Value, currentBuilding.Item));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildState.WaitForFeedback:
|
||||
if (ticks - lastThinkTick > feedbackTime)
|
||||
dstate = BuildState.ChooseItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.Traits.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -30,7 +31,7 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
|
||||
public class Harvester : IIssueOrder, IResolveOrder, INotifyDamage, IPips,
|
||||
IRenderModifier, IExplodeModifier, IOrderCursor, IOrderVoice,
|
||||
IRenderModifier, IExplodeModifier, IOrderVoice,
|
||||
ISpeedModifier
|
||||
{
|
||||
Dictionary<ResourceTypeInfo, int> contents = new Dictionary<ResourceTypeInfo, int>();
|
||||
@@ -93,40 +94,26 @@ namespace OpenRA.Mods.RA
|
||||
contents.Clear();
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
|
||||
// Don't leak info about resources under the shroud
|
||||
if (!self.World.LocalPlayer.Shroud.IsExplored(xy)) return null;
|
||||
|
||||
if (underCursor != null
|
||||
&& self.Owner.Stances[ underCursor.Owner ] == Stance.Ally
|
||||
&& underCursor.HasTrait<IAcceptOre>())
|
||||
{
|
||||
return new Order("Deliver", self, underCursor);
|
||||
}
|
||||
var res = self.World.WorldActor.Trait<ResourceLayer>().GetResource(xy);
|
||||
var info = self.Info.Traits.Get<HarvesterInfo>();
|
||||
|
||||
if (underCursor == null && res != null && info.Resources.Contains(res.info.Name) && !IsFull)
|
||||
return new Order("Harvest", self, xy);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Harvest") return "attackmove";
|
||||
if (order.OrderString == "Deliver") return IsEmpty ? "enter-blocked" : "enter";
|
||||
return null;
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<IAcceptOre>( "Deliver", 5, false, true, _ => true, _ => !IsEmpty );
|
||||
yield return new HarvestOrderTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "Deliver" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
if( order.OrderID == "Harvest" )
|
||||
return new Order( order.OrderID, self, Util.CellContaining( target.CenterLocation ) );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "Harvest" || (order.OrderString == "Deliver" && !IsEmpty)) ? "Move" : null;
|
||||
@@ -153,7 +140,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
if (order.TargetActor != LinkedProc)
|
||||
{
|
||||
if (LinkedProc != null)
|
||||
if (LinkedProc != null && LinkedProc.IsInWorld)
|
||||
LinkedProc.TraitsImplementing<IAcceptOre>().FirstOrDefault().UnlinkHarvester(LinkedProc,self);
|
||||
LinkedProc = order.TargetActor;
|
||||
LinkedProc.TraitsImplementing<IAcceptOre>().FirstOrDefault().LinkHarvester(LinkedProc,self);
|
||||
@@ -222,5 +209,30 @@ namespace OpenRA.Mods.RA
|
||||
return float2.Lerp(1f, Info.FullyLoadedSpeed,
|
||||
contents.Values.Sum() / (float)Info.Capacity);
|
||||
}
|
||||
|
||||
class HarvestOrderTargeter : IOrderTargeter
|
||||
{
|
||||
public string OrderID { get { return "Harvest";}}
|
||||
public int OrderPriority { get { return 10; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
// Don't leak info about resources under the shroud
|
||||
if( !self.World.LocalPlayer.Shroud.IsExplored( location ) ) return false;
|
||||
|
||||
var res = self.World.WorldActor.Trait<ResourceLayer>().GetResource( location );
|
||||
var info = self.Info.Traits.Get<HarvesterInfo>();
|
||||
|
||||
if( res == null ) return false;
|
||||
if( !info.Resources.Contains( res.info.Name ) ) return false;
|
||||
cursor = "attackmove";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -29,7 +30,7 @@ namespace OpenRA.Mods.RA
|
||||
public override object Create( ActorInitializer init ) { return new Helicopter( init, this); }
|
||||
}
|
||||
|
||||
class Helicopter : Aircraft, ITick, IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class Helicopter : Aircraft, ITick, IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public IDisposable reservation;
|
||||
HelicopterInfo Info;
|
||||
@@ -39,32 +40,25 @@ namespace OpenRA.Mods.RA
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
// Force move takes precidence
|
||||
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<Building>( "Enter", 5, false, true,
|
||||
target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) );
|
||||
|
||||
if (underCursor != null && AircraftCanEnter(self, underCursor)
|
||||
&& underCursor.Owner == self.Owner)
|
||||
return new Order("Enter", self, underCursor);
|
||||
|
||||
if (self.TraitOrDefault<IMove>().CanEnterCell(xy))
|
||||
return new Order("Move", self, xy);
|
||||
|
||||
return null;
|
||||
yield return new AircraftMoveOrderTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (order.OrderString == "Move") return "move";
|
||||
if (order.OrderString == "Enter")
|
||||
return Reservable.IsReserved(order.TargetActor) ? "enter-blocked" : "enter";
|
||||
|
||||
if( order.OrderID == "Enter" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
if( order.OrderID == "Move" )
|
||||
return new Order( order.OrderID, self, Util.CellContaining( target.CenterLocation ) );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,44 +26,35 @@ namespace OpenRA.Mods.RA
|
||||
public readonly string[] RearmBuildings = { "fix" };
|
||||
}
|
||||
|
||||
class Minelayer : IIssueOrder, IResolveOrder, IOrderCursor, IPostRenderSelection
|
||||
class Minelayer : IIssueOrder, IResolveOrder, IPostRenderSelection
|
||||
{
|
||||
/* [Sync] when sync can cope with arrays! */
|
||||
public int2[] minefield = null;
|
||||
[Sync] int2 minefieldStart;
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get { yield return new BeginMinefieldOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right && underCursor == null && mi.Modifiers.HasModifier(Modifiers.Ctrl))
|
||||
return new Order("BeginMinefield", self, xy);
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order is BeginMinefieldOrderTargeter )
|
||||
{
|
||||
var start = Util.CellContaining( target.CenterLocation );
|
||||
self.World.OrderGenerator = new MinefieldOrderGenerator( self, start );
|
||||
return new Order( "BeginMinefield", self, start );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "BeginMinefield") ? "ability" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "BeginMinefield")
|
||||
{
|
||||
if( order.OrderString == "BeginMinefield" )
|
||||
minefieldStart = order.TargetLocation;
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.OrderGenerator = new MinefieldOrderGenerator(self);
|
||||
}
|
||||
|
||||
if (order.OrderString == "PlaceMinefield")
|
||||
{
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
var movement = self.Trait<IMove>();
|
||||
|
||||
minefield = GetMinefieldCells(minefieldStart, order.TargetLocation,
|
||||
@@ -97,9 +88,10 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
class MinefieldOrderGenerator : IOrderGenerator
|
||||
{
|
||||
Actor minelayer;
|
||||
readonly Actor minelayer;
|
||||
readonly int2 minefieldStart;
|
||||
|
||||
public MinefieldOrderGenerator(Actor self) { minelayer = self; }
|
||||
public MinefieldOrderGenerator(Actor self, int2 xy ) { minelayer = self; minefieldStart = xy; }
|
||||
|
||||
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
@@ -110,26 +102,31 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
//.Where(a => a.Info.Traits.Contains<SelectableInfo>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>()
|
||||
? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (mi.Button == MouseButton.Right && underCursor == null)
|
||||
yield return new Order("PlaceMinefield", minelayer, xy);
|
||||
if( mi.Button == MouseButton.Right && underCursor == null )
|
||||
{
|
||||
minelayer.World.CancelInputMode();
|
||||
yield return new Order( "PlaceMinefield", minelayer, xy );
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (minelayer.IsDead() || !minelayer.IsInWorld)
|
||||
if (!minelayer.IsInWorld || minelayer.IsDead())
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
int2 lastMousePos;
|
||||
public void RenderAfterWorld(World world)
|
||||
{
|
||||
var ml = minelayer.Trait<Minelayer>();
|
||||
if (!minelayer.IsInWorld)
|
||||
return;
|
||||
|
||||
var movement = minelayer.Trait<IMove>();
|
||||
var minefield = GetMinefieldCells(ml.minefieldStart, lastMousePos, minelayer.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
|
||||
var minefield = GetMinefieldCells(minefieldStart, lastMousePos, minelayer.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
|
||||
.Where(p => movement.CanEnterCell(p)).ToArray();
|
||||
|
||||
world.WorldRenderer.DrawLocus(Color.Cyan, minefield);
|
||||
@@ -148,5 +145,22 @@ namespace OpenRA.Mods.RA
|
||||
if (minefield != null)
|
||||
self.World.WorldRenderer.DrawLocus(Color.Cyan, minefield);
|
||||
}
|
||||
|
||||
class BeginMinefieldOrderTargeter : IOrderTargeter
|
||||
{
|
||||
public string OrderID { get { return "BeginMinefield"; } }
|
||||
public int OrderPriority { get { return 5; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = "ability";
|
||||
return ( actorsAtLocation.Count == 0 && forceAttack );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +91,13 @@
|
||||
<Compile Include="Effects\RepairIndicator.cs" />
|
||||
<Compile Include="Effects\Smoke.cs" />
|
||||
<Compile Include="Effects\TeslaZap.cs" />
|
||||
<Compile Include="FallsToEarth.cs" />
|
||||
<Compile Include="LimitedAmmo.cs" />
|
||||
<Compile Include="MPStartLocations.cs" />
|
||||
<Compile Include="Orders\DeployOrderTargeter.cs" />
|
||||
<Compile Include="Orders\EnterBuildingOrderTargeter.cs" />
|
||||
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
||||
<Compile Include="Orders\UnitOrderTargeter.cs" />
|
||||
<Compile Include="Player\ActorGroupProxy.cs" />
|
||||
<Compile Include="Aircraft.cs" />
|
||||
<Compile Include="Player\ClassicProductionQueue.cs" />
|
||||
@@ -203,6 +207,7 @@
|
||||
<Compile Include="SupportPowers\NukePower.cs" />
|
||||
<Compile Include="SupportPowers\SupportPower.cs" />
|
||||
<Compile Include="TakeCover.cs" />
|
||||
<Compile Include="TargetableAircraft.cs" />
|
||||
<Compile Include="TeslaInstantKills.cs" />
|
||||
<Compile Include="Crates\ResetRadarCrateAction.cs" />
|
||||
<Compile Include="ThrowsParticles.cs" />
|
||||
|
||||
39
OpenRA.Mods.RA/Orders/DeployOrderTargeter.cs
Executable file
39
OpenRA.Mods.RA/Orders/DeployOrderTargeter.cs
Executable file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
{
|
||||
class DeployOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly Func<bool> useDeployCursor;
|
||||
|
||||
public DeployOrderTargeter( string order, int priority )
|
||||
: this( order, priority, () => true )
|
||||
{
|
||||
}
|
||||
|
||||
public DeployOrderTargeter( string order, int priority, Func<bool> useDeployCursor )
|
||||
{
|
||||
this.OrderID = order;
|
||||
this.OrderPriority = priority;
|
||||
this.useDeployCursor = useDeployCursor;
|
||||
}
|
||||
|
||||
public string OrderID { get; private set; }
|
||||
public int OrderPriority { get; private set; }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = useDeployCursor() ? "deploy" : "deploy-blocked";
|
||||
return self == target;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs
Executable file
30
OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs
Executable file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
{
|
||||
class EnterOrderTargeter<T> : UnitTraitOrderTargeter<T>
|
||||
{
|
||||
readonly Func<Actor, bool> canTarget;
|
||||
readonly Func<Actor, bool> useEnterCursor;
|
||||
|
||||
public EnterOrderTargeter( string order, int priority, bool targetEnemy, bool targetAlly,
|
||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor )
|
||||
: base( order, priority, "enter", targetEnemy, targetAlly )
|
||||
{
|
||||
this.canTarget = canTarget;
|
||||
this.useEnterCursor = useEnterCursor;
|
||||
}
|
||||
|
||||
public override bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
if( !base.CanTargetUnit( self, target, forceAttack, forceMove, ref cursor ) ) return false;
|
||||
if( !canTarget( target ) ) return false;
|
||||
cursor = useEnterCursor( target ) ? "enter" : "enter-blocked";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,13 @@ namespace OpenRA.Mods.RA.Orders
|
||||
if (mi.Button == MouseButton.Right)
|
||||
world.CancelInputMode();
|
||||
|
||||
return InnerOrder(world, xy, mi);
|
||||
var ret = InnerOrder( world, xy, mi ).ToList();
|
||||
foreach( var order in ret )
|
||||
{
|
||||
world.CancelInputMode();
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
IEnumerable<Order> InnerOrder(World world, int2 xy, MouseInput mi)
|
||||
@@ -58,14 +64,11 @@ namespace OpenRA.Mods.RA.Orders
|
||||
public void Tick( World world )
|
||||
{
|
||||
// Find the queue with the target actor
|
||||
var queue = Producer.TraitsImplementing<ProductionQueue>()
|
||||
.Where(p => p.CurrentItem() != null &&
|
||||
p.CurrentItem().Item == Building &&
|
||||
p.CurrentItem().RemainingTime == 0)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (queue == null)
|
||||
world.CancelInputMode();
|
||||
//var queue = Producer.TraitsImplementing<ProductionQueue>()
|
||||
// .Where(p => p.CurrentItem() != null &&
|
||||
// p.CurrentItem().Item == Building &&
|
||||
// p.CurrentItem().RemainingTime == 0)
|
||||
// .FirstOrDefault();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld( World world ) {}
|
||||
|
||||
70
OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs
Executable file
70
OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs
Executable file
@@ -0,0 +1,70 @@
|
||||
#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 System.Collections.Generic;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
{
|
||||
class UnitOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly string cursor;
|
||||
readonly bool targetEnemyUnits, targetAllyUnits;
|
||||
|
||||
public UnitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits )
|
||||
{
|
||||
this.OrderID = order;
|
||||
this.OrderPriority = priority;
|
||||
this.cursor = cursor;
|
||||
this.targetEnemyUnits = targetEnemyUnits;
|
||||
this.targetAllyUnits = targetAllyUnits;
|
||||
}
|
||||
|
||||
public string OrderID { get; private set; }
|
||||
public int OrderPriority { get; private set; }
|
||||
|
||||
public virtual bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
if( self == null ) throw new ArgumentNullException( "self" );
|
||||
if( target == null ) throw new ArgumentNullException( "target" );
|
||||
|
||||
cursor = this.cursor;
|
||||
|
||||
var playerRelationship = self.Owner.Stances[ target.Owner ];
|
||||
|
||||
if( !forceAttack && playerRelationship == Stance.Ally && !targetAllyUnits ) return false;
|
||||
if( !forceAttack && playerRelationship == Stance.Enemy && !targetEnemyUnits ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class UnitTraitOrderTargeter<T> : UnitOrderTargeter
|
||||
{
|
||||
public UnitTraitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits )
|
||||
: base( order, priority, cursor, targetEnemyUnits, targetAllyUnits )
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
if( !base.CanTargetUnit( self, target, forceAttack, forceMove, ref cursor ) ) return false;
|
||||
if( !target.HasTrait<T>() ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,64 +8,64 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class PassengerInfo : TraitInfo<Passenger>
|
||||
class PassengerInfo : ITraitInfo
|
||||
{
|
||||
public readonly string CargoType = null;
|
||||
public readonly PipType PipType = PipType.Green;
|
||||
|
||||
public object Create( ActorInitializer init ) { return new Passenger( init.self ); }
|
||||
}
|
||||
|
||||
class Passenger : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class Passenger : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
readonly Actor self;
|
||||
public Passenger( Actor self ) { this.self = self; }
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<Cargo>( "EnterTransport", 6, false, true,
|
||||
target => IsCorrectCargoType( target ), target => CanEnter( target ) );
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right)
|
||||
return null;
|
||||
|
||||
if (underCursor == null || underCursor.Owner != self.Owner)
|
||||
return null;
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "EnterTransport" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
var cargo = underCursor.TraitOrDefault<Cargo>();
|
||||
if (cargo == null)
|
||||
return null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool IsCorrectCargoType( Actor target )
|
||||
{
|
||||
var pi = self.Info.Traits.Get<PassengerInfo>();
|
||||
var ci = underCursor.Info.Traits.Get<CargoInfo>();
|
||||
if (!ci.Types.Contains(pi.CargoType))
|
||||
return null;
|
||||
|
||||
return new Order("EnterTransport", self, underCursor);
|
||||
}
|
||||
|
||||
bool CanEnter(Actor self, Actor a)
|
||||
{
|
||||
var cargo = a.TraitOrDefault<Cargo>();
|
||||
return (cargo != null && !cargo.IsFull(a));
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "EnterTransport") return null;
|
||||
return CanEnter(self, order.TargetActor) ? "enter" : "enter-blocked";
|
||||
var ci = target.Info.Traits.Get<CargoInfo>();
|
||||
return ci.Types.Contains( pi.CargoType );
|
||||
}
|
||||
|
||||
bool CanEnter( Actor target )
|
||||
{
|
||||
var cargo = target.TraitOrDefault<Cargo>();
|
||||
return (cargo != null && !cargo.IsFull(target));
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "EnterTransport" ||
|
||||
!CanEnter(self, order.TargetActor)) return null;
|
||||
!CanEnter(order.TargetActor)) return null;
|
||||
return "Move";
|
||||
}
|
||||
|
||||
@@ -73,7 +73,9 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
if (order.OrderString == "EnterTransport")
|
||||
{
|
||||
if (!CanEnter(self, order.TargetActor)) return;
|
||||
if (order.TargetActor == null) return;
|
||||
if (!CanEnter(order.TargetActor)) return;
|
||||
if (!IsCorrectCargoType(order.TargetActor)) return;
|
||||
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.AddFrameEndTask(w =>
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -22,7 +24,7 @@ namespace OpenRA.Mods.RA
|
||||
public override object Create( ActorInitializer init ) { return new Plane( init, this ); }
|
||||
}
|
||||
|
||||
public class Plane : Aircraft, IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice, ITick
|
||||
public class Plane : Aircraft, IIssueOrder, IResolveOrder, IOrderVoice, ITick
|
||||
{
|
||||
public IDisposable reservation;
|
||||
|
||||
@@ -46,31 +48,28 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
// Force move takes precidence
|
||||
return mi.Modifiers.HasModifier(Modifiers.Alt) ? int.MaxValue : 0;
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<Building>( "Enter", 5, false, true,
|
||||
target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) );
|
||||
|
||||
yield return new AircraftMoveOrderTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button == MouseButton.Left) return null;
|
||||
if (underCursor != null && AircraftCanEnter(self, underCursor)
|
||||
&& underCursor.Owner == self.Owner)
|
||||
return new Order("Enter", self, underCursor);
|
||||
|
||||
return new Order("Move", self, xy);
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Move") return "move";
|
||||
if (order.OrderString == "Enter")
|
||||
return Reservable.IsReserved(order.TargetActor) ? "enter-blocked" : "enter";
|
||||
|
||||
if( order.OrderID == "Enter" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
if( order.OrderID == "Move" )
|
||||
return new Order( order.OrderID, self, Util.CellContaining( target.CenterLocation ) );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "Move" || order.OrderString == "Enter") ? "Move" : null;
|
||||
@@ -134,4 +133,21 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AircraftMoveOrderTargeter : IOrderTargeter
|
||||
{
|
||||
public string OrderID { get { return "Move"; } }
|
||||
public int OrderPriority { get { return 4; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
cursor = "move";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (producers.Count() == 0)
|
||||
{
|
||||
CancelProduction(name);
|
||||
CancelProduction(name,1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
case "CancelProduction":
|
||||
{
|
||||
CancelProduction(order.TargetString);
|
||||
CancelProduction(order.TargetString,order.TargetLocation.X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -194,15 +194,26 @@ namespace OpenRA.Mods.RA
|
||||
return (int) time;
|
||||
}
|
||||
|
||||
protected void CancelProduction( string itemName )
|
||||
{
|
||||
protected void CancelProduction(string itemName, int numberToCancel)
|
||||
{
|
||||
if (Queue.Count == 0)
|
||||
return; // Nothing to do here
|
||||
|
||||
var lastIndex = Queue.FindLastIndex( a => a.Item == itemName );
|
||||
if (lastIndex > 0)
|
||||
|
||||
var lastIndex = Queue.FindLastIndex(a => a.Item == itemName);
|
||||
|
||||
while (lastIndex > 0)
|
||||
{
|
||||
|
||||
Queue.RemoveAt(lastIndex);
|
||||
else if( lastIndex == 0 )
|
||||
lastIndex = Queue.FindLastIndex(a => a.Item == itemName);
|
||||
if (numberToCancel > 0)
|
||||
--numberToCancel;
|
||||
if (numberToCancel == 0)
|
||||
break;
|
||||
//else negative, continue deleting all orders
|
||||
}
|
||||
|
||||
if (lastIndex == 0)
|
||||
{
|
||||
var item = Queue[0];
|
||||
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(item.TotalCost - item.RemainingCost); // refund what's been paid so far.
|
||||
@@ -226,9 +237,16 @@ namespace OpenRA.Mods.RA
|
||||
return a.TraitsImplementing<IDisable>().Any(d => d.Disabled);
|
||||
}
|
||||
|
||||
// Builds a unit from the actor that holds this queue (1 queue per building)
|
||||
protected virtual void BuildUnit( string name )
|
||||
{
|
||||
// queue lives on actor; is produced at same actor
|
||||
// Cannot produce if i'm dead
|
||||
if (!self.IsInWorld || self.IsDead())
|
||||
{
|
||||
CancelProduction(name, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var sp = self.TraitsImplementing<Production>().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault();
|
||||
if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ]))
|
||||
FinishProduction();
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class PrimaryBuildingInfo : TraitInfo<PrimaryBuilding> { }
|
||||
|
||||
class PrimaryBuilding : IIssueOrder, IResolveOrder, IOrderCursor, ITags
|
||||
class PrimaryBuilding : IIssueOrder, IResolveOrder, ITags
|
||||
{
|
||||
bool isPrimary = false;
|
||||
public bool IsPrimary { get { return isPrimary; } }
|
||||
@@ -26,23 +27,19 @@ namespace OpenRA.Mods.RA
|
||||
yield return (isPrimary) ? TagType.Primary : TagType.None;
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 0;
|
||||
get { yield return new DeployOrderTargeter( "PrimaryProducer", 1 ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button == MouseButton.Right && underCursor == self)
|
||||
return new Order("PrimaryProducer", self);
|
||||
if( order.OrderID == "PrimaryProducer" )
|
||||
return new Order( order.OrderID, self );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "PrimaryProducer") ? "deploy" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PrimaryProducer")
|
||||
|
||||
@@ -43,15 +43,17 @@ namespace OpenRA.Mods.RA
|
||||
anim.Image, Traits.Util.CenterOfCell(rallyPoint));
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 0;
|
||||
get { yield return new RallyPointOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button == MouseButton.Left || underCursor != null) return null;
|
||||
return new Order("SetRallyPoint", self, xy);
|
||||
if( order.OrderID == "SetRallyPoint" )
|
||||
return new Order( order.OrderID, self, Traits.Util.CellContaining( target.CenterLocation ) );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResolveOrder( Actor self, Order order )
|
||||
@@ -61,5 +63,21 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
|
||||
public void Tick(Actor self) { anim.Tick(); }
|
||||
|
||||
class RallyPointOrderTargeter : IOrderTargeter
|
||||
{
|
||||
public string OrderID { get { return "SetRallyPoint"; } }
|
||||
public int OrderPriority { get { return 0; } }
|
||||
|
||||
public bool CanTargetUnit( Actor self, Actor target, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanTargetLocation( Actor self, int2 location, List<Actor> actorsAtLocation, bool forceAttack, bool forceMove, ref string cursor )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace OpenRA.Mods.RA.Render
|
||||
|
||||
public void PlayCustomAnimBackwards(Actor self, string name, Action a)
|
||||
{
|
||||
var hasSequence = anim.HasSequence(NormalizeSequence(self, name));
|
||||
anim.PlayBackwardsThen(NormalizeSequence(self, name),
|
||||
() => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace OpenRA.Mods.RA.Render
|
||||
public override object Create(ActorInitializer init) { return new RenderSpy(init.self); }
|
||||
}
|
||||
|
||||
class RenderSpy : RenderInfantry, IRenderModifier, IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class RenderSpy : RenderInfantry, IRenderModifier, IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
Player disguisedAsPlayer;
|
||||
string disguisedAsSprite;
|
||||
@@ -55,25 +56,20 @@ namespace OpenRA.Mods.RA.Render
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get { yield return new UnitTraitOrderTargeter<RenderInfantry>( "Disguise", 5, "ability", true, true ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (underCursor != null && underCursor.HasTrait<RenderInfantry>())
|
||||
return new Order("Disguise", self, underCursor);
|
||||
if( order.OrderID == "Disguise" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
return order.OrderString == "Disguise" ? "ability" : null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return order.OrderString == "Disguise" ? "Attack" : null;
|
||||
|
||||
@@ -51,8 +51,8 @@ namespace OpenRA.Mods.RA.Render
|
||||
public override void Tick(Actor self)
|
||||
{
|
||||
base.Tick(self);
|
||||
|
||||
var isFlying = self.Trait<IMove>().Altitude > 0;
|
||||
|
||||
var isFlying = self.Trait<IMove>().Altitude > 0 && !self.IsDead();
|
||||
if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor"))
|
||||
return;
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ using OpenRA.Effects;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
@@ -23,53 +25,51 @@ namespace OpenRA.Mods.RA
|
||||
public virtual object Create(ActorInitializer init) { return new Repairable(init.self); }
|
||||
}
|
||||
|
||||
class Repairable : IIssueOrder, IResolveOrder, IOrderCursor, IOrderVoice
|
||||
class Repairable : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
Health Health;
|
||||
readonly Actor self;
|
||||
readonly Health Health;
|
||||
|
||||
public Repairable(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
Health = self.Trait<Health>();
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get { yield return new EnterOrderTargeter<Building>( "Repair", 5, false, true, target => CanRepairAt( target ), _ => CanRepair() ); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
|
||||
if (self.Info.Traits.Get<RepairableInfo>().RepairBuildings.Contains(underCursor.Info.Name)
|
||||
&& underCursor.Owner == self.Owner)
|
||||
return new Order("Repair", self, underCursor);
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if( order.OrderID == "Repair" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool CanRepair(Actor self)
|
||||
|
||||
bool CanRepairAt( Actor target )
|
||||
{
|
||||
return self.Info.Traits.Get<RepairableInfo>().RepairBuildings.Contains( target.Info.Name );
|
||||
}
|
||||
|
||||
bool CanRepair()
|
||||
{
|
||||
var li = self.TraitOrDefault<LimitedAmmo>();
|
||||
return (Health.DamageState > DamageState.Undamaged || (li != null && !li.FullAmmo()) );
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "Repair") return null;
|
||||
return CanRepair(self) ? "enter" : "enter-blocked";
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "Repair" && CanRepair(self)) ? "Move" : null;
|
||||
return (order.OrderString == "Repair" && CanRepair()) ? "Move" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Repair")
|
||||
{
|
||||
if (!CanRepair(self))
|
||||
if( !CanRepairAt( order.TargetActor ) || !CanRepair() )
|
||||
return;
|
||||
|
||||
var rp = order.TargetActor.TraitOrDefault<RallyPoint>();
|
||||
|
||||
@@ -13,43 +13,55 @@ using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class RepairableNearInfo : TraitInfo<RepairableNear>, ITraitPrerequisite<HealthInfo>
|
||||
class RepairableNearInfo : ITraitInfo, ITraitPrerequisite<HealthInfo>
|
||||
{
|
||||
[ActorReference]
|
||||
public readonly string[] Buildings = { "spen", "syrd" };
|
||||
|
||||
public object Create( ActorInitializer init ) { return new RepairableNear( init.self ); }
|
||||
}
|
||||
|
||||
class RepairableNear : IIssueOrder, IResolveOrder, IOrderCursor
|
||||
class RepairableNear : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
readonly Actor self;
|
||||
|
||||
public RepairableNear( Actor self ) { this.self = self; }
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
get
|
||||
{
|
||||
yield return new EnterOrderTargeter<Building>( "RepairNear", 5, false, true,
|
||||
target => CanRepairAt( target ), _ => ShouldRepair() );
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
|
||||
if (underCursor.Owner == self.Owner &&
|
||||
self.Info.Traits.Get<RepairableNearInfo>().Buildings.Contains( underCursor.Info.Name ) &&
|
||||
self.GetDamageState() > DamageState.Undamaged)
|
||||
return new Order("Enter", self, underCursor);
|
||||
if( order.OrderID == "RepairNear" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
bool CanRepairAt( Actor target )
|
||||
{
|
||||
return (order.OrderString == "Enter") ? "enter" : null;
|
||||
return self.Info.Traits.Get<RepairableNearInfo>().Buildings.Contains( target.Info.Name );
|
||||
}
|
||||
|
||||
|
||||
bool ShouldRepair()
|
||||
{
|
||||
return self.GetDamageState() > DamageState.Undamaged;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Enter")
|
||||
if (order.OrderString == "RepairNear" && CanRepairAt(order.TargetActor) && ShouldRepair())
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Move(order.TargetActor, 1));
|
||||
|
||||
23
OpenRA.Mods.RA/Reservable.cs
Normal file → Executable file
23
OpenRA.Mods.RA/Reservable.cs
Normal file → Executable file
@@ -13,17 +13,14 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class ReservableInfo : ITraitInfo
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new Reservable(init.self); }
|
||||
}
|
||||
class ReservableInfo : TraitInfo<Reservable> {}
|
||||
|
||||
public class Reservable : ITick
|
||||
{
|
||||
Actor reservedFor;
|
||||
Actor self;
|
||||
//Actor self;
|
||||
|
||||
public Reservable(Actor self) { this.self = self; }
|
||||
//public Reservable(Actor self) { this.self = self; }
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
@@ -36,18 +33,18 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public IDisposable Reserve(Actor forActor)
|
||||
{
|
||||
if (reservedFor != null)
|
||||
Game.Debug("BUG: #{0} {1} was already reserved (by #{2} {3})".F(
|
||||
self.ActorID, self.Info.Name, reservedFor.ActorID, reservedFor.Info.Name));
|
||||
//if (reservedFor != null)
|
||||
// Game.Debug("BUG: #{0} {1} was already reserved (by #{2} {3})".F(
|
||||
// self.ActorID, self.Info.Name, reservedFor.ActorID, reservedFor.Info.Name));
|
||||
|
||||
reservedFor = forActor;
|
||||
Game.Debug("#{0} {1} reserved by #{2} {3}".F(
|
||||
self.ActorID, self.Info.Name, forActor.ActorID, forActor.Info.Name));
|
||||
//Game.Debug("#{0} {1} reserved by #{2} {3}".F(
|
||||
// self.ActorID, self.Info.Name, forActor.ActorID, forActor.Info.Name));
|
||||
|
||||
return new DisposableAction(() =>
|
||||
{
|
||||
Game.Debug("#{0} {1} unreserved".F(
|
||||
self.ActorID, self.Info.Name));
|
||||
//Game.Debug("#{0} {1} unreserved".F(
|
||||
// self.ActorID, self.Info.Name));
|
||||
reservedFor = null;
|
||||
});
|
||||
}
|
||||
|
||||
12
OpenRA.Mods.RA/ReturnOnIdle.cs
Normal file → Executable file
12
OpenRA.Mods.RA/ReturnOnIdle.cs
Normal file → Executable file
@@ -32,9 +32,19 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.Debug("Plane has nowhere to land; flying away");
|
||||
//Game.Debug("Plane has nowhere to land; flying away");
|
||||
self.QueueActivity(new FlyOffMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FlyAwayOnIdleInfo : TraitInfo<FlyAwayOnIdle> { }
|
||||
|
||||
class FlyAwayOnIdle : INotifyIdle
|
||||
{
|
||||
public void Idle(Actor self)
|
||||
{
|
||||
self.QueueActivity(new FlyOffMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,35 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class SpyInfo : TraitInfo<Spy> { }
|
||||
|
||||
class Spy : IIssueOrder, IResolveOrder, IOrderCursor
|
||||
class Spy : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
if (underCursor.Owner == self.Owner) return null;
|
||||
if (!underCursor.HasTrait<IAcceptSpy>()) return null;
|
||||
|
||||
return new Order("Infiltrate", self, underCursor);
|
||||
get { yield return new UnitTraitOrderTargeter<IAcceptSpy>( "SpyInfiltrate", 5, "enter", true, false ); }
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target )
|
||||
{
|
||||
return (order.OrderString == "Infiltrate") ? "enter" : null;
|
||||
if( order.OrderID == "SpyInfiltrate" )
|
||||
return new Order( order.OrderID, self, target.Actor );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Infiltrate")
|
||||
if (order.OrderString == "SpyInfiltrate")
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Move(order.TargetActor, 1));
|
||||
|
||||
@@ -44,13 +44,13 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
int Stored(Actor self)
|
||||
{
|
||||
return (int)(Player.GetSiloFullness() * Info.Capacity);
|
||||
return Info.Capacity * Player.Ore / Player.OreCapacity;
|
||||
}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
if (self.IsDead() && Player.GetSiloFullness() > 0)
|
||||
Player.TakeOre(Stored(self)); // Lose the stored ore
|
||||
if (self.IsDead())
|
||||
Player.TakeOre(Stored(self)); // Lose the stored ore
|
||||
}
|
||||
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
@@ -60,6 +60,6 @@ namespace OpenRA.Mods.RA
|
||||
? Info.PipColor : PipType.Transparent );
|
||||
}
|
||||
|
||||
public bool ShouldExplode(Actor self) { return Player.GetSiloFullness() > 0; }
|
||||
public bool ShouldExplode(Actor self) { return Stored(self) > 0; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,6 @@ namespace OpenRA.Mods.RA
|
||||
a.QueueActivity(new RemoveSelf());
|
||||
});
|
||||
|
||||
if (Owner == Owner.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
FinishActivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,14 +32,11 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (order.OrderString == "ChronosphereSelect" && self.Owner == self.World.LocalPlayer)
|
||||
{
|
||||
self.World.OrderGenerator = new SelectDestination(order.TargetActor);
|
||||
//self.World.OrderGenerator = new SelectDestination(order.TargetActor);
|
||||
}
|
||||
|
||||
if (order.OrderString == "ChronosphereActivate")
|
||||
{
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
// Ensure the target cell is valid for the unit
|
||||
var movement = order.TargetActor.TraitOrDefault<IMove>();
|
||||
if (!movement.CanEnterCell(order.TargetLocation))
|
||||
@@ -63,7 +60,13 @@ namespace OpenRA.Mods.RA
|
||||
if (mi.Button == MouseButton.Right)
|
||||
world.CancelInputMode();
|
||||
|
||||
return OrderInner(world, xy, mi);
|
||||
var ret = OrderInner( world, xy, mi ).ToList();
|
||||
foreach( var order in ret )
|
||||
{
|
||||
world.OrderGenerator = new SelectDestination(order.TargetActor);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
@@ -112,11 +115,19 @@ namespace OpenRA.Mods.RA
|
||||
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right)
|
||||
world.CancelInputMode();
|
||||
|
||||
var ret = OrderInner( world, xy, mi ).ToList();
|
||||
foreach( var order in ret )
|
||||
{
|
||||
world.CancelInputMode();
|
||||
yield break;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
// Cannot chronoshift into unexplored location
|
||||
if (world.LocalPlayer.Shroud.IsExplored(xy))
|
||||
yield return new Order("ChronosphereActivate", world.LocalPlayer.PlayerActor, self, xy);
|
||||
|
||||
@@ -39,9 +39,6 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (order.OrderString == "IronCurtain")
|
||||
{
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
var curtain = self.World.Queries.WithTrait<IronCurtain>()
|
||||
.Where(a => a.Actor.Owner != null)
|
||||
.FirstOrDefault().Actor;
|
||||
@@ -78,8 +75,11 @@ namespace OpenRA.Mods.RA
|
||||
&& a.HasTrait<IronCurtainable>()
|
||||
&& a.HasTrait<Selectable>()).FirstOrDefault();
|
||||
|
||||
if (underCursor != null)
|
||||
yield return new Order("IronCurtain", underCursor.Owner.PlayerActor, underCursor);
|
||||
if( underCursor != null )
|
||||
{
|
||||
world.CancelInputMode();
|
||||
yield return new Order( "IronCurtain", underCursor.Owner.PlayerActor, underCursor );
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
|
||||
@@ -49,7 +49,6 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
silo.Trait<NukeSilo>().Attack(order.TargetLocation);
|
||||
|
||||
self.World.CancelInputMode();
|
||||
FinishActivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,6 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (order.OrderString == "ParatroopersActivate")
|
||||
{
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
|
||||
DoParadrop(Owner, order.TargetLocation,
|
||||
self.Info.Traits.Get<ParatroopersPowerInfo>().DropItems);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user