Compare commits
1058 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
750bdb7bba | ||
|
|
8a796416a4 | ||
|
|
691e6cf9e8 | ||
|
|
de208e7a2f | ||
|
|
63a72c5d28 | ||
|
|
b6b4b89008 | ||
|
|
0b65735d86 | ||
|
|
44215ae6f1 | ||
|
|
fba5b80980 | ||
|
|
3f6af59612 | ||
|
|
693a622322 | ||
|
|
60e9d3f660 | ||
|
|
1d40858f70 | ||
|
|
5188529ff6 | ||
|
|
2079db79f7 | ||
|
|
d73eec068f | ||
|
|
8a32e5761c | ||
|
|
12e1a531fe | ||
|
|
32830da3c2 | ||
|
|
9f47e75492 | ||
|
|
e975681c16 | ||
|
|
a968d296bb | ||
|
|
031240ffc1 | ||
|
|
dfc4b07b1a | ||
|
|
63241dbf69 | ||
|
|
5b7523b9e0 | ||
|
|
4b228a71ef | ||
|
|
1635ace182 | ||
|
|
b4e3ce5de6 | ||
|
|
50ceb7c4dd | ||
|
|
4395a04d57 | ||
|
|
c5313375f0 | ||
|
|
2503ddfde4 | ||
|
|
b356cca528 | ||
|
|
d52394bb47 | ||
|
|
1da2d89ced | ||
|
|
a88a7d9834 | ||
|
|
9507fde91d | ||
|
|
742a27158a | ||
|
|
5ed383e3e2 | ||
|
|
1679837e46 | ||
|
|
eb3685fe67 | ||
|
|
50f8465d1e | ||
|
|
5502864a1f | ||
|
|
d572e59d2e | ||
|
|
e313bbfb31 | ||
|
|
a51c5fd9ca | ||
|
|
0c104cfc3a | ||
|
|
3a77082c66 | ||
|
|
975e4db452 | ||
|
|
d92f184bc9 | ||
|
|
2eea5cc3b2 | ||
|
|
0e8cb14099 | ||
|
|
1ec3b2ffe2 | ||
|
|
c836d69385 | ||
|
|
11c45e4388 | ||
|
|
3b9fac9c84 | ||
|
|
185558985e | ||
|
|
e3d25f6fed | ||
|
|
200071e713 | ||
|
|
bdb7bb97cd | ||
|
|
82809f27f7 | ||
|
|
c8e84b3a11 | ||
|
|
9581f07242 | ||
|
|
411aedafa0 | ||
|
|
f7f307c3bf | ||
|
|
c10df031bd | ||
|
|
a56228aba1 | ||
|
|
1b09544314 | ||
|
|
2dc18594a2 | ||
|
|
baa7a58a10 | ||
|
|
bb5212d2bb | ||
|
|
38db7d1e50 | ||
|
|
3371085da0 | ||
|
|
5c688370ed | ||
|
|
ab01722d96 | ||
|
|
ae5cb9864a | ||
|
|
43e5838555 | ||
|
|
cf8b02de26 | ||
|
|
d3ede583c2 | ||
|
|
cda871d2eb | ||
|
|
2ea3b77b7a | ||
|
|
3ab04e4c30 | ||
|
|
3b2190d720 | ||
|
|
b3691dcce9 | ||
|
|
722bc00c9b | ||
|
|
fe07da8634 | ||
|
|
54feab66e0 | ||
|
|
fda897c69e | ||
|
|
31d3616b8d | ||
|
|
eb6bab36a0 | ||
|
|
81f9798307 | ||
|
|
d1dafd5782 | ||
|
|
799a2ea541 | ||
|
|
4b2e45bbae | ||
|
|
32721ac8cb | ||
|
|
6871d2ed37 | ||
|
|
bdfa6f6ecc | ||
|
|
c59fbd5f9d | ||
|
|
54916cc548 | ||
|
|
3ff3ed39fb | ||
|
|
a8dbedd486 | ||
|
|
988a68dae5 | ||
|
|
9a9c5911a6 | ||
|
|
bfb07e9948 | ||
|
|
dda4e2c33a | ||
|
|
05e143662d | ||
|
|
9e2f15bde4 | ||
|
|
8f90423793 | ||
|
|
eecc002236 | ||
|
|
4167d3291a | ||
|
|
3be6229cf2 | ||
|
|
5f693945f0 | ||
|
|
82f478716c | ||
|
|
6544069aa2 | ||
|
|
8486a4fbae | ||
|
|
edd1138556 | ||
|
|
14ed3ae816 | ||
|
|
d5db9e88d4 | ||
|
|
f0a4fa7712 | ||
|
|
1f92768193 | ||
|
|
ccfcf0a1ee | ||
|
|
51626bf0db | ||
|
|
be6da2452a | ||
|
|
ec423db4e5 | ||
|
|
4c7f215559 | ||
|
|
0f9da06309 | ||
|
|
4ce6cabc46 | ||
|
|
b2b13b98b7 | ||
|
|
4c729ca5ed | ||
|
|
a78f8865b8 | ||
|
|
d5b37d4343 | ||
|
|
e424883857 | ||
|
|
b6e8c9c9ea | ||
|
|
ed9bb72dbe | ||
|
|
9753808936 | ||
|
|
82fdbc4bc6 | ||
|
|
d7f3b81e4c | ||
|
|
36f349ecba | ||
|
|
30a374b9e9 | ||
|
|
2a0b9a8596 | ||
|
|
9a9324946f | ||
|
|
babf1556e3 | ||
|
|
bb1c87b084 | ||
|
|
1c584fb158 | ||
|
|
83e1855919 | ||
|
|
4bc04769ec | ||
|
|
178358c29a | ||
|
|
42b16f74a1 | ||
|
|
9b493ad9e7 | ||
|
|
d7d5baae0e | ||
|
|
a8e434b74d | ||
|
|
07d5ba8405 | ||
|
|
a5141f9908 | ||
|
|
d15fb82b08 | ||
|
|
947b27a227 | ||
|
|
b49110bf5c | ||
|
|
8578958e40 | ||
|
|
65e78ca8b0 | ||
|
|
608bf9ada1 | ||
|
|
4373831317 | ||
|
|
aa78d63d72 | ||
|
|
400d94caba | ||
|
|
1660c4fe7c | ||
|
|
e643f12371 | ||
|
|
339c0bc520 | ||
|
|
e15c240a8f | ||
|
|
7bd66c2560 | ||
|
|
1f8fd404e5 | ||
|
|
93e951eb75 | ||
|
|
c52cd77c4c | ||
|
|
0da911c9f8 | ||
|
|
395aa0fc10 | ||
|
|
e10920d4ea | ||
|
|
914afa2dee | ||
|
|
ca1e0b4c48 | ||
|
|
70cf48dcaf | ||
|
|
68130c85f3 | ||
|
|
d0aea18b3e | ||
|
|
ac301b22e2 | ||
|
|
b56125fa39 | ||
|
|
b362ddac15 | ||
|
|
5f2aa810b1 | ||
|
|
189a6c337e | ||
|
|
9c552839ea | ||
|
|
79aa7901cf | ||
|
|
88959b2e6c | ||
|
|
f256742a0d | ||
|
|
22e2d3d0f4 | ||
|
|
3eed137117 | ||
|
|
e28be10dd4 | ||
|
|
90361cb631 | ||
|
|
c3b959846c | ||
|
|
39884e16fa | ||
|
|
f107f8a87b | ||
|
|
8246b2f35f | ||
|
|
f13d12acec | ||
|
|
4090be72d4 | ||
|
|
90d30005f6 | ||
|
|
7c968a8f88 | ||
|
|
e4ab86e6f9 | ||
|
|
f41fb32d60 | ||
|
|
5249a17d48 | ||
|
|
99256bcad0 | ||
|
|
f402c37b14 | ||
|
|
494ab2db4d | ||
|
|
5d4160bc82 | ||
|
|
b9194e4305 | ||
|
|
8ab1fbe83a | ||
|
|
96a088f998 | ||
|
|
7d4399d7cc | ||
|
|
107c37f33d | ||
|
|
88949024e6 | ||
|
|
aad0b3d2d8 | ||
|
|
4e0e53c714 | ||
|
|
87a2817234 | ||
|
|
f3e796e972 | ||
|
|
7d5a843684 | ||
|
|
f914929eb7 | ||
|
|
8f7b776556 | ||
|
|
aeaa58a01b | ||
|
|
4dacd3be26 | ||
|
|
05929bdfe9 | ||
|
|
0690041347 | ||
|
|
842fd8b4e5 | ||
|
|
7a89e3d67a | ||
|
|
5ecc6224b0 | ||
|
|
f5c592291c | ||
|
|
7f229a3fde | ||
|
|
c859fb1186 | ||
|
|
6dceb30632 | ||
|
|
f3dc31be40 | ||
|
|
a2f5ffd59e | ||
|
|
a2c66a32b0 | ||
|
|
72139675ac | ||
|
|
2b57f04dc0 | ||
|
|
15e09fa83b | ||
|
|
55ee1d41f3 | ||
|
|
2e7908366a | ||
|
|
6ab4fda9a6 | ||
|
|
a5ba41cae8 | ||
|
|
5e9cdad044 | ||
|
|
c14de26c07 | ||
|
|
e5f506c81d | ||
|
|
4160f08c6c | ||
|
|
4ad0d1682e | ||
|
|
8fb4fc9a14 | ||
|
|
5a0187e1db | ||
|
|
7f5141c338 | ||
|
|
354cabf8d1 | ||
|
|
fd734c8553 | ||
|
|
9238de6a47 | ||
|
|
b2c5f488a7 | ||
|
|
c634867cdd | ||
|
|
d7f2273788 | ||
|
|
5c1a982fdd | ||
|
|
0300a67da8 | ||
|
|
862dfb3275 | ||
|
|
03121ed826 | ||
|
|
0cdff00cb6 | ||
|
|
787facec65 | ||
|
|
44d63b9103 | ||
|
|
49571fc78a | ||
|
|
60569bc97c | ||
|
|
b37510c30e | ||
|
|
343b7bf3e1 | ||
|
|
7a2423a742 | ||
|
|
57dfc739c6 | ||
|
|
f3d4b6541c | ||
|
|
d1c20d6c72 | ||
|
|
e4beb8236e | ||
|
|
7574124ff0 | ||
|
|
e1cb4d60c4 | ||
|
|
1d62329969 | ||
|
|
36813ff52f | ||
|
|
267141749d | ||
|
|
edd41c5be1 | ||
|
|
5dc0439173 | ||
|
|
4dbee1c0e3 | ||
|
|
76baba89c1 | ||
|
|
5da96941e1 | ||
|
|
c2ec8cd372 | ||
|
|
b73a0a9720 | ||
|
|
6f3b21616f | ||
|
|
1792f16929 | ||
|
|
8dfd02e69e | ||
|
|
c8b1c1b999 | ||
|
|
da9422824a | ||
|
|
403b51ca4b | ||
|
|
3fad0983b9 | ||
|
|
bbab5237d1 | ||
|
|
699838332d | ||
|
|
6e237b53e1 | ||
|
|
36990601db | ||
|
|
82f9549f01 | ||
|
|
656503c0c5 | ||
|
|
83fc70f415 | ||
|
|
bd8ba636c9 | ||
|
|
6eb2f2bffe | ||
|
|
d9a6cc6b1c | ||
|
|
8c3aabb215 | ||
|
|
d44d9f67f2 | ||
|
|
8f8800803b | ||
|
|
52007b6277 | ||
|
|
795008011e | ||
|
|
ec6b8646e9 | ||
|
|
40206f8280 | ||
|
|
887a9e7c9c | ||
|
|
e4218ede41 | ||
|
|
f4d0f80cd3 | ||
|
|
8661fb6b8d | ||
|
|
c212095a40 | ||
|
|
f337c7fb40 | ||
|
|
073a8ee079 | ||
|
|
a4b01cf114 | ||
|
|
cba069a039 | ||
|
|
bf4829205c | ||
|
|
328dce26ba | ||
|
|
0524708e05 | ||
|
|
7e376330d0 | ||
|
|
762db8b304 | ||
|
|
37479b3cfd | ||
|
|
07c2330245 | ||
|
|
0c6daf191c | ||
|
|
b897579a20 | ||
|
|
fcc0bcf438 | ||
|
|
0cd258f24f | ||
|
|
43e99bf9f5 | ||
|
|
83d10ba838 | ||
|
|
48997725c3 | ||
|
|
631f899f18 | ||
|
|
2a4a9d778f | ||
|
|
2e2b4d04db | ||
|
|
deede92fbc | ||
|
|
e3b2e84792 | ||
|
|
e07d55f5f4 | ||
|
|
1803b412c3 | ||
|
|
8dd7bfdb67 | ||
|
|
d1400ab4fa | ||
|
|
67c40f3119 | ||
|
|
68d0201538 | ||
|
|
d30d3ed05a | ||
|
|
43f2895eb8 | ||
|
|
185e3cffb4 | ||
|
|
d68196a3b0 | ||
|
|
4551302c09 | ||
|
|
56f36e45db | ||
|
|
8fabf1504a | ||
|
|
fd96d08ce8 | ||
|
|
0e801f9d3a | ||
|
|
e5ab56e843 | ||
|
|
ff0ad9cb41 | ||
|
|
3e81a4bd70 | ||
|
|
84f7aa56e1 | ||
|
|
c42f270ce0 | ||
|
|
af31ae4931 | ||
|
|
8b6308d3a2 | ||
|
|
6ecc4c18dc | ||
|
|
56557b8766 | ||
|
|
83ba80f4c9 | ||
|
|
65227c3c09 | ||
|
|
1b5474f377 | ||
|
|
38b5e2f7ca | ||
|
|
0ff3c56d4f | ||
|
|
4888732fb7 | ||
|
|
3079e2b488 | ||
|
|
34d96878b8 | ||
|
|
61e548151b | ||
|
|
7cc7dcc559 | ||
|
|
757c9ca63c | ||
|
|
5cb86f8937 | ||
|
|
cd1a29f1ea | ||
|
|
79b4765d9f | ||
|
|
05e9dcd5ce | ||
|
|
4c915ce8fe | ||
|
|
5d5fe3f5a1 | ||
|
|
5bacf69445 | ||
|
|
0a858ac353 | ||
|
|
b7258e61f3 | ||
|
|
bd45ffa022 | ||
|
|
b45f9568d0 | ||
|
|
f8290b8a7e | ||
|
|
21b002ce22 | ||
|
|
1fbd8f6cc6 | ||
|
|
2798f0d841 | ||
|
|
bf73cdbd01 | ||
|
|
03229eca0c | ||
|
|
489fdc1893 | ||
|
|
e2b2082660 | ||
|
|
5ab2e2b225 | ||
|
|
caa58e46c3 | ||
|
|
e9f4338852 | ||
|
|
f146cedad5 | ||
|
|
cc449f81f8 | ||
|
|
085e29d22b | ||
|
|
f8427fa242 | ||
|
|
eb9b6a3842 | ||
|
|
43fc1219f0 | ||
|
|
1469620831 | ||
|
|
036997a7a0 | ||
|
|
b4d9c40dc8 | ||
|
|
62257459fd | ||
|
|
ea641f081f | ||
|
|
a641c7a87d | ||
|
|
605a1eacf6 | ||
|
|
da3adf4f8e | ||
|
|
8680405b68 | ||
|
|
5ad2d1892f | ||
|
|
b723e350c8 | ||
|
|
0b665bc35b | ||
|
|
c012ea90dd | ||
|
|
b0b0fac847 | ||
|
|
c253e59c57 | ||
|
|
952e277d35 | ||
|
|
f984934270 | ||
|
|
fb58840cea | ||
|
|
3d8dc80f03 | ||
|
|
d970195394 | ||
|
|
c33c9e9f69 | ||
|
|
6d3a932453 | ||
|
|
622650785c | ||
|
|
362dc8128e | ||
|
|
f8e73afbee | ||
|
|
dbbe026b88 | ||
|
|
4b36a9bf7f | ||
|
|
70a5333b40 | ||
|
|
e8359b08c6 | ||
|
|
cebc0b66a5 | ||
|
|
6ac86cbc1a | ||
|
|
60ceb800e1 | ||
|
|
5f47b7b7fc | ||
|
|
7e2866714c | ||
|
|
7e8313b808 | ||
|
|
bfd28abb70 | ||
|
|
1afc0cbfce | ||
|
|
82bcd19d2e | ||
|
|
49049a715b | ||
|
|
3114a5b85e | ||
|
|
222f17a586 | ||
|
|
91027e9961 | ||
|
|
a06a7a8ccb | ||
|
|
a8bae22dd3 | ||
|
|
daa89f52b6 | ||
|
|
22c1059904 | ||
|
|
c0138966e7 | ||
|
|
0f14263b82 | ||
|
|
dfc6304efa | ||
|
|
632d717af8 | ||
|
|
a74a3aa3b5 | ||
|
|
c90c351692 | ||
|
|
5612a57842 | ||
|
|
6e3c8c9745 | ||
|
|
0920c67017 | ||
|
|
1ed0d80348 | ||
|
|
c41fcb15b0 | ||
|
|
6c79b454bf | ||
|
|
610e40b8d6 | ||
|
|
5038018aa5 | ||
|
|
cce12e781f | ||
|
|
245de3abcb | ||
|
|
11f9fa1942 | ||
|
|
85fa7eb8c4 | ||
|
|
62d7168d41 | ||
|
|
2a053daa2e | ||
|
|
21a903fe2d | ||
|
|
83fc546fbe | ||
|
|
f648223c39 | ||
|
|
583c3f9a64 | ||
|
|
0d9c78670e | ||
|
|
32a37d8c0f | ||
|
|
168ff6dc82 | ||
|
|
03f904155e | ||
|
|
f479f9a32d | ||
|
|
bdbb9d2a9f | ||
|
|
e3ae0ceae3 | ||
|
|
34ea82e267 | ||
|
|
fe7e016e33 | ||
|
|
f901355bef | ||
|
|
60fb45c909 | ||
|
|
9ccfb2c322 | ||
|
|
0c9f39df78 | ||
|
|
7fffb71ac4 | ||
|
|
bf0cee9057 | ||
|
|
55b17f70a8 | ||
|
|
c9318cd2dd | ||
|
|
ffd2588f50 | ||
|
|
c3b9b37122 | ||
|
|
a30d82b333 | ||
|
|
81e2c1d2d7 | ||
|
|
5f2ffc0508 | ||
|
|
00297b607b | ||
|
|
1c702048a1 | ||
|
|
fdd356c2e7 | ||
|
|
1e64a63fa4 | ||
|
|
05f079758a | ||
|
|
b220bbeda2 | ||
|
|
0a358a8846 | ||
|
|
ed43c1b482 | ||
|
|
c505954b07 | ||
|
|
d5279d123f | ||
|
|
9be501fc3d | ||
|
|
1721d7e025 | ||
|
|
881484d06a | ||
|
|
537cfb8fd3 | ||
|
|
41f1ea36fe | ||
|
|
486d340028 | ||
|
|
e2bbd22144 | ||
|
|
43d0363a55 | ||
|
|
b253de508b | ||
|
|
1da82aeba9 | ||
|
|
db4d6aaf22 | ||
|
|
5ea86873c6 | ||
|
|
0f126fd630 | ||
|
|
ecc2a7241f | ||
|
|
fbf68db0c0 | ||
|
|
9ce8c90d25 | ||
|
|
affa9ca336 | ||
|
|
3a1c4d1e6f | ||
|
|
45fbecbcd0 | ||
|
|
02f28f54c7 | ||
|
|
81f035904e | ||
|
|
8e2d712688 | ||
|
|
29b63bc3c0 | ||
|
|
d98cdd5331 | ||
|
|
94905afa3c | ||
|
|
a659892227 | ||
|
|
82eddfdf98 | ||
|
|
063191b09e | ||
|
|
3fc6f62aea | ||
|
|
48f934f188 | ||
|
|
192af5d60f | ||
|
|
53a7b0987b | ||
|
|
a3897dbc15 | ||
|
|
55651738a7 | ||
|
|
22bddf9645 | ||
|
|
2a37e6233e | ||
|
|
c1722e1270 | ||
|
|
95c27ef943 | ||
|
|
3aafde7e18 | ||
|
|
85678de9f0 | ||
|
|
bda4bfa4f3 | ||
|
|
481624e3f0 | ||
|
|
d1f12ff801 | ||
|
|
eae482d413 | ||
|
|
abd774d017 | ||
|
|
f2c630731e | ||
|
|
3e3977776d | ||
|
|
36fbddbb5c | ||
|
|
e33d988301 | ||
|
|
a55167c9ac | ||
|
|
d0a4555a1f | ||
|
|
4724ac6b00 | ||
|
|
d998367d35 | ||
|
|
0e9e7d0a9d | ||
|
|
5e1e5903d6 | ||
|
|
25fae5d109 | ||
|
|
44b8630c71 | ||
|
|
6204bfcabf | ||
|
|
1355a9f837 | ||
|
|
db8f22cdbf | ||
|
|
860ec9d85f | ||
|
|
5f2f25b758 | ||
|
|
3728685c67 | ||
|
|
5e6b8deec1 | ||
|
|
21f2b0df43 | ||
|
|
2100484598 | ||
|
|
ba1a36f26e | ||
|
|
9c9a16d80e | ||
|
|
3d8e215598 | ||
|
|
ce806fdbe6 | ||
|
|
208a3a47fe | ||
|
|
f0708ecfb2 | ||
|
|
653d72086c | ||
|
|
9258ba3ec7 | ||
|
|
d851c5646e | ||
|
|
ac0d3779f1 | ||
|
|
9a0d62dc85 | ||
|
|
59e1703b41 | ||
|
|
e49a439c79 | ||
|
|
b2e9085371 | ||
|
|
8cea309ec6 | ||
|
|
a59dfa555c | ||
|
|
e22126ca02 | ||
|
|
867f112dfe | ||
|
|
24e6e23000 | ||
|
|
498adc86a9 | ||
|
|
a20d1c95c8 | ||
|
|
4a101cf1b1 | ||
|
|
583b11a2b2 | ||
|
|
b3c5137add | ||
|
|
3dc39b2c9d | ||
|
|
5897a44fc5 | ||
|
|
8b0f15f80b | ||
|
|
1262cf0f29 | ||
|
|
b74e63f42d | ||
|
|
e89ee2c131 | ||
|
|
c2321e3eea | ||
|
|
22a49ba7c6 | ||
|
|
4d614e9122 | ||
|
|
e0069fd62a | ||
|
|
c75c72b525 | ||
|
|
007b2c5434 | ||
|
|
b8a932a084 | ||
|
|
61c3932340 | ||
|
|
c2029e9d5c | ||
|
|
d0548d6766 | ||
|
|
5a40c5df03 | ||
|
|
f5ba36a735 | ||
|
|
efe2f2e043 | ||
|
|
6681382819 | ||
|
|
7a578a0679 | ||
|
|
5fee165692 | ||
|
|
0a4669b925 | ||
|
|
109546d20f | ||
|
|
f5c606266d | ||
|
|
facf958bae | ||
|
|
480db8be42 | ||
|
|
7c4e32bd94 | ||
|
|
854a9c4eb7 | ||
|
|
cbb0b17c31 | ||
|
|
f2ab8a8541 | ||
|
|
63d21eac8c | ||
|
|
579ff04f68 | ||
|
|
18d75feb15 | ||
|
|
11da96fe22 | ||
|
|
9201b1cced | ||
|
|
e02397da3e | ||
|
|
6014f648f4 | ||
|
|
2c55a008f1 | ||
|
|
b9be918b6c | ||
|
|
781cbc00d3 | ||
|
|
b9365a149f | ||
|
|
1d4f1c657f | ||
|
|
9a66d7b530 | ||
|
|
3a87b934a6 | ||
|
|
9845d0e035 | ||
|
|
3754e791e5 | ||
|
|
643154de15 | ||
|
|
af8b29aee5 | ||
|
|
36c0ec753d | ||
|
|
9115fc4397 | ||
|
|
0d59a4dcd7 | ||
|
|
e0c3c53c00 | ||
|
|
11654cc893 | ||
|
|
bb85ea75e4 | ||
|
|
2450576dbe | ||
|
|
dd81b6d872 | ||
|
|
3160034d66 | ||
|
|
d0d3813173 | ||
|
|
2ff4a76955 | ||
|
|
9626ed356c | ||
|
|
5ecf8d3b7f | ||
|
|
8041b17032 | ||
|
|
b9cda8fcca | ||
|
|
ed6a625c69 | ||
|
|
d498ff1085 | ||
|
|
f8a0dd59b7 | ||
|
|
8e602104af | ||
|
|
aac78773f4 | ||
|
|
d3915ad291 | ||
|
|
b61e4a6083 | ||
|
|
5318380bfa | ||
|
|
a64629f1c5 | ||
|
|
5231da1ea3 | ||
|
|
aa06751de5 | ||
|
|
f10eb9e082 | ||
|
|
9966b4efd1 | ||
|
|
0ec3e8b227 | ||
|
|
984a498ed2 | ||
|
|
c122e6f54d | ||
|
|
1924cc71f1 | ||
|
|
220473bf74 | ||
|
|
4373f577d8 | ||
|
|
2f773e49ef | ||
|
|
03ec1f08cf | ||
|
|
a0f9f98b1c | ||
|
|
b59a0e8c0d | ||
|
|
1fa70d259f | ||
|
|
1f0da42a15 | ||
|
|
845379e577 | ||
|
|
80123b6aa4 | ||
|
|
1aafc9f726 | ||
|
|
8607575e2b | ||
|
|
162c386bdd | ||
|
|
445e5ec84b | ||
|
|
54c35e3721 | ||
|
|
a2b92d0fe4 | ||
|
|
2ed12f1d95 | ||
|
|
fe5bcdeab9 | ||
|
|
9c6bc45f8f | ||
|
|
2cc749118f | ||
|
|
331388bfe8 | ||
|
|
079a52ee65 | ||
|
|
5b470650b7 | ||
|
|
380875ad3e | ||
|
|
79976a4bfe | ||
|
|
769b5d7dc6 | ||
|
|
2a95c5f668 | ||
|
|
1bf649d27d | ||
|
|
bda92f3898 | ||
|
|
7220025a62 | ||
|
|
0b6eda0815 | ||
|
|
e70e778775 | ||
|
|
7fb659bd3a | ||
|
|
b109436cc3 | ||
|
|
6ba0c448c8 | ||
|
|
ed5ff9cd31 | ||
|
|
1146790dc1 | ||
|
|
cf1d4d0efb | ||
|
|
b127ae8027 | ||
|
|
9c49143534 | ||
|
|
6bc3249685 | ||
|
|
3ab197f400 | ||
|
|
9ff69b7946 | ||
|
|
0b98a8ce5e | ||
|
|
2e26047b23 | ||
|
|
2cdd1f7376 | ||
|
|
033dd10192 | ||
|
|
9f5a8512d2 | ||
|
|
5c4e49cc3f | ||
|
|
8eb4782a49 | ||
|
|
99eb3b046d | ||
|
|
ac0389d04f | ||
|
|
6929ed024a | ||
|
|
f4cb798c8b | ||
|
|
8f6b8b75bc | ||
|
|
cb3daab5fa | ||
|
|
4d16ca238c | ||
|
|
84d623397b | ||
|
|
26b75f406f | ||
|
|
b30e4ab432 | ||
|
|
b0e10c9ada | ||
|
|
c6a1031ab7 | ||
|
|
7cbed30dc6 | ||
|
|
ce0099f5d2 | ||
|
|
45a5e317c0 | ||
|
|
11ddd88d60 | ||
|
|
ce05b8dfec | ||
|
|
f5d397030c | ||
|
|
874799c2c3 | ||
|
|
20af089fcd | ||
|
|
21ab0b461c | ||
|
|
7af0e64708 | ||
|
|
527c6dc36b | ||
|
|
8831a93375 | ||
|
|
677efcbced | ||
|
|
4f1a7ff5fb | ||
|
|
c9edf7d0dc | ||
|
|
d64ecac74e | ||
|
|
c804be6f01 | ||
|
|
959875c709 | ||
|
|
4d94cb5593 | ||
|
|
c1fb5dd5f5 | ||
|
|
db0e1eabc7 | ||
|
|
801ff5cc17 | ||
|
|
94f7f1c473 | ||
|
|
9862b8ccee | ||
|
|
722c7a5f7d | ||
|
|
72d038e04e | ||
|
|
b83188d435 | ||
|
|
f9cbd1bbbf | ||
|
|
4e88166673 | ||
|
|
f3d68f4944 | ||
|
|
3827a5436a | ||
|
|
4a7417347a | ||
|
|
dc6b286d25 | ||
|
|
aa36a56b27 | ||
|
|
a831e72fa2 | ||
|
|
b96158adcb | ||
|
|
5414875d00 | ||
|
|
fd4b10c6bd | ||
|
|
d110b45679 | ||
|
|
22e0828566 | ||
|
|
c3052d863a | ||
|
|
0b4455515d | ||
|
|
4ed74c6cc0 | ||
|
|
ebf64f67cf | ||
|
|
b16849768d | ||
|
|
f140c6ec9c | ||
|
|
8f1d06ff31 | ||
|
|
3f0fafb380 | ||
|
|
84124de79d | ||
|
|
8ad4e08651 | ||
|
|
8f981977e0 | ||
|
|
676210422f | ||
|
|
749301899e | ||
|
|
1bb1e00a0d | ||
|
|
83ee6b758e | ||
|
|
accaf027fe | ||
|
|
9b1e798b35 | ||
|
|
cffaabb3bf | ||
|
|
5ab5bc9f7c | ||
|
|
d9c4aada8a | ||
|
|
27fa99852b | ||
|
|
ec7795fa99 | ||
|
|
8e74df6155 | ||
|
|
4984d07960 | ||
|
|
2a312911cb | ||
|
|
a20e30312e | ||
|
|
e0e1011d30 | ||
|
|
1fcf044980 | ||
|
|
2287f1f662 | ||
|
|
ffbc76919e | ||
|
|
083952a531 | ||
|
|
bd29d382c7 | ||
|
|
8df09da816 | ||
|
|
4778ef803e | ||
|
|
37f91542a9 | ||
|
|
e1907364e6 | ||
|
|
7f48a242db | ||
|
|
4362a215d9 | ||
|
|
72b2e03dd0 | ||
|
|
f7c1eb2933 | ||
|
|
5dd46b1b16 | ||
|
|
68a731ed5e | ||
|
|
4c667be946 | ||
|
|
66f82c6c2a | ||
|
|
ff32864b47 | ||
|
|
e9656795a2 | ||
|
|
3fbb81b4fc | ||
|
|
442138e1f8 | ||
|
|
2d39b1dfac | ||
|
|
3b704e25fa | ||
|
|
c068be453a | ||
|
|
6f8f940f31 | ||
|
|
c000640928 | ||
|
|
059347af40 | ||
|
|
f0001856bc | ||
|
|
8c218b67ab | ||
|
|
5426a5fd3c | ||
|
|
d1241c438a | ||
|
|
bc7aa9a491 | ||
|
|
ae94d7ecc7 | ||
|
|
7e1986ecbc | ||
|
|
a07697be03 | ||
|
|
b99e664726 | ||
|
|
881b4ba277 | ||
|
|
3058bfbc17 | ||
|
|
8a08365666 | ||
|
|
6c96a106e7 | ||
|
|
6291c8396b | ||
|
|
79afa07118 | ||
|
|
0e43043a33 | ||
|
|
c06fc02915 | ||
|
|
8badbb3d60 | ||
|
|
57283b4a80 | ||
|
|
d9992eea6a | ||
|
|
c8c4507acf | ||
|
|
5a37c84a8b | ||
|
|
63898820f1 | ||
|
|
63359e156c | ||
|
|
d683d69f3c | ||
|
|
609d5bd611 | ||
|
|
0b894d3b31 | ||
|
|
3a838a05cd | ||
|
|
0a0b136b80 | ||
|
|
82549c6407 | ||
|
|
d737930bb0 | ||
|
|
dad67713fb | ||
|
|
a1082152a4 | ||
|
|
9f729b0c45 | ||
|
|
ee7d8659d5 | ||
|
|
4448c3e51b | ||
|
|
174e925e5a | ||
|
|
e7a8cdf951 | ||
|
|
45f5c054d5 | ||
|
|
15dcd6a9f6 | ||
|
|
9c86196b16 | ||
|
|
9185dc65d5 | ||
|
|
e0bfa287ee | ||
|
|
80f142c8ea | ||
|
|
7050fbc6e1 | ||
|
|
2c938bc305 | ||
|
|
cd6bfb1b9a | ||
|
|
11b253e4c3 | ||
|
|
d625e2624a | ||
|
|
a544bc966b | ||
|
|
9a3aae6586 | ||
|
|
390e607e66 | ||
|
|
22b18f99db | ||
|
|
c30d46c014 | ||
|
|
5d1a071287 | ||
|
|
16e00c1f12 | ||
|
|
87271a0a56 | ||
|
|
dadc496c19 | ||
|
|
a0940e7ae5 | ||
|
|
ca1fbb187b | ||
|
|
89025a3042 | ||
|
|
49f3f740e3 | ||
|
|
4b4bbdf626 | ||
|
|
cebf908bb2 | ||
|
|
75c105cb85 | ||
|
|
6669a66292 | ||
|
|
6e3aa46008 | ||
|
|
84a50e8e86 | ||
|
|
6559d8d8bc | ||
|
|
926686beff | ||
|
|
6ab171af8b | ||
|
|
c4916bd997 | ||
|
|
f86332fd99 | ||
|
|
8d843cd8ad | ||
|
|
0904ac3a70 | ||
|
|
8488223eee | ||
|
|
da3ba159db | ||
|
|
3e0f52db1a | ||
|
|
062c49dac3 | ||
|
|
533f9044cc | ||
|
|
b9eb3a0ad0 | ||
|
|
dbd09ea843 | ||
|
|
a4e1915aff | ||
|
|
9d2833fc2b | ||
|
|
ab4c21f80c | ||
|
|
f7fea5ffce | ||
|
|
87e9a69ae0 | ||
|
|
25fb2a7be3 | ||
|
|
10c1b996ed | ||
|
|
aa21ddaa4d | ||
|
|
eab0e7ddf9 | ||
|
|
891cba456b | ||
|
|
beb6b01796 | ||
|
|
a52af4843e | ||
|
|
8dec48fee3 | ||
|
|
b081103866 | ||
|
|
4a76e2ad33 | ||
|
|
b39eeddb45 | ||
|
|
7d4186c236 | ||
|
|
01a724d632 | ||
|
|
ca1549df2a | ||
|
|
0ae8e41612 | ||
|
|
bc8c433a72 | ||
|
|
7187b14459 | ||
|
|
07d25d97ab | ||
|
|
4d5f89909e | ||
|
|
60fa61840d | ||
|
|
499234e5dd | ||
|
|
1010276cd5 | ||
|
|
fdef80c53a | ||
|
|
22d3709967 | ||
|
|
b2c72d6990 | ||
|
|
6f688275c5 | ||
|
|
5b8334b26d | ||
|
|
23ea8493ba | ||
|
|
cc9dbd43c3 | ||
|
|
8308f82926 | ||
|
|
11f322a758 | ||
|
|
6376615781 | ||
|
|
f4b302e01a | ||
|
|
703d6648d7 | ||
|
|
f19807f0ca | ||
|
|
a523510922 | ||
|
|
47194fab71 | ||
|
|
75e32c0573 | ||
|
|
38b5a8d4f8 | ||
|
|
522c88dcda | ||
|
|
3375a5de51 | ||
|
|
68933880b9 | ||
|
|
469a393585 | ||
|
|
be1fdbdd56 | ||
|
|
2972728b5e | ||
|
|
78ba76250d | ||
|
|
603014b163 | ||
|
|
6b85518b74 | ||
|
|
d3578273db | ||
|
|
54f3c76da8 | ||
|
|
95b908b234 | ||
|
|
3b94728869 | ||
|
|
b8b9d34404 | ||
|
|
a5cfc20e0b | ||
|
|
3cf09e656f | ||
|
|
1f8859f26b | ||
|
|
6555bc9dbc | ||
|
|
49fb0228fa | ||
|
|
ad29926391 | ||
|
|
85293a482e | ||
|
|
6315864f84 | ||
|
|
c169bc3c51 | ||
|
|
1de3db0903 | ||
|
|
965fe88755 | ||
|
|
809b716d0d | ||
|
|
004c59d273 | ||
|
|
c34b254fd8 | ||
|
|
0d25b6b5c9 | ||
|
|
85eeb8b819 | ||
|
|
e84d90fc3a | ||
|
|
418b8d40f9 | ||
|
|
9581595a3d | ||
|
|
0aa7ba6bd4 | ||
|
|
2793d1076a | ||
|
|
d57dfd1997 | ||
|
|
f8122047b6 | ||
|
|
d115c6305c | ||
|
|
f63cdf37d7 | ||
|
|
dd88a1269a | ||
|
|
523183431b | ||
|
|
132c678594 | ||
|
|
f8127ab9df | ||
|
|
d61055af8f | ||
|
|
4e6ff7616c | ||
|
|
f2dd5eb0a3 | ||
|
|
f7e35899cf | ||
|
|
727b897994 | ||
|
|
8029973e33 | ||
|
|
bd4345c2d0 | ||
|
|
4bcd19f57c | ||
|
|
bc38e99495 | ||
|
|
c1e6e3f9b9 | ||
|
|
480c35ab58 | ||
|
|
fdafb9d411 | ||
|
|
23a9e0503d | ||
|
|
aa9dd73fe5 | ||
|
|
1b0724719d | ||
|
|
c8ae6127f3 | ||
|
|
40029c6688 | ||
|
|
af3d00836a | ||
|
|
bf5be88c75 | ||
|
|
58f6816d84 | ||
|
|
ed429a3b30 | ||
|
|
83055f0a17 | ||
|
|
dd55c0ad93 | ||
|
|
1bea7e3286 | ||
|
|
b508f7c300 | ||
|
|
7e590b05c1 | ||
|
|
6c027372ab | ||
|
|
6bac11f071 | ||
|
|
87a420623b | ||
|
|
1e4f1a9f19 | ||
|
|
410cad6f1e | ||
|
|
69a869a44d | ||
|
|
de88cb33f3 | ||
|
|
5ea756506b | ||
|
|
fb1b7ac706 | ||
|
|
3003e49277 | ||
|
|
a7c3052243 | ||
|
|
c3a6674da0 | ||
|
|
9d6094f798 | ||
|
|
2747fadd96 | ||
|
|
66c59add94 | ||
|
|
4610461a81 | ||
|
|
c1cbe0f0f5 | ||
|
|
a566a372f5 | ||
|
|
7b06e39390 | ||
|
|
b8c4ff8668 | ||
|
|
3d25e59e9e | ||
|
|
1df572e6ee | ||
|
|
98d4af18a4 | ||
|
|
0f97466a75 | ||
|
|
58a6c01c3b | ||
|
|
8bdab6a5f2 | ||
|
|
f043aa6366 | ||
|
|
8933b201f1 | ||
|
|
2bb968d0d3 | ||
|
|
bf222425fc | ||
|
|
0ea9e06c22 | ||
|
|
54e8266e37 | ||
|
|
2679e91b03 | ||
|
|
2462902d8b | ||
|
|
55f811faf5 | ||
|
|
45c41b6696 |
17
.gitignore
vendored
17
.gitignore
vendored
@@ -10,8 +10,8 @@ obj
|
||||
*.manifest
|
||||
mods/*/*.dll
|
||||
|
||||
# Red Alert binary files
|
||||
mods/*/packages/*.[mM][iI][xX]
|
||||
# ReSharper crap
|
||||
_ReSharper.*/
|
||||
|
||||
#binary stuff
|
||||
/*.dll
|
||||
@@ -22,6 +22,8 @@ mods/*/packages/*.[mM][iI][xX]
|
||||
# backup files by various editors
|
||||
*~
|
||||
*.orig
|
||||
\#*
|
||||
.*.sw?
|
||||
# dependency DLLs (different for every platform!)
|
||||
cg.dll
|
||||
cgGL.dll
|
||||
@@ -32,8 +34,6 @@ cgGL.dll
|
||||
*.pidb
|
||||
*.userprefs
|
||||
|
||||
packaging/windows/*.exe
|
||||
|
||||
# osx crap
|
||||
.DS_Store
|
||||
|
||||
@@ -52,9 +52,6 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
*.config
|
||||
*.resources
|
||||
|
||||
# other crap
|
||||
Logs/
|
||||
Replays/
|
||||
settings.yaml
|
||||
\#*
|
||||
.*.sw?
|
||||
# KDE crap
|
||||
*.kate-swp
|
||||
*.directory
|
||||
17
AUTHORS
17
AUTHORS
@@ -10,24 +10,33 @@ The OpenRA developers are:
|
||||
* Mike Bundy (kehaar)
|
||||
|
||||
Also thanks to:
|
||||
* Akseli Virtanen (RAGEQUIT)
|
||||
* Andrew Riedi
|
||||
* Barnaby Smith (mvi)
|
||||
* Bellator
|
||||
* Christer Ulfsparre (Holloweye)
|
||||
* Cody Brittain (Generalcamo)
|
||||
* Daniel Derejvanik (Harisson)
|
||||
* Erasmus Schroder (rasco)
|
||||
* Igor Popov (ihptru)
|
||||
* James Dunne (jsd)
|
||||
* Jeff Harris (jeff_1amstudios)
|
||||
* Jes (-Jes-)
|
||||
* Joakim Lindberg (booom3)
|
||||
* Max Ugrumov (katzsmile)
|
||||
* Kenny Hoxworth (hoxworth)
|
||||
* Kyrre Soerensen (zypres)
|
||||
* Lawrence Wang
|
||||
* Mark Olson (markolson)
|
||||
* Matthew Gatland (mgatland)
|
||||
* Matthias Mailänder (Mailaender)
|
||||
* Max Ugrumov (katzsmile)
|
||||
* Max621
|
||||
* Nukem
|
||||
* Paolo Chiodi (paolochiodi)
|
||||
* Paul Dovydaitis (pdovy)
|
||||
* Ragequit
|
||||
* Tim Mylemans (gecko)
|
||||
* Raymond Martineau (mart0258)
|
||||
* Riderr3
|
||||
* Raymond Martineau
|
||||
* Tim Mylemans (gecko)
|
||||
|
||||
Past developers included:
|
||||
* Paul Chote (pchote)
|
||||
|
||||
357
CHANGELOG
357
CHANGELOG
@@ -1,42 +1,353 @@
|
||||
NEW:
|
||||
Engine:
|
||||
Removed mouse capture while composing text in chat
|
||||
Allow classic left-click mouse orders (optional)
|
||||
Asynchronous loading of minimaps in the map chooser dialog
|
||||
Fix bots being able to become admin status on dedicated servers
|
||||
Spawnpoint map tooltips now display players name in lobby
|
||||
Fixed word wrap when chatting ingame
|
||||
Added a tooltip that shows provided and drained power
|
||||
Allow MOTD to be fetched from file for dedicated servers
|
||||
Changed scroll velocity in map chooser to be better suited for mouse scrolling
|
||||
Fixed grounded airplane not landing properly when ordered to another airstrip or service depot
|
||||
Added per player shrouds (units can't shoot enemies covered in unexplored terrain)
|
||||
Don't hardcode READY/HOLD and custom prerequisites anymore for easier translation
|
||||
Removed sound attentuation for PlayNotification sounds - fixes the Extreme cashtick sounds
|
||||
Editor:
|
||||
Map editor now saves and loads from OpenRA user folder
|
||||
Fixed map editor failing to import legacy maps
|
||||
Template categories are now ordered by what is specified in the tileset yaml
|
||||
Added terrain category types to RA Snow tileset
|
||||
Fixed terrain categories for two river tiles in RA Temperat
|
||||
Add terrain category types to RA desert tileset
|
||||
Fixed wrong palette remapping for neutral buildings
|
||||
Red Alert:
|
||||
Added Allies03 mission
|
||||
Added Allies04 mission
|
||||
Added Soviet01Classic mission
|
||||
Allies02 mission - reduced difficulty of the 16 minute reinforcements
|
||||
Allies02 mission - can build medic and spy at captured barracks
|
||||
Added Desert tileset - original and new tiles ported from Tiberium Dawn by Harrison, code by Matt
|
||||
Fixed graphics for craters for Snow maps (art by MrFibble)
|
||||
Ice Floe actors work in maps now (sequences were missing)
|
||||
Brought back music track "Mud" into the playlist
|
||||
Balance:
|
||||
Added missing line of sight for Chronotank
|
||||
Chronotank damage upped from 20 to 30 per rocket and damage improved vs heavy armor
|
||||
Demo truck cost from 1500 to 2500
|
||||
Demo truck health from 110 to 50
|
||||
Demo truck speed from 8 to 6
|
||||
Disguised spies are now invisible under enemy GPS
|
||||
Heroes and missile silos are now limited to one per player
|
||||
Volkov got a new armor type: cybernetic for individual balancing
|
||||
More health points for Volkov to make him the 4tnk equivalent of infantry
|
||||
Medics can't heal Volkov, send him to repair pad or mechanic instead
|
||||
Dogs can't eat Volkov and tanks need two attempts to crush him
|
||||
Reworked Volkov death sounds/animations (Cyborg version from German RA)
|
||||
Replaced supply truck graphics with aftermath SHP which has a shadow (via Arda)
|
||||
Added hotkeys for aircraft, vehicles, ships, infantry
|
||||
Fixed broken shadows on GPS dot
|
||||
Fixed Chronotank teleport causing a desync
|
||||
Fixed replay crash when a Chronotank tries to teleport
|
||||
Fixed Chronotank death causing a crash before teleporting
|
||||
Fixed maps Chaos Canyon and Bomber John
|
||||
Added map: Room Convergence (Sunny Sproket)
|
||||
Added map: Ghost Town (hamb)
|
||||
Updated map: Bombardment Islands (czech army)
|
||||
Added mechanic
|
||||
Added in-game player statistics for observers
|
||||
Added support for map difficulties
|
||||
Oil derricks are now repairable by engineers
|
||||
Added new map: "Bad Neighbors" (Nukem)
|
||||
Renamed airstrip to airfield in tooltip.
|
||||
Don't remap civilian buildings/fields in-game.
|
||||
C&C:
|
||||
Corrected music.yaml track titles
|
||||
Fix wrong civilian field remapping in-game
|
||||
Dune 2000:
|
||||
Merged the Rounded Edges Mod by Jes and Bellator:
|
||||
Bibs have been removed
|
||||
Building offset and selection boxes adapted
|
||||
Units and turrets leave husks
|
||||
Siege tank barrel won't rotate anymore
|
||||
AI capable of building all units using all queues
|
||||
Bullet traces
|
||||
Windtrap and IX Research building animations
|
||||
New unit balance (mix of Dune II, Dune 2000 and Red Alert)
|
||||
Repair pad animation
|
||||
No more obsessive "silos needed"
|
||||
Defense building queue → heavy armor queue
|
||||
Medics (using thumper graphics)
|
||||
Aircraft are no longer buildable
|
||||
Harvesting has been slowed down
|
||||
Replace blank shellmap with random multiplayer stills
|
||||
Starport requires energy to operate
|
||||
|
||||
20121019:
|
||||
Engine:
|
||||
Add --transpose option to Utility
|
||||
Allow --transpose to do multiple operations in one pass
|
||||
Added category headers in editor (RA temperate theme only)
|
||||
Added selection tool in editor for use with copy-pasting terrain
|
||||
Added tilesetbuilder2 and fixed it for Dune 2000
|
||||
Added tilesetbuilder command line
|
||||
Added tileset extractor
|
||||
Upgraded Visual Studio solution to 2010
|
||||
Tons of performance improvements
|
||||
Prevent too many instances of a single sound playing at once
|
||||
Order results from FindByTilesInCircle by distance
|
||||
Added new data types for cell and pixel coordinate pistion/vectors
|
||||
Fixed issue where port in direct connect was dumped to default by force
|
||||
Fixed pathfinding for units heading in opposite directions to prevent pathing deadlocks
|
||||
Fixed volume and scrollspeed being different from their saved scale at game start
|
||||
All Mods:
|
||||
Added basic dedicated server support
|
||||
Added UPnP support for multiplayer
|
||||
Added option to pause the game (F3 key)
|
||||
Added SimpleTeleport for non-chrono jumps for mission scripting
|
||||
Added WaitFor(predicate) for mission scripting
|
||||
Added support for mission objectives
|
||||
Added indicator to show who is admin of a lobby
|
||||
Added map size label to map chooser
|
||||
Added support to set up player required slots for maps
|
||||
Added hover behavior for all units. Give a unit a nonzero Altitude: in its Mobile: block and the WithShadow: trait to make it hover
|
||||
Allow building speed to be set by CustomSellValue trait
|
||||
Bots are forcefully removed from maps which do not allow them
|
||||
Ignore spectators for lobby readiness check
|
||||
Added CloakInfo.UncloakOnMove option
|
||||
Made UnloadCargo.unloadAll configurable, using all by default
|
||||
Support targetlines for defenses
|
||||
Setting for Capturable trait to waste engineer after capturing a building or not
|
||||
Fixed unloading of infantry from cargo vehicles to be spread out instead of one subcell
|
||||
Fixed crates not being picked up when dropped on a unit
|
||||
Fixed being able to repair when eliminated
|
||||
Fixed spectator chat not using contrast
|
||||
Fixed crash cycling stances while a unit dies
|
||||
Fixed crash spawning corpse for actor which has already been destroyed
|
||||
Fixed filtering of passengers to show with RenderCargo
|
||||
Fixed incorrect working "locks" when capture/sell building races happened
|
||||
Fixed radar click position
|
||||
Fixed shift-tab keyboard shortcut in build palette
|
||||
Added mouse-wheel support for flipping tabs in build palette
|
||||
Harvesters:
|
||||
No longer block each other during low-ore contention and wait for a random amount of time to search for more resources.
|
||||
Refineries show which harvesters are linked by holding down the ALT key.
|
||||
Fixed harvesters for AI to search the entire map when no more resources nearby
|
||||
Made search radius configurable for both initial search from refinery, and search from harvest location
|
||||
Harvesters will return to ordered-to location if told to harvest a specific cell while full after delivery instead of the last successfully harvested cell which may be far away
|
||||
Fixed notable issues when trying to play FMVs
|
||||
Red Alert:
|
||||
Added two missions - Allies01 (single player) and Allies02 (co op)
|
||||
Added new tiles for use in the Temperate theatre, made by Harrison
|
||||
Added new crashed helicopter SHPS
|
||||
Added Hospital & Bio Lab yaml definitions
|
||||
Reenabled PrimaryBuilding support for airfield and helipads
|
||||
Fixed chrono not killing passengers on return
|
||||
Fixed missing chrono effects on unit return
|
||||
Fixed tesla coil ignoring weapon offset
|
||||
Fixed some HackyAI issues, such as having a tank husk fetish
|
||||
Fixed some incorrect/missing music strings in music.yaml
|
||||
Fixed broken Install from CD code
|
||||
Fixed another zombie aircraft bug
|
||||
Fixed ReturnToBase causing a crash when you had no airfields available (but an ally did)
|
||||
Balance (General):
|
||||
Added a heal crate (heals all of your units on map, rare occurrence)
|
||||
Removed nuke crate
|
||||
Nuke was made a lot more powerful
|
||||
Nuclear explosions now destroy ore
|
||||
Repair cost for units is always at least 1 per tick
|
||||
Radar Dome cost increased from 1400 to 1600
|
||||
Service Depot cost increased from 1000 to 1200
|
||||
War Factory armor type changed from Heavy to Wood
|
||||
Sam Site/AA Guns will no longer shoot at crashing aircraft
|
||||
Barrel explosions are now more deadly, and chain explosions explode with a delay
|
||||
Churches made garrisonable by Sniper infantry
|
||||
Balance (Soviet):
|
||||
Added Sniper - cloaked infantry with HoldFire stance by default
|
||||
Added Volkov - elite unit meant to replace Tanya
|
||||
Added Demo Truck - armed with a lower damage nuke
|
||||
Mammoth Tank self heal now goes up to 80% health
|
||||
Mammoth Tank turret rotation was slowed down
|
||||
Mammoth Tank tusk rate of turn was doubled
|
||||
Tesla Tank cost lowered from 1500 to 1350
|
||||
Airfield armor changed from Heavy to Wood
|
||||
Airfield cost increased from 300 to 500
|
||||
Iron Curtain duration increased from 10 to 15 seconds, and can't use on enemy units
|
||||
Balance (Allies):
|
||||
Added Chronotank - tank that can "jump" within range of itself
|
||||
Tanya - Colt45 attack range increased from 5.75 to 7
|
||||
Transport Heli - Cost lowered from 1200 to 900, increased hp, increased cargo count to 8
|
||||
AA Gun cost increased from 600 to 800
|
||||
Helipad cost increased from 300 to 500
|
||||
Added map: Ice Woods (Tirili)
|
||||
Added map: Nishnekolymsk (Tirili)
|
||||
Added map: Bomber John (Holloweye)
|
||||
Added map: Bloody Delta (Holloweye)
|
||||
Added map: Room-Warzone (Sunny_S)
|
||||
Added map: Chaos Canyon (Nukem)
|
||||
Added map: Forest Path (Gnx)
|
||||
Updated map: Free Coasts (Ihptru)
|
||||
Replaced map Baywatch with Hasselhoff (Nukem/Zypres)
|
||||
C&C:
|
||||
Added A10 crash site SHP to terrain (via Nyerguds)
|
||||
Re-added the Snow tileset (via Nyerguds)
|
||||
Balance:
|
||||
Tank shells do 100% vs armor again, turret buffed
|
||||
MRLS issues fixed
|
||||
Sonic Tank moved to end of build menu
|
||||
Fixed structure build menu orders in general
|
||||
Fixed Biolab did providing Visceriod after being captured
|
||||
Fixed tooltips not showing on the build menu
|
||||
Do not shade possible build items in CNC if something else is building
|
||||
Dune 2000:
|
||||
Added Dune 2000!
|
||||
|
||||
20120603:
|
||||
Engine:
|
||||
General performance improvements
|
||||
Fixed minimap export breaking subsequent actions in the editor
|
||||
Health.MaxHP is no longer read-only
|
||||
#Comments can be used at end of any lines in yaml files
|
||||
Better error messages for duplicate yaml fields
|
||||
Fixed RenderCargo support for relative altitude
|
||||
Both Mods:
|
||||
Add banlist setting (Server: Ban: IP1, IP2, IP3)
|
||||
Missiles lose guidance and run out of remaining fuel if the target dies
|
||||
Red Alert:
|
||||
Added setting to change CashTick sound frequency when producting structures
|
||||
Re-added camo pillbox for Allies to be garissonable and stealthed
|
||||
Change cargo ownership if capturing actors with cargo
|
||||
Fixed spy resetting exploration if infiltrated enemy had GPS
|
||||
Cannot capture building if yourself or ally is already capturing it
|
||||
Barrels are no longer capturable/sellable
|
||||
Minor AI improvements
|
||||
C&C:
|
||||
Exposed option to toggle shellmap
|
||||
MRLS cost increased to 1200
|
||||
APC gun damage increased
|
||||
Several building hitpoints increase/decreased
|
||||
Several units movement speed adjusted
|
||||
Landed helicopters made targetable by units
|
||||
Mammoth Tank has an 8 second cooldown before regenerating hp
|
||||
Add new Chemball explosion
|
||||
Re-ordered build menu
|
||||
Production hotkeys changed from YUIOP to QWERT
|
||||
Fix crash loading yaml for ArtilleryShell.ContrailLength
|
||||
|
||||
20120504:
|
||||
Engine:
|
||||
General performance improvements
|
||||
Added a setting to change sound engine, Sound:Engine: AL ("AL" uses OpenAL, "Null" gives no sound)
|
||||
Both Mods:
|
||||
Warn lobby when a client joins with DEV_VERSION
|
||||
Produced units attack-move to their rallypoint
|
||||
New CloakPaletteEffect trait to add shimmer effect to cloaked units
|
||||
Cargo trait allows for initial passengers when units are built
|
||||
Buildings now take 10 seconds to be captured
|
||||
Capture time length is adjustable
|
||||
Custom starting units can be used for each faction
|
||||
Main menu no longer vanishes after a lobby disconnect
|
||||
Fixed crash selling/capturing buildings simultaneously
|
||||
Fixed crash in StartGame if there were unvalidated connections
|
||||
Improved error messages given with bad MiniYaml indentations
|
||||
Red Alert:
|
||||
Added Spy to Allies
|
||||
Infiltrates refinery to steal 50% of players cash, minimum $500
|
||||
Infiltrates radar dome to reset exploration for enemy team
|
||||
Can assassinate enemy units with force-fire
|
||||
Added Gap Generator to Allies
|
||||
Tanya made exclusive to Allies
|
||||
Artillery explode chance lowered to 75%
|
||||
Flamethrower has new flame art
|
||||
Pillbox includes a garrisoned riflemen when built, and other infantry can garrison the structure
|
||||
Camo pillbox removed
|
||||
Normal AI removed
|
||||
New AI: Rommel and Zhukov
|
||||
Rommel is a modified Hard AI focusing on artillery and V2, and few light vehicles
|
||||
Zhukov is a turtle, but sends large attacks with artillery and V2
|
||||
Added map: Tainted Peak (Nukem)
|
||||
Removed maps: Daejeon, Mjolnir, No Fly Zone
|
||||
Fixed bug letting passengers shoot from transports
|
||||
C&C:
|
||||
A10s speed increased, Napalm Drop damage increased
|
||||
Chinooks now carry up to 10 passengers
|
||||
Sight of all infantry increased by 1
|
||||
Chem Warrior/Flamethrower/Grenadier damage vs certain armor types increased
|
||||
Chem Warrior will walk through tiberium instead of pathing around it
|
||||
Artillery attack range doubled
|
||||
Guard Tower attack range decreased by 1
|
||||
MCV and Construction Yard sight increased
|
||||
Construction Yard armor type changed to Heavy from Wood
|
||||
Harvester armor type changed to Heavy from Light
|
||||
Proability of SpawnVisceriod from 10% to 2%
|
||||
Reduced damage and size of Grenadier death explosions
|
||||
Units do not attack buildings when attack-moving or idle, exception made for defensive structures
|
||||
Lots of AI changes
|
||||
Removed nuke crate, hide-map crate
|
||||
Fixed crash viewing replays
|
||||
Fixed radar not being shown during replay
|
||||
|
||||
20120315:
|
||||
Engine:
|
||||
General performance improvements
|
||||
Added setting for direct connection on game launch (Game:ConnectTo: ip:port)
|
||||
Added setting to limit framerate via startup argument (Graphics:CapFrameRate: false)
|
||||
Added owner chooser for new actors in the editor
|
||||
Added actor info panel in the editor (doubleclick)
|
||||
Added a Setup Default Players menu item to map editor
|
||||
Fixed minimap export breaking subsequent actions in the editor
|
||||
Fixed writing of empty replays
|
||||
Fixed issue with LaserZap widths (obelisk shots)
|
||||
Both Mods:
|
||||
Server lobbies upon creation use the previously played map
|
||||
Added support for a Game.ConnectTo argument which allows clients to direct connect to a server when game is launched
|
||||
Always allow buildings to be repaired (removed dependency on Construction Yard)
|
||||
Added a new Defend stance for units
|
||||
Added base under attack notification
|
||||
Spacebar focuses viewport to last under attack notification
|
||||
Ctrl-Shift-Numkey groups units into existing group
|
||||
Helicopters now bob slightly in flight
|
||||
Bots now repair their own buildings
|
||||
Fixed a bug where bots would be unable to set rallypoints for production buildings
|
||||
Bots now maintain a level of aggro on enemy units
|
||||
Made SpawnMPUnits' initial unit configurable
|
||||
Added a dropdown list in the map editor for setting an actor's owner upon placement
|
||||
Bots:
|
||||
Repair their own buildings
|
||||
Maintain a level of aggro on enemy units
|
||||
Moved some bot configuration into system.yaml
|
||||
Fixed being unable to set rallypoints for production buildings
|
||||
Replaced the server browser with a new and awesome one
|
||||
Fixed a bug where infantry squish sounds weren't positioned
|
||||
Fixed a bug where actor priority wasn't correct for doubleclick
|
||||
|
||||
Server lobbies upon creation use the previously played map
|
||||
Made SpawnMPUnits' initial unit configurable
|
||||
Fixed infantry squish sounds not being positioned
|
||||
Fixed actor priority not being correct for doubleclick
|
||||
Fixed poor stance switching detection
|
||||
Semi-fixed naval units repairing from anywhere on map
|
||||
Red Alert:
|
||||
Fixed a crash which occurred when playing an online game with Hard AI
|
||||
Fixed a bug where planes could stack more than 1-per-airfield
|
||||
Fixed a bug where planes would not rearm at airfields
|
||||
Fixed crash which occurred when playing an online game with Hard AI
|
||||
Fixed planes stacking more than 1 per airfield
|
||||
Fixed planes being unable to rearm at airfield
|
||||
Improved logic for sending planes and helicopters back to base
|
||||
Changed MIG to fire 2 missiles per burst instead of 4
|
||||
Changed HELI (longbow) to fire missiles in bursts of 2
|
||||
Added a Show Shellmap setting
|
||||
Changed team color picker to match C&C's
|
||||
Fixed a bug where infantry could not pass over anti-tank mines, and vice versa
|
||||
Fixed a bug where the shellmap would reload unnecessarily when disconnecting from a lobby that hasn't started
|
||||
Added AutoTarget capability to submarines, but they are set to HoldFire stance by default
|
||||
Fixed infantry not able to walk over anti-tank mines, and vice versa
|
||||
Fixed pointless reload of shellmap when disconnecting from lobby
|
||||
Added a setting to toggle shellmap
|
||||
Changed team color chooser to match C&C's
|
||||
Balance:
|
||||
MiG fires in bursts of 2 instead of 4, and damage per missile increased
|
||||
Longbow fires in bursts of 2 instead of 1
|
||||
Submarines are set to HoldFire stance by default
|
||||
Mammoth Tank hp regeneration altered - 25hp per second, after 10 seconds since last unit damage
|
||||
Tesla Tank cost decreased and armor increased
|
||||
Flamethrower now only requires Flame Turret to be built
|
||||
Minelayer (Anti-Tank) mine count reduced from 5 to 3
|
||||
New Map: Bombardment Islands (Sprog)
|
||||
New Map: Engagement (Nukem)
|
||||
New Map: Man to Man (Nukem)
|
||||
New Map: Breaking Point (Nukem)
|
||||
New Map: Asymetric Battle (Seru)
|
||||
New Map: Temperal (Blarget2)
|
||||
New Map: Ares National Park (Wuschel)
|
||||
New Map: Poseidon (Wuschel)
|
||||
New Map: Apollo (Wuschel)
|
||||
Removed Maps: Paramount, Pandemonium, Bavarian Redux
|
||||
C&C:
|
||||
Changed the bot spawn picker to match RA's
|
||||
Changed the bot spawn chooser to match RA's
|
||||
Reduced delay of tooltips
|
||||
Fixed a lobby crash when players joined
|
||||
Balance:
|
||||
Stealth Tanks are set to HoldFire stance by default
|
||||
|
||||
20111013:
|
||||
Engine:
|
||||
|
||||
20
INSTALL
20
INSTALL
@@ -41,23 +41,19 @@ UBUNTU (substitute comparable packages for other linux distros):
|
||||
|
||||
OpenRA does not work with some older versions of Compiz. On affected systems, disable desktop effects before playing. This is fixed in Ubuntu Natty and later.
|
||||
|
||||
You will additionally need to copy the third party dependencies (.dll and .config) from the
|
||||
thirdparty and thirdparty/Tao directories into the game root:
|
||||
|
||||
cp -v thirdparty/*.dll thirdparty/Tao/* .
|
||||
|
||||
Alternatively, the dlls can be installed into your system GAC. This is not
|
||||
The following dlls can also be installed into your system GAC. This is not
|
||||
recommended because we ship a custom Tao.FreeType that can conflict with
|
||||
other applications that use Tao:
|
||||
|
||||
gacutil -i thirdparty/Tao/Tao.Cg.dll
|
||||
gacutil -i thirdparty/Tao/Tao.OpenGl.dll
|
||||
gacutil -i thirdparty/Tao/Tao.OpenAl.dll
|
||||
gacutil -i thirdparty/Tao/Tao.Sdl.dll
|
||||
gacutil -i thirdparty/Tao/Tao.FreeType.dll
|
||||
gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
gacutil -i Tao.Cg.dll
|
||||
gacutil -i Tao.OpenGl.dll
|
||||
gacutil -i Tao.OpenAl.dll
|
||||
gacutil -i Tao.Sdl.dll
|
||||
gacutil -i Tao.FreeType.dll
|
||||
gacutil -i ICSharpCode.SharpZipLib.dll
|
||||
|
||||
To compile OpenRA, run `make' from the command line.
|
||||
To install run 'make install'.
|
||||
Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert
|
||||
or `mono OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer
|
||||
|
||||
|
||||
64
Makefile
64
Makefile
@@ -1,14 +1,14 @@
|
||||
CSC = gmcs
|
||||
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
CSFLAGS = -nologo -warn:4 -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
DEFINE = DEBUG;TRACE
|
||||
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
PHONY = core tools package all mods clean distclean
|
||||
|
||||
.SUFFIXES:
|
||||
core: game renderers mod_ra mod_cnc utility
|
||||
core: game renderers mods utility tsbuild
|
||||
tools: editor ralint tsbuild
|
||||
package: core editor
|
||||
mods: mod_ra mod_cnc
|
||||
mods: mod_ra mod_cnc mod_d2k
|
||||
all: core tools
|
||||
clean:
|
||||
@-rm -f *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
|
||||
@@ -97,6 +97,16 @@ mod_cnc_EXTRA_CMDS = mono --debug RALint.exe cnc
|
||||
PROGRAMS += mod_cnc
|
||||
mod_cnc: $(mod_cnc_TARGET)
|
||||
|
||||
# Dune 2000
|
||||
mod_d2k_SRCS := $(shell find OpenRA.Mods.D2k/ -iname '*.cs')
|
||||
mod_d2k_TARGET = mods/d2k/OpenRA.Mods.D2k.dll
|
||||
mod_d2k_KIND = library
|
||||
mod_d2k_DEPS = $(STD_MOD_DEPS) $(mod_ra_TARGET) $(mod_cnc_TARGET) $(utility_TARGET)
|
||||
mod_d2k_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET) $(utility_TARGET)
|
||||
mod_d2k_EXTRA_CMDS = mono --debug RALint.exe d2k
|
||||
PROGRAMS += mod_d2k
|
||||
mod_d2k: $(mod_d2k_TARGET)
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
@@ -127,15 +137,19 @@ ralint: $(ralint_TARGET)
|
||||
|
||||
# Builds and exports tilesets from a bitmap
|
||||
tsbuild_SRCS := $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
tsbuild_TARGET = TilesetBuilder.exe
|
||||
tsbuild_TARGET = OpenRA.TilesetBuilder.exe
|
||||
tsbuild_KIND = winexe
|
||||
tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
|
||||
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
|
||||
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.frmBuilder.resources -resource:OpenRA.TilesetBuilder.frmNew.resources -resource:OpenRA.TilesetBuilder.Surface.resources
|
||||
PROGRAMS += tsbuild
|
||||
OpenRA.TilesetBuilder.Form1.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
|
||||
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
|
||||
OpenRA.TilesetBuilder.frmBuilder.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/frmBuilder.resx OpenRA.TilesetBuilder.frmBuilder.resources 1> /dev/null
|
||||
OpenRA.TilesetBuilder.frmNew.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/frmNew.resx OpenRA.TilesetBuilder.frmNew.resources 1> /dev/null
|
||||
OpenRA.TilesetBuilder.Surface.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Surface.resx OpenRA.TilesetBuilder.Surface.resources 1> /dev/null
|
||||
tsbuild: OpenRA.TilesetBuilder.frmBuilder.resources OpenRA.TilesetBuilder.frmNew.resources OpenRA.TilesetBuilder.Surface.resources $(tsbuild_TARGET)
|
||||
|
||||
#
|
||||
# Launchers / Utilities
|
||||
@@ -180,15 +194,15 @@ $(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
#
|
||||
# Install / Uninstall for *nix
|
||||
#
|
||||
prefix = /usr/local
|
||||
datarootdir = $(prefix)/share
|
||||
datadir = $(datarootdir)
|
||||
bindir = $(prefix)/bin
|
||||
prefix ?= /usr/local
|
||||
datarootdir ?= $(prefix)/share
|
||||
datadir ?= $(datarootdir)
|
||||
bindir ?= $(prefix)/bin
|
||||
BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
|
||||
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
CORE = fileformats rcg rgl rsdl rnull game editor utility
|
||||
CORE = fileformats rcg rgl rsdl rnull game editor utility tsbuild
|
||||
|
||||
install: all
|
||||
@-echo "Installing OpenRA to $(INSTALL_DIR)"
|
||||
@@ -196,6 +210,10 @@ install: all
|
||||
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) $(mod_cnc_TARGET) $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(mod_ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/d2k
|
||||
@$(INSTALL_PROGRAM) $(mod_d2k_TARGET) $(INSTALL_DIR)/mods/d2k
|
||||
|
||||
@-cp $(foreach f,$(shell ls mods/cnc --hide=*.dll),mods/cnc/$(f)) $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/maps $(INSTALL_DIR)/mods/cnc
|
||||
@@ -205,8 +223,6 @@ install: all
|
||||
@cp -r mods/cnc/sequences $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/tilesets $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/uibits $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(mod_ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
|
||||
@-cp $(foreach f,$(shell ls mods/ra --hide=*.dll),mods/ra/$(f)) $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/maps $(INSTALL_DIR)/mods/ra
|
||||
@@ -215,20 +231,34 @@ install: all
|
||||
@cp -r mods/ra/rules $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/tilesets $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/uibits $(INSTALL_DIR)/mods/ra
|
||||
|
||||
@-cp $(foreach f,$(shell ls mods/d2k --hide=*.dll),mods/d2k/$(f)) $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/maps $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/bits $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/chrome $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/rules $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/tilesets $(INSTALL_DIR)/mods/d2k
|
||||
@cp -r mods/d2k/uibits $(INSTALL_DIR)/mods/d2k
|
||||
|
||||
@cp -r glsl $(INSTALL_DIR)
|
||||
@cp -r cg $(INSTALL_DIR)
|
||||
@cp *.ttf $(INSTALL_DIR)
|
||||
@cp --parents -r thirdparty/Tao $(INSTALL_DIR)
|
||||
@cp thirdparty/Tao/* $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) thirdparty/ICSharpCode.SharpZipLib.dll $(INSTALL_DIR)
|
||||
|
||||
@echo "#!/bin/sh" > openra
|
||||
@echo "cd "$(datadir)"/openra" >> openra
|
||||
@echo "mono "$(datadir)"/openra/OpenRA.Game.exe \"$$""@\"" >> openra
|
||||
@echo "exec mono "$(datadir)"/openra/OpenRA.Game.exe \"$$""@\"" >> openra
|
||||
|
||||
@echo "#!/bin/sh" > openra-editor
|
||||
@echo "cd "$(datadir)"/openra" >> openra-editor
|
||||
@echo "exec mono "$(datadir)"/openra/OpenRA.Editor.exe \"$$""@\"" >> openra-editor
|
||||
|
||||
@$(INSTALL_PROGRAM) -d $(BIN_INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) -m +rx openra $(BIN_INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) -m +rx openra-editor $(BIN_INSTALL_DIR)
|
||||
|
||||
uninstall:
|
||||
@-rm -r $(INSTALL_DIR)
|
||||
@-rm $(DESTDIR)$(bindir)/openra
|
||||
@-rm $(DESTDIR)$(bindir)/openra-editor
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.Editor
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
{
|
||||
if (surface.Map.IsInMap(new int2(u, v) + pos))
|
||||
if (surface.Map.IsInMap(new CVec(u, v) + pos))
|
||||
{
|
||||
var z = u + v * template.Size.X;
|
||||
if (tile.TileBitmapBytes[z] != null)
|
||||
@@ -69,17 +69,17 @@ namespace OpenRA.Editor
|
||||
Brush.Bitmap.Height * surface.Zoom);
|
||||
}
|
||||
|
||||
void FloodFillWithBrush(Surface s, int2 pos)
|
||||
void FloodFillWithBrush(Surface s, CPos pos)
|
||||
{
|
||||
var queue = new Queue<int2>();
|
||||
var queue = new Queue<CPos>();
|
||||
var replace = s.Map.MapTiles.Value[pos.X, pos.Y];
|
||||
var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y];
|
||||
|
||||
Action<int, int> MaybeEnqueue = (x, y) =>
|
||||
Action<int, int> maybeEnqueue = (x, y) =>
|
||||
{
|
||||
if (s.Map.IsInMap(x, y) && !touched[x, y])
|
||||
{
|
||||
queue.Enqueue(new int2(x, y));
|
||||
queue.Enqueue(new CPos(x, y));
|
||||
touched[x, y] = true;
|
||||
}
|
||||
};
|
||||
@@ -91,16 +91,16 @@ namespace OpenRA.Editor
|
||||
if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace))
|
||||
continue;
|
||||
|
||||
var a = FindEdge(s, p, new int2(-1, 0), replace);
|
||||
var b = FindEdge(s, p, new int2(1, 0), replace);
|
||||
var a = FindEdge(s, p, new CVec(-1, 0), replace);
|
||||
var b = FindEdge(s, p, new CVec(1, 0), replace);
|
||||
|
||||
for (var x = a.X; x <= b.X; x++)
|
||||
{
|
||||
s.Map.MapTiles.Value[x, p.Y] = new TileReference<ushort, byte> { type = Brush.N, index = (byte)0 };
|
||||
if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace))
|
||||
MaybeEnqueue(x, p.Y - 1);
|
||||
maybeEnqueue(x, p.Y - 1);
|
||||
if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace))
|
||||
MaybeEnqueue(x, p.Y + 1);
|
||||
maybeEnqueue(x, p.Y + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace OpenRA.Editor
|
||||
s.Chunks.Clear();
|
||||
}
|
||||
|
||||
int2 FindEdge(Surface s, int2 p, int2 d, TileReference<ushort, byte> replace)
|
||||
CPos FindEdge(Surface s, CPos p, CVec d, TileReference<ushort, byte> replace)
|
||||
{
|
||||
for (; ; )
|
||||
{
|
||||
|
||||
34
OpenRA.Editor/Form1.Designer.cs
generated
34
OpenRA.Editor/Form1.Designer.cs
generated
@@ -82,6 +82,9 @@ namespace OpenRA.Editor
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabelFiller = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.toolStripStatusLabelMousePosition = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.copySelectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
@@ -225,8 +228,8 @@ namespace OpenRA.Editor
|
||||
this.actorOwnerChooser.Name = "actorOwnerChooser";
|
||||
this.actorOwnerChooser.Size = new System.Drawing.Size(184, 21);
|
||||
this.actorOwnerChooser.TabIndex = 3;
|
||||
this.actorOwnerChooser.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.onDrawPlayerItem);
|
||||
this.actorOwnerChooser.SelectionChangeCommitted += new System.EventHandler(this.onSelectOwner);
|
||||
this.actorOwnerChooser.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawPlayerListItem);
|
||||
this.actorOwnerChooser.SelectionChangeCommitted += new System.EventHandler(this.OnSelectedPlayerChanged);
|
||||
//
|
||||
// tabPage3
|
||||
//
|
||||
@@ -417,8 +420,11 @@ namespace OpenRA.Editor
|
||||
this.resizeToolStripMenuItem,
|
||||
this.showActorNamesToolStripMenuItem,
|
||||
this.showGridToolStripMenuItem,
|
||||
this.toolStripSeparator5,
|
||||
this.fixOpenAreasToolStripMenuItem,
|
||||
this.setupDefaultPlayersMenuItem});
|
||||
this.setupDefaultPlayersMenuItem,
|
||||
this.toolStripSeparator4,
|
||||
this.copySelectionToolStripMenuItem});
|
||||
this.mapToolStripMenuItem.Name = "mapToolStripMenuItem";
|
||||
this.mapToolStripMenuItem.Size = new System.Drawing.Size(43, 23);
|
||||
this.mapToolStripMenuItem.Text = "&Map";
|
||||
@@ -507,6 +513,23 @@ namespace OpenRA.Editor
|
||||
this.toolStripStatusLabelMousePosition.Size = new System.Drawing.Size(22, 17);
|
||||
this.toolStripStatusLabelMousePosition.Text = "0,0";
|
||||
//
|
||||
// copySelectionToolStripMenuItem
|
||||
//
|
||||
this.copySelectionToolStripMenuItem.Name = "copySelectionToolStripMenuItem";
|
||||
this.copySelectionToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
|
||||
this.copySelectionToolStripMenuItem.Text = "Copy Selection";
|
||||
this.copySelectionToolStripMenuItem.Click += new System.EventHandler(this.copySelectionToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator4
|
||||
//
|
||||
this.toolStripSeparator4.Name = "toolStripSeparator4";
|
||||
this.toolStripSeparator4.Size = new System.Drawing.Size(182, 6);
|
||||
//
|
||||
// toolStripSeparator5
|
||||
//
|
||||
this.toolStripSeparator5.Name = "toolStripSeparator5";
|
||||
this.toolStripSeparator5.Size = new System.Drawing.Size(182, 6);
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -520,9 +543,9 @@ namespace OpenRA.Editor
|
||||
this.Name = "Form1";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "OpenRA Editor";
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
@@ -592,6 +615,9 @@ namespace OpenRA.Editor
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.FlowLayoutPanel actorPalette;
|
||||
private System.Windows.Forms.ComboBox actorOwnerChooser;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator5;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
|
||||
private System.Windows.Forms.ToolStripMenuItem copySelectionToolStripMenuItem;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Editor
|
||||
tilePalette.ResumeLayout();
|
||||
actorPalette.ResumeLayout();
|
||||
resourcePalette.ResumeLayout();
|
||||
surface1.Bind(null, null, null);
|
||||
surface1.Bind(null, null, null, null);
|
||||
pmMiniMap.Image = null;
|
||||
currentMod = toolStripComboBox1.SelectedItem as string;
|
||||
|
||||
@@ -138,38 +138,67 @@ namespace OpenRA.Editor
|
||||
Rules.LoadRules(manifest, map);
|
||||
tileset = Rules.TileSets[map.Tileset];
|
||||
tileset.LoadTiles();
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
|
||||
int[] ShadowIndex = { 3, 4 };
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), ShadowIndex);
|
||||
|
||||
surface1.Bind(map, tileset, palette);
|
||||
// required for desert terrain in RA
|
||||
var playerPalette = tileset.PlayerPalette ?? tileset.Palette;
|
||||
var PlayerPalette = new Palette(FileSystem.Open(playerPalette), ShadowIndex);
|
||||
|
||||
surface1.Bind(map, tileset, palette, PlayerPalette);
|
||||
// construct the palette of tiles
|
||||
var palettes = new[] { tilePalette, actorPalette, resourcePalette };
|
||||
foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
|
||||
foreach (var t in tileset.Templates)
|
||||
|
||||
string[] templateOrder = tileset.EditorTemplateOrder ?? new string[]{};
|
||||
foreach (var tc in tileset.Templates.GroupBy(t => t.Value.Category).OrderBy(t => templateOrder.ToList().IndexOf(t.Key)))
|
||||
{
|
||||
try
|
||||
var category = tc.Key ?? "(Uncategorized)";
|
||||
var categoryHeader = new Label
|
||||
{
|
||||
var bitmap = tileset.RenderTemplate((ushort)t.Key, palette);
|
||||
var ibox = new PictureBox
|
||||
BackColor = SystemColors.Highlight,
|
||||
ForeColor = SystemColors.HighlightText,
|
||||
Text = category,
|
||||
AutoSize = false,
|
||||
Height = 24,
|
||||
TextAlign = ContentAlignment.MiddleLeft,
|
||||
Width = tilePalette.ClientSize.Width,
|
||||
};
|
||||
// hook this manually, anchoring inside FlowLayoutPanel is flaky.
|
||||
tilePalette.Resize += (_,e) => categoryHeader.Width = tilePalette.ClientSize.Width;
|
||||
|
||||
if (tilePalette.Controls.Count > 0)
|
||||
tilePalette.SetFlowBreak(
|
||||
tilePalette.Controls[tilePalette.Controls.Count - 1], true);
|
||||
tilePalette.Controls.Add(categoryHeader);
|
||||
|
||||
foreach( var t in tc )
|
||||
{
|
||||
try
|
||||
{
|
||||
Image = bitmap,
|
||||
Width = bitmap.Width / 2,
|
||||
Height = bitmap.Height / 2,
|
||||
SizeMode = PictureBoxSizeMode.StretchImage
|
||||
};
|
||||
|
||||
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
|
||||
ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
|
||||
|
||||
var template = t.Value;
|
||||
tilePalette.Controls.Add(ibox);
|
||||
tt.SetToolTip(ibox,
|
||||
"{1}:{0} ({2}x{3})".F(
|
||||
template.Image,
|
||||
template.Id,
|
||||
template.Size.X,
|
||||
template.Size.Y));
|
||||
var bitmap = tileset.RenderTemplate((ushort)t.Key, palette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = bitmap,
|
||||
Width = bitmap.Width / 2,
|
||||
Height = bitmap.Height / 2,
|
||||
SizeMode = PictureBoxSizeMode.StretchImage
|
||||
};
|
||||
|
||||
var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
|
||||
ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
|
||||
|
||||
var template = t.Value;
|
||||
tilePalette.Controls.Add(ibox);
|
||||
tt.SetToolTip(ibox,
|
||||
"{1}:{0} ({2}x{3})".F(
|
||||
template.Image,
|
||||
template.Id,
|
||||
template.Size.X,
|
||||
template.Size.Y));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
var actorTemplates = new List<ActorTemplate>();
|
||||
@@ -187,7 +216,13 @@ namespace OpenRA.Editor
|
||||
if (etf != null && etf.RequireTilesets != null
|
||||
&& !etf.RequireTilesets.Contains(tileset.Id)) continue;
|
||||
|
||||
var template = RenderUtils.RenderActor(info, tileset, palette);
|
||||
var TemplatePalette = PlayerPalette;
|
||||
var rsi = info.Traits.GetOrDefault<RenderSimpleInfo>();
|
||||
// exception for desert buildings
|
||||
if (rsi != null && rsi.Palette != null && rsi.Palette.Contains("terrain"))
|
||||
TemplatePalette = palette;
|
||||
|
||||
var template = RenderUtils.RenderActor(info, tileset, TemplatePalette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = template.Bitmap,
|
||||
@@ -218,7 +253,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
try
|
||||
{
|
||||
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
|
||||
var template = RenderUtils.RenderResourceType(a, tileset.Extensions, PlayerPalette);
|
||||
var ibox = new PictureBox
|
||||
{
|
||||
Image = template.Bitmap,
|
||||
@@ -286,14 +321,14 @@ namespace OpenRA.Editor
|
||||
return;
|
||||
|
||||
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
|
||||
(int)rd.cordonTop.Value,
|
||||
(int)rd.cordonRight.Value,
|
||||
(int)rd.cordonBottom.Value);
|
||||
(int)rd.cordonTop.Value,
|
||||
(int)rd.cordonRight.Value,
|
||||
(int)rd.cordonBottom.Value);
|
||||
|
||||
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
|
||||
{
|
||||
surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value);
|
||||
surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches
|
||||
surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette, surface1.PlayerPalette); // rebind it to invalidate all caches
|
||||
}
|
||||
|
||||
surface1.Invalidate();
|
||||
@@ -362,6 +397,7 @@ namespace OpenRA.Editor
|
||||
map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value,
|
||||
(int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
|
||||
|
||||
map.Players.Clear();
|
||||
map.MakeDefaultPlayers();
|
||||
|
||||
NewMap(map);
|
||||
@@ -491,6 +527,7 @@ namespace OpenRA.Editor
|
||||
void SetupDefaultPlayers(object sender, EventArgs e)
|
||||
{
|
||||
dirty = true;
|
||||
surface1.Map.Players.Clear();
|
||||
surface1.Map.MakeDefaultPlayers();
|
||||
|
||||
surface1.Chunks.Clear();
|
||||
@@ -499,7 +536,7 @@ namespace OpenRA.Editor
|
||||
PopulateActorOwnerChooser();
|
||||
}
|
||||
|
||||
void onDrawPlayerItem(object sender, DrawItemEventArgs e)
|
||||
void DrawPlayerListItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
// color block
|
||||
var player = e.Index >= 0 ? (PlayerReference)(sender as ComboBox).Items[e.Index] : null;
|
||||
@@ -517,10 +554,15 @@ namespace OpenRA.Editor
|
||||
e.Graphics.DrawString( player.Name, e.Font, foreBrush, e.Bounds.Left + e.Bounds.Height + 12, e.Bounds.Top );
|
||||
}
|
||||
|
||||
void onSelectOwner(object sender, EventArgs e)
|
||||
void OnSelectedPlayerChanged(object sender, EventArgs e)
|
||||
{
|
||||
var player = actorOwnerChooser.SelectedItem as PlayerReference;
|
||||
surface1.NewActorOwner = player.Name;
|
||||
}
|
||||
|
||||
private void copySelectionToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
surface1.CopySelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,13 +120,45 @@
|
||||
<metadata name="tt.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>76, 17</value>
|
||||
</metadata>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>198, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="propertiesToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACCklE
|
||||
QVQ4T6WT30tTUQDHz39QD0UQSpAPIkgPyR60AiUiyoGBL4qZjOyt0tZP9tBDk1AsXIhj93ILdd27DPPH
|
||||
3VwrUrdK2ioJHAgVOdoPaQsarBg43L6ec+akuRsEPnw5D4fP5/vlXg4BQHaSf8LjjwdqaTA2cg+y1Ith
|
||||
qxmi5Tas/SYWk+QRoPgmtNsLcPq7GYX8+XoTqaUL+KR2cAmDxeBgqeBv2NhWzwUFOBk4g5/zRxB3V8Es
|
||||
38AtbzuIw/0RLMrMeyhTs2CzGdRtaOTn1dajvLkAR9VKLNvLcHmoExddzSDKzAfkcjkkEtEiOLxoQpdB
|
||||
z+Er7ScQUg/DL5TD2bsfl5oPoKWnCZ3jehDZGeAC1hwL3uXNs55Jep7Gis/AJWxyTeVe1FXvhq5qH6oP
|
||||
7nlw/NoxGByNIKPT77CezSEeD6Pn+jlEIiGk6X8N+F9zyfLYIZzUVUCwT0J36jy9yX83KjDq7zSADE8t
|
||||
cGB7kpksFt76YDzbgMWVFLzBX0WCTcku8mjiTSm8lkUslcHnH2kK/+aw6k+UCJiESE+9XCApz2Gzu5Gk
|
||||
sEVy4r6got82vRV5blVbIDyZ21rAZrPmL7w5P5s1KxQWXRFtgU15lV8ge2AbdXPY8pAuEIsXWJ6FtAVW
|
||||
+SWSmXWssuZ4vnl+s5nNFl1hMLjP8U1bMGR/wS/+N9tf7o6eMpNtADko6xybtEXLAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="resizeToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAADLklE
|
||||
QVQ4T3WS60/ScRjFf39CL3rR1ovurduWbbU2t7ZqdlkXt7Lrym6O1VoXcdYqQ54wKlGxABE1CzWF0nIm
|
||||
lZcoTbyUNJFIzDJSJK+E0qy8wInvz+i2erazfd+cz3m+zw4nTS+FLOeZNim3Vp6UU5sqvf5MSZqnyjhV
|
||||
pfKUvEx54kqp8rCkWHVQVKSJPHtbs+tUgSYiOicVAMfEqfR1dVFCGSqrX94cHQeN/aXhbyD3Zz91uf3U
|
||||
9tFHTQ4fzVtH9BOQVdKcW2F6/eKkWA1zcxu6vUAQMmCzk/3AErLtDyFrrY035z16T3PXin8B5LfqZE6P
|
||||
HyZzKw5FX+Yh4XtjwZKZGV3lNPIkhhojplON3Uc3S9/Q7LDfADKtKYklMsgTkwV7joixKHQr2Nq2fSET
|
||||
5uQwqtsyjcot45R510ozV8f/2iAhsyolCNh9WIyFoRGYHbIGfYN+SVd7Nznzk8ll0FLzKxdZO3xkaOjG
|
||||
GYUxcIIfRxSlPU4N/rn1fS8JJVlU1WCT3npggVLfAIWuHjJtNRIyjIhTPEKM7D6OSop4RcXpwZ2Wl11l
|
||||
gHanmze/c36ioc8jyRlFjSzljxl2daI9Pwuv1Cnw9PRjZeQ1cCcSS68Fza6+IXL2fCG7w0ssmc3o2IR8
|
||||
gbc1PQU9NUp48sNRcUyAkPBL4AIlUbLk3gEvS6YXrW6p0dx9UZ5n4gHjzBmYAAPPYwRwazeiMXYWqjcs
|
||||
wLSVInAHRYWq0TEf9Q+NUEsg+fr9t2nF1U71leyqn+u3vPuIl2298HZ2wnxkO5q2LYOtxoKpK86D23tW
|
||||
r+7zfCVzywAVGT/QVV2LvNDo0Eo0j3mAtbUTiRnFOJ94Axp9LfIKK5Ctq0RDmw9TQuPAsW7bHYNUYLCQ
|
||||
JL2GRAqjtMDYwV+8wzUAWeY9eIfHYW0fxNodxyGWZeOSPBvzl27C5OXnwG0T5irmr79wgdWTNYyVJFL8
|
||||
kAeo8wyBA/rx2jGErBIH0nXPsWmPEHcM9YgURGPS0jMTZfiXGKDfM4Y0fVOgA/UgRQWECTpExaqxUyDF
|
||||
wuUbJjb4H0AQfxtrDqiweLMUc8LEmLEqnv9zUMzM9B1/cM83lepxTAAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="newToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
@@ -260,41 +292,6 @@
|
||||
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
|
||||
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
|
||||
gg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="propertiesToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACCklE
|
||||
QVQ4T6WT30tTUQDHz39QD0UQSpAPIkgPyR60AiUiyoGBL4qZjOyt0tZP9tBDk1AsXIhj93ILdd27DPPH
|
||||
3VwrUrdK2ioJHAgVOdoPaQsarBg43L6ec+akuRsEPnw5D4fP5/vlXg4BQHaSf8LjjwdqaTA2cg+y1Ith
|
||||
qxmi5Tas/SYWk+QRoPgmtNsLcPq7GYX8+XoTqaUL+KR2cAmDxeBgqeBv2NhWzwUFOBk4g5/zRxB3V8Es
|
||||
38AtbzuIw/0RLMrMeyhTs2CzGdRtaOTn1dajvLkAR9VKLNvLcHmoExddzSDKzAfkcjkkEtEiOLxoQpdB
|
||||
z+Er7ScQUg/DL5TD2bsfl5oPoKWnCZ3jehDZGeAC1hwL3uXNs55Jep7Gis/AJWxyTeVe1FXvhq5qH6oP
|
||||
7nlw/NoxGByNIKPT77CezSEeD6Pn+jlEIiGk6X8N+F9zyfLYIZzUVUCwT0J36jy9yX83KjDq7zSADE8t
|
||||
cGB7kpksFt76YDzbgMWVFLzBX0WCTcku8mjiTSm8lkUslcHnH2kK/+aw6k+UCJiESE+9XCApz2Gzu5Gk
|
||||
sEVy4r6got82vRV5blVbIDyZ21rAZrPmL7w5P5s1KxQWXRFtgU15lV8ge2AbdXPY8pAuEIsXWJ6FtAVW
|
||||
+SWSmXWssuZ4vnl+s5nNFl1hMLjP8U1bMGR/wS/+N9tf7o6eMpNtADko6xybtEXLAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="resizeToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
|
||||
JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAADLklE
|
||||
QVQ4T3WS60/ScRjFf39CL3rR1ovurduWbbU2t7ZqdlkXt7Lrym6O1VoXcdYqQ54wKlGxABE1CzWF0nIm
|
||||
lZcoTbyUNJFIzDJSJK+E0qy8wInvz+i2erazfd+cz3m+zw4nTS+FLOeZNim3Vp6UU5sqvf5MSZqnyjhV
|
||||
pfKUvEx54kqp8rCkWHVQVKSJPHtbs+tUgSYiOicVAMfEqfR1dVFCGSqrX94cHQeN/aXhbyD3Zz91uf3U
|
||||
9tFHTQ4fzVtH9BOQVdKcW2F6/eKkWA1zcxu6vUAQMmCzk/3AErLtDyFrrY035z16T3PXin8B5LfqZE6P
|
||||
HyZzKw5FX+Yh4XtjwZKZGV3lNPIkhhojplON3Uc3S9/Q7LDfADKtKYklMsgTkwV7joixKHQr2Nq2fSET
|
||||
5uQwqtsyjcot45R510ozV8f/2iAhsyolCNh9WIyFoRGYHbIGfYN+SVd7Nznzk8ll0FLzKxdZO3xkaOjG
|
||||
GYUxcIIfRxSlPU4N/rn1fS8JJVlU1WCT3npggVLfAIWuHjJtNRIyjIhTPEKM7D6OSop4RcXpwZ2Wl11l
|
||||
gHanmze/c36ioc8jyRlFjSzljxl2daI9Pwuv1Cnw9PRjZeQ1cCcSS68Fza6+IXL2fCG7w0ssmc3o2IR8
|
||||
gbc1PQU9NUp48sNRcUyAkPBL4AIlUbLk3gEvS6YXrW6p0dx9UZ5n4gHjzBmYAAPPYwRwazeiMXYWqjcs
|
||||
wLSVInAHRYWq0TEf9Q+NUEsg+fr9t2nF1U71leyqn+u3vPuIl2298HZ2wnxkO5q2LYOtxoKpK86D23tW
|
||||
r+7zfCVzywAVGT/QVV2LvNDo0Eo0j3mAtbUTiRnFOJ94Axp9LfIKK5Ctq0RDmw9TQuPAsW7bHYNUYLCQ
|
||||
JL2GRAqjtMDYwV+8wzUAWeY9eIfHYW0fxNodxyGWZeOSPBvzl27C5OXnwG0T5irmr79wgdWTNYyVJFL8
|
||||
kAeo8wyBA/rx2jGErBIH0nXPsWmPEHcM9YgURGPS0jMTZfiXGKDfM4Y0fVOgA/UgRQWECTpExaqxUyDF
|
||||
wuUbJjb4H0AQfxtrDqiweLMUc8LEmLEqnv9zUMzM9B1/cM83lepxTAAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
|
||||
@@ -174,10 +174,10 @@ namespace OpenRA.Editor
|
||||
// Add waypoint actors
|
||||
foreach( var kv in wps )
|
||||
{
|
||||
var a = new ActorReference("mpspawn");
|
||||
a.Add(new LocationInit(kv.Second));
|
||||
var a = new ActorReference("waypoint");
|
||||
a.Add(new LocationInit((CPos)kv.Second));
|
||||
a.Add(new OwnerInit("Neutral"));
|
||||
Map.Actors.Value.Add("spawn" + kv.First, a);
|
||||
Map.Actors.Value.Add("waypoint" + kv.First, a);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -189,27 +189,27 @@ namespace OpenRA.Editor
|
||||
|
||||
static MemoryStream ReadPackedSection(IniSection mapPackSection)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 1; ; i++)
|
||||
{
|
||||
string line = mapPackSection.GetValue(i.ToString(), null);
|
||||
var line = mapPackSection.GetValue(i.ToString(), null);
|
||||
if (line == null)
|
||||
break;
|
||||
|
||||
sb.Append(line.Trim());
|
||||
}
|
||||
|
||||
byte[] data = Convert.FromBase64String(sb.ToString());
|
||||
List<byte[]> chunks = new List<byte[]>();
|
||||
BinaryReader reader = new BinaryReader(new MemoryStream(data));
|
||||
var data = Convert.FromBase64String(sb.ToString());
|
||||
var chunks = new List<byte[]>();
|
||||
var reader = new BinaryReader(new MemoryStream(data));
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
uint length = reader.ReadUInt32() & 0xdfffffff;
|
||||
byte[] dest = new byte[8192];
|
||||
byte[] src = reader.ReadBytes((int)length);
|
||||
var length = reader.ReadUInt32() & 0xdfffffff;
|
||||
var dest = new byte[8192];
|
||||
var src = reader.ReadBytes((int)length);
|
||||
|
||||
/*int actualLength =*/
|
||||
Format80.DecodeInto(src, dest);
|
||||
@@ -219,8 +219,8 @@ namespace OpenRA.Editor
|
||||
}
|
||||
catch (EndOfStreamException) { }
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
foreach (byte[] chunk in chunks)
|
||||
var ms = new MemoryStream();
|
||||
foreach (var chunk in chunks)
|
||||
ms.Write(chunk, 0, chunk.Length);
|
||||
|
||||
ms.Position = 0;
|
||||
@@ -276,7 +276,7 @@ namespace OpenRA.Editor
|
||||
Map.Actors.Value.Add("Actor" + ActorCount++,
|
||||
new ActorReference(overlayActorMapping[raOverlayNames[o]])
|
||||
{
|
||||
new LocationInit( new int2(i, j) ),
|
||||
new LocationInit( new CPos(i, j) ),
|
||||
new OwnerInit( "Neutral" )
|
||||
});
|
||||
}
|
||||
@@ -284,7 +284,7 @@ namespace OpenRA.Editor
|
||||
|
||||
void ReadRATrees(IniFile file)
|
||||
{
|
||||
IniSection terrain = file.GetSection("TERRAIN", true);
|
||||
var terrain = file.GetSection("TERRAIN", true);
|
||||
if (terrain == null)
|
||||
return;
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace OpenRA.Editor
|
||||
Map.Actors.Value.Add("Actor" + ActorCount++,
|
||||
new ActorReference(kv.Value.ToLowerInvariant())
|
||||
{
|
||||
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
|
||||
new LocationInit(new CPos(loc % MapSize, loc / MapSize)),
|
||||
new OwnerInit("Neutral")
|
||||
});
|
||||
}
|
||||
@@ -316,14 +316,14 @@ namespace OpenRA.Editor
|
||||
|
||||
void ReadCncOverlay(IniFile file)
|
||||
{
|
||||
IniSection overlay = file.GetSection("OVERLAY", true);
|
||||
var overlay = file.GetSection("OVERLAY", true);
|
||||
if (overlay == null)
|
||||
return;
|
||||
|
||||
foreach (KeyValuePair<string, string> kv in overlay)
|
||||
{
|
||||
var loc = int.Parse(kv.Key);
|
||||
int2 cell = new int2(loc % MapSize, loc / MapSize);
|
||||
var cell = new CPos(loc % MapSize, loc / MapSize);
|
||||
|
||||
var res = Pair.New((byte)0, (byte)0);
|
||||
if (overlayResourceMapping.ContainsKey(kv.Value.ToLower()))
|
||||
@@ -343,7 +343,7 @@ namespace OpenRA.Editor
|
||||
|
||||
void ReadCncTrees(IniFile file)
|
||||
{
|
||||
IniSection terrain = file.GetSection("TERRAIN", true);
|
||||
var terrain = file.GetSection("TERRAIN", true);
|
||||
if (terrain == null)
|
||||
return;
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace OpenRA.Editor
|
||||
Map.Actors.Value.Add("Actor" + ActorCount++,
|
||||
new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant())
|
||||
{
|
||||
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
|
||||
new LocationInit(new CPos(loc % MapSize, loc / MapSize)),
|
||||
new OwnerInit("Neutral")
|
||||
});
|
||||
}
|
||||
@@ -375,13 +375,12 @@ namespace OpenRA.Editor
|
||||
if (parts[0] == "")
|
||||
parts[0] = "Neutral";
|
||||
|
||||
|
||||
if (!Players.Contains(parts[0]))
|
||||
Players.Add(parts[0]);
|
||||
|
||||
var actor = new ActorReference(parts[1].ToLowerInvariant())
|
||||
{
|
||||
new LocationInit(new int2(loc % MapSize, loc / MapSize)),
|
||||
new LocationInit(new CPos(loc % MapSize, loc / MapSize)),
|
||||
new OwnerInit(parts[0]),
|
||||
new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256),
|
||||
new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])),
|
||||
@@ -415,8 +414,51 @@ namespace OpenRA.Editor
|
||||
|
||||
void LoadPlayer(IniFile file, string section, bool isRA)
|
||||
{
|
||||
var c = section == "BadGuy" ? "red" :
|
||||
isRA ? "blue" : "gold";
|
||||
string c;
|
||||
string race;
|
||||
switch (section)
|
||||
{
|
||||
case "Spain":
|
||||
c = "gold";
|
||||
race = "allies";
|
||||
break;
|
||||
case "England":
|
||||
c = "green";
|
||||
race = "allies";
|
||||
break;
|
||||
case "Ukraine":
|
||||
c = "orange";
|
||||
race = "soviet";
|
||||
break;
|
||||
case "Germany":
|
||||
c = "black";
|
||||
race = "allies";
|
||||
break;
|
||||
case "France":
|
||||
c = "teal";
|
||||
race = "allies";
|
||||
break;
|
||||
case "Turkey":
|
||||
c = "salmon";
|
||||
race = "allies";
|
||||
break;
|
||||
case "Greece":
|
||||
case "GoodGuy":
|
||||
c = isRA? "blue" : "gold";
|
||||
race = isRA ? "allies" : "gdi";
|
||||
break;
|
||||
case "USSR":
|
||||
case "BadGuy":
|
||||
c = "red";
|
||||
race = isRA ? "soviet" : "nod";
|
||||
break;
|
||||
case "Special":
|
||||
case "Neutral":
|
||||
default:
|
||||
c = "neutral";
|
||||
race = isRA ? "allies" : "gdi";
|
||||
break;
|
||||
}
|
||||
|
||||
var color = namedColorMapping[c];
|
||||
|
||||
@@ -425,7 +467,7 @@ namespace OpenRA.Editor
|
||||
Name = section,
|
||||
OwnsWorld = section == "Neutral",
|
||||
NonCombatant = section == "Neutral",
|
||||
Race = isRA ? (section == "BadGuy" ? "soviet" : "allies") : (section == "BadGuy" ? "nod" : "gdi"),
|
||||
Race = race,
|
||||
ColorRamp = new ColorRamp(
|
||||
(byte)((color.First.GetHue() / 360.0f) * 255),
|
||||
(byte)(color.First.GetSaturation() * 255),
|
||||
@@ -433,7 +475,7 @@ namespace OpenRA.Editor
|
||||
(byte)(color.Second.GetBrightness() * 255))
|
||||
};
|
||||
|
||||
var Neutral = new [] {"Neutral"};
|
||||
var neutral = new [] {"Neutral"};
|
||||
foreach (var s in file.GetSection(section, true))
|
||||
{
|
||||
Console.WriteLine(s.Key);
|
||||
@@ -443,8 +485,8 @@ namespace OpenRA.Editor
|
||||
pr.InitialCash = int.Parse(s.Value);
|
||||
break;
|
||||
case "Allies":
|
||||
pr.Allies = s.Value.Split(',').Intersect(Players).Except(Neutral).ToArray();
|
||||
pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(Neutral).ToArray();
|
||||
pr.Allies = s.Value.Split(',').Intersect(Players).Except(neutral).ToArray();
|
||||
pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(neutral).ToArray();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,19 @@ namespace OpenRA.Editor
|
||||
{
|
||||
public string MapFolderPath;
|
||||
|
||||
public bool DirectoryIsEmpty(string path)
|
||||
{
|
||||
return !Directory.GetFileSystemEntries(path).Any();
|
||||
}
|
||||
|
||||
public MapSelect(string currentMod)
|
||||
{
|
||||
MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", currentMod, "maps" }
|
||||
MapFolderPath = new string[] { Platform.SupportDir, "maps", currentMod }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
if (!Directory.Exists(MapFolderPath))
|
||||
Directory.CreateDirectory(MapFolderPath);
|
||||
|
||||
InitializeComponent();
|
||||
MapIconsList.Images.Add(pictureBox1.Image);
|
||||
}
|
||||
@@ -34,6 +42,9 @@ namespace OpenRA.Editor
|
||||
MapList.Items.Clear();
|
||||
txtPathOut.Text = MapFolderPath;
|
||||
|
||||
if (DirectoryIsEmpty(MapFolderPath))
|
||||
return;
|
||||
|
||||
foreach (var map in ModData.FindMapsIn(MapFolderPath))
|
||||
{
|
||||
ListViewItem map1 = new ListViewItem();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -13,6 +13,25 @@
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ApplicationIcon>OpenRA.Editor.Icon.ico</ApplicationIcon>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation />
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -25,6 +44,7 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@@ -35,6 +55,7 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -122,6 +143,7 @@
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
@@ -157,6 +179,23 @@
|
||||
<ItemGroup>
|
||||
<Content Include="OpenRA.Editor.Icon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
114
OpenRA.Editor/Properties/Resources.Designer.cs
generated
114
OpenRA.Editor/Properties/Resources.Designer.cs
generated
@@ -1,71 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:2.0.50727.4927
|
||||
// Runtime Version:4.0.30319.269
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace OpenRA.Editor.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenRA.Editor.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace OpenRA.Editor.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenRA.Editor.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
OpenRA.Editor/Properties/Settings.Designer.cs
generated
36
OpenRA.Editor/Properties/Settings.Designer.cs
generated
@@ -1,30 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:2.0.50727.4927
|
||||
// Runtime Version:4.0.30319.269
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace OpenRA.Editor.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace OpenRA.Editor.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA.Editor
|
||||
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
@@ -84,7 +84,7 @@ namespace OpenRA.Editor
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace OpenRA.Editor
|
||||
public Map Map { get; private set; }
|
||||
public TileSet TileSet { get; private set; }
|
||||
public Palette Palette { get; private set; }
|
||||
public Palette PlayerPalette { get; private set; }
|
||||
public int2 Offset;
|
||||
|
||||
public int2 GetOffset() { return Offset; }
|
||||
@@ -38,6 +39,12 @@ namespace OpenRA.Editor
|
||||
public bool ShowActorNames;
|
||||
public bool ShowGrid;
|
||||
|
||||
public bool IsPaste { get { return TileSelection != null && ResourceSelection != null; } }
|
||||
public TileReference<ushort, byte>[,] TileSelection;
|
||||
public TileReference<byte, byte>[,] ResourceSelection;
|
||||
public CPos SelectionStart;
|
||||
public CPos SelectionEnd;
|
||||
|
||||
public string NewActorOwner;
|
||||
|
||||
public event Action AfterChange = () => { };
|
||||
@@ -49,17 +56,18 @@ namespace OpenRA.Editor
|
||||
|
||||
public Keys GetModifiers() { return ModifierKeys; }
|
||||
|
||||
public void Bind(Map m, TileSet ts, Palette p)
|
||||
public void Bind(Map m, TileSet ts, Palette p, Palette pp)
|
||||
{
|
||||
Map = m;
|
||||
TileSet = ts;
|
||||
Palette = p;
|
||||
PlayerPalette = pp;
|
||||
PlayerPalettes = null;
|
||||
Chunks.Clear();
|
||||
Tool = null;
|
||||
}
|
||||
|
||||
public void SetTool(ITool tool) { Tool = tool; }
|
||||
public void SetTool(ITool tool) { Tool = tool; ClearSelection(); }
|
||||
|
||||
public void BindActorTemplates(IEnumerable<ActorTemplate> templates)
|
||||
{
|
||||
@@ -83,6 +91,8 @@ namespace OpenRA.Editor
|
||||
UpdateStyles();
|
||||
}
|
||||
|
||||
static readonly Pen SelectionPen = new Pen(Color.Blue);
|
||||
static readonly Pen PastePen = new Pen(Color.Green);
|
||||
static readonly Pen CordonPen = new Pen(Color.Red);
|
||||
int2 MousePos;
|
||||
|
||||
@@ -157,23 +167,23 @@ namespace OpenRA.Editor
|
||||
void Erase()
|
||||
{
|
||||
// Crash preventing
|
||||
var BrushLocation = GetBrushLocation();
|
||||
var brushLocation = GetBrushLocation();
|
||||
|
||||
if (Map == null || BrushLocation.X >= Map.MapSize.X ||
|
||||
BrushLocation.Y >= Map.MapSize.Y ||
|
||||
BrushLocation.X < 0 ||
|
||||
BrushLocation.Y < 0)
|
||||
if (Map == null || brushLocation.X >= Map.MapSize.X ||
|
||||
brushLocation.Y >= Map.MapSize.Y ||
|
||||
brushLocation.X < 0 ||
|
||||
brushLocation.Y < 0)
|
||||
return;
|
||||
|
||||
Tool = null;
|
||||
|
||||
var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation);
|
||||
var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == brushLocation);
|
||||
if (key.Key != null) Map.Actors.Value.Remove(key.Key);
|
||||
|
||||
if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0)
|
||||
if (Map.MapResources.Value[brushLocation.X, brushLocation.Y].type != 0)
|
||||
{
|
||||
Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference<byte, byte>();
|
||||
var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize);
|
||||
Map.MapResources.Value[brushLocation.X, brushLocation.Y] = new TileReference<byte, byte>();
|
||||
var ch = new int2((brushLocation.X) / ChunkSize, (brushLocation.Y) / ChunkSize);
|
||||
if (Chunks.ContainsKey(ch))
|
||||
{
|
||||
Chunks[ch].Dispose();
|
||||
@@ -182,12 +192,20 @@ namespace OpenRA.Editor
|
||||
}
|
||||
|
||||
AfterChange();
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
void Draw()
|
||||
{
|
||||
if (Tool != null) Tool.Apply(this);
|
||||
AfterChange();
|
||||
if (Tool != null)
|
||||
{
|
||||
Tool.Apply(this);
|
||||
AfterChange();
|
||||
}
|
||||
else if (IsPaste)
|
||||
PasteSelection();
|
||||
else
|
||||
SelectionEnd = GetBrushLocationBR();
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
@@ -199,7 +217,12 @@ namespace OpenRA.Editor
|
||||
if (!IsPanning)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right) Erase();
|
||||
if (e.Button == MouseButtons.Left) Draw();
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
Draw();
|
||||
if (!IsPaste)
|
||||
SelectionStart = SelectionEnd = GetBrushLocation();
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
@@ -212,7 +235,7 @@ namespace OpenRA.Editor
|
||||
|
||||
var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
@@ -234,7 +257,7 @@ namespace OpenRA.Editor
|
||||
if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0)
|
||||
{
|
||||
var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap;
|
||||
var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height),
|
||||
var srcdata = resourceImage.LockBits(resourceImage.Bounds(),
|
||||
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||
|
||||
int* q = (int*)srcdata.Scan0.ToPointer();
|
||||
@@ -267,31 +290,42 @@ namespace OpenRA.Editor
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public int2 GetBrushLocation()
|
||||
public CPos GetBrushLocation()
|
||||
{
|
||||
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
|
||||
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
|
||||
return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
|
||||
return new CPos(vX / TileSet.TileSize, vY / TileSet.TileSize);
|
||||
}
|
||||
|
||||
public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp)
|
||||
public CPos GetBrushLocationBR()
|
||||
{
|
||||
var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
|
||||
var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
|
||||
return new CPos((vX + TileSet.TileSize - 1) / TileSet.TileSize,
|
||||
(vY + TileSet.TileSize - 1) / TileSet.TileSize);
|
||||
}
|
||||
|
||||
public void DrawActor(SGraphics g, CPos p, ActorTemplate t, ColorPalette cp)
|
||||
{
|
||||
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
|
||||
DrawImage(g, t.Bitmap, p, centered, cp);
|
||||
var actorPalette = cp;
|
||||
if (t.Appearance != null && t.Appearance.UseTerrainPalette)
|
||||
actorPalette = Palette.AsSystemPalette();
|
||||
DrawImage(g, t.Bitmap, p, centered, actorPalette);
|
||||
}
|
||||
|
||||
float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered)
|
||||
float2 GetDrawPosition(CPos location, Bitmap bmp, bool centered)
|
||||
{
|
||||
float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
|
||||
float offsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
|
||||
float drawX = TileSet.TileSize * location.X * Zoom + Offset.X - offsetX;
|
||||
|
||||
float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
|
||||
float offsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
|
||||
float drawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - offsetY;
|
||||
|
||||
return new float2(DrawX, DrawY);
|
||||
return new float2(drawX, drawY);
|
||||
}
|
||||
|
||||
public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp)
|
||||
public void DrawImage(SGraphics g, Bitmap bmp, CPos location, bool centered, ColorPalette cp)
|
||||
{
|
||||
var drawPos = GetDrawPosition(location, bmp, centered);
|
||||
|
||||
@@ -304,7 +338,7 @@ namespace OpenRA.Editor
|
||||
if (cp != null) bmp.Palette = restorePalette;
|
||||
}
|
||||
|
||||
void DrawActorBorder(SGraphics g, int2 p, ActorTemplate t)
|
||||
void DrawActorBorder(SGraphics g, CPos p, ActorTemplate t)
|
||||
{
|
||||
var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
|
||||
var drawPos = GetDrawPosition(p, t.Bitmap, centered);
|
||||
@@ -318,8 +352,8 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var pr = Map.Players[name];
|
||||
var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
|
||||
var remap = new PlayerColorRemap(pcpi.PaletteFormat, pr.ColorRamp);
|
||||
return new Palette(Palette, remap).AsSystemPalette();
|
||||
var remap = new PlayerColorRemap(pcpi.RemapIndex, pr.ColorRamp);
|
||||
return new Palette(PlayerPalette, remap).AsSystemPalette();
|
||||
}
|
||||
|
||||
Cache<string, ColorPalette> PlayerPalettes;
|
||||
@@ -367,6 +401,25 @@ namespace OpenRA.Editor
|
||||
Map.Bounds.Width * TileSet.TileSize * Zoom,
|
||||
Map.Bounds.Height * TileSet.TileSize * Zoom);
|
||||
|
||||
e.Graphics.DrawRectangle(SelectionPen,
|
||||
(SelectionStart.X * TileSet.TileSize * Zoom) + Offset.X,
|
||||
(SelectionStart.Y * TileSet.TileSize * Zoom) + Offset.Y,
|
||||
(SelectionEnd - SelectionStart).X * TileSet.TileSize * Zoom,
|
||||
(SelectionEnd - SelectionStart).Y * TileSet.TileSize * Zoom);
|
||||
|
||||
if (IsPaste)
|
||||
{
|
||||
var loc = GetBrushLocation();
|
||||
var width = Math.Abs((SelectionStart - SelectionEnd).X);
|
||||
var height = Math.Abs((SelectionStart - SelectionEnd).Y);
|
||||
|
||||
e.Graphics.DrawRectangle(PastePen,
|
||||
(loc.X * TileSet.TileSize * Zoom) + Offset.X,
|
||||
(loc.Y * TileSet.TileSize * Zoom) + Offset.Y,
|
||||
width * (TileSet.TileSize * Zoom),
|
||||
height * (TileSet.TileSize * Zoom));
|
||||
}
|
||||
|
||||
foreach (var ar in Map.Actors.Value)
|
||||
{
|
||||
if (ActorTemplates.ContainsKey(ar.Value.Type))
|
||||
@@ -395,13 +448,74 @@ namespace OpenRA.Editor
|
||||
DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
|
||||
}
|
||||
}
|
||||
|
||||
public void CopySelection()
|
||||
{
|
||||
// Grab tiles and resources within selection (doesn't do actors)
|
||||
var start = SelectionStart;
|
||||
var end = SelectionEnd;
|
||||
|
||||
if (start == end) return;
|
||||
|
||||
int width = Math.Abs((start - end).X);
|
||||
int height = Math.Abs((start - end).Y);
|
||||
|
||||
TileSelection = new TileReference<ushort, byte>[width, height];
|
||||
ResourceSelection = new TileReference<byte, byte>[width, height];
|
||||
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
//todo: crash prevention
|
||||
TileSelection[x, y] = Map.MapTiles.Value[start.X + x, start.Y + y];
|
||||
ResourceSelection[x, y] = Map.MapResources.Value[start.X + x, start.Y + y];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PasteSelection()
|
||||
{
|
||||
var loc = GetBrushLocation();
|
||||
var width = Math.Abs((SelectionStart - SelectionEnd).X);
|
||||
var height = Math.Abs((SelectionStart - SelectionEnd).Y);
|
||||
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
var mapX = loc.X + x;
|
||||
var mapY = loc.Y + y;
|
||||
|
||||
//todo: crash prevention for outside of bounds
|
||||
Map.MapTiles.Value[mapX, mapY] = TileSelection[x, y];
|
||||
Map.MapResources.Value[mapX, mapY] = ResourceSelection[x, y];
|
||||
|
||||
var ch = new int2(mapX / ChunkSize, mapY / ChunkSize);
|
||||
if (Chunks.ContainsKey(ch))
|
||||
{
|
||||
Chunks[ch].Dispose();
|
||||
Chunks.Remove(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
AfterChange();
|
||||
}
|
||||
|
||||
void ClearSelection()
|
||||
{
|
||||
SelectionStart = CPos.Zero;
|
||||
SelectionEnd = CPos.Zero;
|
||||
TileSelection = null;
|
||||
ResourceSelection = null;
|
||||
}
|
||||
}
|
||||
|
||||
static class ActorReferenceExts
|
||||
{
|
||||
public static int2 Location(this ActorReference ar)
|
||||
public static CPos Location(this ActorReference ar)
|
||||
{
|
||||
return ar.InitDict.Get<LocationInit>().value;
|
||||
return (CPos)ar.InitDict.Get<LocationInit>().value;
|
||||
}
|
||||
|
||||
public static void DrawStringContrast(this SGraphics g, Font f, string s, int x, int y, Brush fg, Brush bg)
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace OpenRA.FileFormats
|
||||
H = h; S = s; L = l; R = r;
|
||||
}
|
||||
|
||||
public static readonly ColorRamp Empty = new ColorRamp(0,0,0,0);
|
||||
|
||||
/* returns a color along the Lum ramp */
|
||||
public Color GetColor( float t )
|
||||
{
|
||||
@@ -35,7 +33,7 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
|
||||
// hk is hue in the range [0,1] instead of [0,360]
|
||||
public static Color ColorFromHSL(float hk, float s, float l)
|
||||
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);
|
||||
|
||||
@@ -172,9 +172,94 @@ namespace OpenRA
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Size NextPowerOf2(this Size s) { return new Size(NextPowerOf2(s.Width), NextPowerOf2(s.Height)); }
|
||||
|
||||
public static string JoinWith<T>(this IEnumerable<T> ts, string j)
|
||||
{
|
||||
return string.Join(j, ts.Select(t => t.ToString()).ToArray());
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Append<T>( this IEnumerable<T> ts, params T[] moreTs)
|
||||
{
|
||||
return ts.Concat(moreTs);
|
||||
}
|
||||
|
||||
public static Dictionary<TKey, TSource> ToDictionaryWithConflictLog<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, string debugName, Func<TKey, string> logKey, Func<TSource, string> logValue)
|
||||
{
|
||||
return ToDictionaryWithConflictLog(source, keySelector, x => x, debugName, logKey, logValue);
|
||||
}
|
||||
|
||||
public static Dictionary<TKey, TElement> ToDictionaryWithConflictLog<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, string debugName, Func<TKey, string> logKey, Func<TElement, string> logValue)
|
||||
{
|
||||
// Fall back on ToString() if null functions are provided:
|
||||
logKey = logKey ?? (s => s.ToString());
|
||||
logValue = logValue ?? (s => s.ToString());
|
||||
|
||||
// Try to build a dictionary and log all duplicates found (if any):
|
||||
var dupKeys = new Dictionary<TKey, List<string>>();
|
||||
var d = new Dictionary<TKey, TElement>();
|
||||
foreach (var item in source)
|
||||
{
|
||||
TKey key = keySelector(item);
|
||||
TElement element = elementSelector(item);
|
||||
|
||||
// Check for a key conflict:
|
||||
if (d.ContainsKey(key))
|
||||
{
|
||||
List<string> dupKeyMessages;
|
||||
if (!dupKeys.TryGetValue(key, out dupKeyMessages))
|
||||
{
|
||||
// Log the initial conflicting value already inserted:
|
||||
dupKeyMessages = new List<string>();
|
||||
dupKeyMessages.Add(logValue(d[key]));
|
||||
dupKeys.Add(key, dupKeyMessages);
|
||||
}
|
||||
|
||||
// Log this conflicting value:
|
||||
dupKeyMessages.Add(logValue(element));
|
||||
continue;
|
||||
}
|
||||
|
||||
d.Add(key, element);
|
||||
}
|
||||
|
||||
// If any duplicates were found, log it and throw a descriptive error
|
||||
if (dupKeys.Count > 0)
|
||||
{
|
||||
string badKeysFormatted = String.Join(", ", dupKeys.Select(p => "{0}: [{1}]".F(logKey(p.Key), String.Join(",", p.Value.ToArray()))).ToArray());
|
||||
string msg = "{0}, duplicate values found for the following keys: {1}".F(debugName, badKeysFormatted);
|
||||
Log.Write("debug", msg);
|
||||
throw new ArgumentException(msg);
|
||||
}
|
||||
|
||||
// Return the dictionary we built:
|
||||
return d;
|
||||
}
|
||||
|
||||
public static Color ColorLerp(float t, Color c1, Color c2)
|
||||
{
|
||||
return Color.FromArgb(
|
||||
(int)(t * c2.A + (1 - t) * c1.A),
|
||||
(int)(t * c2.R + (1 - t) * c1.R),
|
||||
(int)(t * c2.G + (1 - t) * c1.G),
|
||||
(int)(t * c2.B + (1 - t) * c1.B));
|
||||
}
|
||||
|
||||
public static T[] MakeArray<T>(int count, Func<int, T> f)
|
||||
{
|
||||
T[] result = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = f(i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Rectangle Bounds(this Bitmap b) { return new Rectangle(0, 0, b.Width, b.Height); }
|
||||
}
|
||||
|
||||
public static class Enum<T>
|
||||
{
|
||||
public static T Parse(string s) { return (T)Enum.Parse(typeof(T), s); }
|
||||
public static T[] GetValues() { return (T[])Enum.GetValues(typeof(T)); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace OpenRA.FileFormats
|
||||
ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value );
|
||||
return true;
|
||||
}
|
||||
else if ( n.Count > 1 )
|
||||
{
|
||||
throw new InvalidOperationException("The field {0} has multiple definitions:\n{1}"
|
||||
.F(fieldName, n.Select(m => "\t- " + m.Location).JoinWith("\n")));
|
||||
}
|
||||
throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) );
|
||||
}
|
||||
|
||||
@@ -320,6 +325,10 @@ namespace OpenRA.FileFormats
|
||||
((int)c.B).Clamp(0, 255));
|
||||
}
|
||||
|
||||
// Don't save floats in settings.yaml using country-specific decimal separators which can be misunderstood as group seperators.
|
||||
if (t == typeof(float))
|
||||
return ((float)v).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (t == typeof(Rectangle))
|
||||
{
|
||||
var r = (Rectangle)v;
|
||||
|
||||
@@ -19,24 +19,6 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
const string pubkeyStr = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V";
|
||||
|
||||
static sbyte[] char2num = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
class PublicKey
|
||||
{
|
||||
public uint[] key1 = new uint[64];
|
||||
@@ -128,25 +110,9 @@ namespace OpenRA.FileFormats
|
||||
|
||||
void init_pubkey()
|
||||
{
|
||||
int i = 0;
|
||||
uint i2, tmp;
|
||||
byte[] keytmp = new byte[256];
|
||||
|
||||
init_bignum(pubkey.key2, 0x10001, 64);
|
||||
|
||||
i2 = 0;
|
||||
while (i < pubkeyStr.Length)
|
||||
{
|
||||
tmp = (uint)char2num[pubkeyStr[i++]];
|
||||
tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]];
|
||||
tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]];
|
||||
tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]];
|
||||
keytmp[i2++] = (byte)((tmp >> 16) & 0xff);
|
||||
keytmp[i2++] = (byte)((tmp >> 8) & 0xff);
|
||||
keytmp[i2++] = (byte)(tmp & 0xff);
|
||||
}
|
||||
|
||||
key_to_bignum(pubkey.key1, keytmp, 64);
|
||||
key_to_bignum(pubkey.key1, Convert.FromBase64String(pubkeyStr), 64);
|
||||
pubkey.len = bitlen_bignum(pubkey.key1, 64) - 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.FileFormats
|
||||
static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count )
|
||||
{
|
||||
if( srcIndex > destIndex )
|
||||
throw new NotImplementedException( string.Format( "srcIndex > destIndex {0} {1}", srcIndex, destIndex ) );
|
||||
throw new NotImplementedException("srcIndex > destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
if( destIndex - srcIndex == 1 )
|
||||
{
|
||||
@@ -105,7 +105,7 @@ namespace OpenRA.FileFormats
|
||||
int count = ctx.ReadWord();
|
||||
int srcIndex = ctx.ReadWord();
|
||||
if( srcIndex >= destIndex )
|
||||
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
|
||||
throw new NotImplementedException("srcIndex >= destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] = dest[ srcIndex++ ];
|
||||
@@ -116,7 +116,7 @@ namespace OpenRA.FileFormats
|
||||
int count = count3 + 3;
|
||||
int srcIndex = ctx.ReadWord();
|
||||
if( srcIndex >= destIndex )
|
||||
throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) );
|
||||
throw new NotImplementedException("srcIndex >= destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] = dest[ srcIndex++ ];
|
||||
|
||||
@@ -123,25 +123,7 @@ namespace OpenRA.FileFormats
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Stream Open(string filename)
|
||||
{
|
||||
if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 )
|
||||
{
|
||||
var ret = GetFromCache( allFiles, filename );
|
||||
if( ret != null )
|
||||
return ret;
|
||||
}
|
||||
|
||||
var folder = mountedFolders
|
||||
.Where(x => x.Exists(filename))
|
||||
.OrderByDescending(x => x.Priority)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (folder != null)
|
||||
return folder.GetContent(filename);
|
||||
|
||||
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
|
||||
}
|
||||
public static Stream Open(string filename) { return OpenWithExts(filename, ""); }
|
||||
|
||||
public static Stream OpenWithExts( string filename, params string[] exts )
|
||||
{
|
||||
@@ -157,42 +139,39 @@ namespace OpenRA.FileFormats
|
||||
|
||||
foreach( var ext in exts )
|
||||
{
|
||||
foreach( IFolder folder in mountedFolders )
|
||||
if (folder.Exists(filename + ext))
|
||||
return folder.GetContent( filename + ext );
|
||||
var folder = mountedFolders
|
||||
.Where(x => x.Exists(filename + ext))
|
||||
.OrderByDescending(x => x.Priority)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (folder != null)
|
||||
return folder.GetContent(filename + ext);
|
||||
}
|
||||
|
||||
throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename );
|
||||
throw new FileNotFoundException("File not found: {0}".F(filename), filename);
|
||||
}
|
||||
|
||||
public static bool Exists(string filename)
|
||||
{
|
||||
foreach (var folder in mountedFolders)
|
||||
if (folder.Exists(filename))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
public static bool Exists(string filename) { return mountedFolders.Any(f => f.Exists(filename)); }
|
||||
|
||||
static Dictionary<string, Assembly> assemblyCache = new Dictionary<string, Assembly>();
|
||||
|
||||
public static Assembly ResolveAssembly(object sender, ResolveEventArgs e)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (assembly.FullName == e.Name)
|
||||
return assembly;
|
||||
}
|
||||
|
||||
string[] frags = e.Name.Split(',');
|
||||
var frags = e.Name.Split(',');
|
||||
var filename = frags[0] + ".dll";
|
||||
|
||||
Assembly a;
|
||||
if (assemblyCache.TryGetValue(filename, out a))
|
||||
return a;
|
||||
|
||||
if (FileSystem.Exists(filename))
|
||||
using (Stream s = FileSystem.Open(filename))
|
||||
using (var s = FileSystem.Open(filename))
|
||||
{
|
||||
byte[] buf = new byte[s.Length];
|
||||
var buf = new byte[s.Length];
|
||||
s.Read(buf, 0, buf.Length);
|
||||
a = Assembly.Load(buf);
|
||||
assemblyCache.Add(filename, a);
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace OpenRA.FileFormats
|
||||
isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted);
|
||||
if( isEncrypted )
|
||||
{
|
||||
index = ParseRaHeader( s, out dataStart ).ToDictionary(x => x.Hash);
|
||||
index = ParseRaHeader(s, out dataStart).ToDictionaryWithConflictLog(x => x.Hash,
|
||||
"MixFile.RaHeader", null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +68,9 @@ namespace OpenRA.FileFormats
|
||||
s.Seek( 0, SeekOrigin.Begin );
|
||||
|
||||
isEncrypted = false;
|
||||
index = ParseTdHeader(s, out dataStart).ToDictionary(x => x.Hash);
|
||||
index = ParseTdHeader(s, out dataStart).ToDictionaryWithConflictLog(x => x.Hash,
|
||||
"MixFile.TdHeader", null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)
|
||||
);
|
||||
}
|
||||
|
||||
const long headerStart = 84;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace OpenRA.FileFormats.Graphics
|
||||
|
||||
case "IEND":
|
||||
{
|
||||
var bits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var bits = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
using (var ns = new MemoryStream(data.ToArray()))
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
@@ -30,9 +30,9 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public ImageHeader( BinaryReader reader )
|
||||
{
|
||||
Offset = reader.ReadUInt32();
|
||||
Format = (Format)( Offset >> 24 );
|
||||
Offset &= 0xFFFFFF;
|
||||
var data = reader.ReadUInt32();
|
||||
Offset = data & 0xffffff;
|
||||
Format = (Format)(data >> 24);
|
||||
|
||||
RefOffset = reader.ReadUInt16();
|
||||
RefFormat = (Format)reader.ReadUInt16();
|
||||
@@ -48,14 +48,9 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
public enum Format
|
||||
{
|
||||
Format20 = 0x20,
|
||||
Format40 = 0x40,
|
||||
Format80 = 0x80,
|
||||
}
|
||||
public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
||||
|
||||
public class ShpReader : IEnumerable<ImageHeader>
|
||||
public class ShpReader
|
||||
{
|
||||
public readonly int ImageCount;
|
||||
public readonly ushort Width;
|
||||
@@ -69,40 +64,37 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public ShpReader( Stream stream )
|
||||
{
|
||||
BinaryReader reader = new BinaryReader( stream );
|
||||
|
||||
ImageCount = reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
|
||||
for( int i = 0 ; i < ImageCount ; i++ )
|
||||
headers.Add( new ImageHeader( reader ) );
|
||||
|
||||
new ImageHeader( reader ); // end-of-file header
|
||||
new ImageHeader( reader ); // all-zeroes header
|
||||
|
||||
Dictionary<uint, ImageHeader> offsets = new Dictionary<uint, ImageHeader>();
|
||||
foreach( ImageHeader h in headers )
|
||||
offsets.Add( h.Offset, h );
|
||||
|
||||
for( int i = 0 ; i < ImageCount ; i++ )
|
||||
using( var reader = new BinaryReader( stream ) )
|
||||
{
|
||||
ImageHeader h = headers[ i ];
|
||||
if( h.Format == Format.Format20 )
|
||||
h.RefImage = headers[ i - 1 ];
|
||||
ImageCount = reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
|
||||
else if( h.Format == Format.Format40 )
|
||||
for( int i = 0 ; i < ImageCount ; i++ )
|
||||
headers.Add( new ImageHeader( reader ) );
|
||||
|
||||
new ImageHeader( reader ); // end-of-file header
|
||||
new ImageHeader( reader ); // all-zeroes header
|
||||
|
||||
var offsets = headers.ToDictionary(h => h.Offset, h =>h);
|
||||
|
||||
for( int i = 0 ; i < ImageCount ; i++ )
|
||||
{
|
||||
if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) )
|
||||
throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) );
|
||||
}
|
||||
}
|
||||
var h = headers[ i ];
|
||||
if( h.Format == Format.Format20 )
|
||||
h.RefImage = headers[ i - 1 ];
|
||||
|
||||
foreach( ImageHeader h in headers )
|
||||
Decompress( stream, h );
|
||||
else if( h.Format == Format.Format40 )
|
||||
if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) )
|
||||
throw new InvalidDataException( "Reference doesnt point to image data {0}->{1}".F(h.Offset, h.RefOffset) );
|
||||
}
|
||||
|
||||
foreach( ImageHeader h in headers )
|
||||
Decompress( stream, h );
|
||||
}
|
||||
}
|
||||
|
||||
public ImageHeader this[ int index ]
|
||||
@@ -133,7 +125,7 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
case Format.Format80:
|
||||
{
|
||||
byte[] imageBytes = new byte[ Width * Height ];
|
||||
var imageBytes = new byte[ Width * Height ];
|
||||
Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes );
|
||||
h.Image = imageBytes;
|
||||
break;
|
||||
@@ -147,33 +139,24 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
stream.Position = h.Offset;
|
||||
// Actually, far too big. There's no length field with the correct length though :(
|
||||
int compressedLength = (int)( stream.Length - stream.Position );
|
||||
var compressedLength = (int)( stream.Length - stream.Position );
|
||||
|
||||
byte[] compressedBytes = new byte[ compressedLength ];
|
||||
var compressedBytes = new byte[ compressedLength ];
|
||||
stream.Read( compressedBytes, 0, compressedLength );
|
||||
|
||||
//MemoryStream ms = new MemoryStream( compressedBytes );
|
||||
return compressedBytes;
|
||||
}
|
||||
|
||||
byte[] CopyImageData( byte[] baseImage )
|
||||
{
|
||||
byte[] imageData = new byte[ Width * Height ];
|
||||
var imageData = new byte[ Width * Height ];
|
||||
for( int i = 0 ; i < Width * Height ; i++ )
|
||||
imageData[ i ] = baseImage[ i ];
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
public IEnumerator<ImageHeader> GetEnumerator()
|
||||
{
|
||||
return headers.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
public IEnumerable<ImageHeader> Frames { get { return headers; } }
|
||||
|
||||
public static ShpReader Load(string filename)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.FileFormats
|
||||
public readonly string[]
|
||||
Mods, Folders, Packages, Rules, ServerTraits,
|
||||
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Weapons, Voices, Music, Movies, TileSets, ChromeMetrics;
|
||||
Weapons, Voices, Notifications, Music, Movies, TileSets, ChromeMetrics;
|
||||
public readonly MiniYaml LoadScreen;
|
||||
public readonly Dictionary<string, Pair<string,int>> Fonts;
|
||||
public readonly int TileSize = 24;
|
||||
@@ -44,14 +44,17 @@ namespace OpenRA.FileFormats
|
||||
ChromeLayout = YamlList(yaml, "ChromeLayout");
|
||||
Weapons = YamlList(yaml, "Weapons");
|
||||
Voices = YamlList(yaml, "Voices");
|
||||
Notifications = YamlList(yaml, "Notifications");
|
||||
Music = YamlList(yaml, "Music");
|
||||
Movies = YamlList(yaml, "Movies");
|
||||
TileSets = YamlList(yaml, "TileSets");
|
||||
ChromeMetrics = YamlList(yaml, "ChromeMetrics");
|
||||
|
||||
LoadScreen = yaml["LoadScreen"];
|
||||
Fonts = yaml["Fonts"].NodesDict.ToDictionary(x => x.Key, x => Pair.New(x.Value.NodesDict["Font"].Value,
|
||||
int.Parse(x.Value.NodesDict["Size"].Value)));
|
||||
Fonts = yaml["Fonts"].NodesDict.ToDictionary(x => x.Key,
|
||||
x => Pair.New(x.Value.NodesDict["Font"].Value,
|
||||
int.Parse(x.Value.NodesDict["Size"].Value)));
|
||||
|
||||
if (yaml.ContainsKey("TileSize"))
|
||||
TileSize = int.Parse(yaml["TileSize"].Value);
|
||||
}
|
||||
@@ -59,7 +62,7 @@ namespace OpenRA.FileFormats
|
||||
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key)
|
||||
{
|
||||
if (!yaml.ContainsKey(key))
|
||||
return new string[ 0 ];
|
||||
return new string[] {};
|
||||
|
||||
return yaml[key].NodesDict.Keys.ToArray();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace OpenRA.FileFormats
|
||||
public string Bot = null;
|
||||
public bool DefaultStartingUnits = false;
|
||||
public bool AllowBots = true;
|
||||
public bool Required = false;
|
||||
|
||||
public bool LockRace = false;
|
||||
public string Race;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace OpenRA.FileFormats
|
||||
public readonly string Type;
|
||||
public readonly int2 Location;
|
||||
public readonly int Depth;
|
||||
|
||||
public SmudgeReference( string type, int2 location, int depth )
|
||||
{
|
||||
Type = type;
|
||||
@@ -22,10 +23,9 @@ namespace OpenRA.FileFormats
|
||||
Depth = depth;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} {1},{2} {3}", Type, Location.X,Location.Y, Depth);
|
||||
return "{0} {1},{2} {3}".F(Type, Location.X, Location.Y, Depth);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@ namespace OpenRA.FileFormats
|
||||
public class TerrainTypeInfo
|
||||
{
|
||||
public string Type;
|
||||
public bool AcceptSmudge = true;
|
||||
public string[] AcceptsSmudgeType = { };
|
||||
public bool IsWater = false;
|
||||
public Color Color;
|
||||
public string CustomCursor;
|
||||
|
||||
public TerrainTypeInfo() {}
|
||||
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); }
|
||||
@@ -36,6 +37,7 @@ namespace OpenRA.FileFormats
|
||||
public string Image;
|
||||
public int2 Size;
|
||||
public bool PickAny;
|
||||
public string Category;
|
||||
|
||||
[FieldLoader.LoadUsing( "LoadTiles" )]
|
||||
public Dictionary<byte, string> Tiles = new Dictionary<byte, string>();
|
||||
@@ -76,10 +78,13 @@ namespace OpenRA.FileFormats
|
||||
public string Name;
|
||||
public string Id;
|
||||
public string Palette;
|
||||
public string PlayerPalette;
|
||||
public int TileSize = 24;
|
||||
public string[] Extensions;
|
||||
public int WaterPaletteRotationBase = 0x60;
|
||||
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
|
||||
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
|
||||
public string[] EditorTemplateOrder;
|
||||
|
||||
static readonly string[] fields = {"Name", "TileSize", "Id", "Palette", "Extensions"};
|
||||
|
||||
@@ -166,7 +171,7 @@ namespace OpenRA.FileFormats
|
||||
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
|
||||
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
|
||||
@@ -105,22 +105,26 @@ namespace OpenRA.FileFormats
|
||||
levels.Add(new List<MiniYamlNode>());
|
||||
|
||||
var lineNo = 0;
|
||||
foreach (var line in lines)
|
||||
foreach (var ll in lines)
|
||||
{
|
||||
var line = ll;
|
||||
++lineNo;
|
||||
if (line.Contains('#'))
|
||||
line = line.Substring(0, line.IndexOf('#')).TrimEnd(' ', '\t');
|
||||
var t = line.TrimStart(' ', '\t');
|
||||
if (t.Length == 0 || t[0] == '#')
|
||||
if (t.Length == 0)
|
||||
continue;
|
||||
var level = line.Length - t.Length;
|
||||
var location = new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo };
|
||||
|
||||
if (levels.Count <= level)
|
||||
throw new YamlException("Bad indent in miniyaml");
|
||||
throw new YamlException("Bad indent in miniyaml at {0}".F (location));
|
||||
while (levels.Count > level + 1)
|
||||
levels.RemoveAt(levels.Count - 1);
|
||||
|
||||
var d = new List<MiniYamlNode>();
|
||||
var rhs = SplitAtColon( ref t );
|
||||
levels[ level ].Add( new MiniYamlNode( t, rhs, d, new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo } ) );
|
||||
levels[ level ].Add( new MiniYamlNode( t, rhs, d, location ) );
|
||||
|
||||
levels.Add(d);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -12,10 +12,25 @@
|
||||
<AssemblyName>OpenRA.FileFormats</AssemblyName>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>2.0</OldToolsVersion>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -27,6 +42,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@@ -37,6 +53,7 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -116,6 +133,23 @@
|
||||
<Compile Include="Thirdparty\Random.cs" />
|
||||
<Compile Include="TypeDictionary.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
@@ -124,4 +158,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -46,9 +46,9 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
string filename;
|
||||
if (Names.TryGetValue(Hash, out filename))
|
||||
return string.Format("{0} - offset 0x{1:x8} - length 0x{2:x8}", filename, Offset, Length);
|
||||
return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(filename, Offset, Length);
|
||||
else
|
||||
return string.Format("0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}", Hash, Offset, Length);
|
||||
return "0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}".F(Hash, Offset, Length);
|
||||
}
|
||||
|
||||
public static uint HashFilename(string name)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.FileFormats
|
||||
get { return colors; }
|
||||
}
|
||||
|
||||
public Palette(Stream s, bool remapTransparent)
|
||||
public Palette(Stream s, int[] remapShadow)
|
||||
{
|
||||
colors = new uint[256];
|
||||
|
||||
@@ -54,13 +54,9 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
colors[0] = 0;
|
||||
if (remapTransparent)
|
||||
{
|
||||
colors[1] = 178u << 24; // Hack for d2k; may have side effects
|
||||
colors[3] = 178u << 24;
|
||||
colors[4] = 140u << 24;
|
||||
}
|
||||
colors[0] = 0; //convert black background to transparency
|
||||
foreach (int i in remapShadow)
|
||||
colors[i] = 140u << 24;
|
||||
}
|
||||
|
||||
public Palette(Palette p, IPaletteRemap r)
|
||||
@@ -92,12 +88,12 @@ namespace OpenRA.FileFormats
|
||||
return pal;
|
||||
}
|
||||
|
||||
public static Palette Load( string filename, bool remap )
|
||||
public static Palette Load(string filename, int[] remap)
|
||||
{
|
||||
using(var s = File.OpenRead(filename))
|
||||
return new Palette(s, remap);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
|
||||
public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
|
||||
}
|
||||
|
||||
@@ -14,33 +14,33 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
// TODO: ship this out of here.
|
||||
public enum PaletteFormat { ra, cnc, d2k }
|
||||
|
||||
public class PlayerColorRemap : IPaletteRemap
|
||||
{
|
||||
Dictionary<int, Color> remapColors;
|
||||
|
||||
public PlayerColorRemap(PaletteFormat fmt, ColorRamp c)
|
||||
public static int GetRemapIndex(int[] Ramp, int i)
|
||||
{
|
||||
var c1 = c.GetColor(0);
|
||||
var c2 = c.GetColor(1); /* temptemp: this can be expressed better */
|
||||
|
||||
var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80;
|
||||
var ramp = (fmt == PaletteFormat.cnc)
|
||||
? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 }
|
||||
: new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
remapColors = ramp.Select((x, i) => Pair.New(baseIndex + i, ColorLerp(x / 16f, c1, c2)))
|
||||
.ToDictionary(u => u.First, u => u.Second);
|
||||
return Ramp[i];
|
||||
}
|
||||
|
||||
public static Color ColorLerp(float t, Color c1, Color c2)
|
||||
public PlayerColorRemap(int[] Ramp, ColorRamp c)
|
||||
{
|
||||
return Color.FromArgb(255,
|
||||
(int)(t * c2.R + (1 - t) * c1.R),
|
||||
(int)(t * c2.G + (1 - t) * c1.G),
|
||||
(int)(t * c2.B + (1 - t) * c1.B));
|
||||
var c1 = c.GetColor(0);
|
||||
var c2 = c.GetColor(1); // temptemp: this can be expressed better
|
||||
|
||||
var baseIndex = Ramp[0];
|
||||
var RemapRamp = Ramp.Select(r => r - Ramp[0]).ToArray();
|
||||
|
||||
if (Ramp[0] > Ramp[15]) // reversed remapping
|
||||
{
|
||||
baseIndex = Ramp[15];
|
||||
for (int i=15; i>0; i--)
|
||||
RemapRamp = Ramp.Select(r => r - Ramp[15]).ToArray();
|
||||
}
|
||||
|
||||
remapColors = RemapRamp.Select((x, i) => Pair.New(baseIndex + i, Exts.ColorLerp(x / 16f, c1, c2)))
|
||||
.ToDictionary(u => u.First, u => u.Second);
|
||||
}
|
||||
|
||||
public Color GetRemappedColor(Color original, int index)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public int CompareTo(DelayedAction other)
|
||||
{
|
||||
return Math.Sign(Time - other.Time);
|
||||
return Time.CompareTo(other.Time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Collections
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class Set<T> : IEnumerable<T>
|
||||
{
|
||||
@@ -44,5 +44,13 @@ namespace OpenRA.Collections
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Contains( T obj ) { return data.ContainsKey(obj); }
|
||||
|
||||
public Set( params T[] ts )
|
||||
{
|
||||
foreach( var t in ts )
|
||||
Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace OpenRA
|
||||
public static float Dot(float2 a, float2 b) { return a.X * b.X + a.Y * b.Y; }
|
||||
public float2 Round() { return new float2((float)Math.Round(X), (float)Math.Round(Y)); }
|
||||
|
||||
public override string ToString() { return string.Format("({0},{1})", X, Y); }
|
||||
public override string ToString() { return "({0},{1})".F(X, Y); }
|
||||
public int2 ToInt2() { return new int2((int)X, (int)Y); }
|
||||
|
||||
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
@@ -101,4 +101,18 @@ namespace OpenRA
|
||||
public float LengthSquared { get { return X * X + Y * Y; } }
|
||||
public float Length { get { return (float)Math.Sqrt(LengthSquared); } }
|
||||
}
|
||||
|
||||
public class EWMA
|
||||
{
|
||||
readonly float animRate;
|
||||
float? value;
|
||||
|
||||
public EWMA(float animRate) { this.animRate = animRate; }
|
||||
|
||||
public float Update(float newValue)
|
||||
{
|
||||
value = float2.Lerp(value ?? newValue, newValue, animRate);
|
||||
return value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA
|
||||
public PointF ToPointF() { return new PointF(X, Y); }
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
|
||||
public override string ToString() { return string.Format("{0},{1}", X, Y); }
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
|
||||
// Change endianness of a uint32
|
||||
public static uint Swap(uint orig)
|
||||
|
||||
@@ -48,17 +48,17 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public bool Contains<T>()
|
||||
{
|
||||
return dataSingular.ContainsKey( typeof( T ) ) || dataMultiple.ContainsKey( typeof( T ) );
|
||||
return dataSingular.ContainsKey(typeof(T)) || dataMultiple.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
public T Get<T>()
|
||||
{
|
||||
if( dataMultiple.ContainsKey( typeof( T ) ) )
|
||||
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
|
||||
if (dataMultiple.ContainsKey(typeof(T)))
|
||||
throw new InvalidOperationException("TypeDictionary contains multiple instance of type `{0}`".F(typeof(T)));
|
||||
|
||||
object ret;
|
||||
if( !dataSingular.TryGetValue( typeof( T ), out ret ) )
|
||||
throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T)));
|
||||
if (!dataSingular.TryGetValue(typeof(T), out ret))
|
||||
throw new InvalidOperationException("TypeDictionary does not contain instance of type `{0}`".F(typeof(T)));
|
||||
return (T)ret;
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public object GetOrDefault(Type t)
|
||||
{
|
||||
if( dataMultiple.ContainsKey(t) )
|
||||
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", t ) );
|
||||
if (dataMultiple.ContainsKey(t))
|
||||
throw new InvalidOperationException("TypeDictionary contains multiple instances of type `{0}`".F(t));
|
||||
|
||||
object ret;
|
||||
if( !dataSingular.TryGetValue(t, out ret ) )
|
||||
if (!dataSingular.TryGetValue(t, out ret))
|
||||
return null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace OpenRA
|
||||
|
||||
public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } }
|
||||
|
||||
public int2 Location { get { return occupySpace.Value.TopLeft; } }
|
||||
public CPos Location { get { return occupySpace.Value.TopLeft; } }
|
||||
|
||||
public int2 CenterLocation
|
||||
public PPos CenterLocation
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -43,6 +43,8 @@ namespace OpenRA
|
||||
return HasLocation.PxPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public Shroud.ActorVisibility Sight;
|
||||
|
||||
[Sync]
|
||||
public Player Owner;
|
||||
@@ -85,6 +87,16 @@ namespace OpenRA
|
||||
return (firstSprite.Sprite.size * firstSprite.Scale).ToInt2();
|
||||
});
|
||||
|
||||
if(this.HasTrait<RevealsShroud>())
|
||||
{
|
||||
Sight = new Shroud.ActorVisibility
|
||||
{
|
||||
range = this.Trait<RevealsShroud>().RevealRange,
|
||||
vis = Shroud.GetVisOrigins(this).ToArray()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
ApplyIRender = x => x.Render(this);
|
||||
ApplyRenderModifier = (m, p) => p.ModifyRender(this, m);
|
||||
|
||||
@@ -99,6 +111,11 @@ namespace OpenRA
|
||||
|
||||
currentActivity = Util.RunActivity( this, currentActivity );
|
||||
}
|
||||
|
||||
public void UpdateSight()
|
||||
{
|
||||
Sight.vis = Shroud.GetVisOrigins(this).ToArray();
|
||||
}
|
||||
|
||||
public bool IsIdle
|
||||
{
|
||||
@@ -123,22 +140,30 @@ namespace OpenRA
|
||||
// at its current altitude
|
||||
Rectangle CalculateBounds(bool useAltitude)
|
||||
{
|
||||
var size = Size.Value;
|
||||
var size = (PVecInt)(Size.Value);
|
||||
var loc = CenterLocation - size / 2;
|
||||
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
|
||||
{
|
||||
#if true
|
||||
loc += new PVecInt(si.Bounds[2], si.Bounds[3]);
|
||||
#else
|
||||
loc.X += si.Bounds[2];
|
||||
loc.Y += si.Bounds[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
var move = Move.Value;
|
||||
if (move != null)
|
||||
{
|
||||
#if true
|
||||
loc -= new PVecInt(0, move.Altitude);
|
||||
#else
|
||||
loc.Y -= move.Altitude;
|
||||
#endif
|
||||
if (useAltitude)
|
||||
size = new int2(size.X, size.Y + move.Altitude);
|
||||
size = new PVecInt(size.X, size.Y + move.Altitude);
|
||||
}
|
||||
|
||||
return new Rectangle(loc.X, loc.Y, size.X, size.Y);
|
||||
|
||||
@@ -62,20 +62,28 @@ namespace OpenRA
|
||||
public int Value( World world ) { return value; }
|
||||
}
|
||||
|
||||
public class LocationInit : IActorInit<int2>
|
||||
public class LocationInit : IActorInit<CPos>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int2 value = int2.Zero;
|
||||
public LocationInit() { }
|
||||
public LocationInit( int2 init ) { value = init; }
|
||||
public int2 Value( World world ) { return value; }
|
||||
public LocationInit( CPos init ) { value = init.ToInt2(); }
|
||||
public CPos Value(World world) { return (CPos)value; }
|
||||
}
|
||||
|
||||
public class CenterLocationInit : IActorInit<int2>
|
||||
public class SubCellInit : IActorInit<SubCell>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int value = 0;
|
||||
public SubCellInit() { }
|
||||
public SubCellInit(int init) { value = init; }
|
||||
public SubCell Value(World world) { return (SubCell)value; }
|
||||
}
|
||||
|
||||
public class CenterLocationInit : IActorInit<PPos>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int2 value = int2.Zero;
|
||||
public CenterLocationInit() { }
|
||||
public CenterLocationInit( int2 init ) { value = init; }
|
||||
public int2 Value( World world ) { return value; }
|
||||
public CenterLocationInit(PPos init) { value = init.ToInt2(); }
|
||||
public PPos Value(World world) { return (PPos)value; }
|
||||
}
|
||||
|
||||
public class OwnerInit : IActorInit<Player>
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace OpenRA
|
||||
world.ActorRemoved += a => Remove( a, a.OccupiesSpace );
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> GetUnitsAt( int2 a )
|
||||
public IEnumerable<Actor> GetUnitsAt(CPos a)
|
||||
{
|
||||
if (!map.IsInMap(a)) yield break;
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace OpenRA
|
||||
yield return i.actor;
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> GetUnitsAt( int2 a, SubCell sub )
|
||||
public IEnumerable<Actor> GetUnitsAt(CPos a, SubCell sub)
|
||||
{
|
||||
if (!map.IsInMap(a)) yield break;
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA
|
||||
yield return i.actor;
|
||||
}
|
||||
|
||||
public bool HasFreeSubCell(int2 a)
|
||||
public bool HasFreeSubCell(CPos a)
|
||||
{
|
||||
if (!AnyUnitsAt(a))
|
||||
return true;
|
||||
@@ -64,12 +64,12 @@ namespace OpenRA
|
||||
SubCell.BottomLeft, SubCell.BottomRight }.Any(b => !AnyUnitsAt(a,b));
|
||||
}
|
||||
|
||||
public bool AnyUnitsAt(int2 a)
|
||||
public bool AnyUnitsAt(CPos a)
|
||||
{
|
||||
return influence[ a.X, a.Y ] != null;
|
||||
}
|
||||
|
||||
public bool AnyUnitsAt(int2 a, SubCell sub)
|
||||
public bool AnyUnitsAt(CPos a, SubCell sub)
|
||||
{
|
||||
for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next )
|
||||
if (i.subCell == sub || i.subCell == SubCell.FullCell)
|
||||
|
||||
71
OpenRA.Game/CPos.cs
Normal file
71
OpenRA.Game/CPos.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Cell coordinate position in the world (coarse).
|
||||
/// </summary>
|
||||
public struct CPos
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public CPos(int x, int y) { X = x; Y = y; }
|
||||
|
||||
public static readonly CPos Zero = new CPos(0, 0);
|
||||
|
||||
public static explicit operator CPos(int2 a) { return new CPos(a.X, a.Y); }
|
||||
|
||||
public static CPos operator +(CVec a, CPos b) { return new CPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static CPos operator +(CPos a, CVec b) { return new CPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static CPos operator -(CPos a, CVec b) { return new CPos(a.X - b.X, a.Y - b.Y); }
|
||||
|
||||
public static CVec operator -(CPos a, CPos b) { return new CVec(a.X - b.X, a.Y - b.Y); }
|
||||
|
||||
public static bool operator ==(CPos me, CPos other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(CPos me, CPos other) { return !(me == other); }
|
||||
|
||||
public static CPos Max(CPos a, CPos b) { return new CPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static CPos Min(CPos a, CPos b) { return new CPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
public PPos ToPPos() { return new PPos(Game.CellSize * X, Game.CellSize * Y); }
|
||||
|
||||
public CPos Clamp(Rectangle r)
|
||||
{
|
||||
return new CPos(Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
CPos o = (CPos)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
|
||||
}
|
||||
|
||||
public static class RectangleExtensions
|
||||
{
|
||||
public static CPos TopLeftAsCPos(this Rectangle r) { return new CPos(r.Left, r.Top); }
|
||||
public static CPos BottomRightAsCPos(this Rectangle r) { return new CPos(r.Right, r.Bottom); }
|
||||
}
|
||||
}
|
||||
76
OpenRA.Game/CVec.cs
Normal file
76
OpenRA.Game/CVec.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Cell coordinate vector (coarse).
|
||||
/// </summary>
|
||||
public struct CVec
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public CVec(int x, int y) { X = x; Y = y; }
|
||||
public CVec(Size p) { X = p.Width; Y = p.Height; }
|
||||
|
||||
public static readonly CVec Zero = new CVec(0, 0);
|
||||
|
||||
public static explicit operator CVec(int2 a) { return new CVec(a.X, a.Y); }
|
||||
public static explicit operator CVec(float2 a) { return new CVec((int)a.X, (int)a.Y); }
|
||||
|
||||
public static CVec operator +(CVec a, CVec b) { return new CVec(a.X + b.X, a.Y + b.Y); }
|
||||
public static CVec operator -(CVec a, CVec b) { return new CVec(a.X - b.X, a.Y - b.Y); }
|
||||
public static CVec operator *(int a, CVec b) { return new CVec(a * b.X, a * b.Y); }
|
||||
public static CVec operator *(CVec b, int a) { return new CVec(a * b.X, a * b.Y); }
|
||||
public static CVec operator /(CVec a, int b) { return new CVec(a.X / b, a.Y / b); }
|
||||
|
||||
public static CVec operator -(CVec a) { return new CVec(-a.X, -a.Y); }
|
||||
|
||||
public static bool operator ==(CVec me, CVec other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(CVec me, CVec other) { return !(me == other); }
|
||||
|
||||
public static CVec Max(CVec a, CVec b) { return new CVec(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static CVec Min(CVec a, CVec b) { return new CVec(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static int Dot(CVec a, CVec b) { return a.X * b.X + a.Y * b.Y; }
|
||||
|
||||
public CVec Sign() { return new CVec(Math.Sign(X), Math.Sign(Y)); }
|
||||
public CVec Abs() { return new CVec(Math.Abs(X), Math.Abs(Y)); }
|
||||
public int LengthSquared { get { return X * X + Y * Y; } }
|
||||
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
|
||||
public CVec Clamp(Rectangle r)
|
||||
{
|
||||
return new CVec(
|
||||
Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top))
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
CVec o = (CVec)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ namespace OpenRA
|
||||
{
|
||||
public static int CellSize { get { return modData.Manifest.TileSize; } }
|
||||
|
||||
public static MouseButtonPreference mouseButtonPreference = new MouseButtonPreference();
|
||||
|
||||
public static ModData modData;
|
||||
static WorldRenderer worldRenderer;
|
||||
|
||||
@@ -50,13 +52,8 @@ namespace OpenRA
|
||||
|
||||
public static void JoinServer(string host, int port)
|
||||
{
|
||||
var replayFilename = ChooseReplayFilename();
|
||||
string path = Path.Combine( Platform.SupportDir, "Replays" );
|
||||
if( !Directory.Exists( path ) ) Directory.CreateDirectory( path );
|
||||
var replayFile = File.Create( Path.Combine( path, replayFilename ) );
|
||||
|
||||
JoinInner(new OrderManager(host, port,
|
||||
new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile)));
|
||||
new ReplayRecorderConnection(new NetworkConnection(host, port), ChooseReplayFilename)));
|
||||
}
|
||||
|
||||
static string ChooseReplayFilename()
|
||||
@@ -95,14 +92,14 @@ namespace OpenRA
|
||||
// Hacky workaround for orderManager visibility
|
||||
public static Widget OpenWindow(World world, string widget)
|
||||
{
|
||||
return Widget.OpenWindow(widget, new WidgetArgs() {{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }});
|
||||
return Ui.OpenWindow(widget, new WidgetArgs() {{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }});
|
||||
}
|
||||
|
||||
// Who came up with the great idea of making these things
|
||||
// impossible for the things that want them to access them directly?
|
||||
public static Widget OpenWindow(string widget, WidgetArgs args)
|
||||
{
|
||||
return Widget.OpenWindow(widget, new WidgetArgs(args)
|
||||
return Ui.OpenWindow(widget, new WidgetArgs(args)
|
||||
{
|
||||
{ "world", worldRenderer.world },
|
||||
{ "orderManager", orderManager },
|
||||
@@ -160,7 +157,7 @@ namespace OpenRA
|
||||
using( new PerfSample( "tick_time" ) )
|
||||
{
|
||||
orderManager.LastTickTime += Settings.Game.Timestep;
|
||||
Widget.DoTick();
|
||||
Ui.Tick();
|
||||
var world = orderManager.world;
|
||||
if (orderManager.GameStarted)
|
||||
++Viewport.TicksSinceLastMove;
|
||||
@@ -171,7 +168,7 @@ namespace OpenRA
|
||||
{
|
||||
var isNetTick = LocalTick % NetTickScale == 0;
|
||||
|
||||
if (!isNetTick || orderManager.IsReadyForNextFrame)
|
||||
if ((!isNetTick || orderManager.IsReadyForNextFrame) && !orderManager.GamePaused )
|
||||
{
|
||||
++orderManager.LocalFrameNumber;
|
||||
|
||||
@@ -193,6 +190,8 @@ namespace OpenRA
|
||||
else
|
||||
if (orderManager.NetFrameNumber == 0)
|
||||
orderManager.LastTickTime = Environment.TickCount;
|
||||
|
||||
viewport.Tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +214,7 @@ namespace OpenRA
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
|
||||
if (orderManager.GameStarted) return;
|
||||
Widget.SelectedWidget = null;
|
||||
Ui.SelectedWidget = null;
|
||||
|
||||
orderManager.LocalFrameNumber = 0;
|
||||
orderManager.LastTickTime = Environment.TickCount;
|
||||
@@ -225,7 +224,12 @@ namespace OpenRA
|
||||
|
||||
public static bool IsHost
|
||||
{
|
||||
get { return orderManager.Connection.LocalClientId == 0; }
|
||||
get
|
||||
{
|
||||
var client= orderManager.LobbyInfo.ClientWithIndex (
|
||||
orderManager.Connection.LocalClientId);
|
||||
return ((client!=null) && client.IsAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String, Mod> CurrentMods
|
||||
@@ -244,7 +248,6 @@ namespace OpenRA
|
||||
AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
|
||||
|
||||
Settings = new Settings(Platform.SupportDir + "settings.yaml", args);
|
||||
Settings.Save();
|
||||
|
||||
Log.LogPath = Platform.SupportDir + "Logs" + Path.DirectorySeparatorChar;
|
||||
Log.AddChannel("perf", "perf.log");
|
||||
@@ -259,7 +262,7 @@ namespace OpenRA
|
||||
foreach(var mod in Mod.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
|
||||
Sound.Create();
|
||||
Sound.Create(Settings.Sound.Engine);
|
||||
InitializeWithMods(Settings.Game.Mods);
|
||||
}
|
||||
|
||||
@@ -270,7 +273,7 @@ namespace OpenRA
|
||||
AddChatLine = (a,b,c) => {};
|
||||
ConnectionStateChanged = om => {};
|
||||
BeforeGameStart = () => {};
|
||||
Widget.ResetAll();
|
||||
Ui.ResetAll();
|
||||
|
||||
worldRenderer = null;
|
||||
if (server != null)
|
||||
@@ -278,11 +281,11 @@ namespace OpenRA
|
||||
if (orderManager != null)
|
||||
orderManager.Dispose();
|
||||
|
||||
// Discard any invalid mods
|
||||
// Discard any invalid mods, set RA as default
|
||||
var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray();
|
||||
if (mm.Length == 0) mm = new[] { "ra" };
|
||||
Console.WriteLine("Loading mods: {0}", mm.JoinWith(","));
|
||||
Settings.Game.Mods = mm;
|
||||
Settings.Save();
|
||||
|
||||
Sound.StopMusic();
|
||||
Sound.StopVideo();
|
||||
@@ -301,7 +304,40 @@ namespace OpenRA
|
||||
JoinLocal();
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer);
|
||||
|
||||
modData.LoadScreen.StartGame();
|
||||
if (Game.Settings.Server.Dedicated)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Game.Settings.Server.Map = WidgetUtils.ChooseInitialMap(Game.Settings.Server.Map);
|
||||
Game.Settings.Save();
|
||||
Game.CreateServer(new ServerSettings(Game.Settings.Server));
|
||||
while(true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
|
||||
if((server.State == Server.ServerState.GameStarted)
|
||||
&& (server.conns.Count<=1))
|
||||
{
|
||||
Console.WriteLine("No one is playing, shutting down...");
|
||||
server.Shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Game.Settings.Server.DedicatedLoop)
|
||||
{
|
||||
Console.WriteLine("Starting a new server instance...");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
System.Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
modData.LoadScreen.StartGame();
|
||||
Settings.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadShellMap()
|
||||
@@ -326,8 +362,20 @@ namespace OpenRA
|
||||
internal static void Run()
|
||||
{
|
||||
while (!quit)
|
||||
{
|
||||
var idealFrameTime = 1.0 / Settings.Graphics.MaxFramerate;
|
||||
var sw = new Stopwatch();
|
||||
|
||||
Tick( orderManager, viewport );
|
||||
|
||||
if (Settings.Graphics.CapFramerate)
|
||||
{
|
||||
var waitTime = idealFrameTime - sw.ElapsedTime();
|
||||
if (waitTime > 0)
|
||||
System.Threading.Thread.Sleep( TimeSpan.FromSeconds(waitTime) );
|
||||
}
|
||||
}
|
||||
|
||||
OnQuit();
|
||||
}
|
||||
|
||||
@@ -378,6 +426,7 @@ namespace OpenRA
|
||||
// Work around a miscompile in mono 2.6.7:
|
||||
// booleans that default to true cannot be set false by an initializer
|
||||
settings.AdvertiseOnline = false;
|
||||
settings.AllowUPnP = false;
|
||||
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0),
|
||||
Game.Settings.Game.Mods, settings, modData);
|
||||
|
||||
@@ -70,6 +70,9 @@ namespace OpenRA
|
||||
|
||||
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(my.Value))
|
||||
throw new YamlException("Junk value `{0}` on trait node {1}"
|
||||
.F(my.Value, traitName));
|
||||
var info = Game.CreateObject<ITraitInfo>(traitName + "Info");
|
||||
FieldLoader.Load(info, my);
|
||||
return info;
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace OpenRA
|
||||
{
|
||||
public static Dictionary<string, ActorInfo> Info;
|
||||
public static Dictionary<string, WeaponInfo> Weapons;
|
||||
public static Dictionary<string, VoiceInfo> Voices;
|
||||
public static Dictionary<string, SoundInfo> Voices;
|
||||
public static Dictionary<string, SoundInfo> Notifications;
|
||||
public static Dictionary<string, MusicInfo> Music;
|
||||
public static Dictionary<string, string> Movies;
|
||||
public static Dictionary<string, TileSet> TileSets;
|
||||
@@ -30,7 +31,8 @@ namespace OpenRA
|
||||
// Added support to extend the list of rules (add it to m.LocalRules)
|
||||
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
|
||||
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
|
||||
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
|
||||
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new SoundInfo(k.Value));
|
||||
Notifications = LoadYamlRules(m.Notifications, map.Notifications, (k, _) => new SoundInfo(k.Value));
|
||||
Music = LoadYamlRules(m.Music, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
|
||||
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 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,
|
||||
@@ -19,6 +19,9 @@ using OpenRA.Server;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
public enum MouseScrollType { Disabled, Standard, Inverted }
|
||||
public enum SoundCashTicks { Disabled, Normal, Extreme }
|
||||
|
||||
public class ServerSettings
|
||||
{
|
||||
public string Name = "OpenRA Game";
|
||||
@@ -26,8 +29,13 @@ namespace OpenRA.GameRules
|
||||
public int ExternalPort = 1234;
|
||||
public bool AdvertiseOnline = true;
|
||||
public string MasterServer = "http://master.open-ra.org/";
|
||||
public bool AllowUPnP = false;
|
||||
public bool AllowCheats = false;
|
||||
public string Map = null;
|
||||
public string[] Ban = null;
|
||||
public int TimeOut = 0;
|
||||
public bool Dedicated = false;
|
||||
public bool DedicatedLoop = true;
|
||||
|
||||
public ServerSettings() { }
|
||||
|
||||
@@ -38,8 +46,13 @@ namespace OpenRA.GameRules
|
||||
ExternalPort = other.ExternalPort;
|
||||
AdvertiseOnline = other.AdvertiseOnline;
|
||||
MasterServer = other.MasterServer;
|
||||
AllowUPnP = other.AllowUPnP;
|
||||
AllowCheats = other.AllowCheats;
|
||||
Map = other.Map;
|
||||
Ban = other.Ban;
|
||||
TimeOut = other.TimeOut;
|
||||
Dedicated = other.Dedicated;
|
||||
DedicatedLoop = other.DedicatedLoop;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +73,8 @@ namespace OpenRA.GameRules
|
||||
public int2 FullscreenSize = new int2(0,0);
|
||||
public int2 WindowedSize = new int2(1024, 768);
|
||||
public bool PixelDouble = false;
|
||||
public bool CapFramerate = false;
|
||||
public int MaxFramerate = 60;
|
||||
|
||||
public int BatchSize = 8192;
|
||||
public int NumTempBuffers = 8;
|
||||
@@ -74,6 +89,9 @@ namespace OpenRA.GameRules
|
||||
public bool Shuffle = false;
|
||||
public bool Repeat = false;
|
||||
public bool ShellmapMusic = true;
|
||||
public string Engine = "AL";
|
||||
|
||||
public SoundCashTicks SoundCashTickType = SoundCashTicks.Extreme;
|
||||
}
|
||||
|
||||
public class PlayerSettings
|
||||
@@ -83,8 +101,6 @@ namespace OpenRA.GameRules
|
||||
public string LastServer = "localhost:1234";
|
||||
}
|
||||
|
||||
public enum MouseScrollType { Disabled, Standard, Inverted }
|
||||
|
||||
public class GameSettings
|
||||
{
|
||||
public string[] Mods = { "ra" };
|
||||
@@ -96,6 +112,8 @@ namespace OpenRA.GameRules
|
||||
public MouseScrollType MouseScroll = MouseScrollType.Standard;
|
||||
public float ViewportEdgeScrollStep = 10f;
|
||||
|
||||
public bool UseClassicMouseStyle = false;
|
||||
|
||||
// Internal game settings
|
||||
public int Timestep = 40;
|
||||
|
||||
@@ -139,7 +157,6 @@ namespace OpenRA.GameRules
|
||||
|
||||
if (File.Exists(SettingsFile))
|
||||
{
|
||||
//Console.WriteLine("Loading settings file {0}",SettingsFile);
|
||||
var yaml = MiniYaml.DictFromFile(SettingsFile);
|
||||
|
||||
foreach (var kv in Sections)
|
||||
@@ -168,11 +185,11 @@ namespace OpenRA.GameRules
|
||||
|
||||
void LoadSectionYaml(MiniYaml yaml, object section)
|
||||
{
|
||||
object defaults = Activator.CreateInstance(section.GetType());
|
||||
var defaults = Activator.CreateInstance(section.GetType());
|
||||
FieldLoader.InvalidValueAction = (s,t,f) =>
|
||||
{
|
||||
object ret = defaults.GetType().GetField(f).GetValue(defaults);
|
||||
System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) );
|
||||
var ret = defaults.GetType().GetField(f).GetValue(defaults);
|
||||
Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) );
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -15,12 +15,16 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
public class VoiceInfo
|
||||
public class SoundInfo
|
||||
{
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Variants;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Prefixes;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Voices;
|
||||
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Notifications;
|
||||
public readonly string DefaultVariant = ".aud" ;
|
||||
public readonly string DefaultPrefix = "" ;
|
||||
public readonly string[] DisableVariants = { };
|
||||
public readonly string[] DisablePrefixes = { };
|
||||
|
||||
static Dictionary<string, string[]> Load( MiniYaml y, string name )
|
||||
{
|
||||
@@ -31,30 +35,28 @@ namespace OpenRA.GameRules
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
|
||||
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, SoundPool>> VoicePools;
|
||||
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, SoundPool>> NotificationsPools;
|
||||
|
||||
public VoiceInfo( MiniYaml y )
|
||||
public SoundInfo( MiniYaml y )
|
||||
{
|
||||
FieldLoader.Load( this, y );
|
||||
Variants = Load(y, "Variants");
|
||||
Prefixes = Load(y, "Prefixes");
|
||||
Voices = Load(y, "Voices");
|
||||
Notifications = Load(y, "Notifications");
|
||||
|
||||
if (!Voices.ContainsKey("Attack"))
|
||||
Voices.Add("Attack", Voices["Move"]);
|
||||
|
||||
if (!Voices.ContainsKey("AttackMove"))
|
||||
Voices.Add("AttackMove", Voices["Move"]);
|
||||
|
||||
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
|
||||
VoicePools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new SoundPool(a.Value) ));
|
||||
NotificationsPools = Lazy.New(() => Notifications.ToDictionary( a => a.Key, a => new SoundPool(a.Value) ));
|
||||
}
|
||||
}
|
||||
|
||||
public class VoicePool
|
||||
public class SoundPool
|
||||
{
|
||||
readonly string[] clips;
|
||||
readonly List<string> liveclips = new List<string>();
|
||||
|
||||
public VoicePool(params string[] clips)
|
||||
public SoundPool(params string[] clips)
|
||||
{
|
||||
this.clips = clips;
|
||||
}
|
||||
@@ -24,9 +24,9 @@ namespace OpenRA.GameRules
|
||||
public readonly bool Ore = false; // can this damage ore?
|
||||
public readonly string Explosion = null; // explosion effect to use
|
||||
public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash)
|
||||
public readonly string SmudgeType = null; // type of smudge to apply
|
||||
public readonly string[] SmudgeType = { }; // type of smudge to apply
|
||||
public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner)
|
||||
public readonly int InfDeath = 0; // infantry death animation to use
|
||||
public readonly int InfDeath = 1; // infantry death animation to use
|
||||
public readonly string ImpactSound = null; // sound to play on impact
|
||||
public readonly string WaterImpactSound = null; // sound to play on impact with water
|
||||
public readonly int Damage = 0; // how much (raw) damage to deal
|
||||
@@ -72,11 +72,11 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
public WeaponInfo weapon;
|
||||
public Actor firedBy;
|
||||
public int2 src;
|
||||
public PPos src;
|
||||
public int srcAltitude;
|
||||
public int facing;
|
||||
public Target target;
|
||||
public int2 dest;
|
||||
public PPos dest;
|
||||
public int destAltitude;
|
||||
public float firepowerModifier = 1.0f;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA.GameRules
|
||||
public readonly int Burst = 1;
|
||||
public readonly bool Charges = false;
|
||||
public readonly bool Underwater = false;
|
||||
public readonly string[] ValidTargets = { "Ground" };
|
||||
public readonly string[] ValidTargets = { "Ground", "Water" };
|
||||
public readonly int BurstDelay = 5;
|
||||
public readonly float MinRange = 0;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenRA.Graphics
|
||||
public Renderable Image(Actor self, string pal)
|
||||
{
|
||||
var p = self.CenterLocation;
|
||||
var loc = p - 0.5f * Animation.Image.size
|
||||
var loc = p.ToFloat2() - 0.5f * Animation.Image.size
|
||||
+ (OffsetFunc != null ? OffsetFunc() : float2.Zero);
|
||||
var r = new Renderable(Animation.Image, loc, pal, p.Y);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -25,9 +25,16 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
cursors = new Dictionary<string, CursorSequence>();
|
||||
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal));
|
||||
int[] ShadowIndex = { };
|
||||
|
||||
if (sequences.NodesDict.ContainsKey("ShadowIndex"))
|
||||
{
|
||||
Array.Resize(ref ShadowIndex, ShadowIndex.Length + 1);
|
||||
ShadowIndex[ShadowIndex.Length - 1] = Convert.ToInt32(sequences.NodesDict["ShadowIndex"].Value);
|
||||
}
|
||||
|
||||
foreach (var s in sequences.NodesDict["Palettes"].Nodes)
|
||||
Game.modData.Palette.AddPalette(s.Key, new Palette(FileSystem.Open(s.Value.Value), false));
|
||||
Game.modData.Palette.AddPalette(s.Key, new Palette(FileSystem.Open(s.Value.Value), ShadowIndex));
|
||||
|
||||
foreach (var s in sequences.NodesDict["Cursors"].Nodes)
|
||||
LoadSequencesForCursor(s.Key, s.Value);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
var vb = renderer.GetTempVertexBuffer();
|
||||
vb.SetData( vertices, nv );
|
||||
renderer.SetLineWidth(LineWidth);
|
||||
renderer.SetLineWidth(LineWidth * Game.viewport.Zoom);
|
||||
renderer.DrawBatch( vb, 0, nv, PrimitiveType.LineList );
|
||||
} );
|
||||
|
||||
|
||||
@@ -32,13 +32,11 @@ namespace OpenRA.Graphics
|
||||
var height = map.Bounds.Height;
|
||||
|
||||
if (!actualSize)
|
||||
{
|
||||
width = height = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
}
|
||||
|
||||
var terrain = new Bitmap(width, height);
|
||||
|
||||
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
|
||||
var bitmapData = terrain.LockBits(terrain.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
@@ -69,7 +67,7 @@ namespace OpenRA.Graphics
|
||||
Bitmap terrain = new Bitmap(terrainBitmap);
|
||||
var tileset = Rules.TileSets[map.Tileset];
|
||||
|
||||
var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height),
|
||||
var bitmapData = terrain.LockBits(terrain.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
@@ -104,7 +102,7 @@ namespace OpenRA.Graphics
|
||||
var map = world.Map;
|
||||
var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
var bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var bitmapData = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
@@ -132,7 +130,7 @@ namespace OpenRA.Graphics
|
||||
var map = world.Map;
|
||||
var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
var bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var bitmapData = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
@@ -141,7 +139,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
foreach (var t in world.ActorsWithTrait<IRadarSignature>())
|
||||
{
|
||||
if (!world.LocalShroud.IsVisible(t.Actor))
|
||||
if (!world.RenderedShroud.IsVisible(t.Actor))
|
||||
continue;
|
||||
|
||||
var color = t.Trait.RadarSignatureColor(t.Actor);
|
||||
@@ -160,10 +158,10 @@ namespace OpenRA.Graphics
|
||||
var map = world.Map;
|
||||
var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
var bitmap = new Bitmap(size, size);
|
||||
if (world.LocalShroud.Disabled)
|
||||
if (world.RenderedShroud.Disabled)
|
||||
return bitmap;
|
||||
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
var bitmapData = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
var shroud = Color.Black.ToArgb();
|
||||
@@ -178,9 +176,9 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
if (!world.LocalShroud.IsExplored(mapX, mapY))
|
||||
if (!world.RenderedShroud.IsExplored(mapX, mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
|
||||
else if (!world.LocalShroud.IsVisible(mapX,mapY))
|
||||
else if (!world.RenderedShroud.IsVisible(mapX,mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,6 @@ namespace OpenRA.Graphics
|
||||
public void BeginFrame(float2 scroll, float zoom)
|
||||
{
|
||||
device.Clear();
|
||||
|
||||
WorldLineRenderer.LineWidth = zoom;
|
||||
float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height);
|
||||
float2 r2 = new float2(-1, 1);
|
||||
var zr1 = zoom*r1;
|
||||
@@ -137,7 +135,10 @@ namespace OpenRA.Graphics
|
||||
FixOSX();
|
||||
|
||||
var resolution = GetResolution( windowMode );
|
||||
var rendererPath = Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) );
|
||||
|
||||
string renderer = Game.Settings.Server.Dedicated?"Null":Game.Settings.Graphics.Renderer;
|
||||
var rendererPath = Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(renderer) );
|
||||
|
||||
device = CreateDevice( Assembly.LoadFile( rendererPath ), resolution.Width, resolution.Height, windowMode );
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -26,14 +27,13 @@ namespace OpenRA.Graphics
|
||||
public int Facings { get { return facings; } }
|
||||
public int Tick { get { return tick; } }
|
||||
|
||||
string srcOverride;
|
||||
public Sequence(string unit, string name, MiniYaml info)
|
||||
{
|
||||
srcOverride = info.Value;
|
||||
var srcOverride = info.Value;
|
||||
Name = name;
|
||||
var d = info.NodesDict;
|
||||
|
||||
sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
|
||||
sprites = Game.modData.SpriteLoader.LoadAllSprites(srcOverride ?? unit);
|
||||
start = int.Parse(d["Start"].Value);
|
||||
|
||||
if (!d.ContainsKey("Length"))
|
||||
@@ -53,26 +53,12 @@ namespace OpenRA.Graphics
|
||||
tick = int.Parse(d["Tick"].Value);
|
||||
else
|
||||
tick = 40;
|
||||
}
|
||||
|
||||
public MiniYaml Save()
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
|
||||
root.Add(new MiniYamlNode("Start", start.ToString()));
|
||||
|
||||
if (length > 1 && (start != 0 || length != sprites.Length - start))
|
||||
root.Add(new MiniYamlNode("Length", length.ToString()));
|
||||
else if (length > 1 && length == sprites.Length - start)
|
||||
root.Add(new MiniYamlNode("Length", "*"));
|
||||
|
||||
if (facings > 1)
|
||||
root.Add(new MiniYamlNode("Facings", facings.ToString()));
|
||||
|
||||
if (tick != 40)
|
||||
root.Add(new MiniYamlNode("Tick", tick.ToString()));
|
||||
|
||||
return new MiniYaml(srcOverride, root);
|
||||
if (start < 0 || start + facings * length > sprites.Length)
|
||||
throw new InvalidOperationException(
|
||||
"{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist"
|
||||
.F(unit, name, start, start + facings * length - 1, srcOverride ?? unit, sprites.Length - 1,
|
||||
info.Nodes[0].Location));
|
||||
}
|
||||
|
||||
public Sprite GetSprite( int frame )
|
||||
|
||||
@@ -15,21 +15,25 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
Traits.Shroud shroud;
|
||||
World world;
|
||||
Traits.Shroud shroud {
|
||||
get {
|
||||
return world.RenderedShroud;
|
||||
}
|
||||
}
|
||||
|
||||
Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
|
||||
bool dirty = true;
|
||||
Map map;
|
||||
|
||||
public ShroudRenderer(World world)
|
||||
{
|
||||
this.shroud = world.LocalShroud;
|
||||
this.world = world;
|
||||
this.map = world.Map;
|
||||
|
||||
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
shroud.Dirty += () => dirty = true;
|
||||
}
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
@@ -103,9 +107,9 @@ namespace OpenRA.Graphics
|
||||
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (dirty)
|
||||
if (shroud != null && shroud.dirty)
|
||||
{
|
||||
dirty = false;
|
||||
shroud.dirty = false;
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
sprites[i, j] = ChooseShroud(i, j);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenRA.Graphics
|
||||
Sprite[] LoadSprites(string filename)
|
||||
{
|
||||
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
|
||||
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
||||
return shp.Frames.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
||||
}
|
||||
|
||||
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
||||
|
||||
@@ -72,9 +72,9 @@ namespace OpenRA.Graphics
|
||||
if (firstRow < 0) firstRow = 0;
|
||||
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
|
||||
|
||||
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
|
||||
if (world.RenderedPlayer != null && !world.RenderedShroud.Disabled && world.RenderedShroud.Bounds.HasValue)
|
||||
{
|
||||
var r = world.LocalShroud.Bounds.Value;
|
||||
var r = world.RenderedShroud.Bounds.Value;
|
||||
if (firstRow < r.Top - map.Bounds.Top)
|
||||
firstRow = r.Top - map.Bounds.Top;
|
||||
|
||||
|
||||
@@ -8,40 +8,12 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
public static string[] ReadAllLines(Stream s)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
using (StreamReader reader = new StreamReader(s))
|
||||
while(!reader.EndOfStream)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if( !string.IsNullOrEmpty( line ) && line[0] != '#' )
|
||||
result.Add( line );
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public static T[] MakeArray<T>(int count, Converter<int, T> f)
|
||||
{
|
||||
T[] result = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = f(i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
|
||||
|
||||
public static void FastCreateQuad(Vertex[] vertices, float2 o, Sprite r, int palette, int nv, float2 size)
|
||||
@@ -59,6 +31,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
static readonly int[] channelMasks = { 2, 1, 0, 3 }; // yes, our channel order is nuts.
|
||||
|
||||
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
|
||||
{
|
||||
var data = dest.sheet.Data;
|
||||
@@ -79,28 +52,5 @@ namespace OpenRA.Graphics
|
||||
destOffset += destSkip;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color Lerp(float t, Color a, Color b)
|
||||
{
|
||||
return Color.FromArgb(
|
||||
LerpChannel(t, a.A, b.A),
|
||||
LerpChannel(t, a.R, b.R),
|
||||
LerpChannel(t, a.G, b.G),
|
||||
LerpChannel(t, a.B, b.B));
|
||||
}
|
||||
|
||||
public static int LerpARGBColor(float t, int c1, int c2)
|
||||
{
|
||||
int a = LerpChannel(t, (c1 >> 24) & 255, (c2 >> 24) & 255);
|
||||
int r = LerpChannel(t, (c1 >> 16) & 255, (c2 >> 16) & 255);
|
||||
int g = LerpChannel(t, (c1 >> 8) & 255, (c2 >> 8) & 255);
|
||||
int b = LerpChannel(t, c1 & 255, c2 & 255);
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
public static int LerpChannel(float t, int a, int b)
|
||||
{
|
||||
return (int)((1 - t) * a + t * b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,15 +126,15 @@ namespace OpenRA.Graphics
|
||||
|
||||
using( new PerfSample("render_widgets") )
|
||||
{
|
||||
Widget.DoDraw();
|
||||
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
Ui.Draw();
|
||||
var cursorName = Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
var cursorSequence = CursorProvider.GetCursorSequence(cursorName);
|
||||
var cursorSprite = cursorSequence.GetSprite((int)cursorFrame);
|
||||
|
||||
renderer.SpriteRenderer.DrawSprite(cursorSprite,
|
||||
Viewport.LastMousePos - cursorSequence.Hotspot,
|
||||
Game.modData.Palette.GetPaletteIndex(cursorSequence.Palette),
|
||||
cursorSprite.size);
|
||||
Viewport.LastMousePos - cursorSequence.Hotspot,
|
||||
Game.modData.Palette.GetPaletteIndex(cursorSequence.Palette),
|
||||
cursorSprite.size);
|
||||
}
|
||||
|
||||
using( new PerfSample("render_flip") )
|
||||
@@ -149,18 +149,18 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
// Convert from viewport coords to cell coords (not px)
|
||||
public float2 ViewToWorld(MouseInput mi) { return ViewToWorld(mi.Location); }
|
||||
public float2 ViewToWorld(int2 loc)
|
||||
public CPos ViewToWorld(MouseInput mi) { return ViewToWorld(mi.Location); }
|
||||
public CPos ViewToWorld(int2 loc)
|
||||
{
|
||||
return (1f / Game.CellSize) * (1f/Zoom*loc.ToFloat2() + Location);
|
||||
return (CPos)( (1f / Game.CellSize) * (1f/Zoom*loc.ToFloat2() + Location) ).ToInt2();
|
||||
}
|
||||
|
||||
public int2 ViewToWorldPx(int2 loc) { return (1f/Zoom*loc.ToFloat2() + Location).ToInt2(); }
|
||||
public int2 ViewToWorldPx(MouseInput mi) { return ViewToWorldPx(mi.Location); }
|
||||
public PPos ViewToWorldPx(int2 loc) { return (PPos)(1f/Zoom*loc.ToFloat2() + Location).ToInt2(); }
|
||||
public PPos ViewToWorldPx(MouseInput mi) { return ViewToWorldPx(mi.Location); }
|
||||
|
||||
public void Center(float2 loc)
|
||||
{
|
||||
scrollPosition = NormalizeScrollPosition((Game.CellSize*loc - 1f/(2*Zoom)*screenSize.ToFloat2()).ToInt2());
|
||||
scrollPosition = NormalizeScrollPosition((Game.CellSize * loc - 1f/(2*Zoom)*screenSize.ToFloat2()).ToInt2());
|
||||
}
|
||||
|
||||
public void Center(IEnumerable<Actor> actors)
|
||||
@@ -168,9 +168,9 @@ namespace OpenRA.Graphics
|
||||
if (!actors.Any()) return;
|
||||
|
||||
var avgPos = actors
|
||||
.Select(a => a.CenterLocation)
|
||||
.Select(a => (PVecInt)a.CenterLocation)
|
||||
.Aggregate((a, b) => a + b) / actors.Count();
|
||||
scrollPosition = NormalizeScrollPosition((avgPos - 1f/(2*Zoom)*screenSize.ToFloat2()).ToInt2());
|
||||
scrollPosition = NormalizeScrollPosition(((PVecFloat)avgPos - (PVecFloat)(1f / (2 * Zoom) * screenSize.ToFloat2())).ToInt2());
|
||||
}
|
||||
|
||||
// Rectangle (in viewport coords) that contains things to be drawn
|
||||
@@ -194,7 +194,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
if (cachedScroll != scrollPosition)
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace OpenRA.Graphics
|
||||
cachedScroll = scrollPosition;
|
||||
}
|
||||
|
||||
var b = world.LocalShroud.Bounds;
|
||||
var b = world.RenderedShroud.Bounds;
|
||||
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,9 @@ namespace OpenRA.Graphics
|
||||
var comparer = new SpriteComparer();
|
||||
|
||||
var actors = world.FindUnits(
|
||||
new int2(Game.CellSize*bounds.Left, Game.CellSize*bounds.Top),
|
||||
new int2(Game.CellSize*bounds.Right, Game.CellSize*bounds.Bottom));
|
||||
bounds.TopLeftAsCPos().ToPPos(),
|
||||
bounds.BottomRightAsCPos().ToPPos()
|
||||
);
|
||||
|
||||
var renderables = actors.SelectMany(a => a.Render())
|
||||
.OrderBy(r => r, comparer);
|
||||
@@ -140,25 +141,21 @@ namespace OpenRA.Graphics
|
||||
selectable.DrawRollover(this, unit);
|
||||
}
|
||||
|
||||
public void DrawLocus(Color c, int2[] cells)
|
||||
public void DrawLocus(Color c, CPos[] cells)
|
||||
{
|
||||
var dict = cells.ToDictionary(a => a, a => 0);
|
||||
var wlr = Game.Renderer.WorldLineRenderer;
|
||||
|
||||
foreach (var t in dict.Keys)
|
||||
{
|
||||
if (!dict.ContainsKey(t + new int2(-1, 0)))
|
||||
wlr.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)),
|
||||
c, c);
|
||||
if (!dict.ContainsKey(t + new int2(1, 0)))
|
||||
wlr.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)),
|
||||
c, c);
|
||||
if (!dict.ContainsKey(t + new int2(0, -1)))
|
||||
wlr.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)),
|
||||
c, c);
|
||||
if (!dict.ContainsKey(t + new int2(0, 1)))
|
||||
wlr.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)),
|
||||
c, c);
|
||||
if (!dict.ContainsKey(t + new CVec(-1, 0)))
|
||||
wlr.DrawLine(t.ToPPos().ToFloat2(), (t + new CVec(0, 1)).ToPPos().ToFloat2(), c, c);
|
||||
if (!dict.ContainsKey(t + new CVec(1, 0)))
|
||||
wlr.DrawLine((t + new CVec(1, 0)).ToPPos().ToFloat2(), (t + new CVec(1, 1)).ToPPos().ToFloat2(), c, c);
|
||||
if (!dict.ContainsKey(t + new CVec(0, -1)))
|
||||
wlr.DrawLine(t.ToPPos().ToFloat2(), (t + new CVec(1, 0)).ToPPos().ToFloat2(), c, c);
|
||||
if (!dict.ContainsKey(t + new CVec(0, 1)))
|
||||
wlr.DrawLine((t + new CVec(0, 1)).ToPPos().ToFloat2(), (t + new CVec(1, 1)).ToPPos().ToFloat2(), c, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -15,38 +15,53 @@ namespace OpenRA
|
||||
public class NullInputHandler : IInputHandler
|
||||
{
|
||||
// ignore all input
|
||||
public void ModifierKeys( Modifiers mods ) { }
|
||||
public void OnKeyInput( KeyInput input ) { }
|
||||
public void OnMouseInput( MouseInput input ) { }
|
||||
public void ModifierKeys(Modifiers mods) { }
|
||||
public void OnKeyInput(KeyInput input) { }
|
||||
public void OnMouseInput(MouseInput input) { }
|
||||
}
|
||||
|
||||
public class DefaultInputHandler : IInputHandler
|
||||
{
|
||||
readonly World world;
|
||||
public DefaultInputHandler( World world )
|
||||
public DefaultInputHandler(World world)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void ModifierKeys( Modifiers mods )
|
||||
public void ModifierKeys(Modifiers mods)
|
||||
{
|
||||
Game.HandleModifierKeys( mods );
|
||||
Game.HandleModifierKeys(mods);
|
||||
}
|
||||
|
||||
public void OnKeyInput( KeyInput input )
|
||||
public void OnKeyInput(KeyInput input)
|
||||
{
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Widget.DoHandleKeyPress( input );
|
||||
} );
|
||||
Sync.CheckSyncUnchanged(world, () => Ui.HandleKeyPress(input));
|
||||
}
|
||||
|
||||
public void OnMouseInput( MouseInput input )
|
||||
public void OnMouseInput(MouseInput input)
|
||||
{
|
||||
Sync.CheckSyncUnchanged( world, () =>
|
||||
{
|
||||
Widget.DoHandleInput( input );
|
||||
} );
|
||||
Sync.CheckSyncUnchanged(world, () => Ui.HandleInput(input));
|
||||
}
|
||||
}
|
||||
|
||||
public class MouseButtonPreference
|
||||
{
|
||||
|
||||
public MouseButton Action
|
||||
{
|
||||
get
|
||||
{
|
||||
return Game.Settings.Game.UseClassicMouseStyle ? MouseButton.Left : MouseButton.Right;
|
||||
}
|
||||
}
|
||||
|
||||
public MouseButton Cancel
|
||||
{
|
||||
get
|
||||
{
|
||||
return Game.Settings.Game.UseClassicMouseStyle ? MouseButton.Right : MouseButton.Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace OpenRA
|
||||
public string Description;
|
||||
public string Author;
|
||||
public string Tileset;
|
||||
public string[] Difficulties;
|
||||
|
||||
[FieldLoader.Ignore] public Lazy<Dictionary<string, ActorReference>> Actors;
|
||||
|
||||
@@ -56,17 +57,11 @@ namespace OpenRA
|
||||
[FieldLoader.Ignore] public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>();
|
||||
[FieldLoader.Ignore] public Lazy<List<SmudgeReference>> Smudges;
|
||||
|
||||
// Rules overrides
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Rules = new List<MiniYamlNode>();
|
||||
|
||||
// Sequences overrides
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Sequences = new List<MiniYamlNode>();
|
||||
|
||||
// Weapon overrides
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Weapons = new List<MiniYamlNode>();
|
||||
|
||||
// Voices overrides
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Voices = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Notifications = new List<MiniYamlNode>();
|
||||
|
||||
// Binary map data
|
||||
[FieldLoader.Ignore] public byte TileFormat = 1;
|
||||
@@ -76,10 +71,7 @@ namespace OpenRA
|
||||
[FieldLoader.Ignore] public Lazy<TileReference<byte, byte>[,]> MapResources;
|
||||
[FieldLoader.Ignore] public string [,] CustomTerrain;
|
||||
|
||||
public Map()
|
||||
{
|
||||
// Do nothing; not a valid map (editor hack)
|
||||
}
|
||||
public Map() {} /* doesn't really produce a valid map, but enough for loading a mod */
|
||||
|
||||
public static Map FromTileset(string tileset)
|
||||
{
|
||||
@@ -121,9 +113,6 @@ namespace OpenRA
|
||||
FieldLoader.Load(this, yaml);
|
||||
Uid = ComputeHash();
|
||||
|
||||
// 'Simple' metadata
|
||||
FieldLoader.Load( this, yaml );
|
||||
|
||||
// Support for formats 1-3 dropped 2011-02-11.
|
||||
// Use release-20110207 to convert older maps to format 4
|
||||
// Use release-20110511 to convert older maps to format 5
|
||||
@@ -140,11 +129,8 @@ namespace OpenRA
|
||||
Actors = Lazy.New(() =>
|
||||
{
|
||||
var ret = new Dictionary<string, ActorReference>();
|
||||
// Load actors
|
||||
foreach (var kv in yaml.NodesDict["Actors"].NodesDict)
|
||||
ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.NodesDict));
|
||||
|
||||
// Add waypoint actors
|
||||
return ret;
|
||||
});
|
||||
|
||||
@@ -162,18 +148,11 @@ namespace OpenRA
|
||||
return ret;
|
||||
});
|
||||
|
||||
|
||||
// Rules
|
||||
Rules = yaml.NodesDict["Rules"].Nodes;
|
||||
|
||||
// Sequences
|
||||
Sequences = (yaml.NodesDict.ContainsKey("Sequences")) ? yaml.NodesDict["Sequences"].Nodes : new List<MiniYamlNode>();
|
||||
|
||||
// Weapons
|
||||
Weapons = (yaml.NodesDict.ContainsKey("Weapons")) ? yaml.NodesDict["Weapons"].Nodes : new List<MiniYamlNode>();
|
||||
|
||||
// Voices
|
||||
Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List<MiniYamlNode>();
|
||||
Rules = NodesOrEmpty(yaml, "Rules");
|
||||
Sequences = NodesOrEmpty(yaml, "Sequences");
|
||||
Weapons = NodesOrEmpty(yaml, "Weapons");
|
||||
Voices = NodesOrEmpty(yaml, "Voices");
|
||||
Notifications = NodesOrEmpty(yaml, "Notifications");
|
||||
|
||||
CustomTerrain = new string[MapSize.X, MapSize.Y];
|
||||
|
||||
@@ -181,6 +160,11 @@ namespace OpenRA
|
||||
MapResources = Lazy.New(() => LoadResourceTiles());
|
||||
}
|
||||
|
||||
static List<MiniYamlNode> NodesOrEmpty(MiniYaml y, string s)
|
||||
{
|
||||
return y.NodesDict.ContainsKey(s) ? y.NodesDict[s].Nodes : new List<MiniYamlNode>();
|
||||
}
|
||||
|
||||
public void Save(string toPath)
|
||||
{
|
||||
MapFormat = 5;
|
||||
@@ -195,6 +179,7 @@ namespace OpenRA
|
||||
"Description",
|
||||
"Author",
|
||||
"Tileset",
|
||||
"Difficulties",
|
||||
"MapSize",
|
||||
"Bounds",
|
||||
"UseAsShellmap",
|
||||
@@ -223,6 +208,7 @@ namespace OpenRA
|
||||
root.Add(new MiniYamlNode("Sequences", null, Sequences));
|
||||
root.Add(new MiniYamlNode("Weapons", null, Weapons));
|
||||
root.Add(new MiniYamlNode("Voices", null, Voices));
|
||||
root.Add(new MiniYamlNode("Notifications", null, Notifications));
|
||||
|
||||
var entries = new Dictionary<string, byte[]>();
|
||||
entries.Add("map.bin", SaveBinaryData());
|
||||
@@ -235,7 +221,7 @@ namespace OpenRA
|
||||
Path = toPath;
|
||||
|
||||
// Create a new map package
|
||||
// TODO: Add other files (resources, rules) to the entries list
|
||||
// TODO: Add other files (custom assets) to the entries list
|
||||
Container = FileSystem.CreatePackage(Path, int.MaxValue, entries);
|
||||
}
|
||||
|
||||
@@ -357,7 +343,7 @@ namespace OpenRA
|
||||
return dataStream.ToArray();
|
||||
}
|
||||
|
||||
public bool IsInMap(int2 xy) { return IsInMap(xy.X, xy.Y); }
|
||||
public bool IsInMap(CPos xy) { return IsInMap(xy.X, xy.Y); }
|
||||
public bool IsInMap(int x, int y) { return Bounds.Contains(x,y); }
|
||||
|
||||
static T[,] ResizeArray<T>(T[,] ts, T t, int width, int height)
|
||||
@@ -399,22 +385,24 @@ namespace OpenRA
|
||||
|
||||
public void MakeDefaultPlayers()
|
||||
{
|
||||
Players.Clear();
|
||||
|
||||
var firstRace = OpenRA.Rules.Info["world"].Traits
|
||||
.WithInterface<CountryInfo>().First(c => c.Selectable).Race;
|
||||
|
||||
Players.Add("Neutral", new PlayerReference
|
||||
{
|
||||
Name = "Neutral",
|
||||
Race = firstRace,
|
||||
OwnsWorld = true,
|
||||
NonCombatant = true
|
||||
});
|
||||
if (!Players.ContainsKey("Neutral"))
|
||||
Players.Add("Neutral", new PlayerReference
|
||||
{
|
||||
Name = "Neutral",
|
||||
Race = firstRace,
|
||||
OwnsWorld = true,
|
||||
NonCombatant = true
|
||||
});
|
||||
|
||||
var numSpawns = GetSpawnPoints().Length;
|
||||
for (var index = 0; index < numSpawns; index++)
|
||||
{
|
||||
if (Players.ContainsKey("Multi{0}".F(index)))
|
||||
continue;
|
||||
|
||||
var p = new PlayerReference
|
||||
{
|
||||
Name = "Multi{0}".F(index),
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace OpenRA
|
||||
.Concat(mods.SelectMany(p => FindMapsIn("{1}maps{0}{2}{0}".F(Path.DirectorySeparatorChar, Platform.SupportDir, p))));
|
||||
|
||||
var ret = new Dictionary<string, Map>();
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
try
|
||||
@@ -113,6 +114,7 @@ namespace OpenRA
|
||||
Console.WriteLine("Details: {0}", e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,15 +39,15 @@ namespace OpenRA
|
||||
public readonly Actor Subject;
|
||||
public readonly bool Queued;
|
||||
public Actor TargetActor;
|
||||
public int2 TargetLocation;
|
||||
public CPos TargetLocation;
|
||||
public string TargetString;
|
||||
public int2 ExtraLocation;
|
||||
public CPos ExtraLocation;
|
||||
public bool IsImmediate;
|
||||
|
||||
public Player Player { get { return Subject.Owner; } }
|
||||
|
||||
Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
|
||||
Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation)
|
||||
{
|
||||
this.OrderString = orderString;
|
||||
this.Subject = subject;
|
||||
@@ -60,10 +60,10 @@ namespace OpenRA
|
||||
|
||||
// For scripting special powers
|
||||
public Order()
|
||||
: this(null, null, null, int2.Zero, null, false, int2.Zero) { }
|
||||
: this(null, null, null, CPos.Zero, null, false, CPos.Zero) { }
|
||||
|
||||
public Order(string orderString, Actor subject, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
|
||||
: this(orderString, subject, null, CPos.Zero, null, queued, CPos.Zero) { }
|
||||
|
||||
public Order(string orderstring, Order order)
|
||||
: this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
|
||||
@@ -98,21 +98,21 @@ namespace OpenRA
|
||||
|
||||
OrderFields fields = 0;
|
||||
if (TargetActor != null) fields |= OrderFields.TargetActor;
|
||||
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetLocation != CPos.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||
if (Queued) fields |= OrderFields.Queued;
|
||||
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
|
||||
if (ExtraLocation != CPos.Zero) fields |= OrderFields.ExtraLocation;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (TargetActor != null)
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
if (TargetLocation != int2.Zero)
|
||||
w.Write(TargetLocation);
|
||||
if (TargetLocation != CPos.Zero)
|
||||
w.Write(TargetLocation.ToInt2());
|
||||
if (TargetString != null)
|
||||
w.Write(TargetString);
|
||||
if (ExtraLocation != int2.Zero)
|
||||
w.Write(ExtraLocation);
|
||||
if (ExtraLocation != CPos.Zero)
|
||||
w.Write(ExtraLocation.ToInt2());
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
@@ -130,10 +130,10 @@ namespace OpenRA
|
||||
var flags = (OrderFields)r.ReadByte();
|
||||
|
||||
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
|
||||
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var targetLocation = (CPos)( flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero );
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var extraLocation = (CPos)(flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero);
|
||||
|
||||
Actor subject, targetActor;
|
||||
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
|
||||
@@ -199,7 +199,18 @@ namespace OpenRA
|
||||
{
|
||||
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order PauseRequest()
|
||||
{
|
||||
return new Order("PauseRequest", null, false) { IsImmediate = true, TargetString="" }; //TODO: targetbool?
|
||||
}
|
||||
|
||||
public static Order PauseGame()
|
||||
{
|
||||
return new Order("PauseGame", null, false) { IsImmediate = true, TargetString=""}; //TODO: targetbool?
|
||||
}
|
||||
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
@@ -207,17 +218,17 @@ namespace OpenRA
|
||||
|
||||
public static Order StartProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
return new Order("StartProduction", subject, false) { TargetLocation = new CPos(count, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order PauseProduction(Actor subject, string item, bool pause)
|
||||
{
|
||||
return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
|
||||
return new Order("PauseProduction", subject, false) { TargetLocation = new CPos(pause ? 1 : 0, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
return new Order("CancelProduction", subject, false) { TargetLocation = new CPos(count, 0), TargetString = item };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace OpenRA.Network
|
||||
public int LastTickTime = Environment.TickCount;
|
||||
|
||||
public bool GameStarted { get { return NetFrameNumber != 0; } }
|
||||
public bool GamePaused {get; set;}
|
||||
public IConnection Connection { get; private set; }
|
||||
|
||||
public readonly int SyncHeaderSize = 9;
|
||||
|
||||
@@ -10,35 +10,26 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public class ReplayConnection : IConnection
|
||||
{
|
||||
//uint nextFrame = 1;
|
||||
FileStream replayStream;
|
||||
List<byte[]> sync = new List<byte[]>();
|
||||
|
||||
public ReplayConnection( string replayFilename )
|
||||
{
|
||||
replayStream = File.OpenRead( replayFilename );
|
||||
}
|
||||
public ReplayConnection( string replayFilename ) { replayStream = File.OpenRead( replayFilename ); }
|
||||
|
||||
public int LocalClientId
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public ConnectionState ConnectionState
|
||||
{
|
||||
get { return ConnectionState.Connected; }
|
||||
}
|
||||
public int LocalClientId { get { return 0; } }
|
||||
public ConnectionState ConnectionState { get { return ConnectionState.Connected; } }
|
||||
|
||||
// do nothing; ignore locally generated orders
|
||||
public void Send( int frame, List<byte[]> orders ) { }
|
||||
public void SendImmediate( List<byte[]> orders ) { }
|
||||
|
||||
public void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
@@ -47,8 +38,6 @@ namespace OpenRA.Network
|
||||
sync.Add( ms.ToArray() );
|
||||
}
|
||||
|
||||
List<byte[]> sync = new List<byte[]>();
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
while( sync.Count != 0 )
|
||||
@@ -56,9 +45,11 @@ namespace OpenRA.Network
|
||||
packetFn( LocalClientId, sync[ 0 ] );
|
||||
sync.RemoveAt( 0 );
|
||||
}
|
||||
|
||||
if( replayStream == null ) return;
|
||||
|
||||
var reader = new BinaryReader( replayStream );
|
||||
|
||||
while( replayStream.Position < replayStream.Length )
|
||||
{
|
||||
var client = reader.ReadInt32();
|
||||
@@ -66,56 +57,10 @@ namespace OpenRA.Network
|
||||
var packet = reader.ReadBytes( packetLen );
|
||||
packetFn( client, packet );
|
||||
}
|
||||
|
||||
replayStream = null;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
class ReplayRecorderConnection : IConnection
|
||||
{
|
||||
IConnection inner;
|
||||
BinaryWriter writer;
|
||||
|
||||
public ReplayRecorderConnection( IConnection inner, FileStream replayFile )
|
||||
{
|
||||
this.inner = inner;
|
||||
this.writer = new BinaryWriter( replayFile );
|
||||
}
|
||||
|
||||
public int LocalClientId { get { return inner.LocalClientId; } }
|
||||
public ConnectionState ConnectionState { get { return inner.ConnectionState; } }
|
||||
|
||||
public void Send( int frame, List<byte[]> orders ) { inner.Send( frame, orders ); }
|
||||
public void SendImmediate( List<byte[]> orders ) { inner.SendImmediate( orders ); }
|
||||
public void SendSync( int frame, byte[] syncData ) { inner.SendSync( frame, syncData ); }
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
inner.Receive( ( client, data ) =>
|
||||
{
|
||||
writer.Write( client );
|
||||
writer.Write( data.Length );
|
||||
writer.Write( data );
|
||||
packetFn( client, data );
|
||||
} );
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if( disposed )
|
||||
return;
|
||||
|
||||
writer.Close();
|
||||
inner.Dispose();
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
~ReplayRecorderConnection()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
103
OpenRA.Game/Network/ReplayRecorderConnection.cs
Normal file
103
OpenRA.Game/Network/ReplayRecorderConnection.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class ReplayRecorderConnection : IConnection
|
||||
{
|
||||
IConnection inner;
|
||||
BinaryWriter writer;
|
||||
Func<string> chooseFilename;
|
||||
MemoryStream preStartBuffer = new MemoryStream();
|
||||
|
||||
public ReplayRecorderConnection( IConnection inner, Func<string> chooseFilename )
|
||||
{
|
||||
this.chooseFilename = chooseFilename;
|
||||
this.inner = inner;
|
||||
|
||||
writer = new BinaryWriter(preStartBuffer);
|
||||
}
|
||||
|
||||
void StartSavingReplay(byte[] initialContent)
|
||||
{
|
||||
var filename = chooseFilename();
|
||||
var replayPath = Path.Combine(Platform.SupportDir, "Replays");
|
||||
|
||||
if (!Directory.Exists(replayPath))
|
||||
Directory.CreateDirectory(replayPath);
|
||||
|
||||
var file = File.Create(Path.Combine(replayPath, filename));
|
||||
file.Write(initialContent);
|
||||
this.writer = new BinaryWriter(file);
|
||||
}
|
||||
|
||||
public int LocalClientId { get { return inner.LocalClientId; } }
|
||||
public ConnectionState ConnectionState { get { return inner.ConnectionState; } }
|
||||
|
||||
public void Send( int frame, List<byte[]> orders ) { inner.Send( frame, orders ); }
|
||||
public void SendImmediate( List<byte[]> orders ) { inner.SendImmediate( orders ); }
|
||||
public void SendSync( int frame, byte[] syncData ) { inner.SendSync( frame, syncData ); }
|
||||
|
||||
public void Receive( Action<int, byte[]> packetFn )
|
||||
{
|
||||
inner.Receive((client, data) =>
|
||||
{
|
||||
if (preStartBuffer != null && IsGameStart(data))
|
||||
{
|
||||
writer.Flush();
|
||||
var preStartData = preStartBuffer.ToArray();
|
||||
preStartBuffer = null;
|
||||
StartSavingReplay(preStartData);
|
||||
}
|
||||
|
||||
writer.Write(client);
|
||||
writer.Write(data.Length);
|
||||
writer.Write(data);
|
||||
packetFn(client, data);
|
||||
} );
|
||||
}
|
||||
|
||||
bool IsGameStart(byte[] data)
|
||||
{
|
||||
if (data.Length == 5 && data[4] == 0xbf)
|
||||
return false;
|
||||
if (data.Length >= 5 && data[4] == 0x65)
|
||||
return false;
|
||||
|
||||
var frame = BitConverter.ToInt32(data, 0);
|
||||
return frame == 0 && data.ToOrderList(null).Any(
|
||||
o => o.OrderString == "StartGame");
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if( disposed )
|
||||
return;
|
||||
|
||||
writer.Close();
|
||||
inner.Dispose();
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
~ReplayRecorderConnection()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenRA.Network
|
||||
public int Team;
|
||||
public string Slot; // slot ID, or null for observer
|
||||
public string Bot; // Bot type, null for real clients
|
||||
|
||||
public bool IsAdmin;
|
||||
public bool IsReady { get { return State == ClientState.Ready; } }
|
||||
}
|
||||
|
||||
@@ -64,17 +64,21 @@ namespace OpenRA.Network
|
||||
public bool LockColor;
|
||||
public bool LockTeam;
|
||||
public bool LockSpawn;
|
||||
public bool Required;
|
||||
}
|
||||
|
||||
public class Global
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Ban;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
public int RandomSeed = 0;
|
||||
public bool LockTeams = true; // don't allow team changes after game start.
|
||||
public bool AllowCheats = false;
|
||||
public bool Dedicated;
|
||||
public string Difficulty;
|
||||
}
|
||||
|
||||
public Session(string[] mods)
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace OpenRA.Network
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
|
||||
case "Disconnected": /* reports that the target player disconnected */
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
@@ -59,6 +60,7 @@ namespace OpenRA.Network
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
@@ -69,34 +71,43 @@ namespace OpenRA.Network
|
||||
{
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
order.TargetString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&&
|
||||
(world.LocalPlayer != null &&
|
||||
player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
if (player == null) return;
|
||||
|
||||
if (display)
|
||||
if (world.LocalPlayer != null && player.Stances[world.LocalPlayer] == Stance.Ally || player.WinState == WinState.Lost)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost)
|
||||
? " (Dead)"
|
||||
: " (Team)";
|
||||
var suffix = player.WinState == WinState.Lost ? " (Dead)" : " (Team)";
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "StartGame":
|
||||
{
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case "PauseGame":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if(client != null)
|
||||
{
|
||||
orderManager.GamePaused = !orderManager.GamePaused;
|
||||
var pausetext = "The game is {0} by {1}".F( orderManager.GamePaused ? "paused" : "un-paused", client.Name );
|
||||
Game.AddChatLine(Color.White, "", pausetext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "HandshakeRequest":
|
||||
{
|
||||
var request = HandshakeRequest.Deserialize(order.TargetString);
|
||||
@@ -126,9 +137,11 @@ namespace OpenRA.Network
|
||||
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize()));
|
||||
break;
|
||||
}
|
||||
|
||||
case "ServerError":
|
||||
orderManager.ServerError = order.TargetString;
|
||||
break;
|
||||
|
||||
case "SyncInfo":
|
||||
{
|
||||
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
|
||||
@@ -185,8 +198,7 @@ namespace OpenRA.Network
|
||||
{
|
||||
var oldStance = p.Stances[target];
|
||||
p.Stances[target] = s;
|
||||
if (target == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
|
||||
target.Shroud.UpdatePlayerStance(w, p, oldStance, s);
|
||||
|
||||
foreach (var nsc in w.ActorsWithTrait<INotifyStanceChanged>())
|
||||
nsc.Trait.StanceChanged(nsc.Actor, p, target, oldStance, s);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
@@ -12,9 +12,12 @@
|
||||
<AssemblyName>OpenRA.Game</AssemblyName>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>2.0</OldToolsVersion>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<ApplicationIcon>OpenRA.ico</ApplicationIcon>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
@@ -27,11 +30,8 @@
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<ApplicationIcon>OpenRA.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -44,6 +44,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Optimize>false</Optimize>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@@ -55,11 +56,11 @@
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -79,6 +80,11 @@
|
||||
<Compile Include="ActorInitializer.cs" />
|
||||
<Compile Include="ActorMap.cs" />
|
||||
<Compile Include="ActorReference.cs" />
|
||||
<Compile Include="PSubVec.cs" />
|
||||
<Compile Include="PSubPos.cs" />
|
||||
<Compile Include="PVecInt.cs" />
|
||||
<Compile Include="PVecFloat.cs" />
|
||||
<Compile Include="PPos.cs" />
|
||||
<Compile Include="Download.cs" />
|
||||
<Compile Include="Effects\DelayedAction.cs" />
|
||||
<Compile Include="Effects\FlashTarget.cs" />
|
||||
@@ -88,7 +94,7 @@
|
||||
<Compile Include="GameRules\MusicInfo.cs" />
|
||||
<Compile Include="GameRules\Rules.cs" />
|
||||
<Compile Include="GameRules\Settings.cs" />
|
||||
<Compile Include="GameRules\VoiceInfo.cs" />
|
||||
<Compile Include="GameRules\SoundInfo.cs" />
|
||||
<Compile Include="GameRules\WeaponInfo.cs" />
|
||||
<Compile Include="Graphics\Animation.cs" />
|
||||
<Compile Include="Graphics\AnimationWithOffset.cs" />
|
||||
@@ -115,6 +121,8 @@
|
||||
<Compile Include="Graphics\WorldRenderer.cs" />
|
||||
<Compile Include="Group.cs" />
|
||||
<Compile Include="InputHandler.cs" />
|
||||
<Compile Include="CVec.cs" />
|
||||
<Compile Include="CPos.cs" />
|
||||
<Compile Include="Map.cs" />
|
||||
<Compile Include="ModData.cs" />
|
||||
<Compile Include="Network\Connection.cs" />
|
||||
@@ -143,6 +151,7 @@
|
||||
<Compile Include="Server\Server.cs" />
|
||||
<Compile Include="Server\ServerOrder.cs" />
|
||||
<Compile Include="Server\TraitInterfaces.cs" />
|
||||
<Compile Include="Server\UPnP.cs" />
|
||||
<Compile Include="Sound.cs" />
|
||||
<Compile Include="Support\Arguments.cs" />
|
||||
<Compile Include="Support\PerfHistory.cs" />
|
||||
@@ -151,19 +160,18 @@
|
||||
<Compile Include="TraitDictionary.cs" />
|
||||
<Compile Include="Traits\Activity.cs" />
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Traits\CreatesShroud.cs" />
|
||||
<Compile Include="Traits\DrawLineToTarget.cs" />
|
||||
<Compile Include="Traits\EditorAppearance.cs" />
|
||||
<Compile Include="Traits\EditorTilesetFilter.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Traits\LintAttributes.cs" />
|
||||
<Compile Include="Traits\Player\DeveloperMode.cs" />
|
||||
<Compile Include="Traits\Player\EvaAlerts.cs" />
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="Traits\Render\RenderSimple.cs" />
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Selectable.cs" />
|
||||
<Compile Include="Traits\SelectionDecorations.cs" />
|
||||
<Compile Include="Traits\SubcellInit.cs" />
|
||||
<Compile Include="Traits\Target.cs" />
|
||||
<Compile Include="Traits\TraitsInterfaces.cs" />
|
||||
<Compile Include="Traits\Util.cs" />
|
||||
@@ -186,7 +194,8 @@
|
||||
<Compile Include="Widgets\DropDownButtonWidget.cs" />
|
||||
<Compile Include="Widgets\GridLayout.cs" />
|
||||
<Compile Include="Widgets\ImageWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWidget.cs" />
|
||||
<Compile Include="Widgets\LineGraphWidget.cs" />
|
||||
<Compile Include="Widgets\ListLayout.cs" />
|
||||
<Compile Include="Widgets\MapPreviewWidget.cs" />
|
||||
<Compile Include="Widgets\PasswordFieldWidget.cs" />
|
||||
@@ -206,6 +215,7 @@
|
||||
<Compile Include="Widgets\WorldInteractionControllerWidget.cs" />
|
||||
<Compile Include="World.cs" />
|
||||
<Compile Include="WorldUtils.cs" />
|
||||
<Compile Include="Network\ReplayRecorderConnection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
@@ -214,6 +224,11 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
@@ -229,6 +244,11 @@
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="OpenRA.ico" />
|
||||
|
||||
@@ -48,14 +48,14 @@ namespace OpenRA.Orders
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button != expectedButton)
|
||||
world.CancelInputMode();
|
||||
return OrderInner(world, xy, mi);
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
|
||||
IEnumerable<Order> OrderInner(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == expectedButton && world.Map.IsInMap(xy))
|
||||
{
|
||||
@@ -68,6 +68,6 @@ namespace OpenRA.Orders
|
||||
public virtual void Tick(World world) { }
|
||||
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) { }
|
||||
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace OpenRA
|
||||
{
|
||||
public interface IOrderGenerator
|
||||
{
|
||||
IEnumerable<Order> Order(World world, int2 xy, MouseInput mi);
|
||||
IEnumerable<Order> Order(World world, CPos xy, MouseInput mi);
|
||||
void Tick(World world);
|
||||
void RenderBeforeWorld(WorldRenderer wr, World world);
|
||||
void RenderAfterWorld(WorldRenderer wr, World world);
|
||||
string GetCursor(World world, int2 xy, MouseInput mi);
|
||||
string GetCursor(World world, CPos xy, MouseInput mi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 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,
|
||||
@@ -17,15 +17,11 @@ namespace OpenRA.Orders
|
||||
{
|
||||
class UnitOrderGenerator : IOrderGenerator
|
||||
{
|
||||
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.HasTrait<ITargetable>())
|
||||
.OrderByDescending(
|
||||
a =>
|
||||
a.Info.Traits.Contains<SelectableInfo>()
|
||||
? a.Info.Traits.Get<SelectableInfo>().Priority
|
||||
: int.MinValue)
|
||||
.OrderByDescending(a => a.SelectionPriority())
|
||||
.FirstOrDefault();
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
@@ -45,17 +41,17 @@ namespace OpenRA.Orders
|
||||
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
}
|
||||
|
||||
public void Tick( World world ) { }
|
||||
public void RenderBeforeWorld( WorldRenderer wr, World world ) { }
|
||||
public void RenderAfterWorld( WorldRenderer wr, World world ) { }
|
||||
public void Tick(World world) { }
|
||||
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) { }
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
bool useSelect = false;
|
||||
|
||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||
.Where(a => a.HasTrait<ITargetable>())
|
||||
.OrderByDescending(a => a.Info.Traits.Contains<SelectableInfo>() ? a.Info.Traits.Get<SelectableInfo>().Priority : int.MinValue)
|
||||
.OrderByDescending(a => a.SelectionPriority())
|
||||
.FirstOrDefault();
|
||||
|
||||
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
|
||||
@@ -67,12 +63,11 @@ namespace OpenRA.Orders
|
||||
.Where(o => o != null)
|
||||
.ToArray();
|
||||
|
||||
if( orders.Length == 0 ) return (useSelect) ? "select" : "default";
|
||||
|
||||
return orders[0].cursor ?? ((useSelect) ? "select" : "default");
|
||||
var cursorName = orders.Select(o => o.cursor).FirstOrDefault();
|
||||
return cursorName ?? (useSelect ? "select" : "default");
|
||||
}
|
||||
|
||||
static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor )
|
||||
static UnitOrderResult OrderForUnit(Actor self, CPos xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return null;
|
||||
@@ -80,35 +75,35 @@ namespace OpenRA.Orders
|
||||
if (self.Destroyed)
|
||||
return null;
|
||||
|
||||
if( mi.Button == MouseButton.Right )
|
||||
if (mi.Button == Game.mouseButtonPreference.Action)
|
||||
{
|
||||
foreach( var o in self.TraitsImplementing<IIssueOrder>()
|
||||
.SelectMany( trait => trait.Orders
|
||||
.Select( x => new { Trait = trait, Order = x } ) )
|
||||
.OrderByDescending( x => x.Order.OrderPriority ) )
|
||||
.SelectMany(trait => trait.Orders
|
||||
.Select(x => new { Trait = trait, Order = x } ))
|
||||
.OrderByDescending(x => x.Order.OrderPriority))
|
||||
{
|
||||
var actorsAt = self.World.ActorMap.GetUnitsAt( xy ).ToList();
|
||||
var actorsAt = self.World.ActorMap.GetUnitsAt(xy).ToList();
|
||||
|
||||
var forceAttack = mi.Modifiers.HasModifier(Modifiers.Ctrl);
|
||||
var forceQueue = mi.Modifiers.HasModifier(Modifiers.Shift);
|
||||
string cursor = null;
|
||||
if( underCursor != null )
|
||||
if (underCursor != null)
|
||||
if (o.Order.CanTargetActor(self, underCursor, forceAttack, forceQueue, ref cursor))
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) );
|
||||
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromActor(underCursor));
|
||||
if (o.Order.CanTargetLocation(self, xy, actorsAt, forceAttack, forceQueue, ref cursor))
|
||||
return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) );
|
||||
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromCell(xy));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Order CheckSameOrder( IOrderTargeter iot, Order order )
|
||||
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 );
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -120,7 +115,7 @@ namespace OpenRA.Orders
|
||||
public readonly string cursor;
|
||||
public readonly Target target;
|
||||
|
||||
public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target )
|
||||
public UnitOrderResult(Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target)
|
||||
{
|
||||
this.self = self;
|
||||
this.iot = iot;
|
||||
@@ -130,4 +125,13 @@ namespace OpenRA.Orders
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SelectableExts
|
||||
{
|
||||
public static int SelectionPriority(this Actor a)
|
||||
{
|
||||
var selectableInfo = a.Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
return selectableInfo != null ? selectableInfo.Priority : int.MinValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
71
OpenRA.Game/PPos.cs
Normal file
71
OpenRA.Game/PPos.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Pixel coordinate position in the world (fine).
|
||||
/// </summary>
|
||||
public struct PPos
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public PPos(int x, int y) { X = x; Y = y; }
|
||||
|
||||
public static readonly PPos Zero = new PPos(0, 0);
|
||||
|
||||
public static explicit operator PPos(int2 a) { return new PPos(a.X, a.Y); }
|
||||
|
||||
public static explicit operator PVecInt(PPos a) { return new PVecInt(a.X, a.Y); }
|
||||
public static explicit operator PVecFloat(PPos a) { return new PVecFloat(a.X, a.Y); }
|
||||
|
||||
public static PPos operator +(PPos a, PVecInt b) { return new PPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static PVecInt operator -(PPos a, PPos b) { return new PVecInt(a.X - b.X, a.Y - b.Y); }
|
||||
public static PPos operator -(PPos a, PVecInt b) { return new PPos(a.X - b.X, a.Y - b.Y); }
|
||||
|
||||
public static bool operator ==(PPos me, PPos other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(PPos me, PPos other) { return !(me == other); }
|
||||
|
||||
public static PPos Max(PPos a, PPos b) { return new PPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static PPos Min(PPos a, PPos b) { return new PPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static PPos Lerp(PPos a, PPos b, int mul, int div)
|
||||
{
|
||||
return a + ((PVecInt)(b - a) * mul / div);
|
||||
}
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
public CPos ToCPos() { return new CPos((int)(1f / Game.CellSize * X), (int)(1f / Game.CellSize * Y)); }
|
||||
public PSubPos ToPSubPos() { return new PSubPos(X * PSubPos.PerPx, Y * PSubPos.PerPx); }
|
||||
|
||||
public PPos Clamp(Rectangle r)
|
||||
{
|
||||
return new PPos(Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
PPos o = (PPos)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
}
|
||||
}
|
||||
73
OpenRA.Game/PSubPos.cs
Normal file
73
OpenRA.Game/PSubPos.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Sub-pixel coordinate position in the world (very fine).
|
||||
/// </summary>
|
||||
public struct PSubPos
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public PSubPos(int x, int y) { X = x; Y = y; }
|
||||
|
||||
public const int PerPx = 1024;
|
||||
|
||||
public static readonly PSubPos Zero = new PSubPos(0, 0);
|
||||
|
||||
public static explicit operator PSubPos(int2 a) { return new PSubPos(a.X, a.Y); }
|
||||
|
||||
public static explicit operator PSubVec(PSubPos a) { return new PSubVec(a.X, a.Y); }
|
||||
public static explicit operator PVecFloat(PSubPos a) { return new PVecFloat(a.X, a.Y); }
|
||||
|
||||
public static PSubPos operator +(PSubPos a, PSubVec b) { return new PSubPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static PSubVec operator -(PSubPos a, PSubPos b) { return new PSubVec(a.X - b.X, a.Y - b.Y); }
|
||||
public static PSubPos operator -(PSubPos a, PSubVec b) { return new PSubPos(a.X - b.X, a.Y - b.Y); }
|
||||
|
||||
public static bool operator ==(PSubPos me, PSubPos other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(PSubPos me, PSubPos other) { return !(me == other); }
|
||||
|
||||
public static PSubPos Max(PSubPos a, PSubPos b) { return new PSubPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static PSubPos Min(PSubPos a, PSubPos b) { return new PSubPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static PSubPos Lerp(PSubPos a, PSubPos b, int mul, int div)
|
||||
{
|
||||
return a + ((PSubVec)(b - a) * mul / div);
|
||||
}
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
public PPos ToPPos() { return new PPos(X / PerPx, Y / PerPx); }
|
||||
public CPos ToCPos() { return ToPPos().ToCPos(); }
|
||||
|
||||
public PSubPos Clamp(Rectangle r)
|
||||
{
|
||||
return new PSubPos(Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
PSubPos o = (PSubPos)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
}
|
||||
}
|
||||
103
OpenRA.Game/PSubVec.cs
Normal file
103
OpenRA.Game/PSubVec.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Sub-pixel coordinate vector (very fine)
|
||||
/// </summary>
|
||||
public struct PSubVec
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public PSubVec(int x, int y) { X = x; Y = y; }
|
||||
public PSubVec(Size p) { X = p.Width; Y = p.Height; }
|
||||
|
||||
public static readonly PSubVec Zero = new PSubVec(0, 0);
|
||||
public static PSubVec OneCell { get { return new PSubVec(Game.CellSize, Game.CellSize); } }
|
||||
|
||||
public static explicit operator PSubVec(int2 a) { return new PSubVec(a.X, a.Y); }
|
||||
public static explicit operator PSubVec(float2 a) { return new PSubVec((int)a.X, (int)a.Y); }
|
||||
|
||||
public static PSubVec FromRadius(int r) { return new PSubVec(r, r); }
|
||||
|
||||
public static PSubVec operator +(PSubVec a, PSubVec b) { return new PSubVec(a.X + b.X, a.Y + b.Y); }
|
||||
public static PSubVec operator -(PSubVec a, PSubVec b) { return new PSubVec(a.X - b.X, a.Y - b.Y); }
|
||||
public static PSubVec operator *(int a, PSubVec b) { return new PSubVec(a * b.X, a * b.Y); }
|
||||
public static PSubVec operator *(PSubVec b, int a) { return new PSubVec(a * b.X, a * b.Y); }
|
||||
public static PSubVec operator /(PSubVec a, int b) { return new PSubVec(a.X / b, a.Y / b); }
|
||||
|
||||
public static PSubVec operator -(PSubVec a) { return new PSubVec(-a.X, -a.Y); }
|
||||
|
||||
public static bool operator ==(PSubVec me, PSubVec other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(PSubVec me, PSubVec other) { return !(me == other); }
|
||||
|
||||
public static PSubVec Max(PSubVec a, PSubVec b) { return new PSubVec(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static PSubVec Min(PSubVec a, PSubVec b) { return new PSubVec(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static int Dot(PSubVec a, PSubVec b) { return a.X * b.X + a.Y * b.Y; }
|
||||
|
||||
public PSubVec Sign() { return new PSubVec(Math.Sign(X), Math.Sign(Y)); }
|
||||
public PSubVec Abs() { return new PSubVec(Math.Abs(X), Math.Abs(Y)); }
|
||||
public int LengthSquared { get { return X * X + Y * Y; } }
|
||||
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
public PVecInt ToPVecInt() { return new PVecInt(X / PSubPos.PerPx, Y / PSubPos.PerPx); }
|
||||
|
||||
public PSubVec Clamp(Rectangle r)
|
||||
{
|
||||
return new PSubVec(
|
||||
Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top))
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
PSubVec o = (PSubVec)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
}
|
||||
|
||||
public static class PSubVecExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Scales the float2 vector up to a subpixel vector.
|
||||
/// </summary>
|
||||
/// <param name="vec"></param>
|
||||
/// <returns></returns>
|
||||
public static PSubVec ToPSubVec(this float2 vec)
|
||||
{
|
||||
return new PSubVec((int)(vec.X * PSubPos.PerPx), (int)(vec.Y * PSubPos.PerPx));
|
||||
}
|
||||
|
||||
public static PSubVec ToPSubVec(this PVecInt vec)
|
||||
{
|
||||
return new PSubVec((vec.X * PSubPos.PerPx), (vec.Y * PSubPos.PerPx));
|
||||
}
|
||||
|
||||
public static PSubVec ToPSubVec(this PVecFloat vec)
|
||||
{
|
||||
return new PSubVec((int)(vec.X * PSubPos.PerPx), (int)(vec.Y * PSubPos.PerPx));
|
||||
}
|
||||
}
|
||||
}
|
||||
97
OpenRA.Game/PVecFloat.cs
Normal file
97
OpenRA.Game/PVecFloat.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Pixel coordinate vector (fine; float)
|
||||
/// </summary>
|
||||
public struct PVecFloat
|
||||
{
|
||||
public readonly float X, Y;
|
||||
|
||||
public PVecFloat(float x, float y) { X = x; Y = y; }
|
||||
public PVecFloat(Size p) { X = p.Width; Y = p.Height; }
|
||||
|
||||
public static readonly PVecFloat Zero = new PVecFloat(0, 0);
|
||||
|
||||
public static explicit operator PVecInt(PVecFloat a) { return new PVecInt((int)a.X, (int)a.Y); }
|
||||
public static explicit operator PVecFloat(float2 a) { return new PVecFloat(a.X, a.Y); }
|
||||
|
||||
public static PVecFloat operator +(PVecFloat a, PVecFloat b) { return new PVecFloat(a.X + b.X, a.Y + b.Y); }
|
||||
public static PVecFloat operator -(PVecFloat a, PVecFloat b) { return new PVecFloat(a.X - b.X, a.Y - b.Y); }
|
||||
public static PVecFloat operator *(float a, PVecFloat b) { return new PVecFloat(a * b.X, a * b.Y); }
|
||||
public static PVecFloat operator *(PVecFloat b, float a) { return new PVecFloat(a * b.X, a * b.Y); }
|
||||
public static PVecFloat operator /(PVecFloat a, float b) { return new PVecFloat(a.X / b, a.Y / b); }
|
||||
|
||||
public static PVecFloat operator -(PVecFloat a) { return new PVecFloat(-a.X, -a.Y); }
|
||||
|
||||
public static bool operator ==(PVecFloat me, PVecFloat other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(PVecFloat me, PVecFloat other) { return !(me == other); }
|
||||
|
||||
public static PVecFloat Max(PVecFloat a, PVecFloat b) { return new PVecFloat(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static PVecFloat Min(PVecFloat a, PVecFloat b) { return new PVecFloat(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static float Dot(PVecFloat a, PVecFloat b) { return a.X * b.X + a.Y * b.Y; }
|
||||
|
||||
public static PVecFloat FromAngle(float a) { return new PVecFloat((float)Math.Sin(a), (float)Math.Cos(a)); }
|
||||
|
||||
public static PVecFloat Lerp(PVecFloat a, PVecFloat b, float t)
|
||||
{
|
||||
return new PVecFloat(
|
||||
float2.Lerp(a.X, b.X, t),
|
||||
float2.Lerp(a.Y, b.Y, t)
|
||||
);
|
||||
}
|
||||
|
||||
public static PVecFloat Lerp(PVecFloat a, PVecFloat b, PVecFloat t)
|
||||
{
|
||||
return new PVecFloat(
|
||||
float2.Lerp(a.X, b.X, t.X),
|
||||
float2.Lerp(a.Y, b.Y, t.Y)
|
||||
);
|
||||
}
|
||||
|
||||
public PVecFloat Sign() { return new PVecFloat(Math.Sign(X), Math.Sign(Y)); }
|
||||
public PVecFloat Abs() { return new PVecFloat(Math.Abs(X), Math.Abs(Y)); }
|
||||
public PVecFloat Round() { return new PVecFloat((float)Math.Round(X), (float)Math.Round(Y)); }
|
||||
public float LengthSquared { get { return X * X + Y * Y; } }
|
||||
public float Length { get { return (float)Math.Sqrt(LengthSquared); } }
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2((int)X, (int)Y); }
|
||||
|
||||
static float Constrain(float x, float a, float b) { return x < a ? a : x > b ? b : x; }
|
||||
|
||||
public PVecFloat Constrain(PVecFloat min, PVecFloat max)
|
||||
{
|
||||
return new PVecFloat(
|
||||
Constrain(X, min.X, max.X),
|
||||
Constrain(Y, min.Y, max.Y)
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
PVecFloat o = (PVecFloat)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "({0},{1})".F(X, Y); }
|
||||
}
|
||||
}
|
||||
80
OpenRA.Game/PVecInt.cs
Normal file
80
OpenRA.Game/PVecInt.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
/// Pixel coordinate vector (fine; integer)
|
||||
/// </summary>
|
||||
public struct PVecInt
|
||||
{
|
||||
public readonly int X, Y;
|
||||
|
||||
public PVecInt(int x, int y) { X = x; Y = y; }
|
||||
public PVecInt(Size p) { X = p.Width; Y = p.Height; }
|
||||
|
||||
public static readonly PVecInt Zero = new PVecInt(0, 0);
|
||||
public static PVecInt OneCell { get { return new PVecInt(Game.CellSize, Game.CellSize); } }
|
||||
|
||||
public static implicit operator PVecFloat(PVecInt a) { return new PVecFloat((float)a.X, (float)a.Y); }
|
||||
public static explicit operator PVecInt(int2 a) { return new PVecInt(a.X, a.Y); }
|
||||
|
||||
public static PVecInt FromRadius(int r) { return new PVecInt(r, r); }
|
||||
|
||||
public static PVecInt operator +(PVecInt a, PVecInt b) { return new PVecInt(a.X + b.X, a.Y + b.Y); }
|
||||
public static PVecInt operator -(PVecInt a, PVecInt b) { return new PVecInt(a.X - b.X, a.Y - b.Y); }
|
||||
public static PVecInt operator *(int a, PVecInt b) { return new PVecInt(a * b.X, a * b.Y); }
|
||||
public static PVecInt operator *(PVecInt b, int a) { return new PVecInt(a * b.X, a * b.Y); }
|
||||
public static PVecInt operator /(PVecInt a, int b) { return new PVecInt(a.X / b, a.Y / b); }
|
||||
|
||||
public static PVecInt operator -(PVecInt a) { return new PVecInt(-a.X, -a.Y); }
|
||||
|
||||
public static bool operator ==(PVecInt me, PVecInt other) { return (me.X == other.X && me.Y == other.Y); }
|
||||
public static bool operator !=(PVecInt me, PVecInt other) { return !(me == other); }
|
||||
|
||||
public static PVecInt Max(PVecInt a, PVecInt b) { return new PVecInt(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static PVecInt Min(PVecInt a, PVecInt b) { return new PVecInt(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
|
||||
public static int Dot(PVecInt a, PVecInt b) { return a.X * b.X + a.Y * b.Y; }
|
||||
|
||||
public PVecInt Sign() { return new PVecInt(Math.Sign(X), Math.Sign(Y)); }
|
||||
public PVecInt Abs() { return new PVecInt(Math.Abs(X), Math.Abs(Y)); }
|
||||
public int LengthSquared { get { return X * X + Y * Y; } }
|
||||
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
|
||||
|
||||
public float2 ToFloat2() { return new float2(X, Y); }
|
||||
public int2 ToInt2() { return new int2(X, Y); }
|
||||
public CVec ToCVec() { return new CVec(X / Game.CellSize, Y / Game.CellSize); }
|
||||
|
||||
public PVecInt Clamp(Rectangle r)
|
||||
{
|
||||
return new PVecInt(
|
||||
Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top))
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
PVecInt o = (PVecInt)obj;
|
||||
return o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA
|
||||
public readonly PlayerReference PlayerReference;
|
||||
public bool IsBot;
|
||||
|
||||
public Shroud Shroud { get { return World.LocalShroud; } }
|
||||
public Shroud Shroud;
|
||||
public World World { get; private set; }
|
||||
|
||||
static CountryInfo ChooseCountry(World world, string name)
|
||||
@@ -76,7 +76,8 @@ namespace OpenRA
|
||||
Country = ChooseCountry(world, pr.Race);
|
||||
}
|
||||
PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) });
|
||||
|
||||
Shroud = PlayerActor.Trait<Shroud>();
|
||||
Shroud.Owner = this;
|
||||
// Enable the bot logic on the host
|
||||
IsBot = botType != null;
|
||||
if (IsBot && Game.IsHost)
|
||||
@@ -90,11 +91,6 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public void GiveAdvice(string advice)
|
||||
{
|
||||
Sound.PlayToPlayer(this, advice);
|
||||
}
|
||||
|
||||
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ namespace OpenRA
|
||||
if (actors.Count == 0)
|
||||
return;
|
||||
|
||||
controlGroups[group].Clear();
|
||||
if (!mods.HasModifier(Modifiers.Shift))
|
||||
controlGroups[group].Clear();
|
||||
|
||||
for (var i = 0; i < 10; i++) /* all control groups */
|
||||
controlGroups[i].RemoveAll(a => actors.Contains(a));
|
||||
|
||||
@@ -44,6 +44,11 @@ namespace OpenRA.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
// NOTE(jsd): Poll the socket first to see if there's anything there.
|
||||
// This avoids the exception with SocketErrorCode == `SocketError.WouldBlock` thrown
|
||||
// from `socket.Receive(rx)`.
|
||||
if (!socket.Poll(0, SelectMode.SelectRead)) break;
|
||||
|
||||
if (0 < (len = socket.Receive(rx)))
|
||||
data.AddRange(rx.Take(len));
|
||||
else
|
||||
@@ -52,11 +57,12 @@ namespace OpenRA.Server
|
||||
server.DropClient(this);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// NOTE(jsd): This should no longer be needed with the socket.Poll call above.
|
||||
if (e.SocketErrorCode == SocketError.WouldBlock) break;
|
||||
|
||||
server.DropClient(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -15,13 +15,24 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.NetworkInformation;
|
||||
using UPnP;
|
||||
using System.Threading;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Network;
|
||||
|
||||
using XTimer = System.Timers.Timer;
|
||||
|
||||
namespace OpenRA.Server
|
||||
{
|
||||
public enum ServerState : int
|
||||
{
|
||||
WaitingPlayers = 1,
|
||||
GameStarted = 2,
|
||||
ShuttingDown = 3
|
||||
}
|
||||
|
||||
public class Server
|
||||
{
|
||||
// Valid player connections
|
||||
@@ -36,22 +47,42 @@ namespace OpenRA.Server
|
||||
|
||||
TypeDictionary ServerTraits = new TypeDictionary();
|
||||
public Session lobbyInfo;
|
||||
public bool GameStarted = false;
|
||||
|
||||
public readonly IPAddress Ip;
|
||||
public readonly int Port;
|
||||
int randomSeed;
|
||||
public readonly Thirdparty.Random Random = new Thirdparty.Random();
|
||||
|
||||
public ServerSettings Settings;
|
||||
public ModData ModData;
|
||||
public Map Map;
|
||||
XTimer gameTimeout;
|
||||
|
||||
volatile bool shutdown = false;
|
||||
public void Shutdown() { shutdown = true; }
|
||||
protected volatile ServerState pState = new ServerState();
|
||||
public ServerState State
|
||||
{
|
||||
get { return pState; }
|
||||
protected set { pState = value; }
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
State = ServerState.ShuttingDown;
|
||||
}
|
||||
|
||||
public void EndGame()
|
||||
{
|
||||
foreach (var t in ServerTraits.WithInterface<IEndGame>())
|
||||
t.GameEnded(this);
|
||||
if (Settings.AllowUPnP)
|
||||
RemovePortforward();
|
||||
}
|
||||
|
||||
public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
|
||||
{
|
||||
Log.AddChannel("server", "server.log");
|
||||
|
||||
pState = ServerState.WaitingPlayers;
|
||||
listener = new TcpListener(endpoint);
|
||||
listener.Start();
|
||||
var localEndpoint = (IPEndPoint)listener.LocalEndpoint;
|
||||
@@ -63,6 +94,44 @@ namespace OpenRA.Server
|
||||
|
||||
randomSeed = (int)DateTime.Now.ToBinary();
|
||||
|
||||
if (Settings.AllowUPnP)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UPnP.NAT.Discover())
|
||||
{
|
||||
Log.Write("server", "UPnP-enabled router discovered.");
|
||||
Log.Write("server", "Your IP is: {0}", UPnP.NAT.GetExternalIP() );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Write("server", "No UPnP-enabled router detected.");
|
||||
Settings.AllowUPnP = false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OpenRA.Log.Write("server", "Can't discover UPnP-enabled routers: {0}", e);
|
||||
Settings.AllowUPnP = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Settings.AllowUPnP)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UPnP.NAT.ForwardPort(Port, ProtocolType.Tcp, "OpenRA"))
|
||||
Log.Write("server", "Port {0} (TCP) has been forwarded.", Port);
|
||||
else
|
||||
Settings.AllowUPnP = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OpenRA.Log.Write("server", "Can not forward ports via UPnP: {0}", e);
|
||||
Settings.AllowUPnP = false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var trait in modData.Manifest.ServerTraits)
|
||||
ServerTraits.Add( modData.ObjectCreator.CreateObject<ServerTrait>(trait) );
|
||||
|
||||
@@ -70,6 +139,8 @@ namespace OpenRA.Server
|
||||
lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
|
||||
lobbyInfo.GlobalSettings.Map = settings.Map;
|
||||
lobbyInfo.GlobalSettings.ServerName = settings.Name;
|
||||
lobbyInfo.GlobalSettings.Ban = settings.Ban;
|
||||
lobbyInfo.GlobalSettings.Dedicated = settings.Dedicated;
|
||||
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerStart>())
|
||||
t.ServerStarted(this);
|
||||
@@ -91,8 +162,11 @@ namespace OpenRA.Server
|
||||
foreach( var c in preConns ) checkRead.Add( c.socket );
|
||||
|
||||
Socket.Select( checkRead, null, null, timeout );
|
||||
if (shutdown)
|
||||
if (State == ServerState.ShuttingDown)
|
||||
{
|
||||
EndGame();
|
||||
break;
|
||||
}
|
||||
|
||||
foreach( Socket s in checkRead )
|
||||
if( s == listener.Server ) AcceptConnection();
|
||||
@@ -106,11 +180,13 @@ namespace OpenRA.Server
|
||||
foreach (var t in ServerTraits.WithInterface<ITick>())
|
||||
t.Tick(this);
|
||||
|
||||
if (shutdown)
|
||||
if (State == ServerState.ShuttingDown)
|
||||
{
|
||||
EndGame();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GameStarted = false;
|
||||
foreach (var t in ServerTraits.WithInterface<INotifyServerShutdown>())
|
||||
t.ServerShutdown(this);
|
||||
|
||||
@@ -119,21 +195,30 @@ namespace OpenRA.Server
|
||||
try { listener.Stop(); }
|
||||
catch { }
|
||||
} ) { IsBackground = true }.Start();
|
||||
|
||||
}
|
||||
|
||||
void RemovePortforward()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UPnP.NAT.DeleteForwardingRule(Port, ProtocolType.Tcp))
|
||||
Log.Write("server", "Port {0} (TCP) forwarding rules has been removed.", Port);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OpenRA.Log.Write("server", "Can not remove UPnP portforwarding rules: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* lobby rework todo:
|
||||
* - "teams together" option for team games -- will eliminate most need
|
||||
* for manual spawnpoint choosing.
|
||||
* - 256 max players is a dirty hack
|
||||
*/
|
||||
int nextPlayerIndex = 0;
|
||||
public int ChooseFreePlayerIndex()
|
||||
{
|
||||
for (var i = 0; i < 256; i++)
|
||||
if (conns.All(c => c.PlayerIndex != i) && preConns.All(c => c.PlayerIndex != i)
|
||||
&& lobbyInfo.Clients.All(c => c.Index != i))
|
||||
return i;
|
||||
|
||||
throw new InvalidOperationException("Already got 256 players");
|
||||
return nextPlayerIndex++;
|
||||
}
|
||||
|
||||
void AcceptConnection()
|
||||
@@ -179,7 +264,7 @@ namespace OpenRA.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
if (GameStarted)
|
||||
if (State == ServerState.GameStarted)
|
||||
{
|
||||
Log.Write("server", "Rejected connection from {0}; game is already started.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
@@ -193,11 +278,12 @@ namespace OpenRA.Server
|
||||
var client = handshake.Client;
|
||||
var mods = handshake.Mods;
|
||||
|
||||
// Check that the client has compatable mods
|
||||
// Check that the client has compatible mods
|
||||
var valid = mods.All( m => m.Contains('@')) && //valid format
|
||||
mods.Count() == Game.CurrentMods.Count() && //same number
|
||||
mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1])).All(kv => Game.CurrentMods.ContainsKey(kv.First) &&
|
||||
(kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version));
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
Log.Write("server", "Rejected connection from {0}; mods do not match.",
|
||||
@@ -207,6 +293,32 @@ namespace OpenRA.Server
|
||||
DropClient(newConn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop DEV_VERSION if it's a Dedicated
|
||||
if ( lobbyInfo.GlobalSettings.Dedicated && mods.Any(m => m.Contains("{DEV_VERSION}")) )
|
||||
{
|
||||
Log.Write("server", "Rejected connection from {0}; DEV_VERSION is not allowed here.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
|
||||
SendOrderTo(newConn, "ServerError", "DEV_VERSION is not allowed here");
|
||||
DropClient(newConn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if IP is banned
|
||||
if (lobbyInfo.GlobalSettings.Ban != null)
|
||||
{
|
||||
var remote_addr = ((IPEndPoint)newConn.socket.RemoteEndPoint).Address.ToString();
|
||||
if (lobbyInfo.GlobalSettings.Ban.Contains(remote_addr))
|
||||
{
|
||||
Console.WriteLine("Rejected connection from "+client.Name+"("+newConn.socket.RemoteEndPoint+"); Banned.");
|
||||
Log.Write("server", "Rejected connection from {0}; Banned.",
|
||||
newConn.socket.RemoteEndPoint);
|
||||
SendOrderTo(newConn, "ServerError", "You are banned from the server!");
|
||||
DropClient(newConn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Promote connection to a valid client
|
||||
preConns.Remove(newConn);
|
||||
@@ -220,7 +332,12 @@ namespace OpenRA.Server
|
||||
SyncClientToPlayerReference(client, Map.Players[client.Slot]);
|
||||
|
||||
lobbyInfo.Clients.Add(client);
|
||||
//Assume that first validated client is server admin
|
||||
if(lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count()==1)
|
||||
client.IsAdmin=true;
|
||||
|
||||
OpenRA.Network.Session.Client clientAdmin = lobbyInfo.Clients.Where(c1 => c1.IsAdmin).Single();
|
||||
|
||||
Log.Write("server", "Client {0}: Accepted connection from {1}",
|
||||
newConn.PlayerIndex, newConn.socket.RemoteEndPoint);
|
||||
|
||||
@@ -229,6 +346,24 @@ namespace OpenRA.Server
|
||||
|
||||
SyncLobbyInfo();
|
||||
SendChat(newConn, "has joined the game.");
|
||||
|
||||
if ( File.Exists("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0])) )
|
||||
{
|
||||
var motd = System.IO.File.ReadAllText("{0}motd_{1}.txt".F(Platform.SupportDir, lobbyInfo.GlobalSettings.Mods[0]));
|
||||
SendChatTo(newConn, motd);
|
||||
}
|
||||
|
||||
if ( lobbyInfo.GlobalSettings.Dedicated )
|
||||
{
|
||||
if (client.IsAdmin)
|
||||
SendChatTo(newConn, " You are admin now!");
|
||||
else
|
||||
SendChatTo(newConn, " Current admin is {0}".F(clientAdmin.Name));
|
||||
}
|
||||
|
||||
if (mods.Any(m => m.Contains("{DEV_VERSION}")))
|
||||
SendChat(newConn, "is running a development version, "+
|
||||
"and may cause desync if they have any incompatible changes.");
|
||||
}
|
||||
catch (Exception) { DropClient(newConn); }
|
||||
}
|
||||
@@ -328,6 +463,9 @@ namespace OpenRA.Server
|
||||
|
||||
void InterpretServerOrder(Connection conn, ServerOrder so)
|
||||
{
|
||||
var fromClient = GetClient(conn);
|
||||
var fromIndex = fromClient != null ? fromClient.Index : 0;
|
||||
|
||||
switch (so.Name)
|
||||
{
|
||||
case "Command":
|
||||
@@ -343,17 +481,23 @@ namespace OpenRA.Server
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "HandshakeResponse":
|
||||
ValidateClient(conn, so.Data);
|
||||
break;
|
||||
|
||||
case "Chat":
|
||||
case "TeamChat":
|
||||
var fromClient = GetClient(conn);
|
||||
var fromIndex = fromClient != null ? fromClient.Index : 0;
|
||||
|
||||
foreach (var c in conns.Except(conn).ToArray())
|
||||
DispatchOrdersToClient(c, fromIndex, 0, so.Serialize());
|
||||
break;
|
||||
break;
|
||||
|
||||
case "PauseRequest":
|
||||
foreach (var c in conns.ToArray())
|
||||
{ var x = Order.PauseGame();
|
||||
DispatchOrdersToClient(c, fromIndex, 0, x.Serialize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,15 +514,29 @@ namespace OpenRA.Server
|
||||
{
|
||||
conns.Remove(toDrop);
|
||||
SendChat(toDrop, "Connection Dropped");
|
||||
|
||||
if (GameStarted)
|
||||
|
||||
OpenRA.Network.Session.Client dropClient = lobbyInfo.Clients.Where(c1 => c1.Index == toDrop.PlayerIndex).Single();
|
||||
|
||||
if (State == ServerState.GameStarted)
|
||||
SendDisconnected(toDrop); /* Report disconnection */
|
||||
|
||||
lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
|
||||
|
||||
// reassign admin if necessary
|
||||
if ( lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
|
||||
{
|
||||
if (lobbyInfo.Clients.Where(c1 => c1.Bot == null).Count() > 0)
|
||||
{
|
||||
// client was not alone on the server but he was admin: set admin to the last connected client
|
||||
OpenRA.Network.Session.Client lastClient = lobbyInfo.Clients.Where(c1 => c1.Bot == null).Last();
|
||||
lastClient.IsAdmin = true;
|
||||
SendChat(toDrop, "Admin left! {0} is a new admin now!".F(lastClient.Name));
|
||||
}
|
||||
}
|
||||
|
||||
DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } );
|
||||
|
||||
if (conns.Count != 0)
|
||||
if (conns.Count != 0 || lobbyInfo.GlobalSettings.Dedicated)
|
||||
SyncLobbyInfo();
|
||||
}
|
||||
|
||||
@@ -391,7 +549,7 @@ namespace OpenRA.Server
|
||||
|
||||
public void SyncLobbyInfo()
|
||||
{
|
||||
if (!GameStarted) /* don't do this while the game is running, it breaks things. */
|
||||
if (State != ServerState.GameStarted) /* don't do this while the game is running, it breaks things. */
|
||||
DispatchOrders(null, 0,
|
||||
new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize());
|
||||
|
||||
@@ -401,13 +559,17 @@ namespace OpenRA.Server
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
GameStarted = true;
|
||||
State = ServerState.GameStarted;
|
||||
listener.Stop();
|
||||
|
||||
Console.WriteLine("Game started");
|
||||
|
||||
foreach( var c in conns )
|
||||
foreach( var d in conns )
|
||||
DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } );
|
||||
|
||||
// Drop any unvalidated clients
|
||||
foreach (var c in preConns)
|
||||
foreach (var c in preConns.ToArray())
|
||||
DropClient(c);
|
||||
|
||||
DispatchOrders(null, 0,
|
||||
@@ -415,6 +577,18 @@ namespace OpenRA.Server
|
||||
|
||||
foreach (var t in ServerTraits.WithInterface<IStartGame>())
|
||||
t.GameStarted(this);
|
||||
|
||||
// Check TimeOut
|
||||
if ( Settings.TimeOut > 10000 )
|
||||
{
|
||||
gameTimeout = new XTimer(Settings.TimeOut);
|
||||
gameTimeout.Elapsed += (_,e) =>
|
||||
{
|
||||
Console.WriteLine("Timeout at {0}!!!", e.SignalTime);
|
||||
Environment.Exit(0);
|
||||
};
|
||||
gameTimeout.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenRA.Server
|
||||
public interface INotifyServerShutdown { void ServerShutdown(Server server); }
|
||||
public interface IStartGame { void GameStarted(Server server); }
|
||||
public interface IClientJoined { void ClientJoined(Server server, Connection conn); }
|
||||
public interface IEndGame { void GameEnded(Server server); }
|
||||
public interface ITick
|
||||
{
|
||||
void Tick(Server server);
|
||||
@@ -28,7 +29,7 @@ namespace OpenRA.Server
|
||||
|
||||
public abstract class ServerTrait {}
|
||||
|
||||
public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown
|
||||
public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown, IEndGame
|
||||
{
|
||||
public bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd)
|
||||
{
|
||||
@@ -55,5 +56,10 @@ namespace OpenRA.Server
|
||||
{
|
||||
Console.WriteLine("ServerShutdown()");
|
||||
}
|
||||
|
||||
public void GameEnded(Server server)
|
||||
{
|
||||
Console.WriteLine("GameEnded()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
163
OpenRA.Game/Server/UPnP.cs
Normal file
163
OpenRA.Game/Server/UPnP.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2008-2009 http://www.codeproject.com/Members/Harold-Aptroot
|
||||
* Source: http://www.codeproject.com/Articles/27992/NAT-Traversal-with-UPnP-in-C
|
||||
* This file is licensed under A Public Domain dedication.
|
||||
* For more information, see http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
|
||||
namespace UPnP
|
||||
{
|
||||
public class NAT
|
||||
{
|
||||
static string _serviceUrl;
|
||||
|
||||
public static bool Discover()
|
||||
{
|
||||
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||
s.ReceiveTimeout = 3000; //3 seconds
|
||||
string req = "M-SEARCH * HTTP/1.1\r\n" +
|
||||
"HOST: 239.255.255.250:1900\r\n" +
|
||||
"ST:upnp:rootdevice\r\n" +
|
||||
"MAN:\"ssdp:discover\"\r\n" +
|
||||
"MX:3\r\n\r\n";
|
||||
byte[] data = Encoding.ASCII.GetBytes(req);
|
||||
IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
|
||||
byte[] buffer = new byte[0x1000];
|
||||
|
||||
try
|
||||
{
|
||||
s.SendTo(data, ipe);
|
||||
int length = 0;
|
||||
do
|
||||
{
|
||||
length = s.Receive(buffer);
|
||||
|
||||
string resp = Encoding.ASCII.GetString(buffer, 0, length).ToLower();
|
||||
if (resp.Contains("upnp:rootdevice"))
|
||||
{
|
||||
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
|
||||
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
|
||||
if (!string.IsNullOrEmpty(_serviceUrl = GetServiceUrl(resp)))
|
||||
{
|
||||
s.Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while (length > 0);
|
||||
s.Close();
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
s.Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String GetServiceUrl(string resp)
|
||||
{
|
||||
XmlDocument desc = new XmlDocument();
|
||||
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(resp);
|
||||
r.KeepAlive = false;
|
||||
using (WebResponse wres = r.GetResponse())
|
||||
{
|
||||
using (Stream ress = wres.GetResponseStream())
|
||||
{
|
||||
desc.Load(ress);
|
||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
|
||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
|
||||
if (!typen.Value.Contains("InternetGatewayDevice"))
|
||||
return null;
|
||||
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
|
||||
if (node == null)
|
||||
return null;
|
||||
Uri respUri = new Uri(resp);
|
||||
Uri combinedUri = new Uri(respUri, node.Value);
|
||||
return combinedUri.AbsoluteUri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ForwardPort(int port, ProtocolType protocol, string description)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
string body = String.Format("<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"+
|
||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
||||
"<NewProtocol>{1}</NewProtocol><NewInternalPort>{0}</NewInternalPort>" +
|
||||
"<NewInternalClient>{2}</NewInternalClient><NewEnabled>1</NewEnabled>" +
|
||||
"<NewPortMappingDescription>{3}</NewPortMappingDescription>"+
|
||||
"<NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>",
|
||||
port, protocol.ToString().ToUpper(),Dns.GetHostAddresses(Dns.GetHostName())[0], description);
|
||||
if (SOAPRequest(_serviceUrl, body, "AddPortMapping") != null)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool DeleteForwardingRule(int port, ProtocolType protocol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
string body = String.Format("<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
||||
"<NewRemoteHost></NewRemoteHost><NewExternalPort>{0}</NewExternalPort>"+
|
||||
"<NewProtocol>{1}</NewProtocol></u:DeletePortMapping>", port, protocol.ToString().ToUpper() );
|
||||
if (SOAPRequest(_serviceUrl, body, "DeletePortMapping") != null)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IPAddress GetExternalIP()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_serviceUrl))
|
||||
throw new Exception("No UPnP service available or Discover() has not been called");
|
||||
XmlDocument xdoc = SOAPRequest(_serviceUrl, "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
|
||||
"</u:GetExternalIPAddress>", "GetExternalIPAddress");
|
||||
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
|
||||
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
|
||||
string IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value;
|
||||
return IPAddress.Parse(IP);
|
||||
}
|
||||
|
||||
private static XmlDocument SOAPRequest(string url, string soap, string function)
|
||||
{
|
||||
string body = "<?xml version=\"1.0\"?>" +
|
||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
|
||||
"<s:Body>" +
|
||||
soap +
|
||||
"</s:Body>" +
|
||||
"</s:Envelope>";
|
||||
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(url);
|
||||
r.KeepAlive = false;
|
||||
r.Method = "POST";
|
||||
byte[] b = Encoding.UTF8.GetBytes(body);
|
||||
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
|
||||
r.ContentType = "text/xml; charset=\"utf-8\"";
|
||||
r.ContentLength = b.Length;
|
||||
Stream newStream = r.GetRequestStream();
|
||||
newStream.Write(b, 0, b.Length);
|
||||
XmlDocument resp = new XmlDocument();
|
||||
using (WebResponse wres = r.GetResponse())
|
||||
{
|
||||
using (Stream ress = wres.GetResponseStream())
|
||||
{
|
||||
resp.Load(ress);
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,12 @@ namespace OpenRA
|
||||
|
||||
static ISoundSource LoadSound(string filename)
|
||||
{
|
||||
if (!FileSystem.Exists(filename))
|
||||
{
|
||||
Log.Write("debug", "LoadSound, file does not exist: {0}", filename);
|
||||
return null;
|
||||
}
|
||||
|
||||
return LoadSoundRaw(AudLoader.LoadSound(FileSystem.Open(filename)));
|
||||
}
|
||||
|
||||
@@ -37,9 +43,22 @@ namespace OpenRA
|
||||
return soundEngine.AddSoundSourceFromMemory(rawData, 1, 16, 22050);
|
||||
}
|
||||
|
||||
public static void Create()
|
||||
static ISoundEngine CreateEngine(string engine)
|
||||
{
|
||||
soundEngine = new OpenAlSoundEngine();
|
||||
engine = Game.Settings.Server.Dedicated?"Null":engine;
|
||||
switch (engine)
|
||||
{ /* todo: if someone cares about pluggable crap here, ship this out */
|
||||
case "AL": return new OpenAlSoundEngine();
|
||||
case "Null": return new NullSoundEngine();
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported sound engine: {0}".F (engine));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Create(string engine)
|
||||
{
|
||||
soundEngine = CreateEngine(engine);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
@@ -52,29 +71,29 @@ namespace OpenRA
|
||||
|
||||
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
|
||||
|
||||
static ISound Play(Player player, string name, bool headRelative, float2 pos, float volumeModifier)
|
||||
static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier)
|
||||
{
|
||||
if (player != null && player != player.World.LocalPlayer)
|
||||
if (String.IsNullOrEmpty(name))
|
||||
return null;
|
||||
if (name == "" || name == null)
|
||||
if (player != null && player != player.World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
return soundEngine.Play2D(sounds[name],
|
||||
false, headRelative, pos,
|
||||
InternalSoundVolume * volumeModifier);
|
||||
false, headRelative, pos.ToFloat2(),
|
||||
InternalSoundVolume * volumeModifier, true);
|
||||
}
|
||||
|
||||
public static ISound Play(string name) { return Play(null, name, true, float2.Zero, 1); }
|
||||
public static ISound Play(string name, float2 pos) { return Play(null, name, false, pos, 1); }
|
||||
public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, float2.Zero, volumeModifier); }
|
||||
public static ISound Play(string name, float2 pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
|
||||
public static ISound PlayToPlayer(Player player, string name) { return Play( player, name, true, float2.Zero, 1); }
|
||||
public static ISound PlayToPlayer(Player player, string name, float2 pos) { return Play(player, name, false, pos, 1); }
|
||||
public static ISound Play(string name) { return Play(null, name, true, PPos.Zero, 1); }
|
||||
public static ISound Play(string name, PPos pos) { return Play(null, name, false, pos, 1); }
|
||||
public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, PPos.Zero, volumeModifier); }
|
||||
public static ISound Play(string name, PPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
|
||||
public static ISound PlayToPlayer(Player player, string name) { return Play(player, name, true, PPos.Zero, 1); }
|
||||
public static ISound PlayToPlayer(Player player, string name, PPos pos) { return Play(player, name, false, pos, 1); }
|
||||
|
||||
public static void PlayVideo(byte[] raw)
|
||||
{
|
||||
rawSource = LoadSoundRaw(raw);
|
||||
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume);
|
||||
video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume, false);
|
||||
}
|
||||
|
||||
public static void PlayVideo()
|
||||
@@ -128,10 +147,12 @@ namespace OpenRA
|
||||
}
|
||||
StopMusic();
|
||||
|
||||
var sound = sounds[m.Filename];
|
||||
if (sound == null) return;
|
||||
|
||||
music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume, false);
|
||||
currentMusic = m;
|
||||
MusicPlaying = true;
|
||||
var sound = sounds[m.Filename];
|
||||
music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume);
|
||||
}
|
||||
|
||||
public static void PlayMusic()
|
||||
@@ -226,7 +247,51 @@ namespace OpenRA
|
||||
get { return (video != null) ? video.SeekPosition : 0; }
|
||||
}
|
||||
|
||||
// Returns true if it played a phrase
|
||||
// Returns true if played successfully
|
||||
public static bool PlayPredefined(Player p, Actor voicedUnit, string type, string definition, string variant, bool attentuateVolume)
|
||||
{
|
||||
if (definition == null) return false;
|
||||
|
||||
if (Rules.Voices == null) return false;
|
||||
if (Rules.Notifications == null) return false;
|
||||
var rules = (voicedUnit != null) ? Rules.Voices[type] : Rules.Notifications[type];
|
||||
if (rules == null) return false;
|
||||
|
||||
var ID = (voicedUnit != null) ? voicedUnit.ActorID : 0;
|
||||
|
||||
var clip = (voicedUnit != null) ? rules.VoicePools.Value[definition].GetNext() : rules.NotificationsPools.Value[definition].GetNext();
|
||||
if (clip == null) return false;
|
||||
|
||||
var suffix = rules.DefaultVariant;
|
||||
var prefix = rules.DefaultPrefix;
|
||||
|
||||
if (voicedUnit != null)
|
||||
{
|
||||
if (!rules.VoicePools.Value.ContainsKey("Attack"))
|
||||
rules.VoicePools.Value.Add("Attack", rules.VoicePools.Value["Move"]);
|
||||
|
||||
if (!rules.VoicePools.Value.ContainsKey("AttackMove"))
|
||||
rules.VoicePools.Value.Add("AttackMove", rules.VoicePools.Value["Move"]);
|
||||
}
|
||||
|
||||
if (variant != null)
|
||||
{
|
||||
if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition))
|
||||
suffix = rules.Variants[variant][ID % rules.Variants[variant].Length];
|
||||
if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition))
|
||||
prefix = rules.Prefixes[variant][ID % rules.Prefixes[variant].Length];
|
||||
}
|
||||
|
||||
var name = prefix + clip + suffix;
|
||||
|
||||
if (!String.IsNullOrEmpty(name) && (p == null || p == p.World.LocalPlayer))
|
||||
soundEngine.Play2D(sounds[name],
|
||||
false, true, float2.Zero,
|
||||
InternalSoundVolume, attentuateVolume);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool PlayVoice(string phrase, Actor voicedUnit, string variant)
|
||||
{
|
||||
if (voicedUnit == null) return false;
|
||||
@@ -236,23 +301,24 @@ namespace OpenRA
|
||||
if (mi == null) return false;
|
||||
if (mi.Voice == null) return false;
|
||||
|
||||
var vi = Rules.Voices[mi.Voice.ToLowerInvariant()];
|
||||
var type = mi.Voice.ToLowerInvariant();
|
||||
|
||||
var clip = vi.Pools.Value[phrase].GetNext();
|
||||
if (clip == null)
|
||||
return false;
|
||||
return PlayPredefined(null, voicedUnit, type, phrase, variant, true);
|
||||
}
|
||||
|
||||
var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase)) ?
|
||||
vi.Variants[variant][voicedUnit.ActorID % vi.Variants[variant].Length] : vi.DefaultVariant;
|
||||
Play(clip + variantext);
|
||||
return true;
|
||||
public static bool PlayNotification(Player player, string type, string notification, string variant)
|
||||
{
|
||||
if (type == null) return false;
|
||||
if (notification == null) return false;
|
||||
|
||||
return PlayPredefined(player, null, type.ToLowerInvariant(), notification, variant, false);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISoundEngine
|
||||
{
|
||||
ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate);
|
||||
ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume);
|
||||
ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume);
|
||||
float Volume { get; set; }
|
||||
void PauseSound(ISound sound, bool paused);
|
||||
void StopSound(ISound sound);
|
||||
@@ -273,8 +339,17 @@ namespace OpenRA
|
||||
|
||||
class OpenAlSoundEngine : ISoundEngine
|
||||
{
|
||||
class PoolSlot
|
||||
{
|
||||
public bool isActive;
|
||||
public int frameStarted;
|
||||
public float2 pos;
|
||||
public bool isRelative;
|
||||
public ISoundSource sound;
|
||||
}
|
||||
|
||||
float volume = 1f;
|
||||
Dictionary<int, bool> sourcePool = new Dictionary<int, bool>();
|
||||
Dictionary<int, PoolSlot> sourcePool = new Dictionary<int, PoolSlot>();
|
||||
const int POOL_SIZE = 32;
|
||||
|
||||
public OpenAlSoundEngine()
|
||||
@@ -298,7 +373,7 @@ namespace OpenRA
|
||||
return;
|
||||
}
|
||||
|
||||
sourcePool.Add(source, false);
|
||||
sourcePool.Add(source, new PoolSlot() { isActive = false });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,9 +381,9 @@ namespace OpenRA
|
||||
{
|
||||
foreach (var kvp in sourcePool)
|
||||
{
|
||||
if (!kvp.Value)
|
||||
if (!kvp.Value.isActive)
|
||||
{
|
||||
sourcePool[kvp.Key] = true;
|
||||
sourcePool[kvp.Key].isActive = true;
|
||||
return kvp.Key;
|
||||
}
|
||||
}
|
||||
@@ -326,9 +401,9 @@ namespace OpenRA
|
||||
return -1;
|
||||
|
||||
foreach (int i in freeSources)
|
||||
sourcePool[i] = false;
|
||||
sourcePool[i].isActive = false;
|
||||
|
||||
sourcePool[freeSources[0]] = true;
|
||||
sourcePool[freeSources[0]].isActive = true;
|
||||
|
||||
return freeSources[0];
|
||||
}
|
||||
@@ -338,10 +413,62 @@ namespace OpenRA
|
||||
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
|
||||
}
|
||||
|
||||
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume)
|
||||
const int maxInstancesPerFrame = 3;
|
||||
const int groupDistance = 64;
|
||||
const int groupDistanceSqr = groupDistance * groupDistance;
|
||||
|
||||
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume)
|
||||
{
|
||||
if (sound == null)
|
||||
{
|
||||
Log.Write("debug", "Attempt to Play2D a null `ISoundSource`");
|
||||
return null;
|
||||
}
|
||||
|
||||
var world = Game.orderManager.world;
|
||||
int currFrame = world != null ? world.FrameNumber : 0;
|
||||
float atten = 1f;
|
||||
|
||||
// Check if max # of instances-per-location reached:
|
||||
if (attenuateVolume)
|
||||
{
|
||||
int instances = 0, activeCount = 0;
|
||||
foreach (var s in sourcePool.Values)
|
||||
{
|
||||
if (!s.isActive)
|
||||
continue;
|
||||
if (s.isRelative != relative)
|
||||
continue;
|
||||
|
||||
++activeCount;
|
||||
if (s.sound != sound)
|
||||
continue;
|
||||
if (currFrame - s.frameStarted >= 5)
|
||||
continue;
|
||||
|
||||
// Too far away to count?
|
||||
var lensqr = (s.pos - pos).LengthSquared;
|
||||
if (lensqr >= groupDistanceSqr)
|
||||
continue;
|
||||
|
||||
// If we are starting too many instances of the same sound within a short time then stop this one:
|
||||
if (++instances == maxInstancesPerFrame)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Attenuate a little bit based on number of active sounds:
|
||||
atten = 0.66f * ((POOL_SIZE - activeCount * 0.5f) / POOL_SIZE);
|
||||
}
|
||||
|
||||
int source = GetSourceFromPool();
|
||||
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume);
|
||||
if (source == -1) return null;
|
||||
|
||||
var slot = sourcePool[source];
|
||||
slot.pos = pos;
|
||||
slot.frameStarted = currFrame;
|
||||
slot.sound = sound;
|
||||
slot.isRelative = relative;
|
||||
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume * atten);
|
||||
}
|
||||
|
||||
public float Volume
|
||||
@@ -352,6 +479,8 @@ namespace OpenRA
|
||||
|
||||
public void PauseSound(ISound sound, bool paused)
|
||||
{
|
||||
if (sound == null) return;
|
||||
|
||||
int key = ((OpenAlSound)sound).source;
|
||||
int state;
|
||||
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
|
||||
@@ -393,6 +522,8 @@ namespace OpenRA
|
||||
|
||||
public void StopSound(ISound sound)
|
||||
{
|
||||
if (sound == null) return;
|
||||
|
||||
int key = ((OpenAlSound)sound).source;
|
||||
int state;
|
||||
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
|
||||
@@ -450,15 +581,14 @@ namespace OpenRA
|
||||
if (source == -1) return;
|
||||
this.source = source;
|
||||
Al.alSourcef(source, Al.AL_PITCH, 1f);
|
||||
Al.alSourcef(source, Al.AL_GAIN, 1f);
|
||||
Volume = volume;
|
||||
Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f);
|
||||
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
|
||||
Al.alSourcei(source, Al.AL_BUFFER, buffer);
|
||||
Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE);
|
||||
Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0);
|
||||
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200);
|
||||
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500);
|
||||
Volume = volume;
|
||||
Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 160);
|
||||
Al.alSourcef(source, Al.AL_MAX_DISTANCE, 3200 / Game.viewport.Zoom);
|
||||
Al.alSourcePlay(source);
|
||||
}
|
||||
|
||||
@@ -492,4 +622,35 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NullSoundEngine : ISoundEngine
|
||||
{
|
||||
public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate)
|
||||
{
|
||||
return new NullSoundSource();
|
||||
}
|
||||
|
||||
public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume, bool attenuateVolume)
|
||||
{
|
||||
return new NullSound();
|
||||
}
|
||||
|
||||
public void PauseSound(ISound sound, bool paused) {}
|
||||
public void StopSound(ISound sound) {}
|
||||
public void SetAllSoundsPaused(bool paused) {}
|
||||
public void StopAllSounds() {}
|
||||
public void SetListenerPosition(float2 position) {}
|
||||
public void SetSoundVolume(float volume, ISound music, ISound video) {}
|
||||
|
||||
public float Volume { get; set; }
|
||||
}
|
||||
|
||||
class NullSoundSource : ISoundSource {}
|
||||
|
||||
class NullSound : ISound
|
||||
{
|
||||
public float Volume { get; set; }
|
||||
public float SeekPosition { get { return 0; } }
|
||||
public bool Playing { get { return false; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,14 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main( string[] args )
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// brutal hack
|
||||
Application.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
@@ -32,19 +33,60 @@ namespace OpenRA
|
||||
|
||||
try
|
||||
{
|
||||
Run( args );
|
||||
Run(args);
|
||||
}
|
||||
catch( Exception e )
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.AddChannel("exception", "exception.log");
|
||||
Log.Write("exception", "{0}", e.ToString());
|
||||
throw;
|
||||
var rpt = BuildExceptionReport(e).ToString();
|
||||
Log.Write("exception", "{0}", rpt);
|
||||
Console.Error.WriteLine(rpt);
|
||||
}
|
||||
}
|
||||
|
||||
static void Run( string[] args )
|
||||
static StringBuilder BuildExceptionReport(Exception e)
|
||||
{
|
||||
Game.Initialize( new Arguments(args) );
|
||||
return BuildExceptionReport(e, new StringBuilder(), 0);
|
||||
}
|
||||
|
||||
static void Indent(StringBuilder sb, int d)
|
||||
{
|
||||
sb.Append(new string(' ', d * 2));
|
||||
}
|
||||
|
||||
static StringBuilder BuildExceptionReport(Exception e, StringBuilder sb, int d)
|
||||
{
|
||||
if (e == null) return sb;
|
||||
|
||||
sb.AppendFormat("Exception of type `{0}`: {1}", e.GetType().FullName, e.Message);
|
||||
|
||||
if (e is TypeLoadException)
|
||||
{
|
||||
var tle = (TypeLoadException)e;
|
||||
sb.AppendLine();
|
||||
Indent(sb, d);
|
||||
sb.AppendFormat("TypeName=`{0}`", tle.TypeName);
|
||||
}
|
||||
else // TODO: more exception types
|
||||
{
|
||||
}
|
||||
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
sb.AppendLine();
|
||||
Indent(sb, d); sb.Append("Inner ");
|
||||
BuildExceptionReport(e.InnerException, sb, d + 1);
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
Indent(sb, d); sb.Append(e.StackTrace);
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
static void Run(string[] args)
|
||||
{
|
||||
Game.Initialize(new Arguments(args));
|
||||
GC.Collect();
|
||||
Game.Run();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,36 @@ namespace OpenRA
|
||||
il.EmitCall(OpCodes.Call, ((Func<int2, int>)hash_int2).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(CPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<CPos, int>)hash_CPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(CVec))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<CVec, int>)hash_CVec).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PPos, int>)hash_PPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PVecInt))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PVecInt, int>)hash_PVecInt).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PSubPos))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PSubPos, int>)hash_PSubPos).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(PSubVec))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<PSubVec, int>)hash_PSubVec).Method, null);
|
||||
il.Emit(OpCodes.Xor);
|
||||
}
|
||||
else if (type == typeof(TypeDictionary))
|
||||
{
|
||||
il.EmitCall(OpCodes.Call, ((Func<TypeDictionary, int>)hash_tdict).Method, null);
|
||||
@@ -110,6 +140,36 @@ namespace OpenRA
|
||||
return ( ( i2.X * 5 ) ^ ( i2.Y * 3 ) ) / 4;
|
||||
}
|
||||
|
||||
public static int hash_CPos( CPos i2 )
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
}
|
||||
|
||||
public static int hash_CVec( CVec i2 )
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PPos( PPos i2 )
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PVecInt( PVecInt i2 )
|
||||
{
|
||||
return ( ( i2.X * 5) ^ ( i2.Y * 3 ) ) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PSubPos(PSubPos i2)
|
||||
{
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_PSubVec(PSubVec i2)
|
||||
{
|
||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||
}
|
||||
|
||||
public static int hash_tdict( TypeDictionary d )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -54,31 +54,33 @@ namespace OpenRA
|
||||
InnerGet( t ).Add( actor, val );
|
||||
}
|
||||
|
||||
void CheckDestroyed(Actor actor)
|
||||
{
|
||||
if (actor.Destroyed)
|
||||
throw new InvalidOperationException("Attempted to get trait from destroyed object ({0})".F(actor));
|
||||
}
|
||||
|
||||
public bool Contains<T>( Actor actor )
|
||||
{
|
||||
if( actor.Destroyed )
|
||||
throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) );
|
||||
CheckDestroyed(actor);
|
||||
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ).Count() != 0;
|
||||
}
|
||||
|
||||
public T Get<T>( Actor actor )
|
||||
{
|
||||
if( actor.Destroyed )
|
||||
throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) );
|
||||
CheckDestroyed(actor);
|
||||
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).Get( actor.ActorID );
|
||||
}
|
||||
|
||||
public T GetOrDefault<T>( Actor actor )
|
||||
{
|
||||
if( actor.Destroyed )
|
||||
throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) );
|
||||
CheckDestroyed(actor);
|
||||
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetOrDefault( actor.ActorID );
|
||||
}
|
||||
|
||||
public IEnumerable<T> WithInterface<T>( Actor actor )
|
||||
{
|
||||
if( actor.Destroyed )
|
||||
throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) );
|
||||
CheckDestroyed(actor);
|
||||
return ( (TraitContainer<T>)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID );
|
||||
}
|
||||
|
||||
@@ -118,14 +120,10 @@ namespace OpenRA
|
||||
|
||||
public T Get( uint actor )
|
||||
{
|
||||
++queries;
|
||||
var index = actors.BinarySearchMany( actor );
|
||||
if( index >= actors.Count || actors[ index ].ActorID != actor )
|
||||
throw new InvalidOperationException( string.Format( "TraitDictionary does not contain instance of type `{0}`", typeof( T ) ) );
|
||||
else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor )
|
||||
throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
|
||||
else
|
||||
return traits[ index ];
|
||||
var result = GetOrDefault(actor);
|
||||
if ((object)result == null)
|
||||
throw new InvalidOperationException("Actor does not have trait of type `{0}`".F(typeof(T)));
|
||||
return result;
|
||||
}
|
||||
|
||||
public T GetOrDefault( uint actor )
|
||||
@@ -135,7 +133,7 @@ namespace OpenRA
|
||||
if( index >= actors.Count || actors[ index ].ActorID != actor )
|
||||
return default( T );
|
||||
else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor )
|
||||
throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
|
||||
throw new InvalidOperationException("Actor has multiple traits of type `{0}`".F(typeof(T)));
|
||||
else return traits[ index ];
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public static IEnumerable<Target> GetTargetQueue( this Actor self )
|
||||
{
|
||||
return self.GetCurrentActivity().Iterate( u => u.NextActivity ).TakeWhile( u => u != null )
|
||||
return self.GetCurrentActivity()
|
||||
.Iterate( u => u.NextActivity )
|
||||
.TakeWhile( u => u != null )
|
||||
.SelectMany( u => u.GetTargets( self ) );
|
||||
}
|
||||
}
|
||||
|
||||
40
OpenRA.Game/Traits/CreatesShroud.cs
Normal file
40
OpenRA.Game/Traits/CreatesShroud.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class CreatesShroudInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Range = 0;
|
||||
public object Create(ActorInitializer init) { return new CreatesShroud(this); }
|
||||
}
|
||||
|
||||
public class CreatesShroud : ITick
|
||||
{
|
||||
CreatesShroudInfo Info;
|
||||
|
||||
public CreatesShroud(CreatesShroudInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.TraitsImplementing<IDisable>().Any(d => d.Disabled)) {
|
||||
var shrouds = self.World.ActorsWithTrait<Traits.Shroud>().Select(s => s.Actor.Owner.Shroud);
|
||||
foreach (var shroud in shrouds) {
|
||||
shroud.HideActor(self, Info.Range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Effects;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -25,7 +26,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
Actor self;
|
||||
DrawLineToTargetInfo Info;
|
||||
Target target;
|
||||
List<Target> targets;
|
||||
Color c;
|
||||
int lifetime;
|
||||
|
||||
@@ -33,7 +34,16 @@ namespace OpenRA.Traits
|
||||
|
||||
public void SetTarget(Actor self, Target target, Color c, bool display)
|
||||
{
|
||||
this.target = target;
|
||||
this.targets = new List<Target> { target };
|
||||
this.c = c;
|
||||
|
||||
if (display)
|
||||
lifetime = Info.Ticks;
|
||||
}
|
||||
|
||||
public void SetTargets(Actor self, List<Target> targets, Color c, bool display)
|
||||
{
|
||||
this.targets = targets;
|
||||
this.c = c;
|
||||
|
||||
if (display)
|
||||
@@ -42,23 +52,29 @@ namespace OpenRA.Traits
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr)
|
||||
{
|
||||
if (self.IsIdle) return;
|
||||
//if (self.IsIdle) return;
|
||||
|
||||
var force = Game.GetModifierKeys().HasModifier(Modifiers.Alt);
|
||||
if ((lifetime <= 0 || --lifetime <= 0) && !force)
|
||||
return;
|
||||
|
||||
if (!target.IsValid)
|
||||
if (targets == null || targets.Count == 0)
|
||||
return;
|
||||
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
var origin = move != null ? self.CenterLocation - new int2(0, move.Altitude) : self.CenterLocation;
|
||||
var origin = (move != null ? self.CenterLocation - new PVecInt(0, move.Altitude) : self.CenterLocation).ToFloat2();
|
||||
|
||||
var wlr = Game.Renderer.WorldLineRenderer;
|
||||
|
||||
wlr.DrawLine(origin, target.CenterLocation, c, c);
|
||||
DrawTargetMarker(wlr, target.CenterLocation);
|
||||
DrawTargetMarker(wlr, origin);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (!target.IsValid)
|
||||
continue;
|
||||
|
||||
wlr.DrawLine(origin, target.CenterLocation.ToFloat2(), c, c);
|
||||
DrawTargetMarker(wlr, target.CenterLocation.ToFloat2());
|
||||
DrawTargetMarker(wlr, origin);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTargetMarker(LineRenderer wlr, float2 p)
|
||||
@@ -72,6 +88,18 @@ namespace OpenRA.Traits
|
||||
|
||||
public static class LineTargetExts
|
||||
{
|
||||
public static void SetTargetLines(this Actor self, List<Target> targets, Color color)
|
||||
{
|
||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||
if (line != null)
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
line.SetTargets(self, targets, color, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTargetLine(this Actor self, Target target, Color color)
|
||||
{
|
||||
self.SetTargetLine(target, color, true);
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace OpenRA.Traits
|
||||
public class EditorAppearanceInfo : TraitInfo<EditorAppearance>
|
||||
{
|
||||
public readonly bool RelativeToTopLeft = false;
|
||||
public readonly bool UseTerrainPalette = false;
|
||||
}
|
||||
|
||||
public class EditorAppearance { }
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public int HP { get { return hp; } }
|
||||
public readonly int MaxHP;
|
||||
public int MaxHP;
|
||||
|
||||
public bool IsDead { get { return hp <= 0; } }
|
||||
public bool RemoveOnDeath = true;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.LocalShroud.Disabled = DisableShroud;
|
||||
self.World.RenderedShroud.Disabled = DisableShroud;
|
||||
break;
|
||||
}
|
||||
case "DevPathDebug":
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA.Traits
|
||||
case "DevGiveExploration":
|
||||
{
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.WorldActor.Trait<Shroud>().ExploreAll(self.World);
|
||||
self.World.LocalPlayer.Shroud.ExploreAll(self.World);
|
||||
break;
|
||||
}
|
||||
case "DevUnlimitedPower":
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 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 COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class EvaAlertsInfo : TraitInfo<EvaAlerts>
|
||||
{
|
||||
// Sound effects
|
||||
public readonly string RadarUp = "radaron2.aud";
|
||||
public readonly string RadarDown = "radardn1.aud";
|
||||
|
||||
public readonly string CashTickUp = "cashup1.aud";
|
||||
public readonly string CashTickDown = "cashdn1.aud";
|
||||
|
||||
// Build Palette
|
||||
public readonly string BuildingCannotPlaceAudio = "nodeply1.aud";
|
||||
public readonly string NewOptions = "newopt1.aud";
|
||||
|
||||
// For manual powerup/down in ra-ng
|
||||
public readonly string DisablePower = "bleep11.aud";
|
||||
public readonly string EnablePower = "bleep12.aud";
|
||||
|
||||
// Eva speech
|
||||
public readonly string Repairing = "repair1.aud";
|
||||
public readonly string LowPower = "lopower1.aud";
|
||||
public readonly string SilosNeeded = "silond1.aud";
|
||||
public readonly string PrimaryBuildingSelected = "pribldg1.aud";
|
||||
|
||||
// Special powers
|
||||
public readonly string AbilityInsufficientPower = "nopowr1.aud";
|
||||
|
||||
public readonly string LevelUp = "hydrod1.aud";
|
||||
}
|
||||
|
||||
public class EvaAlerts {}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2012 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -62,6 +63,8 @@ namespace OpenRA.Traits
|
||||
{
|
||||
readonly Player Owner;
|
||||
int AdviceInterval;
|
||||
|
||||
int cashtickallowed = 0;
|
||||
|
||||
public PlayerResources(Actor self, PlayerResourcesInfo info)
|
||||
{
|
||||
@@ -83,6 +86,9 @@ namespace OpenRA.Traits
|
||||
public int DisplayCash;
|
||||
public int DisplayOre;
|
||||
|
||||
public int Earned;
|
||||
public int Spent;
|
||||
|
||||
public bool CanGiveOre(int amount)
|
||||
{
|
||||
return Ore + amount <= OreCapacity;
|
||||
@@ -91,10 +97,13 @@ namespace OpenRA.Traits
|
||||
public void GiveOre(int num)
|
||||
{
|
||||
Ore += num;
|
||||
Earned += num;
|
||||
|
||||
if (Ore > OreCapacity)
|
||||
{
|
||||
nextSiloAdviceTime = 0;
|
||||
|
||||
Earned -= Ore - OreCapacity;
|
||||
Ore = OreCapacity;
|
||||
}
|
||||
}
|
||||
@@ -103,6 +112,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
if (Ore < num) return false;
|
||||
Ore -= num;
|
||||
Spent += num;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -110,6 +120,7 @@ namespace OpenRA.Traits
|
||||
public void GiveCash(int num)
|
||||
{
|
||||
Cash += num;
|
||||
Earned += num;
|
||||
}
|
||||
|
||||
public bool TakeCash(int num)
|
||||
@@ -118,6 +129,7 @@ namespace OpenRA.Traits
|
||||
|
||||
// Spend ore before cash
|
||||
Ore -= num;
|
||||
Spent += num;
|
||||
if (Ore < 0)
|
||||
{
|
||||
Cash += Ore;
|
||||
@@ -133,8 +145,10 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
|
||||
if(cashtickallowed > 0) {
|
||||
cashtickallowed = cashtickallowed - 1;
|
||||
}
|
||||
|
||||
OreCapacity = self.World.ActorsWithTrait<IStoreOre>()
|
||||
.Where(a => a.Actor.Owner == Owner)
|
||||
.Sum(a => a.Trait.Capacity);
|
||||
@@ -145,7 +159,7 @@ namespace OpenRA.Traits
|
||||
if (--nextSiloAdviceTime <= 0)
|
||||
{
|
||||
if (Ore > 0.8*OreCapacity)
|
||||
Owner.GiveAdvice(eva.SilosNeeded);
|
||||
Sound.PlayNotification(Owner, "Speech", "SilosNeeded", Owner.Country.Race);
|
||||
|
||||
nextSiloAdviceTime = AdviceInterval;
|
||||
}
|
||||
@@ -158,12 +172,12 @@ namespace OpenRA.Traits
|
||||
if (DisplayCash < Cash)
|
||||
{
|
||||
DisplayCash += move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
|
||||
playCashTickUp(self);
|
||||
}
|
||||
else if (DisplayCash > Cash)
|
||||
{
|
||||
DisplayCash -= move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
playCashTickDown(self);
|
||||
}
|
||||
|
||||
diff = Math.Abs(Ore - DisplayOre);
|
||||
@@ -173,13 +187,34 @@ namespace OpenRA.Traits
|
||||
if (DisplayOre < Ore)
|
||||
{
|
||||
DisplayOre += move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
|
||||
playCashTickUp(self);
|
||||
}
|
||||
else if (DisplayOre > Ore)
|
||||
{
|
||||
DisplayOre -= move;
|
||||
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
|
||||
playCashTickDown(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void playCashTickUp(Actor self)
|
||||
{
|
||||
if (Game.Settings.Sound.SoundCashTickType != SoundCashTicks.Disabled)
|
||||
{
|
||||
Sound.PlayNotification(self.Owner, "Sounds", "CashTickUp", self.Owner.Country.Race);
|
||||
}
|
||||
}
|
||||
|
||||
public void playCashTickDown(Actor self)
|
||||
{
|
||||
if (
|
||||
Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Extreme ||
|
||||
(Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Normal && cashtickallowed == 0)
|
||||
) {
|
||||
Sound.PlayNotification(self.Owner, "Sounds", "CashTickDown", self.Owner.Country.Race);
|
||||
cashtickallowed = 3;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class RevealsShroudInfo : ITraitInfo
|
||||
public class RevealsShroudInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Range = 0;
|
||||
public object Create(ActorInitializer init) { return new RevealsShroud(this); }
|
||||
}
|
||||
|
||||
class RevealsShroud : ITick
|
||||
public class RevealsShroud : ITick
|
||||
{
|
||||
RevealsShroudInfo Info;
|
||||
int2 previousLocation;
|
||||
CPos previousLocation;
|
||||
|
||||
public RevealsShroud(RevealsShroudInfo info)
|
||||
{
|
||||
@@ -29,11 +29,22 @@ namespace OpenRA.Traits
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
// todo: don't tick all the time.
|
||||
|
||||
World w = self.World;
|
||||
if(self.Owner == null) return;
|
||||
|
||||
if (previousLocation != self.Location)
|
||||
{
|
||||
previousLocation = self.Location;
|
||||
self.World.WorldActor.Trait<Shroud>().UpdateActor(self);
|
||||
var actors = w.ActorsWithTrait<Shroud>();
|
||||
|
||||
foreach( var s in actors )
|
||||
s.Actor.Owner.Shroud.RemoveActor(self);
|
||||
|
||||
self.UpdateSight();
|
||||
|
||||
foreach( var s in actors )
|
||||
s.Actor.Owner.Shroud.AddActor(self);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user