Compare commits
1077 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
967128a14c | ||
|
|
1f82b13d0d | ||
|
|
8eefff1127 | ||
|
|
19caf7b6f2 | ||
|
|
d4dc1b49e1 | ||
|
|
6a879cda8c | ||
|
|
4ae72f5f5d | ||
|
|
f6dd2c2c68 | ||
|
|
e13d213098 | ||
|
|
1be67ec4d3 | ||
|
|
4025db45a3 | ||
|
|
15c2930eeb | ||
|
|
82ac8d8d80 | ||
|
|
52b4ac0aed | ||
|
|
a29111a9a8 | ||
|
|
5eb91d2811 | ||
|
|
d4bc4ac827 | ||
|
|
f8e1779f24 | ||
|
|
1ac4c6d1e1 | ||
|
|
b8831bb59d | ||
|
|
c8547d6004 | ||
|
|
59a1cfe914 | ||
|
|
1be6339590 | ||
|
|
b8646f98ab | ||
|
|
4d71e37ab0 | ||
|
|
94b2debaa4 | ||
|
|
c76ebbdc46 | ||
|
|
db19846972 | ||
|
|
70c2156325 | ||
|
|
5265366287 | ||
|
|
d7f3128978 | ||
|
|
718ba1f1d1 | ||
|
|
e8601d8df9 | ||
|
|
4f9f258413 | ||
|
|
ae5a3ca548 | ||
|
|
dde4923e7b | ||
|
|
af1801cfb2 | ||
|
|
cb2a3fe1fe | ||
|
|
95d8d1d45d | ||
|
|
c9d1431987 | ||
|
|
38f1aff0bb | ||
|
|
c720cb0b41 | ||
|
|
fa775a88c1 | ||
|
|
de4898badf | ||
|
|
3f63eb4ec6 | ||
|
|
b5c63175e2 | ||
|
|
8694698a1a | ||
|
|
a5223a519c | ||
|
|
aa77536e96 | ||
|
|
31991c3679 | ||
|
|
1acede6041 | ||
|
|
a4e3d7ee5f | ||
|
|
13f6075638 | ||
|
|
ff9c0f693b | ||
|
|
6be25468bb | ||
|
|
143d3aa083 | ||
|
|
bf0c7297e2 | ||
|
|
6b8fd4efd9 | ||
|
|
296d9c5072 | ||
|
|
1ea48b0167 | ||
|
|
146b49e251 | ||
|
|
3d6086187e | ||
|
|
b82510023f | ||
|
|
ecb5b71d3e | ||
|
|
e41fca3d47 | ||
|
|
b3e3b1bd7c | ||
|
|
bdfac27d14 | ||
|
|
c7ed2aacaf | ||
|
|
7fb53e336a | ||
|
|
c4b28b9016 | ||
|
|
043b02ebf8 | ||
|
|
031461e188 | ||
|
|
98a3d7d55d | ||
|
|
64b4f62af0 | ||
|
|
d514689ec7 | ||
|
|
f7551016c4 | ||
|
|
af5eed22a8 | ||
|
|
153aba469d | ||
|
|
9c92980635 | ||
|
|
647dc749f0 | ||
|
|
61749e145d | ||
|
|
758babcad4 | ||
|
|
c1f936b24c | ||
|
|
fc2d0510d8 | ||
|
|
5f31fbb009 | ||
|
|
4c00b73818 | ||
|
|
951e441ff9 | ||
|
|
096ce9e9a3 | ||
|
|
ee05bd20fc | ||
|
|
b9fdf6b66a | ||
|
|
c0a3a8d09a | ||
|
|
7b3974d688 | ||
|
|
af1db08503 | ||
|
|
55ad12d9a3 | ||
|
|
272e872357 | ||
|
|
71357950f7 | ||
|
|
3a8c94d8f8 | ||
|
|
a31cdec87a | ||
|
|
8beb9ffc57 | ||
|
|
8b207274ee | ||
|
|
f744939530 | ||
|
|
2c8fc4603a | ||
|
|
6ced7b274c | ||
|
|
104b520b21 | ||
|
|
21544ce235 | ||
|
|
37101ba88e | ||
|
|
ca786f6039 | ||
|
|
0eb1e2cc6d | ||
|
|
3f2ca8d9d3 | ||
|
|
6cb9b3afda | ||
|
|
333d7ee7be | ||
|
|
28efe99f21 | ||
|
|
9fce6dd310 | ||
|
|
9541686de3 | ||
|
|
ccbe4f3768 | ||
|
|
0bc3a68e9f | ||
|
|
255bfc70d1 | ||
|
|
595ef7bfae | ||
|
|
6538f696fa | ||
|
|
c3ba27ef6c | ||
|
|
6b199d3376 | ||
|
|
e2e0728e20 | ||
|
|
fcb3d7347a | ||
|
|
f5f84244eb | ||
|
|
c5ba8548c4 | ||
|
|
1020d45664 | ||
|
|
491fbcfef6 | ||
|
|
793f4a9d55 | ||
|
|
de9ddc4716 | ||
|
|
9993eacf65 | ||
|
|
3f9e89a746 | ||
|
|
4f7f0b7a55 | ||
|
|
4555157ed2 | ||
|
|
1878713866 | ||
|
|
387a5ded4b | ||
|
|
d7d00fffef | ||
|
|
11d4567b5d | ||
|
|
ea79eb28fc | ||
|
|
9d1526f4e7 | ||
|
|
96cc1276c2 | ||
|
|
0ca7ee280f | ||
|
|
b31240ccc5 | ||
|
|
400bb26e94 | ||
|
|
88e1ecd2a4 | ||
|
|
468df7986a | ||
|
|
c0f10dc5c1 | ||
|
|
8535e8d257 | ||
|
|
48f3d8f3c0 | ||
|
|
3355add49d | ||
|
|
725f690aaa | ||
|
|
94e30503a7 | ||
|
|
4b09ecd630 | ||
|
|
715e0299bf | ||
|
|
ef2aff3fa5 | ||
|
|
121d3339b9 | ||
|
|
ceea851436 | ||
|
|
e4ca66ab31 | ||
|
|
c223e23572 | ||
|
|
2b3e116f74 | ||
|
|
de735fbd27 | ||
|
|
262e0fc484 | ||
|
|
8b3b894fc5 | ||
|
|
ac5a4589ea | ||
|
|
dfbce62024 | ||
|
|
6db8952ce2 | ||
|
|
1b0708eedc | ||
|
|
1f9dd53b4d | ||
|
|
5151161d78 | ||
|
|
6392d62f2e | ||
|
|
d59f9b3c72 | ||
|
|
f9b1c75cf9 | ||
|
|
538a25ae6c | ||
|
|
9145ef0ad3 | ||
|
|
90519a37a9 | ||
|
|
c01c5ff72d | ||
|
|
972f3ae8dc | ||
|
|
e367ce4457 | ||
|
|
52e27f036a | ||
|
|
9f31304743 | ||
|
|
e6c041e53f | ||
|
|
cc34a40ebc | ||
|
|
50d89629a2 | ||
|
|
c098f85e6f | ||
|
|
3050cff67c | ||
|
|
64a18389b7 | ||
|
|
00bc3f71fe | ||
|
|
800665579b | ||
|
|
d6673d9ae8 | ||
|
|
9209c52cb5 | ||
|
|
7cfe18d332 | ||
|
|
b5679a55fb | ||
|
|
cc8284740c | ||
|
|
76f7e87633 | ||
|
|
77c0d4b7fb | ||
|
|
cd43bf118b | ||
|
|
8cd643e06a | ||
|
|
f528ff5c6f | ||
|
|
8fc78603bc | ||
|
|
2106393122 | ||
|
|
a4a285bef5 | ||
|
|
a501828660 | ||
|
|
4c4783262f | ||
|
|
c30b18a9d6 | ||
|
|
63068d5a7c | ||
|
|
3392d00294 | ||
|
|
e4d5404c6c | ||
|
|
634567f98e | ||
|
|
fafd9e81a9 | ||
|
|
c1453791d0 | ||
|
|
a5d5067f7a | ||
|
|
f8f60e52bc | ||
|
|
4768c3d6a5 | ||
|
|
8576c24988 | ||
|
|
26e75621c3 | ||
|
|
baf3c55f26 | ||
|
|
90c8072591 | ||
|
|
716fce4462 | ||
|
|
5d9b2d8b6e | ||
|
|
5daef851e8 | ||
|
|
bc7c4ea6cd | ||
|
|
d785cc04a2 | ||
|
|
104fb2d7c6 | ||
|
|
67cbc1db1b | ||
|
|
3980b6b7f2 | ||
|
|
8af0310686 | ||
|
|
34d1ccb82c | ||
|
|
fc2c46a2c2 | ||
|
|
4c1b70e28d | ||
|
|
5a5ed657d4 | ||
|
|
acea219f55 | ||
|
|
70dea5303f | ||
|
|
687f1f9bcd | ||
|
|
704c4c17f8 | ||
|
|
15019d5b06 | ||
|
|
5df88cb186 | ||
|
|
963db53b7b | ||
|
|
f80710ac7a | ||
|
|
9f69d13336 | ||
|
|
58c648daa9 | ||
|
|
5deb5e6686 | ||
|
|
7e9793fa90 | ||
|
|
d5edbc2bc7 | ||
|
|
45ad52f737 | ||
|
|
c21b27cddb | ||
|
|
0d6517ec25 | ||
|
|
3b78d6f343 | ||
|
|
212cf93ca4 | ||
|
|
0c20e38443 | ||
|
|
c5ef9cbfb2 | ||
|
|
ba79e33d40 | ||
|
|
fbf408b886 | ||
|
|
987f285714 | ||
|
|
d65ec5a4da | ||
|
|
5dd5e90175 | ||
|
|
ee6eac2436 | ||
|
|
4ce31f39c6 | ||
|
|
1f18374733 | ||
|
|
acda996227 | ||
|
|
d7d12ef799 | ||
|
|
91ea2d978f | ||
|
|
2d80a8d0d8 | ||
|
|
0a4423a9b8 | ||
|
|
daf106ddb3 | ||
|
|
27d49f48d2 | ||
|
|
1d95f5331d | ||
|
|
ce49d5df5e | ||
|
|
2fd47ee743 | ||
|
|
113bfe5311 | ||
|
|
116e4acda3 | ||
|
|
a8bd25a6a5 | ||
|
|
93c8be4e79 | ||
|
|
6d95c93bea | ||
|
|
b28ba09728 | ||
|
|
059ba575ee | ||
|
|
cf75240c7e | ||
|
|
865f6ed0d5 | ||
|
|
b5b3043811 | ||
|
|
8063e25f3b | ||
|
|
53479d1ac6 | ||
|
|
32c2e001b6 | ||
|
|
37bf88f5a5 | ||
|
|
20b88fd904 | ||
|
|
a7d6f717c4 | ||
|
|
c724558b75 | ||
|
|
9287fd1a76 | ||
|
|
3d2dceba61 | ||
|
|
cba19ffaa9 | ||
|
|
1079f37a68 | ||
|
|
31525c90c3 | ||
|
|
623452a884 | ||
|
|
bd077d337f | ||
|
|
b4bb268f45 | ||
|
|
c95114deff | ||
|
|
2720261eae | ||
|
|
2ea184e89e | ||
|
|
6190b7794b | ||
|
|
c777c621e0 | ||
|
|
d36dc41429 | ||
|
|
274fee2156 | ||
|
|
19ac138275 | ||
|
|
306271e93f | ||
|
|
bce0a7b39e | ||
|
|
6385e7ebaa | ||
|
|
fd4aa222f7 | ||
|
|
e2a33dbc10 | ||
|
|
36a1992d31 | ||
|
|
6dbe28cdbe | ||
|
|
2293453b8f | ||
|
|
c1954f498b | ||
|
|
a91741ebfa | ||
|
|
9720b7a966 | ||
|
|
bba0e20ef5 | ||
|
|
856120f2b2 | ||
|
|
1d9681a1d2 | ||
|
|
2566eea1c5 | ||
|
|
5c436e32e1 | ||
|
|
34e6773005 | ||
|
|
6483fc571f | ||
|
|
525b4eee93 | ||
|
|
8a318cad9b | ||
|
|
82cd2b9520 | ||
|
|
2319709749 | ||
|
|
a980d82162 | ||
|
|
6480fd7601 | ||
|
|
f74fb2d60e | ||
|
|
7d43ecc33f | ||
|
|
79d1a944bc | ||
|
|
a538914d6c | ||
|
|
718ddf9afd | ||
|
|
efb718a109 | ||
|
|
cf3cc43a28 | ||
|
|
9e1f15448d | ||
|
|
56470b918b | ||
|
|
2165518418 | ||
|
|
1bb0b41293 | ||
|
|
7867aea4dc | ||
|
|
72ccbca84b | ||
|
|
7a478dbcd5 | ||
|
|
51c1fc53de | ||
|
|
ec50906296 | ||
|
|
ed6147ce0b | ||
|
|
10e8a44151 | ||
|
|
c11a6c13a6 | ||
|
|
cf3493be6d | ||
|
|
9ce25bd400 | ||
|
|
b3adb032fa | ||
|
|
2f5947fffc | ||
|
|
cb43581c91 | ||
|
|
9a8c9d1985 | ||
|
|
f28fed01c9 | ||
|
|
2c649f0eaf | ||
|
|
b5b98feadb | ||
|
|
28e672fcf8 | ||
|
|
5ab7b26fbf | ||
|
|
b0c1e40609 | ||
|
|
3c3a047c21 | ||
|
|
5343fe1700 | ||
|
|
ca2f68ab32 | ||
|
|
ed92111c2a | ||
|
|
405061e05b | ||
|
|
2072f48ef7 | ||
|
|
394e230545 | ||
|
|
6d4eada679 | ||
|
|
2ea5e3df04 | ||
|
|
f12be6f0ce | ||
|
|
a487bee148 | ||
|
|
0e905a39eb | ||
|
|
4d86792b76 | ||
|
|
fefb43eb8e | ||
|
|
39484bdd45 | ||
|
|
232f0da14a | ||
|
|
9e35e01e3a | ||
|
|
e00a6933cc | ||
|
|
d7b891d995 | ||
|
|
38eeb42ff8 | ||
|
|
b469351f8f | ||
|
|
338fb38bd3 | ||
|
|
c6b0e37f7e | ||
|
|
88121b272d | ||
|
|
4075742d19 | ||
|
|
3d7815d8c1 | ||
|
|
89ca2686d0 | ||
|
|
4912a6cdb0 | ||
|
|
b8c3ceee59 | ||
|
|
a4569d3b35 | ||
|
|
666f9b4e47 | ||
|
|
0c4aeb8398 | ||
|
|
c2d534f527 | ||
|
|
b97a082c84 | ||
|
|
1faf5abd90 | ||
|
|
71a5ddc176 | ||
|
|
aa6e970611 | ||
|
|
d5f4813bc4 | ||
|
|
0052000f7b | ||
|
|
cd26a4e5fc | ||
|
|
945a7121e4 | ||
|
|
dcac88b27b | ||
|
|
578d2363b3 | ||
|
|
8c5957d0d8 | ||
|
|
0a9a959ecf | ||
|
|
06caf7f156 | ||
|
|
2a8efde8e6 | ||
|
|
1e1eea9619 | ||
|
|
7be3078115 | ||
|
|
3ed2053d4a | ||
|
|
8bcb2e15c7 | ||
|
|
864c4bc03a | ||
|
|
5418441bb5 | ||
|
|
fae9bf2c2c | ||
|
|
e65626cc6b | ||
|
|
bfc34df581 | ||
|
|
ba1558259b | ||
|
|
2931f9dfcb | ||
|
|
a742362a26 | ||
|
|
7f4c1addb3 | ||
|
|
873a8d8287 | ||
|
|
7ac65d2909 | ||
|
|
38c1a68be6 | ||
|
|
18fe8e93fa | ||
|
|
d51fd0587f | ||
|
|
2ec3d2c3a5 | ||
|
|
fb5c238475 | ||
|
|
7f73a49c3e | ||
|
|
e7874b850d | ||
|
|
b014af11b0 | ||
|
|
de574910e5 | ||
|
|
f47f65e9c4 | ||
|
|
dc8605825b | ||
|
|
7596876d45 | ||
|
|
e0b40e2088 | ||
|
|
28df2d6982 | ||
|
|
d18b657bfd | ||
|
|
d1d29d0fad | ||
|
|
5b7db7ed68 | ||
|
|
e4e6af6536 | ||
|
|
cf19429eea | ||
|
|
878c1bd80b | ||
|
|
04481cb958 | ||
|
|
1ac4de9260 | ||
|
|
2b674f71cd | ||
|
|
5305e8398b | ||
|
|
98b158e370 | ||
|
|
3d42dc8e0f | ||
|
|
881d17a996 | ||
|
|
025de83d3a | ||
|
|
b996d4cf7b | ||
|
|
1020dc0e55 | ||
|
|
c3b5495177 | ||
|
|
8b99ecb721 | ||
|
|
af61a48ac7 | ||
|
|
ea1d1320be | ||
|
|
74e72cfc01 | ||
|
|
6dc02c3b26 | ||
|
|
35bf03aade | ||
|
|
449fe81bf0 | ||
|
|
bb29723332 | ||
|
|
3c80024113 | ||
|
|
91908c560d | ||
|
|
eba8e8f33f | ||
|
|
2f2afd9fc5 | ||
|
|
ba5e835035 | ||
|
|
4fc9e0e288 | ||
|
|
5581e6c4d9 | ||
|
|
9dcf5c3dbb | ||
|
|
54e09edd2c | ||
|
|
dd103ddc60 | ||
|
|
5bdc047c5a | ||
|
|
c9514e37fc | ||
|
|
e7be3a8dc9 | ||
|
|
643f8282ba | ||
|
|
5e8a1710dc | ||
|
|
6bf66fbfc4 | ||
|
|
39fac0dce3 | ||
|
|
030fb92140 | ||
|
|
a2579aadd0 | ||
|
|
a0f9a81ea7 | ||
|
|
2f9b1459a8 | ||
|
|
6be0a26353 | ||
|
|
886efd0b97 | ||
|
|
42532efd8f | ||
|
|
b3323869cb | ||
|
|
5322096dc4 | ||
|
|
43e386a48d | ||
|
|
9500a11689 | ||
|
|
9c4ad15d1e | ||
|
|
6f3617361e | ||
|
|
3b2517ab8e | ||
|
|
4b38390907 | ||
|
|
477e486054 | ||
|
|
aae1e7e134 | ||
|
|
d6ca396b73 | ||
|
|
0bca2bf882 | ||
|
|
e4effd0125 | ||
|
|
16ddecdcbf | ||
|
|
e344b95a6f | ||
|
|
1d8e785d0d | ||
|
|
efd0b5c189 | ||
|
|
ff1c4ae44b | ||
|
|
e58053cb69 | ||
|
|
fae9611d27 | ||
|
|
697b50c149 | ||
|
|
1759d73ed7 | ||
|
|
9147e1f778 | ||
|
|
db9ebd4a61 | ||
|
|
4eaaa052cc | ||
|
|
c781d4c2fe | ||
|
|
8d26d5e3fa | ||
|
|
d13e7ed432 | ||
|
|
61f5ab7167 | ||
|
|
85500c0ec7 | ||
|
|
3aad269ac2 | ||
|
|
60bda58538 | ||
|
|
0de1e20651 | ||
|
|
a0e50762ad | ||
|
|
018f30c86e | ||
|
|
7a77f3a755 | ||
|
|
255945076c | ||
|
|
d77614bf8b | ||
|
|
1a3ec26a1e | ||
|
|
81ec978a61 | ||
|
|
7b84b10a16 | ||
|
|
dda39ff14d | ||
|
|
a32d440b05 | ||
|
|
06be4d3efd | ||
|
|
7e8e427449 | ||
|
|
9b7233ebd1 | ||
|
|
7ef9c99221 | ||
|
|
9d9807b23a | ||
|
|
f897b57f4c | ||
|
|
17cf890dce | ||
|
|
8685ec64ae | ||
|
|
87c7968795 | ||
|
|
bc205f0a5c | ||
|
|
8d76d8e4e0 | ||
|
|
b8740a3a47 | ||
|
|
1a77180a5d | ||
|
|
85a4a1e272 | ||
|
|
18d8034153 | ||
|
|
2433b6d6df | ||
|
|
417a1f5419 | ||
|
|
00631e5da3 | ||
|
|
aace7ca607 | ||
|
|
d28992c054 | ||
|
|
d812872d91 | ||
|
|
44f00dc48e | ||
|
|
da59468fa5 | ||
|
|
493de23527 | ||
|
|
617012bd36 | ||
|
|
151f7dc9c6 | ||
|
|
8217a1c161 | ||
|
|
d939d5183c | ||
|
|
ecca689f34 | ||
|
|
e496f2a36d | ||
|
|
c6db460291 | ||
|
|
dd581e0135 | ||
|
|
b3e0632e25 | ||
|
|
d5039e1ddb | ||
|
|
ca770e89c3 | ||
|
|
b9cdbaebbf | ||
|
|
211bcedb95 | ||
|
|
c6c47ccfcd | ||
|
|
d2d29269d6 | ||
|
|
99cb698424 | ||
|
|
abaed4e8be | ||
|
|
f053379458 | ||
|
|
e07453bb7f | ||
|
|
d34de25495 | ||
|
|
c4220a42dc | ||
|
|
13ccfa0b34 | ||
|
|
d2fa1a12f9 | ||
|
|
29e689178d | ||
|
|
3cdeea009b | ||
|
|
c333b59eb9 | ||
|
|
27ef3352f4 | ||
|
|
3a57c18154 | ||
|
|
14b264e553 | ||
|
|
69c97a6e39 | ||
|
|
0083e60590 | ||
|
|
51ef37fc02 | ||
|
|
0c67bce545 | ||
|
|
589f5297d9 | ||
|
|
dd6b1f877d | ||
|
|
fe47907024 | ||
|
|
0763fc0167 | ||
|
|
26013c21f9 | ||
|
|
ca61536c15 | ||
|
|
9ec7f32473 | ||
|
|
191c797de3 | ||
|
|
a6610d8e9c | ||
|
|
9ca3361c2f | ||
|
|
8046bb60f0 | ||
|
|
9c13f0dfc3 | ||
|
|
ad2cf62c45 | ||
|
|
ab021f9868 | ||
|
|
c5b7d268b3 | ||
|
|
2b07bd0f1c | ||
|
|
dcd83db15e | ||
|
|
bc3c4163ab | ||
|
|
91050ba458 | ||
|
|
197c583ea6 | ||
|
|
f3c58570f7 | ||
|
|
888bceaa80 | ||
|
|
09335f839d | ||
|
|
74b24c0f8d | ||
|
|
55c1a93bf5 | ||
|
|
b2a8763d06 | ||
|
|
84b4456a3a | ||
|
|
1103d63f70 | ||
|
|
4c05d98e9b | ||
|
|
2b56c0eb2f | ||
|
|
cb3861b6de | ||
|
|
81791b15fe | ||
|
|
a58c0f66cd | ||
|
|
ddf7c15c6a | ||
|
|
7e437c620c | ||
|
|
3ced83e94e | ||
|
|
a6c5b80731 | ||
|
|
4d99f9ce53 | ||
|
|
3de1516747 | ||
|
|
e3a2addca0 | ||
|
|
9730b41162 | ||
|
|
027a281ae3 | ||
|
|
4b43bb1cad | ||
|
|
3a6989ce24 | ||
|
|
87d544fd26 | ||
|
|
e367cea840 | ||
|
|
b823356842 | ||
|
|
fc5185d552 | ||
|
|
c2df142df4 | ||
|
|
10cf992265 | ||
|
|
3bf385b485 | ||
|
|
62ffe4aeaf | ||
|
|
5c290c949f | ||
|
|
411b1650a0 | ||
|
|
4d1551c7d6 | ||
|
|
f7fb05891a | ||
|
|
16fd5559e9 | ||
|
|
98f7995d00 | ||
|
|
c75aafee14 | ||
|
|
10876eb773 | ||
|
|
902fc3dc35 | ||
|
|
bdc593c8ea | ||
|
|
c1aa85bba6 | ||
|
|
9e49652488 | ||
|
|
bfa7421e40 | ||
|
|
40834d1701 | ||
|
|
dc89c54c14 | ||
|
|
bc176c56ed | ||
|
|
5bb101b9a5 | ||
|
|
7797ee910c | ||
|
|
1933ca0edc | ||
|
|
8738692259 | ||
|
|
bce9626962 | ||
|
|
a774e33e14 | ||
|
|
f8576ab05d | ||
|
|
42231f5009 | ||
|
|
9e0ac761f1 | ||
|
|
be2d600810 | ||
|
|
a941bc567b | ||
|
|
48f153ed47 | ||
|
|
c6d9574d52 | ||
|
|
9cea5f96cd | ||
|
|
50bc073791 | ||
|
|
147fb64185 | ||
|
|
752562dca7 | ||
|
|
7af935469d | ||
|
|
93da201b81 | ||
|
|
af7fb5f69b | ||
|
|
4a037fd751 | ||
|
|
74ba22ce0f | ||
|
|
4a4885a905 | ||
|
|
d20a47d37a | ||
|
|
ffaa2698b2 | ||
|
|
abfe972dc2 | ||
|
|
45894a9fe4 | ||
|
|
220b1bb073 | ||
|
|
7b2a801c8c | ||
|
|
ec3f44e536 | ||
|
|
4bf5f62ed4 | ||
|
|
512358eb72 | ||
|
|
7d6d484afd | ||
|
|
7d19e25627 | ||
|
|
da8341e336 | ||
|
|
193fc72708 | ||
|
|
8ada3d34ec | ||
|
|
d87810a29c | ||
|
|
e9151e3749 | ||
|
|
e6faa86570 | ||
|
|
b8e461a901 | ||
|
|
2df7dec72b | ||
|
|
0143e8bfb8 | ||
|
|
1e792fa58b | ||
|
|
1cb4d11dc0 | ||
|
|
d116f8a1ce | ||
|
|
ef77ec21d0 | ||
|
|
119cfbd671 | ||
|
|
a5316a488f | ||
|
|
f35400ad3e | ||
|
|
6e5b5d430f | ||
|
|
bb37d90781 | ||
|
|
fa9e98d844 | ||
|
|
9baa2d004a | ||
|
|
fd235f11cf | ||
|
|
f251f64c11 | ||
|
|
195fc55496 | ||
|
|
9afffb2473 | ||
|
|
9d221b85e4 | ||
|
|
ed19969afe | ||
|
|
83915eefb4 | ||
|
|
c08335b7b2 | ||
|
|
c78a856894 | ||
|
|
9d09f82393 | ||
|
|
59c674a427 | ||
|
|
f8dca4b834 | ||
|
|
fe0c34c8ef | ||
|
|
a65358f191 | ||
|
|
0c77dab922 | ||
|
|
61ef48585c | ||
|
|
16a3f38a11 | ||
|
|
c92155cd84 | ||
|
|
4ba664da47 | ||
|
|
3a4c4eb481 | ||
|
|
e8d1b9b9e5 | ||
|
|
996877d9e5 | ||
|
|
bd334a6295 | ||
|
|
0b8dafcdf0 | ||
|
|
c7914ec68f | ||
|
|
f116c516ce | ||
|
|
7a034a6609 | ||
|
|
ecdae4cbbe | ||
|
|
aca897fa76 | ||
|
|
c49b06fdde | ||
|
|
aa2f865d5d | ||
|
|
c42a6f8386 | ||
|
|
1a31368953 | ||
|
|
253349e3eb | ||
|
|
d71a0c3e5d | ||
|
|
4f17209260 | ||
|
|
50fb67cb60 | ||
|
|
f00c82a110 | ||
|
|
9db32178b3 | ||
|
|
5e42554b2b | ||
|
|
88ee768bc7 | ||
|
|
12199da97f | ||
|
|
3c769d6579 | ||
|
|
35e906c606 | ||
|
|
63f3a9e611 | ||
|
|
99a559c202 | ||
|
|
75372ff706 | ||
|
|
be56f1ebeb | ||
|
|
43586a1178 | ||
|
|
04b3387f0e | ||
|
|
8e9364e5a4 | ||
|
|
6a0c0ae202 | ||
|
|
b6d5f53465 | ||
|
|
b55b64e86c | ||
|
|
15f9a6a0a4 | ||
|
|
5ebeb1b077 | ||
|
|
c86d7b85a4 | ||
|
|
639cf857af | ||
|
|
7ca5d56c1f | ||
|
|
883b014888 | ||
|
|
09b694095c | ||
|
|
613262d597 | ||
|
|
a8074ea23a | ||
|
|
3cf06119f7 | ||
|
|
061eb412ca | ||
|
|
a4f3caa6e7 | ||
|
|
23cb4defa3 | ||
|
|
e8fb96c55f | ||
|
|
b2e9de810e | ||
|
|
8e9835f2fa | ||
|
|
6406e1d052 | ||
|
|
58fd9b8d1d | ||
|
|
29b3d790b2 | ||
|
|
0a24aa0ac6 | ||
|
|
fbefebfb93 | ||
|
|
1f2ec0932a | ||
|
|
83bb3f97f6 | ||
|
|
c1b894959e | ||
|
|
d4ab156352 | ||
|
|
1b41848623 | ||
|
|
56894f811a | ||
|
|
9ef971a159 | ||
|
|
50ad3b64d8 | ||
|
|
b96c36f38f | ||
|
|
ff5cbc65c5 | ||
|
|
37ea791841 | ||
|
|
9acfbc30e5 | ||
|
|
dfc56f6201 | ||
|
|
7ae831381a | ||
|
|
7e89763eb9 | ||
|
|
d63dcc5dd1 | ||
|
|
49ba44fbaa | ||
|
|
e9e2e353f7 | ||
|
|
74461f91bc | ||
|
|
b6753fb076 | ||
|
|
f1372acf3f | ||
|
|
58f8b7228f | ||
|
|
f99dd6748b | ||
|
|
1aa95ab8a4 | ||
|
|
d14fd27ac1 | ||
|
|
393b1bbc0a | ||
|
|
45ccf0035e | ||
|
|
d0752736fc | ||
|
|
88c9b6d73b | ||
|
|
e424d7c6c1 | ||
|
|
1bbe200e32 | ||
|
|
ffcfe051e0 | ||
|
|
8f71861a6b | ||
|
|
f76caa5fb7 | ||
|
|
0c199126cc | ||
|
|
0b73478869 | ||
|
|
bdd6c29539 | ||
|
|
c09e4ff541 | ||
|
|
e15637ad7f | ||
|
|
f984dd16eb | ||
|
|
3abadd1ec6 | ||
|
|
8c7f77d2c7 | ||
|
|
719c9c1cd2 | ||
|
|
f5123981fa | ||
|
|
efd1f7f621 | ||
|
|
0e33f5d3d9 | ||
|
|
439d800f03 | ||
|
|
a15e73a699 | ||
|
|
186cc55d6e | ||
|
|
4d70996012 | ||
|
|
4e814a8c2e | ||
|
|
089973280d | ||
|
|
f4d2e7cd6f | ||
|
|
89d1d17b80 | ||
|
|
8bd05909e4 | ||
|
|
e1c14cc114 | ||
|
|
06a26e19ab | ||
|
|
fa067fa905 | ||
|
|
653155eda3 | ||
|
|
b8e492eda6 | ||
|
|
7b01b74ffc | ||
|
|
4d6c21d4c4 | ||
|
|
844a1355c7 | ||
|
|
ef28f4eb94 | ||
|
|
18ccb50054 | ||
|
|
e0efa00d95 | ||
|
|
2e6646bd73 | ||
|
|
c19a739ae9 | ||
|
|
a4ef4124ce | ||
|
|
5794e69d52 | ||
|
|
0a13633036 | ||
|
|
4d77e961b5 | ||
|
|
cbffc7ca09 | ||
|
|
e0eff775e2 | ||
|
|
ca83a82ba3 | ||
|
|
f30622a885 | ||
|
|
bbc19df512 | ||
|
|
11b9c3ad80 | ||
|
|
6e7229f97f | ||
|
|
e76dbcd4bf | ||
|
|
9923d162c5 | ||
|
|
660c0c74b2 | ||
|
|
10736a7a6c | ||
|
|
404dd70e9e | ||
|
|
8c2670916c | ||
|
|
2ba6b481ee | ||
|
|
3fa5aef8d4 | ||
|
|
708c549d27 | ||
|
|
943156aed3 | ||
|
|
269b7e25c1 | ||
|
|
a13de137e7 | ||
|
|
2e785df6c7 | ||
|
|
cd2a1cb30f | ||
|
|
8f737719fd | ||
|
|
250a7cb349 | ||
|
|
73f4f880cc | ||
|
|
510e812c02 | ||
|
|
f5f6f1e7aa | ||
|
|
127c9bb98c | ||
|
|
b72ea8c227 | ||
|
|
316161a3e0 | ||
|
|
bcba26a04e | ||
|
|
28cf6d36f4 | ||
|
|
b06784dfdd | ||
|
|
dfba973690 | ||
|
|
f5d5a3ca8e | ||
|
|
c293474c79 | ||
|
|
1434d4ae8f | ||
|
|
af17cb2c0c | ||
|
|
f3243de08b | ||
|
|
ec157f7811 | ||
|
|
4c5c0974ad | ||
|
|
784284969e | ||
|
|
173b99c76a | ||
|
|
afb83e3007 | ||
|
|
001dc88dc9 | ||
|
|
b1eb083746 | ||
|
|
c3e4cb5069 | ||
|
|
4b70448823 | ||
|
|
08166c0a64 | ||
|
|
3ca220ef17 | ||
|
|
1a4888b050 | ||
|
|
5799cfdcf2 | ||
|
|
df7487ec01 | ||
|
|
0d0de71840 | ||
|
|
e65cfe00c1 | ||
|
|
fc8063a223 | ||
|
|
3e2690a1ad | ||
|
|
f7eb6a29d5 | ||
|
|
1b898d5b31 | ||
|
|
dcace8924e | ||
|
|
9eaf496d72 | ||
|
|
ca2749dcc0 | ||
|
|
410cd1c7b1 | ||
|
|
3315c43295 | ||
|
|
452a0c0e25 | ||
|
|
c39bd53e2a | ||
|
|
aca618ceef | ||
|
|
4ea217ef7b | ||
|
|
1cf1086122 | ||
|
|
16edd98300 | ||
|
|
e05e17c22e | ||
|
|
60f6a07014 | ||
|
|
8d9282811b | ||
|
|
52ecac7336 | ||
|
|
5a4fc712a9 | ||
|
|
06b0ce621f | ||
|
|
2d17ec41b6 | ||
|
|
e6eb7a9768 | ||
|
|
989165d71c | ||
|
|
0b5b3b22b4 | ||
|
|
dafd68b392 | ||
|
|
84b99687c9 | ||
|
|
2fd2167665 | ||
|
|
983409037c | ||
|
|
2016448471 | ||
|
|
19ddb61d18 | ||
|
|
14df1ac6df | ||
|
|
701e9e2684 | ||
|
|
3895d79e5c | ||
|
|
93bec5e14b | ||
|
|
efdc14e1d5 | ||
|
|
42961b9dd5 | ||
|
|
568988b435 | ||
|
|
79b52e4c66 | ||
|
|
0948c353e5 | ||
|
|
473f8dfbb8 | ||
|
|
599faba94e | ||
|
|
29fcb3dc35 | ||
|
|
c2413b63f7 | ||
|
|
4d12ea0941 | ||
|
|
b6cce50ccc | ||
|
|
863e368ff5 | ||
|
|
870685995d | ||
|
|
3d47fd503d | ||
|
|
57c2e75a59 | ||
|
|
7fac962c09 | ||
|
|
8cfd3756c4 | ||
|
|
867d4cd096 | ||
|
|
1e7f436448 | ||
|
|
30f150fc91 | ||
|
|
e3e2758bfb | ||
|
|
6881dcc710 | ||
|
|
21f2e88d83 | ||
|
|
314f819940 | ||
|
|
bfd50b97e2 | ||
|
|
3f2be59056 | ||
|
|
ed163aea82 | ||
|
|
246c5e4526 | ||
|
|
e636f99c48 | ||
|
|
e4fe2b49f4 | ||
|
|
f92ce8bf51 | ||
|
|
20a6c75ba4 | ||
|
|
5b947090f4 | ||
|
|
f153516151 | ||
|
|
01155a655a | ||
|
|
152c5d2049 | ||
|
|
cebc77085f | ||
|
|
0fe839add0 | ||
|
|
9acba84acc | ||
|
|
68b9fbf796 | ||
|
|
4f0c35b848 | ||
|
|
244f573197 | ||
|
|
5577d38129 | ||
|
|
925d53484f | ||
|
|
afecaf6d54 | ||
|
|
aa5ea1a3ce | ||
|
|
e640122d3f | ||
|
|
0ca8f41114 | ||
|
|
1c09d4434b | ||
|
|
f7c39aaf3b | ||
|
|
e4d477b0e0 | ||
|
|
6a14434cff | ||
|
|
e4e6169f7f | ||
|
|
b69508fb6b | ||
|
|
0527c883b9 | ||
|
|
9312a7e03a | ||
|
|
6e4187cca1 | ||
|
|
c861d7a930 | ||
|
|
76c332acca | ||
|
|
a99d7fee82 | ||
|
|
54c81eb2c7 | ||
|
|
58bf488ad0 | ||
|
|
d30f60809b | ||
|
|
1f789b4296 | ||
|
|
f743cedb10 | ||
|
|
09606e8ffd | ||
|
|
4c92280b7e | ||
|
|
90fa7743c3 | ||
|
|
bad95a3652 | ||
|
|
3e74e224c3 | ||
|
|
7777a3673e | ||
|
|
2c889af346 | ||
|
|
703145fc14 | ||
|
|
07c9c70426 | ||
|
|
593a1ff0d6 | ||
|
|
60e861e6e4 | ||
|
|
f5f6545ba0 | ||
|
|
4664e3ed2b | ||
|
|
45afbcb38e | ||
|
|
9883658d0f | ||
|
|
701c5b6aac | ||
|
|
f9c2e90c6b | ||
|
|
e73b3705c6 | ||
|
|
394a2b5166 | ||
|
|
915bf2cff0 | ||
|
|
6327a88b68 | ||
|
|
94d1936286 | ||
|
|
fcd8997c25 | ||
|
|
5f92b69211 | ||
|
|
c257b3e74b | ||
|
|
2062a1bf9b | ||
|
|
1d60b86b9b | ||
|
|
a0d0bc9830 | ||
|
|
17a024202b | ||
|
|
6498e0ec7a | ||
|
|
3e5255d619 | ||
|
|
acd7efd957 | ||
|
|
d01ee2a75e | ||
|
|
e730580030 | ||
|
|
cd0b3d8862 | ||
|
|
b2f46a56ea | ||
|
|
0a50371a37 | ||
|
|
55423b159a | ||
|
|
d9148edc8d | ||
|
|
da235d7aee | ||
|
|
8a13cd6c6a | ||
|
|
dd848ddd11 | ||
|
|
9e50f577a0 | ||
|
|
e981275cb1 | ||
|
|
d9ac907315 | ||
|
|
6171ea7cf3 | ||
|
|
f6bd53c15e | ||
|
|
d973ed307f | ||
|
|
5d3987dee3 | ||
|
|
a8a5a88e8f | ||
|
|
8026b6ded6 | ||
|
|
b875e9f0a2 | ||
|
|
d6f1debe22 | ||
|
|
a08dbdba05 | ||
|
|
6d6d1e230b | ||
|
|
4d893cb1f2 | ||
|
|
e8f961b13c | ||
|
|
3f117d751b | ||
|
|
74e2baeb48 | ||
|
|
49b1e69f44 | ||
|
|
dfd19187fe | ||
|
|
1394c1dcee | ||
|
|
8197f29606 | ||
|
|
f1f1a2b166 | ||
|
|
00ec1ca87a | ||
|
|
86a3e14f2d | ||
|
|
7c5f3cc0f1 | ||
|
|
c373bc22e8 | ||
|
|
9643609c31 | ||
|
|
b659d83239 | ||
|
|
eb46b5a131 | ||
|
|
fb4e1b4805 | ||
|
|
1959326c4d | ||
|
|
43a878887c |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -14,11 +14,14 @@ _ReSharper.*/
|
||||
|
||||
# binaries
|
||||
mods/*/*.dll
|
||||
mods/*/*.mdb
|
||||
/*.dll
|
||||
/*.dll.config
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.exe
|
||||
/*.so
|
||||
/*.dylib
|
||||
/*.pdb
|
||||
/*.mdb
|
||||
/*.exe
|
||||
|
||||
# backup files by various editors
|
||||
*~
|
||||
@@ -47,10 +50,6 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.perspectivev3
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
*.resources
|
||||
|
||||
# KDE
|
||||
*.kate-swp
|
||||
*.directory
|
||||
|
||||
# auto-generated documentation
|
||||
DOCUMENTATION.md
|
||||
*.html
|
||||
|
||||
45
AUTHORS
45
AUTHORS
@@ -34,13 +34,14 @@ Also thanks to:
|
||||
* Erasmus Schroder (rasco)
|
||||
* Fahrradkette
|
||||
* Frank Razenberg (zzattack)
|
||||
* Gareth Needham (Ripley`)
|
||||
* Igor Popov (ihptru)
|
||||
* Iran
|
||||
* James Dunne (jsd)
|
||||
* Jeff Harris (jeff_1amstudios)
|
||||
* Jes
|
||||
* Joakim Lindberg (booom3)
|
||||
* JOo
|
||||
* Kanar
|
||||
* Kenny Hoxworth (hoxworth)
|
||||
* Krishnakanth Mallik
|
||||
* Kyrre Soerensen (zypres)
|
||||
@@ -49,26 +50,68 @@ Also thanks to:
|
||||
* Maarten Meuris (Nyerguds)
|
||||
* Mark Olson (markolson)
|
||||
* Matthew Gatland (mgatland)
|
||||
* Matthew Uzzell (MUzzell)
|
||||
* Max621
|
||||
* Max Ugrumov (katzsmile)
|
||||
* Nukem
|
||||
* Okunev Yu Dmitry (xaionaro)
|
||||
* Olaf van der Spek
|
||||
* Paolo Chiodi (paolochiodi)
|
||||
* Paul Dovydaitis (pdovy)
|
||||
* Pizzaoverhead
|
||||
* Psydev
|
||||
* Raymond Martineau (mart0258)
|
||||
* Reaperrr
|
||||
* Riderr3
|
||||
* Sascha Biedermann (bidifx)
|
||||
* Sebastien Kerguen (xanax)
|
||||
* Taryn Hill (Phrohdoh)
|
||||
* Teemu Nieminen (Temeez)
|
||||
* Tim Mylemans (gecko)
|
||||
* Tirili
|
||||
* Tristan Keating (Kilkakon)
|
||||
* Tristan Mühlbacher (MicroBit)
|
||||
* Vladimir Komarov (VrKomarov)
|
||||
* Wuschel
|
||||
* Ian T. Jacobsen (Smilex)
|
||||
|
||||
Using Simple DirectMedia Layer distributed under
|
||||
the terms of the zlib license.
|
||||
|
||||
Using FreeType distributed under the terms of the
|
||||
FreeType License.
|
||||
|
||||
Using OpenAL Soft distributed under the GNU LGPL.
|
||||
|
||||
Using GeoLite data created by MaxMind and
|
||||
distributed under the CC BY-SA 3.0 license.
|
||||
|
||||
Using KopiLua created by Mark Feldman and
|
||||
maintained by Vinicius Jarina and distributed
|
||||
under the MIT license.
|
||||
|
||||
Using NLua created by Vinicius Jarina and
|
||||
distributed under the MIT license.
|
||||
|
||||
Using SharpFont created by Robert Rouhani and
|
||||
distributed under the MIT license.
|
||||
|
||||
Using the Tao framework and distributed under
|
||||
the MIT license.
|
||||
|
||||
Using SDL2# created by Ethan Lee and released
|
||||
under the zlib license.
|
||||
|
||||
Using FuzzyLogicLibrary (fuzzynet) by Dmitry
|
||||
Kaluzhny and released under the GNU GPL terms.
|
||||
|
||||
Using Mono.Nat by Alan McGovern and Ben
|
||||
Motmans and distributed under the MIT license.
|
||||
|
||||
Using ICSharpCode.SharpZipLib intially by Mike
|
||||
Krueger and distributed under the GNU GPL terms.
|
||||
|
||||
|
||||
Finally, special thanks goes to the original teams
|
||||
at Westwood Studios and EA for creating the classic
|
||||
games which OpenRA aims to reimagine.
|
||||
|
||||
242
CHANGELOG
242
CHANGELOG
@@ -1,6 +1,192 @@
|
||||
NEW:
|
||||
All Mods:
|
||||
Added the ability to place map beacons for highlighting areas to teammates (Hotkey: F9).
|
||||
The default pause hotkey has changed to F8.
|
||||
Structures under attack and friendly superweapon launch targets will now be highlighted on the radar.
|
||||
Fixed unloading passengers moving unnecessarily far from their transport.
|
||||
Fixed the unload cursor sometimes being displayed for transports even when they were unable to unload.
|
||||
An error dialog is now displayed when server connections are lost.
|
||||
Added AttackMove and Guard abilities to Aircraft and Helicopters.
|
||||
Aircraft and Helicopters can now be guarded by other units.
|
||||
Unified the main menu navigation between TD and other mods:
|
||||
Moved Create Game and Direct Connect facilities to the server browser.
|
||||
Added skirmish mode to RA and D2k to complement TD's skirmish mode.
|
||||
Added an Extras submenu for miscellaneous game extras.
|
||||
Husks are now rendered with a black overlay.
|
||||
Allow force fire to destroy husks.
|
||||
A player's units, and allied units, now move out of the way when blocking production facilities.
|
||||
Added cheat button to grow map resources.
|
||||
Fixed units staying selected and contributing to control groups when becoming cloaked or hidden in fog.
|
||||
Swapped the cursors used for sabotaging and capturing buildings/units.
|
||||
Added Ctrl+T shortcut for selection of all units matching the types of the currently selected ones across the screen and map.
|
||||
Added a toggle spectators to multiplayer.
|
||||
Removed the ability of commandos to plant C4 on walls.
|
||||
Order lines are now shown on unit selection.
|
||||
Fixed chat synchronization in replays.
|
||||
Added a combined shroud view of every player to the replay viewer and spectator mode.
|
||||
Improved the observer/replay view selector with teams, factions, player colors, and hotkeys.
|
||||
Added playback speed controls to replays.
|
||||
Fixed the game sometimes crashing when deploying and activating the guard cursor at the same time.
|
||||
Build time is now set when an item reaches the front of a queue, instead of immediately when queued.
|
||||
The attack cursor now changes if the target is out of range.
|
||||
The server browser will now show map details from other mods if the maps are available online.
|
||||
Fixed a crash when connecting to a server with an unavailable map.
|
||||
Added a warning dialog when force starting a match.
|
||||
Added a new mod selection window, which now appears on the first game start.
|
||||
Fixed walls not updating when neighboring sections were sold or destroyed.
|
||||
Dune 2000:
|
||||
Engineers can now regain control over husks.
|
||||
Added the Atreides grenadier from the 1.06 patch.
|
||||
Added randomized tiles for Sand and Rock terrain.
|
||||
Shroud is now displayed by default again (disable it in the lobby settings).
|
||||
Removed the build radius restrictions.
|
||||
Added the BLOXXMAS terrain tiles from the 1.06 patch.
|
||||
Saboteur can now plant C4 on vehicles.
|
||||
Added concrete plates and building weathering.
|
||||
Turrets now integrate with walls (visually, and as line building targets).
|
||||
Fixed unclickable area on the right edge of the production palette.
|
||||
Red Alert:
|
||||
Mechanics can now regain control over husks.
|
||||
Engineers are now remapped to team colors.
|
||||
Added some remap to the bottom edge of SAM sites.
|
||||
Chinook rotors now counter-rotate.
|
||||
Transports will now open their doors when at shore.
|
||||
Tanya can now plant C4 on bridges.
|
||||
Submarine torpedoes can now hit bridges when force fired.
|
||||
Increased torpedo splash damage and raised multiplier vs. concrete.
|
||||
Fixed transparency glitches in the sniper icon.
|
||||
Removed health bars and selection boxes from walls.
|
||||
Renamed Flak Truck to Mobile Flak.
|
||||
Increased the shroud reveal range of Mobile Flak from 4 to 6.
|
||||
Increased the turret rotation speed of Mobile Flak from 5 to 10.
|
||||
Increased the hitpoints of Mobile Flak from 120 to 150.
|
||||
Fixed Tanya being unavailable after using the Chronosphere on a vehicle she is in.
|
||||
Tanya can now plant C4 on vehicles.
|
||||
Decreased the cost of Mobile Radar Jammer from 1000 to 800.
|
||||
Increased the hitpoints of Shock Trooper from 80 to 100.
|
||||
Fixed Shock Trooper tooltip having the incorrect unit name.
|
||||
Removed the TakeCover trait from Shock Trooper.
|
||||
Parachute bomb air strike will reveal the whole target area.
|
||||
Adjusted AA Guns to fire their guns alternately at a high fire rate, and added contrails to their bullets.
|
||||
Decreased AA Gun ZSU-23 damage from 25 to 12.
|
||||
Increased SAM Site power cost from -20 to -40.
|
||||
Decreased SAM Site Nike damage from 100 to 50.
|
||||
Increased Radar Dome cost from 1600 to 1800.
|
||||
Added a snow variation of the Allied Barracks by Kilkakon.
|
||||
Added a desert variation of the Allied Barracks by Kilkakon.
|
||||
Added a desert variation of the Missile Silo by Kilkakon.
|
||||
Removed the temperate shellmap and improved the design and performance of the desert shellmap.
|
||||
Removed the hardcoded missions. These will be later reimplemented.
|
||||
Removed maps: Battle Lake, Crossing the River, Doughnut Hole, Ice Woods, Island Hoppers (KOTH), Mad Scramble, Nishnekolymsk, Strip Mine, Free Coasts
|
||||
Fixed spies staying on the minimap after infiltration.
|
||||
Added maps: Blitzkrieg and Burlesca by s1w.
|
||||
Added map: Seaside 2 by hamb.
|
||||
Both Allied and Soviet factions now build general-purpose mines instead of AT and AP mines respectively.
|
||||
Added new attack-move cursor artwork.
|
||||
Added Phase Transport, an Allied high-tech infantry transport which can cloak.
|
||||
Added Hijacker, a Soviet infantry unit with a vehicle hijacking ability.
|
||||
Attack Dogs, Snipers, Mobile Radar Jammers, Camo Pillboxes, Phase Transports, Radar Domes, and Spy Planes can now detect cloaked units.
|
||||
Removed the submarine detection ability from Cruiser and Transport.
|
||||
Added the submarine detection ability to Submarines and Missile Subs.
|
||||
Increased the submarine detection range of Gunboat from 3 to 4.
|
||||
Fixed Spies having an enemy color health bar when disguised as a friendly unit (occurred using the Team Health Colors setting).
|
||||
Chrono Tanks can now be teleported in groups by holding SHIFT or ALT and issuing a move order.
|
||||
Increased the maximum teleport distance in cells for Chrono Tank from 10 to 12.
|
||||
Decreased the teleport cooldown in seconds for Chrono Tank from 30 to 20.
|
||||
Added Minibibs for bibless buildings.
|
||||
Fixed Small portion of Production tab on Right side was unresponsive
|
||||
Fixed unclickable area on the right edge of the production palette.
|
||||
Tiberian Dawn:
|
||||
Engineers can now regain control over husks.
|
||||
Chinook rotors now counter-rotate.
|
||||
Commando can now plant C4 on bridges.
|
||||
Added the Asset Browser to the Extras menu.
|
||||
Removed health bars and selection boxes from walls.
|
||||
Changed Nod Obelisk HP to 600 from 400, same as Advanced Guard Tower
|
||||
Fixed dinosaurs not being able to collect crates.
|
||||
A10 air strike will only reveal the target area.
|
||||
Reduced Guard Tower vision from 7 to 6.
|
||||
Increased Guard Tower build time from 12 seconds to 24 seconds.
|
||||
Reduced Gun Turret vision from 7 to 6.
|
||||
Increased Gun Turret build time from 15 seconds to 30 seconds.
|
||||
Increased Sam Site build time from 18 seconds to 36 seconds.
|
||||
Reduced Advanced Guard Tower vision from 9 to 7.
|
||||
Increased Advanced Guard Tower build time from 24 seconds to 48 seconds.
|
||||
Reduced Obelisk vision from 8 to 7.
|
||||
Increased Obelisk build time from 36 seconds to 52 seconds.
|
||||
Decreased Tiberium damage rate by a factor of 3.
|
||||
Decreased Visceroid health by 25% and removed their ability to gain experience.
|
||||
Increased the chance of Tiberium or chemical deaths spawning a Visceroid from 2% to 10%.
|
||||
Increased Obelisk of Light laser damage from 200 to 360.
|
||||
Fixed Obelisk of Light charge animation and sound not playing.
|
||||
Replaced or improved several mouse cursors.
|
||||
Added Minibibs for bibless buildings.
|
||||
The Construction Yard fans now turn in the color picker preview.
|
||||
The chance of artillery exploding on death has been reduced from 100% to 75%.
|
||||
Fixed Chinook being unable to land on tiberium.
|
||||
Engine:
|
||||
Converted Aircraft CruiseAltitude to world coordinates.
|
||||
Converted Health Radius to world coordinates.
|
||||
Converted production exits to world coordinates.
|
||||
Converted weapon projectiles to world coordinates.
|
||||
Converted actor speed to world coordinates.
|
||||
Added support for rectangular cells with forced perspective.
|
||||
Added initial support for Tmp(TS) sprites.
|
||||
Added GainsUnitUpgrades trait for leveling specific unit upgrades - firepower, armor, speed.
|
||||
Added support for crates to level up specific unit upgrades.
|
||||
Merged CrateDrop functionality into CrateSpawner.
|
||||
Added support to CrateSpawner for spawning multiple types of crates.
|
||||
Added a new Launch.Replay=$FILEPATH parameter for OpenRA.Game.exe to instantly start watching a *.rep file.
|
||||
Added HackyAI settings: ExcessPowerFactor, MinimumExcessPower, IdleBaseUnitsMaximum, RushAttackScanRadius, ProtectUnitScanRadius, RallyPointScanRadius. See the traits documentation for more information.
|
||||
Added HitAnimPalette trait for LaserZap projectiles. Laser hit animations can now specify individual palettes. Defaults to effect palette.
|
||||
Added RenderNameTag trait to show the player's name above an actor.
|
||||
Fixed performance issues with units pathing to naval transports.
|
||||
Fixed unit moving to transports that have moved.
|
||||
Updated shroud-based traits to use world units.
|
||||
Renamed AttackTesla into AttackCharge and un-hardcoded initial charge delay and delay for additional charges.
|
||||
Updated RenderBuildingCharge so you can set a custom charge sequence name (default is active).
|
||||
Added IEffectiveOwner interface for traits/logic that temporarily alter an actor's apparent owner.
|
||||
Renamed Spy trait to Disguise, SpyToolTip trait to DisguiseToolTip, and RenderSpy trait to RenderDisguise.
|
||||
Overhauled the internal map management and preview generation code.
|
||||
Muzzleflash definitions have moved from WithMuzzleFlash to each Armament. Only one WithMuzzleFlash is now required per actor.
|
||||
Added an AttackGarrisoned trait that allows passengers to fire through a set of defined ports.
|
||||
Maps can define initial cargo for actors by adding "Cargo: actora, actorb, ..." to the actor reference.
|
||||
Modified Teleport activity to use the best/closest open cell to the target destination for teleports (for ChronoshiftPower this only applies on the return trip).
|
||||
Renamed ChronoshiftDeploy trait to PortableChrono.
|
||||
Added LineBuildNode trait to filter which structure(s) a LineBuild actor can be attached to.
|
||||
Server:
|
||||
Message of the day is now shared between all mods and a default motd.txt gets created in the user directory.
|
||||
Asset Browser:
|
||||
Filenames are now listed in alphabetical order
|
||||
Map Editor:
|
||||
Removed legacy INI/MPR map import.
|
||||
Fixed being unable to use the flood fill tool on similar grass/snow/desert tiles.
|
||||
Utility:
|
||||
Added an improved INI/MPR map import.
|
||||
Added an --upgrade-mod feature to upgrade the yaml of mods to the latest specifications.
|
||||
Packaging:
|
||||
Removed portable install option from Windows installer as the game left without write access breaks content download and error log generation.
|
||||
Added HTML documentation to the Windows installer.
|
||||
Fixed broken FreeType 2 dependency for Fedora RPM.
|
||||
Added SDL 2 as a dependency for the RPM package.
|
||||
Mod / Custom map compatibility:
|
||||
Altitude is no longer parsed from actor templates in maps. Specify CenterPosition instead.
|
||||
system.yaml has been split into four files for all mods: system-actor.yaml, system-ai.yaml, system-player.yaml and system-world.yaml.
|
||||
Run `OpenRA.Utility.exe --upgrade-mod <mod> 20131223` to automatically upgrade mod rules.
|
||||
Run `OpenRA.Utility.exe --upgrade-map <map path> 20131223` to automatically upgrade custom map rules.
|
||||
Added a new trait Demolishable for buildings to handle the C4 demolition.
|
||||
Mods that use custom TileSize must specify both width and height.
|
||||
If you spot black tiles in your Dune 2000 ARRAKIS maps, replace them with the remaining sand and rock tiles. Go to Map → Fix Open Areas to randomize them.
|
||||
The TestFile check in mod.yaml has been renamed to TestFiles (plural!) and now supports a comma-separated list of assets that are required to load the game.
|
||||
DisabledOverlay has been split from RenderBuilding. Use it together with RequiresPower and CanPowerDown for buildings or directly with Husk.
|
||||
Added support for custom map previews that replace the minimap in the game browser and lobby. Add map.png inside the map package.
|
||||
The UI definition files have changed. Refer to the RA or TD mod.yaml and adjust the ChromeLayout of your mod.yaml to match.
|
||||
A new cursor definition is required for "attackoutsiderange".
|
||||
Mods can now include a 96x96 logo.png for the mod selector.
|
||||
Mods can now include a 296x196 preview.png for the mod selector.
|
||||
|
||||
20131223:
|
||||
All mods:
|
||||
Added global chat to the server browser.
|
||||
Fixed dead units sometimes exploding or leaving husks when they weren't in the world.
|
||||
Added hover and disabled button states [RA / D2K / TS]
|
||||
Added double click start support to the replay browser.
|
||||
@@ -13,6 +199,17 @@ NEW:
|
||||
Improved the ingame chat interface and input, with it defaulting to Team Chat.
|
||||
Redesigned the settings panel.
|
||||
Re-added move flashes.
|
||||
Added a setting to always display unit status bars (can also be toggled by hotkey).
|
||||
Added a setting for team health bar colors.
|
||||
Added a new hotkey to select all units on screen (default: CTRL + A).
|
||||
Added a new hotkey to jump to production buildings (default: TAB).
|
||||
Changed default hotkey (PageUp/Down) for build palette cycling and made reverse user configurable.
|
||||
Improved shroud/fog rendering.
|
||||
Asset Browser:
|
||||
Fixed crashes when trying to load invalid filenames or sprites with just 1 frame.
|
||||
Added support for all sprite types.
|
||||
Added palette chooser and colorpicker dropdown boxes.
|
||||
Overhauled layout.
|
||||
Red Alert:
|
||||
Added MAD Tank.
|
||||
Fixed a crash in Monster Tank Madness.
|
||||
@@ -38,6 +235,8 @@ NEW:
|
||||
Reduced Mechanic price from $800 to $500.
|
||||
Added a 20% chance to eject a driver from destroyed vehicles.
|
||||
Added production speed-ups for additional production buildings of the same type. Up to 50% faster production can be achieved with 7 production buildings.
|
||||
Decreased the Oil Derrick cash rate from every 10 seconds to every 15 seconds.
|
||||
Overhauled the Atom Bomb's damage model and introduced damage falloff over a wide radius.
|
||||
Athena:
|
||||
Reduced strategic victory timer to 3 minutes.
|
||||
Increased the size of the starting islands.
|
||||
@@ -45,6 +244,10 @@ NEW:
|
||||
Fixed ant hills using the wrong tile ID.
|
||||
Adjusted Zombie build palette position.
|
||||
Fixed attack dogs causing crashes by attacking non-infantry.
|
||||
Disabled cloak/uncloak sound for camouflaged Pillbox.
|
||||
Added two Lua-powered single player missions, ported from Red Alert's single player campaign.
|
||||
Fixed aircraft falling down not revealing shroud.
|
||||
Fixed floating crate artwork.
|
||||
Tiberian Dawn:
|
||||
C&C mod renamed to Tiberian Dawn to resolve naming ambiguities.
|
||||
Fixed Bio Lab wrongly belonging to a hostile faction in East vs West 3.
|
||||
@@ -59,31 +262,54 @@ NEW:
|
||||
Added cash tick sounds.
|
||||
Disabled the main menu target reticle showing when a window is open.
|
||||
Added a display of the faction logos when the shellmap is disabled.
|
||||
Viceroids now heal on and move faster on Tiberium.
|
||||
Implemented the original shroud artwork.
|
||||
Fixed helicopters falling down not revealing shroud.
|
||||
Fixed effect (explosions, etc) saturation when the ingame menu is activated.
|
||||
Added shadow to crate artwork.
|
||||
Dune 2000:
|
||||
Added buildable concrete walls.
|
||||
Fixed some cliffs being passable.
|
||||
Fixed infantry sometimes using the wrong animation when standing.
|
||||
Fixed A* debug overlay.
|
||||
Fixed R8 offsets for sprites with embedded palettes.
|
||||
Implemented proper spice rendering.
|
||||
Implemented the original shroud artwork.
|
||||
Engine:
|
||||
Replays are now saved in per-mod and per-version folders.
|
||||
Added password protection support for servers.
|
||||
Added language translation support.
|
||||
Added game ID and version information to exception and sync reports.
|
||||
Map folders are now explicitly specified in mod.yaml.
|
||||
Most UI widgets are now customizable in terms of font type, color, contrast and had their global defaults moved from code to metrics.yaml.
|
||||
Replaced the OS X binary launcher with a script to use a new SDL2 renderer.
|
||||
Improved cash tick sound playback.
|
||||
Added modifier support to hotkeys.
|
||||
Fixed a desync related to projectile contrails.
|
||||
Fixed corrupted replays (which would immediately desync).
|
||||
Removed runtime mod merging.
|
||||
Added support for map scripting with Lua.
|
||||
Overhauled sprite loading code.
|
||||
Improved error message when loading corrupted sprites.
|
||||
Rewritten shp(ts) parser makes more efficient use of texture space.
|
||||
Added support for the dune 2 shp and pak formats.
|
||||
Map format 6 requires the RequiresMod to be defined.
|
||||
Added a multiplicitive blend mode.
|
||||
Build system and packages:
|
||||
Added GeoIP to Makefile so it is installed properly.
|
||||
Added desktop shortcut creation support to the Makefile and Windows installer.
|
||||
COPYING and CHANGELOG are now shipped on all platforms.
|
||||
Fixed 'make docs' crashing when the game assets are not installed.
|
||||
Renamed Game.Mods launch argument to Game.Mod.
|
||||
Linux packages now install to /usr/lib/openra for consistency with other Mono applications.
|
||||
Added an optional map.yaml check to the OpenRA.Lint.exe command line tool.
|
||||
Map Editor:
|
||||
Fixed custom assets being removed when saving an oramap.
|
||||
Mod / Custom map compatibility:
|
||||
Mods can now include traits from TD and D2K in RA.
|
||||
Mods can now customize UI text settings like font type/color/contrast for most widgets and set global defaults in metrics.yaml.
|
||||
New sections MapFolders and Translations added to mod.yaml.
|
||||
Mods must now explicitly specify the mods that they can inherit maps from by defining `SupportsMapsFrom: parent_mod' in mod.yaml.
|
||||
Renamed CarpetBomb trait to AttackBomber, and additional functionality added. An Armament trait is now required to specify the weapons.
|
||||
Renamed Capture trait to ExternalCapture.
|
||||
Renamed CapturableBar trait to ExternalCapturableBar.
|
||||
@@ -99,6 +325,20 @@ NEW:
|
||||
Removed traits from World: SpatialBins.
|
||||
Added InvalidTargets property to weapons.
|
||||
Added modifier support for build palette hotkeys.
|
||||
The Requires: option for inheriting from a parent mod has been removed. Mods can directly reference the parent mod files instead.
|
||||
Icons definitions have moved from the unit's rules to its sequence.
|
||||
Mouse cursors (cursors.yaml) must now specify their file extension.
|
||||
OpenRA.Utility --png will now generate a set of frames for any sprite type [shp(td)/shp(ts)/shp(d2)/r8/tmp(td)/tmp(ra)].
|
||||
OpenRA.Utility --shp now requires a list of frames to be combined into a shp.
|
||||
Removed Utility --tmp-png, --r8, --fromd2 commands (use --png instead).
|
||||
Removed Asset Browser file extraction / conversion (use the Utility instead).
|
||||
Added OpenRA.Utility --map-preview for generating minimap previews.
|
||||
Added OpenRA.Utility --map-upgrade for updating maps from format 5 to format 6.
|
||||
The map format has been changed. All user-installed maps will be upgraded on the first mod launch, or using OpenRA.Utility --map-upgrade.
|
||||
Unified sprite loading allows any sprite type to be used anywhere: shp can now be used for terrain, and tmp for units.
|
||||
Harvestable resource definitions (ResourceTypes) have changed, and now specify their artwork using sequences.
|
||||
Shroud definitions (ShroudRenderer / ShroudPalette) have changed, and now specifies its artwork using sequences.
|
||||
Crater and smudge definitions (SmudgeLayer) have changed, and now specify their artwork using sequences.
|
||||
|
||||
20130915:
|
||||
All mods:
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GeoIP
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GeoIP
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GeoIP
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
public class Region
|
||||
{
|
||||
|
||||
5
INSTALL
5
INSTALL
@@ -29,13 +29,14 @@ or build it from the command-line with MSBuild.
|
||||
Copy both the native DLLs from .\packaging\windows
|
||||
and the CLI images from .\thirdparty to the main folder.
|
||||
|
||||
Run the game with `OpenRA.Game.exe Game.Mods=ra` for Red Alert
|
||||
or `OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer
|
||||
Run the game with `OpenRA.Game.exe Game.Mod=ra` for Red Alert
|
||||
or `OpenRA.Game.exe Game.Mod=cnc` for Command & Conquer
|
||||
|
||||
Debian/Ubuntu
|
||||
-------------
|
||||
|
||||
* mono-gmcs
|
||||
* libmono-winforms2.0-cil
|
||||
* cli-common-dev (>= 2.10)
|
||||
* freetype
|
||||
* openal
|
||||
|
||||
254
Makefile
254
Makefile
@@ -48,8 +48,10 @@ prefix ?= /usr/local
|
||||
datarootdir ?= $(prefix)/share
|
||||
datadir ?= $(datarootdir)
|
||||
bindir ?= $(prefix)/bin
|
||||
libexecdir ?= $(prefix)/lib
|
||||
BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
|
||||
DATA_INSTALL_DIR = $(DESTDIR)$(datadir)/openra
|
||||
# TODO: separate data and binaries properly
|
||||
DATA_INSTALL_DIR = $(DESTDIR)$(libexecdir)/openra
|
||||
|
||||
# install tools
|
||||
RM = rm
|
||||
@@ -63,7 +65,7 @@ INSTALL_PROGRAM = $(INSTALL) -m755
|
||||
INSTALL_DATA = $(INSTALL) -m644
|
||||
|
||||
# program targets
|
||||
CORE = fileformats rcg rgl rsdl rnull game utility geoip irc
|
||||
CORE = fileformats rcg rgl rsdl rsdl2 rnull game utility geoip irc
|
||||
TOOLS = editor tsbuild ralint
|
||||
|
||||
VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`)
|
||||
@@ -73,126 +75,124 @@ VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev
|
||||
######################## PROGRAM TARGET RULES ##########################
|
||||
#
|
||||
# Core binaries
|
||||
fileformats_SRCS := $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll
|
||||
PROGRAMS = fileformats
|
||||
fileformats_SRCS := $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll
|
||||
PROGRAMS = fileformats
|
||||
fileformats: $(fileformats_TARGET)
|
||||
|
||||
geoip_SRCS := $(shell find GeoIP/ -iname '*.cs')
|
||||
geoip_TARGET = GeoIP.dll
|
||||
geoip_KIND = library
|
||||
geoip_LIBS = $(COMMON_LIBS)
|
||||
PROGRAMS += geoip
|
||||
geoip_SRCS := $(shell find GeoIP/ -iname '*.cs')
|
||||
geoip_TARGET = GeoIP.dll
|
||||
geoip_KIND = library
|
||||
geoip_LIBS = $(COMMON_LIBS)
|
||||
PROGRAMS += geoip
|
||||
geoip: $(geoip_TARGET)
|
||||
|
||||
game_SRCS := $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
|
||||
thirdparty/Tao/Tao.OpenAl.dll thirdparty/SharpFont.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
PROGRAMS += game
|
||||
game_SRCS := $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) thirdparty/Tao/Tao.OpenAl.dll thirdparty/SharpFont.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
PROGRAMS += game
|
||||
game: $(game_TARGET)
|
||||
|
||||
irc_SRCS := $(shell find OpenRA.Irc/ -iname '*.cs')
|
||||
irc_TARGET = OpenRA.Irc.dll
|
||||
irc_KIND = library
|
||||
irc_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
irc_LIBS = $(COMMON_LIBS) $(irc_DEPS)
|
||||
PROGRAMS += irc
|
||||
irc_SRCS := $(shell find OpenRA.Irc/ -iname '*.cs')
|
||||
irc_TARGET = OpenRA.Irc.dll
|
||||
irc_KIND = library
|
||||
irc_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
irc_LIBS = $(COMMON_LIBS) $(irc_DEPS)
|
||||
PROGRAMS += irc
|
||||
irc: $(irc_TARGET)
|
||||
|
||||
# Renderer dlls
|
||||
rsdl_SRCS := $(shell find OpenRA.Renderer.SdlCommon/ -iname '*.cs')
|
||||
rsdl_TARGET = OpenRA.Renderer.SdlCommon.dll
|
||||
rsdl_KIND = library
|
||||
rsdl_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rsdl_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll \
|
||||
$(rsdl_DEPS)
|
||||
rsdl_SRCS := $(shell find OpenRA.Renderer.SdlCommon/ -iname '*.cs')
|
||||
rsdl_TARGET = OpenRA.Renderer.SdlCommon.dll
|
||||
rsdl_KIND = library
|
||||
rsdl_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rsdl_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll thirdparty/Tao/Tao.Sdl.dll $(rsdl_DEPS)
|
||||
|
||||
rcg_SRCS := $(shell find OpenRA.Renderer.Cg/ -iname '*.cs')
|
||||
rcg_TARGET = OpenRA.Renderer.Cg.dll
|
||||
rcg_KIND = library
|
||||
rcg_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET)
|
||||
rcg_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll $(rcg_DEPS)
|
||||
rcg_SRCS := $(shell find OpenRA.Renderer.Cg/ -iname '*.cs')
|
||||
rcg_TARGET = OpenRA.Renderer.Cg.dll
|
||||
rcg_KIND = library
|
||||
rcg_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET)
|
||||
rcg_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Cg.dll thirdparty/Tao/Tao.OpenGl.dll $(rcg_DEPS)
|
||||
|
||||
rgl_SRCS := $(shell find OpenRA.Renderer.Gl/ -iname '*.cs')
|
||||
rgl_TARGET = OpenRA.Renderer.Gl.dll
|
||||
rgl_KIND = library
|
||||
rgl_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET)
|
||||
rgl_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll $(rgl_DEPS)
|
||||
rgl_SRCS := $(shell find OpenRA.Renderer.Gl/ -iname '*.cs')
|
||||
rgl_TARGET = OpenRA.Renderer.Gl.dll
|
||||
rgl_KIND = library
|
||||
rgl_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET)
|
||||
rgl_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll $(rgl_DEPS)
|
||||
|
||||
rsdl2_SRCS := $(shell find OpenRA.Renderer.Sdl2/ -iname '*.cs')
|
||||
rsdl2_TARGET = OpenRA.Renderer.Sdl2.dll
|
||||
rsdl2_KIND = library
|
||||
rsdl2_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET) $(rgl_TARGET)
|
||||
rsdl2_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll thirdparty/SDL2\#.dll $(rsdl2_DEPS)
|
||||
rsdl2_SRCS := $(shell find OpenRA.Renderer.Sdl2/ -iname '*.cs')
|
||||
rsdl2_TARGET = OpenRA.Renderer.Sdl2.dll
|
||||
rsdl2_KIND = library
|
||||
rsdl2_DEPS = $(fileformats_TARGET) $(game_TARGET) $(rsdl_TARGET) $(rgl_TARGET)
|
||||
rsdl2_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.OpenGl.dll thirdparty/SDL2\#.dll $(rsdl2_DEPS)
|
||||
|
||||
rnull_SRCS := $(shell find OpenRA.Renderer.Null/ -iname '*.cs')
|
||||
rnull_TARGET = OpenRA.Renderer.Null.dll
|
||||
rnull_KIND = library
|
||||
rnull_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rnull_LIBS = $(COMMON_LIBS) $(rnull_DEPS)
|
||||
PROGRAMS += rcg rgl rsdl2 rnull rsdl
|
||||
rnull_SRCS := $(shell find OpenRA.Renderer.Null/ -iname '*.cs')
|
||||
rnull_TARGET = OpenRA.Renderer.Null.dll
|
||||
rnull_KIND = library
|
||||
rnull_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rnull_LIBS = $(COMMON_LIBS) $(rnull_DEPS)
|
||||
PROGRAMS += rcg rgl rsdl2 rnull rsdl
|
||||
renderers: $(rcg_TARGET) $(rgl_TARGET) $(rsdl2_TARGET) $(rnull_TARGET) $(rsdl_TARGET)
|
||||
|
||||
|
||||
##### Official Mods #####
|
||||
|
||||
STD_MOD_LIBS = $(fileformats_TARGET) $(game_TARGET)
|
||||
STD_MOD_LIBS = $(fileformats_TARGET) $(game_TARGET) thirdparty/KopiLua.dll thirdparty/NLua.dll
|
||||
STD_MOD_DEPS = $(STD_MOD_LIBS) $(ralint_TARGET)
|
||||
|
||||
# Red Alert
|
||||
mod_ra_SRCS := $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
mod_ra_KIND = library
|
||||
mod_ra_DEPS = $(STD_MOD_DEPS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET)
|
||||
mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET)
|
||||
PROGRAMS += mod_ra
|
||||
mod_ra_SRCS := $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
mod_ra_KIND = library
|
||||
mod_ra_DEPS = $(STD_MOD_DEPS) $(geoip_TARGET) $(irc_TARGET)
|
||||
mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(geoip_TARGET) $(irc_TARGET)
|
||||
PROGRAMS += mod_ra
|
||||
mod_ra: $(mod_ra_TARGET)
|
||||
|
||||
# Command and Conquer
|
||||
mod_cnc_SRCS := $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
mod_cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
mod_cnc_KIND = library
|
||||
mod_cnc_DEPS = $(STD_MOD_DEPS) $(mod_ra_TARGET)
|
||||
mod_cnc_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
PROGRAMS += mod_cnc
|
||||
mod_cnc_SRCS := $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
mod_cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
mod_cnc_KIND = library
|
||||
mod_cnc_DEPS = $(STD_MOD_DEPS) $(mod_ra_TARGET)
|
||||
mod_cnc_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
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)
|
||||
mod_d2k_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
PROGRAMS += mod_d2k
|
||||
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)
|
||||
mod_d2k_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
PROGRAMS += mod_d2k
|
||||
mod_d2k: $(mod_d2k_TARGET)
|
||||
|
||||
# Tiberian Sun
|
||||
mod_ts_SRCS := $(shell find OpenRA.Mods.TS/ -iname '*.cs')
|
||||
mod_ts_TARGET = mods/ts/OpenRA.Mods.TS.dll
|
||||
mod_ts_KIND = library
|
||||
mod_ts_DEPS = $(STD_MOD_DEPS) $(mod_ra_TARGET)
|
||||
mod_ts_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
PROGRAMS += mod_ts
|
||||
mod_ts_SRCS := $(shell find OpenRA.Mods.TS/ -iname '*.cs')
|
||||
mod_ts_TARGET = mods/ts/OpenRA.Mods.TS.dll
|
||||
mod_ts_KIND = library
|
||||
mod_ts_DEPS = $(STD_MOD_DEPS) $(mod_ra_TARGET)
|
||||
mod_ts_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(mod_ra_TARGET)
|
||||
PROGRAMS += mod_ts
|
||||
mod_ts: $(mod_ts_TARGET)
|
||||
|
||||
##### Tools #####
|
||||
|
||||
# Map Editor
|
||||
editor_SRCS := $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||
editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
editor_FLAGS = -win32icon:OpenRA.Editor/OpenRA.Editor.Icon.ico
|
||||
editor_SRCS := $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||
editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
editor_FLAGS = -win32icon:OpenRA.Editor/OpenRA.Editor.Icon.ico
|
||||
|
||||
PROGRAMS += editor
|
||||
PROGRAMS += editor
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
OpenRA.Editor.Form1.resources:
|
||||
@@ -200,32 +200,32 @@ OpenRA.Editor.Form1.resources:
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
|
||||
# Analyses mod yaml for easy to detect errors
|
||||
ralint_SRCS := $(shell find OpenRA.Lint/ -iname '*.cs')
|
||||
ralint_TARGET = OpenRA.Lint.exe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
PROGRAMS += ralint
|
||||
ralint_SRCS := $(shell find OpenRA.Lint/ -iname '*.cs')
|
||||
ralint_TARGET = OpenRA.Lint.exe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
PROGRAMS += ralint
|
||||
ralint: $(ralint_TARGET)
|
||||
|
||||
test:
|
||||
@mono --debug OpenRA.Lint.exe ra
|
||||
@echo "OpenRA.Lint: ra mod yaml checks passed."
|
||||
@mono --debug OpenRA.Lint.exe cnc
|
||||
@echo "OpenRA.Lint: cnc mod yaml checks passed."
|
||||
@mono --debug OpenRA.Lint.exe d2k
|
||||
@echo "OpenRA.Lint: d2k mod yaml checks passed."
|
||||
@mono --debug OpenRA.Lint.exe ts
|
||||
@echo "OpenRA.Lint: ts mod yaml checks passed."
|
||||
@echo "OpenRA.Lint: checking Red Alert mod MiniYAML..."
|
||||
@mono --debug OpenRA.Lint.exe --verbose ra
|
||||
@echo "OpenRA.Lint: checking Tiberian Dawn mod MiniYAML..."
|
||||
@mono --debug OpenRA.Lint.exe --verbose cnc
|
||||
@echo "OpenRA.Lint: checking Dune 2000 mod MiniYAML..."
|
||||
@mono --debug OpenRA.Lint.exe --verbose d2k
|
||||
@echo "OpenRA.Lint: checking Tiberian Sun mod MiniYAML..."
|
||||
@mono --debug OpenRA.Lint.exe --verbose ts
|
||||
|
||||
# Builds and exports tilesets from a bitmap
|
||||
tsbuild_SRCS := $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
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.FormBuilder.resources -resource:OpenRA.TilesetBuilder.FormNew.resources -resource:OpenRA.TilesetBuilder.Surface.resources
|
||||
PROGRAMS += tsbuild
|
||||
tsbuild_SRCS := $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
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.FormBuilder.resources -resource:OpenRA.TilesetBuilder.FormNew.resources -resource:OpenRA.TilesetBuilder.Surface.resources
|
||||
PROGRAMS += tsbuild
|
||||
OpenRA.TilesetBuilder.FormBuilder.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/FormBuilder.resx OpenRA.TilesetBuilder.FormBuilder.resources 1> /dev/null
|
||||
OpenRA.TilesetBuilder.FormNew.resources:
|
||||
@@ -238,12 +238,12 @@ tsbuild: OpenRA.TilesetBuilder.FormBuilder.resources OpenRA.TilesetBuilder.FormN
|
||||
##### Launchers / Utilities #####
|
||||
|
||||
# Backend for the launcher apps - queries game/mod info and applies actions to an install
|
||||
utility_SRCS := $(shell find OpenRA.Utility/ -iname '*.cs')
|
||||
utility_TARGET = OpenRA.Utility.exe
|
||||
utility_KIND = exe
|
||||
utility_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/ICSharpCode.SharpZipLib.dll System.Windows.Forms.dll
|
||||
PROGRAMS += utility
|
||||
utility_SRCS := $(shell find OpenRA.Utility/ -iname '*.cs')
|
||||
utility_TARGET = OpenRA.Utility.exe
|
||||
utility_KIND = exe
|
||||
utility_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/ICSharpCode.SharpZipLib.dll System.Windows.Forms.dll
|
||||
PROGRAMS += utility
|
||||
utility: $(utility_TARGET)
|
||||
|
||||
|
||||
@@ -314,6 +314,7 @@ install-core: default
|
||||
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)/mods"
|
||||
@$(CP_R) mods/common "$(DATA_INSTALL_DIR)/mods/"
|
||||
@$(CP_R) mods/cnc "$(DATA_INSTALL_DIR)/mods/"
|
||||
@$(INSTALL_PROGRAM) $(mod_cnc_TARGET) "$(DATA_INSTALL_DIR)/mods/cnc"
|
||||
@$(CP_R) mods/ra "$(DATA_INSTALL_DIR)/mods/"
|
||||
@@ -331,18 +332,21 @@ install-core: default
|
||||
@$(CP_R) cg "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) *.ttf "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) thirdparty/Tao/* "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) thirdparty/SDL2\#* "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/ICSharpCode.SharpZipLib.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/FuzzyLogicLibrary.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/SharpFont.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(CP) thirdparty/SharpFont.dll.config "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/Mono.Nat.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/KopiLua.dll "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) thirdparty/NLua.dll "$(DATA_INSTALL_DIR)"
|
||||
|
||||
@echo "#!/bin/sh" > openra
|
||||
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra
|
||||
@echo 'ROOTDIR="$${BINDIR%'"$(bindir)"'}"' >> openra
|
||||
@echo 'DATADIR="$${ROOTDIR}'"$(datadir)"'"' >> openra
|
||||
@echo 'cd "$${DATADIR}/openra"' >> openra
|
||||
@echo 'exec mono OpenRA.Game.exe "$$@"' >> openra
|
||||
@echo "#!/bin/sh" > openra
|
||||
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra
|
||||
@echo 'ROOTDIR="$${BINDIR%'"$(bindir)"'}"' >> openra
|
||||
@echo 'EXECDIR="$${ROOTDIR}'"$(libexecdir)"'"' >> openra
|
||||
@echo 'cd "$${EXECDIR}/openra"' >> openra
|
||||
@echo 'exec mono OpenRA.Game.exe "$$@"' >> openra
|
||||
@$(INSTALL_DIR) "$(BIN_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) -m +rx openra "$(BIN_INSTALL_DIR)"
|
||||
@-$(RM) openra
|
||||
@@ -352,12 +356,12 @@ install-tools: tools
|
||||
@$(INSTALL_DIR) "$(DATA_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) $(foreach prog,$(TOOLS),$($(prog)_TARGET)) "$(DATA_INSTALL_DIR)"
|
||||
|
||||
@echo "#!/bin/sh" > openra-editor
|
||||
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra-editor
|
||||
@echo 'ROOTDIR="$${BINDIR%'"$(bindir)"'}"' >> openra-editor
|
||||
@echo 'DATADIR="$${ROOTDIR}/'"$(datadir)"'"' >> openra-editor
|
||||
@echo 'cd "$${DATADIR}/openra"' >> openra-editor
|
||||
@echo 'exec mono OpenRA.Editor.exe "$$@"' >> openra-editor
|
||||
@echo "#!/bin/sh" > openra-editor
|
||||
@echo 'BINDIR=$$(dirname $$(readlink -f $$0))' >> openra-editor
|
||||
@echo 'ROOTDIR="$${BINDIR%'"$(bindir)"'}"' >> openra-editor
|
||||
@echo 'EXECDIR="$${ROOTDIR}'"$(libexecdir)"'"' >> openra-editor
|
||||
@echo 'cd "$${EXECDIR}/openra"' >> openra-editor
|
||||
@echo 'exec mono OpenRA.Editor.exe "$$@"' >> openra-editor
|
||||
@$(INSTALL_DIR) "$(BIN_INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) -m +rx openra-editor "$(BIN_INSTALL_DIR)"
|
||||
@-$(RM) openra-editor
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Editor
|
||||
if (surface.Map.IsInMap(new CVec(u, v) + pos))
|
||||
{
|
||||
var z = u + v * template.Size.X;
|
||||
if (tile[z] != null)
|
||||
if (tile[z].Length > 0)
|
||||
surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] =
|
||||
new TileReference<ushort, byte>
|
||||
{
|
||||
@@ -63,8 +63,8 @@ namespace OpenRA.Editor
|
||||
public void Preview(Surface surface, SGraphics g)
|
||||
{
|
||||
g.DrawImage(brushTemplate.Bitmap,
|
||||
surface.TileSetRenderer.TileSize.Width * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X,
|
||||
surface.TileSetRenderer.TileSize.Height * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y,
|
||||
surface.TileSetRenderer.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X,
|
||||
surface.TileSetRenderer.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y,
|
||||
brushTemplate.Bitmap.Width * surface.Zoom,
|
||||
brushTemplate.Bitmap.Height * surface.Zoom);
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace OpenRA.Editor
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var p = queue.Dequeue();
|
||||
if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace))
|
||||
if (s.Map.MapTiles.Value[p.X, p.Y].Type != replace.Type)
|
||||
continue;
|
||||
|
||||
var a = FindEdge(s, p, new CVec(-1, 0), replace);
|
||||
@@ -97,9 +97,9 @@ namespace OpenRA.Editor
|
||||
for (var x = a.X; x <= b.X; x++)
|
||||
{
|
||||
s.Map.MapTiles.Value[x, p.Y] = new TileReference<ushort, byte> { Type = brushTemplate.N, Index = (byte)0 };
|
||||
if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace))
|
||||
if (s.Map.MapTiles.Value[x, p.Y - 1].Type == replace.Type)
|
||||
maybeEnqueue(x, p.Y - 1);
|
||||
if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace))
|
||||
if (s.Map.MapTiles.Value[x, p.Y + 1].Type == replace.Type)
|
||||
maybeEnqueue(x, p.Y + 1);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var q = p + d;
|
||||
if (!s.Map.IsInMap(q)) return p;
|
||||
if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p;
|
||||
if (s.Map.MapTiles.Value[q.X, q.Y].Type != replace.Type) return p;
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
|
||||
24
OpenRA.Editor/Form1.Designer.cs
generated
24
OpenRA.Editor/Form1.Designer.cs
generated
@@ -85,8 +85,6 @@ namespace OpenRA.Editor
|
||||
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.redAlertMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miniMapExport = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miniMapToPng = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.fullMapRenderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -582,7 +580,6 @@ namespace OpenRA.Editor
|
||||
this.saveToolStripMenuItem,
|
||||
this.saveAsToolStripMenuItem,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripMenuItem1,
|
||||
this.miniMapExport,
|
||||
this.toolStripSeparator3,
|
||||
this.exitToolStripMenuItem});
|
||||
@@ -639,25 +636,6 @@ namespace OpenRA.Editor
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(120, 6);
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.redAlertMapToolStripMenuItem});
|
||||
this.toolStripMenuItem1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem1.Image")));
|
||||
this.toolStripMenuItem1.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(123, 22);
|
||||
this.toolStripMenuItem1.Text = "&Import";
|
||||
//
|
||||
// cCRedAlertMapToolStripMenuItem
|
||||
//
|
||||
this.redAlertMapToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("cCRedAlertMapToolStripMenuItem.Image")));
|
||||
this.redAlertMapToolStripMenuItem.Name = "cCRedAlertMapToolStripMenuItem";
|
||||
this.redAlertMapToolStripMenuItem.Size = new System.Drawing.Size(188, 22);
|
||||
this.redAlertMapToolStripMenuItem.Text = "&Legacy Map Format...";
|
||||
this.redAlertMapToolStripMenuItem.ToolTipText = "Import an original C&C / Red Alert and convert it to the .oramap format.";
|
||||
this.redAlertMapToolStripMenuItem.Click += new System.EventHandler(this.ImportLegacyMapClicked);
|
||||
//
|
||||
// mnuExport
|
||||
//
|
||||
this.miniMapExport.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -1097,8 +1075,6 @@ namespace OpenRA.Editor
|
||||
private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem redAlertMapToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem miniMapExport;
|
||||
private System.Windows.Forms.ToolStripMenuItem miniMapToPng;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
|
||||
|
||||
@@ -50,8 +50,8 @@ namespace OpenRA.Editor
|
||||
FileSystem.LoadFromManifest(Game.modData.Manifest);
|
||||
Rules.LoadRules(Game.modData.Manifest, new Map());
|
||||
|
||||
var mod = Game.modData.Manifest.Mods[0];
|
||||
Text = "{0} Mod Version: {1} - OpenRA Editor".F(Mod.AllMods[mod].Title, Mod.AllMods[mod].Version);
|
||||
var mod = Game.modData.Manifest.Mod;
|
||||
Text = "{0} Mod Version: {1} - OpenRA Editor".F(mod.Title, mod.Version);
|
||||
|
||||
loadedMapName = null;
|
||||
};
|
||||
@@ -145,7 +145,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
Rules.LoadRules(manifest, map);
|
||||
tileset = Rules.TileSets[map.Tileset];
|
||||
tilesetRenderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize));
|
||||
tilesetRenderer = new TileSetRenderer(tileset, manifest.TileSize);
|
||||
var shadowIndex = new int[] { 3, 4 };
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex);
|
||||
|
||||
@@ -343,6 +343,7 @@ namespace OpenRA.Editor
|
||||
SaveAsClicked(sender, e);
|
||||
else
|
||||
{
|
||||
surface1.Map.RequiresMod = currentMod;
|
||||
surface1.Map.Save(loadedMapName);
|
||||
dirty = false;
|
||||
}
|
||||
@@ -392,7 +393,8 @@ namespace OpenRA.Editor
|
||||
|
||||
if (DialogResult.OK == nmd.ShowDialog())
|
||||
{
|
||||
var map = Map.FromTileset(nmd.TheaterBox.SelectedItem as string);
|
||||
var tileset = OpenRA.Rules.TileSets[nmd.TheaterBox.SelectedItem as string];
|
||||
var map = Map.FromTileset(tileset);
|
||||
|
||||
map.Resize((int)nmd.MapWidth.Value, (int)nmd.MapHeight.Value);
|
||||
map.ResizeCordon((int)nmd.CordonLeft.Value, (int)nmd.CordonTop.Value,
|
||||
@@ -400,6 +402,7 @@ namespace OpenRA.Editor
|
||||
|
||||
map.Players.Clear();
|
||||
map.MakeDefaultPlayers();
|
||||
map.FixOpenAreas();
|
||||
|
||||
NewMap(map);
|
||||
}
|
||||
@@ -435,37 +438,6 @@ namespace OpenRA.Editor
|
||||
Close();
|
||||
}
|
||||
|
||||
void ImportLegacyMapClicked(object sender, EventArgs e)
|
||||
{
|
||||
using (var ofd = new OpenFileDialog { RestoreDirectory = true,
|
||||
Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
|
||||
if (DialogResult.OK == ofd.ShowDialog())
|
||||
{
|
||||
/* massive hack: we should be able to call NewMap() with the imported Map object,
|
||||
* but something's not right internally in it, unless loaded via the real maploader */
|
||||
|
||||
var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import");
|
||||
Directory.CreateDirectory(savePath);
|
||||
|
||||
var errors = new List<string>();
|
||||
|
||||
var map = LegacyMapImporter.Import(ofd.FileName, a => errors.Add(a));
|
||||
|
||||
if (errors.Count > 0)
|
||||
using (var eld = new ErrorListDialog(errors))
|
||||
eld.ShowDialog();
|
||||
|
||||
map.MakeDefaultPlayers();
|
||||
|
||||
map.Save(savePath);
|
||||
LoadMap(savePath);
|
||||
loadedMapName = null; /* editor needs to think this hasnt been saved */
|
||||
|
||||
Directory.Delete(savePath, true);
|
||||
MakeDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void OnFormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (!dirty) return;
|
||||
@@ -513,18 +485,7 @@ namespace OpenRA.Editor
|
||||
void FixOpenAreas(object sender, EventArgs e)
|
||||
{
|
||||
dirty = true;
|
||||
var r = new Random();
|
||||
|
||||
for (var j = surface1.Map.Bounds.Top; j < surface1.Map.Bounds.Bottom; j++)
|
||||
for (var i = surface1.Map.Bounds.Left; i < surface1.Map.Bounds.Right; i++)
|
||||
{
|
||||
var tr = surface1.Map.MapTiles.Value[i, j];
|
||||
if (tr.Type == 0xff || tr.Type == 0xffff || tr.Type == 1 || tr.Type == 2)
|
||||
tr.Index = (byte)r.Next(0, surface1.TileSetRenderer.Data(tr.Type).Count);
|
||||
|
||||
surface1.Map.MapTiles.Value[i, j] = tr;
|
||||
}
|
||||
|
||||
surface1.Map.FixOpenAreas();
|
||||
surface1.Chunks.Clear();
|
||||
surface1.Invalidate();
|
||||
}
|
||||
@@ -597,7 +558,7 @@ namespace OpenRA.Editor
|
||||
|
||||
void DeveloperBountiesToolStripMenuItemClick(object sender, EventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start("https://www.bountysource.com/#repos/OpenRA/OpenRA");
|
||||
System.Diagnostics.Process.Start("https://www.bountysource.com/trackers/36085-openra");
|
||||
}
|
||||
|
||||
void SourceCodeToolStripMenuItemClick(object sender, EventArgs e)
|
||||
@@ -700,7 +661,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
int imageLength = 0;
|
||||
int type = surface1.Map.MapResources.Value[x, y].Type;
|
||||
var template = surface1.ResourceTemplates.Where(a => a.Value.Info.ResourceType == type).FirstOrDefault().Value;
|
||||
var template = surface1.ResourceTemplates.FirstOrDefault(a => a.Value.Info.ResourceType == type).Value;
|
||||
if (type == 1)
|
||||
imageLength = 12;
|
||||
else if (type == 2)
|
||||
@@ -753,4 +714,4 @@ namespace OpenRA.Editor
|
||||
surface1.IsErasing = eraserToolStripButton.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.Editor
|
||||
if (DirectoryIsEmpty(MapFolderPath))
|
||||
return;
|
||||
|
||||
foreach (var map in ModData.FindMapsIn(MapFolderPath))
|
||||
foreach (var map in MapCache.FindMapsIn(MapFolderPath))
|
||||
{
|
||||
ListViewItem map1 = new ListViewItem();
|
||||
map1.Tag = map;
|
||||
@@ -79,7 +79,7 @@ namespace OpenRA.Editor
|
||||
}
|
||||
catch (Exception ed)
|
||||
{
|
||||
Console.WriteLine("No map preview image found: {0}", ed.ToString());
|
||||
Console.WriteLine("No map preview image found: {0}", ed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ITool.cs" />
|
||||
<Compile Include="LegacyMapImporter.cs" />
|
||||
<Compile Include="MapSelect.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -165,6 +164,7 @@
|
||||
<Compile Include="Surface.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TileSetRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -22,38 +22,11 @@ namespace OpenRA.Editor
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length >= 2 && args[0] == "--convert")
|
||||
{
|
||||
Game.modData = new ModData(args[1]);
|
||||
FileSystem.LoadFromManifest(Game.modData.Manifest);
|
||||
Rules.LoadRules(Game.modData.Manifest, new Map());
|
||||
UpgradeMaps(args[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
Application.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
Application.Run(new Form1(args));
|
||||
}
|
||||
|
||||
static void UpgradeMaps(string mod)
|
||||
{
|
||||
var mapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" }
|
||||
.Aggregate(Path.Combine);
|
||||
|
||||
foreach (var path in ModData.FindMapsIn(mapFolderPath))
|
||||
{
|
||||
var map = new Map(path);
|
||||
|
||||
// Touch the lazy bits to initialize them
|
||||
map.Actors.Force();
|
||||
map.Smudges.Force();
|
||||
map.MapTiles.Force();
|
||||
map.MapResources.Force();
|
||||
map.Save(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -18,11 +19,11 @@ namespace OpenRA.Editor
|
||||
{
|
||||
static class RenderUtils
|
||||
{
|
||||
static Bitmap RenderShp(ShpReader shp, Palette p)
|
||||
static Bitmap RenderShp(ISpriteSource shp, Palette p)
|
||||
{
|
||||
var frame = shp[0];
|
||||
var frame = shp.Frames.First();
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
||||
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
||||
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
|
||||
@@ -34,9 +35,9 @@ namespace OpenRA.Editor
|
||||
byte* q = (byte*)data.Scan0.ToPointer();
|
||||
var stride2 = data.Stride;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
|
||||
for (var i = 0; i < frame.Size.Width; i++)
|
||||
for (var j = 0; j < frame.Size.Height; j++)
|
||||
q[j * stride2 + i] = frame.Data[i + frame.Size.Width * j];
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
@@ -76,13 +77,14 @@ namespace OpenRA.Editor
|
||||
|
||||
public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p)
|
||||
{
|
||||
var image = info.SpriteNames[0];
|
||||
var image = info.EditorSprite;
|
||||
using (var s = FileSystem.OpenWithExts(image, exts))
|
||||
{
|
||||
var shp = new ShpReader(s);
|
||||
var frame = shp[shp.ImageCount - 1];
|
||||
// TODO: Do this properly
|
||||
var shp = new ShpReader(s) as ISpriteSource;
|
||||
var frame = shp.Frames.Last();
|
||||
|
||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
||||
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
@@ -92,13 +94,13 @@ namespace OpenRA.Editor
|
||||
byte* q = (byte*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride;
|
||||
|
||||
for (var i = 0; i < shp.Width; i++)
|
||||
for (var j = 0; j < shp.Height; j++)
|
||||
q[j * stride + i] = frame.Image[i + shp.Width * j];
|
||||
for (var i = 0; i < frame.Size.Width; i++)
|
||||
for (var j = 0; j < frame.Size.Height; j++)
|
||||
q[j * stride + i] = frame.Data[i + frame.Size.Width * j];
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
|
||||
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.Frames.Count() - 1 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.Editor
|
||||
= new TileReference<byte, byte>
|
||||
{
|
||||
Type = (byte)resourceTemplate.Info.ResourceType,
|
||||
Index = (byte)random.Next(resourceTemplate.Info.SpriteNames.Length)
|
||||
Index = (byte)random.Next(resourceTemplate.Info.MaxDensity)
|
||||
};
|
||||
|
||||
var ch = new int2(surface.GetBrushLocation().X / Surface.ChunkSize,
|
||||
|
||||
@@ -107,7 +107,6 @@ namespace OpenRA.Editor
|
||||
public Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
|
||||
|
||||
public Surface()
|
||||
: base()
|
||||
{
|
||||
BackColor = Color.Black;
|
||||
|
||||
@@ -258,7 +257,7 @@ namespace OpenRA.Editor
|
||||
|
||||
Bitmap RenderChunk(int u, int v)
|
||||
{
|
||||
var bitmap = new Bitmap(ChunkSize * TileSetRenderer.TileSize.Width, ChunkSize * TileSetRenderer.TileSize.Height);
|
||||
var bitmap = new Bitmap(ChunkSize * TileSetRenderer.TileSize, ChunkSize * TileSetRenderer.TileSize);
|
||||
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
||||
@@ -275,9 +274,9 @@ namespace OpenRA.Editor
|
||||
var tile = TileSetRenderer.Data(tr.Type);
|
||||
var index = (tr.Index < tile.Count) ? tr.Index : (byte)0;
|
||||
var rawImage = tile[index];
|
||||
for (var x = 0; x < TileSetRenderer.TileSize.Width; x++)
|
||||
for (var y = 0; y < TileSetRenderer.TileSize.Height; y++)
|
||||
p[(j * TileSetRenderer.TileSize.Width + y) * stride + i * TileSetRenderer.TileSize.Width + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize.Width * y]).ToArgb();
|
||||
for (var x = 0; x < TileSetRenderer.TileSize; x++)
|
||||
for (var y = 0; y < TileSetRenderer.TileSize; y++)
|
||||
p[(j * TileSetRenderer.TileSize + y) * stride + i * TileSetRenderer.TileSize + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize * y]).ToArgb();
|
||||
|
||||
if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].Type != 0)
|
||||
{
|
||||
@@ -288,12 +287,12 @@ namespace OpenRA.Editor
|
||||
int* q = (int*)srcdata.Scan0.ToPointer();
|
||||
var srcstride = srcdata.Stride >> 2;
|
||||
|
||||
for (var x = 0; x < TileSetRenderer.TileSize.Width; x++)
|
||||
for (var y = 0; y < TileSetRenderer.TileSize.Height; y++)
|
||||
for (var x = 0; x < TileSetRenderer.TileSize; x++)
|
||||
for (var y = 0; y < TileSetRenderer.TileSize; y++)
|
||||
{
|
||||
var c = q[y * srcstride + x];
|
||||
if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
|
||||
p[(j * TileSetRenderer.TileSize.Width + y) * stride + i * TileSetRenderer.TileSize.Width + x] = c;
|
||||
p[(j * TileSetRenderer.TileSize + y) * stride + i * TileSetRenderer.TileSize + x] = c;
|
||||
}
|
||||
|
||||
resourceImage.UnlockBits(srcdata);
|
||||
@@ -304,14 +303,16 @@ namespace OpenRA.Editor
|
||||
bitmap.UnlockBits(data);
|
||||
|
||||
if (ShowGrid)
|
||||
{
|
||||
using (var g = SGraphics.FromImage(bitmap))
|
||||
{
|
||||
var ts = Game.modData.Manifest.TileSize;
|
||||
var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(2, Game.CellSize), Color.DarkRed);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(Game.CellSize, 2), Color.DarkRed);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(Game.CellSize, Game.CellSize), Color.Red);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(2, ts.Height), Color.DarkRed);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(ts.Width, 2), Color.DarkRed);
|
||||
ControlPaint.DrawGrid(g, rect, new Size(ts.Width, ts.Height), Color.Red);
|
||||
}
|
||||
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@@ -319,15 +320,15 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var vX = (int)Math.Floor((mousePos.X - Offset.X) / Zoom);
|
||||
var vY = (int)Math.Floor((mousePos.Y - Offset.Y) / Zoom);
|
||||
return new CPos(vX / TileSetRenderer.TileSize.Width, vY / TileSetRenderer.TileSize.Height);
|
||||
return new CPos(vX / TileSetRenderer.TileSize, vY / TileSetRenderer.TileSize);
|
||||
}
|
||||
|
||||
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 + TileSetRenderer.TileSize.Width - 1) / TileSetRenderer.TileSize.Width,
|
||||
(vY + TileSetRenderer.TileSize.Height - 1) / TileSetRenderer.TileSize.Height);
|
||||
return new CPos((vX + TileSetRenderer.TileSize - 1) / TileSetRenderer.TileSize,
|
||||
(vY + TileSetRenderer.TileSize - 1) / TileSetRenderer.TileSize);
|
||||
}
|
||||
|
||||
public void DrawActor(SGraphics g, CPos p, ActorTemplate t, ColorPalette cp)
|
||||
@@ -341,11 +342,11 @@ namespace OpenRA.Editor
|
||||
|
||||
float2 GetDrawPosition(CPos location, Bitmap bmp, bool centered)
|
||||
{
|
||||
float offsetX = centered ? bmp.Width / 2 - TileSetRenderer.TileSize.Width / 2 : 0;
|
||||
float drawX = TileSetRenderer.TileSize.Width * location.X * Zoom + Offset.X - offsetX;
|
||||
float offsetX = centered ? bmp.Width / 2 - TileSetRenderer.TileSize / 2 : 0;
|
||||
float drawX = TileSetRenderer.TileSize * location.X * Zoom + Offset.X - offsetX;
|
||||
|
||||
float offsetY = centered ? bmp.Height / 2 - TileSetRenderer.TileSize.Height / 2 : 0;
|
||||
float drawY = TileSetRenderer.TileSize.Height * location.Y * Zoom + Offset.Y - offsetY;
|
||||
float offsetY = centered ? bmp.Height / 2 - TileSetRenderer.TileSize / 2 : 0;
|
||||
float drawY = TileSetRenderer.TileSize * location.Y * Zoom + Offset.Y - offsetY;
|
||||
|
||||
return new float2(drawX, drawY);
|
||||
}
|
||||
@@ -413,24 +414,24 @@ namespace OpenRA.Editor
|
||||
|
||||
var bmp = Chunks[x];
|
||||
|
||||
var drawX = TileSetRenderer.TileSize.Width * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
var drawY = TileSetRenderer.TileSize.Height * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
|
||||
var drawX = TileSetRenderer.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
|
||||
var drawY = TileSetRenderer.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
|
||||
RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
|
||||
RectangleF destRect = new RectangleF(drawX, drawY, bmp.Width * Zoom, bmp.Height * Zoom);
|
||||
e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(CordonPen,
|
||||
Map.Bounds.Left * TileSetRenderer.TileSize.Width * Zoom + Offset.X,
|
||||
Map.Bounds.Top * TileSetRenderer.TileSize.Height * Zoom + Offset.Y,
|
||||
Map.Bounds.Width * TileSetRenderer.TileSize.Width * Zoom,
|
||||
Map.Bounds.Height * TileSetRenderer.TileSize.Height * Zoom);
|
||||
Map.Bounds.Left * TileSetRenderer.TileSize * Zoom + Offset.X,
|
||||
Map.Bounds.Top * TileSetRenderer.TileSize * Zoom + Offset.Y,
|
||||
Map.Bounds.Width * TileSetRenderer.TileSize * Zoom,
|
||||
Map.Bounds.Height * TileSetRenderer.TileSize * Zoom);
|
||||
|
||||
e.Graphics.DrawRectangle(SelectionPen,
|
||||
(SelectionStart.X * TileSetRenderer.TileSize.Width * Zoom) + Offset.X,
|
||||
(SelectionStart.Y * TileSetRenderer.TileSize.Height * Zoom) + Offset.Y,
|
||||
(SelectionEnd - SelectionStart).X * TileSetRenderer.TileSize.Width * Zoom,
|
||||
(SelectionEnd - SelectionStart).Y * TileSetRenderer.TileSize.Height * Zoom);
|
||||
(SelectionStart.X * TileSetRenderer.TileSize * Zoom) + Offset.X,
|
||||
(SelectionStart.Y * TileSetRenderer.TileSize * Zoom) + Offset.Y,
|
||||
(SelectionEnd - SelectionStart).X * TileSetRenderer.TileSize * Zoom,
|
||||
(SelectionEnd - SelectionStart).Y * TileSetRenderer.TileSize * Zoom);
|
||||
|
||||
if (IsPaste)
|
||||
{
|
||||
@@ -439,10 +440,10 @@ namespace OpenRA.Editor
|
||||
var height = Math.Abs((SelectionStart - SelectionEnd).Y);
|
||||
|
||||
e.Graphics.DrawRectangle(PastePen,
|
||||
(loc.X * TileSetRenderer.TileSize.Width * Zoom) + Offset.X,
|
||||
(loc.Y * TileSetRenderer.TileSize.Height * Zoom) + Offset.Y,
|
||||
width * (TileSetRenderer.TileSize.Width * Zoom),
|
||||
height * (TileSetRenderer.TileSize.Height * Zoom));
|
||||
(loc.X * TileSetRenderer.TileSize * Zoom) + Offset.X,
|
||||
(loc.Y * TileSetRenderer.TileSize * Zoom) + Offset.Y,
|
||||
width * (TileSetRenderer.TileSize * Zoom),
|
||||
height * (TileSetRenderer.TileSize * Zoom));
|
||||
}
|
||||
|
||||
foreach (var ar in Map.Actors.Value)
|
||||
@@ -458,8 +459,8 @@ namespace OpenRA.Editor
|
||||
foreach (var ar in Map.Actors.Value)
|
||||
if (!ar.Key.StartsWith("Actor")) // if it has a custom name
|
||||
e.Graphics.DrawStringContrast(Font, ar.Key,
|
||||
(int)(ar.Value.Location().X * TileSetRenderer.TileSize.Width * Zoom + Offset.X),
|
||||
(int)(ar.Value.Location().Y * TileSetRenderer.TileSize.Height * Zoom + Offset.Y),
|
||||
(int)(ar.Value.Location().X * TileSetRenderer.TileSize * Zoom + Offset.X),
|
||||
(int)(ar.Value.Location().Y * TileSetRenderer.TileSize * Zoom + Offset.Y),
|
||||
Brushes.White,
|
||||
Brushes.Black);
|
||||
|
||||
@@ -469,7 +470,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
if (i % 8 == 0)
|
||||
{
|
||||
PointF point = new PointF(i * TileSetRenderer.TileSize.Width * Zoom + Offset.X, (Map.Bounds.Top - 8) * TileSetRenderer.TileSize.Height * Zoom + Offset.Y);
|
||||
PointF point = new PointF(i * TileSetRenderer.TileSize * Zoom + Offset.X, (Map.Bounds.Top - 8) * TileSetRenderer.TileSize * Zoom + Offset.Y);
|
||||
e.Graphics.DrawString((i - Map.Bounds.Left).ToString(), MarkerFont, TextBrush, point);
|
||||
}
|
||||
}
|
||||
@@ -478,7 +479,7 @@ namespace OpenRA.Editor
|
||||
{
|
||||
if (i % 8 == 0)
|
||||
{
|
||||
PointF point = new PointF((Map.Bounds.Left - 8) * TileSetRenderer.TileSize.Width * Zoom + Offset.X, i * TileSetRenderer.TileSize.Height * Zoom + Offset.Y);
|
||||
PointF point = new PointF((Map.Bounds.Left - 8) * TileSetRenderer.TileSize * Zoom + Offset.X, i * TileSetRenderer.TileSize * Zoom + Offset.Y);
|
||||
e.Graphics.DrawString((i - Map.Bounds.Left).ToString(), MarkerFont, TextBrush, point);
|
||||
}
|
||||
}
|
||||
@@ -490,7 +491,7 @@ namespace OpenRA.Editor
|
||||
if (currentTool == null)
|
||||
{
|
||||
var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
|
||||
if (x.Key != null)
|
||||
if (x.Key != null && actorTemplates.ContainsKey(x.Value.Type))
|
||||
DrawActorBorder(e.Graphics, x.Value.Location(), actorTemplates[x.Value.Type]);
|
||||
}
|
||||
}
|
||||
|
||||
133
OpenRA.Editor/TileSetRenderer.cs
Normal file
133
OpenRA.Editor/TileSetRenderer.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Editor
|
||||
{
|
||||
public class TileSetRenderer
|
||||
{
|
||||
public TileSet TileSet;
|
||||
Dictionary<ushort, List<byte[]>> templates;
|
||||
public readonly int TileSize;
|
||||
|
||||
// Extract a square tile that the editor can render
|
||||
byte[] ExtractSquareTile(ISpriteFrame frame)
|
||||
{
|
||||
var data = new byte[TileSize * TileSize];
|
||||
|
||||
// Invalid tile size: return blank tile
|
||||
if (frame.Size.Width < TileSize || frame.Size.Height < TileSize)
|
||||
return new byte[0];
|
||||
|
||||
var frameData = frame.Data;
|
||||
var xOffset = (frame.Size.Width - TileSize) / 2;
|
||||
var yOffset = (frame.Size.Height - TileSize) / 2;
|
||||
|
||||
for (var y = 0; y < TileSize; y++)
|
||||
for (var x = 0; x < TileSize; x++)
|
||||
data[y * TileSize + x] = frameData[(yOffset + y) * frame.Size.Width + x + xOffset];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
List<byte[]> LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
|
||||
{
|
||||
ISpriteSource source;
|
||||
if (!sourceCache.ContainsKey(filename))
|
||||
{
|
||||
using (var s = FileSystem.OpenWithExts(filename, exts))
|
||||
source = SpriteSource.LoadSpriteSource(s, filename);
|
||||
|
||||
if (source.CacheWhenLoadingTileset)
|
||||
sourceCache.Add(filename, source);
|
||||
}
|
||||
else
|
||||
source = sourceCache[filename];
|
||||
|
||||
if (frames != null)
|
||||
{
|
||||
var ret = new List<byte[]>();
|
||||
var srcFrames = source.Frames.ToArray();
|
||||
foreach (var i in frames)
|
||||
ret.Add(ExtractSquareTile(srcFrames[i]));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return source.Frames.Select(f => ExtractSquareTile(f)).ToList();
|
||||
}
|
||||
|
||||
public TileSetRenderer(TileSet tileset, Size tileSize)
|
||||
{
|
||||
this.TileSet = tileset;
|
||||
this.TileSize = Math.Min(tileSize.Width, tileSize.Height);
|
||||
|
||||
templates = new Dictionary<ushort, List<byte[]>>();
|
||||
var sourceCache = new Dictionary<string, ISpriteSource>();
|
||||
foreach (var t in TileSet.Templates)
|
||||
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
|
||||
}
|
||||
|
||||
public Bitmap RenderTemplate(ushort id, Palette p)
|
||||
{
|
||||
var template = TileSet.Templates[id];
|
||||
var templateData = templates[id];
|
||||
|
||||
var bitmap = new Bitmap(TileSize * template.Size.X, TileSize * template.Size.Y,
|
||||
PixelFormat.Format8bppIndexed);
|
||||
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
{
|
||||
var q = (byte*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride;
|
||||
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
{
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
{
|
||||
var rawImage = templateData[u + v * template.Size.X];
|
||||
if (rawImage != null && rawImage.Length > 0)
|
||||
{
|
||||
for (var i = 0; i < TileSize; i++)
|
||||
for (var j = 0; j < TileSize; j++)
|
||||
q[(v * TileSize + j) * stride + u * TileSize + i] = rawImage[i + TileSize * j];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < TileSize; i++)
|
||||
for (var j = 0; j < TileSize; j++)
|
||||
q[(v * TileSize + j) * stride + u * TileSize + i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public List<byte[]> Data(ushort id)
|
||||
{
|
||||
return templates[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
CPos o = (CPos)obj;
|
||||
return o == this;
|
||||
var o = obj as CPos?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
@@ -65,11 +65,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
CVec o = (CVec)obj;
|
||||
return o == this;
|
||||
var o = obj as CVec?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1}".F(X, Y); }
|
||||
@@ -11,7 +11,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -83,12 +82,6 @@ namespace OpenRA
|
||||
return (k & mod) == mod;
|
||||
}
|
||||
|
||||
public static bool IsValidInput(this KeyInput key)
|
||||
{
|
||||
return char.IsLetter(key.UnicodeChar) || char.IsDigit(key.UnicodeChar) ||
|
||||
char.IsSymbol(key.UnicodeChar) || char.IsSeparator(key.UnicodeChar) ||
|
||||
char.IsPunctuation(key.UnicodeChar);
|
||||
}
|
||||
|
||||
public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
|
||||
where V : new()
|
||||
|
||||
@@ -247,6 +247,18 @@ namespace OpenRA.FileFormats
|
||||
return InvalidValueAction(value, fieldType, fieldName);
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(CPos))
|
||||
{
|
||||
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return new CPos(int.Parse(parts[0]), int.Parse(parts[1]));
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(CVec))
|
||||
{
|
||||
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return new CVec(int.Parse(parts[0]), int.Parse(parts[1]));
|
||||
}
|
||||
|
||||
else if (fieldType.IsEnum)
|
||||
{
|
||||
if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(value.ToLower()))
|
||||
@@ -270,6 +282,12 @@ namespace OpenRA.FileFormats
|
||||
return ret;
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(Size))
|
||||
{
|
||||
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return new Size(int.Parse(parts[0]), int.Parse(parts[1]));
|
||||
}
|
||||
|
||||
else if (fieldType == typeof(int2))
|
||||
{
|
||||
var parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -314,7 +332,7 @@ namespace OpenRA.FileFormats
|
||||
return null;
|
||||
}
|
||||
|
||||
static object ParseYesNo(string p, System.Type fieldType, string field)
|
||||
static object ParseYesNo(string p, Type fieldType, string field)
|
||||
{
|
||||
p = p.ToLowerInvariant();
|
||||
if (p == "yes") return true;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public static MiniYamlNode SaveField(object o, string field)
|
||||
{
|
||||
return new MiniYamlNode(field, FieldSaver.FormatValue(o, o.GetType().GetField(field)));
|
||||
return new MiniYamlNode(field, FormatValue(o, o.GetType().GetField(field)));
|
||||
}
|
||||
|
||||
public static string FormatValue(object v, Type t)
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace OpenRA.FileFormats
|
||||
/// A fast (native) CRC32 implementation that can be used on a regular byte arrays.
|
||||
/// </summary>
|
||||
/// <param name="data">The data from which to calculate the checksum.</param>
|
||||
/// <param name="polynomal">The polynomal.</param>
|
||||
/// <param name="polynomial">The polynomial.</param>
|
||||
/// <returns>
|
||||
/// The calculated checksum.
|
||||
/// </returns>
|
||||
@@ -115,7 +115,7 @@ namespace OpenRA.FileFormats
|
||||
/// </summary>
|
||||
/// <param name="data"> [in,out] If non-null, the.</param>
|
||||
/// <param name="len"> The length of the data data.</param>
|
||||
/// <param name="polynomal">The polynomal to xor with.</param>
|
||||
/// <param name="polynomial">The polynomal to xor with.</param>
|
||||
/// <returns>The calculated checksum.</returns>
|
||||
public static unsafe uint Calculate(byte* data, uint len, uint polynomial)
|
||||
{
|
||||
|
||||
@@ -12,25 +12,22 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public static class Format2
|
||||
{
|
||||
public static int DecodeInto(byte[] src, byte[] dest)
|
||||
public static void DecodeInto(byte[] src, byte[] dest, int destIndex)
|
||||
{
|
||||
FastByteReader r = new FastByteReader(src);
|
||||
var r = new FastByteReader(src);
|
||||
|
||||
int i = 0;
|
||||
while (!r.Done())
|
||||
{
|
||||
byte cmd = r.ReadByte();
|
||||
var cmd = r.ReadByte();
|
||||
if (cmd == 0)
|
||||
{
|
||||
byte count = r.ReadByte();
|
||||
var count = r.ReadByte();
|
||||
while (count-- > 0)
|
||||
dest[i++] = 0;
|
||||
dest[destIndex++] = 0;
|
||||
}
|
||||
else
|
||||
dest[i++] = cmd;
|
||||
dest[destIndex++] = cmd;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.FileFormats
|
||||
public byte ReadByte() { return src[offset++]; }
|
||||
public int ReadWord()
|
||||
{
|
||||
int x = ReadByte();
|
||||
var x = ReadByte();
|
||||
return x | (ReadByte() << 8);
|
||||
}
|
||||
|
||||
@@ -42,84 +42,84 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public static class Format80
|
||||
{
|
||||
static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count )
|
||||
static void ReplicatePrevious(byte[] dest, int destIndex, int srcIndex, int count)
|
||||
{
|
||||
if( srcIndex > destIndex )
|
||||
if (srcIndex > destIndex)
|
||||
throw new NotImplementedException("srcIndex > destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
if( destIndex - srcIndex == 1 )
|
||||
if (destIndex - srcIndex == 1)
|
||||
{
|
||||
for( int i = 0 ; i < count ; i++ )
|
||||
dest[ destIndex + i ] = dest[ destIndex - 1 ];
|
||||
for (var i = 0; i < count; i++)
|
||||
dest[destIndex + i] = dest[destIndex - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0 ; i < count ; i++ )
|
||||
dest[ destIndex + i ] = dest[ srcIndex + i ];
|
||||
for (var i = 0; i < count; i++)
|
||||
dest[destIndex + i] = dest[srcIndex + i];
|
||||
}
|
||||
}
|
||||
|
||||
public static int DecodeInto( byte[] src, byte[] dest )
|
||||
public static int DecodeInto(byte[] src, byte[] dest)
|
||||
{
|
||||
var ctx = new FastByteReader(src);
|
||||
int destIndex = 0;
|
||||
var destIndex = 0;
|
||||
|
||||
while( true )
|
||||
while (true)
|
||||
{
|
||||
byte i = ctx.ReadByte();
|
||||
if( ( i & 0x80 ) == 0 )
|
||||
var i = ctx.ReadByte();
|
||||
if ((i & 0x80) == 0)
|
||||
{
|
||||
// case 2
|
||||
byte secondByte = ctx.ReadByte();
|
||||
int count = ( ( i & 0x70 ) >> 4 ) + 3;
|
||||
int rpos = ( ( i & 0xf ) << 8 ) + secondByte;
|
||||
var secondByte = ctx.ReadByte();
|
||||
var count = ((i & 0x70) >> 4) + 3;
|
||||
var rpos = ((i & 0xf) << 8) + secondByte;
|
||||
|
||||
ReplicatePrevious( dest, destIndex, destIndex - rpos, count );
|
||||
ReplicatePrevious(dest, destIndex, destIndex - rpos, count);
|
||||
destIndex += count;
|
||||
}
|
||||
else if( ( i & 0x40 ) == 0 )
|
||||
else if ((i & 0x40) == 0)
|
||||
{
|
||||
// case 1
|
||||
int count = i & 0x3F;
|
||||
if( count == 0 )
|
||||
var count = i & 0x3F;
|
||||
if (count == 0)
|
||||
return destIndex;
|
||||
|
||||
ctx.CopyTo( dest, destIndex, count );
|
||||
ctx.CopyTo(dest, destIndex, count);
|
||||
destIndex += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int count3 = i & 0x3F;
|
||||
if( count3 == 0x3E )
|
||||
var count3 = i & 0x3F;
|
||||
if (count3 == 0x3E)
|
||||
{
|
||||
// case 4
|
||||
int count = ctx.ReadWord();
|
||||
byte color = ctx.ReadByte();
|
||||
var count = ctx.ReadWord();
|
||||
var color = ctx.ReadByte();
|
||||
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] = color;
|
||||
for (var end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] = color;
|
||||
}
|
||||
else if( count3 == 0x3F )
|
||||
else if (count3 == 0x3F)
|
||||
{
|
||||
// case 5
|
||||
int count = ctx.ReadWord();
|
||||
int srcIndex = ctx.ReadWord();
|
||||
if( srcIndex >= destIndex )
|
||||
var count = ctx.ReadWord();
|
||||
var srcIndex = ctx.ReadWord();
|
||||
if (srcIndex >= destIndex)
|
||||
throw new NotImplementedException("srcIndex >= destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] = dest[ srcIndex++ ];
|
||||
for (var end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] = dest[srcIndex++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// case 3
|
||||
int count = count3 + 3;
|
||||
int srcIndex = ctx.ReadWord();
|
||||
if( srcIndex >= destIndex )
|
||||
var count = count3 + 3;
|
||||
var srcIndex = ctx.ReadWord();
|
||||
if (srcIndex >= destIndex)
|
||||
throw new NotImplementedException("srcIndex >= destIndex {0} {1}".F(srcIndex, destIndex));
|
||||
|
||||
for( int end = destIndex + count ; destIndex < end ; destIndex++ )
|
||||
dest[ destIndex ] = dest[ srcIndex++ ];
|
||||
for (var end = destIndex + count; destIndex < end; destIndex++)
|
||||
dest[destIndex] = dest[srcIndex++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.FileFormats
|
||||
IniSection ProcessSection(string line)
|
||||
{
|
||||
Match m = sectionPattern.Match(line);
|
||||
if (m == null || !m.Success)
|
||||
if (!m.Success)
|
||||
return null;
|
||||
string sectionName = m.Groups[1].Value.ToLowerInvariant();
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
@@ -9,11 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace OpenRA.FileFormats
|
||||
throw new NotImplementedException("Creating .RS archives is unsupported");
|
||||
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("Creating .Z archives is unsupported");
|
||||
else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new NotImplementedException("Creating .PAK archives is unsupported");
|
||||
else
|
||||
return new Folder(filename, order, content);
|
||||
}
|
||||
@@ -77,6 +79,8 @@ namespace OpenRA.FileFormats
|
||||
return new D2kSoundResources(filename, order);
|
||||
else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new InstallShieldPackage(filename, order);
|
||||
else if (filename.EndsWith(".PAK", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new PakFile(filename, order);
|
||||
else
|
||||
return new Folder(filename, order);
|
||||
}
|
||||
@@ -97,7 +101,7 @@ namespace OpenRA.FileFormats
|
||||
name = Platform.SupportDir + name.Substring(1);
|
||||
|
||||
FolderPaths.Add(name);
|
||||
Action a = () => FileSystem.MountInner(OpenPackage(name, annotation, order++));
|
||||
Action a = () => MountInner(OpenPackage(name, annotation, order++));
|
||||
|
||||
if (optional)
|
||||
try { a(); }
|
||||
@@ -197,8 +201,8 @@ namespace OpenRA.FileFormats
|
||||
if (assemblyCache.TryGetValue(filename, out a))
|
||||
return a;
|
||||
|
||||
if (FileSystem.Exists(filename))
|
||||
using (var s = FileSystem.Open(filename))
|
||||
if (Exists(filename))
|
||||
using (var s = Open(filename))
|
||||
{
|
||||
var buf = new byte[s.Length];
|
||||
s.Read(buf, 0, buf.Length);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
97
OpenRA.FileFormats/FileSystem/Pak.cs
Normal file
97
OpenRA.FileFormats/FileSystem/Pak.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
public uint Offset;
|
||||
public uint Length;
|
||||
public string Filename;
|
||||
}
|
||||
|
||||
public class PakFile : IFolder
|
||||
{
|
||||
string filename;
|
||||
int priority;
|
||||
Dictionary<string, Entry> index;
|
||||
Stream stream;
|
||||
|
||||
public PakFile(string filename, int priority)
|
||||
{
|
||||
this.filename = filename;
|
||||
this.priority = priority;
|
||||
index = new Dictionary<string, Entry>();
|
||||
stream = FileSystem.Open(filename);
|
||||
|
||||
index = new Dictionary<string, Entry>();
|
||||
var offset = stream.ReadUInt32();
|
||||
while (offset != 0)
|
||||
{
|
||||
var file = stream.ReadASCIIZ();
|
||||
var next = stream.ReadUInt32();
|
||||
var length = (next == 0 ? (uint)stream.Length : next) - offset;
|
||||
|
||||
// Ignore duplicate files
|
||||
if (index.ContainsKey(file))
|
||||
continue;
|
||||
|
||||
index.Add(file, new Entry { Offset = offset, Length = length, Filename = file });
|
||||
offset = next;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetContent(string filename)
|
||||
{
|
||||
Entry entry;
|
||||
if (!index.TryGetValue(filename, out entry))
|
||||
return null;
|
||||
|
||||
stream.Seek(entry.Offset, SeekOrigin.Begin);
|
||||
var data = new byte[entry.Length];
|
||||
stream.Read(data, 0, (int)entry.Length);
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
public IEnumerable<uint> ClassicHashes()
|
||||
{
|
||||
foreach (var filename in index.Keys)
|
||||
yield return PackageEntry.HashFilename(filename, PackageHashType.Classic);
|
||||
}
|
||||
|
||||
public IEnumerable<uint> CrcHashes()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllFileNames()
|
||||
{
|
||||
foreach (var filename in index.Keys)
|
||||
yield return filename;
|
||||
}
|
||||
|
||||
public bool Exists(string filename)
|
||||
{
|
||||
return index.ContainsKey(filename);
|
||||
}
|
||||
|
||||
public void Write(Dictionary<string, byte[]> contents)
|
||||
{
|
||||
throw new NotImplementedException("Cannot save Pak archives.");
|
||||
}
|
||||
|
||||
public int Priority { get { return 1000 + priority; } }
|
||||
public string Name { get { return filename; } }
|
||||
}
|
||||
}
|
||||
@@ -1,144 +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
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public enum Dune2ImageFlags : int
|
||||
{
|
||||
F80_F2 = 0,
|
||||
F2 = 2,
|
||||
L16_F80_F2_1 = 1,
|
||||
L16_F80_F2_2 = 3,
|
||||
Ln_F80_F2 = 5
|
||||
}
|
||||
|
||||
public class Dune2ImageHeader
|
||||
{
|
||||
public readonly Dune2ImageFlags Flags;
|
||||
public readonly int Width;
|
||||
public readonly int Height;
|
||||
public readonly int Slices;
|
||||
public readonly int FileSize;
|
||||
public readonly int DataSize;
|
||||
|
||||
public readonly byte[] LookupTable;
|
||||
public byte[] Image;
|
||||
|
||||
public Dune2ImageHeader(Stream s)
|
||||
{
|
||||
Flags = (Dune2ImageFlags)s.ReadUInt16();
|
||||
Slices = s.ReadUInt8();
|
||||
Width = s.ReadUInt16();
|
||||
Height = s.ReadUInt8();
|
||||
FileSize = s.ReadUInt16();
|
||||
DataSize = s.ReadUInt16();
|
||||
|
||||
if (Flags == Dune2ImageFlags.L16_F80_F2_1 ||
|
||||
Flags == Dune2ImageFlags.L16_F80_F2_2 ||
|
||||
Flags == Dune2ImageFlags.Ln_F80_F2)
|
||||
{
|
||||
int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? s.ReadUInt8() : (byte)16;
|
||||
LookupTable = new byte[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
LookupTable[i] = s.ReadUInt8();
|
||||
}
|
||||
else
|
||||
{
|
||||
LookupTable = new byte[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
LookupTable[i] = (byte)i;
|
||||
LookupTable[1] = 0x7f;
|
||||
LookupTable[2] = 0x7e;
|
||||
LookupTable[3] = 0x7d;
|
||||
LookupTable[4] = 0x7c;
|
||||
}
|
||||
}
|
||||
|
||||
public Size Size
|
||||
{
|
||||
get { return new Size(Width, Height); }
|
||||
}
|
||||
}
|
||||
|
||||
public class Dune2ShpReader : IEnumerable<Dune2ImageHeader>
|
||||
{
|
||||
public readonly int ImageCount;
|
||||
|
||||
List<Dune2ImageHeader> headers = new List<Dune2ImageHeader>();
|
||||
|
||||
public Dune2ShpReader(Stream s)
|
||||
{
|
||||
ImageCount = s.ReadUInt16();
|
||||
|
||||
//Last offset is pointer to end of file.
|
||||
uint[] offsets = new uint[ImageCount + 1];
|
||||
|
||||
uint temp = s.ReadUInt32();
|
||||
|
||||
//If fourth byte in file is non-zero, the offsets are two bytes each.
|
||||
bool twoByteOffsets = (temp & 0xFF0000) > 0;
|
||||
if (twoByteOffsets)
|
||||
{
|
||||
offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes
|
||||
offsets[1] = (temp & 0xFFFF) + 2;
|
||||
}
|
||||
else
|
||||
offsets[0] = temp + 2;
|
||||
|
||||
for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++)
|
||||
offsets[i] = (twoByteOffsets ? s.ReadUInt16() : s.ReadUInt32()) + 2;
|
||||
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
s.Seek(offsets[i], SeekOrigin.Begin);
|
||||
Dune2ImageHeader header = new Dune2ImageHeader(s);
|
||||
byte[] imgData = s.ReadBytes(header.FileSize);
|
||||
header.Image = new byte[header.Height * header.Width];
|
||||
|
||||
//Decode image data
|
||||
if (header.Flags != Dune2ImageFlags.F2)
|
||||
{
|
||||
byte[] tempData = new byte[header.DataSize];
|
||||
Format80.DecodeInto(imgData, tempData);
|
||||
Format2.DecodeInto(tempData, header.Image);
|
||||
}
|
||||
else
|
||||
Format2.DecodeInto(imgData, header.Image);
|
||||
|
||||
//Lookup values in lookup table
|
||||
if (header.LookupTable != null)
|
||||
for (int j = 0; j < header.Image.Length; j++)
|
||||
header.Image[j] = header.LookupTable[header.Image[j]];
|
||||
|
||||
headers.Add(header);
|
||||
}
|
||||
}
|
||||
|
||||
public Dune2ImageHeader this[int index]
|
||||
{
|
||||
get { return headers[index]; }
|
||||
}
|
||||
|
||||
public IEnumerator<Dune2ImageHeader> GetEnumerator()
|
||||
{
|
||||
return headers.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats.Graphics
|
||||
{
|
||||
@@ -32,7 +31,7 @@ namespace OpenRA.FileFormats.Graphics
|
||||
IGraphicsDevice Create( Size size, WindowMode windowMode );
|
||||
}
|
||||
|
||||
public enum BlendMode { None, Alpha, Additive, Subtractive }
|
||||
public enum BlendMode { None, Alpha, Additive, Subtractive, Multiply }
|
||||
|
||||
public interface IGraphicsDevice
|
||||
{
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
@@ -8,22 +8,20 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class R8Image
|
||||
class R8Image : ISpriteFrame
|
||||
{
|
||||
public readonly Size Size;
|
||||
public readonly int2 Offset;
|
||||
public readonly byte[] Image;
|
||||
|
||||
// Legacy variable. Can be removed when the utility command is made sensible.
|
||||
public readonly Size FrameSize;
|
||||
public Size Size { get; private set; }
|
||||
public Size FrameSize { get; private set; }
|
||||
public float2 Offset { get; private set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public R8Image(Stream s)
|
||||
{
|
||||
@@ -53,7 +51,7 @@ namespace OpenRA.FileFormats
|
||||
// Skip alignment byte
|
||||
s.ReadUInt8();
|
||||
|
||||
Image = s.ReadBytes(width*height);
|
||||
Data = s.ReadBytes(width*height);
|
||||
|
||||
// Ignore palette
|
||||
if (type == 1 && paletteOffset != 0)
|
||||
@@ -61,33 +59,20 @@ namespace OpenRA.FileFormats
|
||||
}
|
||||
}
|
||||
|
||||
public class R8Reader : IEnumerable<R8Image>
|
||||
public class R8Reader : ISpriteSource
|
||||
{
|
||||
readonly List<R8Image> headers = new List<R8Image>();
|
||||
readonly List<R8Image> frames = new List<R8Image>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return true; } }
|
||||
|
||||
public readonly int Frames;
|
||||
public readonly int ImageCount;
|
||||
public R8Reader(Stream stream)
|
||||
{
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
headers.Add(new R8Image(stream));
|
||||
Frames++;
|
||||
frames.Add(new R8Image(stream));
|
||||
ImageCount++;
|
||||
}
|
||||
}
|
||||
|
||||
public R8Image this[int index]
|
||||
{
|
||||
get { return headers[index]; }
|
||||
}
|
||||
|
||||
public IEnumerator<R8Image> GetEnumerator()
|
||||
{
|
||||
return headers.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
114
OpenRA.FileFormats/Graphics/ShpD2Reader.cs
Normal file
114
OpenRA.FileFormats/Graphics/ShpD2Reader.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
[Flags] enum FormatFlags : int
|
||||
{
|
||||
PaletteTable = 1,
|
||||
SkipFormat80 = 2,
|
||||
VariableLengthTable = 4
|
||||
}
|
||||
|
||||
class Frame : ISpriteFrame
|
||||
{
|
||||
public Size Size { get; private set; }
|
||||
public Size FrameSize { get { return Size; } }
|
||||
public float2 Offset { get { return float2.Zero; } }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public Frame(Stream s)
|
||||
{
|
||||
var flags = (FormatFlags)s.ReadUInt16();
|
||||
s.Position += 1;
|
||||
var width = s.ReadUInt16();
|
||||
var height = s.ReadUInt8();
|
||||
Size = new Size(width, height);
|
||||
|
||||
// Subtract header size
|
||||
var dataLeft = s.ReadUInt16() - 10;
|
||||
var dataSize = s.ReadUInt16();
|
||||
|
||||
byte[] table;
|
||||
if ((flags & FormatFlags.PaletteTable) != 0)
|
||||
{
|
||||
var n = (flags & FormatFlags.VariableLengthTable) != 0 ? s.ReadUInt8() : (byte)16;
|
||||
table = new byte[n];
|
||||
for (var i = 0; i < n; i++)
|
||||
table[i] = s.ReadUInt8();
|
||||
|
||||
dataLeft -= n;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
table[i] = (byte)i;
|
||||
table[1] = 0x7f;
|
||||
table[2] = 0x7e;
|
||||
table[3] = 0x7d;
|
||||
table[4] = 0x7c;
|
||||
}
|
||||
|
||||
Data = new byte[width * height];
|
||||
|
||||
// Decode image data
|
||||
var compressed = s.ReadBytes(dataLeft);
|
||||
if ((flags & FormatFlags.SkipFormat80) == 0)
|
||||
{
|
||||
var temp = new byte[dataSize];
|
||||
Format80.DecodeInto(compressed, temp);
|
||||
compressed = temp;
|
||||
}
|
||||
|
||||
Format2.DecodeInto(compressed, Data, 0);
|
||||
|
||||
// Lookup values in lookup table
|
||||
for (var j = 0; j < Data.Length; j++)
|
||||
Data[j] = table[Data[j]];
|
||||
}
|
||||
}
|
||||
|
||||
public class ShpD2Reader : ISpriteSource
|
||||
{
|
||||
List<Frame> headers = new List<Frame>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return headers.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
|
||||
public ShpD2Reader(Stream s)
|
||||
{
|
||||
var imageCount = s.ReadUInt16();
|
||||
|
||||
// Last offset is pointer to end of file.
|
||||
var offsets = new uint[imageCount + 1];
|
||||
var temp = s.ReadUInt32();
|
||||
|
||||
// If fourth byte in file is non-zero, the offsets are two bytes each.
|
||||
var twoByteOffset = (temp & 0xFF0000) > 0;
|
||||
s.Position = 2;
|
||||
|
||||
for (var i = 0; i < imageCount + 1; i++)
|
||||
offsets[i] = (twoByteOffset ? s.ReadUInt16() : s.ReadUInt32()) + 2;
|
||||
|
||||
for (var i = 0; i < imageCount; i++)
|
||||
{
|
||||
s.Position = offsets[i];
|
||||
headers.Add(new Frame(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
@@ -15,153 +15,184 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class ImageHeader
|
||||
enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
||||
|
||||
class ImageHeader : ISpriteFrame
|
||||
{
|
||||
public uint Offset;
|
||||
public Size Size { get { return reader.Size; } }
|
||||
public Size FrameSize { get { return reader.Size; } }
|
||||
public float2 Offset { get { return float2.Zero; } }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public uint FileOffset;
|
||||
public Format Format;
|
||||
|
||||
public uint RefOffset;
|
||||
public Format RefFormat;
|
||||
public ImageHeader RefImage;
|
||||
|
||||
public byte[] Image;
|
||||
|
||||
ShpReader reader;
|
||||
// Used by ShpWriter
|
||||
public ImageHeader() { }
|
||||
|
||||
public ImageHeader( BinaryReader reader )
|
||||
public ImageHeader(Stream stream, ShpReader reader)
|
||||
{
|
||||
var data = reader.ReadUInt32();
|
||||
Offset = data & 0xffffff;
|
||||
this.reader = reader;
|
||||
var data = stream.ReadUInt32();
|
||||
FileOffset = data & 0xffffff;
|
||||
Format = (Format)(data >> 24);
|
||||
|
||||
RefOffset = reader.ReadUInt16();
|
||||
RefFormat = (Format)reader.ReadUInt16();
|
||||
RefOffset = stream.ReadUInt16();
|
||||
RefFormat = (Format)stream.ReadUInt16();
|
||||
}
|
||||
|
||||
public static readonly int SizeOnDisk = 8;
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(Offset | ((uint)Format << 24));
|
||||
writer.Write(FileOffset | ((uint)Format << 24));
|
||||
writer.Write((ushort)RefOffset);
|
||||
writer.Write((ushort)RefFormat);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
||||
|
||||
public class ShpReader
|
||||
public class ShpReader : ISpriteSource
|
||||
{
|
||||
public readonly int ImageCount;
|
||||
public readonly ushort Width;
|
||||
public readonly ushort Height;
|
||||
|
||||
public Size Size { get { return new Size(Width, Height); } }
|
||||
|
||||
readonly List<ImageHeader> headers = new List<ImageHeader>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return headers.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
public readonly Size Size;
|
||||
|
||||
int recurseDepth = 0;
|
||||
readonly int imageCount;
|
||||
|
||||
public ShpReader(Stream stream)
|
||||
{
|
||||
using (var reader = new BinaryReader(stream))
|
||||
imageCount = stream.ReadUInt16();
|
||||
stream.Position += 4;
|
||||
var width = stream.ReadUInt16();
|
||||
var height = stream.ReadUInt16();
|
||||
Size = new Size(width, height);
|
||||
|
||||
stream.Position += 4;
|
||||
for (var i = 0; i < imageCount; i++)
|
||||
headers.Add(new ImageHeader(stream, this));
|
||||
|
||||
// Skip eof and zero headers
|
||||
stream.Position += 16;
|
||||
|
||||
var offsets = headers.ToDictionary(h => h.FileOffset, h => h);
|
||||
for (var i = 0; i < imageCount; i++)
|
||||
{
|
||||
ImageCount = reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
var h = headers[i];
|
||||
if (h.Format == Format.Format20)
|
||||
h.RefImage = headers[i - 1];
|
||||
|
||||
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++)
|
||||
{
|
||||
var h = headers[ i ];
|
||||
if (h.Format == Format.Format20)
|
||||
h.RefImage = headers[i - 1];
|
||||
|
||||
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);
|
||||
else if (h.Format == Format.Format40 && !offsets.TryGetValue(h.RefOffset, out h.RefImage))
|
||||
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
|
||||
}
|
||||
|
||||
foreach (var h in headers)
|
||||
Decompress(stream, h);
|
||||
}
|
||||
|
||||
public ImageHeader this[int index]
|
||||
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
||||
{
|
||||
get { return headers[index]; }
|
||||
stream.Position = h.FileOffset;
|
||||
|
||||
// Actually, far too big. There's no length field with the correct length though :(
|
||||
var compressedLength = (int)(stream.Length - stream.Position);
|
||||
var compressedBytes = new byte[compressedLength];
|
||||
stream.Read(compressedBytes, 0, compressedLength);
|
||||
|
||||
return compressedBytes;
|
||||
}
|
||||
|
||||
void Decompress(Stream stream, ImageHeader h)
|
||||
{
|
||||
if (recurseDepth > ImageCount)
|
||||
// No extra work is required for empty frames
|
||||
if (h.Size.Width == 0 || h.Size.Height == 0)
|
||||
return;
|
||||
|
||||
if (recurseDepth > imageCount)
|
||||
throw new InvalidDataException("Format20/40 headers contain infinite loop");
|
||||
|
||||
switch(h.Format)
|
||||
switch (h.Format)
|
||||
{
|
||||
case Format.Format20:
|
||||
case Format.Format40:
|
||||
{
|
||||
if (h.RefImage.Data == null)
|
||||
{
|
||||
if (h.RefImage.Image == null)
|
||||
{
|
||||
++recurseDepth;
|
||||
Decompress(stream, h.RefImage);
|
||||
--recurseDepth;
|
||||
}
|
||||
++recurseDepth;
|
||||
Decompress(stream, h.RefImage);
|
||||
--recurseDepth;
|
||||
}
|
||||
|
||||
h.Data = CopyImageData(h.RefImage.Data);
|
||||
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
|
||||
break;
|
||||
}
|
||||
|
||||
h.Image = CopyImageData(h.RefImage.Image);
|
||||
Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
|
||||
break;
|
||||
}
|
||||
case Format.Format80:
|
||||
{
|
||||
var imageBytes = new byte[Width * Height];
|
||||
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
||||
h.Image = imageBytes;
|
||||
break;
|
||||
}
|
||||
{
|
||||
var imageBytes = new byte[Size.Width * Size.Height];
|
||||
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
||||
h.Data = imageBytes;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
||||
{
|
||||
stream.Position = h.Offset;
|
||||
// TODO: Actually, far too big. There's no length field with the correct length though :(
|
||||
var compressedLength = (int)(stream.Length - stream.Position);
|
||||
|
||||
var compressedBytes = new byte[ compressedLength ];
|
||||
stream.Read( compressedBytes, 0, compressedLength );
|
||||
|
||||
return compressedBytes;
|
||||
}
|
||||
|
||||
byte[] CopyImageData(byte[] baseImage)
|
||||
{
|
||||
var imageData = new byte[Width * Height];
|
||||
for (int i = 0 ; i < Width * Height ; i++)
|
||||
var imageData = new byte[Size.Width * Size.Height];
|
||||
for (var i = 0; i < Size.Width * Size.Height; i++)
|
||||
imageData[i] = baseImage[i];
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageHeader> Frames { get { return headers; } }
|
||||
|
||||
public static ShpReader Load(string filename)
|
||||
{
|
||||
using (var s = File.OpenRead(filename))
|
||||
return new ShpReader(s);
|
||||
}
|
||||
|
||||
public static void Write(Stream s, Size size, IEnumerable<byte[]> frames)
|
||||
{
|
||||
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
||||
|
||||
// note: end-of-file and all-zeroes headers
|
||||
var dataOffset = 14 + (compressedFrames.Length + 2) * 8;
|
||||
|
||||
using (var bw = new BinaryWriter(s))
|
||||
{
|
||||
bw.Write((ushort)compressedFrames.Length);
|
||||
bw.Write((ushort)0);
|
||||
bw.Write((ushort)0);
|
||||
bw.Write((ushort)size.Width);
|
||||
bw.Write((ushort)size.Height);
|
||||
bw.Write((uint)0);
|
||||
|
||||
foreach (var f in compressedFrames)
|
||||
{
|
||||
var ih = new ImageHeader { Format = Format.Format80, FileOffset = (uint)dataOffset };
|
||||
dataOffset += f.Length;
|
||||
|
||||
ih.WriteTo(bw);
|
||||
}
|
||||
|
||||
var eof = new ImageHeader { FileOffset = (uint)dataOffset };
|
||||
eof.WriteTo(bw);
|
||||
|
||||
var allZeroes = new ImageHeader { };
|
||||
allZeroes.WriteTo(bw);
|
||||
|
||||
foreach (var f in compressedFrames)
|
||||
bw.Write(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,615 +1,99 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
|
||||
public struct Header
|
||||
class FrameHeader : ISpriteFrame
|
||||
{
|
||||
public ushort A;
|
||||
// Unknown
|
||||
// Width and Height of the images
|
||||
public ushort Width;
|
||||
public ushort Height;
|
||||
public ushort NumImages;
|
||||
public Size Size { get; private set; }
|
||||
public Size FrameSize { get; private set; }
|
||||
public float2 Offset { get; private set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public readonly uint FileOffset;
|
||||
public readonly byte Format;
|
||||
|
||||
public FrameHeader(Stream stream, Size frameSize)
|
||||
{
|
||||
var x = stream.ReadUInt16();
|
||||
var y = stream.ReadUInt16();
|
||||
var width = stream.ReadUInt16();
|
||||
var height = stream.ReadUInt16();
|
||||
|
||||
Offset = new float2(x + 0.5f * (width - frameSize.Width), y + 0.5f * (height - frameSize.Height));
|
||||
Size = new Size(width, height);
|
||||
FrameSize = frameSize;
|
||||
|
||||
Format = stream.ReadUInt8();
|
||||
stream.Position += 11;
|
||||
FileOffset = stream.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class HeaderImage
|
||||
public class ShpTSReader : ISpriteSource
|
||||
{
|
||||
public ushort x;
|
||||
public ushort y;
|
||||
public ushort cx;
|
||||
public ushort cy;
|
||||
// cx and cy are width n height of stored image
|
||||
public byte compression;
|
||||
public byte[] align;
|
||||
public byte[] transparent;
|
||||
public int zero;
|
||||
public int offset;
|
||||
public byte[] Image;
|
||||
readonly List<FrameHeader> frames = new List<FrameHeader>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
|
||||
public ShpTSReader(Stream stream)
|
||||
{
|
||||
stream.ReadUInt16();
|
||||
var width = stream.ReadUInt16();
|
||||
var height = stream.ReadUInt16();
|
||||
var size = new Size(width, height);
|
||||
var frameCount = stream.ReadUInt16();
|
||||
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
frames.Add(new FrameHeader(stream, size));
|
||||
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
{
|
||||
var f = frames[i];
|
||||
if (f.FileOffset == 0)
|
||||
continue;
|
||||
|
||||
stream.Position = f.FileOffset;
|
||||
|
||||
// Uncompressed
|
||||
if (f.Format == 1 || f.Format == 0)
|
||||
f.Data = stream.ReadBytes(f.Size.Width * f.Size.Height);
|
||||
|
||||
// Uncompressed scanlines
|
||||
else if (f.Format == 2)
|
||||
{
|
||||
f.Data = new byte[f.Size.Width * f.Size.Height];
|
||||
for (var j = 0; j < f.Size.Height; j++)
|
||||
{
|
||||
var length = stream.ReadUInt16() - 2;
|
||||
stream.Read(f.Data, f.Size.Width * j, length);
|
||||
}
|
||||
}
|
||||
|
||||
// RLE-zero compressed scanlines
|
||||
else if (f.Format == 3)
|
||||
{
|
||||
f.Data = new byte[f.Size.Width * f.Size.Height];
|
||||
|
||||
for (var j = 0; j < f.Size.Height; j++)
|
||||
{
|
||||
var length = stream.ReadUInt16() - 2;
|
||||
Format2.DecodeInto(stream.ReadBytes(length), f.Data, j * f.Size.Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct SHPData
|
||||
{
|
||||
public HeaderImage HeaderImage;
|
||||
public byte[] Databuffer;
|
||||
public byte[] FrameImage;
|
||||
}
|
||||
|
||||
public struct SHP
|
||||
{
|
||||
public Header Header;
|
||||
public SHPData[] Data;
|
||||
}
|
||||
|
||||
|
||||
public class ShpTSReader : IEnumerable<HeaderImage>
|
||||
{
|
||||
public readonly int ImageCount;
|
||||
public readonly ushort Width;
|
||||
public readonly ushort Height;
|
||||
public readonly ushort Width2;
|
||||
public readonly ushort Height2;
|
||||
public int arroff = 0;
|
||||
public int erri = 0;
|
||||
public int errj = 0;
|
||||
public int errk = 0;
|
||||
public int errl = 0;
|
||||
|
||||
public static int FindNextOffsetFrom(SHP SHP, int Init, int Last)
|
||||
{
|
||||
int result;
|
||||
result = 0;
|
||||
Last++;
|
||||
while ((result == 0) && (Init < Last))
|
||||
{
|
||||
result = SHP.Data[Init].HeaderImage.offset;
|
||||
Init++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private readonly List<HeaderImage> headers = new List<HeaderImage>();
|
||||
|
||||
public ShpTSReader(Stream s)
|
||||
{
|
||||
|
||||
SHP SHP = new SHP();
|
||||
int FileSize;
|
||||
int x;
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
|
||||
int ImageSize;
|
||||
int NextOffset;
|
||||
|
||||
byte[] FData;
|
||||
byte cp;
|
||||
byte[] Databuffer;
|
||||
|
||||
FileSize = (int)s.Length;
|
||||
// Get Header
|
||||
SHP.Header.A = s.ReadUInt16();
|
||||
SHP.Header.Width = s.ReadUInt16();
|
||||
SHP.Header.Height = s.ReadUInt16();
|
||||
SHP.Header.NumImages = s.ReadUInt16();
|
||||
|
||||
SHP.Data = new SHPData[SHP.Header.NumImages + 1];
|
||||
|
||||
ImageCount = SHP.Header.NumImages;
|
||||
|
||||
for (x = 1; x <= SHP.Header.NumImages; x++)
|
||||
{
|
||||
SHP.Data[x].HeaderImage = new HeaderImage();
|
||||
|
||||
SHP.Data[x].HeaderImage.x = s.ReadUInt16();
|
||||
SHP.Data[x].HeaderImage.y = s.ReadUInt16();
|
||||
SHP.Data[x].HeaderImage.cx = s.ReadUInt16();
|
||||
SHP.Data[x].HeaderImage.cy = s.ReadUInt16();
|
||||
|
||||
SHP.Data[x].HeaderImage.compression = s.ReadUInt8();
|
||||
SHP.Data[x].HeaderImage.align = s.ReadBytes(3);
|
||||
s.ReadInt32();
|
||||
SHP.Data[x].HeaderImage.zero = s.ReadUInt8();
|
||||
SHP.Data[x].HeaderImage.transparent = s.ReadBytes(3);
|
||||
|
||||
SHP.Data[x].HeaderImage.offset = s.ReadInt32();
|
||||
|
||||
}
|
||||
|
||||
Width = SHP.Header.Width;
|
||||
Height = SHP.Header.Height;
|
||||
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
headers.Add(SHP.Data[i+1].HeaderImage);
|
||||
}
|
||||
|
||||
// Read and decode each image from the file
|
||||
for (x = 1; x <= SHP.Header.NumImages; x++)
|
||||
{
|
||||
headers[x - 1].Image = new byte[(Width * Height)];
|
||||
for (int i = 0; i < headers[x - 1].Image.Length; i++)
|
||||
headers[x - 1].Image[i] = 0;
|
||||
|
||||
FData = new byte[(Width * Height)];
|
||||
|
||||
// Does it really reads the frame?
|
||||
if (SHP.Data[x].HeaderImage.offset != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Now it checks the compression:
|
||||
if ((SHP.Data[x].HeaderImage.compression == 3))
|
||||
{
|
||||
// decode it
|
||||
// Compression 3
|
||||
NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages);
|
||||
if (NextOffset != 0)
|
||||
{
|
||||
|
||||
ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset;
|
||||
Databuffer = new byte[ImageSize];
|
||||
for (int i = 0; i < ImageSize; i++)
|
||||
{
|
||||
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
|
||||
Databuffer[i] = s.ReadUInt8();
|
||||
}
|
||||
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
|
||||
Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref FileSize);
|
||||
|
||||
k = 0;
|
||||
l = 0;
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
erri = i;
|
||||
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
|
||||
{
|
||||
errj = j;
|
||||
errl = l;
|
||||
errk = k;
|
||||
arroff = i + j + l;
|
||||
|
||||
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
|
||||
cp = 0;
|
||||
else
|
||||
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
|
||||
|
||||
FData[i + j + k] = cp;
|
||||
|
||||
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
|
||||
l = l + (SHP.Data[x].HeaderImage.cx - 1);
|
||||
|
||||
if (j == (Width - 1))
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
//FData = headers[x - 1].Image;
|
||||
k = 0;
|
||||
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
|
||||
if (j == (Width - 1))
|
||||
{
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ImageSize = 0;
|
||||
ImageSize = FileSize - SHP.Data[x].HeaderImage.offset;
|
||||
Databuffer = new byte[ImageSize];
|
||||
for (int i = 0; i < ImageSize; i++)
|
||||
{
|
||||
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
|
||||
Databuffer[i] = s.ReadUInt8();
|
||||
}
|
||||
SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))];
|
||||
|
||||
Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
|
||||
|
||||
k = 0;
|
||||
l = 0;
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
erri = i;
|
||||
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
|
||||
{
|
||||
errj = j;
|
||||
errl = l;
|
||||
errk = k;
|
||||
arroff = i + j + l;
|
||||
|
||||
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
|
||||
cp = 0;
|
||||
else
|
||||
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
|
||||
|
||||
FData[i + j + k] = cp;
|
||||
|
||||
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
|
||||
l = l + (SHP.Data[x].HeaderImage.cx - 1);
|
||||
|
||||
if (j == (Width - 1))
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
//FData = headers[x - 1].Image;
|
||||
k = 0;
|
||||
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
|
||||
if (j == (Width - 1))
|
||||
{
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((SHP.Data[x].HeaderImage.compression == 2))
|
||||
{
|
||||
NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages);
|
||||
if (NextOffset != 0)
|
||||
{
|
||||
ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset;
|
||||
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
|
||||
Databuffer = new byte[ImageSize];
|
||||
for (int i = 0; i < ImageSize; i++)
|
||||
{
|
||||
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
|
||||
Databuffer[i] = s.ReadUInt8();
|
||||
}
|
||||
|
||||
Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
|
||||
|
||||
k = 0;
|
||||
l = 0;
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
erri = i;
|
||||
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
|
||||
{
|
||||
errj = j;
|
||||
errl = l;
|
||||
errk = k;
|
||||
arroff = i + j + l;
|
||||
|
||||
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
|
||||
cp = 0;
|
||||
else
|
||||
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
|
||||
|
||||
FData[i + j + k] = cp;
|
||||
|
||||
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
|
||||
l = l + (SHP.Data[x].HeaderImage.cx - 1);
|
||||
|
||||
if (j == (Width - 1))
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
//FData = headers[x - 1].Image;
|
||||
k = 0;
|
||||
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
|
||||
if (j == (Width - 1))
|
||||
{
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compression 2
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageSize = 0;
|
||||
ImageSize = FileSize - SHP.Data[x].HeaderImage.offset;
|
||||
Databuffer = new byte[ImageSize];
|
||||
for (int i = 0; i < ImageSize; i++)
|
||||
{
|
||||
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
|
||||
Databuffer[i] = s.ReadUInt8();
|
||||
}
|
||||
SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))];
|
||||
Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
|
||||
|
||||
k = 0;
|
||||
l = 0;
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
erri = i;
|
||||
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
|
||||
{
|
||||
errj = j;
|
||||
errl = l;
|
||||
errk = k;
|
||||
arroff = i + j + l;
|
||||
|
||||
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
|
||||
cp = 0;
|
||||
else
|
||||
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
|
||||
|
||||
FData[i + j + k] = cp;
|
||||
|
||||
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
|
||||
l = l + (SHP.Data[x].HeaderImage.cx - 1);
|
||||
|
||||
if (j == (Width - 1))
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
//FData = headers[x - 1].Image;
|
||||
k = 0;
|
||||
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
|
||||
if (j == (Width - 1))
|
||||
{
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Compression 2
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compression 1
|
||||
ImageSize = (int)(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy);
|
||||
Databuffer = new byte[ImageSize];
|
||||
for (int i = 0; i < ImageSize; i++)
|
||||
{
|
||||
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
|
||||
Databuffer[i] = s.ReadUInt8();
|
||||
}
|
||||
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
|
||||
SHP.Data[x].Databuffer = Databuffer;
|
||||
|
||||
k = 0;
|
||||
l = 0;
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
erri = i;
|
||||
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
|
||||
{
|
||||
errj = j;
|
||||
errl = l;
|
||||
errk = k;
|
||||
arroff = i + j + l;
|
||||
|
||||
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
|
||||
cp = 0;
|
||||
else
|
||||
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
|
||||
|
||||
FData[i + j + k] = cp;
|
||||
|
||||
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
|
||||
l = l + (SHP.Data[x].HeaderImage.cx - 1);
|
||||
|
||||
if (j == (Width - 1))
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
//FData = headers[x - 1].Image;
|
||||
k = 0;
|
||||
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
{
|
||||
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
|
||||
if (j == (Width - 1))
|
||||
{
|
||||
k = k + (Width - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
// Set the shp's databuffer to the result after decompression
|
||||
}
|
||||
//Width = Width2;
|
||||
//Height = Height2;
|
||||
}
|
||||
|
||||
public HeaderImage this[int index]
|
||||
{
|
||||
get { return headers[index]; }
|
||||
}
|
||||
|
||||
public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref ushort FullValue)
|
||||
{
|
||||
FullValue = (ushort)((Byte2 * 256) + Byte1);
|
||||
}
|
||||
|
||||
public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref uint FullValue)
|
||||
{
|
||||
FullValue = (uint)((Byte2 * 256) + Byte1);
|
||||
}
|
||||
|
||||
// Compression 3:
|
||||
public static void Decode3(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max)
|
||||
{
|
||||
int SP;
|
||||
int DP;
|
||||
int x;
|
||||
int y;
|
||||
int Count;
|
||||
int v;
|
||||
int maxdp;
|
||||
ushort Pos;
|
||||
maxdp = cx * cy;
|
||||
SP = 0;
|
||||
DP = 0;
|
||||
Pos = 0;
|
||||
try
|
||||
{
|
||||
for (y = 1; y <= cy; y++)
|
||||
{
|
||||
ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos);
|
||||
|
||||
Count = Pos - 2;
|
||||
|
||||
SP = SP + 2;
|
||||
|
||||
x = 0;
|
||||
while (Count > 0)
|
||||
{
|
||||
Count = Count - 1;
|
||||
if ((SP > max) || (DP > maxdp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// SP has reached max value, exit
|
||||
v = Source[SP];
|
||||
SP++;
|
||||
if (v != 0)
|
||||
{
|
||||
if ((SP > max) || (DP > maxdp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
x++;
|
||||
Dest[DP] += (byte)v;
|
||||
}
|
||||
DP++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Count -= 1;
|
||||
v = Source[SP];
|
||||
|
||||
SP++;
|
||||
if ((x + v) > cx)
|
||||
{
|
||||
v = cx - x;
|
||||
}
|
||||
x = x + v;
|
||||
while (v > 0)
|
||||
{
|
||||
if ((SP > max) || (DP > maxdp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
v -= 1;
|
||||
Dest[DP] = 0;
|
||||
|
||||
}
|
||||
DP++;
|
||||
// SP has reached max value, exit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((SP >= max) || (DP >= maxdp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// SP has reached max value, exit
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Decode2(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max)
|
||||
{
|
||||
int SP;
|
||||
int DP;
|
||||
int y;
|
||||
int Count;
|
||||
int maxdp;
|
||||
ushort Pos;
|
||||
maxdp = cx * cy;
|
||||
SP = 0;
|
||||
DP = 0;
|
||||
Pos = 0;
|
||||
try
|
||||
{
|
||||
for (y = 1; y <= cy; y++)
|
||||
{
|
||||
ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos);
|
||||
Count = Pos - 2;
|
||||
SP += 2;
|
||||
while (Count > 0)
|
||||
{
|
||||
Count -= 1;
|
||||
if ((SP > max) || (DP > maxdp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// SP has reached max value, exit
|
||||
Dest[DP] = Source[SP];
|
||||
SP++;
|
||||
DP++;
|
||||
}
|
||||
if ((SP >= max) || (DP >= maxdp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// SP has reached max value, exit
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<HeaderImage> GetEnumerator()
|
||||
{
|
||||
return headers.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Size Size { get { return new Size(Width, Height); } }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats.Graphics
|
||||
{
|
||||
// format80-only SHP writer
|
||||
|
||||
public static class ShpWriter
|
||||
{
|
||||
public static void Write(Stream s, int width, int height, IEnumerable<byte[]> frames)
|
||||
{
|
||||
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
||||
|
||||
// note: end-of-file and all-zeroes headers
|
||||
var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk;
|
||||
|
||||
using (var bw = new BinaryWriter(s))
|
||||
{
|
||||
bw.Write((ushort)compressedFrames.Length);
|
||||
bw.Write((ushort)0); // unused
|
||||
bw.Write((ushort)0); // unused
|
||||
bw.Write((ushort)width);
|
||||
bw.Write((ushort)height);
|
||||
bw.Write((uint)0); // unused
|
||||
|
||||
foreach (var f in compressedFrames)
|
||||
{
|
||||
var ih = new ImageHeader { Format = Format.Format80, Offset = (uint)dataOffset };
|
||||
dataOffset += f.Length;
|
||||
|
||||
ih.WriteTo(bw);
|
||||
}
|
||||
|
||||
var eof = new ImageHeader { Offset = (uint)dataOffset };
|
||||
eof.WriteTo(bw);
|
||||
|
||||
var allZeroes = new ImageHeader { };
|
||||
allZeroes.WriteTo(bw);
|
||||
|
||||
foreach (var f in compressedFrames)
|
||||
bw.Write(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
264
OpenRA.FileFormats/Graphics/SpriteSource.cs
Normal file
264
OpenRA.FileFormats/Graphics/SpriteSource.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public interface ISpriteFrame
|
||||
{
|
||||
Size Size { get; }
|
||||
Size FrameSize { get; }
|
||||
float2 Offset { get; }
|
||||
byte[] Data { get; }
|
||||
}
|
||||
|
||||
public interface ISpriteSource
|
||||
{
|
||||
IEnumerable<ISpriteFrame> Frames { get; }
|
||||
bool CacheWhenLoadingTileset { get; }
|
||||
}
|
||||
|
||||
public enum SpriteType { Unknown, ShpTD, ShpTS, ShpD2, TmpTD, TmpRA, TmpTS, R8 }
|
||||
public static class SpriteSource
|
||||
{
|
||||
static bool IsTmpRA(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
s.Position += 20;
|
||||
var a = s.ReadUInt32();
|
||||
s.Position += 2;
|
||||
var b = s.ReadUInt16();
|
||||
|
||||
s.Position = start;
|
||||
return a == 0 && b == 0x2c73;
|
||||
}
|
||||
|
||||
static bool IsTmpTD(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
s.Position += 16;
|
||||
var a = s.ReadUInt32();
|
||||
var b = s.ReadUInt32();
|
||||
|
||||
s.Position = start;
|
||||
return a == 0 && b == 0x0D1AFFFF;
|
||||
}
|
||||
|
||||
static bool IsTmpTS(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
s.Position += 8;
|
||||
var sx = s.ReadUInt32();
|
||||
var sy = s.ReadUInt32();
|
||||
|
||||
// Find the first frame
|
||||
var offset = s.ReadUInt32();
|
||||
|
||||
if (offset > s.Length - 52)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
s.Position = offset + 12;
|
||||
var test = s.ReadUInt32();
|
||||
|
||||
s.Position = start;
|
||||
return test == sx * sy / 2 + 52;
|
||||
}
|
||||
|
||||
static bool IsShpTS(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
// First word is zero
|
||||
if (s.ReadUInt16() != 0)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sanity Check the image count
|
||||
s.Position += 4;
|
||||
var imageCount = s.ReadUInt16();
|
||||
if (s.Position + 24 * imageCount > s.Length)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the size and format flag
|
||||
// Some files define bogus frames, so loop until we find a valid one
|
||||
s.Position += 4;
|
||||
ushort w, h, f = 0;
|
||||
byte type;
|
||||
do
|
||||
{
|
||||
w = s.ReadUInt16();
|
||||
h = s.ReadUInt16();
|
||||
type = s.ReadUInt8();
|
||||
}
|
||||
while (w == 0 && h == 0 && f++ < imageCount);
|
||||
|
||||
s.Position = start;
|
||||
return type < 4;
|
||||
}
|
||||
|
||||
static bool IsShpTD(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
// First word is the image count
|
||||
var imageCount = s.ReadUInt16();
|
||||
if (imageCount == 0)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Last offset should point to the end of file
|
||||
var finalOffset = start + 14 + 8 * imageCount;
|
||||
if (finalOffset > s.Length)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
s.Position = finalOffset;
|
||||
var eof = s.ReadUInt32();
|
||||
if (eof != s.Length)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the format flag on the first frame
|
||||
s.Position = start + 17;
|
||||
var b = s.ReadUInt8();
|
||||
|
||||
s.Position = start;
|
||||
return b == 0x20 || b == 0x40 || b == 0x80;
|
||||
}
|
||||
|
||||
static bool IsShpD2(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
// First word is the image count
|
||||
var imageCount = s.ReadUInt16();
|
||||
if (imageCount == 0)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test for two vs four byte offset
|
||||
var testOffset = s.ReadUInt32();
|
||||
var offsetSize = (testOffset & 0xFF0000) > 0 ? 2 : 4;
|
||||
|
||||
// Last offset should point to the end of file
|
||||
var finalOffset = start + 2 + offsetSize * imageCount;
|
||||
if (finalOffset > s.Length)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
s.Position = finalOffset;
|
||||
var eof = offsetSize == 2 ? s.ReadUInt16() : s.ReadUInt32();
|
||||
if (eof + 2 != s.Length)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the format flag on the first frame
|
||||
var b = s.ReadUInt16();
|
||||
s.Position = start;
|
||||
return b == 5 || b <= 3;
|
||||
}
|
||||
|
||||
static bool IsR8(Stream s)
|
||||
{
|
||||
var start = s.Position;
|
||||
|
||||
// First byte is nonzero
|
||||
if (s.ReadUInt8() == 0)
|
||||
{
|
||||
s.Position = start;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the format of the first frame
|
||||
s.Position = start + 25;
|
||||
var d = s.ReadUInt8();
|
||||
|
||||
s.Position = start;
|
||||
return d == 8;
|
||||
}
|
||||
|
||||
public static SpriteType DetectSpriteType(Stream s)
|
||||
{
|
||||
if (IsShpTD(s))
|
||||
return SpriteType.ShpTD;
|
||||
|
||||
if (IsShpTS(s))
|
||||
return SpriteType.ShpTS;
|
||||
|
||||
if (IsR8(s))
|
||||
return SpriteType.R8;
|
||||
|
||||
if (IsTmpRA(s))
|
||||
return SpriteType.TmpRA;
|
||||
|
||||
if (IsTmpTD(s))
|
||||
return SpriteType.TmpTD;
|
||||
|
||||
if (IsTmpTS(s))
|
||||
return SpriteType.TmpTS;
|
||||
|
||||
if (IsShpD2(s))
|
||||
return SpriteType.ShpD2;
|
||||
|
||||
return SpriteType.Unknown;
|
||||
}
|
||||
|
||||
public static ISpriteSource LoadSpriteSource(Stream s, string filename)
|
||||
{
|
||||
var type = DetectSpriteType(s);
|
||||
switch (type)
|
||||
{
|
||||
case SpriteType.ShpTD:
|
||||
return new ShpReader(s);
|
||||
case SpriteType.ShpTS:
|
||||
return new ShpTSReader(s);
|
||||
case SpriteType.R8:
|
||||
return new R8Reader(s);
|
||||
case SpriteType.TmpRA:
|
||||
return new TmpRAReader(s);
|
||||
case SpriteType.TmpTD:
|
||||
return new TmpTDReader(s);
|
||||
case SpriteType.TmpTS:
|
||||
return new TmpTSReader(s);
|
||||
case SpriteType.ShpD2:
|
||||
return new ShpD2Reader(s);
|
||||
case SpriteType.Unknown:
|
||||
default:
|
||||
throw new InvalidDataException(filename + " is not a valid sprite file");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class TileSetRenderer
|
||||
{
|
||||
public TileSet TileSet;
|
||||
Dictionary<ushort, List<byte[]>> templates;
|
||||
public Size TileSize;
|
||||
|
||||
List<byte[]> LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8cache, int[] frames)
|
||||
{
|
||||
if (exts.Contains(".R8") && FileSystem.Exists(filename + ".R8"))
|
||||
{
|
||||
var data = new List<byte[]>();
|
||||
|
||||
foreach (var f in frames)
|
||||
data.Add(f >= 0 ? r8cache[filename][f].Image : null);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
using (var s = FileSystem.OpenWithExts(filename, exts))
|
||||
return new Terrain(s).TileBitmapBytes;
|
||||
}
|
||||
|
||||
public TileSetRenderer(TileSet tileset, Size tileSize)
|
||||
{
|
||||
this.TileSet = tileset;
|
||||
this.TileSize = tileSize;
|
||||
|
||||
templates = new Dictionary<ushort, List<byte[]>>();
|
||||
var r8cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")));
|
||||
foreach (var t in TileSet.Templates)
|
||||
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8cache, t.Value.Frames));
|
||||
}
|
||||
|
||||
public Bitmap RenderTemplate(ushort id, Palette p)
|
||||
{
|
||||
var template = TileSet.Templates[id];
|
||||
var templateData = templates[id];
|
||||
|
||||
var bitmap = new Bitmap(TileSize.Width * template.Size.X, TileSize.Height * template.Size.Y,
|
||||
PixelFormat.Format8bppIndexed);
|
||||
|
||||
bitmap.Palette = p.AsSystemPalette();
|
||||
|
||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
unsafe
|
||||
{
|
||||
var q = (byte*)data.Scan0.ToPointer();
|
||||
var stride = data.Stride;
|
||||
|
||||
for (var u = 0; u < template.Size.X; u++)
|
||||
for (var v = 0; v < template.Size.Y; v++)
|
||||
if (templateData[u + v * template.Size.X] != null)
|
||||
{
|
||||
var rawImage = templateData[u + v * template.Size.X];
|
||||
for (var i = 0; i < TileSize.Width; i++)
|
||||
for (var j = 0; j < TileSize.Height; j++)
|
||||
q[(v * TileSize.Width + j) * stride + u * TileSize.Width + i] = rawImage[i + TileSize.Width * j];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < TileSize.Width; i++)
|
||||
for (var j = 0; j < TileSize.Height; j++)
|
||||
q[(v * TileSize.Width + j) * stride + u * TileSize.Width + i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public List<byte[]> Data(ushort id)
|
||||
{
|
||||
return templates[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
50
OpenRA.FileFormats/Graphics/TmpRAReader.cs
Normal file
50
OpenRA.FileFormats/Graphics/TmpRAReader.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class TmpRAReader : ISpriteSource
|
||||
{
|
||||
readonly List<TmpTile> tiles = new List<TmpTile>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return tiles.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
|
||||
public TmpRAReader(Stream s)
|
||||
{
|
||||
var width = s.ReadUInt16();
|
||||
var height = s.ReadUInt16();
|
||||
var size = new Size(width, height);
|
||||
|
||||
s.Position += 12;
|
||||
var imgStart = s.ReadUInt32();
|
||||
s.Position += 8;
|
||||
var indexEnd = s.ReadInt32();
|
||||
s.Position += 4;
|
||||
var indexStart = s.ReadInt32();
|
||||
|
||||
s.Position = indexStart;
|
||||
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
|
||||
{
|
||||
if (b != 255)
|
||||
{
|
||||
s.Position = imgStart + b * width * height;
|
||||
tiles.Add(new TmpTile(s.ReadBytes(width * height), size));
|
||||
}
|
||||
else
|
||||
tiles.Add(new TmpTile(null, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
OpenRA.FileFormats/Graphics/TmpTDReader.cs
Normal file
68
OpenRA.FileFormats/Graphics/TmpTDReader.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class TmpTile : ISpriteFrame
|
||||
{
|
||||
public Size Size { get; private set; }
|
||||
public Size FrameSize { get; private set; }
|
||||
public float2 Offset { get { return float2.Zero; } }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public TmpTile(byte[] data, Size size)
|
||||
{
|
||||
FrameSize = size;
|
||||
Data = data;
|
||||
|
||||
if (data == null)
|
||||
Data = new byte[0];
|
||||
else
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
public class TmpTDReader : ISpriteSource
|
||||
{
|
||||
readonly List<TmpTile> tiles = new List<TmpTile>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return tiles.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
|
||||
public TmpTDReader(Stream s)
|
||||
{
|
||||
var width = s.ReadUInt16();
|
||||
var height = s.ReadUInt16();
|
||||
var size = new Size(width, height);
|
||||
|
||||
s.Position += 8;
|
||||
var imgStart = s.ReadUInt32();
|
||||
s.Position += 8;
|
||||
var indexEnd = s.ReadInt32();
|
||||
var indexStart = s.ReadInt32();
|
||||
|
||||
s.Position = indexStart;
|
||||
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
|
||||
{
|
||||
if (b != 255)
|
||||
{
|
||||
s.Position = imgStart + b * width * height;
|
||||
tiles.Add(new TmpTile(s.ReadBytes(width * height), size));
|
||||
}
|
||||
else
|
||||
tiles.Add(new TmpTile(null, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
OpenRA.FileFormats/Graphics/TmpTSReader.cs
Normal file
75
OpenRA.FileFormats/Graphics/TmpTSReader.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class TmpTSTile : ISpriteFrame
|
||||
{
|
||||
public Size Size { get; private set; }
|
||||
public Size FrameSize { get { return Size; } }
|
||||
public float2 Offset { get { return float2.Zero; } }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public TmpTSTile(Stream s, Size size)
|
||||
{
|
||||
Size = size;
|
||||
|
||||
// Ignore tile header for now
|
||||
s.Position += 52;
|
||||
|
||||
Data = new byte[size.Width * size.Height];
|
||||
|
||||
// Unpack tile data
|
||||
var width = 4;
|
||||
for (var i = 0; i < size.Height; i++)
|
||||
{
|
||||
var start = i * size.Width + (size.Width - width) / 2;
|
||||
for (var j = 0; j < width; j++)
|
||||
Data[start + j] = s.ReadUInt8();
|
||||
|
||||
width += (i < size.Height / 2 - 1? 1 : -1) * 4;
|
||||
}
|
||||
|
||||
// Ignore Z-data for now
|
||||
// Ignore extra data for now
|
||||
}
|
||||
}
|
||||
|
||||
public class TmpTSReader : ISpriteSource
|
||||
{
|
||||
readonly List<TmpTSTile> tiles = new List<TmpTSTile>();
|
||||
public IEnumerable<ISpriteFrame> Frames { get { return tiles.Cast<ISpriteFrame>(); } }
|
||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
||||
|
||||
public TmpTSReader(Stream s)
|
||||
{
|
||||
var templateWidth = s.ReadUInt32();
|
||||
var templateHeight = s.ReadUInt32();
|
||||
var tileWidth = s.ReadInt32();
|
||||
var tileHeight = s.ReadInt32();
|
||||
var size = new Size(tileWidth, tileHeight);
|
||||
var offsets = new uint[templateWidth * templateHeight];
|
||||
for (var i = 0; i < offsets.Length; i++)
|
||||
offsets[i] = s.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < offsets.Length; i++)
|
||||
{
|
||||
s.Position = offsets[i];
|
||||
tiles.Add(new TmpTSTile(s, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
||||
@@ -95,11 +95,8 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
HSLColor o = (HSLColor)obj;
|
||||
return o == this;
|
||||
var o = obj as HSLColor?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public struct Hotkey
|
||||
@@ -72,10 +67,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
return (Hotkey)obj == this;
|
||||
var o = obj as Hotkey?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0} {1}".F(Key, Modifiers.ToString("F")); }
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
@@ -9,33 +9,35 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
/* describes what is to be loaded in order to run a set of mods */
|
||||
|
||||
// Describes what is to be loaded in order to run a mod
|
||||
public class Manifest
|
||||
{
|
||||
public readonly Mod Mod;
|
||||
public readonly string[]
|
||||
Mods, Folders, MapFolders, Rules, ServerTraits,
|
||||
Folders, MapFolders, Rules, ServerTraits,
|
||||
Sequences, VoxelSequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Weapons, Voices, Notifications, Music, Movies, Translations, TileSets,
|
||||
ChromeMetrics, PackageContents;
|
||||
ChromeMetrics, PackageContents, LuaScripts, MapCompatibility;
|
||||
|
||||
public readonly Dictionary<string, string> Packages;
|
||||
public readonly MiniYaml LoadScreen;
|
||||
public readonly MiniYaml LobbyDefaults;
|
||||
public readonly Dictionary<string, Pair<string,int>> Fonts;
|
||||
public readonly int TileSize = 24;
|
||||
public readonly Dictionary<string, Pair<string, int>> Fonts;
|
||||
public readonly Size TileSize = new Size(24, 24);
|
||||
|
||||
public Manifest(string[] mods)
|
||||
public Manifest(string mod)
|
||||
{
|
||||
Mods = mods;
|
||||
var yaml = new MiniYaml(null, mods
|
||||
.Select(m => MiniYaml.FromFile("mods{0}{1}{0}mod.yaml".F(Path.DirectorySeparatorChar, m)))
|
||||
.Aggregate(MiniYaml.MergeLiberal)).NodesDict;
|
||||
var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine);
|
||||
var yaml = new MiniYaml(null, MiniYaml.FromFile(path)).NodesDict;
|
||||
|
||||
Mod = FieldLoader.Load<Mod>(yaml["Metadata"]);
|
||||
Mod.Id = mod;
|
||||
|
||||
// TODO: Use fieldloader
|
||||
Folders = YamlList(yaml, "Folders");
|
||||
@@ -58,6 +60,7 @@ namespace OpenRA.FileFormats
|
||||
TileSets = YamlList(yaml, "TileSets");
|
||||
ChromeMetrics = YamlList(yaml, "ChromeMetrics");
|
||||
PackageContents = YamlList(yaml, "PackageContents");
|
||||
LuaScripts = YamlList(yaml, "LuaScripts");
|
||||
|
||||
LoadScreen = yaml["LoadScreen"];
|
||||
LobbyDefaults = yaml["LobbyDefaults"];
|
||||
@@ -66,13 +69,23 @@ namespace OpenRA.FileFormats
|
||||
int.Parse(x.Value.NodesDict["Size"].Value)));
|
||||
|
||||
if (yaml.ContainsKey("TileSize"))
|
||||
TileSize = int.Parse(yaml["TileSize"].Value);
|
||||
TileSize = FieldLoader.GetValue<Size>("TileSize", yaml["TileSize"].Value);
|
||||
|
||||
// Allow inherited mods to import parent maps.
|
||||
var compat = new List<string>();
|
||||
compat.Add(mod);
|
||||
|
||||
if (yaml.ContainsKey("SupportsMapsFrom"))
|
||||
foreach (var c in yaml["SupportsMapsFrom"].Value.Split(','))
|
||||
compat.Add(c.Trim());
|
||||
|
||||
MapCompatibility = compat.ToArray();
|
||||
}
|
||||
|
||||
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key)
|
||||
{
|
||||
if (!yaml.ContainsKey(key))
|
||||
return new string[] {};
|
||||
return new string[] { };
|
||||
|
||||
return yaml[key].NodesDict.Keys.ToArray();
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class PlayerReference
|
||||
@@ -20,6 +17,7 @@ namespace OpenRA.FileFormats
|
||||
public bool OwnsWorld = false;
|
||||
public bool NonCombatant = false;
|
||||
public bool Playable = false;
|
||||
public bool Spectating = false;
|
||||
public string Bot = null;
|
||||
public string StartingUnitsClass = null;
|
||||
public bool AllowBots = true;
|
||||
|
||||
@@ -1,77 +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
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class Terrain
|
||||
{
|
||||
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
|
||||
public readonly int Width;
|
||||
public readonly int Height;
|
||||
|
||||
public Terrain(Stream s)
|
||||
{
|
||||
// Try loading as a cnc .tem
|
||||
Width = s.ReadUInt16();
|
||||
Height = s.ReadUInt16();
|
||||
|
||||
/*NumTiles = */s.ReadUInt16();
|
||||
/*Zero1 = */s.ReadUInt16();
|
||||
/*uint Size = */s.ReadUInt32();
|
||||
var imgStart = s.ReadUInt32();
|
||||
/*Zero2 = */s.ReadUInt32();
|
||||
|
||||
int indexEnd, indexStart;
|
||||
|
||||
// ID1 = FFFFh for cnc
|
||||
if (s.ReadUInt16() == 65535)
|
||||
{
|
||||
/*ID2 = */s.ReadUInt16();
|
||||
indexEnd = s.ReadInt32();
|
||||
indexStart = s.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load as a ra .tem
|
||||
s.Position = 0;
|
||||
Width = s.ReadUInt16();
|
||||
Height = s.ReadUInt16();
|
||||
|
||||
/*NumTiles = */s.ReadUInt16();
|
||||
s.ReadUInt16();
|
||||
/*XDim = */s.ReadUInt16();
|
||||
/*YDim = */s.ReadUInt16();
|
||||
/*uint FileSize = */s.ReadUInt32();
|
||||
imgStart = s.ReadUInt32();
|
||||
s.ReadUInt32();
|
||||
s.ReadUInt32();
|
||||
indexEnd = s.ReadInt32();
|
||||
s.ReadUInt32();
|
||||
indexStart = s.ReadInt32();
|
||||
}
|
||||
|
||||
s.Position = indexStart;
|
||||
|
||||
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
|
||||
{
|
||||
if (b != 255)
|
||||
{
|
||||
s.Position = imgStart + b * Width * Height;
|
||||
TileBitmapBytes.Add(s.ReadBytes(Width * Height));
|
||||
}
|
||||
else
|
||||
TileBitmapBytes.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -20,8 +18,9 @@ namespace OpenRA.FileFormats
|
||||
public class TerrainTypeInfo
|
||||
{
|
||||
public string Type;
|
||||
public string[] TargetTypes = { };
|
||||
public string[] AcceptsSmudgeType = { };
|
||||
public bool IsWater = false;
|
||||
public bool IsWater = false; // TODO: Remove this
|
||||
public Color Color;
|
||||
public string CustomCursor;
|
||||
|
||||
@@ -87,7 +86,7 @@ namespace OpenRA.FileFormats
|
||||
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
|
||||
public string[] EditorTemplateOrder;
|
||||
|
||||
static readonly string[] Fields = { "Name", "TileSize", "Id", "SheetSize", "Palette", "Extensions" };
|
||||
static readonly string[] Fields = { "Name", "Id", "SheetSize", "Palette", "Extensions" };
|
||||
|
||||
public TileSet() { }
|
||||
|
||||
|
||||
@@ -16,21 +16,20 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public class Mod
|
||||
{
|
||||
public static readonly Dictionary<string, Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public string Id;
|
||||
public string Title;
|
||||
public string Description;
|
||||
public string Version;
|
||||
public string Author;
|
||||
public string Requires;
|
||||
|
||||
public static readonly Dictionary<string, Mod> AllMods = ValidateMods(Directory.GetDirectories("mods").Select(x => x.Substring(5)).ToArray());
|
||||
|
||||
public static Dictionary<string, Mod> ValidateMods(string[] mods)
|
||||
{
|
||||
var ret = new Dictionary<string, Mod>();
|
||||
foreach (var m in mods)
|
||||
{
|
||||
var yamlPath = new[] { "mods", m, "mod.yaml" }.Aggregate( Path.Combine );
|
||||
var yamlPath = new[] { "mods", m, "mod.yaml" }.Aggregate(Path.Combine);
|
||||
if (!File.Exists(yamlPath))
|
||||
continue;
|
||||
|
||||
@@ -43,14 +42,8 @@ namespace OpenRA.FileFormats
|
||||
|
||||
ret.Add(m, mod);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public string[] WithPrerequisites()
|
||||
{
|
||||
return Id.Iterate(m => AllMods[m].Requires)
|
||||
.TakeWhile(m => m != null)
|
||||
.ToArray();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,19 +90,16 @@
|
||||
<Compile Include="FileFormats\Format40.cs" />
|
||||
<Compile Include="FileFormats\Format80.cs" />
|
||||
<Compile Include="FileFormats\IniFile.cs" />
|
||||
<Compile Include="Graphics\Dune2ShpReader.cs" />
|
||||
<Compile Include="Graphics\IGraphicsDevice.cs" />
|
||||
<Compile Include="Graphics\IInputHandler.cs" />
|
||||
<Compile Include="Graphics\PngLoader.cs" />
|
||||
<Compile Include="Graphics\ShpReader.cs" />
|
||||
<Compile Include="Graphics\ShpWriter.cs" />
|
||||
<Compile Include="Graphics\Vertex.cs" />
|
||||
<Compile Include="Graphics\VqaReader.cs" />
|
||||
<Compile Include="InstallUtils.cs" />
|
||||
<Compile Include="Manifest.cs" />
|
||||
<Compile Include="Map\PlayerReference.cs" />
|
||||
<Compile Include="Map\SmudgeReference.cs" />
|
||||
<Compile Include="Map\Terrain.cs" />
|
||||
<Compile Include="Map\TileReference.cs" />
|
||||
<Compile Include="Map\TileSet.cs" />
|
||||
<Compile Include="MiniYaml.cs" />
|
||||
@@ -144,7 +141,6 @@
|
||||
<Compile Include="StreamExts.cs" />
|
||||
<Compile Include="FileFormats\WavLoader.cs" />
|
||||
<Compile Include="Graphics\R8Reader.cs" />
|
||||
<Compile Include="Graphics\TileSetRenderer.cs" />
|
||||
<Compile Include="Keycode.cs" />
|
||||
<Compile Include="Hotkey.cs" />
|
||||
<Compile Include="FileSystem\FileSystem.cs" />
|
||||
@@ -153,6 +149,14 @@
|
||||
<Compile Include="FileSystem\MixFile.cs" />
|
||||
<Compile Include="FileSystem\ZipFile.cs" />
|
||||
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
||||
<Compile Include="Graphics\SpriteSource.cs" />
|
||||
<Compile Include="Graphics\TmpRAReader.cs" />
|
||||
<Compile Include="Graphics\TmpTDReader.cs" />
|
||||
<Compile Include="Graphics\ShpD2Reader.cs" />
|
||||
<Compile Include="FileSystem\Pak.cs" />
|
||||
<Compile Include="CPos.cs" />
|
||||
<Compile Include="CVec.cs" />
|
||||
<Compile Include="Graphics\TmpTSReader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.FileFormats.Primitives
|
||||
public event Action<object, object> OnSet = (o, n) => { };
|
||||
public event Action OnRefresh = () => { };
|
||||
|
||||
public ObservableCollection() : base() { }
|
||||
public ObservableCollection() { }
|
||||
public ObservableCollection(IList<T> list) : base(list) { }
|
||||
|
||||
protected override void SetItem(int index, T item)
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.FileFormats.Primitives
|
||||
|
||||
public IEnumerable ObservedItems
|
||||
{
|
||||
get { return base.Items; }
|
||||
get { return Items; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
@@ -40,10 +39,8 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is Pair<T, U>))
|
||||
return false;
|
||||
|
||||
return (Pair<T, U>)obj == this;
|
||||
var o = obj as Pair<T, U>?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
||||
@@ -73,11 +73,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
float2 o = (float2)obj;
|
||||
return o == this;
|
||||
var o = obj as float2?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public static readonly float2 Zero = new float2(0, 0);
|
||||
|
||||
@@ -43,11 +43,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
int2 o = (int2)obj;
|
||||
return o == this;
|
||||
var o = obj as int2?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public static readonly int2 Zero = new int2(0, 0);
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -40,11 +39,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
WAngle o = (WAngle)obj;
|
||||
return o == this;
|
||||
var o = obj as WAngle?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public int Sin() { return new WAngle(Angle - 256).Cos(); }
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -56,11 +54,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
WPos o = (WPos)obj;
|
||||
return o == this;
|
||||
var o = obj as WPos?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1},{2}".F(X, Y, Z); }
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -17,7 +16,7 @@ namespace OpenRA
|
||||
/// <summary>
|
||||
/// 1d world distance - 1024 units = 1 cell.
|
||||
/// </summary>
|
||||
public struct WRange
|
||||
public struct WRange : IComparable, IComparable<WRange>
|
||||
{
|
||||
public readonly int Range;
|
||||
|
||||
@@ -80,13 +79,21 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
WRange o = (WRange)obj;
|
||||
return o == this;
|
||||
var o = obj as WRange?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
var o = obj as WRange?;
|
||||
if (o == null)
|
||||
return 1;
|
||||
|
||||
return Range.CompareTo(o.Value.Range);
|
||||
}
|
||||
|
||||
public int CompareTo(WRange other) { return Range.CompareTo(other.Range); }
|
||||
|
||||
public override string ToString() { return "{0}".F(Range); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
/// <summary>
|
||||
@@ -97,11 +94,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
WRot o = (WRot)obj;
|
||||
return o == this;
|
||||
var o = obj as WRot?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1},{2}".F(Roll, Pitch, Yaw); }
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -83,11 +82,8 @@ namespace OpenRA
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
WVec o = (WVec)obj;
|
||||
return o == this;
|
||||
var o = obj as WVec?;
|
||||
return o != null && o == this;
|
||||
}
|
||||
|
||||
public override string ToString() { return "{0},{1},{2}".F(X, Y, Z); }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2014 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,
|
||||
@@ -28,8 +28,11 @@ namespace OpenRA
|
||||
|
||||
Lazy<IOccupySpace> occupySpace;
|
||||
Lazy<IFacing> facing;
|
||||
Lazy<Health> health;
|
||||
Lazy<IEffectiveOwner> effectiveOwner;
|
||||
|
||||
public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } }
|
||||
public IEffectiveOwner EffectiveOwner { get { return effectiveOwner.Value; } }
|
||||
|
||||
public CPos Location { get { return occupySpace.Value.TopLeft; } }
|
||||
public WPos CenterPosition { get { return occupySpace.Value.CenterPosition; } }
|
||||
@@ -72,6 +75,8 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
facing = Lazy.New(() => TraitOrDefault<IFacing>());
|
||||
health = Lazy.New(() => TraitOrDefault<Health>());
|
||||
effectiveOwner = Lazy.New(() => TraitOrDefault<IEffectiveOwner>());
|
||||
|
||||
applyIRender = (x, wr) => x.Render(this, wr);
|
||||
applyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);
|
||||
@@ -92,7 +97,11 @@ namespace OpenRA
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
var wasIdle = IsIdle;
|
||||
currentActivity = Traits.Util.RunActivity(this, currentActivity);
|
||||
if (!wasIdle && IsIdle)
|
||||
foreach (var n in TraitsImplementing<INotifyBecomingIdle>())
|
||||
n.OnBecomingIdle(this);
|
||||
}
|
||||
|
||||
public bool IsIdle
|
||||
@@ -210,5 +219,26 @@ namespace OpenRA
|
||||
t.OnOwnerChanged(this, oldOwner, newOwner);
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsDead()
|
||||
{
|
||||
if (Destroyed)
|
||||
return true;
|
||||
|
||||
return (health.Value == null) ? false : health.Value.IsDead;
|
||||
}
|
||||
|
||||
public bool IsDisguised()
|
||||
{
|
||||
return effectiveOwner.Value != null && effectiveOwner.Value.Disguised;
|
||||
}
|
||||
|
||||
public void Kill(Actor attacker)
|
||||
{
|
||||
if (health.Value == null)
|
||||
return;
|
||||
|
||||
health.Value.InflictDamage(this, attacker, health.Value.MaxHP, null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,53 +21,45 @@ namespace OpenRA
|
||||
|
||||
internal TypeDictionary dict;
|
||||
|
||||
public ActorInitializer( Actor actor, TypeDictionary dict )
|
||||
public ActorInitializer(Actor actor, TypeDictionary dict)
|
||||
{
|
||||
this.self = actor;
|
||||
this.dict = dict;
|
||||
}
|
||||
|
||||
public T Get<T>() where T : IActorInit { return dict.Get<T>(); }
|
||||
public U Get<T,U>() where T : IActorInit<U> { return dict.Get<T>().Value( world ); }
|
||||
public U Get<T, U>() where T : IActorInit<U> { return dict.Get<T>().Value(world); }
|
||||
public bool Contains<T>() where T : IActorInit { return dict.Contains<T>(); }
|
||||
}
|
||||
|
||||
public interface IActorInit {}
|
||||
public interface IActorInit { }
|
||||
|
||||
public interface IActorInit<T> : IActorInit
|
||||
{
|
||||
T Value( World world );
|
||||
T Value(World world);
|
||||
}
|
||||
|
||||
public class FacingInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int value = 128;
|
||||
public FacingInit() { }
|
||||
public FacingInit( int init ) { value = init; }
|
||||
public int Value( World world ) { return value; }
|
||||
public FacingInit(int init) { value = init; }
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
|
||||
public class TurretFacingInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int value = 128;
|
||||
public TurretFacingInit() { }
|
||||
public TurretFacingInit( int init ) { value = init; }
|
||||
public int Value( World world ) { return value; }
|
||||
}
|
||||
|
||||
public class AltitudeInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int value = 0;
|
||||
public AltitudeInit() { }
|
||||
public AltitudeInit( int init ) { value = init; }
|
||||
public int Value( World world ) { return value; }
|
||||
public TurretFacingInit(int init) { value = init; }
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
|
||||
public class LocationInit : IActorInit<CPos>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int2 value = int2.Zero;
|
||||
public LocationInit() { }
|
||||
public LocationInit( CPos init ) { value = init.ToInt2(); }
|
||||
public LocationInit(CPos init) { value = init.ToInt2(); }
|
||||
public CPos Value(World world) { return (CPos)value; }
|
||||
}
|
||||
|
||||
@@ -94,18 +86,20 @@ namespace OpenRA
|
||||
Player player;
|
||||
|
||||
public OwnerInit() { }
|
||||
public OwnerInit( string playerName ) { this.PlayerName = playerName; }
|
||||
public OwnerInit(string playerName) { this.PlayerName = playerName; }
|
||||
|
||||
public OwnerInit( Player player ) {
|
||||
public OwnerInit(Player player)
|
||||
{
|
||||
this.player = player;
|
||||
this.PlayerName = player.InternalName;
|
||||
}
|
||||
|
||||
public Player Value( World world )
|
||||
public Player Value(World world)
|
||||
{
|
||||
if( player != null )
|
||||
if (player != null)
|
||||
return player;
|
||||
return world.Players.First( x => x.InternalName == PlayerName );
|
||||
|
||||
return world.Players.First(x => x.InternalName == PlayerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenRA
|
||||
|
||||
public static string FormatErrorMessage(Exception e)
|
||||
{
|
||||
var ex = e as System.Net.WebException;
|
||||
var ex = e as WebException;
|
||||
if (ex == null)
|
||||
return e.Message;
|
||||
|
||||
@@ -46,15 +46,29 @@ namespace OpenRA
|
||||
wc.DownloadProgressChanged += (_, a) => onProgress(a);
|
||||
wc.DownloadFileCompleted += (_, a) => onComplete(a, cancelled);
|
||||
|
||||
Game.OnQuit += () => Cancel();
|
||||
wc.DownloadFileCompleted += (_, a) => { Game.OnQuit -= () => Cancel(); };
|
||||
Game.OnQuit += Cancel;
|
||||
wc.DownloadFileCompleted += (_, a) => { Game.OnQuit -= Cancel; };
|
||||
|
||||
wc.DownloadFileAsync(new Uri(url), path);
|
||||
}
|
||||
|
||||
public Download(string url, Action<DownloadProgressChangedEventArgs> onProgress, Action<DownloadDataCompletedEventArgs, bool> onComplete)
|
||||
{
|
||||
wc = new WebClient();
|
||||
wc.Proxy = null;
|
||||
|
||||
wc.DownloadProgressChanged += (_, a) => onProgress(a);
|
||||
wc.DownloadDataCompleted += (_, a) => onComplete(a, cancelled);
|
||||
|
||||
Game.OnQuit += Cancel;
|
||||
wc.DownloadDataCompleted += (_, a) => { Game.OnQuit -= Cancel; };
|
||||
|
||||
wc.DownloadDataAsync(new Uri(url));
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
Game.OnQuit -= () => Cancel();
|
||||
Game.OnQuit -= Cancel;
|
||||
wc.CancelAsync();
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
|
||||
@@ -9,10 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2014 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,
|
||||
@@ -27,8 +27,6 @@ namespace OpenRA
|
||||
{
|
||||
public static class Game
|
||||
{
|
||||
public static int CellSize { get { return modData.Manifest.TileSize; } }
|
||||
|
||||
public static MouseButtonPreference mouseButtonPreference = new MouseButtonPreference();
|
||||
|
||||
public static ModData modData;
|
||||
@@ -75,17 +73,18 @@ namespace OpenRA
|
||||
public static int RenderFrame = 0;
|
||||
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
|
||||
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
public const int NetTickScale = 3; // 120ms net tick for 40ms local tick
|
||||
public const int NetTickScale = 3; // 120 ms net tick for 40 ms local tick
|
||||
public const int Timestep = 40;
|
||||
public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms
|
||||
|
||||
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||
public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } }
|
||||
|
||||
|
||||
// Hacky workaround for orderManager visibility
|
||||
public static Widget OpenWindow(World world, string widget)
|
||||
{
|
||||
return Ui.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
|
||||
@@ -103,7 +102,7 @@ namespace OpenRA
|
||||
// Load a widget with world, orderManager, worldRenderer args, without adding it to the widget tree
|
||||
public static Widget LoadWidget(World world, string id, Widget parent, WidgetArgs args)
|
||||
{
|
||||
return Game.modData.WidgetLoader.LoadWidget(new WidgetArgs(args)
|
||||
return modData.WidgetLoader.LoadWidget(new WidgetArgs(args)
|
||||
{
|
||||
{ "world", world },
|
||||
{ "orderManager", orderManager },
|
||||
@@ -135,23 +134,23 @@ namespace OpenRA
|
||||
// worldRenderer is null during the initial install/download screen
|
||||
if (worldRenderer != null)
|
||||
{
|
||||
Game.Renderer.BeginFrame(worldRenderer.Viewport.TopLeft.ToFloat2(), worldRenderer.Viewport.Zoom);
|
||||
Renderer.BeginFrame(worldRenderer.Viewport.TopLeft.ToFloat2(), worldRenderer.Viewport.Zoom);
|
||||
Sound.SetListenerPosition(worldRenderer.Position(worldRenderer.Viewport.CenterLocation));
|
||||
worldRenderer.Draw();
|
||||
}
|
||||
else
|
||||
Game.Renderer.BeginFrame(float2.Zero, 1f);
|
||||
Renderer.BeginFrame(float2.Zero, 1f);
|
||||
|
||||
using (new PerfSample("render_widgets"))
|
||||
{
|
||||
Ui.Draw();
|
||||
var cursorName = Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
CursorProvider.DrawCursor(Game.Renderer, cursorName, Viewport.LastMousePos, (int)cursorFrame);
|
||||
CursorProvider.DrawCursor(Renderer, cursorName, Viewport.LastMousePos, (int)cursorFrame);
|
||||
}
|
||||
|
||||
using (new PerfSample("render_flip"))
|
||||
{
|
||||
Game.Renderer.EndFrame(new DefaultInputHandler(orderManager.world));
|
||||
Renderer.EndFrame(new DefaultInputHandler(orderManager.world));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,16 +164,34 @@ namespace OpenRA
|
||||
|
||||
static void TickInner(OrderManager orderManager)
|
||||
{
|
||||
int t = Environment.TickCount;
|
||||
int dt = t - orderManager.LastTickTime;
|
||||
if (dt >= Settings.Game.Timestep)
|
||||
var tick = Environment.TickCount;
|
||||
|
||||
var world = orderManager.world;
|
||||
var uiTickDelta = tick - Ui.LastTickTime;
|
||||
if (uiTickDelta >= Timestep)
|
||||
{
|
||||
// Explained below for the world tick calculation
|
||||
var integralTickTimestep = (uiTickDelta / Timestep) * Timestep;
|
||||
Ui.LastTickTime += integralTickTimestep >= TimestepJankThreshold ? integralTickTimestep : Timestep;
|
||||
|
||||
Viewport.TicksSinceLastMove += uiTickDelta / Timestep;
|
||||
|
||||
Sync.CheckSyncUnchanged(world, Ui.Tick);
|
||||
cursorFrame += 0.5f;
|
||||
}
|
||||
|
||||
var worldTimestep = world == null ? Timestep : world.Timestep;
|
||||
var worldTickDelta = (tick - orderManager.LastTickTime);
|
||||
if (worldTimestep != 0 && worldTickDelta >= worldTimestep)
|
||||
using (new PerfSample("tick_time"))
|
||||
{
|
||||
orderManager.LastTickTime += Settings.Game.Timestep;
|
||||
Ui.Tick();
|
||||
var world = orderManager.world;
|
||||
if (orderManager.GameStarted)
|
||||
++Viewport.TicksSinceLastMove;
|
||||
// Tick the world to advance the world time to match real time:
|
||||
// If dt < TickJankThreshold then we should try and catch up by repeatedly ticking
|
||||
// If dt >= TickJankThreshold then we should accept the jank and progress at the normal rate
|
||||
// dt is rounded down to an integer tick count in order to preserve fractional tick components.
|
||||
|
||||
var integralTickTimestep = (worldTickDelta / worldTimestep) * worldTimestep;
|
||||
orderManager.LastTickTime += integralTickTimestep >= TimestepJankThreshold ? integralTickTimestep : worldTimestep;
|
||||
|
||||
Sound.Tick();
|
||||
Sync.CheckSyncUnchanged(world, orderManager.TickImmediate);
|
||||
@@ -207,8 +224,6 @@ namespace OpenRA
|
||||
orderManager.LastTickTime = Environment.TickCount;
|
||||
|
||||
Sync.CheckSyncUnchanged(world, () => world.TickRender(worldRenderer));
|
||||
|
||||
cursorFrame += 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,13 +235,14 @@ namespace OpenRA
|
||||
LobbyInfoChanged();
|
||||
}
|
||||
|
||||
public static event Action BeforeGameStart = () => {};
|
||||
public static event Action BeforeGameStart = () => { };
|
||||
internal static void StartGame(string mapUID, bool isShellmap)
|
||||
{
|
||||
BeforeGameStart();
|
||||
|
||||
var map = modData.PrepareMap(mapUID);
|
||||
orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap);
|
||||
orderManager.world.Timestep = Timestep;
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
orderManager.world.LoadComplete(worldRenderer);
|
||||
|
||||
@@ -249,21 +265,9 @@ namespace OpenRA
|
||||
{
|
||||
get
|
||||
{
|
||||
var client= orderManager.LobbyInfo.ClientWithIndex(
|
||||
orderManager.Connection.LocalClientId);
|
||||
return ((client!=null) && client.IsAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String, Mod> CurrentMods
|
||||
{
|
||||
get
|
||||
{
|
||||
// Initialization hasn't completed yet
|
||||
if (Mod.AllMods == null || modData == null)
|
||||
return null;
|
||||
|
||||
return Mod.AllMods.Where(k => modData.Manifest.Mods.Contains(k.Key)).ToDictionary(k => k.Key, k => k.Value);
|
||||
var id = orderManager.Connection.LocalClientId;
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(id);
|
||||
return client != null && client.IsAdmin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,9 +300,12 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
FileSystem.Mount("."); // Needed to access shaders
|
||||
var renderers = new [] { Settings.Graphics.Renderer, "Sdl2", "Gl", "Cg" };
|
||||
var renderers = new[] { Settings.Graphics.Renderer, "Sdl2", "Gl", "Cg", null };
|
||||
foreach (var r in renderers)
|
||||
{
|
||||
if (r == null)
|
||||
throw new InvalidOperationException("No suitable renderers were found. Check graphics.log for details.");
|
||||
|
||||
Settings.Graphics.Renderer = r;
|
||||
try
|
||||
{
|
||||
@@ -311,6 +318,7 @@ namespace OpenRA
|
||||
Console.WriteLine("Renderer initialization failed. Fallback in place. Check graphics.log for details.");
|
||||
}
|
||||
}
|
||||
|
||||
Renderer = new Renderer();
|
||||
|
||||
try
|
||||
@@ -326,25 +334,22 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
Console.WriteLine("Available mods:");
|
||||
foreach(var mod in Mod.AllMods)
|
||||
foreach (var mod in Mod.AllMods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
||||
InitializeWithMods(Settings.Game.Mods);
|
||||
|
||||
InitializeWithMod(Settings.Game.Mod, args.GetValue("Launch.Replay", null));
|
||||
|
||||
if (Settings.Server.DiscoverNatDevices)
|
||||
{
|
||||
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, () =>
|
||||
UPnP.TryStoppingNatDiscovery()
|
||||
);
|
||||
}
|
||||
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, UPnP.TryStoppingNatDiscovery);
|
||||
}
|
||||
|
||||
public static void InitializeWithMods(string[] mods)
|
||||
public static void InitializeWithMod(string mod, string replay)
|
||||
{
|
||||
// Clear static state if we have switched mods
|
||||
LobbyInfoChanged = () => {};
|
||||
AddChatLine = (a,b,c) => {};
|
||||
ConnectionStateChanged = om => {};
|
||||
BeforeGameStart = () => {};
|
||||
LobbyInfoChanged = () => { };
|
||||
AddChatLine = (a, b, c) => { };
|
||||
ConnectionStateChanged = om => { };
|
||||
BeforeGameStart = () => { };
|
||||
Ui.ResetAll();
|
||||
|
||||
worldRenderer = null;
|
||||
@@ -353,19 +358,21 @@ namespace OpenRA
|
||||
if (orderManager != null)
|
||||
orderManager.Dispose();
|
||||
|
||||
// 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;
|
||||
// Fall back to default if the mod doesn't exist
|
||||
if (!Mod.AllMods.ContainsKey(mod))
|
||||
mod = new GameSettings().Mod;
|
||||
|
||||
Console.WriteLine("Loading mod: {0}", mod);
|
||||
Settings.Game.Mod = mod;
|
||||
|
||||
Sound.StopMusic();
|
||||
Sound.StopVideo();
|
||||
Sound.Initialize();
|
||||
|
||||
modData = new ModData(mm);
|
||||
modData = new ModData(mod);
|
||||
Renderer.InitializeFonts(modData.Manifest);
|
||||
modData.InitializeLoaders();
|
||||
modData.MapCache.LoadMaps();
|
||||
|
||||
PerfHistory.items["render"].hasNormalTick = false;
|
||||
PerfHistory.items["batches"].hasNormalTick = false;
|
||||
@@ -374,39 +381,43 @@ namespace OpenRA
|
||||
|
||||
JoinLocal();
|
||||
|
||||
if (Game.Settings.Server.Dedicated)
|
||||
if (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));
|
||||
Settings.Server.Map = WidgetUtils.ChooseInitialMap(Settings.Server.Map);
|
||||
Settings.Save();
|
||||
CreateServer(new ServerSettings(Settings.Server));
|
||||
while (true)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
|
||||
if ((server.State == Server.ServerState.GameStarted)
|
||||
&& (server.Conns.Count<=1))
|
||||
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)
|
||||
|
||||
if (Settings.Server.DedicatedLoop)
|
||||
{
|
||||
Console.WriteLine("Starting a new server instance...");
|
||||
modData.MapCache.LoadMaps();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
System.Environment.Exit(0);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
modData.LoadScreen.StartGame();
|
||||
Settings.Save();
|
||||
if (!string.IsNullOrEmpty(replay))
|
||||
Game.JoinReplay(replay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,33 +428,49 @@ namespace OpenRA
|
||||
|
||||
static string ChooseShellmap()
|
||||
{
|
||||
var shellmaps = modData.AvailableMaps
|
||||
.Where(m => m.Value.UseAsShellmap);
|
||||
var shellmaps = modData.MapCache
|
||||
.Where(m => m.Status == MapStatus.Available && m.Map.UseAsShellmap)
|
||||
.Select(m => m.Uid);
|
||||
|
||||
if (shellmaps.Count() == 0)
|
||||
if (!shellmaps.Any())
|
||||
throw new InvalidDataException("No valid shellmaps available");
|
||||
|
||||
return shellmaps.Random(CosmeticRandom).Key;
|
||||
return shellmaps.Random(CosmeticRandom);
|
||||
}
|
||||
|
||||
static bool quit;
|
||||
public static event Action OnQuit = () => {};
|
||||
public static event Action OnQuit = () => { };
|
||||
|
||||
static double idealFrameTime;
|
||||
public static void SetIdealFrameTime(int fps)
|
||||
{
|
||||
idealFrameTime = 1.0 / fps;
|
||||
}
|
||||
|
||||
internal static void Run()
|
||||
{
|
||||
if (Settings.Graphics.MaxFramerate < 1)
|
||||
{
|
||||
Settings.Graphics.MaxFramerate = new GraphicSettings().MaxFramerate;
|
||||
Settings.Graphics.CapFramerate = false;
|
||||
}
|
||||
|
||||
SetIdealFrameTime(Settings.Graphics.MaxFramerate);
|
||||
|
||||
while (!quit)
|
||||
{
|
||||
var idealFrameTime = 1.0 / Settings.Graphics.MaxFramerate;
|
||||
var sw = new Stopwatch();
|
||||
|
||||
Tick(orderManager);
|
||||
|
||||
if (Settings.Graphics.CapFramerate)
|
||||
{
|
||||
var waitTime = idealFrameTime - sw.ElapsedTime();
|
||||
var sw = new Stopwatch();
|
||||
|
||||
Tick(orderManager);
|
||||
|
||||
var waitTime = Math.Min(idealFrameTime - sw.ElapsedTime(), 1);
|
||||
if (waitTime > 0)
|
||||
System.Threading.Thread.Sleep( TimeSpan.FromSeconds(waitTime) );
|
||||
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(waitTime));
|
||||
}
|
||||
else
|
||||
Tick(orderManager);
|
||||
}
|
||||
|
||||
OnQuit();
|
||||
@@ -451,11 +478,11 @@ namespace OpenRA
|
||||
|
||||
public static void Exit() { quit = true; }
|
||||
|
||||
public static Action<Color,string,string> AddChatLine = (c,n,s) => {};
|
||||
public static Action<Color, string, string> AddChatLine = (c, n, s) => { };
|
||||
|
||||
public static void Debug(string s, params object[] args)
|
||||
{
|
||||
AddChatLine(Color.White, "Debug", String.Format(s,args));
|
||||
AddChatLine(Color.White, "Debug", string.Format(s, args));
|
||||
}
|
||||
|
||||
public static void Disconnect()
|
||||
@@ -474,15 +501,14 @@ namespace OpenRA
|
||||
server.Shutdown();
|
||||
}
|
||||
|
||||
public static T CreateObject<T>( string name )
|
||||
public static T CreateObject<T>(string name)
|
||||
{
|
||||
return modData.ObjectCreator.CreateObject<T>(name);
|
||||
}
|
||||
|
||||
public static void CreateServer(ServerSettings settings)
|
||||
{
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort),
|
||||
Game.Settings.Game.Mods, settings, modData);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, modData);
|
||||
}
|
||||
|
||||
public static int CreateLocalServer(string map)
|
||||
@@ -492,11 +518,10 @@ namespace OpenRA
|
||||
Name = "Skirmish Game",
|
||||
Map = map,
|
||||
AdvertiseOnline = false,
|
||||
AllowPortForward = false
|
||||
AllowPortForward = false
|
||||
};
|
||||
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0),
|
||||
Game.Settings.Game.Mods, settings, modData);
|
||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, modData);
|
||||
|
||||
return server.Port;
|
||||
}
|
||||
@@ -505,29 +530,5 @@ namespace OpenRA
|
||||
{
|
||||
return orderManager != null && orderManager.world == world;
|
||||
}
|
||||
|
||||
public static bool DownloadMap(string mapHash)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mod = Game.CurrentMods.FirstOrDefault().Value.Id;
|
||||
var dirPath = "{1}maps{0}{2}".F(Path.DirectorySeparatorChar, Platform.SupportDir, mod);
|
||||
if(!Directory.Exists(dirPath))
|
||||
Directory.CreateDirectory(dirPath);
|
||||
var mapPath = "{1}{0}{2}".F(Path.DirectorySeparatorChar, dirPath, mapHash+".oramap");
|
||||
Console.Write("Trying to download map to {0} ... ".F(mapPath));
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile(Game.Settings.Game.MapRepository + mapHash, mapPath);
|
||||
Game.modData.AvailableMaps.Add(mapHash, new Map(mapPath));
|
||||
Console.WriteLine("done");
|
||||
return true;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
Log.Write("debug", "Could not download map '{0}'", mapHash);
|
||||
Log.Write("debug", e.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Server;
|
||||
|
||||
namespace OpenRA.GameRules
|
||||
{
|
||||
@@ -78,7 +75,6 @@ namespace OpenRA.GameRules
|
||||
public bool SanityCheckUnsyncedCode = false;
|
||||
public int Samples = 25;
|
||||
public bool IgnoreVersionMismatch = false;
|
||||
public bool DeveloperMenu = false;
|
||||
|
||||
public bool ShowFatalErrorDialog = true;
|
||||
public string FatalErrorDialogFaq = "http://github.com/OpenRA/OpenRA/wiki/FAQ";
|
||||
@@ -88,7 +84,7 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
public string Renderer = "Gl";
|
||||
public WindowMode Mode = WindowMode.PseudoFullscreen;
|
||||
public int2 FullscreenSize = new int2(0,0);
|
||||
public int2 FullscreenSize = new int2(0, 0);
|
||||
public int2 WindowedSize = new int2(1024, 768);
|
||||
public bool PixelDouble = false;
|
||||
public bool CapFramerate = true;
|
||||
@@ -127,7 +123,8 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class GameSettings
|
||||
{
|
||||
public string[] Mods = { "ra" };
|
||||
public string Mod = "modchooser";
|
||||
public string PreviousMod = "ra";
|
||||
|
||||
public bool ShowShellmap = true;
|
||||
|
||||
@@ -136,12 +133,11 @@ namespace OpenRA.GameRules
|
||||
public float ViewportEdgeScrollStep = 10f;
|
||||
|
||||
public bool UseClassicMouseStyle = false;
|
||||
|
||||
// Internal game settings
|
||||
public int Timestep = 40;
|
||||
public bool AlwaysShowStatusBars = false;
|
||||
public bool TeamHealthColors = false;
|
||||
|
||||
public bool AllowDownloading = true;
|
||||
public string MapRepository = "http://content.open-ra.org/map/";
|
||||
public string MapRepository = "http://resource.openra.net/map/";
|
||||
}
|
||||
|
||||
public class KeySettings
|
||||
@@ -149,12 +145,21 @@ namespace OpenRA.GameRules
|
||||
public Hotkey CycleBaseKey = new Hotkey(Keycode.BACKSPACE, Modifiers.None);
|
||||
public Hotkey ToLastEventKey = new Hotkey(Keycode.SPACE, Modifiers.None);
|
||||
public Hotkey ToSelectionKey = new Hotkey(Keycode.HOME, Modifiers.None);
|
||||
public Hotkey SelectAllUnitsKey = new Hotkey(Keycode.A, Modifiers.Ctrl);
|
||||
public Hotkey SelectUnitsByTypeKey = new Hotkey(Keycode.T, Modifiers.Ctrl);
|
||||
|
||||
public Hotkey PauseKey = new Hotkey(Keycode.F9, Modifiers.None);
|
||||
public Hotkey PauseKey = new Hotkey(Keycode.F8, Modifiers.None);
|
||||
public Hotkey PlaceBeaconKey = new Hotkey(Keycode.F9, Modifiers.None);
|
||||
public Hotkey SellKey = new Hotkey(Keycode.F10, Modifiers.None);
|
||||
public Hotkey PowerDownKey = new Hotkey(Keycode.F11, Modifiers.None);
|
||||
public Hotkey RepairKey = new Hotkey(Keycode.F12, Modifiers.None);
|
||||
|
||||
public Hotkey NextProductionTabKey = new Hotkey(Keycode.PAGEDOWN, Modifiers.None);
|
||||
public Hotkey PreviousProductionTabKey = new Hotkey(Keycode.PAGEUP, Modifiers.None);
|
||||
public Hotkey CycleProductionBuildingsKey = new Hotkey(Keycode.TAB, Modifiers.None);
|
||||
|
||||
public Hotkey ToggleStatusBarsKey = new Hotkey(Keycode.INSERT, Modifiers.None);
|
||||
|
||||
public Hotkey AttackMoveKey = new Hotkey(Keycode.A, Modifiers.None);
|
||||
public Hotkey StopKey = new Hotkey(Keycode.S, Modifiers.None);
|
||||
public Hotkey ScatterKey = new Hotkey(Keycode.X, Modifiers.None);
|
||||
@@ -162,7 +167,8 @@ namespace OpenRA.GameRules
|
||||
public Hotkey StanceCycleKey = new Hotkey(Keycode.Z, Modifiers.None);
|
||||
public Hotkey GuardKey = new Hotkey(Keycode.D, Modifiers.None);
|
||||
|
||||
public Hotkey CycleTabsKey = new Hotkey(Keycode.TAB, Modifiers.None);
|
||||
public Hotkey ObserverCombinedView = new Hotkey(Keycode.MINUS, Modifiers.None);
|
||||
public Hotkey ObserverWorldView = new Hotkey(Keycode.EQUALS, Modifiers.None);
|
||||
}
|
||||
|
||||
public class IrcSettings
|
||||
@@ -183,7 +189,7 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class Settings
|
||||
{
|
||||
string SettingsFile;
|
||||
string settingsFile;
|
||||
|
||||
public PlayerSettings Player = new PlayerSettings();
|
||||
public GameSettings Game = new GameSettings();
|
||||
@@ -198,31 +204,31 @@ namespace OpenRA.GameRules
|
||||
|
||||
public Settings(string file, Arguments args)
|
||||
{
|
||||
SettingsFile = file;
|
||||
settingsFile = file;
|
||||
Sections = new Dictionary<string, object>()
|
||||
{
|
||||
{"Player", Player},
|
||||
{"Game", Game},
|
||||
{"Sound", Sound},
|
||||
{"Graphics", Graphics},
|
||||
{"Server", Server},
|
||||
{"Debug", Debug},
|
||||
{"Keys", Keys},
|
||||
{"Irc", Irc}
|
||||
{ "Player", Player },
|
||||
{ "Game", Game },
|
||||
{ "Sound", Sound },
|
||||
{ "Graphics", Graphics },
|
||||
{ "Server", Server },
|
||||
{ "Debug", Debug },
|
||||
{ "Keys", Keys },
|
||||
{ "Irc", Irc }
|
||||
};
|
||||
|
||||
// Override fieldloader to ignore invalid entries
|
||||
var err1 = FieldLoader.UnknownFieldAction;
|
||||
var err2 = FieldLoader.InvalidValueAction;
|
||||
|
||||
FieldLoader.UnknownFieldAction = (s,f) =>
|
||||
FieldLoader.UnknownFieldAction = (s, f) =>
|
||||
{
|
||||
Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) );
|
||||
Console.WriteLine("Ignoring unknown field `{0}` on `{1}`".F(s, f.Name));
|
||||
};
|
||||
|
||||
if (File.Exists(SettingsFile))
|
||||
if (File.Exists(settingsFile))
|
||||
{
|
||||
var yaml = MiniYaml.DictFromFile(SettingsFile);
|
||||
var yaml = MiniYaml.DictFromFile(settingsFile);
|
||||
|
||||
foreach (var kv in Sections)
|
||||
if (yaml.ContainsKey(kv.Key))
|
||||
@@ -232,8 +238,8 @@ namespace OpenRA.GameRules
|
||||
// Override with commandline args
|
||||
foreach (var kv in Sections)
|
||||
foreach (var f in kv.Value.GetType().GetFields())
|
||||
if (args.Contains(kv.Key+"."+f.Name))
|
||||
FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") );
|
||||
if (args.Contains(kv.Key + "." + f.Name))
|
||||
FieldLoader.LoadField(kv.Value, f.Name, args.GetValue(kv.Key + "." + f.Name, ""));
|
||||
|
||||
FieldLoader.UnknownFieldAction = err1;
|
||||
FieldLoader.InvalidValueAction = err2;
|
||||
@@ -242,19 +248,19 @@ namespace OpenRA.GameRules
|
||||
public void Save()
|
||||
{
|
||||
var root = new List<MiniYamlNode>();
|
||||
foreach( var kv in Sections )
|
||||
root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) );
|
||||
foreach (var kv in Sections)
|
||||
root.Add(new MiniYamlNode(kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType()))));
|
||||
|
||||
root.WriteToFile(SettingsFile);
|
||||
root.WriteToFile(settingsFile);
|
||||
}
|
||||
|
||||
void LoadSectionYaml(MiniYaml yaml, object section)
|
||||
{
|
||||
var defaults = Activator.CreateInstance(section.GetType());
|
||||
FieldLoader.InvalidValueAction = (s,t,f) =>
|
||||
FieldLoader.InvalidValueAction = (s, t, f) =>
|
||||
{
|
||||
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) );
|
||||
Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s, t.Name, f, ret));
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace OpenRA.GameRules
|
||||
{
|
||||
public class WarheadInfo
|
||||
{
|
||||
[Desc("Distance (in pixels) from the explosion center at which damage is 1/2.")]
|
||||
public readonly int Spread = 1;
|
||||
[Desc("Distance from the explosion center at which damage is 1/2.")]
|
||||
public readonly WRange Spread = new WRange(43);
|
||||
[FieldLoader.LoadUsing("LoadVersus")]
|
||||
[Desc("Damage vs each armortype. 0% = can't target.")]
|
||||
public readonly Dictionary<string, float> Versus;
|
||||
@@ -99,17 +99,17 @@ namespace OpenRA.GameRules
|
||||
|
||||
public class WeaponInfo
|
||||
{
|
||||
public readonly float Range = 0;
|
||||
public readonly WRange Range = WRange.Zero;
|
||||
public readonly string[] Report = null;
|
||||
[Desc("Rate of Fire")]
|
||||
public readonly int ROF = 1;
|
||||
public readonly int Burst = 1;
|
||||
public readonly bool Charges = false;
|
||||
public readonly bool Underwater = false;
|
||||
public readonly string Palette = "effect";
|
||||
public readonly string[] ValidTargets = { "Ground", "Water" };
|
||||
public readonly string[] InvalidTargets = { };
|
||||
public readonly int BurstDelay = 5;
|
||||
public readonly float MinRange = 0;
|
||||
public readonly WRange MinRange = WRange.Zero;
|
||||
|
||||
[FieldLoader.LoadUsing("LoadProjectile")] public IProjectileInfo Projectile;
|
||||
[FieldLoader.LoadUsing("LoadWarheads")] public List<WarheadInfo> Warheads;
|
||||
@@ -179,13 +179,12 @@ namespace OpenRA.GameRules
|
||||
if (!world.Map.IsInMap(cell))
|
||||
return false;
|
||||
|
||||
if (ValidTargets.Contains("Ground") && world.GetTerrainType(cell) != "Water")
|
||||
return true;
|
||||
var cellInfo = world.GetTerrainInfo(cell);
|
||||
if (!ValidTargets.Intersect(cellInfo.TargetTypes).Any()
|
||||
|| InvalidTargets.Intersect(cellInfo.TargetTypes).Any())
|
||||
return false;
|
||||
|
||||
if (ValidTargets.Contains("Water") && world.GetTerrainType(cell) == "Water")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
|
||||
@@ -79,12 +79,8 @@ namespace OpenRA.Graphics
|
||||
return cachedSprites[collection][image];
|
||||
|
||||
MappedImage mi;
|
||||
try { mi = collections[collection].regions[image]; }
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Collection `{0}` does not have an image `{1}`".F(collection, image));
|
||||
}
|
||||
if (!collections[collection].regions.TryGetValue(image, out mi))
|
||||
return null;
|
||||
|
||||
// Cached sheet
|
||||
Sheet sheet;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
@@ -17,6 +15,8 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public struct ContrailRenderable : IRenderable
|
||||
{
|
||||
public int Length { get { return trail.Length; } }
|
||||
|
||||
readonly World world;
|
||||
|
||||
// Store trail positions in a circular buffer
|
||||
|
||||
@@ -10,11 +10,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Xml;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using OpenRA.FileFormats;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -114,7 +113,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
var custom = map.CustomTerrain[mapX,mapY];
|
||||
var custom = map.CustomTerrain[mapX, mapY];
|
||||
if (custom == null)
|
||||
continue;
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb();
|
||||
@@ -186,9 +185,9 @@ namespace OpenRA.Graphics
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Bitmap RenderMapPreview(Map map)
|
||||
public static Bitmap RenderMapPreview(Map map, bool actualSize)
|
||||
{
|
||||
Bitmap terrain = TerrainBitmap(map);
|
||||
Bitmap terrain = TerrainBitmap(map, actualSize);
|
||||
return AddStaticResources(map, terrain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
@@ -68,5 +68,14 @@ namespace OpenRA.Graphics
|
||||
|
||||
return units[unit].ContainsKey(seq);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Sequences(string unit)
|
||||
{
|
||||
if (!units.ContainsKey(unit))
|
||||
throw new InvalidOperationException(
|
||||
"Unit `{0}` does not have all sequences defined.".F(unit));
|
||||
|
||||
return units[unit].Keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -38,13 +39,13 @@ namespace OpenRA.Graphics
|
||||
|
||||
public static Sheet AllocateSheet()
|
||||
{
|
||||
return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize));;
|
||||
return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize));
|
||||
}
|
||||
|
||||
internal SheetBuilder(SheetType t)
|
||||
public SheetBuilder(SheetType t)
|
||||
: this(t, AllocateSheet) {}
|
||||
|
||||
internal SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
|
||||
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
|
||||
{
|
||||
channel = TextureChannel.Red;
|
||||
type = t;
|
||||
@@ -52,15 +53,28 @@ namespace OpenRA.Graphics
|
||||
this.allocateSheet = allocateSheet;
|
||||
}
|
||||
|
||||
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, frame.Offset); }
|
||||
public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); }
|
||||
public Sprite Add(byte[] src, Size size, float2 spriteOffset)
|
||||
{
|
||||
// Don't bother allocating empty sprites
|
||||
if (size.Width == 0 || size.Height == 0)
|
||||
return new Sprite(current, Rectangle.Empty, spriteOffset, channel, BlendMode.Alpha);
|
||||
|
||||
var rect = Allocate(size, spriteOffset);
|
||||
Util.FastCopyIntoChannel(rect, src);
|
||||
current.CommitData();
|
||||
return rect;
|
||||
}
|
||||
|
||||
public Sprite Add(Bitmap src)
|
||||
{
|
||||
var rect = Allocate(src.Size);
|
||||
Util.FastCopyIntoSprite(rect, src);
|
||||
current.CommitData();
|
||||
return rect;
|
||||
}
|
||||
|
||||
public Sprite Add(Size size, byte paletteIndex)
|
||||
{
|
||||
var data = new byte[size.Width * size.Height];
|
||||
|
||||
@@ -1,210 +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
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
World world;
|
||||
Map map;
|
||||
Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
int shroudHash;
|
||||
|
||||
bool initializePalettes = true;
|
||||
PaletteReference fogPalette, shroudPalette;
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
{
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
|
||||
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
|
||||
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
|
||||
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
|
||||
new byte[] { 44 },
|
||||
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
|
||||
new byte[] { 40 },
|
||||
new byte[] { 35, 24, 17, 18 },
|
||||
new byte[] { 39, 39, 29, 29 },
|
||||
new byte[] { 45 },
|
||||
new byte[] { 43 },
|
||||
new byte[] { 38, 28 },
|
||||
new byte[] { 42 },
|
||||
new byte[] { 41 },
|
||||
new byte[] { 46 },
|
||||
};
|
||||
|
||||
public ShroudRenderer(World world)
|
||||
{
|
||||
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];
|
||||
|
||||
// Force update on first render
|
||||
shroudHash = -1;
|
||||
}
|
||||
|
||||
Sprite ChooseShroud(Shroud s, int i, int j)
|
||||
{
|
||||
if (!s.IsExplored(i, j))
|
||||
return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (!s.IsExplored(i, j - 1)) { v |= 1; u |= 3; }
|
||||
if (!s.IsExplored(i + 1, j)) { v |= 2; u |= 6; }
|
||||
if (!s.IsExplored(i, j + 1)) { v |= 4; u |= 12; }
|
||||
if (!s.IsExplored(i - 1, j)) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
if (!s.IsExplored(i - 1, j - 1)) u |= 1;
|
||||
if (!s.IsExplored(i + 1, j - 1)) u |= 2;
|
||||
if (!s.IsExplored(i + 1, j + 1)) u |= 4;
|
||||
if (!s.IsExplored(i - 1, j + 1)) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
Sprite ChooseFog(Shroud s, int i, int j)
|
||||
{
|
||||
if (!s.IsVisible(i, j)) return shadowBits[0xf];
|
||||
if (!s.IsExplored(i, j)) return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (!s.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
|
||||
if (!s.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
|
||||
if (!s.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
|
||||
if (!s.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if (!s.IsVisible(i - 1, j - 1)) u |= 1;
|
||||
if (!s.IsVisible(i + 1, j - 1)) u |= 2;
|
||||
if (!s.IsVisible(i + 1, j + 1)) u |= 4;
|
||||
if (!s.IsVisible(i - 1, j + 1)) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
void GenerateSprites(Shroud shroud)
|
||||
{
|
||||
var hash = shroud != null ? shroud.Hash : 0;
|
||||
if (shroudHash == hash)
|
||||
return;
|
||||
|
||||
shroudHash = hash;
|
||||
if (shroud == null)
|
||||
{
|
||||
// Players with no shroud see the whole map so we only need to set the edges
|
||||
var b = map.Bounds;
|
||||
for (int i = b.Left; i < b.Right; i++)
|
||||
for (int j = b.Top; j < b.Bottom; j++)
|
||||
{
|
||||
var v = 0;
|
||||
var u = 0;
|
||||
|
||||
if (j == b.Top) { v |= 1; u |= 3; }
|
||||
if (i == b.Right - 1) { v |= 2; u |= 6; }
|
||||
if (j == b.Bottom - 1) { v |= 4; u |= 12; }
|
||||
if (i == b.Left) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
if (i == b.Left && j == b.Top) u |= 1;
|
||||
if (i == b.Right - 1 && j == b.Top) u |= 2;
|
||||
if (i == b.Right - 1 && j == b.Bottom - 1) u |= 4;
|
||||
if (i == b.Left && j == b.Bottom - 1) u |= 8;
|
||||
|
||||
sprites[i, j] = fogSprites[i, j] = shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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(shroud, i, j);
|
||||
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
fogSprites[i, j] = ChooseFog(shroud, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Draw(WorldRenderer wr, Shroud shroud)
|
||||
{
|
||||
if (initializePalettes)
|
||||
{
|
||||
if (world.LobbyInfo.GlobalSettings.Fog)
|
||||
fogPalette = wr.Palette("fog");
|
||||
|
||||
shroudPalette = world.LobbyInfo.GlobalSettings.Fog ? wr.Palette("shroud") : wr.Palette("shroudfog");
|
||||
initializePalettes = false;
|
||||
}
|
||||
|
||||
GenerateSprites(shroud);
|
||||
|
||||
// We draw the shroud when disabled to hide the sharp map edges
|
||||
var clipRect = wr.Viewport.CellBounds;
|
||||
DrawShroud(wr, clipRect, sprites, shroudPalette);
|
||||
|
||||
if (world.LobbyInfo.GlobalSettings.Fog)
|
||||
DrawShroud(wr, clipRect, fogSprites, fogPalette);
|
||||
}
|
||||
|
||||
void DrawShroud(WorldRenderer wr, Rectangle clip, Sprite[,] s, PaletteReference pal)
|
||||
{
|
||||
for (var j = clip.Top; j < clip.Bottom; j++)
|
||||
{
|
||||
var starti = clip.Left;
|
||||
var last = shadowBits[0x0f];
|
||||
for (var i = clip.Left; i < clip.Right; i++)
|
||||
{
|
||||
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|
||||
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
// Stretch a solid black sprite over the rows above
|
||||
// TODO: This doesn't make sense for isometric terrain
|
||||
Game.Renderer.WorldSpriteRenderer.DrawSprite(
|
||||
s[starti, j],
|
||||
Game.CellSize * new float2(starti, j),
|
||||
pal,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
Game.Renderer.WorldSpriteRenderer.DrawSprite(s[i, j], Game.CellSize * new float2(i, j), pal);
|
||||
starti = i + 1;
|
||||
last = s[i, j];
|
||||
}
|
||||
|
||||
// Stretch a solid black sprite over the rows to the left
|
||||
// TODO: This doesn't make sense for isometric terrain
|
||||
if (starti < clip.Right)
|
||||
Game.Renderer.WorldSpriteRenderer.DrawSprite(s[starti, j],
|
||||
Game.CellSize * new float2(starti, j), pal,
|
||||
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenRA.FileFormats;
|
||||
using SharpFont;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
@@ -17,39 +16,25 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class SpriteLoader
|
||||
{
|
||||
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
|
||||
{
|
||||
SheetBuilder = sheetBuilder;
|
||||
this.exts = exts;
|
||||
sprites = new Cache<string, Sprite[]>(LoadSprites);
|
||||
}
|
||||
|
||||
readonly SheetBuilder SheetBuilder;
|
||||
readonly Cache<string, Sprite[]> sprites;
|
||||
readonly string[] exts;
|
||||
|
||||
Sprite[] LoadSprites(string filename)
|
||||
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
|
||||
{
|
||||
// TODO: Cleanly abstract file type detection
|
||||
if (filename.ToLower().EndsWith("r8"))
|
||||
{
|
||||
var r8 = new R8Reader(FileSystem.Open(filename));
|
||||
return r8.Select(a => SheetBuilder.Add(a.Image, a.Size, a.Offset)).ToArray();
|
||||
}
|
||||
SheetBuilder = sheetBuilder;
|
||||
|
||||
BinaryReader reader = new BinaryReader(FileSystem.OpenWithExts(filename, exts));
|
||||
// Include extension-less version
|
||||
this.exts = exts.Append("").ToArray();
|
||||
sprites = new Cache<string, Sprite[]>(CacheSpriteFrames);
|
||||
}
|
||||
|
||||
var ImageCount = reader.ReadUInt16();
|
||||
if (ImageCount == 0)
|
||||
{
|
||||
var shp = new ShpTSReader(FileSystem.OpenWithExts(filename, exts));
|
||||
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
|
||||
return shp.Frames.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
||||
}
|
||||
Sprite[] CacheSpriteFrames(string filename)
|
||||
{
|
||||
var stream = FileSystem.OpenWithExts(filename, exts);
|
||||
return SpriteSource.LoadSpriteSource(stream, filename).Frames
|
||||
.Select(a => SheetBuilder.Add(a))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -33,12 +30,15 @@ namespace OpenRA.Graphics
|
||||
int nv = 0;
|
||||
|
||||
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
{
|
||||
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
{
|
||||
var tile = wr.Theater.TileSprite(map.MapTiles.Value[i, j]);
|
||||
Util.FastCreateQuad(vertices, Game.CellSize * new float2(i, j), tile, terrainPalette, nv, tile.size);
|
||||
var pos = wr.ScreenPosition(new CPos(i, j).CenterPosition) - 0.5f * tile.size;
|
||||
Util.FastCreateQuad(vertices, pos, tile, terrainPalette, nv, tile.size);
|
||||
nv += 4;
|
||||
}
|
||||
}
|
||||
|
||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(vertices.Length);
|
||||
vertexBuffer.SetData(vertices, nv);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
|
||||
@@ -14,8 +14,6 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -25,27 +23,31 @@ namespace OpenRA.Graphics
|
||||
Dictionary<ushort, Sprite[]> templates;
|
||||
Sprite missingTile;
|
||||
|
||||
Sprite[] LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8Cache, int[] frames)
|
||||
Sprite[] LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
|
||||
{
|
||||
if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8"))
|
||||
ISpriteSource source;
|
||||
if (!sourceCache.ContainsKey(filename))
|
||||
{
|
||||
return frames.Select(f =>
|
||||
{
|
||||
if (f < 0)
|
||||
return null;
|
||||
using (var s = FileSystem.OpenWithExts(filename, exts))
|
||||
source = SpriteSource.LoadSpriteSource(s, filename);
|
||||
|
||||
var image = r8Cache[filename][f];
|
||||
return sheetBuilder.Add(image.Image, new Size(image.Size.Width, image.Size.Height));
|
||||
}).ToArray();
|
||||
if (source.CacheWhenLoadingTileset)
|
||||
sourceCache.Add(filename, source);
|
||||
}
|
||||
else
|
||||
source = sourceCache[filename];
|
||||
|
||||
if (frames != null)
|
||||
{
|
||||
var ret = new List<Sprite>();
|
||||
var srcFrames = source.Frames.ToArray();
|
||||
foreach (var i in frames)
|
||||
ret.Add(sheetBuilder.Add(srcFrames[i]));
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
using (var s = FileSystem.OpenWithExts(filename, exts))
|
||||
{
|
||||
var t = new Terrain(s);
|
||||
return t.TileBitmapBytes
|
||||
.Select(b => b != null ? sheetBuilder.Add(b, new Size(t.Width, t.Height)) : null)
|
||||
.ToArray();
|
||||
}
|
||||
return source.Frames.Select(f => sheetBuilder.Add(f)).ToArray();
|
||||
}
|
||||
|
||||
public Theater(TileSet tileset)
|
||||
@@ -60,11 +62,11 @@ namespace OpenRA.Graphics
|
||||
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize));
|
||||
};
|
||||
|
||||
var r8Cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")));
|
||||
var sourceCache = new Dictionary<string, ISpriteSource>();
|
||||
templates = new Dictionary<ushort, Sprite[]>();
|
||||
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
||||
foreach (var t in tileset.Templates)
|
||||
templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames));
|
||||
templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
|
||||
|
||||
// 1x1px transparent tile
|
||||
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
|
||||
@@ -73,11 +75,13 @@ namespace OpenRA.Graphics
|
||||
public Sprite TileSprite(TileReference<ushort, byte> r)
|
||||
{
|
||||
Sprite[] template;
|
||||
if (templates.TryGetValue(r.Type, out template))
|
||||
if (template.Length > r.Index && template[r.Index] != null)
|
||||
return template[r.Index];
|
||||
if (!templates.TryGetValue(r.Type, out template))
|
||||
return missingTile;
|
||||
|
||||
return missingTile;
|
||||
if (r.Index >= template.Length)
|
||||
return missingTile;
|
||||
|
||||
return template[r.Index];
|
||||
}
|
||||
|
||||
public Sheet Sheet { get { return sheetBuilder.Current; } }
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -59,6 +61,36 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public static void FastCopyIntoSprite(Sprite dest, Bitmap src)
|
||||
{
|
||||
var destStride = dest.sheet.Size.Width;
|
||||
var width = dest.bounds.Width;
|
||||
var height = dest.bounds.Height;
|
||||
|
||||
var srcData = src.LockBits(src.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
var c = (int*)srcData.Scan0;
|
||||
|
||||
// Cast the data to an int array so we can copy the src data directly
|
||||
fixed (byte* bd = &dest.sheet.Data[0])
|
||||
{
|
||||
var data = (int*)bd;
|
||||
var x = dest.bounds.Left;
|
||||
var y = dest.bounds.Top;
|
||||
|
||||
for (var j = 0; j < height; j++)
|
||||
for (var i = 0; i < width; i++)
|
||||
data[(y + j) * destStride + x + i] = *(c + (j * srcData.Stride >> 2) + i);
|
||||
}
|
||||
}
|
||||
|
||||
src.UnlockBits(srcData);
|
||||
|
||||
}
|
||||
|
||||
public static float[] IdentityMatrix()
|
||||
{
|
||||
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
|
||||
@@ -258,7 +290,7 @@ namespace OpenRA.Graphics
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var vec = new float[] {bounds[ix[i]], bounds[iy[i]], bounds[iz[i]], 1};
|
||||
var tvec = Util.MatrixVectorMultiply(mtx, vec);
|
||||
var tvec = MatrixVectorMultiply(mtx, vec);
|
||||
|
||||
ret[0] = Math.Min(ret[0], tvec[0]/tvec[3]);
|
||||
ret[1] = Math.Min(ret[1], tvec[1]/tvec[3]);
|
||||
|
||||
@@ -12,7 +12,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -41,6 +40,9 @@ namespace OpenRA.Graphics
|
||||
|
||||
// Viewport geometry (world-px)
|
||||
public int2 CenterLocation { get; private set; }
|
||||
|
||||
public WPos CenterPosition { get { return worldRenderer.Position(CenterLocation); } }
|
||||
|
||||
public int2 TopLeft { get { return CenterLocation - viewportSize / 2; } }
|
||||
public int2 BottomRight { get { return CenterLocation + viewportSize / 2; } }
|
||||
int2 viewportSize;
|
||||
|
||||
@@ -9,11 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user